xref: /minix/minix/servers/vfs/request.c (revision 9f988b79)
1 /* This file contains the wrapper functions for issuing a request
2  * and receiving response from FS processes.
3  * Each function builds a request message according to the request
4  * parameter, calls the most low-level fs_sendrec, and copies
5  * back the response.
6  */
7 
8 #include "fs.h"
9 #include <minix/com.h>
10 #include <minix/const.h>
11 #include <minix/endpoint.h>
12 #include <minix/u64.h>
13 #include <minix/vfsif.h>
14 #include <sys/dirent.h>
15 #include <sys/stat.h>
16 #include <sys/statvfs.h>
17 #include <assert.h>
18 #include <stddef.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <time.h>
22 #include "path.h"
23 #include "vmnt.h"
24 #include "vnode.h"
25 
26 
27 /*===========================================================================*
28  *			req_breadwrite_actual				     *
29  *===========================================================================*/
30 static int req_breadwrite_actual(endpoint_t fs_e, endpoint_t user_e, dev_t dev, off_t pos,
31         unsigned int num_of_bytes, vir_bytes user_addr, int rw_flag,
32         off_t *new_pos, size_t *cum_iop, int cpflag)
33 {
34   int r;
35   cp_grant_id_t grant_id;
36   message m;
37 
38   grant_id = cpf_grant_magic(fs_e, user_e, user_addr, num_of_bytes,
39 			(rw_flag == READING ? CPF_WRITE : CPF_READ) | cpflag);
40   if(grant_id == -1)
41 	  panic("req_breadwrite: cpf_grant_magic failed");
42 
43   /* Fill in request message */
44   m.m_type = rw_flag == READING ? REQ_BREAD : REQ_BWRITE;
45   m.m_vfs_fs_breadwrite.device = dev;
46   m.m_vfs_fs_breadwrite.grant = grant_id;
47   m.m_vfs_fs_breadwrite.seek_pos = pos;
48   m.m_vfs_fs_breadwrite.nbytes = num_of_bytes;
49 
50   /* Send/rec request */
51   r = fs_sendrec(fs_e, &m);
52   cpf_revoke(grant_id);
53   if (r != OK) return(r);
54 
55   /* Fill in response structure */
56   *new_pos = m.m_fs_vfs_breadwrite.seek_pos;
57   *cum_iop = m.m_fs_vfs_breadwrite.nbytes;
58 
59   return(OK);
60 }
61 
62 int req_breadwrite(endpoint_t fs_e, endpoint_t user_e, dev_t dev, off_t pos,
63         unsigned int num_of_bytes, vir_bytes user_addr, int rw_flag,
64         off_t *new_pos, size_t *cum_iop)
65 {
66 	int r;
67 
68 	r = req_breadwrite_actual(fs_e, user_e, dev, pos, num_of_bytes,
69 		user_addr, rw_flag, new_pos, cum_iop, CPF_TRY);
70 
71 	if(r == EFAULT) {
72 		if((r=vm_vfs_procctl_handlemem(user_e, user_addr, num_of_bytes,
73 			rw_flag == READING)) != OK) {
74 			return r;
75 		}
76 
77 		r = req_breadwrite_actual(fs_e, user_e, dev, pos, num_of_bytes,
78 			user_addr, rw_flag, new_pos, cum_iop, 0);
79 	}
80 
81 	return r;
82 }
83 
84 /*===========================================================================*
85  *			req_bpeek					     *
86  *===========================================================================*/
87 int req_bpeek(endpoint_t fs_e, dev_t dev, off_t pos, unsigned int num_of_bytes)
88 {
89   message m;
90 
91   memset(&m, 0, sizeof(m));
92 
93   /* Fill in request message */
94   m.m_type = REQ_BPEEK;
95   m.m_vfs_fs_breadwrite.device = dev;
96   m.m_vfs_fs_breadwrite.seek_pos = pos;
97   m.m_vfs_fs_breadwrite.nbytes = num_of_bytes;
98 
99   /* Send/rec request */
100   return fs_sendrec(fs_e, &m);
101 }
102 
103 /*===========================================================================*
104  *				req_chmod	      			     *
105  *===========================================================================*/
106 int req_chmod(
107   endpoint_t fs_e,
108   ino_t inode_nr,
109   mode_t rmode,
110   mode_t *new_modep
111 )
112 {
113   message m;
114   int r;
115 
116   /* Fill in request message */
117   m.m_type = REQ_CHMOD;
118   m.m_vfs_fs_chmod.inode = inode_nr;
119   m.m_vfs_fs_chmod.mode = rmode;
120 
121   /* Send/rec request */
122   r = fs_sendrec(fs_e, &m);
123 
124   /* Copy back actual mode. */
125   *new_modep = m.m_fs_vfs_chmod.mode;
126 
127   return(r);
128 }
129 
130 
131 /*===========================================================================*
132  *				req_chown          			     *
133  *===========================================================================*/
134 int req_chown(
135   endpoint_t fs_e,
136   ino_t inode_nr,
137   uid_t newuid,
138   gid_t newgid,
139   mode_t *new_modep
140 )
141 {
142   message m;
143   int r;
144 
145   /* Fill in request message */
146   m.m_type = REQ_CHOWN;
147   m.m_vfs_fs_chown.inode = inode_nr;
148   m.m_vfs_fs_chown.uid = newuid;
149   m.m_vfs_fs_chown.gid = newgid;
150 
151   /* Send/rec request */
152   r = fs_sendrec(fs_e, &m);
153 
154   /* Return new mode to caller. */
155   *new_modep = m.m_fs_vfs_chown.mode;
156 
157   return(r);
158 }
159 
160 
161 /*===========================================================================*
162  *				req_create				     *
163  *===========================================================================*/
164 int req_create(
165   endpoint_t fs_e,
166   ino_t inode_nr,
167   int omode,
168   uid_t uid,
169   gid_t gid,
170   char *path,
171   node_details_t *res
172 )
173 {
174   int r;
175   cp_grant_id_t grant_id;
176   size_t len;
177   message m;
178   struct vmnt *vmp;
179 
180   vmp = find_vmnt(fs_e);
181 
182   len = strlen(path) + 1;
183   grant_id = cpf_grant_direct(fs_e, (vir_bytes) path, len, CPF_READ);
184   if (grant_id == -1)
185 	panic("req_create: cpf_grant_direct failed");
186 
187   /* Fill in request message */
188   m.m_type = REQ_CREATE;
189   m.m_vfs_fs_create.inode = inode_nr;
190   m.m_vfs_fs_create.mode = omode;
191   m.m_vfs_fs_create.uid = uid;
192   m.m_vfs_fs_create.gid = gid;
193   m.m_vfs_fs_create.grant = grant_id;
194   m.m_vfs_fs_create.path_len = len;
195 
196   /* Send/rec request */
197   r = fs_sendrec(fs_e, &m);
198   cpf_revoke(grant_id);
199   if (r != OK) return(r);
200 
201   /* Fill in response structure */
202   res->fs_e	= m.m_source;
203   res->inode_nr	= m.m_fs_vfs_create.inode;
204   res->fmode	= m.m_fs_vfs_create.mode;
205   res->fsize    = m.m_fs_vfs_create.file_size;
206   res->uid	= m.m_fs_vfs_create.uid;
207   res->gid	= m.m_fs_vfs_create.gid;
208   res->dev	= NO_DEV;
209 
210   return(OK);
211 }
212 
213 
214 /*===========================================================================*
215  *				req_flush	      			     *
216  *===========================================================================*/
217 int req_flush(endpoint_t fs_e, dev_t dev)
218 {
219   message m;
220 
221   /* Fill in request message */
222   m.m_type = REQ_FLUSH;
223   m.m_vfs_fs_flush.device = dev;
224 
225   /* Send/rec request */
226   return fs_sendrec(fs_e, &m);
227 }
228 
229 
230 /*===========================================================================*
231  *				req_statvfs	    			     *
232  *===========================================================================*/
233 int req_statvfs(endpoint_t fs_e, struct statvfs *buf)
234 {
235   int r;
236   cp_grant_id_t grant_id;
237   message m;
238 
239   grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, sizeof(struct statvfs),
240 			CPF_WRITE);
241   if(grant_id == GRANT_INVALID)
242 	panic("req_statvfs: cpf_grant_direct failed");
243 
244   /* Fill in request message */
245   m.m_type = REQ_STATVFS;
246   m.m_vfs_fs_statvfs.grant = grant_id;
247 
248   /* Send/rec request */
249   r = fs_sendrec(fs_e, &m);
250   cpf_revoke(grant_id);
251 
252   return(r);
253 }
254 
255 
256 /*===========================================================================*
257  *				req_ftrunc	     			     *
258  *===========================================================================*/
259 int req_ftrunc(endpoint_t fs_e, ino_t inode_nr, off_t start, off_t end)
260 {
261   message m;
262   struct vmnt *vmp;
263 
264   vmp = find_vmnt(fs_e);
265 
266   /* Fill in request message */
267   m.m_type = REQ_FTRUNC;
268   m.m_vfs_fs_ftrunc.inode = inode_nr;
269   m.m_vfs_fs_ftrunc.trc_start = start;
270   m.m_vfs_fs_ftrunc.trc_end = end;
271 
272   if (!(vmp->m_fs_flags & RES_64BIT) &&
273 	((start > INT_MAX) || (end > INT_MAX))) {
274 	/* FS does not support 64-bit off_t and 32 bits is not enough */
275 	return EINVAL;
276   }
277 
278   /* Send/rec request */
279   return fs_sendrec(fs_e, &m);
280 }
281 
282 
283 /*===========================================================================*
284  *				req_getdents_actual    			     *
285  *===========================================================================*/
286 static int req_getdents_actual(
287   endpoint_t fs_e,
288   ino_t inode_nr,
289   off_t pos,
290   vir_bytes buf,
291   size_t size,
292   off_t *new_pos,
293   int direct,
294   int cpflag
295 )
296 {
297   int r;
298   message m;
299   cp_grant_id_t grant_id;
300   struct vmnt *vmp;
301 
302   vmp = find_vmnt(fs_e);
303   assert(vmp != NULL);
304 
305   if (direct) {
306 	grant_id = cpf_grant_direct(fs_e, buf, size, CPF_WRITE);
307   } else {
308 	grant_id = cpf_grant_magic(fs_e, who_e, buf, size,
309 				   CPF_WRITE | cpflag);
310   }
311 
312   if (grant_id < 0)
313 	panic("req_getdents: cpf_grant_direct/cpf_grant_magic failed: %d",
314 								grant_id);
315 
316   m.m_type = REQ_GETDENTS;
317   m.m_vfs_fs_getdents.inode = inode_nr;
318   m.m_vfs_fs_getdents.grant = grant_id;
319   m.m_vfs_fs_getdents.mem_size = size;
320   m.m_vfs_fs_getdents.seek_pos = pos;
321   if (!(vmp->m_fs_flags & RES_64BIT) && (pos > INT_MAX)) {
322 	/* FS does not support 64-bit off_t and 32 bits is not enough */
323 	return EINVAL;
324   }
325 
326   r = fs_sendrec(fs_e, &m);
327   cpf_revoke(grant_id);
328 
329   if (r == OK) {
330 	*new_pos = m.m_fs_vfs_getdents.seek_pos;
331 	r = m.m_fs_vfs_getdents.nbytes;
332   }
333 
334   return(r);
335 }
336 
337 /*===========================================================================*
338  *				req_getdents	     			     *
339  *===========================================================================*/
340 int req_getdents(
341   endpoint_t fs_e,
342   ino_t inode_nr,
343   off_t pos,
344   vir_bytes buf,
345   size_t size,
346   off_t *new_pos,
347   int direct)
348 {
349 	int r;
350 
351 	r = req_getdents_actual(fs_e, inode_nr, pos, buf, size, new_pos,
352 		direct, CPF_TRY);
353 
354 	if(r == EFAULT && !direct) {
355 		if((r=vm_vfs_procctl_handlemem(who_e, buf, size, 1)) != OK) {
356 			return r;
357 		}
358 
359 		r = req_getdents_actual(fs_e, inode_nr, pos, buf, size,
360 			new_pos, direct, 0);
361 	}
362 
363 	return r;
364 }
365 
366 /*===========================================================================*
367  *				req_inhibread	  			     *
368  *===========================================================================*/
369 int req_inhibread(endpoint_t fs_e, ino_t inode_nr)
370 {
371   message m;
372 
373   /* Fill in request message */
374   m.m_type = REQ_INHIBREAD;
375   m.m_vfs_fs_inhibread.inode = inode_nr;
376 
377   /* Send/rec request */
378   return fs_sendrec(fs_e, &m);
379 }
380 
381 
382 /*===========================================================================*
383  *				req_link	       			     *
384  *===========================================================================*/
385 int req_link(
386   endpoint_t fs_e,
387   ino_t link_parent,
388   char *lastc,
389   ino_t linked_file
390 )
391 {
392   int r;
393   cp_grant_id_t grant_id;
394   const size_t len = strlen(lastc) + 1;
395   message m;
396 
397   grant_id = cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ);
398   if(grant_id == -1)
399 	  panic("req_link: cpf_grant_direct failed");
400 
401   /* Fill in request message */
402   m.m_type = REQ_LINK;
403   m.m_vfs_fs_link.inode = linked_file;
404   m.m_vfs_fs_link.dir_ino = link_parent;
405   m.m_vfs_fs_link.grant = grant_id;
406   m.m_vfs_fs_link.path_len = len;
407 
408   /* Send/rec request */
409   r = fs_sendrec(fs_e, &m);
410   cpf_revoke(grant_id);
411 
412   return(r);
413 }
414 
415 
416 /*===========================================================================*
417  *				req_lookup	                   	     *
418  *===========================================================================*/
419 int req_lookup(
420   endpoint_t fs_e,
421   ino_t dir_ino,
422   ino_t root_ino,
423   uid_t uid,
424   gid_t gid,
425   struct lookup *resolve,
426   lookup_res_t *res,
427   struct fproc *rfp
428 )
429 {
430   message m;
431   vfs_ucred_t credentials;
432   int r, flags;
433   size_t len;
434   struct vmnt *vmp;
435   cp_grant_id_t grant_id=0, grant_id2=0;
436 
437   vmp = find_vmnt(fs_e);
438 
439   grant_id = cpf_grant_direct(fs_e, (vir_bytes) resolve->l_path, PATH_MAX,
440 			      CPF_READ | CPF_WRITE);
441   if(grant_id == -1)
442 	  panic("req_lookup: cpf_grant_direct failed");
443 
444   flags = resolve->l_flags;
445   len = strlen(resolve->l_path) + 1;
446 
447   m.m_type			= REQ_LOOKUP;
448   m.m_vfs_fs_lookup.grant_path	= grant_id;
449   m.m_vfs_fs_lookup.path_len 	= len;
450   m.m_vfs_fs_lookup.path_size 	= PATH_MAX + 1;
451   m.m_vfs_fs_lookup.dir_ino 	= dir_ino;
452   m.m_vfs_fs_lookup.root_ino 	= root_ino;
453 
454   if(rfp->fp_ngroups > 0) { /* Is the process member of multiple groups? */
455 	/* In that case the FS has to copy the uid/gid credentials */
456 	int i;
457 
458 	/* Set credentials */
459 	credentials.vu_uid = rfp->fp_effuid;
460 	credentials.vu_gid = rfp->fp_effgid;
461 	credentials.vu_ngroups = rfp->fp_ngroups;
462 	for (i = 0; i < rfp->fp_ngroups; i++)
463 		credentials.vu_sgroups[i] = rfp->fp_sgroups[i];
464 
465 	grant_id2 = cpf_grant_direct(fs_e, (vir_bytes) &credentials,
466 				     sizeof(credentials), CPF_READ);
467 	if(grant_id2 == -1)
468 		panic("req_lookup: cpf_grant_direct failed");
469 
470 	m.m_vfs_fs_lookup.grant_ucred	= grant_id2;
471 	m.m_vfs_fs_lookup.ucred_size	= sizeof(credentials);
472 	flags		|= PATH_GET_UCRED;
473   } else {
474 	/* When there's only one gid, we can send it directly */
475 	m.m_vfs_fs_lookup.uid = uid;
476 	m.m_vfs_fs_lookup.gid = gid;
477 	flags		&= ~PATH_GET_UCRED;
478   }
479 
480   m.m_vfs_fs_lookup.flags = flags;
481 
482   /* Send/rec request */
483   r = fs_sendrec(fs_e, &m);
484   cpf_revoke(grant_id);
485   if(rfp->fp_ngroups > 0) cpf_revoke(grant_id2);
486 
487   /* Fill in response according to the return value */
488   res->fs_e = m.m_source;
489 
490   switch (r) {
491   case OK:
492 	res->inode_nr = m.m_fs_vfs_lookup.inode;
493 	res->fmode = m.m_fs_vfs_lookup.mode;
494 	res->fsize = m.m_fs_vfs_lookup.file_size;
495 	res->dev = m.m_fs_vfs_lookup.device;
496 	res->uid = m.m_fs_vfs_lookup.uid;
497 	res->gid = m.m_fs_vfs_lookup.gid;
498 	break;
499   case EENTERMOUNT:
500 	res->inode_nr = m.m_fs_vfs_lookup.inode;
501 	res->char_processed = m.m_fs_vfs_lookup.offset;
502 	res->symloop = m.m_fs_vfs_lookup.symloop;
503 	break;
504   case ELEAVEMOUNT:
505 	res->char_processed = m.m_fs_vfs_lookup.offset;
506 	res->symloop = m.m_fs_vfs_lookup.symloop;
507 	break;
508   case ESYMLINK:
509 	res->char_processed = m.m_fs_vfs_lookup.offset;
510 	res->symloop = m.m_fs_vfs_lookup.symloop;
511 	break;
512   default:
513 	break;
514   }
515 
516   return(r);
517 }
518 
519 
520 /*===========================================================================*
521  *				req_mkdir	      			     *
522  *===========================================================================*/
523 int req_mkdir(
524   endpoint_t fs_e,
525   ino_t inode_nr,
526   char *lastc,
527   uid_t uid,
528   gid_t gid,
529   mode_t dmode
530 )
531 {
532   int r;
533   cp_grant_id_t grant_id;
534   size_t len;
535   message m;
536 
537   len = strlen(lastc) + 1;
538   grant_id = cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ);
539   if(grant_id == -1)
540 	  panic("req_mkdir: cpf_grant_direct failed");
541 
542   /* Fill in request message */
543   m.m_type = REQ_MKDIR;
544   m.m_vfs_fs_mkdir.inode = inode_nr;
545   m.m_vfs_fs_mkdir.mode = dmode;
546   m.m_vfs_fs_mkdir.uid = uid;
547   m.m_vfs_fs_mkdir.gid = gid;
548   m.m_vfs_fs_mkdir.grant = grant_id;
549   m.m_vfs_fs_mkdir.path_len = len;
550 
551   /* Send/rec request */
552   r = fs_sendrec(fs_e, &m);
553   cpf_revoke(grant_id);
554 
555   return(r);
556 }
557 
558 
559 /*===========================================================================*
560  *				req_mknod	      			     *
561  *===========================================================================*/
562 int req_mknod(
563   endpoint_t fs_e,
564   ino_t inode_nr,
565   char *lastc,
566   uid_t uid,
567   gid_t gid,
568   mode_t dmode,
569   dev_t dev
570 )
571 {
572   int r;
573   size_t len;
574   cp_grant_id_t grant_id;
575   message m;
576 
577   len = strlen(lastc) + 1;
578   grant_id = cpf_grant_direct(fs_e, (vir_bytes)lastc, len, CPF_READ);
579   if(grant_id == -1)
580 	  panic("req_mknod: cpf_grant_direct failed");
581 
582   /* Fill in request message */
583   m.m_type = REQ_MKNOD;
584   m.m_vfs_fs_mknod.inode = inode_nr;
585   m.m_vfs_fs_mknod.mode = dmode;
586   m.m_vfs_fs_mknod.device = dev;
587   m.m_vfs_fs_mknod.uid = uid;
588   m.m_vfs_fs_mknod.gid = gid;
589   m.m_vfs_fs_mknod.grant = grant_id;
590   m.m_vfs_fs_mknod.path_len = len;
591 
592   /* Send/rec request */
593   r = fs_sendrec(fs_e, &m);
594   cpf_revoke(grant_id);
595 
596   return(r);
597 }
598 
599 
600 /*===========================================================================*
601  *				req_mountpoint	                 	     *
602  *===========================================================================*/
603 int req_mountpoint(endpoint_t fs_e, ino_t inode_nr)
604 {
605   message m;
606 
607   /* Fill in request message */
608   m.m_type = REQ_MOUNTPOINT;
609   m.m_vfs_fs_mountpoint.inode = inode_nr;
610 
611   /* Send/rec request */
612   return fs_sendrec(fs_e, &m);
613 }
614 
615 
616 /*===========================================================================*
617  *				req_newnode	      			     *
618  *===========================================================================*/
619 int req_newnode(
620   endpoint_t fs_e,
621   uid_t uid,
622   gid_t gid,
623   mode_t dmode,
624   dev_t dev,
625   struct node_details *res
626 )
627 {
628   struct vmnt *vmp;
629   int r;
630   message m;
631 
632   vmp = find_vmnt(fs_e);
633 
634   /* Fill in request message */
635   m.m_type = REQ_NEWNODE;
636   m.m_vfs_fs_newnode.mode = dmode;
637   m.m_vfs_fs_newnode.device = dev;
638   m.m_vfs_fs_newnode.uid = uid;
639   m.m_vfs_fs_newnode.gid = gid;
640 
641   /* Send/rec request */
642   r = fs_sendrec(fs_e, &m);
643 
644   res->fs_e	= m.m_source;
645   res->inode_nr = m.m_fs_vfs_newnode.inode;
646   res->fmode	= m.m_fs_vfs_newnode.mode;
647   res->fsize    = m.m_fs_vfs_newnode.file_size;
648   res->dev	= m.m_fs_vfs_newnode.device;
649   res->uid	= m.m_fs_vfs_newnode.uid;
650   res->gid	= m.m_fs_vfs_newnode.gid;
651 
652   return(r);
653 }
654 
655 
656 /*===========================================================================*
657  *				req_newdriver          			     *
658  *===========================================================================*/
659 int req_newdriver(
660   endpoint_t fs_e,
661   dev_t dev,
662   char *label
663 )
664 {
665   cp_grant_id_t grant_id;
666   size_t len;
667   message m;
668   int r;
669 
670   /* Grant access to label */
671   len = strlen(label) + 1;
672   grant_id = cpf_grant_direct(fs_e, (vir_bytes) label, len, CPF_READ);
673   if (grant_id == -1)
674 	panic("req_newdriver: cpf_grant_direct failed");
675 
676   /* Fill in request message */
677   m.m_type = REQ_NEW_DRIVER;
678   m.m_vfs_fs_new_driver.device = dev;
679   m.m_vfs_fs_new_driver.grant = grant_id;
680   m.m_vfs_fs_new_driver.path_len = len;
681 
682   /* Issue request */
683   r = fs_sendrec(fs_e, &m);
684 
685   cpf_revoke(grant_id);
686 
687   return(r);
688 }
689 
690 
691 /*===========================================================================*
692  *				req_putnode				     *
693  *===========================================================================*/
694 int req_putnode(fs_e, inode_nr, count)
695 int fs_e;
696 ino_t inode_nr;
697 int count;
698 {
699   message m;
700 
701   /* Fill in request message */
702   m.m_type = REQ_PUTNODE;
703   m.m_vfs_fs_putnode.inode = inode_nr;
704   m.m_vfs_fs_putnode.count = count;
705 
706   /* Send/rec request */
707   return fs_sendrec(fs_e, &m);
708 }
709 
710 
711 /*===========================================================================*
712  *				req_rdlink_actual     			     *
713  *===========================================================================*/
714 static int req_rdlink_actual(endpoint_t fs_e, ino_t inode_nr,
715 	endpoint_t proc_e, vir_bytes buf, size_t len,
716 	int direct, /* set to 1 to use direct grants instead of magic grants */
717 	int cpflag)
718 {
719   message m;
720   int r;
721   cp_grant_id_t grant_id;
722 
723   if (direct) {
724 	grant_id = cpf_grant_direct(fs_e, buf, len, CPF_WRITE);
725   } else {
726 	grant_id = cpf_grant_magic(fs_e, proc_e, buf, len, CPF_WRITE | cpflag);
727   }
728   if (grant_id == -1)
729 	  panic("req_rdlink: cpf_grant_magic failed");
730 
731   /* Fill in request message */
732   m.m_type = REQ_RDLINK;
733   m.m_vfs_fs_rdlink.inode = inode_nr;
734   m.m_vfs_fs_rdlink.grant = grant_id;
735   m.m_vfs_fs_rdlink.mem_size = len;
736 
737   /* Send/rec request */
738   r = fs_sendrec(fs_e, &m);
739   cpf_revoke(grant_id);
740 
741   if (r == OK) r = m.m_fs_vfs_rdlink.nbytes;
742 
743   return(r);
744 }
745 
746 /*===========================================================================*
747  *				req_rdlink	     			     *
748  *===========================================================================*/
749 int req_rdlink(endpoint_t fs_e, ino_t inode_nr, endpoint_t proc_e,
750 	vir_bytes buf, size_t len,
751 	int direct /* set to 1 to use direct grants instead of magic grants */
752 )
753 {
754 	int r;
755 
756 	r = req_rdlink_actual(fs_e, inode_nr, proc_e, buf, len, direct,
757 		CPF_TRY);
758 
759 	if(r == EFAULT && !direct) {
760 		if((r=vm_vfs_procctl_handlemem(proc_e, buf, len, 1)) != OK) {
761 			return r;
762 		}
763 
764 		r = req_rdlink_actual(fs_e, inode_nr, proc_e, buf, len,
765 			direct, 0);
766 	}
767 
768 	return r;
769 }
770 
771 /*===========================================================================*
772  *				req_readsuper	                  	     *
773  *===========================================================================*/
774 int req_readsuper(
775   struct vmnt *vmp,
776   char *label,
777   dev_t dev,
778   int readonly,
779   int isroot,
780   struct node_details *res,
781   unsigned int *fs_flags
782 )
783 {
784   int r;
785   cp_grant_id_t grant_id;
786   size_t len;
787   message m;
788   endpoint_t fs_e;
789 
790   fs_e = vmp->m_fs_e;
791 
792   len = strlen(label)+1;
793   grant_id = cpf_grant_direct(fs_e, (vir_bytes) label, len, CPF_READ);
794   if (grant_id == -1)
795 	  panic("req_readsuper: cpf_grant_direct failed");
796 
797   /* Fill in request message */
798   m.m_type = REQ_READSUPER;
799   m.m_vfs_fs_readsuper.flags = 0;
800   if(readonly) m.m_vfs_fs_readsuper.flags |= REQ_RDONLY;
801   if(isroot)   m.m_vfs_fs_readsuper.flags |= REQ_ISROOT;
802   m.m_vfs_fs_readsuper.grant = grant_id;
803   m.m_vfs_fs_readsuper.device = dev;
804   m.m_vfs_fs_readsuper.path_len = len;
805 
806   /* Send/rec request */
807   r = fs_sendrec(fs_e, &m);
808   cpf_revoke(grant_id);
809 
810   if(r == OK) {
811 	/* Fill in response structure */
812 	res->fs_e = m.m_source;
813 	res->inode_nr = m.m_fs_vfs_readsuper.inode;
814 	res->fmode = m.m_fs_vfs_readsuper.mode;
815 	res->fsize = m.m_fs_vfs_readsuper.file_size;
816 	res->uid = m.m_fs_vfs_readsuper.uid;
817 	res->gid = m.m_fs_vfs_readsuper.gid;
818 	*fs_flags = m.m_fs_vfs_readsuper.flags;
819   }
820 
821   return(r);
822 }
823 
824 
825 /*===========================================================================*
826  *				req_readwrite_actual			     *
827  *===========================================================================*/
828 static int req_readwrite_actual(endpoint_t fs_e, ino_t inode_nr, off_t pos,
829 	int rw_flag, endpoint_t user_e, vir_bytes user_addr,
830 	unsigned int num_of_bytes, off_t *new_posp, size_t *cum_iop,
831 	int cpflag)
832 {
833   struct vmnt *vmp;
834   int r;
835   cp_grant_id_t grant_id;
836   message m;
837 
838   vmp = find_vmnt(fs_e);
839 
840   grant_id = cpf_grant_magic(fs_e, user_e, user_addr, num_of_bytes,
841 			     (rw_flag==READING ? CPF_WRITE:CPF_READ) | cpflag);
842   if (grant_id == -1)
843 	  panic("req_readwrite: cpf_grant_magic failed");
844 
845   /* Fill in request message */
846   m.m_type = rw_flag == READING ? REQ_READ : REQ_WRITE;
847   m.m_vfs_fs_readwrite.inode = inode_nr;
848   m.m_vfs_fs_readwrite.grant = grant_id;
849   m.m_vfs_fs_readwrite.seek_pos = pos;
850   if ((!(vmp->m_fs_flags & RES_64BIT)) && (pos > INT_MAX)) {
851 	return EINVAL;
852   }
853   m.m_vfs_fs_readwrite.nbytes = num_of_bytes;
854 
855   /* Send/rec request */
856   r = fs_sendrec(fs_e, &m);
857   cpf_revoke(grant_id);
858 
859   if (r == OK) {
860 	/* Fill in response structure */
861 	*new_posp = m.m_fs_vfs_readwrite.seek_pos;
862 	*cum_iop = m.m_fs_vfs_readwrite.nbytes;
863   }
864 
865   return(r);
866 }
867 
868 /*===========================================================================*
869  *				req_readwrite				     *
870  *===========================================================================*/
871 int req_readwrite(endpoint_t fs_e, ino_t inode_nr, off_t pos,
872 	int rw_flag, endpoint_t user_e, vir_bytes user_addr,
873 	unsigned int num_of_bytes, off_t *new_posp, size_t *cum_iop)
874 {
875 	int r;
876 
877 	r = req_readwrite_actual(fs_e, inode_nr, pos, rw_flag, user_e,
878 		user_addr, num_of_bytes, new_posp, cum_iop, CPF_TRY);
879 
880 	if(r == EFAULT) {
881 		if((r=vm_vfs_procctl_handlemem(user_e, (vir_bytes) user_addr, num_of_bytes,
882 			rw_flag == READING)) != OK) {
883 			return r;
884 		}
885 
886 		r = req_readwrite_actual(fs_e, inode_nr, pos, rw_flag, user_e,
887 			user_addr, num_of_bytes, new_posp, cum_iop, 0);
888 	}
889 
890 	return r;
891 }
892 
893 /*===========================================================================*
894  *				req_peek				     *
895  *===========================================================================*/
896 int req_peek(endpoint_t fs_e, ino_t inode_nr, off_t pos, unsigned int bytes)
897 {
898   message m;
899 
900   memset(&m, 0, sizeof(m));
901 
902   if (ex64hi(pos) != 0)
903 	  panic("req_peek: pos too large");
904 
905   /* Fill in request message */
906   m.m_type = REQ_PEEK;
907   m.m_vfs_fs_readwrite.inode = inode_nr;
908   m.m_vfs_fs_readwrite.grant = -1;
909   m.m_vfs_fs_readwrite.seek_pos = pos;
910   m.m_vfs_fs_readwrite.nbytes = bytes;
911 
912   /* Send/rec request */
913   return fs_sendrec(fs_e, &m);
914 }
915 
916 /*===========================================================================*
917  *				req_rename	     			     *
918  *===========================================================================*/
919 int req_rename(fs_e, old_dir, old_name, new_dir, new_name)
920 endpoint_t fs_e;
921 ino_t old_dir;
922 char *old_name;
923 ino_t new_dir;
924 char *new_name;
925 {
926   int r;
927   cp_grant_id_t gid_old, gid_new;
928   size_t len_old, len_new;
929   message m;
930 
931   len_old = strlen(old_name) + 1;
932   gid_old = cpf_grant_direct(fs_e, (vir_bytes) old_name, len_old, CPF_READ);
933   if(gid_old == -1)
934 	  panic("req_rename: cpf_grant_direct failed");
935 
936   len_new = strlen(new_name) + 1;
937   gid_new = cpf_grant_direct(fs_e, (vir_bytes) new_name, len_new, CPF_READ);
938   if(gid_new == -1)
939 	  panic("req_rename: cpf_grant_direct failed");
940 
941   /* Fill in request message */
942   m.m_type = REQ_RENAME;
943   m.m_vfs_fs_rename.dir_old = old_dir;
944   m.m_vfs_fs_rename.grant_old = gid_old;
945   m.m_vfs_fs_rename.len_old = len_old;
946 
947   m.m_vfs_fs_rename.dir_new = new_dir;
948   m.m_vfs_fs_rename.grant_new = gid_new;
949   m.m_vfs_fs_rename.len_new = len_new;
950 
951   /* Send/rec request */
952   r = fs_sendrec(fs_e, &m);
953   cpf_revoke(gid_old);
954   cpf_revoke(gid_new);
955 
956   return(r);
957 }
958 
959 
960 /*===========================================================================*
961  *				req_rmdir	      			     *
962  *===========================================================================*/
963 int req_rmdir(fs_e, inode_nr, lastc)
964 endpoint_t fs_e;
965 ino_t inode_nr;
966 char *lastc;
967 {
968   int r;
969   cp_grant_id_t grant_id;
970   size_t len;
971   message m;
972 
973   len = strlen(lastc) + 1;
974   grant_id = cpf_grant_direct(fs_e, (vir_bytes) lastc, len, CPF_READ);
975   if(grant_id == -1)
976 	  panic("req_rmdir: cpf_grant_direct failed");
977 
978   /* Fill in request message */
979   m.m_type = REQ_RMDIR;
980   m.m_vfs_fs_unlink.inode = inode_nr;
981   m.m_vfs_fs_unlink.grant = grant_id;
982   m.m_vfs_fs_unlink.path_len = len;
983 
984   /* Send/rec request */
985   r = fs_sendrec(fs_e, &m);
986   cpf_revoke(grant_id);
987 
988   return(r);
989 }
990 
991 
992 /*===========================================================================*
993  *				req_slink_actual      			     *
994  *===========================================================================*/
995 static int req_slink_actual(
996   endpoint_t fs_e,
997   ino_t inode_nr,
998   char *lastc,
999   endpoint_t proc_e,
1000   vir_bytes path_addr,
1001   size_t path_length,
1002   uid_t uid,
1003   gid_t gid,
1004   int cpflag
1005 )
1006 {
1007   int r;
1008   size_t len;
1009   cp_grant_id_t gid_name, gid_buf;
1010   message m;
1011 
1012   len = strlen(lastc) + 1;
1013   gid_name = cpf_grant_direct(fs_e, (vir_bytes) lastc, len, CPF_READ);
1014   if (gid_name == GRANT_INVALID)
1015 	  panic("req_slink: cpf_grant_direct failed");
1016 
1017   gid_buf = cpf_grant_magic(fs_e, proc_e, path_addr, path_length,
1018 	CPF_READ | cpflag);
1019 
1020   if (gid_buf == GRANT_INVALID) {
1021 	  cpf_revoke(gid_name);
1022 	  panic("req_slink: cpf_grant_magic failed");
1023   }
1024 
1025   /* Fill in request message */
1026   m.m_type = REQ_SLINK;
1027   m.m_vfs_fs_slink.inode = inode_nr;
1028   m.m_vfs_fs_slink.uid = uid;
1029   m.m_vfs_fs_slink.gid = gid;
1030   m.m_vfs_fs_slink.grant_path = gid_name;
1031   m.m_vfs_fs_slink.path_len = len;
1032   m.m_vfs_fs_slink.grant_target = gid_buf;
1033   m.m_vfs_fs_slink.mem_size = path_length;
1034 
1035   /* Send/rec request */
1036   r = fs_sendrec(fs_e, &m);
1037   cpf_revoke(gid_name);
1038   cpf_revoke(gid_buf);
1039 
1040   return(r);
1041 }
1042 
1043 /*===========================================================================*
1044  *				req_slink	      			     *
1045  *===========================================================================*/
1046 int req_slink(
1047   endpoint_t fs_e,
1048   ino_t inode_nr,
1049   char *lastc,
1050   endpoint_t proc_e,
1051   vir_bytes path_addr,
1052   size_t path_length,
1053   uid_t uid,
1054   gid_t gid
1055 )
1056 {
1057 	int r;
1058 
1059 	r = req_slink_actual(fs_e, inode_nr, lastc, proc_e, path_addr,
1060 		path_length, uid, gid, CPF_TRY);
1061 
1062 	if(r == EFAULT) {
1063 		if((r=vm_vfs_procctl_handlemem(proc_e, (vir_bytes) path_addr,
1064 			path_length, 0)) != OK) {
1065 			return r;
1066 		}
1067 
1068 		r = req_slink_actual(fs_e, inode_nr, lastc, proc_e, path_addr,
1069 			path_length, uid, gid, 0);
1070 	}
1071 
1072 	return r;
1073 }
1074 
1075 /*===========================================================================*
1076  *				req_stat_actual	       			     *
1077  *===========================================================================*/
1078 int req_stat_actual(endpoint_t fs_e, ino_t inode_nr, endpoint_t proc_e,
1079 	vir_bytes buf, int cpflag)
1080 {
1081   cp_grant_id_t grant_id;
1082   int r;
1083   message m;
1084 
1085   /* Grant FS access to copy straight into user provided buffer */
1086   grant_id = cpf_grant_magic(fs_e, proc_e, buf, sizeof(struct stat),
1087 	CPF_WRITE | cpflag);
1088 
1089   if (grant_id < 0)
1090 	panic("req_stat: cpf_grant_* failed");
1091 
1092   /* Fill in request message */
1093   m.m_type = REQ_STAT;
1094   m.m_vfs_fs_stat.inode = inode_nr;
1095   m.m_vfs_fs_stat.grant = grant_id;
1096 
1097   /* Send/rec request */
1098   r = fs_sendrec(fs_e, &m);
1099   cpf_revoke(grant_id);
1100 
1101   return(r);
1102 }
1103 
1104 
1105 /*===========================================================================*
1106  *				req_stat	       			     *
1107  *===========================================================================*/
1108 int req_stat(endpoint_t fs_e, ino_t inode_nr, endpoint_t proc_e,
1109 	vir_bytes buf)
1110 {
1111 	int r;
1112 
1113 	r = req_stat_actual(fs_e, inode_nr, proc_e, buf, CPF_TRY);
1114 
1115 	if(r == EFAULT) {
1116 		if((r=vm_vfs_procctl_handlemem(proc_e, (vir_bytes) buf,
1117 			sizeof(struct stat), 1)) != OK) {
1118 			return r;
1119 		}
1120 
1121 		r = req_stat_actual(fs_e, inode_nr, proc_e, buf, 0);
1122 	}
1123 
1124 	return r;
1125 }
1126 
1127 /*===========================================================================*
1128  *				req_sync	       			     *
1129  *===========================================================================*/
1130 int req_sync(fs_e)
1131 endpoint_t fs_e;
1132 {
1133   message m;
1134 
1135   /* Fill in request message */
1136   m.m_type = REQ_SYNC;
1137 
1138   /* Send/rec request */
1139   return fs_sendrec(fs_e, &m);
1140 }
1141 
1142 
1143 /*===========================================================================*
1144  *				req_unlink	     			     *
1145  *===========================================================================*/
1146 int req_unlink(fs_e, inode_nr, lastc)
1147 endpoint_t fs_e;
1148 ino_t inode_nr;
1149 char *lastc;
1150 {
1151   cp_grant_id_t grant_id;
1152   size_t len;
1153   int r;
1154   message m;
1155 
1156   len = strlen(lastc) + 1;
1157   grant_id = cpf_grant_direct(fs_e, (vir_bytes) lastc, len, CPF_READ);
1158   if(grant_id == -1)
1159 	  panic("req_unlink: cpf_grant_direct failed");
1160 
1161   /* Fill in request message */
1162   m.m_type = REQ_UNLINK;
1163   m.m_vfs_fs_unlink.inode = inode_nr;
1164   m.m_vfs_fs_unlink.grant = grant_id;
1165   m.m_vfs_fs_unlink.path_len = len;
1166 
1167   /* Send/rec request */
1168   r = fs_sendrec(fs_e, &m);
1169   cpf_revoke(grant_id);
1170 
1171   return(r);
1172 }
1173 
1174 
1175 /*===========================================================================*
1176  *				req_unmount	    			     *
1177  *===========================================================================*/
1178 int req_unmount(fs_e)
1179 endpoint_t fs_e;
1180 {
1181   message m;
1182 
1183   /* Fill in request message */
1184   m.m_type = REQ_UNMOUNT;
1185 
1186   /* Send/rec request */
1187   return fs_sendrec(fs_e, &m);
1188 }
1189 
1190 
1191 /*===========================================================================*
1192  *				req_utime	      			     *
1193  *===========================================================================*/
1194 int req_utime(endpoint_t fs_e, ino_t inode_nr, struct timespec * actimespec,
1195 	struct timespec * modtimespec)
1196 {
1197   message m;
1198 
1199   assert(actimespec != NULL);
1200   assert(modtimespec != NULL);
1201 
1202   /* Fill in request message */
1203   m.m_type = REQ_UTIME;
1204   m.m_vfs_fs_utime.inode = inode_nr;
1205   m.m_vfs_fs_utime.actime = actimespec->tv_sec;
1206   m.m_vfs_fs_utime.modtime = modtimespec->tv_sec;
1207   m.m_vfs_fs_utime.acnsec = actimespec->tv_nsec;
1208   m.m_vfs_fs_utime.modnsec = modtimespec->tv_nsec;
1209 
1210   /* Send/rec request */
1211   return fs_sendrec(fs_e, &m);
1212 }
1213