1 /* $NetBSD: msdosfs_lookup.c,v 1.32 2014/02/07 15:29:21 hannken 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.32 2014/02/07 15:29:21 hannken 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_v2_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 || 305 memcmp(&dosfilename[0],dep->deName,8) || 306 memcmp(&dosfilename[8],dep->deExtension,3))) { 307 chksum = -1; 308 continue; 309 } 310 #ifdef MSDOSFS_DEBUG 311 printf("msdosfs_lookup(): match blkoff %d, diroff %d\n", 312 blkoff, diroff); 313 #endif 314 /* 315 * Remember where this directory 316 * entry came from for whoever did 317 * this lookup. 318 */ 319 dp->de_fndoffset = diroff; 320 if (chksum_ok && nameiop == RENAME) { 321 /* 322 * Target had correct long name 323 * directory entries, reuse them 324 * as needed. 325 */ 326 dp->de_fndcnt = wincnt - 1; 327 } else { 328 /* 329 * Long name directory entries 330 * not present or corrupt, can only 331 * reuse dos directory entry. 332 */ 333 dp->de_fndcnt = 0; 334 } 335 336 goto found; 337 } 338 } /* for (blkoff = 0; .... */ 339 /* 340 * Release the buffer holding the directory cluster just 341 * searched. 342 */ 343 brelse(bp, 0); 344 } /* for (frcn = 0; ; frcn++) */ 345 346 notfound: 347 /* 348 * We hold no disk buffers at this point. 349 */ 350 351 /* 352 * If we get here we didn't find the entry we were looking for. But 353 * that's ok if we are creating or renaming and are at the end of 354 * the pathname and the directory hasn't been removed. 355 */ 356 #ifdef MSDOSFS_DEBUG 357 printf("msdosfs_lookup(): op %d, refcnt %ld, slotcount %d, slotoffset %d\n", 358 nameiop, dp->de_refcnt, slotcount, slotoffset); 359 #endif 360 if ((nameiop == CREATE || nameiop == RENAME) && 361 (flags & ISLASTCN) && dp->de_refcnt != 0) { 362 /* 363 * Access for write is interpreted as allowing 364 * creation of files in the directory. 365 */ 366 error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred); 367 if (error) 368 return (error); 369 370 /* 371 * Fixup the slot description to point to the place where 372 * we might put the new DOS direntry (putting the Win95 373 * long name entries before that) 374 */ 375 if (!slotcount) { 376 slotcount = 1; 377 slotoffset = diroff; 378 } 379 if (wincnt > slotcount) { 380 slotoffset += 381 sizeof(struct direntry) * (wincnt - slotcount); 382 } 383 384 /* 385 * Return an indication of where the new directory 386 * entry should be put. 387 */ 388 dp->de_fndoffset = slotoffset; 389 dp->de_fndcnt = wincnt - 1; 390 391 /* 392 * We return with the directory locked, so that 393 * the parameters we set up above will still be 394 * valid if we actually decide to do a direnter(). 395 * We return ni_vp == NULL to indicate that the entry 396 * does not currently exist; we leave a pointer to 397 * the (locked) directory inode in ndp->ni_dvp. 398 * 399 * NB - if the directory is unlocked, then this 400 * information cannot be used. 401 */ 402 return (EJUSTRETURN); 403 } 404 405 #if 0 406 /* 407 * Insert name into cache (as non-existent) if appropriate. 408 * 409 * XXX Negative caching is broken for msdosfs because the name 410 * cache doesn't understand peculiarities such as case insensitivity 411 * and 8.3 filenames. Hence, it may not invalidate all negative 412 * entries if a file with this name is later created. 413 * e.g. creating a file 'foo' won't invalidate a negative entry 414 * for 'FOO'. 415 */ 416 if (nameiop != CREATE) 417 cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, 418 cnp->cn_flags); 419 #endif 420 421 return (ENOENT); 422 423 found: 424 /* 425 * NOTE: We still have the buffer with matched directory entry at 426 * this point. 427 */ 428 isadir = dep->deAttributes & ATTR_DIRECTORY; 429 scn = getushort(dep->deStartCluster); 430 if (FAT32(pmp)) { 431 scn |= getushort(dep->deHighClust) << 16; 432 if (scn == pmp->pm_rootdirblk) { 433 /* 434 * There should actually be 0 here. 435 * Just ignore the error. 436 */ 437 scn = MSDOSFSROOT; 438 } 439 } 440 441 if (isadir) { 442 cluster = scn; 443 if (cluster == MSDOSFSROOT) 444 blkoff = MSDOSFSROOT_OFS; 445 else 446 blkoff = 0; 447 } else if (cluster == MSDOSFSROOT) 448 blkoff = diroff; 449 450 /* 451 * Now release buf to allow deget to read the entry again. 452 * Reserving it here and giving it to deget could result 453 * in a deadlock. 454 */ 455 brelse(bp, 0); 456 457 foundroot: 458 /* 459 * If we entered at foundroot, then we are looking for the . or .. 460 * entry of the filesystems root directory. isadir and scn were 461 * setup before jumping here. And, bp is already null. 462 */ 463 if (FAT32(pmp) && scn == MSDOSFSROOT) 464 scn = pmp->pm_rootdirblk; 465 466 /* 467 * If deleting, and at end of pathname, return 468 * parameters which can be used to remove file. 469 * Lock the inode, being careful with ".". 470 */ 471 if (nameiop == DELETE && (flags & ISLASTCN)) { 472 /* 473 * Don't allow deleting the root. 474 */ 475 if (blkoff == MSDOSFSROOT_OFS) 476 return EINVAL; 477 478 /* 479 * Write access to directory required to delete files. 480 */ 481 error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred); 482 if (error) 483 return (error); 484 485 /* 486 * Return pointer to current entry in dp->i_offset. 487 * Save directory inode pointer in ndp->ni_dvp for dirremove(). 488 */ 489 if (dp->de_StartCluster == scn && isadir) { /* "." */ 490 vref(vdp); 491 *vpp = vdp; 492 return (0); 493 } 494 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) 495 return (error); 496 *vpp = DETOV(tdp); 497 VOP_UNLOCK(*vpp); 498 return (0); 499 } 500 501 /* 502 * If rewriting (RENAME), return the inode and the 503 * information required to rewrite the present directory 504 * Must get inode of directory entry to verify it's a 505 * regular file, or empty directory. 506 */ 507 if (nameiop == RENAME && (flags & ISLASTCN)) { 508 509 if (vdp->v_mount->mnt_flag & MNT_RDONLY) 510 return (EROFS); 511 512 if (blkoff == MSDOSFSROOT_OFS) 513 return EINVAL; 514 515 error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred); 516 if (error) 517 return (error); 518 519 /* 520 * Careful about locking second inode. 521 * This can only occur if the target is ".". 522 */ 523 if (dp->de_StartCluster == scn && isadir) 524 return (EISDIR); 525 526 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) 527 return (error); 528 *vpp = DETOV(tdp); 529 VOP_UNLOCK(*vpp); 530 return (0); 531 } 532 533 /* 534 * Step through the translation in the name. We do not `vput' the 535 * directory because we may need it again if a symbolic link 536 * is relative to the current directory. Instead we save it 537 * unlocked as "pdp". We must get the target inode before unlocking 538 * the directory to insure that the inode will not be removed 539 * before we get it. We prevent deadlock by always fetching 540 * inodes from the root, moving down the directory tree. Thus 541 * when following backward pointers ".." we must unlock the 542 * parent directory before getting the requested directory. 543 * There is a potential race condition here if both the current 544 * and parent directories are removed before the VFS_VGET for the 545 * inode associated with ".." returns. We hope that this occurs 546 * infrequently since we cannot avoid this race condition without 547 * implementing a sophisticated deadlock detection algorithm. 548 * Note also that this simple deadlock detection scheme will not 549 * work if the file system has any hard links other than ".." 550 * that point backwards in the directory structure. 551 */ 552 pdp = vdp; 553 if (flags & ISDOTDOT) { 554 VOP_UNLOCK(pdp); /* race to get the inode */ 555 error = deget(pmp, cluster, blkoff, &tdp); 556 vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); 557 if (error) { 558 return error; 559 } 560 *vpp = DETOV(tdp); 561 } else if (dp->de_StartCluster == scn && isadir) { 562 vref(vdp); /* we want ourself, ie "." */ 563 *vpp = vdp; 564 } else { 565 if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) 566 return (error); 567 *vpp = DETOV(tdp); 568 } 569 570 /* 571 * Insert name into cache if appropriate. 572 */ 573 cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags); 574 575 if (*vpp != vdp) 576 VOP_UNLOCK(*vpp); 577 578 return 0; 579 } 580 #endif /* _KERNEL */ 581 582 /* 583 * dep - directory entry to copy into the directory 584 * ddep - directory to add to 585 * depp - return the address of the denode for the created directory entry 586 * if depp != 0 587 * cnp - componentname needed for Win95 long filenames 588 */ 589 int 590 createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp) 591 { 592 int error, rberror; 593 u_long dirclust, clusoffset; 594 u_long fndoffset, havecnt = 0, wcnt = 1, i; 595 struct direntry *ndep; 596 struct msdosfsmount *pmp = ddep->de_pmp; 597 struct buf *bp; 598 daddr_t bn; 599 int blsize; 600 #ifdef _KERNEL 601 int async = ddep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC; 602 #else 603 #define async 0 604 #endif 605 606 #ifdef MSDOSFS_DEBUG 607 printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n", 608 dep, ddep, depp, cnp); 609 #endif 610 611 /* 612 * If no space left in the directory then allocate another cluster 613 * and chain it onto the end of the file. There is one exception 614 * to this. That is, if the root directory has no more space it 615 * can NOT be expanded. extendfile() checks for and fails attempts 616 * to extend the root directory. We just return an error in that 617 * case. 618 */ 619 if (ddep->de_fndoffset >= ddep->de_FileSize) { 620 u_long needlen = ddep->de_fndoffset + sizeof(struct direntry) 621 - ddep->de_FileSize; 622 dirclust = de_clcount(pmp, needlen); 623 if ((error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR)) != 0) { 624 (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED); 625 goto err_norollback; 626 } 627 628 /* 629 * Update the size of the directory 630 */ 631 ddep->de_FileSize += de_cn2off(pmp, dirclust); 632 } 633 634 /* 635 * We just read in the cluster with space. Copy the new directory 636 * entry in. Then write it to disk. NOTE: DOS directories 637 * do not get smaller as clusters are emptied. 638 */ 639 error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), 640 &bn, &dirclust, &blsize); 641 if (error) 642 goto err_norollback; 643 clusoffset = ddep->de_fndoffset; 644 if (dirclust != MSDOSFSROOT) 645 clusoffset &= pmp->pm_crbomask; 646 if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 647 B_MODIFY, &bp)) != 0) { 648 goto err_norollback; 649 } 650 ndep = bptoep(pmp, bp, clusoffset); 651 652 DE_EXTERNALIZE(ndep, dep); 653 654 /* 655 * Now write the Win95 long name 656 */ 657 if (ddep->de_fndcnt > 0) { 658 u_int8_t chksum = winChksum(ndep->deName); 659 const u_char *un = (const u_char *)cnp->cn_nameptr; 660 int unlen = cnp->cn_namelen; 661 u_long xhavecnt; 662 663 fndoffset = ddep->de_fndoffset; 664 xhavecnt = ddep->de_fndcnt + 1; 665 666 for(; wcnt < xhavecnt; wcnt++) { 667 if ((fndoffset & pmp->pm_crbomask) == 0) { 668 /* we should never get here if ddep is root 669 * directory */ 670 671 if (async) 672 (void) bdwrite(bp); 673 else if ((error = bwrite(bp)) != 0) 674 goto rollback; 675 676 fndoffset -= sizeof(struct direntry); 677 error = pcbmap(ddep, 678 de_cluster(pmp, fndoffset), 679 &bn, 0, &blsize); 680 if (error) 681 goto rollback; 682 683 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), 684 blsize, NOCRED, B_MODIFY, &bp); 685 if (error) { 686 goto rollback; 687 } 688 ndep = bptoep(pmp, bp, 689 fndoffset & pmp->pm_crbomask); 690 } else { 691 ndep--; 692 fndoffset -= sizeof(struct direntry); 693 } 694 if (!unix2winfn(un, unlen, (struct winentry *)ndep, 695 wcnt, chksum)) 696 break; 697 } 698 } 699 700 if (async) 701 bdwrite(bp); 702 else if ((error = bwrite(bp)) != 0) 703 goto rollback; 704 705 /* 706 * If they want us to return with the denode gotten. 707 */ 708 if (depp) { 709 u_long diroffset = clusoffset; 710 if (dep->de_Attributes & ATTR_DIRECTORY) { 711 dirclust = dep->de_StartCluster; 712 if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk) 713 dirclust = MSDOSFSROOT; 714 if (dirclust == MSDOSFSROOT) 715 diroffset = MSDOSFSROOT_OFS; 716 else 717 diroffset = 0; 718 } 719 error = deget(pmp, dirclust, diroffset, depp); 720 #ifndef MAKEFS 721 if (error == 0) 722 VOP_UNLOCK(DETOV(*depp)); 723 #endif 724 return error; 725 } 726 727 return 0; 728 729 rollback: 730 /* 731 * Mark all slots modified so far as deleted. Note that we 732 * can't just call removede(), since directory is not in 733 * consistent state. 734 */ 735 fndoffset = ddep->de_fndoffset; 736 rberror = pcbmap(ddep, de_cluster(pmp, fndoffset), 737 &bn, NULL, &blsize); 738 if (rberror) 739 goto err_norollback; 740 if ((rberror = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 741 B_MODIFY, &bp)) != 0) { 742 goto err_norollback; 743 } 744 ndep = bptoep(pmp, bp, clusoffset); 745 746 havecnt = ddep->de_fndcnt + 1; 747 for(i = wcnt; i <= havecnt; i++) { 748 /* mark entry as deleted */ 749 ndep->deName[0] = SLOT_DELETED; 750 751 if ((fndoffset & pmp->pm_crbomask) == 0) { 752 /* we should never get here if ddep is root 753 * directory */ 754 755 if (async) 756 bdwrite(bp); 757 else if ((rberror = bwrite(bp)) != 0) 758 goto err_norollback; 759 760 fndoffset -= sizeof(struct direntry); 761 rberror = pcbmap(ddep, 762 de_cluster(pmp, fndoffset), 763 &bn, 0, &blsize); 764 if (rberror) 765 goto err_norollback; 766 767 rberror = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), 768 blsize, NOCRED, B_MODIFY, &bp); 769 if (rberror) { 770 goto err_norollback; 771 } 772 ndep = bptoep(pmp, bp, fndoffset); 773 } else { 774 ndep--; 775 fndoffset -= sizeof(struct direntry); 776 } 777 } 778 779 /* ignore any further error */ 780 if (async) 781 (void) bdwrite(bp); 782 else 783 (void) bwrite(bp); 784 785 err_norollback: 786 return error; 787 } 788 789 /* 790 * Be sure a directory is empty except for "." and "..". Return 1 if empty, 791 * return 0 if not empty or error. 792 */ 793 int 794 dosdirempty(struct denode *dep) 795 { 796 int blsize; 797 int error; 798 u_long cn; 799 daddr_t bn; 800 struct buf *bp; 801 struct msdosfsmount *pmp = dep->de_pmp; 802 struct direntry *dentp; 803 804 /* 805 * Since the filesize field in directory entries for a directory is 806 * zero, we just have to feel our way through the directory until 807 * we hit end of file. 808 */ 809 for (cn = 0;; cn++) { 810 if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 811 if (error == E2BIG) 812 return (1); /* it's empty */ 813 return (0); 814 } 815 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 816 0, &bp); 817 if (error) { 818 return (0); 819 } 820 for (dentp = (struct direntry *)bp->b_data; 821 (char *)dentp < (char *)bp->b_data + blsize; 822 dentp++) { 823 if (dentp->deName[0] != SLOT_DELETED && 824 (dentp->deAttributes & ATTR_VOLUME) == 0) { 825 /* 826 * In dos directories an entry whose name 827 * starts with SLOT_EMPTY (0) starts the 828 * beginning of the unused part of the 829 * directory, so we can just return that it 830 * is empty. 831 */ 832 if (dentp->deName[0] == SLOT_EMPTY) { 833 brelse(bp, 0); 834 return (1); 835 } 836 /* 837 * Any names other than "." and ".." in a 838 * directory mean it is not empty. 839 */ 840 if (memcmp(dentp->deName, ". ", 11) && 841 memcmp(dentp->deName, ".. ", 11)) { 842 brelse(bp, 0); 843 #ifdef MSDOSFS_DEBUG 844 printf("dosdirempty(): found %.11s, %d, %d\n", 845 dentp->deName, dentp->deName[0], 846 dentp->deName[1]); 847 #endif 848 return (0); /* not empty */ 849 } 850 } 851 } 852 brelse(bp, 0); 853 } 854 /* NOTREACHED */ 855 } 856 857 /* 858 * Check to see if the directory described by target is in some 859 * subdirectory of source. This prevents something like the following from 860 * succeeding and leaving a bunch or files and directories orphaned. mv 861 * /a/b/c /a/b/c/d/e/f Where c and f are directories. 862 * 863 * source - the inode for /a/b/c 864 * target - the inode for /a/b/c/d/e/f 865 * 866 * Returns 0 if target is NOT a subdirectory of source. 867 * Otherwise returns a non-zero error number. 868 * The target inode is always unlocked on return. 869 */ 870 int 871 doscheckpath(struct denode *source, struct denode *target) 872 { 873 u_long scn; 874 struct msdosfsmount *pmp; 875 struct direntry *ep; 876 struct denode *dep; 877 struct buf *bp = NULL; 878 int error = 0; 879 880 dep = target; 881 if ((target->de_Attributes & ATTR_DIRECTORY) == 0 || 882 (source->de_Attributes & ATTR_DIRECTORY) == 0) { 883 error = ENOTDIR; 884 goto out; 885 } 886 if (dep->de_StartCluster == source->de_StartCluster) { 887 error = EEXIST; 888 goto out; 889 } 890 if (dep->de_StartCluster == MSDOSFSROOT) 891 goto out; 892 pmp = dep->de_pmp; 893 #ifdef DIAGNOSTIC 894 if (pmp != source->de_pmp) 895 panic("doscheckpath: source and target on different filesystems"); 896 #endif 897 if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk) 898 goto out; 899 900 for (;;) { 901 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) { 902 error = ENOTDIR; 903 break; 904 } 905 scn = dep->de_StartCluster; 906 error = bread(pmp->pm_devvp, de_bn2kb(pmp, cntobn(pmp, scn)), 907 pmp->pm_bpcluster, NOCRED, 0, &bp); 908 if (error) 909 break; 910 911 ep = (struct direntry *) bp->b_data + 1; 912 if ((ep->deAttributes & ATTR_DIRECTORY) == 0 || 913 memcmp(ep->deName, ".. ", 11) != 0) { 914 error = ENOTDIR; 915 break; 916 } 917 scn = getushort(ep->deStartCluster); 918 if (FAT32(pmp)) 919 scn |= getushort(ep->deHighClust) << 16; 920 921 if (scn == source->de_StartCluster) { 922 error = EINVAL; 923 break; 924 } 925 if (scn == MSDOSFSROOT) 926 break; 927 if (FAT32(pmp) && scn == pmp->pm_rootdirblk) { 928 /* 929 * scn should be 0 in this case, 930 * but we silently ignore the error. 931 */ 932 break; 933 } 934 935 vput(DETOV(dep)); 936 brelse(bp, 0); 937 bp = NULL; 938 /* NOTE: deget() clears dep on error */ 939 if ((error = deget(pmp, scn, 0, &dep)) != 0) 940 break; 941 } 942 out: 943 if (bp) 944 brelse(bp, 0); 945 if (error == ENOTDIR) 946 printf("doscheckpath(): .. not a directory?\n"); 947 if (dep != NULL) 948 vput(DETOV(dep)); 949 return (error); 950 } 951 952 /* 953 * Read in the disk block containing the directory entry (dirclu, dirofs) 954 * and return the address of the buf header, and the address of the 955 * directory entry within the block. 956 */ 957 int 958 readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, struct buf **bpp, struct direntry **epp) 959 { 960 int error; 961 daddr_t bn; 962 int blsize; 963 964 blsize = pmp->pm_bpcluster; 965 if (dirclust == MSDOSFSROOT 966 && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) 967 blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; 968 bn = detobn(pmp, dirclust, diroffset); 969 if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 970 0, bpp)) != 0) { 971 *bpp = NULL; 972 return (error); 973 } 974 if (epp) 975 *epp = bptoep(pmp, *bpp, diroffset); 976 return (0); 977 } 978 979 /* 980 * Read in the disk block containing the directory entry dep came from and 981 * return the address of the buf header, and the address of the directory 982 * entry within the block. 983 */ 984 int 985 readde(struct denode *dep, struct buf **bpp, struct direntry **epp) 986 { 987 return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset, 988 bpp, epp)); 989 } 990 991 /* 992 * Remove a directory entry. At this point the file represented by the 993 * directory entry to be removed is still full length until noone has it 994 * open. When the file no longer being used msdosfs_inactive() is called 995 * and will truncate the file to 0 length. When the vnode containing the 996 * denode is needed for some other purpose by VFS it will call 997 * msdosfs_reclaim() which will remove the denode from the denode cache. 998 */ 999 int 1000 removede(struct denode *pdep, struct denode *dep) 1001 /* pdep: directory where the entry is removed */ 1002 /* dep: file to be removed */ 1003 { 1004 int error; 1005 struct direntry *ep; 1006 struct buf *bp; 1007 daddr_t bn; 1008 int blsize; 1009 struct msdosfsmount *pmp = pdep->de_pmp; 1010 u_long offset = pdep->de_fndoffset; 1011 #ifdef _KERNEL 1012 int async = pdep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC; 1013 #else 1014 #define async 0 1015 #endif 1016 1017 #ifdef MSDOSFS_DEBUG 1018 printf("removede(): filename %s, dep %p, offset %08lx\n", 1019 dep->de_Name, dep, offset); 1020 #endif 1021 1022 dep->de_refcnt--; 1023 offset += sizeof(struct direntry); 1024 do { 1025 offset -= sizeof(struct direntry); 1026 error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize); 1027 if (error) 1028 return error; 1029 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 1030 B_MODIFY, &bp); 1031 if (error) { 1032 return error; 1033 } 1034 ep = bptoep(pmp, bp, offset); 1035 /* 1036 * Check whether, if we came here the second time, i.e. 1037 * when underflowing into the previous block, the last 1038 * entry in this block is a longfilename entry, too. 1039 */ 1040 if (ep->deAttributes != ATTR_WIN95 1041 && offset != pdep->de_fndoffset) { 1042 brelse(bp, 0); 1043 break; 1044 } 1045 offset += sizeof(struct direntry); 1046 while (1) { 1047 /* 1048 * We are a bit agressive here in that we delete any Win95 1049 * entries preceding this entry, not just the ones we "own". 1050 * Since these presumably aren't valid anyway, 1051 * there should be no harm. 1052 */ 1053 offset -= sizeof(struct direntry); 1054 ep--->deName[0] = SLOT_DELETED; 1055 if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) 1056 || !(offset & pmp->pm_crbomask) 1057 || ep->deAttributes != ATTR_WIN95) 1058 break; 1059 } 1060 if (async) 1061 bdwrite(bp); 1062 else if ((error = bwrite(bp)) != 0) 1063 return error; 1064 } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95) 1065 && !(offset & pmp->pm_crbomask) 1066 && offset); 1067 return 0; 1068 } 1069 1070 /* 1071 * Create a unique DOS name in dvp 1072 */ 1073 int 1074 uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp) 1075 { 1076 struct msdosfsmount *pmp = dep->de_pmp; 1077 struct direntry *dentp; 1078 int gen; 1079 int blsize; 1080 u_long cn; 1081 daddr_t bn; 1082 struct buf *bp; 1083 int error; 1084 1085 for (gen = 1;; gen++) { 1086 /* 1087 * Generate DOS name with generation number 1088 */ 1089 if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp, 1090 cnp->cn_namelen, gen)) 1091 return gen == 1 ? EINVAL : EEXIST; 1092 1093 /* 1094 * Now look for a dir entry with this exact name 1095 */ 1096 for (cn = error = 0; !error; cn++) { 1097 if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 1098 if (error == E2BIG) /* EOF reached and not found */ 1099 return 0; 1100 return error; 1101 } 1102 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, 1103 NOCRED, 0, &bp); 1104 if (error) { 1105 return error; 1106 } 1107 for (dentp = (struct direntry *)bp->b_data; 1108 (char *)dentp < (char *)bp->b_data + blsize; 1109 dentp++) { 1110 if (dentp->deName[0] == SLOT_EMPTY) { 1111 /* 1112 * Last used entry and not found 1113 */ 1114 brelse(bp, 0); 1115 return 0; 1116 } 1117 /* 1118 * Ignore volume labels and Win95 entries 1119 */ 1120 if (dentp->deAttributes & ATTR_VOLUME) 1121 continue; 1122 if (!memcmp(dentp->deName, cp, 11)) { 1123 error = EEXIST; 1124 break; 1125 } 1126 } 1127 brelse(bp, 0); 1128 } 1129 } 1130 } 1131 1132 /* 1133 * Find any Win'95 long filename entry in directory dep 1134 */ 1135 int 1136 findwin95(struct denode *dep) 1137 { 1138 struct msdosfsmount *pmp = dep->de_pmp; 1139 struct direntry *dentp; 1140 int blsize, win95; 1141 u_long cn; 1142 daddr_t bn; 1143 struct buf *bp; 1144 1145 win95 = 1; 1146 /* 1147 * Read through the directory looking for Win'95 entries 1148 * XXX Note: Error currently handled just as EOF 1149 */ 1150 for (cn = 0;; cn++) { 1151 if (pcbmap(dep, cn, &bn, 0, &blsize)) 1152 return win95; 1153 if (bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, NOCRED, 1154 0, &bp)) { 1155 return win95; 1156 } 1157 for (dentp = (struct direntry *)bp->b_data; 1158 (char *)dentp < (char *)bp->b_data + blsize; 1159 dentp++) { 1160 if (dentp->deName[0] == SLOT_EMPTY) { 1161 /* 1162 * Last used entry and not found 1163 */ 1164 brelse(bp, 0); 1165 return win95; 1166 } 1167 if (dentp->deName[0] == SLOT_DELETED) { 1168 /* 1169 * Ignore deleted files 1170 * Note: might be an indication of Win'95 1171 * anyway XXX 1172 */ 1173 continue; 1174 } 1175 if (dentp->deAttributes == ATTR_WIN95) { 1176 brelse(bp, 0); 1177 return 1; 1178 } 1179 win95 = 0; 1180 } 1181 brelse(bp, 0); 1182 } 1183 } 1184