1
2 #include "fsdriver.h"
3 #include <minix/ds.h>
4 #include <sys/mman.h>
5
6 static int fsdriver_vmcache; /* have we used the VM cache? */
7
8 /*
9 * Process a READSUPER request from VFS.
10 */
11 int
fsdriver_readsuper(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out)12 fsdriver_readsuper(const struct fsdriver * __restrict fdp,
13 const message * __restrict m_in, message * __restrict m_out)
14 {
15 struct fsdriver_node root_node;
16 char label[DS_MAX_KEYLEN];
17 cp_grant_id_t label_grant;
18 size_t label_len;
19 unsigned int flags, res_flags;
20 dev_t dev;
21 int r;
22
23 dev = m_in->m_vfs_fs_readsuper.device;
24 label_grant = m_in->m_vfs_fs_readsuper.grant;
25 label_len = m_in->m_vfs_fs_readsuper.path_len;
26 flags = m_in->m_vfs_fs_readsuper.flags;
27
28 if (fdp->fdr_mount == NULL)
29 return ENOSYS;
30
31 if (fsdriver_mounted) {
32 printf("fsdriver: attempt to mount multiple times\n");
33 return EBUSY;
34 }
35
36 if ((r = fsdriver_getname(m_in->m_source, label_grant, label_len,
37 label, sizeof(label), FALSE /*not_empty*/)) != OK)
38 return r;
39
40 if (fdp->fdr_driver != NULL)
41 fdp->fdr_driver(dev, label);
42
43 res_flags = RES_NOFLAGS;
44
45 r = fdp->fdr_mount(dev, flags, &root_node, &res_flags);
46
47 if (r == OK) {
48 /* This one we can set on the file system's behalf. */
49 if ((fdp->fdr_peek != NULL && fdp->fdr_bpeek != NULL) ||
50 major(dev) == NONE_MAJOR)
51 res_flags |= RES_HASPEEK;
52
53 m_out->m_fs_vfs_readsuper.inode = root_node.fn_ino_nr;
54 m_out->m_fs_vfs_readsuper.mode = root_node.fn_mode;
55 m_out->m_fs_vfs_readsuper.file_size = root_node.fn_size;
56 m_out->m_fs_vfs_readsuper.uid = root_node.fn_uid;
57 m_out->m_fs_vfs_readsuper.gid = root_node.fn_gid;
58 m_out->m_fs_vfs_readsuper.flags = res_flags;
59
60 /* Update library-local state. */
61 fsdriver_mounted = TRUE;
62 fsdriver_device = dev;
63 fsdriver_root = root_node.fn_ino_nr;
64 fsdriver_vmcache = FALSE;
65 }
66
67 return r;
68 }
69
70 /*
71 * Process an UNMOUNT request from VFS.
72 */
73 int
fsdriver_unmount(const struct fsdriver * __restrict fdp,const message * __restrict __unused m_in,message * __restrict __unused m_out)74 fsdriver_unmount(const struct fsdriver * __restrict fdp,
75 const message * __restrict __unused m_in,
76 message * __restrict __unused m_out)
77 {
78
79 if (fdp->fdr_unmount != NULL)
80 fdp->fdr_unmount();
81
82 /* If we used mmap emulation, clear any cached blocks from VM. */
83 if (fsdriver_vmcache)
84 vm_clear_cache(fsdriver_device);
85
86 /* Update library-local state. */
87 fsdriver_mounted = FALSE;
88
89 return OK;
90 }
91
92 /*
93 * Process a PUTNODE request from VFS.
94 */
95 int
fsdriver_putnode(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)96 fsdriver_putnode(const struct fsdriver * __restrict fdp,
97 const message * __restrict m_in, message * __restrict __unused m_out)
98 {
99 ino_t ino_nr;
100 unsigned int count;
101
102 ino_nr = m_in->m_vfs_fs_putnode.inode;
103 count = m_in->m_vfs_fs_putnode.count;
104
105 if (count == 0 || count > INT_MAX) {
106 printf("fsdriver: invalid reference count\n");
107 return EINVAL;
108 }
109
110 if (fdp->fdr_putnode != NULL)
111 return fdp->fdr_putnode(ino_nr, count);
112 else
113 return OK;
114 }
115
116 /*
117 * Process a NEWNODE request from VFS.
118 */
119 int
fsdriver_newnode(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out)120 fsdriver_newnode(const struct fsdriver * __restrict fdp,
121 const message * __restrict m_in, message * __restrict m_out)
122 {
123 struct fsdriver_node node;
124 mode_t mode;
125 uid_t uid;
126 gid_t gid;
127 dev_t dev;
128 int r;
129
130 mode = m_in->m_vfs_fs_newnode.mode;
131 uid = m_in->m_vfs_fs_newnode.uid;
132 gid = m_in->m_vfs_fs_newnode.gid;
133 dev = m_in->m_vfs_fs_newnode.device;
134
135 if (fdp->fdr_newnode == NULL)
136 return ENOSYS;
137
138 if ((r = fdp->fdr_newnode(mode, uid, gid, dev, &node)) == OK) {
139 m_out->m_fs_vfs_newnode.inode = node.fn_ino_nr;
140 m_out->m_fs_vfs_newnode.mode = node.fn_mode;
141 m_out->m_fs_vfs_newnode.file_size = node.fn_size;
142 m_out->m_fs_vfs_newnode.uid = node.fn_uid;
143 m_out->m_fs_vfs_newnode.gid = node.fn_gid;
144 m_out->m_fs_vfs_newnode.device = node.fn_dev;
145 }
146
147 return r;
148 }
149
150 /*
151 * Process a read or write request from VFS.
152 */
153 static int
read_write(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out,int call)154 read_write(const struct fsdriver * __restrict fdp,
155 const message * __restrict m_in, message * __restrict m_out, int call)
156 {
157 struct fsdriver_data data;
158 ino_t ino_nr;
159 off_t pos;
160 size_t nbytes;
161 ssize_t r;
162
163 ino_nr = m_in->m_vfs_fs_readwrite.inode;
164 pos = m_in->m_vfs_fs_readwrite.seek_pos;
165 nbytes = m_in->m_vfs_fs_readwrite.nbytes;
166
167 if (pos < 0 || nbytes > SSIZE_MAX)
168 return EINVAL;
169
170 data.endpt = m_in->m_source;
171 data.grant = m_in->m_vfs_fs_readwrite.grant;
172 data.size = nbytes;
173
174 if (call == FSC_WRITE)
175 r = fdp->fdr_write(ino_nr, &data, nbytes, pos, call);
176 else
177 r = fdp->fdr_read(ino_nr, &data, nbytes, pos, call);
178
179 if (r >= 0) {
180 pos += r;
181
182 m_out->m_fs_vfs_readwrite.seek_pos = pos;
183 m_out->m_fs_vfs_readwrite.nbytes = r;
184 r = OK;
185 }
186
187 return r;
188 }
189
190 /*
191 * Process a READ request from VFS.
192 */
193 int
fsdriver_read(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out)194 fsdriver_read(const struct fsdriver * __restrict fdp,
195 const message * __restrict m_in, message * __restrict m_out)
196 {
197
198 if (fdp->fdr_read == NULL)
199 return ENOSYS;
200
201 return read_write(fdp, m_in, m_out, FSC_READ);
202 }
203
204 /*
205 * Process a WRITE request from VFS.
206 */
207 int
fsdriver_write(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out)208 fsdriver_write(const struct fsdriver * __restrict fdp,
209 const message * __restrict m_in, message * __restrict m_out)
210 {
211
212 if (fdp->fdr_write == NULL)
213 return ENOSYS;
214
215 return read_write(fdp, m_in, m_out, FSC_WRITE);
216 }
217
218 /*
219 * A read-based peek implementation. This allows file systems that do not have
220 * a buffer cache and do not implement peek, to support a limited form of mmap.
221 * We map in a block, fill it by calling the file system's read function, tell
222 * VM about the page, and then unmap the block again. We tell VM not to cache
223 * the block beyond its immediate use for the mmap request, so as to prevent
224 * potentially stale data from being cached--at the cost of performance.
225 */
226 static ssize_t
builtin_peek(const struct fsdriver * __restrict fdp,ino_t ino_nr,size_t nbytes,off_t pos)227 builtin_peek(const struct fsdriver * __restrict fdp, ino_t ino_nr,
228 size_t nbytes, off_t pos)
229 {
230 static u32_t flags = 0; /* storage for the VMMC_ flags of all blocks */
231 static off_t dev_off = 0; /* fake device offset, see below */
232 struct fsdriver_data data;
233 char *buf;
234 ssize_t r;
235
236 if ((buf = mmap(NULL, nbytes, PROT_READ | PROT_WRITE,
237 MAP_ANON | MAP_PRIVATE, -1, 0)) == MAP_FAILED)
238 return ENOMEM;
239
240 data.endpt = SELF;
241 data.grant = (cp_grant_id_t)buf;
242 data.size = nbytes;
243
244 r = fdp->fdr_read(ino_nr, &data, nbytes, pos, FSC_READ);
245
246 if (r >= 0) {
247 if ((size_t)r < nbytes)
248 memset(&buf[r], 0, nbytes - r);
249
250 /*
251 * VM uses serialized communication to VFS. Since the page is
252 * to be used only once, VM will use and then discard it before
253 * sending a new peek request. Thus, it should be safe to
254 * reuse the same device offset all the time. However, relying
255 * on assumptions in protocols elsewhere a bit dangerous, so we
256 * use an ever-increasing device offset just to be safe.
257 */
258 r = vm_set_cacheblock(buf, fsdriver_device, dev_off, ino_nr,
259 pos, &flags, nbytes, VMSF_ONCE);
260
261 if (r == OK) {
262 fsdriver_vmcache = TRUE;
263
264 dev_off += nbytes;
265
266 r = nbytes;
267 }
268 }
269
270 munmap(buf, nbytes);
271
272 return r;
273 }
274
275 /*
276 * Process a PEEK request from VFS.
277 */
278 int
fsdriver_peek(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)279 fsdriver_peek(const struct fsdriver * __restrict fdp,
280 const message * __restrict m_in, message * __restrict __unused m_out)
281 {
282 ino_t ino_nr;
283 off_t pos;
284 size_t nbytes;
285 ssize_t r;
286
287 ino_nr = m_in->m_vfs_fs_readwrite.inode;
288 pos = m_in->m_vfs_fs_readwrite.seek_pos;
289 nbytes = m_in->m_vfs_fs_readwrite.nbytes;
290
291 if (pos < 0 || nbytes > SSIZE_MAX)
292 return EINVAL;
293
294 if (fdp->fdr_peek == NULL) {
295 if (major(fsdriver_device) != NONE_MAJOR)
296 return ENOSYS;
297
298 /*
299 * For file systems that have no backing device, emulate peek
300 * support by reading into temporary buffers and passing these
301 * to VM.
302 */
303 r = builtin_peek(fdp, ino_nr, nbytes, pos);
304 } else
305 r = fdp->fdr_peek(ino_nr, NULL /*data*/, nbytes, pos,
306 FSC_PEEK);
307
308 /* Do not return a new position. */
309 if (r >= 0) {
310 m_out->m_fs_vfs_readwrite.nbytes = r;
311 r = OK;
312 }
313
314 return r;
315 }
316
317 /*
318 * Process a GETDENTS request from VFS.
319 */
320 int
fsdriver_getdents(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out)321 fsdriver_getdents(const struct fsdriver * __restrict fdp,
322 const message * __restrict m_in, message * __restrict m_out)
323 {
324 struct fsdriver_data data;
325 ino_t ino_nr;
326 off_t pos;
327 size_t nbytes;
328 ssize_t r;
329
330 ino_nr = m_in->m_vfs_fs_getdents.inode;
331 pos = m_in->m_vfs_fs_getdents.seek_pos;
332 nbytes = m_in->m_vfs_fs_getdents.mem_size;
333
334 if (fdp->fdr_getdents == NULL)
335 return ENOSYS;
336
337 if (pos < 0 || nbytes > SSIZE_MAX)
338 return EINVAL;
339
340 data.endpt = m_in->m_source;
341 data.grant = m_in->m_vfs_fs_getdents.grant;
342 data.size = nbytes;
343
344 r = fdp->fdr_getdents(ino_nr, &data, nbytes, &pos);
345
346 if (r >= 0) {
347 m_out->m_fs_vfs_getdents.seek_pos = pos;
348 m_out->m_fs_vfs_getdents.nbytes = r;
349 r = OK;
350 }
351
352 return r;
353 }
354
355 /*
356 * Process a FTRUNC request from VFS.
357 */
358 int
fsdriver_trunc(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)359 fsdriver_trunc(const struct fsdriver * __restrict fdp,
360 const message * __restrict m_in, message * __restrict __unused m_out)
361 {
362 ino_t ino_nr;
363 off_t start_pos, end_pos;
364
365 ino_nr = m_in->m_vfs_fs_ftrunc.inode;
366 start_pos = m_in->m_vfs_fs_ftrunc.trc_start;
367 end_pos = m_in->m_vfs_fs_ftrunc.trc_end;
368
369 if (start_pos < 0 || end_pos < 0)
370 return EINVAL;
371
372 if (fdp->fdr_trunc == NULL)
373 return ENOSYS;
374
375 return fdp->fdr_trunc(ino_nr, start_pos, end_pos);
376 }
377
378 /*
379 * Process a INHIBREAD request from VFS.
380 */
381 int
fsdriver_inhibread(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)382 fsdriver_inhibread(const struct fsdriver * __restrict fdp,
383 const message * __restrict m_in, message * __restrict __unused m_out)
384 {
385 ino_t ino_nr;
386
387 ino_nr = m_in->m_vfs_fs_inhibread.inode;
388
389 if (fdp->fdr_seek != NULL)
390 fdp->fdr_seek(ino_nr);
391
392 return OK;
393 }
394
395 /*
396 * Process a CREATE request from VFS.
397 */
398 int
fsdriver_create(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out)399 fsdriver_create(const struct fsdriver * __restrict fdp,
400 const message * __restrict m_in, message * __restrict m_out)
401 {
402 struct fsdriver_node node;
403 char name[NAME_MAX+1];
404 cp_grant_id_t grant;
405 size_t len;
406 ino_t dir_nr;
407 mode_t mode;
408 uid_t uid;
409 gid_t gid;
410 int r;
411
412 grant = m_in->m_vfs_fs_create.grant;
413 len = m_in->m_vfs_fs_create.path_len;
414 dir_nr = m_in->m_vfs_fs_create.inode;
415 mode = m_in->m_vfs_fs_create.mode;
416 uid = m_in->m_vfs_fs_create.uid;
417 gid = m_in->m_vfs_fs_create.gid;
418
419 if (fdp->fdr_create == NULL)
420 return ENOSYS;
421
422 if ((r = fsdriver_getname(m_in->m_source, grant, len, name,
423 sizeof(name), TRUE /*not_empty*/)) != OK)
424 return r;
425
426 if (!strcmp(name, ".") || !strcmp(name, ".."))
427 return EEXIST;
428
429 if ((r = fdp->fdr_create(dir_nr, name, mode, uid, gid, &node)) == OK) {
430 m_out->m_fs_vfs_create.inode = node.fn_ino_nr;
431 m_out->m_fs_vfs_create.mode = node.fn_mode;
432 m_out->m_fs_vfs_create.file_size = node.fn_size;
433 m_out->m_fs_vfs_create.uid = node.fn_uid;
434 m_out->m_fs_vfs_create.gid = node.fn_gid;
435 }
436
437 return r;
438 }
439
440 /*
441 * Process a MKDIR request from VFS.
442 */
443 int
fsdriver_mkdir(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)444 fsdriver_mkdir(const struct fsdriver * __restrict fdp,
445 const message * __restrict m_in, message * __restrict __unused m_out)
446 {
447 char name[NAME_MAX+1];
448 cp_grant_id_t grant;
449 size_t path_len;
450 ino_t dir_nr;
451 mode_t mode;
452 uid_t uid;
453 gid_t gid;
454 int r;
455
456 grant = m_in->m_vfs_fs_mkdir.grant;
457 path_len = m_in->m_vfs_fs_mkdir.path_len;
458 dir_nr = m_in->m_vfs_fs_mkdir.inode;
459 mode = m_in->m_vfs_fs_mkdir.mode;
460 uid = m_in->m_vfs_fs_mkdir.uid;
461 gid = m_in->m_vfs_fs_mkdir.gid;
462
463 if (fdp->fdr_mkdir == NULL)
464 return ENOSYS;
465
466 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name,
467 sizeof(name), TRUE /*not_empty*/)) != OK)
468 return r;
469
470 if (!strcmp(name, ".") || !strcmp(name, ".."))
471 return EEXIST;
472
473 return fdp->fdr_mkdir(dir_nr, name, mode, uid, gid);
474 }
475
476 /*
477 * Process a MKNOD request from VFS.
478 */
479 int
fsdriver_mknod(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)480 fsdriver_mknod(const struct fsdriver * __restrict fdp,
481 const message * __restrict m_in, message * __restrict __unused m_out)
482 {
483 char name[NAME_MAX+1];
484 cp_grant_id_t grant;
485 size_t path_len;
486 ino_t dir_nr;
487 mode_t mode;
488 uid_t uid;
489 gid_t gid;
490 dev_t dev;
491 int r;
492
493 grant = m_in->m_vfs_fs_mknod.grant;
494 path_len = m_in->m_vfs_fs_mknod.path_len;
495 dir_nr = m_in->m_vfs_fs_mknod.inode;
496 mode = m_in->m_vfs_fs_mknod.mode;
497 uid = m_in->m_vfs_fs_mknod.uid;
498 gid = m_in->m_vfs_fs_mknod.gid;
499 dev = m_in->m_vfs_fs_mknod.device;
500
501 if (fdp->fdr_mknod == NULL)
502 return ENOSYS;
503
504 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name,
505 sizeof(name), TRUE /*not_empty*/)) != OK)
506 return r;
507
508 if (!strcmp(name, ".") || !strcmp(name, ".."))
509 return EEXIST;
510
511 return fdp->fdr_mknod(dir_nr, name, mode, uid, gid, dev);
512 }
513
514 /*
515 * Process a LINK request from VFS.
516 */
517 int
fsdriver_link(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)518 fsdriver_link(const struct fsdriver * __restrict fdp,
519 const message * __restrict m_in, message * __restrict __unused m_out)
520 {
521 char name[NAME_MAX+1];
522 cp_grant_id_t grant;
523 size_t path_len;
524 ino_t dir_nr, ino_nr;
525 int r;
526
527 grant = m_in->m_vfs_fs_link.grant;
528 path_len = m_in->m_vfs_fs_link.path_len;
529 dir_nr = m_in->m_vfs_fs_link.dir_ino;
530 ino_nr = m_in->m_vfs_fs_link.inode;
531
532 if (fdp->fdr_link == NULL)
533 return ENOSYS;
534
535 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name,
536 sizeof(name), TRUE /*not_empty*/)) != OK)
537 return r;
538
539 if (!strcmp(name, ".") || !strcmp(name, ".."))
540 return EEXIST;
541
542 return fdp->fdr_link(dir_nr, name, ino_nr);
543 }
544
545 /*
546 * Process an UNLINK request from VFS.
547 */
548 int
fsdriver_unlink(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)549 fsdriver_unlink(const struct fsdriver * __restrict fdp,
550 const message * __restrict m_in, message * __restrict __unused m_out)
551 {
552 char name[NAME_MAX+1];
553 cp_grant_id_t grant;
554 size_t path_len;
555 ino_t dir_nr;
556 int r;
557
558 grant = m_in->m_vfs_fs_unlink.grant;
559 path_len = m_in->m_vfs_fs_unlink.path_len;
560 dir_nr = m_in->m_vfs_fs_unlink.inode;
561
562 if (fdp->fdr_unlink == NULL)
563 return ENOSYS;
564
565 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name,
566 sizeof(name), TRUE /*not_empty*/)) != OK)
567 return r;
568
569 if (!strcmp(name, ".") || !strcmp(name, ".."))
570 return EPERM;
571
572 return fdp->fdr_unlink(dir_nr, name, FSC_UNLINK);
573 }
574
575 /*
576 * Process a RMDIR request from VFS.
577 */
578 int
fsdriver_rmdir(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)579 fsdriver_rmdir(const struct fsdriver * __restrict fdp,
580 const message * __restrict m_in, message * __restrict __unused m_out)
581 {
582 char name[NAME_MAX+1];
583 cp_grant_id_t grant;
584 size_t path_len;
585 ino_t dir_nr;
586 int r;
587
588 grant = m_in->m_vfs_fs_unlink.grant;
589 path_len = m_in->m_vfs_fs_unlink.path_len;
590 dir_nr = m_in->m_vfs_fs_unlink.inode;
591
592 if (fdp->fdr_rmdir == NULL)
593 return ENOSYS;
594
595 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name,
596 sizeof(name), TRUE /*not_empty*/)) != OK)
597 return r;
598
599 if (!strcmp(name, "."))
600 return EINVAL;
601
602 if (!strcmp(name, ".."))
603 return ENOTEMPTY;
604
605 return fdp->fdr_rmdir(dir_nr, name, FSC_RMDIR);
606 }
607
608 /*
609 * Process a RENAME request from VFS.
610 */
611 int
fsdriver_rename(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)612 fsdriver_rename(const struct fsdriver * __restrict fdp,
613 const message * __restrict m_in, message * __restrict __unused m_out)
614 {
615 char old_name[NAME_MAX+1], new_name[NAME_MAX+1];
616 cp_grant_id_t old_grant, new_grant;
617 size_t old_len, new_len;
618 ino_t old_dir_nr, new_dir_nr;
619 int r;
620
621 old_grant = m_in->m_vfs_fs_rename.grant_old;
622 old_len = m_in->m_vfs_fs_rename.len_old;
623 old_dir_nr = m_in->m_vfs_fs_rename.dir_old;
624 new_grant = m_in->m_vfs_fs_rename.grant_new;
625 new_len = m_in->m_vfs_fs_rename.len_new;
626 new_dir_nr = m_in->m_vfs_fs_rename.dir_new;
627
628 if (fdp->fdr_rename == NULL)
629 return ENOSYS;
630
631 if ((r = fsdriver_getname(m_in->m_source, old_grant, old_len, old_name,
632 sizeof(old_name), TRUE /*not_empty*/)) != OK)
633 return r;
634
635 if (!strcmp(old_name, ".") || !strcmp(old_name, ".."))
636 return EINVAL;
637
638 if ((r = fsdriver_getname(m_in->m_source, new_grant, new_len, new_name,
639 sizeof(new_name), TRUE /*not_empty*/)) != OK)
640 return r;
641
642 if (!strcmp(new_name, ".") || !strcmp(new_name, ".."))
643 return EINVAL;
644
645 return fdp->fdr_rename(old_dir_nr, old_name, new_dir_nr, new_name);
646 }
647
648 /*
649 * Process a SLINK request from VFS.
650 */
651 int
fsdriver_slink(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)652 fsdriver_slink(const struct fsdriver * __restrict fdp,
653 const message * __restrict m_in, message * __restrict __unused m_out)
654 {
655 struct fsdriver_data data;
656 char name[NAME_MAX+1];
657 cp_grant_id_t grant;
658 size_t path_len;
659 ino_t dir_nr;
660 uid_t uid;
661 gid_t gid;
662 int r;
663
664 grant = m_in->m_vfs_fs_slink.grant_path;
665 path_len = m_in->m_vfs_fs_slink.path_len;
666 dir_nr = m_in->m_vfs_fs_slink.inode;
667 uid = m_in->m_vfs_fs_slink.uid;
668 gid = m_in->m_vfs_fs_slink.gid;
669
670 if (fdp->fdr_slink == NULL)
671 return ENOSYS;
672
673 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name,
674 sizeof(name), TRUE /*not_empty*/)) != OK)
675 return r;
676
677 if (!strcmp(name, ".") || !strcmp(name, ".."))
678 return EEXIST;
679
680 data.endpt = m_in->m_source;
681 data.grant = m_in->m_vfs_fs_slink.grant_target;
682 data.size = m_in->m_vfs_fs_slink.mem_size;
683
684 return fdp->fdr_slink(dir_nr, name, uid, gid, &data, data.size);
685 }
686
687 /*
688 * Process a RDLINK request from VFS.
689 */
690 int
fsdriver_rdlink(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out)691 fsdriver_rdlink(const struct fsdriver * __restrict fdp,
692 const message * __restrict m_in, message * __restrict m_out)
693 {
694 struct fsdriver_data data;
695 ssize_t r;
696
697 if (fdp->fdr_rdlink == NULL)
698 return ENOSYS;
699
700 data.endpt = m_in->m_source;
701 data.grant = m_in->m_vfs_fs_rdlink.grant;
702 data.size = m_in->m_vfs_fs_rdlink.mem_size;
703
704 r = fdp->fdr_rdlink(m_in->m_vfs_fs_rdlink.inode, &data, data.size);
705
706 if (r >= 0) {
707 m_out->m_fs_vfs_rdlink.nbytes = r;
708 r = OK;
709 }
710
711 return r;
712 }
713
714 /*
715 * Process a STAT request from VFS.
716 */
717 int
fsdriver_stat(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)718 fsdriver_stat(const struct fsdriver * __restrict fdp,
719 const message * __restrict m_in, message * __restrict __unused m_out)
720 {
721 struct stat buf;
722 cp_grant_id_t grant;
723 ino_t ino_nr;
724 int r;
725
726 ino_nr = m_in->m_vfs_fs_stat.inode;
727 grant = m_in->m_vfs_fs_stat.grant;
728
729 if (fdp->fdr_stat == NULL)
730 return ENOSYS;
731
732 memset(&buf, 0, sizeof(buf));
733 buf.st_dev = fsdriver_device;
734 buf.st_ino = ino_nr;
735
736 if ((r = fdp->fdr_stat(ino_nr, &buf)) == OK)
737 r = sys_safecopyto(m_in->m_source, grant, 0, (vir_bytes)&buf,
738 (phys_bytes)sizeof(buf));
739
740 return r;
741 }
742
743 /*
744 * Process a CHOWN request from VFS.
745 */
746 int
fsdriver_chown(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out)747 fsdriver_chown(const struct fsdriver * __restrict fdp,
748 const message * __restrict m_in, message * __restrict m_out)
749 {
750 ino_t ino_nr;
751 uid_t uid;
752 gid_t gid;
753 mode_t mode;
754 int r;
755
756 ino_nr = m_in->m_vfs_fs_chown.inode;
757 uid = m_in->m_vfs_fs_chown.uid;
758 gid = m_in->m_vfs_fs_chown.gid;
759
760 if (fdp->fdr_chown == NULL)
761 return ENOSYS;
762
763 if ((r = fdp->fdr_chown(ino_nr, uid, gid, &mode)) == OK)
764 m_out->m_fs_vfs_chown.mode = mode;
765
766 return r;
767 }
768
769 /*
770 * Process a CHMOD request from VFS.
771 */
772 int
fsdriver_chmod(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out)773 fsdriver_chmod(const struct fsdriver * __restrict fdp,
774 const message * __restrict m_in, message * __restrict m_out)
775 {
776 ino_t ino_nr;
777 mode_t mode;
778 int r;
779
780 ino_nr = m_in->m_vfs_fs_chmod.inode;
781 mode = m_in->m_vfs_fs_chmod.mode;
782
783 if (fdp->fdr_chmod == NULL)
784 return ENOSYS;
785
786 if ((r = fdp->fdr_chmod(ino_nr, &mode)) == OK)
787 m_out->m_fs_vfs_chmod.mode = mode;
788
789 return r;
790 }
791
792 /*
793 * Process a UTIME request from VFS.
794 */
795 int
fsdriver_utime(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)796 fsdriver_utime(const struct fsdriver * __restrict fdp,
797 const message * __restrict m_in, message * __restrict __unused m_out)
798 {
799 ino_t ino_nr;
800 struct timespec atime, mtime;
801
802 ino_nr = m_in->m_vfs_fs_utime.inode;
803 atime.tv_sec = m_in->m_vfs_fs_utime.actime;
804 atime.tv_nsec = m_in->m_vfs_fs_utime.acnsec;
805 mtime.tv_sec = m_in->m_vfs_fs_utime.modtime;
806 mtime.tv_nsec = m_in->m_vfs_fs_utime.modnsec;
807
808 if (fdp->fdr_utime == NULL)
809 return ENOSYS;
810
811 return fdp->fdr_utime(ino_nr, &atime, &mtime);
812 }
813
814 /*
815 * Process a MOUNTPOINT request from VFS.
816 */
817 int
fsdriver_mountpoint(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)818 fsdriver_mountpoint(const struct fsdriver * __restrict fdp,
819 const message * __restrict m_in, message * __restrict __unused m_out)
820 {
821 ino_t ino_nr;
822
823 ino_nr = m_in->m_vfs_fs_mountpoint.inode;
824
825 if (fdp->fdr_mountpt == NULL)
826 return ENOSYS;
827
828 return fdp->fdr_mountpt(ino_nr);
829 }
830
831 /*
832 * Process a STATVFS request from VFS.
833 */
834 int
fsdriver_statvfs(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)835 fsdriver_statvfs(const struct fsdriver * __restrict fdp,
836 const message * __restrict m_in, message * __restrict __unused m_out)
837 {
838 struct statvfs buf;
839 int r;
840
841 if (fdp->fdr_statvfs == NULL)
842 return ENOSYS;
843
844 memset(&buf, 0, sizeof(buf));
845
846 if ((r = fdp->fdr_statvfs(&buf)) != OK)
847 return r;
848
849 return sys_safecopyto(m_in->m_source, m_in->m_vfs_fs_statvfs.grant, 0,
850 (vir_bytes)&buf, (phys_bytes)sizeof(buf));
851 }
852
853 /*
854 * Process a SYNC request from VFS.
855 */
856 int
fsdriver_sync(const struct fsdriver * __restrict fdp,const message * __restrict __unused m_in,message * __restrict __unused m_out)857 fsdriver_sync(const struct fsdriver * __restrict fdp,
858 const message * __restrict __unused m_in,
859 message * __restrict __unused m_out)
860 {
861
862 if (fdp->fdr_sync != NULL)
863 fdp->fdr_sync();
864
865 return OK;
866 }
867
868 /*
869 * Process a NEW_DRIVER request from VFS.
870 */
871 int
fsdriver_newdriver(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)872 fsdriver_newdriver(const struct fsdriver * __restrict fdp,
873 const message * __restrict m_in, message * __restrict __unused m_out)
874 {
875 char label[DS_MAX_KEYLEN];
876 cp_grant_id_t grant;
877 size_t path_len;
878 dev_t dev;
879 int r;
880
881 dev = m_in->m_vfs_fs_new_driver.device;
882 grant = m_in->m_vfs_fs_new_driver.grant;
883 path_len = m_in->m_vfs_fs_new_driver.path_len;
884
885 if (fdp->fdr_driver == NULL)
886 return OK;
887
888 if ((r = fsdriver_getname(m_in->m_source, grant, path_len, label,
889 sizeof(label), FALSE /*not_empty*/)) != OK)
890 return r;
891
892 fdp->fdr_driver(dev, label);
893
894 return OK;
895 }
896
897 /*
898 * Process a block read or write request from VFS.
899 */
900 static ssize_t
bread_bwrite(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out,int call)901 bread_bwrite(const struct fsdriver * __restrict fdp,
902 const message * __restrict m_in, message * __restrict m_out, int call)
903 {
904 struct fsdriver_data data;
905 dev_t dev;
906 off_t pos;
907 size_t nbytes;
908 ssize_t r;
909
910 dev = m_in->m_vfs_fs_breadwrite.device;
911 pos = m_in->m_vfs_fs_breadwrite.seek_pos;
912 nbytes = m_in->m_vfs_fs_breadwrite.nbytes;
913
914 if (pos < 0 || nbytes > SSIZE_MAX)
915 return EINVAL;
916
917 data.endpt = m_in->m_source;
918 data.grant = m_in->m_vfs_fs_breadwrite.grant;
919 data.size = nbytes;
920
921 if (call == FSC_WRITE)
922 r = fdp->fdr_bwrite(dev, &data, nbytes, pos, call);
923 else
924 r = fdp->fdr_bread(dev, &data, nbytes, pos, call);
925
926 if (r >= 0) {
927 pos += r;
928
929 m_out->m_fs_vfs_breadwrite.seek_pos = pos;
930 m_out->m_fs_vfs_breadwrite.nbytes = r;
931 r = OK;
932 }
933
934 return r;
935 }
936
937 /*
938 * Process a BREAD request from VFS.
939 */
940 ssize_t
fsdriver_bread(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out)941 fsdriver_bread(const struct fsdriver * __restrict fdp,
942 const message * __restrict m_in, message * __restrict m_out)
943 {
944
945 if (fdp->fdr_bread == NULL)
946 return ENOSYS;
947
948 return bread_bwrite(fdp, m_in, m_out, FSC_READ);
949 }
950
951 /*
952 * Process a BWRITE request from VFS.
953 */
954 ssize_t
fsdriver_bwrite(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict m_out)955 fsdriver_bwrite(const struct fsdriver * __restrict fdp,
956 const message * __restrict m_in, message * __restrict m_out)
957 {
958
959 if (fdp->fdr_bwrite == NULL)
960 return ENOSYS;
961
962 return bread_bwrite(fdp, m_in, m_out, FSC_WRITE);
963 }
964
965 /*
966 * Process a BPEEK request from VFS.
967 */
968 int
fsdriver_bpeek(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)969 fsdriver_bpeek(const struct fsdriver * __restrict fdp,
970 const message * __restrict m_in, message * __restrict __unused m_out)
971 {
972 dev_t dev;
973 off_t pos;
974 size_t nbytes;
975 ssize_t r;
976
977 dev = m_in->m_vfs_fs_breadwrite.device;
978 pos = m_in->m_vfs_fs_breadwrite.seek_pos;
979 nbytes = m_in->m_vfs_fs_breadwrite.nbytes;
980
981 if (fdp->fdr_bpeek == NULL)
982 return ENOSYS;
983
984 if (pos < 0 || nbytes > SSIZE_MAX)
985 return EINVAL;
986
987 r = fdp->fdr_bpeek(dev, NULL /*data*/, nbytes, pos, FSC_PEEK);
988
989 /* Do not return a new position. */
990 if (r >= 0) {
991 m_out->m_fs_vfs_breadwrite.nbytes = r;
992 r = OK;
993 }
994
995 return r;
996 }
997
998 /*
999 * Process a FLUSH request from VFS.
1000 */
1001 int
fsdriver_flush(const struct fsdriver * __restrict fdp,const message * __restrict m_in,message * __restrict __unused m_out)1002 fsdriver_flush(const struct fsdriver * __restrict fdp,
1003 const message * __restrict m_in, message * __restrict __unused m_out)
1004 {
1005 dev_t dev;
1006
1007 dev = m_in->m_vfs_fs_flush.device;
1008
1009 if (fdp->fdr_bflush != NULL)
1010 fdp->fdr_bflush(dev);
1011
1012 return OK;
1013 }
1014