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 
245  virtual int fchmodat(const char *pathname,
246  mode_t mode, int flags) throw() = 0;
247 
248  virtual int utimensat(const char *pathname,
249  const struct timespec times[2], int flags) throw() = 0;
250 
254  virtual int get_entry(const char *, int, mode_t, cxx::Ref_ptr<File> *) throw() = 0;
255 };
256 
257 inline
258 Directory::~Directory() throw()
259 {}
260 
267 {
268 public:
269  virtual ~Regular_file() throw() = 0;
270 
281  virtual L4::Cap<L4Re::Dataspace> data_space() const throw() = 0;
282 
292  virtual ssize_t readv(const struct iovec*, int iovcnt) throw() = 0;
293 
304  virtual ssize_t writev(const struct iovec*, int iovcnt) throw() = 0;
305 
306  virtual ssize_t preadv(const struct iovec *iov, int iovcnt, off64_t offset) throw() = 0;
307  virtual ssize_t pwritev(const struct iovec *iov, int iovcnt, off64_t offset) throw() = 0;
308 
316  virtual off64_t lseek64(off64_t, int) throw() = 0;
317 
318 
326  virtual int ftruncate64(off64_t pos) throw() = 0;
327 
333  virtual int fsync() const throw() = 0;
334 
340  virtual int fdatasync() const throw() = 0;
341 
351  virtual int get_lock(struct flock64 *lock) throw() = 0;
352 
361  virtual int set_lock(struct flock64 *lock, bool wait) throw() = 0;
362 };
363 
364 inline
365 Regular_file::~Regular_file() throw()
366 {}
367 
368 class Socket
369 {
370 public:
371  virtual ~Socket() throw() = 0;
372  virtual int bind(sockaddr const *, socklen_t) throw() = 0;
373  virtual int connect(sockaddr const *, socklen_t) throw() = 0;
374  virtual ssize_t send(void const *, size_t, int) throw() = 0;
375  virtual ssize_t recv(void *, size_t, int) throw() = 0;
376  virtual ssize_t sendto(void const *, size_t, int, sockaddr const *, socklen_t) throw() = 0;
377  virtual ssize_t recvfrom(void *, size_t, int, sockaddr *, socklen_t *) throw() = 0;
378  virtual ssize_t sendmsg(msghdr const *, int) throw() = 0;
379  virtual ssize_t recvmsg(msghdr *, int) throw() = 0;
380  virtual int getsockopt(int level, int opt, void *, socklen_t *) throw() = 0;
381  virtual int setsockopt(int level, int opt, void const *, socklen_t) throw() = 0;
382  virtual int listen(int) throw() = 0;
383  virtual int accept(sockaddr *addr, socklen_t *) throw() = 0;
384  virtual int shutdown(int) throw() = 0;
385 
386  virtual int getsockname(sockaddr *, socklen_t *) throw() = 0;
387  virtual int getpeername(sockaddr *, socklen_t *) throw() = 0;
388 };
389 
390 inline
391 Socket::~Socket() throw()
392 {}
393 
400 {
401 public:
402  virtual ~Special_file() throw() = 0;
403 
414  virtual int ioctl(unsigned long cmd, va_list args) throw() = 0;
415 };
416 
417 inline
418 Special_file::~Special_file() throw()
419 {}
420 
434 class File :
435  public Generic_file,
436  public Regular_file,
437  public Directory,
438  public Special_file,
439  public Socket
440 {
441  friend class Mount_tree;
442 
443 private:
444  void operator = (File const &);
445 
446 protected:
447  File() throw() : _ref_cnt(0) {}
448  File(File const &)
449  : Generic_file(),Regular_file(), Directory(), Special_file(), _ref_cnt(0)
450  {}
451 
452 public:
453 
454  const char *get_mount(const char *path, cxx::Ref_ptr<File> *dir,
455  cxx::Ref_ptr<Mount_tree> *mt = 0) throw();
456 
457  int openat(const char *path, int flags, mode_t mode,
458  cxx::Ref_ptr<File> *f) throw();
459 
460  void add_ref() throw() { ++_ref_cnt; }
461  int remove_ref() throw() { return --_ref_cnt; }
462 
463  virtual ~File() throw() = 0;
464 
465  cxx::Ref_ptr<Mount_tree> mount_tree() const throw()
466  { return _mount_tree; }
467 
468 private:
469  int _ref_cnt;
470  cxx::Ref_ptr<Mount_tree> _mount_tree;
471 
472 };
473 
474 inline
475 File::~File() throw()
476 {}
477 
478 class Path
479 {
480 private:
481  char const *_p;
482  unsigned _l;
483 
484 public:
485  Path() throw() : _p(0), _l(0) {}
486 
487  explicit Path(char const *p) throw() : _p(p)
488  { for (_l = 0; *p; ++p, ++_l) ; }
489 
490  Path(char const *p, unsigned l) throw() : _p(p), _l(l)
491  {}
492 
493  static bool __is_sep(char s) throw();
494 
495  Path cmp_path(char const *prefix) const throw();
496 
497  struct Invalid_ptr;
498  operator Invalid_ptr const * () const
499  { return reinterpret_cast<Invalid_ptr const *>(_p); }
500 
501  unsigned length() const { return _l; }
502  char const *path() const { return _p; }
503 
504  bool empty() const { return _l == 0; }
505 
506  bool is_sep(unsigned offset) const { return __is_sep(_p[offset]); }
507 
508  bool strip_sep()
509  {
510  bool s = false;
511  for (; __is_sep(*_p) && _l; ++_p, --_l)
512  s = true;
513  return s;
514  }
515 
516  Path first() const
517  {
518  unsigned i;
519  for (i = 0; i < _l && !is_sep(i); ++i)
520  ;
521 
522  return Path(_p, i);
523  }
524 
525  Path strip_first()
526  {
527  Path r = first();
528  _p += r.length();
529  _l -= r.length();
530  strip_sep();
531  return r;
532  }
533 
534 };
535 
536 
543 class Mount_tree
544 {
545 public:
546 
547  explicit Mount_tree(char *n) throw();
548 
549  Path lookup(Path const &path, cxx::Ref_ptr<Mount_tree> *mt,
550  cxx::Ref_ptr<Mount_tree> *mp = 0) throw();
551 
552  Path find(Path const &p, cxx::Ref_ptr<Mount_tree> *t) throw();
553 
554  cxx::Ref_ptr<File> mount() const
555  { return _mount; }
556 
557  void mount(cxx::Ref_ptr<File> const &m)
558  {
559  m->_mount_tree = cxx::ref_ptr(this);
560  _mount = m;
561  }
562 
563  static int create_tree(cxx::Ref_ptr<Mount_tree> const &root,
564  char const *path,
565  cxx::Ref_ptr<File> const &dir) throw();
566 
567  void add_child_node(cxx::Ref_ptr<Mount_tree> const &cld);
568 
569  virtual ~Mount_tree() throw() = 0;
570 
571  void add_ref() throw() { ++_ref_cnt; }
572  int remove_ref() throw() { return --_ref_cnt; }
573 
574 private:
575  friend class Real_mount_tree;
576 
577  int _ref_cnt;
578  char *_name;
581  cxx::Ref_ptr<File> _mount;
582 };
583 
584 inline
585 Mount_tree::~Mount_tree() throw()
586 {}
587 
588 inline bool
589 Path::__is_sep(char s) throw()
590 { return s == '/'; }
591 
592 inline Path
593 Path::cmp_path(char const *n) const throw()
594 {
595  char const *p = _p;
596  for (; *p && !__is_sep(*p) && *n; ++p, ++n)
597  if (*p != *n)
598  return Path();
599 
600  if (*n || (*p && !__is_sep(*p)))
601  return Path();
602 
603  return Path(p, _l - (p - _p));
604 }
605 
606 inline
607 Mount_tree::Mount_tree(char *n) throw()
608 : _ref_cnt(0), _name(n)
609 {}
610 
611 inline Path
612 Mount_tree::find(Path const &p, cxx::Ref_ptr<Mount_tree> *t) throw()
613 {
614  if (!_cld)
615  return Path();
616 
617  for (cxx::Ref_ptr<Mount_tree> x = _cld; x; x = x->_sib)
618  {
619  Path const r = p.cmp_path(x->_name);
620  if (r)
621  {
622  *t = x;
623  return r;
624  }
625  }
626 
627  return Path();
628 }
629 
630 inline Path
631 Mount_tree::lookup(Path const &path, cxx::Ref_ptr<Mount_tree> *mt,
632  cxx::Ref_ptr<Mount_tree> *mp) throw()
633 {
634  cxx::Ref_ptr<Mount_tree> x(this);
635  Path p = path;
636 
637  if (p.first().cmp_path("."))
638  p.strip_first();
639 
640  Path last_mp = p;
641 
642  if (mp)
643  *mp = x;;
644 
645  while (1)
646  {
647  Path r = x->find(p, &x);
648 
649  if (!r)
650  {
651  if (mp)
652  return last_mp;
653 
654  if (mt)
655  *mt = x;
656 
657  return p;
658  }
659 
660  r.strip_sep();
661 
662  if (mp && x->_mount)
663  {
664  last_mp = r;
665  *mp = x;
666  }
667 
668  if (r.empty())
669  {
670  if (mt)
671  *mt = x;
672 
673  if (mp)
674  return last_mp;
675  else
676  return r;
677  }
678 
679  p = r;
680  }
681 }
682 
683 inline
684 void
685 Mount_tree::add_child_node(cxx::Ref_ptr<Mount_tree> const &cld)
686 {
687  cld->_sib = _cld;
688  _cld = cld;
689 }
690 
691 
692 inline
693 const char *
694 File::get_mount(const char *path, cxx::Ref_ptr<File> *dir,
695  cxx::Ref_ptr<Mount_tree> *mt) throw()
696 {
697  if (!_mount_tree)
698  {
699  *dir = cxx::ref_ptr(this);
700  return path;
701  }
702 
704  Path p = _mount_tree->lookup(Path(path), mt, &mp);
705  if (mp->mount())
706  {
707  *dir = mp->mount();
708  return p.path();
709  }
710  else
711  {
712  *dir = cxx::ref_ptr(this);
713  return path;
714  }
715 }
716 
717 inline int
718 File::openat(const char *path, int flags, mode_t mode,
719  cxx::Ref_ptr<File> *f) throw()
720 {
721  cxx::Ref_ptr<File> dir;
723  path = get_mount(path, &dir, &mt);
724 
725  int res = dir->get_entry(path, flags, mode, f);
726 
727  if (res < 0)
728  return res;
729 
730  if (!(*f)->_mount_tree && mt)
731  (*f)->_mount_tree = mt;
732 
733  return res;
734 }
735 
744 class Mman
745 {
746 public:
748  virtual int mmap2(void *start, size_t len, int prot, int flags, int fd,
749  off_t offset, void **ptr) throw() = 0;
750 
752  virtual int munmap(void *start, size_t len) throw() = 0;
753 
755  virtual int mremap(void *old, size_t old_sz, size_t new_sz, int flags,
756  void **new_addr) throw() = 0;
757 
759  virtual int mprotect(const void *a, size_t sz, int prot) throw() = 0;
760 
762  virtual int msync(void *addr, size_t len, int flags) throw() = 0;
763 
765  virtual int madvise(void *addr, size_t len, int advice) throw() = 0;
766 
767  virtual ~Mman() throw() = 0;
768 };
769 
770 inline
771 Mman::~Mman() throw() {}
772 
773 class File_factory
774 {
775 private:
776  int _ref_cnt = 0;
777  int _proto = 0;
778  char const *_proto_name = 0;
779 
780  template<typename T> friend struct cxx::Default_ref_counter;
781  void add_ref() throw() { ++_ref_cnt; }
782  int remove_ref() throw() { return --_ref_cnt; }
783 
784 public:
785  explicit File_factory(int proto) : _proto(proto) {}
786  explicit File_factory(char const *proto_name) : _proto_name(proto_name) {}
787  File_factory(File_factory const &) = delete;
788  File_factory &operator = (File_factory const &) = delete;
789 
790  char const *proto_name() const { return _proto_name; }
791  int proto() const { return _proto; }
792 
793  virtual ~File_factory() throw() = 0;
794  virtual cxx::Ref_ptr<File> create(L4::Cap<void> file) = 0;
795 };
796 
797 inline File_factory::~File_factory() throw() {}
798 
799 template<typename IFACE, typename IMPL>
800 class File_factory_t : public File_factory
801 {
802 public:
803  File_factory_t() : File_factory(IFACE::Protocol) {}
804  cxx::Ref_ptr<File> create(L4::Cap<void> file)
805  { return cxx::ref_ptr(new IMPL(L4::cap_cast<IFACE>(file))); }
806 };
807 
822 {
823 protected:
824  File_system *_next;
825 
826 public:
827  File_system() throw() : _next(0) {}
833  virtual char const *type() const throw() = 0;
834 
850  virtual int mount(char const *source, unsigned long mountflags,
851  void const *data, cxx::Ref_ptr<File> *dir) throw() = 0;
852 
853  virtual ~File_system() throw() = 0;
854 
859  File_system *next() const throw() { return _next; }
860  File_system *&next() throw() { return _next; }
861  void next(File_system *n) throw() { _next = n; }
862 };
863 
864 inline
865 File_system::~File_system() throw()
866 {}
867 
873 class Fs
874 {
875 public:
881  virtual cxx::Ref_ptr<File> get_file(int fd) throw() = 0;
882 
884  virtual cxx::Ref_ptr<File> get_root() throw() = 0;
885 
887  virtual cxx::Ref_ptr<File> get_cwd() throw() { return get_root(); }
888 
890  virtual void set_cwd(cxx::Ref_ptr<File> const &) throw() {}
891 
897  virtual int alloc_fd(cxx::Ref_ptr<File> const &f = cxx::Ref_ptr<>::Nil) throw() = 0;
898 
905  virtual cxx::Ref_ptr<File> set_fd(int fd, cxx::Ref_ptr<File> const &f = cxx::Ref_ptr<>::Nil) throw() = 0;
906 
912  virtual cxx::Ref_ptr<File> free_fd(int fd) throw() = 0;
913 
921  virtual int mount(char const *path, cxx::Ref_ptr<File> const &dir) throw() = 0;
922 
930  virtual int register_file_system(File_system *f) throw() = 0;
931 
939  virtual int unregister_file_system(File_system *f) throw() = 0;
940 
948  virtual File_system *get_file_system(char const *fstype) throw() = 0;
949 
953  int mount(char const *source, char const *target,
954  char const *fstype, unsigned long mountflags,
955  void const *data) throw();
956 
957  virtual int register_file_factory(cxx::Ref_ptr<File_factory> f) throw() = 0;
958  virtual int unregister_file_factory(cxx::Ref_ptr<File_factory> f) throw() = 0;
959  virtual cxx::Ref_ptr<File_factory> get_file_factory(int proto) throw() = 0;
960  virtual cxx::Ref_ptr<File_factory> get_file_factory(char const *proto_name) throw() = 0;
961 
962  virtual ~Fs() = 0;
963 };
964 
965 inline int
966 Fs::mount(char const *source, char const *target,
967  char const *fstype, unsigned long mountflags,
968  void const *data) throw()
969 {
970  File_system *fs = get_file_system(fstype);
971 
972  if (!fs)
973  return -ENODEV;
974 
975  cxx::Ref_ptr<File> dir;
976  int res = fs->mount(source, mountflags, data, &dir);
977 
978  if (res < 0)
979  return res;
980 
981  return mount(target, dir);
982 }
983 
984 inline
985 Fs::~Fs()
986 {}
987 
994 class Ops : public Mman, public Fs
995 {
996 public:
997  virtual void *malloc(size_t bytes) noexcept = 0;
998  virtual void free(void *mem) noexcept = 0;
999  virtual ~Ops() throw() = 0;
1000 
1001  char *strndup(char const *str, unsigned l) noexcept
1002  {
1003  unsigned len;
1004  for (len = 0; str[len] && len < l; ++len)
1005  ;
1006 
1007  if (len == 0)
1008  return nullptr;
1009 
1010  ++len;
1011 
1012  char *b = (char *)this->malloc(len);
1013  if (b == nullptr)
1014  return nullptr;
1015 
1016  char *r = b;
1017  for (; len - 1 > 0 && *str; --len, ++b, ++str)
1018  *b = *str;
1019 
1020  *b = 0;
1021  return r;
1022  }
1023 
1024 };
1025 
1026 inline
1027 Ops::~Ops() throw()
1028 {}
1029 
1030 }}
1031 
1032 #endif
1033 
POSIX File-system related functionality.
Definition: vfs.h:873
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:994
Interface for the POSIX memory management.
Definition: vfs.h:744
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:887
L4Re C++ Interfaces.
Definition: cmd_control:15
The basic interface for an open POSIX file.
Definition: vfs.h:434
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:890
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:399
Interface for a POSIX file that provides regular file semantics.
Definition: vfs.h:266
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:821