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