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