1/* 2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <sys/systm.h> 30#include <sys/param.h> 31#include <sys/kernel.h> 32#include <sys/file_internal.h> 33#include <sys/dirent.h> 34#include <sys/stat.h> 35#include <sys/buf.h> 36#include <sys/buf_internal.h> 37#include <sys/mount.h> 38#include <sys/vnode_if.h> 39#include <sys/vnode_internal.h> 40#include <sys/malloc.h> 41#include <sys/ubc.h> 42#include <sys/ubc_internal.h> 43#include <sys/paths.h> 44#include <sys/quota.h> 45#include <sys/time.h> 46#include <sys/disk.h> 47#include <sys/kauth.h> 48#include <sys/uio_internal.h> 49#include <sys/fsctl.h> 50#include <sys/cprotect.h> 51#include <sys/xattr.h> 52#include <string.h> 53 54#include <miscfs/specfs/specdev.h> 55#include <miscfs/fifofs/fifo.h> 56#include <vfs/vfs_support.h> 57#include <machine/spl.h> 58 59#include <sys/kdebug.h> 60#include <sys/sysctl.h> 61 62#include "hfs.h" 63#include "hfs_catalog.h" 64#include "hfs_cnode.h" 65#include "hfs_dbg.h" 66#include "hfs_mount.h" 67#include "hfs_quota.h" 68#include "hfs_endian.h" 69 70#include "hfscommon/headers/BTreesInternal.h" 71#include "hfscommon/headers/FileMgrInternal.h" 72 73#define KNDETACH_VNLOCKED 0x00000001 74 75/* Global vfs data structures for hfs */ 76 77/* Always F_FULLFSYNC? 1=yes,0=no (default due to "various" reasons is 'no') */ 78int always_do_fullfsync = 0; 79SYSCTL_DECL(_vfs_generic); 80SYSCTL_INT (_vfs_generic, OID_AUTO, always_do_fullfsync, CTLFLAG_RW | CTLFLAG_LOCKED, &always_do_fullfsync, 0, "always F_FULLFSYNC when fsync is called"); 81 82int hfs_makenode(struct vnode *dvp, struct vnode **vpp, 83 struct componentname *cnp, struct vnode_attr *vap, 84 vfs_context_t ctx); 85int hfs_metasync(struct hfsmount *hfsmp, daddr64_t node, __unused struct proc *p); 86int hfs_metasync_all(struct hfsmount *hfsmp); 87 88int hfs_removedir(struct vnode *, struct vnode *, struct componentname *, 89 int, int); 90int hfs_removefile(struct vnode *, struct vnode *, struct componentname *, 91 int, int, int, struct vnode *, int); 92 93/* Used here and in cnode teardown -- for symlinks */ 94int hfs_removefile_callback(struct buf *bp, void *hfsmp); 95 96int hfs_movedata (struct vnode *, struct vnode*); 97static int hfs_move_fork (struct filefork *srcfork, struct cnode *src, 98 struct filefork *dstfork, struct cnode *dst); 99 100#if FIFO 101static int hfsfifo_read(struct vnop_read_args *); 102static int hfsfifo_write(struct vnop_write_args *); 103static int hfsfifo_close(struct vnop_close_args *); 104 105extern int (**fifo_vnodeop_p)(void *); 106#endif /* FIFO */ 107 108int hfs_vnop_close(struct vnop_close_args*); 109int hfs_vnop_create(struct vnop_create_args*); 110int hfs_vnop_exchange(struct vnop_exchange_args*); 111int hfs_vnop_fsync(struct vnop_fsync_args*); 112int hfs_vnop_mkdir(struct vnop_mkdir_args*); 113int hfs_vnop_mknod(struct vnop_mknod_args*); 114int hfs_vnop_getattr(struct vnop_getattr_args*); 115int hfs_vnop_open(struct vnop_open_args*); 116int hfs_vnop_readdir(struct vnop_readdir_args*); 117int hfs_vnop_remove(struct vnop_remove_args*); 118int hfs_vnop_rename(struct vnop_rename_args*); 119int hfs_vnop_rmdir(struct vnop_rmdir_args*); 120int hfs_vnop_symlink(struct vnop_symlink_args*); 121int hfs_vnop_setattr(struct vnop_setattr_args*); 122int hfs_vnop_readlink(struct vnop_readlink_args *); 123int hfs_vnop_pathconf(struct vnop_pathconf_args *); 124int hfs_vnop_whiteout(struct vnop_whiteout_args *); 125int hfs_vnop_mmap(struct vnop_mmap_args *ap); 126int hfsspec_read(struct vnop_read_args *); 127int hfsspec_write(struct vnop_write_args *); 128int hfsspec_close(struct vnop_close_args *); 129 130/* Options for hfs_removedir and hfs_removefile */ 131#define HFSRM_SKIP_RESERVE 0x01 132 133 134 135 136/***************************************************************************** 137* 138* Common Operations on vnodes 139* 140*****************************************************************************/ 141 142/* 143 * Is the given cnode either the .journal or .journal_info_block file on 144 * a volume with an active journal? Many VNOPs use this to deny access 145 * to those files. 146 * 147 * Note: the .journal file on a volume with an external journal still 148 * returns true here, even though it does not actually hold the contents 149 * of the volume's journal. 150 */ 151static _Bool 152hfs_is_journal_file(struct hfsmount *hfsmp, struct cnode *cp) 153{ 154 if (hfsmp->jnl != NULL && 155 (cp->c_fileid == hfsmp->hfs_jnlinfoblkid || 156 cp->c_fileid == hfsmp->hfs_jnlfileid)) { 157 return true; 158 } else { 159 return false; 160 } 161} 162 163/* 164 * Create a regular file. 165 */ 166int 167hfs_vnop_create(struct vnop_create_args *ap) 168{ 169 int error; 170 171again: 172 error = hfs_makenode(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap, ap->a_context); 173 174 /* 175 * We speculatively skipped the original lookup of the leaf 176 * for CREATE. Since it exists, go get it as long as they 177 * didn't want an exclusive create. 178 */ 179 if ((error == EEXIST) && !(ap->a_vap->va_vaflags & VA_EXCLUSIVE)) { 180 struct vnop_lookup_args args; 181 182 args.a_desc = &vnop_lookup_desc; 183 args.a_dvp = ap->a_dvp; 184 args.a_vpp = ap->a_vpp; 185 args.a_cnp = ap->a_cnp; 186 args.a_context = ap->a_context; 187 args.a_cnp->cn_nameiop = LOOKUP; 188 error = hfs_vnop_lookup(&args); 189 /* 190 * We can also race with remove for this file. 191 */ 192 if (error == ENOENT) { 193 goto again; 194 } 195 196 /* Make sure it was file. */ 197 if ((error == 0) && !vnode_isreg(*args.a_vpp)) { 198 vnode_put(*args.a_vpp); 199 *args.a_vpp = NULLVP; 200 error = EEXIST; 201 } 202 args.a_cnp->cn_nameiop = CREATE; 203 } 204 return (error); 205} 206 207/* 208 * Make device special file. 209 */ 210int 211hfs_vnop_mknod(struct vnop_mknod_args *ap) 212{ 213 struct vnode_attr *vap = ap->a_vap; 214 struct vnode *dvp = ap->a_dvp; 215 struct vnode **vpp = ap->a_vpp; 216 struct cnode *cp; 217 int error; 218 219 if (VTOVCB(dvp)->vcbSigWord != kHFSPlusSigWord) { 220 return (ENOTSUP); 221 } 222 223 /* Create the vnode */ 224 error = hfs_makenode(dvp, vpp, ap->a_cnp, vap, ap->a_context); 225 if (error) 226 return (error); 227 228 cp = VTOC(*vpp); 229 cp->c_touch_acctime = TRUE; 230 cp->c_touch_chgtime = TRUE; 231 cp->c_touch_modtime = TRUE; 232 233 if ((vap->va_rdev != VNOVAL) && 234 (vap->va_type == VBLK || vap->va_type == VCHR)) 235 cp->c_rdev = vap->va_rdev; 236 237 return (0); 238} 239 240#if HFS_COMPRESSION 241/* 242 * hfs_ref_data_vp(): returns the data fork vnode for a given cnode. 243 * In the (hopefully rare) case where the data fork vnode is not 244 * present, it will use hfs_vget() to create a new vnode for the 245 * data fork. 246 * 247 * NOTE: If successful and a vnode is returned, the caller is responsible 248 * for releasing the returned vnode with vnode_rele(). 249 */ 250static int 251hfs_ref_data_vp(struct cnode *cp, struct vnode **data_vp, int skiplock) 252{ 253 int vref = 0; 254 255 if (!data_vp || !cp) /* sanity check incoming parameters */ 256 return EINVAL; 257 258 /* maybe we should take the hfs cnode lock here, and if so, use the skiplock parameter to tell us not to */ 259 260 if (!skiplock) hfs_lock(cp, HFS_SHARED_LOCK); 261 struct vnode *c_vp = cp->c_vp; 262 if (c_vp) { 263 /* we already have a data vnode */ 264 *data_vp = c_vp; 265 vref = vnode_ref(*data_vp); 266 if (!skiplock) hfs_unlock(cp); 267 if (vref == 0) { 268 return 0; 269 } 270 return EINVAL; 271 } 272 /* no data fork vnode in the cnode, so ask hfs for one. */ 273 274 if (!cp->c_rsrc_vp) { 275 /* if we don't have either a c_vp or c_rsrc_vp, we can't really do anything useful */ 276 *data_vp = NULL; 277 if (!skiplock) hfs_unlock(cp); 278 return EINVAL; 279 } 280 281 if (0 == hfs_vget(VTOHFS(cp->c_rsrc_vp), cp->c_cnid, data_vp, 1, 0) && 282 0 != data_vp) { 283 vref = vnode_ref(*data_vp); 284 vnode_put(*data_vp); 285 if (!skiplock) hfs_unlock(cp); 286 if (vref == 0) { 287 return 0; 288 } 289 return EINVAL; 290 } 291 /* there was an error getting the vnode */ 292 *data_vp = NULL; 293 if (!skiplock) hfs_unlock(cp); 294 return EINVAL; 295} 296 297/* 298 * hfs_lazy_init_decmpfs_cnode(): returns the decmpfs_cnode for a cnode, 299 * allocating it if necessary; returns NULL if there was an allocation error 300 */ 301static decmpfs_cnode * 302hfs_lazy_init_decmpfs_cnode(struct cnode *cp) 303{ 304 if (!cp->c_decmp) { 305 decmpfs_cnode *dp = NULL; 306 MALLOC_ZONE(dp, decmpfs_cnode *, sizeof(decmpfs_cnode), M_DECMPFS_CNODE, M_WAITOK); 307 if (!dp) { 308 /* error allocating a decmpfs cnode */ 309 return NULL; 310 } 311 decmpfs_cnode_init(dp); 312 if (!OSCompareAndSwapPtr(NULL, dp, (void * volatile *)&cp->c_decmp)) { 313 /* another thread got here first, so free the decmpfs_cnode we allocated */ 314 decmpfs_cnode_destroy(dp); 315 FREE_ZONE(dp, sizeof(*dp), M_DECMPFS_CNODE); 316 } 317 } 318 319 return cp->c_decmp; 320} 321 322/* 323 * hfs_file_is_compressed(): returns 1 if the file is compressed, and 0 (zero) if not. 324 * if the file's compressed flag is set, makes sure that the decmpfs_cnode field 325 * is allocated by calling hfs_lazy_init_decmpfs_cnode(), then makes sure it is populated, 326 * or else fills it in via the decmpfs_file_is_compressed() function. 327 */ 328int 329hfs_file_is_compressed(struct cnode *cp, int skiplock) 330{ 331 int ret = 0; 332 333 /* fast check to see if file is compressed. If flag is clear, just answer no */ 334 if (!(cp->c_bsdflags & UF_COMPRESSED)) { 335 return 0; 336 } 337 338 decmpfs_cnode *dp = hfs_lazy_init_decmpfs_cnode(cp); 339 if (!dp) { 340 /* error allocating a decmpfs cnode, treat the file as uncompressed */ 341 return 0; 342 } 343 344 /* flag was set, see if the decmpfs_cnode state is valid (zero == invalid) */ 345 uint32_t decmpfs_state = decmpfs_cnode_get_vnode_state(dp); 346 switch(decmpfs_state) { 347 case FILE_IS_COMPRESSED: 348 case FILE_IS_CONVERTING: /* treat decompressing files as if they are compressed */ 349 return 1; 350 case FILE_IS_NOT_COMPRESSED: 351 return 0; 352 /* otherwise the state is not cached yet */ 353 } 354 355 /* decmpfs hasn't seen this file yet, so call decmpfs_file_is_compressed() to init the decmpfs_cnode struct */ 356 struct vnode *data_vp = NULL; 357 if (0 == hfs_ref_data_vp(cp, &data_vp, skiplock)) { 358 if (data_vp) { 359 ret = decmpfs_file_is_compressed(data_vp, VTOCMP(data_vp)); // fill in decmpfs_cnode 360 vnode_rele(data_vp); 361 } 362 } 363 return ret; 364} 365 366/* hfs_uncompressed_size_of_compressed_file() - get the uncompressed size of the file. 367 * if the caller has passed a valid vnode (has a ref count > 0), then hfsmp and fid are not required. 368 * if the caller doesn't have a vnode, pass NULL in vp, and pass valid hfsmp and fid. 369 * files size is returned in size (required) 370 * if the indicated file is a directory (or something that doesn't have a data fork), then this call 371 * will return an error and the caller should fall back to treating the item as an uncompressed file 372 */ 373int 374hfs_uncompressed_size_of_compressed_file(struct hfsmount *hfsmp, struct vnode *vp, cnid_t fid, off_t *size, int skiplock) 375{ 376 int ret = 0; 377 int putaway = 0; /* flag to remember if we used hfs_vget() */ 378 379 if (!size) { 380 return EINVAL; /* no place to put the file size */ 381 } 382 383 if (NULL == vp) { 384 if (!hfsmp || !fid) { /* make sure we have the required parameters */ 385 return EINVAL; 386 } 387 if (0 != hfs_vget(hfsmp, fid, &vp, skiplock, 0)) { /* vnode is null, use hfs_vget() to get it */ 388 vp = NULL; 389 } else { 390 putaway = 1; /* note that hfs_vget() was used to aquire the vnode */ 391 } 392 } 393 /* this double check for compression (hfs_file_is_compressed) 394 * ensures the cached size is present in case decmpfs hasn't 395 * encountered this node yet. 396 */ 397 if (vp) { 398 if (hfs_file_is_compressed(VTOC(vp), skiplock) ) { 399 *size = decmpfs_cnode_get_vnode_cached_size(VTOCMP(vp)); /* file info will be cached now, so get size */ 400 } else { 401 if (VTOCMP(vp) && VTOCMP(vp)->cmp_type >= CMP_MAX) { 402 if (VTOCMP(vp)->cmp_type != DATALESS_CMPFS_TYPE) { 403 // if we don't recognize this type, just use the real data fork size 404 if (VTOC(vp)->c_datafork) { 405 *size = VTOC(vp)->c_datafork->ff_size; 406 ret = 0; 407 } else { 408 ret = EINVAL; 409 } 410 } else { 411 *size = decmpfs_cnode_get_vnode_cached_size(VTOCMP(vp)); /* file info will be cached now, so get size */ 412 ret = 0; 413 } 414 } else { 415 ret = EINVAL; 416 } 417 } 418 } 419 420 if (putaway) { /* did we use hfs_vget() to get this vnode? */ 421 vnode_put(vp); /* if so, release it and set it to null */ 422 vp = NULL; 423 } 424 return ret; 425} 426 427int 428hfs_hides_rsrc(vfs_context_t ctx, struct cnode *cp, int skiplock) 429{ 430 if (ctx == decmpfs_ctx) 431 return 0; 432 if (!hfs_file_is_compressed(cp, skiplock)) 433 return 0; 434 return decmpfs_hides_rsrc(ctx, cp->c_decmp); 435} 436 437int 438hfs_hides_xattr(vfs_context_t ctx, struct cnode *cp, const char *name, int skiplock) 439{ 440 if (ctx == decmpfs_ctx) 441 return 0; 442 if (!hfs_file_is_compressed(cp, skiplock)) 443 return 0; 444 return decmpfs_hides_xattr(ctx, cp->c_decmp, name); 445} 446#endif /* HFS_COMPRESSION */ 447 448/* 449 * Open a file/directory. 450 */ 451int 452hfs_vnop_open(struct vnop_open_args *ap) 453{ 454 struct vnode *vp = ap->a_vp; 455 struct filefork *fp; 456 struct timeval tv; 457 int error; 458 static int past_bootup = 0; 459 struct cnode *cp = VTOC(vp); 460 struct hfsmount *hfsmp = VTOHFS(vp); 461 462#if HFS_COMPRESSION 463 if (ap->a_mode & FWRITE) { 464 /* open for write */ 465 if ( hfs_file_is_compressed(cp, 1) ) { /* 1 == don't take the cnode lock */ 466 /* opening a compressed file for write, so convert it to decompressed */ 467 struct vnode *data_vp = NULL; 468 error = hfs_ref_data_vp(cp, &data_vp, 1); /* 1 == don't take the cnode lock */ 469 if (0 == error) { 470 if (data_vp) { 471 error = decmpfs_decompress_file(data_vp, VTOCMP(data_vp), -1, 1, 0); 472 vnode_rele(data_vp); 473 } else { 474 error = EINVAL; 475 } 476 } 477 if (error != 0) 478 return error; 479 } 480 } else { 481 /* open for read */ 482 if (hfs_file_is_compressed(cp, 1) ) { /* 1 == don't take the cnode lock */ 483 if (VNODE_IS_RSRC(vp)) { 484 /* opening the resource fork of a compressed file, so nothing to do */ 485 } else { 486 /* opening a compressed file for read, make sure it validates */ 487 error = decmpfs_validate_compressed_file(vp, VTOCMP(vp)); 488 if (error != 0) 489 return error; 490 } 491 } 492 } 493#endif 494 495 /* 496 * Files marked append-only must be opened for appending. 497 */ 498 if ((cp->c_bsdflags & APPEND) && !vnode_isdir(vp) && 499 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) 500 return (EPERM); 501 502 if (vnode_isreg(vp) && !UBCINFOEXISTS(vp)) 503 return (EBUSY); /* file is in use by the kernel */ 504 505 /* Don't allow journal to be opened externally. */ 506 if (hfs_is_journal_file(hfsmp, cp)) 507 return (EPERM); 508 509 if ((hfsmp->hfs_flags & HFS_READ_ONLY) || 510 (hfsmp->jnl == NULL) || 511#if NAMEDSTREAMS 512 !vnode_isreg(vp) || vnode_isinuse(vp, 0) || vnode_isnamedstream(vp)) { 513#else 514 !vnode_isreg(vp) || vnode_isinuse(vp, 0)) { 515#endif 516 return (0); 517 } 518 519 if ((error = hfs_lock(cp, HFS_EXCLUSIVE_LOCK))) 520 return (error); 521 522#if QUOTA 523 /* If we're going to write to the file, initialize quotas. */ 524 if ((ap->a_mode & FWRITE) && (hfsmp->hfs_flags & HFS_QUOTAS)) 525 (void)hfs_getinoquota(cp); 526#endif /* QUOTA */ 527 528 /* 529 * On the first (non-busy) open of a fragmented 530 * file attempt to de-frag it (if its less than 20MB). 531 */ 532 fp = VTOF(vp); 533 if (fp->ff_blocks && 534 fp->ff_extents[7].blockCount != 0 && 535 fp->ff_size <= (20 * 1024 * 1024)) { 536 int no_mods = 0; 537 struct timeval now; 538 /* 539 * Wait until system bootup is done (3 min). 540 * And don't relocate a file that's been modified 541 * within the past minute -- this can lead to 542 * system thrashing. 543 */ 544 545 if (!past_bootup) { 546 microuptime(&tv); 547 if (tv.tv_sec > (60*3)) { 548 past_bootup = 1; 549 } 550 } 551 552 microtime(&now); 553 if ((now.tv_sec - cp->c_mtime) > 60) { 554 no_mods = 1; 555 } 556 557 if (past_bootup && no_mods) { 558 (void) hfs_relocate(vp, hfsmp->nextAllocation + 4096, 559 vfs_context_ucred(ap->a_context), 560 vfs_context_proc(ap->a_context)); 561 } 562 } 563 564 hfs_unlock(cp); 565 566 return (0); 567} 568 569 570/* 571 * Close a file/directory. 572 */ 573int 574hfs_vnop_close(ap) 575 struct vnop_close_args /* { 576 struct vnode *a_vp; 577 int a_fflag; 578 vfs_context_t a_context; 579 } */ *ap; 580{ 581 register struct vnode *vp = ap->a_vp; 582 register struct cnode *cp; 583 struct proc *p = vfs_context_proc(ap->a_context); 584 struct hfsmount *hfsmp; 585 int busy; 586 int tooktrunclock = 0; 587 int knownrefs = 0; 588 589 if ( hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK) != 0) 590 return (0); 591 cp = VTOC(vp); 592 hfsmp = VTOHFS(vp); 593 594 /* 595 * If the rsrc fork is a named stream, it can cause the data fork to 596 * stay around, preventing de-allocation of these blocks. 597 * Do checks for truncation on close. Purge extra extents if they exist. 598 * Make sure the vp is not a directory, and that it has a resource fork, 599 * and that resource fork is also a named stream. 600 */ 601 602 if ((vp->v_type == VREG) && (cp->c_rsrc_vp) 603 && (vnode_isnamedstream(cp->c_rsrc_vp))) { 604 uint32_t blks; 605 606 blks = howmany(VTOF(vp)->ff_size, VTOVCB(vp)->blockSize); 607 /* 608 * If there are extra blocks and there are only 2 refs on 609 * this vp (ourselves + rsrc fork holding ref on us), go ahead 610 * and try to truncate. 611 */ 612 if ((blks < VTOF(vp)->ff_blocks) && (!vnode_isinuse(vp, 2))) { 613 // release cnode lock; must acquire truncate lock BEFORE cnode lock 614 hfs_unlock(cp); 615 616 hfs_lock_truncate(cp, HFS_EXCLUSIVE_LOCK); 617 tooktrunclock = 1; 618 619 if (hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK) != 0) { 620 hfs_unlock_truncate(cp, 0); 621 // bail out if we can't re-acquire cnode lock 622 return 0; 623 } 624 // now re-test to make sure it's still valid 625 if (cp->c_rsrc_vp) { 626 knownrefs = 1 + vnode_isnamedstream(cp->c_rsrc_vp); 627 if (!vnode_isinuse(vp, knownrefs)){ 628 // now we can truncate the file, if necessary 629 blks = howmany(VTOF(vp)->ff_size, VTOVCB(vp)->blockSize); 630 if (blks < VTOF(vp)->ff_blocks){ 631 (void) hfs_truncate(vp, VTOF(vp)->ff_size, IO_NDELAY, 0, 0, ap->a_context); 632 } 633 } 634 } 635 } 636 } 637 638 639 // if we froze the fs and we're exiting, then "thaw" the fs 640 if (hfsmp->hfs_freezing_proc == p && proc_exiting(p)) { 641 hfsmp->hfs_freezing_proc = NULL; 642 hfs_unlock_global (hfsmp); 643 lck_rw_unlock_exclusive(&hfsmp->hfs_insync); 644 } 645 646 busy = vnode_isinuse(vp, 1); 647 648 if (busy) { 649 hfs_touchtimes(VTOHFS(vp), cp); 650 } 651 if (vnode_isdir(vp)) { 652 hfs_reldirhints(cp, busy); 653 } else if (vnode_issystem(vp) && !busy) { 654 vnode_recycle(vp); 655 } 656 657 if (tooktrunclock){ 658 hfs_unlock_truncate(cp, 0); 659 } 660 hfs_unlock(cp); 661 662 if (ap->a_fflag & FWASWRITTEN) { 663 hfs_sync_ejectable(hfsmp); 664 } 665 666 return (0); 667} 668 669/* 670 * Get basic attributes. 671 */ 672int 673hfs_vnop_getattr(struct vnop_getattr_args *ap) 674{ 675#define VNODE_ATTR_TIMES \ 676 (VNODE_ATTR_va_access_time|VNODE_ATTR_va_change_time|VNODE_ATTR_va_modify_time) 677#define VNODE_ATTR_AUTH \ 678 (VNODE_ATTR_va_mode | VNODE_ATTR_va_uid | VNODE_ATTR_va_gid | \ 679 VNODE_ATTR_va_flags | VNODE_ATTR_va_acl) 680 681 struct vnode *vp = ap->a_vp; 682 struct vnode_attr *vap = ap->a_vap; 683 struct vnode *rvp = NULLVP; 684 struct hfsmount *hfsmp; 685 struct cnode *cp; 686 uint64_t data_size; 687 enum vtype v_type; 688 int error = 0; 689 cp = VTOC(vp); 690 691#if HFS_COMPRESSION 692 /* we need to inspect the decmpfs state of the file before we take the hfs cnode lock */ 693 int compressed = 0; 694 int hide_size = 0; 695 off_t uncompressed_size = -1; 696 if (VATTR_IS_ACTIVE(vap, va_data_size) || VATTR_IS_ACTIVE(vap, va_total_alloc) || VATTR_IS_ACTIVE(vap, va_data_alloc) || VATTR_IS_ACTIVE(vap, va_total_size)) { 697 /* we only care about whether the file is compressed if asked for the uncompressed size */ 698 if (VNODE_IS_RSRC(vp)) { 699 /* if it's a resource fork, decmpfs may want us to hide the size */ 700 hide_size = hfs_hides_rsrc(ap->a_context, cp, 0); 701 } else { 702 /* if it's a data fork, we need to know if it was compressed so we can report the uncompressed size */ 703 compressed = hfs_file_is_compressed(cp, 0); 704 } 705 if ((VATTR_IS_ACTIVE(vap, va_data_size) || VATTR_IS_ACTIVE(vap, va_total_size))) { 706 // if it's compressed 707 if (compressed || (!VNODE_IS_RSRC(vp) && cp->c_decmp && cp->c_decmp->cmp_type >= CMP_MAX)) { 708 if (0 != hfs_uncompressed_size_of_compressed_file(NULL, vp, 0, &uncompressed_size, 0)) { 709 /* failed to get the uncompressed size, we'll check for this later */ 710 uncompressed_size = -1; 711 } else { 712 // fake that it's compressed 713 compressed = 1; 714 } 715 } 716 } 717 } 718#endif 719 720 /* 721 * Shortcut for vnode_authorize path. Each of the attributes 722 * in this set is updated atomically so we don't need to take 723 * the cnode lock to access them. 724 */ 725 if ((vap->va_active & ~VNODE_ATTR_AUTH) == 0) { 726 /* Make sure file still exists. */ 727 if (cp->c_flag & C_NOEXISTS) 728 return (ENOENT); 729 730 vap->va_uid = cp->c_uid; 731 vap->va_gid = cp->c_gid; 732 vap->va_mode = cp->c_mode; 733 vap->va_flags = cp->c_bsdflags; 734 vap->va_supported |= VNODE_ATTR_AUTH & ~VNODE_ATTR_va_acl; 735 736 if ((cp->c_attr.ca_recflags & kHFSHasSecurityMask) == 0) { 737 vap->va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE; 738 VATTR_SET_SUPPORTED(vap, va_acl); 739 } 740 741 return (0); 742 } 743 744 hfsmp = VTOHFS(vp); 745 v_type = vnode_vtype(vp); 746 /* 747 * If time attributes are requested and we have cnode times 748 * that require updating, then acquire an exclusive lock on 749 * the cnode before updating the times. Otherwise we can 750 * just acquire a shared lock. 751 */ 752 if ((vap->va_active & VNODE_ATTR_TIMES) && 753 (cp->c_touch_acctime || cp->c_touch_chgtime || cp->c_touch_modtime)) { 754 if ((error = hfs_lock(cp, HFS_EXCLUSIVE_LOCK))) 755 return (error); 756 hfs_touchtimes(hfsmp, cp); 757 } 758 else { 759 if ((error = hfs_lock(cp, HFS_SHARED_LOCK))) 760 return (error); 761 } 762 763 if (v_type == VDIR) { 764 data_size = (cp->c_entries + 2) * AVERAGE_HFSDIRENTRY_SIZE; 765 766 if (VATTR_IS_ACTIVE(vap, va_nlink)) { 767 int nlink; 768 769 /* 770 * For directories, the va_nlink is esentially a count 771 * of the ".." references to a directory plus the "." 772 * reference and the directory itself. So for HFS+ this 773 * becomes the sub-directory count plus two. 774 * 775 * In the absence of a sub-directory count we use the 776 * directory's item count. This will be too high in 777 * most cases since it also includes files. 778 */ 779 if ((hfsmp->hfs_flags & HFS_FOLDERCOUNT) && 780 (cp->c_attr.ca_recflags & kHFSHasFolderCountMask)) 781 nlink = cp->c_attr.ca_dircount; /* implied ".." entries */ 782 else 783 nlink = cp->c_entries; 784 785 /* Account for ourself and our "." entry */ 786 nlink += 2; 787 /* Hide our private directories. */ 788 if (cp->c_cnid == kHFSRootFolderID) { 789 if (hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid != 0) { 790 --nlink; 791 } 792 if (hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid != 0) { 793 --nlink; 794 } 795 } 796 VATTR_RETURN(vap, va_nlink, (u_int64_t)nlink); 797 } 798 if (VATTR_IS_ACTIVE(vap, va_nchildren)) { 799 int entries; 800 801 entries = cp->c_entries; 802 /* Hide our private files and directories. */ 803 if (cp->c_cnid == kHFSRootFolderID) { 804 if (hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid != 0) 805 --entries; 806 if (hfsmp->hfs_private_desc[DIR_HARDLINKS].cd_cnid != 0) 807 --entries; 808 if (hfsmp->jnl || ((hfsmp->vcbAtrb & kHFSVolumeJournaledMask) && (hfsmp->hfs_flags & HFS_READ_ONLY))) 809 entries -= 2; /* hide the journal files */ 810 } 811 VATTR_RETURN(vap, va_nchildren, entries); 812 } 813 /* 814 * The va_dirlinkcount is the count of real directory hard links. 815 * (i.e. its not the sum of the implied "." and ".." references) 816 */ 817 if (VATTR_IS_ACTIVE(vap, va_dirlinkcount)) { 818 VATTR_RETURN(vap, va_dirlinkcount, (uint32_t)cp->c_linkcount); 819 } 820 } else /* !VDIR */ { 821 data_size = VCTOF(vp, cp)->ff_size; 822 823 VATTR_RETURN(vap, va_nlink, (u_int64_t)cp->c_linkcount); 824 if (VATTR_IS_ACTIVE(vap, va_data_alloc)) { 825 u_int64_t blocks; 826 827#if HFS_COMPRESSION 828 if (hide_size) { 829 VATTR_RETURN(vap, va_data_alloc, 0); 830 } else if (compressed) { 831 /* for compressed files, we report all allocated blocks as belonging to the data fork */ 832 blocks = cp->c_blocks; 833 VATTR_RETURN(vap, va_data_alloc, blocks * (u_int64_t)hfsmp->blockSize); 834 } 835 else 836#endif 837 { 838 blocks = VCTOF(vp, cp)->ff_blocks; 839 VATTR_RETURN(vap, va_data_alloc, blocks * (u_int64_t)hfsmp->blockSize); 840 } 841 } 842 } 843 844 /* conditional because 64-bit arithmetic can be expensive */ 845 if (VATTR_IS_ACTIVE(vap, va_total_size)) { 846 if (v_type == VDIR) { 847 VATTR_RETURN(vap, va_total_size, (cp->c_entries + 2) * AVERAGE_HFSDIRENTRY_SIZE); 848 } else { 849 u_int64_t total_size = ~0ULL; 850 struct cnode *rcp; 851#if HFS_COMPRESSION 852 if (hide_size) { 853 /* we're hiding the size of this file, so just return 0 */ 854 total_size = 0; 855 } else if (compressed) { 856 if (uncompressed_size == -1) { 857 /* 858 * We failed to get the uncompressed size above, 859 * so we'll fall back to the standard path below 860 * since total_size is still -1 861 */ 862 } else { 863 /* use the uncompressed size we fetched above */ 864 total_size = uncompressed_size; 865 } 866 } 867#endif 868 if (total_size == ~0ULL) { 869 if (cp->c_datafork) { 870 total_size = cp->c_datafork->ff_size; 871 } 872 873 if (cp->c_blocks - VTOF(vp)->ff_blocks) { 874 /* We deal with rsrc fork vnode iocount at the end of the function */ 875 error = hfs_vgetrsrc(hfsmp, vp, &rvp, TRUE, FALSE); 876 if (error) { 877 /* 878 * Note that we call hfs_vgetrsrc with error_on_unlinked 879 * set to FALSE. This is because we may be invoked via 880 * fstat() on an open-unlinked file descriptor and we must 881 * continue to support access to the rsrc fork until it disappears. 882 * The code at the end of this function will be 883 * responsible for releasing the iocount generated by 884 * hfs_vgetrsrc. This is because we can't drop the iocount 885 * without unlocking the cnode first. 886 */ 887 goto out; 888 } 889 890 rcp = VTOC(rvp); 891 if (rcp && rcp->c_rsrcfork) { 892 total_size += rcp->c_rsrcfork->ff_size; 893 } 894 } 895 } 896 897 VATTR_RETURN(vap, va_total_size, total_size); 898 } 899 } 900 if (VATTR_IS_ACTIVE(vap, va_total_alloc)) { 901 if (v_type == VDIR) { 902 VATTR_RETURN(vap, va_total_alloc, 0); 903 } else { 904 VATTR_RETURN(vap, va_total_alloc, (u_int64_t)cp->c_blocks * (u_int64_t)hfsmp->blockSize); 905 } 906 } 907 908 /* 909 * If the VFS wants extended security data, and we know that we 910 * don't have any (because it never told us it was setting any) 911 * then we can return the supported bit and no data. If we do 912 * have extended security, we can just leave the bit alone and 913 * the VFS will use the fallback path to fetch it. 914 */ 915 if (VATTR_IS_ACTIVE(vap, va_acl)) { 916 if ((cp->c_attr.ca_recflags & kHFSHasSecurityMask) == 0) { 917 vap->va_acl = (kauth_acl_t) KAUTH_FILESEC_NONE; 918 VATTR_SET_SUPPORTED(vap, va_acl); 919 } 920 } 921 if (VATTR_IS_ACTIVE(vap, va_access_time)) { 922 /* Access times are lazily updated, get current time if needed */ 923 if (cp->c_touch_acctime) { 924 struct timeval tv; 925 926 microtime(&tv); 927 vap->va_access_time.tv_sec = tv.tv_sec; 928 } else { 929 vap->va_access_time.tv_sec = cp->c_atime; 930 } 931 vap->va_access_time.tv_nsec = 0; 932 VATTR_SET_SUPPORTED(vap, va_access_time); 933 } 934 vap->va_create_time.tv_sec = cp->c_itime; 935 vap->va_create_time.tv_nsec = 0; 936 vap->va_modify_time.tv_sec = cp->c_mtime; 937 vap->va_modify_time.tv_nsec = 0; 938 vap->va_change_time.tv_sec = cp->c_ctime; 939 vap->va_change_time.tv_nsec = 0; 940 vap->va_backup_time.tv_sec = cp->c_btime; 941 vap->va_backup_time.tv_nsec = 0; 942 943 /* See if we need to emit the date added field to the user */ 944 if (VATTR_IS_ACTIVE(vap, va_addedtime)) { 945 u_int32_t dateadded = hfs_get_dateadded (cp); 946 if (dateadded) { 947 vap->va_addedtime.tv_sec = dateadded; 948 vap->va_addedtime.tv_nsec = 0; 949 VATTR_SET_SUPPORTED (vap, va_addedtime); 950 } 951 } 952 953 /* XXX is this really a good 'optimal I/O size'? */ 954 vap->va_iosize = hfsmp->hfs_logBlockSize; 955 vap->va_uid = cp->c_uid; 956 vap->va_gid = cp->c_gid; 957 vap->va_mode = cp->c_mode; 958 vap->va_flags = cp->c_bsdflags; 959 960 /* 961 * Exporting file IDs from HFS Plus: 962 * 963 * For "normal" files the c_fileid is the same value as the 964 * c_cnid. But for hard link files, they are different - the 965 * c_cnid belongs to the active directory entry (ie the link) 966 * and the c_fileid is for the actual inode (ie the data file). 967 * 968 * The stat call (getattr) uses va_fileid and the Carbon APIs, 969 * which are hardlink-ignorant, will ask for va_linkid. 970 */ 971 vap->va_fileid = (u_int64_t)cp->c_fileid; 972 /* 973 * We need to use the origin cache for both hardlinked files 974 * and directories. Hardlinked directories have multiple cnids 975 * and parents (one per link). Hardlinked files also have their 976 * own parents and link IDs separate from the indirect inode number. 977 * If we don't use the cache, we could end up vending the wrong ID 978 * because the cnode will only reflect the link that was looked up most recently. 979 */ 980 if (cp->c_flag & C_HARDLINK) { 981 vap->va_linkid = (u_int64_t)hfs_currentcnid(cp); 982 vap->va_parentid = (u_int64_t)hfs_currentparent(cp); 983 } else { 984 vap->va_linkid = (u_int64_t)cp->c_cnid; 985 vap->va_parentid = (u_int64_t)cp->c_parentcnid; 986 } 987 vap->va_fsid = hfsmp->hfs_raw_dev; 988 vap->va_filerev = 0; 989 vap->va_encoding = cp->c_encoding; 990 vap->va_rdev = (v_type == VBLK || v_type == VCHR) ? cp->c_rdev : 0; 991#if HFS_COMPRESSION 992 if (VATTR_IS_ACTIVE(vap, va_data_size)) { 993 if (hide_size) 994 vap->va_data_size = 0; 995 else if (compressed) { 996 if (uncompressed_size == -1) { 997 /* failed to get the uncompressed size above, so just return data_size */ 998 vap->va_data_size = data_size; 999 } else { 1000 /* use the uncompressed size we fetched above */ 1001 vap->va_data_size = uncompressed_size; 1002 } 1003 } else 1004 vap->va_data_size = data_size; 1005// vap->va_supported |= VNODE_ATTR_va_data_size; 1006 VATTR_SET_SUPPORTED(vap, va_data_size); 1007 } 1008#else 1009 vap->va_data_size = data_size; 1010 vap->va_supported |= VNODE_ATTR_va_data_size; 1011#endif 1012 1013 /* Mark them all at once instead of individual VATTR_SET_SUPPORTED calls. */ 1014 vap->va_supported |= VNODE_ATTR_va_create_time | VNODE_ATTR_va_modify_time | 1015 VNODE_ATTR_va_change_time| VNODE_ATTR_va_backup_time | 1016 VNODE_ATTR_va_iosize | VNODE_ATTR_va_uid | 1017 VNODE_ATTR_va_gid | VNODE_ATTR_va_mode | 1018 VNODE_ATTR_va_flags |VNODE_ATTR_va_fileid | 1019 VNODE_ATTR_va_linkid | VNODE_ATTR_va_parentid | 1020 VNODE_ATTR_va_fsid | VNODE_ATTR_va_filerev | 1021 VNODE_ATTR_va_encoding | VNODE_ATTR_va_rdev; 1022 1023 /* If this is the root, let VFS to find out the mount name, which 1024 * may be different from the real name. Otherwise, we need to take care 1025 * for hardlinked files, which need to be looked up, if necessary 1026 */ 1027 if (VATTR_IS_ACTIVE(vap, va_name) && (cp->c_cnid != kHFSRootFolderID)) { 1028 struct cat_desc linkdesc; 1029 int lockflags; 1030 int uselinkdesc = 0; 1031 cnid_t nextlinkid = 0; 1032 cnid_t prevlinkid = 0; 1033 1034 /* Get the name for ATTR_CMN_NAME. We need to take special care for hardlinks 1035 * here because the info. for the link ID requested by getattrlist may be 1036 * different than what's currently in the cnode. This is because the cnode 1037 * will be filled in with the information for the most recent link ID that went 1038 * through namei/lookup(). If there are competing lookups for hardlinks that point 1039 * to the same inode, one (or more) getattrlists could be vended incorrect name information. 1040 * Also, we need to beware of open-unlinked files which could have a namelen of 0. 1041 */ 1042 1043 if ((cp->c_flag & C_HARDLINK) && 1044 ((cp->c_desc.cd_namelen == 0) || (vap->va_linkid != cp->c_cnid))) { 1045 /* If we have no name and our link ID is the raw inode number, then we may 1046 * have an open-unlinked file. Go to the next link in this case. 1047 */ 1048 if ((cp->c_desc.cd_namelen == 0) && (vap->va_linkid == cp->c_fileid)) { 1049 if ((error = hfs_lookup_siblinglinks(hfsmp, vap->va_linkid, &prevlinkid, &nextlinkid))){ 1050 goto out; 1051 } 1052 } 1053 else { 1054 /* just use link obtained from vap above */ 1055 nextlinkid = vap->va_linkid; 1056 } 1057 1058 /* We need to probe the catalog for the descriptor corresponding to the link ID 1059 * stored in nextlinkid. Note that we don't know if we have the exclusive lock 1060 * for the cnode here, so we can't just update the descriptor. Instead, 1061 * we should just store the descriptor's value locally and then use it to pass 1062 * out the name value as needed below. 1063 */ 1064 if (nextlinkid){ 1065 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); 1066 error = cat_findname(hfsmp, nextlinkid, &linkdesc); 1067 hfs_systemfile_unlock(hfsmp, lockflags); 1068 if (error == 0) { 1069 uselinkdesc = 1; 1070 } 1071 } 1072 } 1073 1074 /* By this point, we've either patched up the name above and the c_desc 1075 * points to the correct data, or it already did, in which case we just proceed 1076 * by copying the name into the vap. Note that we will never set va_name to 1077 * supported if nextlinkid is never initialized. This could happen in the degenerate 1078 * case above involving the raw inode number, where it has no nextlinkid. In this case 1079 * we will simply not mark the name bit as supported. 1080 */ 1081 if (uselinkdesc) { 1082 strlcpy(vap->va_name, (const char*) linkdesc.cd_nameptr, MAXPATHLEN); 1083 VATTR_SET_SUPPORTED(vap, va_name); 1084 cat_releasedesc(&linkdesc); 1085 } 1086 else if (cp->c_desc.cd_namelen) { 1087 strlcpy(vap->va_name, (const char*) cp->c_desc.cd_nameptr, MAXPATHLEN); 1088 VATTR_SET_SUPPORTED(vap, va_name); 1089 } 1090 } 1091 1092out: 1093 hfs_unlock(cp); 1094 /* 1095 * We need to vnode_put the rsrc fork vnode only *after* we've released 1096 * the cnode lock, since vnode_put can trigger an inactive call, which 1097 * will go back into HFS and try to acquire a cnode lock. 1098 */ 1099 if (rvp) { 1100 vnode_put (rvp); 1101 } 1102 1103 return (error); 1104} 1105 1106int 1107hfs_vnop_setattr(ap) 1108 struct vnop_setattr_args /* { 1109 struct vnode *a_vp; 1110 struct vnode_attr *a_vap; 1111 vfs_context_t a_context; 1112 } */ *ap; 1113{ 1114 struct vnode_attr *vap = ap->a_vap; 1115 struct vnode *vp = ap->a_vp; 1116 struct cnode *cp = NULL; 1117 struct hfsmount *hfsmp; 1118 kauth_cred_t cred = vfs_context_ucred(ap->a_context); 1119 struct proc *p = vfs_context_proc(ap->a_context); 1120 int error = 0; 1121 uid_t nuid; 1122 gid_t ngid; 1123 time_t orig_ctime; 1124 1125 orig_ctime = VTOC(vp)->c_ctime; 1126 1127#if HFS_COMPRESSION 1128 int decmpfs_reset_state = 0; 1129 /* 1130 we call decmpfs_update_attributes even if the file is not compressed 1131 because we want to update the incoming flags if the xattrs are invalid 1132 */ 1133 error = decmpfs_update_attributes(vp, vap); 1134 if (error) 1135 return error; 1136 1137 // 1138 // if this is not a size-changing setattr and it is not just 1139 // an atime update, then check for a snapshot. 1140 // 1141 if (!VATTR_IS_ACTIVE(vap, va_data_size) && !(vap->va_active == VNODE_ATTR_va_access_time)) { 1142 check_for_tracked_file(vp, orig_ctime, NAMESPACE_HANDLER_METADATA_MOD, NULL); 1143 } 1144#endif 1145 1146 1147#if CONFIG_PROTECT 1148 if ((error = cp_handle_vnop(vp, CP_WRITE_ACCESS, 0)) != 0) { 1149 return (error); 1150 } 1151#endif /* CONFIG_PROTECT */ 1152 1153 hfsmp = VTOHFS(vp); 1154 1155 /* Don't allow modification of the journal. */ 1156 if (hfs_is_journal_file(hfsmp, VTOC(vp))) { 1157 return (EPERM); 1158 } 1159 1160 /* 1161 * File size change request. 1162 * We are guaranteed that this is not a directory, and that 1163 * the filesystem object is writeable. 1164 * 1165 * NOTE: HFS COMPRESSION depends on the data_size being set *before* the bsd flags are updated 1166 */ 1167 VATTR_SET_SUPPORTED(vap, va_data_size); 1168 if (VATTR_IS_ACTIVE(vap, va_data_size) && !vnode_islnk(vp)) { 1169#if HFS_COMPRESSION 1170 /* keep the compressed state locked until we're done truncating the file */ 1171 decmpfs_cnode *dp = VTOCMP(vp); 1172 if (!dp) { 1173 /* 1174 * call hfs_lazy_init_decmpfs_cnode() to make sure that the decmpfs_cnode 1175 * is filled in; we need a decmpfs_cnode to lock out decmpfs state changes 1176 * on this file while it's truncating 1177 */ 1178 dp = hfs_lazy_init_decmpfs_cnode(VTOC(vp)); 1179 if (!dp) { 1180 /* failed to allocate a decmpfs_cnode */ 1181 return ENOMEM; /* what should this be? */ 1182 } 1183 } 1184 1185 check_for_tracked_file(vp, orig_ctime, vap->va_data_size == 0 ? NAMESPACE_HANDLER_TRUNCATE_OP|NAMESPACE_HANDLER_DELETE_OP : NAMESPACE_HANDLER_TRUNCATE_OP, NULL); 1186 1187 decmpfs_lock_compressed_data(dp, 1); 1188 if (hfs_file_is_compressed(VTOC(vp), 1)) { 1189 error = decmpfs_decompress_file(vp, dp, -1/*vap->va_data_size*/, 0, 1); 1190 if (error != 0) { 1191 decmpfs_unlock_compressed_data(dp, 1); 1192 return error; 1193 } 1194 } 1195#endif 1196 1197 /* Take truncate lock before taking cnode lock. */ 1198 hfs_lock_truncate(VTOC(vp), HFS_EXCLUSIVE_LOCK); 1199 1200 /* Perform the ubc_setsize before taking the cnode lock. */ 1201 ubc_setsize(vp, vap->va_data_size); 1202 1203 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK))) { 1204 hfs_unlock_truncate(VTOC(vp), 0); 1205#if HFS_COMPRESSION 1206 decmpfs_unlock_compressed_data(dp, 1); 1207#endif 1208 return (error); 1209 } 1210 cp = VTOC(vp); 1211 1212 error = hfs_truncate(vp, vap->va_data_size, vap->va_vaflags & 0xffff, 1, 0, ap->a_context); 1213 1214 hfs_unlock_truncate(cp, 0); 1215#if HFS_COMPRESSION 1216 decmpfs_unlock_compressed_data(dp, 1); 1217#endif 1218 if (error) 1219 goto out; 1220 } 1221 if (cp == NULL) { 1222 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK))) 1223 return (error); 1224 cp = VTOC(vp); 1225 } 1226 1227 /* 1228 * If it is just an access time update request by itself 1229 * we know the request is from kernel level code, and we 1230 * can delay it without being as worried about consistency. 1231 * This change speeds up mmaps, in the rare case that they 1232 * get caught behind a sync. 1233 */ 1234 1235 if (vap->va_active == VNODE_ATTR_va_access_time) { 1236 cp->c_touch_acctime=TRUE; 1237 goto out; 1238 } 1239 1240 1241 1242 /* 1243 * Owner/group change request. 1244 * We are guaranteed that the new owner/group is valid and legal. 1245 */ 1246 VATTR_SET_SUPPORTED(vap, va_uid); 1247 VATTR_SET_SUPPORTED(vap, va_gid); 1248 nuid = VATTR_IS_ACTIVE(vap, va_uid) ? vap->va_uid : (uid_t)VNOVAL; 1249 ngid = VATTR_IS_ACTIVE(vap, va_gid) ? vap->va_gid : (gid_t)VNOVAL; 1250 if (((nuid != (uid_t)VNOVAL) || (ngid != (gid_t)VNOVAL)) && 1251 ((error = hfs_chown(vp, nuid, ngid, cred, p)) != 0)) 1252 goto out; 1253 1254 /* 1255 * Mode change request. 1256 * We are guaranteed that the mode value is valid and that in 1257 * conjunction with the owner and group, this change is legal. 1258 */ 1259 VATTR_SET_SUPPORTED(vap, va_mode); 1260 if (VATTR_IS_ACTIVE(vap, va_mode) && 1261 ((error = hfs_chmod(vp, (int)vap->va_mode, cred, p)) != 0)) 1262 goto out; 1263 1264 /* 1265 * File flags change. 1266 * We are guaranteed that only flags allowed to change given the 1267 * current securelevel are being changed. 1268 */ 1269 VATTR_SET_SUPPORTED(vap, va_flags); 1270 if (VATTR_IS_ACTIVE(vap, va_flags)) { 1271 u_int16_t *fdFlags; 1272 1273#if HFS_COMPRESSION 1274 if ((cp->c_bsdflags ^ vap->va_flags) & UF_COMPRESSED) { 1275 /* 1276 * the UF_COMPRESSED was toggled, so reset our cached compressed state 1277 * but we don't want to actually do the update until we've released the cnode lock down below 1278 * NOTE: turning the flag off doesn't actually decompress the file, so that we can 1279 * turn off the flag and look at the "raw" file for debugging purposes 1280 */ 1281 decmpfs_reset_state = 1; 1282 } 1283#endif 1284 1285 cp->c_bsdflags = vap->va_flags; 1286 cp->c_touch_chgtime = TRUE; 1287 1288 /* 1289 * Mirror the UF_HIDDEN flag to the invisible bit of the Finder Info. 1290 * 1291 * The fdFlags for files and frFlags for folders are both 8 bytes 1292 * into the userInfo (the first 16 bytes of the Finder Info). They 1293 * are both 16-bit fields. 1294 */ 1295 fdFlags = (u_int16_t *) &cp->c_finderinfo[8]; 1296 if (vap->va_flags & UF_HIDDEN) 1297 *fdFlags |= OSSwapHostToBigConstInt16(kFinderInvisibleMask); 1298 else 1299 *fdFlags &= ~OSSwapHostToBigConstInt16(kFinderInvisibleMask); 1300 } 1301 1302 /* 1303 * Timestamp updates. 1304 */ 1305 VATTR_SET_SUPPORTED(vap, va_create_time); 1306 VATTR_SET_SUPPORTED(vap, va_access_time); 1307 VATTR_SET_SUPPORTED(vap, va_modify_time); 1308 VATTR_SET_SUPPORTED(vap, va_backup_time); 1309 VATTR_SET_SUPPORTED(vap, va_change_time); 1310 if (VATTR_IS_ACTIVE(vap, va_create_time) || 1311 VATTR_IS_ACTIVE(vap, va_access_time) || 1312 VATTR_IS_ACTIVE(vap, va_modify_time) || 1313 VATTR_IS_ACTIVE(vap, va_backup_time)) { 1314 if (VATTR_IS_ACTIVE(vap, va_create_time)) 1315 cp->c_itime = vap->va_create_time.tv_sec; 1316 if (VATTR_IS_ACTIVE(vap, va_access_time)) { 1317 cp->c_atime = vap->va_access_time.tv_sec; 1318 cp->c_touch_acctime = FALSE; 1319 } 1320 if (VATTR_IS_ACTIVE(vap, va_modify_time)) { 1321 cp->c_mtime = vap->va_modify_time.tv_sec; 1322 cp->c_touch_modtime = FALSE; 1323 cp->c_touch_chgtime = TRUE; 1324 1325 /* 1326 * The utimes system call can reset the modification 1327 * time but it doesn't know about HFS create times. 1328 * So we need to ensure that the creation time is 1329 * always at least as old as the modification time. 1330 */ 1331 if ((VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) && 1332 (cp->c_cnid != kHFSRootFolderID) && 1333 (cp->c_mtime < cp->c_itime)) { 1334 cp->c_itime = cp->c_mtime; 1335 } 1336 } 1337 if (VATTR_IS_ACTIVE(vap, va_backup_time)) 1338 cp->c_btime = vap->va_backup_time.tv_sec; 1339 cp->c_flag |= C_MODIFIED; 1340 } 1341 1342 /* 1343 * Set name encoding. 1344 */ 1345 VATTR_SET_SUPPORTED(vap, va_encoding); 1346 if (VATTR_IS_ACTIVE(vap, va_encoding)) { 1347 cp->c_encoding = vap->va_encoding; 1348 hfs_setencodingbits(hfsmp, cp->c_encoding); 1349 } 1350 1351 if ((error = hfs_update(vp, TRUE)) != 0) 1352 goto out; 1353out: 1354 if (cp) { 1355 /* Purge origin cache for cnode, since caller now has correct link ID for it 1356 * We purge it here since it was acquired for us during lookup, and we no longer need it. 1357 */ 1358 if ((cp->c_flag & C_HARDLINK) && (vp->v_type != VDIR)){ 1359 hfs_relorigin(cp, 0); 1360 } 1361 1362 hfs_unlock(cp); 1363#if HFS_COMPRESSION 1364 if (decmpfs_reset_state) { 1365 /* 1366 * we've changed the UF_COMPRESSED flag, so reset the decmpfs state for this cnode 1367 * but don't do it while holding the hfs cnode lock 1368 */ 1369 decmpfs_cnode *dp = VTOCMP(vp); 1370 if (!dp) { 1371 /* 1372 * call hfs_lazy_init_decmpfs_cnode() to make sure that the decmpfs_cnode 1373 * is filled in; we need a decmpfs_cnode to prevent decmpfs state changes 1374 * on this file if it's locked 1375 */ 1376 dp = hfs_lazy_init_decmpfs_cnode(VTOC(vp)); 1377 if (!dp) { 1378 /* failed to allocate a decmpfs_cnode */ 1379 return ENOMEM; /* what should this be? */ 1380 } 1381 } 1382 decmpfs_cnode_set_vnode_state(dp, FILE_TYPE_UNKNOWN, 0); 1383 } 1384#endif 1385 } 1386 return (error); 1387} 1388 1389 1390/* 1391 * Change the mode on a file. 1392 * cnode must be locked before calling. 1393 */ 1394int 1395hfs_chmod(struct vnode *vp, int mode, __unused kauth_cred_t cred, __unused struct proc *p) 1396{ 1397 register struct cnode *cp = VTOC(vp); 1398 1399 if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord) 1400 return (0); 1401 1402 // Don't allow modification of the journal or journal_info_block 1403 if (hfs_is_journal_file(VTOHFS(vp), cp)) { 1404 return EPERM; 1405 } 1406 1407#if OVERRIDE_UNKNOWN_PERMISSIONS 1408 if (((unsigned int)vfs_flags(VTOVFS(vp))) & MNT_UNKNOWNPERMISSIONS) { 1409 return (0); 1410 }; 1411#endif 1412 cp->c_mode &= ~ALLPERMS; 1413 cp->c_mode |= (mode & ALLPERMS); 1414 cp->c_touch_chgtime = TRUE; 1415 return (0); 1416} 1417 1418 1419int 1420hfs_write_access(struct vnode *vp, kauth_cred_t cred, struct proc *p, Boolean considerFlags) 1421{ 1422 struct cnode *cp = VTOC(vp); 1423 int retval = 0; 1424 int is_member; 1425 1426 /* 1427 * Disallow write attempts on read-only file systems; 1428 * unless the file is a socket, fifo, or a block or 1429 * character device resident on the file system. 1430 */ 1431 switch (vnode_vtype(vp)) { 1432 case VDIR: 1433 case VLNK: 1434 case VREG: 1435 if (VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) 1436 return (EROFS); 1437 break; 1438 default: 1439 break; 1440 } 1441 1442 /* If immutable bit set, nobody gets to write it. */ 1443 if (considerFlags && (cp->c_bsdflags & IMMUTABLE)) 1444 return (EPERM); 1445 1446 /* Otherwise, user id 0 always gets access. */ 1447 if (!suser(cred, NULL)) 1448 return (0); 1449 1450 /* Otherwise, check the owner. */ 1451 if ((retval = hfs_owner_rights(VTOHFS(vp), cp->c_uid, cred, p, false)) == 0) 1452 return ((cp->c_mode & S_IWUSR) == S_IWUSR ? 0 : EACCES); 1453 1454 /* Otherwise, check the groups. */ 1455 if (kauth_cred_ismember_gid(cred, cp->c_gid, &is_member) == 0 && is_member) { 1456 return ((cp->c_mode & S_IWGRP) == S_IWGRP ? 0 : EACCES); 1457 } 1458 1459 /* Otherwise, check everyone else. */ 1460 return ((cp->c_mode & S_IWOTH) == S_IWOTH ? 0 : EACCES); 1461} 1462 1463 1464/* 1465 * Perform chown operation on cnode cp; 1466 * code must be locked prior to call. 1467 */ 1468int 1469#if !QUOTA 1470hfs_chown(struct vnode *vp, uid_t uid, gid_t gid, __unused kauth_cred_t cred, 1471 __unused struct proc *p) 1472#else 1473hfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred, 1474 __unused struct proc *p) 1475#endif 1476{ 1477 register struct cnode *cp = VTOC(vp); 1478 uid_t ouid; 1479 gid_t ogid; 1480#if QUOTA 1481 int error = 0; 1482 register int i; 1483 int64_t change; 1484#endif /* QUOTA */ 1485 1486 if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord) 1487 return (ENOTSUP); 1488 1489 if (((unsigned int)vfs_flags(VTOVFS(vp))) & MNT_UNKNOWNPERMISSIONS) 1490 return (0); 1491 1492 if (uid == (uid_t)VNOVAL) 1493 uid = cp->c_uid; 1494 if (gid == (gid_t)VNOVAL) 1495 gid = cp->c_gid; 1496 1497#if 0 /* we are guaranteed that this is already the case */ 1498 /* 1499 * If we don't own the file, are trying to change the owner 1500 * of the file, or are not a member of the target group, 1501 * the caller must be superuser or the call fails. 1502 */ 1503 if ((kauth_cred_getuid(cred) != cp->c_uid || uid != cp->c_uid || 1504 (gid != cp->c_gid && 1505 (kauth_cred_ismember_gid(cred, gid, &is_member) || !is_member))) && 1506 (error = suser(cred, 0))) 1507 return (error); 1508#endif 1509 1510 ogid = cp->c_gid; 1511 ouid = cp->c_uid; 1512#if QUOTA 1513 if ((error = hfs_getinoquota(cp))) 1514 return (error); 1515 if (ouid == uid) { 1516 dqrele(cp->c_dquot[USRQUOTA]); 1517 cp->c_dquot[USRQUOTA] = NODQUOT; 1518 } 1519 if (ogid == gid) { 1520 dqrele(cp->c_dquot[GRPQUOTA]); 1521 cp->c_dquot[GRPQUOTA] = NODQUOT; 1522 } 1523 1524 /* 1525 * Eventually need to account for (fake) a block per directory 1526 * if (vnode_isdir(vp)) 1527 * change = VTOHFS(vp)->blockSize; 1528 * else 1529 */ 1530 1531 change = (int64_t)(cp->c_blocks) * (int64_t)VTOVCB(vp)->blockSize; 1532 (void) hfs_chkdq(cp, -change, cred, CHOWN); 1533 (void) hfs_chkiq(cp, -1, cred, CHOWN); 1534 for (i = 0; i < MAXQUOTAS; i++) { 1535 dqrele(cp->c_dquot[i]); 1536 cp->c_dquot[i] = NODQUOT; 1537 } 1538#endif /* QUOTA */ 1539 cp->c_gid = gid; 1540 cp->c_uid = uid; 1541#if QUOTA 1542 if ((error = hfs_getinoquota(cp)) == 0) { 1543 if (ouid == uid) { 1544 dqrele(cp->c_dquot[USRQUOTA]); 1545 cp->c_dquot[USRQUOTA] = NODQUOT; 1546 } 1547 if (ogid == gid) { 1548 dqrele(cp->c_dquot[GRPQUOTA]); 1549 cp->c_dquot[GRPQUOTA] = NODQUOT; 1550 } 1551 if ((error = hfs_chkdq(cp, change, cred, CHOWN)) == 0) { 1552 if ((error = hfs_chkiq(cp, 1, cred, CHOWN)) == 0) 1553 goto good; 1554 else 1555 (void) hfs_chkdq(cp, -change, cred, CHOWN|FORCE); 1556 } 1557 for (i = 0; i < MAXQUOTAS; i++) { 1558 dqrele(cp->c_dquot[i]); 1559 cp->c_dquot[i] = NODQUOT; 1560 } 1561 } 1562 cp->c_gid = ogid; 1563 cp->c_uid = ouid; 1564 if (hfs_getinoquota(cp) == 0) { 1565 if (ouid == uid) { 1566 dqrele(cp->c_dquot[USRQUOTA]); 1567 cp->c_dquot[USRQUOTA] = NODQUOT; 1568 } 1569 if (ogid == gid) { 1570 dqrele(cp->c_dquot[GRPQUOTA]); 1571 cp->c_dquot[GRPQUOTA] = NODQUOT; 1572 } 1573 (void) hfs_chkdq(cp, change, cred, FORCE|CHOWN); 1574 (void) hfs_chkiq(cp, 1, cred, FORCE|CHOWN); 1575 (void) hfs_getinoquota(cp); 1576 } 1577 return (error); 1578good: 1579 if (hfs_getinoquota(cp)) 1580 panic("hfs_chown: lost quota"); 1581#endif /* QUOTA */ 1582 1583 1584 /* 1585 According to the SUSv3 Standard, chown() shall mark 1586 for update the st_ctime field of the file. 1587 (No exceptions mentioned) 1588 */ 1589 cp->c_touch_chgtime = TRUE; 1590 return (0); 1591} 1592 1593 1594/* 1595 * The hfs_exchange routine swaps the fork data in two files by 1596 * exchanging some of the information in the cnode. It is used 1597 * to preserve the file ID when updating an existing file, in 1598 * case the file is being tracked through its file ID. Typically 1599 * its used after creating a new file during a safe-save. 1600 */ 1601int 1602hfs_vnop_exchange(ap) 1603 struct vnop_exchange_args /* { 1604 struct vnode *a_fvp; 1605 struct vnode *a_tvp; 1606 int a_options; 1607 vfs_context_t a_context; 1608 } */ *ap; 1609{ 1610 struct vnode *from_vp = ap->a_fvp; 1611 struct vnode *to_vp = ap->a_tvp; 1612 struct cnode *from_cp; 1613 struct cnode *to_cp; 1614 struct hfsmount *hfsmp; 1615 struct cat_desc tempdesc; 1616 struct cat_attr tempattr; 1617 const unsigned char *from_nameptr; 1618 const unsigned char *to_nameptr; 1619 char from_iname[32]; 1620 char to_iname[32]; 1621 uint32_t to_flag_special; 1622 uint32_t from_flag_special; 1623 cnid_t from_parid; 1624 cnid_t to_parid; 1625 int lockflags; 1626 int error = 0, started_tr = 0, got_cookie = 0; 1627 cat_cookie_t cookie; 1628 time_t orig_from_ctime, orig_to_ctime; 1629 1630 /* The files must be on the same volume. */ 1631 if (vnode_mount(from_vp) != vnode_mount(to_vp)) 1632 return (EXDEV); 1633 1634 if (from_vp == to_vp) 1635 return (EINVAL); 1636 1637 orig_from_ctime = VTOC(from_vp)->c_ctime; 1638 orig_to_ctime = VTOC(to_vp)->c_ctime; 1639 1640 1641#if CONFIG_PROTECT 1642 /* 1643 * Do not allow exchangedata/F_MOVEDATAEXTENTS on data-protected filesystems 1644 * because the EAs will not be swapped. As a result, the persistent keys would not 1645 * match and the files will be garbage. 1646 */ 1647 if (cp_fs_protected (vnode_mount(from_vp))) { 1648 return EINVAL; 1649 } 1650#endif 1651 1652#if HFS_COMPRESSION 1653 if ( hfs_file_is_compressed(VTOC(from_vp), 0) ) { 1654 if ( 0 != ( error = decmpfs_decompress_file(from_vp, VTOCMP(from_vp), -1, 0, 1) ) ) { 1655 return error; 1656 } 1657 } 1658 1659 if ( hfs_file_is_compressed(VTOC(to_vp), 0) ) { 1660 if ( 0 != ( error = decmpfs_decompress_file(to_vp, VTOCMP(to_vp), -1, 0, 1) ) ) { 1661 return error; 1662 } 1663 } 1664#endif // HFS_COMPRESSION 1665 1666 /* 1667 * Normally, we want to notify the user handlers about the event, 1668 * except if it's a handler driving the event. 1669 */ 1670 if ((ap->a_options & FSOPT_EXCHANGE_DATA_ONLY) == 0) { 1671 check_for_tracked_file(from_vp, orig_from_ctime, NAMESPACE_HANDLER_WRITE_OP, NULL); 1672 check_for_tracked_file(to_vp, orig_to_ctime, NAMESPACE_HANDLER_WRITE_OP, NULL); 1673 } else { 1674 /* 1675 * We're doing a data-swap. 1676 * Take the truncate lock/cnode lock, then verify there are no mmap references. 1677 * Issue a hfs_filedone to flush out all of the remaining state for this file. 1678 * Allow the rest of the codeflow to re-acquire the cnode locks in order. 1679 */ 1680 1681 hfs_lock_truncate (VTOC(from_vp), HFS_SHARED_LOCK); 1682 1683 if ((error = hfs_lock(VTOC(from_vp), HFS_EXCLUSIVE_LOCK))) { 1684 hfs_unlock_truncate (VTOC(from_vp), 0); 1685 return error; 1686 } 1687 1688 /* Verify the source file is not in use by anyone besides us (including mmap refs) */ 1689 if (vnode_isinuse(from_vp, 1)) { 1690 error = EBUSY; 1691 hfs_unlock(VTOC(from_vp)); 1692 hfs_unlock_truncate (VTOC(from_vp), 0); 1693 return error; 1694 } 1695 1696 /* Flush out the data in the source file */ 1697 VTOC(from_vp)->c_flag |= C_SWAPINPROGRESS; 1698 error = hfs_filedone (from_vp, ap->a_context); 1699 VTOC(from_vp)->c_flag &= ~C_SWAPINPROGRESS; 1700 hfs_unlock(VTOC(from_vp)); 1701 hfs_unlock_truncate(VTOC(from_vp), 0); 1702 1703 if (error) { 1704 return error; 1705 } 1706 } 1707 1708 if ((error = hfs_lockpair(VTOC(from_vp), VTOC(to_vp), HFS_EXCLUSIVE_LOCK))) 1709 return (error); 1710 1711 from_cp = VTOC(from_vp); 1712 to_cp = VTOC(to_vp); 1713 hfsmp = VTOHFS(from_vp); 1714 1715 /* Resource forks cannot be exchanged. */ 1716 if (VNODE_IS_RSRC(from_vp) || VNODE_IS_RSRC(to_vp)) { 1717 error = EINVAL; 1718 goto exit; 1719 } 1720 1721 // Don't allow modification of the journal or journal_info_block 1722 if (hfs_is_journal_file(hfsmp, from_cp) || 1723 hfs_is_journal_file(hfsmp, to_cp)) { 1724 error = EPERM; 1725 goto exit; 1726 } 1727 1728 /* 1729 * Ok, now that all of the pre-flighting is done, call the underlying 1730 * function if needed. 1731 */ 1732 if (ap->a_options & FSOPT_EXCHANGE_DATA_ONLY) { 1733 error = hfs_movedata(from_vp, to_vp); 1734 goto exit; 1735 } 1736 1737 1738 if ((error = hfs_start_transaction(hfsmp)) != 0) { 1739 goto exit; 1740 } 1741 started_tr = 1; 1742 1743 /* 1744 * Reserve some space in the Catalog file. 1745 */ 1746 if ((error = cat_preflight(hfsmp, CAT_EXCHANGE, &cookie, vfs_context_proc(ap->a_context)))) { 1747 goto exit; 1748 } 1749 got_cookie = 1; 1750 1751 /* The backend code always tries to delete the virtual 1752 * extent id for exchanging files so we need to lock 1753 * the extents b-tree. 1754 */ 1755 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_EXTENTS | SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK); 1756 1757 /* Account for the location of the catalog objects. */ 1758 if (from_cp->c_flag & C_HARDLINK) { 1759 MAKE_INODE_NAME(from_iname, sizeof(from_iname), 1760 from_cp->c_attr.ca_linkref); 1761 from_nameptr = (unsigned char *)from_iname; 1762 from_parid = hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid; 1763 from_cp->c_hint = 0; 1764 } else { 1765 from_nameptr = from_cp->c_desc.cd_nameptr; 1766 from_parid = from_cp->c_parentcnid; 1767 } 1768 if (to_cp->c_flag & C_HARDLINK) { 1769 MAKE_INODE_NAME(to_iname, sizeof(to_iname), 1770 to_cp->c_attr.ca_linkref); 1771 to_nameptr = (unsigned char *)to_iname; 1772 to_parid = hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid; 1773 to_cp->c_hint = 0; 1774 } else { 1775 to_nameptr = to_cp->c_desc.cd_nameptr; 1776 to_parid = to_cp->c_parentcnid; 1777 } 1778 1779 /* Do the exchange */ 1780 error = ExchangeFileIDs(hfsmp, from_nameptr, to_nameptr, from_parid, 1781 to_parid, from_cp->c_hint, to_cp->c_hint); 1782 hfs_systemfile_unlock(hfsmp, lockflags); 1783 1784 /* 1785 * Note that we don't need to exchange any extended attributes 1786 * since the attributes are keyed by file ID. 1787 */ 1788 1789 if (error != E_NONE) { 1790 error = MacToVFSError(error); 1791 goto exit; 1792 } 1793 1794 /* Purge the vnodes from the name cache */ 1795 if (from_vp) 1796 cache_purge(from_vp); 1797 if (to_vp) 1798 cache_purge(to_vp); 1799 1800 /* Save a copy of from attributes before swapping. */ 1801 bcopy(&from_cp->c_desc, &tempdesc, sizeof(struct cat_desc)); 1802 bcopy(&from_cp->c_attr, &tempattr, sizeof(struct cat_attr)); 1803 1804 /* Save whether or not each cnode is a hardlink or has EAs */ 1805 from_flag_special = from_cp->c_flag & (C_HARDLINK | C_HASXATTRS); 1806 to_flag_special = to_cp->c_flag & (C_HARDLINK | C_HASXATTRS); 1807 1808 /* Drop the special bits from each cnode */ 1809 from_cp->c_flag &= ~(C_HARDLINK | C_HASXATTRS); 1810 to_cp->c_flag &= ~(C_HARDLINK | C_HASXATTRS); 1811 1812 /* 1813 * Swap the descriptors and all non-fork related attributes. 1814 * (except the modify date) 1815 */ 1816 bcopy(&to_cp->c_desc, &from_cp->c_desc, sizeof(struct cat_desc)); 1817 1818 from_cp->c_hint = 0; 1819 /* 1820 * If 'to' was a hardlink, then we copied over its link ID/CNID/(namespace ID) 1821 * when we bcopy'd the descriptor above. However, we need to be careful 1822 * when setting up the fileID below, because we cannot assume that the 1823 * file ID is the same as the CNID if either one was a hardlink. 1824 * The file ID is stored in the c_attr as the ca_fileid. So it needs 1825 * to be pulled explicitly; we cannot just use the CNID. 1826 */ 1827 from_cp->c_fileid = to_cp->c_attr.ca_fileid; 1828 1829 from_cp->c_itime = to_cp->c_itime; 1830 from_cp->c_btime = to_cp->c_btime; 1831 from_cp->c_atime = to_cp->c_atime; 1832 from_cp->c_ctime = to_cp->c_ctime; 1833 from_cp->c_gid = to_cp->c_gid; 1834 from_cp->c_uid = to_cp->c_uid; 1835 from_cp->c_bsdflags = to_cp->c_bsdflags; 1836 from_cp->c_mode = to_cp->c_mode; 1837 from_cp->c_linkcount = to_cp->c_linkcount; 1838 from_cp->c_attr.ca_linkref = to_cp->c_attr.ca_linkref; 1839 from_cp->c_attr.ca_firstlink = to_cp->c_attr.ca_firstlink; 1840 1841 /* 1842 * The cnode flags need to stay with the cnode and not get transferred 1843 * over along with everything else because they describe the content; they are 1844 * not attributes that reflect changes specific to the file ID. In general, 1845 * fields that are tied to the file ID are the ones that will move. 1846 * 1847 * This reflects the fact that the file may have borrowed blocks, dirty metadata, 1848 * or other extents, which may not yet have been written to the catalog. If 1849 * they were, they would have been transferred above in the ExchangeFileIDs call above... 1850 * 1851 * The flags that are special are: 1852 * C_HARDLINK, C_HASXATTRS 1853 * 1854 * These flags move with the item and file ID in the namespace since their 1855 * state is tied to that of the file ID. 1856 * 1857 * So to transfer the flags, we have to take the following steps 1858 * 1) Store in a localvar whether or not the special bits are set. 1859 * 2) Drop the special bits from the current flags 1860 * 3) swap the special flag bits to their destination 1861 */ 1862 from_cp->c_flag |= to_flag_special; 1863 1864 from_cp->c_attr.ca_recflags = to_cp->c_attr.ca_recflags; 1865 bcopy(to_cp->c_finderinfo, from_cp->c_finderinfo, 32); 1866 1867 bcopy(&tempdesc, &to_cp->c_desc, sizeof(struct cat_desc)); 1868 to_cp->c_hint = 0; 1869 /* 1870 * Pull the file ID from the tempattr we copied above. We can't assume 1871 * it is the same as the CNID. 1872 */ 1873 to_cp->c_fileid = tempattr.ca_fileid; 1874 to_cp->c_itime = tempattr.ca_itime; 1875 to_cp->c_btime = tempattr.ca_btime; 1876 to_cp->c_atime = tempattr.ca_atime; 1877 to_cp->c_ctime = tempattr.ca_ctime; 1878 to_cp->c_gid = tempattr.ca_gid; 1879 to_cp->c_uid = tempattr.ca_uid; 1880 to_cp->c_bsdflags = tempattr.ca_flags; 1881 to_cp->c_mode = tempattr.ca_mode; 1882 to_cp->c_linkcount = tempattr.ca_linkcount; 1883 to_cp->c_attr.ca_linkref = tempattr.ca_linkref; 1884 to_cp->c_attr.ca_firstlink = tempattr.ca_firstlink; 1885 1886 /* 1887 * Only OR in the "from" flags into our cnode flags below. 1888 * Leave the rest of the flags alone. 1889 */ 1890 to_cp->c_flag |= from_flag_special; 1891 1892 to_cp->c_attr.ca_recflags = tempattr.ca_recflags; 1893 bcopy(tempattr.ca_finderinfo, to_cp->c_finderinfo, 32); 1894 1895 /* Rehash the cnodes using their new file IDs */ 1896 hfs_chash_rehash(hfsmp, from_cp, to_cp); 1897 1898 /* 1899 * When a file moves out of "Cleanup At Startup" 1900 * we can drop its NODUMP status. 1901 */ 1902 if ((from_cp->c_bsdflags & UF_NODUMP) && 1903 (from_cp->c_parentcnid != to_cp->c_parentcnid)) { 1904 from_cp->c_bsdflags &= ~UF_NODUMP; 1905 from_cp->c_touch_chgtime = TRUE; 1906 } 1907 if ((to_cp->c_bsdflags & UF_NODUMP) && 1908 (to_cp->c_parentcnid != from_cp->c_parentcnid)) { 1909 to_cp->c_bsdflags &= ~UF_NODUMP; 1910 to_cp->c_touch_chgtime = TRUE; 1911 } 1912 1913exit: 1914 if (got_cookie) { 1915 cat_postflight(hfsmp, &cookie, vfs_context_proc(ap->a_context)); 1916 } 1917 if (started_tr) { 1918 hfs_end_transaction(hfsmp); 1919 } 1920 1921 hfs_unlockpair(from_cp, to_cp); 1922 return (error); 1923} 1924 1925int 1926hfs_vnop_mmap(struct vnop_mmap_args *ap) 1927{ 1928 struct vnode *vp = ap->a_vp; 1929 int error; 1930 1931 if (VNODE_IS_RSRC(vp)) { 1932 /* allow pageins of the resource fork */ 1933 } else { 1934 int compressed = hfs_file_is_compressed(VTOC(vp), 1); /* 1 == don't take the cnode lock */ 1935 time_t orig_ctime = VTOC(vp)->c_ctime; 1936 1937 if (!compressed && (VTOC(vp)->c_bsdflags & UF_COMPRESSED)) { 1938 error = check_for_dataless_file(vp, NAMESPACE_HANDLER_READ_OP); 1939 if (error != 0) { 1940 return error; 1941 } 1942 } 1943 1944 if (ap->a_fflags & PROT_WRITE) { 1945 check_for_tracked_file(vp, orig_ctime, NAMESPACE_HANDLER_WRITE_OP, NULL); 1946 } 1947 } 1948 1949 // 1950 // NOTE: we return ENOTSUP because we want the cluster layer 1951 // to actually do all the real work. 1952 // 1953 return (ENOTSUP); 1954} 1955 1956/* 1957 * hfs_movedata 1958 * 1959 * This is a non-symmetric variant of exchangedata. In this function, 1960 * the contents of the fork in from_vp are moved to the fork 1961 * specified by to_vp. 1962 * 1963 * The cnodes pointed to by 'from_vp' and 'to_vp' must be locked. 1964 * 1965 * The vnode pointed to by 'to_vp' *must* be empty prior to invoking this function. 1966 * We impose this restriction because we may not be able to fully delete the entire 1967 * file's contents in a single transaction, particularly if it has a lot of extents. 1968 * In the normal file deletion codepath, the file is screened for two conditions: 1969 * 1) bigger than 400MB, and 2) more than 8 extents. If so, the file is relocated to 1970 * the hidden directory and the deletion is broken up into multiple truncates. We can't 1971 * do that here because both files need to exist in the namespace. The main reason this 1972 * is imposed is that we may have to touch a whole lot of bitmap blocks if there are 1973 * many extents. 1974 * 1975 * Any data written to 'from_vp' after this call completes is not guaranteed 1976 * to be moved. 1977 * 1978 * Arguments: 1979 * vnode from_vp: source file 1980 * vnode to_vp: destination file; must be empty 1981 * 1982 * Returns: 1983 * EFBIG - Destination file was not empty 1984 * 0 - success 1985 * 1986 * 1987 */ 1988int hfs_movedata (struct vnode *from_vp, struct vnode *to_vp) { 1989 1990 struct cnode *from_cp; 1991 struct cnode *to_cp; 1992 struct hfsmount *hfsmp = NULL; 1993 int error = 0; 1994 int started_tr = 0; 1995 int lockflags = 0; 1996 int overflow_blocks; 1997 int rsrc = 0; 1998 1999 2000 /* Get the HFS pointers */ 2001 from_cp = VTOC(from_vp); 2002 to_cp = VTOC(to_vp); 2003 hfsmp = VTOHFS(from_vp); 2004 2005 /* Verify that neither source/dest file is open-unlinked */ 2006 if (from_cp->c_flag & (C_DELETED | C_NOEXISTS)) { 2007 error = EBUSY; 2008 goto movedata_exit; 2009 } 2010 2011 if (to_cp->c_flag & (C_DELETED | C_NOEXISTS)) { 2012 error = EBUSY; 2013 goto movedata_exit; 2014 } 2015 2016 /* 2017 * Verify the source file is not in use by anyone besides us. 2018 * 2019 * This function is typically invoked by a namespace handler 2020 * process responding to a temporarily stalled system call. 2021 * The FD that it is working off of is opened O_EVTONLY, so 2022 * it really has no active usecounts (the kusecount from O_EVTONLY 2023 * is subtracted from the total usecounts). 2024 * 2025 * As a result, we shouldn't have any active usecounts against 2026 * this vnode when we go to check it below. 2027 */ 2028 if (vnode_isinuse(from_vp, 0)) { 2029 error = EBUSY; 2030 goto movedata_exit; 2031 } 2032 2033 if (from_cp->c_rsrc_vp == from_vp) { 2034 rsrc = 1; 2035 } 2036 2037 /* 2038 * We assume that the destination file is already empty. 2039 * Verify that it is. 2040 */ 2041 if (rsrc) { 2042 if (to_cp->c_rsrcfork->ff_size > 0) { 2043 error = EFBIG; 2044 goto movedata_exit; 2045 } 2046 } 2047 else { 2048 if (to_cp->c_datafork->ff_size > 0) { 2049 error = EFBIG; 2050 goto movedata_exit; 2051 } 2052 } 2053 2054 /* If the source has the rsrc open, make sure the destination is also the rsrc */ 2055 if (rsrc) { 2056 if (to_vp != to_cp->c_rsrc_vp) { 2057 error = EINVAL; 2058 goto movedata_exit; 2059 } 2060 } 2061 else { 2062 /* Verify that both forks are data forks */ 2063 if (to_vp != to_cp->c_vp) { 2064 error = EINVAL; 2065 goto movedata_exit; 2066 } 2067 } 2068 2069 /* 2070 * See if the source file has overflow extents. If it doesn't, we don't 2071 * need to call into MoveData, and the catalog will be enough. 2072 */ 2073 if (rsrc) { 2074 overflow_blocks = overflow_extents(from_cp->c_rsrcfork); 2075 } 2076 else { 2077 overflow_blocks = overflow_extents(from_cp->c_datafork); 2078 } 2079 2080 if ((error = hfs_start_transaction (hfsmp)) != 0) { 2081 goto movedata_exit; 2082 } 2083 started_tr = 1; 2084 2085 /* Lock the system files: catalog, extents, attributes */ 2086 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_EXTENTS | SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK); 2087 2088 /* Copy over any catalog allocation data into the new spot. */ 2089 if (rsrc) { 2090 if ((error = hfs_move_fork (from_cp->c_rsrcfork, from_cp, to_cp->c_rsrcfork, to_cp))){ 2091 hfs_systemfile_unlock(hfsmp, lockflags); 2092 goto movedata_exit; 2093 } 2094 } 2095 else { 2096 if ((error = hfs_move_fork (from_cp->c_datafork, from_cp, to_cp->c_datafork, to_cp))) { 2097 hfs_systemfile_unlock(hfsmp, lockflags); 2098 goto movedata_exit; 2099 } 2100 } 2101 2102 /* 2103 * Note that because all we're doing is moving the extents around, we can 2104 * probably do this in a single transaction: Each extent record (group of 8) 2105 * is 64 bytes. A extent overflow B-Tree node is typically 4k. This means 2106 * each node can hold roughly ~60 extent records == (480 extents). 2107 * 2108 * If a file was massively fragmented and had 20k extents, this means we'd 2109 * roughly touch 20k/480 == 41 to 42 nodes, plus the index nodes, for half 2110 * of the operation. (inserting or deleting). So if we're manipulating 80-100 2111 * nodes, this is basically 320k of data to write to the journal in 2112 * a bad case. 2113 */ 2114 if (overflow_blocks != 0) { 2115 if (rsrc) { 2116 error = MoveData(hfsmp, from_cp->c_cnid, to_cp->c_cnid, 1); 2117 } 2118 else { 2119 error = MoveData (hfsmp, from_cp->c_cnid, to_cp->c_cnid, 0); 2120 } 2121 } 2122 2123 if (error) { 2124 /* Reverse the operation. Copy the fork data back into the source */ 2125 if (rsrc) { 2126 hfs_move_fork (to_cp->c_rsrcfork, to_cp, from_cp->c_rsrcfork, from_cp); 2127 } 2128 else { 2129 hfs_move_fork (to_cp->c_datafork, to_cp, from_cp->c_datafork, from_cp); 2130 } 2131 } 2132 else { 2133 struct cat_fork *src_data = NULL; 2134 struct cat_fork *src_rsrc = NULL; 2135 struct cat_fork *dst_data = NULL; 2136 struct cat_fork *dst_rsrc = NULL; 2137 2138 /* Touch the times*/ 2139 to_cp->c_touch_acctime = TRUE; 2140 to_cp->c_touch_chgtime = TRUE; 2141 to_cp->c_touch_modtime = TRUE; 2142 2143 from_cp->c_touch_acctime = TRUE; 2144 from_cp->c_touch_chgtime = TRUE; 2145 from_cp->c_touch_modtime = TRUE; 2146 2147 hfs_touchtimes(hfsmp, to_cp); 2148 hfs_touchtimes(hfsmp, from_cp); 2149 2150 if (from_cp->c_datafork) { 2151 src_data = &from_cp->c_datafork->ff_data; 2152 } 2153 if (from_cp->c_rsrcfork) { 2154 src_rsrc = &from_cp->c_rsrcfork->ff_data; 2155 } 2156 2157 if (to_cp->c_datafork) { 2158 dst_data = &to_cp->c_datafork->ff_data; 2159 } 2160 if (to_cp->c_rsrcfork) { 2161 dst_rsrc = &to_cp->c_rsrcfork->ff_data; 2162 } 2163 2164 /* Update the catalog nodes */ 2165 (void) cat_update(hfsmp, &from_cp->c_desc, &from_cp->c_attr, 2166 src_data, src_rsrc); 2167 2168 (void) cat_update(hfsmp, &to_cp->c_desc, &to_cp->c_attr, 2169 dst_data, dst_rsrc); 2170 2171 } 2172 /* unlock the system files */ 2173 hfs_systemfile_unlock(hfsmp, lockflags); 2174 2175 2176movedata_exit: 2177 if (started_tr) { 2178 hfs_end_transaction(hfsmp); 2179 } 2180 2181 return error; 2182 2183} 2184 2185/* 2186 * Copy all of the catalog and runtime data in srcfork to dstfork. 2187 * 2188 * This allows us to maintain the invalid ranges across the movedata operation so 2189 * we don't need to force all of the pending IO right now. In addition, we move all 2190 * non overflow-extent extents into the destination here. 2191 */ 2192static int hfs_move_fork (struct filefork *srcfork, struct cnode *src_cp, 2193 struct filefork *dstfork, struct cnode *dst_cp) { 2194 struct rl_entry *invalid_range; 2195 int size = sizeof(struct HFSPlusExtentDescriptor); 2196 size = size * kHFSPlusExtentDensity; 2197 2198 /* If the dstfork has any invalid ranges, bail out */ 2199 invalid_range = TAILQ_FIRST(&dstfork->ff_invalidranges); 2200 if (invalid_range != NULL) { 2201 return EFBIG; 2202 } 2203 2204 if (dstfork->ff_data.cf_size != 0 || dstfork->ff_data.cf_new_size != 0) { 2205 return EFBIG; 2206 } 2207 2208 /* First copy the invalid ranges */ 2209 while ((invalid_range = TAILQ_FIRST(&srcfork->ff_invalidranges))) { 2210 off_t start = invalid_range->rl_start; 2211 off_t end = invalid_range->rl_end; 2212 2213 /* Remove it from the srcfork and add it to dstfork */ 2214 rl_remove(start, end, &srcfork->ff_invalidranges); 2215 rl_add(start, end, &dstfork->ff_invalidranges); 2216 } 2217 2218 /* 2219 * Ignore the ff_union. We don't move symlinks or system files. 2220 * Now copy the in-catalog extent information 2221 */ 2222 dstfork->ff_data.cf_size = srcfork->ff_data.cf_size; 2223 dstfork->ff_data.cf_new_size = srcfork->ff_data.cf_new_size; 2224 dstfork->ff_data.cf_vblocks = srcfork->ff_data.cf_vblocks; 2225 dstfork->ff_data.cf_blocks = srcfork->ff_data.cf_blocks; 2226 2227 /* just memcpy the whole array of extents to the new location. */ 2228 memcpy (dstfork->ff_data.cf_extents, srcfork->ff_data.cf_extents, size); 2229 2230 /* 2231 * Copy the cnode attribute data. 2232 * 2233 */ 2234 src_cp->c_blocks -= srcfork->ff_data.cf_vblocks; 2235 src_cp->c_blocks -= srcfork->ff_data.cf_blocks; 2236 2237 dst_cp->c_blocks += srcfork->ff_data.cf_vblocks; 2238 dst_cp->c_blocks += srcfork->ff_data.cf_blocks; 2239 2240 /* Now delete the entries in the source fork */ 2241 srcfork->ff_data.cf_size = 0; 2242 srcfork->ff_data.cf_new_size = 0; 2243 srcfork->ff_data.cf_union.cfu_bytesread = 0; 2244 srcfork->ff_data.cf_vblocks = 0; 2245 srcfork->ff_data.cf_blocks = 0; 2246 2247 /* Zero out the old extents */ 2248 bzero (srcfork->ff_data.cf_extents, size); 2249 return 0; 2250} 2251 2252 2253/* 2254 * cnode must be locked 2255 */ 2256int 2257hfs_fsync(struct vnode *vp, int waitfor, int fullsync, struct proc *p) 2258{ 2259 struct cnode *cp = VTOC(vp); 2260 struct filefork *fp = NULL; 2261 int retval = 0; 2262 struct hfsmount *hfsmp = VTOHFS(vp); 2263 struct rl_entry *invalid_range; 2264 struct timeval tv; 2265 int waitdata; /* attributes necessary for data retrieval */ 2266 int wait; /* all other attributes (e.g. atime, etc.) */ 2267 int lockflag; 2268 int took_trunc_lock = 0; 2269 int locked_buffers = 0; 2270 2271 /* 2272 * Applications which only care about data integrity rather than full 2273 * file integrity may opt out of (delay) expensive metadata update 2274 * operations as a performance optimization. 2275 */ 2276 wait = (waitfor == MNT_WAIT); 2277 waitdata = (waitfor == MNT_DWAIT) | wait; 2278 if (always_do_fullfsync) 2279 fullsync = 1; 2280 2281 /* HFS directories don't have any data blocks. */ 2282 if (vnode_isdir(vp)) 2283 goto metasync; 2284 fp = VTOF(vp); 2285 2286 /* 2287 * For system files flush the B-tree header and 2288 * for regular files write out any clusters 2289 */ 2290 if (vnode_issystem(vp)) { 2291 if (VTOF(vp)->fcbBTCBPtr != NULL) { 2292 // XXXdbg 2293 if (hfsmp->jnl == NULL) { 2294 BTFlushPath(VTOF(vp)); 2295 } 2296 } 2297 } else if (UBCINFOEXISTS(vp)) { 2298 hfs_unlock(cp); 2299 hfs_lock_truncate(cp, HFS_SHARED_LOCK); 2300 took_trunc_lock = 1; 2301 2302 if (fp->ff_unallocblocks != 0) { 2303 hfs_unlock_truncate(cp, 0); 2304 2305 hfs_lock_truncate(cp, HFS_EXCLUSIVE_LOCK); 2306 } 2307 /* Don't hold cnode lock when calling into cluster layer. */ 2308 (void) cluster_push(vp, waitdata ? IO_SYNC : 0); 2309 2310 hfs_lock(cp, HFS_FORCE_LOCK); 2311 } 2312 /* 2313 * When MNT_WAIT is requested and the zero fill timeout 2314 * has expired then we must explicitly zero out any areas 2315 * that are currently marked invalid (holes). 2316 * 2317 * Files with NODUMP can bypass zero filling here. 2318 */ 2319 if (fp && (((cp->c_flag & C_ALWAYS_ZEROFILL) && !TAILQ_EMPTY(&fp->ff_invalidranges)) || 2320 ((wait || (cp->c_flag & C_ZFWANTSYNC)) && 2321 ((cp->c_bsdflags & UF_NODUMP) == 0) && 2322 UBCINFOEXISTS(vp) && (vnode_issystem(vp) ==0) && 2323 cp->c_zftimeout != 0))) { 2324 2325 microuptime(&tv); 2326 if ((cp->c_flag & C_ALWAYS_ZEROFILL) == 0 && !fullsync && tv.tv_sec < (long)cp->c_zftimeout) { 2327 /* Remember that a force sync was requested. */ 2328 cp->c_flag |= C_ZFWANTSYNC; 2329 goto datasync; 2330 } 2331 if (!TAILQ_EMPTY(&fp->ff_invalidranges)) { 2332 if (!took_trunc_lock || (cp->c_truncatelockowner == HFS_SHARED_OWNER)) { 2333 hfs_unlock(cp); 2334 if (took_trunc_lock) { 2335 hfs_unlock_truncate(cp, 0); 2336 } 2337 hfs_lock_truncate(cp, HFS_EXCLUSIVE_LOCK); 2338 hfs_lock(cp, HFS_FORCE_LOCK); 2339 took_trunc_lock = 1; 2340 } 2341 while ((invalid_range = TAILQ_FIRST(&fp->ff_invalidranges))) { 2342 off_t start = invalid_range->rl_start; 2343 off_t end = invalid_range->rl_end; 2344 2345 /* The range about to be written must be validated 2346 * first, so that VNOP_BLOCKMAP() will return the 2347 * appropriate mapping for the cluster code: 2348 */ 2349 rl_remove(start, end, &fp->ff_invalidranges); 2350 2351 /* Don't hold cnode lock when calling into cluster layer. */ 2352 hfs_unlock(cp); 2353 (void) cluster_write(vp, (struct uio *) 0, 2354 fp->ff_size, end + 1, start, (off_t)0, 2355 IO_HEADZEROFILL | IO_NOZERODIRTY | IO_NOCACHE); 2356 hfs_lock(cp, HFS_FORCE_LOCK); 2357 cp->c_flag |= C_MODIFIED; 2358 } 2359 hfs_unlock(cp); 2360 (void) cluster_push(vp, waitdata ? IO_SYNC : 0); 2361 hfs_lock(cp, HFS_FORCE_LOCK); 2362 } 2363 cp->c_flag &= ~C_ZFWANTSYNC; 2364 cp->c_zftimeout = 0; 2365 } 2366datasync: 2367 if (took_trunc_lock) { 2368 hfs_unlock_truncate(cp, 0); 2369 took_trunc_lock = 0; 2370 } 2371 /* 2372 * if we have a journal and if journal_active() returns != 0 then the 2373 * we shouldn't do anything to a locked block (because it is part 2374 * of a transaction). otherwise we'll just go through the normal 2375 * code path and flush the buffer. note journal_active() can return 2376 * -1 if the journal is invalid -- however we still need to skip any 2377 * locked blocks as they get cleaned up when we finish the transaction 2378 * or close the journal. 2379 */ 2380 // if (hfsmp->jnl && journal_active(hfsmp->jnl) >= 0) 2381 if (hfsmp->jnl) 2382 lockflag = BUF_SKIP_LOCKED; 2383 else 2384 lockflag = 0; 2385 2386 /* 2387 * Flush all dirty buffers associated with a vnode. 2388 * Record how many of them were dirty AND locked (if necessary). 2389 */ 2390 locked_buffers = buf_flushdirtyblks_skipinfo(vp, waitdata, lockflag, "hfs_fsync"); 2391 if ((lockflag & BUF_SKIP_LOCKED) && (locked_buffers) && (vnode_vtype(vp) == VLNK)) { 2392 /* 2393 * If there are dirty symlink buffers, then we may need to take action 2394 * to prevent issues later on if we are journaled. If we're fsyncing a 2395 * symlink vnode then we are in one of three cases: 2396 * 2397 * 1) automatic sync has fired. In this case, we don't want the behavior to change. 2398 * 2399 * 2) Someone has opened the FD for the symlink (not what it points to) 2400 * and has issued an fsync against it. This should be rare, and we don't 2401 * want the behavior to change. 2402 * 2403 * 3) We are being called by a vclean which is trying to reclaim this 2404 * symlink vnode. If this is the case, then allowing this fsync to 2405 * proceed WITHOUT flushing the journal could result in the vclean 2406 * invalidating the buffer's blocks before the journal transaction is 2407 * written to disk. To prevent this, we force a journal flush 2408 * if the vnode is in the middle of a recycle (VL_TERMINATE or VL_DEAD is set). 2409 */ 2410 if (vnode_isrecycled(vp)) { 2411 fullsync = 1; 2412 } 2413 } 2414 2415metasync: 2416 if (vnode_isreg(vp) && vnode_issystem(vp)) { 2417 if (VTOF(vp)->fcbBTCBPtr != NULL) { 2418 microuptime(&tv); 2419 BTSetLastSync(VTOF(vp), tv.tv_sec); 2420 } 2421 cp->c_touch_acctime = FALSE; 2422 cp->c_touch_chgtime = FALSE; 2423 cp->c_touch_modtime = FALSE; 2424 } else if ( !(vp->v_flag & VSWAP) ) /* User file */ { 2425 retval = hfs_update(vp, wait); 2426 2427 /* 2428 * When MNT_WAIT is requested push out the catalog record for 2429 * this file. If they asked for a full fsync, we can skip this 2430 * because the journal_flush or hfs_metasync_all will push out 2431 * all of the metadata changes. 2432 */ 2433 if ((retval == 0) && wait && !fullsync && cp->c_hint && 2434 !ISSET(cp->c_flag, C_DELETED | C_NOEXISTS)) { 2435 hfs_metasync(VTOHFS(vp), (daddr64_t)cp->c_hint, p); 2436 } 2437 2438 /* 2439 * If this was a full fsync, make sure all metadata 2440 * changes get to stable storage. 2441 */ 2442 if (fullsync) { 2443 if (hfsmp->jnl) { 2444 hfs_journal_flush(hfsmp, FALSE); 2445 2446 if (journal_uses_fua(hfsmp->jnl)) { 2447 /* 2448 * the journal_flush did NOT issue a sync track cache command, 2449 * and the fullsync indicates we are supposed to flush all cached 2450 * data to the media, so issue the sync track cache command 2451 * explicitly 2452 */ 2453 VNOP_IOCTL(hfsmp->hfs_devvp, DKIOCSYNCHRONIZECACHE, NULL, FWRITE, NULL); 2454 } 2455 } else { 2456 retval = hfs_metasync_all(hfsmp); 2457 /* XXX need to pass context! */ 2458 VNOP_IOCTL(hfsmp->hfs_devvp, DKIOCSYNCHRONIZECACHE, NULL, FWRITE, NULL); 2459 } 2460 } 2461 } 2462 2463 return (retval); 2464} 2465 2466 2467/* Sync an hfs catalog b-tree node */ 2468int 2469hfs_metasync(struct hfsmount *hfsmp, daddr64_t node, __unused struct proc *p) 2470{ 2471 vnode_t vp; 2472 buf_t bp; 2473 int lockflags; 2474 2475 vp = HFSTOVCB(hfsmp)->catalogRefNum; 2476 2477 // XXXdbg - don't need to do this on a journaled volume 2478 if (hfsmp->jnl) { 2479 return 0; 2480 } 2481 2482 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK); 2483 /* 2484 * Look for a matching node that has been delayed 2485 * but is not part of a set (B_LOCKED). 2486 * 2487 * BLK_ONLYVALID causes buf_getblk to return a 2488 * buf_t for the daddr64_t specified only if it's 2489 * currently resident in the cache... the size 2490 * parameter to buf_getblk is ignored when this flag 2491 * is set 2492 */ 2493 bp = buf_getblk(vp, node, 0, 0, 0, BLK_META | BLK_ONLYVALID); 2494 2495 if (bp) { 2496 if ((buf_flags(bp) & (B_LOCKED | B_DELWRI)) == B_DELWRI) 2497 (void) VNOP_BWRITE(bp); 2498 else 2499 buf_brelse(bp); 2500 } 2501 2502 hfs_systemfile_unlock(hfsmp, lockflags); 2503 2504 return (0); 2505} 2506 2507 2508/* 2509 * Sync all hfs B-trees. Use this instead of journal_flush for a volume 2510 * without a journal. Note that the volume bitmap does not get written; 2511 * we rely on fsck_hfs to fix that up (which it can do without any loss 2512 * of data). 2513 */ 2514int 2515hfs_metasync_all(struct hfsmount *hfsmp) 2516{ 2517 int lockflags; 2518 2519 /* Lock all of the B-trees so we get a mutually consistent state */ 2520 lockflags = hfs_systemfile_lock(hfsmp, 2521 SFL_CATALOG|SFL_EXTENTS|SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK); 2522 2523 /* Sync each of the B-trees */ 2524 if (hfsmp->hfs_catalog_vp) 2525 hfs_btsync(hfsmp->hfs_catalog_vp, 0); 2526 if (hfsmp->hfs_extents_vp) 2527 hfs_btsync(hfsmp->hfs_extents_vp, 0); 2528 if (hfsmp->hfs_attribute_vp) 2529 hfs_btsync(hfsmp->hfs_attribute_vp, 0); 2530 2531 /* Wait for all of the writes to complete */ 2532 if (hfsmp->hfs_catalog_vp) 2533 vnode_waitforwrites(hfsmp->hfs_catalog_vp, 0, 0, 0, "hfs_metasync_all"); 2534 if (hfsmp->hfs_extents_vp) 2535 vnode_waitforwrites(hfsmp->hfs_extents_vp, 0, 0, 0, "hfs_metasync_all"); 2536 if (hfsmp->hfs_attribute_vp) 2537 vnode_waitforwrites(hfsmp->hfs_attribute_vp, 0, 0, 0, "hfs_metasync_all"); 2538 2539 hfs_systemfile_unlock(hfsmp, lockflags); 2540 2541 return 0; 2542} 2543 2544 2545/*ARGSUSED 1*/ 2546static int 2547hfs_btsync_callback(struct buf *bp, __unused void *dummy) 2548{ 2549 buf_clearflags(bp, B_LOCKED); 2550 (void) buf_bawrite(bp); 2551 2552 return(BUF_CLAIMED); 2553} 2554 2555 2556int 2557hfs_btsync(struct vnode *vp, int sync_transaction) 2558{ 2559 struct cnode *cp = VTOC(vp); 2560 struct timeval tv; 2561 int flags = 0; 2562 2563 if (sync_transaction) 2564 flags |= BUF_SKIP_NONLOCKED; 2565 /* 2566 * Flush all dirty buffers associated with b-tree. 2567 */ 2568 buf_iterate(vp, hfs_btsync_callback, flags, 0); 2569 2570 microuptime(&tv); 2571 if (vnode_issystem(vp) && (VTOF(vp)->fcbBTCBPtr != NULL)) 2572 (void) BTSetLastSync(VTOF(vp), tv.tv_sec); 2573 cp->c_touch_acctime = FALSE; 2574 cp->c_touch_chgtime = FALSE; 2575 cp->c_touch_modtime = FALSE; 2576 2577 return 0; 2578} 2579 2580/* 2581 * Remove a directory. 2582 */ 2583int 2584hfs_vnop_rmdir(ap) 2585 struct vnop_rmdir_args /* { 2586 struct vnode *a_dvp; 2587 struct vnode *a_vp; 2588 struct componentname *a_cnp; 2589 vfs_context_t a_context; 2590 } */ *ap; 2591{ 2592 struct vnode *dvp = ap->a_dvp; 2593 struct vnode *vp = ap->a_vp; 2594 struct cnode *dcp = VTOC(dvp); 2595 struct cnode *cp = VTOC(vp); 2596 int error; 2597 time_t orig_ctime; 2598 2599 orig_ctime = VTOC(vp)->c_ctime; 2600 2601 if (!S_ISDIR(cp->c_mode)) { 2602 return (ENOTDIR); 2603 } 2604 if (dvp == vp) { 2605 return (EINVAL); 2606 } 2607 2608 check_for_tracked_file(vp, orig_ctime, NAMESPACE_HANDLER_DELETE_OP, NULL); 2609 cp = VTOC(vp); 2610 2611 if ((error = hfs_lockpair(dcp, cp, HFS_EXCLUSIVE_LOCK))) { 2612 return (error); 2613 } 2614 2615 /* Check for a race with rmdir on the parent directory */ 2616 if (dcp->c_flag & (C_DELETED | C_NOEXISTS)) { 2617 hfs_unlockpair (dcp, cp); 2618 return ENOENT; 2619 } 2620 error = hfs_removedir(dvp, vp, ap->a_cnp, 0, 0); 2621 2622 hfs_unlockpair(dcp, cp); 2623 2624 return (error); 2625} 2626 2627/* 2628 * Remove a directory 2629 * 2630 * Both dvp and vp cnodes are locked 2631 */ 2632int 2633hfs_removedir(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, 2634 int skip_reserve, int only_unlink) 2635{ 2636 struct cnode *cp; 2637 struct cnode *dcp; 2638 struct hfsmount * hfsmp; 2639 struct cat_desc desc; 2640 int lockflags; 2641 int error = 0, started_tr = 0; 2642 2643 cp = VTOC(vp); 2644 dcp = VTOC(dvp); 2645 hfsmp = VTOHFS(vp); 2646 2647 if (dcp == cp) { 2648 return (EINVAL); /* cannot remove "." */ 2649 } 2650 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) { 2651 return (0); 2652 } 2653 if (cp->c_entries != 0) { 2654 return (ENOTEMPTY); 2655 } 2656 2657 /* 2658 * If the directory is open or in use (e.g. opendir() or current working 2659 * directory for some process); wait for inactive/reclaim to actually 2660 * remove cnode from the catalog. Both inactive and reclaim codepaths are capable 2661 * of removing open-unlinked directories from the catalog, as well as getting rid 2662 * of EAs still on the element. So change only_unlink to true, so that it will get 2663 * cleaned up below. 2664 * 2665 * Otherwise, we can get into a weird old mess where the directory has C_DELETED, 2666 * but it really means C_NOEXISTS because the item was actually removed from the 2667 * catalog. Then when we try to remove the entry from the catalog later on, it won't 2668 * really be there anymore. 2669 */ 2670 if (vnode_isinuse(vp, 0)) { 2671 only_unlink = 1; 2672 } 2673 2674 /* Deal with directory hardlinks */ 2675 if (cp->c_flag & C_HARDLINK) { 2676 /* 2677 * Note that if we have a directory which was a hardlink at any point, 2678 * its actual directory data is stored in the directory inode in the hidden 2679 * directory rather than the leaf element(s) present in the namespace. 2680 * 2681 * If there are still other hardlinks to this directory, 2682 * then we'll just eliminate this particular link and the vnode will still exist. 2683 * If this is the last link to an empty directory, then we'll open-unlink the 2684 * directory and it will be only tagged with C_DELETED (as opposed to C_NOEXISTS). 2685 * 2686 * We could also return EBUSY here. 2687 */ 2688 2689 return hfs_unlink(hfsmp, dvp, vp, cnp, skip_reserve); 2690 } 2691 2692 /* 2693 * In a few cases, we may want to allow the directory to persist in an 2694 * open-unlinked state. If the directory is being open-unlinked (still has usecount 2695 * references), or if it has EAs, or if it was being deleted as part of a rename, 2696 * then we go ahead and move it to the hidden directory. 2697 * 2698 * If the directory is being open-unlinked, then we want to keep the catalog entry 2699 * alive so that future EA calls and fchmod/fstat etc. do not cause issues later. 2700 * 2701 * If the directory had EAs, then we want to use the open-unlink trick so that the 2702 * EA removal is not done in one giant transaction. Otherwise, it could cause a panic 2703 * due to overflowing the journal. 2704 * 2705 * Finally, if it was deleted as part of a rename, we move it to the hidden directory 2706 * in order to maintain rename atomicity. 2707 * 2708 * Note that the allow_dirs argument to hfs_removefile specifies that it is 2709 * supposed to handle directories for this case. 2710 */ 2711 2712 if (((hfsmp->hfs_attribute_vp != NULL) && 2713 ((cp->c_attr.ca_recflags & kHFSHasAttributesMask) != 0)) || 2714 (only_unlink != 0)) { 2715 2716 int ret = hfs_removefile(dvp, vp, cnp, 0, 0, 1, NULL, only_unlink); 2717 /* 2718 * Even though hfs_vnop_rename calls vnode_recycle for us on tvp we call 2719 * it here just in case we were invoked by rmdir() on a directory that had 2720 * EAs. To ensure that we start reclaiming the space as soon as possible, 2721 * we call vnode_recycle on the directory. 2722 */ 2723 vnode_recycle(vp); 2724 2725 return ret; 2726 2727 } 2728 2729 dcp->c_flag |= C_DIR_MODIFICATION; 2730 2731#if QUOTA 2732 if (hfsmp->hfs_flags & HFS_QUOTAS) 2733 (void)hfs_getinoquota(cp); 2734#endif 2735 if ((error = hfs_start_transaction(hfsmp)) != 0) { 2736 goto out; 2737 } 2738 started_tr = 1; 2739 2740 /* 2741 * Verify the directory is empty (and valid). 2742 * (Rmdir ".." won't be valid since 2743 * ".." will contain a reference to 2744 * the current directory and thus be 2745 * non-empty.) 2746 */ 2747 if ((dcp->c_bsdflags & APPEND) || (cp->c_bsdflags & (IMMUTABLE | APPEND))) { 2748 error = EPERM; 2749 goto out; 2750 } 2751 2752 /* Remove the entry from the namei cache: */ 2753 cache_purge(vp); 2754 2755 /* 2756 * Protect against a race with rename by using the component 2757 * name passed in and parent id from dvp (instead of using 2758 * the cp->c_desc which may have changed). 2759 */ 2760 desc.cd_nameptr = (const u_int8_t *)cnp->cn_nameptr; 2761 desc.cd_namelen = cnp->cn_namelen; 2762 desc.cd_parentcnid = dcp->c_fileid; 2763 desc.cd_cnid = cp->c_cnid; 2764 desc.cd_flags = CD_ISDIR; 2765 desc.cd_encoding = cp->c_encoding; 2766 desc.cd_hint = 0; 2767 2768 if (!hfs_valid_cnode(hfsmp, dvp, cnp, cp->c_fileid, NULL, &error)) { 2769 error = 0; 2770 goto out; 2771 } 2772 2773 /* Remove entry from catalog */ 2774 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_ATTRIBUTE | SFL_BITMAP, HFS_EXCLUSIVE_LOCK); 2775 2776 if (!skip_reserve) { 2777 /* 2778 * Reserve some space in the Catalog file. 2779 */ 2780 if ((error = cat_preflight(hfsmp, CAT_DELETE, NULL, 0))) { 2781 hfs_systemfile_unlock(hfsmp, lockflags); 2782 goto out; 2783 } 2784 } 2785 2786 error = cat_delete(hfsmp, &desc, &cp->c_attr); 2787 if (error == 0) { 2788 /* The parent lost a child */ 2789 if (dcp->c_entries > 0) 2790 dcp->c_entries--; 2791 DEC_FOLDERCOUNT(hfsmp, dcp->c_attr); 2792 dcp->c_dirchangecnt++; 2793 dcp->c_touch_chgtime = TRUE; 2794 dcp->c_touch_modtime = TRUE; 2795 hfs_touchtimes(hfsmp, cp); 2796 (void) cat_update(hfsmp, &dcp->c_desc, &dcp->c_attr, NULL, NULL); 2797 cp->c_flag &= ~(C_MODIFIED | C_FORCEUPDATE); 2798 } 2799 2800 hfs_systemfile_unlock(hfsmp, lockflags); 2801 2802 if (error) 2803 goto out; 2804 2805#if QUOTA 2806 if (hfsmp->hfs_flags & HFS_QUOTAS) 2807 (void)hfs_chkiq(cp, -1, NOCRED, 0); 2808#endif /* QUOTA */ 2809 2810 hfs_volupdate(hfsmp, VOL_RMDIR, (dcp->c_cnid == kHFSRootFolderID)); 2811 2812 /* Mark C_NOEXISTS since the catalog entry is now gone */ 2813 cp->c_flag |= C_NOEXISTS; 2814out: 2815 dcp->c_flag &= ~C_DIR_MODIFICATION; 2816 wakeup((caddr_t)&dcp->c_flag); 2817 2818 if (started_tr) { 2819 hfs_end_transaction(hfsmp); 2820 } 2821 2822 return (error); 2823} 2824 2825 2826/* 2827 * Remove a file or link. 2828 */ 2829int 2830hfs_vnop_remove(ap) 2831 struct vnop_remove_args /* { 2832 struct vnode *a_dvp; 2833 struct vnode *a_vp; 2834 struct componentname *a_cnp; 2835 int a_flags; 2836 vfs_context_t a_context; 2837 } */ *ap; 2838{ 2839 struct vnode *dvp = ap->a_dvp; 2840 struct vnode *vp = ap->a_vp; 2841 struct cnode *dcp = VTOC(dvp); 2842 struct cnode *cp; 2843 struct vnode *rvp = NULL; 2844 int error=0, recycle_rsrc=0; 2845 time_t orig_ctime; 2846 uint32_t rsrc_vid = 0; 2847 2848 if (dvp == vp) { 2849 return (EINVAL); 2850 } 2851 2852 orig_ctime = VTOC(vp)->c_ctime; 2853 if ( (!vnode_isnamedstream(vp)) && ((ap->a_flags & VNODE_REMOVE_SKIP_NAMESPACE_EVENT) == 0)) { 2854 error = check_for_tracked_file(vp, orig_ctime, NAMESPACE_HANDLER_DELETE_OP, NULL); 2855 if (error) { 2856 // XXXdbg - decide on a policy for handling namespace handler failures! 2857 // for now we just let them proceed. 2858 } 2859 } 2860 error = 0; 2861 2862 cp = VTOC(vp); 2863 2864relock: 2865 2866 hfs_lock_truncate(cp, HFS_EXCLUSIVE_LOCK); 2867 2868 if ((error = hfs_lockpair(dcp, cp, HFS_EXCLUSIVE_LOCK))) { 2869 hfs_unlock_truncate(cp, 0); 2870 if (rvp) { 2871 vnode_put (rvp); 2872 } 2873 return (error); 2874 } 2875 2876 /* 2877 * Lazily respond to determining if there is a valid resource fork 2878 * vnode attached to 'cp' if it is a regular file or symlink. 2879 * If the vnode does not exist, then we may proceed without having to 2880 * create it. 2881 * 2882 * If, however, it does exist, then we need to acquire an iocount on the 2883 * vnode after acquiring its vid. This ensures that if we have to do I/O 2884 * against it, it can't get recycled from underneath us in the middle 2885 * of this call. 2886 * 2887 * Note: this function may be invoked for directory hardlinks, so just skip these 2888 * steps if 'vp' is a directory. 2889 */ 2890 2891 2892 if ((vp->v_type == VLNK) || (vp->v_type == VREG)) { 2893 if ((cp->c_rsrc_vp) && (rvp == NULL)) { 2894 /* We need to acquire the rsrc vnode */ 2895 rvp = cp->c_rsrc_vp; 2896 rsrc_vid = vnode_vid (rvp); 2897 2898 /* Unlock everything to acquire iocount on the rsrc vnode */ 2899 hfs_unlock_truncate (cp, 0); 2900 hfs_unlockpair (dcp, cp); 2901 2902 /* Use the vid to maintain identity on rvp */ 2903 if (vnode_getwithvid(rvp, rsrc_vid)) { 2904 /* 2905 * If this fails, then it was recycled or 2906 * reclaimed in the interim. Reset fields and 2907 * start over. 2908 */ 2909 rvp = NULL; 2910 rsrc_vid = 0; 2911 } 2912 goto relock; 2913 } 2914 } 2915 2916 /* 2917 * Check to see if we raced rmdir for the parent directory 2918 * hfs_removefile already checks for a race on vp/cp 2919 */ 2920 if (dcp->c_flag & (C_DELETED | C_NOEXISTS)) { 2921 error = ENOENT; 2922 goto rm_done; 2923 } 2924 2925 error = hfs_removefile(dvp, vp, ap->a_cnp, ap->a_flags, 0, 0, NULL, 0); 2926 2927 /* 2928 * If the remove succeeded in deleting the file, then we may need to mark 2929 * the resource fork for recycle so that it is reclaimed as quickly 2930 * as possible. If it were not recycled quickly, then this resource fork 2931 * vnode could keep a v_parent reference on the data fork, which prevents it 2932 * from going through reclaim (by giving it extra usecounts), except in the force- 2933 * unmount case. 2934 * 2935 * However, a caveat: we need to continue to supply resource fork 2936 * access to open-unlinked files even if the resource fork is not open. This is 2937 * a requirement for the compressed files work. Luckily, hfs_vgetrsrc will handle 2938 * this already if the data fork has been re-parented to the hidden directory. 2939 * 2940 * As a result, all we really need to do here is mark the resource fork vnode 2941 * for recycle. If it goes out of core, it can be brought in again if needed. 2942 * If the cnode was instead marked C_NOEXISTS, then there wouldn't be any 2943 * more work. 2944 */ 2945 if ((error == 0) && (rvp)) { 2946 recycle_rsrc = 1; 2947 } 2948 2949 /* 2950 * Drop the truncate lock before unlocking the cnode 2951 * (which can potentially perform a vnode_put and 2952 * recycle the vnode which in turn might require the 2953 * truncate lock) 2954 */ 2955rm_done: 2956 hfs_unlock_truncate(cp, 0); 2957 hfs_unlockpair(dcp, cp); 2958 2959 if (recycle_rsrc) { 2960 /* inactive or reclaim on rvp will clean up the blocks from the rsrc fork */ 2961 vnode_recycle(rvp); 2962 } 2963 2964 if (rvp) { 2965 /* drop iocount on rsrc fork, was obtained at beginning of fxn */ 2966 vnode_put(rvp); 2967 } 2968 2969 return (error); 2970} 2971 2972 2973int 2974hfs_removefile_callback(struct buf *bp, void *hfsmp) { 2975 2976 if ( !(buf_flags(bp) & B_META)) 2977 panic("hfs: symlink bp @ %p is not marked meta-data!\n", bp); 2978 /* 2979 * it's part of the current transaction, kill it. 2980 */ 2981 journal_kill_block(((struct hfsmount *)hfsmp)->jnl, bp); 2982 2983 return (BUF_CLAIMED); 2984} 2985 2986/* 2987 * hfs_removefile 2988 * 2989 * Similar to hfs_vnop_remove except there are additional options. 2990 * This function may be used to remove directories if they have 2991 * lots of EA's -- note the 'allow_dirs' argument. 2992 * 2993 * This function is able to delete blocks & fork data for the resource 2994 * fork even if it does not exist in core (and have a backing vnode). 2995 * It should infer the correct behavior based on the number of blocks 2996 * in the cnode and whether or not the resource fork pointer exists or 2997 * not. As a result, one only need pass in the 'vp' corresponding to the 2998 * data fork of this file (or main vnode in the case of a directory). 2999 * Passing in a resource fork will result in an error. 3000 * 3001 * Because we do not create any vnodes in this function, we are not at 3002 * risk of deadlocking against ourselves by double-locking. 3003 * 3004 * Requires cnode and truncate locks to be held. 3005 */ 3006int 3007hfs_removefile(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, 3008 int flags, int skip_reserve, int allow_dirs, 3009 __unused struct vnode *rvp, int only_unlink) 3010{ 3011 struct cnode *cp; 3012 struct cnode *dcp; 3013 struct vnode *rsrc_vp = NULL; 3014 struct hfsmount *hfsmp; 3015 struct cat_desc desc; 3016 struct timeval tv; 3017 int dataforkbusy = 0; 3018 int rsrcforkbusy = 0; 3019 int lockflags; 3020 int error = 0; 3021 int started_tr = 0; 3022 int isbigfile = 0, defer_remove=0, isdir=0; 3023 int update_vh = 0; 3024 3025 cp = VTOC(vp); 3026 dcp = VTOC(dvp); 3027 hfsmp = VTOHFS(vp); 3028 3029 /* Check if we lost a race post lookup. */ 3030 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) { 3031 return (0); 3032 } 3033 3034 if (!hfs_valid_cnode(hfsmp, dvp, cnp, cp->c_fileid, NULL, &error)) { 3035 return 0; 3036 } 3037 3038 /* Make sure a remove is permitted */ 3039 if (VNODE_IS_RSRC(vp)) { 3040 return (EPERM); 3041 } 3042 else { 3043 /* 3044 * We know it's a data fork. 3045 * Probe the cnode to see if we have a valid resource fork 3046 * in hand or not. 3047 */ 3048 rsrc_vp = cp->c_rsrc_vp; 3049 } 3050 3051 /* Don't allow deleting the journal or journal_info_block. */ 3052 if (hfs_is_journal_file(hfsmp, cp)) { 3053 return (EPERM); 3054 } 3055 3056 /* 3057 * If removing a symlink, then we need to ensure that the 3058 * data blocks for the symlink are not still in-flight or pending. 3059 * If so, we will unlink the symlink here, making its blocks 3060 * available for re-allocation by a subsequent transaction. That is OK, but 3061 * then the I/O for the data blocks could then go out before the journal 3062 * transaction that created it was flushed, leading to I/O ordering issues. 3063 */ 3064 if (vp->v_type == VLNK) { 3065 /* 3066 * This will block if the asynchronous journal flush is in progress. 3067 * If this symlink is not being renamed over and doesn't have any open FDs, 3068 * then we'll remove it from the journal's bufs below in kill_block. 3069 */ 3070 buf_wait_for_shadow_io (vp, 0); 3071 } 3072 3073 /* 3074 * Hard links require special handling. 3075 */ 3076 if (cp->c_flag & C_HARDLINK) { 3077 if ((flags & VNODE_REMOVE_NODELETEBUSY) && vnode_isinuse(vp, 0)) { 3078 return (EBUSY); 3079 } else { 3080 /* A directory hard link with a link count of one is 3081 * treated as a regular directory. Therefore it should 3082 * only be removed using rmdir(). 3083 */ 3084 if ((vnode_isdir(vp) == 1) && (cp->c_linkcount == 1) && 3085 (allow_dirs == 0)) { 3086 return (EPERM); 3087 } 3088 return hfs_unlink(hfsmp, dvp, vp, cnp, skip_reserve); 3089 } 3090 } 3091 3092 /* Directories should call hfs_rmdir! (unless they have a lot of attributes) */ 3093 if (vnode_isdir(vp)) { 3094 if (allow_dirs == 0) 3095 return (EPERM); /* POSIX */ 3096 isdir = 1; 3097 } 3098 /* Sanity check the parent ids. */ 3099 if ((cp->c_parentcnid != hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid) && 3100 (cp->c_parentcnid != dcp->c_fileid)) { 3101 return (EINVAL); 3102 } 3103 3104 dcp->c_flag |= C_DIR_MODIFICATION; 3105 3106 // this guy is going away so mark him as such 3107 cp->c_flag |= C_DELETED; 3108 3109 3110 /* Remove our entry from the namei cache. */ 3111 cache_purge(vp); 3112 3113 /* 3114 * If the caller was operating on a file (as opposed to a 3115 * directory with EAs), then we need to figure out 3116 * whether or not it has a valid resource fork vnode. 3117 * 3118 * If there was a valid resource fork vnode, then we need 3119 * to use hfs_truncate to eliminate its data. If there is 3120 * no vnode, then we hold the cnode lock which would 3121 * prevent it from being created. As a result, 3122 * we can use the data deletion functions which do not 3123 * require that a cnode/vnode pair exist. 3124 */ 3125 3126 /* Check if this file is being used. */ 3127 if (isdir == 0) { 3128 dataforkbusy = vnode_isinuse(vp, 0); 3129 /* 3130 * At this point, we know that 'vp' points to the 3131 * a data fork because we checked it up front. And if 3132 * there is no rsrc fork, rsrc_vp will be NULL. 3133 */ 3134 if (rsrc_vp && (cp->c_blocks - VTOF(vp)->ff_blocks)) { 3135 rsrcforkbusy = vnode_isinuse(rsrc_vp, 0); 3136 } 3137 } 3138 3139 /* Check if we have to break the deletion into multiple pieces. */ 3140 if (isdir == 0) { 3141 isbigfile = ((cp->c_datafork->ff_size >= HFS_BIGFILE_SIZE) && overflow_extents(VTOF(vp))); 3142 } 3143 3144 /* Check if the file has xattrs. If it does we'll have to delete them in 3145 individual transactions in case there are too many */ 3146 if ((hfsmp->hfs_attribute_vp != NULL) && 3147 (cp->c_attr.ca_recflags & kHFSHasAttributesMask) != 0) { 3148 defer_remove = 1; 3149 } 3150 3151 /* If we are explicitly told to only unlink item and move to hidden dir, then do it */ 3152 if (only_unlink) { 3153 defer_remove = 1; 3154 } 3155 3156 /* 3157 * Carbon semantics prohibit deleting busy files. 3158 * (enforced when VNODE_REMOVE_NODELETEBUSY is requested) 3159 */ 3160 if (dataforkbusy || rsrcforkbusy) { 3161 if ((flags & VNODE_REMOVE_NODELETEBUSY) || 3162 (hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid == 0)) { 3163 error = EBUSY; 3164 goto out; 3165 } 3166 } 3167 3168#if QUOTA 3169 if (hfsmp->hfs_flags & HFS_QUOTAS) 3170 (void)hfs_getinoquota(cp); 3171#endif /* QUOTA */ 3172 3173 /* 3174 * Do a ubc_setsize to indicate we need to wipe contents if: 3175 * 1) item is a regular file. 3176 * 2) Neither fork is busy AND we are not told to unlink this. 3177 * 3178 * We need to check for the defer_remove since it can be set without 3179 * having a busy data or rsrc fork 3180 */ 3181 if (isdir == 0 && (!dataforkbusy || !rsrcforkbusy) && (defer_remove == 0)) { 3182 /* 3183 * A ubc_setsize can cause a pagein so defer it 3184 * until after the cnode lock is dropped. The 3185 * cnode lock cannot be dropped/reacquired here 3186 * since we might already hold the journal lock. 3187 */ 3188 if (!dataforkbusy && cp->c_datafork->ff_blocks && !isbigfile) { 3189 cp->c_flag |= C_NEED_DATA_SETSIZE; 3190 } 3191 if (!rsrcforkbusy && rsrc_vp) { 3192 cp->c_flag |= C_NEED_RSRC_SETSIZE; 3193 } 3194 } 3195 3196 if ((error = hfs_start_transaction(hfsmp)) != 0) { 3197 goto out; 3198 } 3199 started_tr = 1; 3200 3201 // XXXdbg - if we're journaled, kill any dirty symlink buffers 3202 if (hfsmp->jnl && vnode_islnk(vp) && (defer_remove == 0)) { 3203 buf_iterate(vp, hfs_removefile_callback, BUF_SKIP_NONLOCKED, (void *)hfsmp); 3204 } 3205 3206 /* 3207 * Prepare to truncate any non-busy forks. Busy forks will 3208 * get truncated when their vnode goes inactive. 3209 * Note that we will only enter this region if we 3210 * can avoid creating an open-unlinked file. If 3211 * either region is busy, we will have to create an open 3212 * unlinked file. 3213 * 3214 * Since we are deleting the file, we need to stagger the runtime 3215 * modifications to do things in such a way that a crash won't 3216 * result in us getting overlapped extents or any other 3217 * bad inconsistencies. As such, we call prepare_release_storage 3218 * which updates the UBC, updates quota information, and releases 3219 * any loaned blocks that belong to this file. No actual 3220 * truncation or bitmap manipulation is done until *AFTER* 3221 * the catalog record is removed. 3222 */ 3223 if (isdir == 0 && (!dataforkbusy && !rsrcforkbusy) && (only_unlink == 0)) { 3224 3225 if (!dataforkbusy && !isbigfile && cp->c_datafork->ff_blocks != 0) { 3226 3227 error = hfs_prepare_release_storage (hfsmp, vp); 3228 if (error) { 3229 goto out; 3230 } 3231 update_vh = 1; 3232 } 3233 3234 /* 3235 * If the resource fork vnode does not exist, we can skip this step. 3236 */ 3237 if (!rsrcforkbusy && rsrc_vp) { 3238 error = hfs_prepare_release_storage (hfsmp, rsrc_vp); 3239 if (error) { 3240 goto out; 3241 } 3242 update_vh = 1; 3243 } 3244 } 3245 3246 /* 3247 * Protect against a race with rename by using the component 3248 * name passed in and parent id from dvp (instead of using 3249 * the cp->c_desc which may have changed). Also, be aware that 3250 * because we allow directories to be passed in, we need to special case 3251 * this temporary descriptor in case we were handed a directory. 3252 */ 3253 if (isdir) { 3254 desc.cd_flags = CD_ISDIR; 3255 } 3256 else { 3257 desc.cd_flags = 0; 3258 } 3259 desc.cd_encoding = cp->c_desc.cd_encoding; 3260 desc.cd_nameptr = (const u_int8_t *)cnp->cn_nameptr; 3261 desc.cd_namelen = cnp->cn_namelen; 3262 desc.cd_parentcnid = dcp->c_fileid; 3263 desc.cd_hint = cp->c_desc.cd_hint; 3264 desc.cd_cnid = cp->c_cnid; 3265 microtime(&tv); 3266 3267 /* 3268 * There are two cases to consider: 3269 * 1. File/Dir is busy/big/defer_remove ==> move/rename the file/dir 3270 * 2. File is not in use ==> remove the file 3271 * 3272 * We can get a directory in case 1 because it may have had lots of attributes, 3273 * which need to get removed here. 3274 */ 3275 if (dataforkbusy || rsrcforkbusy || isbigfile || defer_remove) { 3276 char delname[32]; 3277 struct cat_desc to_desc; 3278 struct cat_desc todir_desc; 3279 3280 /* 3281 * Orphan this file or directory (move to hidden directory). 3282 * Again, we need to take care that we treat directories as directories, 3283 * and files as files. Because directories with attributes can be passed in 3284 * check to make sure that we have a directory or a file before filling in the 3285 * temporary descriptor's flags. We keep orphaned directories AND files in 3286 * the FILE_HARDLINKS private directory since we're generalizing over all 3287 * orphaned filesystem objects. 3288 */ 3289 bzero(&todir_desc, sizeof(todir_desc)); 3290 todir_desc.cd_parentcnid = 2; 3291 3292 MAKE_DELETED_NAME(delname, sizeof(delname), cp->c_fileid); 3293 bzero(&to_desc, sizeof(to_desc)); 3294 to_desc.cd_nameptr = (const u_int8_t *)delname; 3295 to_desc.cd_namelen = strlen(delname); 3296 to_desc.cd_parentcnid = hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid; 3297 if (isdir) { 3298 to_desc.cd_flags = CD_ISDIR; 3299 } 3300 else { 3301 to_desc.cd_flags = 0; 3302 } 3303 to_desc.cd_cnid = cp->c_cnid; 3304 3305 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK); 3306 if (!skip_reserve) { 3307 if ((error = cat_preflight(hfsmp, CAT_RENAME, NULL, 0))) { 3308 hfs_systemfile_unlock(hfsmp, lockflags); 3309 goto out; 3310 } 3311 } 3312 3313 error = cat_rename(hfsmp, &desc, &todir_desc, 3314 &to_desc, (struct cat_desc *)NULL); 3315 3316 if (error == 0) { 3317 hfsmp->hfs_private_attr[FILE_HARDLINKS].ca_entries++; 3318 if (isdir == 1) { 3319 INC_FOLDERCOUNT(hfsmp, hfsmp->hfs_private_attr[FILE_HARDLINKS]); 3320 } 3321 (void) cat_update(hfsmp, &hfsmp->hfs_private_desc[FILE_HARDLINKS], 3322 &hfsmp->hfs_private_attr[FILE_HARDLINKS], NULL, NULL); 3323 3324 /* Update the parent directory */ 3325 if (dcp->c_entries > 0) 3326 dcp->c_entries--; 3327 if (isdir == 1) { 3328 DEC_FOLDERCOUNT(hfsmp, dcp->c_attr); 3329 } 3330 dcp->c_dirchangecnt++; 3331 dcp->c_ctime = tv.tv_sec; 3332 dcp->c_mtime = tv.tv_sec; 3333 (void) cat_update(hfsmp, &dcp->c_desc, &dcp->c_attr, NULL, NULL); 3334 3335 /* Update the file or directory's state */ 3336 cp->c_flag |= C_DELETED; 3337 cp->c_ctime = tv.tv_sec; 3338 --cp->c_linkcount; 3339 (void) cat_update(hfsmp, &to_desc, &cp->c_attr, NULL, NULL); 3340 } 3341 hfs_systemfile_unlock(hfsmp, lockflags); 3342 if (error) 3343 goto out; 3344 3345 } 3346 else { 3347 /* 3348 * Nobody is using this item; we can safely remove everything. 3349 */ 3350 struct filefork *temp_rsrc_fork = NULL; 3351#if QUOTA 3352 off_t savedbytes; 3353 int blksize = hfsmp->blockSize; 3354#endif 3355 u_int32_t fileid = cp->c_fileid; 3356 3357 /* 3358 * Figure out if we need to read the resource fork data into 3359 * core before wiping out the catalog record. 3360 * 3361 * 1) Must not be a directory 3362 * 2) cnode's c_rsrcfork ptr must be NULL. 3363 * 3) rsrc fork must have actual blocks 3364 */ 3365 if ((isdir == 0) && (cp->c_rsrcfork == NULL) && 3366 (cp->c_blocks - VTOF(vp)->ff_blocks)) { 3367 /* 3368 * The resource fork vnode & filefork did not exist. 3369 * Create a temporary one for use in this function only. 3370 */ 3371 MALLOC_ZONE (temp_rsrc_fork, struct filefork *, sizeof (struct filefork), M_HFSFORK, M_WAITOK); 3372 bzero(temp_rsrc_fork, sizeof(struct filefork)); 3373 temp_rsrc_fork->ff_cp = cp; 3374 rl_init(&temp_rsrc_fork->ff_invalidranges); 3375 } 3376 3377 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_ATTRIBUTE | SFL_BITMAP, HFS_EXCLUSIVE_LOCK); 3378 3379 /* Look up the resource fork first, if necessary */ 3380 if (temp_rsrc_fork) { 3381 error = cat_lookup (hfsmp, &desc, 1, (struct cat_desc*) NULL, 3382 (struct cat_attr*) NULL, &temp_rsrc_fork->ff_data, NULL); 3383 if (error) { 3384 FREE_ZONE (temp_rsrc_fork, sizeof(struct filefork), M_HFSFORK); 3385 hfs_systemfile_unlock (hfsmp, lockflags); 3386 goto out; 3387 } 3388 } 3389 3390 if (!skip_reserve) { 3391 if ((error = cat_preflight(hfsmp, CAT_DELETE, NULL, 0))) { 3392 if (temp_rsrc_fork) { 3393 FREE_ZONE (temp_rsrc_fork, sizeof(struct filefork), M_HFSFORK); 3394 } 3395 hfs_systemfile_unlock(hfsmp, lockflags); 3396 goto out; 3397 } 3398 } 3399 3400 error = cat_delete(hfsmp, &desc, &cp->c_attr); 3401 3402 if (error && error != ENXIO && error != ENOENT) { 3403 printf("hfs_removefile: deleting file %s (%d), err: %d\n", 3404 cp->c_desc.cd_nameptr, cp->c_attr.ca_fileid, error); 3405 } 3406 3407 if (error == 0) { 3408 /* Update the parent directory */ 3409 if (dcp->c_entries > 0) 3410 dcp->c_entries--; 3411 dcp->c_dirchangecnt++; 3412 dcp->c_ctime = tv.tv_sec; 3413 dcp->c_mtime = tv.tv_sec; 3414 (void) cat_update(hfsmp, &dcp->c_desc, &dcp->c_attr, NULL, NULL); 3415 } 3416 hfs_systemfile_unlock(hfsmp, lockflags); 3417 3418 if (error) { 3419 if (temp_rsrc_fork) { 3420 FREE_ZONE (temp_rsrc_fork, sizeof(struct filefork), M_HFSFORK); 3421 } 3422 goto out; 3423 } 3424 3425 /* 3426 * Now that we've wiped out the catalog record, the file effectively doesn't 3427 * exist anymore. So update the quota records to reflect the loss of the 3428 * data fork and the resource fork. 3429 */ 3430#if QUOTA 3431 if (cp->c_datafork->ff_blocks > 0) { 3432 savedbytes = ((off_t)cp->c_datafork->ff_blocks * (off_t)blksize); 3433 (void) hfs_chkdq(cp, (int64_t)-(savedbytes), NOCRED, 0); 3434 } 3435 3436 /* 3437 * We may have just deleted the catalog record for a resource fork even 3438 * though it did not exist in core as a vnode. However, just because there 3439 * was a resource fork pointer in the cnode does not mean that it had any blocks. 3440 */ 3441 if (temp_rsrc_fork || cp->c_rsrcfork) { 3442 if (cp->c_rsrcfork) { 3443 if (cp->c_rsrcfork->ff_blocks > 0) { 3444 savedbytes = ((off_t)cp->c_rsrcfork->ff_blocks * (off_t)blksize); 3445 (void) hfs_chkdq(cp, (int64_t)-(savedbytes), NOCRED, 0); 3446 } 3447 } 3448 else { 3449 /* we must have used a temporary fork */ 3450 savedbytes = ((off_t)temp_rsrc_fork->ff_blocks * (off_t)blksize); 3451 (void) hfs_chkdq(cp, (int64_t)-(savedbytes), NOCRED, 0); 3452 } 3453 } 3454 3455 if (hfsmp->hfs_flags & HFS_QUOTAS) { 3456 (void)hfs_chkiq(cp, -1, NOCRED, 0); 3457 } 3458#endif 3459 3460 /* 3461 * If we didn't get any errors deleting the catalog entry, then go ahead 3462 * and release the backing store now. The filefork pointers are still valid. 3463 */ 3464 if (temp_rsrc_fork) { 3465 error = hfs_release_storage (hfsmp, cp->c_datafork, temp_rsrc_fork, fileid); 3466 } 3467 else { 3468 /* if cp->c_rsrcfork == NULL, hfs_release_storage will skip over it. */ 3469 error = hfs_release_storage (hfsmp, cp->c_datafork, cp->c_rsrcfork, fileid); 3470 } 3471 if (error) { 3472 /* 3473 * If we encountered an error updating the extents and bitmap, 3474 * mark the volume inconsistent. At this point, the catalog record has 3475 * already been deleted, so we can't recover it at this point. We need 3476 * to proceed and update the volume header and mark the cnode C_NOEXISTS. 3477 * The subsequent fsck should be able to recover the free space for us. 3478 */ 3479 hfs_mark_volume_inconsistent(hfsmp); 3480 } 3481 else { 3482 /* reset update_vh to 0, since hfs_release_storage should have done it for us */ 3483 update_vh = 0; 3484 } 3485 3486 /* Get rid of the temporary rsrc fork */ 3487 if (temp_rsrc_fork) { 3488 FREE_ZONE (temp_rsrc_fork, sizeof(struct filefork), M_HFSFORK); 3489 } 3490 3491 cp->c_flag |= C_NOEXISTS; 3492 cp->c_flag &= ~C_DELETED; 3493 3494 cp->c_touch_chgtime = TRUE; /* XXX needed ? */ 3495 --cp->c_linkcount; 3496 3497 /* 3498 * We must never get a directory if we're in this else block. We could 3499 * accidentally drop the number of files in the volume header if we did. 3500 */ 3501 hfs_volupdate(hfsmp, VOL_RMFILE, (dcp->c_cnid == kHFSRootFolderID)); 3502 3503 } 3504 3505 /* 3506 * All done with this cnode's descriptor... 3507 * 3508 * Note: all future catalog calls for this cnode must be by 3509 * fileid only. This is OK for HFS (which doesn't have file 3510 * thread records) since HFS doesn't support the removal of 3511 * busy files. 3512 */ 3513 cat_releasedesc(&cp->c_desc); 3514 3515out: 3516 if (error) { 3517 cp->c_flag &= ~C_DELETED; 3518 } 3519 3520 if (update_vh) { 3521 /* 3522 * If we bailed out earlier, we may need to update the volume header 3523 * to deal with the borrowed blocks accounting. 3524 */ 3525 hfs_volupdate (hfsmp, VOL_UPDATE, 0); 3526 } 3527 3528 if (started_tr) { 3529 hfs_end_transaction(hfsmp); 3530 } 3531 3532 dcp->c_flag &= ~C_DIR_MODIFICATION; 3533 wakeup((caddr_t)&dcp->c_flag); 3534 3535 return (error); 3536} 3537 3538 3539__private_extern__ void 3540replace_desc(struct cnode *cp, struct cat_desc *cdp) 3541{ 3542 // fixes 4348457 and 4463138 3543 if (&cp->c_desc == cdp) { 3544 return; 3545 } 3546 3547 /* First release allocated name buffer */ 3548 if (cp->c_desc.cd_flags & CD_HASBUF && cp->c_desc.cd_nameptr != 0) { 3549 const u_int8_t *name = cp->c_desc.cd_nameptr; 3550 3551 cp->c_desc.cd_nameptr = 0; 3552 cp->c_desc.cd_namelen = 0; 3553 cp->c_desc.cd_flags &= ~CD_HASBUF; 3554 vfs_removename((const char *)name); 3555 } 3556 bcopy(cdp, &cp->c_desc, sizeof(cp->c_desc)); 3557 3558 /* Cnode now owns the name buffer */ 3559 cdp->cd_nameptr = 0; 3560 cdp->cd_namelen = 0; 3561 cdp->cd_flags &= ~CD_HASBUF; 3562} 3563 3564 3565/* 3566 * Rename a cnode. 3567 * 3568 * The VFS layer guarantees that: 3569 * - source and destination will either both be directories, or 3570 * both not be directories. 3571 * - all the vnodes are from the same file system 3572 * 3573 * When the target is a directory, HFS must ensure that its empty. 3574 * 3575 * Note that this function requires up to 6 vnodes in order to work properly 3576 * if it is operating on files (and not on directories). This is because only 3577 * files can have resource forks, and we now require iocounts to be held on the 3578 * vnodes corresponding to the resource forks (if applicable) as well as 3579 * the files or directories undergoing rename. The problem with not holding 3580 * iocounts on the resource fork vnodes is that it can lead to a deadlock 3581 * situation: The rsrc fork of the source file may be recycled and reclaimed 3582 * in order to provide a vnode for the destination file's rsrc fork. Since 3583 * data and rsrc forks share the same cnode, we'd eventually try to lock the 3584 * source file's cnode in order to sync its rsrc fork to disk, but it's already 3585 * been locked. By taking the rsrc fork vnodes up front we ensure that they 3586 * cannot be recycled, and that the situation mentioned above cannot happen. 3587 */ 3588int 3589hfs_vnop_rename(ap) 3590 struct vnop_rename_args /* { 3591 struct vnode *a_fdvp; 3592 struct vnode *a_fvp; 3593 struct componentname *a_fcnp; 3594 struct vnode *a_tdvp; 3595 struct vnode *a_tvp; 3596 struct componentname *a_tcnp; 3597 vfs_context_t a_context; 3598 } */ *ap; 3599{ 3600 struct vnode *tvp = ap->a_tvp; 3601 struct vnode *tdvp = ap->a_tdvp; 3602 struct vnode *fvp = ap->a_fvp; 3603 struct vnode *fdvp = ap->a_fdvp; 3604 /* 3605 * Note that we only need locals for the target/destination's 3606 * resource fork vnode (and only if necessary). We don't care if the 3607 * source has a resource fork vnode or not. 3608 */ 3609 struct vnode *tvp_rsrc = NULLVP; 3610 uint32_t tvp_rsrc_vid = 0; 3611 struct componentname *tcnp = ap->a_tcnp; 3612 struct componentname *fcnp = ap->a_fcnp; 3613 struct proc *p = vfs_context_proc(ap->a_context); 3614 struct cnode *fcp; 3615 struct cnode *fdcp; 3616 struct cnode *tdcp; 3617 struct cnode *tcp; 3618 struct cnode *error_cnode; 3619 struct cat_desc from_desc; 3620 struct cat_desc to_desc; 3621 struct cat_desc out_desc; 3622 struct hfsmount *hfsmp; 3623 cat_cookie_t cookie; 3624 int tvp_deleted = 0; 3625 int started_tr = 0, got_cookie = 0; 3626 int took_trunc_lock = 0; 3627 int lockflags; 3628 int error; 3629 time_t orig_from_ctime, orig_to_ctime; 3630 int emit_rename = 1; 3631 int emit_delete = 1; 3632 3633 orig_from_ctime = VTOC(fvp)->c_ctime; 3634 if (tvp && VTOC(tvp)) { 3635 orig_to_ctime = VTOC(tvp)->c_ctime; 3636 } else { 3637 orig_to_ctime = ~0; 3638 } 3639 3640 hfsmp = VTOHFS(tdvp); 3641 /* 3642 * Do special case checks here. If fvp == tvp then we need to check the 3643 * cnode with locks held. 3644 */ 3645 if (fvp == tvp) { 3646 int is_hardlink = 0; 3647 /* 3648 * In this case, we do *NOT* ever emit a DELETE event. 3649 * We may not necessarily emit a RENAME event 3650 */ 3651 emit_delete = 0; 3652 if ((error = hfs_lock(VTOC(fvp), HFS_SHARED_LOCK))) { 3653 return error; 3654 } 3655 /* Check to see if the item is a hardlink or not */ 3656 is_hardlink = (VTOC(fvp)->c_flag & C_HARDLINK); 3657 hfs_unlock (VTOC(fvp)); 3658 3659 /* 3660 * If the item is not a hardlink, then case sensitivity must be off, otherwise 3661 * two names should not resolve to the same cnode unless they were case variants. 3662 */ 3663 if (is_hardlink) { 3664 emit_rename = 0; 3665 /* 3666 * Hardlinks are a little trickier. We only want to emit a rename event 3667 * if the item is a hardlink, the parent directories are the same, case sensitivity 3668 * is off, and the case folded names are the same. See the fvp == tvp case below for more 3669 * info. 3670 */ 3671 3672 if ((fdvp == tdvp) && ((hfsmp->hfs_flags & HFS_CASE_SENSITIVE) == 0)) { 3673 if (hfs_namecmp((const u_int8_t *)fcnp->cn_nameptr, fcnp->cn_namelen, 3674 (const u_int8_t *)tcnp->cn_nameptr, tcnp->cn_namelen) == 0) { 3675 /* Then in this case only it is ok to emit a rename */ 3676 emit_rename = 1; 3677 } 3678 } 3679 } 3680 } 3681 if (emit_rename) { 3682 check_for_tracked_file(fvp, orig_from_ctime, NAMESPACE_HANDLER_RENAME_OP, NULL); 3683 } 3684 3685 if (tvp && VTOC(tvp)) { 3686 if (emit_delete) { 3687 check_for_tracked_file(tvp, orig_to_ctime, NAMESPACE_HANDLER_DELETE_OP, NULL); 3688 } 3689 } 3690 3691retry: 3692 /* When tvp exists, take the truncate lock for hfs_removefile(). */ 3693 if (tvp && (vnode_isreg(tvp) || vnode_islnk(tvp))) { 3694 hfs_lock_truncate(VTOC(tvp), HFS_EXCLUSIVE_LOCK); 3695 took_trunc_lock = 1; 3696 } 3697 3698 error = hfs_lockfour(VTOC(fdvp), VTOC(fvp), VTOC(tdvp), tvp ? VTOC(tvp) : NULL, 3699 HFS_EXCLUSIVE_LOCK, &error_cnode); 3700 if (error) { 3701 if (took_trunc_lock) { 3702 hfs_unlock_truncate(VTOC(tvp), 0); 3703 took_trunc_lock = 0; 3704 } 3705 3706 /* 3707 * We hit an error path. If we were trying to re-acquire the locks 3708 * after coming through here once, we might have already obtained 3709 * an iocount on tvp's resource fork vnode. Drop that before dealing 3710 * with the failure. Note this is safe -- since we are in an 3711 * error handling path, we can't be holding the cnode locks. 3712 */ 3713 if (tvp_rsrc) { 3714 vnode_put (tvp_rsrc); 3715 tvp_rsrc_vid = 0; 3716 tvp_rsrc = NULL; 3717 } 3718 3719 /* 3720 * tvp might no longer exist. If the cause of the lock failure 3721 * was tvp, then we can try again with tvp/tcp set to NULL. 3722 * This is ok because the vfs syscall will vnode_put the vnodes 3723 * after we return from hfs_vnop_rename. 3724 */ 3725 if ((error == ENOENT) && (tvp != NULL) && (error_cnode == VTOC(tvp))) { 3726 tcp = NULL; 3727 tvp = NULL; 3728 goto retry; 3729 } 3730 3731 return (error); 3732 } 3733 3734 fdcp = VTOC(fdvp); 3735 fcp = VTOC(fvp); 3736 tdcp = VTOC(tdvp); 3737 tcp = tvp ? VTOC(tvp) : NULL; 3738 3739 /* 3740 * Acquire iocounts on the destination's resource fork vnode 3741 * if necessary. If dst/src are files and the dst has a resource 3742 * fork vnode, then we need to try and acquire an iocount on the rsrc vnode. 3743 * If it does not exist, then we don't care and can skip it. 3744 */ 3745 if ((vnode_isreg(fvp)) || (vnode_islnk(fvp))) { 3746 if ((tvp) && (tcp->c_rsrc_vp) && (tvp_rsrc == NULL)) { 3747 tvp_rsrc = tcp->c_rsrc_vp; 3748 /* 3749 * We can look at the vid here because we're holding the 3750 * cnode lock on the underlying cnode for this rsrc vnode. 3751 */ 3752 tvp_rsrc_vid = vnode_vid (tvp_rsrc); 3753 3754 /* Unlock everything to acquire iocount on this rsrc vnode */ 3755 if (took_trunc_lock) { 3756 hfs_unlock_truncate (VTOC(tvp), 0); 3757 took_trunc_lock = 0; 3758 } 3759 hfs_unlockfour(fdcp, fcp, tdcp, tcp); 3760 3761 if (vnode_getwithvid (tvp_rsrc, tvp_rsrc_vid)) { 3762 /* iocount acquisition failed. Reset fields and start over.. */ 3763 tvp_rsrc_vid = 0; 3764 tvp_rsrc = NULL; 3765 } 3766 goto retry; 3767 } 3768 } 3769 3770 /* Ensure we didn't race src or dst parent directories with rmdir. */ 3771 if (fdcp->c_flag & (C_NOEXISTS | C_DELETED)) { 3772 error = ENOENT; 3773 goto out; 3774 } 3775 3776 if (tdcp->c_flag & (C_NOEXISTS | C_DELETED)) { 3777 error = ENOENT; 3778 goto out; 3779 } 3780 3781 3782 /* Check for a race against unlink. The hfs_valid_cnode checks validate 3783 * the parent/child relationship with fdcp and tdcp, as well as the 3784 * component name of the target cnodes. 3785 */ 3786 if ((fcp->c_flag & (C_NOEXISTS | C_DELETED)) || !hfs_valid_cnode(hfsmp, fdvp, fcnp, fcp->c_fileid, NULL, &error)) { 3787 error = ENOENT; 3788 goto out; 3789 } 3790 3791 if (tcp && ((tcp->c_flag & (C_NOEXISTS | C_DELETED)) || !hfs_valid_cnode(hfsmp, tdvp, tcnp, tcp->c_fileid, NULL, &error))) { 3792 // 3793 // hmm, the destination vnode isn't valid any more. 3794 // in this case we can just drop him and pretend he 3795 // never existed in the first place. 3796 // 3797 if (took_trunc_lock) { 3798 hfs_unlock_truncate(VTOC(tvp), 0); 3799 took_trunc_lock = 0; 3800 } 3801 error = 0; 3802 3803 hfs_unlockfour(fdcp, fcp, tdcp, tcp); 3804 3805 tcp = NULL; 3806 tvp = NULL; 3807 3808 // retry the locking with tvp null'ed out 3809 goto retry; 3810 } 3811 3812 fdcp->c_flag |= C_DIR_MODIFICATION; 3813 if (fdvp != tdvp) { 3814 tdcp->c_flag |= C_DIR_MODIFICATION; 3815 } 3816 3817 /* 3818 * Disallow renaming of a directory hard link if the source and 3819 * destination parent directories are different, or a directory whose 3820 * descendant is a directory hard link and the one of the ancestors 3821 * of the destination directory is a directory hard link. 3822 */ 3823 if (vnode_isdir(fvp) && (fdvp != tdvp)) { 3824 if (fcp->c_flag & C_HARDLINK) { 3825 error = EPERM; 3826 goto out; 3827 } 3828 if (fcp->c_attr.ca_recflags & kHFSHasChildLinkMask) { 3829 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); 3830 if (cat_check_link_ancestry(hfsmp, tdcp->c_fileid, 0)) { 3831 error = EPERM; 3832 hfs_systemfile_unlock(hfsmp, lockflags); 3833 goto out; 3834 } 3835 hfs_systemfile_unlock(hfsmp, lockflags); 3836 } 3837 } 3838 3839 /* 3840 * The following edge case is caught here: 3841 * (to cannot be a descendent of from) 3842 * 3843 * o fdvp 3844 * / 3845 * / 3846 * o fvp 3847 * \ 3848 * \ 3849 * o tdvp 3850 * / 3851 * / 3852 * o tvp 3853 */ 3854 if (tdcp->c_parentcnid == fcp->c_fileid) { 3855 error = EINVAL; 3856 goto out; 3857 } 3858 3859 /* 3860 * The following two edge cases are caught here: 3861 * (note tvp is not empty) 3862 * 3863 * o tdvp o tdvp 3864 * / / 3865 * / / 3866 * o tvp tvp o fdvp 3867 * \ \ 3868 * \ \ 3869 * o fdvp o fvp 3870 * / 3871 * / 3872 * o fvp 3873 */ 3874 if (tvp && vnode_isdir(tvp) && (tcp->c_entries != 0) && fvp != tvp) { 3875 error = ENOTEMPTY; 3876 goto out; 3877 } 3878 3879 /* 3880 * The following edge case is caught here: 3881 * (the from child and parent are the same) 3882 * 3883 * o tdvp 3884 * / 3885 * / 3886 * fdvp o fvp 3887 */ 3888 if (fdvp == fvp) { 3889 error = EINVAL; 3890 goto out; 3891 } 3892 3893 /* 3894 * Make sure "from" vnode and its parent are changeable. 3895 */ 3896 if ((fcp->c_bsdflags & (IMMUTABLE | APPEND)) || (fdcp->c_bsdflags & APPEND)) { 3897 error = EPERM; 3898 goto out; 3899 } 3900 3901 /* 3902 * If the destination parent directory is "sticky", then the 3903 * user must own the parent directory, or the destination of 3904 * the rename, otherwise the destination may not be changed 3905 * (except by root). This implements append-only directories. 3906 * 3907 * Note that checks for immutable and write access are done 3908 * by the call to hfs_removefile. 3909 */ 3910 if (tvp && (tdcp->c_mode & S_ISTXT) && 3911 (suser(vfs_context_ucred(tcnp->cn_context), NULL)) && 3912 (kauth_cred_getuid(vfs_context_ucred(tcnp->cn_context)) != tdcp->c_uid) && 3913 (hfs_owner_rights(hfsmp, tcp->c_uid, vfs_context_ucred(tcnp->cn_context), p, false)) ) { 3914 error = EPERM; 3915 goto out; 3916 } 3917 3918 /* Don't allow modification of the journal or journal_info_block */ 3919 if (hfs_is_journal_file(hfsmp, fcp) || 3920 (tcp && hfs_is_journal_file(hfsmp, tcp))) { 3921 error = EPERM; 3922 goto out; 3923 } 3924 3925#if QUOTA 3926 if (tvp) 3927 (void)hfs_getinoquota(tcp); 3928#endif 3929 /* Preflighting done, take fvp out of the name space. */ 3930 cache_purge(fvp); 3931 3932 bzero(&from_desc, sizeof(from_desc)); 3933 from_desc.cd_nameptr = (const u_int8_t *)fcnp->cn_nameptr; 3934 from_desc.cd_namelen = fcnp->cn_namelen; 3935 from_desc.cd_parentcnid = fdcp->c_fileid; 3936 from_desc.cd_flags = fcp->c_desc.cd_flags & ~(CD_HASBUF | CD_DECOMPOSED); 3937 from_desc.cd_cnid = fcp->c_cnid; 3938 3939 bzero(&to_desc, sizeof(to_desc)); 3940 to_desc.cd_nameptr = (const u_int8_t *)tcnp->cn_nameptr; 3941 to_desc.cd_namelen = tcnp->cn_namelen; 3942 to_desc.cd_parentcnid = tdcp->c_fileid; 3943 to_desc.cd_flags = fcp->c_desc.cd_flags & ~(CD_HASBUF | CD_DECOMPOSED); 3944 to_desc.cd_cnid = fcp->c_cnid; 3945 3946 if ((error = hfs_start_transaction(hfsmp)) != 0) { 3947 goto out; 3948 } 3949 started_tr = 1; 3950 3951 /* hfs_vnop_link() and hfs_vnop_rename() set kHFSHasChildLinkMask 3952 * inside a journal transaction and without holding a cnode lock. 3953 * As setting of this bit depends on being in journal transaction for 3954 * concurrency, check this bit again after we start journal transaction for rename 3955 * to ensure that this directory does not have any descendant that 3956 * is a directory hard link. 3957 */ 3958 if (vnode_isdir(fvp) && (fdvp != tdvp)) { 3959 if (fcp->c_attr.ca_recflags & kHFSHasChildLinkMask) { 3960 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); 3961 if (cat_check_link_ancestry(hfsmp, tdcp->c_fileid, 0)) { 3962 error = EPERM; 3963 hfs_systemfile_unlock(hfsmp, lockflags); 3964 goto out; 3965 } 3966 hfs_systemfile_unlock(hfsmp, lockflags); 3967 } 3968 } 3969 3970 // if it's a hardlink then re-lookup the name so 3971 // that we get the correct cnid in from_desc (see 3972 // the comment in hfs_removefile for more details) 3973 // 3974 if (fcp->c_flag & C_HARDLINK) { 3975 struct cat_desc tmpdesc; 3976 cnid_t real_cnid; 3977 3978 tmpdesc.cd_nameptr = (const u_int8_t *)fcnp->cn_nameptr; 3979 tmpdesc.cd_namelen = fcnp->cn_namelen; 3980 tmpdesc.cd_parentcnid = fdcp->c_fileid; 3981 tmpdesc.cd_hint = fdcp->c_childhint; 3982 tmpdesc.cd_flags = fcp->c_desc.cd_flags & CD_ISDIR; 3983 tmpdesc.cd_encoding = 0; 3984 3985 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); 3986 3987 if (cat_lookup(hfsmp, &tmpdesc, 0, NULL, NULL, NULL, &real_cnid) != 0) { 3988 hfs_systemfile_unlock(hfsmp, lockflags); 3989 goto out; 3990 } 3991 3992 // use the real cnid instead of whatever happened to be there 3993 from_desc.cd_cnid = real_cnid; 3994 hfs_systemfile_unlock(hfsmp, lockflags); 3995 } 3996 3997 /* 3998 * Reserve some space in the Catalog file. 3999 */ 4000 if ((error = cat_preflight(hfsmp, CAT_RENAME + CAT_DELETE, &cookie, p))) { 4001 goto out; 4002 } 4003 got_cookie = 1; 4004 4005 /* 4006 * If the destination exists then it may need to be removed. 4007 * 4008 * Due to HFS's locking system, we should always move the 4009 * existing 'tvp' element to the hidden directory in hfs_vnop_rename. 4010 * Because the VNOP_LOOKUP call enters and exits the filesystem independently 4011 * of the actual vnop that it was trying to do (stat, link, readlink), 4012 * we must release the cnode lock of that element during the interim to 4013 * do MAC checking, vnode authorization, and other calls. In that time, 4014 * the item can be deleted (or renamed over). However, only in the rename 4015 * case is it inappropriate to return ENOENT from any of those calls. Either 4016 * the call should return information about the old element (stale), or get 4017 * information about the newer element that we are about to write in its place. 4018 * 4019 * HFS lookup has been modified to detect a rename and re-drive its 4020 * lookup internally. For other calls that have already succeeded in 4021 * their lookup call and are waiting to acquire the cnode lock in order 4022 * to proceed, that cnode lock will not fail due to the cnode being marked 4023 * C_NOEXISTS, because it won't have been marked as such. It will only 4024 * have C_DELETED. Thus, they will simply act on the stale open-unlinked 4025 * element. All future callers will get the new element. 4026 * 4027 * To implement this behavior, we pass the "only_unlink" argument to 4028 * hfs_removefile and hfs_removedir. This will result in the vnode acting 4029 * as though it is open-unlinked. Additionally, when we are done moving the 4030 * element to the hidden directory, we vnode_recycle the target so that it is 4031 * reclaimed as soon as possible. Reclaim and inactive are both 4032 * capable of clearing out unused blocks for an open-unlinked file or dir. 4033 */ 4034 if (tvp) { 4035 /* 4036 * When fvp matches tvp they could be case variants 4037 * or matching hard links. 4038 */ 4039 if (fvp == tvp) { 4040 if (!(fcp->c_flag & C_HARDLINK)) { 4041 /* 4042 * If they're not hardlinks, then fvp == tvp must mean we 4043 * are using case-insensitive HFS because case-sensitive would 4044 * not use the same vnode for both. In this case we just update 4045 * the catalog for: a -> A 4046 */ 4047 goto skip_rm; /* simple case variant */ 4048 4049 } 4050 /* For all cases below, we must be using hardlinks */ 4051 else if ((fdvp != tdvp) || 4052 (hfsmp->hfs_flags & HFS_CASE_SENSITIVE)) { 4053 /* 4054 * If the parent directories are not the same, AND the two items 4055 * are hardlinks, posix says to do nothing: 4056 * dir1/fred <-> dir2/bob and the op was mv dir1/fred -> dir2/bob 4057 * We just return 0 in this case. 4058 * 4059 * If case sensitivity is on, and we are using hardlinks 4060 * then renaming is supposed to do nothing. 4061 * dir1/fred <-> dir2/FRED, and op == mv dir1/fred -> dir2/FRED 4062 */ 4063 goto out; /* matching hardlinks, nothing to do */ 4064 4065 } else if (hfs_namecmp((const u_int8_t *)fcnp->cn_nameptr, fcnp->cn_namelen, 4066 (const u_int8_t *)tcnp->cn_nameptr, tcnp->cn_namelen) == 0) { 4067 /* 4068 * If we get here, then the following must be true: 4069 * a) We are running case-insensitive HFS+. 4070 * b) Both paths 'fvp' and 'tvp' are in the same parent directory. 4071 * c) the two names are case-variants of each other. 4072 * 4073 * In this case, we are really only dealing with a single catalog record 4074 * whose name is being updated. 4075 * 4076 * op is dir1/fred -> dir1/FRED 4077 * 4078 * We need to special case the name matching, because if 4079 * dir1/fred <-> dir1/bob were the two links, and the 4080 * op was dir1/fred -> dir1/bob 4081 * That would fail/do nothing. 4082 */ 4083 goto skip_rm; /* case-variant hardlink in the same dir */ 4084 } else { 4085 goto out; /* matching hardlink, nothing to do */ 4086 } 4087 } 4088 4089 4090 if (vnode_isdir(tvp)) { 4091 /* 4092 * hfs_removedir will eventually call hfs_removefile on the directory 4093 * we're working on, because only hfs_removefile does the renaming of the 4094 * item to the hidden directory. The directory will stay around in the 4095 * hidden directory with C_DELETED until it gets an inactive or a reclaim. 4096 * That way, we can destroy all of the EAs as needed and allow new ones to be 4097 * written. 4098 */ 4099 error = hfs_removedir(tdvp, tvp, tcnp, HFSRM_SKIP_RESERVE, 1); 4100 } 4101 else { 4102 error = hfs_removefile(tdvp, tvp, tcnp, 0, HFSRM_SKIP_RESERVE, 0, NULL, 1); 4103 4104 /* 4105 * If the destination file had a resource fork vnode, then we need to get rid of 4106 * its blocks when there are no more references to it. Because the call to 4107 * hfs_removefile above always open-unlinks things, we need to force an inactive/reclaim 4108 * on the resource fork vnode, in order to prevent block leaks. Otherwise, 4109 * the resource fork vnode could prevent the data fork vnode from going out of scope 4110 * because it holds a v_parent reference on it. So we mark it for termination 4111 * with a call to vnode_recycle. hfs_vnop_reclaim has been modified so that it 4112 * can clean up the blocks of open-unlinked files and resource forks. 4113 * 4114 * We can safely call vnode_recycle on the resource fork because we took an iocount 4115 * reference on it at the beginning of the function. 4116 */ 4117 4118 if ((error == 0) && (tcp->c_flag & C_DELETED) && (tvp_rsrc)) { 4119 vnode_recycle(tvp_rsrc); 4120 } 4121 } 4122 4123 if (error) { 4124 goto out; 4125 } 4126 4127 tvp_deleted = 1; 4128 4129 /* Mark 'tcp' as being deleted due to a rename */ 4130 tcp->c_flag |= C_RENAMED; 4131 4132 /* 4133 * Aggressively mark tvp/tcp for termination to ensure that we recover all blocks 4134 * as quickly as possible. 4135 */ 4136 vnode_recycle(tvp); 4137 } 4138skip_rm: 4139 /* 4140 * All done with tvp and fvp. 4141 * 4142 * We also jump to this point if there was no destination observed during lookup and namei. 4143 * However, because only iocounts are held at the VFS layer, there is nothing preventing a 4144 * competing thread from racing us and creating a file or dir at the destination of this rename 4145 * operation. If this occurs, it may cause us to get a spurious EEXIST out of the cat_rename 4146 * call below. To preserve rename's atomicity, we need to signal VFS to re-drive the 4147 * namei/lookup and restart the rename operation. EEXIST is an allowable errno to be bubbled 4148 * out of the rename syscall, but not for this reason, since it is a synonym errno for ENOTEMPTY. 4149 * To signal VFS, we return ERECYCLE (which is also used for lookup restarts). This errno 4150 * will be swallowed and it will restart the operation. 4151 */ 4152 4153 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK); 4154 error = cat_rename(hfsmp, &from_desc, &tdcp->c_desc, &to_desc, &out_desc); 4155 hfs_systemfile_unlock(hfsmp, lockflags); 4156 4157 if (error) { 4158 if (error == EEXIST) { 4159 error = ERECYCLE; 4160 } 4161 goto out; 4162 } 4163 4164 /* Invalidate negative cache entries in the destination directory */ 4165 if (tdcp->c_flag & C_NEG_ENTRIES) { 4166 cache_purge_negatives(tdvp); 4167 tdcp->c_flag &= ~C_NEG_ENTRIES; 4168 } 4169 4170 /* Update cnode's catalog descriptor */ 4171 replace_desc(fcp, &out_desc); 4172 fcp->c_parentcnid = tdcp->c_fileid; 4173 fcp->c_hint = 0; 4174 4175 /* Now indicate this cnode needs to have date-added written to the finderinfo */ 4176 fcp->c_flag |= C_NEEDS_DATEADDED; 4177 (void) hfs_update (fvp, 0); 4178 4179 4180 hfs_volupdate(hfsmp, vnode_isdir(fvp) ? VOL_RMDIR : VOL_RMFILE, 4181 (fdcp->c_cnid == kHFSRootFolderID)); 4182 hfs_volupdate(hfsmp, vnode_isdir(fvp) ? VOL_MKDIR : VOL_MKFILE, 4183 (tdcp->c_cnid == kHFSRootFolderID)); 4184 4185 /* Update both parent directories. */ 4186 if (fdvp != tdvp) { 4187 if (vnode_isdir(fvp)) { 4188 /* If the source directory has directory hard link 4189 * descendants, set the kHFSHasChildLinkBit in the 4190 * destination parent hierarchy 4191 */ 4192 if ((fcp->c_attr.ca_recflags & kHFSHasChildLinkMask) && 4193 !(tdcp->c_attr.ca_recflags & kHFSHasChildLinkMask)) { 4194 4195 tdcp->c_attr.ca_recflags |= kHFSHasChildLinkMask; 4196 4197 error = cat_set_childlinkbit(hfsmp, tdcp->c_parentcnid); 4198 if (error) { 4199 printf ("hfs_vnop_rename: error updating parent chain for %u\n", tdcp->c_cnid); 4200 error = 0; 4201 } 4202 } 4203 INC_FOLDERCOUNT(hfsmp, tdcp->c_attr); 4204 DEC_FOLDERCOUNT(hfsmp, fdcp->c_attr); 4205 } 4206 tdcp->c_entries++; 4207 tdcp->c_dirchangecnt++; 4208 if (fdcp->c_entries > 0) 4209 fdcp->c_entries--; 4210 fdcp->c_dirchangecnt++; 4211 fdcp->c_touch_chgtime = TRUE; 4212 fdcp->c_touch_modtime = TRUE; 4213 4214 fdcp->c_flag |= C_FORCEUPDATE; // XXXdbg - force it out! 4215 (void) hfs_update(fdvp, 0); 4216 } 4217 tdcp->c_childhint = out_desc.cd_hint; /* Cache directory's location */ 4218 tdcp->c_touch_chgtime = TRUE; 4219 tdcp->c_touch_modtime = TRUE; 4220 4221 tdcp->c_flag |= C_FORCEUPDATE; // XXXdbg - force it out! 4222 (void) hfs_update(tdvp, 0); 4223 4224 /* Update the vnode's name now that the rename has completed. */ 4225 vnode_update_identity(fvp, tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, 4226 tcnp->cn_hash, (VNODE_UPDATE_PARENT | VNODE_UPDATE_NAME)); 4227 4228 /* 4229 * At this point, we may have a resource fork vnode attached to the 4230 * 'from' vnode. If it exists, we will want to update its name, because 4231 * it contains the old name + _PATH_RSRCFORKSPEC. ("/..namedfork/rsrc"). 4232 * 4233 * Note that the only thing we need to update here is the name attached to 4234 * the vnode, since a resource fork vnode does not have a separate resource 4235 * cnode -- it's still 'fcp'. 4236 */ 4237 if (fcp->c_rsrc_vp) { 4238 char* rsrc_path = NULL; 4239 int len; 4240 4241 /* Create a new temporary buffer that's going to hold the new name */ 4242 MALLOC_ZONE (rsrc_path, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); 4243 len = snprintf (rsrc_path, MAXPATHLEN, "%s%s", tcnp->cn_nameptr, _PATH_RSRCFORKSPEC); 4244 len = MIN(len, MAXPATHLEN); 4245 4246 /* 4247 * vnode_update_identity will do the following for us: 4248 * 1) release reference on the existing rsrc vnode's name. 4249 * 2) copy/insert new name into the name cache 4250 * 3) attach the new name to the resource vnode 4251 * 4) update the vnode's vid 4252 */ 4253 vnode_update_identity (fcp->c_rsrc_vp, fvp, rsrc_path, len, 0, (VNODE_UPDATE_NAME | VNODE_UPDATE_CACHE)); 4254 4255 /* Free the memory associated with the resource fork's name */ 4256 FREE_ZONE (rsrc_path, MAXPATHLEN, M_NAMEI); 4257 } 4258out: 4259 if (got_cookie) { 4260 cat_postflight(hfsmp, &cookie, p); 4261 } 4262 if (started_tr) { 4263 hfs_end_transaction(hfsmp); 4264 } 4265 4266 fdcp->c_flag &= ~C_DIR_MODIFICATION; 4267 wakeup((caddr_t)&fdcp->c_flag); 4268 if (fdvp != tdvp) { 4269 tdcp->c_flag &= ~C_DIR_MODIFICATION; 4270 wakeup((caddr_t)&tdcp->c_flag); 4271 } 4272 4273 if (took_trunc_lock) { 4274 hfs_unlock_truncate(VTOC(tvp), 0); 4275 } 4276 4277 hfs_unlockfour(fdcp, fcp, tdcp, tcp); 4278 4279 /* Now vnode_put the resource fork vnode if necessary */ 4280 if (tvp_rsrc) { 4281 vnode_put(tvp_rsrc); 4282 tvp_rsrc = NULL; 4283 } 4284 4285 /* After tvp is removed the only acceptable error is EIO */ 4286 if (error && tvp_deleted) 4287 error = EIO; 4288 4289 return (error); 4290} 4291 4292 4293/* 4294 * Make a directory. 4295 */ 4296int 4297hfs_vnop_mkdir(struct vnop_mkdir_args *ap) 4298{ 4299 /***** HACK ALERT ********/ 4300 ap->a_cnp->cn_flags |= MAKEENTRY; 4301 return hfs_makenode(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap, ap->a_context); 4302} 4303 4304 4305/* 4306 * Create a symbolic link. 4307 */ 4308int 4309hfs_vnop_symlink(struct vnop_symlink_args *ap) 4310{ 4311 struct vnode **vpp = ap->a_vpp; 4312 struct vnode *dvp = ap->a_dvp; 4313 struct vnode *vp = NULL; 4314 struct cnode *cp = NULL; 4315 struct hfsmount *hfsmp; 4316 struct filefork *fp; 4317 struct buf *bp = NULL; 4318 char *datap; 4319 int started_tr = 0; 4320 u_int32_t len; 4321 int error; 4322 4323 /* HFS standard disks don't support symbolic links */ 4324 if (VTOVCB(dvp)->vcbSigWord != kHFSPlusSigWord) 4325 return (ENOTSUP); 4326 4327 /* Check for empty target name */ 4328 if (ap->a_target[0] == 0) 4329 return (EINVAL); 4330 4331 hfsmp = VTOHFS(dvp); 4332 len = strlen(ap->a_target); 4333 4334 /* Check for free space */ 4335 if (((u_int64_t)hfs_freeblks(hfsmp, 0) * (u_int64_t)hfsmp->blockSize) < len) { 4336 return (ENOSPC); 4337 } 4338 4339 /* Create the vnode */ 4340 ap->a_vap->va_mode |= S_IFLNK; 4341 if ((error = hfs_makenode(dvp, vpp, ap->a_cnp, ap->a_vap, ap->a_context))) { 4342 goto out; 4343 } 4344 vp = *vpp; 4345 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK))) { 4346 goto out; 4347 } 4348 cp = VTOC(vp); 4349 fp = VTOF(vp); 4350 4351 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) { 4352 goto out; 4353 } 4354 4355#if QUOTA 4356 (void)hfs_getinoquota(cp); 4357#endif /* QUOTA */ 4358 4359 if ((error = hfs_start_transaction(hfsmp)) != 0) { 4360 goto out; 4361 } 4362 started_tr = 1; 4363 4364 /* 4365 * Allocate space for the link. 4366 * 4367 * Since we're already inside a transaction, 4368 * tell hfs_truncate to skip the ubc_setsize. 4369 * 4370 * Don't need truncate lock since a symlink is treated as a system file. 4371 */ 4372 error = hfs_truncate(vp, len, IO_NOZEROFILL, 1, 0, ap->a_context); 4373 4374 /* On errors, remove the symlink file */ 4375 if (error) { 4376 /* 4377 * End the transaction so we don't re-take the cnode lock 4378 * below while inside a transaction (lock order violation). 4379 */ 4380 hfs_end_transaction(hfsmp); 4381 4382 /* hfs_removefile() requires holding the truncate lock */ 4383 hfs_unlock(cp); 4384 hfs_lock_truncate(cp, HFS_EXCLUSIVE_LOCK); 4385 hfs_lock(cp, HFS_FORCE_LOCK); 4386 4387 if (hfs_start_transaction(hfsmp) != 0) { 4388 started_tr = 0; 4389 hfs_unlock_truncate(cp, TRUE); 4390 goto out; 4391 } 4392 4393 (void) hfs_removefile(dvp, vp, ap->a_cnp, 0, 0, 0, NULL, 0); 4394 hfs_unlock_truncate(cp, 0); 4395 goto out; 4396 } 4397 4398 /* Write the link to disk */ 4399 bp = buf_getblk(vp, (daddr64_t)0, roundup((int)fp->ff_size, hfsmp->hfs_physical_block_size), 4400 0, 0, BLK_META); 4401 if (hfsmp->jnl) { 4402 journal_modify_block_start(hfsmp->jnl, bp); 4403 } 4404 datap = (char *)buf_dataptr(bp); 4405 bzero(datap, buf_size(bp)); 4406 bcopy(ap->a_target, datap, len); 4407 4408 if (hfsmp->jnl) { 4409 journal_modify_block_end(hfsmp->jnl, bp, NULL, NULL); 4410 } else { 4411 buf_bawrite(bp); 4412 } 4413 /* 4414 * We defered the ubc_setsize for hfs_truncate 4415 * since we were inside a transaction. 4416 * 4417 * We don't need to drop the cnode lock here 4418 * since this is a symlink. 4419 */ 4420 ubc_setsize(vp, len); 4421out: 4422 if (started_tr) 4423 hfs_end_transaction(hfsmp); 4424 if ((cp != NULL) && (vp != NULL)) { 4425 hfs_unlock(cp); 4426 } 4427 if (error) { 4428 if (vp) { 4429 vnode_put(vp); 4430 } 4431 *vpp = NULL; 4432 } 4433 return (error); 4434} 4435 4436 4437/* structures to hold a "." or ".." directory entry */ 4438struct hfs_stddotentry { 4439 u_int32_t d_fileno; /* unique file number */ 4440 u_int16_t d_reclen; /* length of this structure */ 4441 u_int8_t d_type; /* dirent file type */ 4442 u_int8_t d_namlen; /* len of filename */ 4443 char d_name[4]; /* "." or ".." */ 4444}; 4445 4446struct hfs_extdotentry { 4447 u_int64_t d_fileno; /* unique file number */ 4448 u_int64_t d_seekoff; /* seek offset (optional, used by servers) */ 4449 u_int16_t d_reclen; /* length of this structure */ 4450 u_int16_t d_namlen; /* len of filename */ 4451 u_int8_t d_type; /* dirent file type */ 4452 u_char d_name[3]; /* "." or ".." */ 4453}; 4454 4455typedef union { 4456 struct hfs_stddotentry std; 4457 struct hfs_extdotentry ext; 4458} hfs_dotentry_t; 4459 4460/* 4461 * hfs_vnop_readdir reads directory entries into the buffer pointed 4462 * to by uio, in a filesystem independent format. Up to uio_resid 4463 * bytes of data can be transferred. The data in the buffer is a 4464 * series of packed dirent structures where each one contains the 4465 * following entries: 4466 * 4467 * u_int32_t d_fileno; // file number of entry 4468 * u_int16_t d_reclen; // length of this record 4469 * u_int8_t d_type; // file type 4470 * u_int8_t d_namlen; // length of string in d_name 4471 * char d_name[MAXNAMELEN+1]; // null terminated file name 4472 * 4473 * The current position (uio_offset) refers to the next block of 4474 * entries. The offset can only be set to a value previously 4475 * returned by hfs_vnop_readdir or zero. This offset does not have 4476 * to match the number of bytes returned (in uio_resid). 4477 * 4478 * In fact, the offset used by HFS is essentially an index (26 bits) 4479 * with a tag (6 bits). The tag is for associating the next request 4480 * with the current request. This enables us to have multiple threads 4481 * reading the directory while the directory is also being modified. 4482 * 4483 * Each tag/index pair is tied to a unique directory hint. The hint 4484 * contains information (filename) needed to build the catalog b-tree 4485 * key for finding the next set of entries. 4486 * 4487 * If the directory is marked as deleted-but-in-use (cp->c_flag & C_DELETED), 4488 * do NOT synthesize entries for "." and "..". 4489 */ 4490int 4491hfs_vnop_readdir(ap) 4492 struct vnop_readdir_args /* { 4493 vnode_t a_vp; 4494 uio_t a_uio; 4495 int a_flags; 4496 int *a_eofflag; 4497 int *a_numdirent; 4498 vfs_context_t a_context; 4499 } */ *ap; 4500{ 4501 struct vnode *vp = ap->a_vp; 4502 uio_t uio = ap->a_uio; 4503 struct cnode *cp; 4504 struct hfsmount *hfsmp; 4505 directoryhint_t *dirhint = NULL; 4506 directoryhint_t localhint; 4507 off_t offset; 4508 off_t startoffset; 4509 int error = 0; 4510 int eofflag = 0; 4511 user_addr_t user_start = 0; 4512 user_size_t user_len = 0; 4513 int index; 4514 unsigned int tag; 4515 int items; 4516 int lockflags; 4517 int extended; 4518 int nfs_cookies; 4519 cnid_t cnid_hint = 0; 4520 4521 items = 0; 4522 startoffset = offset = uio_offset(uio); 4523 extended = (ap->a_flags & VNODE_READDIR_EXTENDED); 4524 nfs_cookies = extended && (ap->a_flags & VNODE_READDIR_REQSEEKOFF); 4525 4526 /* Sanity check the uio data. */ 4527 if (uio_iovcnt(uio) > 1) 4528 return (EINVAL); 4529 4530 if (VTOC(vp)->c_bsdflags & UF_COMPRESSED) { 4531 int compressed = hfs_file_is_compressed(VTOC(vp), 0); /* 0 == take the cnode lock */ 4532 if (VTOCMP(vp) != NULL && !compressed) { 4533 error = check_for_dataless_file(vp, NAMESPACE_HANDLER_READ_OP); 4534 if (error) { 4535 return error; 4536 } 4537 } 4538 } 4539 4540 cp = VTOC(vp); 4541 hfsmp = VTOHFS(vp); 4542 4543 /* Note that the dirhint calls require an exclusive lock. */ 4544 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK))) 4545 return (error); 4546 4547 /* Pick up cnid hint (if any). */ 4548 if (nfs_cookies) { 4549 cnid_hint = (cnid_t)(uio_offset(uio) >> 32); 4550 uio_setoffset(uio, uio_offset(uio) & 0x00000000ffffffffLL); 4551 if (cnid_hint == INT_MAX) { /* searching pass the last item */ 4552 eofflag = 1; 4553 goto out; 4554 } 4555 } 4556 /* 4557 * Synthesize entries for "." and "..", unless the directory has 4558 * been deleted, but not closed yet (lazy delete in progress). 4559 */ 4560 if (offset == 0 && !(cp->c_flag & C_DELETED)) { 4561 hfs_dotentry_t dotentry[2]; 4562 size_t uiosize; 4563 4564 if (extended) { 4565 struct hfs_extdotentry *entry = &dotentry[0].ext; 4566 4567 entry->d_fileno = cp->c_cnid; 4568 entry->d_reclen = sizeof(struct hfs_extdotentry); 4569 entry->d_type = DT_DIR; 4570 entry->d_namlen = 1; 4571 entry->d_name[0] = '.'; 4572 entry->d_name[1] = '\0'; 4573 entry->d_name[2] = '\0'; 4574 entry->d_seekoff = 1; 4575 4576 ++entry; 4577 entry->d_fileno = cp->c_parentcnid; 4578 entry->d_reclen = sizeof(struct hfs_extdotentry); 4579 entry->d_type = DT_DIR; 4580 entry->d_namlen = 2; 4581 entry->d_name[0] = '.'; 4582 entry->d_name[1] = '.'; 4583 entry->d_name[2] = '\0'; 4584 entry->d_seekoff = 2; 4585 uiosize = 2 * sizeof(struct hfs_extdotentry); 4586 } else { 4587 struct hfs_stddotentry *entry = &dotentry[0].std; 4588 4589 entry->d_fileno = cp->c_cnid; 4590 entry->d_reclen = sizeof(struct hfs_stddotentry); 4591 entry->d_type = DT_DIR; 4592 entry->d_namlen = 1; 4593 *(int *)&entry->d_name[0] = 0; 4594 entry->d_name[0] = '.'; 4595 4596 ++entry; 4597 entry->d_fileno = cp->c_parentcnid; 4598 entry->d_reclen = sizeof(struct hfs_stddotentry); 4599 entry->d_type = DT_DIR; 4600 entry->d_namlen = 2; 4601 *(int *)&entry->d_name[0] = 0; 4602 entry->d_name[0] = '.'; 4603 entry->d_name[1] = '.'; 4604 uiosize = 2 * sizeof(struct hfs_stddotentry); 4605 } 4606 if ((error = uiomove((caddr_t)&dotentry, uiosize, uio))) { 4607 goto out; 4608 } 4609 offset += 2; 4610 } 4611 4612 /* If there are no real entries then we're done. */ 4613 if (cp->c_entries == 0) { 4614 error = 0; 4615 eofflag = 1; 4616 uio_setoffset(uio, offset); 4617 goto seekoffcalc; 4618 } 4619 4620 // 4621 // We have to lock the user's buffer here so that we won't 4622 // fault on it after we've acquired a shared lock on the 4623 // catalog file. The issue is that you can get a 3-way 4624 // deadlock if someone else starts a transaction and then 4625 // tries to lock the catalog file but can't because we're 4626 // here and we can't service our page fault because VM is 4627 // blocked trying to start a transaction as a result of 4628 // trying to free up pages for our page fault. It's messy 4629 // but it does happen on dual-processors that are paging 4630 // heavily (see radar 3082639 for more info). By locking 4631 // the buffer up-front we prevent ourselves from faulting 4632 // while holding the shared catalog file lock. 4633 // 4634 // Fortunately this and hfs_search() are the only two places 4635 // currently (10/30/02) that can fault on user data with a 4636 // shared lock on the catalog file. 4637 // 4638 if (hfsmp->jnl && uio_isuserspace(uio)) { 4639 user_start = uio_curriovbase(uio); 4640 user_len = uio_curriovlen(uio); 4641 4642 if ((error = vslock(user_start, user_len)) != 0) { 4643 user_start = 0; 4644 goto out; 4645 } 4646 } 4647 /* Convert offset into a catalog directory index. */ 4648 index = (offset & HFS_INDEX_MASK) - 2; 4649 tag = offset & ~HFS_INDEX_MASK; 4650 4651 /* Lock catalog during cat_findname and cat_getdirentries. */ 4652 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); 4653 4654 /* When called from NFS, try and resolve a cnid hint. */ 4655 if (nfs_cookies && cnid_hint != 0) { 4656 if (cat_findname(hfsmp, cnid_hint, &localhint.dh_desc) == 0) { 4657 if ( localhint.dh_desc.cd_parentcnid == cp->c_fileid) { 4658 localhint.dh_index = index - 1; 4659 localhint.dh_time = 0; 4660 bzero(&localhint.dh_link, sizeof(localhint.dh_link)); 4661 dirhint = &localhint; /* don't forget to release the descriptor */ 4662 } else { 4663 cat_releasedesc(&localhint.dh_desc); 4664 } 4665 } 4666 } 4667 4668 /* Get a directory hint (cnode must be locked exclusive) */ 4669 if (dirhint == NULL) { 4670 dirhint = hfs_getdirhint(cp, ((index - 1) & HFS_INDEX_MASK) | tag, 0); 4671 4672 /* Hide tag from catalog layer. */ 4673 dirhint->dh_index &= HFS_INDEX_MASK; 4674 if (dirhint->dh_index == HFS_INDEX_MASK) { 4675 dirhint->dh_index = -1; 4676 } 4677 } 4678 4679 if (index == 0) { 4680 dirhint->dh_threadhint = cp->c_dirthreadhint; 4681 } 4682 else { 4683 /* 4684 * If we have a non-zero index, there is a possibility that during the last 4685 * call to hfs_vnop_readdir we hit EOF for this directory. If that is the case 4686 * then we don't want to return any new entries for the caller. Just return 0 4687 * items, mark the eofflag, and bail out. Because we won't have done any work, the 4688 * code at the end of the function will release the dirhint for us. 4689 * 4690 * Don't forget to unlock the catalog lock on the way out, too. 4691 */ 4692 if (dirhint->dh_desc.cd_flags & CD_EOF) { 4693 error = 0; 4694 eofflag = 1; 4695 uio_setoffset(uio, startoffset); 4696 hfs_systemfile_unlock (hfsmp, lockflags); 4697 4698 goto seekoffcalc; 4699 } 4700 } 4701 4702 /* Pack the buffer with dirent entries. */ 4703 error = cat_getdirentries(hfsmp, cp->c_entries, dirhint, uio, ap->a_flags, &items, &eofflag); 4704 4705 if (index == 0 && error == 0) { 4706 cp->c_dirthreadhint = dirhint->dh_threadhint; 4707 } 4708 4709 hfs_systemfile_unlock(hfsmp, lockflags); 4710 4711 if (error != 0) { 4712 goto out; 4713 } 4714 4715 /* Get index to the next item */ 4716 index += items; 4717 4718 if (items >= (int)cp->c_entries) { 4719 eofflag = 1; 4720 } 4721 4722 /* Convert catalog directory index back into an offset. */ 4723 while (tag == 0) 4724 tag = (++cp->c_dirhinttag) << HFS_INDEX_BITS; 4725 uio_setoffset(uio, (index + 2) | tag); 4726 dirhint->dh_index |= tag; 4727 4728seekoffcalc: 4729 cp->c_touch_acctime = TRUE; 4730 4731 if (ap->a_numdirent) { 4732 if (startoffset == 0) 4733 items += 2; 4734 *ap->a_numdirent = items; 4735 } 4736 4737out: 4738 if (user_start) { 4739 vsunlock(user_start, user_len, TRUE); 4740 } 4741 /* If we didn't do anything then go ahead and dump the hint. */ 4742 if ((dirhint != NULL) && 4743 (dirhint != &localhint) && 4744 (uio_offset(uio) == startoffset)) { 4745 hfs_reldirhint(cp, dirhint); 4746 eofflag = 1; 4747 } 4748 if (ap->a_eofflag) { 4749 *ap->a_eofflag = eofflag; 4750 } 4751 if (dirhint == &localhint) { 4752 cat_releasedesc(&localhint.dh_desc); 4753 } 4754 hfs_unlock(cp); 4755 return (error); 4756} 4757 4758 4759/* 4760 * Read contents of a symbolic link. 4761 */ 4762int 4763hfs_vnop_readlink(ap) 4764 struct vnop_readlink_args /* { 4765 struct vnode *a_vp; 4766 struct uio *a_uio; 4767 vfs_context_t a_context; 4768 } */ *ap; 4769{ 4770 struct vnode *vp = ap->a_vp; 4771 struct cnode *cp; 4772 struct filefork *fp; 4773 int error; 4774 4775 if (!vnode_islnk(vp)) 4776 return (EINVAL); 4777 4778 if ((error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK))) 4779 return (error); 4780 cp = VTOC(vp); 4781 fp = VTOF(vp); 4782 4783 /* Zero length sym links are not allowed */ 4784 if (fp->ff_size == 0 || fp->ff_size > MAXPATHLEN) { 4785 error = EINVAL; 4786 goto exit; 4787 } 4788 4789 /* Cache the path so we don't waste buffer cache resources */ 4790 if (fp->ff_symlinkptr == NULL) { 4791 struct buf *bp = NULL; 4792 4793 MALLOC(fp->ff_symlinkptr, char *, fp->ff_size, M_TEMP, M_WAITOK); 4794 if (fp->ff_symlinkptr == NULL) { 4795 error = ENOMEM; 4796 goto exit; 4797 } 4798 error = (int)buf_meta_bread(vp, (daddr64_t)0, 4799 roundup((int)fp->ff_size, VTOHFS(vp)->hfs_physical_block_size), 4800 vfs_context_ucred(ap->a_context), &bp); 4801 if (error) { 4802 if (bp) 4803 buf_brelse(bp); 4804 if (fp->ff_symlinkptr) { 4805 FREE(fp->ff_symlinkptr, M_TEMP); 4806 fp->ff_symlinkptr = NULL; 4807 } 4808 goto exit; 4809 } 4810 bcopy((char *)buf_dataptr(bp), fp->ff_symlinkptr, (size_t)fp->ff_size); 4811 4812 if (VTOHFS(vp)->jnl && (buf_flags(bp) & B_LOCKED) == 0) { 4813 buf_markinvalid(bp); /* data no longer needed */ 4814 } 4815 buf_brelse(bp); 4816 } 4817 error = uiomove((caddr_t)fp->ff_symlinkptr, (int)fp->ff_size, ap->a_uio); 4818 4819 /* 4820 * Keep track blocks read 4821 */ 4822 if ((VTOHFS(vp)->hfc_stage == HFC_RECORDING) && (error == 0)) { 4823 4824 /* 4825 * If this file hasn't been seen since the start of 4826 * the current sampling period then start over. 4827 */ 4828 if (cp->c_atime < VTOHFS(vp)->hfc_timebase) 4829 VTOF(vp)->ff_bytesread = fp->ff_size; 4830 else 4831 VTOF(vp)->ff_bytesread += fp->ff_size; 4832 4833 // if (VTOF(vp)->ff_bytesread > fp->ff_size) 4834 // cp->c_touch_acctime = TRUE; 4835 } 4836 4837exit: 4838 hfs_unlock(cp); 4839 return (error); 4840} 4841 4842 4843/* 4844 * Get configurable pathname variables. 4845 */ 4846int 4847hfs_vnop_pathconf(ap) 4848 struct vnop_pathconf_args /* { 4849 struct vnode *a_vp; 4850 int a_name; 4851 int *a_retval; 4852 vfs_context_t a_context; 4853 } */ *ap; 4854{ 4855 switch (ap->a_name) { 4856 case _PC_LINK_MAX: 4857 if (VTOHFS(ap->a_vp)->hfs_flags & HFS_STANDARD) 4858 *ap->a_retval = 1; 4859 else 4860 *ap->a_retval = HFS_LINK_MAX; 4861 break; 4862 case _PC_NAME_MAX: 4863 if (VTOHFS(ap->a_vp)->hfs_flags & HFS_STANDARD) 4864 *ap->a_retval = kHFSMaxFileNameChars; /* 31 */ 4865 else 4866 *ap->a_retval = kHFSPlusMaxFileNameChars; /* 255 */ 4867 break; 4868 case _PC_PATH_MAX: 4869 *ap->a_retval = PATH_MAX; /* 1024 */ 4870 break; 4871 case _PC_PIPE_BUF: 4872 *ap->a_retval = PIPE_BUF; 4873 break; 4874 case _PC_CHOWN_RESTRICTED: 4875 *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */ 4876 break; 4877 case _PC_NO_TRUNC: 4878 *ap->a_retval = 200112; /* _POSIX_NO_TRUNC */ 4879 break; 4880 case _PC_NAME_CHARS_MAX: 4881 if (VTOHFS(ap->a_vp)->hfs_flags & HFS_STANDARD) 4882 *ap->a_retval = kHFSMaxFileNameChars; /* 31 */ 4883 else 4884 *ap->a_retval = kHFSPlusMaxFileNameChars; /* 255 */ 4885 break; 4886 case _PC_CASE_SENSITIVE: 4887 if (VTOHFS(ap->a_vp)->hfs_flags & HFS_CASE_SENSITIVE) 4888 *ap->a_retval = 1; 4889 else 4890 *ap->a_retval = 0; 4891 break; 4892 case _PC_CASE_PRESERVING: 4893 *ap->a_retval = 1; 4894 break; 4895 case _PC_FILESIZEBITS: 4896 if (VTOHFS(ap->a_vp)->hfs_flags & HFS_STANDARD) 4897 *ap->a_retval = 32; 4898 else 4899 *ap->a_retval = 64; /* number of bits to store max file size */ 4900 break; 4901 case _PC_XATTR_SIZE_BITS: 4902 /* Number of bits to store maximum extended attribute size */ 4903 *ap->a_retval = HFS_XATTR_SIZE_BITS; 4904 break; 4905 default: 4906 return (EINVAL); 4907 } 4908 4909 return (0); 4910} 4911 4912 4913/* 4914 * Update a cnode's on-disk metadata. 4915 * 4916 * If waitfor is set, then wait for the disk write of 4917 * the node to complete. 4918 * 4919 * The cnode must be locked exclusive 4920 */ 4921int 4922hfs_update(struct vnode *vp, __unused int waitfor) 4923{ 4924 struct cnode *cp = VTOC(vp); 4925 struct proc *p; 4926 struct cat_fork *dataforkp = NULL; 4927 struct cat_fork *rsrcforkp = NULL; 4928 struct cat_fork datafork; 4929 struct cat_fork rsrcfork; 4930 struct hfsmount *hfsmp; 4931 int lockflags; 4932 int error; 4933 4934 p = current_proc(); 4935 hfsmp = VTOHFS(vp); 4936 4937 if (((vnode_issystem(vp) && (cp->c_cnid < kHFSFirstUserCatalogNodeID))) || 4938 hfsmp->hfs_catalog_vp == NULL){ 4939 return (0); 4940 } 4941 if ((hfsmp->hfs_flags & HFS_READ_ONLY) || (cp->c_mode == 0)) { 4942 cp->c_flag &= ~C_MODIFIED; 4943 cp->c_touch_acctime = 0; 4944 cp->c_touch_chgtime = 0; 4945 cp->c_touch_modtime = 0; 4946 return (0); 4947 } 4948 4949 hfs_touchtimes(hfsmp, cp); 4950 4951 /* Nothing to update. */ 4952 if ((cp->c_flag & (C_MODIFIED | C_FORCEUPDATE)) == 0) { 4953 return (0); 4954 } 4955 4956 if (cp->c_datafork) 4957 dataforkp = &cp->c_datafork->ff_data; 4958 if (cp->c_rsrcfork) 4959 rsrcforkp = &cp->c_rsrcfork->ff_data; 4960 4961 /* 4962 * For delayed allocations updates are 4963 * postponed until an fsync or the file 4964 * gets written to disk. 4965 * 4966 * Deleted files can defer meta data updates until inactive. 4967 * 4968 * If we're ever called with the C_FORCEUPDATE flag though 4969 * we have to do the update. 4970 */ 4971 if (ISSET(cp->c_flag, C_FORCEUPDATE) == 0 && 4972 (ISSET(cp->c_flag, C_DELETED) || 4973 (dataforkp && cp->c_datafork->ff_unallocblocks) || 4974 (rsrcforkp && cp->c_rsrcfork->ff_unallocblocks))) { 4975 // cp->c_flag &= ~(C_ACCESS | C_CHANGE | C_UPDATE); 4976 cp->c_flag |= C_MODIFIED; 4977 4978 return (0); 4979 } 4980 4981 if ((error = hfs_start_transaction(hfsmp)) != 0) { 4982 return error; 4983 } 4984 4985 /* 4986 * Modify the values passed to cat_update based on whether or not 4987 * the file has invalid ranges or borrowed blocks. 4988 */ 4989 if (dataforkp) { 4990 off_t numbytes = 0; 4991 4992 /* copy the datafork into a temporary copy so we don't pollute the cnode's */ 4993 bcopy(dataforkp, &datafork, sizeof(datafork)); 4994 dataforkp = &datafork; 4995 4996 /* 4997 * If there are borrowed blocks, ensure that they are subtracted 4998 * from the total block count before writing the cnode entry to disk. 4999 * Only extents that have actually been marked allocated in the bitmap 5000 * should be reflected in the total block count for this fork. 5001 */ 5002 if (cp->c_datafork->ff_unallocblocks != 0) { 5003 // make sure that we don't assign a negative block count 5004 if (cp->c_datafork->ff_blocks < cp->c_datafork->ff_unallocblocks) { 5005 panic("hfs: ff_blocks %d is less than unalloc blocks %d\n", 5006 cp->c_datafork->ff_blocks, cp->c_datafork->ff_unallocblocks); 5007 } 5008 5009 /* Also cap the LEOF to the total number of bytes that are allocated. */ 5010 datafork.cf_blocks = (cp->c_datafork->ff_blocks - cp->c_datafork->ff_unallocblocks); 5011 datafork.cf_size = datafork.cf_blocks * HFSTOVCB(hfsmp)->blockSize; 5012 } 5013 5014 /* 5015 * For files with invalid ranges (holes) the on-disk 5016 * field representing the size of the file (cf_size) 5017 * must be no larger than the start of the first hole. 5018 * However, note that if the first invalid range exists 5019 * solely within borrowed blocks, then our LEOF and block 5020 * count should both be zero. As a result, set it to the 5021 * min of the current cf_size and the start of the first 5022 * invalid range, because it may have already been reduced 5023 * to zero by the borrowed blocks check above. 5024 */ 5025 if (!TAILQ_EMPTY(&cp->c_datafork->ff_invalidranges)) { 5026 numbytes = TAILQ_FIRST(&cp->c_datafork->ff_invalidranges)->rl_start; 5027 datafork.cf_size = MIN((numbytes), (datafork.cf_size)); 5028 } 5029 } 5030 5031 /* 5032 * For resource forks with delayed allocations, make sure 5033 * the block count and file size match the number of blocks 5034 * actually allocated to the file on disk. 5035 */ 5036 if (rsrcforkp && (cp->c_rsrcfork->ff_unallocblocks != 0)) { 5037 bcopy(rsrcforkp, &rsrcfork, sizeof(rsrcfork)); 5038 rsrcfork.cf_blocks = (cp->c_rsrcfork->ff_blocks - cp->c_rsrcfork->ff_unallocblocks); 5039 rsrcfork.cf_size = rsrcfork.cf_blocks * HFSTOVCB(hfsmp)->blockSize; 5040 rsrcforkp = &rsrcfork; 5041 } 5042 5043 /* 5044 * Lock the Catalog b-tree file. 5045 */ 5046 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_EXCLUSIVE_LOCK); 5047 5048 /* XXX - waitfor is not enforced */ 5049 error = cat_update(hfsmp, &cp->c_desc, &cp->c_attr, dataforkp, rsrcforkp); 5050 5051 hfs_systemfile_unlock(hfsmp, lockflags); 5052 5053 /* After the updates are finished, clear the flags */ 5054 cp->c_flag &= ~(C_MODIFIED | C_FORCEUPDATE); 5055 5056 hfs_end_transaction(hfsmp); 5057 5058 return (error); 5059} 5060 5061/* 5062 * Allocate a new node 5063 * Note - Function does not create and return a vnode for whiteout creation. 5064 */ 5065int 5066hfs_makenode(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, 5067 struct vnode_attr *vap, vfs_context_t ctx) 5068{ 5069 struct cnode *cp = NULL; 5070 struct cnode *dcp = NULL; 5071 struct vnode *tvp; 5072 struct hfsmount *hfsmp; 5073 struct cat_desc in_desc, out_desc; 5074 struct cat_attr attr; 5075 struct timeval tv; 5076 int lockflags; 5077 int error, started_tr = 0; 5078 enum vtype vnodetype; 5079 int mode; 5080 int newvnode_flags = 0; 5081 u_int32_t gnv_flags = 0; 5082 int protectable_target = 0; 5083 5084#if CONFIG_PROTECT 5085 struct cprotect *entry = NULL; 5086 uint32_t cp_class = 0; 5087 if (VATTR_IS_ACTIVE(vap, va_dataprotect_class)) { 5088 cp_class = vap->va_dataprotect_class; 5089 } 5090 int protected_mount = 0; 5091#endif 5092 5093 5094 if ((error = hfs_lock(VTOC(dvp), HFS_EXCLUSIVE_LOCK))) 5095 return (error); 5096 5097 /* set the cnode pointer only after successfully acquiring lock */ 5098 dcp = VTOC(dvp); 5099 5100 /* Don't allow creation of new entries in open-unlinked directories */ 5101 if ((error = hfs_checkdeleted(dcp))) { 5102 hfs_unlock(dcp); 5103 return error; 5104 } 5105 5106 dcp->c_flag |= C_DIR_MODIFICATION; 5107 5108 hfsmp = VTOHFS(dvp); 5109 5110 *vpp = NULL; 5111 tvp = NULL; 5112 out_desc.cd_flags = 0; 5113 out_desc.cd_nameptr = NULL; 5114 5115 vnodetype = vap->va_type; 5116 if (vnodetype == VNON) 5117 vnodetype = VREG; 5118 mode = MAKEIMODE(vnodetype, vap->va_mode); 5119 5120 if (S_ISDIR (mode) || S_ISREG (mode)) { 5121 protectable_target = 1; 5122 } 5123 5124 5125 /* Check if were out of usable disk space. */ 5126 if ((hfs_freeblks(hfsmp, 1) == 0) && (vfs_context_suser(ctx) != 0)) { 5127 error = ENOSPC; 5128 goto exit; 5129 } 5130 5131 microtime(&tv); 5132 5133 /* Setup the default attributes */ 5134 bzero(&attr, sizeof(attr)); 5135 attr.ca_mode = mode; 5136 attr.ca_linkcount = 1; 5137 if (VATTR_IS_ACTIVE(vap, va_rdev)) { 5138 attr.ca_rdev = vap->va_rdev; 5139 } 5140 if (VATTR_IS_ACTIVE(vap, va_create_time)) { 5141 VATTR_SET_SUPPORTED(vap, va_create_time); 5142 attr.ca_itime = vap->va_create_time.tv_sec; 5143 } else { 5144 attr.ca_itime = tv.tv_sec; 5145 } 5146 if ((hfsmp->hfs_flags & HFS_STANDARD) && gTimeZone.tz_dsttime) { 5147 attr.ca_itime += 3600; /* Same as what hfs_update does */ 5148 } 5149 attr.ca_atime = attr.ca_ctime = attr.ca_mtime = attr.ca_itime; 5150 attr.ca_atimeondisk = attr.ca_atime; 5151 if (VATTR_IS_ACTIVE(vap, va_flags)) { 5152 VATTR_SET_SUPPORTED(vap, va_flags); 5153 attr.ca_flags = vap->va_flags; 5154 } 5155 5156 /* 5157 * HFS+ only: all files get ThreadExists 5158 * HFSX only: dirs get HasFolderCount 5159 */ 5160 if (!(hfsmp->hfs_flags & HFS_STANDARD)) { 5161 if (vnodetype == VDIR) { 5162 if (hfsmp->hfs_flags & HFS_FOLDERCOUNT) 5163 attr.ca_recflags = kHFSHasFolderCountMask; 5164 } else { 5165 attr.ca_recflags = kHFSThreadExistsMask; 5166 } 5167 } 5168 5169#if CONFIG_PROTECT 5170 if (cp_fs_protected(hfsmp->hfs_mp)) { 5171 protected_mount = 1; 5172 } 5173 /* 5174 * On a content-protected HFS+/HFSX filesystem, files and directories 5175 * cannot be created without atomically setting/creating the EA that 5176 * contains the protection class metadata and keys at the same time, in 5177 * the same transaction. As a result, pre-set the "EAs exist" flag 5178 * on the cat_attr for protectable catalog record creations. This will 5179 * cause the cnode creation routine in hfs_getnewvnode to mark the cnode 5180 * as having EAs. 5181 */ 5182 if ((protected_mount) && (protectable_target)) { 5183 attr.ca_recflags |= kHFSHasAttributesMask; 5184 } 5185#endif 5186 5187 5188 /* 5189 * Add the date added to the item. See above, as 5190 * all of the dates are set to the itime. 5191 */ 5192 hfs_write_dateadded (&attr, attr.ca_atime); 5193 5194 attr.ca_uid = vap->va_uid; 5195 attr.ca_gid = vap->va_gid; 5196 VATTR_SET_SUPPORTED(vap, va_mode); 5197 VATTR_SET_SUPPORTED(vap, va_uid); 5198 VATTR_SET_SUPPORTED(vap, va_gid); 5199 5200#if QUOTA 5201 /* check to see if this node's creation would cause us to go over 5202 * quota. If so, abort this operation. 5203 */ 5204 if (hfsmp->hfs_flags & HFS_QUOTAS) { 5205 if ((error = hfs_quotacheck(hfsmp, 1, attr.ca_uid, attr.ca_gid, 5206 vfs_context_ucred(ctx)))) { 5207 goto exit; 5208 } 5209 } 5210#endif 5211 5212 5213 /* Tag symlinks with a type and creator. */ 5214 if (vnodetype == VLNK) { 5215 struct FndrFileInfo *fip; 5216 5217 fip = (struct FndrFileInfo *)&attr.ca_finderinfo; 5218 fip->fdType = SWAP_BE32(kSymLinkFileType); 5219 fip->fdCreator = SWAP_BE32(kSymLinkCreator); 5220 } 5221 if (cnp->cn_flags & ISWHITEOUT) 5222 attr.ca_flags |= UF_OPAQUE; 5223 5224 /* Setup the descriptor */ 5225 in_desc.cd_nameptr = (const u_int8_t *)cnp->cn_nameptr; 5226 in_desc.cd_namelen = cnp->cn_namelen; 5227 in_desc.cd_parentcnid = dcp->c_fileid; 5228 in_desc.cd_flags = S_ISDIR(mode) ? CD_ISDIR : 0; 5229 in_desc.cd_hint = dcp->c_childhint; 5230 in_desc.cd_encoding = 0; 5231 5232#if CONFIG_PROTECT 5233 /* 5234 * To preserve file creation atomicity with regards to the content protection EA, 5235 * we must create the file in the catalog and then write out the EA in the same 5236 * transaction. Pre-flight any operations that we can (such as allocating/preparing 5237 * the buffer, wrapping the keys) before we start the txn and take the requisite 5238 * b-tree locks. We pass '0' as the fileid because we do not know it yet. 5239 */ 5240 if ((protected_mount) && (protectable_target)) { 5241 error = cp_entry_create_keys (&entry, dcp, hfsmp, cp_class, 0, attr.ca_mode); 5242 if (error) { 5243 goto exit; 5244 } 5245 } 5246#endif 5247 5248 if ((error = hfs_start_transaction(hfsmp)) != 0) { 5249 goto exit; 5250 } 5251 started_tr = 1; 5252 5253 // have to also lock the attribute file because cat_create() needs 5254 // to check that any fileID it wants to use does not have orphaned 5255 // attributes in it. 5256 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG | SFL_ATTRIBUTE, HFS_EXCLUSIVE_LOCK); 5257 5258 /* Reserve some space in the Catalog file. */ 5259 if ((error = cat_preflight(hfsmp, CAT_CREATE, NULL, 0))) { 5260 hfs_systemfile_unlock(hfsmp, lockflags); 5261 goto exit; 5262 } 5263 error = cat_create(hfsmp, &in_desc, &attr, &out_desc); 5264 if (error == 0) { 5265 /* Update the parent directory */ 5266 dcp->c_childhint = out_desc.cd_hint; /* Cache directory's location */ 5267 dcp->c_entries++; 5268 if (vnodetype == VDIR) { 5269 INC_FOLDERCOUNT(hfsmp, dcp->c_attr); 5270 } 5271 dcp->c_dirchangecnt++; 5272 dcp->c_ctime = tv.tv_sec; 5273 dcp->c_mtime = tv.tv_sec; 5274 (void) cat_update(hfsmp, &dcp->c_desc, &dcp->c_attr, NULL, NULL); 5275 5276#if CONFIG_PROTECT 5277 /* 5278 * If we are creating a content protected file, now is when 5279 * we create the EA. We must create it in the same transaction 5280 * that creates the file. We can also guarantee that the file 5281 * MUST exist because we are still holding the catalog lock 5282 * at this point. 5283 */ 5284 if ((attr.ca_fileid != 0) && (protected_mount) && (protectable_target)) { 5285 error = cp_setxattr (NULL, entry, hfsmp, attr.ca_fileid, XATTR_CREATE); 5286 5287 if (error) { 5288 int delete_err; 5289 /* 5290 * If we fail the EA creation, then we need to delete the file. 5291 * Luckily, we are still holding all of the right locks. 5292 */ 5293 delete_err = cat_delete (hfsmp, &out_desc, &attr); 5294 if (delete_err == 0) { 5295 /* Update the parent directory */ 5296 if (dcp->c_entries > 0) 5297 dcp->c_entries--; 5298 dcp->c_dirchangecnt++; 5299 dcp->c_ctime = tv.tv_sec; 5300 dcp->c_mtime = tv.tv_sec; 5301 (void) cat_update(hfsmp, &dcp->c_desc, &dcp->c_attr, NULL, NULL); 5302 } 5303 5304 /* Emit EINVAL if we fail to create EA*/ 5305 error = EINVAL; 5306 } 5307 } 5308#endif 5309 } 5310 hfs_systemfile_unlock(hfsmp, lockflags); 5311 if (error) 5312 goto exit; 5313 5314 /* Invalidate negative cache entries in the directory */ 5315 if (dcp->c_flag & C_NEG_ENTRIES) { 5316 cache_purge_negatives(dvp); 5317 dcp->c_flag &= ~C_NEG_ENTRIES; 5318 } 5319 5320 hfs_volupdate(hfsmp, vnodetype == VDIR ? VOL_MKDIR : VOL_MKFILE, 5321 (dcp->c_cnid == kHFSRootFolderID)); 5322 5323 // XXXdbg 5324 // have to end the transaction here before we call hfs_getnewvnode() 5325 // because that can cause us to try and reclaim a vnode on a different 5326 // file system which could cause us to start a transaction which can 5327 // deadlock with someone on that other file system (since we could be 5328 // holding two transaction locks as well as various vnodes and we did 5329 // not obtain the locks on them in the proper order). 5330 // 5331 // NOTE: this means that if the quota check fails or we have to update 5332 // the change time on a block-special device that those changes 5333 // will happen as part of independent transactions. 5334 // 5335 if (started_tr) { 5336 hfs_end_transaction(hfsmp); 5337 started_tr = 0; 5338 } 5339 5340#if CONFIG_PROTECT 5341 /* 5342 * At this point, we must have encountered success with writing the EA. 5343 * Update MKB with the data for the cached key, then destroy it. This may 5344 * prevent information leakage by ensuring the cache key is only unwrapped 5345 * to perform file I/O and it is allowed. 5346 */ 5347 5348 if ((attr.ca_fileid != 0) && (protected_mount) && (protectable_target)) { 5349 cp_update_mkb (entry, attr.ca_fileid); 5350 cp_entry_destroy (&entry); 5351 } 5352#endif 5353 5354 /* Do not create vnode for whiteouts */ 5355 if (S_ISWHT(mode)) { 5356 goto exit; 5357 } 5358 5359 gnv_flags |= GNV_CREATE; 5360 5361 /* 5362 * Create a vnode for the object just created. 5363 * 5364 * NOTE: Maintaining the cnode lock on the parent directory is important, 5365 * as it prevents race conditions where other threads want to look up entries 5366 * in the directory and/or add things as we are in the process of creating 5367 * the vnode below. However, this has the potential for causing a 5368 * double lock panic when dealing with shadow files on a HFS boot partition. 5369 * The panic could occur if we are not cleaning up after ourselves properly 5370 * when done with a shadow file or in the error cases. The error would occur if we 5371 * try to create a new vnode, and then end up reclaiming another shadow vnode to 5372 * create the new one. However, if everything is working properly, this should 5373 * be a non-issue as we would never enter that reclaim codepath. 5374 * 5375 * The cnode is locked on successful return. 5376 */ 5377 error = hfs_getnewvnode(hfsmp, dvp, cnp, &out_desc, gnv_flags, &attr, 5378 NULL, &tvp, &newvnode_flags); 5379 if (error) 5380 goto exit; 5381 5382 cp = VTOC(tvp); 5383 *vpp = tvp; 5384 5385#if QUOTA 5386 /* 5387 * Once we create this vnode, we need to initialize its quota data 5388 * structures, if necessary. We know that it is OK to just go ahead and 5389 * initialize because we've already validated earlier (through the hfs_quotacheck 5390 * function) to see if creating this cnode/vnode would cause us to go over quota. 5391 */ 5392 if (hfsmp->hfs_flags & HFS_QUOTAS) { 5393 (void) hfs_getinoquota(cp); 5394 } 5395#endif 5396 5397exit: 5398 cat_releasedesc(&out_desc); 5399 5400#if CONFIG_PROTECT 5401 /* 5402 * We may have jumped here in error-handling various situations above. 5403 * If we haven't already dumped the temporary CP used to initialize 5404 * the file atomically, then free it now. cp_entry_destroy should null 5405 * out the pointer if it was called already. 5406 */ 5407 if (entry) { 5408 cp_entry_destroy (&entry); 5409 } 5410#endif 5411 5412 /* 5413 * Make sure we release cnode lock on dcp. 5414 */ 5415 if (dcp) { 5416 dcp->c_flag &= ~C_DIR_MODIFICATION; 5417 wakeup((caddr_t)&dcp->c_flag); 5418 5419 hfs_unlock(dcp); 5420 } 5421 if (error == 0 && cp != NULL) { 5422 hfs_unlock(cp); 5423 } 5424 if (started_tr) { 5425 hfs_end_transaction(hfsmp); 5426 started_tr = 0; 5427 } 5428 5429 return (error); 5430} 5431 5432 5433/* 5434 * hfs_vgetrsrc acquires a resource fork vnode corresponding to the cnode that is 5435 * found in 'vp'. The rsrc fork vnode is returned with the cnode locked and iocount 5436 * on the rsrc vnode. 5437 * 5438 * *rvpp is an output argument for returning the pointer to the resource fork vnode. 5439 * In most cases, the resource fork vnode will not be set if we return an error. 5440 * However, if error_on_unlinked is set, we may have already acquired the resource fork vnode 5441 * before we discover the error (the file has gone open-unlinked). In this case only, 5442 * we may return a vnode in the output argument despite an error. 5443 * 5444 * If can_drop_lock is set, then it is safe for this function to temporarily drop 5445 * and then re-acquire the cnode lock. We may need to do this, for example, in order to 5446 * acquire an iocount or promote our lock. 5447 * 5448 * error_on_unlinked is an argument which indicates that we are to return an error if we 5449 * discover that the cnode has gone into an open-unlinked state ( C_DELETED or C_NOEXISTS) 5450 * is set in the cnode flags. This is only necessary if can_drop_lock is true, otherwise 5451 * there's really no reason to double-check for errors on the cnode. 5452 */ 5453 5454int 5455hfs_vgetrsrc(struct hfsmount *hfsmp, struct vnode *vp, struct vnode **rvpp, 5456 int can_drop_lock, int error_on_unlinked) 5457{ 5458 struct vnode *rvp; 5459 struct vnode *dvp = NULLVP; 5460 struct cnode *cp = VTOC(vp); 5461 int error; 5462 int vid; 5463 int delete_status = 0; 5464 5465 if (vnode_vtype(vp) == VDIR) { 5466 return EINVAL; 5467 } 5468 5469 /* 5470 * Need to check the status of the cnode to validate it hasn't gone 5471 * open-unlinked on us before we can actually do work with it. 5472 */ 5473 delete_status = hfs_checkdeleted(cp); 5474 if ((delete_status) && (error_on_unlinked)) { 5475 return delete_status; 5476 } 5477 5478restart: 5479 /* Attempt to use existing vnode */ 5480 if ((rvp = cp->c_rsrc_vp)) { 5481 vid = vnode_vid(rvp); 5482 5483 /* 5484 * It is not safe to hold the cnode lock when calling vnode_getwithvid() 5485 * for the alternate fork -- vnode_getwithvid() could deadlock waiting 5486 * for a VL_WANTTERM while another thread has an iocount on the alternate 5487 * fork vnode and is attempting to acquire the common cnode lock. 5488 * 5489 * But it's also not safe to drop the cnode lock when we're holding 5490 * multiple cnode locks, like during a hfs_removefile() operation 5491 * since we could lock out of order when re-acquiring the cnode lock. 5492 * 5493 * So we can only drop the lock here if its safe to drop it -- which is 5494 * most of the time with the exception being hfs_removefile(). 5495 */ 5496 if (can_drop_lock) 5497 hfs_unlock(cp); 5498 5499 error = vnode_getwithvid(rvp, vid); 5500 5501 if (can_drop_lock) { 5502 (void) hfs_lock(cp, HFS_FORCE_LOCK); 5503 5504 /* 5505 * When we relinquished our cnode lock, the cnode could have raced 5506 * with a delete and gotten deleted. If the caller did not want 5507 * us to ignore open-unlinked files, then re-check the C_DELETED 5508 * state and see if we need to return an ENOENT here because the item 5509 * got deleted in the intervening time. 5510 */ 5511 if (error_on_unlinked) { 5512 if ((delete_status = hfs_checkdeleted(cp))) { 5513 /* 5514 * If error == 0, this means that we succeeded in acquiring an iocount on the 5515 * rsrc fork vnode. However, if we're in this block of code, that means that we noticed 5516 * that the cnode has gone open-unlinked. In this case, the caller requested that we 5517 * not do any other work and return an errno. The caller will be responsible for 5518 * dropping the iocount we just acquired because we can't do it until we've released 5519 * the cnode lock. 5520 */ 5521 if (error == 0) { 5522 *rvpp = rvp; 5523 } 5524 return delete_status; 5525 } 5526 } 5527 5528 /* 5529 * When our lock was relinquished, the resource fork 5530 * could have been recycled. Check for this and try 5531 * again. 5532 */ 5533 if (error == ENOENT) 5534 goto restart; 5535 } 5536 if (error) { 5537 const char * name = (const char *)VTOC(vp)->c_desc.cd_nameptr; 5538 5539 if (name) 5540 printf("hfs_vgetrsrc: couldn't get resource" 5541 " fork for %s, err %d\n", name, error); 5542 return (error); 5543 } 5544 } else { 5545 struct cat_fork rsrcfork; 5546 struct componentname cn; 5547 struct cat_desc *descptr = NULL; 5548 struct cat_desc to_desc; 5549 char delname[32]; 5550 int lockflags; 5551 int newvnode_flags = 0; 5552 5553 /* 5554 * Make sure cnode lock is exclusive, if not upgrade it. 5555 * 5556 * We assume that we were called from a read-only VNOP (getattr) 5557 * and that its safe to have the cnode lock dropped and reacquired. 5558 */ 5559 if (cp->c_lockowner != current_thread()) { 5560 if (!can_drop_lock) { 5561 return (EINVAL); 5562 } 5563 /* 5564 * If the upgrade fails we lose the lock and 5565 * have to take the exclusive lock on our own. 5566 */ 5567 if (lck_rw_lock_shared_to_exclusive(&cp->c_rwlock) == FALSE) 5568 lck_rw_lock_exclusive(&cp->c_rwlock); 5569 cp->c_lockowner = current_thread(); 5570 } 5571 5572 /* 5573 * hfs_vgetsrc may be invoked for a cnode that has already been marked 5574 * C_DELETED. This is because we need to continue to provide rsrc 5575 * fork access to open-unlinked files. In this case, build a fake descriptor 5576 * like in hfs_removefile. If we don't do this, buildkey will fail in 5577 * cat_lookup because this cnode has no name in its descriptor. However, 5578 * only do this if the caller did not specify that they wanted us to 5579 * error out upon encountering open-unlinked files. 5580 */ 5581 5582 if ((error_on_unlinked) && (can_drop_lock)) { 5583 if ((error = hfs_checkdeleted(cp))) { 5584 return error; 5585 } 5586 } 5587 5588 if ((cp->c_flag & C_DELETED ) && (cp->c_desc.cd_namelen == 0)) { 5589 bzero (&to_desc, sizeof(to_desc)); 5590 bzero (delname, 32); 5591 MAKE_DELETED_NAME(delname, sizeof(delname), cp->c_fileid); 5592 to_desc.cd_nameptr = (const u_int8_t*) delname; 5593 to_desc.cd_namelen = strlen(delname); 5594 to_desc.cd_parentcnid = hfsmp->hfs_private_desc[FILE_HARDLINKS].cd_cnid; 5595 to_desc.cd_flags = 0; 5596 to_desc.cd_cnid = cp->c_cnid; 5597 5598 descptr = &to_desc; 5599 } 5600 else { 5601 descptr = &cp->c_desc; 5602 } 5603 5604 5605 lockflags = hfs_systemfile_lock(hfsmp, SFL_CATALOG, HFS_SHARED_LOCK); 5606 5607 /* 5608 * Get resource fork data 5609 * 5610 * We call cat_idlookup (instead of cat_lookup) below because we can't 5611 * trust the descriptor in the provided cnode for lookups at this point. 5612 * Between the time of the original lookup of this vnode and now, the 5613 * descriptor could have gotten swapped or replaced. If this occurred, 5614 * the parent/name combo originally desired may not necessarily be provided 5615 * if we use the descriptor. Even worse, if the vnode represents 5616 * a hardlink, we could have removed one of the links from the namespace 5617 * but left the descriptor alone, since hfs_unlink does not invalidate 5618 * the descriptor in the cnode if other links still point to the inode. 5619 * 5620 * Consider the following (slightly contrived) scenario: 5621 * /tmp/a <--> /tmp/b (hardlinks). 5622 * 1. Thread A: open rsrc fork on /tmp/b. 5623 * 1a. Thread A: does lookup, goes out to lunch right before calling getnamedstream. 5624 * 2. Thread B does 'mv /foo/b /tmp/b' 5625 * 2. Thread B succeeds. 5626 * 3. Thread A comes back and wants rsrc fork info for /tmp/b. 5627 * 5628 * Even though the hardlink backing /tmp/b is now eliminated, the descriptor 5629 * is not removed/updated during the unlink process. So, if you were to 5630 * do a lookup on /tmp/b, you'd acquire an entirely different record's resource 5631 * fork. 5632 * 5633 * As a result, we use the fileid, which should be invariant for the lifetime 5634 * of the cnode (possibly barring calls to exchangedata). 5635 * 5636 * Addendum: We can't do the above for HFS standard since we aren't guaranteed to 5637 * have thread records for files. They were only required for directories. So 5638 * we need to do the lookup with the catalog name. This is OK since hardlinks were 5639 * never allowed on HFS standard. 5640 */ 5641 5642 if (hfsmp->hfs_flags & HFS_STANDARD) { 5643 /* 5644 * HFS standard only: 5645 * 5646 * Get the resource fork for this item via catalog lookup 5647 * since HFS standard was case-insensitive only. We don't want the 5648 * descriptor; just the fork data here. 5649 */ 5650 error = cat_lookup (hfsmp, descptr, 1, (struct cat_desc*)NULL, 5651 (struct cat_attr*)NULL, &rsrcfork, NULL); 5652 } 5653 else { 5654 error = cat_idlookup (hfsmp, cp->c_fileid, 0, 1, NULL, NULL, &rsrcfork); 5655 } 5656 5657 hfs_systemfile_unlock(hfsmp, lockflags); 5658 if (error) { 5659 return (error); 5660 } 5661 5662 /* 5663 * Supply hfs_getnewvnode with a component name. 5664 */ 5665 cn.cn_pnbuf = NULL; 5666 if (descptr->cd_nameptr) { 5667 MALLOC_ZONE(cn.cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); 5668 cn.cn_nameiop = LOOKUP; 5669 cn.cn_flags = ISLASTCN | HASBUF; 5670 cn.cn_context = NULL; 5671 cn.cn_pnlen = MAXPATHLEN; 5672 cn.cn_nameptr = cn.cn_pnbuf; 5673 cn.cn_hash = 0; 5674 cn.cn_consume = 0; 5675 cn.cn_namelen = snprintf(cn.cn_nameptr, MAXPATHLEN, 5676 "%s%s", descptr->cd_nameptr, 5677 _PATH_RSRCFORKSPEC); 5678 } 5679 dvp = vnode_getparent(vp); 5680 error = hfs_getnewvnode(hfsmp, dvp, cn.cn_pnbuf ? &cn : NULL, 5681 descptr, GNV_WANTRSRC | GNV_SKIPLOCK, &cp->c_attr, 5682 &rsrcfork, &rvp, &newvnode_flags); 5683 if (dvp) 5684 vnode_put(dvp); 5685 if (cn.cn_pnbuf) 5686 FREE_ZONE(cn.cn_pnbuf, cn.cn_pnlen, M_NAMEI); 5687 if (error) 5688 return (error); 5689 } 5690 5691 *rvpp = rvp; 5692 return (0); 5693} 5694 5695/* 5696 * Wrapper for special device reads 5697 */ 5698int 5699hfsspec_read(ap) 5700 struct vnop_read_args /* { 5701 struct vnode *a_vp; 5702 struct uio *a_uio; 5703 int a_ioflag; 5704 vfs_context_t a_context; 5705 } */ *ap; 5706{ 5707 /* 5708 * Set access flag. 5709 */ 5710 VTOC(ap->a_vp)->c_touch_acctime = TRUE; 5711 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_read), ap)); 5712} 5713 5714/* 5715 * Wrapper for special device writes 5716 */ 5717int 5718hfsspec_write(ap) 5719 struct vnop_write_args /* { 5720 struct vnode *a_vp; 5721 struct uio *a_uio; 5722 int a_ioflag; 5723 vfs_context_t a_context; 5724 } */ *ap; 5725{ 5726 /* 5727 * Set update and change flags. 5728 */ 5729 VTOC(ap->a_vp)->c_touch_chgtime = TRUE; 5730 VTOC(ap->a_vp)->c_touch_modtime = TRUE; 5731 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_write), ap)); 5732} 5733 5734/* 5735 * Wrapper for special device close 5736 * 5737 * Update the times on the cnode then do device close. 5738 */ 5739int 5740hfsspec_close(ap) 5741 struct vnop_close_args /* { 5742 struct vnode *a_vp; 5743 int a_fflag; 5744 vfs_context_t a_context; 5745 } */ *ap; 5746{ 5747 struct vnode *vp = ap->a_vp; 5748 struct cnode *cp; 5749 5750 if (vnode_isinuse(ap->a_vp, 0)) { 5751 if (hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK) == 0) { 5752 cp = VTOC(vp); 5753 hfs_touchtimes(VTOHFS(vp), cp); 5754 hfs_unlock(cp); 5755 } 5756 } 5757 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_close), ap)); 5758} 5759 5760#if FIFO 5761/* 5762 * Wrapper for fifo reads 5763 */ 5764static int 5765hfsfifo_read(ap) 5766 struct vnop_read_args /* { 5767 struct vnode *a_vp; 5768 struct uio *a_uio; 5769 int a_ioflag; 5770 vfs_context_t a_context; 5771 } */ *ap; 5772{ 5773 /* 5774 * Set access flag. 5775 */ 5776 VTOC(ap->a_vp)->c_touch_acctime = TRUE; 5777 return (VOCALL (fifo_vnodeop_p, VOFFSET(vnop_read), ap)); 5778} 5779 5780/* 5781 * Wrapper for fifo writes 5782 */ 5783static int 5784hfsfifo_write(ap) 5785 struct vnop_write_args /* { 5786 struct vnode *a_vp; 5787 struct uio *a_uio; 5788 int a_ioflag; 5789 vfs_context_t a_context; 5790 } */ *ap; 5791{ 5792 /* 5793 * Set update and change flags. 5794 */ 5795 VTOC(ap->a_vp)->c_touch_chgtime = TRUE; 5796 VTOC(ap->a_vp)->c_touch_modtime = TRUE; 5797 return (VOCALL (fifo_vnodeop_p, VOFFSET(vnop_write), ap)); 5798} 5799 5800/* 5801 * Wrapper for fifo close 5802 * 5803 * Update the times on the cnode then do device close. 5804 */ 5805static int 5806hfsfifo_close(ap) 5807 struct vnop_close_args /* { 5808 struct vnode *a_vp; 5809 int a_fflag; 5810 vfs_context_t a_context; 5811 } */ *ap; 5812{ 5813 struct vnode *vp = ap->a_vp; 5814 struct cnode *cp; 5815 5816 if (vnode_isinuse(ap->a_vp, 1)) { 5817 if (hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK) == 0) { 5818 cp = VTOC(vp); 5819 hfs_touchtimes(VTOHFS(vp), cp); 5820 hfs_unlock(cp); 5821 } 5822 } 5823 return (VOCALL (fifo_vnodeop_p, VOFFSET(vnop_close), ap)); 5824} 5825 5826 5827#endif /* FIFO */ 5828 5829/* 5830 * Synchronize a file's in-core state with that on disk. 5831 */ 5832int 5833hfs_vnop_fsync(ap) 5834 struct vnop_fsync_args /* { 5835 struct vnode *a_vp; 5836 int a_waitfor; 5837 vfs_context_t a_context; 5838 } */ *ap; 5839{ 5840 struct vnode* vp = ap->a_vp; 5841 int error; 5842 5843 /* Note: We check hfs flags instead of vfs mount flag because during 5844 * read-write update, hfs marks itself read-write much earlier than 5845 * the vfs, and hence won't result in skipping of certain writes like 5846 * zero'ing out of unused nodes, creation of hotfiles btree, etc. 5847 */ 5848 if (VTOHFS(vp)->hfs_flags & HFS_READ_ONLY) { 5849 return 0; 5850 } 5851 5852#if CONFIG_PROTECT 5853 if ((error = cp_handle_vnop(vp, CP_WRITE_ACCESS, 0)) != 0) { 5854 return (error); 5855 } 5856#endif /* CONFIG_PROTECT */ 5857 5858 /* 5859 * We need to allow ENOENT lock errors since unlink 5860 * systenm call can call VNOP_FSYNC during vclean. 5861 */ 5862 error = hfs_lock(VTOC(vp), HFS_EXCLUSIVE_LOCK); 5863 if (error) 5864 return (0); 5865 5866 error = hfs_fsync(vp, ap->a_waitfor, 0, vfs_context_proc(ap->a_context)); 5867 5868 hfs_unlock(VTOC(vp)); 5869 return (error); 5870} 5871 5872 5873int 5874hfs_vnop_whiteout(ap) 5875 struct vnop_whiteout_args /* { 5876 struct vnode *a_dvp; 5877 struct componentname *a_cnp; 5878 int a_flags; 5879 vfs_context_t a_context; 5880 } */ *ap; 5881{ 5882 int error = 0; 5883 struct vnode *vp = NULL; 5884 struct vnode_attr va; 5885 struct vnop_lookup_args lookup_args; 5886 struct vnop_remove_args remove_args; 5887 struct hfsmount *hfsmp; 5888 5889 hfsmp = VTOHFS(ap->a_dvp); 5890 if (hfsmp->hfs_flags & HFS_STANDARD) { 5891 error = ENOTSUP; 5892 goto exit; 5893 } 5894 5895 switch (ap->a_flags) { 5896 case LOOKUP: 5897 error = 0; 5898 break; 5899 5900 case CREATE: 5901 VATTR_INIT(&va); 5902 VATTR_SET(&va, va_type, VREG); 5903 VATTR_SET(&va, va_mode, S_IFWHT); 5904 VATTR_SET(&va, va_uid, 0); 5905 VATTR_SET(&va, va_gid, 0); 5906 5907 error = hfs_makenode(ap->a_dvp, &vp, ap->a_cnp, &va, ap->a_context); 5908 /* No need to release the vnode as no vnode is created for whiteouts */ 5909 break; 5910 5911 case DELETE: 5912 lookup_args.a_dvp = ap->a_dvp; 5913 lookup_args.a_vpp = &vp; 5914 lookup_args.a_cnp = ap->a_cnp; 5915 lookup_args.a_context = ap->a_context; 5916 5917 error = hfs_vnop_lookup(&lookup_args); 5918 if (error) { 5919 break; 5920 } 5921 5922 remove_args.a_dvp = ap->a_dvp; 5923 remove_args.a_vp = vp; 5924 remove_args.a_cnp = ap->a_cnp; 5925 remove_args.a_flags = 0; 5926 remove_args.a_context = ap->a_context; 5927 5928 error = hfs_vnop_remove(&remove_args); 5929 vnode_put(vp); 5930 break; 5931 5932 default: 5933 panic("hfs_vnop_whiteout: unknown operation (flag = %x)\n", ap->a_flags); 5934 }; 5935 5936exit: 5937 return (error); 5938} 5939 5940int (**hfs_vnodeop_p)(void *); 5941int (**hfs_std_vnodeop_p) (void *); 5942 5943#define VOPFUNC int (*)(void *) 5944 5945static int hfs_readonly_op (__unused void* ap) { return (EROFS); } 5946 5947/* 5948 * In 10.6 and forward, HFS Standard is read-only and deprecated. The vnop table below 5949 * is for use with HFS standard to block out operations that would modify the file system 5950 */ 5951 5952struct vnodeopv_entry_desc hfs_standard_vnodeop_entries[] = { 5953 { &vnop_default_desc, (VOPFUNC)vn_default_error }, 5954 { &vnop_lookup_desc, (VOPFUNC)hfs_vnop_lookup }, /* lookup */ 5955 { &vnop_create_desc, (VOPFUNC)hfs_readonly_op }, /* create (READONLY) */ 5956 { &vnop_mknod_desc, (VOPFUNC)hfs_readonly_op }, /* mknod (READONLY) */ 5957 { &vnop_open_desc, (VOPFUNC)hfs_vnop_open }, /* open */ 5958 { &vnop_close_desc, (VOPFUNC)hfs_vnop_close }, /* close */ 5959 { &vnop_getattr_desc, (VOPFUNC)hfs_vnop_getattr }, /* getattr */ 5960 { &vnop_setattr_desc, (VOPFUNC)hfs_readonly_op }, /* setattr */ 5961 { &vnop_read_desc, (VOPFUNC)hfs_vnop_read }, /* read */ 5962 { &vnop_write_desc, (VOPFUNC)hfs_readonly_op }, /* write (READONLY) */ 5963 { &vnop_ioctl_desc, (VOPFUNC)hfs_vnop_ioctl }, /* ioctl */ 5964 { &vnop_select_desc, (VOPFUNC)hfs_vnop_select }, /* select */ 5965 { &vnop_revoke_desc, (VOPFUNC)nop_revoke }, /* revoke */ 5966 { &vnop_exchange_desc, (VOPFUNC)hfs_readonly_op }, /* exchange (READONLY)*/ 5967 { &vnop_mmap_desc, (VOPFUNC)err_mmap }, /* mmap */ 5968 { &vnop_fsync_desc, (VOPFUNC)hfs_readonly_op}, /* fsync (READONLY) */ 5969 { &vnop_remove_desc, (VOPFUNC)hfs_readonly_op }, /* remove (READONLY) */ 5970 { &vnop_link_desc, (VOPFUNC)hfs_readonly_op }, /* link ( READONLLY) */ 5971 { &vnop_rename_desc, (VOPFUNC)hfs_readonly_op }, /* rename (READONLY)*/ 5972 { &vnop_mkdir_desc, (VOPFUNC)hfs_readonly_op }, /* mkdir (READONLY) */ 5973 { &vnop_rmdir_desc, (VOPFUNC)hfs_readonly_op }, /* rmdir (READONLY) */ 5974 { &vnop_symlink_desc, (VOPFUNC)hfs_readonly_op }, /* symlink (READONLY) */ 5975 { &vnop_readdir_desc, (VOPFUNC)hfs_vnop_readdir }, /* readdir */ 5976 { &vnop_readdirattr_desc, (VOPFUNC)hfs_vnop_readdirattr }, /* readdirattr */ 5977 { &vnop_readlink_desc, (VOPFUNC)hfs_vnop_readlink }, /* readlink */ 5978 { &vnop_inactive_desc, (VOPFUNC)hfs_vnop_inactive }, /* inactive */ 5979 { &vnop_reclaim_desc, (VOPFUNC)hfs_vnop_reclaim }, /* reclaim */ 5980 { &vnop_strategy_desc, (VOPFUNC)hfs_vnop_strategy }, /* strategy */ 5981 { &vnop_pathconf_desc, (VOPFUNC)hfs_vnop_pathconf }, /* pathconf */ 5982 { &vnop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */ 5983 { &vnop_allocate_desc, (VOPFUNC)hfs_readonly_op }, /* allocate (READONLY) */ 5984#if CONFIG_SEARCHFS 5985 { &vnop_searchfs_desc, (VOPFUNC)hfs_vnop_search }, /* search fs */ 5986#else 5987 { &vnop_searchfs_desc, (VOPFUNC)err_searchfs }, /* search fs */ 5988#endif 5989 { &vnop_bwrite_desc, (VOPFUNC)hfs_readonly_op }, /* bwrite (READONLY) */ 5990 { &vnop_pagein_desc, (VOPFUNC)hfs_vnop_pagein }, /* pagein */ 5991 { &vnop_pageout_desc,(VOPFUNC) hfs_readonly_op }, /* pageout (READONLY) */ 5992 { &vnop_copyfile_desc, (VOPFUNC)hfs_readonly_op }, /* copyfile (READONLY)*/ 5993 { &vnop_blktooff_desc, (VOPFUNC)hfs_vnop_blktooff }, /* blktooff */ 5994 { &vnop_offtoblk_desc, (VOPFUNC)hfs_vnop_offtoblk }, /* offtoblk */ 5995 { &vnop_blockmap_desc, (VOPFUNC)hfs_vnop_blockmap }, /* blockmap */ 5996 { &vnop_getxattr_desc, (VOPFUNC)hfs_vnop_getxattr}, 5997 { &vnop_setxattr_desc, (VOPFUNC)hfs_readonly_op}, /* set xattr (READONLY) */ 5998 { &vnop_removexattr_desc, (VOPFUNC)hfs_readonly_op}, /* remove xattr (READONLY) */ 5999 { &vnop_listxattr_desc, (VOPFUNC)hfs_vnop_listxattr}, 6000 { &vnop_whiteout_desc, (VOPFUNC)hfs_readonly_op}, /* whiteout (READONLY) */ 6001#if NAMEDSTREAMS 6002 { &vnop_getnamedstream_desc, (VOPFUNC)hfs_vnop_getnamedstream }, 6003 { &vnop_makenamedstream_desc, (VOPFUNC)hfs_readonly_op }, 6004 { &vnop_removenamedstream_desc, (VOPFUNC)hfs_readonly_op }, 6005#endif 6006 { NULL, (VOPFUNC)NULL } 6007}; 6008 6009struct vnodeopv_desc hfs_std_vnodeop_opv_desc = 6010{ &hfs_std_vnodeop_p, hfs_standard_vnodeop_entries }; 6011 6012 6013/* VNOP table for HFS+ */ 6014struct vnodeopv_entry_desc hfs_vnodeop_entries[] = { 6015 { &vnop_default_desc, (VOPFUNC)vn_default_error }, 6016 { &vnop_lookup_desc, (VOPFUNC)hfs_vnop_lookup }, /* lookup */ 6017 { &vnop_create_desc, (VOPFUNC)hfs_vnop_create }, /* create */ 6018 { &vnop_mknod_desc, (VOPFUNC)hfs_vnop_mknod }, /* mknod */ 6019 { &vnop_open_desc, (VOPFUNC)hfs_vnop_open }, /* open */ 6020 { &vnop_close_desc, (VOPFUNC)hfs_vnop_close }, /* close */ 6021 { &vnop_getattr_desc, (VOPFUNC)hfs_vnop_getattr }, /* getattr */ 6022 { &vnop_setattr_desc, (VOPFUNC)hfs_vnop_setattr }, /* setattr */ 6023 { &vnop_read_desc, (VOPFUNC)hfs_vnop_read }, /* read */ 6024 { &vnop_write_desc, (VOPFUNC)hfs_vnop_write }, /* write */ 6025 { &vnop_ioctl_desc, (VOPFUNC)hfs_vnop_ioctl }, /* ioctl */ 6026 { &vnop_select_desc, (VOPFUNC)hfs_vnop_select }, /* select */ 6027 { &vnop_revoke_desc, (VOPFUNC)nop_revoke }, /* revoke */ 6028 { &vnop_exchange_desc, (VOPFUNC)hfs_vnop_exchange }, /* exchange */ 6029 { &vnop_mmap_desc, (VOPFUNC)hfs_vnop_mmap }, /* mmap */ 6030 { &vnop_fsync_desc, (VOPFUNC)hfs_vnop_fsync }, /* fsync */ 6031 { &vnop_remove_desc, (VOPFUNC)hfs_vnop_remove }, /* remove */ 6032 { &vnop_link_desc, (VOPFUNC)hfs_vnop_link }, /* link */ 6033 { &vnop_rename_desc, (VOPFUNC)hfs_vnop_rename }, /* rename */ 6034 { &vnop_mkdir_desc, (VOPFUNC)hfs_vnop_mkdir }, /* mkdir */ 6035 { &vnop_rmdir_desc, (VOPFUNC)hfs_vnop_rmdir }, /* rmdir */ 6036 { &vnop_symlink_desc, (VOPFUNC)hfs_vnop_symlink }, /* symlink */ 6037 { &vnop_readdir_desc, (VOPFUNC)hfs_vnop_readdir }, /* readdir */ 6038 { &vnop_readdirattr_desc, (VOPFUNC)hfs_vnop_readdirattr }, /* readdirattr */ 6039 { &vnop_readlink_desc, (VOPFUNC)hfs_vnop_readlink }, /* readlink */ 6040 { &vnop_inactive_desc, (VOPFUNC)hfs_vnop_inactive }, /* inactive */ 6041 { &vnop_reclaim_desc, (VOPFUNC)hfs_vnop_reclaim }, /* reclaim */ 6042 { &vnop_strategy_desc, (VOPFUNC)hfs_vnop_strategy }, /* strategy */ 6043 { &vnop_pathconf_desc, (VOPFUNC)hfs_vnop_pathconf }, /* pathconf */ 6044 { &vnop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */ 6045 { &vnop_allocate_desc, (VOPFUNC)hfs_vnop_allocate }, /* allocate */ 6046#if CONFIG_SEARCHFS 6047 { &vnop_searchfs_desc, (VOPFUNC)hfs_vnop_search }, /* search fs */ 6048#else 6049 { &vnop_searchfs_desc, (VOPFUNC)err_searchfs }, /* search fs */ 6050#endif 6051 { &vnop_bwrite_desc, (VOPFUNC)hfs_vnop_bwrite }, /* bwrite */ 6052 { &vnop_pagein_desc, (VOPFUNC)hfs_vnop_pagein }, /* pagein */ 6053 { &vnop_pageout_desc,(VOPFUNC) hfs_vnop_pageout }, /* pageout */ 6054 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* copyfile */ 6055 { &vnop_blktooff_desc, (VOPFUNC)hfs_vnop_blktooff }, /* blktooff */ 6056 { &vnop_offtoblk_desc, (VOPFUNC)hfs_vnop_offtoblk }, /* offtoblk */ 6057 { &vnop_blockmap_desc, (VOPFUNC)hfs_vnop_blockmap }, /* blockmap */ 6058 { &vnop_getxattr_desc, (VOPFUNC)hfs_vnop_getxattr}, 6059 { &vnop_setxattr_desc, (VOPFUNC)hfs_vnop_setxattr}, 6060 { &vnop_removexattr_desc, (VOPFUNC)hfs_vnop_removexattr}, 6061 { &vnop_listxattr_desc, (VOPFUNC)hfs_vnop_listxattr}, 6062 { &vnop_whiteout_desc, (VOPFUNC)hfs_vnop_whiteout}, 6063#if NAMEDSTREAMS 6064 { &vnop_getnamedstream_desc, (VOPFUNC)hfs_vnop_getnamedstream }, 6065 { &vnop_makenamedstream_desc, (VOPFUNC)hfs_vnop_makenamedstream }, 6066 { &vnop_removenamedstream_desc, (VOPFUNC)hfs_vnop_removenamedstream }, 6067#endif 6068 { NULL, (VOPFUNC)NULL } 6069}; 6070 6071struct vnodeopv_desc hfs_vnodeop_opv_desc = 6072{ &hfs_vnodeop_p, hfs_vnodeop_entries }; 6073 6074 6075/* Spec Op vnop table for HFS+ */ 6076int (**hfs_specop_p)(void *); 6077struct vnodeopv_entry_desc hfs_specop_entries[] = { 6078 { &vnop_default_desc, (VOPFUNC)vn_default_error }, 6079 { &vnop_lookup_desc, (VOPFUNC)spec_lookup }, /* lookup */ 6080 { &vnop_create_desc, (VOPFUNC)spec_create }, /* create */ 6081 { &vnop_mknod_desc, (VOPFUNC)spec_mknod }, /* mknod */ 6082 { &vnop_open_desc, (VOPFUNC)spec_open }, /* open */ 6083 { &vnop_close_desc, (VOPFUNC)hfsspec_close }, /* close */ 6084 { &vnop_getattr_desc, (VOPFUNC)hfs_vnop_getattr }, /* getattr */ 6085 { &vnop_setattr_desc, (VOPFUNC)hfs_vnop_setattr }, /* setattr */ 6086 { &vnop_read_desc, (VOPFUNC)hfsspec_read }, /* read */ 6087 { &vnop_write_desc, (VOPFUNC)hfsspec_write }, /* write */ 6088 { &vnop_ioctl_desc, (VOPFUNC)spec_ioctl }, /* ioctl */ 6089 { &vnop_select_desc, (VOPFUNC)spec_select }, /* select */ 6090 { &vnop_revoke_desc, (VOPFUNC)spec_revoke }, /* revoke */ 6091 { &vnop_mmap_desc, (VOPFUNC)spec_mmap }, /* mmap */ 6092 { &vnop_fsync_desc, (VOPFUNC)hfs_vnop_fsync }, /* fsync */ 6093 { &vnop_remove_desc, (VOPFUNC)spec_remove }, /* remove */ 6094 { &vnop_link_desc, (VOPFUNC)spec_link }, /* link */ 6095 { &vnop_rename_desc, (VOPFUNC)spec_rename }, /* rename */ 6096 { &vnop_mkdir_desc, (VOPFUNC)spec_mkdir }, /* mkdir */ 6097 { &vnop_rmdir_desc, (VOPFUNC)spec_rmdir }, /* rmdir */ 6098 { &vnop_symlink_desc, (VOPFUNC)spec_symlink }, /* symlink */ 6099 { &vnop_readdir_desc, (VOPFUNC)spec_readdir }, /* readdir */ 6100 { &vnop_readlink_desc, (VOPFUNC)spec_readlink }, /* readlink */ 6101 { &vnop_inactive_desc, (VOPFUNC)hfs_vnop_inactive }, /* inactive */ 6102 { &vnop_reclaim_desc, (VOPFUNC)hfs_vnop_reclaim }, /* reclaim */ 6103 { &vnop_strategy_desc, (VOPFUNC)spec_strategy }, /* strategy */ 6104 { &vnop_pathconf_desc, (VOPFUNC)spec_pathconf }, /* pathconf */ 6105 { &vnop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */ 6106 { &vnop_bwrite_desc, (VOPFUNC)hfs_vnop_bwrite }, 6107 { &vnop_pagein_desc, (VOPFUNC)hfs_vnop_pagein }, /* Pagein */ 6108 { &vnop_pageout_desc, (VOPFUNC)hfs_vnop_pageout }, /* Pageout */ 6109 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* copyfile */ 6110 { &vnop_blktooff_desc, (VOPFUNC)hfs_vnop_blktooff }, /* blktooff */ 6111 { &vnop_offtoblk_desc, (VOPFUNC)hfs_vnop_offtoblk }, /* offtoblk */ 6112 { (struct vnodeop_desc*)NULL, (VOPFUNC)NULL } 6113}; 6114struct vnodeopv_desc hfs_specop_opv_desc = 6115 { &hfs_specop_p, hfs_specop_entries }; 6116 6117#if FIFO 6118/* HFS+ FIFO VNOP table */ 6119int (**hfs_fifoop_p)(void *); 6120struct vnodeopv_entry_desc hfs_fifoop_entries[] = { 6121 { &vnop_default_desc, (VOPFUNC)vn_default_error }, 6122 { &vnop_lookup_desc, (VOPFUNC)fifo_lookup }, /* lookup */ 6123 { &vnop_create_desc, (VOPFUNC)fifo_create }, /* create */ 6124 { &vnop_mknod_desc, (VOPFUNC)fifo_mknod }, /* mknod */ 6125 { &vnop_open_desc, (VOPFUNC)fifo_open }, /* open */ 6126 { &vnop_close_desc, (VOPFUNC)hfsfifo_close }, /* close */ 6127 { &vnop_getattr_desc, (VOPFUNC)hfs_vnop_getattr }, /* getattr */ 6128 { &vnop_setattr_desc, (VOPFUNC)hfs_vnop_setattr }, /* setattr */ 6129 { &vnop_read_desc, (VOPFUNC)hfsfifo_read }, /* read */ 6130 { &vnop_write_desc, (VOPFUNC)hfsfifo_write }, /* write */ 6131 { &vnop_ioctl_desc, (VOPFUNC)fifo_ioctl }, /* ioctl */ 6132 { &vnop_select_desc, (VOPFUNC)fifo_select }, /* select */ 6133 { &vnop_revoke_desc, (VOPFUNC)fifo_revoke }, /* revoke */ 6134 { &vnop_mmap_desc, (VOPFUNC)fifo_mmap }, /* mmap */ 6135 { &vnop_fsync_desc, (VOPFUNC)hfs_vnop_fsync }, /* fsync */ 6136 { &vnop_remove_desc, (VOPFUNC)fifo_remove }, /* remove */ 6137 { &vnop_link_desc, (VOPFUNC)fifo_link }, /* link */ 6138 { &vnop_rename_desc, (VOPFUNC)fifo_rename }, /* rename */ 6139 { &vnop_mkdir_desc, (VOPFUNC)fifo_mkdir }, /* mkdir */ 6140 { &vnop_rmdir_desc, (VOPFUNC)fifo_rmdir }, /* rmdir */ 6141 { &vnop_symlink_desc, (VOPFUNC)fifo_symlink }, /* symlink */ 6142 { &vnop_readdir_desc, (VOPFUNC)fifo_readdir }, /* readdir */ 6143 { &vnop_readlink_desc, (VOPFUNC)fifo_readlink }, /* readlink */ 6144 { &vnop_inactive_desc, (VOPFUNC)hfs_vnop_inactive }, /* inactive */ 6145 { &vnop_reclaim_desc, (VOPFUNC)hfs_vnop_reclaim }, /* reclaim */ 6146 { &vnop_strategy_desc, (VOPFUNC)fifo_strategy }, /* strategy */ 6147 { &vnop_pathconf_desc, (VOPFUNC)fifo_pathconf }, /* pathconf */ 6148 { &vnop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */ 6149 { &vnop_bwrite_desc, (VOPFUNC)hfs_vnop_bwrite }, 6150 { &vnop_pagein_desc, (VOPFUNC)hfs_vnop_pagein }, /* Pagein */ 6151 { &vnop_pageout_desc, (VOPFUNC)hfs_vnop_pageout }, /* Pageout */ 6152 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* copyfile */ 6153 { &vnop_blktooff_desc, (VOPFUNC)hfs_vnop_blktooff }, /* blktooff */ 6154 { &vnop_offtoblk_desc, (VOPFUNC)hfs_vnop_offtoblk }, /* offtoblk */ 6155 { &vnop_blockmap_desc, (VOPFUNC)hfs_vnop_blockmap }, /* blockmap */ 6156 { (struct vnodeop_desc*)NULL, (VOPFUNC)NULL } 6157}; 6158struct vnodeopv_desc hfs_fifoop_opv_desc = 6159 { &hfs_fifoop_p, hfs_fifoop_entries }; 6160#endif /* FIFO */ 6161 6162 6163 6164