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