/*
* 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
*
#include <sys/vnode.h>
#include <sys/uio.h>
#include <sys/vfs_context.h>
+#include <sys/disk.h>
+#include <sys/sysctl.h>
#include <miscfs/specfs/specdev.h>
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
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:
if (!(hfsmp->jnl))
return (ENOTSUP);
+
+ lck_rw_lock_exclusive(&hfsmp->hfs_insync);
task = current_task();
task_working_set_disable(task);
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)
// 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
//
hfsmp->hfs_freezing_proc = NULL;
hfs_global_exclusive_lock_release(hfsmp);
+ lck_rw_unlock_exclusive(&hfsmp->hfs_insync);
return (0);
}
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;
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
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.
off_t bytesToAdd;
off_t actualBytesAdded;
off_t filebytes;
+ u_int64_t old_filesize;
u_long fileblocks;
int blksize;
struct hfsmount *hfsmp;
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);
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);
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);
}
#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;
}
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! */
} else {
filebytes = length;
}
+ cp->c_flag |= C_FORCEUPDATE;
error = do_hfs_truncate(vp, filebytes, flags, skipsetsize, context);
if (error)
break;
} else {
filebytes = length;
}
+ cp->c_flag |= C_FORCEUPDATE;
error = do_hfs_truncate(vp, filebytes, flags, skipsetsize, context);
if (error)
break;
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);
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 */
(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