Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/udfs/udf_dir.c
          +++ new/usr/src/uts/common/fs/udfs/udf_dir.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  24   24   */
  25   25  
  26   26  #include <sys/types.h>
  27   27  #include <sys/t_lock.h>
  28   28  #include <sys/param.h>
  29   29  #include <sys/time.h>
  30   30  #include <sys/systm.h>
  31   31  #include <sys/sysmacros.h>
  32   32  #include <sys/resource.h>
  33   33  #include <sys/signal.h>
  34   34  #include <sys/cred.h>
  35   35  #include <sys/user.h>
  36   36  #include <sys/buf.h>
  37   37  #include <sys/vfs.h>
  38   38  #include <sys/stat.h>
  39   39  #include <sys/vnode.h>
  40   40  #include <sys/mode.h>
  41   41  #include <sys/proc.h>
  42   42  #include <sys/disp.h>
  43   43  #include <sys/file.h>
  44   44  #include <sys/fcntl.h>
  45   45  #include <sys/flock.h>
  46   46  #include <sys/kmem.h>
  47   47  #include <sys/uio.h>
  48   48  #include <sys/dnlc.h>
  49   49  #include <sys/conf.h>
  50   50  #include <sys/errno.h>
  51   51  #include <sys/mman.h>
  52   52  #include <sys/fbuf.h>
  53   53  #include <sys/pathname.h>
  54   54  #include <sys/debug.h>
  55   55  #include <sys/vmsystm.h>
  56   56  #include <sys/cmn_err.h>
  57   57  #include <sys/dirent.h>
  58   58  #include <sys/errno.h>
  59   59  #include <sys/modctl.h>
  60   60  #include <sys/statvfs.h>
  61   61  #include <sys/mount.h>
  62   62  #include <sys/sunddi.h>
  63   63  #include <sys/bootconf.h>
  64   64  #include <sys/policy.h>
  65   65  
  66   66  #include <vm/hat.h>
  67   67  #include <vm/page.h>
  68   68  #include <vm/pvn.h>
  69   69  #include <vm/as.h>
  70   70  #include <vm/seg.h>
  71   71  #include <vm/seg_map.h>
  72   72  #include <vm/seg_kmem.h>
  73   73  #include <vm/seg_vn.h>
  74   74  #include <vm/rm.h>
  75   75  #include <vm/page.h>
  76   76  #include <sys/swap.h>
  77   77  
  78   78  
  79   79  #include <fs/fs_subr.h>
  80   80  
  81   81  
  82   82  #include <sys/fs/udf_volume.h>
  83   83  #include <sys/fs/udf_inode.h>
  84   84  
  85   85  
  86   86  struct slot {
  87   87          enum    {NONE, COMPACT, FOUND, EXIST} status;
  88   88          off_t   offset;         /* offset of area with free space */
  89   89          int     size;           /* size of area at slotoffset */
  90   90          struct  fbuf *fbp;      /* dir buf where slot is */
  91   91          struct file_id *ep;     /* pointer to slot */
  92   92          off_t   endoff;         /* last useful location found in search */
  93   93  };
  94   94  
  95   95  
  96   96  int32_t ud_dircheckforname(struct ud_inode *, char *, int,
  97   97                  struct slot *, struct ud_inode **, uint8_t *, struct cred *);
  98   98  int32_t ud_dirempty(struct ud_inode *, uint64_t, struct cred *);
  99   99  int32_t str2cmp(char *, int32_t, char *, int32_t, char *, int32_t);
 100  100  int32_t ud_dircheckpath(int32_t, struct ud_inode *, struct cred *);
 101  101  int32_t ud_dirmakeinode(struct ud_inode *, struct ud_inode **,
 102  102          struct vattr *, enum de_op, struct cred *);
 103  103  int32_t ud_diraddentry(struct ud_inode *, char *,
 104  104          enum de_op, int, struct slot *, struct ud_inode *,
 105  105          struct ud_inode *, struct cred *);
 106  106  int32_t ud_dirmakedirect(struct ud_inode *, struct ud_inode *, struct cred *);
 107  107  int32_t ud_dirrename(struct ud_inode *, struct ud_inode *,
 108  108          struct ud_inode *, struct ud_inode *, char *, uint8_t *,
 109  109          struct slot *, struct cred *);
 110  110  int32_t ud_dirprepareentry(struct ud_inode *,
 111  111          struct slot *, uint8_t *, struct cred *);
 112  112  int32_t ud_dirfixdotdot(struct ud_inode *, struct ud_inode *,
 113  113                  struct ud_inode *);
 114  114  int32_t ud_write_fid(struct ud_inode *, struct slot *, uint8_t *);
 115  115  
 116  116  int
 117  117  ud_dirlook(struct ud_inode *dip,
 118  118          char *namep, struct ud_inode **ipp, struct cred *cr, int32_t skipdnlc)
 119  119  {
 120  120          struct udf_vfs *udf_vfsp;
 121  121          int32_t error = 0, namelen, adhoc_search;
 122  122          u_offset_t offset, adhoc_offset, dirsize, end;
 123  123          struct vnode *dvp, *vp;
 124  124          struct fbuf *fbp;
 125  125          struct file_id *fid;
 126  126          uint8_t *fname, dummy[3];
 127  127          int32_t id_len, doingchk;
 128  128          uint32_t old_loc;
 129  129          uint16_t old_prn;
 130  130  
 131  131          uint8_t *dname;
 132  132          uint8_t *buf = NULL;
 133  133  
 134  134          ud_printf("ud_dirlook\n");
 135  135  
 136  136          udf_vfsp = dip->i_udf;
 137  137  
 138  138  restart:
 139  139          doingchk = 0;
 140  140          old_prn = 0xFFFF;
 141  141          old_loc = 0;
 142  142          dvp = ITOV(dip);
 143  143          /*
 144  144           * Check accessibility of directory.
 145  145           */
 146  146          if (dip->i_type != VDIR) {
 147  147                  return (ENOTDIR);
 148  148          }
 149  149          if (error = ud_iaccess(dip, IEXEC, cr, 1)) {
 150  150                  return (error);
 151  151          }
 152  152  
 153  153          /*
 154  154           * Null component name is synonym for directory being searched.
 155  155           */
 156  156          if (*namep == '\0') {
 157  157                  VN_HOLD(dvp);
 158  158                  *ipp = dip;
 159  159                  return (0);
 160  160          }
 161  161          namelen = strlen(namep);
 162  162          if ((namelen == 1) &&
 163  163              (namep[0] == '.') && (namep[1] == '\0')) {
 164  164                  /* Current directory */
 165  165                  VN_HOLD(dvp);
 166  166                  *ipp = dip;
 167  167                  dnlc_enter(dvp, namep, ITOV(*ipp));
 168  168                  return (0);
 169  169          }
 170  170  
 171  171          if ((!skipdnlc) && (vp = dnlc_lookup(dvp, namep))) {
 172  172                  /* vp is already held from dnlc_lookup */
 173  173  
 174  174                  *ipp = VTOI(vp);
 175  175                  return (0);
 176  176          }
 177  177  
 178  178          dname = kmem_zalloc(1024, KM_SLEEP);
 179  179          buf = kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
 180  180  
 181  181          /*
 182  182           * Read lock the inode we are searching.  You will notice that we
 183  183           * didn't hold the read lock while searching the dnlc.  This means
 184  184           * that the entry could now be in the dnlc.  This doesn't cause any
 185  185           * problems because dnlc_enter won't add an entry if it is already
 186  186           * there.
 187  187           */
 188  188          rw_enter(&dip->i_rwlock, RW_READER);
 189  189  
 190  190          /*
 191  191           * Take care to look at dip->i_diroff only once, as it
 192  192           * may be changing due to other threads/cpus.
 193  193           */
 194  194  
 195  195  recheck:
 196  196          offset = dip->i_diroff;
 197  197          end = dirsize = dip->i_size;
 198  198  
 199  199          if (offset > dirsize) {
 200  200                  offset = 0;
 201  201          }
 202  202          adhoc_offset = offset;
 203  203          adhoc_search = (offset == 0) ? 1 : 2;
 204  204  
 205  205          fbp = NULL;
 206  206  
 207  207          while (adhoc_search--) {
 208  208                  while (offset < end) {
 209  209                          error = ud_get_next_fid(dip, &fbp,
 210  210                              offset, &fid, &fname, buf);
 211  211                          if (error != 0) {
 212  212                                  break;
 213  213                          }
 214  214                          if ((fid->fid_flags & FID_DELETED) == 0) {
 215  215                                  if (fid->fid_flags & FID_PARENT) {
 216  216                                          id_len = 2;
 217  217                                          fname = dummy;
 218  218                                          dummy[0] = '.';
 219  219                                          dummy[1] = '.';
 220  220                                          dummy[2] = '\0';
 221  221                                  } else {
 222  222                                          if ((error = ud_uncompress(
 223  223                                              fid->fid_idlen, &id_len,
 224  224                                              fname, dname)) != 0) {
 225  225                                                  break;
 226  226                                          }
 227  227                                          fname = (uint8_t *)dname;
 228  228                                          fname[id_len] = '\0';
 229  229                                  }
 230  230                                  if ((namelen == id_len) &&
 231  231                                      (strncmp(namep, (caddr_t)fname,
 232  232                                      namelen) == 0)) {
 233  233                                          uint32_t loc;
 234  234                                          uint16_t prn;
 235  235  
 236  236  
 237  237                                          loc = SWAP_32(fid->fid_icb.lad_ext_loc);
 238  238                                          prn = SWAP_16(fid->fid_icb.lad_ext_prn);
 239  239                                          dip->i_diroff = offset + FID_LEN(fid);
 240  240  
 241  241                                          if (doingchk) {
 242  242                                                  if ((loc == old_loc) &&
 243  243                                                      (prn == old_prn)) {
 244  244                                                          goto checkok;
 245  245                                                  } else {
 246  246                                                          if (fbp != NULL) {
 247  247                                                                  fbrelse(fbp,
 248  248                                                                      S_READ);
 249  249                                                                  fbp = NULL;
 250  250                                                          }
 251  251                                                          VN_RELE(ITOV(*ipp));
 252  252                                                          rw_exit(&dip->i_rwlock);
 253  253                                                          goto restart;
 254  254                                                  }
 255  255                                                  /* NOTREACHED */
 256  256                                          }
 257  257  
 258  258                                          if (namelen == 2 &&
 259  259                                              fname[0] == '.' &&
 260  260                                              fname[1] == '.') {
 261  261  
 262  262                                                  struct timespec32 omtime;
 263  263  
 264  264                                                  omtime = dip->i_mtime;
 265  265                                                  rw_exit(&dip->i_rwlock);
 266  266  
 267  267                                                  error = ud_iget(dip->i_vfs, prn,
 268  268                                                      loc, ipp, NULL, cr);
 269  269  
 270  270                                                  rw_enter(&dip->i_rwlock,
 271  271                                                      RW_READER);
 272  272  
 273  273                                                  if (error) {
 274  274                                                          goto done;
 275  275                                                  }
 276  276  
 277  277                                                  if ((omtime.tv_sec !=
 278  278                                                      dip->i_mtime.tv_sec) ||
 279  279                                                      (omtime.tv_nsec !=
 280  280                                                      dip->i_mtime.tv_nsec)) {
 281  281  
 282  282                                                          doingchk = 1;
 283  283                                                          old_prn = prn;
 284  284                                                          old_loc = loc;
 285  285                                                          dip->i_diroff = 0;
 286  286                                                          if (fbp != NULL) {
 287  287                                                                  fbrelse(fbp,
 288  288                                                                      S_READ);
 289  289                                                                  fbp = NULL;
 290  290                                                          }
 291  291                                                          goto recheck;
 292  292                                                  }
 293  293                                          } else {
 294  294  
 295  295                                                  error = ud_iget(dip->i_vfs, prn,
 296  296                                                      loc, ipp, NULL, cr);
 297  297                                          }
 298  298  checkok:
 299  299                                          if (error == 0) {
 300  300                                                  dnlc_enter(dvp, namep,
 301  301                                                      ITOV(*ipp));
 302  302                                          }
 303  303                                          goto done;
 304  304                                  }
 305  305                          }
 306  306                          offset += FID_LEN(fid);
 307  307                  }
 308  308                  if (fbp != NULL) {
 309  309                          fbrelse(fbp, S_READ);
 310  310                          fbp = NULL;
 311  311                  }
 312  312                  end = adhoc_offset;
 313  313                  offset = 0;
 314  314          }
 315  315          error = ENOENT;
 316  316  done:
 317  317          kmem_free(buf, udf_vfsp->udf_lbsize);
 318  318          kmem_free(dname, 1024);
 319  319          if (fbp != NULL) {
 320  320                  fbrelse(fbp, S_READ);
 321  321          }
 322  322          rw_exit(&dip->i_rwlock);
 323  323          return (error);
 324  324  }
 325  325  
 326  326  int
 327  327  ud_direnter(
 328  328          struct ud_inode *tdp,
 329  329          char *namep,
 330  330          enum de_op op,
 331  331          struct ud_inode *sdp,
 332  332          struct ud_inode *sip,
 333  333          struct vattr *vap,
 334  334          struct ud_inode **ipp,
 335  335          struct cred *cr,
 336  336          caller_context_t *ctp)
 337  337  {
 338  338          struct udf_vfs *udf_vfsp;
 339  339          struct ud_inode *tip;
 340  340          struct slot slot;
 341  341          int32_t namlen, err;
 342  342          char *s;
 343  343  
 344  344          uint8_t *buf = NULL;
 345  345  
 346  346          ud_printf("ud_direnter\n");
 347  347  
 348  348          udf_vfsp = tdp->i_udf;
 349  349          /* don't allow '/' characters in pathname component */
 350  350          for (s = namep, namlen = 0; *s; s++, namlen++) {
 351  351                  if (*s == '/') {
 352  352                          return (EACCES);
 353  353                  }
 354  354          }
 355  355  
 356  356          if (namlen == 0) {
 357  357                  cmn_err(CE_WARN, "name length == 0 in ud_direnter");
 358  358                  return (EINVAL);
 359  359          }
 360  360  
 361  361          ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
 362  362          /*
 363  363           * If name is "." or ".." then if this is a create look it up
 364  364           * and return EEXIST.  Rename or link TO "." or ".." is forbidden.
 365  365           */
 366  366          if (namep[0] == '.' &&
 367  367              (namlen == 1 || (namlen == 2 && namep[1] == '.'))) {
 368  368                  if (op == DE_RENAME) {
 369  369                          return (EINVAL);        /* *SIGH* should be ENOTEMPTY */
 370  370                  }
 371  371                  if (ipp) {
 372  372                          /*
 373  373                           * ud_dirlook will acquire the i_rwlock
 374  374                           */
 375  375                          rw_exit(&tdp->i_rwlock);
 376  376                          if (err = ud_dirlook(tdp, namep, ipp, cr, 0)) {
 377  377                                  rw_enter(&tdp->i_rwlock, RW_WRITER);
 378  378                                  return (err);
 379  379                          }
 380  380                          rw_enter(&tdp->i_rwlock, RW_WRITER);
 381  381                  }
 382  382                  return (EEXIST);
 383  383          }
 384  384  
 385  385          tip = NULL;
 386  386          slot.status = NONE;
 387  387          slot.offset = 0;
 388  388          slot.size = 0;
 389  389          slot.fbp = NULL;
 390  390          slot.ep = NULL;
 391  391          slot.endoff = 0;
 392  392  
 393  393          /*
 394  394           * For link and rename lock the source entry and check the link count
 395  395           * to see if it has been removed while it was unlocked.  If not, we
 396  396           * increment the link count and force the inode to disk to make sure
 397  397           * that it is there before any directory entry that points to it.
 398  398           */
 399  399          if (op == DE_LINK || op == DE_RENAME) {
 400  400                  rw_enter(&sip->i_contents, RW_WRITER);
 401  401                  if (sip->i_nlink == 0) {
 402  402                          rw_exit(&sip->i_contents);
 403  403                          return (ENOENT);
 404  404                  }
 405  405                  if (sip->i_nlink == MAXLINK) {
 406  406                          rw_exit(&sip->i_contents);
 407  407                          return (EMLINK);
 408  408                  }
 409  409  
 410  410                  sip->i_nlink++;
 411  411                  mutex_enter(&sip->i_tlock);
 412  412                  sip->i_flag |= ICHG;
 413  413                  mutex_exit(&sip->i_tlock);
 414  414                  ud_iupdat(sip, 1);
 415  415                  rw_exit(&sip->i_contents);
 416  416          }
 417  417          /*
 418  418           * If target directory has not been removed, then we can consider
 419  419           * allowing file to be created.
 420  420           */
 421  421          if (tdp->i_nlink == 0) {
 422  422                  err = ENOENT;
 423  423                  goto out2;
 424  424          }
 425  425          /*
 426  426           * Check accessibility of directory.
 427  427           */
 428  428          if (tdp->i_type != VDIR) {
 429  429                  err = ENOTDIR;
 430  430                  goto out2;
 431  431          }
 432  432          /*
 433  433           * Execute access is required to search the directory.
 434  434           */
 435  435          if (err = ud_iaccess(tdp, IEXEC, cr, 1)) {
 436  436                  goto out2;
 437  437          }
 438  438          /*
 439  439           * If this is a rename of a directory and the parent is
 440  440           * different (".." must be changed), then the source
 441  441           * directory must not be in the directory hierarchy
 442  442           * above the target, as this would orphan everything
 443  443           * below the source directory.  Also the user must have
 444  444           * write permission in the source so as to be able to
 445  445           * change "..".
 446  446           */
 447  447          if (op == DE_RENAME) {
 448  448                  if (sip == tdp) {
 449  449                          err = EINVAL;
 450  450                          goto out2;
 451  451                  }
 452  452                  rw_enter(&sip->i_contents, RW_READER);
 453  453                  if ((sip->i_type == VDIR) && (sdp != tdp)) {
 454  454                          uint32_t blkno;
 455  455  
 456  456                          if ((err = ud_iaccess(sip, IWRITE, cr, 0))) {
 457  457                                  rw_exit(&sip->i_contents);
 458  458                                  goto out2;
 459  459                          }
 460  460                          blkno = sip->i_icb_lbano;
 461  461                          rw_exit(&sip->i_contents);
 462  462                          if ((err = ud_dircheckpath(blkno, tdp, cr))) {
 463  463                                  goto out2;
 464  464                          }
 465  465                  } else {
 466  466                          rw_exit(&sip->i_contents);
 467  467                  }
 468  468          }
 469  469  
 470  470          /*
 471  471           * Search for the entry. Return VN_HELD tip if found.
 472  472           */
 473  473          buf = kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
 474  474          rw_enter(&tdp->i_contents, RW_WRITER);
 475  475          if (err = ud_dircheckforname(tdp,
 476  476              namep, namlen, &slot, &tip, buf, cr)) {
 477  477                  goto out;
 478  478          }
 479  479          if (tip) {
 480  480                  switch (op) {
 481  481                          case DE_CREATE :
 482  482                          case DE_MKDIR :
 483  483                                  if (ipp) {
 484  484                                          *ipp = tip;
 485  485                                          err = EEXIST;
 486  486                                  } else {
 487  487                                          VN_RELE(ITOV(tip));
 488  488                                  }
 489  489                                  break;
 490  490                          case DE_RENAME :
 491  491                                  err = ud_dirrename(sdp, sip, tdp, tip,
 492  492                                      namep, buf, &slot, cr);
 493  493                                  /*
 494  494                                   * We used to VN_RELE() here, but this
 495  495                                   * was moved down so that we could send
 496  496                                   * a vnevent after the locks were dropped.
 497  497                                   */
 498  498                                  break;
 499  499                          case DE_LINK :
 500  500                                  /*
 501  501                                   * Can't link to an existing file.
 502  502                                   */
 503  503                                  VN_RELE(ITOV(tip));
 504  504                                  err = EEXIST;
 505  505                                  break;
 506  506                  }
 507  507          } else {
 508  508                  /*
 509  509                   * The entry does not exist. Check write permission in
 510  510                   * directory to see if entry can be created.
 511  511                   */
 512  512                  if (err = ud_iaccess(tdp, IWRITE, cr, 0)) {
 513  513                          goto out;
 514  514                  }
 515  515                  if ((op == DE_CREATE) || (op == DE_MKDIR)) {
 516  516                          /*
 517  517                           * Make new inode and directory entry as required.
 518  518                           */
 519  519                          if (err = ud_dirmakeinode(tdp, &sip, vap, op, cr))
 520  520                                  goto out;
 521  521                  }
 522  522                  if (err = ud_diraddentry(tdp, namep, op,
 523  523                      namlen, &slot, sip, sdp, cr)) {
 524  524                          if ((op == DE_CREATE) || (op == DE_MKDIR)) {
 525  525                                  /*
 526  526                                   * Unmake the inode we just made.
 527  527                                   */
 528  528                                  rw_enter(&sip->i_contents, RW_WRITER);
 529  529                                  if (sip->i_type == VDIR) {
 530  530                                          tdp->i_nlink--;
 531  531                                  }
 532  532                                  sip->i_nlink = 0;
 533  533                                  mutex_enter(&sip->i_tlock);
 534  534                                  sip->i_flag |= ICHG;
 535  535                                  mutex_exit(&sip->i_tlock);
 536  536                                  rw_exit(&sip->i_contents);
 537  537                                  VN_RELE(ITOV(sip));
 538  538                                  sip = NULL;
 539  539                          }
 540  540                  } else if (ipp) {
 541  541                          *ipp = sip;
 542  542                  } else if ((op == DE_CREATE) || (op == DE_MKDIR)) {
 543  543                          VN_RELE(ITOV(sip));
 544  544                  }
 545  545          }
 546  546  out:
 547  547          if (buf != NULL) {
 548  548                  kmem_free(buf, udf_vfsp->udf_lbsize);
 549  549          }
 550  550          if (slot.fbp) {
 551  551                  fbrelse(slot.fbp, S_OTHER);
 552  552          }
 553  553          rw_exit(&tdp->i_contents);
 554  554  
 555  555          if (op == DE_RENAME) {
 556  556                  /*
 557  557                   * If it's all good, send events after locks are dropped
 558  558                   * but before vnodes are released.
 559  559                   */
 560  560                  if (err == 0) {
 561  561                          if (tip) {
 562  562                                  vnevent_rename_dest(ITOV(tip), ITOV(tdp),
 563  563                                      namep, ctp);
 564  564                          }
 565  565  
 566  566                          vnevent_rename_dest_dir(ITOV(tdp), ITOV(tip),
 567  567                              namep, ctp);
 568  568                  }
 569  569  
 570  570                  /*
 571  571                   * The following VN_RELE() was moved from the
 572  572                   * DE_RENAME case above
 573  573                   */
 574  574                  if (tip) {
 575  575                          VN_RELE(ITOV(tip));
 576  576                  }
 577  577          }
 578  578  
 579  579  out2:
 580  580          if (err && ((op == DE_LINK) || (op == DE_RENAME))) {
 581  581                  /*
 582  582                   * Undo bumped link count.
 583  583                   */
 584  584                  rw_enter(&sip->i_contents, RW_WRITER);
 585  585                  sip->i_nlink--;
 586  586                  rw_exit(&sip->i_contents);
 587  587  
 588  588                  mutex_enter(&sip->i_tlock);
 589  589                  sip->i_flag |= ICHG;
 590  590                  mutex_exit(&sip->i_tlock);
 591  591          }
 592  592          return (err);
 593  593  }
 594  594  
 595  595  /*
 596  596   * Locking i_contents in this
 597  597   * function seems to be really weird
 598  598   */
 599  599  int
 600  600  ud_dirremove(
 601  601          struct ud_inode *dp,
 602  602          char *namep,
 603  603          struct ud_inode *oip,
 604  604          struct vnode *cdir,
 605  605          enum dr_op op,
 606  606          struct cred *cr,
 607  607          caller_context_t *ctp)
 608  608  {
 609  609          struct udf_vfs *udf_vfsp;
 610  610          int32_t namelen, err = 0;
 611  611          struct slot slot;
 612  612          struct ud_inode *ip;
 613  613          mode_t mode;
 614  614          struct file_id *fid;
 615  615          uint8_t *buf = NULL;
 616  616          uint32_t tbno;
 617  617  
 618  618          ud_printf("ud_dirremove\n");
 619  619  
 620  620          ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
 621  621  
 622  622          udf_vfsp = dp->i_udf;
 623  623          namelen = (int)strlen(namep);
 624  624          if (namelen == 0) {
 625  625                  cmn_err(CE_WARN, "name length == 0 in ud_dirremove");
 626  626                  return (EINVAL);
 627  627          }
 628  628  
 629  629          /*
 630  630           * return err when removing . and ..
 631  631           */
 632  632          if (namep[0] == '.') {
 633  633                  if (namelen == 1) {
 634  634                          return (EINVAL);
 635  635                  } else if (namelen == 2 && namep[1] == '.') {
 636  636                          return (EEXIST);        /* SIGH should be ENOTEMPTY */
 637  637                  }
 638  638          }
 639  639  
 640  640          ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
 641  641  
 642  642          /*
 643  643           * Check accessibility of directory.
 644  644           */
 645  645          if (dp->i_type != VDIR) {
 646  646                  return (ENOTDIR);
 647  647          }
 648  648  
 649  649          ip = NULL;
 650  650          slot.status = FOUND;    /* don't need to look for empty slot */
 651  651          slot.offset = 0;
 652  652          slot.size = 0;
 653  653          slot.fbp = NULL;
 654  654          slot.ep = NULL;
 655  655          slot.endoff = 0;
 656  656          /*
 657  657           * Execute access is required to search the directory.
 658  658           * Access for write is interpreted as allowing
 659  659           * deletion of files in the directory.
 660  660           */
 661  661          if (err = ud_iaccess(dp, IEXEC|IWRITE, cr, 1)) {
 662  662                  return (err);
 663  663          }
 664  664  
 665  665          buf = (uint8_t *)kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
 666  666  
 667  667          rw_enter(&dp->i_contents, RW_WRITER);
 668  668  
 669  669          if (err = ud_dircheckforname(dp, namep, namelen, &slot, &ip,
 670  670              buf, cr)) {
 671  671                  goto out_novfs;
 672  672          }
 673  673          if (ip == NULL) {
 674  674                  err = ENOENT;
 675  675                  goto out_novfs;
 676  676          }
 677  677          if (oip && oip != ip) {
 678  678                  err = ENOENT;
 679  679                  goto out_novfs;
 680  680          }
 681  681  
 682  682          if ((mode = ip->i_type) == VDIR) {
 683  683                  /*
 684  684                   * vn_vfswlock() prevents races between mount and rmdir.
 685  685                   */
 686  686                  if (vn_vfswlock(ITOV(ip))) {
 687  687                          err = EBUSY;
 688  688                          goto out_novfs;
 689  689                  }
 690  690                  if (vn_mountedvfs(ITOV(ip)) != NULL && op != DR_RENAME) {
 691  691                          err = EBUSY;
 692  692                          goto out;
 693  693                  }
 694  694                  /*
 695  695                   * If we are removing a directory, get a lock on it.
 696  696                   * If the directory is empty, it will stay empty until
 697  697                   * we can remove it.
 698  698                   */
 699  699                  rw_enter(&ip->i_rwlock, RW_READER);
 700  700          }
 701  701          /* We must be holding i_contents */
 702  702          rw_enter(&ip->i_contents, RW_READER);
 703  703  
 704  704          if (err = ud_sticky_remove_access(dp, ip, cr)) {
 705  705                  rw_exit(&ip->i_contents);
 706  706                  if (mode == VDIR) {
 707  707                          rw_exit(&ip->i_rwlock);
 708  708                  }
 709  709                  goto out;
 710  710          }
 711  711          if (op == DR_RMDIR) {
 712  712                  /*
 713  713                   * For rmdir(2), some special checks are required.
 714  714                   * (a) Don't remove any alias of the parent (e.g. ".").
 715  715                   * (b) Don't remove the current directory.
 716  716                   * (c) Make sure the entry is (still) a directory.
 717  717                   * (d) Make sure the directory is empty.
 718  718                   */
 719  719  
 720  720                  if (dp == ip || ITOV(ip) == cdir) {
 721  721                          err = EINVAL;
 722  722                  } else if (ip->i_type != VDIR) {
 723  723                          err = ENOTDIR;
 724  724                  } else if ((ip->i_nlink != 1) ||
 725  725                      (!ud_dirempty(ip, dp->i_uniqid, cr))) {
 726  726                          /*
 727  727                           * Directories do not have an
 728  728                           * entry for "." so only one link
 729  729                           * will be there
 730  730                           */
 731  731                          err = EEXIST;   /* SIGH should be ENOTEMPTY */
 732  732                  }
 733  733                  if (err) {
 734  734                          rw_exit(&ip->i_contents);
 735  735                          if (mode == VDIR) {
 736  736                                  rw_exit(&ip->i_rwlock);
 737  737                          }
 738  738                          goto out;
 739  739                  }
 740  740          } else if (op == DR_REMOVE)  {
 741  741                  /*
 742  742                   * unlink(2) requires a different check: allow only
 743  743                   * privileged processes to unlink a directory.
 744  744                   */
 745  745                  struct vnode *vp = ITOV(ip);
 746  746  
 747  747                  if (vp->v_type == VDIR &&
 748  748                      secpolicy_fs_linkdir(cr, vp->v_vfsp)) {
 749  749                          err = EPERM;
 750  750                          rw_exit(&ip->i_contents);
 751  751                          rw_exit(&ip->i_rwlock);
 752  752                          goto out;
 753  753                  }
 754  754          }
 755  755          rw_exit(&ip->i_contents);
 756  756  
 757  757          /*
 758  758           * Remove the cache'd entry, if any.
 759  759           */
 760  760          dnlc_remove(ITOV(dp), namep);
 761  761  
 762  762          /*
 763  763           * We can collapse all the directory
 764  764           * entries that are deleted into one big entry
 765  765           * but the better way is to
 766  766           * defer it till next directory entry
 767  767           * creation. where we can do this
 768  768           * in a more efficient way
 769  769           */
 770  770          fid = slot.ep;
 771  771  
 772  772          /*
 773  773           * If this is the last entry
 774  774           * just truncate the file instead
 775  775           * of marking it deleted
 776  776           */
 777  777          if ((slot.offset + FID_LEN(fid)) == dp->i_size) {
 778  778                  fbrelse(slot.fbp, S_OTHER);
 779  779                  if ((err = ud_itrunc(dp, slot.offset, 0, cr)) != 0) {
 780  780                          goto out;
 781  781                  }
 782  782          } else {
 783  783                  fid->fid_flags |= FID_DELETED;
 784  784  
 785  785                  if ((err = ud_ip_off2bno(dp, slot.offset, &tbno)) != 0) {
 786  786                          goto out;
 787  787                  }
 788  788  
 789  789                  ud_make_tag(dp->i_udf, &fid->fid_tag,
 790  790                      UD_FILE_ID_DESC, tbno, FID_LEN(fid));
 791  791  
 792  792                  err = ud_write_fid(dp, &slot, buf);
 793  793          }
 794  794  
 795  795          slot.fbp = NULL;
 796  796  
 797  797          /*
 798  798           * If we were removing a directory, it is 'gone' now so we can
 799  799           * unlock it.
 800  800           */
 801  801          if (mode == VDIR) {
 802  802                  rw_exit(&ip->i_rwlock);
 803  803          }
 804  804  
 805  805          mutex_enter(&dp->i_tlock);
 806  806          dp->i_flag |= IUPD|ICHG;
 807  807          mutex_exit(&dp->i_tlock);
 808  808          mutex_enter(&ip->i_tlock);
 809  809          ip->i_flag |= ICHG;
 810  810          mutex_exit(&ip->i_tlock);
 811  811  
 812  812          if (err != 0) {
 813  813                  goto out;
 814  814          }
 815  815  
 816  816          rw_enter(&ip->i_contents, RW_WRITER);
 817  817  
 818  818          /*
 819  819           * Now dispose of the inode.
 820  820           */
 821  821          if (ip->i_nlink > 0) {
 822  822                  if ((op == DR_RMDIR) && (ip->i_type == VDIR)) {
 823  823                          /*
 824  824                           * Decrement by 1 because there is no "."
 825  825                           * Clear the inode, but there may be other hard
 826  826                           * links so don't free the inode.
 827  827                           * Decrement the dp linkcount because we're
 828  828                           * trashing the ".." entry.
 829  829                           */
 830  830                          ip->i_nlink --;
 831  831                          dp->i_nlink--;
 832  832                          dnlc_remove(ITOV(ip), ".");
 833  833                          dnlc_remove(ITOV(ip), "..");
 834  834  /*
 835  835   *                      (void) ud_itrunc(ip, 0, 0, cr);
 836  836   */
 837  837                  } else {
 838  838                          ip->i_nlink--;
 839  839                  }
 840  840          }
 841  841          ITIMES_NOLOCK(dp);
 842  842          ITIMES_NOLOCK(ip);
 843  843          rw_exit(&ip->i_contents);
 844  844  out:
 845  845          if (mode == VDIR) {
 846  846                  vn_vfsunlock(ITOV(ip));
 847  847          }
 848  848  out_novfs:
 849  849          ASSERT(RW_WRITE_HELD(&dp->i_contents));
 850  850  
 851  851          if (slot.fbp != NULL) {
 852  852                  fbrelse(slot.fbp, S_OTHER);
 853  853          }
 854  854          rw_exit(&dp->i_contents);
 855  855  
 856  856          if (ip) {
 857  857                  /*
 858  858                   * If no errors, send any events after locks are dropped,
 859  859                   * but before the VN_RELE().
 860  860                   */
 861  861                  if (err == 0) {
 862  862                          if (op == DR_REMOVE) {
 863  863                                  vnevent_remove(ITOV(ip), ITOV(dp), namep, ctp);
 864  864                          } else if (op == DR_RMDIR) {
 865  865                                  vnevent_rmdir(ITOV(ip), ITOV(dp), namep, ctp);
 866  866                          }
 867  867                  }
 868  868                  VN_RELE(ITOV(ip));
 869  869          }
 870  870  
 871  871          kmem_free(buf, udf_vfsp->udf_lbsize);
 872  872          return (err);
 873  873  }
 874  874  
 875  875  int
 876  876  ud_dircheckforname(struct ud_inode *tdp,
 877  877          char *namep, int32_t namelen, struct slot *slotp,
 878  878          struct ud_inode **ipp, uint8_t *buf, struct cred *cr)
 879  879  {
 880  880          struct udf_vfs *udf_vfsp;
 881  881          uint32_t dirsize, offset;
 882  882          struct fbuf *fbp;
 883  883          struct file_id *fid;
 884  884          int32_t sz, error = 0, sz_req, matched = 0;
 885  885          uint8_t *nm;
 886  886  
 887  887          uint8_t *dname;
 888  888          int32_t id_len;
 889  889  
 890  890          ud_printf("ud_dircheckforname\n");
 891  891  
 892  892          ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
 893  893          fbp = NULL;
 894  894  
 895  895          dname = (uint8_t *)kmem_zalloc(1024, KM_SLEEP);
 896  896  
 897  897          udf_vfsp = tdp->i_udf;
 898  898  
 899  899          offset = 0;
 900  900          dirsize = tdp->i_size;
 901  901  
 902  902          if (slotp->status != FOUND) {
 903  903                  int32_t temp;
 904  904  
 905  905                  temp = 1024; /* set to size of dname allocated above */
 906  906                  if ((error = ud_compress(namelen, &temp,
 907  907                      (uint8_t *)namep, dname)) != 0) {
 908  908                          goto end;
 909  909                  }
 910  910                  sz_req = F_LEN + temp;
 911  911                  sz_req  = (sz_req + 3) & ~3;
 912  912          }
 913  913  
 914  914          while (offset < dirsize) {
 915  915                  if ((error = ud_get_next_fid(tdp, &fbp,
 916  916                      offset, &fid, &nm, buf)) != 0) {
 917  917                          break;
 918  918                  }
 919  919                  if ((error = ud_uncompress(fid->fid_idlen,
 920  920                      &id_len, nm, dname)) != 0) {
 921  921                          break;
 922  922                  }
 923  923                  if ((fid->fid_flags & FID_DELETED) == 0) {
 924  924                          /* Check for name match */
 925  925                          if (((namelen == id_len) &&
 926  926                              (strncmp(namep, (caddr_t)dname, namelen) == 0)) ||
 927  927                              ((fid->fid_flags & FID_PARENT) &&
 928  928                              (namep[0] == '.' &&
 929  929                              (namelen == 1 ||
 930  930                              (namelen == 2 && namep[1] == '.'))))) {
 931  931  
 932  932                                  tdp->i_diroff = offset;
 933  933                                  if ((fid->fid_flags & FID_PARENT) &&
 934  934                                      (namelen == 1) && (namep[0] == '.')) {
 935  935                                          struct vnode *vp = ITOV(tdp);
 936  936  
 937  937                                          *ipp = tdp;
 938  938                                          VN_HOLD(vp);
 939  939                                  } else {
 940  940                                          uint16_t prn;
 941  941                                          uint32_t loc;
 942  942  
 943  943                                          prn = SWAP_16(fid->fid_icb.lad_ext_prn);
 944  944                                          loc = SWAP_32(fid->fid_icb.lad_ext_loc);
 945  945                                          if ((error = ud_iget(tdp->i_vfs, prn,
 946  946                                              loc, ipp, NULL, cr)) != 0) {
 947  947  
 948  948                                                  fbrelse(fbp, S_OTHER);
 949  949                                                  goto end;
 950  950                                          }
 951  951                                  }
 952  952                                  slotp->status = EXIST;
 953  953                                  slotp->offset = offset;
 954  954                                  slotp->size = FID_LEN(fid);
 955  955                                  slotp->fbp = fbp;
 956  956                                  slotp->ep = fid;
 957  957                                  slotp->endoff = 0;
 958  958                                  goto end;
 959  959                          }
 960  960                  } else {
 961  961                          /*
 962  962                           * see if we need to find an
 963  963                           * empty slot and the current slot
 964  964                           * matches
 965  965                           */
 966  966                          if ((slotp->status != FOUND) || (matched == 0)) {
 967  967                                  sz = FID_LEN(fid);
 968  968                                  if (sz == sz_req) {
 969  969                                          slotp->status = FOUND;
 970  970                                          slotp->offset = offset;
 971  971                                          slotp->size = sz;
 972  972                                  }
 973  973                                  if (matched == 0) {
 974  974                                          if ((namelen == id_len) &&
 975  975                                              (strncmp(namep, (caddr_t)dname,
 976  976                                              namelen) == 0)) {
 977  977                                                  matched = 1;
 978  978                                                  slotp->status = FOUND;
 979  979                                                  slotp->offset = offset;
 980  980                                                  slotp->size = sz;
 981  981                                          }
 982  982                                  }
 983  983                          }
 984  984                  }
 985  985                  offset += FID_LEN(fid);
 986  986          }
 987  987          if (fbp) {
 988  988                  fbrelse(fbp, S_OTHER);
 989  989          }
 990  990          if (slotp->status == NONE) {
 991  991                  /*
 992  992                   * We didn't find a slot; the new directory entry should be put
 993  993                   * at the end of the directory.  Return an indication of where
 994  994                   * this is, and set "endoff" to zero; since we're going to have
 995  995                   * to extend the directory, we're certainly not going to
 996  996                   * trucate it.
 997  997                   */
 998  998                  slotp->offset = dirsize;
 999  999                  if (tdp->i_desc_type == ICB_FLAG_ONE_AD) {
1000 1000                          slotp->size = tdp->i_max_emb - tdp->i_size;
1001 1001                  } else {
1002 1002                          slotp->size = udf_vfsp->udf_lbsize -
1003 1003                              slotp->offset & udf_vfsp->udf_lbmask;
1004 1004                  }
1005 1005                  slotp->endoff = 0;
1006 1006          }
1007 1007  
1008 1008          *ipp = NULL;
1009 1009  end:
1010 1010          kmem_free((caddr_t)dname, 1024);
1011 1011          return (error);
1012 1012  }
1013 1013  
1014 1014  /*
1015 1015   * Return 1 if the dir has all files
1016 1016   * deleted except the parent
1017 1017   * else return 0
1018 1018   */
1019 1019  /* ARGSUSED */
1020 1020  int
1021 1021  ud_dirempty(struct ud_inode *ip, uint64_t ino, struct cred *cr)
1022 1022  {
1023 1023          offset_t off;
1024 1024          int32_t empty = 1, error, count, entry_len, rcount;
1025 1025          struct file_id *fid;
1026 1026          caddr_t addr;
1027 1027          uint32_t tbno;
1028 1028          int32_t desc_len;
1029 1029  
1030 1030          ud_printf("ud_dirempty\n");
1031 1031  
1032 1032          ASSERT(RW_LOCK_HELD(&ip->i_contents));
1033 1033  
1034 1034          if (ip->i_size == 0) {
1035 1035                  return (empty);
1036 1036          }
1037 1037  
1038 1038          desc_len = 1024;
1039 1039          addr = kmem_zalloc(desc_len, KM_SLEEP);
1040 1040          fid = (struct file_id *)addr;
1041 1041  
1042 1042          for (off = 0; off < ip->i_size; off += entry_len) {
1043 1043  
1044 1044                  /*
1045 1045                   * First read fid
1046 1046                   * and verify checksum
1047 1047                   */
1048 1048  
1049 1049                  rcount = sizeof (struct file_id);
1050 1050                  error = ud_rdwri(UIO_READ, FREAD, ip, addr, rcount, off,
1051 1051                      UIO_SYSSPACE, &count, cr);
1052 1052                  if ((error != 0) || (count != 0)) {
1053 1053                          empty = 0;
1054 1054                          break;
1055 1055                  }
1056 1056  
1057 1057                  if ((error = ud_ip_off2bno(ip, off, &tbno)) != 0) {
1058 1058                          empty = 0;
1059 1059                          break;
1060 1060                  }
1061 1061  
1062 1062                  /*
1063 1063                   * We verify the tag id and also the FID_LEN.
1064 1064                   * FID_LEN should be <= desc_len.
1065 1065                   */
1066 1066                  if (ud_verify_tag_and_desc(&fid->fid_tag,
1067 1067                      UD_FILE_ID_DESC,
1068 1068                      tbno, 0, desc_len) != 0) {
1069 1069                  /* Corrupted directory */
1070 1070                          empty = 0;
1071 1071                          break;
1072 1072                  }
1073 1073  
1074 1074                  /*
1075 1075                   * Read the fid + iulen + len
1076 1076                   * Now verify both checksum andCRC
1077 1077                   */
1078 1078  
1079 1079                  rcount = FID_LEN(fid);
1080 1080                  error = ud_rdwri(UIO_READ, FREAD, ip, addr, rcount, off,
1081 1081                      UIO_SYSSPACE, &count, cr);
1082 1082                  if ((error != 0) || (count != 0)) {
1083 1083                          empty = 0;
1084 1084                          break;
1085 1085                  }
1086 1086                  /*
1087 1087                   * Now that the entire decsriptor is read we verify the
1088 1088                   * crc.
1089 1089                   */
1090 1090                  if (ud_verify_tag_and_desc(&fid->fid_tag,
1091 1091                      UD_FILE_ID_DESC,
1092 1092                      tbno,
1093 1093                      1, rcount) != 0) {
1094 1094                          /* Corrupted directory */
1095 1095                          empty = 0;
1096 1096                          break;
1097 1097                  }
1098 1098  
1099 1099                  /*
1100 1100                   * Is the file deleted
1101 1101                   */
1102 1102  
1103 1103                  if ((fid->fid_flags & FID_DELETED) == 0) {
1104 1104                          if ((fid->fid_flags & FID_PARENT) == 0) {
1105 1105                                  empty = 0;
1106 1106                                  break;
1107 1107                          }
1108 1108                  }
1109 1109                  entry_len = FID_LEN(fid);
1110 1110          }
1111 1111  
1112 1112          kmem_free(addr, 1024);
1113 1113  
1114 1114          return (empty);
1115 1115  }
1116 1116  
1117 1117  
1118 1118  int
1119 1119  ud_dircheckpath(int32_t blkno,
1120 1120          struct ud_inode *target, struct cred *cr)
1121 1121  {
1122 1122          int32_t err = 0;
1123 1123          struct vfs *vfsp;
1124 1124          struct udf_vfs *udf_vfsp;
1125 1125          struct fbuf *fbp;
1126 1126          struct file_id *fid;
1127 1127          struct ud_inode *ip, *tip;
1128 1128          uint16_t prn;
1129 1129          uint32_t lbno, dummy, tbno;
1130 1130          daddr_t parent_icb_loc;
1131 1131  
1132 1132          ud_printf("ud_dircheckpath\n");
1133 1133  
1134 1134          udf_vfsp = target->i_udf;
1135 1135          ip = target;
1136 1136  
1137 1137          ASSERT(udf_vfsp != NULL);
1138 1138          ASSERT(MUTEX_HELD(&target->i_udf->udf_rename_lck));
1139 1139          ASSERT(RW_WRITE_HELD(&ip->i_rwlock));
1140 1140  
1141 1141          if (ip->i_icb_lbano == blkno) {
1142 1142                  err = EINVAL;
1143 1143                  goto out;
1144 1144          }
1145 1145          if (ip->i_icb_lbano == udf_vfsp->udf_root_blkno) {
1146 1146                  goto out;
1147 1147          }
1148 1148  
1149 1149          /*
1150 1150           * Search back through the directory tree, using the PARENT entries
1151 1151           * Fail any attempt to move a directory into an ancestor directory.
1152 1152           */
1153 1153          for (;;) {
1154 1154                  if ((err = fbread(ITOV(ip), 0,
1155 1155                      udf_vfsp->udf_lbsize, S_READ, &fbp)) != 0) {
1156 1156                          break;
1157 1157                  }
1158 1158  
1159 1159                  if ((err = ud_ip_off2bno(ip, 0, &tbno)) != 0) {
1160 1160                          break;
1161 1161                  }
1162 1162                  fid = (struct file_id *)fbp->fb_addr;
1163 1163                  /* IS this a valid file_identifier */
1164 1164                  if (ud_verify_tag_and_desc(&fid->fid_tag,
1165 1165                      UD_FILE_ID_DESC,
1166 1166                      tbno,
1167 1167                      1, udf_vfsp->udf_lbsize) != 0) {
1168 1168                          break;
1169 1169                  }
1170 1170                  if ((fid->fid_flags & FID_DELETED) != 0) {
1171 1171                          break;
1172 1172                  }
1173 1173                  if ((fid->fid_flags & FID_PARENT) == 0) {
1174 1174                          /*
1175 1175                           * This cannot happen unless
1176 1176                           * something is grossly wrong
1177 1177                           * First entry has to be parent
1178 1178                           */
1179 1179                          break;
1180 1180                  }
1181 1181                  prn = SWAP_16(fid->fid_icb.lad_ext_prn);
1182 1182                  lbno = SWAP_32(fid->fid_icb.lad_ext_loc);
1183 1183                  parent_icb_loc =
1184 1184                      ud_xlate_to_daddr(udf_vfsp, prn, lbno, 1, &dummy);
1185 1185                  ASSERT(dummy == 1);
1186 1186                  if (parent_icb_loc == blkno) {
1187 1187                          err = EINVAL;
1188 1188                          break;
1189 1189                  }
1190 1190                  vfsp = ip->i_vfs;
1191 1191                  udf_vfsp = ip->i_udf;
1192 1192                  if (parent_icb_loc == udf_vfsp->udf_root_blkno) {
1193 1193                          break;
1194 1194                  }
1195 1195                  if (fbp != NULL) {
1196 1196                          fbrelse(fbp, S_OTHER);
1197 1197                          fbp = NULL;
1198 1198                  }
1199 1199                  if (ip != target) {
1200 1200                          rw_exit(&ip->i_rwlock);
1201 1201                          VN_RELE(ITOV(ip));
1202 1202                  }
1203 1203  
1204 1204                  /*
1205 1205                   * Race to get the inode.
1206 1206                   */
1207 1207                  if (err = ud_iget(vfsp, prn, lbno, &tip, NULL, cr)) {
1208 1208                          ip = NULL;
1209 1209                          break;
1210 1210                  }
1211 1211                  ip = tip;
1212 1212                  rw_enter(&ip->i_rwlock, RW_READER);
1213 1213          }
1214 1214          if (fbp) {
1215 1215                  fbrelse(fbp, S_OTHER);
1216 1216          }
1217 1217  out:
1218 1218          if (ip) {
1219 1219                  if (ip != target) {
1220 1220                          rw_exit(&ip->i_rwlock);
1221 1221                          VN_RELE(ITOV(ip));
1222 1222                  }
1223 1223          }
1224 1224          return (err);
1225 1225  }
1226 1226  
1227 1227  int
1228 1228  ud_dirmakeinode(struct ud_inode *tdp, struct ud_inode **ipp,
1229 1229          struct vattr *vap, enum de_op op, struct cred *cr)
1230 1230  {
1231 1231          struct ud_inode *ip;
1232 1232          int32_t error;
1233 1233  
1234 1234          ASSERT(vap != NULL);
1235 1235          ASSERT(op == DE_CREATE || op == DE_MKDIR);
1236 1236          ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
1237 1237          ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1238 1238  
1239 1239          /*
1240 1240           * Allocate a new inode.
1241 1241           */
1242 1242          if ((error = ud_ialloc(tdp, &ip, vap, cr)) != 0) {
1243 1243                  return (error);
1244 1244          }
1245 1245  
1246 1246          ASSERT(ip != NULL);
1247 1247  
1248 1248          rw_enter(&ip->i_contents, RW_WRITER);
1249 1249  
1250 1250          if (op == DE_MKDIR) {
1251 1251                  error = ud_dirmakedirect(ip, tdp, cr);
1252 1252          }
1253 1253  
1254 1254          ip->i_flag |= IACC|IUPD|ICHG;
1255 1255          /*
1256 1256           * Clear IACC and/or IUPD if the caller specified the atime and/or
1257 1257           * mtime fields.  They were set from the passed in attributes in
1258 1258           * ud_ialloc().
1259 1259           */
1260 1260          if (vap->va_mask & AT_ATIME)
1261 1261                  ip->i_flag &= ~IACC;
1262 1262          if (vap->va_mask & AT_MTIME)
1263 1263                  ip->i_flag &= ~IUPD;
1264 1264          /*
1265 1265           * push inode before it's name appears in a directory
1266 1266           */
1267 1267          ud_iupdat(ip, 1);
1268 1268          *ipp = ip;
1269 1269          rw_exit(&ip->i_contents);
1270 1270          return (error);
1271 1271  }
1272 1272  
1273 1273  /*
1274 1274   * Enter the file sip in the directory tdp with name namep.
1275 1275   */
1276 1276  int
1277 1277  ud_diraddentry(struct ud_inode *tdp, char *namep,
1278 1278          enum de_op op, int32_t namelen, struct slot *slotp,
1279 1279          struct ud_inode *sip, struct ud_inode *sdp, struct cred *cr)
1280 1280  {
1281 1281          struct udf_vfs *udf_vfsp;
1282 1282          int32_t error, temp;
1283 1283          struct file_id *fid;
1284 1284          uint8_t *buf = NULL;
1285 1285  
1286 1286          ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1287 1287  
1288 1288          ud_printf("ud_diraddentry\n");
1289 1289  
1290 1290          udf_vfsp = sip->i_udf;
1291 1291  
1292 1292          /*
1293 1293           * Check inode to be linked to see if it is in the
1294 1294           * same filesystem.
1295 1295           */
1296 1296          if (ITOV(tdp)->v_vfsp != ITOV(sip)->v_vfsp) {
1297 1297                  error = EXDEV;
1298 1298                  goto bad;
1299 1299          }
1300 1300  
1301 1301          if ((op == DE_RENAME) && (sip->i_type == VDIR)) {
1302 1302                  if ((error = ud_dirfixdotdot(sip, sdp, tdp)) != 0) {
1303 1303                          goto bad;
1304 1304                  }
1305 1305          }
1306 1306  
1307 1307          buf = (uint8_t *)kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
1308 1308  
1309 1309          /*
1310 1310           * Fill in entry data.
1311 1311           */
1312 1312          fid = (struct file_id *)buf;
1313 1313          fid->fid_ver = SWAP_16(1);
1314 1314          if (sip->i_type == VDIR) {
1315 1315                  fid->fid_flags = FID_DIR;
1316 1316          } else {
1317 1317                  fid->fid_flags = 0;
1318 1318          }
1319 1319          fid->fid_iulen = 0;
1320 1320  
1321 1321          fid->fid_icb.lad_ext_len = SWAP_32(sip->i_udf->udf_lbsize);
1322 1322          fid->fid_icb.lad_ext_loc = SWAP_32(sip->i_icb_block);
1323 1323          fid->fid_icb.lad_ext_prn = SWAP_16(sip->i_icb_prn);
1324 1324          fid->fid_iulen = 0;
1325 1325  
1326 1326          temp = MIN(udf_vfsp->udf_lbsize - F_LEN, MAXNAMELEN);
1327 1327          if ((error = ud_compress(namelen, &temp,
1328 1328              (uint8_t *)namep, fid->fid_spec)) == 0) {
1329 1329                  fid->fid_idlen = (uint8_t)temp;
1330 1330                  error = ud_dirprepareentry(tdp, slotp, buf, cr);
1331 1331          }
1332 1332  
1333 1333          kmem_free(buf, udf_vfsp->udf_lbsize);
1334 1334  
1335 1335  bad:
1336 1336          return (error);
1337 1337  }
1338 1338  
1339 1339  /*
1340 1340   * Write a prototype directory into the empty inode ip, whose parent is dp.
1341 1341   */
1342 1342  /* ARGSUSED2 */
1343 1343  int
1344 1344  ud_dirmakedirect(struct ud_inode *ip,
1345 1345          struct ud_inode *dp, struct cred *cr)
1346 1346  {
1347 1347          int32_t err;
1348 1348          uint32_t blkno, size, parent_len, tbno;
1349 1349          struct fbuf *fbp;
1350 1350          struct file_id *fid;
1351 1351          struct icb_ext *iext;
1352 1352  
1353 1353          ud_printf("ud_dirmakedirect\n");
1354 1354  
1355 1355          ASSERT(RW_WRITE_HELD(&ip->i_contents));
1356 1356          ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
1357 1357  
1358 1358          parent_len = sizeof (struct file_id);
1359 1359  
1360 1360          if ((ip->i_desc_type != ICB_FLAG_ONE_AD) ||
1361 1361              (parent_len > ip->i_max_emb)) {
1362 1362                  ASSERT(ip->i_ext);
1363 1363                  /*
1364 1364                   * Allocate space for the directory we're creating.
1365 1365                   */
1366 1366                  if ((err = ud_alloc_space(ip->i_vfs, ip->i_icb_prn,
1367 1367                      0, 1, &blkno, &size, 0, 0)) != 0) {
1368 1368                          return (err);
1369 1369                  }
1370 1370                  /*
1371 1371                   * init with the size of
1372 1372                   * directory with just the
1373 1373                   * parent
1374 1374                   */
1375 1375                  ip->i_size = sizeof (struct file_id);
1376 1376                  ip->i_flag |= IUPD|ICHG|IATTCHG;
1377 1377                  iext = ip->i_ext;
1378 1378                  iext->ib_prn = ip->i_icb_prn;
1379 1379                  iext->ib_block = blkno;
1380 1380                  iext->ib_count = ip->i_size;
1381 1381                  iext->ib_offset = 0;
1382 1382                  ip->i_ext_used = 1;
1383 1383          } else {
1384 1384                  ip->i_size = sizeof (struct file_id);
1385 1385                  ip->i_flag |= IUPD|ICHG|IATTCHG;
1386 1386          }
1387 1387  
1388 1388          ITIMES_NOLOCK(ip);
1389 1389  
1390 1390          /*
1391 1391           * Update the dp link count and write out the change.
1392 1392           * This reflects the ".." entry we'll soon write.
1393 1393           */
1394 1394          if (dp->i_nlink == MAXLINK) {
1395 1395                  return (EMLINK);
1396 1396          }
1397 1397          dp->i_nlink++;
1398 1398          dp->i_flag |= ICHG;
1399 1399          ud_iupdat(dp, 1);
1400 1400  
1401 1401          /*
1402 1402           * Initialize directory with ".."
1403 1403           * Since the parent directory is locked, we don't have to
1404 1404           * worry about anything changing when we drop the write
1405 1405           * lock on (ip).
1406 1406           */
1407 1407          rw_exit(&ip->i_contents);
1408 1408          if ((err = fbread(ITOV(ip), (offset_t)0,
1409 1409              ip->i_udf->udf_lbsize, S_WRITE, &fbp)) != 0) {
1410 1410                  rw_enter(&ip->i_contents, RW_WRITER);
1411 1411                  return (err);
1412 1412          }
1413 1413  
1414 1414          bzero(fbp->fb_addr, ip->i_udf->udf_lbsize);
1415 1415  
1416 1416          fid = (struct file_id *)fbp->fb_addr;
1417 1417          fid->fid_ver = SWAP_16(1);
1418 1418          fid->fid_flags = FID_DIR | FID_PARENT;
1419 1419          fid->fid_icb.lad_ext_len = SWAP_32(dp->i_udf->udf_lbsize);
1420 1420          fid->fid_icb.lad_ext_loc = SWAP_32(dp->i_icb_block);
1421 1421          fid->fid_icb.lad_ext_prn = SWAP_16(dp->i_icb_prn);
1422 1422  
1423 1423          /*
1424 1424           * fid_idlen, fid_iulen and fid_spec are zero
1425 1425           * due to bzero above
1426 1426           */
1427 1427  
1428 1428          if ((err = ud_ip_off2bno(ip, 0, &tbno)) == 0) {
1429 1429                  ud_make_tag(ip->i_udf, &fid->fid_tag,
1430 1430                      UD_FILE_ID_DESC, tbno, FID_LEN(fid));
1431 1431          }
1432 1432  
1433 1433          err = ud_fbwrite(fbp, ip);
1434 1434          rw_enter(&ip->i_contents, RW_WRITER);
1435 1435  
1436 1436          return (err);
1437 1437  }
1438 1438  
1439 1439  int
1440 1440  ud_dirrename(struct ud_inode *sdp, struct ud_inode *sip,
1441 1441          struct ud_inode *tdp, struct ud_inode *tip, char *namep,
1442 1442          uint8_t *buf, struct slot *slotp, struct cred *cr)
1443 1443  {
1444 1444          int32_t error = 0, doingdirectory;
1445 1445          struct file_id *fid;
1446 1446  
1447 1447          ud_printf("ud_dirrename\n");
1448 1448          ASSERT(sdp->i_udf != NULL);
1449 1449          ASSERT(MUTEX_HELD(&sdp->i_udf->udf_rename_lck));
1450 1450          ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1451 1451          ASSERT(RW_WRITE_HELD(&tdp->i_contents));
1452 1452          ASSERT(buf);
1453 1453          ASSERT(slotp->ep);
1454 1454  
1455 1455          fid = slotp->ep;
1456 1456  
1457 1457          /*
1458 1458           * Short circuit rename of something to itself.
1459 1459           */
1460 1460          if (sip->i_icb_lbano == tip->i_icb_lbano) {
1461 1461                  return (ESAME);         /* special KLUDGE error code */
1462 1462          }
1463 1463          /*
1464 1464           * Everything is protected under the vfs_rename_lock so the ordering
1465 1465           * of i_contents locks doesn't matter here.
1466 1466           */
1467 1467          rw_enter(&sip->i_contents, RW_READER);
1468 1468          rw_enter(&tip->i_contents, RW_READER);
1469 1469  
1470 1470          /*
1471 1471           * Check that everything is on the same filesystem.
1472 1472           */
1473 1473          if ((ITOV(tip)->v_vfsp != ITOV(tdp)->v_vfsp) ||
1474 1474              (ITOV(tip)->v_vfsp != ITOV(sip)->v_vfsp)) {
1475 1475                  error = EXDEV;          /* XXX archaic */
1476 1476                  goto out;
1477 1477          }
1478 1478  
1479 1479          /*
1480 1480           * Must have write permission to rewrite target entry.
1481 1481           */
1482 1482          if ((error = ud_iaccess(tdp, IWRITE, cr, 0)) != 0 ||
1483 1483              (error = ud_sticky_remove_access(tdp, tip, cr)) != 0)
1484 1484                  goto out;
1485 1485  
1486 1486          /*
1487 1487           * Ensure source and target are compatible (both directories
1488 1488           * or both not directories).  If target is a directory it must
1489 1489           * be empty and have no links to it; in addition it must not
1490 1490           * be a mount point, and both the source and target must be
1491 1491           * writable.
1492 1492           */
1493 1493          doingdirectory = (sip->i_type == VDIR);
1494 1494          if (tip->i_type == VDIR) {
1495 1495                  if (!doingdirectory) {
1496 1496                          error = EISDIR;
1497 1497                          goto out;
1498 1498                  }
1499 1499                  /*
1500 1500                   * vn_vfswlock will prevent mounts from using the directory
1501 1501                   * until we are done.
1502 1502                   */
1503 1503                  if (vn_vfswlock(ITOV(tip))) {
1504 1504                          error = EBUSY;
1505 1505                          goto out;
1506 1506                  }
1507 1507                  if (vn_mountedvfs(ITOV(tip)) != NULL) {
1508 1508                          vn_vfsunlock(ITOV(tip));
1509 1509                          error = EBUSY;
1510 1510                          goto out;
1511 1511                  }
1512 1512                  if (!ud_dirempty(tip, tdp->i_uniqid, cr) || tip->i_nlink > 2) {
1513 1513                          vn_vfsunlock(ITOV(tip));
1514 1514                          error = EEXIST; /* SIGH should be ENOTEMPTY */
1515 1515                          goto out;
1516 1516                  }
1517 1517          } else if (doingdirectory) {
1518 1518                  error = ENOTDIR;
1519 1519                  goto out;
1520 1520          }
1521 1521  
1522 1522          /*
1523 1523           * Rewrite the inode pointer for target name entry
1524 1524           * from the target inode (ip) to the source inode (sip).
1525 1525           * This prevents the target entry from disappearing
1526 1526           * during a crash. Mark the directory inode to reflect the changes.
1527 1527           */
1528 1528          dnlc_remove(ITOV(tdp), namep);
1529 1529          fid->fid_icb.lad_ext_prn = SWAP_16(sip->i_icb_prn);
1530 1530          fid->fid_icb.lad_ext_loc = SWAP_32(sip->i_icb_block);
1531 1531          dnlc_enter(ITOV(tdp), namep, ITOV(sip));
1532 1532  
1533 1533          ud_make_tag(tdp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1534 1534              SWAP_32(fid->fid_tag.tag_loc), FID_LEN(fid));
1535 1535  
1536 1536          error = ud_write_fid(tdp, slotp, buf);
1537 1537  
1538 1538          if (error) {
1539 1539                  if (doingdirectory) {
1540 1540                          vn_vfsunlock(ITOV(tip));
1541 1541                  }
1542 1542                  goto out;
1543 1543          }
1544 1544  
1545 1545          /*
1546 1546           * Upgrade to write lock on tip
1547 1547           */
1548 1548          rw_exit(&tip->i_contents);
1549 1549          rw_enter(&tip->i_contents, RW_WRITER);
1550 1550  
1551 1551          mutex_enter(&tdp->i_tlock);
1552 1552          tdp->i_flag |= IUPD|ICHG;
1553 1553          mutex_exit(&tdp->i_tlock);
1554 1554          /*
1555 1555           * Decrement the link count of the target inode.
1556 1556           * Fix the ".." entry in sip to point to dp.
1557 1557           * This is done after the new entry is on the disk.
1558 1558           */
1559 1559          tip->i_nlink--;
1560 1560          mutex_enter(&tip->i_tlock);
1561 1561          tip->i_flag |= ICHG;
1562 1562          mutex_exit(&tip->i_tlock);
1563 1563  
1564 1564          if (doingdirectory) {
1565 1565                  /*
1566 1566                   * The entry for tip no longer exists so I can unlock the
1567 1567                   * vfslock.
1568 1568                   */
1569 1569                  vn_vfsunlock(ITOV(tip));
1570 1570                  /*
1571 1571                   * Decrement target link count once more if it was a directory.
1572 1572                   */
1573 1573                  if (tip->i_nlink != 0) {
1574 1574                          cmn_err(CE_WARN,
1575 1575                          "ud_direnter: target directory link count != 0");
1576 1576                          rw_exit(&tip->i_contents);
1577 1577                          rw_exit(&sip->i_contents);
1578 1578                          return (EINVAL);
1579 1579                  }
1580 1580                  /*
1581 1581                   * Renaming a directory with the parent different
1582 1582                   * requires that ".." be rewritten.  The window is
1583 1583                   * still there for ".." to be inconsistent, but this
1584 1584                   * is unavoidable, and a lot shorter than when it was
1585 1585                   * done in a user process.  We decrement the link
1586 1586                   * count in the new parent as appropriate to reflect
1587 1587                   * the just-removed target.  If the parent is the
1588 1588                   * same, this is appropriate since the original
1589 1589                   * directory is going away.  If the new parent is
1590 1590                   * different, dirfixdotdot() will bump the link count
1591 1591                   * back.
1592 1592                   */
1593 1593                  tdp->i_nlink--;
1594 1594                  mutex_enter(&tdp->i_tlock);
1595 1595                  tdp->i_flag |= ICHG;
1596 1596                  mutex_exit(&tdp->i_tlock);
1597 1597                  ITIMES_NOLOCK(tdp);
1598 1598                  if (sdp != tdp) {
1599 1599                          rw_exit(&tip->i_contents);
1600 1600                          rw_exit(&sip->i_contents);
1601 1601                          error = ud_dirfixdotdot(sip, sdp, tdp);
1602 1602                          return (error);
1603 1603                  }
1604 1604          }
1605 1605  
1606 1606  out:
1607 1607          rw_exit(&tip->i_contents);
1608 1608          rw_exit(&sip->i_contents);
1609 1609          return (error);
1610 1610  }
1611 1611  
1612 1612  
1613 1613  /*
1614 1614   * 1. When we find a slot that belonged to a file which was deleted
1615 1615   *      and is in the middle of the directory
1616 1616   * 2. There is not empty slot available. The new entry
1617 1617   *      will be at the end of the directory and fits in the same block.
1618 1618   * 3. There is no empty slot available. The new
1619 1619   *      entry will not fit the left over directory
1620 1620   *      so we need to allocate a new block. If
1621 1621   *      we cannot allocate a proximity block we need
1622 1622   *      to allocate a new icb, and data block.
1623 1623   */
1624 1624  int
1625 1625  ud_dirprepareentry(struct ud_inode *dp,
1626 1626          struct slot *slotp, uint8_t *buf, struct cred *cr)
1627 1627  {
1628 1628          struct fbuf *fbp;
1629 1629          uint16_t old_dtype;
1630 1630          int32_t error = 0;
1631 1631          uint32_t entrysize, count, offset, tbno, old_size, off;
1632 1632          struct file_id *fid;
1633 1633          int32_t lbsize, lbmask, mask;
1634 1634  
1635 1635          ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
1636 1636  
1637 1637          ASSERT((slotp->status == NONE) || (slotp->status == FOUND));
1638 1638  
1639 1639          ud_printf("ud_dirprepareentry\n");
1640 1640          lbsize = dp->i_udf->udf_lbsize;
1641 1641          lbmask = dp->i_udf->udf_lbmask;
1642 1642          mask = ~lbmask;
1643 1643  
1644 1644          fid = (struct file_id *)buf;
1645 1645          entrysize = FID_LEN(fid);
1646 1646  
1647 1647          /*
1648 1648           * If we didn't find a slot, then indicate that the
1649 1649           * new slot belongs at the end of the directory.
1650 1650           * If we found a slot, then the new entry can be
1651 1651           * put at slotp->offset.
1652 1652           */
1653 1653          if (slotp->status == NONE) {
1654 1654                  /*
1655 1655                   * We did not find a slot, the next
1656 1656                   * entry will be in the end of the directory
1657 1657                   * see if we can fit the new entry inside
1658 1658                   * the old block. If not allocate a new block.
1659 1659                   */
1660 1660                  if (entrysize > slotp->size) {
1661 1661                          /*
1662 1662                           * extend the directory
1663 1663                           * size by one new block
1664 1664                           */
1665 1665                          old_dtype = dp->i_desc_type;
1666 1666                          old_size = (uint32_t)dp->i_size;
1667 1667                          error = ud_bmap_write(dp, slotp->offset,
1668 1668                              blkoff(dp->i_udf, slotp->offset) + entrysize,
1669 1669                              0, cr);
1670 1670                          if (error != 0) {
1671 1671                                  return (error);
1672 1672                          }
1673 1673                          if (old_dtype != dp->i_desc_type) {
1674 1674                                  /*
1675 1675                                   * oops we changed the astrat
1676 1676                                   * of the file, we have to
1677 1677                                   * recaliculate tags
1678 1678                                   * fortunately we donot have more
1679 1679                                   * than one lbsize to handle here
1680 1680                                   */
1681 1681                                  if ((error = ud_ip_off2bno(dp,
1682 1682                                      0, &tbno)) != 0) {
1683 1683                                          return (error);
1684 1684                                  }
1685 1685                                  if ((error = fbread(ITOV(dp), 0,
1686 1686                                      dp->i_udf->udf_lbsize,
1687 1687                                      S_WRITE, &fbp)) != 0) {
1688 1688                                          return (error);
1689 1689                                  }
1690 1690                                  off = 0;
1691 1691                                  while (off < old_size) {
1692 1692                                          struct file_id *tfid;
1693 1693  
1694 1694                                          tfid = (struct file_id *)
1695 1695                                              (fbp->fb_addr + off);
1696 1696  
1697 1697                                          ud_make_tag(dp->i_udf, &tfid->fid_tag,
1698 1698                                              UD_FILE_ID_DESC, tbno,
1699 1699                                              FID_LEN(tfid));
1700 1700  
1701 1701                                          off += FID_LEN(tfid);
1702 1702                                  }
1703 1703                                  if (error = ud_fbwrite(fbp, dp)) {
1704 1704                                          return (error);
1705 1705                                  }
1706 1706                          }
1707 1707                  } else {
1708 1708                          /* Extend the directory size */
1709 1709                          if (dp->i_desc_type != ICB_FLAG_ONE_AD) {
1710 1710                                  ASSERT(dp->i_ext);
1711 1711                                  dp->i_ext[dp->i_ext_used - 1].ib_count +=
1712 1712                                      entrysize;
1713 1713                          }
1714 1714                  }
1715 1715                  dp->i_size += entrysize;
1716 1716                  dp->i_flag |= IUPD|ICHG|IATTCHG;
1717 1717                  ITIMES_NOLOCK(dp);
1718 1718          } else if (slotp->status != FOUND) {
1719 1719                  cmn_err(CE_WARN, "status is not NONE/FOUND");
1720 1720                  return (EINVAL);
1721 1721          }
1722 1722  
1723 1723          if ((error = ud_ip_off2bno(dp, slotp->offset, &tbno)) != 0) {
1724 1724                  return (error);
1725 1725          }
1726 1726          ud_make_tag(dp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1727 1727              tbno, FID_LEN(fid));
1728 1728  
1729 1729          /*
1730 1730           * fbread cannot cross a
1731 1731           * MAXBSIZE boundary so handle it here
1732 1732           */
1733 1733          offset = slotp->offset;
1734 1734          if ((error = fbread(ITOV(dp), offset & mask, lbsize,
1735 1735              S_WRITE, &fbp)) != 0) {
1736 1736                  return (error);
1737 1737          }
1738 1738          if ((offset & mask) != ((offset + entrysize) & mask)) {
1739 1739                  count = entrysize - ((offset + entrysize) & lbmask);
1740 1740          } else {
1741 1741                  count = entrysize;
1742 1742          }
1743 1743          bcopy((caddr_t)buf, fbp->fb_addr + (offset & lbmask), count);
1744 1744  
1745 1745          if (error = ud_fbwrite(fbp, dp)) {
1746 1746                  return (error);
1747 1747          }
1748 1748  
1749 1749          if (entrysize > count) {
1750 1750                  if ((error = fbread(ITOV(dp), (offset + entrysize) & mask,
1751 1751                      lbsize, S_WRITE, &fbp)) != 0) {
1752 1752                          return (error);
1753 1753                  }
1754 1754                  bcopy((caddr_t)(buf + count), fbp->fb_addr, entrysize - count);
1755 1755                  if (error = ud_fbwrite(fbp, dp)) {
1756 1756                          return (error);
1757 1757                  }
1758 1758          }
1759 1759  
1760 1760          dp->i_flag |= IUPD|ICHG|IATTCHG;
1761 1761          ITIMES_NOLOCK(dp);
1762 1762          return (error);
1763 1763  }
1764 1764  
1765 1765  
1766 1766  /*
1767 1767   * Fix the FID_PARENT entry of the child directory so that it points
1768 1768   * to the new parent directory instead of the old one.  Routine
1769 1769   * assumes that dp is a directory and that all the inodes are on
1770 1770   * the same file system.
1771 1771   */
1772 1772  int
1773 1773  ud_dirfixdotdot(struct ud_inode *dp,
1774 1774          struct ud_inode *opdp, struct ud_inode *npdp)
1775 1775  {
1776 1776          int32_t err = 0;
1777 1777          struct fbuf *fbp;
1778 1778          struct file_id *fid;
1779 1779          uint32_t loc, dummy, tbno;
1780 1780  
1781 1781          ud_printf("ud_dirfixdotdot\n");
1782 1782  
1783 1783          ASSERT(opdp->i_type == VDIR);
1784 1784          ASSERT(npdp->i_type == VDIR);
1785 1785  
1786 1786          ASSERT(RW_WRITE_HELD(&npdp->i_rwlock));
1787 1787  
1788 1788          err = fbread(ITOV(dp), (offset_t)0,
1789 1789              dp->i_udf->udf_lbsize, S_WRITE, &fbp);
1790 1790  
1791 1791          if (err || dp->i_nlink == 0 ||
1792 1792              dp->i_size < sizeof (struct file_id)) {
1793 1793                  goto bad;
1794 1794          }
1795 1795  
1796 1796          if ((err = ud_ip_off2bno(dp, 0, &tbno)) != 0) {
1797 1797                  goto bad;
1798 1798          }
1799 1799  
1800 1800          fid = (struct file_id *)fbp->fb_addr;
1801 1801          if ((ud_verify_tag_and_desc(&fid->fid_tag, UD_FILE_ID_DESC,
1802 1802              tbno,
1803 1803              1, dp->i_udf->udf_lbsize) != 0) ||
1804 1804              ((fid->fid_flags & (FID_DIR | FID_PARENT)) !=
1805 1805              (FID_DIR | FID_PARENT))) {
1806 1806                  err = ENOTDIR;
1807 1807                  goto bad;
1808 1808          }
1809 1809  
1810 1810          loc = ud_xlate_to_daddr(dp->i_udf,
1811 1811              SWAP_16(fid->fid_icb.lad_ext_prn),
1812 1812              SWAP_32(fid->fid_icb.lad_ext_loc), 1, &dummy);
1813 1813          ASSERT(dummy == 1);
1814 1814          if (loc == npdp->i_icb_lbano) {
1815 1815                  goto bad;
1816 1816          }
1817 1817  
1818 1818          /*
1819 1819           * Increment the link count in the new parent inode and force it out.
1820 1820           */
1821 1821          if (npdp->i_nlink == MAXLINK) {
1822 1822                  err = EMLINK;
1823 1823                  goto bad;
1824 1824          }
1825 1825  
1826 1826          npdp->i_nlink++;
1827 1827          mutex_enter(&npdp->i_tlock);
1828 1828          npdp->i_flag |= ICHG;
1829 1829          mutex_exit(&npdp->i_tlock);
1830 1830          ud_iupdat(npdp, 1);
1831 1831  
1832 1832          /*
1833 1833           * Rewrite the child FID_PARENT entry and force it out.
1834 1834           */
1835 1835          dnlc_remove(ITOV(dp), "..");
1836 1836          fid->fid_icb.lad_ext_loc = SWAP_32(npdp->i_icb_block);
1837 1837          fid->fid_icb.lad_ext_prn = SWAP_16(npdp->i_icb_prn);
1838 1838          ud_make_tag(npdp->i_udf, &fid->fid_tag,
1839 1839              UD_FILE_ID_DESC, tbno, FID_LEN(fid));
1840 1840          dnlc_enter(ITOV(dp), "..", ITOV(npdp));
1841 1841  
1842 1842          err = ud_fbwrite(fbp, dp);
1843 1843          fbp = NULL;
1844 1844          if (err != 0) {
1845 1845                  goto bad;
1846 1846          }
1847 1847  
1848 1848          /*
1849 1849           * Decrement the link count of the old parent inode and force
1850 1850           * it out.  If opdp is NULL, then this is a new directory link;
1851 1851           * it has no parent, so we need not do anything.
1852 1852           */
1853 1853          if (opdp != NULL) {
1854 1854                  rw_enter(&opdp->i_contents, RW_WRITER);
1855 1855                  if (opdp->i_nlink != 0) {
1856 1856                          opdp->i_nlink--;
1857 1857                          mutex_enter(&opdp->i_tlock);
1858 1858                          opdp->i_flag |= ICHG;
1859 1859                          mutex_exit(&opdp->i_tlock);
1860 1860                          ud_iupdat(opdp, 1);
1861 1861                  }
1862 1862                  rw_exit(&opdp->i_contents);
1863 1863          }
1864 1864          return (0);
1865 1865  
1866 1866  bad:
1867 1867          if (fbp) {
1868 1868                  fbrelse(fbp, S_OTHER);
1869 1869          }
1870 1870          return (err);
1871 1871  }
1872 1872  
1873 1873  int32_t
1874 1874  ud_write_fid(struct ud_inode *dp, struct slot *slot, uint8_t *buf)
1875 1875  {
1876 1876          struct udf_vfs *udf_vfsp;
1877 1877          struct fbuf *lfbp;
1878 1878          struct file_id *fid;
1879 1879          int32_t error = 0;
1880 1880          uint32_t lbsize, lbmask, count, old_count;
1881 1881  
1882 1882  
1883 1883          ASSERT(slot->fbp);
1884 1884          ASSERT(slot->ep);
1885 1885  
1886 1886          udf_vfsp = dp->i_udf;
1887 1887          fid = slot->ep;
1888 1888          lbsize = dp->i_udf->udf_lbsize;
1889 1889          lbmask = dp->i_udf->udf_lbmask;
1890 1890  
1891 1891          if (((uint8_t *)fid >= buf) &&
1892 1892              ((uint8_t *)fid < &buf[udf_vfsp->udf_lbsize])) {
1893 1893  
1894 1894                  if ((error = fbread(ITOV(dp),
1895 1895                      (offset_t)(slot->offset & ~lbmask),
1896 1896                      lbsize, S_WRITE, &lfbp)) != 0) {
1897 1897                          goto out;
1898 1898                  }
1899 1899  
1900 1900  
1901 1901                  /*
1902 1902                   * We do not need to write the
1903 1903                   * file name. So check if the entry
1904 1904                   * does not cross a block boundary
1905 1905                   * and write only required portions
1906 1906                   */
1907 1907                  if (((slot->offset & lbmask) +
1908 1908                          sizeof (struct file_id)) > lbsize) {
1909 1909  
1910 1910                          if ((slot->offset & lbmask) != 0) {
1911 1911                                  old_count = lbsize -
1912 1912                                          (slot->offset & lbmask);
1913 1913                                  count = (slot->offset +
1914 1914                                          sizeof (struct file_id)) &
1915 1915                                          lbmask;
1916 1916                          } else {
1917 1917                                  old_count = 0;
1918 1918                                  count = sizeof (struct file_id);
1919 1919                          }
1920 1920  
1921 1921                          bcopy(buf, lfbp->fb_addr +
1922 1922                                  (slot->offset & lbmask), old_count);
1923 1923                          bcopy(buf + old_count,
1924 1924                                  slot->fbp->fb_addr, count);
1925 1925  
1926 1926                          error = ud_fbwrite(lfbp, dp);
1927 1927  
1928 1928                          error = ud_fbwrite(slot->fbp, dp);
1929 1929                  } else {
1930 1930                          bcopy(buf, lfbp->fb_addr +
1931 1931                                  (slot->offset & lbmask),
1932 1932                                  sizeof (struct file_id));
1933 1933  
1934 1934                          error = ud_fbwrite(lfbp, dp);
1935 1935  
1936 1936                          fbrelse(slot->fbp, S_OTHER);
1937 1937                  }
1938 1938          } else {
1939 1939                  if ((error = ud_fbwrite(slot->fbp, dp)) != 0) {
1940 1940                          fid->fid_flags &= ~FID_DELETED;
1941 1941                          ud_make_tag(dp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1942 1942                              SWAP_32(fid->fid_tag.tag_loc), FID_LEN(fid));
1943 1943                  }
1944 1944          }
1945 1945          slot->fbp = NULL;
1946 1946  
1947 1947  out:
1948 1948          return (error);
1949 1949  }
  
    | 
      ↓ open down ↓ | 
    1949 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX