1 /*
2 * (c) 2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3 * Alexander Warg <warg@os.inf.tu-dresden.de>
4 * economic rights: Technische Universität Dresden (Germany)
5 *
6 * This file is part of TUD:OS and distributed under the terms of the
7 * GNU General Public License 2.
8 * Please see the COPYING-GPL-2 file for details.
9 *
10 * As a special exception, you may use this file as part of a free software
11 * library without restriction. Specifically, if other files instantiate
12 * templates or use macros or inline functions from this file, or you compile
13 * this file and link it with other files to produce an executable, this
14 * file does not by itself cause the resulting executable to be covered by
15 * the GNU General Public License. This exception does not however
16 * invalidate any other reasons why the executable file might be covered by
17 * the GNU General Public License.
18 */
19 #pragma once
20
21 #include <l4/sys/compiler.h>
22
23 #include <unistd.h>
24 #include <stdarg.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <sys/socket.h>
29 #include <utime.h>
30 #include <errno.h>
31
32 #ifndef AT_FDCWD
33 # define AT_FDCWD -100
34 #endif
35
36 #ifdef __cplusplus
37
38 #include <l4/sys/capability>
39 #include <l4/re/cap_alloc>
40 #include <l4/re/dataspace>
41 #include <l4/cxx/pair>
42 #include <l4/cxx/ref_ptr>
43
44 namespace L4Re {
45 /**
46 * \brief Virtual file system for interfaces POSIX libc.
47 */
48 namespace Vfs {
49
50 class Mount_tree;
51 class File;
52
53 /**
54 * \brief The common interface for an open POSIX file.
55 *
56 * This interface is common to all kinds of open files, independent of
57 * the file type (e.g., directory, regular file etc.). However, in
58 * the L4Re::Vfs the interface File is used for every real object.
59 *
60 * \see L4Re::Vfs::File for mor information.
61 */
62 class Generic_file
63 {
64 public:
65 virtual ~Generic_file() throw() = 0;
66 /**
67 * \brief Unlock all locks on the file.
68 * \note All locks means all locks independent by which file
69 * the locks were taken.
70 *
71 * This method is called by the POSIX close implementation to
72 * get the POSIX semantics of releasing all locks taken by this
73 * application on a close for any fd referencing the real file.
74 *
75 * \return 0 on success, or <0 on error.
76 */
77 virtual int unlock_all_locks() throw() = 0;
78
79 /**
80 * \brief Get status information for the file.
81 *
82 * This is the backend for POSIX fstat, stat, fstat64 and friends.
83 *
84 * \param[out] buf This buffer is filled with the status information.
85 * \return 0 on success, or <0 on error.
86 */
87 virtual int fstat64(struct stat64 *buf) const throw() = 0;
88
89 /**
90 * \brief Change POSIX access rights on that file.
91 *
92 * Backend for POSIX chmod and fchmod.
93 */
94 virtual int fchmod(mode_t) throw() = 0;
95
96 /**
97 * \brief Get file status flags (fcntl F_GETFL).
98 *
99 * This function is used by the fcntl implementation for the F_GETFL
100 * command.
101 *
102 * \return flags such as `O_RDONLY`, `O_WRONLY`, `O_RDWR`, `O_DIRECT`,
103 * `O_ASYNC`, `O_NOATIME`, `O_NONBLOCK`, or <0 on error.
104 */
105 virtual int get_status_flags() const throw() = 0;
106
107 /**
108 * \brief Set file status flags (fcntl F_SETFL).
109 *
110 * This function is used by the fcntl implementation for the F_SETFL
111 * command.
112 *
113 * \param flags The file status flags to set. This must be a combination of
114 * `O_RDONLY`, `O_WRONLY`, `O_RDWR`, `O_APPEND`, `O_ASYNC`,
115 * `O_DIRECT`, `O_NOATIME`, `O_NONBLOCK`.
116 *
117 * \note Creation flags such as `O_CREAT`, `O_EXCL`, `O_NOCTTY`, `O_TRUNC`
118 * are ignored.
119 *
120 * \return 0 on success, or <0 on error.
121 */
122 virtual int set_status_flags(long flags) throw() = 0;
123
124 virtual int utime(const struct utimbuf *) throw() = 0;
125 virtual int utimes(const struct timeval [2]) throw() = 0;
126 virtual ssize_t readlink(char *, size_t) = 0;
127 };
128
129 inline
~Generic_file()130 Generic_file::~Generic_file() throw()
131 {}
132
133 /**
134 * \brief Interface for a POSIX file that is a directory.
135 *
136 * This interface provides functionality for directory files
137 * in the L4Re::Vfs. However, real objects use always the
138 * combined L4Re::Vfs::File interface.
139 */
140 class Directory
141 {
142 public:
143 virtual ~Directory() throw() = 0;
144
145 /**
146 * \brief Check access permissions on the given file.
147 *
148 * Backend function for POSIX access and faccessat functions.
149 *
150 * \param path The path relative to this directory.
151 * Note: \a path is relative to this directory and
152 * may contain subdirectories.
153 * \param mode The access mode to check.
154 * \param flags The flags as in POSIX faccessat (AT_EACCESS,
155 * AT_SYMLINK_NOFOLLOW).
156 * \return 0 on success, or <0 on error.
157 */
158 virtual int faccessat(const char *path, int mode, int flags) throw() = 0;
159
160 /**
161 * \brief Create a new subdirectory.
162 *
163 * Backend for POSIX mkdir and mkdirat function calls.
164 *
165 * \param path The name of the subdirectory to create.
166 * Note: \a path is relative to this directory and
167 * may contain subdirectories.
168 * \param mode The file mode to use for the new directory.
169 * \return 0 on success, or <0 on error. -ENOTDIR if this or some component
170 * in path is is not a directory.
171 */
172 virtual int mkdir(const char *path, mode_t mode) throw() = 0;
173
174 /**
175 * \brief Unlink the given file from that directory.
176 *
177 * Backend for the POSIX unlink and unlinkat functions.
178 *
179 * \param path The name to the file to unlink. Note: \a path
180 * is relative to this directory and may
181 * contain subdirectories.
182 * \return 0 on success, or <0 on error.
183 */
184 virtual int unlink(const char *path) throw() = 0;
185
186 /**
187 * \brief Rename the given file.
188 *
189 * Backend for the POSIX rename, renameat functions.
190 *
191 * \param src_path The old name to the file to rename.
192 * Note: \a src_path is relative to this
193 * directory and may contain subdirectories.
194 * \param dst_path The new name for the file.
195 * Note: \a dst_path is relative to this
196 * directory and may contain subdirectories.
197 * \return 0 on success, or <0 on error.
198 */
199 virtual int rename(const char *src_path, const char *dst_path) throw() = 0;
200
201 /**
202 * \brief Create a hard link (second name) for the given file.
203 *
204 * Backend for the POSIX link and linkat functions.
205 *
206 * \param src_path The old name to the file.
207 * Note: \a src_path is relative to this
208 * directory and may contain subdirectories.
209 * \param dst_path The new (second) name for the file.
210 * Note: \a dst_path is relative to this
211 * directory and may contain subdirectories.
212 * \return 0 on success, or <0 on error.
213 */
214 virtual int link(const char *src_path, const char *dst_path) throw() = 0;
215
216 /**
217 * \brief Create a symbolic link for the given file.
218 *
219 * Backend for the POSIX symlink and symlinkat functions.
220 *
221 * \param src_path The old name to the file.
222 * Note: \a src_path shall be an absolute path.
223 * \param dst_path The name for symlink.
224 * Note: \a dst_path is relative to this
225 * directory and may contain subdirectories.
226 * \return 0 on success, or <0 on error.
227 */
228 virtual int symlink(const char *src_path, const char *dst_path) throw() = 0;
229
230 /**
231 * \brief Delete an empty directory.
232 *
233 * Backend for POSIX rmdir, rmdirat functions.
234 *
235 * \param path The name of the directory to remove.
236 * Note: \a path is relative to this
237 * directory and may contain subdirectories.
238 * \return 0 on success, or <0 on error.
239 */
240 virtual int rmdir(const char *path) throw() = 0;
241 virtual int openat(const char *path, int flags, mode_t mode,
242 cxx::Ref_ptr<File> *f) throw() = 0;
243
244 virtual ssize_t getdents(char *buf, size_t sizebytes) throw() = 0;
245
246 virtual int fchmodat(const char *pathname,
247 mode_t mode, int flags) throw() = 0;
248
249 virtual int utimensat(const char *pathname,
250 const struct timespec times[2], int flags) throw() = 0;
251
252 /**
253 * \internal
254 */
255 virtual int get_entry(const char *, int, mode_t, cxx::Ref_ptr<File> *) throw() = 0;
256 };
257
258 inline
~Directory()259 Directory::~Directory() throw()
260 {}
261
262 /**
263 * \brief Interface for a POSIX file that provides regular file semantics.
264 *
265 * Real objects use always the combined L4Re::Vfs::File interface.
266 */
267 class Regular_file
268 {
269 public:
270 virtual ~Regular_file() throw() = 0;
271
272 /**
273 * \brief Get an L4Re::Dataspace object for the file.
274 *
275 * This is used as a backend for POSIX mmap and mmap2 functions.
276 * \note mmap is not possible if the function returns an invalid
277 * capability.
278 *
279 * \return A capability to an L4Re::Dataspace, that represents the file
280 * contents in an L4Re way.
281 */
282 virtual L4::Cap<L4Re::Dataspace> data_space() const throw() = 0;
283
284 /**
285 * \brief Read one or more blocks of data from the file.
286 *
287 * This function acts as backend for POSIX read and readv calls and
288 * reads data starting for the f_pos pointer of that open file.
289 * The file pointer is advanced according to the number of red bytes.
290 *
291 * \return The number of bytes red from the file. or <0 on error-
292 */
293 virtual ssize_t readv(const struct iovec*, int iovcnt) throw() = 0;
294
295 /**
296 * \brief Write one or more blocks of data to the file.
297 *
298 * This function acts as backend for POSIX write and writev calls.
299 * The data is written starting at the current file pointer and the
300 * file pointer must be advanced according to the number of written
301 * bytes.
302 *
303 * \return The number of bytes written to the file, or <0 on error.
304 */
305 virtual ssize_t writev(const struct iovec*, int iovcnt) throw() = 0;
306
307 virtual ssize_t preadv(const struct iovec *iov, int iovcnt, off64_t offset) throw() = 0;
308 virtual ssize_t pwritev(const struct iovec *iov, int iovcnt, off64_t offset) throw() = 0;
309
310 /**
311 * \brief Change the file pointer.
312 *
313 * This is the backend for POSIX seek, lseek and friends.
314 *
315 * \return The new file position, or <0 on error.
316 */
317 virtual off64_t lseek64(off64_t, int) throw() = 0;
318
319
320 /**
321 * \brief Truncate the file at the given position.
322 *
323 * This function is the backend for truncate and friends.
324 * \param pos The offset at which the file shall be truncated.
325 * \return 0 on success, or <0 on error.
326 */
327 virtual int ftruncate64(off64_t pos) throw() = 0;
328
329 /**
330 * \brief Sync the data and meta data to persistent storage.
331 *
332 * This is the backend for POSIX fsync.
333 */
334 virtual int fsync() const throw() = 0;
335
336 /**
337 * \brief Sync the data to persistent storage.
338 *
339 * This is the backend for POSIX fdatasync.
340 */
341 virtual int fdatasync() const throw() = 0;
342
343 /**
344 * \brief Test if the given lock can be placed in the file.
345 *
346 * This function is used as backend for fcntl F_GETLK commands.
347 * \param lock The lock that shall be placed on the file. The
348 * \a l_type member will contain `F_UNLCK` if the lock
349 * could be placed.
350 * \return 0 on success, <0 on error.
351 */
352 virtual int get_lock(struct flock64 *lock) throw() = 0;
353
354 /**
355 * \brief Acquire or release the given lock on the file.
356 *
357 * This function is used as backend for fcntl F_SETLK and F_SETLKW commands.
358 * \param lock The lock that shall be placed on the file.
359 * \param wait If true, then block if there is a conflicting lock on the file.
360 * \return 0 on success, <0 on error.
361 */
362 virtual int set_lock(struct flock64 *lock, bool wait) throw() = 0;
363 };
364
365 inline
~Regular_file()366 Regular_file::~Regular_file() throw()
367 {}
368
369 class Socket
370 {
371 public:
372 virtual ~Socket() throw() = 0;
373 virtual int bind(sockaddr const *, socklen_t) throw() = 0;
374 virtual int connect(sockaddr const *, socklen_t) throw() = 0;
375 virtual ssize_t send(void const *, size_t, int) throw() = 0;
376 virtual ssize_t recv(void *, size_t, int) throw() = 0;
377 virtual ssize_t sendto(void const *, size_t, int, sockaddr const *, socklen_t) throw() = 0;
378 virtual ssize_t recvfrom(void *, size_t, int, sockaddr *, socklen_t *) throw() = 0;
379 virtual ssize_t sendmsg(msghdr const *, int) throw() = 0;
380 virtual ssize_t recvmsg(msghdr *, int) throw() = 0;
381 virtual int getsockopt(int level, int opt, void *, socklen_t *) throw() = 0;
382 virtual int setsockopt(int level, int opt, void const *, socklen_t) throw() = 0;
383 virtual int listen(int) throw() = 0;
384 virtual int accept(sockaddr *addr, socklen_t *) throw() = 0;
385 virtual int shutdown(int) throw() = 0;
386
387 virtual int getsockname(sockaddr *, socklen_t *) throw() = 0;
388 virtual int getpeername(sockaddr *, socklen_t *) throw() = 0;
389 };
390
391 inline
~Socket()392 Socket::~Socket() throw()
393 {}
394
395 /**
396 * \brief Interface for a POSIX file that provides special file semantics.
397 *
398 * Real objects use always the combined L4Re::Vfs::File interface.
399 */
400 class Special_file
401 {
402 public:
403 virtual ~Special_file() throw() = 0;
404
405 /**
406 * \brief The famous IO control.
407 *
408 * Backend for POSIX generic object invocation ioctl.
409 *
410 * \param cmd The ioctl command.
411 * \param args The arguments for the ioctl, usually some kind
412 * of pointer.
413 * \return >=0 on success, or <0 on error.
414 */
415 virtual int ioctl(unsigned long cmd, va_list args) throw() = 0;
416 };
417
418 inline
~Special_file()419 Special_file::~Special_file() throw()
420 {}
421
422 /**
423 * \brief The basic interface for an open POSIX file.
424 *
425 * An open POSIX file can be anything that hides behind a
426 * POSIX file descriptor. This means that even a directories
427 * are files. An open file can be anything from a directory to a
428 * special device file so see Generic_file, Regular_file, Directory,
429 * and Special_file for more information.
430 *
431 * \note For implementing a backend for the L4Re::Vfs you may use
432 * L4Re::Vfs::Be_file as a base class.
433 *
434 */
435 class File :
436 public Generic_file,
437 public Regular_file,
438 public Directory,
439 public Special_file,
440 public Socket
441 {
442 friend class Mount_tree;
443
444 private:
445 void operator = (File const &);
446
447 protected:
File()448 File() throw() : _ref_cnt(0) {}
File(File const &)449 File(File const &)
450 : Generic_file(),Regular_file(), Directory(), Special_file(), _ref_cnt(0)
451 {}
452
453 public:
454
455 const char *get_mount(const char *path, cxx::Ref_ptr<File> *dir,
456 cxx::Ref_ptr<Mount_tree> *mt = 0) throw();
457
458 int openat(const char *path, int flags, mode_t mode,
459 cxx::Ref_ptr<File> *f) throw();
460
add_ref()461 void add_ref() throw() { ++_ref_cnt; }
remove_ref()462 int remove_ref() throw() { return --_ref_cnt; }
463
464 virtual ~File() throw() = 0;
465
mount_tree()466 cxx::Ref_ptr<Mount_tree> mount_tree() const throw()
467 { return _mount_tree; }
468
469 private:
470 int _ref_cnt;
471 cxx::Ref_ptr<Mount_tree> _mount_tree;
472
473 };
474
475 inline
~File()476 File::~File() throw()
477 {}
478
479 class Path
480 {
481 private:
482 char const *_p;
483 unsigned _l;
484
485 public:
Path()486 Path() throw() : _p(0), _l(0) {}
487
Path(char const * p)488 explicit Path(char const *p) throw() : _p(p)
489 { for (_l = 0; *p; ++p, ++_l) ; }
490
Path(char const * p,unsigned l)491 Path(char const *p, unsigned l) throw() : _p(p), _l(l)
492 {}
493
494 static bool __is_sep(char s) throw();
495
496 Path cmp_path(char const *prefix) const throw();
497
498 struct Invalid_ptr;
499 operator Invalid_ptr const * () const
500 { return reinterpret_cast<Invalid_ptr const *>(_p); }
501
length()502 unsigned length() const { return _l; }
path()503 char const *path() const { return _p; }
504
empty()505 bool empty() const { return _l == 0; }
506
is_sep(unsigned offset)507 bool is_sep(unsigned offset) const { return __is_sep(_p[offset]); }
508
strip_sep()509 bool strip_sep()
510 {
511 bool s = false;
512 for (; __is_sep(*_p) && _l; ++_p, --_l)
513 s = true;
514 return s;
515 }
516
first()517 Path first() const
518 {
519 unsigned i;
520 for (i = 0; i < _l && !is_sep(i); ++i)
521 ;
522
523 return Path(_p, i);
524 }
525
strip_first()526 Path strip_first()
527 {
528 Path r = first();
529 _p += r.length();
530 _l -= r.length();
531 strip_sep();
532 return r;
533 }
534
535 };
536
537
538 /**
539 * \internal
540 * \brief Internal representation for a tree of mount points.
541 * \note You should never need to deal with a Mount_tree objects
542 * directly.
543 */
544 class Mount_tree
545 {
546 public:
547
548 explicit Mount_tree(char *n) throw();
549
550 Path lookup(Path const &path, cxx::Ref_ptr<Mount_tree> *mt,
551 cxx::Ref_ptr<Mount_tree> *mp = 0) throw();
552
553 Path find(Path const &p, cxx::Ref_ptr<Mount_tree> *t) throw();
554
mount()555 cxx::Ref_ptr<File> mount() const
556 { return _mount; }
557
mount(cxx::Ref_ptr<File> const & m)558 void mount(cxx::Ref_ptr<File> const &m)
559 {
560 m->_mount_tree = cxx::ref_ptr(this);
561 _mount = m;
562 }
563
564 static int create_tree(cxx::Ref_ptr<Mount_tree> const &root,
565 char const *path,
566 cxx::Ref_ptr<File> const &dir) throw();
567
568 void add_child_node(cxx::Ref_ptr<Mount_tree> const &cld);
569
570 virtual ~Mount_tree() throw() = 0;
571
add_ref()572 void add_ref() throw() { ++_ref_cnt; }
remove_ref()573 int remove_ref() throw() { return --_ref_cnt; }
574
575 private:
576 friend class Real_mount_tree;
577
578 int _ref_cnt;
579 char *_name;
580 cxx::Ref_ptr<Mount_tree> _cld;
581 cxx::Ref_ptr<Mount_tree> _sib;
582 cxx::Ref_ptr<File> _mount;
583 };
584
585 inline
~Mount_tree()586 Mount_tree::~Mount_tree() throw()
587 {}
588
589 inline bool
__is_sep(char s)590 Path::__is_sep(char s) throw()
591 { return s == '/'; }
592
593 inline Path
cmp_path(char const * n)594 Path::cmp_path(char const *n) const throw()
595 {
596 char const *p = _p;
597 for (; *p && !__is_sep(*p) && *n; ++p, ++n)
598 if (*p != *n)
599 return Path();
600
601 if (*n || (*p && !__is_sep(*p)))
602 return Path();
603
604 return Path(p, _l - (p - _p));
605 }
606
607 inline
Mount_tree(char * n)608 Mount_tree::Mount_tree(char *n) throw()
609 : _ref_cnt(0), _name(n)
610 {}
611
612 inline Path
find(Path const & p,cxx::Ref_ptr<Mount_tree> * t)613 Mount_tree::find(Path const &p, cxx::Ref_ptr<Mount_tree> *t) throw()
614 {
615 if (!_cld)
616 return Path();
617
618 for (cxx::Ref_ptr<Mount_tree> x = _cld; x; x = x->_sib)
619 {
620 Path const r = p.cmp_path(x->_name);
621 if (r)
622 {
623 *t = x;
624 return r;
625 }
626 }
627
628 return Path();
629 }
630
631 inline Path
lookup(Path const & path,cxx::Ref_ptr<Mount_tree> * mt,cxx::Ref_ptr<Mount_tree> * mp)632 Mount_tree::lookup(Path const &path, cxx::Ref_ptr<Mount_tree> *mt,
633 cxx::Ref_ptr<Mount_tree> *mp) throw()
634 {
635 cxx::Ref_ptr<Mount_tree> x(this);
636 Path p = path;
637
638 if (p.first().cmp_path("."))
639 p.strip_first();
640
641 Path last_mp = p;
642
643 if (mp)
644 *mp = x;;
645
646 while (1)
647 {
648 Path r = x->find(p, &x);
649
650 if (!r)
651 {
652 if (mp)
653 return last_mp;
654
655 if (mt)
656 *mt = x;
657
658 return p;
659 }
660
661 r.strip_sep();
662
663 if (mp && x->_mount)
664 {
665 last_mp = r;
666 *mp = x;
667 }
668
669 if (r.empty())
670 {
671 if (mt)
672 *mt = x;
673
674 if (mp)
675 return last_mp;
676 else
677 return r;
678 }
679
680 p = r;
681 }
682 }
683
684 inline
685 void
add_child_node(cxx::Ref_ptr<Mount_tree> const & cld)686 Mount_tree::add_child_node(cxx::Ref_ptr<Mount_tree> const &cld)
687 {
688 cld->_sib = _cld;
689 _cld = cld;
690 }
691
692
693 inline
694 const char *
get_mount(const char * path,cxx::Ref_ptr<File> * dir,cxx::Ref_ptr<Mount_tree> * mt)695 File::get_mount(const char *path, cxx::Ref_ptr<File> *dir,
696 cxx::Ref_ptr<Mount_tree> *mt) throw()
697 {
698 if (!_mount_tree)
699 {
700 *dir = cxx::ref_ptr(this);
701 return path;
702 }
703
704 cxx::Ref_ptr<Mount_tree> mp;
705 Path p = _mount_tree->lookup(Path(path), mt, &mp);
706 if (mp->mount())
707 {
708 *dir = mp->mount();
709 return p.path();
710 }
711 else
712 {
713 *dir = cxx::ref_ptr(this);
714 return path;
715 }
716 }
717
718 inline int
openat(const char * path,int flags,mode_t mode,cxx::Ref_ptr<File> * f)719 File::openat(const char *path, int flags, mode_t mode,
720 cxx::Ref_ptr<File> *f) throw()
721 {
722 cxx::Ref_ptr<File> dir;
723 cxx::Ref_ptr<Mount_tree> mt;
724 path = get_mount(path, &dir, &mt);
725
726 int res = dir->get_entry(path, flags, mode, f);
727
728 if (res < 0)
729 return res;
730
731 if (!(*f)->_mount_tree && mt)
732 (*f)->_mount_tree = mt;
733
734 return res;
735 }
736
737 /**
738 * \brief Interface for the POSIX memory management.
739 * \note This interface exists usually as a singleton as superclass
740 * of L4Re::Vfs::Ops.
741 *
742 * An implementation for this interface is in l4/l4re_vfs/impl/vfs_impl.h
743 * and used by the l4re_vfs library or by the VFS implementation in ldso.
744 */
745 class Mman
746 {
747 public:
748 /// Backend for the mmap2 system call.
749 virtual int mmap2(void *start, size_t len, int prot, int flags, int fd,
750 off_t offset, void **ptr) throw() = 0;
751
752 /// Backend for the munmap system call.
753 virtual int munmap(void *start, size_t len) throw() = 0;
754
755 /// Backend for the mremap system call.
756 virtual int mremap(void *old, size_t old_sz, size_t new_sz, int flags,
757 void **new_addr) throw() = 0;
758
759 /// Backend for the mprotect system call.
760 virtual int mprotect(const void *a, size_t sz, int prot) throw() = 0;
761
762 /// Backend for the msync system call
763 virtual int msync(void *addr, size_t len, int flags) throw() = 0;
764
765 /// Backend for the madvice system call
766 virtual int madvise(void *addr, size_t len, int advice) throw() = 0;
767
768 virtual ~Mman() throw() = 0;
769 };
770
771 inline
~Mman()772 Mman::~Mman() throw() {}
773
774 class File_factory
775 {
776 private:
777 int _ref_cnt = 0;
778 int _proto = 0;
779 char const *_proto_name = 0;
780
781 template<typename T> friend struct cxx::Default_ref_counter;
add_ref()782 void add_ref() throw() { ++_ref_cnt; }
remove_ref()783 int remove_ref() throw() { return --_ref_cnt; }
784
785 public:
File_factory(int proto)786 explicit File_factory(int proto) : _proto(proto) {}
File_factory(char const * proto_name)787 explicit File_factory(char const *proto_name) : _proto_name(proto_name) {}
File_factory(int proto,char const * proto_name)788 File_factory(int proto, char const *proto_name)
789 : _proto(proto), _proto_name(proto_name)
790 {}
791
792 File_factory(File_factory const &) = delete;
793 File_factory &operator = (File_factory const &) = delete;
794
proto_name()795 char const *proto_name() const { return _proto_name; }
proto()796 int proto() const { return _proto; }
797
798 virtual ~File_factory() throw() = 0;
799 virtual cxx::Ref_ptr<File> create(L4::Cap<void> file) = 0;
800 };
801
~File_factory()802 inline File_factory::~File_factory() throw() {}
803
804 template<typename IFACE, typename IMPL>
805 class File_factory_t : public File_factory
806 {
807 public:
File_factory_t()808 File_factory_t()
809 : File_factory(IFACE::Protocol, L4::kobject_typeid<IFACE>()->name())
810 {}
811
create(L4::Cap<void> file)812 cxx::Ref_ptr<File> create(L4::Cap<void> file)
813 { return cxx::ref_ptr(new IMPL(L4::cap_cast<IFACE>(file))); }
814 };
815
816 /**
817 * \brief Basic interface for an L4Re::Vfs file system.
818 * \note For implementing a special file system you may
819 * use L4Re::Vfs::Be_file_system as a base class.
820 *
821 * The may purpose of this interface is that there is a
822 * single object for each supported file-system type (e.g., ext2, vfat)
823 * exists in your application and is registered at the L4Re::Vfs::Fs
824 * singleton available in via L4Re::Vfs::vfs_ops.
825 * At the end the POSIX mount function call the File_system::mount method
826 * for the given file-system type given in mount.
827 *
828 */
829 class File_system
830 {
831 protected:
832 File_system *_next;
833
834 public:
File_system()835 File_system() throw() : _next(0) {}
836 /**
837 * \brief Returns the type of the file system, used in mount as fstype
838 * argument.
839 * \note This method is already provided by Be_file_system.
840 */
841 virtual char const *type() const throw() = 0;
842
843 /**
844 * \brief Create a directory object \a dir representing \a source
845 * mounted with this file system.
846 *
847 * \param source The path to the source device to mount. This may
848 * also be some URL or anything file-system specific.
849 * \param mountflags The mount flags as specified in the POSIX
850 * mount call.
851 * \param data The data as specified in the POSIX mount call. The
852 * contents are file-system specific.
853 * \retval dir A new directory object representing the file-system
854 * root directory.
855 * \return 0 on success, and <0 on error (e.g. -EINVAL).
856 *
857 */
858 virtual int mount(char const *source, unsigned long mountflags,
859 void const *data, cxx::Ref_ptr<File> *dir) throw() = 0;
860
861 virtual ~File_system() throw() = 0;
862
863 /**
864 * \internal
865 * \brief Get the next file system in the internal registry.
866 */
next()867 File_system *next() const throw() { return _next; }
next()868 File_system *&next() throw() { return _next; }
next(File_system * n)869 void next(File_system *n) throw() { _next = n; }
870 };
871
872 inline
~File_system()873 File_system::~File_system() throw()
874 {}
875
876 /**
877 * \brief POSIX File-system related functionality.
878 * \note This class usually exists as a singleton as a superclass
879 * of L4Re::Vfs::Ops (\see L4Re::Vfs::vfs_ops).
880 */
881 class Fs
882 {
883 public:
884 /**
885 * \brief Get the L4Re::Vfs::File for the file descriptor \a fd.
886 * \param fd The POSIX file descriptor number.
887 * \return A pointer to the File object, or 0 if \a fd is not open.
888 */
889 virtual cxx::Ref_ptr<File> get_file(int fd) throw() = 0;
890
891 /// Get the directory object for the applications root directory.
892 virtual cxx::Ref_ptr<File> get_root() throw() = 0;
893
894 /// Get the directory object for the applications current working directory.
get_cwd()895 virtual cxx::Ref_ptr<File> get_cwd() throw() { return get_root(); }
896
897 /// Set the current working directory for the application.
set_cwd(cxx::Ref_ptr<File> const &)898 virtual void set_cwd(cxx::Ref_ptr<File> const &) throw() {}
899
900 /**
901 * \brief Allocate the next free file descriptor.
902 * \param f The file to assign to that file descriptor.
903 * \return the allocated file descriptor, or -EMFILE on error.
904 */
905 virtual int alloc_fd(cxx::Ref_ptr<File> const &f = cxx::Ref_ptr<>::Nil) throw() = 0;
906
907 /**
908 * \brief Set the file object referenced by the file descriptor \a fd.
909 * \param fd The file descriptor to set to \a f.
910 * \param f The file object to assign.
911 * \return A pair of a pointer to the file object that was previously
912 * assigned to fd (`first`) and a return value (`second`).
913 * `second` contains `-#EBADF` if the passed file descriptor is
914 * outside the valid range. `first` contains a Nil pointer in that
915 * case. On success, `second` contains 0.
916 */
917 virtual cxx::Pair<cxx::Ref_ptr<File>, int>
918 set_fd(int fd, cxx::Ref_ptr<File> const &f = cxx::Ref_ptr<>::Nil) throw() = 0;
919
920 /**
921 * \brief Free the file descriptor \a fd.
922 * \param fd The file descriptor to free.
923 * \return A pointer to the file object that was assigned to the fd.
924 */
925 virtual cxx::Ref_ptr<File> free_fd(int fd) throw() = 0;
926
927 /**
928 * \brief Mount a given file object at the given global path in the VFS.
929 * \param path The global path to mount \a dir at.
930 * \param dir A pointer to the file/directory object that shall be mounted
931 * at \a path.
932 * \return 0 on success, or <0 on error.
933 */
934 virtual int mount(char const *path, cxx::Ref_ptr<File> const &dir) throw() = 0;
935
936 /**
937 * \internal
938 * \brief Register a file-system type in the global registry.
939 * \note this is done automatically by Be_file_system.
940 * \param f A pointer to the file system to register.
941 * \return 0 on success, or <0 on error.
942 */
943 virtual int register_file_system(File_system *f) throw() = 0;
944
945 /**
946 * \internal
947 * \brief Removed the given file system from the global registry.
948 * \note This is done automatically by Be_file_system.
949 * \param f The file system instance to remove from the registry.
950 * \return 0 on success, <0 on error.
951 */
952 virtual int unregister_file_system(File_system *f) throw() = 0;
953
954 /**
955 * \internal
956 * \brief Find the file-system object for the given file-system type.
957 * \note This function is used by the mount.
958 * \param fstype The file-system type (e.g. ext, vfat).
959 * \return A pointer to the file-system object, or 0 on error.
960 */
961 virtual File_system *get_file_system(char const *fstype) throw() = 0;
962
963 /**
964 * \brief Backend for the POSIX mount call.
965 */
966 int mount(char const *source, char const *target,
967 char const *fstype, unsigned long mountflags,
968 void const *data) throw();
969
970 virtual int register_file_factory(cxx::Ref_ptr<File_factory> f) throw() = 0;
971 virtual int unregister_file_factory(cxx::Ref_ptr<File_factory> f) throw() = 0;
972 virtual cxx::Ref_ptr<File_factory> get_file_factory(int proto) throw() = 0;
973 virtual cxx::Ref_ptr<File_factory> get_file_factory(char const *proto_name) throw() = 0;
974
975 virtual ~Fs() = 0;
976 };
977
978 inline int
mount(char const * source,char const * target,char const * fstype,unsigned long mountflags,void const * data)979 Fs::mount(char const *source, char const *target,
980 char const *fstype, unsigned long mountflags,
981 void const *data) throw()
982 {
983 File_system *fs = get_file_system(fstype);
984
985 if (!fs)
986 return -ENODEV;
987
988 cxx::Ref_ptr<File> dir;
989 int res = fs->mount(source, mountflags, data, &dir);
990
991 if (res < 0)
992 return res;
993
994 return mount(target, dir);
995 }
996
997 inline
~Fs()998 Fs::~Fs()
999 {}
1000
1001 /**
1002 * \brief Interface for the POSIX backends for an application.
1003 * \note There usually exists a singe instance of this interface
1004 * available via L4Re::Vfs::vfs_ops that is used for all
1005 * kinds of C-Library functions.
1006 */
1007 class Ops : public Mman, public Fs
1008 {
1009 public:
1010 virtual void *malloc(size_t bytes) noexcept = 0;
1011 virtual void free(void *mem) noexcept = 0;
1012 virtual ~Ops() throw() = 0;
1013
strndup(char const * str,unsigned l)1014 char *strndup(char const *str, unsigned l) noexcept
1015 {
1016 unsigned len;
1017 for (len = 0; str[len] && len < l; ++len)
1018 ;
1019
1020 if (len == 0)
1021 return nullptr;
1022
1023 ++len;
1024
1025 char *b = (char *)this->malloc(len);
1026 if (b == nullptr)
1027 return nullptr;
1028
1029 char *r = b;
1030 for (; len - 1 > 0 && *str; --len, ++b, ++str)
1031 *b = *str;
1032
1033 *b = 0;
1034 return r;
1035 }
1036
1037 };
1038
1039 inline
~Ops()1040 Ops::~Ops() throw()
1041 {}
1042
1043 }}
1044
1045 #endif
1046
1047