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