1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * linux/fs/hfs/attr.c |
4 | * |
5 | * (C) 2003 Ardis Technologies <roman@ardistech.com> |
6 | * |
7 | * Export hfs data via xattr |
8 | */ |
9 | |
10 | |
11 | #include <linux/fs.h> |
12 | #include <linux/xattr.h> |
13 | |
14 | #include "hfs_fs.h" |
15 | #include "btree.h" |
16 | |
17 | enum hfs_xattr_type { |
18 | HFS_TYPE, |
19 | HFS_CREATOR, |
20 | }; |
21 | |
22 | static int __hfs_setxattr(struct inode *inode, enum hfs_xattr_type type, |
23 | const void *value, size_t size, int flags) |
24 | { |
25 | struct hfs_find_data fd; |
26 | hfs_cat_rec rec; |
27 | struct hfs_cat_file *file; |
28 | int res; |
29 | |
30 | if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode)) |
31 | return -EOPNOTSUPP; |
32 | |
33 | res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd); |
34 | if (res) |
35 | return res; |
36 | fd.search_key->cat = HFS_I(inode)->cat_key; |
37 | res = hfs_brec_find(&fd); |
38 | if (res) |
39 | goto out; |
40 | hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, |
41 | sizeof(struct hfs_cat_file)); |
42 | file = &rec.file; |
43 | |
44 | switch (type) { |
45 | case HFS_TYPE: |
46 | if (size == 4) |
47 | memcpy(&file->UsrWds.fdType, value, 4); |
48 | else |
49 | res = -ERANGE; |
50 | break; |
51 | |
52 | case HFS_CREATOR: |
53 | if (size == 4) |
54 | memcpy(&file->UsrWds.fdCreator, value, 4); |
55 | else |
56 | res = -ERANGE; |
57 | break; |
58 | } |
59 | |
60 | if (!res) |
61 | hfs_bnode_write(fd.bnode, &rec, fd.entryoffset, |
62 | sizeof(struct hfs_cat_file)); |
63 | out: |
64 | hfs_find_exit(&fd); |
65 | return res; |
66 | } |
67 | |
68 | static ssize_t __hfs_getxattr(struct inode *inode, enum hfs_xattr_type type, |
69 | void *value, size_t size) |
70 | { |
71 | struct hfs_find_data fd; |
72 | hfs_cat_rec rec; |
73 | struct hfs_cat_file *file; |
74 | ssize_t res = 0; |
75 | |
76 | if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode)) |
77 | return -EOPNOTSUPP; |
78 | |
79 | if (size) { |
80 | res = hfs_find_init(HFS_SB(inode->i_sb)->cat_tree, &fd); |
81 | if (res) |
82 | return res; |
83 | fd.search_key->cat = HFS_I(inode)->cat_key; |
84 | res = hfs_brec_find(&fd); |
85 | if (res) |
86 | goto out; |
87 | hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, |
88 | sizeof(struct hfs_cat_file)); |
89 | } |
90 | file = &rec.file; |
91 | |
92 | switch (type) { |
93 | case HFS_TYPE: |
94 | if (size >= 4) { |
95 | memcpy(value, &file->UsrWds.fdType, 4); |
96 | res = 4; |
97 | } else |
98 | res = size ? -ERANGE : 4; |
99 | break; |
100 | |
101 | case HFS_CREATOR: |
102 | if (size >= 4) { |
103 | memcpy(value, &file->UsrWds.fdCreator, 4); |
104 | res = 4; |
105 | } else |
106 | res = size ? -ERANGE : 4; |
107 | break; |
108 | } |
109 | |
110 | out: |
111 | if (size) |
112 | hfs_find_exit(&fd); |
113 | return res; |
114 | } |
115 | |
116 | static int hfs_xattr_get(const struct xattr_handler *handler, |
117 | struct dentry *unused, struct inode *inode, |
118 | const char *name, void *value, size_t size) |
119 | { |
120 | return __hfs_getxattr(inode, type: handler->flags, value, size); |
121 | } |
122 | |
123 | static int hfs_xattr_set(const struct xattr_handler *handler, |
124 | struct mnt_idmap *idmap, |
125 | struct dentry *unused, struct inode *inode, |
126 | const char *name, const void *value, size_t size, |
127 | int flags) |
128 | { |
129 | if (!value) |
130 | return -EOPNOTSUPP; |
131 | |
132 | return __hfs_setxattr(inode, type: handler->flags, value, size, flags); |
133 | } |
134 | |
135 | static const struct xattr_handler hfs_creator_handler = { |
136 | .name = "hfs.creator" , |
137 | .flags = HFS_CREATOR, |
138 | .get = hfs_xattr_get, |
139 | .set = hfs_xattr_set, |
140 | }; |
141 | |
142 | static const struct xattr_handler hfs_type_handler = { |
143 | .name = "hfs.type" , |
144 | .flags = HFS_TYPE, |
145 | .get = hfs_xattr_get, |
146 | .set = hfs_xattr_set, |
147 | }; |
148 | |
149 | const struct xattr_handler * const hfs_xattr_handlers[] = { |
150 | &hfs_creator_handler, |
151 | &hfs_type_handler, |
152 | NULL |
153 | }; |
154 | |