L4Re - L4 Runtime Environment
vfs.h
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/ref_ptr>
42 
43 namespace L4Re {
47 namespace Vfs {
48 
49 class Mount_tree;
50 class File;
51 
62 {
63 public:
64  virtual ~Generic_file() throw() = 0;
76  virtual int unlock_all_locks() throw() = 0;
77 
86  virtual int fstat64(struct stat64 *buf) const throw() = 0;
87 
93  virtual int fchmod(mode_t) throw() = 0;
94 
104  virtual int get_status_flags() const throw() = 0;
105 
121  virtual int set_status_flags(long flags) throw() = 0;
122 
123  virtual int utime(const struct utimbuf *) throw() = 0;
124  virtual int utimes(const struct timeval [2]) throw() = 0;
125  virtual ssize_t readlink(char *, size_t) = 0;
126 };
127 
128 inline
129 Generic_file::~Generic_file() throw()
130 {}
131 
140 {
141 public:
142  virtual ~Directory() throw() = 0;
143 
157  virtual int faccessat(const char *path, int mode, int flags) throw() = 0;
158 
171  virtual int mkdir(const char *path, mode_t mode) throw() = 0;
172 
183  virtual int unlink(const char *path) throw() = 0;
184 
198  virtual int rename(const char *src_path, const char *dst_path) throw() = 0;
199 
213  virtual int link(const char *src_path, const char *dst_path) throw() = 0;
214 
227  virtual int symlink(const char *src_path, const char *dst_path) throw() = 0;
228 
239  virtual int rmdir(const char *path) throw() = 0;
240  virtual int openat(const char *path, int flags, mode_t mode,
241  cxx::Ref_ptr<File> *f) throw() = 0;
242 
243  virtual ssize_t getdents(char *buf, size_t sizebytes) throw() = 0;
244 
248  virtual int get_entry(const char *, int, mode_t, cxx::Ref_ptr<File> *) throw() = 0;
249 };
250 
251 inline
252 Directory::~Directory() throw()
253 {}
254 
261 {
262 public:
263  virtual ~Regular_file() throw() = 0;
264 
275  virtual L4::Cap<L4Re::Dataspace> data_space() const throw() = 0;
276 
286  virtual ssize_t readv(const struct iovec*, int iovcnt) throw() = 0;
287 
298  virtual ssize_t writev(const struct iovec*, int iovcnt) throw() = 0;
299 
300  virtual ssize_t preadv(const struct iovec *iov, int iovcnt, off64_t offset) throw() = 0;
301  virtual ssize_t pwritev(const struct iovec *iov, int iovcnt, off64_t offset) throw() = 0;
302 
310  virtual off64_t lseek64(off64_t, int) throw() = 0;
311 
312 
320  virtual int ftruncate64(off64_t pos) throw() = 0;
321 
327  virtual int fsync() const throw() = 0;
328 
334  virtual int fdatasync() const throw() = 0;
335 
345  virtual int get_lock(struct flock64 *lock) throw() = 0;
346 
355  virtual int set_lock(struct flock64 *lock, bool wait) throw() = 0;
356 };
357 
358 inline
359 Regular_file::~Regular_file() throw()
360 {}
361 
362 class Socket
363 {
364 public:
365  virtual ~Socket() throw() = 0;
366  virtual int bind(sockaddr const *, socklen_t) throw() = 0;
367  virtual int connect(sockaddr const *, socklen_t) throw() = 0;
368  virtual ssize_t send(void const *, size_t, int) throw() = 0;
369  virtual ssize_t recv(void *, size_t, int) throw() = 0;
370  virtual ssize_t sendto(void const *, size_t, int, sockaddr const *, socklen_t) throw() = 0;
371  virtual ssize_t recvfrom(void *, size_t, int, sockaddr *, socklen_t *) throw() = 0;
372  virtual ssize_t sendmsg(msghdr const *, int) throw() = 0;
373  virtual ssize_t recvmsg(msghdr *, int) throw() = 0;
374  virtual int getsockopt(int level, int opt, void *, socklen_t *) throw() = 0;
375  virtual int setsockopt(int level, int opt, void const *, socklen_t) throw() = 0;
376  virtual int listen(int) throw() = 0;
377  virtual int accept(sockaddr *addr, socklen_t *) throw() = 0;
378  virtual int shutdown(int) throw() = 0;
379 
380  virtual int getsockname(sockaddr *, socklen_t *) throw() = 0;
381  virtual int getpeername(sockaddr *, socklen_t *) throw() = 0;
382 };
383 
384 inline
385 Socket::~Socket() throw()
386 {}
387 
394 {
395 public:
396  virtual ~Special_file() throw() = 0;
397 
408  virtual int ioctl(unsigned long cmd, va_list args) throw() = 0;
409 };
410 
411 inline
412 Special_file::~Special_file() throw()
413 {}
414 
428 class File :
429  public Generic_file,
430  public Regular_file,
431  public Directory,
432  public Special_file,
433  public Socket
434 {
435  friend class Mount_tree;
436 
437 private:
438  void operator = (File const &);
439 
440 protected:
441  File() throw() : _ref_cnt(0) {}
442  File(File const &)
443  : Generic_file(),Regular_file(), Directory(), Special_file(), _ref_cnt(0)
444  {}
445 
446 public:
447 
448  const char *get_mount(const char *path, cxx::Ref_ptr<File> *dir,
449  cxx::Ref_ptr<Mount_tree> *mt = 0) throw();
450 
451  int openat(const char *path, int flags, mode_t mode,
452  cxx::Ref_ptr<File> *f) throw();
453 
454  void add_ref() throw() { ++_ref_cnt; }
455  int remove_ref() throw() { return --_ref_cnt; }
456 
457  virtual ~File() throw() = 0;
458 
459  cxx::Ref_ptr<Mount_tree> mount_tree() const throw()
460  { return _mount_tree; }
461 
462 private:
463  int _ref_cnt;
464  cxx::Ref_ptr<Mount_tree> _mount_tree;
465 
466 };
467 
468 inline
469 File::~File() throw()
470 {}
471 
472 class Path
473 {
474 private:
475  char const *_p;
476  unsigned _l;
477 
478 public:
479  Path() throw() : _p(0), _l(0) {}
480 
481  explicit Path(char const *p) throw() : _p(p)
482  { for (_l = 0; *p; ++p, ++_l) ; }
483 
484  Path(char const *p, unsigned l) throw() : _p(p), _l(l)
485  {}
486 
487  static bool __is_sep(char s) throw();
488 
489  Path cmp_path(char const *prefix) const throw();
490 
491  struct Invalid_ptr;
492  operator Invalid_ptr const * () const
493  { return reinterpret_cast<Invalid_ptr const *>(_p); }
494 
495  unsigned length() const { return _l; }
496  char const *path() const { return _p; }
497 
498  bool empty() const { return _l == 0; }
499 
500  bool is_sep(unsigned offset) const { return __is_sep(_p[offset]); }
501 
502  bool strip_sep()
503  {
504  bool s = false;
505  for (; __is_sep(*_p) && _l; ++_p, --_l)
506  s = true;
507  return s;
508  }
509 
510  Path first() const
511  {
512  unsigned i;
513  for (i = 0; i < _l && !is_sep(i); ++i)
514  ;
515 
516  return Path(_p, i);
517  }
518 
519  Path strip_first()
520  {
521  Path r = first();
522  _p += r.length();
523  _l -= r.length();
524  strip_sep();
525  return r;
526  }
527 
528 };
529 
530 
537 class Mount_tree
538 {
539 public:
540 
541  explicit Mount_tree(char *n) throw();
542 
543  Path lookup(Path const &path, cxx::Ref_ptr<Mount_tree> *mt,
544  cxx::Ref_ptr<Mount_tree> *mp = 0) throw();
545 
546  Path find(Path const &p, cxx::Ref_ptr<Mount_tree> *t) throw();
547 
548  cxx::Ref_ptr<File> mount() const
549  { return _mount; }
550 
551  void mount(cxx::Ref_ptr<File> const &m)
552  {
553  m->_mount_tree = cxx::ref_ptr(this);
554  _mount = m;
555  }
556 
557  static int create_tree(cxx::Ref_ptr<Mount_tree> const &root,
558  char const *path,
559  cxx::Ref_ptr<File> const &dir) throw();
560 
561  void add_child_node(cxx::Ref_ptr<Mount_tree> const &cld);
562 
563  virtual ~Mount_tree() throw() = 0;
564 
565  void add_ref() throw() { ++_ref_cnt; }
566  int remove_ref() throw() { return --_ref_cnt; }
567 
568 private:
569  friend class Real_mount_tree;
570 
571  int _ref_cnt;
572  char *_name;
575  cxx::Ref_ptr<File> _mount;
576 };
577 
578 inline
579 Mount_tree::~Mount_tree() throw()
580 {}
581 
582 inline bool
583 Path::__is_sep(char s) throw()
584 { return s == '/'; }
585 
586 inline Path
587 Path::cmp_path(char const *n) const throw()
588 {
589  char const *p = _p;
590  for (; *p && !__is_sep(*p) && *n; ++p, ++n)
591  if (*p != *n)
592  return Path();
593 
594  if (*n || (*p && !__is_sep(*p)))
595  return Path();
596 
597  return Path(p, _l - (p - _p));
598 }
599 
600 inline
601 Mount_tree::Mount_tree(char *n) throw()
602 : _ref_cnt(0), _name(n)
603 {}
604 
605 inline Path
606 Mount_tree::find(Path const &p, cxx::Ref_ptr<Mount_tree> *t) throw()
607 {
608  if (!_cld)
609  return Path();
610 
611  for (cxx::Ref_ptr<Mount_tree> x = _cld; x; x = x->_sib)
612  {
613  Path const r = p.cmp_path(x->_name);
614  if (r)
615  {
616  *t = x;
617  return r;
618  }
619  }
620 
621  return Path();
622 }
623 
624 inline Path
625 Mount_tree::lookup(Path const &path, cxx::Ref_ptr<Mount_tree> *mt,
626  cxx::Ref_ptr<Mount_tree> *mp) throw()
627 {
628  cxx::Ref_ptr<Mount_tree> x(this);
629  Path p = path;
630 
631  if (p.first().cmp_path("."))
632  p.strip_first();
633 
634  Path last_mp = p;
635 
636  if (mp)
637  *mp = x;;
638 
639  while (1)
640  {
641  Path r = x->find(p, &x);
642 
643  if (!r)
644  {
645  if (mp)
646  return last_mp;
647 
648  if (mt)
649  *mt = x;
650 
651  return p;
652  }
653 
654  r.strip_sep();
655 
656  if (mp && x->_mount)
657  {
658  last_mp = r;
659  *mp = x;
660  }
661 
662  if (r.empty())
663  {
664  if (mt)
665  *mt = x;
666 
667  if (mp)
668  return last_mp;
669  else
670  return r;
671  }
672 
673  p = r;
674  }
675 }
676 
677 inline
678 void
679 Mount_tree::add_child_node(cxx::Ref_ptr<Mount_tree> const &cld)
680 {
681  cld->_sib = _cld;
682  _cld = cld;
683 }
684 
685 
686 inline
687 const char *
688 File::get_mount(const char *path, cxx::Ref_ptr<File> *dir,
689  cxx::Ref_ptr<Mount_tree> *mt) throw()
690 {
691  if (!_mount_tree)
692  {
693  *dir = cxx::ref_ptr(this);
694  return path;
695  }
696 
698  Path p = _mount_tree->lookup(Path(path), mt, &mp);
699  if (mp->mount())
700  {
701  *dir = mp->mount();
702  return p.path();
703  }
704  else
705  {
706  *dir = cxx::ref_ptr(this);
707  return path;
708  }
709 }
710 
711 inline int
712 File::openat(const char *path, int flags, mode_t mode,
713  cxx::Ref_ptr<File> *f) throw()
714 {
715  cxx::Ref_ptr<File> dir;
717  path = get_mount(path, &dir, &mt);
718 
719  int res = dir->get_entry(path, flags, mode, f);
720 
721  if (res < 0)
722  return res;
723 
724  if (!(*f)->_mount_tree && mt)
725  (*f)->_mount_tree = mt;
726 
727  return res;
728 }
729 
738 class Mman
739 {
740 public:
742  virtual int mmap2(void *start, size_t len, int prot, int flags, int fd,
743  off_t offset, void **ptr) throw() = 0;
744 
746  virtual int munmap(void *start, size_t len) throw() = 0;
747 
749  virtual int mremap(void *old, size_t old_sz, size_t new_sz, int flags,
750  void **new_addr) throw() = 0;
751 
753  virtual int mprotect(const void *a, size_t sz, int prot) throw() = 0;
754 
756  virtual int msync(void *addr, size_t len, int flags) throw() = 0;
757 
759  virtual int madvise(void *addr, size_t len, int advice) throw() = 0;
760 
761  virtual ~Mman() throw() = 0;
762 };
763 
764 inline
765 Mman::~Mman() throw() {}
766 
767 class File_factory
768 {
769 private:
770  int _ref_cnt = 0;
771  int _proto = 0;
772  char const *_proto_name = 0;
773 
774  template<typename T> friend struct cxx::Default_ref_counter;
775  void add_ref() throw() { ++_ref_cnt; }
776  int remove_ref() throw() { return --_ref_cnt; }
777 
778 public:
779  explicit File_factory(int proto) : _proto(proto) {}
780  explicit File_factory(char const *proto_name) : _proto_name(proto_name) {}
781  File_factory(File_factory const &) = delete;
782  File_factory &operator = (File_factory const &) = delete;
783 
784  char const *proto_name() const { return _proto_name; }
785  int proto() const { return _proto; }
786 
787  virtual ~File_factory() throw() = 0;
788  virtual cxx::Ref_ptr<File> create(L4::Cap<void> file) = 0;
789 };
790 
791 inline File_factory::~File_factory() throw() {}
792 
793 template<typename IFACE, typename IMPL>
794 class File_factory_t : public File_factory
795 {
796 public:
797  File_factory_t() : File_factory(IFACE::Protocol) {}
798  cxx::Ref_ptr<File> create(L4::Cap<void> file)
799  { return cxx::ref_ptr(new IMPL(L4::cap_cast<IFACE>(file))); }
800 };
801 
816 {
817 protected:
818  File_system *_next;
819 
820 public:
821  File_system() throw() : _next(0) {}
827  virtual char const *type() const throw() = 0;
828 
844  virtual int mount(char const *source, unsigned long mountflags,
845  void const *data, cxx::Ref_ptr<File> *dir) throw() = 0;
846 
847  virtual ~File_system() throw() = 0;
848 
853  File_system *next() const throw() { return _next; }
854  File_system *&next() throw() { return _next; }
855  void next(File_system *n) throw() { _next = n; }
856 };
857 
858 inline
859 File_system::~File_system() throw()
860 {}
861 
867 class Fs
868 {
869 public:
875  virtual cxx::Ref_ptr<File> get_file(int fd) throw() = 0;
876 
878  virtual cxx::Ref_ptr<File> get_root() throw() = 0;
879 
881  virtual cxx::Ref_ptr<File> get_cwd() throw() { return get_root(); }
882 
884  virtual void set_cwd(cxx::Ref_ptr<File> const &) throw() {}
885 
891  virtual int alloc_fd(cxx::Ref_ptr<File> const &f = cxx::Ref_ptr<>::Nil) throw() = 0;
892 
899  virtual cxx::Ref_ptr<File> set_fd(int fd, cxx::Ref_ptr<File> const &f = cxx::Ref_ptr<>::Nil) throw() = 0;
900 
906  virtual cxx::Ref_ptr<File> free_fd(int fd) throw() = 0;
907 
915  virtual int mount(char const *path, cxx::Ref_ptr<File> const &dir) throw() = 0;
916 
924  virtual int register_file_system(File_system *f) throw() = 0;
925 
933  virtual int unregister_file_system(File_system *f) throw() = 0;
934 
942  virtual File_system *get_file_system(char const *fstype) throw() = 0;
943 
947  int mount(char const *source, char const *target,
948  char const *fstype, unsigned long mountflags,
949  void const *data) throw();
950 
951  virtual int register_file_factory(cxx::Ref_ptr<File_factory> f) throw() = 0;
952  virtual int unregister_file_factory(cxx::Ref_ptr<File_factory> f) throw() = 0;
953  virtual cxx::Ref_ptr<File_factory> get_file_factory(int proto) throw() = 0;
954  virtual cxx::Ref_ptr<File_factory> get_file_factory(char const *proto_name) throw() = 0;
955 
956  virtual ~Fs() = 0;
957 };
958 
959 inline int
960 Fs::mount(char const *source, char const *target,
961  char const *fstype, unsigned long mountflags,
962  void const *data) throw()
963 {
964  File_system *fs = get_file_system(fstype);
965 
966  if (!fs)
967  return -ENODEV;
968 
969  cxx::Ref_ptr<File> dir;
970  int res = fs->mount(source, mountflags, data, &dir);
971 
972  if (res < 0)
973  return res;
974 
975  return mount(target, dir);
976 }
977 
978 inline
979 Fs::~Fs()
980 {}
981 
988 class Ops : public Mman, public Fs
989 {
990 public:
991  virtual void *malloc(size_t bytes) noexcept = 0;
992  virtual void free(void *mem) noexcept = 0;
993  virtual ~Ops() throw() = 0;
994 
995  char *strndup(char const *str, unsigned l) noexcept
996  {
997  unsigned len;
998  for (len = 0; str[len] && len < l; ++len)
999  ;
1000 
1001  if (len == 0)
1002  return nullptr;
1003 
1004  ++len;
1005 
1006  char *b = (char *)this->malloc(len);
1007  if (b == nullptr)
1008  return nullptr;
1009 
1010  char *r = b;
1011  for (; len - 1 > 0 && *str; --len, ++b, ++str)
1012  *b = *str;
1013 
1014  *b = 0;
1015  return r;
1016  }
1017 
1018 };
1019 
1020 inline
1021 Ops::~Ops() throw()
1022 {}
1023 
1024 }}
1025 
1026 #endif
1027 
POSIX File-system related functionality.
Definition: vfs.h:867
A reference-counting pointer with automatic cleanup.
Definition: ref_ptr:80
virtual int mount(char const *source, unsigned long mountflags, void const *data, cxx::Ref_ptr< File > *dir)=0
Create a directory object dir representing source mounted with this file system.
Interface for the POSIX backends for an application.
Definition: vfs.h:988
Interface for the POSIX memory management.
Definition: vfs.h:738
virtual int unlock_all_locks()=0
Unlock all locks on the file.
Abstract capability-allocator interface.
virtual cxx::Ref_ptr< File > get_cwd()
Get the directory object for the applications current working directory.
Definition: vfs.h:881
L4Re C++ Interfaces.
Definition: backend:25
The basic interface for an open POSIX file.
Definition: vfs.h:428
L4::Cap related definitions.
L4 compiler related defines.
virtual void set_cwd(cxx::Ref_ptr< File > const &)
Set the current working directory for the application.
Definition: vfs.h:884
virtual int set_status_flags(long flags)=0
Set file status flags (fcntl F_SETFL).
The common interface for an open POSIX file.
Definition: vfs.h:61
Interface for a POSIX file that provides special file semantics.
Definition: vfs.h:393
Interface for a POSIX file that provides regular file semantics.
Definition: vfs.h:260
Interface for a POSIX file that is a directory.
Definition: vfs.h:139
Dataspace interface.
virtual int fchmod(mode_t)=0
Change POSIX access rights on that file.
virtual int mount(char const *path, cxx::Ref_ptr< File > const &dir)=0
Mount a given file object at the given global path in the VFS.
virtual int get_status_flags() const =0
Get file status flags (fcntl F_GETFL).
virtual int fstat64(struct stat64 *buf) const =0
Get status information for the file.
Basic interface for an L4Re::Vfs file system.
Definition: vfs.h:815