1 /* $NetBSD: msdosfs_lookup.c,v 1.15 2007/11/26 19:01:46 pooka Exp $ */ 2 3 /*- 4 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 5 * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 6 * All rights reserved. 7 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by TooLs GmbH. 20 * 4. The name of TooLs GmbH may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 /* 35 * Written by Paul Popelka (paulp@uts.amdahl.com) 36 * 37 * You can do anything you want with this software, just don't say you wrote 38 * it, and don't remove this notice. 39 * 40 * This software is provided "as is". 41 * 42 * The author supplies this software to be publicly redistributed on the 43 * understanding that the author is not responsible for the correct 44 * functioning of this software in any circumstances and is not liable for 45 * any damages caused by this software. 46 * 47 * October 1992 48 */ 49 50 #include <sys/cdefs.h> 51 __KERNEL_RCSID(0, "$NetBSD: msdosfs_lookup.c,v 1.15 2007/11/26 19:01:46 pooka Exp $"); 52 53 #include <sys/param.h> 54 #include <sys/systm.h> 55 #include <sys/namei.h> 56 #include <sys/buf.h> 57 #include <sys/vnode.h> 58 #include <sys/mount.h> 59 #include <sys/dirent.h> 60 #include <sys/kauth.h> 61 62 #include <fs/msdosfs/bpb.h> 63 #include <fs/msdosfs/direntry.h> 64 #include <fs/msdosfs/denode.h> 65 #include <fs/msdosfs/msdosfsmount.h> 66 #include <fs/msdosfs/fat.h> 67 68 /* 69 * When we search a directory the blocks containing directory entries are 70 * read and examined. The directory entries contain information that would 71 * normally be in the inode of a unix filesystem. This means that some of 72 * a directory's contents may also be in memory resident denodes (sort of 73 * an inode). This can cause problems if we are searching while some other 74 * process is modifying a directory. To prevent one process from accessing 75 * incompletely modified directory information we depend upon being the 76 * sole owner of a directory block. bread/brelse provide this service. 77 * This being the case, when a process modifies a directory it must first 78 * acquire the disk block that contains the directory entry to be modified. 79 * Then update the disk block and the denode, and then write the disk block 80 * out to disk. This way disk blocks containing directory entries and in 81 * memory denode's will be in synch. 82 */ 83 int 84 msdosfs_lookup(v) 85 void *v; 86 { 87 struct vop_lookup_args /* { 88 struct vnode *a_dvp; 89 struct vnode **a_vpp; 90 struct componentname *a_cnp; 91 } */ *ap = v; 92 struct vnode *vdp = ap->a_dvp; 93 struct vnode **vpp = ap->a_vpp; 94 struct componentname *cnp = ap->a_cnp; 95 daddr_t bn; 96 int error; 97 int slotcount; 98 int slotoffset = 0; 99 int frcn; 100 u_long cluster; 101 int blkoff; 102 int diroff; 103 int blsize; 104 int isadir; /* ~0 if found direntry is a directory */ 105 u_long scn; /* starting cluster number */ 106 struct vnode *pdp; 107 struct denode *dp; 108 struct denode *tdp; 109 struct msdosfsmount *pmp; 110 struct buf *bp = 0; 111 struct direntry *dep; 112 u_char dosfilename[12]; 113 int flags; 114 int nameiop = cnp->cn_nameiop; 115 int wincnt = 1; 116 int chksum = -1, chksum_ok; 117 int olddos = 1; 118 119 flags = cnp->cn_flags; 120 121 #ifdef MSDOSFS_DEBUG 122 printf("msdosfs_lookup(): looking for %.*s\n", 123 (int)cnp->cn_namelen, cnp->cn_nameptr); 124 #endif 125 dp = VTODE(vdp); 126 pmp = dp->de_pmp; 127 *vpp = NULL; 128 #ifdef MSDOSFS_DEBUG 129 printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n", 130 vdp, dp, dp->de_Attributes); 131 #endif 132 133 /* 134 * Check accessiblity of directory. 135 */ 136 if ((error = VOP_ACCESS(vdp, VEXEC, cnp->cn_cred)) != 0) 137 return (error); 138 139 if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && 140 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 141 return (EROFS); 142 143 /* 144 * We now have a segment name to search for, and a directory to search. 145 * 146 * Before tediously performing a linear scan of the directory, 147 * check the name cache to see if the directory/name pair 148 * we are looking for is known already. 149 */ 150 if ((error = cache_lookup(vdp, vpp, cnp)) >= 0) 151 return (error); 152 153 /* 154 * If they are going after the . or .. entry in the root directory, 155 * they won't find it. DOS filesystems don't have them in the root 156 * directory. So, we fake it. deget() is in on this scam too. 157 */ 158 if ((vdp->v_vflag & VV_ROOT) && cnp->cn_nameptr[0] == '.' && 159 (cnp->cn_namelen == 1 || 160 (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) { 161 isadir = ATTR_DIRECTORY; 162 scn = MSDOSFSROOT; 163 #ifdef MSDOSFS_DEBUG 164 printf("msdosfs_lookup(): looking for . or .. in root directory\n"); 165 #endif 166 cluster = MSDOSFSROOT; 167 blkoff = MSDOSFSROOT_OFS; 168 goto foundroot; 169 } 170 171 switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename, 172 cnp->cn_namelen, 0)) { 173 case 0: 174 return (EINVAL); 175 case 1: 176 break; 177 case 2: 178 wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, 179 cnp->cn_namelen) + 1; 180 break; 181 case 3: 182 olddos = 0; 183 wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, 184 cnp->cn_namelen) + 1; 185 break; 186 } 187 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 188 wincnt = 1; 189 190 /* 191 * Suppress search for slots unless creating 192 * file and at end of pathname, in which case 193 * we watch for a place to put the new file in 194 * case it doesn't already exist. 195 */ 196 slotcount = wincnt; 197 if ((nameiop == CREATE || nameiop == RENAME) && 198 (flags & ISLASTCN)) 199 slotcount = 0; 200 201 #ifdef MSDOSFS_DEBUG 202 printf("msdosfs_lookup(): dos filename: %s\n", dosfilename); 203 #endif 204 /* 205 * Search the directory pointed at by vdp for the name pointed at 206 * by cnp->cn_nameptr. 207 */ 208 tdp = NULL; 209 /* 210 * The outer loop ranges over the clusters that make up the 211 * directory. Note that the root directory is different from all 212 * other directories. It has a fixed number of blocks that are not 213 * part of the pool of allocatable clusters. So, we treat it a 214 * little differently. The root directory starts at "cluster" 0. 215 */ 216 diroff = 0; 217 for (frcn = 0; diroff < dp->de_FileSize; frcn++) { 218 if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) { 219 if (error == E2BIG) 220 break; 221 return (error); 222 } 223 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 224 &bp); 225 if (error) { 226 brelse(bp, 0); 227 return (error); 228 } 229 for (blkoff = 0; blkoff < blsize; 230 blkoff += sizeof(struct direntry), 231 diroff += sizeof(struct direntry)) { 232 dep = (struct direntry *)((char *)bp->b_data + blkoff); 233 /* 234 * If the slot is empty and we are still looking 235 * for an empty then remember this one. If the 236 * slot is not empty then check to see if it 237 * matches what we are looking for. If the slot 238 * has never been filled with anything, then the 239 * remainder of the directory has never been used, 240 * so there is no point in searching it. 241 */ 242 if (dep->deName[0] == SLOT_EMPTY || 243 dep->deName[0] == SLOT_DELETED) { 244 /* 245 * Drop memory of previous long matches 246 */ 247 chksum = -1; 248 249 if (slotcount < wincnt) { 250 slotcount++; 251 slotoffset = diroff; 252 } 253 if (dep->deName[0] == SLOT_EMPTY) { 254 brelse(bp, 0); 255 goto notfound; 256 } 257 } else { 258 /* 259 * If there wasn't enough space for our 260 * winentries, forget about the empty space 261 */ 262 if (slotcount < wincnt) 263 slotcount = 0; 264 265 /* 266 * Check for Win95 long filename entry 267 */ 268 if (dep->deAttributes == ATTR_WIN95) { 269 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 270 continue; 271 272 chksum = winChkName((const u_char *)cnp->cn_nameptr, 273 cnp->cn_namelen, 274 (struct winentry *)dep, 275 chksum); 276 continue; 277 } 278 279 /* 280 * Ignore volume labels (anywhere, not just 281 * the root directory). 282 */ 283 if (dep->deAttributes & ATTR_VOLUME) { 284 chksum = -1; 285 continue; 286 } 287 288 /* 289 * Check for a checksum or name match 290 */ 291 chksum_ok = (chksum == winChksum(dep->deName)); 292 if (!chksum_ok 293 && (!olddos || memcmp(dosfilename, dep->deName, 11))) { 294 chksum = -1; 295 continue; 296 } 297 #ifdef MSDOSFS_DEBUG 298 printf("msdosfs_lookup(): match blkoff %d, diroff %d\n", 299 blkoff, diroff); 300 #endif 301 /* 302 * Remember where this directory 303 * entry came from for whoever did 304 * this lookup. 305 */ 306 dp->de_fndoffset = diroff; 307 if (chksum_ok && nameiop == RENAME) { 308 /* 309 * Target had correct long name 310 * directory entries, reuse them 311 * as needed. 312 */ 313 dp->de_fndcnt = wincnt - 1; 314 } else { 315 /* 316 * Long name directory entries 317 * not present or corrupt, can only 318 * reuse dos directory entry. 319 */ 320 dp->de_fndcnt = 0; 321 } 322 323 goto found; 324 } 325 } /* for (blkoff = 0; .... */ 326 /* 327 * Release the buffer holding the directory cluster just 328 * searched. 329 */ 330 brelse(bp, 0); 331 } /* for (frcn = 0; ; frcn++) */ 332 333 notfound: 334 /* 335 * We hold no disk buffers at this point. 336 */ 337 338 /* 339 * If we get here we didn't find the entry we were looking for. But 340 * that's ok if we are creating or renaming and are at the end of 341 * the pathname and the directory hasn't been removed. 342 */ 343 #ifdef MSDOSFS_DEBUG 344 printf("msdosfs_lookup(): op %d, refcnt %ld, slotcount %d, slotoffset %d\n", 345 nameiop, dp->de_refcnt, slotcount, slotoffset); 346 #endif 347 if ((nameiop == CREATE || nameiop == RENAME) && 348 (flags & ISLASTCN) && dp->de_refcnt != 0) { 349 /* 350 * Access for write is interpreted as allowing 351 * creation of files in the directory. 352 */ 353 error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred); 354 if (error) 355 return (error); 356 357 /* 358 * Fixup the slot description to point to the place where 359 * we might put the new DOS direntry (putting the Win95 360 * long name entries before that) 361 */ 362 if (!slotcount) { 363 slotcount = 1; 364 slotoffset = diroff; 365 } 366 if (wincnt > slotcount) { 367 slotoffset += 368 sizeof(struct direntry) * (wincnt - slotcount); 369 } 370 371 /* 372 * Return an indication of where the new directory 373 * entry should be put. 374 */ 375 dp->de_fndoffset = slotoffset; 376 dp->de_fndcnt = wincnt - 1; 377 378 /* 379 * We return with the directory locked, so that 380 * the parameters we set up above will still be 381 * valid if we actually decide to do a direnter(). 382 * We return ni_vp == NULL to indicate that the entry 383 * does not currently exist; we leave a pointer to 384 * the (locked) directory inode in ndp->ni_dvp. 385 * The pathname buffer is saved so that the name 386 * can be obtained later. 387 * 388 * NB - if the directory is unlocked, then this 389 * information cannot be used. 390 */ 391 cnp->cn_flags |= SAVENAME; 392 return (EJUSTRETURN); 393 } 394 395 #if 0 396 /* 397 * Insert name into cache (as non-existent) if appropriate. 398 * 399 * XXX Negative caching is broken for msdosfs because the name 400 * cache doesn't understand peculiarities such as case insensitivity 401 * and 8.3 filenames. Hence, it may not invalidate all negative 402 * entries if a file with this name is later created. 403 * e.g. creating a file 'foo' won't invalidate a negative entry 404 * for 'FOO'. 405 */ 406 if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) 407 cache_enter(vdp, *vpp, cnp); 408 #endif 409 410 return (ENOENT); 411 412 found: 413 /* 414 * NOTE: We still have the buffer with matched directory entry at 415 * this point. 416 */ 417 isadir = dep->deAttributes & ATTR_DIRECTORY; 418 scn = getushort(dep->deStartCluster); 419 if (FAT32(pmp)) { 420 scn |= getushort(dep->deHighClust) << 16; 421 if (scn == pmp->pm_rootdirblk) { 422 /* 423 * There should actually be 0 here. 424 * Just ignore the error. 425 */ 426 scn = MSDOSFSROOT; 427 } 428 } 429 430 if (isadir) { 431 cluster = scn; 432 if (cluster == MSDOSFSROOT) 433 blkoff = MSDOSFSROOT_OFS; 434 else 435 blkoff = 0; 436 } else if (cluster == MSDOSFSROOT) 437 blkoff = diroff; 438 439 /* 440 * Now release buf to allow deget to read the entry again. 441 * Reserving it here and giving it to deget could result 442 * in a deadlock. 443 */ 444 brelse(bp, 0); 445 446 foundroot: 447 /* 448 * If we entered at foundroot, then we are looking for the . or .. 449 * entry of the filesystems root directory. isadir and scn were 450 * setup before jumping here. And, bp is already null. 451 */ 452 if (FAT32(pmp) && scn == MSDOSFSROOT) 453 scn = pmp->pm_rootdirblk; 454 455 /* 456 * If deleting, and at end of pathname, return 457 * parameters which can be used to remove file. 458 * Lock the inode, being careful with ".". 459 */ 460 if (nameiop == DELETE && (flags & ISLASTCN)) { 461 /* 462 * Don't allow deleting the root. 463 */ 464 if (blkoff == MSDOSFSROOT_OFS) 465 return EROFS; /* really? XXX */ 466 467 /* 468 * Write access to directory required to delete files. 469 */ 470 error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred); 471 if (error) 472 return (error); 473 474 /* 475 * Return pointer to current entry in dp->i_offset. 476 * Save directory inode pointer in ndp->ni_dvp for dirremove(). 477 */ 478 if (dp->de_StartCluster == scn && isadir) { /* "." */ 479 VREF(vdp); 480 *vpp = vdp; 481 return (0); 482 } 483 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) 484 return (error); 485 *vpp = DETOV(tdp); 486 return (0); 487 } 488 489 /* 490 * If rewriting (RENAME), return the inode and the 491 * information required to rewrite the present directory 492 * Must get inode of directory entry to verify it's a 493 * regular file, or empty directory. 494 */ 495 if (nameiop == RENAME && (flags & ISLASTCN)) { 496 497 if (vdp->v_mount->mnt_flag & MNT_RDONLY) 498 return (EROFS); 499 500 if (blkoff == MSDOSFSROOT_OFS) 501 return EROFS; /* really? XXX */ 502 503 error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred); 504 if (error) 505 return (error); 506 507 /* 508 * Careful about locking second inode. 509 * This can only occur if the target is ".". 510 */ 511 if (dp->de_StartCluster == scn && isadir) 512 return (EISDIR); 513 514 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) 515 return (error); 516 *vpp = DETOV(tdp); 517 cnp->cn_flags |= SAVENAME; 518 return (0); 519 } 520 521 /* 522 * Step through the translation in the name. We do not `vput' the 523 * directory because we may need it again if a symbolic link 524 * is relative to the current directory. Instead we save it 525 * unlocked as "pdp". We must get the target inode before unlocking 526 * the directory to insure that the inode will not be removed 527 * before we get it. We prevent deadlock by always fetching 528 * inodes from the root, moving down the directory tree. Thus 529 * when following backward pointers ".." we must unlock the 530 * parent directory before getting the requested directory. 531 * There is a potential race condition here if both the current 532 * and parent directories are removed before the VFS_VGET for the 533 * inode associated with ".." returns. We hope that this occurs 534 * infrequently since we cannot avoid this race condition without 535 * implementing a sophisticated deadlock detection algorithm. 536 * Note also that this simple deadlock detection scheme will not 537 * work if the file system has any hard links other than ".." 538 * that point backwards in the directory structure. 539 */ 540 pdp = vdp; 541 if (flags & ISDOTDOT) { 542 VOP_UNLOCK(pdp, 0); /* race to get the inode */ 543 error = deget(pmp, cluster, blkoff, &tdp); 544 vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); 545 if (error) { 546 return error; 547 } 548 *vpp = DETOV(tdp); 549 } else if (dp->de_StartCluster == scn && isadir) { 550 VREF(vdp); /* we want ourself, ie "." */ 551 *vpp = vdp; 552 } else { 553 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) 554 return (error); 555 *vpp = DETOV(tdp); 556 } 557 558 /* 559 * Insert name into cache if appropriate. 560 */ 561 if (cnp->cn_flags & MAKEENTRY) 562 cache_enter(vdp, *vpp, cnp); 563 564 return (0); 565 } 566 567 /* 568 * dep - directory entry to copy into the directory 569 * ddep - directory to add to 570 * depp - return the address of the denode for the created directory entry 571 * if depp != 0 572 * cnp - componentname needed for Win95 long filenames 573 */ 574 int 575 createde(dep, ddep, depp, cnp) 576 struct denode *dep; 577 struct denode *ddep; 578 struct denode **depp; 579 struct componentname *cnp; 580 { 581 int error, rberror; 582 u_long dirclust, clusoffset; 583 u_long fndoffset, havecnt=0, wcnt=1; 584 struct direntry *ndep; 585 struct msdosfsmount *pmp = ddep->de_pmp; 586 struct buf *bp; 587 daddr_t bn; 588 int blsize, i; 589 int async = ddep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC; 590 591 #ifdef MSDOSFS_DEBUG 592 printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n", 593 dep, ddep, depp, cnp); 594 #endif 595 596 /* 597 * If no space left in the directory then allocate another cluster 598 * and chain it onto the end of the file. There is one exception 599 * to this. That is, if the root directory has no more space it 600 * can NOT be expanded. extendfile() checks for and fails attempts 601 * to extend the root directory. We just return an error in that 602 * case. 603 */ 604 if (ddep->de_fndoffset >= ddep->de_FileSize) { 605 u_long needlen = ddep->de_fndoffset + sizeof(struct direntry) 606 - ddep->de_FileSize; 607 dirclust = de_clcount(pmp, needlen); 608 if ((error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR)) != 0) { 609 (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED); 610 goto err_norollback; 611 } 612 613 /* 614 * Update the size of the directory 615 */ 616 ddep->de_FileSize += de_cn2off(pmp, dirclust); 617 } 618 619 /* 620 * We just read in the cluster with space. Copy the new directory 621 * entry in. Then write it to disk. NOTE: DOS directories 622 * do not get smaller as clusters are emptied. 623 */ 624 error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), 625 &bn, &dirclust, &blsize); 626 if (error) 627 goto err_norollback; 628 clusoffset = ddep->de_fndoffset; 629 if (dirclust != MSDOSFSROOT) 630 clusoffset &= pmp->pm_crbomask; 631 if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 632 &bp)) != 0) { 633 brelse(bp, 0); 634 goto err_norollback; 635 } 636 ndep = bptoep(pmp, bp, clusoffset); 637 638 DE_EXTERNALIZE(ndep, dep); 639 640 /* 641 * Now write the Win95 long name 642 */ 643 if (ddep->de_fndcnt > 0) { 644 u_int8_t chksum = winChksum(ndep->deName); 645 const u_char *un = (const u_char *)cnp->cn_nameptr; 646 int unlen = cnp->cn_namelen; 647 u_long xhavecnt; 648 649 fndoffset = ddep->de_fndoffset; 650 xhavecnt = ddep->de_fndcnt + 1; 651 652 for(; wcnt < xhavecnt; wcnt++) { 653 if ((fndoffset & pmp->pm_crbomask) == 0) { 654 /* we should never get here if ddep is root 655 * directory */ 656 657 if (async) 658 (void) bdwrite(bp); 659 else if ((error = bwrite(bp)) != 0) 660 goto rollback; 661 662 fndoffset -= sizeof(struct direntry); 663 error = pcbmap(ddep, 664 de_cluster(pmp, fndoffset), 665 &bn, 0, &blsize); 666 if (error) 667 goto rollback; 668 669 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), 670 blsize, NOCRED, &bp); 671 if (error) { 672 brelse(bp, 0); 673 goto rollback; 674 } 675 ndep = bptoep(pmp, bp, 676 fndoffset & pmp->pm_crbomask); 677 } else { 678 ndep--; 679 fndoffset -= sizeof(struct direntry); 680 } 681 if (!unix2winfn(un, unlen, (struct winentry *)ndep, 682 wcnt, chksum)) 683 break; 684 } 685 } 686 687 if (async) 688 bdwrite(bp); 689 else if ((error = bwrite(bp)) != 0) 690 goto rollback; 691 692 /* 693 * If they want us to return with the denode gotten. 694 */ 695 if (depp) { 696 u_long diroffset = clusoffset; 697 if (dep->de_Attributes & ATTR_DIRECTORY) { 698 dirclust = dep->de_StartCluster; 699 if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk) 700 dirclust = MSDOSFSROOT; 701 if (dirclust == MSDOSFSROOT) 702 diroffset = MSDOSFSROOT_OFS; 703 else 704 diroffset = 0; 705 } 706 return deget(pmp, dirclust, diroffset, depp); 707 } 708 709 return 0; 710 711 rollback: 712 /* 713 * Mark all slots modified so far as deleted. Note that we 714 * can't just call removede(), since directory is not in 715 * consistent state. 716 */ 717 fndoffset = ddep->de_fndoffset; 718 rberror = pcbmap(ddep, de_cluster(pmp, fndoffset), 719 &bn, NULL, &blsize); 720 if (rberror) 721 goto err_norollback; 722 if ((rberror = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 723 &bp)) != 0) { 724 brelse(bp, 0); 725 goto err_norollback; 726 } 727 ndep = bptoep(pmp, bp, clusoffset); 728 729 havecnt = ddep->de_fndcnt + 1; 730 for(i=wcnt; i <= havecnt; i++) { 731 /* mark entry as deleted */ 732 ndep->deName[0] = SLOT_DELETED; 733 734 if ((fndoffset & pmp->pm_crbomask) == 0) { 735 /* we should never get here if ddep is root 736 * directory */ 737 738 if (async) 739 bdwrite(bp); 740 else if ((rberror = bwrite(bp)) != 0) 741 goto err_norollback; 742 743 fndoffset -= sizeof(struct direntry); 744 rberror = pcbmap(ddep, 745 de_cluster(pmp, fndoffset), 746 &bn, 0, &blsize); 747 if (rberror) 748 goto err_norollback; 749 750 rberror = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), 751 blsize, NOCRED, &bp); 752 if (rberror) { 753 brelse(bp, 0); 754 goto err_norollback; 755 } 756 ndep = bptoep(pmp, bp, fndoffset); 757 } else { 758 ndep--; 759 fndoffset -= sizeof(struct direntry); 760 } 761 } 762 763 /* ignore any further error */ 764 if (async) 765 (void) bdwrite(bp); 766 else 767 (void) bwrite(bp); 768 769 err_norollback: 770 return error; 771 } 772 773 /* 774 * Be sure a directory is empty except for "." and "..". Return 1 if empty, 775 * return 0 if not empty or error. 776 */ 777 int 778 dosdirempty(dep) 779 struct denode *dep; 780 { 781 int blsize; 782 int error; 783 u_long cn; 784 daddr_t bn; 785 struct buf *bp; 786 struct msdosfsmount *pmp = dep->de_pmp; 787 struct direntry *dentp; 788 789 /* 790 * Since the filesize field in directory entries for a directory is 791 * zero, we just have to feel our way through the directory until 792 * we hit end of file. 793 */ 794 for (cn = 0;; cn++) { 795 if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 796 if (error == E2BIG) 797 return (1); /* it's empty */ 798 return (0); 799 } 800 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 801 &bp); 802 if (error) { 803 brelse(bp, 0); 804 return (0); 805 } 806 for (dentp = (struct direntry *)bp->b_data; 807 (char *)dentp < (char *)bp->b_data + blsize; 808 dentp++) { 809 if (dentp->deName[0] != SLOT_DELETED && 810 (dentp->deAttributes & ATTR_VOLUME) == 0) { 811 /* 812 * In dos directories an entry whose name 813 * starts with SLOT_EMPTY (0) starts the 814 * beginning of the unused part of the 815 * directory, so we can just return that it 816 * is empty. 817 */ 818 if (dentp->deName[0] == SLOT_EMPTY) { 819 brelse(bp, 0); 820 return (1); 821 } 822 /* 823 * Any names other than "." and ".." in a 824 * directory mean it is not empty. 825 */ 826 if (memcmp(dentp->deName, ". ", 11) && 827 memcmp(dentp->deName, ".. ", 11)) { 828 brelse(bp, 0); 829 #ifdef MSDOSFS_DEBUG 830 printf("dosdirempty(): found %.11s, %d, %d\n", 831 dentp->deName, dentp->deName[0], 832 dentp->deName[1]); 833 #endif 834 return (0); /* not empty */ 835 } 836 } 837 } 838 brelse(bp, 0); 839 } 840 /* NOTREACHED */ 841 } 842 843 /* 844 * Check to see if the directory described by target is in some 845 * subdirectory of source. This prevents something like the following from 846 * succeeding and leaving a bunch or files and directories orphaned. mv 847 * /a/b/c /a/b/c/d/e/f Where c and f are directories. 848 * 849 * source - the inode for /a/b/c 850 * target - the inode for /a/b/c/d/e/f 851 * 852 * Returns 0 if target is NOT a subdirectory of source. 853 * Otherwise returns a non-zero error number. 854 * The target inode is always unlocked on return. 855 */ 856 int 857 doscheckpath(source, target) 858 struct denode *source; 859 struct denode *target; 860 { 861 u_long scn; 862 struct msdosfsmount *pmp; 863 struct direntry *ep; 864 struct denode *dep; 865 struct buf *bp = NULL; 866 int error = 0; 867 868 dep = target; 869 if ((target->de_Attributes & ATTR_DIRECTORY) == 0 || 870 (source->de_Attributes & ATTR_DIRECTORY) == 0) { 871 error = ENOTDIR; 872 goto out; 873 } 874 if (dep->de_StartCluster == source->de_StartCluster) { 875 error = EEXIST; 876 goto out; 877 } 878 if (dep->de_StartCluster == MSDOSFSROOT) 879 goto out; 880 pmp = dep->de_pmp; 881 #ifdef DIAGNOSTIC 882 if (pmp != source->de_pmp) 883 panic("doscheckpath: source and target on different filesystems"); 884 #endif 885 if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk) 886 goto out; 887 888 for (;;) { 889 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) { 890 error = ENOTDIR; 891 break; 892 } 893 scn = dep->de_StartCluster; 894 error = bread(pmp->pm_devvp, de_bn2kb(pmp, cntobn(pmp, scn)), 895 pmp->pm_bpcluster, NOCRED, &bp); 896 if (error) 897 break; 898 899 ep = (struct direntry *) bp->b_data + 1; 900 if ((ep->deAttributes & ATTR_DIRECTORY) == 0 || 901 memcmp(ep->deName, ".. ", 11) != 0) { 902 error = ENOTDIR; 903 break; 904 } 905 scn = getushort(ep->deStartCluster); 906 if (FAT32(pmp)) 907 scn |= getushort(ep->deHighClust) << 16; 908 909 if (scn == source->de_StartCluster) { 910 error = EINVAL; 911 break; 912 } 913 if (scn == MSDOSFSROOT) 914 break; 915 if (FAT32(pmp) && scn == pmp->pm_rootdirblk) { 916 /* 917 * scn should be 0 in this case, 918 * but we silently ignore the error. 919 */ 920 break; 921 } 922 923 vput(DETOV(dep)); 924 brelse(bp, 0); 925 bp = NULL; 926 /* NOTE: deget() clears dep on error */ 927 if ((error = deget(pmp, scn, 0, &dep)) != 0) 928 break; 929 } 930 out: 931 if (bp) 932 brelse(bp, 0); 933 if (error == ENOTDIR) 934 printf("doscheckpath(): .. not a directory?\n"); 935 if (dep != NULL) 936 vput(DETOV(dep)); 937 return (error); 938 } 939 940 /* 941 * Read in the disk block containing the directory entry (dirclu, dirofs) 942 * and return the address of the buf header, and the address of the 943 * directory entry within the block. 944 */ 945 int 946 readep(pmp, dirclust, diroffset, bpp, epp) 947 struct msdosfsmount *pmp; 948 u_long dirclust, diroffset; 949 struct buf **bpp; 950 struct direntry **epp; 951 { 952 int error; 953 daddr_t bn; 954 int blsize; 955 956 blsize = pmp->pm_bpcluster; 957 if (dirclust == MSDOSFSROOT 958 && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) 959 blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; 960 bn = detobn(pmp, dirclust, diroffset); 961 if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 962 bpp)) != 0) { 963 brelse(*bpp, 0); 964 *bpp = NULL; 965 return (error); 966 } 967 if (epp) 968 *epp = bptoep(pmp, *bpp, diroffset); 969 return (0); 970 } 971 972 /* 973 * Read in the disk block containing the directory entry dep came from and 974 * return the address of the buf header, and the address of the directory 975 * entry within the block. 976 */ 977 int 978 readde(dep, bpp, epp) 979 struct denode *dep; 980 struct buf **bpp; 981 struct direntry **epp; 982 { 983 return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset, 984 bpp, epp)); 985 } 986 987 /* 988 * Remove a directory entry. At this point the file represented by the 989 * directory entry to be removed is still full length until noone has it 990 * open. When the file no longer being used msdosfs_inactive() is called 991 * and will truncate the file to 0 length. When the vnode containing the 992 * denode is needed for some other purpose by VFS it will call 993 * msdosfs_reclaim() which will remove the denode from the denode cache. 994 */ 995 int 996 removede(pdep, dep) 997 struct denode *pdep; /* directory where the entry is removed */ 998 struct denode *dep; /* file to be removed */ 999 { 1000 int error; 1001 struct direntry *ep; 1002 struct buf *bp; 1003 daddr_t bn; 1004 int blsize; 1005 struct msdosfsmount *pmp = pdep->de_pmp; 1006 u_long offset = pdep->de_fndoffset; 1007 int async = pdep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC; 1008 1009 #ifdef MSDOSFS_DEBUG 1010 printf("removede(): filename %s, dep %p, offset %08lx\n", 1011 dep->de_Name, dep, offset); 1012 #endif 1013 1014 dep->de_refcnt--; 1015 offset += sizeof(struct direntry); 1016 do { 1017 offset -= sizeof(struct direntry); 1018 error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize); 1019 if (error) 1020 return error; 1021 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 1022 &bp); 1023 if (error) { 1024 brelse(bp, 0); 1025 return error; 1026 } 1027 ep = bptoep(pmp, bp, offset); 1028 /* 1029 * Check whether, if we came here the second time, i.e. 1030 * when underflowing into the previous block, the last 1031 * entry in this block is a longfilename entry, too. 1032 */ 1033 if (ep->deAttributes != ATTR_WIN95 1034 && offset != pdep->de_fndoffset) { 1035 brelse(bp, 0); 1036 break; 1037 } 1038 offset += sizeof(struct direntry); 1039 while (1) { 1040 /* 1041 * We are a bit agressive here in that we delete any Win95 1042 * entries preceding this entry, not just the ones we "own". 1043 * Since these presumably aren't valid anyway, 1044 * there should be no harm. 1045 */ 1046 offset -= sizeof(struct direntry); 1047 ep--->deName[0] = SLOT_DELETED; 1048 if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) 1049 || !(offset & pmp->pm_crbomask) 1050 || ep->deAttributes != ATTR_WIN95) 1051 break; 1052 } 1053 if (async) 1054 bdwrite(bp); 1055 else if ((error = bwrite(bp)) != 0) 1056 return error; 1057 } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95) 1058 && !(offset & pmp->pm_crbomask) 1059 && offset); 1060 return 0; 1061 } 1062 1063 /* 1064 * Create a unique DOS name in dvp 1065 */ 1066 int 1067 uniqdosname(dep, cnp, cp) 1068 struct denode *dep; 1069 struct componentname *cnp; 1070 u_char *cp; 1071 { 1072 struct msdosfsmount *pmp = dep->de_pmp; 1073 struct direntry *dentp; 1074 int gen; 1075 int blsize; 1076 u_long cn; 1077 daddr_t bn; 1078 struct buf *bp; 1079 int error; 1080 1081 for (gen = 1;; gen++) { 1082 /* 1083 * Generate DOS name with generation number 1084 */ 1085 if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp, 1086 cnp->cn_namelen, gen)) 1087 return gen == 1 ? EINVAL : EEXIST; 1088 1089 /* 1090 * Now look for a dir entry with this exact name 1091 */ 1092 for (cn = error = 0; !error; cn++) { 1093 if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 1094 if (error == E2BIG) /* EOF reached and not found */ 1095 return 0; 1096 return error; 1097 } 1098 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, 1099 NOCRED, &bp); 1100 if (error) { 1101 brelse(bp, 0); 1102 return error; 1103 } 1104 for (dentp = (struct direntry *)bp->b_data; 1105 (char *)dentp < (char *)bp->b_data + blsize; 1106 dentp++) { 1107 if (dentp->deName[0] == SLOT_EMPTY) { 1108 /* 1109 * Last used entry and not found 1110 */ 1111 brelse(bp, 0); 1112 return 0; 1113 } 1114 /* 1115 * Ignore volume labels and Win95 entries 1116 */ 1117 if (dentp->deAttributes & ATTR_VOLUME) 1118 continue; 1119 if (!memcmp(dentp->deName, cp, 11)) { 1120 error = EEXIST; 1121 break; 1122 } 1123 } 1124 brelse(bp, 0); 1125 } 1126 } 1127 } 1128 1129 /* 1130 * Find any Win'95 long filename entry in directory dep 1131 */ 1132 int 1133 findwin95(dep) 1134 struct denode *dep; 1135 { 1136 struct msdosfsmount *pmp = dep->de_pmp; 1137 struct direntry *dentp; 1138 int blsize; 1139 u_long cn; 1140 daddr_t bn; 1141 struct buf *bp; 1142 1143 /* 1144 * Read through the directory looking for Win'95 entries 1145 * XXX Note: Error currently handled just as EOF 1146 */ 1147 for (cn = 0;; cn++) { 1148 if (pcbmap(dep, cn, &bn, 0, &blsize)) 1149 return 0; 1150 if (bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 1151 &bp)) { 1152 brelse(bp, 0); 1153 return 0; 1154 } 1155 for (dentp = (struct direntry *)bp->b_data; 1156 (char *)dentp < (char *)bp->b_data + blsize; 1157 dentp++) { 1158 if (dentp->deName[0] == SLOT_EMPTY) { 1159 /* 1160 * Last used entry and not found 1161 */ 1162 brelse(bp, 0); 1163 return 0; 1164 } 1165 if (dentp->deName[0] == SLOT_DELETED) { 1166 /* 1167 * Ignore deleted files 1168 * Note: might be an indication of Win'95 1169 * anyway XXX 1170 */ 1171 continue; 1172 } 1173 if (dentp->deAttributes == ATTR_WIN95) { 1174 brelse(bp, 0); 1175 return 1; 1176 } 1177 } 1178 brelse(bp, 0); 1179 } 1180 } 1181