1 /* vu.c - virtual unix file-system interface
2  *
3  ****************************************************************
4  * Copyright (C) 1998, 2000 Thomas Lord
5  *
6  * See the file "COPYING" for further information about
7  * the copyright and warranty status of this work.
8  */
9 
10 
11 
12 #include "hackerlab/os/errno.h"
13 #include "hackerlab/bugs/panic.h"
14 #include "hackerlab/char/str.h"
15 #include "hackerlab/arrays/ar.h"
16 #include "hackerlab/vu/reserv.h"
17 #include "hackerlab/vu/vu-bad-arg.h"
18 #include "hackerlab/vu/vu-sys.h"
19 #include "hackerlab/vu/vu.h"
20 
21 
22 /************************************************************************
23  *(h0 "A Virtual Unix File-System Interface"
24  *    :include ("vu/vu.h"))
25  *
26  * VU provides a "virtual file-system interface" -- a way for programs
27  * to redefine the meaning of the basic file-system functions for a
28  * particular file descriptor or for a particular part of the
29  * file-system namespace.  When a process defines a virtual
30  * file-system, its definitions apply to that process only.
31  */
32 /*(menu)
33  */
34 
35 
36 /****************************************************************
37  *(h1 "The VU File-System Functions")
38  *
39  * For the purposes of this section, the unix file system interface is
40  * defined as these functions:
41  *
42  *
43  *	access chdir chmod chown chroot close closedir fchdir fchmod
44  *	fchown fstat fsync ftruncate link lseek lstat mkdir open
45  *	opendir read readdir readlink rename rmdir stat
46  *	symlink truncate unlink utime write fcntl
47  *	dup dup2
48  *
49  * For each of those functions, there is a corresponding `vu_' function:
50  *
51  *	vu_access vu_chdir vu_chmod ...
52  *
53  * The function prototypes of the `vu_' functions are slightly
54  * different from the traditional unix functions.  For one thing, all
55  * `vu_' functions accept an output paramter, `errn', as the first
56  * argument:
57  *
58  *	int vu_open (int * errn, char * path, int flags, int mode)
59  *
60  * That parameter takes the place of the global variable `errno'.
61  * When an error occurs in a `vu_' function, the error number is
62  * returned in `*errn'.
63  *
64  * The other interface difference is the functions for reading
65  * directories.  The `vu_' functions return an integer to indicate
66  * success (0) or failure (-1) and return other information through
67  * output parameters:
68  *
69  * 	int vu_opendir (int * errn, DIR ** retv,  char * path)
70  *	int vu_readdir (int * errn,
71  *			struct alloc_limits * limits,
72  *			char ** file_ret,
73  *			DIR * dir)
74  *
75  * Aside from those difference, `vu_' functions can be substituted
76  * freely for their unix counterparts.  If no other changes are made,
77  * the modified program will run just the same as the original.
78  *
79  * There are two additional `vu_' functions:
80  *
81  *	vu_read_retry vu_write_retry
82  *
83  * which are similar to `read' and `write' but which
84  * automatically restart after a `EINTR' or `EAGAIN'.
85  *
86  */
87 
88 /****************************************************************
89  *(h1 "Virtual File-System Functions")
90  *
91  * Programs can provide their own definitions of the `vu_' file-system
92  * functions.  These definitions can be made to apply to specific file
93  * descriptors or to a subset of the names in the file-system
94  * namespace of the process.
95  *
96  * To define a set of virtual functions, a program defines functions
97  * having the same return types and almost the same parameters as the
98  * `vu_' virtual functions.  The virtual functions take one extra
99  * (final) argument, `void * closure'.  For example:
100  *
101  *	int my_virtual_open (int * errn,
102  *			     char * path,
103  *			     int flags,
104  * 			     int mode,
105  *			     void * closure)
106  *
107  * All of these functions must be named consistently by adding a
108  * prefix to the root name of the file system functions:
109  *
110  *	my_virtual_access my_virtual_chdir my_virtual_chmod ...
111  *
112  * Two additional functions must be provided:
113  *
114  *	void * my_virtual_make_closure (void * closure)
115  *	void my_virtual_free_closure (void * closure)
116  *
117  * These are explained below.
118  *
119  * Having defined a set of virtual file system functions, a program
120  * must declare a "vtable" for the functions:
121  *
122  *	#include "hackerlab/vu/vu.h"
123  *	...
124  *
125  *	struct vu_fs_discipline my_fs_vtable
126  * 	 = { VU_FS_DISCIPLINE_INITIALIZERS (my_virtual_) };
127  *
128  * Note that the prefix used to name virtual functions is used by
129  * the macro `VU_FS_DISCIPLINE_INITIALIZERS' to initialize the vtable.
130  *
131  * Finally, the functions may be applied to either a portion of the
132  * file-system namespace or to a particular descriptor:
133  *
134  *	// Applying `my_virtual_' functions to a particular
135  *	// descriptor:
136  *	//
137  *	vu_set_fd_handler (fd, &my_fs_vtable, closure);
138  *
139  *	// Applying `my_virtual_' functions to a part
140  *	// of the file-system namespace.  Note that
141  *	// preg is a `regex_t' -- a regular expression
142  *	// compiled by `regcomp'.  `eflags' is like the
143  *	// parameter of the same name to `regexec':
144  *	//
145  *	vu_push_name_handler (name, doc, preg, eflags,
146  *			      &my_fs_vtable, closure, 0);
147  *
148  * After those calls, a call to a `vu_' file-system using descriptor
149  * `fd' will do its work by calling a `my_virtual_' function (e.g.
150  * `vu_read' will call `my_virtual_read' to read from `fd').
151  *
152  * A call to a `vu_' function with a path that matches the regexp
153  * `preg' will also do its work by calling a `my_virtual_' function
154  * (e.g. `vu_open' will call `my_virtual_open' to open a matching
155  * file-name).  If a new file is successfully opened this way, VU
156  * automatically calls `vu_set_fd_handler' to establish the same
157  * vtable as the handler for the new descriptor.
158  *
159  * Name-space handlers are kept on a stack and searched from the
160   * top of stack down.  Each handler has a name and an array of
161  * strings which are its documentation.
162  */
163 
164 /****************************************************************
165  *(h1 "VU Closures")
166  *
167  * When a set of virtual file system functions is installed by
168  * `vu_set_fd_handler' or `vu_push_name_handler' the caller provides a
169  * closure.  This closure is an opaque value to `vu' itself.  A copy
170  * of the closure is passed as the final parameter to the caller's
171  * virtual functions.  For example, to open a file that has matched a
172  * regular expression passed to `vu_push_name_handler', `vu_open' uses
173  * the sequence:
174  *
175  *     fd = handler->vtable->open (errn, path, flags, mode,
176  *				   handler->closure);
177  *
178  * VU doesn't save a copy of the closure directly.  Instead, it calls
179  * the `make_closure' function from the vtable to create the value
180  * to save and the `free_closure' function when that copy is being
181  * discarded.  `make_closure' is called once when
182  * `vu_push_name_handler' is called, and once each time
183  * `vu_set_fd_handler' is called.   `free_closure' is called each time
184  * `vu_close' or `vu_closedir' is called.
185  */
186 
187 /*(c vu_handler :category type)
188  * struct vu_handler;
189  *
190  * For each VU namespace handler and file-descriptor handler, there
191  * is a `struct vu_handler' that indicates the `vtable' and `closure'
192  * to use for that portion of the file-system.
193  *
194  *    struct vu_handler
195  *    {
196  *      struct vu_fs_discipline * vtable;
197  *      void * closure;
198  *    };
199  *
200  */
201 
202 /****************************************************************
203  *(h1 "Pseudo-Descriptors")
204  *
205  * The `vu_' functions can operate on file descriptors which are
206  * created by the program itself without the knowledge of the
207  * operating system kernel.  The advantage of such descriptors is that
208  * they take up no kernel resources so it is practical to create a
209  * large number of them.
210  *
211  * Pseudo-descriptors which are guaranteed to be distinct from all
212  * kernel descriptors can be created using the function
213  * `reserv_pseudo' and destroyed using the function `unreserv_pseudo'.
214  * For example:
215  *
216  *	fd = reserv_pseudo ();
217  *	vu_set_fd_handler (fd, &my_fs_vtable, 0);
218  *
219  * and:
220  *
221  *	int
222  *	my_virtual_close (int * errn, int fd, void * closure)
223  *	{
224  * 	  unreserv_pseudo (fd);
225  *	  return 0;
226  *	}
227  *
228  * One way to use a pseudo-descriptor is to combine it with
229  * buffered-I/O to create a file that corresponds to a string in the
230  * program's address space.  (See xref:"Buffered File Descriptors".)
231  */
232 
233 
234 
235 /* static struct _vu_namespace_handler * _vu_fs_handlers;
236  *
237  * A stack (using `ar_push' and `ar_pop') of VU namespace handlers.
238  */
239 union _t_vu_fs_handlers _vu_fs_handlers = {0};
240 
241 
242 /* static struct _vu_namespace_handler * _vu_optional_fs_handlers;
243  *
244  * A stack (using `ar_push' and `ar_pop') of optional VU namespace
245  * handlers.
246  */
247 union _t_vu_fs_handlers _vu_optional_fs_handlers = {0};
248 
249 
250 /* static struct vu_handler * fd_handlers;
251  *
252  * An array (using `ar_ref') of VU descriptor handlers, indexed by
253  * descriptor numbers.
254  */
255 static union {
256     struct vu_handler * hp;
257     void *void_ptr;
258 } fd_handlers = {0};
259 
260 
261 /* static DIR * known_dirs;
262  *
263  * An array (using `ar_ref') of open directories known to VU.
264  * Indexed by descriptor numbers.
265  */
266 static union {
267     DIR ** DIR_ptr_ptr;
268     void * void_ptr;
269 } known_dirs = {0};
270 
271 
272 /* static struct vu_handler bad_arg_handler;
273  *
274  * The vu_handler for non-descriptors (descriptor numbers less than 0).
275  */
276 static struct vu_handler bad_arg_handler = { &_vu_bad_arg_functions, 0 };
277 
278 
279 /* static struct vu_handler default_handler;
280  *
281  * The vu_handler for file names and descriptors with no other handler.
282  */
283 static struct vu_handler default_handler = { &_vu_system_fs_vtable, 0 };
284 
285 
286 
287 
288 /************************************************************************
289  *(h1 "Establishing VU Handlers")
290  *
291  */
292 
293 /* Dynamically setting rules for dispatching on file names and
294  * descriptor numbers:
295  */
296 
297 /*(c vu_push_name_handler)
298  * void vu_push_name_handler (const t_uchar * name,
299  *			      const t_uchar ** doc,
300  *			      regex_t * preg,
301  *			      int eflags,
302  *			      struct vu_fs_discipline * vtable,
303  *			      void * closure,
304  *			      int is_optional);
305  *
306  * `vu_push_name_handler' establishs a vtable of virtual file system
307  * functions for a portion of the file-system namespace.
308  *
309  * `name' is the name for the handler recognized by
310  * `vu_enable_optional_name_handler'.  Conventionally,
311  * this name may be used as an option argument to the
312  * command line options `-N' or `--namespace'.  For optimal
313  * help message formatting, `name' should be no longer than
314  * 30 characters.  A pointer to `name' is kept by this function.
315  *
316  * `doc' is a documentation string for the handler, printed in the
317  * outpupt of `vu_help_for_optional_handlers'.  For optimal help
318  * message formatting, each line of `doc' should be no longer than 40
319  * characters.  The last element of the array `doc' must be 0.
320  * A pointer to `doc' is kept by this function.
321  *
322  * File-names matching `preg' are handled by the functions in
323  * `vtable'.  Matching is performed by `regexec':
324  *
325  *	regexec (preg, path, 0, 0, eflags)
326  *
327  * If a matching file is successfully opened, `vu_open' and
328  * `vu_opendir' call:
329  *
330  *	vu_set_fd_handler (new_fd, vtable, closure)
331  *
332  * If `is_optional' is not 0, the file-name handler is recorded
333  * but not enabled.  It can be made active by a call to
334  * `vu_enable_optional_name_handler'.
335  */
336 void
vu_push_name_handler(const t_uchar * name,const t_uchar ** doc,regex_t * preg,int eflags,struct vu_fs_discipline * vtable,void * closure,int is_optional)337 vu_push_name_handler (const t_uchar * name,
338 		      const t_uchar ** doc,
339 		      regex_t * preg,
340 		      int eflags,
341 		      struct vu_fs_discipline * vtable,
342 		      void * closure,
343 		      int is_optional)
344 {
345   struct _vu_namespace_handler * name_handler;
346 
347   if (is_optional)
348     name_handler = (struct _vu_namespace_handler *)ar_push ((void **)&_vu_optional_fs_handlers, lim_use_must_malloc, sizeof (*name_handler));
349   else
350     name_handler = (struct _vu_namespace_handler *)ar_push ((void **)&_vu_fs_handlers, lim_use_must_malloc, sizeof (*name_handler));
351   name_handler->preg = preg;
352   name_handler->eflags = eflags;
353   name_handler->handler.vtable = vtable;
354   name_handler->handler.closure = vtable->make_closure (closure);
355   name_handler->name = name;
356   name_handler->doc = doc;
357 }
358 
359 
360 /*(c vu_enable_optional_name_handler)
361  * int vu_enable_optional_name_handler (const t_uchar * name);
362  *
363  * Push the named namespace handler on the VU namespace stack.
364  *
365  * The named handler must have previously been established by a
366  * call to `vu_push_optional_name_handler'.
367  *
368  * Return 0 on success, -1 if the named handler was not found.
369  */
370 int
vu_enable_optional_name_handler(const t_uchar * name)371 vu_enable_optional_name_handler (const t_uchar * name)
372 {
373   int x;
374   int len;
375 
376   len = ar_size (_vu_optional_fs_handlers.void_ptr, lim_use_must_malloc, sizeof (*_vu_optional_fs_handlers.nhp));
377   for (x = 0; x < len; ++x)
378     {
379       if (!str_cmp (name, _vu_optional_fs_handlers.nhp[x].name))
380 	{
381 	  vu_push_name_handler (_vu_optional_fs_handlers.nhp[x].name,
382 				_vu_optional_fs_handlers.nhp[x].doc,
383 				_vu_optional_fs_handlers.nhp[x].preg,
384 				_vu_optional_fs_handlers.nhp[x].eflags,
385 				_vu_optional_fs_handlers.nhp[x].handler.vtable,
386 				_vu_optional_fs_handlers.nhp[x].handler.closure,
387 				0);
388 	  return 0;
389 	}
390     }
391   return -1;
392 }
393 
394 
395 static void
close_vu_files()396 close_vu_files ()
397 {
398   int n_dirs;
399   int n_handlers;
400   int x;
401 
402   n_dirs = ar_size (known_dirs.void_ptr, lim_use_must_malloc, sizeof (*known_dirs.DIR_ptr_ptr));
403   for (x = 0; x < n_dirs; ++x)
404     {
405       int errn;
406       if (known_dirs.DIR_ptr_ptr[x])
407 	vu_closedir (&errn, known_dirs.DIR_ptr_ptr[x]);
408     }
409   n_handlers = ar_size (fd_handlers.void_ptr, lim_use_must_malloc, sizeof (*fd_handlers.hp));
410   for (x = 0; x < n_handlers; ++x)
411     {
412       if (fd_handlers.hp[x].vtable)
413 	{
414 	  int errn;
415 	  vu_close (&errn, x);
416 	}
417     }
418 }
419 
420 
421 /*(c vu_set_fd_handler)
422  * void vu_set_fd_handler (int fd,
423  *			   struct vu_fs_discipline * vtable,
424  *			   void * closure);
425  *
426  * Establish a vtable of virtual file system functions for a
427  * particular descriptor or pseudo-descriptor.
428  *
429  * The handler is automatically removed by `vu_close'.
430  */
431 void
vu_set_fd_handler(int fd,struct vu_fs_discipline * vtable,void * closure)432 vu_set_fd_handler (int fd,
433 		   struct vu_fs_discipline * vtable,
434 		   void * closure)
435 {
436   static int initialized = 0;
437   struct vu_handler * handler;
438 
439   if (!initialized)
440     {
441       if (0 > atexit (close_vu_files))
442 	panic ("error registering atexit function in vu_set_fd_handler");
443       initialized = 1;
444     }
445 
446   handler = (struct vu_handler *)ar_ref (&fd_handlers.void_ptr, lim_use_must_malloc, fd, sizeof (*handler));
447   handler->vtable = vtable;
448   handler->closure = vtable->make_closure (closure);
449 }
450 
451 
452 void
vu_reinit_after_unexec(void)453 vu_reinit_after_unexec (void)
454 {
455   if (0 > atexit (close_vu_files))
456     panic ("error registering atexit function in vu_reinit_after_unexec");
457 }
458 
459 /*(c vu_move_state)
460  * int vu_move_state (int * errn, int fd, int newfd);
461  *
462  * Move the VU handler for `fd' to `newfd'.
463  *
464  */
465 int
vu_move_state(int * errn,int fd,int newfd)466 vu_move_state (int * errn, int fd, int newfd)
467 {
468   struct vu_handler * handler;
469   int rv;
470 
471   handler = vu_fd_dispatch (fd);
472   rv = handler->vtable->move_state (errn, fd, newfd, handler->closure);
473   return rv;
474 }
475 
476 
477 
478 
479 
480 /************************************************************************
481  *(h1 "Looking Up VU Handlers")
482  *
483  *
484  *
485  */
486 
487 /*(c vu_path_dispatch)
488  * struct vu_handler * vu_path_dispatch (char * path);
489  *
490  * Return the vtable and closure that handle the file-name `path'.
491  * (See xref:"vu_handler".)
492  */
493 struct vu_handler *
vu_path_dispatch(const char * path)494 vu_path_dispatch (const char * path)
495 {
496   int x;
497   for (x = ar_size (_vu_fs_handlers.void_ptr, lim_use_must_malloc, sizeof (*_vu_fs_handlers.nhp)) - 1; x >= 0; --x)
498     {
499       if (!regexec (_vu_fs_handlers.nhp[x].preg, path, 0, 0, _vu_fs_handlers.nhp[x].eflags))
500 	return &_vu_fs_handlers.nhp[x].handler;
501     }
502   return &default_handler;
503 }
504 
505 
506 /*(c vu_fd_dispatch)
507  * struct vu_handler * vu_fd_dispatch (int fd);
508  *
509  * Return the vtable and closure that handle the descriptor `fd'.
510  * (See xref:"vu_handler".)
511  */
512 struct vu_handler *
vu_fd_dispatch(int fd)513 vu_fd_dispatch (int fd)
514 {
515   if (fd < 0)
516     return &bad_arg_handler;
517 
518   if ((fd >= ar_size (fd_handlers.void_ptr, lim_use_must_malloc, sizeof (*fd_handlers.hp))) || !fd_handlers.hp[fd].vtable)
519     return &default_handler;
520 
521   return &fd_handlers.hp[fd];
522 }
523 
524 
525 /*(c vu_dir_dispatch)
526  * struct vu_handler * vu_dir_dispatch (DIR * dir);
527  *
528  * Return the vtable and closure that handle the directory `dir'.
529  * (See xref:"vu_handler".)
530  */
531 struct vu_handler *
vu_dir_dispatch(DIR * dir)532 vu_dir_dispatch (DIR * dir)
533 {
534   return vu_fd_dispatch (vu_dir_fd (dir));
535 }
536 
537 
538 
539 /************************************************************************
540  *(h1 "Stacking Descriptor Handlers")
541  *
542  * The function `vu_fd_dispatch' returns a pointer to a `struct
543  * vu_handler' which in turn holds a pointer to the vtable and closure
544  * used to handle `vu_' functions for a particular descriptor (see
545  * xref:"vu_handler").
546  *
547  *
548  * Using `vu_fd_dispatch', descriptor handlers can be stacked.  For
549  * example, the buffered-I/O functions (`vfdbuf_') work by imposing a
550  * file-system vtable that maintains a buffer but that performs actual
551  * I/O by calling functions from an underlying vtable.  To establish
552  * the buffering vtable, the function `vfdbuf_buffer_fd' uses a
553  * sequence of operations like:
554  *
555  *	int
556  *	vfdbuf_buffer_fd (int * errn, int fd,
557  *			  long bufsize, int flags, int zero_buffer)
558  * 	{
559  *	  struct vu_handler * sub_handler;
560  *
561  * 	  ...
562  *	  sub_handler = vu_fd_dispatch (fd);
563  *
564  *	  ... remember that sub_handler does I/O for fd:
565  *	  bufs[fd].sub_handler = sub_handler;
566  *	  ...
567  *
568  * 	  ... Establish the buffering functions as the new vtable for
569  * 	      `fd'.
570  *
571  *	  vu_set_fd_handler (fd, &vfdbuf_vtable, 0);
572  *	}
573  *
574  * The `vfdbuf_' file-system functions follow this example:
575  *
576  * 	int
577  * 	vfdbuf_fsync (int * errn, int fd, void * closure)
578  * 	{
579  * 	  ... Empty the buffer.
580  *
581  * 	  if (vfdbuf_flush (errn, fd) < 0)
582  * 	    return -1;
583  *
584  * 	  ... Perform the actual `fsync' using the vtable set aside
585  *	      in vfdbuf_buffer_fd:
586  *
587  * 	  return bufs[fd].sub_handler.vtable->fsync
588  *			(errn, fd, bufs[fd].sub_handler.closure);
589  * 	}
590  *
591  * Note that when closing a file, it is the responsibility of the
592  * `vfdbuf_' functions to free the closure for the underlying vtable:
593  *
594  * 	int
595  * 	vfdbuf_close (int * errn, int fd, void * closure)
596  * 	{
597  * 	  int errn
598  * 	  int got;
599  * 	  int ign;
600  *
601  *	  ...
602  * 	  got = bufs[fd].sub_handler.vtable->close
603  *			(errn, fd, bufs[fd].sub_handler.closure);
604  *
605  * 	  bufs[fd].sub_handler.vtable->free_closure
606  * 		(bufs[fd].sub_handler.closure);
607  *	  ...
608  * 	}
609  *
610  */
611 
612 /************************************************************************
613  *(h1 "The VU File-system Interface")
614  *
615  * These functions approximately mirror the traditional unix system call
616  * interface, but have these improvments:
617  *
618  * 	1. Error numbers are not stored in a global, but
619  *	   in a return value.
620  *
621  *	2. Functions dispatch on file names and descriptors,
622  *	   permitting these functions to work on objects other than
623  *	   ordinary files and sockets and to work on ordinary files
624  *	   and sockets in unusual ways.
625  */
626 
627 /*(c vu_access)
628  * int vu_access (int * errn, const char * path, int mode);
629  *
630  * See the manual page for `access'.
631  */
632 int
vu_access(int * errn,const char * path,int mode)633 vu_access (int * errn, const char * path, int mode)
634 {
635   struct vu_handler * handler;
636 
637   handler = vu_path_dispatch (path);
638   return handler->vtable->access(errn, path, mode, handler->closure);
639 }
640 
641 
642 /*(c vu_chdir)
643  * int vu_chdir (int * errn, const char * path);
644  *
645  * See the manual page for `chdir'.
646  */
647 int
vu_chdir(int * errn,const char * path)648 vu_chdir (int * errn, const char * path)
649 {
650   struct vu_handler * handler;
651 
652   handler = vu_path_dispatch (path);
653   return handler->vtable->chdir(errn, path, handler->closure);
654 }
655 
656 
657 /*(c vu_chmod)
658  * int vu_chmod (int * errn, const char * path, int mode);
659  *
660  * See the manual page for `chmod'.
661  */
662 int
vu_chmod(int * errn,const char * path,int mode)663 vu_chmod (int * errn, const char * path, int mode)
664 {
665   struct vu_handler * handler;
666 
667   handler = vu_path_dispatch (path);
668   return handler->vtable->chmod(errn, path, mode, handler->closure);
669 }
670 
671 
672 /*(c vu_chown)
673  * int vu_chown (int * errn, const char * path, int owner, int group);
674  *
675  * See the manual page for `chown'.
676  */
677 int
vu_chown(int * errn,const char * path,int owner,int group)678 vu_chown (int * errn, const char * path, int owner, int group)
679 {
680   struct vu_handler * handler;
681 
682   handler = vu_path_dispatch (path);
683   return handler->vtable->chown(errn, path, owner, group, handler->closure);
684 }
685 
686 
687 /*(c vu_chroot)
688  * int vu_chroot (int * errn, const char * path);
689  *
690  * See the manual page for `chroot'.
691  */
692 int
vu_chroot(int * errn,const char * path)693 vu_chroot (int * errn, const char * path)
694 {
695   struct vu_handler * handler;
696 
697   handler = vu_path_dispatch (path);
698   return handler->vtable->chroot(errn, path, handler->closure);
699 }
700 
701 
702 /*(c vu_close)
703  * int vu_close (int * errn, int fd);
704  *
705  * See the manual page for `close'.
706  */
707 int
vu_close(int * errn,int fd)708 vu_close (int * errn, int fd)
709 {
710   struct vu_handler * handler;
711   int status;
712 
713   handler = vu_fd_dispatch (fd);
714   status = handler->vtable->close(errn, fd, handler->closure);
715   if (status >= 0)
716     {
717       if (handler != &default_handler)
718 	{
719 	  if (handler->vtable->free_closure)
720 	    handler->vtable->free_closure (handler->closure);
721 	  handler->vtable = 0;
722 	  handler->closure = 0;
723 	}
724     }
725   return status;
726 }
727 
728 /*(c vu_closedir)
729  * int vu_closedir (int * errn, DIR * dir);
730  *
731  * See the manual page for `closedir'.
732  */
733 int
vu_closedir(int * errn,DIR * dir)734 vu_closedir (int * errn, DIR * dir)
735 {
736   struct vu_handler * handler;
737   int fd;
738   int status;
739 
740   handler = vu_dir_dispatch (dir);
741   fd = vu_dir_fd (dir);
742   status = handler->vtable->closedir(errn, dir, handler->closure);
743   if (status >= 0)
744     {
745       DIR ** dirp;
746 
747       dirp = (DIR **)ar_ref (&known_dirs.void_ptr, lim_use_must_malloc, fd, sizeof (DIR *));
748       *dirp = 0;
749       if (handler != &default_handler)
750 	{
751 	  if (handler->vtable->free_closure)
752 	    handler->vtable->free_closure (handler->closure);
753 	  handler->vtable = 0;
754 	  handler->closure = 0;
755 	}
756       unreserv_pseudo (fd);
757     }
758   return status;
759 }
760 
761 
762 /*(c vu_fchdir)
763  * int vu_fchdir (int * errn, int fd);
764  *
765  * See the manual page for `fchdir'.
766  */
767 int
vu_fchdir(int * errn,int fd)768 vu_fchdir (int * errn, int fd)
769 {
770   struct vu_handler * handler;
771 
772   handler = vu_fd_dispatch (fd);
773   return handler->vtable->fchdir(errn, fd, handler->closure);
774 }
775 
776 
777 /*(c vu_fchmod)
778  * int vu_fchmod (int * errn, int fd, int mode);
779  *
780  * See the manual page for `fchmod'.
781  */
782 int
vu_fchmod(int * errn,int fd,int mode)783 vu_fchmod (int * errn, int fd, int mode)
784 {
785   struct vu_handler * handler;
786 
787   handler = vu_fd_dispatch (fd);
788   return handler->vtable->fchmod (errn, fd, mode, handler->closure);
789 }
790 
791 
792 /*(c vu_fchown)
793  * int vu_fchown (int * errn, int fd, int owner, int group);
794  *
795  * See the manual page for `fchown'.
796  */
797 int
vu_fchown(int * errn,int fd,int owner,int group)798 vu_fchown (int * errn, int fd, int owner, int group)
799 {
800   struct vu_handler * handler;
801 
802   handler = vu_fd_dispatch (fd);
803   return handler->vtable->fchown (errn, fd, owner, group, handler->closure);
804 }
805 
806 
807 /*(c vu_fstat)
808  * int vu_fstat (int * errn, int fd, struct stat * buf);
809  *
810  * See the manual page for `fstat'.
811  */
812 int
vu_fstat(int * errn,int fd,struct stat * buf)813 vu_fstat (int * errn, int fd, struct stat * buf)
814 {
815   struct vu_handler * handler;
816 
817   handler = vu_fd_dispatch (fd);
818   return handler->vtable->fstat(errn, fd, buf, handler->closure);
819 }
820 
821 
822 /*(c vu_fsync)
823  * int vu_fsync (int * errn, int fd);
824  *
825  * See the manual page for `fsync'.
826  */
827 int
vu_fsync(int * errn,int fd)828 vu_fsync (int * errn, int fd)
829 {
830   struct vu_handler * handler;
831 
832   handler = vu_fd_dispatch (fd);
833   return handler->vtable->fsync(errn, fd, handler->closure);
834 }
835 
836 
837 /*(c vu_ftruncate)
838  * int vu_ftruncate (int * errn, int fd, off_t where);
839  *
840  * See the manual page for `ftruncate'.
841  */
842 int
vu_ftruncate(int * errn,int fd,off_t where)843 vu_ftruncate (int * errn, int fd, off_t where)
844 {
845   struct vu_handler * handler;
846 
847   handler = vu_fd_dispatch (fd);
848   return handler->vtable->ftruncate(errn, fd, where, handler->closure);
849 }
850 
851 
852 /*(c vu_link)
853  * int vu_link (int * errn, const char * from, const char * to);
854  *
855  * See the manual page for `link'.
856  */
857 int
vu_link(int * errn,const char * from,const char * to)858 vu_link (int * errn, const char * from, const char * to)
859 {
860   struct vu_handler * handler;
861   struct vu_handler * handler2;
862 
863   handler = vu_path_dispatch (from);
864   handler2 = vu_path_dispatch (to);
865   if (   (handler->vtable->link != handler2->vtable->link)
866       || (handler->closure != handler2->closure))
867     {
868       if (errn) *errn = EXDEV;
869       return -1;
870     }
871   return handler->vtable->link(errn, from, to, handler->closure);
872 }
873 
874 
875 /*(c vu_lseek)
876  * off_t vu_lseek (int * errn, int fd, off_t offset, int whence);
877  *
878  * See the manual page for `lseek'.
879  */
880 off_t
vu_lseek(int * errn,int fd,off_t offset,int whence)881 vu_lseek (int * errn, int fd, off_t offset, int whence)
882 {
883   struct vu_handler * handler;
884 
885   handler = vu_fd_dispatch (fd);
886   return handler->vtable->lseek(errn, fd, offset, whence, handler->closure);
887 }
888 
889 
890 /*(c vu_lstat)
891  * int vu_lstat (int * errn, const char * path, struct stat * buf);
892  *
893  * See the manual page for `lstat'.
894  */
895 int
vu_lstat(int * errn,const char * path,struct stat * buf)896 vu_lstat (int * errn, const char * path, struct stat * buf)
897 {
898   struct vu_handler * handler;
899 
900   handler = vu_path_dispatch (path);
901   return handler->vtable->lstat(errn, path, buf, handler->closure);
902 }
903 
904 
905 /*(c vu_mkdir)
906  * int vu_mkdir (int * errn, const char * path, int mode);
907  *
908  * See the manual page for `mkdir'.
909  */
910 int
vu_mkdir(int * errn,const char * path,int mode)911 vu_mkdir (int * errn, const char * path, int mode)
912 {
913   struct vu_handler * handler;
914 
915   handler = vu_path_dispatch (path);
916   return handler->vtable->mkdir(errn, path, mode, handler->closure);
917 }
918 
919 
920 /*(c vu_open)
921  * int vu_open (int * errn, const char * path, int flags, int mode);
922  *
923  * See the manual page for `open'.
924  */
925 int
vu_open(int * errn,const char * path,int flags,int mode)926 vu_open (int * errn, const char * path, int flags, int mode)
927 {
928   struct vu_handler * handler;
929   int fd;
930 
931   handler = vu_path_dispatch (path);
932   fd = handler->vtable->open(errn, path, flags, mode, handler->closure);
933   if (fd >= 0)
934     {
935       if ((ar_size (fd_handlers.void_ptr, lim_use_must_malloc, sizeof (*fd_handlers.hp)) <= fd) || !fd_handlers.hp [fd].vtable)
936 	vu_set_fd_handler (fd, handler->vtable, handler->closure);
937     }
938 
939   return fd;
940 }
941 
942 
943 /*(c vu_dir_fd)
944  * int vu_dir_fd (DIR * dir);
945  *
946  * Return the pseudo descriptor associated with DIR.
947  */
948 int
vu_dir_fd(DIR * dir)949 vu_dir_fd (DIR * dir)
950 {
951   int x;
952 
953   x = ar_size (known_dirs.void_ptr, lim_use_must_malloc, sizeof (*known_dirs.DIR_ptr_ptr)) - 1;
954 
955   while (x >= 0)
956     {
957       if (known_dirs.DIR_ptr_ptr[x] == dir)
958 	return x;
959       --x;
960     }
961 
962   panic ("attempt to find pseudo fd for unknown dir");
963   return -1;
964 }
965 
966 
967 /*(c vu_opendir)
968  * int vu_opendir (int * errn, DIR ** retv,  const char * path);
969  *
970  * See the manual page for `opendir'.
971  */
972 int
vu_opendir(int * errn,DIR ** retv,const char * path)973 vu_opendir (int * errn, DIR ** retv,  const char * path)
974 {
975   struct vu_handler * handler;
976   int fd;
977   int status;
978 
979   handler = vu_path_dispatch (path);
980   status = handler->vtable->opendir(errn, retv, path, handler->closure);
981   if (status >= 0)
982     {
983       fd = reserv_pseudo (errn, 0);
984       if (fd < 0)
985 	panic ("unable to reserve pseudo fd in vu_opendir");
986       {
987 	DIR ** dirp;
988 
989 	dirp = (DIR **)ar_ref (&known_dirs.void_ptr, lim_use_must_malloc, fd, sizeof (DIR *));
990 	*dirp = *retv;
991 	vu_set_fd_handler (fd, handler->vtable, handler->closure);
992       }
993     }
994   return status;
995 }
996 
997 
998 /*(c vu_read)
999  * ssize_t vu_read (int * errn, int fd, char * buf, size_t count);
1000  *
1001  * See the manual page for `read'.
1002  */
1003 ssize_t
vu_read(int * errn,int fd,char * buf,size_t count)1004 vu_read (int * errn, int fd, char * buf, size_t count)
1005 {
1006   struct vu_handler * handler;
1007 
1008   handler = vu_fd_dispatch (fd);
1009   return handler->vtable->read (errn, fd, buf, count, handler->closure);
1010 }
1011 
1012 
1013 /*(c vu_read_retry)
1014  * ssize_t vu_read_retry (int * errn, int fd, char * buf, size_t count);
1015  *
1016  * Use `vu_read' to read from `fd'.  Read repeatedly (even if a read
1017  * returns early from EINTR or EAGAIN) until `count' characters are
1018  * read, or the end-of-file is reached.
1019  *
1020  * Return the number of characters read or -1 on error.
1021  */
1022 ssize_t
vu_read_retry(int * errn,int fd,char * buf,size_t count)1023 vu_read_retry (int * errn, int fd, char * buf, size_t count)
1024 {
1025   ssize_t amt_read;
1026 
1027   amt_read = 0;
1028   while (1)
1029     {
1030       ssize_t amt;
1031       amt = vu_read (errn, fd, buf, count);
1032       if (amt < 0)
1033         {
1034           if ((*errn == EAGAIN) || (*errn == EINTR))
1035             continue;
1036           else
1037             return amt;
1038         }
1039 
1040       amt_read += amt;
1041       if (!amt || (amt == count))
1042 	return amt_read;
1043       count -= amt;
1044       buf += amt;
1045     }
1046 }
1047 
1048 
1049 /*(c vu_readdir)
1050  * int vu_readdir (int * errn,
1051  *		   struct alloc_limits * limits,
1052  *		   char ** file_ret,
1053  *		   DIR * dir);
1054  *
1055  * See the manual page for `readdir'.
1056  *
1057  * Note that in `vu', the file name is returned in `*file_ret'
1058  * and is dynamically allocated using `limits'.  It is up to the
1059  * caller to free the file name.
1060  */
1061 int
vu_readdir(int * errn,struct alloc_limits * limits,char ** file_ret,DIR * dir)1062 vu_readdir (int * errn,
1063 	    struct alloc_limits * limits,
1064 	    char ** file_ret,
1065 	    DIR * dir)
1066 {
1067   struct vu_handler * handler;
1068 
1069   handler = vu_dir_dispatch (dir);
1070   return handler->vtable->readdir(errn, limits, file_ret, dir, handler->closure);
1071 }
1072 
1073 
1074 /*(c vu_readlink)
1075  * int vu_readlink (int * errn, const char * path, char * buf, int bufsize);
1076  *
1077  * See the manual page for `readlink'.
1078  */
1079 int
vu_readlink(int * errn,const char * path,char * buf,int bufsize)1080 vu_readlink (int * errn, const char * path, char * buf, int bufsize)
1081 {
1082   struct vu_handler * handler;
1083 
1084   handler = vu_path_dispatch (path);
1085   return handler->vtable->readlink(errn, path, buf, bufsize, handler->closure);
1086 }
1087 
1088 
1089 /*(c vu_rename)
1090  * int vu_rename (int * errn, const char * from, const char * to);
1091  *
1092  * See the manual page for `rename'.
1093  */
1094 int
vu_rename(int * errn,const char * from,const char * to)1095 vu_rename (int * errn, const char * from, const char * to)
1096 {
1097   struct vu_handler * handler;
1098   struct vu_handler * handler2;
1099 
1100   handler = vu_path_dispatch (from);
1101   handler2 = vu_path_dispatch (to);
1102   if (   (handler->vtable->rename != handler2->vtable->rename)
1103       || (handler->closure != handler2->closure))
1104     {
1105       if (errn) *errn = EXDEV;
1106       return -1;
1107     }
1108   return handler->vtable->rename(errn, from, to, handler->closure);
1109 }
1110 
1111 
1112 /*(c vu_rmdir)
1113  * int vu_rmdir (int * errn, const char * path);
1114  *
1115  * See the manual page for `rmdir'.
1116  */
1117 int
vu_rmdir(int * errn,const char * path)1118 vu_rmdir (int * errn, const char * path)
1119 {
1120   struct vu_handler * handler;
1121 
1122   handler = vu_path_dispatch (path);
1123   return handler->vtable->rmdir(errn, path, handler->closure);
1124 }
1125 
1126 
1127 /*(c vu_stat)
1128  * int vu_stat (int * errn, const char * path, struct stat * buf);
1129  *
1130  * See the manual page for `stat'.
1131  */
1132 int
vu_stat(int * errn,const char * path,struct stat * buf)1133 vu_stat (int * errn, const char * path, struct stat * buf)
1134 {
1135   struct vu_handler * handler;
1136 
1137   handler = vu_path_dispatch (path);
1138   return handler->vtable->stat(errn, path, buf, handler->closure);
1139 }
1140 
1141 
1142 /*(c vu_symlink)
1143  * int vu_symlink (int * errn, const char * from, const char * to);
1144  *
1145  * See the manual page for `symlink'.
1146  */
1147 int
vu_symlink(int * errn,const char * from,const char * to)1148 vu_symlink (int * errn, const char * from, const char * to)
1149 {
1150   struct vu_handler * handler;
1151   struct vu_handler * handler2;
1152 
1153   handler = vu_path_dispatch (from);
1154   handler2 = vu_path_dispatch (to);
1155   if (   (handler->vtable->symlink != handler2->vtable->symlink)
1156       || (handler->closure != handler2->closure))
1157     {
1158       if (errn) *errn = EXDEV;
1159       return -1;
1160     }
1161   return handler->vtable->symlink(errn, from, to, handler->closure);
1162 }
1163 
1164 
1165 
1166 /*(c vu_truncate)
1167  * int vu_truncate (int * errn, const char * path, off_t where);
1168  *
1169  * See the manual page for `truncate'.
1170  */
1171 int
vu_truncate(int * errn,const char * path,off_t where)1172 vu_truncate (int * errn, const char * path, off_t where)
1173 {
1174   struct vu_handler * handler;
1175 
1176   handler = vu_path_dispatch (path);
1177   return handler->vtable->truncate(errn, path, where, handler->closure);
1178 }
1179 
1180 
1181 /*(c vu_unlink)
1182  * int vu_unlink (int * errn, const char * path);
1183  *
1184  * See the manual page for `unlink'.
1185  */
1186 int
vu_unlink(int * errn,const char * path)1187 vu_unlink (int * errn, const char * path)
1188 {
1189   struct vu_handler * handler;
1190 
1191   handler = vu_path_dispatch (path);
1192   return handler->vtable->unlink(errn, path, handler->closure);
1193 }
1194 
1195 
1196 /*(c vu_utime)
1197  * int vu_utime (int * errn, const char * path, struct utimbuf *times);
1198  *
1199  * See the manual page for `utime'.
1200  */
1201 int
vu_utime(int * errn,const char * path,struct utimbuf * times)1202 vu_utime (int * errn, const char * path, struct utimbuf * times)
1203 {
1204   struct vu_handler * handler;
1205 
1206   handler = vu_path_dispatch (path);
1207   return handler->vtable->utime (errn, path, times, handler->closure);
1208 }
1209 
1210 
1211 /*(c vu_write)
1212  * ssize_t vu_write (int * errn, int fd, const char * buf, size_t count);
1213  *
1214  * See the manual page for `write'.
1215  */
1216 ssize_t
vu_write(int * errn,int fd,const char * buf,size_t count)1217 vu_write (int * errn, int fd, const char * buf, size_t count)
1218 {
1219   struct vu_handler * handler;
1220 
1221   handler = vu_fd_dispatch (fd);
1222   return handler->vtable->write(errn, fd, buf, count, handler->closure);
1223 }
1224 
1225 
1226 /*(c vu_write_retry)
1227  * ssize_t vu_write_retry (int * errn, int fd, const char * buf, size_t count);
1228  *
1229  * Use `vu_write' to write to `fd'.  Write repeatedly (even if a write
1230  * returns early from EINTR or EAGAIN) until `count' characters are
1231  * written.
1232  *
1233  * Return the number of characters written or -1 on error.
1234  */
1235 ssize_t
vu_write_retry(int * errn,int fd,const char * buf,size_t count)1236 vu_write_retry (int * errn, int fd, const char * buf, size_t count)
1237 {
1238   size_t orig_count;
1239 
1240   orig_count = count;
1241   while (1)
1242     {
1243       ssize_t amt;
1244 
1245       amt = vu_write (errn, fd, buf, count);
1246       if (amt < 0)
1247         {
1248           if ((*errn == EAGAIN) || (*errn == EINTR))
1249             continue;
1250           else
1251             return amt;
1252         }
1253       else if (amt == count)
1254 	return orig_count;
1255       else
1256         {
1257           count -= amt;
1258           buf += amt;
1259         }
1260     }
1261 }
1262 
1263 
1264 /*(c vu_fcntl)
1265  * int vu_fcntl (int * errn, int fd, int cmd, long arg);
1266  *
1267  * See the manual page for `fcntl'.
1268  */
1269 int
vu_fcntl(int * errn,int fd,int cmd,long arg)1270 vu_fcntl (int * errn, int fd, int cmd, long arg)
1271 {
1272   struct vu_handler * handler;
1273 
1274   handler = vu_fd_dispatch (fd);
1275   return handler->vtable->fcntl(errn, fd, cmd, arg, handler->closure);
1276 }
1277 
1278 
1279 /*(c vu_dup)
1280  * int vu_dup (int * errn, int fd);
1281  *
1282  * See the manual page for `dup'.
1283  */
1284 int
vu_dup(int * errn,int fd)1285 vu_dup (int * errn, int fd)
1286 {
1287   struct vu_handler * handler;
1288   int new_fd;
1289 
1290   handler = vu_fd_dispatch (fd);
1291   new_fd = handler->vtable->dup(errn, fd, handler->closure);
1292 
1293   return new_fd;
1294 }
1295 
1296 
1297 /*(c vu_dup2)
1298  * int vu_dup2 (int * errn, int fd, int newfd);
1299  *
1300  * See the manual page for `dup2'.
1301  */
1302 int
vu_dup2(int * errn,int fd,int newfd)1303 vu_dup2 (int * errn, int fd, int newfd)
1304 {
1305   struct vu_handler * handler;
1306   int new_fd;
1307 
1308   handler = vu_fd_dispatch (fd);
1309   new_fd = handler->vtable->dup2(errn, fd, newfd, handler->closure);
1310   return new_fd;
1311 }
1312 
1313