X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/b36670cedae0009469e8ee117453de831de64a6b..8f6c56a50524aa785f7e596d52dddfb331e18961:/bsd/hfs/hfs_readwrite.c diff --git a/bsd/hfs/hfs_readwrite.c b/bsd/hfs/hfs_readwrite.c index 46f8e54e5..fd934e2f5 100644 --- a/bsd/hfs/hfs_readwrite.c +++ b/bsd/hfs/hfs_readwrite.c @@ -1,23 +1,29 @@ /* * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* @(#)hfs_readwrite.c 1.0 * @@ -40,6 +46,8 @@ #include #include #include +#include +#include #include @@ -76,6 +84,10 @@ static int hfs_clonefile(struct vnode *, int, int, int); static int hfs_clonesysfile(struct vnode *, int, int, int, kauth_cred_t, struct proc *); +int flush_cache_on_write = 0; +SYSCTL_INT (_kern, OID_AUTO, flush_cache_on_write, CTLFLAG_RW, &flush_cache_on_write, 0, "always flush the drive cache on writes to uncached files"); + + /***************************************************************************** * * I/O Operations on vnodes @@ -464,6 +476,13 @@ sizeok: cp->c_touch_modtime = TRUE; } } + + // XXXdbg - testing for vivek and paul lambert + { + if (flush_cache_on_write && ((ioflag & IO_NOCACHE) || vnode_isnocache(vp))) { + VNOP_IOCTL(hfsmp->hfs_devvp, DKIOCSYNCHRONIZECACHE, NULL, FWRITE, NULL); + } + } HFS_KNOTE(vp, NOTE_WRITE); ioerr_exit: @@ -990,6 +1009,8 @@ hfs_vnop_ioctl( struct vnop_ioctl_args /* { if (!(hfsmp->jnl)) return (ENOTSUP); + + lck_rw_lock_exclusive(&hfsmp->hfs_insync); task = current_task(); task_working_set_disable(task); @@ -1001,9 +1022,9 @@ hfs_vnop_ioctl( struct vnop_ioctl_args /* { vnode_iterate(mp, 0, hfs_freezewrite_callback, NULL); hfs_global_exclusive_lock_acquire(hfsmp); journal_flush(hfsmp->jnl); + // don't need to iterate on all vnodes, we just need to // wait for writes to the system files and the device vnode - // vnode_iterate(mp, 0, hfs_freezewrite_callback, NULL); if (HFSTOVCB(hfsmp)->extentsRefNum) vnode_waitforwrites(HFSTOVCB(hfsmp)->extentsRefNum, 0, 0, 0, "hfs freeze"); if (HFSTOVCB(hfsmp)->catalogRefNum) @@ -1026,7 +1047,7 @@ hfs_vnop_ioctl( struct vnop_ioctl_args /* { // if we're not the one who froze the fs then we // can't thaw it. if (hfsmp->hfs_freezing_proc != current_proc()) { - return EINVAL; + return EPERM; } // NOTE: if you add code here, also go check the @@ -1034,6 +1055,7 @@ hfs_vnop_ioctl( struct vnop_ioctl_args /* { // hfsmp->hfs_freezing_proc = NULL; hfs_global_exclusive_lock_release(hfsmp); + lck_rw_unlock_exclusive(&hfsmp->hfs_insync); return (0); } @@ -1155,6 +1177,7 @@ hfs_vnop_ioctl( struct vnop_ioctl_args /* { goto err_exit_bulk_access; } myucred.cr_rgid = myucred.cr_svgid = myucred.cr_groups[0]; + myucred.cr_gmuid = myucred.cr_uid; my_context.vc_proc = p; my_context.vc_ucred = &myucred; @@ -1262,13 +1285,18 @@ hfs_vnop_ioctl( struct vnop_ioctl_args /* { case HFS_SETACLSTATE: { int state; - if (!is_suser()) { - return (EPERM); - } if (ap->a_data == NULL) { return (EINVAL); } + + vfsp = vfs_statfs(HFSTOVFS(hfsmp)); state = *(int *)ap->a_data; + + // super-user can enable or disable acl's on a volume. + // the volume owner can only enable acl's + if (!is_suser() && (state == 0 || kauth_cred_getuid(cred) != vfsp->f_owner)) { + return (EPERM); + } if (state == 0 || state == 1) return hfs_setextendedsecurity(hfsmp, state); else @@ -1605,6 +1633,11 @@ hfs_vnop_blockmap(struct vnop_blockmap_args *ap) int started_tr = 0; int tooklock = 0; + /* Do not allow blockmap operation on a directory */ + if (vnode_isdir(vp)) { + return (ENOTSUP); + } + /* * Check for underlying vnode requests and ensure that logical * to physical mapping is requested. @@ -1799,6 +1832,7 @@ do_hfs_truncate(struct vnode *vp, off_t length, int flags, int skipsetsize, vfs_ off_t bytesToAdd; off_t actualBytesAdded; off_t filebytes; + u_int64_t old_filesize; u_long fileblocks; int blksize; struct hfsmount *hfsmp; @@ -1807,6 +1841,7 @@ do_hfs_truncate(struct vnode *vp, off_t length, int flags, int skipsetsize, vfs_ blksize = VTOVCB(vp)->blockSize; fileblocks = fp->ff_blocks; filebytes = (off_t)fileblocks * (off_t)blksize; + old_filesize = fp->ff_size; KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 7)) | DBG_FUNC_START, (int)length, (int)fp->ff_size, (int)filebytes, 0, 0); @@ -1814,6 +1849,10 @@ do_hfs_truncate(struct vnode *vp, off_t length, int flags, int skipsetsize, vfs_ if (length < 0) return (EINVAL); + /* This should only happen with a corrupt filesystem */ + if ((off_t)fp->ff_size < 0) + return (EINVAL); + if ((!ISHFSPLUS(VTOVCB(vp))) && (length > (off_t)MAXHFSFILESIZE)) return (EFBIG); @@ -2057,6 +2096,9 @@ do_hfs_truncate(struct vnode *vp, off_t length, int flags, int skipsetsize, vfs_ hfs_systemfile_unlock(hfsmp, lockflags); } if (hfsmp->jnl) { + if (retval == 0) { + fp->ff_size = length; + } (void) hfs_update(vp, TRUE); (void) hfs_volupdate(hfsmp, VOL_UPDATE, 0); } @@ -2072,7 +2114,7 @@ do_hfs_truncate(struct vnode *vp, off_t length, int flags, int skipsetsize, vfs_ #endif /* QUOTA */ } /* Only set update flag if the logical length changes */ - if ((off_t)fp->ff_size != length) + if (old_filesize != length) cp->c_touch_modtime = TRUE; fp->ff_size = length; } @@ -2106,6 +2148,7 @@ hfs_truncate(struct vnode *vp, off_t length, int flags, int skipsetsize, off_t filebytes; u_long fileblocks; int blksize, error = 0; + struct cnode *cp = VTOC(vp); if (vnode_isdir(vp)) return (EISDIR); /* cannot truncate an HFS directory! */ @@ -2125,6 +2168,7 @@ hfs_truncate(struct vnode *vp, off_t length, int flags, int skipsetsize, } else { filebytes = length; } + cp->c_flag |= C_FORCEUPDATE; error = do_hfs_truncate(vp, filebytes, flags, skipsetsize, context); if (error) break; @@ -2136,6 +2180,7 @@ hfs_truncate(struct vnode *vp, off_t length, int flags, int skipsetsize, } else { filebytes = length; } + cp->c_flag |= C_FORCEUPDATE; error = do_hfs_truncate(vp, filebytes, flags, skipsetsize, context); if (error) break; @@ -2472,6 +2517,12 @@ hfs_vnop_pageout(struct vnop_pageout_args *ap) cp->c_desc.cd_nameptr ? cp->c_desc.cd_nameptr : ""); } if ( (retval = hfs_lock(cp, HFS_EXCLUSIVE_LOCK))) { + if (!(ap->a_flags & UPL_NOCOMMIT)) { + ubc_upl_abort_range(ap->a_pl, + ap->a_pl_offset, + ap->a_size, + UPL_ABORT_FREE_ON_EMPTY); + } return (retval); } fp = VTOF(vp); @@ -2516,7 +2567,6 @@ hfs_vnop_bwrite(struct vnop_bwrite_args *ap) int retval = 0; register struct buf *bp = ap->a_bp; register struct vnode *vp = buf_vnode(bp); -#if BYTE_ORDER == LITTLE_ENDIAN BlockDescriptor block; /* Trap B-Tree writes */ @@ -2524,22 +2574,29 @@ hfs_vnop_bwrite(struct vnop_bwrite_args *ap) (VTOC(vp)->c_fileid == kHFSCatalogFileID) || (VTOC(vp)->c_fileid == kHFSAttributesFileID)) { - /* Swap if the B-Tree node is in native byte order */ + /* + * Swap and validate the node if it is in native byte order. + * This is always be true on big endian, so we always validate + * before writing here. On little endian, the node typically has + * been swapped and validatated when it was written to the journal, + * so we won't do anything here. + */ if (((UInt16 *)((char *)buf_dataptr(bp) + buf_count(bp) - 2))[0] == 0x000e) { /* Prepare the block pointer */ block.blockHeader = bp; block.buffer = (char *)buf_dataptr(bp); + block.blockNum = buf_lblkno(bp); /* not found in cache ==> came from disk */ block.blockReadFromDisk = (buf_fromcache(bp) == 0); block.blockSize = buf_count(bp); /* Endian un-swap B-Tree node */ - SWAP_BT_NODE (&block, ISHFSPLUS (VTOVCB(vp)), VTOC(vp)->c_fileid, 1); + retval = hfs_swap_BTNode (&block, vp, kSwapBTNodeHostToBig); + if (retval) + panic("hfs_vnop_bwrite: about to write corrupt node!\n"); } - - /* We don't check to make sure that it's 0x0e00 because it could be all zeros */ } -#endif + /* This buffer shouldn't be locked anymore but if it is clear it */ if ((buf_flags(bp) & B_LOCKED)) { // XXXdbg