xref: /kernel/linux/linux-5.10/fs/jfs/acl.c (revision 8c2ecf20)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 *   Copyright (C) International Business Machines  Corp., 2002-2004
4 *   Copyright (C) Andreas Gruenbacher, 2001
5 *   Copyright (C) Linus Torvalds, 1991, 1992
6 */
7
8#include <linux/sched.h>
9#include <linux/slab.h>
10#include <linux/fs.h>
11#include <linux/posix_acl_xattr.h>
12#include "jfs_incore.h"
13#include "jfs_txnmgr.h"
14#include "jfs_xattr.h"
15#include "jfs_acl.h"
16
17struct posix_acl *jfs_get_acl(struct inode *inode, int type)
18{
19	struct posix_acl *acl;
20	char *ea_name;
21	int size;
22	char *value = NULL;
23
24	switch(type) {
25		case ACL_TYPE_ACCESS:
26			ea_name = XATTR_NAME_POSIX_ACL_ACCESS;
27			break;
28		case ACL_TYPE_DEFAULT:
29			ea_name = XATTR_NAME_POSIX_ACL_DEFAULT;
30			break;
31		default:
32			return ERR_PTR(-EINVAL);
33	}
34
35	size = __jfs_getxattr(inode, ea_name, NULL, 0);
36
37	if (size > 0) {
38		value = kmalloc(size, GFP_KERNEL);
39		if (!value)
40			return ERR_PTR(-ENOMEM);
41		size = __jfs_getxattr(inode, ea_name, value, size);
42	}
43
44	if (size < 0) {
45		if (size == -ENODATA)
46			acl = NULL;
47		else
48			acl = ERR_PTR(size);
49	} else {
50		acl = posix_acl_from_xattr(&init_user_ns, value, size);
51	}
52	kfree(value);
53	return acl;
54}
55
56static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
57		       struct posix_acl *acl)
58{
59	char *ea_name;
60	int rc;
61	int size = 0;
62	char *value = NULL;
63
64	switch (type) {
65	case ACL_TYPE_ACCESS:
66		ea_name = XATTR_NAME_POSIX_ACL_ACCESS;
67		break;
68	case ACL_TYPE_DEFAULT:
69		ea_name = XATTR_NAME_POSIX_ACL_DEFAULT;
70		break;
71	default:
72		return -EINVAL;
73	}
74
75	if (acl) {
76		size = posix_acl_xattr_size(acl->a_count);
77		value = kmalloc(size, GFP_KERNEL);
78		if (!value)
79			return -ENOMEM;
80		rc = posix_acl_to_xattr(&init_user_ns, acl, value, size);
81		if (rc < 0)
82			goto out;
83	}
84	rc = __jfs_setxattr(tid, inode, ea_name, value, size, 0);
85out:
86	kfree(value);
87
88	if (!rc)
89		set_cached_acl(inode, type, acl);
90
91	return rc;
92}
93
94int jfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
95{
96	int rc;
97	tid_t tid;
98	int update_mode = 0;
99	umode_t mode = inode->i_mode;
100
101	tid = txBegin(inode->i_sb, 0);
102	mutex_lock(&JFS_IP(inode)->commit_mutex);
103	if (type == ACL_TYPE_ACCESS && acl) {
104		rc = posix_acl_update_mode(inode, &mode, &acl);
105		if (rc)
106			goto end_tx;
107		if (mode != inode->i_mode)
108			update_mode = 1;
109	}
110	rc = __jfs_set_acl(tid, inode, type, acl);
111	if (!rc) {
112		if (update_mode) {
113			inode->i_mode = mode;
114			inode->i_ctime = current_time(inode);
115			mark_inode_dirty(inode);
116		}
117		rc = txCommit(tid, 1, &inode, 0);
118	}
119end_tx:
120	txEnd(tid);
121	mutex_unlock(&JFS_IP(inode)->commit_mutex);
122	return rc;
123}
124
125int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
126{
127	struct posix_acl *default_acl, *acl;
128	int rc = 0;
129
130	rc = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
131	if (rc)
132		return rc;
133
134	if (default_acl) {
135		rc = __jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, default_acl);
136		posix_acl_release(default_acl);
137	} else {
138		inode->i_default_acl = NULL;
139	}
140
141	if (acl) {
142		if (!rc)
143			rc = __jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl);
144		posix_acl_release(acl);
145	} else {
146		inode->i_acl = NULL;
147	}
148
149	JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
150			       inode->i_mode;
151
152	return rc;
153}
154