1/* 2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* $FreeBSD: src/sys/msdosfs/msdosfs_lookup.c,v 1.31 2000/05/05 09:58:35 phk Exp $ */ 24/* $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $ */ 25 26/*- 27 * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 28 * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 29 * All rights reserved. 30 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 3. All advertising materials mentioning features or use of this software 41 * must display the following acknowledgement: 42 * This product includes software developed by TooLs GmbH. 43 * 4. The name of TooLs GmbH may not be used to endorse or promote products 44 * derived from this software without specific prior written permission. 45 * 46 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 */ 57/* 58 * Written by Paul Popelka (paulp@uts.amdahl.com) 59 * 60 * You can do anything you want with this software, just don't say you wrote 61 * it, and don't remove this notice. 62 * 63 * This software is provided "as is". 64 * 65 * The author supplies this software to be publicly redistributed on the 66 * understanding that the author is not responsible for the correct 67 * functioning of this software in any circumstances and is not liable for 68 * any damages caused by this software. 69 * 70 * October 1992 71 */ 72 73#include <sys/param.h> 74#include <sys/systm.h> 75#include <sys/buf.h> 76#include <sys/vnode.h> 77#include <sys/mount.h> 78#include <sys/namei.h> 79#include <sys/utfconv.h> 80#include <libkern/OSMalloc.h> 81 82#include "bpb.h" 83#include "direntry.h" 84#include "denode.h" 85#include "msdosfsmount.h" 86#include "fat.h" 87#include "msdosfs_kdebug.h" 88 89#ifndef DEBUG 90#define DEBUG 0 91#endif 92 93int msdosfs_unicode_to_dos_lookup(u_int16_t *unicode, size_t unichars, u_char shortname[SHORT_NAME_LEN]); 94 95/* 96 * Convert a Unicode filename to the equivalent short name. 97 * 98 * Note: This is for use during lookup, not when creating new names. 99 * Therefore, it does not cut out embedded spaces, and does not worry 100 * about mixed case. 101 * 102 * Returns non-zero if the name was successfully converted to a short name. 103 */ 104int msdosfs_unicode_to_dos_lookup(u_int16_t *unicode, size_t unichars, u_char shortname[SHORT_NAME_LEN]) 105{ 106 size_t i; 107 int j; 108 u_char c = ' '; 109 110 if (unichars > SHORT_NAME_LEN+1) 111 return 0; 112 113 /* Fill the short name with spaces, the short name pad character */ 114 memset(shortname, ' ', SHORT_NAME_LEN); 115 116 /* Process the base name, up to the first period */ 117 for (i=0; i<unichars && i<8; ++i) 118 { 119 if (unicode[i] == '.') /* Dot => start extension */ 120 break; 121 122 if (unicode[i] == ' ') 123 c = ' '; 124 else 125 c = msdosfs_unicode2dos(unicode[i]); 126 127 if (c < ' ') 128 return 0; 129 shortname[i] = c; 130 } 131 132 /* 133 * Fail if last char of base is a space (since msdosfs_dos2unicodefn would trim it), 134 * or if the base name is empty (the loop above never executed). 135 */ 136 if (c == ' ') 137 return 0; 138 139 /* Short names cannot start with a space. */ 140 if (shortname[0] == ' ') 141 return 0; 142 143 /* Is the name a base only, no extension? */ 144 if (i == unichars) 145 return 1; 146 147 /* Skip over the dot between base and extension */ 148 if (unicode[i] == '.') 149 ++i; 150 else 151 return 0; /* Base name too long */ 152 153 /* Process the extension */ 154 for (j=8; j < 11 && i < unichars; ++i, ++j) 155 { 156 if (unicode[i] == '.') /* No dots in the extension */ 157 return 0; 158 159 if (unicode[i] == ' ') 160 c = ' '; 161 else 162 c = msdosfs_unicode2dos(unicode[i]); 163 164 if (c < ' ') 165 return 0; 166 shortname[j] = c; 167 } 168 169 /* Was the extension too long? */ 170 if (i < unichars) 171 return 0; 172 173 /* Was the extension empty? */ 174 if (j == 8) 175 return 0; 176 177 /* Fail if last char of extension is a space (since msdosfs_dos2unicodefn would trim it) */ 178 if (c == ' ') 179 return 0; 180 181 /* Do we need to bother with names starting with 0xE5? */ 182 if (shortname[0] == 0xE5) 183 shortname[0] = SLOT_E5; 184 185 return 1; 186} 187 188 189/* 190 * msdosfs_lookup_name 191 * 192 * Search a directory for an entry with a given name. If found, returns 193 * the cluster containing the name's short name directory entry, and the 194 * byte offset from the start of the directory (not the cluster!). 195 * 196 * Assumes dep's de_lock has been acquired. 197 */ 198int msdosfs_lookup_name( 199 struct denode *dep, /* parent directory */ 200 struct componentname *cnp, /* the name to look up */ 201 uint32_t *dirclust, /* cluster containing short name entry */ 202 uint32_t *diroffset, /* byte offset from start of directory */ 203 struct dosdirentry *direntry, /* copy of found directory entry */ 204 u_int16_t *found_name, 205 u_int16_t *found_name_length, 206 boolean_t *case_folded, 207 vfs_context_t context) 208{ 209 int error; 210 int chksum; /* checksum of short name entry */ 211 struct dosdirentry *dirp; 212 buf_t bp; 213 daddr64_t bn; 214 int frcn; /* file relative cluster (within parent directory) */ 215 uint32_t cluster=0; /* physical cluster containing directory entry */ 216 unsigned blkoff; /* offset within directory block */ 217 unsigned diroff=0; /* offset from start of directory */ 218 uint32_t blsize; /* size of one directory block */ 219 u_int16_t ucfn[WIN_MAXLEN]; 220 u_char shortname[SHORT_NAME_LEN]; 221 size_t unichars; /* number of UTF-16 characters in original name */ 222 int try_short_name; /* If true, compare short names */ 223 boolean_t did_case_fold = FALSE; 224 225 KERNEL_DEBUG_CONSTANT(MSDOSFS_LOOKUP_NAME|DBG_FUNC_START, dep->de_pmp, dep, 0, 0, 0); 226 227 dirp = NULL; 228 chksum = -1; 229 230 /* 231 * Decode lookup name into UCS-2 (Unicode) 232 */ 233 error = utf8_decodestr((uint8_t *)cnp->cn_nameptr, cnp->cn_namelen, ucfn, &unichars, sizeof(ucfn), 0, UTF_PRECOMPOSED|UTF_SFM_CONVERSIONS); 234 if (error) goto exit; 235 unichars /= 2; /* bytes to chars */ 236 if (found_name_length) 237 *found_name_length = unichars; 238 239 /* 240 * Try to convert the name to a short name. Unlike the case of creating 241 * a new name in the directory, allow embedded spaces and mixed case, 242 * but do not mangle the short name. Keep track of whether there is 243 * a valid short name to look up. 244 */ 245 try_short_name = msdosfs_unicode_to_dos_lookup(ucfn, unichars, shortname); 246 247 /* 248 * Search the directory pointed at by dep for the name in ucfn. 249 */ 250 251 /* 252 * The outer loop ranges over the clusters that make up the 253 * directory. Note that the root directory is different from all 254 * other directories. It has a fixed number of blocks that are not 255 * part of the pool of allocatable clusters. So, we treat it a 256 * little differently. The root directory starts at "cluster" 0. 257 */ 258 diroff = 0; 259 for (frcn = 0; error == 0; frcn++) { 260 error = msdosfs_pcbmap(dep, frcn, 1, &bn, &cluster, &blsize); 261 if (error) { 262 if (error == E2BIG) 263 error = ENOENT; 264 break; 265 } 266 error = (int)buf_meta_bread(dep->de_pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp); 267 if (error) { 268 buf_brelse(bp); 269 break; 270 } 271 for (blkoff = 0; blkoff < blsize; 272 blkoff += sizeof(struct dosdirentry), 273 diroff += sizeof(struct dosdirentry)) 274 { 275 dirp = (struct dosdirentry *)((char *)buf_dataptr(bp) + blkoff); 276 277 /* 278 * Skip over deleted entries. 279 */ 280 if (dirp->deName[0] == SLOT_DELETED) 281 { 282 chksum = -1; /* Forget previous matching long name entries. */ 283 continue; 284 } 285 286 /* 287 * If we found an entry that has never been used, then 288 * there is no need to search further. 289 */ 290 if (dirp->deName[0] == SLOT_EMPTY) 291 { 292 error = ENOENT; 293 break; 294 } 295 296 /* 297 * Check for Win95 long filename entry 298 */ 299 if (dirp->deAttributes == ATTR_WIN95) { 300 chksum = msdosfs_winChkName(ucfn, (int)unichars, 301 (struct winentry *)dirp, 302 chksum, 303 found_name, &did_case_fold); 304 continue; 305 } 306 307 /* 308 * Ignore volume labels (anywhere, not just 309 * the root directory). 310 */ 311 if (dirp->deAttributes & ATTR_VOLUME) { 312 chksum = -1; 313 continue; 314 } 315 316 /* 317 * If we get here, we've found a short name entry. 318 * 319 * If there was a long name, and it matched, then verify the 320 * checksum. If the checksum doesn't match, then compare the 321 * short name. 322 */ 323 if (chksum != msdosfs_winChksum(dirp->deName) && 324 (!try_short_name || bcmp(shortname, dirp->deName, SHORT_NAME_LEN))) 325 { 326 /* No match. Forget long name checksum, if any. */ 327 chksum = -1; 328 continue; 329 } 330 331 /* If we get here, we found a matching name. */ 332 333 /* 334 * If we need to return the actual on-disk name, and there was no valid 335 * long name, then convert the short name to Unicode. 336 */ 337 if (found_name && found_name_length && chksum == -1) 338 { 339 *found_name_length = msdosfs_dos2unicodefn(dirp->deName, found_name, dirp->deLowerCase); 340 } 341 342 /* Return the location and contents of the short name entry. */ 343 if (dirclust) 344 *dirclust = cluster; 345 if (diroffset) 346 *diroffset = diroff; 347 if (direntry) 348 *direntry = *dirp; 349 error = 0; 350 buf_brelse(bp); 351 goto exit; 352 } /* for (blkoff = 0; .... */ 353 354 /* 355 * Release the buffer holding the directory cluster just 356 * searched. 357 */ 358 buf_brelse(bp); 359 } /* for (frcn = 0; error == 0; frcn++) */ 360 361exit: 362 if (case_folded) 363 *case_folded = did_case_fold; 364 KERNEL_DEBUG_CONSTANT(MSDOSFS_LOOKUP_NAME|DBG_FUNC_END, error, cluster, diroff, 0, 0); 365 return error; 366} 367 368/* 369 * Try to find the file/directory in the name cache. If not 370 * found there, then look in the directory on disk. 371 * 372 * When we search a directory the blocks containing directory entries are 373 * read and examined. The directory entries contain information that would 374 * normally be in the inode of a unix filesystem. This means that some of 375 * a directory's contents may also be in memory resident denodes (sort of 376 * an inode). This can cause problems if we are searching while some other 377 * process is modifying a directory. To prevent one process from accessing 378 * incompletely modified directory information we depend upon being the 379 * sole owner of a directory block. buf_bread/buf_brelse provide this service. 380 * This being the case, when a process modifies a directory it must first 381 * acquire the disk block that contains the directory entry to be modified. 382 * Then update the disk block and the denode, and then write the disk block 383 * out to disk. This way disk blocks containing directory entries and in 384 * memory denode's will be in synch. 385 */ 386 387int msdosfs_vnop_lookup(struct vnop_lookup_args *ap) 388/* { 389 vnode_t a_dvp; 390 vnode_t *a_vpp; 391 struct componentname *a_cnp; 392 vfs_context_t a_context; 393 } */ 394{ 395 vnode_t dvp = ap->a_dvp; 396 vnode_t *vpp = ap->a_vpp; 397 struct componentname *cnp = ap->a_cnp; 398 vfs_context_t context = ap->a_context; 399 int flags = cnp->cn_flags; 400 int nameiop = cnp->cn_nameiop; 401 int error; 402 struct msdosfsmount *pmp; 403 struct denode *pdp; /* denode of dvp */ 404 struct denode *dp; /* denode of found item */ 405 uint32_t cluster; /* physical cluster containing directory entry */ 406 uint32_t diroff; /* offset from start of directory */ 407 uint32_t scn; /* starting cluster number of found item */ 408 int isadir; /* non-zero if found dosdirentry is a directory */ 409 struct dosdirentry direntry; 410 u_int16_t found_name[WIN_MAXLEN]; /* TODO: Should we malloc this? */ 411 u_int16_t found_name_len; 412 size_t utf8_len; 413 boolean_t case_folded; 414 415 /* 416 * TODO: What should we log here? pmp, pdp, flags, nameiop? 417 */ 418 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_LOOKUP|DBG_FUNC_START, VTODE(dvp), flags, nameiop, 0, 0); 419 420 *vpp = NULL; /* In case we return an error */ 421 422 error = cache_lookup(dvp, vpp, cnp); 423 424 if (error) 425 { 426 /* We found a cache entry, positive or negative. */ 427 if (error == -1) /* Positive entry? */ 428 error = 0; /* Yes. Caller expects no error */ 429 430 /* TODO: Should log that we found something via cache_lookup. */ 431 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_LOOKUP|DBG_FUNC_END, error, 0, 0, 0, 0); 432 return error; 433 } 434 435 /* If we get here, we need to look for the item on disk. */ 436 437 pdp = VTODE(dvp); 438 lck_mtx_lock(pdp->de_lock); 439 pmp = pdp->de_pmp; 440 441 /* 442 * If they are going after the . or .. entry in the root directory, 443 * they won't find it. DOS filesystems don't have them in the root 444 * directory. So, we fake it. msdosfs_deget() is in on this scam too. 445 */ 446 if ((pdp->de_flag & DE_ROOT) && cnp->cn_nameptr[0] == '.' && 447 (cnp->cn_namelen == 1 || 448 (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) 449 { 450 isadir = ATTR_DIRECTORY; 451 scn = MSDOSFSROOT; 452 cluster = MSDOSFSROOT; 453 diroff = MSDOSFSROOT_OFS; 454 goto foundroot; 455 } 456 457 /* 458 * If they're looking for ".", then just take another reference on dvp. 459 */ 460 if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') 461 { 462 vnode_get(dvp); 463 *vpp = dvp; 464 goto exit; /* error must be 0 if we got here */ 465 } 466 467 /* 468 * If they're looking for "..", then just take another reference on dvp's 469 * parent vnode. 470 */ 471 if (flags & ISDOTDOT) 472 { 473 vnode_t vp; 474 475 dp = pdp->de_parent; 476 if (dp == NULL) 477 panic("msdosfs_vnop_lookup: de_parent == NULL when looking for ..\n"); 478 vp = DETOV(dp); 479 if (vp == NULLVP) 480 panic("msdosfs_vnop_lookup: vp == NULL when looking for ..\n"); 481 vnode_get(vp); 482 *vpp = vp; 483 goto exit; /* error must be 0 if we got here */ 484 } 485 486 error = msdosfs_lookup_name(pdp, cnp, &cluster, &diroff, &direntry, found_name, &found_name_len, &case_folded, context); 487 488 if (error == ENOENT) 489 { 490 /* 491 * If we get here we didn't find the entry we were looking for. But 492 * that's ok if we are creating or renaming and are at the end of 493 * the pathname and the directory hasn't been removed. 494 */ 495 if ((nameiop == CREATE || nameiop == RENAME) && 496 (flags & ISLASTCN) && pdp->de_refcnt != 0) 497 { 498 error = EJUSTRETURN; 499 goto exit; 500 } 501 502 /* 503 * Insert name into cache (as non-existent) if appropriate. 504 */ 505 if ((flags & MAKEENTRY) && nameiop != CREATE) 506 cache_enter(dvp, *vpp, cnp); 507 508 goto exit; 509 } 510 511 /* 512 * If we got any other error from msdosfs_lookup_name, return it now. 513 */ 514 if (error) 515 goto exit; 516 517 /* 518 * If we get here, we've found the directory entry. 519 */ 520 isadir = direntry.deAttributes & ATTR_DIRECTORY; 521 scn = getuint16(direntry.deStartCluster); 522 if (FAT32(pmp)) { 523 scn |= getuint16(direntry.deHighClust) << 16; 524 if (scn == pmp->pm_rootdirblk) { 525 /* 526 * There should actually be 0 here. 527 * Just ignore the error. 528 */ 529 scn = MSDOSFSROOT; 530 } 531 } 532 533foundroot: 534 /* 535 * If we entered at foundroot, then we are looking for the . or .. 536 * entry of the filesystems root directory. isadir and scn were 537 * setup before jumping here. 538 */ 539 if (FAT32(pmp) && scn == MSDOSFSROOT) 540 scn = pmp->pm_rootdirblk; 541 542 if (nameiop == DELETE && (flags & ISLASTCN)) { 543 /* 544 * Don't allow deleting the root. 545 */ 546 if (diroff == MSDOSFSROOT_OFS) 547 { 548 error = EROFS; /* correct error? */ 549 goto exit; 550 } 551 } 552 553 if (nameiop == RENAME && (flags & ISLASTCN)) { 554 if (diroff == MSDOSFSROOT_OFS) 555 { 556 error = EROFS; /* really? XXX */ 557 goto exit; 558 } 559 560 if (pdp->de_StartCluster == scn && isadir) 561 { 562 error = EISDIR; 563 goto exit; 564 } 565 } 566 567 /* 568 * Return a vnode for the found directory entry. 569 * 570 * We construct a temporary componentname to hold the actual 571 * on-disk name so that the on-disk name (with correct case) 572 * gets inserted into the name cache. 573 */ 574 struct componentname found_cnp; 575 if (case_folded) 576 { 577 found_cnp = *cnp; 578 found_cnp.cn_pnlen = 1024; 579 found_cnp.cn_pnbuf = found_cnp.cn_nameptr = OSMalloc(found_cnp.cn_pnlen, msdosfs_malloc_tag); 580 if (found_cnp.cn_nameptr == NULL) 581 { 582 error = ENOMEM; 583 goto exit; 584 } 585 error = utf8_encodestr(found_name, found_name_len * 2, (u_int8_t *)found_cnp.cn_nameptr, &utf8_len, found_cnp.cn_pnlen, 0, UTF_DECOMPOSED|UTF_SFM_CONVERSIONS); 586 if (error == 0) 587 { 588 found_cnp.cn_namelen = (int)utf8_len; 589 } 590 } 591 if (error == 0) 592 { 593 error = msdosfs_deget(pmp, cluster, diroff, dvp, case_folded ? &found_cnp : cnp, &dp, context); 594 } 595 if (case_folded) 596 { 597 OSFree(found_cnp.cn_nameptr, 1024, msdosfs_malloc_tag); 598 } 599 if (error == 0) 600 *vpp = DETOV(dp); 601 602exit: 603 lck_mtx_unlock(pdp->de_lock); 604 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_LOOKUP|DBG_FUNC_END, error, 0, 0, 0, 0); 605 return error; 606} 607 608 609/* 610 * dep - directory entry to copy into the directory 611 * ddep - directory to add to 612 * depp - return the address of the denode for the created directory entry 613 * if depp != 0 614 * cnp - componentname needed for Win95 long filenames 615 * offset - directory offset for short name entry 616 * long_count - number of long name entries needed 617 */ 618int msdosfs_createde( 619 struct denode *dep, 620 struct denode *ddep, 621 struct denode **depp, 622 struct componentname *cnp, 623 uint32_t offset, /* also offset of current entry being written */ 624 uint32_t long_count, /* also count of entries remaining to write */ 625 vfs_context_t context) 626{ 627 int error; 628 uint32_t dirclust, diroffset; 629 struct dosdirentry *ndep; 630 struct msdosfsmount *pmp = ddep->de_pmp; 631 struct buf *bp; 632 daddr64_t bn; 633 uint32_t blsize; 634 635 KERNEL_DEBUG_CONSTANT(MSDOSFS_CREATEDE|DBG_FUNC_START, ddep, offset, long_count, 0, 0); 636 637 /* 638 * If no space left in the directory then allocate another cluster 639 * and chain it onto the end of the file. There is one exception 640 * to this. That is, if the root directory has no more space it 641 * can NOT be expanded. msdosfs_extendfile() checks for and fails attempts 642 * to extend the root directory. We just return an error in that 643 * case. 644 */ 645 if (offset >= ddep->de_FileSize) { 646 diroffset = offset + sizeof(struct dosdirentry) 647 - ddep->de_FileSize; 648 dirclust = de_clcount(pmp, diroffset); 649 error = msdosfs_extendfile(ddep, dirclust, NULL); 650 if (error) { 651 (void)msdosfs_detrunc(ddep, ddep->de_FileSize, 0, context); 652 goto done; 653 } 654 655 /* 656 * Update the size of the directory 657 */ 658 ddep->de_FileSize += de_cn2off(pmp, dirclust); 659 } 660 661 /* 662 * We just read in the cluster with space. Copy the new directory 663 * entry in. Then write it to disk. NOTE: DOS directories 664 * do not get smaller as clusters are emptied. 665 */ 666 error = msdosfs_pcbmap(ddep, de_cluster(pmp, offset), 1, 667 &bn, &dirclust, &blsize); 668 if (error) 669 goto done; 670 diroffset = offset; 671 if ((error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp)) != 0) { 672 buf_brelse(bp); 673 goto done; 674 } 675 ndep = bptoep(pmp, bp, offset); 676 677 if (DEBUG) 678 { 679 /* Make sure the slot is not in use */ 680 if (ndep->deName[0] != 0 && ndep->deName[0] != 0xE5) 681 panic("msdosfs_createde: short name slot in use!"); 682 683 /* If it's a directory, make sure it's start cluster is non-zero */ 684 if ((ndep->deAttributes & ATTR_DIRECTORY) && 685 *(uint16_t *)(ndep->deStartCluster) == 0 && 686 *(uint16_t *)(ndep->deHighClust) == 0) 687 { 688 panic("msdosfs_createde: directory with start cluster == 0"); 689 } 690 } 691 692 /* NOTE: DE_EXTERNALIZE does not set the name or lower case flags */ 693 bcopy(dep->de_Name, ndep->deName, 11); 694 ndep->deLowerCase = dep->de_LowerCase; 695 DE_EXTERNALIZE(ndep, dep); 696 697 /* 698 * Now write the Win95 long name 699 */ 700 if (long_count > 0) { 701 u_int8_t chksum = msdosfs_winChksum(ndep->deName); 702 u_int16_t ucfn[WIN_MAXLEN]; 703 size_t unichars; 704 int cnt = 1; 705 706 /* 707 * Decode component name into Unicode 708 * NOTE: We should be using a "precompose" flag 709 */ 710 (void) utf8_decodestr((u_int8_t*)cnp->cn_nameptr, cnp->cn_namelen, ucfn, 711 &unichars, sizeof(ucfn), 0, 712 UTF_PRECOMPOSED|UTF_SFM_CONVERSIONS); 713 unichars /= 2; /* bytes to chars */ 714 715 while (long_count-- > 0) { 716 if (!(offset & pmp->pm_crbomask)) { 717 error = (int)buf_bdwrite(bp); 718 if (error) 719 goto done; 720 721 offset -= sizeof(struct dosdirentry); 722 error = msdosfs_pcbmap(ddep, 723 de_cluster(pmp, offset), 1, 724 &bn, 0, &blsize); 725 if (error) 726 goto done; 727 728 error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, 729 vfs_context_ucred(context), &bp); 730 if (error) { 731 buf_brelse(bp); 732 goto done; 733 } 734 ndep = bptoep(pmp, bp, offset); 735 } else { 736 ndep--; 737 offset -= sizeof(struct dosdirentry); 738 } 739 740 if (DEBUG) 741 { 742 /* Make sure the slot is not in use */ 743 if (ndep->deName[0] != 0 && ndep->deName[0] != 0xE5) 744 panic("msdosfs_createde: long name slot in use!\n"); 745 } 746 747 if (!msdosfs_unicode2winfn(ucfn, (int)unichars, (struct winentry *)ndep, cnt++, chksum)) 748 break; 749 } 750 } 751 752 error = (int)buf_bdwrite(bp); 753 if (error) 754 goto done; 755 756 ddep->de_flag |= DE_UPDATE; 757 758 /* 759 * If they want us to return with the denode gotten. 760 */ 761 if (depp) 762 error = msdosfs_deget(pmp, dirclust, diroffset, DETOV(ddep), cnp, depp, context); 763 764done: 765 KERNEL_DEBUG_CONSTANT(MSDOSFS_CREATEDE|DBG_FUNC_END, error, depp ? (uintptr_t)*depp : 0, 0, 0, 0); 766 767 return error; 768} 769 770/* 771 * Be sure a directory is empty except for "." and "..". Return 1 if empty, 772 * return 0 if not empty or error. 773 */ 774int msdosfs_dosdirempty(struct denode *dep, vfs_context_t context) 775{ 776 uint32_t blsize; 777 int error; 778 uint32_t cn; 779 daddr64_t bn; 780 struct buf *bp; 781 struct msdosfsmount *pmp = dep->de_pmp; 782 struct dosdirentry *dentp; 783 char *bdata; 784 785 /* 786 * Since the filesize field in directory entries for a directory is 787 * zero, we just have to feel our way through the directory until 788 * we hit end of file. 789 */ 790 for (cn = 0;; cn++) { 791 if ((error = msdosfs_pcbmap(dep, cn, 1, &bn, NULL, &blsize)) != 0) { 792 if (error == E2BIG) 793 return (1); /* it's empty */ 794 return (0); 795 } 796 error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp); 797 if (error) { 798 buf_brelse(bp); 799 return (0); 800 } 801 bdata = (char *)buf_dataptr(bp); 802 803 for (dentp = (struct dosdirentry *)bdata; 804 (char *)dentp < bdata + blsize; 805 dentp++) 806 { 807 if (dentp->deName[0] != SLOT_DELETED && 808 (dentp->deAttributes & ATTR_VOLUME) == 0) { 809 /* 810 * In dos directories an entry whose name 811 * starts with SLOT_EMPTY (0) starts the 812 * beginning of the unused part of the 813 * directory, so we can just return that it 814 * is empty. 815 */ 816 if (dentp->deName[0] == SLOT_EMPTY) { 817 buf_brelse(bp); 818 return 1; 819 } 820 /* 821 * Any names other than "." and ".." in a 822 * directory mean it is not empty. 823 */ 824 if (bcmp(dentp->deName, ". ", SHORT_NAME_LEN) && 825 bcmp(dentp->deName, ".. ", SHORT_NAME_LEN)) { 826 buf_brelse(bp); 827 return (0); /* not empty */ 828 } 829 } 830 } 831 buf_brelse(bp); 832 } 833 834 return 1; 835} 836 837/* 838 * Check to see if the directory described by target is in some 839 * subdirectory of source. This prevents something like the following from 840 * succeeding and leaving a bunch or files and directories orphaned: 841 * mv /a/b/c /a/b/c/d/e/f 842 * where c and f are directories. 843 * 844 * source - the inode for /a/b/c (the directory being moved) 845 * target - the inode for /a/b/c/d/e/f (the destination parent directory) 846 * 847 * Returns 0 if target is NOT a subdirectory of source. 848 * Otherwise returns a non-zero error number. 849 * 850 * This routine works by following the chain of ".." entries starting at 851 * target until we reach source, or the root of the volume. It reads the 852 * directory entries directly, not via directory denodes. It assumes that 853 * the caller has prevented the hierarchy from changing. This routine takes 854 * no locks. 855 */ 856int msdosfs_doscheckpath(struct denode *source, struct denode *target, vfs_context_t context) 857{ 858 daddr64_t scn, source_scn; 859 struct msdosfsmount *pmp; 860 struct dosdirentry *ep; 861 struct buf *bp = NULL; 862 int error = 0; 863 int isFAT32; 864 char *bdata; 865 866 pmp = target->de_pmp; 867 isFAT32 = FAT32(pmp); 868 scn = target->de_StartCluster; 869 if (scn == pmp->pm_rootdirblk) 870 scn = 0; 871 source_scn = source->de_StartCluster; 872 /* Assumes the caller has prevented the source from being the root */ 873 874 /* scn == 0 means the root directory */ 875 while (scn != 0) 876 { 877 if (scn == source_scn) 878 return EINVAL; 879 880 /* Read the first cluster of the current directory */ 881 error = (int)buf_meta_bread(pmp->pm_devvp, cntobn(pmp, scn), 882 pmp->pm_bpcluster, vfs_context_ucred(context), &bp); 883 if (error) break; 884 bdata = (char *)buf_dataptr(bp); 885 886 /* Point to the second entry, which should be the ".." entry */ 887 ep = (struct dosdirentry *) bdata + 1; 888 if ((ep->deAttributes & ATTR_DIRECTORY) == 0 || 889 bcmp(ep->deName, ".. ", SHORT_NAME_LEN) != 0) 890 { 891 error = ENOTDIR; 892 break; 893 } 894 895 /* Get the cluster number from the ".." entry */ 896 scn = getuint16(ep->deStartCluster); 897 if (isFAT32) 898 scn |= getuint16(ep->deHighClust) << 16; 899 900 /* 901 * When ".." points to the root, the cluster number should be 0. 902 * On FAT32, it's conceivable that an implementation might incorrectly 903 * have set the cluster number to the first cluster of the root. 904 * If so, we need to exit. For FAT12 and FAT16, pm_rootdirblk will be 905 * 0, in which case this is just a slightly early exit of the loop 906 * (the while condition would be false the next time through). 907 */ 908 if (scn == pmp->pm_rootdirblk) 909 break; 910 911 /* Release the block we read above */ 912 buf_brelse(bp); 913 bp = NULL; 914 } 915 916 if (bp) 917 buf_brelse(bp); 918 if (error == ENOTDIR) 919 printf("msdosfs_doscheckpath(): .. not a directory?\n"); 920 return (error); 921} 922 923/* 924 * Read in the disk block containing the directory entry (dirclu, dirofs) 925 * and return the address of the buf header, and the address of the 926 * directory entry within the block. 927 */ 928int msdosfs_readep(struct msdosfsmount *pmp, 929 uint32_t dirclust, uint32_t diroffset, 930 struct buf **bpp, struct dosdirentry **epp, vfs_context_t context) 931{ 932 int error; 933 daddr64_t bn; 934 int blsize; 935 936 /* 937 * Handle the special case of the root directory. If there is a volume 938 * label entry, then get that. Otherwise, return an error. 939 */ 940 if ((dirclust == MSDOSFSROOT 941 || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)) 942 && diroffset == MSDOSFSROOT_OFS) 943 { 944 if (pmp->pm_label_cluster == CLUST_EOFE) 945 return EIO; 946 else 947 { 948 dirclust = pmp->pm_label_cluster; 949 diroffset = pmp->pm_label_offset; 950 } 951 } 952 953 /* 954 * Sanity check the diroffset. It should be a multiple of the directory 955 * entry size (i.e. a multiple of 32). 956 */ 957 if (diroffset % sizeof(struct dosdirentry)) 958 { 959 printf("msdosfs: msdosfs_readep: invalid diroffset (%u)\n", diroffset); 960 return EIO; 961 } 962 963 /* Figure out which block contains the directory entry. */ 964 blsize = pmp->pm_bpcluster; 965 if (dirclust == MSDOSFSROOT 966 && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) 967 { 968 blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; 969 } 970 bn = detobn(pmp, dirclust, diroffset); 971 972 /* 973 * We occasionally get panic reports that appear to be caused because 974 * blsize == 0. I haven't figured out what can cause that, so try 975 * logging some information that might help, and return an error. 976 */ 977 if (blsize == 0) 978 { 979 printf("msdosfs: msdosfs_readep: blsize==0; pm_fatmask=0x%x, pm_bpcluster=0x%x, " 980 "pm_BlockSize=0x%x, pm_PhysBlockSize=0x%x, pm_BlocksPerSec=0x%x, " 981 "pm_cnshift=0x%x, pm_bnshift=0x%x, pm_crbomask=0x%x, " 982 "pm_rootdirblk=0x%x, pm_rootdirsize=0x%x, " 983 "pm_label_cluster=0x%x, pm_label_offset=0x%x, " 984 "dirclust=0x%x, diroffset=0x%x, bn=0x%llx\n", 985 pmp->pm_fatmask, pmp->pm_bpcluster, 986 pmp->pm_BlockSize, pmp->pm_PhysBlockSize, pmp->pm_BlocksPerSec, 987 pmp->pm_cnshift, pmp->pm_bnshift, pmp->pm_crbomask, 988 pmp->pm_rootdirblk, pmp->pm_rootdirsize, 989 pmp->pm_label_cluster, pmp->pm_label_offset, 990 dirclust, diroffset, bn); 991 return EIO; 992 } 993 994 /* Read the block containing the directory entry, then return the requested entry. */ 995 if ((error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), bpp)) != 0) 996 { 997 buf_brelse(*bpp); 998 *bpp = NULL; 999 return (error); 1000 } 1001 if (epp) 1002 *epp = bptoep(pmp, *bpp, diroffset); 1003 return (0); 1004} 1005 1006 1007/* 1008 * Remove a directory entry. At this point the file represented by the 1009 * directory entry to be removed is still full length until noone has it 1010 * open. When the file no longer being used msdosfs_vnop_inactive() is called 1011 * and will truncate the file to 0 length. When the vnode containing the 1012 * denode is needed for some other purpose by VFS it will call 1013 * msdosfs_vnop_reclaim() which will remove the denode from the denode cache. 1014 */ 1015int msdosfs_removede(struct denode *pdep, uint32_t offset, vfs_context_t context) 1016{ 1017 int error; 1018 struct dosdirentry *ep; 1019 struct buf *bp; 1020 daddr64_t bn; 1021 uint32_t blsize; 1022 struct msdosfsmount *pmp = pdep->de_pmp; 1023 uint32_t cur_offset; 1024 1025 cur_offset = offset; 1026 cur_offset += sizeof(struct dosdirentry); 1027 do { 1028 cur_offset -= sizeof(struct dosdirentry); 1029 error = msdosfs_pcbmap(pdep, de_cluster(pmp, cur_offset), 1, &bn, NULL, &blsize); 1030 if (error) 1031 return error; 1032 error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp); 1033 if (error) { 1034 buf_brelse(bp); 1035 return error; 1036 } 1037 ep = bptoep(pmp, bp, cur_offset); 1038 1039 /* 1040 * Stop deleting long name entries when we find some other short 1041 * name entry. 1042 */ 1043 if (ep->deAttributes != ATTR_WIN95 1044 && cur_offset != offset) { 1045 buf_brelse(bp); 1046 break; 1047 } 1048 cur_offset += sizeof(struct dosdirentry); 1049 while (1) { 1050 /* 1051 * We are a bit agressive here in that we delete any Win95 1052 * entries preceding this entry, not just the ones we "own". 1053 * Since these presumably aren't valid anyway, 1054 * there should be no harm. 1055 */ 1056 cur_offset -= sizeof(struct dosdirentry); 1057 ep--->deName[0] = SLOT_DELETED; 1058 if ((cur_offset & pmp->pm_crbomask) == 0 1059 || ep->deAttributes != ATTR_WIN95) 1060 break; 1061 } 1062 error = (int)buf_bdwrite(bp); 1063 if (error) 1064 return error; 1065 } while ((cur_offset & pmp->pm_crbomask) == 0 1066 && cur_offset); 1067 pdep->de_flag |= DE_UPDATE; 1068 1069 return error; 1070} 1071 1072/* 1073 * Scan the directory given by "dep" and determine whether it contains a DOS 1074 * (8.3-style) short name equal to "short_name". If not, then return 0. 1075 * If the short name already exists in the directory, return EEXIST. If 1076 * there is any other error reading the directory, return that error. 1077 */ 1078int msdosfs_scan_dir_for_short_name( 1079 struct denode *dep, 1080 u_char short_name[SHORT_NAME_LEN], 1081 vfs_context_t context) 1082{ 1083 daddr64_t bn; 1084 struct dosdirentry *dentp; 1085 struct buf *bp = NULL; 1086 char *bdata; 1087 uint32_t blsize; 1088 uint32_t cn; 1089 int error; 1090 1091 for (cn = error = 0; !error; cn++) { 1092 if ((error = msdosfs_pcbmap(dep, cn, 1, &bn, NULL, &blsize)) != 0) { 1093 if (error == E2BIG) /* EOF reached and not found */ 1094 error = 0; 1095 break; 1096 } 1097 error = (int)buf_meta_bread(dep->de_pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp); 1098 if (error) { 1099 break; 1100 } 1101 bdata = (char *)buf_dataptr(bp); 1102 1103 for (dentp = (struct dosdirentry *)bdata; (char *)dentp < bdata + blsize; dentp++) { 1104 if (dentp->deName[0] == SLOT_EMPTY) { 1105 /* 1106 * Last used entry and not found. Note: error == 0 here. 1107 */ 1108 break; 1109 } 1110 /* 1111 * Ignore volume labels and Win95 entries 1112 */ 1113 if (dentp->deAttributes & ATTR_VOLUME) 1114 continue; 1115 if (!bcmp(dentp->deName, short_name, SHORT_NAME_LEN)) { 1116 error = EEXIST; 1117 break; 1118 } 1119 } 1120 buf_brelse(bp); 1121 bp = NULL; 1122 } 1123 if (bp) 1124 buf_brelse(bp); 1125 1126 return error; 1127} 1128 1129/* 1130 * Determine a DOS (8.3-style) short name that is unique within the directory given 1131 * by "dep". The short_name parameter is both input and output; on input, it is 1132 * the short name derived from the Unicode name (as produced by msdosfs_unicode_to_dos_name); 1133 * on output, it is the unique short name (which may contain a generation number). 1134 * The dir_offset parameter is the offset (in bytes, a multiple of 32) from the start 1135 * of the directory to the first long name entry (used as a hint to derive a 1136 * likely unique generation number), or 1 if no generation number should be used. 1137 */ 1138int msdosfs_uniqdosname(struct denode *dep, 1139 u_char short_name[SHORT_NAME_LEN], 1140 uint32_t dir_offset, 1141 vfs_context_t context) 1142{ 1143 int generation; 1144 int error; 1145 enum { SIMPLE_GENERATION_LIMIT = 6 }; 1146 1147 KERNEL_DEBUG_CONSTANT(MSDOSFS_UNIQDOSNAME|DBG_FUNC_START, dep->de_pmp, dep, 0, 0, 0); 1148 1149 if (dir_offset == 1) 1150 { 1151 /* 1152 * dir_offset == 1 means the short name is case-insensitively equal to 1153 * the long name, so don't use a generation number. 1154 */ 1155 error = msdosfs_scan_dir_for_short_name(dep, short_name, context); 1156 } 1157 else 1158 { 1159 /* Try a few simple (small) generation numbers first. */ 1160 for (error = EEXIST, generation = 1; 1161 error == EEXIST && generation < SIMPLE_GENERATION_LIMIT; 1162 ++generation) 1163 { 1164 error = msdosfs_apply_generation_to_short_name(short_name, generation); 1165 if (!error) 1166 error = msdosfs_scan_dir_for_short_name(dep, short_name, context); 1167 } 1168 if (error == 0) 1169 goto done; 1170 1171 /* 1172 * We've had too many collisions, so use a generation number based on dir_offset, 1173 * that is likely to be unique in the directory. 1174 */ 1175 generation = SIMPLE_GENERATION_LIMIT + (dir_offset / sizeof(struct dosdirentry)); 1176 KERNEL_DEBUG_CONSTANT(MSDOSFS_UNIQDOSNAME, dep->de_pmp, dep, generation, 0, 0); 1177 1178 for (error = EEXIST; error == EEXIST && generation < 1000000; ++generation) 1179 { 1180 error = msdosfs_apply_generation_to_short_name(short_name, generation); 1181 if (!error) 1182 error = msdosfs_scan_dir_for_short_name(dep, short_name, context); 1183 } 1184 } 1185 1186done: 1187 KERNEL_DEBUG_CONSTANT(MSDOSFS_UNIQDOSNAME|DBG_FUNC_END, error, 0, 0, 0, 0); 1188 1189 return error; 1190} 1191 1192/* 1193 * Find room in a directory to create the entries for a given name. It also returns 1194 * the short name (without any generation number that may be needed), whether the 1195 * short name needs a generation number, and the lower case flags. 1196 * 1197 * Inputs: 1198 * dep directory to search for free/unused entries 1199 * cnp the name to be created (used to determine number of slots needed). 1200 * 1201 * Outputs: 1202 * short_name The derived short name, without any generation number 1203 * needs_generation 1204 * Returns non-zero if the short name needs a generation number inserted 1205 * lower_case The case ("NT") flags for the new name 1206 * offset Byte offset from start of directory where short name (last entry) goes 1207 * long_count Number of entries needed for long name entries 1208 * 1209 * Result: 1210 * 0 1211 * The outputs are valid. Note: the resulting offset may be beyond the 1212 * end of the directory; if so, it is the caller's responsibility to try 1213 * to grow the directory. 1214 * ENAMETOOLONG 1215 * The name provided is illegal. 1216 * other errno 1217 * An error reading the directory. 1218 */ 1219int msdosfs_findslots( 1220 struct denode *dep, 1221 struct componentname *cnp, 1222 uint8_t short_name[SHORT_NAME_LEN], 1223 int *needs_generation, 1224 uint8_t *lower_case, 1225 uint32_t *offset, 1226 uint32_t *long_count, 1227 vfs_context_t context) 1228{ 1229 int error = 0; 1230 u_int16_t ucfn[WIN_MAXLEN]; 1231 size_t unichars; 1232 int wincnt=0; /* Number of consecutive entries needed for long name + dir entry */ 1233 int short_name_kind; 1234 int slotcount; /* Number of consecutive entries found so far */ 1235 uint32_t diroff; /* Byte offset of entry from start of directory */ 1236 unsigned blkoff; /* Byte offset of entry from start of block */ 1237 int frcn; /* File (directory) relative cluster number */ 1238 daddr64_t bn; /* Physical disk block number */ 1239 uint32_t blsize; /* Size of directory cluster, in bytes */ 1240 struct dosdirentry *entry; 1241 struct msdosfsmount *pmp; 1242 struct buf *bp = NULL; 1243 char *bdata; 1244 1245 pmp = dep->de_pmp; 1246 1247 KERNEL_DEBUG_CONSTANT(MSDOSFS_FINDSLOTS|DBG_FUNC_START, pmp, dep, 0, 0, 0); 1248 1249 /* 1250 * Decode name into UCS-2 (Unicode) 1251 * 1252 * This function does not generate the on-disk Unicode name; it just cares 1253 * about the length of the Unicode name. It assumes that the Services For 1254 * Macintosh conversions do not change the Unicode name length. Therefore, 1255 * we don't pass the flag for Services For Macintosh conversions here. 1256 */ 1257 (void) utf8_decodestr((u_int8_t*)cnp->cn_nameptr, cnp->cn_namelen, ucfn, &unichars, 1258 sizeof(ucfn), 0, UTF_PRECOMPOSED); 1259 unichars /= 2; /* bytes to chars */ 1260 1261 /* 1262 * Determine the number of consecutive directory entries we'll need. 1263 */ 1264 short_name_kind = msdosfs_unicode_to_dos_name(ucfn, unichars, short_name, lower_case); 1265 switch (short_name_kind) { 1266 case 0: 1267 /* 1268 * The name is syntactically invalid. Normally, we'd return EINVAL, 1269 * but ENAMETOOLONG makes it clear that the name is the problem (and 1270 * allows Carbon to return a more meaningful error). 1271 */ 1272 error = ENAMETOOLONG; 1273 goto done; 1274 case 1: 1275 /* 1276 * The name is already a short, DOS name, so no long name entries needed. 1277 */ 1278 wincnt = 1; 1279 break; 1280 case 2: 1281 case 3: 1282 /* 1283 * The name needs long name entries. The +1 is for the short name entry. 1284 */ 1285 wincnt = msdosfs_winSlotCnt(ucfn, (int)unichars) + 1; 1286 break; 1287 } 1288 1289 /* 1290 * Look for some consecutive unused directory entries. 1291 */ 1292 slotcount = 0; /* None found yet. */ 1293 1294 /* The outer loop ranges over the clusters in the directory. */ 1295 diroff = 0; 1296 for (frcn = 0; ; frcn++) { 1297 error = msdosfs_pcbmap(dep, frcn, 1, &bn, NULL, &blsize); 1298 if (error) { 1299 if (error == E2BIG) 1300 { 1301 /* E2BIG means we hit the end of directory, which is OK here. */ 1302 error = 0; 1303 break; 1304 } 1305 else 1306 { 1307 goto done; 1308 } 1309 } 1310 error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp); 1311 if (error) { 1312 goto done; 1313 } 1314 bdata = (char *)buf_dataptr(bp); 1315 1316 /* Loop over entries in the cluster. */ 1317 for (blkoff = 0; blkoff < blsize; 1318 blkoff += sizeof(struct dosdirentry), 1319 diroff += sizeof(struct dosdirentry)) 1320 { 1321 entry = (struct dosdirentry *)(bdata + blkoff); 1322 1323 if (entry->deName[0] == SLOT_EMPTY || 1324 entry->deName[0] == SLOT_DELETED) 1325 { 1326 slotcount++; 1327 if (slotcount == wincnt) { 1328 /* Found enough space! */ 1329 *offset = diroff; 1330 goto found; 1331 } 1332 } else { 1333 /* Empty space wasn't big enough, so forget about it. */ 1334 slotcount = 0; 1335 } 1336 } 1337 buf_brelse(bp); 1338 bp = NULL; 1339 } 1340 /* 1341 * Fix up the slot description to point to where we would put the 1342 * DOS entry (with Win95 long name entries before that). If we 1343 * would need to grow the directory, then the offset will be greater 1344 * than or equal to the size of the directory. 1345 */ 1346found: 1347 if (wincnt > slotcount) { 1348 /* 1349 * If we get here, we hit the end of the directory without finding 1350 * enough consecutive slots. "slotcount" is the number of free slots 1351 * at the end of the last cluster. "diroff" is the size of the 1352 * directory, in bytes. 1353 * 1354 * Note the "- 1" below; that's because the returned offset is the 1355 * offset of the last slot that would be used (for the short name 1356 * entry); without subtracting one, we'd end up pointing to the slot 1357 * immediately past the last one being used. 1358 */ 1359 *offset = diroff + sizeof(struct dosdirentry) * (wincnt - slotcount - 1); 1360 } 1361 *long_count = wincnt - 1; 1362 *needs_generation = (short_name_kind == 3); 1363 1364done: 1365 if (bp) 1366 buf_brelse(bp); 1367 1368 KERNEL_DEBUG_CONSTANT(MSDOSFS_FINDSLOTS|DBG_FUNC_END, error, *lower_case, *offset, *long_count, 0); 1369 1370 return error; 1371} 1372 1373 1374/* 1375 * Write all modified blocks for a given directory. 1376 */ 1377int msdosfs_dir_flush(struct denode *dep, int sync) 1378{ 1379 int error; 1380 uint32_t frcn; /* File (directory) relative cluster number */ 1381 uint32_t blsize; /* Size of directory block */ 1382 daddr64_t bn; /* Device block number */ 1383 vnode_t devvp = dep->de_pmp->pm_devvp; 1384 buf_t bp; 1385 1386 if (dep->de_refcnt <= 0) 1387 { 1388 /* Don't bother updating a deleted directory */ 1389 return 0; 1390 } 1391 1392 for (frcn=0; ; frcn++) 1393 { 1394 error = msdosfs_pcbmap(dep, frcn, 1, &bn, NULL, &blsize); 1395 if (error) 1396 { 1397 if (error == E2BIG) 1398 break; 1399 return error; 1400 } 1401 1402 bp = buf_getblk(devvp, bn, blsize, 0, 0, BLK_META|BLK_ONLYVALID); 1403 if (bp) 1404 { 1405 if (buf_flags(bp) & B_DELWRI) 1406 { 1407 if (sync) 1408 buf_bwrite(bp); 1409 else 1410 buf_bawrite(bp); 1411 } 1412 else 1413 { 1414 buf_brelse(bp); 1415 } 1416 } 1417 } 1418 1419 return 0; 1420} 1421 1422 1423/* 1424 * Invalidate all blocks for a given directory. 1425 */ 1426int msdosfs_dir_invalidate(struct denode *dep) 1427{ 1428 int error; 1429 uint32_t frcn; /* File (directory) relative cluster number */ 1430 uint32_t blsize; /* Size of directory block */ 1431 daddr64_t bn; /* Device block number */ 1432 vnode_t devvp = dep->de_pmp->pm_devvp; 1433 1434 for (frcn=0; ; frcn++) 1435 { 1436 error = msdosfs_pcbmap(dep, frcn, 1, &bn, NULL, &blsize); 1437 if (error) 1438 { 1439 if (error == E2BIG) 1440 break; 1441 return error; 1442 } 1443 1444 (void) buf_invalblkno(devvp, bn, BUF_WAIT); 1445 } 1446 1447 return 0; 1448} 1449