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_vnops.c,v 1.99 2000/05/05 09:58:36 phk Exp $ */ 24/* $NetBSD: msdosfs_vnops.c,v 1.68 1998/02/10 14:10:04 mrg 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#include <sys/param.h> 73#include <sys/systm.h> 74#include <sys/vnode.h> 75#include <sys/kernel.h> 76#include <sys/stat.h> 77#include <sys/buf.h> 78#include <sys/proc.h> 79#include <sys/mount.h> 80#include <sys/unistd.h> 81#include <sys/vnode.h> 82#include <miscfs/specfs/specdev.h> 83#include <sys/malloc.h> 84#include <sys/dirent.h> 85#include <sys/signalvar.h> 86#include <sys/ubc.h> 87#include <sys/utfconv.h> 88#include <sys/attr.h> 89#include <sys/namei.h> 90#include <libkern/crypto/md5.h> 91#include <sys/disk.h> 92#include <mach/boolean.h> 93#include <libkern/OSMalloc.h> 94 95#include "bpb.h" 96#include "direntry.h" 97#include "denode.h" 98#include "msdosfsmount.h" 99#include "fat.h" 100#include "msdosfs_kdebug.h" 101 102#ifndef DEBUG 103#define DEBUG 0 104#endif 105 106/* 107 * The maximum file size on FAT is 4GB-1, which is the largest value that fits 108 * in an unsigned 32-bit integer. 109 */ 110#define DOS_FILESIZE_MAX 0xffffffff 111 112union msdosfs_dirbuf { 113 struct dirent dirent; 114 struct direntry direntry; 115}; 116 117/* 118 * Prototypes for MSDOSFS vnode operations 119 */ 120int msdosfs_vnop_create(struct vnop_create_args *); 121int msdosfs_vnop_mknod(struct vnop_mknod_args *); 122int msdosfs_vnop_open(struct vnop_open_args *ap); 123int msdosfs_vnop_close(struct vnop_close_args *); 124int msdosfs_vnop_getattr(struct vnop_getattr_args *); 125int msdosfs_vnop_setattr(struct vnop_setattr_args *); 126int msdosfs_vnop_getxattr(struct vnop_getxattr_args *ap); 127int msdosfs_vnop_setxattr(struct vnop_setxattr_args *ap); 128int msdosfs_vnop_removexattr(struct vnop_removexattr_args *ap); 129int msdosfs_vnop_listxattr(struct vnop_listxattr_args *ap); 130int msdosfs_vnop_read(struct vnop_read_args *); 131int msdosfs_vnop_write(struct vnop_write_args *); 132int msdosfs_vnop_pagein(struct vnop_pagein_args *); 133int msdosfs_vnop_fsync(struct vnop_fsync_args *); 134int msdosfs_vnop_remove(struct vnop_remove_args *); 135int msdosfs_vnop_rename(struct vnop_rename_args *); 136int msdosfs_vnop_mkdir(struct vnop_mkdir_args *); 137int msdosfs_vnop_rmdir(struct vnop_rmdir_args *); 138int msdosfs_vnop_readdir(struct vnop_readdir_args *); 139int msdosfs_vnop_strategy(struct vnop_strategy_args *); 140int msdosfs_vnop_pathconf(struct vnop_pathconf_args *ap); 141int msdosfs_vnop_symlink(struct vnop_symlink_args *ap); 142int msdosfs_vnop_readlink(struct vnop_readlink_args *ap); 143int msdosfs_vnop_ioctl(struct vnop_ioctl_args *ap); 144int msdosfs_vnop_pageout(struct vnop_pageout_args *ap); 145 146/* Other prototypes */ 147void msdosfs_lock_two(struct denode *dep1, struct denode *dep2); 148void msdosfs_sort_denodes(struct denode *deps[4]); 149void msdosfs_lock_four(struct denode *dep0, struct denode *dep1, struct denode *dep2, struct denode *dep3); 150void msdosfs_unlock_four(struct denode *dep0, struct denode *dep1, struct denode *dep2, struct denode *dep3); 151void msdosfs_md5_digest(void *text, size_t length, char digest[33]); 152ssize_t msdosfs_dirbuf_size(union msdosfs_dirbuf *buf, size_t name_length, int flags); 153 154 155/* 156 * Some general notes: 157 * 158 * In the ufs filesystem the inodes, superblocks, and indirect blocks are 159 * read/written using the vnode for the filesystem. Blocks that represent 160 * the contents of a file are read/written using the vnode for the file 161 * (including directories when they are read/written as files). This 162 * presents problems for the dos filesystem because data that should be in 163 * an inode (if dos had them) resides in the directory itself. Since we 164 * must update directory entries without the benefit of having the vnode 165 * for the directory we must use the vnode for the filesystem. This means 166 * that when a directory is actually read/written (via read, write, or 167 * readdir, or seek) we must use the vnode for the filesystem instead of 168 * the vnode for the directory as would happen in ufs. This is to insure we 169 * retreive the correct block from the buffer cache since the hash value is 170 * based upon the vnode address and the desired block number. 171 */ 172 173 174/* 175 * msdosfs_lock_two 176 * 177 * Acquire the denode locks for two denodes. The locks are always 178 * acquired in order of increasing address of the denode. 179 */ 180void msdosfs_lock_two(struct denode *dep1, struct denode *dep2) 181{ 182 if (dep1 == NULL) 183 panic("msdosfs_lock_two: dep1 == NULL\n"); 184 if (dep2 == NULL) 185 panic("msdosfs_lock_two: dep2 == NULL\n"); 186 if (dep1 == dep2) 187 panic("msdosfs_lock_two: dep1 == dep2\n"); 188 189 if (dep1 < dep2) 190 { 191 lck_mtx_lock(dep1->de_lock); 192 lck_mtx_lock(dep2->de_lock); 193 } 194 else 195 { 196 lck_mtx_lock(dep2->de_lock); 197 lck_mtx_lock(dep1->de_lock); 198 } 199} 200 201/* 202 * Sort a list of denodes into increasing address order. Remove duplicate addresses. 203 * Any unused entries will be NULL. Some of the entries may be NULL on input. 204 */ 205void msdosfs_sort_denodes(struct denode *deps[4]) 206{ 207 int i, j; 208 struct denode *temp; 209 210 /* A simple bubble sort */ 211 for (j=3; j>0; --j) 212 for (i=0; i<j; ++i) 213 if (deps[i] > deps[i+1]) 214 { 215 temp = deps[i]; 216 deps[i] = deps[i+1]; 217 deps[i+1] = temp; 218 } 219 220 /* Remove duplicates */ 221 for (i=0; i<3; ++i) 222 if (deps[i] == deps[i+1]) 223 deps[i] = NULL; 224} 225 226void msdosfs_lock_four(struct denode *dep0, struct denode *dep1, struct denode *dep2, struct denode *dep3) 227{ 228 int i; 229 struct denode *deps[4] = {dep0, dep1, dep2, dep3}; 230 231 msdosfs_sort_denodes(deps); 232 233 for (i=0; i<4; ++i) 234 if (deps[i] != NULL) 235 lck_mtx_lock(deps[i]->de_lock); 236} 237 238void msdosfs_unlock_four(struct denode *dep0, struct denode *dep1, struct denode *dep2, struct denode *dep3) 239{ 240 int i; 241 struct denode *deps[4] = {dep0, dep1, dep2, dep3}; 242 243 /* 244 * We don't actually care about the order of the denodes when unlocking. 245 * But we do care about removing duplicates. 246 */ 247 msdosfs_sort_denodes(deps); 248 249 for (i=0; i<4; ++i) 250 if (deps[i] != NULL) 251 lck_mtx_unlock(deps[i]->de_lock); 252} 253 254/* 255 * Create a regular file. 256 */ 257int msdosfs_vnop_create(struct vnop_create_args *ap) 258/* { 259 vnode_t a_dvp; 260 vnode_t *a_vpp; 261 struct componentname *a_cnp; 262 struct vnode_attr *a_vap; 263 vfs_context_t a_context; 264 } */ 265{ 266 vnode_t dvp = ap->a_dvp; 267 struct denode *pdep = VTODE(dvp); 268 struct componentname *cnp = ap->a_cnp; 269 vfs_context_t context = ap->a_context; 270 struct vnode_attr *vap = ap->a_vap; 271 struct denode ndirent; 272 struct denode *dep = NULL; 273 struct timespec ts; 274 int error; 275 uint32_t offset = 0; /* byte offset in directory for new entry */ 276 uint32_t long_count = 0; /* number of long name entries needed */ 277 int needs_generation; 278 279 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_CREATE|DBG_FUNC_START, pdep->de_pmp, pdep, 0, 0, 0); 280 281 lck_mtx_lock(pdep->de_lock); 282 283 /* 284 * Make sure the parent directory hasn't been deleted. 285 */ 286 if (pdep->de_refcnt <= 0) 287 { 288 cache_purge(dvp); 289 error = ENOENT; 290 goto exit; 291 } 292 293 /* 294 * Make sure the name does not exist in the parent directory. (It didn't 295 * exist during VNOP_LOOKUP, but another thread may have created the name 296 * before we got the lock on the parent.) 297 */ 298 error = msdosfs_lookup_name(pdep, cnp, NULL, NULL, NULL, NULL, NULL, NULL, context); 299 if (error != ENOENT) 300 { 301 error = EEXIST; 302 goto exit; 303 } 304 305 /* 306 * Find space in the directory to place the new name. 307 */ 308 bzero(&ndirent, sizeof(ndirent)); 309 error = msdosfs_findslots(pdep, cnp, ndirent.de_Name, &needs_generation, &ndirent.de_LowerCase, &offset, &long_count, context); 310 if (error) 311 goto exit; 312 313 /* 314 * If this is the root directory and there is no space left we 315 * can't do anything. This is because the root directory can not 316 * change size. (FAT12 and FAT16 only) 317 * 318 * On FAT32, we can grow the root directory, and de_StartCluster 319 * will be the actual cluster number of the root directory. 320 */ 321 if (pdep->de_StartCluster == MSDOSFSROOT && offset >= pdep->de_FileSize) 322 { 323 printf("msdosfs_vnop_create: Cannot grow the root directory on FAT12 or FAT16; returning ENOSPC.\n"); 324 error = ENOSPC; 325 goto exit; 326 } 327 328 /* 329 * Create a directory entry for the file, then call msdosfs_createde() to 330 * have it installed. NOTE: DOS files are always executable. 331 * The supplied mode is ignored (DOS doesn't store mode, so 332 * all files on a volume have a constant mode). The immutable 333 * flag is used to set DOS's read-only attribute. 334 */ 335 error = msdosfs_uniqdosname(pdep, ndirent.de_Name, needs_generation ? offset - long_count * sizeof(struct dosdirentry) : 1, context); 336 if (error) 337 { 338 if (DEBUG) panic("msdosfs_vnop_create: msdosfs_uniqdosname returned %d\n", error); 339 goto exit; 340 } 341 342 // Set read-only attribute if one of the immutable bits is set. 343 // Always set the "needs archive" attribute on newly created files. 344 ndirent.de_Attributes = ATTR_ARCHIVE; 345 if (VATTR_IS_ACTIVE(vap, va_flags)) 346 { 347 if ((vap->va_flags & (SF_IMMUTABLE | UF_IMMUTABLE)) != 0) 348 ndirent.de_Attributes |= ATTR_READONLY; 349 VATTR_SET_SUPPORTED(vap, va_flags); 350 } 351 352 353 /* 354 * If the file name starts with ".", make it invisible on Windows. 355 */ 356 if (cnp->cn_nameptr[0] == '.') 357 ndirent.de_Attributes |= ATTR_HIDDEN; 358 359 ndirent.de_StartCluster = 0; 360 ndirent.de_FileSize = 0; 361 ndirent.de_dev = pdep->de_dev; 362 ndirent.de_devvp = pdep->de_devvp; 363 ndirent.de_pmp = pdep->de_pmp; 364 ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; 365 getnanotime(&ts); 366 DETIMES(&ndirent, &ts, &ts, &ts); 367 error = msdosfs_createde(&ndirent, pdep, &dep, cnp, offset, long_count, context); 368 if (error) 369 { 370 /* 371 * ENOSPC is a common and expected failure. Anything else is 372 * unexpected, and I want a chance to debug it. 373 */ 374 if (DEBUG && error != ENOSPC) panic("msdosfs_vnop_create: msdosfs_createde returned %d\n", error); 375 goto exit; 376 } 377 *ap->a_vpp = DETOV(dep); 378 cache_purge_negatives(dvp); 379 380exit: 381 msdosfs_meta_flush(pdep->de_pmp, FALSE); 382 lck_mtx_unlock(pdep->de_lock); 383 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_CREATE|DBG_FUNC_END, error, dep, offset, long_count, 0); 384 return error; 385} 386 387int msdosfs_vnop_mknod(struct vnop_mknod_args *ap) 388/* { 389 vnode_t a_dvp; 390 vnode_t *a_vpp; 391 struct componentname *a_cnp; 392 struct vattr *a_vap; 393 vfs_context_t a_context; 394 } */ 395{ 396#pragma unused (ap) 397 /* We don't support special files */ 398 return EINVAL; 399} 400 401int msdosfs_vnop_open(struct vnop_open_args *ap) 402/* { 403 vnode_t a_vp; 404 int a_mode; 405 vfs_context_t a_context; 406 } */ 407{ 408#pragma unused (ap) 409 return 0; 410} 411 412int msdosfs_vnop_close(struct vnop_close_args *ap) 413/* { 414 vnode_t a_vp; 415 int a_fflag; 416 vfs_context_t a_context; 417 } */ 418{ 419 vnode_t vp = ap->a_vp; 420 struct denode *dep = VTODE(vp); 421 422 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_CLOSE|DBG_FUNC_START, dep, 0, 0, 0, 0); 423 lck_mtx_lock(dep->de_lock); 424 425 cluster_push(vp, IO_CLOSE); 426 msdosfs_deupdat(dep, 0, ap->a_context); 427 msdosfs_meta_flush(dep->de_pmp, FALSE); 428 429 lck_mtx_unlock(dep->de_lock); 430 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_CLOSE|DBG_FUNC_END, 0, 0, 0, 0, 0); 431 432 return 0; 433} 434 435int msdosfs_vnop_getattr(struct vnop_getattr_args *ap) 436/* { 437 vnode_t a_vp; 438 struct vnode_attr *a_vap; 439 vfs_context_t a_context; 440 } */ 441{ 442 vnode_t vp = ap->a_vp; 443 struct denode *dep = VTODE(vp); 444 struct msdosfsmount *pmp = dep->de_pmp; 445 struct vnode_attr *vap = ap->a_vap; 446 447 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_GETATTR|DBG_FUNC_START, dep, vap->va_active, 0, 0, 0); 448 lck_mtx_lock(dep->de_lock); 449 450 VATTR_RETURN(vap, va_rdev, 0); 451 VATTR_RETURN(vap, va_nlink, 1); 452 VATTR_RETURN(vap, va_total_size, dep->de_FileSize); 453 /* va_total_alloc is wrong for symlinks */ 454 VATTR_RETURN(vap, va_total_alloc, ((off_t)dep->de_FileSize + pmp->pm_crbomask) & ~((off_t)pmp->pm_crbomask)); 455 VATTR_RETURN(vap, va_data_size, dep->de_FileSize); 456 VATTR_RETURN(vap, va_data_alloc, vap->va_total_alloc); 457 VATTR_RETURN(vap, va_iosize, pmp->pm_iosize); 458 VATTR_RETURN(vap, va_uid, 99); 459 VATTR_RETURN(vap, va_gid, 99); 460 VATTR_RETURN(vap, va_mode, ALLPERMS & pmp->pm_mask); 461 if (VATTR_IS_ACTIVE(vap, va_flags)) { 462 vap->va_flags = 0; 463 /* MSDOS does not set ATTR_ARCHIVE or ATTR_READONLY bits for directories. */ 464 if ((dep->de_Attributes & (ATTR_ARCHIVE | ATTR_DIRECTORY)) == 0) // DOS: flag set means "needs to be archived" 465 vap->va_flags |= SF_ARCHIVED; // BSD: flag set means "has been archived" 466 if ((dep->de_Attributes & (ATTR_READONLY | ATTR_DIRECTORY)) == ATTR_READONLY) 467 vap->va_flags |= UF_IMMUTABLE; // DOS read-only becomes BSD user immutable 468 if (dep->de_Attributes & ATTR_HIDDEN) 469 vap->va_flags |= UF_HIDDEN; 470 VATTR_SET_SUPPORTED(vap, va_flags); 471 } 472 473 /* FAT doesn't support extended security data */ 474 475 if (vap->va_active & (VNODE_ATTR_va_create_time | 476 VNODE_ATTR_va_access_time | VNODE_ATTR_va_modify_time | 477 VNODE_ATTR_va_change_time)) 478 { 479 struct timespec ts; 480 getnanotime(&ts); 481 DETIMES(dep, &ts, &ts, &ts); 482 483 msdosfs_dos2unixtime(dep->de_CDate, dep->de_CTime, 0, &vap->va_create_time); 484 msdosfs_dos2unixtime(dep->de_ADate, 0, 0, &vap->va_access_time); 485 msdosfs_dos2unixtime(dep->de_MDate, dep->de_MTime, 0, &vap->va_modify_time); 486 vap->va_change_time = vap->va_modify_time; 487 /* FAT doesn't have a backup date/time */ 488 489 vap->va_supported |= VNODE_ATTR_va_create_time | 490 VNODE_ATTR_va_access_time | 491 VNODE_ATTR_va_modify_time | 492 VNODE_ATTR_va_change_time; 493 } 494 495 if (VATTR_IS_ACTIVE(vap, va_fileid)) 496 VATTR_RETURN(vap, va_fileid, msdosfs_defileid(dep)); 497 /* FAT has no va_linkid, and no easy access to va_parentid */ 498 499 VATTR_RETURN(vap, va_fsid, dep->de_dev); 500 VATTR_RETURN(vap, va_filerev, dep->de_modrev); 501 VATTR_RETURN(vap, va_gen, 0); 502 503 lck_mtx_unlock(dep->de_lock); 504 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_GETATTR|DBG_FUNC_END, 0, vap->va_supported, 0, 0, 0); 505 506 return 0; 507} 508 509int msdosfs_vnop_setattr(struct vnop_setattr_args *ap) 510 /* { 511 vnode_t a_vp; 512 struct vnode_attr *a_vap; 513 vfs_context_t a_context; 514 } */ 515{ 516 struct denode *dep = VTODE(ap->a_vp); 517 struct vnode_attr *vap = ap->a_vap; 518 int error = 0; 519 520 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_SETATTR|DBG_FUNC_START, dep, vap->va_active, vap->va_data_size, vap->va_flags, 0); 521 lck_mtx_lock(dep->de_lock); 522 523 int isDir = dep->de_Attributes & ATTR_DIRECTORY; 524 525 if (VATTR_IS_ACTIVE(vap, va_data_size)) { 526 if (isDir) 527 { 528 error = EPERM; /* Cannot change size of a directory or symlink! */ 529 goto exit; 530 } 531 if (dep->de_FileSize != vap->va_data_size) { 532 /* msdosfs_detrunc internally updates dep->de_FileSize and calls ubc_setsize. */ 533 if (vap->va_data_size > DOS_FILESIZE_MAX) 534 error = EFBIG; 535 else 536 error = msdosfs_detrunc(dep, (uint32_t)vap->va_data_size, vap->va_vaflags, ap->a_context); 537 if (error) 538 goto exit; 539 } 540 VATTR_SET_SUPPORTED(vap, va_data_size); 541 } 542 543 /* FAT does not support setting uid, gid or mode */ 544 545 if (VATTR_IS_ACTIVE(vap, va_flags)) { 546 /* 547 * Here we are strict, stricter than ufs in not allowing 548 * users to attempt to set SF_SETTABLE bits or anyone to 549 * set unsupported bits. However, we ignore attempts to 550 * set ATTR_ARCHIVE for directories `cp -pr' from a more 551 * sensible file system attempts it a lot. 552 */ 553 554 if (vap->va_flags & ~(SF_ARCHIVED | SF_IMMUTABLE | UF_IMMUTABLE | UF_HIDDEN)) 555 { 556 error = EINVAL; 557 goto exit; 558 } 559 560 uint8_t originalAttributes = dep->de_Attributes; 561 562 if (vap->va_flags & SF_ARCHIVED) 563 dep->de_Attributes &= ~ATTR_ARCHIVE; 564 else if (!isDir) 565 dep->de_Attributes |= ATTR_ARCHIVE; 566 567 /* For files, copy the immutable flag to read-only attribute. */ 568 /* Ignore immutable bit for directories. */ 569 if (!isDir) 570 { 571 if (vap->va_flags & (SF_IMMUTABLE | UF_IMMUTABLE)) 572 dep->de_Attributes |= ATTR_READONLY; 573 else 574 dep->de_Attributes &= ~ATTR_READONLY; 575 } 576 577 if (vap->va_flags & UF_HIDDEN) 578 dep->de_Attributes |= ATTR_HIDDEN; 579 else 580 dep->de_Attributes &= ~ATTR_HIDDEN; 581 582 if (dep->de_Attributes != originalAttributes) 583 dep->de_flag |= DE_MODIFIED | DE_ATTR_MOD; 584 585 VATTR_SET_SUPPORTED(vap, va_flags); 586 } 587 588 /* 589 * Update times. Since we don't explicitly store a change time, we 590 * don't let you set it here. (An alternative behavior would be to 591 * set the denode's mod time to the greater of va_modify_time and 592 * va_change_time.) 593 */ 594 if (VATTR_IS_ACTIVE(vap, va_create_time) | 595 VATTR_IS_ACTIVE(vap, va_access_time) | 596 VATTR_IS_ACTIVE(vap, va_modify_time)) 597 { 598 if (VATTR_IS_ACTIVE(vap, va_create_time)) { 599 msdosfs_unix2dostime(&vap->va_create_time, &dep->de_CDate, &dep->de_CTime, NULL); 600 VATTR_SET_SUPPORTED(vap, va_create_time); 601 } 602 if (VATTR_IS_ACTIVE(vap, va_access_time)) { 603 msdosfs_unix2dostime(&vap->va_access_time, &dep->de_ADate, NULL, NULL); 604 VATTR_SET_SUPPORTED(vap, va_access_time); 605 } 606 if (VATTR_IS_ACTIVE(vap, va_modify_time)) { 607 msdosfs_unix2dostime(&vap->va_modify_time, &dep->de_MDate, &dep->de_MTime, NULL); 608 VATTR_SET_SUPPORTED(vap, va_modify_time); 609 } 610 dep->de_Attributes |= ATTR_ARCHIVE; 611 dep->de_flag |= DE_MODIFIED; 612 } 613 614 error = msdosfs_deupdat(dep, 1, ap->a_context); 615 msdosfs_meta_flush(dep->de_pmp, FALSE); 616 617exit: 618 lck_mtx_unlock(dep->de_lock); 619 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_SETATTR|DBG_FUNC_END, error, vap->va_supported, 0, 0, 0); 620 return error; 621} 622 623static char MSDOSFS_XATTR_VOLUME_ID_NAME[] = "com.apple.filesystems.msdosfs.volume_id"; 624 625int msdosfs_vnop_getxattr(struct vnop_getxattr_args *ap) 626/* { 627 struct vnodeop_desc *a_desc; 628 vnode_t a_vp; 629 const char * a_name; 630 uio_t a_uio; 631 size_t *a_size; 632 int a_options; 633 vfs_context_t a_context; 634 } */ 635{ 636 if (vnode_isvroot(ap->a_vp) && 637 !bcmp(ap->a_name, MSDOSFS_XATTR_VOLUME_ID_NAME, sizeof(MSDOSFS_XATTR_VOLUME_ID_NAME))) 638 { 639 struct denode *dep = VTODE(ap->a_vp); 640 struct msdosfsmount *pmp = dep->de_pmp; 641 uio_t uio = ap->a_uio; 642 643 /* Make sure the volume actually has a serial number. */ 644 if (!(pmp->pm_flags & MSDOSFS_HAS_EXT_BOOT)) 645 return ENOATTR; 646 647 /* Return the volume serial number */ 648 if (uio == NULL) 649 { 650 *ap->a_size = sizeof(pmp->pm_volume_serial_num); 651 return 0; 652 } 653 else if ((user_size_t)uio_resid(uio) < sizeof(pmp->pm_volume_serial_num)) 654 { 655 return ERANGE; 656 } 657 else 658 { 659 return uiomove((char *)pmp->pm_volume_serial_num, sizeof(pmp->pm_volume_serial_num), ap->a_uio); 660 } 661 } 662 663 /* Let VFS handle all other extended attributes. */ 664 return ENOTSUP; 665} 666 667 668int msdosfs_vnop_setxattr(struct vnop_setxattr_args *ap) 669/* { 670 struct vnodeop_desc *a_desc; 671 vnode_t a_vp; 672 const char * a_name; 673 uio_t a_uio; 674 int a_options; 675 vfs_context_t a_context; 676 } */ 677{ 678 if (vnode_isvroot(ap->a_vp) && 679 !bcmp(ap->a_name, MSDOSFS_XATTR_VOLUME_ID_NAME, sizeof(MSDOSFS_XATTR_VOLUME_ID_NAME))) 680 { 681 return EPERM; 682 } 683 684 /* Let VFS handle all other extended attributes. */ 685 return ENOTSUP; 686} 687 688 689int msdosfs_vnop_removexattr(struct vnop_removexattr_args *ap) 690/* { 691 struct vnodeop_desc *a_desc; 692 vnode_t a_vp; 693 const char * a_name; 694 int a_options; 695 vfs_context_t a_context; 696 } */ 697{ 698 if (vnode_isvroot(ap->a_vp) && 699 !bcmp(ap->a_name, MSDOSFS_XATTR_VOLUME_ID_NAME, sizeof(MSDOSFS_XATTR_VOLUME_ID_NAME))) 700 { 701 return EPERM; 702 } 703 704 /* Let VFS handle all other extended attributes. */ 705 return ENOTSUP; 706} 707 708 709int msdosfs_vnop_listxattr(struct vnop_listxattr_args *ap) 710/* { 711 struct vnodeop_desc *a_desc; 712 vnode_t a_vp; 713 uio_t a_uio; 714 size_t *a_size; 715 int a_options; 716 vfs_context_t a_context; 717 } */ 718{ 719 /* Return our xattrs, then return ENOTSUP to let VFS add the rest from AppleDouble files. */ 720 if (vnode_isvroot(ap->a_vp)) 721 { 722 struct denode *dep = VTODE(ap->a_vp); 723 struct msdosfsmount *pmp = dep->de_pmp; 724 725 if (pmp->pm_flags & MSDOSFS_HAS_EXT_BOOT) 726 { 727 /* 728 * The volume has a serial number, so return its name. 729 */ 730 731 uio_t uio = ap->a_uio; 732 733 if (uio == NULL) 734 { 735 /* Just update the size */ 736 *ap->a_size += sizeof(MSDOSFS_XATTR_VOLUME_ID_NAME); 737 } 738 else if (uio_resid(uio) < (user_ssize_t)sizeof(MSDOSFS_XATTR_VOLUME_ID_NAME)) 739 { 740 return ERANGE; 741 } 742 else 743 { 744 int error = uiomove(MSDOSFS_XATTR_VOLUME_ID_NAME, sizeof(MSDOSFS_XATTR_VOLUME_ID_NAME), uio); 745 if (error) 746 return ERANGE; 747 } 748 } 749 } 750 751 return ENOTSUP; 752} 753 754 755int msdosfs_vnop_read(struct vnop_read_args *ap) 756/* { 757 vnode_t a_vp; 758 struct uio *a_uio; 759 int a_ioflag; 760 vfs_context_t a_context; 761 } */ 762{ 763 int error = 0; 764 user_ssize_t orig_resid; 765 vnode_t vp = ap->a_vp; 766 struct uio *uio = ap->a_uio; 767 vfs_context_t context = ap->a_context; 768 struct denode *dep = VTODE(vp); 769 struct msdosfsmount *pmp = dep->de_pmp; 770 771 if (uio_offset(uio) < 0) 772 return EINVAL; 773 774 if (uio_offset(uio) > DOS_FILESIZE_MAX) 775 return 0; 776 777 /* If they didn't ask for any data, then we are done. */ 778 orig_resid = uio_resid(uio); 779 if (orig_resid <= 0) 780 return 0; 781 782 lck_mtx_lock(dep->de_lock); 783 784 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_READ|DBG_FUNC_START, dep, uio_offset(uio), uio_resid(uio), dep->de_FileSize, 0); 785 786 if (vnode_isreg(vp)) { 787 error = cluster_read(vp, uio, (off_t)dep->de_FileSize, ap->a_ioflag); 788 if (error == 0 && (vfs_flags(pmp->pm_mountp) & (MNT_RDONLY | MNT_NOATIME)) == 0) 789 dep->de_flag |= DE_ACCESS; 790 } 791 else 792 { 793 uint32_t blsize; 794 u_int n; 795 uint32_t diff; 796 uint32_t on; 797 daddr64_t lbn; 798 buf_t bp; 799 800 /* The following code is only used for reading directories */ 801 802 do { 803 if (uio_offset(uio) >= dep->de_FileSize) 804 break; 805 lbn = de_cluster(pmp, uio_offset(uio)); 806 /* 807 * If we are operating on a directory file then be sure to 808 * do i/o with the vnode for the filesystem instead of the 809 * vnode for the directory. 810 */ 811 /* convert cluster # to block # */ 812 error = msdosfs_pcbmap(dep, (uint32_t)lbn, 1, &lbn, NULL, &blsize); 813 if (error == E2BIG) { 814 error = EINVAL; 815 break; 816 } else if (error) 817 break; 818 error = (int)buf_meta_bread(pmp->pm_devvp, lbn, blsize, vfs_context_ucred(context), &bp); 819 if (error) { 820 buf_brelse(bp); 821 break; 822 } 823 if (ISSET(ap->a_ioflag, IO_NOCACHE) && buf_fromcache(bp) == 0) 824 buf_markaged(bp); 825 on = uio_offset(uio) & pmp->pm_crbomask; 826 diff = pmp->pm_bpcluster - on; 827 n = diff > (uint32_t)uio_resid(uio) ? (uint32_t)uio_resid(uio) : diff; 828 diff = (uint32_t)(dep->de_FileSize - uio_offset(uio)); 829 if (diff < n) 830 n = diff; 831 diff = blsize - buf_resid(bp); 832 if (diff < n) 833 n = diff; 834 error = uiomove((char *)buf_dataptr(bp) + on, (int) n, uio); 835 buf_brelse(bp); 836 } while (error == 0 && uio_resid(uio) > 0 && n != 0); 837 } 838 839 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_READ|DBG_FUNC_END, error, uio_offset(uio), uio_resid(uio), dep->de_FileSize, 0); 840 lck_mtx_unlock(dep->de_lock); 841 842 return error; 843} 844 845/* 846 * Write data to a file. 847 */ 848int msdosfs_vnop_write(struct vnop_write_args *ap) 849/* { 850 vnode_t a_vp; 851 struct uio *a_uio; 852 int a_ioflag; 853 vfs_context_t a_context; 854 } */ 855{ 856 int error = 0; 857 vnode_t vp = ap->a_vp; 858 struct uio *uio = ap->a_uio; 859 int ioflag = ap->a_ioflag; 860 vfs_context_t context = ap->a_context; 861 struct denode *dep = VTODE(vp); 862 struct msdosfsmount *pmp = dep->de_pmp; 863 off_t zero_off; 864 uint32_t original_size; 865 uint32_t original_clusters; 866 uint32_t filesize; 867 int lflag; 868 user_ssize_t original_resid; 869 user_ssize_t partial_resid; 870 off_t original_offset; 871 off_t offset; 872 873 switch (vnode_vtype(vp)) { 874 case VREG: 875 break; 876 case VDIR: 877 return EISDIR; 878 default: 879 panic("msdosfs_vnop_write: bad file type"); 880 return EINVAL; 881 } 882 883 lck_mtx_lock(dep->de_lock); 884 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_WRITE|DBG_FUNC_START, dep, uio_offset(uio), uio_resid(uio), dep->de_FileSize, 0); 885 886 /* 887 * Remember some values in case the write fails. 888 */ 889 partial_resid = 0; 890 original_resid = uio_resid(uio); 891 original_size = filesize = dep->de_FileSize; 892 original_clusters = de_clcount(pmp, original_size); 893 original_offset = uio_offset(uio); 894 offset = original_offset; 895 896 if (ioflag & IO_APPEND) { 897 uio_setoffset(uio, dep->de_FileSize); 898 offset = dep->de_FileSize; 899 } 900 901 if (offset < 0) 902 { 903 error = EFBIG; 904 goto exit; 905 } 906 907 if (original_resid == 0) 908 { 909 goto exit; 910 } 911 912 if (offset + original_resid > DOS_FILESIZE_MAX) 913 { 914 error = EFBIG; 915 goto exit; 916 } 917 918 /* 919 * If the end of the write will be beyond the current end of file, 920 * then grow the file now to accommodate the bytes we want to write. 921 */ 922 if (offset + original_resid > original_size) { 923 uint32_t clusters_needed, clusters_got; 924 filesize = (uint32_t)(offset + original_resid); 925 clusters_needed = de_clcount(pmp, filesize) - original_clusters; 926 if (clusters_needed) 927 error = msdosfs_extendfile(dep, clusters_needed, &clusters_got); 928 929 if (error == ENOSPC) 930 { 931 /* 932 * We got fewer clusters than we wanted. Set the file size 933 * to the end of the last cluster we now have. 934 */ 935 filesize = de_cn2off(pmp, original_clusters + clusters_got); 936 if (filesize > offset) 937 { 938 /* 939 * We allocated enough to be able to do a partial write. 940 * Limit the I/O amount to not exceed the new end of file. 941 * Keep track of the number of bytes beyond the new end 942 * of file that we're unable to write, so we can add them 943 * back in later. 944 */ 945 uio_setresid(uio, filesize-offset); 946 partial_resid = offset + original_resid - filesize; 947 error = 0; 948 } 949 } 950 if (error) 951 goto errexit; 952 } 953 954 lflag = ioflag; 955 956 /* 957 * If the offset we are starting the write at is beyond the end of 958 * the file, then they've done a seek. Unix filesystems allow 959 * files with holes in them. DOS doesn't, so we must fill the hole 960 * with zeroed blocks. 961 */ 962 if (offset > original_size) { 963 zero_off = original_size; 964 lflag |= IO_HEADZEROFILL; 965 } else 966 zero_off = 0; 967 968 /* Write the data, and any zero filling */ 969 error = cluster_write(vp, uio, (off_t)original_size, (off_t)filesize, 970 (off_t)zero_off, (off_t)0, lflag); 971 972 if (uio_offset(uio) > dep->de_FileSize) { 973 dep->de_FileSize = (uint32_t)uio_offset(uio); 974 ubc_setsize(vp, (off_t)dep->de_FileSize); 975 } 976 977 if (partial_resid) 978 uio_setresid(uio, uio_resid(uio) + partial_resid); 979 980 if (original_resid > uio_resid(uio)) 981 dep->de_flag |= DE_UPDATE; 982 983 /* 984 * If the write failed and they want us to, truncate the file back 985 * to the size it was before the write was attempted. 986 */ 987errexit: 988 if (error) { 989 if (ioflag & IO_UNIT) { 990 /* msdosfs_detrunc internally updates dep->de_FileSize and calls ubc_setsize. */ 991 msdosfs_detrunc(dep, original_size, ioflag, context); 992 uio_setoffset(uio, original_offset); 993 uio_setresid(uio, original_resid); 994 } else { 995 /* msdosfs_detrunc internally updates dep->de_FileSize and calls ubc_setsize. */ 996 msdosfs_detrunc(dep, dep->de_FileSize, ioflag, context); 997 } 998 } else if (ioflag & IO_SYNC) 999 error = msdosfs_deupdat(dep, 1, context); 1000 msdosfs_meta_flush(pmp, (ioflag & IO_SYNC)); 1001 1002exit: 1003 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_WRITE|DBG_FUNC_END, error, uio_offset(uio), uio_resid(uio), dep->de_FileSize, 0); 1004 lck_mtx_unlock(dep->de_lock); 1005 return error; 1006} 1007 1008/* 1009 * Read one or more VM pages from a file on disk. 1010 * 1011 * This routine assumes that the denode's de_lock has already been acquired 1012 * (such as inside of msdosfs_vnop_read). 1013 * 1014 * [It wouldn't make sense to call this routine if the file's size or 1015 * location on disk could be changing. If it could, then the page(s) 1016 * passed in could be invalid before we could reference them.] 1017 */ 1018int msdosfs_vnop_pagein(struct vnop_pagein_args *ap) 1019/* { 1020 vnode_t a_vp; 1021 upl_t a_pl; 1022 vm_offset_t a_pl_offset; 1023 off_t a_f_offset; 1024 size_t a_size; 1025 int a_flags; 1026 vfs_context_t a_context; 1027 } */ 1028{ 1029 vnode_t vp = ap->a_vp; 1030 struct denode *dep = VTODE(vp); 1031 int error; 1032 1033 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_PAGEIN|DBG_FUNC_START, dep, ap->a_f_offset, ap->a_size, dep->de_FileSize, 0); 1034 error = cluster_pagein(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset, 1035 (int)ap->a_size, (off_t)dep->de_FileSize, 1036 ap->a_flags); 1037 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_PAGEIN|DBG_FUNC_END, error, 0, 0, 0, 0); 1038 1039 return error; 1040} 1041 1042/* 1043 * Write one or more VM pages to a file on disk. 1044 * 1045 * This routine assumes that the denode's de_lock has already been acquired 1046 * (such as inside of msdosfs_vnop_write). 1047 * 1048 * [It wouldn't make sense to call this routine if the file's size or 1049 * location on disk could be changing. If it could, then the page(s) 1050 * passed in could be invalid before we could reference them.] 1051 */ 1052int msdosfs_vnop_pageout(struct vnop_pageout_args *ap) 1053/* { 1054 vnode_t a_vp; 1055 upl_t a_pl; 1056 vm_offset_t a_pl_offset; 1057 off_t a_f_offset; 1058 size_t a_size; 1059 int a_flags; 1060 vfs_context_t a_context; 1061 } */ 1062{ 1063 vnode_t vp = ap->a_vp; 1064 struct denode *dep = VTODE(vp); 1065 int error; 1066 1067 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_PAGEOUT|DBG_FUNC_START, dep, ap->a_f_offset, ap->a_size, dep->de_FileSize, 0); 1068 error = cluster_pageout(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset, 1069 (int)ap->a_size, (off_t)dep->de_FileSize, 1070 ap->a_flags); 1071 if (!error) 1072 dep->de_flag |= DE_UPDATE; 1073 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_PAGEOUT|DBG_FUNC_END, error, 0, 0, 0, 0); 1074 1075 return error; 1076} 1077 1078/* 1079 * Assumes the denode's de_lock is already acquired. 1080 */ 1081int msdosfs_fsync_internal(vnode_t vp, int sync, int do_dirs, vfs_context_t context) 1082{ 1083 int error; 1084 struct denode *dep = VTODE(vp); 1085 1086 /* 1087 * First of all, write out any clusters. 1088 */ 1089 cluster_push(vp, sync ? IO_SYNC : 0); 1090 1091 /* 1092 * Flush all dirty buffers associated with a vnode. 1093 */ 1094 buf_flushdirtyblks(vp, sync, 0, "msdosfs_fsync_internal"); 1095 1096 if (do_dirs && (dep->de_Attributes & ATTR_DIRECTORY)) 1097 (void) msdosfs_dir_flush(dep, sync); 1098 1099 error = msdosfs_deupdat(dep, sync, context); 1100 1101 return error; 1102} 1103 1104/* 1105 * Flush the blocks of a file to disk. 1106 * 1107 * This function is worthless for vnodes that represent directories. Maybe we 1108 * could just do a sync if they try an fsync on a directory file. 1109 * 1110 * NOTE: This gets called for every vnode, with a_waitfor=MNT_WAIT, during 1111 * an unmount (via vflush and vclean). Possible optimization: keep track 1112 * of whether the file has dirty content, dirty FAT blocks, or dirty 1113 * directory blocks; skip the msdosfs_fsync_internal and msdosfs_meta_flush 1114 * if nothing is dirty. 1115 */ 1116int msdosfs_vnop_fsync(struct vnop_fsync_args *ap) 1117/* { 1118 vnode_t a_vp; 1119 int a_waitfor; 1120 vfs_context_t a_context; 1121 } */ 1122{ 1123 int error; 1124 vnode_t vp = ap->a_vp; 1125 struct denode *dep = VTODE(vp); 1126 1127 /* 1128 * Skip everything if there was no denode. This can happen 1129 * If the vnode was temporarily created in msdosfs_check_link. 1130 */ 1131 if (dep == NULL) 1132 return 0; 1133 1134 if (dep->de_pmp->pm_flags & MSDOSFSMNT_RONLY) { 1135 /* For read-only mounts, there's nothing to do */ 1136 return 0; 1137 } 1138 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_FSYNC|DBG_FUNC_START, dep, 0, 0, 0, 0); 1139 1140 lck_mtx_lock(dep->de_lock); 1141 1142 /* sync dirty buffers associated with this vnode */ 1143 error = msdosfs_fsync_internal(vp, (ap->a_waitfor == MNT_WAIT), TRUE, ap->a_context); 1144 1145 /* 1146 * Flush primary copy of FAT and all directory blocks delayed or asynchronously. 1147 * 1148 * Ideally, we would do this synchronously if MNT_WAIT was given. But that 1149 * leads to poor performance because every unlink_rmdir causes the vnode to 1150 * be recycled, and VFS does a VNOP_FSYNC(..., MNT_WAIT, ...), causing us 1151 * to flush ALL dirty metadata synchronously. Ouch. 1152 * 1153 * Note that HFS with journal does not write the dirty metadata in this 1154 * case, either. And there is always fcntl(F_FULLFSYNC) if the user really 1155 * wants to be sure the data has made it to the media. 1156 */ 1157 msdosfs_meta_flush(dep->de_pmp, FALSE); 1158 1159 lck_mtx_unlock(dep->de_lock); 1160 1161 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_FSYNC|DBG_FUNC_END, error, 0, 0, 0, 0); 1162 1163 return error; 1164} 1165 1166/* 1167 * Remove (unlink) a file. 1168 */ 1169int msdosfs_vnop_remove(struct vnop_remove_args *ap) 1170/* { 1171 vnode_t a_dvp; 1172 vnode_t a_vp; 1173 struct componentname *a_cnp; 1174 int a_flags; 1175 vfs_context_t a_context; 1176 } */ 1177{ 1178 vnode_t vp = ap->a_vp; 1179 vnode_t dvp = ap->a_dvp; 1180 struct denode *dep = VTODE(vp); 1181 struct denode *ddep = VTODE(dvp); 1182 int error; 1183 uint32_t cluster, offset; 1184 1185 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_REMOVE|DBG_FUNC_START, ddep, dep, 0, 0, 0); 1186 1187 msdosfs_lock_two(ddep, dep); 1188 1189 /* 1190 * Make sure the parent directory hasn't been deleted. 1191 */ 1192 if (ddep->de_refcnt <= 0) 1193 { 1194 cache_purge(dvp); 1195 error = ENOENT; 1196 goto exit; 1197 } 1198 1199 /* 1200 * Make sure the child denode hasn't been deleted. 1201 */ 1202 if (dep->de_refcnt <= 0) 1203 { 1204 cache_purge(vp); 1205 error = ENOENT; 1206 goto exit; 1207 } 1208 1209 /* 1210 * Make sure the child still has the same name. 1211 */ 1212 error = msdosfs_lookup_name(ddep, ap->a_cnp, &cluster, &offset, NULL, NULL, NULL, NULL, ap->a_context); 1213 if (error || cluster != dep->de_dirclust || offset != dep->de_diroffset) 1214 { 1215 cache_purge(vp); 1216 error = ENOENT; 1217 goto exit; 1218 } 1219 1220 /* Make sure the file isn't read-only */ 1221 /* Note that this is an additional imposition over the 1222 normal deletability rules... */ 1223 if (dep->de_Attributes & ATTR_READONLY) 1224 { 1225 error = EPERM; 1226 goto exit; 1227 } 1228 1229 /* Don't allow deletes of busy files (option used by Carbon) */ 1230 if ((ap->a_flags & VNODE_REMOVE_NODELETEBUSY) && vnode_isinuse(vp, 0)) 1231 { 1232 error = EBUSY; 1233 goto exit; 1234 } 1235 1236 cache_purge(vp); 1237 dep->de_refcnt--; 1238 if (DEBUG && dep->de_refcnt < 0) 1239 panic("msdosfs_vnop_remove: de_refcnt went negative"); 1240 error = msdosfs_removede(ddep, dep->de_diroffset, ap->a_context); 1241 if (DEBUG && error) panic("msdosfs_vnop_remove: msdosfs_removede returned %d\n", error); 1242 msdosfs_meta_flush(ddep->de_pmp, FALSE); 1243 1244exit: 1245 lck_mtx_unlock(ddep->de_lock); 1246 lck_mtx_unlock(dep->de_lock); 1247 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_REMOVE|DBG_FUNC_END, error, 0, 0, 0, 0); 1248 return error; 1249} 1250 1251/* 1252 * Renames on files require moving the denode to a new hash queue since the 1253 * location of the directory entry is used to compute the hash. 1254 * 1255 * What follows is the basic algorithm: 1256 * 1257 * if (file move) { 1258 * if (dest file exists) { 1259 * remove dest file 1260 * } 1261 * if (dest and src in same directory) { 1262 * rewrite name in existing directory slot 1263 * } else { 1264 * write new entry in dest directory 1265 * update offset and dirclust in denode 1266 * move denode to new hash chain 1267 * clear old directory entry 1268 * } 1269 * } else { 1270 * directory move 1271 * if (dest directory exists) { 1272 * if (dest is not empty) { 1273 * return ENOTEMPTY 1274 * } 1275 * remove dest directory 1276 * } 1277 * if (dest and src in same directory) { 1278 * rewrite name in existing entry 1279 * } else { 1280 * be sure dest is not a child of src directory 1281 * write entry in dest directory 1282 * update "." and ".." in moved directory 1283 * clear old directory entry for moved directory 1284 * } 1285 * } 1286 * 1287 * Locking: 1288 * On entry, VFS has locked all of the vnodes in an 1289 * arbitrary, but consistent, order. For example, 1290 * it may lock the parent with the smallest vnode pointer, 1291 * then its child, then the parent with the larger vnode 1292 * pointer, then its child. 1293 * 1294 * However, VFS doesn't acquire the locks until after the 1295 * lookups on both source and destination have completed. 1296 * It is possible that the source or destination have been 1297 * deleted or renamed between the lookup and locking the vnode. 1298 * So we must be paranoid and make sure things haven't changed 1299 * since VFS locked the vnodes. 1300 * 1301 * Traditionally, one of the hardest parts about rename's 1302 * locking is when the source is a directory, and we 1303 * have to verify that the destination parent isn't a 1304 * descendant of the source. We need to walk up the 1305 * directory hierarchy from the destination parent up to 1306 * the root. If any of those directories is the source, 1307 * the operation is invalid. But walking up the hierarchy 1308 * violates the top-down lock order; to avoid deadlock, we 1309 * must not have two nodes locked at the same time. 1310 * 1311 * But there is a solution: a mutex on rename operations that 1312 * reshape the hierarchy (i.e. the source and destination parents 1313 * are different). During the walk up the hierarchy, we must 1314 * prevent any change to the hierarchy that could cause the 1315 * destination parent to become or stop being an ancestor of 1316 * the source. Any operation on a file can't affect the 1317 * ancestry of directories. Directory create operations can't 1318 * affect the ancestry of pre-existing directories. 1319 * Directory delete operations outside the ancestry path 1320 * don't matter, and deletes within the ancestry path will 1321 * fail as long as the directories remain locked (the delete 1322 * will fail because the directory is locked, or not empty, or 1323 * both). The only operation that can affect the ancestry is 1324 * other rename operations on the same volume (and even then, 1325 * only if the source parent is not the destination parent). 1326 * 1327 * It is sufficient if the rename mutex is taken only 1328 * when the source parent is not the destination parent. 1329 */ 1330int msdosfs_vnop_rename(struct vnop_rename_args *ap) 1331/* { 1332 vnode_t a_fdvp; 1333 vnode_t a_fvp; 1334 struct componentname *a_fcnp; 1335 vnode_t a_tdvp; 1336 vnode_t a_tvp; 1337 struct componentname *a_tcnp; 1338 vfs_context_t a_context; 1339 } */ 1340{ 1341 vnode_t tdvp = ap->a_tdvp; 1342 vnode_t fvp = ap->a_fvp; 1343 vnode_t fdvp = ap->a_fdvp; 1344 vnode_t tvp = ap->a_tvp; 1345 struct componentname *tcnp = ap->a_tcnp; 1346 vfs_context_t context = ap->a_context; 1347 u_char toname[SHORT_NAME_LEN], oldname[SHORT_NAME_LEN]; 1348 uint32_t to_diroffset; 1349 uint32_t to_long_count; 1350 int needs_generation; 1351 u_int32_t from_offset; 1352 u_int8_t new_deLowerCase; /* deLowerCase corresponding to toname */ 1353 int doingdirectory = 0, newparent = 0; 1354 int change_case; 1355 int error; 1356 uint32_t cn; 1357 daddr64_t bn = 0; 1358 struct denode *fddep; /* from file's parent directory */ 1359 struct denode *fdep; /* from file or directory */ 1360 struct denode *tddep; /* to file's parent directory */ 1361 struct denode *tdep; /* to file or directory */ 1362 struct msdosfsmount *pmp; 1363 struct buf *bp; 1364 uint32_t cluster, offset; 1365 1366 fddep = VTODE(fdvp); 1367 fdep = VTODE(fvp); 1368 tddep = VTODE(tdvp); 1369 tdep = tvp ? VTODE(tvp) : NULL; 1370 1371 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_RENAME|DBG_FUNC_START, fddep, fdep, tddep, tdep, 0); 1372 1373 msdosfs_lock_four(fddep, fdep, tddep, tdep); 1374 1375 pmp = fddep->de_pmp; 1376 1377 /* 1378 * VNOP_RENAME is different from other VNOPs to non-thread-safe file 1379 * systems. Because two paths are involved, VFS does not lock the 1380 * parent vnodes before the VNOP_LOOKUPs. It locks all four vnodes 1381 * after all of the lookups are done (and all vnodes referenced). 1382 * 1383 * This means that the source and destination objects may no longer 1384 * exist in the namespace, and that the children may no longer be 1385 * children of the given parents (the child may have been renamed 1386 * by another thread). And the children may not have the names you 1387 * find in the component name. 1388 * 1389 * I think the best we can do is to try to verify that the vnodes 1390 * still have the indicated relationship. Plus, we need to check that 1391 * the desintation name does not exist in the desintation directory. 1392 * (A wrinkle here is that a case variant of the desintation name may 1393 * exist, and it may be the source! 1394 */ 1395 1396 /* 1397 * Make sure the from parent directory hasn't been deleted. 1398 */ 1399 if (fddep->de_refcnt <= 0) 1400 { 1401 cache_purge(fdvp); 1402 error = ENOENT; 1403 goto exit; 1404 } 1405 1406 /* 1407 * Make sure the from child denode hasn't been deleted. 1408 */ 1409 if (fdep->de_refcnt <= 0) 1410 { 1411 cache_purge(fvp); 1412 error = ENOENT; 1413 goto exit; 1414 } 1415 1416 /* 1417 * Make sure the from child still has the same name. 1418 */ 1419 error = msdosfs_lookup_name(fddep, ap->a_fcnp, &cluster, &offset, NULL, NULL, NULL, NULL, context); 1420 if (error || cluster != fdep->de_dirclust || offset != fdep->de_diroffset) 1421 { 1422 cache_purge(fvp); 1423 error = ENOENT; 1424 goto exit; 1425 } 1426 1427 /* 1428 * Make sure the to parent directory hasn't been deleted. 1429 */ 1430 if (tddep->de_refcnt <= 0) 1431 { 1432 cache_purge(tdvp); 1433 error = ENOENT; 1434 goto exit; 1435 } 1436 1437 /* 1438 * If there was a to child, make sure it hasn't been deleted. 1439 */ 1440 if (tdep && tdep->de_refcnt <= 0) 1441 { 1442 cache_purge(tvp); 1443 error = ENOENT; 1444 goto exit; 1445 } 1446 1447 /* 1448 * Look for the destination name in the destination directory. If it exists, 1449 * it had better be tdep; otherwise, tdep had better be NULL. 1450 */ 1451 error = msdosfs_lookup_name(tddep, tcnp, &cluster, &offset, NULL, NULL, NULL, NULL, context); 1452 if (tdep) 1453 { 1454 /* We think the destination exists... */ 1455 if (error || cluster != tdep->de_dirclust || offset != tdep->de_diroffset) 1456 { 1457 error = ERESTART; 1458 goto exit; 1459 } 1460 } 1461 else 1462 { 1463 /* We think the destination does not exist... */ 1464 if (error != ENOENT) 1465 { 1466 error = EEXIST; 1467 goto exit; 1468 } 1469 } 1470 1471 /* 1472 * If source and dest are the same, then it is a rename 1473 * that may be changing the upper/lower case of the name. 1474 */ 1475 change_case = 0; 1476 if (tvp == fvp) { 1477 /* Pretend the destination doesn't exist. */ 1478 tvp = NULL; 1479 1480 /* Remember we're changing case, so we can skip msdosfs_uniqdosname() */ 1481 change_case = 1; 1482 } 1483 1484 /* 1485 * If there is a destination, and it's a file, make sure it isn't 1486 * read-only. 1487 */ 1488 if (tdep && (tdep->de_Attributes & (ATTR_READONLY | ATTR_DIRECTORY)) == ATTR_READONLY) 1489 { 1490 error = EPERM; 1491 goto exit; 1492 } 1493 1494 /* If the source is a file, make sure it isn't read-only. */ 1495 if ((fdep->de_Attributes & (ATTR_READONLY | ATTR_DIRECTORY)) == ATTR_READONLY) 1496 { 1497 error = EPERM; 1498 goto exit; 1499 } 1500 1501 /* 1502 * Figure out where to put the new directory entry. 1503 */ 1504 error = msdosfs_findslots(tddep, tcnp, toname, &needs_generation, &new_deLowerCase, &to_diroffset, &to_long_count, context); 1505 if (error) 1506 goto exit; 1507 1508 /* 1509 * If this is the root directory and there is no space left we 1510 * can't do anything. This is because the root directory can not 1511 * change size. (FAT12 and FAT16 only) 1512 * 1513 * On FAT32, we can grow the root directory, and de_StartCluster 1514 * will be the actual cluster number of the root directory. 1515 */ 1516 if (tddep->de_StartCluster == MSDOSFSROOT && to_diroffset >= tddep->de_FileSize) 1517 { 1518 printf("msdosfs_vnop_rename: Cannot grow the root directory on FAT12 or FAT16; returning ENOSPC.\n"); 1519 error = ENOSPC; 1520 goto exit; 1521 } 1522 1523 if (fdep->de_Attributes & ATTR_DIRECTORY) 1524 doingdirectory = 1; 1525 1526 /* 1527 * If ".." must be changed (ie the directory gets a new 1528 * parent) then the source directory must not be in the 1529 * directory heirarchy above the target, as this would 1530 * orphan everything below the source directory. Also 1531 * the user must have write permission in the source so 1532 * as to be able to change "..". 1533 */ 1534 if (fddep->de_StartCluster != tddep->de_StartCluster) 1535 newparent = 1; 1536 if (doingdirectory && newparent) { 1537 lck_mtx_lock(pmp->pm_rename_lock); 1538 error = msdosfs_doscheckpath(fdep, tddep, context); 1539 if (error) goto exit; 1540 } 1541 1542 /* Remember the offset of fdep within fddep. */ 1543 from_offset = fdep->de_diroffset; 1544 1545 if (tvp != NULL && tdep != NULL) { 1546 uint32_t dest_offset; /* Of the pre-existing entry being removed */ 1547 1548 /* 1549 * Target must be empty if a directory and have no links 1550 * to it. Also, ensure source and target are compatible 1551 * (both directories, or both not directories). 1552 */ 1553 if (tdep->de_Attributes & ATTR_DIRECTORY) { 1554 if (!msdosfs_dosdirempty(tdep, context)) { 1555 error = ENOTEMPTY; 1556 goto exit; 1557 } 1558 if (!doingdirectory) { 1559 error = ENOTDIR; 1560 goto exit; 1561 } 1562 } else { 1563 if (doingdirectory) { 1564 error = EISDIR; 1565 goto exit; 1566 } 1567 } 1568 dest_offset = tdep->de_diroffset; 1569 cache_purge(tvp); /* Purge tvp before we delete it on disk */ 1570 tdep->de_refcnt--; 1571 if (DEBUG && tdep->de_refcnt < 0) 1572 panic("msdosfs_vnop_rename: de_refcnt went negative"); 1573 error = msdosfs_removede(tddep, dest_offset, context); 1574 if (error) 1575 { 1576 if (DEBUG) panic("msdosfs_vnop_rename: msdosfs_removede (destination) returned %d\n", error); 1577 goto flush_exit; 1578 } 1579 } 1580 1581 /* 1582 * Figure out the new short name (toname). If we're just changing 1583 * case, then the short name stays the same. Otherwise, we have 1584 * to convert the long name to a unique short name. 1585 */ 1586 if (change_case) 1587 { 1588 bcopy(fdep->de_Name, toname, SHORT_NAME_LEN); 1589 } 1590 else 1591 { 1592 error = msdosfs_uniqdosname(tddep, toname, needs_generation ? to_diroffset - to_long_count * sizeof(struct dosdirentry) : 1, context); 1593 /*� What if we get an error and we already deleted the target? */ 1594 if (error) 1595 { 1596 if (DEBUG) panic("msdosfs_vnop_rename: msdosfs_uniqdosname returned %d\n", error); 1597 goto flush_exit; 1598 } 1599 } 1600 1601 /* 1602 * First write a new entry in the destination 1603 * directory and mark the entry in the source directory 1604 * as deleted. Then move the denode to the correct hash 1605 * chain for its new location in the filesystem. And, if 1606 * we moved a directory, then update its .. entry to point 1607 * to the new parent directory. Set the name in the denode 1608 * to the new short name. 1609 * 1610 * The name in the denode is updated for files. For 1611 * directories, the denode points at the "." entry in 1612 * the directory, so temporarily change the name in 1613 * the denode, and restore it; otherwise the "." entry 1614 * may be overwritten. 1615 */ 1616 cache_purge(fvp); 1617 bcopy(fdep->de_Name, oldname, SHORT_NAME_LEN); 1618 bcopy(toname, fdep->de_Name, SHORT_NAME_LEN); /* update denode */ 1619 fdep->de_LowerCase = new_deLowerCase; 1620 1621 /* 1622 * If the new name starts with ".", make it invisible on Windows. 1623 * Otherwise, make it visible. 1624 */ 1625 if (tcnp->cn_nameptr[0] == '.') 1626 fdep->de_Attributes |= ATTR_HIDDEN; 1627 else 1628 fdep->de_Attributes &= ~ATTR_HIDDEN; 1629 1630 error = msdosfs_createde(fdep, tddep, NULL, tcnp, to_diroffset, to_long_count, context); 1631 if (error) 1632 { 1633 if (DEBUG) panic("msdosfs_vnop_rename: msdosfs_createde returned %d\n", error); 1634 bcopy(oldname, fdep->de_Name, SHORT_NAME_LEN); 1635 /*� What if we already deleted the target? */ 1636 /* And shouldn't we also restore fdep->de_LowerCase? */ 1637 goto flush_exit; 1638 } 1639 else 1640 { 1641 cache_purge_negatives(tdvp); 1642 } 1643 1644 fdep->de_parent = tddep; 1645 1646 error = msdosfs_removede(fddep, from_offset, context); 1647 if (error) { 1648 if (DEBUG) panic("msdosfs_vnop_rename: msdosfs_removede (source) returned %d\n", error); 1649 goto flush_exit; 1650 } 1651 1652 /* 1653 * Fix fdep's de_dirclust and de_diroffset to reflect 1654 * its new location in the destination directory. 1655 */ 1656 error = msdosfs_pcbmap(tddep, de_cluster(pmp, to_diroffset), 1, 1657 NULL, &fdep->de_dirclust, NULL); 1658 if (error) { 1659 if (DEBUG) panic("msdosfs_vnop_rename: msdosfs_pcbmap returned %d\n", error); 1660 goto flush_exit; 1661 } 1662 fdep->de_diroffset = to_diroffset; 1663 1664 /* 1665 * fdep's identity (name and parent) have changed, so we must msdosfs_hash_reinsert 1666 * it in our denode hash. 1667 */ 1668 msdosfs_hash_reinsert(fdep); 1669 1670 /* 1671 * If we moved a directory to a new parent directory, then we must 1672 * fixup the ".." entry in the moved directory. 1673 */ 1674 if (doingdirectory && newparent) { 1675 struct dosdirentry *dotdotp; 1676 1677 /* Read in the first cluster of the directory and point to ".." entry */ 1678 cn = fdep->de_StartCluster; 1679 bn = cntobn(pmp, cn); 1680 error = (int)buf_meta_bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, vfs_context_ucred(context), &bp); 1681 if (error) { 1682 if (DEBUG) panic("msdosfs_vnop_rename: buf_meta_bread returned %d\n", error); 1683 buf_brelse(bp); 1684 goto flush_exit; 1685 } 1686 dotdotp = (struct dosdirentry *)buf_dataptr(bp) + 1; 1687 1688 /* Update the starting cluster of ".." */ 1689 putuint16(dotdotp->deStartCluster, tddep->de_StartCluster); 1690 if (FAT32(pmp)) 1691 putuint16(dotdotp->deHighClust, tddep->de_StartCluster >> 16); 1692 1693 error = (int)buf_bdwrite(bp); 1694 if (error) { 1695 if (DEBUG) panic("msdosfs_vnop_rename: buf_bdwrite returned %d\n", error); 1696 goto flush_exit; 1697 } 1698 } 1699 1700flush_exit: 1701 msdosfs_meta_flush(pmp, FALSE); 1702exit: 1703 1704 if (doingdirectory && newparent) 1705 lck_mtx_unlock(pmp->pm_rename_lock); 1706 msdosfs_unlock_four(fddep, fdep, tddep, tdep); 1707 1708 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_RENAME|DBG_FUNC_END, error, 0, 0, 0, 0); 1709 1710 return error; 1711 1712} 1713 1714static struct { 1715 struct dosdirentry dot; 1716 struct dosdirentry dotdot; 1717} dosdirtemplate = { 1718 { ". ", " ", /* the . entry */ 1719 ATTR_DIRECTORY, /* file attribute */ 1720 0, /* reserved */ 1721 0, { 0, 0 }, { 0, 0 }, /* create time & date */ 1722 { 0, 0 }, /* access date */ 1723 { 0, 0 }, /* high bits of start cluster */ 1724 { 210, 4 }, { 210, 4 }, /* modify time & date */ 1725 { 0, 0 }, /* startcluster */ 1726 { 0, 0, 0, 0 } /* filesize */ 1727 }, 1728 { ".. ", " ", /* the .. entry */ 1729 ATTR_DIRECTORY, /* file attribute */ 1730 0, /* reserved */ 1731 0, { 0, 0 }, { 0, 0 }, /* create time & date */ 1732 { 0, 0 }, /* access date */ 1733 { 0, 0 }, /* high bits of start cluster */ 1734 { 210, 4 }, { 210, 4 }, /* modify time & date */ 1735 { 0, 0 }, /* startcluster */ 1736 { 0, 0, 0, 0 } /* filesize */ 1737 } 1738}; 1739 1740int msdosfs_vnop_mkdir(struct vnop_mkdir_args *ap) 1741/* { 1742 vnode_t a_dvp; 1743 vnode_t *a_vpp; 1744 struct componentname *a_cnp; 1745 struct vattr *a_vap; 1746 vfs_context_t a_context; 1747 } */ 1748{ 1749 vnode_t dvp = ap->a_dvp; 1750 struct denode *pdep = VTODE(dvp); 1751 struct componentname *cnp = ap->a_cnp; 1752 vfs_context_t context = ap->a_context; 1753 struct denode *dep; 1754 struct dosdirentry *denp; 1755 struct msdosfsmount *pmp = pdep->de_pmp; 1756 struct buf *bp; 1757 uint32_t newcluster, pcl; 1758 daddr64_t bn; 1759 int error; 1760 struct denode ndirent; 1761 struct timespec ts; 1762 char *bdata; 1763 uint32_t offset; 1764 uint32_t long_count; 1765 int needs_generation; 1766 1767 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_MKDIR|DBG_FUNC_START, pdep, 0, 0, 0, 0); 1768 1769 lck_mtx_lock(pdep->de_lock); 1770 1771 /* 1772 * Make sure the parent directory hasn't been deleted. 1773 */ 1774 if (pdep->de_refcnt <= 0) 1775 { 1776 cache_purge(dvp); 1777 error = ENOENT; 1778 goto exit; 1779 } 1780 1781 /* 1782 * Make sure the name does not exist in the parent directory. (It didn't 1783 * exist during VNOP_LOOKUP, but another thread may have created the name 1784 * before we got the lock on the parent.) 1785 */ 1786 error = msdosfs_lookup_name(pdep, cnp, NULL, NULL, NULL, NULL, NULL, NULL, context); 1787 if (error != ENOENT) 1788 { 1789 error = EEXIST; 1790 goto exit; 1791 } 1792 1793 /* 1794 * Find space in the directory to place the new name. 1795 */ 1796 bzero(&ndirent, sizeof(ndirent)); 1797 error = msdosfs_findslots(pdep, cnp, ndirent.de_Name, &needs_generation, &ndirent.de_LowerCase, &offset, &long_count, context); 1798 if (error) 1799 goto exit; 1800 1801 /* 1802 * If this is the root directory and there is no space left we 1803 * can't do anything. This is because the root directory can not 1804 * change size. (FAT12 and FAT16 only) 1805 * 1806 * On FAT32, we can grow the root directory, and de_StartCluster 1807 * will be the actual cluster number of the root directory. 1808 */ 1809 if (pdep->de_StartCluster == MSDOSFSROOT && offset >= pdep->de_FileSize) 1810 { 1811 printf("msdosfs_vnop_mkdir: Cannot grow the root directory on FAT12 or FAT16; returning ENOSPC.\n"); 1812 error = ENOSPC; 1813 goto exit; 1814 } 1815 1816 /* 1817 * Allocate a cluster to hold the about to be created directory. 1818 */ 1819 error = msdosfs_clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL); 1820 if (error) 1821 goto exit; 1822 1823 ndirent.de_pmp = pmp; 1824 ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; 1825 getnanotime(&ts); 1826 DETIMES(&ndirent, &ts, &ts, &ts); 1827 1828 /* 1829 * Now fill the cluster with the "." and ".." entries. And write 1830 * the cluster to disk. This way it is there for the parent 1831 * directory to be pointing at if there were a crash. 1832 */ 1833 bn = cntobn(pmp, newcluster); 1834 bp = buf_getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0, BLK_META); 1835 bdata = (char *)buf_dataptr(bp); 1836 1837 bzero(bdata, pmp->pm_bpcluster); 1838 bcopy(&dosdirtemplate, bdata, sizeof dosdirtemplate); 1839 denp = (struct dosdirentry *)bdata; 1840 putuint16(denp[0].deStartCluster, newcluster); 1841 putuint16(denp[0].deCDate, ndirent.de_CDate); 1842 putuint16(denp[0].deCTime, ndirent.de_CTime); 1843 denp[0].deCHundredth = ndirent.de_CHun; 1844 putuint16(denp[0].deADate, ndirent.de_ADate); 1845 putuint16(denp[0].deMDate, ndirent.de_MDate); 1846 putuint16(denp[0].deMTime, ndirent.de_MTime); 1847 pcl = pdep->de_StartCluster; 1848 if (FAT32(pmp) && pcl == pmp->pm_rootdirblk) 1849 pcl = 0; 1850 putuint16(denp[1].deStartCluster, pcl); 1851 putuint16(denp[1].deCDate, ndirent.de_CDate); 1852 putuint16(denp[1].deCTime, ndirent.de_CTime); 1853 denp[1].deCHundredth = ndirent.de_CHun; 1854 putuint16(denp[1].deADate, ndirent.de_ADate); 1855 putuint16(denp[1].deMDate, ndirent.de_MDate); 1856 putuint16(denp[1].deMTime, ndirent.de_MTime); 1857 if (FAT32(pmp)) { 1858 putuint16(denp[0].deHighClust, newcluster >> 16); 1859 putuint16(denp[1].deHighClust, pdep->de_StartCluster >> 16); 1860 } 1861 1862 error = (int)buf_bdwrite(bp); 1863 if (error) 1864 goto exit; 1865 1866 /* 1867 * Now build up a directory entry pointing to the newly allocated 1868 * cluster. This will be written to an empty slot in the parent 1869 * directory. 1870 */ 1871 error = msdosfs_uniqdosname(pdep, ndirent.de_Name, needs_generation ? offset - long_count * sizeof(struct dosdirentry) : 1, context); 1872 if (error) 1873 goto exit; 1874 1875 ndirent.de_Attributes = ATTR_DIRECTORY; 1876 ndirent.de_StartCluster = newcluster; 1877 ndirent.de_FileSize = 0; 1878 ndirent.de_dev = pdep->de_dev; 1879 ndirent.de_devvp = pdep->de_devvp; 1880 1881 /* 1882 * If the file name starts with ".", make it invisible on Windows. 1883 */ 1884 if (cnp->cn_nameptr[0] == '.') 1885 ndirent.de_Attributes |= ATTR_HIDDEN; 1886 1887 error = msdosfs_createde(&ndirent, pdep, &dep, cnp, offset, long_count, context); 1888 if (error) 1889 { 1890 if (DEBUG) 1891 panic("msodsfs_mkdir: msdosfs_createde failed\n"); 1892 msdosfs_freeclusterchain(pmp, newcluster); 1893 } 1894 else 1895 { 1896 *ap->a_vpp = DETOV(dep); 1897 cache_purge_negatives(dvp); 1898 } 1899 1900exit: 1901 msdosfs_meta_flush(pmp, FALSE); 1902 lck_mtx_unlock(pdep->de_lock); 1903 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_MKDIR|DBG_FUNC_END, error, 0, 0, 0, 0); 1904 return error; 1905} 1906 1907/* 1908 * Remove a directory. 1909 * 1910 * On entry, vp has been suspended, so there are no pending 1911 * create or lookup operations happening using it as the 1912 * parent directory. 1913 * 1914 * VFS has already checked that dvp != vp. 1915 * 1916 */ 1917int msdosfs_vnop_rmdir(struct vnop_rmdir_args *ap) 1918/* { 1919 vnode_t a_dvp; 1920 vnode_t a_vp; 1921 struct componentname *a_cnp; 1922 vfs_context_t a_context; 1923 } */ 1924{ 1925 vnode_t vp = ap->a_vp; 1926 vnode_t dvp = ap->a_dvp; 1927 vfs_context_t context = ap->a_context; 1928 struct denode *ip, *dp; 1929 int error; 1930 uint32_t cluster, offset; 1931 1932 ip = VTODE(vp); 1933 dp = VTODE(dvp); 1934 1935 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_RMDIR|DBG_FUNC_START, dp, ip, 0, 0, 0); 1936 msdosfs_lock_two(dp, ip); 1937 1938 /* 1939 * Make sure the parent directory hasn't been deleted. 1940 */ 1941 if (dp->de_refcnt <= 0) 1942 { 1943 cache_purge(dvp); 1944 error = ENOENT; 1945 goto exit; 1946 } 1947 1948 /* 1949 * Make sure the child denode hasn't been deleted. 1950 */ 1951 if (ip->de_refcnt <= 0) 1952 { 1953 cache_purge(vp); 1954 error = ENOENT; 1955 goto exit; 1956 } 1957 1958 /* 1959 * Make sure the child still has the same name. 1960 */ 1961 error = msdosfs_lookup_name(dp, ap->a_cnp, &cluster, &offset, NULL, NULL, NULL, NULL, context); 1962 if (error || cluster != ip->de_dirclust || offset != ip->de_diroffset) 1963 { 1964 cache_purge(vp); 1965 error = ENOENT; 1966 goto exit; 1967 } 1968 1969 /* 1970 * No rmdir "." please. 1971 * 1972 * VFS already checks this in rmdir(), so do we 1973 * need to check again? (It would only be useful if 1974 * some other entity called our VNOP directly.) 1975 */ 1976 if (dp == ip) { 1977 error = EINVAL; 1978 goto exit; 1979 } 1980 1981 /* 1982 * Verify the directory is empty (and valid). 1983 * (Rmdir ".." won't be valid since 1984 * ".." will contain a reference to 1985 * the current directory and thus be 1986 * non-empty.) 1987 */ 1988 if (!msdosfs_dosdirempty(ip, context)) { 1989 error = ENOTEMPTY; 1990 goto exit; 1991 } 1992 1993 /* 1994 * Delete the entry from the directory. For dos filesystems this 1995 * gets rid of the directory entry on disk. The in memory copy 1996 * still exists but the de_refcnt is <= 0. This prevents it from 1997 * being found by msdosfs_deget(). When the vput() on dep is done we give 1998 * up access and eventually msdosfs_vnop_reclaim() will be called which 1999 * will remove it from the denode cache. 2000 */ 2001 ip->de_refcnt--; 2002 if (DEBUG && ip->de_refcnt < 0) 2003 panic("msdosfs_vnop_rmdir: de_refcnt went negative"); 2004 error = msdosfs_removede(dp, ip->de_diroffset, context); 2005 if (error) 2006 { 2007 if (DEBUG) panic("msdosfs_vnop_rmdir: msdosfs_removede returned %d\n", error); 2008 goto flush_exit; 2009 } 2010 2011 /* 2012 * Invalidate the directory's contents. If directory I/O went through 2013 * the directory's vnode, this wouldn't be needed; the invalidation 2014 * done in msdosfs_detrunc would be sufficient. 2015 */ 2016 error = msdosfs_dir_invalidate(ip); 2017 if (error) 2018 { 2019 if (DEBUG) panic("msdosfs_vnop_rmdir: msdosfs_dir_invalidate returned %d\n", error); 2020 goto flush_exit; 2021 } 2022 2023 /* 2024 * Truncate the directory that is being deleted. 2025 * msdosfs_detrunc internally updates dep->de_FileSize and calls ubc_setsize. 2026 */ 2027 error = msdosfs_detrunc(ip, 0, 0, context); 2028 if (DEBUG && error) panic("msdosfs_vnop_rmdir: msdosfs_detrunc returned %d\n", error); 2029 cache_purge(vp); 2030 2031flush_exit: 2032 msdosfs_meta_flush(dp->de_pmp, FALSE); 2033exit: 2034 lck_mtx_unlock(dp->de_lock); 2035 lck_mtx_unlock(ip->de_lock); 2036 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_RMDIR|DBG_FUNC_END, error, 0, 0, 0, 0); 2037 return error; 2038} 2039 2040 2041/* 2042 * Set the d_namlen and d_reclen fields in a directory buffer. 2043 * 2044 * The d_reclen field must be rounded up to a multiple of the length of the d_ino 2045 * field so that all entries will have their d_ino field on natural alignment. 2046 */ 2047ssize_t msdosfs_dirbuf_size(union msdosfs_dirbuf *buf, size_t name_length, int flags) 2048{ 2049 if (flags & VNODE_READDIR_EXTENDED) 2050 { 2051 buf->direntry.d_namlen = name_length; 2052 buf->direntry.d_reclen = (offsetof(struct direntry, d_name) + name_length + 8) & ~7; 2053 return buf->direntry.d_reclen; 2054 } 2055 else 2056 { 2057 buf->dirent.d_namlen = name_length; 2058 buf->dirent.d_reclen = (offsetof(struct dirent, d_name) + name_length + 4) & ~3; 2059 return buf->dirent.d_reclen; 2060 } 2061} 2062 2063int msdosfs_vnop_readdir(struct vnop_readdir_args *ap) 2064/* { 2065 vnode_t a_vp; 2066 struct uio *a_uio; 2067 int a_flags; 2068 int *a_eofflag; 2069 int *a_numdirent; 2070 vfs_context_t a_context; 2071 } */ 2072{ 2073 int error = 0; 2074 vnode_t vp = ap->a_vp; 2075 struct uio *uio = ap->a_uio; 2076 struct denode *dep = VTODE(vp); 2077 struct msdosfsmount *pmp = dep->de_pmp; 2078 vfs_context_t context = ap->a_context; 2079 uint32_t blsize; 2080 int32_t entry_offset; 2081 uint32_t cn; 2082 uint32_t fileno; 2083 int32_t bias = 0; 2084 daddr64_t bn, dir_cluster; 2085 struct buf *bp; 2086 struct dosdirentry *dentp; 2087 off_t offset; /* Current offset within directory */ 2088 off_t long_name_offset; /* Offset to start of long name */ 2089 int chksum = -1; 2090 u_int16_t ucfn[WIN_MAXLEN]; 2091 u_int16_t unichars = 0; 2092 size_t outbytes; 2093 char *bdata; 2094 union msdosfs_dirbuf buf; 2095 char *buf_name; 2096 size_t max_name; 2097 ssize_t buf_reclen; 2098 uint8_t buf_type; 2099 int eofflag = 0; 2100 int numdirent = 0; 2101 2102 if (ap->a_numdirent) 2103 *ap->a_numdirent = 0; 2104 2105 /* Assume we won't hit end of directory */ 2106 if (ap->a_eofflag) 2107 *ap->a_eofflag = 0; 2108 2109 if (ap->a_flags & VNODE_READDIR_REQSEEKOFF) 2110 return EINVAL; 2111 2112 /* Make a pointer to the start of the name field in the buffer. */ 2113 if (ap->a_flags & VNODE_READDIR_EXTENDED) 2114 { 2115 buf_name = &buf.direntry.d_name[0]; 2116 max_name = sizeof(buf.direntry.d_name); 2117 buf.direntry.d_seekoff = 0; 2118 } 2119 else 2120 { 2121 buf_name = &buf.dirent.d_name[0]; 2122 max_name = sizeof(buf.dirent.d_name); 2123 } 2124 2125 /* 2126 * msdosfs_vnop_readdir() won't operate properly on regular files since 2127 * it does i/o only with the device vnode, and hence can 2128 * retrieve the wrong block from the buffer cache for a plain file. 2129 * So, fail attempts to readdir() on a plain file. 2130 */ 2131 if (!vnode_isdir(vp)) 2132 return ENOTDIR; 2133 2134 /* 2135 * If the file offset is not a multiple of the size of a 2136 * directory entry, then we fail the read. The remaining 2137 * space in the buffer will be checked before each uiomove. 2138 */ 2139 long_name_offset = offset = uio_offset(uio); 2140 if (offset & (sizeof(struct dosdirentry) - 1)) 2141 return EINVAL; 2142 2143 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_READDIR|DBG_FUNC_START, dep, uio_offset(uio), uio_resid(uio), ap->a_flags, 0); 2144 lck_mtx_lock(dep->de_lock); 2145 2146 /* 2147 * If they are reading from the root directory, then we simulate 2148 * the . and .. entries since these don't exist in the root 2149 * directory. We also set the offset bias to make up for having to 2150 * simulate these entries. By this I mean that at file offset 64 we 2151 * read the first entry in the root directory that lives on disk. 2152 */ 2153 if (dep->de_StartCluster == MSDOSFSROOT 2154 || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) { 2155 bias = 2 * sizeof(struct dosdirentry); 2156 while (offset < bias) { 2157 if (ap->a_flags & VNODE_READDIR_EXTENDED) { 2158 buf.direntry.d_fileno = msdosfs_defileid(dep); 2159 buf.direntry.d_type = DT_DIR; 2160 } else { 2161 buf.dirent.d_fileno = msdosfs_defileid(dep); 2162 buf.dirent.d_type = DT_DIR; 2163 } 2164 if (offset == 0) { 2165 strlcpy(buf_name, ".", max_name); 2166 outbytes = 1; 2167 } else { 2168 strlcpy(buf_name, "..", max_name); 2169 outbytes = 2; 2170 } 2171 buf_reclen = msdosfs_dirbuf_size(&buf, outbytes, ap->a_flags); 2172 if (uio_resid(uio) < buf_reclen) 2173 goto out; 2174 error = uiomove((caddr_t) &buf, (int)buf_reclen, uio); 2175 if (error) 2176 goto out; 2177 ++numdirent; 2178 offset += sizeof(struct dosdirentry); 2179 } 2180 } 2181 2182 while (uio_resid(uio) > 0) { 2183 dir_cluster = de_cluster(pmp, offset - bias); 2184 entry_offset = (offset - bias) & pmp->pm_crbomask; 2185 if (dep->de_FileSize <= (offset - bias)) { 2186 eofflag = 1; /* Hit end of directory */ 2187 break; 2188 } 2189 error = msdosfs_pcbmap(dep, (uint32_t)dir_cluster, 1, &bn, &cn, &blsize); 2190 if (error) 2191 break; 2192 error = (int)buf_meta_bread(pmp->pm_devvp, bn, blsize, vfs_context_ucred(context), &bp); 2193 if (error) { 2194 buf_brelse(bp); 2195 goto exit; 2196 } 2197 bdata = (char *)buf_dataptr(bp); 2198 2199 /* 2200 * Correct the block size to be just the amount of data actually 2201 * returned in the buffer. That is, the amount we asked to read 2202 * minus the "resid" (amount remaining to read). 2203 * 2204 * Normally, buf_resid() should return 0; that is, it should have 2205 * read as much as we asked for. But we've seen some badly behaved 2206 * devices which either misreport the number of sectors (giving us 2207 * a value that is too large), or are unable to access sectors past 2208 * a given offset. If we end up trying to read past that offset, 2209 * the devices tend to return success but zero bytes of data, 2210 * and buf_resid() will end up being the number of bytes we 2211 * expected to get, but didn't actually get. 2212 */ 2213 blsize -= buf_resid(bp); 2214 2215 /* 2216 * Convert from dos directory entries to fs-independent 2217 * directory entries. 2218 */ 2219 for (dentp = (struct dosdirentry *)(bdata + entry_offset); 2220 (char *)dentp < bdata + blsize; 2221 dentp++, offset += sizeof(struct dosdirentry)) { 2222 /* 2223 * If this is an unused entry, we can stop. 2224 */ 2225 if (dentp->deName[0] == SLOT_EMPTY) { 2226 buf_brelse(bp); 2227 if (ap->a_eofflag) 2228 *ap->a_eofflag = 1; /* Hit end of directory */ 2229 goto out; 2230 } 2231 /* 2232 * Skip deleted entries. 2233 */ 2234 if (dentp->deName[0] == SLOT_DELETED) { 2235 chksum = -1; 2236 continue; 2237 } 2238 2239 /* 2240 * Handle Win95 long directory entries 2241 */ 2242 if ((dentp->deAttributes & ATTR_WIN95_MASK) == ATTR_WIN95) { 2243 if (dentp->deName[0] & WIN_LAST) 2244 long_name_offset = offset; 2245 chksum = msdosfs_getunicodefn((struct winentry *)dentp, 2246 ucfn, &unichars, chksum); 2247 continue; 2248 } 2249 2250 /* 2251 * Skip volume labels 2252 */ 2253 if (dentp->deAttributes & ATTR_VOLUME) { 2254 chksum = -1; 2255 continue; 2256 } 2257 2258 /* 2259 * This computation of d_fileno must match 2260 * the computation in msdosfs_defileid(). 2261 */ 2262 fileno = getuint16(dentp->deStartCluster); 2263 if (FAT32(pmp)) 2264 fileno |= getuint16(dentp->deHighClust) << 16; 2265 if (dentp->deAttributes & ATTR_DIRECTORY) { 2266 if (fileno == MSDOSFSROOT) { 2267 /* if this is the root directory */ 2268 if (FAT32(pmp)) 2269 fileno = pmp->pm_rootdirblk; 2270 else 2271 fileno = FILENO_ROOT; 2272 } 2273 buf_type = DT_DIR; 2274 } else { 2275 if (fileno == 0) 2276 fileno = FILENO_EMPTY; /* constant for empty files */ 2277 if (getuint32(dentp->deFileSize) == sizeof(struct symlink)) 2278 buf_type = DT_UNKNOWN; /* Might be a symlink */ 2279 else 2280 buf_type = DT_REG; 2281 } 2282 if (chksum != msdosfs_winChksum(dentp->deName)) { 2283 chksum = -1; 2284 unichars = msdosfs_dos2unicodefn(dentp->deName, ucfn, 2285 dentp->deLowerCase); 2286 } 2287 2288 /* translate the name in ucfn into UTF-8 */ 2289 (void) utf8_encodestr(ucfn, unichars * 2, (u_int8_t*)buf_name, 2290 &outbytes, max_name, 0, 2291 UTF_DECOMPOSED|UTF_SFM_CONVERSIONS); 2292 2293 /* Fill in the other buffer fields. */ 2294 if (ap->a_flags & VNODE_READDIR_EXTENDED) 2295 { 2296 buf.direntry.d_ino = fileno; 2297 buf.direntry.d_type = buf_type; 2298 } 2299 else 2300 { 2301 buf.dirent.d_ino = fileno; 2302 buf.dirent.d_type = buf_type; 2303 } 2304 buf_reclen = msdosfs_dirbuf_size(&buf, outbytes, ap->a_flags); 2305 2306 if (uio_resid(uio) < buf_reclen) { 2307 buf_brelse(bp); 2308 goto out; 2309 } 2310 error = uiomove((caddr_t) &buf, (int)buf_reclen, uio); 2311 if (error) { 2312 buf_brelse(bp); 2313 goto out; 2314 } 2315 chksum = -1; 2316 ++numdirent; 2317 } 2318 buf_brelse(bp); 2319 } 2320 2321out: 2322 /* Update the current position within the directory */ 2323 if (chksum != -1) 2324 offset = long_name_offset; 2325 uio_setoffset(uio, offset); 2326exit: 2327 lck_mtx_unlock(dep->de_lock); 2328 if (ap->a_eofflag) 2329 *ap->a_eofflag = eofflag; 2330 if (ap->a_numdirent) 2331 *ap->a_numdirent = numdirent; 2332 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_READDIR|DBG_FUNC_END, error, uio_offset(uio), numdirent, eofflag, 0); 2333 return error; 2334} 2335 2336/* blktooff converts a logical block number to a file offset */ 2337int msdosfs_vnop_blktooff(struct vnop_blktooff_args *ap) 2338/* { 2339 vnode_t a_vp; 2340 daddr64_t a_lblkno; 2341 off_t *a_offset; 2342 } */ 2343{ 2344 if (ap->a_vp == NULL) 2345 return EINVAL; 2346 2347 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_BLKTOOFF|DBG_FUNC_START, ap->a_lblkno, 0, 0, 0, 0); 2348 *ap->a_offset = ap->a_lblkno * PAGE_SIZE_64; 2349 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_BLKTOOFF|DBG_FUNC_END, 0, *ap->a_offset, 0, 0, 0); 2350 2351 return 0; 2352} 2353 2354/* offtoblk converts a file offset to a logical block number */ 2355int msdosfs_vnop_offtoblk(struct vnop_offtoblk_args *ap) 2356/* { 2357 vnode_t a_vp; 2358 off_t a_offset; 2359 daddr64_t *a_lblkno; 2360 } */ 2361{ 2362 if (ap->a_vp == NULL) 2363 return EINVAL; 2364 2365 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_OFFTOBLK|DBG_FUNC_START, ap->a_offset, 0, 0, 0, 0); 2366 *ap->a_lblkno = ap->a_offset / PAGE_SIZE_64; 2367 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_OFFTOBLK|DBG_FUNC_END, 0, *ap->a_lblkno, 0, 0, 0); 2368 2369 return 0; 2370} 2371 2372 2373/* 2374 * Map a logical file range (offset and length) to an on-disk extent 2375 * (block number and number of contiguous blocks). 2376 * 2377 * This routine assumes that the denode's de_lock has already been acquired 2378 * (such as inside of msdosfs_vnop_read or msdosfs_vnop_write, or by the caller of 2379 * buf_meta_bread). 2380 * 2381 * [It wouldn't make sense to call this routine if the file's size or 2382 * location on disk could be changing. If it could, then any output 2383 * from this routine could be obsolete before the caller could use it.] 2384 */ 2385int msdosfs_vnop_blockmap(struct vnop_blockmap_args *ap) 2386/* { 2387 vnode_t a_vp; 2388 off_t a_foffset; 2389 size_t a_size; 2390 daddr64_t *a_bpn; 2391 size_t *a_run; 2392 void *a_poff; 2393 int a_flags; 2394 vfs_context_t a_context; 2395 } */ 2396{ 2397 int error; 2398 vnode_t vp = ap->a_vp; 2399 struct denode *dep = VTODE(vp); 2400 struct msdosfsmount *pmp = dep->de_pmp; 2401 uint32_t runsize; 2402 uint32_t cn; 2403 uint32_t numclusters; 2404 daddr64_t bn; 2405 2406 if (ap->a_bpn == NULL) 2407 return 0; 2408 2409 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_BLOCKMAP|DBG_FUNC_START, dep, ap->a_foffset, ap->a_size, 0, 0); 2410 if (ap->a_size == 0) 2411 panic("msdosfs_vnop_blockmap: a_size == 0"); 2412 2413 /* Find the cluster that contains the given file offset */ 2414 cn = de_cluster(pmp, ap->a_foffset); 2415 2416 /* Determine number of clusters occupied by the given range */ 2417 numclusters = de_cluster(pmp, ap->a_foffset + ap->a_size - 1) - cn + 1; 2418 2419 /* Find the physical (device) block where that cluster starts */ 2420 error = msdosfs_pcbmap(dep, cn, numclusters, &bn, NULL, &runsize); 2421 2422 /* Add the offset in physical (device) blocks from the start of the cluster */ 2423 bn += (((uint32_t)ap->a_foffset - de_cn2off(pmp, cn)) >> pmp->pm_bnshift); 2424 runsize -= ((uint32_t)ap->a_foffset - (de_cn2off(pmp, cn))); 2425 2426 *ap->a_bpn = bn; 2427 if (error == 0 && ap->a_run) { 2428 if (runsize > ap->a_size) 2429 * ap->a_run = ap->a_size; 2430 else 2431 * ap->a_run = runsize; 2432 } 2433 if (ap->a_poff) 2434 *(int *)ap->a_poff = 0; 2435 2436 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_BLOCKMAP|DBG_FUNC_END, error, bn, runsize, 0, 0); 2437 return error; 2438} 2439 2440/* 2441 * prepare and issue the I/O 2442 * buf_strategy knows how to deal 2443 * with requests that require 2444 * fragmented I/Os 2445 */ 2446int msdosfs_vnop_strategy(struct vnop_strategy_args *ap) 2447/* { 2448 struct buf *a_bp; 2449 } */ 2450{ 2451 buf_t bp = ap->a_bp; 2452 vnode_t vp = buf_vnode(bp); 2453 struct denode *dep = VTODE(vp); 2454 int error; 2455 2456 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_STRATEGY|DBG_FUNC_START, dep, buf_lblkno(bp), buf_resid(bp), buf_flags(bp), 0); 2457 error = buf_strategy(dep->de_devvp, ap); 2458 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_STRATEGY|DBG_FUNC_END, error, buf_error(bp), buf_resid(bp), buf_flags(bp), 0); 2459 return error; 2460} 2461 2462int msdosfs_vnop_pathconf(struct vnop_pathconf_args *ap) 2463/* { 2464 vnode_t a_vp; 2465 int a_name; 2466 register_t *a_retval; 2467 vfs_context_t a_context; 2468 } */ 2469{ 2470 int error = 0; 2471 2472 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_PATHCONF|DBG_FUNC_START, ap->a_name, 0, 0, 0, 0); 2473 switch (ap->a_name) { 2474 case _PC_LINK_MAX: 2475 *ap->a_retval = 1; 2476 break; 2477 case _PC_NAME_MAX: 2478 *ap->a_retval = WIN_MAXLEN; 2479 break; 2480 case _PC_PATH_MAX: 2481 *ap->a_retval = PATH_MAX; 2482 break; 2483 case _PC_CHOWN_RESTRICTED: 2484 *ap->a_retval = 1; 2485 break; 2486 case _PC_NO_TRUNC: 2487 *ap->a_retval = 0; 2488 break; 2489 case _PC_CASE_SENSITIVE: 2490 *ap->a_retval = 0; 2491 break; 2492 case _PC_CASE_PRESERVING: 2493 *ap->a_retval = 1; 2494 break; 2495 case _PC_FILESIZEBITS: 2496 *ap->a_retval = 32; 2497 break; 2498 default: 2499 error = EINVAL; 2500 break; 2501 } 2502 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_PATHCONF|DBG_FUNC_END, error, *ap->a_retval, 0, 0, 0); 2503 return error; 2504} 2505 2506 2507/* 2508 * Given a chunk of memory, compute the md5 digest as a string of 32 2509 * hex digits followed by a NUL character. 2510 */ 2511void msdosfs_md5_digest(void *text, size_t length, char digest[33]) 2512{ 2513 int i; 2514 MD5_CTX context; 2515 unsigned char digest_raw[16]; 2516 2517 MD5Init(&context); 2518 MD5Update(&context, text, (unsigned)length); 2519 MD5Final(digest_raw, &context); 2520 2521 for (i=0; i<16; ++i) 2522 { 2523 /* 2524 * The "3" below is for the two hex digits plus trailing '\0'. 2525 * Note that the trailing '\0' from byte N is overwritten 2526 * by the first character of byte N+1, and that digest[] has 2527 * a length of 33 == 2 * 16 + 1 in order to have room for a 2528 * trailing '\0' after the last byte's characters. 2529 */ 2530 (void) snprintf(digest, 3, "%02x", digest_raw[i]); 2531 digest += 2; 2532 } 2533} 2534 2535 2536/* 2537 * Determine whether the given denode refers to a symlink or an ordinary 2538 * file. This is called during vnode creation, so the de_vnode field 2539 * has not been set up. Returns the vnode type to create (either 2540 * VREG or VLNK). 2541 * 2542 * In order to tell whether the file is an ordinary file or a symlink, 2543 * we need to read from it. The easiest way to do this is to create a 2544 * temporary vnode of type VREG, so we can use the buffer cache. We will 2545 * terminate the vnode before returning. msdosfs_deget() will create the real 2546 * vnode to be returned. 2547 * 2548 * Assumes that the denode's de_lock is already acquired, or that the denode is 2549 * otherwise protected (not part of the denode hash, not in the name cache, not 2550 * in the volume's name space). 2551 */ 2552enum vtype msdosfs_check_link(struct denode *dep, vfs_context_t context) 2553{ 2554 int error; 2555 int i; 2556 unsigned length; 2557 char c; 2558 enum vtype result; 2559 struct msdosfsmount *pmp; 2560 vnode_t vp = NULL; 2561 buf_t bp = NULL; 2562 struct symlink *link; 2563 char digest[33]; 2564 struct vnode_fsparam vfsp; 2565 2566 if (dep->de_FileSize != sizeof(struct symlink)) 2567 { 2568 result = VREG; 2569 goto exit; 2570 } 2571 2572 /* 2573 * The file is the magic symlink size. We need to read it in so we 2574 * can validate the header and update the size to reflect the 2575 * length of the symlink. 2576 * 2577 * We create a temporary vnode to read in the contents of the file 2578 * (since it may be fragmented, and this lets us take advantage of the 2579 * blockmap and strategy routines). 2580 * 2581 * The temporary vnode's type is set to VNON instead of VREG so that 2582 * vnode_iterate won't return it. This prevents a race with 2583 * msdosfs_vfs_sync that might try to fsync this vnode as its v_data pointer 2584 * gets cleared by vnode_clearfsnode below. (The race can lead to a 2585 * NULL denode pointer in msdosfs_deupdat(), which causes a panic.) 2586 */ 2587 result = VREG; /* Assume it's not a symlink, until we verify it. */ 2588 pmp = dep->de_pmp; 2589 2590 vfsp.vnfs_mp = pmp->pm_mountp; 2591 vfsp.vnfs_vtype = VNON; 2592 vfsp.vnfs_str = "msdosfs"; 2593 vfsp.vnfs_dvp = NULL; 2594 vfsp.vnfs_fsnode = dep; 2595 vfsp.vnfs_cnp = NULL; 2596 vfsp.vnfs_vops = msdosfs_vnodeop_p; 2597 vfsp.vnfs_rdev = 0; 2598 vfsp.vnfs_filesize = dep->de_FileSize; 2599 vfsp.vnfs_flags = VNFS_NOCACHE; 2600 vfsp.vnfs_markroot = 0; 2601 vfsp.vnfs_marksystem = 0; 2602 2603 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &dep->de_vnode); 2604 vp = dep->de_vnode; 2605 if (error) goto exit; 2606 2607 error = buf_meta_bread(vp, 0, roundup(sizeof(*link),pmp->pm_bpcluster), 2608 vfs_context_ucred(context), &bp); 2609 if (error) goto exit; 2610 link = (struct symlink *) buf_dataptr(bp); 2611 2612 /* Verify the magic */ 2613 if (strncmp(link->magic, symlink_magic, 5) != 0) 2614 goto exit; 2615 2616 /* Parse and sanity check the length field */ 2617 length = 0; 2618 for (i=0; i<4; ++i) 2619 { 2620 c = link->length[i]; 2621 if (c < '0' || c > '9') 2622 goto exit; /* Length is non-decimal */ 2623 length = 10 * length + c - '0'; 2624 } 2625 if (length > SYMLINK_LINK_MAX) 2626 goto exit; /* Length is too big */ 2627 2628 /* Verify the MD5 digest */ 2629 msdosfs_md5_digest(link->link, length, digest); 2630 if (strncmp(digest, link->md5, 32) != 0) 2631 goto exit; 2632 2633 /* It passed all the checks; must be a symlink */ 2634 result = VLNK; 2635 dep->de_FileSize = length; 2636 dep->de_flag |= DE_SYMLINK; 2637 2638exit: 2639 if (bp) 2640 { 2641 /* 2642 * We're going to be getting rid of the vnode, so we might as well 2643 * mark the buffer invalid so that it will get reused right away. 2644 */ 2645 buf_markinvalid(bp); 2646 buf_brelse(bp); 2647 } 2648 2649 if (vp) 2650 { 2651 (void) vnode_clearfsnode(vp); /* So we won't free dep */ 2652 (void) vnode_recycle(vp); /* get rid of the vnode now */ 2653 (void) vnode_put(vp); /* to balance vnode_create */ 2654 } 2655 2656 return result; 2657} 2658 2659 2660/* 2661 * Create a symbolic link. 2662 * 2663 * The idea is to write the symlink file content to disk and 2664 * create a new directory entry pointing at the symlink content. 2665 * Then msdosfs_createde will automatically create the correct type of 2666 * vnode. 2667 */ 2668int msdosfs_vnop_symlink(struct vnop_symlink_args *ap) 2669/* { 2670 vnode_t a_dvp; 2671 vnode_t *a_vpp; 2672 struct componentname *a_cnp; 2673 struct vnode_attr *a_vap; 2674 char *a_target; 2675 vfs_context_t a_context; 2676 } */ 2677{ 2678 int error; 2679 vnode_t dvp = ap->a_dvp; 2680 struct denode *dep = VTODE(dvp); 2681 struct msdosfsmount *pmp = dep->de_pmp; 2682 struct componentname *cnp = ap->a_cnp; 2683 struct vnode_attr *vap = ap->a_vap; 2684 char *target = ap->a_target; 2685 vfs_context_t context = ap->a_context; 2686 size_t length; /* length of target path */ 2687 struct symlink *link = NULL; 2688 uint32_t cn = 0; /* first cluster of symlink */ 2689 uint32_t clusters, got; /* count of clusters needed, actually allocated */ 2690 buf_t bp = NULL; 2691 struct denode ndirent; 2692 struct denode *new_dep; 2693 struct timespec ts; 2694 uint32_t offset; 2695 uint32_t long_count; 2696 int needs_generation; 2697 2698 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_SYMLINK|DBG_FUNC_START, dep, 0, 0, 0, 0); 2699 lck_mtx_lock(dep->de_lock); 2700 2701 /* 2702 * Make sure the parent directory hasn't been deleted. 2703 */ 2704 if (dep->de_refcnt <= 0) 2705 { 2706 cache_purge(dvp); 2707 error = ENOENT; 2708 goto exit; 2709 } 2710 2711 /* 2712 * Make sure the name does not exist in the parent directory. (It didn't 2713 * exist during VNOP_LOOKUP, but another thread may have created the name 2714 * before we got the lock on the parent.) 2715 */ 2716 error = msdosfs_lookup_name(dep, cnp, NULL, NULL, NULL, NULL, NULL, NULL, context); 2717 if (error != ENOENT) 2718 { 2719 error = EEXIST; 2720 goto exit; 2721 } 2722 2723 /* 2724 * Find space in the directory to place the new name. 2725 */ 2726 bzero(&ndirent, sizeof(ndirent)); 2727 error = msdosfs_findslots(dep, cnp, ndirent.de_Name, &needs_generation, &ndirent.de_LowerCase, &offset, &long_count, context); 2728 if (error) 2729 goto exit; 2730 2731 /* 2732 * If this is the root directory and there is no space left we 2733 * can't do anything. This is because the root directory can not 2734 * change size. (FAT12 and FAT16 only) 2735 * 2736 * On FAT32, we can grow the root directory, and de_StartCluster 2737 * will be the actual cluster number of the root directory. 2738 */ 2739 if (dep->de_StartCluster == MSDOSFSROOT && offset >= dep->de_FileSize) 2740 { 2741 printf("msdosfs_vnop_symlink: Cannot grow the root directory on FAT12 or FAT16; returning ENOSPC.\n"); 2742 error = ENOSPC; 2743 goto exit; 2744 } 2745 2746 length = strlen(target); 2747 if (length > SYMLINK_LINK_MAX) 2748 { 2749 error = ENAMETOOLONG; 2750 goto exit; 2751 } 2752 2753 /* 2754 * Allocate (contiguous) space to store the symlink. In an ideal world, 2755 * we should support creating a non-contiguous symlink file, but that 2756 * would be much more complicated (creating a temporary denode and vnode 2757 * just so that we can allocate and write to the link, then removing that 2758 * vnode and creating a real one with the correct vtype). 2759 */ 2760 clusters = de_clcount(pmp, sizeof(*link)); 2761 error = msdosfs_clusteralloc(pmp, 0, clusters, CLUST_EOFE, &cn, &got); 2762 if (error) goto exit; 2763 if (got < clusters) 2764 { 2765 error = ENOSPC; 2766 goto exit; 2767 } 2768 2769 /* Get a buffer to hold the symlink */ 2770 bp = buf_getblk(pmp->pm_devvp, cntobn(pmp, cn), 2771 roundup(sizeof(*link),pmp->pm_bpcluster), 2772 0, 0, BLK_META); 2773 buf_clear(bp); 2774 link = (struct symlink *) buf_dataptr(bp); 2775 2776 /* 2777 * Fill in each of the symlink fields. We have to do this in the same 2778 * order as the fields appear in the structure because some of the 2779 * operations clobber one byte past the end of their field (with a 2780 * NUL character that is a string terminator). 2781 */ 2782 bcopy(symlink_magic, link->magic, sizeof(symlink_magic)); 2783 /* 6 = 4 bytes of digits + newline + '\0' */ 2784 snprintf(link->length, 6, "%04u\n", (unsigned)length); 2785 msdosfs_md5_digest(target, length, link->md5); 2786 link->newline2 = '\n'; 2787 bcopy(target, link->link, length); 2788 2789 /* Pad with newline if there is room */ 2790 if (length < SYMLINK_LINK_MAX) 2791 link->link[length++] = '\n'; 2792 2793 /* Pad with spaces if there is room */ 2794 if (length < SYMLINK_LINK_MAX) 2795 memset(&link->link[length], ' ', SYMLINK_LINK_MAX-length); 2796 2797 /* Write out the symlink */ 2798 error = buf_bwrite(bp); 2799 bp = NULL; 2800 buf_invalblkno(pmp->pm_devvp, cntobn(pmp, cn), BUF_WAIT); 2801 if (error) 2802 { 2803 if (DEBUG) panic("msdosfs_vnop_symlink: buf_bwrite returned %d\n", error); 2804 goto exit; 2805 } 2806 2807 /* Start setting up new directory entry */ 2808 error = msdosfs_uniqdosname(dep, ndirent.de_Name, needs_generation ? offset - long_count * sizeof(struct dosdirentry) : 1, context); 2809 if (error) 2810 { 2811 if (DEBUG) panic("msdosfs_vnop_symlink: msdosfs_uniqdosname returned %d\n", error); 2812 goto exit; 2813 } 2814 2815 /* 2816 * Set read-only attribute if one of the immutable bits is set. 2817 * Always set the "needs archive" attribute on newly created files. 2818 */ 2819 ndirent.de_Attributes = ATTR_ARCHIVE; 2820 if (VATTR_IS_ACTIVE(vap, va_flags)) 2821 { 2822 if ((vap->va_flags & (SF_IMMUTABLE | UF_IMMUTABLE)) != 0) 2823 ndirent.de_Attributes |= ATTR_READONLY; 2824 VATTR_SET_SUPPORTED(vap, va_flags); 2825 } 2826 2827 ndirent.de_StartCluster = cn; 2828 ndirent.de_FileSize = sizeof(*link); 2829 ndirent.de_dev = dep->de_dev; 2830 ndirent.de_devvp = dep->de_devvp; 2831 ndirent.de_pmp = dep->de_pmp; 2832 ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; 2833 getnanotime(&ts); 2834 DETIMES(&ndirent, &ts, &ts, &ts); 2835 2836 /* Create a new directory entry pointing at the newly allocated clusters */ 2837 error = msdosfs_createde(&ndirent, dep, &new_dep, cnp, offset, long_count, context); 2838 if (error) 2839 { 2840 if (DEBUG) panic("msdosfs_vnop_symlink: msdosfs_createde returned %d\n", error); 2841 goto exit; 2842 } 2843 *ap->a_vpp = DETOV(new_dep); 2844 cache_purge_negatives(dvp); 2845 2846exit: 2847 if (bp) 2848 { 2849 /* 2850 * After the symlink is created, we should access the contents via the 2851 * symlink's vnode, not via the device. Marking it invalid here 2852 * prevents double caching (and the inconsistencies which can result). 2853 */ 2854 buf_markinvalid(bp); 2855 buf_brelse(bp); 2856 } 2857 if (error != 0 && cn != 0) 2858 (void) msdosfs_freeclusterchain(pmp, cn); 2859 2860 msdosfs_meta_flush(pmp, FALSE); 2861 lck_mtx_unlock(dep->de_lock); 2862 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_SYMLINK|DBG_FUNC_END, error, 0, 0, 0, 0); 2863 return error; 2864} 2865 2866 2867int msdosfs_vnop_readlink(struct vnop_readlink_args *ap) 2868/* { 2869 vnode_t a_vp; 2870 struct uio *a_uio; 2871 vfs_context_t a_context; 2872 } */ 2873{ 2874 int error; 2875 vnode_t vp = ap->a_vp; 2876 struct denode *dep = VTODE(vp); 2877 struct msdosfsmount *pmp = dep->de_pmp; 2878 buf_t bp = NULL; 2879 struct symlink *link; 2880 2881 if (vnode_vtype(vp) != VLNK) 2882 return EINVAL; 2883 2884 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_READLINK|DBG_FUNC_START, dep, 0, 0, 0, 0); 2885 lck_mtx_lock(dep->de_lock); 2886 2887 if (dep->de_refcnt <= 0) 2888 { 2889 cache_purge(vp); 2890 error = EAGAIN; 2891 goto exit; 2892 } 2893 2894 if (dep->de_StartCluster == 0) 2895 panic("msdosfs_vnop_readlink: de_StartCluster == 0!\n"); 2896 2897 /* 2898 * If the vnode was created of type VLNK, then we assume the symlink 2899 * file has been checked for consistency. So we skip it here. 2900 */ 2901 error = buf_meta_bread(vp, 0, roundup(sizeof(*link),pmp->pm_bpcluster), 2902 vfs_context_ucred(ap->a_context), &bp); 2903 if (error) goto exit; 2904 link = (struct symlink *) buf_dataptr(bp); 2905 2906 /* 2907 * Return the link. Assumes de_FileSize was set to the length 2908 * of the symlink. 2909 */ 2910 error = uiomove(link->link, dep->de_FileSize, ap->a_uio); 2911 2912exit: 2913 if (bp) 2914 buf_brelse(bp); 2915 2916 lck_mtx_unlock(dep->de_lock); 2917 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_READLINK|DBG_FUNC_END, error, 0, 0, 0, 0); 2918 2919 return error; 2920} 2921 2922 2923int msdosfs_vnop_ioctl(struct vnop_ioctl_args *ap) 2924/* { 2925 vnode_t a_vp; 2926 uint32_t a_command; 2927 caddr_t a_data; 2928 int a_fflag; 2929 vfs_context_t a_context; 2930 } */ 2931{ 2932 int error; 2933 vnode_t vp = ap->a_vp; 2934 2935 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_IOCTL|DBG_FUNC_START, VTODE(vp), ap->a_command, 0, 0, 0); 2936 switch(ap->a_command) { 2937 case F_FULLFSYNC: 2938 { 2939 struct vnop_fsync_args fsync_args; 2940 2941 bzero(&fsync_args, sizeof(fsync_args)); 2942 fsync_args.a_vp = ap->a_vp; 2943 fsync_args.a_waitfor = MNT_WAIT; 2944 fsync_args.a_context = ap->a_context; 2945 2946 error = msdosfs_vnop_fsync(&fsync_args); 2947 if (error) { 2948 goto exit; 2949 } 2950 2951 /* Call device ioctl to flush media track cache */ 2952 error = VNOP_IOCTL(VTODE(vp)->de_pmp->pm_devvp, DKIOCSYNCHRONIZECACHE, 2953 NULL, FWRITE, ap->a_context); 2954 if (error) { 2955 goto exit; 2956 } 2957 2958 break; 2959 } /* F_FULLFSYNC */ 2960 2961 default: 2962 { 2963 error = ENOTTY; 2964 goto exit; 2965 } 2966 }/* switch(ap->a_command) */ 2967 2968exit: 2969 KERNEL_DEBUG_CONSTANT(MSDOSFS_VNOP_IOCTL|DBG_FUNC_START, error, 0, 0, 0, 0); 2970 return error; 2971} 2972 2973 2974 2975/* Global vfs data structures for msdosfs */ 2976 2977typedef int vnop_t(void *); 2978 2979int (**msdosfs_vnodeop_p)(void *); 2980static struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = { 2981 { &vnop_default_desc, (vnop_t *) vn_default_error }, 2982 { &vnop_lookup_desc, (vnop_t *) msdosfs_vnop_lookup }, 2983 { &vnop_create_desc, (vnop_t *) msdosfs_vnop_create }, 2984 { &vnop_mknod_desc, (vnop_t *) msdosfs_vnop_mknod }, 2985 { &vnop_open_desc, (vnop_t *) msdosfs_vnop_open }, 2986 { &vnop_close_desc, (vnop_t *) msdosfs_vnop_close }, 2987 { &vnop_getattr_desc, (vnop_t *) msdosfs_vnop_getattr }, 2988 { &vnop_setattr_desc, (vnop_t *) msdosfs_vnop_setattr }, 2989 { &vnop_getxattr_desc, (vnop_t *) msdosfs_vnop_getxattr }, 2990 { &vnop_setxattr_desc, (vnop_t *) msdosfs_vnop_setxattr }, 2991 { &vnop_removexattr_desc, (vnop_t *) msdosfs_vnop_removexattr }, 2992 { &vnop_listxattr_desc, (vnop_t *) msdosfs_vnop_listxattr }, 2993 { &vnop_read_desc, (vnop_t *) msdosfs_vnop_read }, 2994 { &vnop_write_desc, (vnop_t *) msdosfs_vnop_write }, 2995 { &vnop_fsync_desc, (vnop_t *) msdosfs_vnop_fsync }, 2996 { &vnop_remove_desc, (vnop_t *) msdosfs_vnop_remove }, 2997 { &vnop_rename_desc, (vnop_t *) msdosfs_vnop_rename }, 2998 { &vnop_mkdir_desc, (vnop_t *) msdosfs_vnop_mkdir }, 2999 { &vnop_rmdir_desc, (vnop_t *) msdosfs_vnop_rmdir }, 3000 { &vnop_readdir_desc, (vnop_t *) msdosfs_vnop_readdir }, 3001 { &vnop_inactive_desc, (vnop_t *) msdosfs_vnop_inactive }, 3002 { &vnop_reclaim_desc, (vnop_t *) msdosfs_vnop_reclaim }, 3003 { &vnop_pathconf_desc, (vnop_t *) msdosfs_vnop_pathconf }, 3004 { &vnop_pagein_desc, (vnop_t *) msdosfs_vnop_pagein }, 3005 { &vnop_pageout_desc, (vnop_t *) msdosfs_vnop_pageout }, 3006 { &vnop_blktooff_desc, (vnop_t *) msdosfs_vnop_blktooff }, 3007 { &vnop_offtoblk_desc, (vnop_t *) msdosfs_vnop_offtoblk }, 3008 { &vnop_blockmap_desc, (vnop_t *) msdosfs_vnop_blockmap }, 3009 { &vnop_strategy_desc, (vnop_t *) msdosfs_vnop_strategy }, 3010 { &vnop_symlink_desc, (vnop_t *) msdosfs_vnop_symlink }, 3011 { &vnop_readlink_desc, (vnop_t *) msdosfs_vnop_readlink }, 3012 { &vnop_ioctl_desc, (vnop_t *) msdosfs_vnop_ioctl}, 3013 { &vnop_bwrite_desc, (vnop_t *) vn_bwrite }, 3014 { NULL, NULL } 3015}; 3016 3017extern int (**msdosfs_fat_vnodeop_p)(void *); 3018extern struct vnodeopv_entry_desc msdosfs_fat_vnodeop_entries[]; 3019 3020struct vnodeopv_desc msdosfs_vnodeop_opv_desc = 3021 { &msdosfs_vnodeop_p, msdosfs_vnodeop_entries }; 3022