6fdb300727f574972c5c3b99d104956681111efd
[lunaix-os.git] / lunaix-os / kernel / fs / xattr.c
1 #include <klibc/string.h>
2 #include <lunaix/fs.h>
3 #include <lunaix/mm/valloc.h>
4 #include <lunaix/process.h>
5 #include <lunaix/syscall.h>
6 #include <lunaix/syscall_utils.h>
7
8 #define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno)
9
10 struct v_xattr_entry*
11 xattr_new(struct hstr* name)
12 {
13     struct v_xattr_entry* entry = valloc(sizeof(*entry));
14     if (!entry) {
15         return NULL;
16     }
17     *entry =
18       (struct v_xattr_entry){ .name = HHSTR(valloc(VFS_NAME_MAXLEN), 0, 0) };
19
20     hstrcpy(&entry->name, name);
21     return entry;
22 }
23
24 void
25 xattr_free(struct v_xattr_entry* entry)
26 {
27     vfree(entry->name.value);
28     vfree(entry);
29 }
30
31 struct v_xattr_entry*
32 xattr_getcache(struct v_inode* inode, struct hstr* name)
33 {
34     struct v_xattr_entry *pos, *n;
35     llist_for_each(pos, n, &inode->xattrs, entries)
36     {
37         if (HSTR_EQ(&pos->name, name)) {
38             return pos;
39         }
40     }
41
42     return NULL;
43 }
44
45 void
46 xattr_addcache(struct v_inode* inode, struct v_xattr_entry* xattr)
47 {
48     llist_append(&inode->xattrs, &xattr->entries);
49 }
50
51 void
52 xattr_delcache(struct v_inode* inode, struct v_xattr_entry* xattr)
53 {
54     llist_delete(&xattr->entries);
55 }
56
57 int
58 __vfs_getxattr(struct v_inode* inode,
59                struct v_xattr_entry** xentry,
60                const char* name)
61 {
62     if (!inode->ops->getxattr) {
63         return ENOTSUP;
64     }
65
66     int errno = 0;
67     size_t len = strlen(name);
68
69     if (len > VFS_NAME_MAXLEN) {
70         return ERANGE;
71     }
72
73     struct hstr hname = HSTR(name, len);
74
75     hstr_rehash(&hname, HSTR_FULL_HASH);
76
77     struct v_xattr_entry* entry = xattr_getcache(inode, &hname);
78     if (!entry) {
79         if (!(entry = xattr_new(&hname))) {
80             return ENOMEM;
81         }
82     }
83
84     if (!(errno = inode->ops->getxattr(inode, entry))) {
85         *xentry = entry;
86         xattr_addcache(inode, entry);
87     } else {
88         xattr_free(entry);
89     }
90     return errno;
91 }
92
93 int
94 __vfs_setxattr(struct v_inode* inode,
95                const char* name,
96                const void* data,
97                size_t len)
98 {
99     if (!inode->ops->setxattr || !inode->ops->delxattr) {
100         return ENOTSUP;
101     }
102
103     int errno = 0;
104     size_t slen = strlen(name);
105
106     if (slen > VFS_NAME_MAXLEN) {
107         return ERANGE;
108     }
109
110     struct hstr hname = HSTR(name, slen);
111
112     hstr_rehash(&hname, HSTR_FULL_HASH);
113
114     struct v_xattr_entry* entry = xattr_getcache(inode, &hname);
115     if (!entry) {
116         if (!(entry = xattr_new(&hname))) {
117             return ENOMEM;
118         }
119     } else {
120         xattr_delcache(inode, entry);
121     }
122
123     if ((errno = inode->ops->delxattr(inode, entry))) {
124         xattr_free(entry);
125         goto done;
126     }
127
128     entry->value = data;
129     entry->len = len;
130
131     if ((errno = inode->ops->setxattr(inode, entry))) {
132         xattr_free(entry);
133         goto done;
134     }
135
136     xattr_addcache(inode, entry);
137 done:
138     return errno;
139 }
140
141 __DEFINE_LXSYSCALL4(int,
142                     getxattr,
143                     const char*,
144                     path,
145                     const char*,
146                     name,
147                     void*,
148                     value,
149                     size_t,
150                     len)
151 {
152     struct v_dnode* dnode;
153     struct v_xattr_entry* xattr;
154     int errno = 0;
155
156     if ((errno = vfs_walk_proc(path, &dnode, NULL, 0))) {
157         goto done;
158     }
159
160     if ((errno = __vfs_getxattr(dnode->inode, &xattr, name))) {
161         goto done;
162     }
163
164     if (len < xattr->len) {
165         errno = ERANGE;
166         goto done;
167     }
168
169     memcpy(value, xattr->value, len);
170
171 done:
172     return DO_STATUS(errno);
173 }
174
175 __DEFINE_LXSYSCALL4(int,
176                     setxattr,
177                     const char*,
178                     path,
179                     const char*,
180                     name,
181                     void*,
182                     value,
183                     size_t,
184                     len)
185 {
186     struct v_dnode* dnode;
187     struct v_xattr_entry* xattr;
188     int errno = 0;
189
190     if ((errno = vfs_walk_proc(path, &dnode, NULL, 0))) {
191         goto done;
192     }
193
194     if ((errno = __vfs_setxattr(dnode->inode, name, value, len))) {
195         goto done;
196     }
197
198 done:
199     return DO_STATUS(errno);
200 }
201
202 __DEFINE_LXSYSCALL4(int,
203                     fgetxattr,
204                     int,
205                     fd,
206                     const char*,
207                     name,
208                     void*,
209                     value,
210                     size_t,
211                     len)
212 {
213     struct v_fd* fd_s;
214     struct v_xattr_entry* xattr;
215     int errno = 0;
216
217     if ((errno = vfs_getfd(fd, &fd_s))) {
218         goto done;
219     }
220
221     if ((errno = __vfs_getxattr(fd_s->file->inode, &xattr, name))) {
222         goto done;
223     }
224
225     if (len < xattr->len) {
226         errno = ERANGE;
227         goto done;
228     }
229
230     memcpy(value, xattr->value, len);
231
232 done:
233     return DO_STATUS(errno);
234 }
235
236 __DEFINE_LXSYSCALL4(int,
237                     fsetxattr,
238                     int,
239                     fd,
240                     const char*,
241                     name,
242                     void*,
243                     value,
244                     size_t,
245                     len)
246 {
247     struct v_fd* fd_s;
248     struct v_xattr_entry* xattr;
249     int errno = 0;
250
251     if ((errno = vfs_getfd(fd, &fd_s))) {
252         goto done;
253     }
254
255     if ((errno = __vfs_setxattr(fd_s->file->inode, name, value, len))) {
256         goto done;
257     }
258
259 done:
260     return DO_STATUS(errno);
261 }