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