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