1 /* $NetBSD: msdosfs_lookup.c,v 1.35 2016/01/30 09:59:27 mlelstv 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.35 2016/01/30 09:59:27 mlelstv 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 #include <sys/atomic.h> 68 #else 69 #include <ffs/buf.h> 70 #endif /* _KERNEL */ 71 72 #include <fs/msdosfs/bpb.h> 73 #include <fs/msdosfs/direntry.h> 74 #include <fs/msdosfs/denode.h> 75 #include <fs/msdosfs/msdosfsmount.h> 76 #include <fs/msdosfs/fat.h> 77 78 79 #ifdef _KERNEL 80 /* 81 * When we search a directory the blocks containing directory entries are 82 * read and examined. The directory entries contain information that would 83 * normally be in the inode of a unix filesystem. This means that some of 84 * a directory's contents may also be in memory resident denodes (sort of 85 * an inode). This can cause problems if we are searching while some other 86 * process is modifying a directory. To prevent one process from accessing 87 * incompletely modified directory information we depend upon being the 88 * sole owner of a directory block. bread/brelse provide this service. 89 * This being the case, when a process modifies a directory it must first 90 * acquire the disk block that contains the directory entry to be modified. 91 * Then update the disk block and the denode, and then write the disk block 92 * out to disk. This way disk blocks containing directory entries and in 93 * memory denode's will be in synch. 94 */ 95 int 96 msdosfs_lookup(void *v) 97 { 98 struct vop_lookup_v2_args /* { 99 struct vnode *a_dvp; 100 struct vnode **a_vpp; 101 struct componentname *a_cnp; 102 } */ *ap = v; 103 struct vnode *vdp = ap->a_dvp; 104 struct vnode **vpp = ap->a_vpp; 105 struct componentname *cnp = ap->a_cnp; 106 daddr_t bn; 107 int error; 108 int slotcount; 109 int slotoffset = 0; 110 int frcn; 111 u_long cluster; 112 int blkoff; 113 int diroff; 114 int blsize; 115 int isadir; /* ~0 if found direntry is a directory */ 116 u_long scn; /* starting cluster number */ 117 struct denode *dp; 118 struct msdosfsmount *pmp; 119 struct buf *bp = 0; 120 struct direntry *dep; 121 u_char dosfilename[12]; 122 int flags; 123 int nameiop = cnp->cn_nameiop; 124 int wincnt = 1; 125 int chksum = -1, chksum_ok; 126 int olddos = 1; 127 128 flags = cnp->cn_flags; 129 130 #ifdef MSDOSFS_DEBUG 131 printf("msdosfs_lookup(): looking for %.*s\n", 132 (int)cnp->cn_namelen, cnp->cn_nameptr); 133 #endif 134 dp = VTODE(vdp); 135 pmp = dp->de_pmp; 136 *vpp = NULL; 137 #ifdef MSDOSFS_DEBUG 138 printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n", 139 vdp, dp, dp->de_Attributes); 140 #endif 141 142 /* 143 * Check accessiblity of directory. 144 */ 145 if ((error = VOP_ACCESS(vdp, VEXEC, cnp->cn_cred)) != 0) 146 return (error); 147 148 if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && 149 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 150 return (EROFS); 151 152 /* 153 * We now have a segment name to search for, and a directory to search. 154 * 155 * Before tediously performing a linear scan of the directory, 156 * check the name cache to see if the directory/name pair 157 * we are looking for is known already. 158 */ 159 if (cache_lookup(vdp, cnp->cn_nameptr, cnp->cn_namelen, 160 cnp->cn_nameiop, cnp->cn_flags, NULL, vpp)) { 161 return *vpp == NULLVP ? ENOENT: 0; 162 } 163 164 /* 165 * If they are going after the . or .. entry in the root directory, 166 * they won't find it. DOS filesystems don't have them in the root 167 * directory. So, we fake it. deget() is in on this scam too. 168 */ 169 if ((vdp->v_vflag & VV_ROOT) && cnp->cn_nameptr[0] == '.' && 170 (cnp->cn_namelen == 1 || 171 (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) { 172 isadir = ATTR_DIRECTORY; 173 scn = MSDOSFSROOT; 174 #ifdef MSDOSFS_DEBUG 175 printf("msdosfs_lookup(): looking for . or .. in root directory\n"); 176 #endif 177 cluster = MSDOSFSROOT; 178 blkoff = MSDOSFSROOT_OFS; 179 goto foundroot; 180 } 181 182 switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename, 183 cnp->cn_namelen, 0)) { 184 case 0: 185 return (EINVAL); 186 case 1: 187 break; 188 case 2: 189 wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, 190 cnp->cn_namelen, pmp->pm_flags & MSDOSFSMNT_UTF8) + 1; 191 break; 192 case 3: 193 olddos = 0; 194 wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, 195 cnp->cn_namelen, pmp->pm_flags & MSDOSFSMNT_UTF8) + 1; 196 break; 197 } 198 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 199 wincnt = 1; 200 201 /* 202 * Suppress search for slots unless creating 203 * file and at end of pathname, in which case 204 * we watch for a place to put the new file in 205 * case it doesn't already exist. 206 */ 207 slotcount = wincnt; 208 if ((nameiop == CREATE || nameiop == RENAME) && 209 (flags & ISLASTCN)) 210 slotcount = 0; 211 212 #ifdef MSDOSFS_DEBUG 213 printf("msdosfs_lookup(): dos filename: %s\n", dosfilename); 214 #endif 215 /* 216 * Search the directory pointed at by vdp for the name pointed at 217 * by cnp->cn_nameptr. 218 */ 219 220 /* 221 * The outer loop ranges over the clusters that make up the 222 * directory. Note that the root directory is different from all 223 * other directories. It has a fixed number of blocks that are not 224 * part of the pool of allocatable clusters. So, we treat it a 225 * little differently. The root directory starts at "cluster" 0. 226 */ 227 diroff = 0; 228 for (frcn = 0; diroff < dp->de_FileSize; frcn++) { 229 if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) { 230 if (error == E2BIG) 231 break; 232 return (error); 233 } 234 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, 235 0, &bp); 236 if (error) { 237 return (error); 238 } 239 for (blkoff = 0; blkoff < blsize; 240 blkoff += sizeof(struct direntry), 241 diroff += sizeof(struct direntry)) { 242 dep = (struct direntry *)((char *)bp->b_data + blkoff); 243 /* 244 * If the slot is empty and we are still looking 245 * for an empty then remember this one. If the 246 * slot is not empty then check to see if it 247 * matches what we are looking for. If the slot 248 * has never been filled with anything, then the 249 * remainder of the directory has never been used, 250 * so there is no point in searching it. 251 */ 252 if (dep->deName[0] == SLOT_EMPTY || 253 dep->deName[0] == SLOT_DELETED) { 254 /* 255 * Drop memory of previous long matches 256 */ 257 chksum = -1; 258 259 if (slotcount < wincnt) { 260 slotcount++; 261 slotoffset = diroff; 262 } 263 if (dep->deName[0] == SLOT_EMPTY) { 264 brelse(bp, 0); 265 goto notfound; 266 } 267 } else { 268 /* 269 * If there wasn't enough space for our 270 * winentries, forget about the empty space 271 */ 272 if (slotcount < wincnt) 273 slotcount = 0; 274 275 /* 276 * Check for Win95 long filename entry 277 */ 278 if (dep->deAttributes == ATTR_WIN95) { 279 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) 280 continue; 281 282 chksum = winChkName((const u_char *)cnp->cn_nameptr, 283 cnp->cn_namelen, 284 (struct winentry *)dep, 285 chksum, 286 pmp->pm_flags & MSDOSFSMNT_UTF8); 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 error = deget(pmp, cluster, blkoff, vpp); 495 return error; 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 error = deget(pmp, cluster, blkoff, vpp); 524 return error; 525 } 526 527 if (dp->de_StartCluster == scn && isadir) { 528 vref(vdp); /* we want ourself, ie "." */ 529 *vpp = vdp; 530 } else if ((error = deget(pmp, cluster, blkoff, vpp)) != 0) { 531 return error; 532 } 533 534 /* 535 * Insert name into cache if appropriate. 536 */ 537 cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags); 538 539 return 0; 540 } 541 #endif /* _KERNEL */ 542 543 /* 544 * dep - directory entry to copy into the directory 545 * ddep - directory to add to 546 * depp - return the address of the denode for the created directory entry 547 * if depp != 0 548 * cnp - componentname needed for Win95 long filenames 549 */ 550 int 551 createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp) 552 { 553 int error, rberror; 554 u_long dirclust, clusoffset; 555 u_long fndoffset, havecnt = 0, wcnt = 1, i; 556 struct direntry *ndep; 557 struct msdosfsmount *pmp = ddep->de_pmp; 558 struct buf *bp; 559 daddr_t bn; 560 int blsize; 561 #ifdef _KERNEL 562 int async = ddep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC; 563 #else 564 #define async 0 565 #endif 566 567 #ifdef MSDOSFS_DEBUG 568 printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n", 569 dep, ddep, depp, cnp); 570 #endif 571 572 /* 573 * If no space left in the directory then allocate another cluster 574 * and chain it onto the end of the file. There is one exception 575 * to this. That is, if the root directory has no more space it 576 * can NOT be expanded. extendfile() checks for and fails attempts 577 * to extend the root directory. We just return an error in that 578 * case. 579 */ 580 if (ddep->de_fndoffset >= ddep->de_FileSize) { 581 u_long needlen = ddep->de_fndoffset + sizeof(struct direntry) 582 - ddep->de_FileSize; 583 dirclust = de_clcount(pmp, needlen); 584 if ((error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR)) != 0) { 585 (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED); 586 goto err_norollback; 587 } 588 589 /* 590 * Update the size of the directory 591 */ 592 ddep->de_FileSize += de_cn2off(pmp, dirclust); 593 } 594 595 /* 596 * We just read in the cluster with space. Copy the new directory 597 * entry in. Then write it to disk. NOTE: DOS directories 598 * do not get smaller as clusters are emptied. 599 */ 600 error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), 601 &bn, &dirclust, &blsize); 602 if (error) 603 goto err_norollback; 604 clusoffset = ddep->de_fndoffset; 605 if (dirclust != MSDOSFSROOT) 606 clusoffset &= pmp->pm_crbomask; 607 if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, 608 B_MODIFY, &bp)) != 0) { 609 goto err_norollback; 610 } 611 ndep = bptoep(pmp, bp, clusoffset); 612 613 DE_EXTERNALIZE(ndep, dep); 614 615 /* 616 * Now write the Win95 long name 617 */ 618 if (ddep->de_fndcnt > 0) { 619 u_int8_t chksum = winChksum(ndep->deName); 620 const u_char *un = (const u_char *)cnp->cn_nameptr; 621 int unlen = cnp->cn_namelen; 622 u_long xhavecnt; 623 624 fndoffset = ddep->de_fndoffset; 625 xhavecnt = ddep->de_fndcnt + 1; 626 627 for(; wcnt < xhavecnt; wcnt++) { 628 if ((fndoffset & pmp->pm_crbomask) == 0) { 629 /* we should never get here if ddep is root 630 * directory */ 631 632 if (async) 633 (void) bdwrite(bp); 634 else if ((error = bwrite(bp)) != 0) 635 goto rollback; 636 637 fndoffset -= sizeof(struct direntry); 638 error = pcbmap(ddep, 639 de_cluster(pmp, fndoffset), 640 &bn, 0, &blsize); 641 if (error) 642 goto rollback; 643 644 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), 645 blsize, B_MODIFY, &bp); 646 if (error) { 647 goto rollback; 648 } 649 ndep = bptoep(pmp, bp, 650 fndoffset & pmp->pm_crbomask); 651 } else { 652 ndep--; 653 fndoffset -= sizeof(struct direntry); 654 } 655 if (!unix2winfn(un, unlen, (struct winentry *)ndep, 656 wcnt, chksum, 657 ddep->de_pmp->pm_flags & MSDOSFSMNT_UTF8)) 658 break; 659 } 660 } 661 662 if (async) 663 bdwrite(bp); 664 else if ((error = bwrite(bp)) != 0) 665 goto rollback; 666 667 /* 668 * If they want us to return with the denode gotten. 669 */ 670 if (depp) { 671 u_long diroffset = clusoffset; 672 673 if (dep->de_Attributes & ATTR_DIRECTORY) { 674 dirclust = dep->de_StartCluster; 675 if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk) 676 dirclust = MSDOSFSROOT; 677 if (dirclust == MSDOSFSROOT) 678 diroffset = MSDOSFSROOT_OFS; 679 else 680 diroffset = 0; 681 } 682 #ifdef MAKEFS 683 error = deget(pmp, dirclust, diroffset, depp); 684 #else 685 struct vnode *vp; 686 687 error = deget(pmp, dirclust, diroffset, &vp); 688 if (error == 0) 689 *depp = VTODE(vp); 690 else 691 *depp = NULL; 692 #endif 693 return error; 694 } 695 696 return 0; 697 698 rollback: 699 /* 700 * Mark all slots modified so far as deleted. Note that we 701 * can't just call removede(), since directory is not in 702 * consistent state. 703 */ 704 fndoffset = ddep->de_fndoffset; 705 rberror = pcbmap(ddep, de_cluster(pmp, fndoffset), 706 &bn, NULL, &blsize); 707 if (rberror) 708 goto err_norollback; 709 if ((rberror = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, 710 B_MODIFY, &bp)) != 0) { 711 goto err_norollback; 712 } 713 ndep = bptoep(pmp, bp, clusoffset); 714 715 havecnt = ddep->de_fndcnt + 1; 716 for(i = wcnt; i <= havecnt; i++) { 717 /* mark entry as deleted */ 718 ndep->deName[0] = SLOT_DELETED; 719 720 if ((fndoffset & pmp->pm_crbomask) == 0) { 721 /* we should never get here if ddep is root 722 * directory */ 723 724 if (async) 725 bdwrite(bp); 726 else if ((rberror = bwrite(bp)) != 0) 727 goto err_norollback; 728 729 fndoffset -= sizeof(struct direntry); 730 rberror = pcbmap(ddep, 731 de_cluster(pmp, fndoffset), 732 &bn, 0, &blsize); 733 if (rberror) 734 goto err_norollback; 735 736 rberror = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), 737 blsize, B_MODIFY, &bp); 738 if (rberror) { 739 goto err_norollback; 740 } 741 ndep = bptoep(pmp, bp, fndoffset); 742 } else { 743 ndep--; 744 fndoffset -= sizeof(struct direntry); 745 } 746 } 747 748 /* ignore any further error */ 749 if (async) 750 (void) bdwrite(bp); 751 else 752 (void) bwrite(bp); 753 754 err_norollback: 755 return error; 756 } 757 758 /* 759 * Be sure a directory is empty except for "." and "..". Return 1 if empty, 760 * return 0 if not empty or error. 761 */ 762 int 763 dosdirempty(struct denode *dep) 764 { 765 int blsize; 766 int error; 767 u_long cn; 768 daddr_t bn; 769 struct buf *bp; 770 struct msdosfsmount *pmp = dep->de_pmp; 771 struct direntry *dentp; 772 773 /* 774 * Since the filesize field in directory entries for a directory is 775 * zero, we just have to feel our way through the directory until 776 * we hit end of file. 777 */ 778 for (cn = 0;; cn++) { 779 if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 780 if (error == E2BIG) 781 return (1); /* it's empty */ 782 return (0); 783 } 784 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, 785 0, &bp); 786 if (error) { 787 return (0); 788 } 789 for (dentp = (struct direntry *)bp->b_data; 790 (char *)dentp < (char *)bp->b_data + blsize; 791 dentp++) { 792 if (dentp->deName[0] != SLOT_DELETED && 793 (dentp->deAttributes & ATTR_VOLUME) == 0) { 794 /* 795 * In dos directories an entry whose name 796 * starts with SLOT_EMPTY (0) starts the 797 * beginning of the unused part of the 798 * directory, so we can just return that it 799 * is empty. 800 */ 801 if (dentp->deName[0] == SLOT_EMPTY) { 802 brelse(bp, 0); 803 return (1); 804 } 805 /* 806 * Any names other than "." and ".." in a 807 * directory mean it is not empty. 808 */ 809 if (memcmp(dentp->deName, ". ", 11) && 810 memcmp(dentp->deName, ".. ", 11)) { 811 brelse(bp, 0); 812 #ifdef MSDOSFS_DEBUG 813 printf("dosdirempty(): found %.11s, %d, %d\n", 814 dentp->deName, dentp->deName[0], 815 dentp->deName[1]); 816 #endif 817 return (0); /* not empty */ 818 } 819 } 820 } 821 brelse(bp, 0); 822 } 823 /* NOTREACHED */ 824 } 825 826 /* 827 * Check to see if the directory described by target is in some 828 * subdirectory of source. This prevents something like the following from 829 * succeeding and leaving a bunch or files and directories orphaned. mv 830 * /a/b/c /a/b/c/d/e/f Where c and f are directories. 831 * 832 * source - the inode for /a/b/c 833 * target - the inode for /a/b/c/d/e/f 834 * 835 * Returns 0 if target is NOT a subdirectory of source. 836 * Otherwise returns a non-zero error number. 837 * The target inode is always unlocked on return. 838 */ 839 int 840 doscheckpath(struct denode *source, struct denode *target) 841 { 842 u_long scn; 843 struct msdosfsmount *pmp; 844 struct direntry *ep; 845 struct denode *dep; 846 struct buf *bp = NULL; 847 int error = 0; 848 849 dep = target; 850 if ((target->de_Attributes & ATTR_DIRECTORY) == 0 || 851 (source->de_Attributes & ATTR_DIRECTORY) == 0) { 852 error = ENOTDIR; 853 goto out; 854 } 855 if (dep->de_StartCluster == source->de_StartCluster) { 856 error = EEXIST; 857 goto out; 858 } 859 if (dep->de_StartCluster == MSDOSFSROOT) 860 goto out; 861 pmp = dep->de_pmp; 862 #ifdef DIAGNOSTIC 863 if (pmp != source->de_pmp) 864 panic("doscheckpath: source and target on different filesystems"); 865 #endif 866 if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk) 867 goto out; 868 869 for (;;) { 870 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) { 871 error = ENOTDIR; 872 break; 873 } 874 scn = dep->de_StartCluster; 875 error = bread(pmp->pm_devvp, de_bn2kb(pmp, cntobn(pmp, scn)), 876 pmp->pm_bpcluster, 0, &bp); 877 if (error) 878 break; 879 880 ep = (struct direntry *) bp->b_data + 1; 881 if ((ep->deAttributes & ATTR_DIRECTORY) == 0 || 882 memcmp(ep->deName, ".. ", 11) != 0) { 883 error = ENOTDIR; 884 break; 885 } 886 scn = getushort(ep->deStartCluster); 887 if (FAT32(pmp)) 888 scn |= getushort(ep->deHighClust) << 16; 889 890 if (scn == source->de_StartCluster) { 891 error = EINVAL; 892 break; 893 } 894 if (scn == MSDOSFSROOT) 895 break; 896 if (FAT32(pmp) && scn == pmp->pm_rootdirblk) { 897 /* 898 * scn should be 0 in this case, 899 * but we silently ignore the error. 900 */ 901 break; 902 } 903 904 vput(DETOV(dep)); 905 brelse(bp, 0); 906 bp = NULL; 907 #ifdef MAKEFS 908 /* NOTE: deget() clears dep on error */ 909 if ((error = deget(pmp, scn, 0, &dep)) != 0) 910 break; 911 #else 912 struct vnode *vp; 913 914 dep = NULL; 915 error = deget(pmp, scn, 0, &vp); 916 if (error) 917 break; 918 error = vn_lock(vp, LK_EXCLUSIVE); 919 if (error) { 920 vrele(vp); 921 break; 922 } 923 dep = VTODE(vp); 924 #endif 925 } 926 out: 927 if (bp) 928 brelse(bp, 0); 929 if (error == ENOTDIR) 930 printf("doscheckpath(): .. not a directory?\n"); 931 if (dep != NULL) 932 vput(DETOV(dep)); 933 return (error); 934 } 935 936 /* 937 * Read in the disk block containing the directory entry (dirclu, dirofs) 938 * and return the address of the buf header, and the address of the 939 * directory entry within the block. 940 */ 941 int 942 readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, struct buf **bpp, struct direntry **epp) 943 { 944 int error; 945 daddr_t bn; 946 int blsize; 947 948 blsize = pmp->pm_bpcluster; 949 if (dirclust == MSDOSFSROOT 950 && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) 951 blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; 952 bn = detobn(pmp, dirclust, diroffset); 953 if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, 954 0, bpp)) != 0) { 955 *bpp = NULL; 956 return (error); 957 } 958 if (epp) 959 *epp = bptoep(pmp, *bpp, diroffset); 960 return (0); 961 } 962 963 /* 964 * Read in the disk block containing the directory entry dep came from and 965 * return the address of the buf header, and the address of the directory 966 * entry within the block. 967 */ 968 int 969 readde(struct denode *dep, struct buf **bpp, struct direntry **epp) 970 { 971 return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset, 972 bpp, epp)); 973 } 974 975 /* 976 * Remove a directory entry. At this point the file represented by the 977 * directory entry to be removed is still full length until noone has it 978 * open. When the file no longer being used msdosfs_inactive() is called 979 * and will truncate the file to 0 length. When the vnode containing the 980 * denode is needed for some other purpose by VFS it will call 981 * msdosfs_reclaim() which will remove the denode from the denode cache. 982 */ 983 int 984 removede(struct denode *pdep, struct denode *dep) 985 /* pdep: directory where the entry is removed */ 986 /* dep: file to be removed */ 987 { 988 int error; 989 struct direntry *ep; 990 struct buf *bp; 991 daddr_t bn; 992 int blsize; 993 struct msdosfsmount *pmp = pdep->de_pmp; 994 u_long offset = pdep->de_fndoffset; 995 #ifdef _KERNEL 996 int async = pdep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC; 997 #else 998 #define async 0 999 #endif 1000 1001 #ifdef MSDOSFS_DEBUG 1002 printf("removede(): filename %s, dep %p, offset %08lx\n", 1003 dep->de_Name, dep, offset); 1004 #endif 1005 1006 if (--dep->de_refcnt == 0) { 1007 #ifndef MAKEFS 1008 struct denode_key old_key = dep->de_key; 1009 struct denode_key new_key = dep->de_key; 1010 1011 KASSERT(new_key.dk_dirgen == NULL); 1012 new_key.dk_dirgen = dep; 1013 vcache_rekey_enter(pmp->pm_mountp, DETOV(dep), &old_key, 1014 sizeof(old_key), &new_key, sizeof(new_key)); 1015 dep->de_key = new_key; 1016 vcache_rekey_exit(pmp->pm_mountp, DETOV(dep), &old_key, 1017 sizeof(old_key), &dep->de_key, sizeof(dep->de_key)); 1018 #endif 1019 } 1020 offset += sizeof(struct direntry); 1021 do { 1022 offset -= sizeof(struct direntry); 1023 error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize); 1024 if (error) 1025 return error; 1026 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, 1027 B_MODIFY, &bp); 1028 if (error) { 1029 return error; 1030 } 1031 ep = bptoep(pmp, bp, offset); 1032 /* 1033 * Check whether, if we came here the second time, i.e. 1034 * when underflowing into the previous block, the last 1035 * entry in this block is a longfilename entry, too. 1036 */ 1037 if (ep->deAttributes != ATTR_WIN95 1038 && offset != pdep->de_fndoffset) { 1039 brelse(bp, 0); 1040 break; 1041 } 1042 offset += sizeof(struct direntry); 1043 while (1) { 1044 /* 1045 * We are a bit agressive here in that we delete any Win95 1046 * entries preceding this entry, not just the ones we "own". 1047 * Since these presumably aren't valid anyway, 1048 * there should be no harm. 1049 */ 1050 offset -= sizeof(struct direntry); 1051 ep--->deName[0] = SLOT_DELETED; 1052 if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) 1053 || !(offset & pmp->pm_crbomask) 1054 || ep->deAttributes != ATTR_WIN95) 1055 break; 1056 } 1057 if (async) 1058 bdwrite(bp); 1059 else if ((error = bwrite(bp)) != 0) 1060 return error; 1061 } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95) 1062 && !(offset & pmp->pm_crbomask) 1063 && offset); 1064 return 0; 1065 } 1066 1067 /* 1068 * Create a unique DOS name in dvp 1069 */ 1070 int 1071 uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp) 1072 { 1073 struct msdosfsmount *pmp = dep->de_pmp; 1074 struct direntry *dentp; 1075 int gen; 1076 int blsize; 1077 u_long cn; 1078 daddr_t bn; 1079 struct buf *bp; 1080 int error; 1081 1082 for (gen = 1;; gen++) { 1083 /* 1084 * Generate DOS name with generation number 1085 */ 1086 if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp, 1087 cnp->cn_namelen, gen)) 1088 return gen == 1 ? EINVAL : EEXIST; 1089 1090 /* 1091 * Now look for a dir entry with this exact name 1092 */ 1093 for (cn = error = 0; !error; cn++) { 1094 if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { 1095 if (error == E2BIG) /* EOF reached and not found */ 1096 return 0; 1097 return error; 1098 } 1099 error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, 1100 0, &bp); 1101 if (error) { 1102 return error; 1103 } 1104 for (dentp = (struct direntry *)bp->b_data; 1105 (char *)dentp < (char *)bp->b_data + blsize; 1106 dentp++) { 1107 if (dentp->deName[0] == SLOT_EMPTY) { 1108 /* 1109 * Last used entry and not found 1110 */ 1111 brelse(bp, 0); 1112 return 0; 1113 } 1114 /* 1115 * Ignore volume labels and Win95 entries 1116 */ 1117 if (dentp->deAttributes & ATTR_VOLUME) 1118 continue; 1119 if (!memcmp(dentp->deName, cp, 11)) { 1120 error = EEXIST; 1121 break; 1122 } 1123 } 1124 brelse(bp, 0); 1125 } 1126 } 1127 } 1128 1129 /* 1130 * Find any Win'95 long filename entry in directory dep 1131 */ 1132 int 1133 findwin95(struct denode *dep) 1134 { 1135 struct msdosfsmount *pmp = dep->de_pmp; 1136 struct direntry *dentp; 1137 int blsize, win95; 1138 u_long cn; 1139 daddr_t bn; 1140 struct buf *bp; 1141 1142 win95 = 1; 1143 /* 1144 * Read through the directory looking for Win'95 entries 1145 * XXX Note: Error currently handled just as EOF 1146 */ 1147 for (cn = 0;; cn++) { 1148 if (pcbmap(dep, cn, &bn, 0, &blsize)) 1149 return win95; 1150 if (bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, 1151 0, &bp)) { 1152 return win95; 1153 } 1154 for (dentp = (struct direntry *)bp->b_data; 1155 (char *)dentp < (char *)bp->b_data + blsize; 1156 dentp++) { 1157 if (dentp->deName[0] == SLOT_EMPTY) { 1158 /* 1159 * Last used entry and not found 1160 */ 1161 brelse(bp, 0); 1162 return win95; 1163 } 1164 if (dentp->deName[0] == SLOT_DELETED) { 1165 /* 1166 * Ignore deleted files 1167 * Note: might be an indication of Win'95 1168 * anyway XXX 1169 */ 1170 continue; 1171 } 1172 if (dentp->deAttributes == ATTR_WIN95) { 1173 brelse(bp, 0); 1174 return 1; 1175 } 1176 win95 = 0; 1177 } 1178 brelse(bp, 0); 1179 } 1180 } 1181