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