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