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