struct inode *ip;
vattr_t va;
vnode_t *vp = NULL, *dvp = LINVFS_GET_VP(dir);
+ xfs_acl_t *default_acl = NULL;
xattr_exists_t test_default_acl = _ACL_DEFAULT_EXISTS;
- int have_default_acl = 0;
- int error = EINVAL;
+ int error;
- if (test_default_acl)
- have_default_acl = test_default_acl(dvp);
+ if (test_default_acl && test_default_acl(dvp)) {
+ if (!_ACL_ALLOC(default_acl))
+ return -ENOMEM;
+ if (!_ACL_GET_DEFAULT(dvp, default_acl)) {
+ _ACL_FREE(default_acl);
+ default_acl = NULL;
+ }
+ }
- if (IS_POSIXACL(dir) && !have_default_acl && has_fs_struct(current))
+ if (IS_POSIXACL(dir) && !default_acl && has_fs_struct(current))
mode &= ~current->fs->umask;
memset(&va, 0, sizeof(va));
break;
}
+ if (default_acl) {
+ if (!error) {
+ error = _ACL_INHERIT(vp, &va, default_acl);
+ if (!error) {
+ VMODIFY(vp);
+ } else {
+ struct dentry teardown = {};
+ int err2;
+
+ /* Oh, the horror.
+ * If we can't add the ACL we must back out.
+ * ENOSPC can hit here, among other things.
+ */
+ teardown.d_inode = ip = LINVFS_GET_IP(vp);
+ teardown.d_name = dentry->d_name;
+ remove_inode_hash(ip);
+ make_bad_inode(ip);
+ if (S_ISDIR(mode))
+ VOP_RMDIR(dvp, &teardown, NULL, err2);
+ else
+ VOP_REMOVE(dvp, &teardown, NULL, err2);
+ VN_RELE(vp);
+ }
+ }
+ _ACL_FREE(default_acl);
+ }
+
if (!error) {
ASSERT(vp);
ip = LINVFS_GET_IP(vp);
- if (!ip) {
- VN_RELE(vp);
- return -ENOMEM;
- }
if (S_ISCHR(mode) || S_ISBLK(mode))
ip->i_rdev = to_kdev_t(rdev);
d_instantiate(dentry, ip);
validate_fields(dir);
}
-
- if (!error && have_default_acl) {
- _ACL_DECL (pdacl);
-
- if (!_ACL_ALLOC(pdacl)) {
- error = -ENOMEM;
- } else {
- if (_ACL_GET_DEFAULT(dvp, pdacl))
- error = _ACL_INHERIT(vp, &va, pdacl);
- VMODIFY(vp);
- _ACL_FREE(pdacl);
- }
- }
return -error;
}
int i;
state = xfs_da_state_alloc();
+ state->holeok = 1;
state->args = args;
state->mp = args->dp->i_mount;
state->blocksize = state->mp->m_sb.sb_blocksize;
/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
xfs_da_node_entry_t *btree;
xfs_dablk_t blkno;
int probe, span, max, error, retval;
+ xfs_daddr_t mappedbno;
xfs_dahash_t hashval;
xfs_da_args_t *args;
args = state->args;
+ mappedbno = state->holeok ? -2 : -1;
+
/*
* Descend thru the B-tree searching each level for the right
* node to use, until the right hashval is found.
* Read the next node down in the tree.
*/
blk->blkno = blkno;
- error = xfs_da_read_buf(state->args->trans, state->args->dp,
- blkno, -1, &blk->bp,
- state->args->whichfork);
+ error = xfs_da_read_buf(args->trans, args->dp, blkno,
+ mappedbno, &blk->bp, args->whichfork);
+ if (!error && unlikely(state->holeok && !blk->bp))
+ error = XFS_ERROR(ENOATTR); /* always attr here */
if (error) {
blk->blkno = 0;
state->path.active--;
return(error);
}
- ASSERT(blk->bp != NULL);
curr = blk->bp->data;
ASSERT(INT_GET(curr->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC ||
INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) ||
*/
max = INT_GET(node->hdr.count, ARCH_CONVERT);
probe = span = max / 2;
- hashval = state->args->hashval;
+ hashval = args->hashval;
for (btree = &node->btree[probe]; span > 4;
btree = &node->btree[probe]) {
span /= 2;
for (;;) {
if (blk->magic == XFS_DIR_LEAF_MAGIC) {
ASSERT(XFS_DIR_IS_V1(state->mp));
- retval = xfs_dir_leaf_lookup_int(blk->bp, state->args,
+ retval = xfs_dir_leaf_lookup_int(blk->bp, args,
&blk->index);
} else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {
ASSERT(XFS_DIR_IS_V2(state->mp));
- retval = xfs_dir2_leafn_lookup_int(blk->bp, state->args,
+ retval = xfs_dir2_leafn_lookup_int(blk->bp, args,
&blk->index, state);
}
#ifdef __KERNEL__
else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
- retval = xfs_attr_leaf_lookup_int(blk->bp, state->args);
- blk->index = state->args->index;
- state->args->blkno = blk->blkno;
+ retval = xfs_attr_leaf_lookup_int(blk->bp, args);
+ blk->index = args->index;
+ args->blkno = blk->blkno;
}
#endif
if (((retval == ENOENT) || (retval == ENOATTR)) &&
- (blk->hashval == state->args->hashval)) {
+ (blk->hashval == args->hashval)) {
error = xfs_da_path_shift(state, &state->path, 1, 1,
&retval);
if (error)
int index; /* index of attr of interest in blk */
xfs_dablk_t rmtblkno; /* remote attr value starting blkno */
int rmtblkcnt; /* remote attr value block count */
- int rename; /* T/F: this is an atomic rename op */
xfs_dablk_t blkno2; /* blkno of 2nd attr leaf of interest */
int index2; /* index of 2nd attr in blk */
xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */
int rmtblkcnt2; /* remote attr value block count */
- int justcheck; /* check for ok with no space */
- int addname; /* T/F: this is an add operation */
- int oknoent; /* T/F: ok to return ENOENT, else die */
+ int justcheck : 1; /* T/F: check for ok with no space */
+ int rename : 1; /* T/F: this is an atomic rename op */
+ int addname : 1; /* T/F: this is an add operation */
+ int oknoent : 1; /* T/F: ok to return ENOENT, else die */
} xfs_da_args_t;
/*
xfs_da_state_path_t path; /* search/split paths */
xfs_da_state_path_t altpath; /* alternate path for join */
unsigned int inleaf : 1; /* insert into 1->lf, 0->splf */
+ unsigned int holeok : 1; /* T/F: can deal with a hole */
unsigned int extravalid : 1; /* T/F: extrablk is in use */
unsigned int extraafter : 1; /* T/F: extrablk is after new */
xfs_da_state_blk_t extrablk; /* for double-splits on leafs */