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