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