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