From: Andreas Gruenbacher <agrue...@redhat.com>

A file can have "no acl" in the sense that only the file mode permission
bits determine access.  In that case, the getxattr system call fails with
errno == ENODATA (No such attribute).

Over the NFSv4 protocol, a file always has an acl, and we convert the file
mode permission bits into an equivalent acl with richacl_from_mode.  Such
"trivial" acls can be converted back to a file mode with
richacl_equiv_mode.

Signed-off-by: Andreas Gruenbacher <agrue...@redhat.com>
Reviewed-by: J. Bruce Fields <bfie...@redhat.com>
---
 fs/richacl_compat.c     | 88 +++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/richacl.h |  1 +
 2 files changed, 89 insertions(+)

diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index c99274f..e513958 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -827,3 +827,91 @@ richacl_apply_masks(struct richacl **acl, kuid_t owner)
        return 0;
 }
 EXPORT_SYMBOL_GPL(richacl_apply_masks);
+
+/**
+ * richacl_from_mode  -  create an acl which corresponds to @mode
+ *
+ * The resulting acl doesn't have the RICHACL_MASKED flag set.
+ *
+ * @mode:      file mode including the file type
+ */
+struct richacl *
+richacl_from_mode(umode_t mode)
+{
+       unsigned int owner_mask = richacl_mode_to_mask(mode >> 6);
+       unsigned int group_mask = richacl_mode_to_mask(mode >> 3);
+       unsigned int other_mask = richacl_mode_to_mask(mode);
+       unsigned int denied;
+       unsigned int entries = 0;
+       struct richacl *acl;
+       struct richace *ace;
+
+       /* RICHACE_DELETE_CHILD is meaningless for non-directories. */
+       if (!S_ISDIR(mode)) {
+               owner_mask &= ~RICHACE_DELETE_CHILD;
+               group_mask &= ~RICHACE_DELETE_CHILD;
+               other_mask &= ~RICHACE_DELETE_CHILD;
+       }
+
+       denied = ~owner_mask & (group_mask | other_mask);
+       if (denied)
+               entries++;  /* owner@ deny entry needed */
+       if (owner_mask & ~(group_mask & other_mask))
+               entries++;  /* owner@ allow entry needed */
+       denied = ~group_mask & other_mask;
+       if (denied)
+               entries++;  /* group@ deny entry needed */
+       if (group_mask & ~other_mask)
+               entries++;  /* group@ allow entry needed */
+       if (other_mask)
+               entries++;  /* everyone@ allow entry needed */
+
+       acl = richacl_alloc(entries, GFP_KERNEL);
+       if (!acl)
+               return NULL;
+       acl->a_owner_mask = owner_mask;
+       acl->a_group_mask = group_mask;
+       acl->a_other_mask = other_mask;
+       ace = acl->a_entries;
+
+       denied = ~owner_mask & (group_mask | other_mask);
+       if (denied) {
+               ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE;
+               ace->e_flags = RICHACE_SPECIAL_WHO;
+               ace->e_mask = denied;
+               ace->e_id.special = RICHACE_OWNER_SPECIAL_ID;
+               ace++;
+       }
+       if (owner_mask & ~(group_mask & other_mask)) {
+               ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+               ace->e_flags = RICHACE_SPECIAL_WHO;
+               ace->e_mask = owner_mask;
+               ace->e_id.special = RICHACE_OWNER_SPECIAL_ID;
+               ace++;
+       }
+       denied = ~group_mask & other_mask;
+       if (denied) {
+               ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE;
+               ace->e_flags = RICHACE_SPECIAL_WHO;
+               ace->e_mask = denied;
+               ace->e_id.special = RICHACE_GROUP_SPECIAL_ID;
+               ace++;
+       }
+       if (group_mask & ~other_mask) {
+               ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+               ace->e_flags = RICHACE_SPECIAL_WHO;
+               ace->e_mask = group_mask;
+               ace->e_id.special = RICHACE_GROUP_SPECIAL_ID;
+               ace++;
+       }
+       if (other_mask) {
+               ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+               ace->e_flags = RICHACE_SPECIAL_WHO;
+               ace->e_mask = other_mask;
+               ace->e_id.special = RICHACE_EVERYONE_SPECIAL_ID;
+               ace++;
+       }
+
+       return acl;
+}
+EXPORT_SYMBOL_GPL(richacl_from_mode);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 77b6779..708926f 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -335,5 +335,6 @@ extern struct richacl *richacl_create(umode_t *, struct 
inode *);
 
 /* richacl_compat.c */
 extern int richacl_apply_masks(struct richacl **, kuid_t);
+extern struct richacl *richacl_from_mode(umode_t);
 
 #endif /* __RICHACL_H */
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to