1652ecc20SKaiGai Kohei /* 2652ecc20SKaiGai Kohei * JFFS2 -- Journalling Flash File System, Version 2. 3aa98d7cfSKaiGai Kohei * 4c00c310eSDavid Woodhouse * Copyright © 2006 NEC Corporation 5aa98d7cfSKaiGai Kohei * 6652ecc20SKaiGai Kohei * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> 7652ecc20SKaiGai Kohei * 8652ecc20SKaiGai Kohei * For licensing information, see the file 'LICENCE' in this directory. 9652ecc20SKaiGai Kohei * 10652ecc20SKaiGai Kohei */ 11c00c310eSDavid Woodhouse 125a528957SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 135a528957SJoe Perches 14aa98d7cfSKaiGai Kohei #include <linux/kernel.h> 15aa98d7cfSKaiGai Kohei #include <linux/slab.h> 16aa98d7cfSKaiGai Kohei #include <linux/fs.h> 17914e2637SAl Viro #include <linux/sched.h> 18aa98d7cfSKaiGai Kohei #include <linux/time.h> 19aa98d7cfSKaiGai Kohei #include <linux/crc32.h> 20aa98d7cfSKaiGai Kohei #include <linux/jffs2.h> 21aa98d7cfSKaiGai Kohei #include <linux/xattr.h> 22aa98d7cfSKaiGai Kohei #include <linux/posix_acl_xattr.h> 23aa98d7cfSKaiGai Kohei #include <linux/mtd/mtd.h> 24aa98d7cfSKaiGai Kohei #include "nodelist.h" 25aa98d7cfSKaiGai Kohei 26aa98d7cfSKaiGai Kohei static size_t jffs2_acl_size(int count) 27aa98d7cfSKaiGai Kohei { 28aa98d7cfSKaiGai Kohei if (count <= 4) { 29de1f72faSKaiGai Kohei return sizeof(struct jffs2_acl_header) 30de1f72faSKaiGai Kohei + count * sizeof(struct jffs2_acl_entry_short); 31aa98d7cfSKaiGai Kohei } else { 32de1f72faSKaiGai Kohei return sizeof(struct jffs2_acl_header) 33de1f72faSKaiGai Kohei + 4 * sizeof(struct jffs2_acl_entry_short) 34de1f72faSKaiGai Kohei + (count - 4) * sizeof(struct jffs2_acl_entry); 35aa98d7cfSKaiGai Kohei } 36aa98d7cfSKaiGai Kohei } 37aa98d7cfSKaiGai Kohei 38aa98d7cfSKaiGai Kohei static int jffs2_acl_count(size_t size) 39aa98d7cfSKaiGai Kohei { 40aa98d7cfSKaiGai Kohei size_t s; 41aa98d7cfSKaiGai Kohei 42de1f72faSKaiGai Kohei size -= sizeof(struct jffs2_acl_header); 43fc371a25SRoel Kluin if (size < 4 * sizeof(struct jffs2_acl_entry_short)) { 44de1f72faSKaiGai Kohei if (size % sizeof(struct jffs2_acl_entry_short)) 45aa98d7cfSKaiGai Kohei return -1; 46de1f72faSKaiGai Kohei return size / sizeof(struct jffs2_acl_entry_short); 47aa98d7cfSKaiGai Kohei } else { 48fc371a25SRoel Kluin s = size - 4 * sizeof(struct jffs2_acl_entry_short); 49de1f72faSKaiGai Kohei if (s % sizeof(struct jffs2_acl_entry)) 50aa98d7cfSKaiGai Kohei return -1; 51de1f72faSKaiGai Kohei return s / sizeof(struct jffs2_acl_entry) + 4; 52aa98d7cfSKaiGai Kohei } 53aa98d7cfSKaiGai Kohei } 54aa98d7cfSKaiGai Kohei 55dea80134SKaiGai Kohei static struct posix_acl *jffs2_acl_from_medium(void *value, size_t size) 56aa98d7cfSKaiGai Kohei { 57dea80134SKaiGai Kohei void *end = value + size; 58dea80134SKaiGai Kohei struct jffs2_acl_header *header = value; 59dea80134SKaiGai Kohei struct jffs2_acl_entry *entry; 60aa98d7cfSKaiGai Kohei struct posix_acl *acl; 61aa98d7cfSKaiGai Kohei uint32_t ver; 62aa98d7cfSKaiGai Kohei int i, count; 63aa98d7cfSKaiGai Kohei 64aa98d7cfSKaiGai Kohei if (!value) 65aa98d7cfSKaiGai Kohei return NULL; 66de1f72faSKaiGai Kohei if (size < sizeof(struct jffs2_acl_header)) 67aa98d7cfSKaiGai Kohei return ERR_PTR(-EINVAL); 68dea80134SKaiGai Kohei ver = je32_to_cpu(header->a_version); 69aa98d7cfSKaiGai Kohei if (ver != JFFS2_ACL_VERSION) { 70aa98d7cfSKaiGai Kohei JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver); 71aa98d7cfSKaiGai Kohei return ERR_PTR(-EINVAL); 72aa98d7cfSKaiGai Kohei } 73aa98d7cfSKaiGai Kohei 74dea80134SKaiGai Kohei value += sizeof(struct jffs2_acl_header); 75aa98d7cfSKaiGai Kohei count = jffs2_acl_count(size); 76aa98d7cfSKaiGai Kohei if (count < 0) 77aa98d7cfSKaiGai Kohei return ERR_PTR(-EINVAL); 78aa98d7cfSKaiGai Kohei if (count == 0) 79aa98d7cfSKaiGai Kohei return NULL; 80aa98d7cfSKaiGai Kohei 81aa98d7cfSKaiGai Kohei acl = posix_acl_alloc(count, GFP_KERNEL); 82aa98d7cfSKaiGai Kohei if (!acl) 83aa98d7cfSKaiGai Kohei return ERR_PTR(-ENOMEM); 84aa98d7cfSKaiGai Kohei 85aa98d7cfSKaiGai Kohei for (i=0; i < count; i++) { 86dea80134SKaiGai Kohei entry = value; 87dea80134SKaiGai Kohei if (value + sizeof(struct jffs2_acl_entry_short) > end) 88aa98d7cfSKaiGai Kohei goto fail; 89aa98d7cfSKaiGai Kohei acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag); 90aa98d7cfSKaiGai Kohei acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm); 91aa98d7cfSKaiGai Kohei switch (acl->a_entries[i].e_tag) { 92aa98d7cfSKaiGai Kohei case ACL_USER_OBJ: 93aa98d7cfSKaiGai Kohei case ACL_GROUP_OBJ: 94aa98d7cfSKaiGai Kohei case ACL_MASK: 95aa98d7cfSKaiGai Kohei case ACL_OTHER: 96dea80134SKaiGai Kohei value += sizeof(struct jffs2_acl_entry_short); 97aa98d7cfSKaiGai Kohei break; 98aa98d7cfSKaiGai Kohei 99aa98d7cfSKaiGai Kohei case ACL_USER: 1000cfe53d3SEric W. Biederman value += sizeof(struct jffs2_acl_entry); 1010cfe53d3SEric W. Biederman if (value > end) 1020cfe53d3SEric W. Biederman goto fail; 1030cfe53d3SEric W. Biederman acl->a_entries[i].e_uid = 1040cfe53d3SEric W. Biederman make_kuid(&init_user_ns, 1050cfe53d3SEric W. Biederman je32_to_cpu(entry->e_id)); 1060cfe53d3SEric W. Biederman break; 107aa98d7cfSKaiGai Kohei case ACL_GROUP: 108dea80134SKaiGai Kohei value += sizeof(struct jffs2_acl_entry); 109dea80134SKaiGai Kohei if (value > end) 110aa98d7cfSKaiGai Kohei goto fail; 1110cfe53d3SEric W. Biederman acl->a_entries[i].e_gid = 1120cfe53d3SEric W. Biederman make_kgid(&init_user_ns, 1130cfe53d3SEric W. Biederman je32_to_cpu(entry->e_id)); 114aa98d7cfSKaiGai Kohei break; 115aa98d7cfSKaiGai Kohei 116aa98d7cfSKaiGai Kohei default: 117aa98d7cfSKaiGai Kohei goto fail; 118aa98d7cfSKaiGai Kohei } 119aa98d7cfSKaiGai Kohei } 120aa98d7cfSKaiGai Kohei if (value != end) 121aa98d7cfSKaiGai Kohei goto fail; 122aa98d7cfSKaiGai Kohei return acl; 123aa98d7cfSKaiGai Kohei fail: 124aa98d7cfSKaiGai Kohei posix_acl_release(acl); 125aa98d7cfSKaiGai Kohei return ERR_PTR(-EINVAL); 126aa98d7cfSKaiGai Kohei } 127aa98d7cfSKaiGai Kohei 128aa98d7cfSKaiGai Kohei static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size) 129aa98d7cfSKaiGai Kohei { 130dea80134SKaiGai Kohei struct jffs2_acl_header *header; 131dea80134SKaiGai Kohei struct jffs2_acl_entry *entry; 132dea80134SKaiGai Kohei void *e; 133aa98d7cfSKaiGai Kohei size_t i; 134aa98d7cfSKaiGai Kohei 135aa98d7cfSKaiGai Kohei *size = jffs2_acl_size(acl->a_count); 136dea80134SKaiGai Kohei header = kmalloc(sizeof(*header) + acl->a_count * sizeof(*entry), GFP_KERNEL); 137dea80134SKaiGai Kohei if (!header) 138aa98d7cfSKaiGai Kohei return ERR_PTR(-ENOMEM); 139dea80134SKaiGai Kohei header->a_version = cpu_to_je32(JFFS2_ACL_VERSION); 140dea80134SKaiGai Kohei e = header + 1; 141aa98d7cfSKaiGai Kohei for (i=0; i < acl->a_count; i++) { 1420cfe53d3SEric W. Biederman const struct posix_acl_entry *acl_e = &acl->a_entries[i]; 143dea80134SKaiGai Kohei entry = e; 1440cfe53d3SEric W. Biederman entry->e_tag = cpu_to_je16(acl_e->e_tag); 1450cfe53d3SEric W. Biederman entry->e_perm = cpu_to_je16(acl_e->e_perm); 1460cfe53d3SEric W. Biederman switch(acl_e->e_tag) { 147aa98d7cfSKaiGai Kohei case ACL_USER: 1480cfe53d3SEric W. Biederman entry->e_id = cpu_to_je32( 1490cfe53d3SEric W. Biederman from_kuid(&init_user_ns, acl_e->e_uid)); 1500cfe53d3SEric W. Biederman e += sizeof(struct jffs2_acl_entry); 1510cfe53d3SEric W. Biederman break; 152aa98d7cfSKaiGai Kohei case ACL_GROUP: 1530cfe53d3SEric W. Biederman entry->e_id = cpu_to_je32( 1540cfe53d3SEric W. Biederman from_kgid(&init_user_ns, acl_e->e_gid)); 155de1f72faSKaiGai Kohei e += sizeof(struct jffs2_acl_entry); 156aa98d7cfSKaiGai Kohei break; 157aa98d7cfSKaiGai Kohei 158aa98d7cfSKaiGai Kohei case ACL_USER_OBJ: 159aa98d7cfSKaiGai Kohei case ACL_GROUP_OBJ: 160aa98d7cfSKaiGai Kohei case ACL_MASK: 161aa98d7cfSKaiGai Kohei case ACL_OTHER: 162de1f72faSKaiGai Kohei e += sizeof(struct jffs2_acl_entry_short); 163aa98d7cfSKaiGai Kohei break; 164aa98d7cfSKaiGai Kohei 165aa98d7cfSKaiGai Kohei default: 166aa98d7cfSKaiGai Kohei goto fail; 167aa98d7cfSKaiGai Kohei } 168aa98d7cfSKaiGai Kohei } 169dea80134SKaiGai Kohei return header; 170aa98d7cfSKaiGai Kohei fail: 171dea80134SKaiGai Kohei kfree(header); 172aa98d7cfSKaiGai Kohei return ERR_PTR(-EINVAL); 173aa98d7cfSKaiGai Kohei } 174aa98d7cfSKaiGai Kohei 1754e34e719SChristoph Hellwig struct posix_acl *jffs2_get_acl(struct inode *inode, int type) 176aa98d7cfSKaiGai Kohei { 177aa98d7cfSKaiGai Kohei struct posix_acl *acl; 178aa98d7cfSKaiGai Kohei char *value = NULL; 179aa98d7cfSKaiGai Kohei int rc, xprefix; 180aa98d7cfSKaiGai Kohei 181073aaa1bSAl Viro acl = get_cached_acl(inode, type); 182290c263bSAl Viro if (acl != ACL_NOT_CACHED) 183aa98d7cfSKaiGai Kohei return acl; 184073aaa1bSAl Viro 185073aaa1bSAl Viro switch (type) { 186073aaa1bSAl Viro case ACL_TYPE_ACCESS: 187aa98d7cfSKaiGai Kohei xprefix = JFFS2_XPREFIX_ACL_ACCESS; 188aa98d7cfSKaiGai Kohei break; 189aa98d7cfSKaiGai Kohei case ACL_TYPE_DEFAULT: 190aa98d7cfSKaiGai Kohei xprefix = JFFS2_XPREFIX_ACL_DEFAULT; 191aa98d7cfSKaiGai Kohei break; 192aa98d7cfSKaiGai Kohei default: 193073aaa1bSAl Viro BUG(); 194aa98d7cfSKaiGai Kohei } 195aa98d7cfSKaiGai Kohei rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0); 196aa98d7cfSKaiGai Kohei if (rc > 0) { 197aa98d7cfSKaiGai Kohei value = kmalloc(rc, GFP_KERNEL); 198aa98d7cfSKaiGai Kohei if (!value) 199aa98d7cfSKaiGai Kohei return ERR_PTR(-ENOMEM); 200aa98d7cfSKaiGai Kohei rc = do_jffs2_getxattr(inode, xprefix, "", value, rc); 201aa98d7cfSKaiGai Kohei } 202aa98d7cfSKaiGai Kohei if (rc > 0) { 203aa98d7cfSKaiGai Kohei acl = jffs2_acl_from_medium(value, rc); 204aa98d7cfSKaiGai Kohei } else if (rc == -ENODATA || rc == -ENOSYS) { 205aa98d7cfSKaiGai Kohei acl = NULL; 206aa98d7cfSKaiGai Kohei } else { 207aa98d7cfSKaiGai Kohei acl = ERR_PTR(rc); 208aa98d7cfSKaiGai Kohei } 209aa98d7cfSKaiGai Kohei if (value) 210aa98d7cfSKaiGai Kohei kfree(value); 211073aaa1bSAl Viro if (!IS_ERR(acl)) 212073aaa1bSAl Viro set_cached_acl(inode, type, acl); 213aa98d7cfSKaiGai Kohei return acl; 214aa98d7cfSKaiGai Kohei } 215aa98d7cfSKaiGai Kohei 216cfc8dc6fSKaiGai Kohei static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *acl) 217cfc8dc6fSKaiGai Kohei { 218cfc8dc6fSKaiGai Kohei char *value = NULL; 219cfc8dc6fSKaiGai Kohei size_t size = 0; 220cfc8dc6fSKaiGai Kohei int rc; 221cfc8dc6fSKaiGai Kohei 222cfc8dc6fSKaiGai Kohei if (acl) { 223cfc8dc6fSKaiGai Kohei value = jffs2_acl_to_medium(acl, &size); 224cfc8dc6fSKaiGai Kohei if (IS_ERR(value)) 225cfc8dc6fSKaiGai Kohei return PTR_ERR(value); 226cfc8dc6fSKaiGai Kohei } 227cfc8dc6fSKaiGai Kohei rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0); 228cfc8dc6fSKaiGai Kohei if (!value && rc == -ENODATA) 229cfc8dc6fSKaiGai Kohei rc = 0; 230cfc8dc6fSKaiGai Kohei kfree(value); 231cfc8dc6fSKaiGai Kohei 232cfc8dc6fSKaiGai Kohei return rc; 233cfc8dc6fSKaiGai Kohei } 234cfc8dc6fSKaiGai Kohei 235aa98d7cfSKaiGai Kohei static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) 236aa98d7cfSKaiGai Kohei { 237aa98d7cfSKaiGai Kohei int rc, xprefix; 238aa98d7cfSKaiGai Kohei 239aa98d7cfSKaiGai Kohei if (S_ISLNK(inode->i_mode)) 240aa98d7cfSKaiGai Kohei return -EOPNOTSUPP; 241aa98d7cfSKaiGai Kohei 242aa98d7cfSKaiGai Kohei switch (type) { 243aa98d7cfSKaiGai Kohei case ACL_TYPE_ACCESS: 244aa98d7cfSKaiGai Kohei xprefix = JFFS2_XPREFIX_ACL_ACCESS; 245aa98d7cfSKaiGai Kohei if (acl) { 246d6952123SAl Viro umode_t mode = inode->i_mode; 247aa98d7cfSKaiGai Kohei rc = posix_acl_equiv_mode(acl, &mode); 248aa98d7cfSKaiGai Kohei if (rc < 0) 249aa98d7cfSKaiGai Kohei return rc; 250aa98d7cfSKaiGai Kohei if (inode->i_mode != mode) { 2519ed437c5SDavid Woodhouse struct iattr attr; 2529ed437c5SDavid Woodhouse 2531c24d06fSJan Kara attr.ia_valid = ATTR_MODE | ATTR_CTIME; 2549ed437c5SDavid Woodhouse attr.ia_mode = mode; 2551c24d06fSJan Kara attr.ia_ctime = CURRENT_TIME_SEC; 2569ed437c5SDavid Woodhouse rc = jffs2_do_setattr(inode, &attr); 2579ed437c5SDavid Woodhouse if (rc < 0) 2589ed437c5SDavid Woodhouse return rc; 259aa98d7cfSKaiGai Kohei } 260aa98d7cfSKaiGai Kohei if (rc == 0) 261aa98d7cfSKaiGai Kohei acl = NULL; 262aa98d7cfSKaiGai Kohei } 263aa98d7cfSKaiGai Kohei break; 264aa98d7cfSKaiGai Kohei case ACL_TYPE_DEFAULT: 265aa98d7cfSKaiGai Kohei xprefix = JFFS2_XPREFIX_ACL_DEFAULT; 266aa98d7cfSKaiGai Kohei if (!S_ISDIR(inode->i_mode)) 267aa98d7cfSKaiGai Kohei return acl ? -EACCES : 0; 268aa98d7cfSKaiGai Kohei break; 269aa98d7cfSKaiGai Kohei default: 270aa98d7cfSKaiGai Kohei return -EINVAL; 271aa98d7cfSKaiGai Kohei } 272cfc8dc6fSKaiGai Kohei rc = __jffs2_set_acl(inode, xprefix, acl); 273073aaa1bSAl Viro if (!rc) 274073aaa1bSAl Viro set_cached_acl(inode, type, acl); 275aa98d7cfSKaiGai Kohei return rc; 276aa98d7cfSKaiGai Kohei } 277aa98d7cfSKaiGai Kohei 278d3fb6120SAl Viro int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode) 279aa98d7cfSKaiGai Kohei { 280826cae2fSAl Viro struct posix_acl *acl; 281cfc8dc6fSKaiGai Kohei int rc; 282aa98d7cfSKaiGai Kohei 28372c04902SAl Viro cache_no_acl(inode); 2849ed437c5SDavid Woodhouse 285cfc8dc6fSKaiGai Kohei if (S_ISLNK(*i_mode)) 286cfc8dc6fSKaiGai Kohei return 0; /* Symlink always has no-ACL */ 287cfc8dc6fSKaiGai Kohei 288cfc8dc6fSKaiGai Kohei acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT); 289cfc8dc6fSKaiGai Kohei if (IS_ERR(acl)) 290cfc8dc6fSKaiGai Kohei return PTR_ERR(acl); 291cfc8dc6fSKaiGai Kohei 292cfc8dc6fSKaiGai Kohei if (!acl) { 293ce3b0f8dSAl Viro *i_mode &= ~current_umask(); 294cfc8dc6fSKaiGai Kohei } else { 295cfc8dc6fSKaiGai Kohei if (S_ISDIR(*i_mode)) 296073aaa1bSAl Viro set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); 297cfc8dc6fSKaiGai Kohei 298826cae2fSAl Viro rc = posix_acl_create(&acl, GFP_KERNEL, i_mode); 299826cae2fSAl Viro if (rc < 0) 300cfc8dc6fSKaiGai Kohei return rc; 301aa98d7cfSKaiGai Kohei if (rc > 0) 302826cae2fSAl Viro set_cached_acl(inode, ACL_TYPE_ACCESS, acl); 303cfc8dc6fSKaiGai Kohei 304826cae2fSAl Viro posix_acl_release(acl); 305aa98d7cfSKaiGai Kohei } 306cfc8dc6fSKaiGai Kohei return 0; 307cfc8dc6fSKaiGai Kohei } 308cfc8dc6fSKaiGai Kohei 309cfc8dc6fSKaiGai Kohei int jffs2_init_acl_post(struct inode *inode) 310cfc8dc6fSKaiGai Kohei { 311cfc8dc6fSKaiGai Kohei int rc; 312cfc8dc6fSKaiGai Kohei 313290c263bSAl Viro if (inode->i_default_acl) { 314290c263bSAl Viro rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, inode->i_default_acl); 315cfc8dc6fSKaiGai Kohei if (rc) 316cfc8dc6fSKaiGai Kohei return rc; 317cfc8dc6fSKaiGai Kohei } 318cfc8dc6fSKaiGai Kohei 319290c263bSAl Viro if (inode->i_acl) { 320290c263bSAl Viro rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, inode->i_acl); 321cfc8dc6fSKaiGai Kohei if (rc) 322cfc8dc6fSKaiGai Kohei return rc; 323cfc8dc6fSKaiGai Kohei } 324cfc8dc6fSKaiGai Kohei 3258d6ea587SDavid Woodhouse return 0; 326aa98d7cfSKaiGai Kohei } 327aa98d7cfSKaiGai Kohei 328aa98d7cfSKaiGai Kohei int jffs2_acl_chmod(struct inode *inode) 329aa98d7cfSKaiGai Kohei { 330bc26ab5fSAl Viro struct posix_acl *acl; 331aa98d7cfSKaiGai Kohei int rc; 332aa98d7cfSKaiGai Kohei 333aa98d7cfSKaiGai Kohei if (S_ISLNK(inode->i_mode)) 334aa98d7cfSKaiGai Kohei return -EOPNOTSUPP; 335aa98d7cfSKaiGai Kohei acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); 336aa98d7cfSKaiGai Kohei if (IS_ERR(acl) || !acl) 337aa98d7cfSKaiGai Kohei return PTR_ERR(acl); 338bc26ab5fSAl Viro rc = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); 339bc26ab5fSAl Viro if (rc) 340bc26ab5fSAl Viro return rc; 341bc26ab5fSAl Viro rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, acl); 342aa98d7cfSKaiGai Kohei posix_acl_release(acl); 343aa98d7cfSKaiGai Kohei return rc; 344aa98d7cfSKaiGai Kohei } 345aa98d7cfSKaiGai Kohei 346431547b3SChristoph Hellwig static size_t jffs2_acl_access_listxattr(struct dentry *dentry, char *list, 347431547b3SChristoph Hellwig size_t list_size, const char *name, size_t name_len, int type) 348aa98d7cfSKaiGai Kohei { 349aa98d7cfSKaiGai Kohei const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS); 350aa98d7cfSKaiGai Kohei 351aa98d7cfSKaiGai Kohei if (list && retlen <= list_size) 352aa98d7cfSKaiGai Kohei strcpy(list, POSIX_ACL_XATTR_ACCESS); 353aa98d7cfSKaiGai Kohei return retlen; 354aa98d7cfSKaiGai Kohei } 355aa98d7cfSKaiGai Kohei 356431547b3SChristoph Hellwig static size_t jffs2_acl_default_listxattr(struct dentry *dentry, char *list, 357431547b3SChristoph Hellwig size_t list_size, const char *name, size_t name_len, int type) 358aa98d7cfSKaiGai Kohei { 359aa98d7cfSKaiGai Kohei const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT); 360aa98d7cfSKaiGai Kohei 361aa98d7cfSKaiGai Kohei if (list && retlen <= list_size) 362aa98d7cfSKaiGai Kohei strcpy(list, POSIX_ACL_XATTR_DEFAULT); 363aa98d7cfSKaiGai Kohei return retlen; 364aa98d7cfSKaiGai Kohei } 365aa98d7cfSKaiGai Kohei 366431547b3SChristoph Hellwig static int jffs2_acl_getxattr(struct dentry *dentry, const char *name, 367431547b3SChristoph Hellwig void *buffer, size_t size, int type) 368aa98d7cfSKaiGai Kohei { 369aa98d7cfSKaiGai Kohei struct posix_acl *acl; 370aa98d7cfSKaiGai Kohei int rc; 371aa98d7cfSKaiGai Kohei 372431547b3SChristoph Hellwig if (name[0] != '\0') 373431547b3SChristoph Hellwig return -EINVAL; 374431547b3SChristoph Hellwig 375431547b3SChristoph Hellwig acl = jffs2_get_acl(dentry->d_inode, type); 376aa98d7cfSKaiGai Kohei if (IS_ERR(acl)) 377aa98d7cfSKaiGai Kohei return PTR_ERR(acl); 378aa98d7cfSKaiGai Kohei if (!acl) 379aa98d7cfSKaiGai Kohei return -ENODATA; 3805f3a4a28SEric W. Biederman rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size); 381aa98d7cfSKaiGai Kohei posix_acl_release(acl); 382aa98d7cfSKaiGai Kohei 383aa98d7cfSKaiGai Kohei return rc; 384aa98d7cfSKaiGai Kohei } 385aa98d7cfSKaiGai Kohei 386431547b3SChristoph Hellwig static int jffs2_acl_setxattr(struct dentry *dentry, const char *name, 387431547b3SChristoph Hellwig const void *value, size_t size, int flags, int type) 388aa98d7cfSKaiGai Kohei { 389aa98d7cfSKaiGai Kohei struct posix_acl *acl; 390aa98d7cfSKaiGai Kohei int rc; 391aa98d7cfSKaiGai Kohei 392431547b3SChristoph Hellwig if (name[0] != '\0') 393431547b3SChristoph Hellwig return -EINVAL; 3942e149670SSerge E. Hallyn if (!inode_owner_or_capable(dentry->d_inode)) 395aa98d7cfSKaiGai Kohei return -EPERM; 396aa98d7cfSKaiGai Kohei 397aa98d7cfSKaiGai Kohei if (value) { 3985f3a4a28SEric W. Biederman acl = posix_acl_from_xattr(&init_user_ns, value, size); 399aa98d7cfSKaiGai Kohei if (IS_ERR(acl)) 400aa98d7cfSKaiGai Kohei return PTR_ERR(acl); 401aa98d7cfSKaiGai Kohei if (acl) { 402aa98d7cfSKaiGai Kohei rc = posix_acl_valid(acl); 403aa98d7cfSKaiGai Kohei if (rc) 404aa98d7cfSKaiGai Kohei goto out; 405aa98d7cfSKaiGai Kohei } 406aa98d7cfSKaiGai Kohei } else { 407aa98d7cfSKaiGai Kohei acl = NULL; 408aa98d7cfSKaiGai Kohei } 409431547b3SChristoph Hellwig rc = jffs2_set_acl(dentry->d_inode, type, acl); 410aa98d7cfSKaiGai Kohei out: 411aa98d7cfSKaiGai Kohei posix_acl_release(acl); 412aa98d7cfSKaiGai Kohei return rc; 413aa98d7cfSKaiGai Kohei } 414aa98d7cfSKaiGai Kohei 415365f0cb9SStephen Hemminger const struct xattr_handler jffs2_acl_access_xattr_handler = { 416aa98d7cfSKaiGai Kohei .prefix = POSIX_ACL_XATTR_ACCESS, 417431547b3SChristoph Hellwig .flags = ACL_TYPE_DEFAULT, 418aa98d7cfSKaiGai Kohei .list = jffs2_acl_access_listxattr, 419431547b3SChristoph Hellwig .get = jffs2_acl_getxattr, 420431547b3SChristoph Hellwig .set = jffs2_acl_setxattr, 421aa98d7cfSKaiGai Kohei }; 422aa98d7cfSKaiGai Kohei 423365f0cb9SStephen Hemminger const struct xattr_handler jffs2_acl_default_xattr_handler = { 424aa98d7cfSKaiGai Kohei .prefix = POSIX_ACL_XATTR_DEFAULT, 425431547b3SChristoph Hellwig .flags = ACL_TYPE_DEFAULT, 426aa98d7cfSKaiGai Kohei .list = jffs2_acl_default_listxattr, 427431547b3SChristoph Hellwig .get = jffs2_acl_getxattr, 428431547b3SChristoph Hellwig .set = jffs2_acl_setxattr, 429aa98d7cfSKaiGai Kohei }; 430