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