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