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