10a8165d7SJaegeuk Kim /* 2af48b85bSJaegeuk Kim * fs/f2fs/acl.c 3af48b85bSJaegeuk Kim * 4af48b85bSJaegeuk Kim * Copyright (c) 2012 Samsung Electronics Co., Ltd. 5af48b85bSJaegeuk Kim * http://www.samsung.com/ 6af48b85bSJaegeuk Kim * 7af48b85bSJaegeuk Kim * Portions of this code from linux/fs/ext2/acl.c 8af48b85bSJaegeuk Kim * 9af48b85bSJaegeuk Kim * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> 10af48b85bSJaegeuk Kim * 11af48b85bSJaegeuk Kim * This program is free software; you can redistribute it and/or modify 12af48b85bSJaegeuk Kim * it under the terms of the GNU General Public License version 2 as 13af48b85bSJaegeuk Kim * published by the Free Software Foundation. 14af48b85bSJaegeuk Kim */ 15af48b85bSJaegeuk Kim #include <linux/f2fs_fs.h> 16af48b85bSJaegeuk Kim #include "f2fs.h" 17af48b85bSJaegeuk Kim #include "xattr.h" 18af48b85bSJaegeuk Kim #include "acl.h" 19af48b85bSJaegeuk Kim 20af48b85bSJaegeuk Kim #define get_inode_mode(i) ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \ 21af48b85bSJaegeuk Kim (F2FS_I(i)->i_acl_mode) : ((i)->i_mode)) 22af48b85bSJaegeuk Kim 23af48b85bSJaegeuk Kim static inline size_t f2fs_acl_size(int count) 24af48b85bSJaegeuk Kim { 25af48b85bSJaegeuk Kim if (count <= 4) { 26af48b85bSJaegeuk Kim return sizeof(struct f2fs_acl_header) + 27af48b85bSJaegeuk Kim count * sizeof(struct f2fs_acl_entry_short); 28af48b85bSJaegeuk Kim } else { 29af48b85bSJaegeuk Kim return sizeof(struct f2fs_acl_header) + 30af48b85bSJaegeuk Kim 4 * sizeof(struct f2fs_acl_entry_short) + 31af48b85bSJaegeuk Kim (count - 4) * sizeof(struct f2fs_acl_entry); 32af48b85bSJaegeuk Kim } 33af48b85bSJaegeuk Kim } 34af48b85bSJaegeuk Kim 35af48b85bSJaegeuk Kim static inline int f2fs_acl_count(size_t size) 36af48b85bSJaegeuk Kim { 37af48b85bSJaegeuk Kim ssize_t s; 38af48b85bSJaegeuk Kim size -= sizeof(struct f2fs_acl_header); 39af48b85bSJaegeuk Kim s = size - 4 * sizeof(struct f2fs_acl_entry_short); 40af48b85bSJaegeuk Kim if (s < 0) { 41af48b85bSJaegeuk Kim if (size % sizeof(struct f2fs_acl_entry_short)) 42af48b85bSJaegeuk Kim return -1; 43af48b85bSJaegeuk Kim return size / sizeof(struct f2fs_acl_entry_short); 44af48b85bSJaegeuk Kim } else { 45af48b85bSJaegeuk Kim if (s % sizeof(struct f2fs_acl_entry)) 46af48b85bSJaegeuk Kim return -1; 47af48b85bSJaegeuk Kim return s / sizeof(struct f2fs_acl_entry) + 4; 48af48b85bSJaegeuk Kim } 49af48b85bSJaegeuk Kim } 50af48b85bSJaegeuk Kim 51af48b85bSJaegeuk Kim static struct posix_acl *f2fs_acl_from_disk(const char *value, size_t size) 52af48b85bSJaegeuk Kim { 53af48b85bSJaegeuk Kim int i, count; 54af48b85bSJaegeuk Kim struct posix_acl *acl; 55af48b85bSJaegeuk Kim struct f2fs_acl_header *hdr = (struct f2fs_acl_header *)value; 56af48b85bSJaegeuk Kim struct f2fs_acl_entry *entry = (struct f2fs_acl_entry *)(hdr + 1); 57af48b85bSJaegeuk Kim const char *end = value + size; 58af48b85bSJaegeuk Kim 59af48b85bSJaegeuk Kim if (hdr->a_version != cpu_to_le32(F2FS_ACL_VERSION)) 60af48b85bSJaegeuk Kim return ERR_PTR(-EINVAL); 61af48b85bSJaegeuk Kim 62af48b85bSJaegeuk Kim count = f2fs_acl_count(size); 63af48b85bSJaegeuk Kim if (count < 0) 64af48b85bSJaegeuk Kim return ERR_PTR(-EINVAL); 65af48b85bSJaegeuk Kim if (count == 0) 66af48b85bSJaegeuk Kim return NULL; 67af48b85bSJaegeuk Kim 68af48b85bSJaegeuk Kim acl = posix_acl_alloc(count, GFP_KERNEL); 69af48b85bSJaegeuk Kim if (!acl) 70af48b85bSJaegeuk Kim return ERR_PTR(-ENOMEM); 71af48b85bSJaegeuk Kim 72af48b85bSJaegeuk Kim for (i = 0; i < count; i++) { 73af48b85bSJaegeuk Kim 74af48b85bSJaegeuk Kim if ((char *)entry > end) 75af48b85bSJaegeuk Kim goto fail; 76af48b85bSJaegeuk Kim 77af48b85bSJaegeuk Kim acl->a_entries[i].e_tag = le16_to_cpu(entry->e_tag); 78af48b85bSJaegeuk Kim acl->a_entries[i].e_perm = le16_to_cpu(entry->e_perm); 79af48b85bSJaegeuk Kim 80af48b85bSJaegeuk Kim switch (acl->a_entries[i].e_tag) { 81af48b85bSJaegeuk Kim case ACL_USER_OBJ: 82af48b85bSJaegeuk Kim case ACL_GROUP_OBJ: 83af48b85bSJaegeuk Kim case ACL_MASK: 84af48b85bSJaegeuk Kim case ACL_OTHER: 85af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)((char *)entry + 86af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry_short)); 87af48b85bSJaegeuk Kim break; 88af48b85bSJaegeuk Kim 89af48b85bSJaegeuk Kim case ACL_USER: 90af48b85bSJaegeuk Kim acl->a_entries[i].e_uid = 91af48b85bSJaegeuk Kim make_kuid(&init_user_ns, 92af48b85bSJaegeuk Kim le32_to_cpu(entry->e_id)); 93af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)((char *)entry + 94af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry)); 95af48b85bSJaegeuk Kim break; 96af48b85bSJaegeuk Kim case ACL_GROUP: 97af48b85bSJaegeuk Kim acl->a_entries[i].e_gid = 98af48b85bSJaegeuk Kim make_kgid(&init_user_ns, 99af48b85bSJaegeuk Kim le32_to_cpu(entry->e_id)); 100af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)((char *)entry + 101af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry)); 102af48b85bSJaegeuk Kim break; 103af48b85bSJaegeuk Kim default: 104af48b85bSJaegeuk Kim goto fail; 105af48b85bSJaegeuk Kim } 106af48b85bSJaegeuk Kim } 107af48b85bSJaegeuk Kim if ((char *)entry != end) 108af48b85bSJaegeuk Kim goto fail; 109af48b85bSJaegeuk Kim return acl; 110af48b85bSJaegeuk Kim fail: 111af48b85bSJaegeuk Kim posix_acl_release(acl); 112af48b85bSJaegeuk Kim return ERR_PTR(-EINVAL); 113af48b85bSJaegeuk Kim } 114af48b85bSJaegeuk Kim 115af48b85bSJaegeuk Kim static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size) 116af48b85bSJaegeuk Kim { 117af48b85bSJaegeuk Kim struct f2fs_acl_header *f2fs_acl; 118af48b85bSJaegeuk Kim struct f2fs_acl_entry *entry; 119af48b85bSJaegeuk Kim int i; 120af48b85bSJaegeuk Kim 121af48b85bSJaegeuk Kim f2fs_acl = kmalloc(sizeof(struct f2fs_acl_header) + acl->a_count * 122af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry), GFP_KERNEL); 123af48b85bSJaegeuk Kim if (!f2fs_acl) 124af48b85bSJaegeuk Kim return ERR_PTR(-ENOMEM); 125af48b85bSJaegeuk Kim 126af48b85bSJaegeuk Kim f2fs_acl->a_version = cpu_to_le32(F2FS_ACL_VERSION); 127af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)(f2fs_acl + 1); 128af48b85bSJaegeuk Kim 129af48b85bSJaegeuk Kim for (i = 0; i < acl->a_count; i++) { 130af48b85bSJaegeuk Kim 131af48b85bSJaegeuk Kim entry->e_tag = cpu_to_le16(acl->a_entries[i].e_tag); 132af48b85bSJaegeuk Kim entry->e_perm = cpu_to_le16(acl->a_entries[i].e_perm); 133af48b85bSJaegeuk Kim 134af48b85bSJaegeuk Kim switch (acl->a_entries[i].e_tag) { 135af48b85bSJaegeuk Kim case ACL_USER: 136af48b85bSJaegeuk Kim entry->e_id = cpu_to_le32( 137af48b85bSJaegeuk Kim from_kuid(&init_user_ns, 138af48b85bSJaegeuk Kim acl->a_entries[i].e_uid)); 139af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)((char *)entry + 140af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry)); 141af48b85bSJaegeuk Kim break; 142af48b85bSJaegeuk Kim case ACL_GROUP: 143af48b85bSJaegeuk Kim entry->e_id = cpu_to_le32( 144af48b85bSJaegeuk Kim from_kgid(&init_user_ns, 145af48b85bSJaegeuk Kim acl->a_entries[i].e_gid)); 146af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)((char *)entry + 147af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry)); 148af48b85bSJaegeuk Kim break; 149af48b85bSJaegeuk Kim case ACL_USER_OBJ: 150af48b85bSJaegeuk Kim case ACL_GROUP_OBJ: 151af48b85bSJaegeuk Kim case ACL_MASK: 152af48b85bSJaegeuk Kim case ACL_OTHER: 153af48b85bSJaegeuk Kim entry = (struct f2fs_acl_entry *)((char *)entry + 154af48b85bSJaegeuk Kim sizeof(struct f2fs_acl_entry_short)); 155af48b85bSJaegeuk Kim break; 156af48b85bSJaegeuk Kim default: 157af48b85bSJaegeuk Kim goto fail; 158af48b85bSJaegeuk Kim } 159af48b85bSJaegeuk Kim } 160af48b85bSJaegeuk Kim *size = f2fs_acl_size(acl->a_count); 161af48b85bSJaegeuk Kim return (void *)f2fs_acl; 162af48b85bSJaegeuk Kim 163af48b85bSJaegeuk Kim fail: 164af48b85bSJaegeuk Kim kfree(f2fs_acl); 165af48b85bSJaegeuk Kim return ERR_PTR(-EINVAL); 166af48b85bSJaegeuk Kim } 167af48b85bSJaegeuk Kim 168af48b85bSJaegeuk Kim struct posix_acl *f2fs_get_acl(struct inode *inode, int type) 169af48b85bSJaegeuk Kim { 170af48b85bSJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 171af48b85bSJaegeuk Kim int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; 172af48b85bSJaegeuk Kim void *value = NULL; 173af48b85bSJaegeuk Kim struct posix_acl *acl; 174af48b85bSJaegeuk Kim int retval; 175af48b85bSJaegeuk Kim 176af48b85bSJaegeuk Kim if (!test_opt(sbi, POSIX_ACL)) 177af48b85bSJaegeuk Kim return NULL; 178af48b85bSJaegeuk Kim 179af48b85bSJaegeuk Kim acl = get_cached_acl(inode, type); 180af48b85bSJaegeuk Kim if (acl != ACL_NOT_CACHED) 181af48b85bSJaegeuk Kim return acl; 182af48b85bSJaegeuk Kim 183af48b85bSJaegeuk Kim if (type == ACL_TYPE_ACCESS) 184af48b85bSJaegeuk Kim name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; 185af48b85bSJaegeuk Kim 186af48b85bSJaegeuk Kim retval = f2fs_getxattr(inode, name_index, "", NULL, 0); 187af48b85bSJaegeuk Kim if (retval > 0) { 188af48b85bSJaegeuk Kim value = kmalloc(retval, GFP_KERNEL); 189af48b85bSJaegeuk Kim if (!value) 190af48b85bSJaegeuk Kim return ERR_PTR(-ENOMEM); 191af48b85bSJaegeuk Kim retval = f2fs_getxattr(inode, name_index, "", value, retval); 192af48b85bSJaegeuk Kim } 193af48b85bSJaegeuk Kim 194*c1b75eabSJaegeuk Kim if (retval > 0) 195*c1b75eabSJaegeuk Kim acl = f2fs_acl_from_disk(value, retval); 196*c1b75eabSJaegeuk Kim else if (retval == -ENODATA) 197af48b85bSJaegeuk Kim acl = NULL; 198af48b85bSJaegeuk Kim else 199af48b85bSJaegeuk Kim acl = ERR_PTR(retval); 200af48b85bSJaegeuk Kim kfree(value); 201*c1b75eabSJaegeuk Kim 202af48b85bSJaegeuk Kim if (!IS_ERR(acl)) 203af48b85bSJaegeuk Kim set_cached_acl(inode, type, acl); 204af48b85bSJaegeuk Kim 205af48b85bSJaegeuk Kim return acl; 206af48b85bSJaegeuk Kim } 207af48b85bSJaegeuk Kim 208af48b85bSJaegeuk Kim static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl) 209af48b85bSJaegeuk Kim { 210af48b85bSJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 211af48b85bSJaegeuk Kim struct f2fs_inode_info *fi = F2FS_I(inode); 212af48b85bSJaegeuk Kim int name_index; 213af48b85bSJaegeuk Kim void *value = NULL; 214af48b85bSJaegeuk Kim size_t size = 0; 215af48b85bSJaegeuk Kim int error; 216af48b85bSJaegeuk Kim 217af48b85bSJaegeuk Kim if (!test_opt(sbi, POSIX_ACL)) 218af48b85bSJaegeuk Kim return 0; 219af48b85bSJaegeuk Kim if (S_ISLNK(inode->i_mode)) 220af48b85bSJaegeuk Kim return -EOPNOTSUPP; 221af48b85bSJaegeuk Kim 222af48b85bSJaegeuk Kim switch (type) { 223af48b85bSJaegeuk Kim case ACL_TYPE_ACCESS: 224af48b85bSJaegeuk Kim name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS; 225af48b85bSJaegeuk Kim if (acl) { 226af48b85bSJaegeuk Kim error = posix_acl_equiv_mode(acl, &inode->i_mode); 227af48b85bSJaegeuk Kim if (error < 0) 228af48b85bSJaegeuk Kim return error; 229af48b85bSJaegeuk Kim set_acl_inode(fi, inode->i_mode); 230af48b85bSJaegeuk Kim if (error == 0) 231af48b85bSJaegeuk Kim acl = NULL; 232af48b85bSJaegeuk Kim } 233af48b85bSJaegeuk Kim break; 234af48b85bSJaegeuk Kim 235af48b85bSJaegeuk Kim case ACL_TYPE_DEFAULT: 236af48b85bSJaegeuk Kim name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT; 237af48b85bSJaegeuk Kim if (!S_ISDIR(inode->i_mode)) 238af48b85bSJaegeuk Kim return acl ? -EACCES : 0; 239af48b85bSJaegeuk Kim break; 240af48b85bSJaegeuk Kim 241af48b85bSJaegeuk Kim default: 242af48b85bSJaegeuk Kim return -EINVAL; 243af48b85bSJaegeuk Kim } 244af48b85bSJaegeuk Kim 245af48b85bSJaegeuk Kim if (acl) { 246af48b85bSJaegeuk Kim value = f2fs_acl_to_disk(acl, &size); 247af48b85bSJaegeuk Kim if (IS_ERR(value)) { 248af48b85bSJaegeuk Kim cond_clear_inode_flag(fi, FI_ACL_MODE); 249af48b85bSJaegeuk Kim return (int)PTR_ERR(value); 250af48b85bSJaegeuk Kim } 251af48b85bSJaegeuk Kim } 252af48b85bSJaegeuk Kim 253af48b85bSJaegeuk Kim error = f2fs_setxattr(inode, name_index, "", value, size); 254af48b85bSJaegeuk Kim 255af48b85bSJaegeuk Kim kfree(value); 256af48b85bSJaegeuk Kim if (!error) 257af48b85bSJaegeuk Kim set_cached_acl(inode, type, acl); 258af48b85bSJaegeuk Kim 259af48b85bSJaegeuk Kim cond_clear_inode_flag(fi, FI_ACL_MODE); 260af48b85bSJaegeuk Kim return error; 261af48b85bSJaegeuk Kim } 262af48b85bSJaegeuk Kim 263af48b85bSJaegeuk Kim int f2fs_init_acl(struct inode *inode, struct inode *dir) 264af48b85bSJaegeuk Kim { 265af48b85bSJaegeuk Kim struct posix_acl *acl = NULL; 266af48b85bSJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); 267af48b85bSJaegeuk Kim int error = 0; 268af48b85bSJaegeuk Kim 269af48b85bSJaegeuk Kim if (!S_ISLNK(inode->i_mode)) { 270af48b85bSJaegeuk Kim if (test_opt(sbi, POSIX_ACL)) { 271af48b85bSJaegeuk Kim acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT); 272af48b85bSJaegeuk Kim if (IS_ERR(acl)) 273af48b85bSJaegeuk Kim return PTR_ERR(acl); 274af48b85bSJaegeuk Kim } 275af48b85bSJaegeuk Kim if (!acl) 276af48b85bSJaegeuk Kim inode->i_mode &= ~current_umask(); 277af48b85bSJaegeuk Kim } 278af48b85bSJaegeuk Kim 279af48b85bSJaegeuk Kim if (test_opt(sbi, POSIX_ACL) && acl) { 280af48b85bSJaegeuk Kim 281af48b85bSJaegeuk Kim if (S_ISDIR(inode->i_mode)) { 282af48b85bSJaegeuk Kim error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl); 283af48b85bSJaegeuk Kim if (error) 284af48b85bSJaegeuk Kim goto cleanup; 285af48b85bSJaegeuk Kim } 286af48b85bSJaegeuk Kim error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); 287af48b85bSJaegeuk Kim if (error < 0) 288af48b85bSJaegeuk Kim return error; 289af48b85bSJaegeuk Kim if (error > 0) 290af48b85bSJaegeuk Kim error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); 291af48b85bSJaegeuk Kim } 292af48b85bSJaegeuk Kim cleanup: 293af48b85bSJaegeuk Kim posix_acl_release(acl); 294af48b85bSJaegeuk Kim return error; 295af48b85bSJaegeuk Kim } 296af48b85bSJaegeuk Kim 297af48b85bSJaegeuk Kim int f2fs_acl_chmod(struct inode *inode) 298af48b85bSJaegeuk Kim { 299af48b85bSJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); 300af48b85bSJaegeuk Kim struct posix_acl *acl; 301af48b85bSJaegeuk Kim int error; 302af48b85bSJaegeuk Kim mode_t mode = get_inode_mode(inode); 303af48b85bSJaegeuk Kim 304af48b85bSJaegeuk Kim if (!test_opt(sbi, POSIX_ACL)) 305af48b85bSJaegeuk Kim return 0; 306af48b85bSJaegeuk Kim if (S_ISLNK(mode)) 307af48b85bSJaegeuk Kim return -EOPNOTSUPP; 308af48b85bSJaegeuk Kim 309af48b85bSJaegeuk Kim acl = f2fs_get_acl(inode, ACL_TYPE_ACCESS); 310af48b85bSJaegeuk Kim if (IS_ERR(acl) || !acl) 311af48b85bSJaegeuk Kim return PTR_ERR(acl); 312af48b85bSJaegeuk Kim 313af48b85bSJaegeuk Kim error = posix_acl_chmod(&acl, GFP_KERNEL, mode); 314af48b85bSJaegeuk Kim if (error) 315af48b85bSJaegeuk Kim return error; 316af48b85bSJaegeuk Kim error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl); 317af48b85bSJaegeuk Kim posix_acl_release(acl); 318af48b85bSJaegeuk Kim return error; 319af48b85bSJaegeuk Kim } 320af48b85bSJaegeuk Kim 321af48b85bSJaegeuk Kim static size_t f2fs_xattr_list_acl(struct dentry *dentry, char *list, 322af48b85bSJaegeuk Kim size_t list_size, const char *name, size_t name_len, int type) 323af48b85bSJaegeuk Kim { 324af48b85bSJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); 325af48b85bSJaegeuk Kim const char *xname = POSIX_ACL_XATTR_DEFAULT; 326af48b85bSJaegeuk Kim size_t size; 327af48b85bSJaegeuk Kim 328af48b85bSJaegeuk Kim if (!test_opt(sbi, POSIX_ACL)) 329af48b85bSJaegeuk Kim return 0; 330af48b85bSJaegeuk Kim 331af48b85bSJaegeuk Kim if (type == ACL_TYPE_ACCESS) 332af48b85bSJaegeuk Kim xname = POSIX_ACL_XATTR_ACCESS; 333af48b85bSJaegeuk Kim 334af48b85bSJaegeuk Kim size = strlen(xname) + 1; 335af48b85bSJaegeuk Kim if (list && size <= list_size) 336af48b85bSJaegeuk Kim memcpy(list, xname, size); 337af48b85bSJaegeuk Kim return size; 338af48b85bSJaegeuk Kim } 339af48b85bSJaegeuk Kim 340af48b85bSJaegeuk Kim static int f2fs_xattr_get_acl(struct dentry *dentry, const char *name, 341af48b85bSJaegeuk Kim void *buffer, size_t size, int type) 342af48b85bSJaegeuk Kim { 343af48b85bSJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); 344af48b85bSJaegeuk Kim struct posix_acl *acl; 345af48b85bSJaegeuk Kim int error; 346af48b85bSJaegeuk Kim 347af48b85bSJaegeuk Kim if (strcmp(name, "") != 0) 348af48b85bSJaegeuk Kim return -EINVAL; 349af48b85bSJaegeuk Kim if (!test_opt(sbi, POSIX_ACL)) 350af48b85bSJaegeuk Kim return -EOPNOTSUPP; 351af48b85bSJaegeuk Kim 352af48b85bSJaegeuk Kim acl = f2fs_get_acl(dentry->d_inode, type); 353af48b85bSJaegeuk Kim if (IS_ERR(acl)) 354af48b85bSJaegeuk Kim return PTR_ERR(acl); 355af48b85bSJaegeuk Kim if (!acl) 356af48b85bSJaegeuk Kim return -ENODATA; 357af48b85bSJaegeuk Kim error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); 358af48b85bSJaegeuk Kim posix_acl_release(acl); 359af48b85bSJaegeuk Kim 360af48b85bSJaegeuk Kim return error; 361af48b85bSJaegeuk Kim } 362af48b85bSJaegeuk Kim 363af48b85bSJaegeuk Kim static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name, 364af48b85bSJaegeuk Kim const void *value, size_t size, int flags, int type) 365af48b85bSJaegeuk Kim { 366af48b85bSJaegeuk Kim struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); 367af48b85bSJaegeuk Kim struct inode *inode = dentry->d_inode; 368af48b85bSJaegeuk Kim struct posix_acl *acl = NULL; 369af48b85bSJaegeuk Kim int error; 370af48b85bSJaegeuk Kim 371af48b85bSJaegeuk Kim if (strcmp(name, "") != 0) 372af48b85bSJaegeuk Kim return -EINVAL; 373af48b85bSJaegeuk Kim if (!test_opt(sbi, POSIX_ACL)) 374af48b85bSJaegeuk Kim return -EOPNOTSUPP; 375af48b85bSJaegeuk Kim if (!inode_owner_or_capable(inode)) 376af48b85bSJaegeuk Kim return -EPERM; 377af48b85bSJaegeuk Kim 378af48b85bSJaegeuk Kim if (value) { 379af48b85bSJaegeuk Kim acl = posix_acl_from_xattr(&init_user_ns, value, size); 380af48b85bSJaegeuk Kim if (IS_ERR(acl)) 381af48b85bSJaegeuk Kim return PTR_ERR(acl); 382af48b85bSJaegeuk Kim if (acl) { 383af48b85bSJaegeuk Kim error = posix_acl_valid(acl); 384af48b85bSJaegeuk Kim if (error) 385af48b85bSJaegeuk Kim goto release_and_out; 386af48b85bSJaegeuk Kim } 387af48b85bSJaegeuk Kim } else { 388af48b85bSJaegeuk Kim acl = NULL; 389af48b85bSJaegeuk Kim } 390af48b85bSJaegeuk Kim 391af48b85bSJaegeuk Kim error = f2fs_set_acl(inode, type, acl); 392af48b85bSJaegeuk Kim 393af48b85bSJaegeuk Kim release_and_out: 394af48b85bSJaegeuk Kim posix_acl_release(acl); 395af48b85bSJaegeuk Kim return error; 396af48b85bSJaegeuk Kim } 397af48b85bSJaegeuk Kim 398af48b85bSJaegeuk Kim const struct xattr_handler f2fs_xattr_acl_default_handler = { 399af48b85bSJaegeuk Kim .prefix = POSIX_ACL_XATTR_DEFAULT, 400af48b85bSJaegeuk Kim .flags = ACL_TYPE_DEFAULT, 401af48b85bSJaegeuk Kim .list = f2fs_xattr_list_acl, 402af48b85bSJaegeuk Kim .get = f2fs_xattr_get_acl, 403af48b85bSJaegeuk Kim .set = f2fs_xattr_set_acl, 404af48b85bSJaegeuk Kim }; 405af48b85bSJaegeuk Kim 406af48b85bSJaegeuk Kim const struct xattr_handler f2fs_xattr_acl_access_handler = { 407af48b85bSJaegeuk Kim .prefix = POSIX_ACL_XATTR_ACCESS, 408af48b85bSJaegeuk Kim .flags = ACL_TYPE_ACCESS, 409af48b85bSJaegeuk Kim .list = f2fs_xattr_list_acl, 410af48b85bSJaegeuk Kim .get = f2fs_xattr_get_acl, 411af48b85bSJaegeuk Kim .set = f2fs_xattr_set_acl, 412af48b85bSJaegeuk Kim }; 413