static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); size_t size = 0; char *value = NULL; int rc, xprefix; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch (type) { case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; rc = posix_acl_equiv_mode(acl, &mode); if (rc < 0) return rc; if (inode->i_mode != mode) { inode->i_mode = mode; jffs2_dirty_inode(inode); } if (rc == 0) acl = NULL; } break; case ACL_TYPE_DEFAULT: xprefix = JFFS2_XPREFIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } if (acl) { value = jffs2_acl_to_medium(acl, &size); if (IS_ERR(value)) return PTR_ERR(value); } rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0); if (!value && rc == -ENODATA) rc = 0; if (value) kfree(value); if (!rc) { switch(type) { case ACL_TYPE_ACCESS: jffs2_iset_acl(inode, &f->i_acl_access, acl); break; case ACL_TYPE_DEFAULT: jffs2_iset_acl(inode, &f->i_acl_default, acl); break; } } return rc; }
static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct posix_acl *acl; char *value = NULL; int rc, xprefix; switch (type) { case ACL_TYPE_ACCESS: acl = jffs2_iget_acl(inode, &f->i_acl_access); if (acl != JFFS2_ACL_NOT_CACHED) return acl; xprefix = JFFS2_XPREFIX_ACL_ACCESS; break; case ACL_TYPE_DEFAULT: acl = jffs2_iget_acl(inode, &f->i_acl_default); if (acl != JFFS2_ACL_NOT_CACHED) return acl; xprefix = JFFS2_XPREFIX_ACL_DEFAULT; break; default: return ERR_PTR(-EINVAL); } rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0); if (rc > 0) { value = kmalloc(rc, GFP_KERNEL); if (!value) return ERR_PTR(-ENOMEM); rc = do_jffs2_getxattr(inode, xprefix, "", value, rc); } if (rc > 0) { acl = jffs2_acl_from_medium(value, rc); } else if (rc == -ENODATA || rc == -ENOSYS) { acl = NULL; } else { acl = ERR_PTR(rc); } if (value) kfree(value); if (!IS_ERR(acl)) { switch (type) { case ACL_TYPE_ACCESS: jffs2_iset_acl(inode, &f->i_acl_access, acl); break; case ACL_TYPE_DEFAULT: jffs2_iset_acl(inode, &f->i_acl_default, acl); break; } } return acl; }
static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); int rc, xprefix; if (S_ISLNK(inode->i_mode)) return -EOPNOTSUPP; switch (type) { case ACL_TYPE_ACCESS: xprefix = JFFS2_XPREFIX_ACL_ACCESS; if (acl) { mode_t mode = inode->i_mode; rc = posix_acl_equiv_mode(acl, &mode); if (rc < 0) return rc; if (inode->i_mode != mode) { struct iattr attr; attr.ia_valid = ATTR_MODE; attr.ia_mode = mode; rc = jffs2_do_setattr(inode, &attr); if (rc < 0) return rc; } if (rc == 0) acl = NULL; } break; case ACL_TYPE_DEFAULT: xprefix = JFFS2_XPREFIX_ACL_DEFAULT; if (!S_ISDIR(inode->i_mode)) return acl ? -EACCES : 0; break; default: return -EINVAL; } rc = __jffs2_set_acl(inode, xprefix, acl); if (!rc) { switch(type) { case ACL_TYPE_ACCESS: jffs2_iset_acl(inode, &f->i_acl_access, acl); break; case ACL_TYPE_DEFAULT: jffs2_iset_acl(inode, &f->i_acl_default, acl); break; } } return rc; }
int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) { struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct posix_acl *acl, *clone; int rc; f->i_acl_default = NULL; f->i_acl_access = NULL; if (S_ISLNK(*i_mode)) return 0; /* Symlink always has no-ACL */ acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) return PTR_ERR(acl); if (!acl) { *i_mode &= ~current->fs->umask; } else { if (S_ISDIR(*i_mode)) jffs2_iset_acl(inode, &f->i_acl_default, acl); clone = posix_acl_clone(acl, GFP_KERNEL); if (!clone) return -ENOMEM; rc = posix_acl_create_masq(clone, (mode_t *)i_mode); if (rc < 0) { posix_acl_release(clone); return rc; } if (rc > 0) jffs2_iset_acl(inode, &f->i_acl_access, clone); posix_acl_release(clone); } return 0; }