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 #include <cstdlib>
43 #include <cstring>
44 
45 namespace L4Re {
49 namespace Vfs {
50 
51 class Mount_tree;
52 class File;
53 
64 {
65 public:
66  virtual ~Generic_file() throw() = 0;
78  virtual int unlock_all_locks() throw() = 0;
79 
88  virtual int fstat64(struct stat64 *buf) const throw() = 0;
89 
95  virtual int fchmod(mode_t) throw() = 0;
96 
106  virtual int get_status_flags() const throw() = 0;
107 
123  virtual int set_status_flags(long flags) throw() = 0;
124 
125  virtual int utime(const struct utimbuf *) throw() = 0;
126  virtual int utimes(const struct timeval [2]) throw() = 0;
127  virtual ssize_t readlink(char *, size_t) = 0;
128 };
129 
130 inline
131 Generic_file::~Generic_file() throw()
132 {}
133 
142 {
143 public:
144  virtual ~Directory() throw() = 0;
145 
159  virtual int faccessat(const char *path, int mode, int flags) throw() = 0;
160 
173  virtual int mkdir(const char *path, mode_t mode) throw() = 0;
174 
185  virtual int unlink(const char *path) throw() = 0;
186 
200  virtual int rename(const char *src_path, const char *dst_path) throw() = 0;
201 
215  virtual int link(const char *src_path, const char *dst_path) throw() = 0;
216 
229  virtual int symlink(const char *src_path, const char *dst_path) throw() = 0;
230 
241  virtual int rmdir(const char *path) throw() = 0;
242  virtual int openat(const char *path, int flags, mode_t mode,
243  cxx::Ref_ptr<File> *f) throw() = 0;
244 
245  virtual ssize_t getdents(char *buf, size_t sizebytes) throw() = 0;
246 
250  virtual int get_entry(const char *, int, mode_t, cxx::Ref_ptr<File> *) throw() = 0;
251 };
252 
253 inline
254 Directory::~Directory() throw()
255 {}
256 
263 {
264 public:
265  virtual ~Regular_file() throw() = 0;
266 
277  virtual L4::Cap<L4Re::Dataspace> data_space() const throw() = 0;
278 
288  virtual ssize_t readv(const struct iovec*, int iovcnt) throw() = 0;
289 
300  virtual ssize_t writev(const struct iovec*, int iovcnt) throw() = 0;
301 
302  virtual ssize_t preadv(const struct iovec *iov, int iovcnt, off64_t offset) throw() = 0;
303  virtual ssize_t pwritev(const struct iovec *iov, int iovcnt, off64_t offset) throw() = 0;
304 
312  virtual off64_t lseek64(off64_t, int) throw() = 0;
313 
314 
322  virtual int ftruncate64(off64_t pos) throw() = 0;
323 
329  virtual int fsync() const throw() = 0;
330 
336  virtual int fdatasync() const throw() = 0;
337 
347  virtual int get_lock(struct flock64 *lock) throw() = 0;
348 
357  virtual int set_lock(struct flock64 *lock, bool wait) throw() = 0;
358 };
359 
360 inline
361 Regular_file::~Regular_file() throw()
362 {}
363 
364 class Socket
365 {
366 public:
367  virtual ~Socket() throw() = 0;
368  virtual int bind(sockaddr const *, socklen_t) throw() = 0;
369  virtual int connect(sockaddr const *, socklen_t) throw() = 0;
370  virtual ssize_t send(void const *, size_t, int) throw() = 0;
371  virtual ssize_t recv(void *, size_t, int) throw() = 0;
372  virtual ssize_t sendto(void const *, size_t, int, sockaddr const *, socklen_t) throw() = 0;
373  virtual ssize_t recvfrom(void *, size_t, int, sockaddr *, socklen_t *) throw() = 0;
374  virtual ssize_t sendmsg(msghdr const *, int) throw() = 0;
375  virtual ssize_t recvmsg(msghdr *, int) throw() = 0;
376  virtual int getsockopt(int level, int opt, void *, socklen_t *) throw() = 0;
377  virtual int setsockopt(int level, int opt, void const *, socklen_t) throw() = 0;
378  virtual int listen(int) throw() = 0;
379  virtual int accept(sockaddr *addr, socklen_t *) throw() = 0;
380  virtual int shutdown(int) throw() = 0;
381 
382  virtual int getsockname(sockaddr *, socklen_t *) throw() = 0;
383  virtual int getpeername(sockaddr *, socklen_t *) throw() = 0;
384 };
385 
386 inline
387 Socket::~Socket() throw()
388 {}
389 
396 {
397 public:
398  virtual ~Special_file() throw() = 0;
399 
410  virtual int ioctl(unsigned long cmd, va_list args) throw() = 0;
411 };
412 
413 inline
414 Special_file::~Special_file() throw()
415 {}
416 
430 class File :
431  public Generic_file,
432  public Regular_file,
433  public Directory,
434  public Special_file,
435  public Socket
436 {
437  friend class Mount_tree;
438 
439 private:
440  void operator = (File const &);
441 
442 protected:
443  File() throw() : _ref_cnt(0) {}
444  File(File const &)
445  : Generic_file(),Regular_file(), Directory(), Special_file(), _ref_cnt(0)
446  {}
447 
448 public:
449 
450  const char *get_mount(const char *path, cxx::Ref_ptr<File> *dir,
451  cxx::Ref_ptr<Mount_tree> *mt = 0) throw();
452 
453  int openat(const char *path, int flags, mode_t mode,
454  cxx::Ref_ptr<File> *f) throw();
455 
456  void add_ref() throw() { ++_ref_cnt; }
457  int remove_ref() throw() { return --_ref_cnt; }
458 
459  virtual ~File() throw() = 0;
460 
461  cxx::Ref_ptr<Mount_tree> mount_tree() const throw()
462  { return _mount_tree; }
463 
464 private:
465  int _ref_cnt;
466  cxx::Ref_ptr<Mount_tree> _mount_tree;
467 
468 };
469 
470 inline
471 File::~File() throw()
472 {}
473 
474 class Path
475 {
476 private:
477  char const *_p;
478  unsigned _l;
479 
480 public:
481  Path() throw() : _p(0), _l(0) {}
482 
483  explicit Path(char const *p) throw() : _p(p)
484  { for (_l = 0; *p; ++p, ++_l) ; }
485 
486  Path(char const *p, unsigned l) throw() : _p(p), _l(l)
487  {}
488 
489  static bool __is_sep(char s) throw();
490 
491  Path cmp_path(char const *prefix) const throw();
492 
493  struct Invalid_ptr;
494  operator Invalid_ptr const * () const
495  { return reinterpret_cast<Invalid_ptr const *>(_p); }
496 
497  unsigned length() const { return _l; }
498  char const *path() const { return _p; }
499 
500  bool empty() const { return _l == 0; }
501 
502  bool is_sep(unsigned offset) const { return __is_sep(_p[offset]); }
503 
504  bool strip_sep()
505  {
506  bool s = false;
507  for (; __is_sep(*_p) && _l; ++_p, --_l)
508  s = true;
509  return s;
510  }
511 
512  Path first() const
513  {
514  unsigned i;
515  for (i = 0; i < _l && !is_sep(i); ++i)
516  ;
517 
518  return Path(_p, i);
519  }
520 
521  Path strip_first()
522  {
523  Path r = first();
524  _p += r.length();
525  _l -= r.length();
526  strip_sep();
527  return r;
528  }
529 
530 };
531 
532 
539 class Mount_tree
540 {
541 public:
542 
543  explicit Mount_tree(char *n) throw();
544 
545  Path lookup(Path const &path, cxx::Ref_ptr<Mount_tree> *mt,
546  cxx::Ref_ptr<Mount_tree> *mp = 0) throw();
547 
548  Path find(Path const &p, cxx::Ref_ptr<Mount_tree> *t) throw();
549 
550  cxx::Ref_ptr<File> mount() const
551  { return _mount; }
552 
553  void mount(cxx::Ref_ptr<File> const &m)
554  {
555  m->_mount_tree = cxx::ref_ptr(this);
556  _mount = m;
557  }
558 
559  static int create_tree(cxx::Ref_ptr<Mount_tree> const &root,
560  char const *path,
561  cxx::Ref_ptr<File> const &dir) throw();
562 
563  void add_child_node(cxx::Ref_ptr<Mount_tree> const &cld);
564 
565  virtual ~Mount_tree() throw() = 0;
566 
567  void add_ref() throw() { ++_ref_cnt; }
568  int remove_ref() throw() { return --_ref_cnt; }
569 
570 private:
571  friend class Real_mount_tree;
572 
573  int _ref_cnt;
574  char *_name;
577  cxx::Ref_ptr<File> _mount;
578 };
579 
580 inline
581 Mount_tree::~Mount_tree() throw()
582 {}
583 
584 inline bool
585 Path::__is_sep(char s) throw()
586 { return s == '/'; }
587 
588 inline Path
589 Path::cmp_path(char const *n) const throw()
590 {
591  char const *p = _p;
592  for (; *p && !__is_sep(*p) && *n; ++p, ++n)
593  if (*p != *n)
594  return Path();
595 
596  if (*n || (*p && !__is_sep(*p)))
597  return Path();
598 
599  return Path(p, _l - (p - _p));
600 }
601 
602 inline
603 Mount_tree::Mount_tree(char *n) throw()
604 : _ref_cnt(0), _name(n)
605 {}
606 
607 inline Path
608 Mount_tree::find(Path const &p, cxx::Ref_ptr<Mount_tree> *t) throw()
609 {
610  if (!_cld)
611  return Path();
612 
613  for (cxx::Ref_ptr<Mount_tree> x = _cld; x; x = x->_sib)
614  {
615  Path const r = p.cmp_path(x->_name);
616  if (r)
617  {
618  *t = x;
619  return r;
620  }
621  }
622 
623  return Path();
624 }
625 
626 inline Path
627 Mount_tree::lookup(Path const &path, cxx::Ref_ptr<Mount_tree> *mt,
628  cxx::Ref_ptr<Mount_tree> *mp) throw()
629 {
630  cxx::Ref_ptr<Mount_tree> x(this);
631  Path p = path;
632 
633  if (p.first().cmp_path("."))
634  p.strip_first();
635 
636  Path last_mp = p;
637 
638  if (mp)
639  *mp = x;;
640 
641  while (1)
642  {
643  Path r = x->find(p, &x);
644 
645  if (!r)
646  {
647  if (mp)
648  return last_mp;
649 
650  if (mt)
651  *mt = x;
652 
653  return p;
654  }
655 
656  r.strip_sep();
657 
658  if (mp && x->_mount)
659  {
660  last_mp = r;
661  *mp = x;
662  }
663 
664  if (r.empty())
665  {
666  if (mt)
667  *mt = x;
668 
669  if (mp)
670  return last_mp;
671  else
672  return r;
673  }
674 
675  p = r;
676  }
677 }
678 
679 inline
680 void
681 Mount_tree::add_child_node(cxx::Ref_ptr<Mount_tree> const &cld)
682 {
683  cld->_sib = _cld;
684  _cld = cld;
685 }
686 
691 class Real_mount_tree : public Mount_tree
692 {
693 public:
694  explicit Real_mount_tree(char *n) : Mount_tree(n) {}
695 };
696 
697 inline int
698 Mount_tree::create_tree(cxx::Ref_ptr<Mount_tree> const &root,
699  char const *path, cxx::Ref_ptr<File> const &dir) throw()
700 {
702  Path p = root->lookup(Path(path), &base);
703 
704  while (!p.empty())
705  {
706  Path f = p.strip_first();
707 
708  if (f.empty())
709  return -EEXIST;
710 
711  char *name = strndup(f.path(), f.length());
712  if (!name)
713  return -ENOMEM;
714 
715  cxx::Ref_ptr<Mount_tree> nt(new Real_mount_tree(name));
716  if (!nt)
717  {
718  free(name);
719  return -ENOMEM;
720  }
721 
722  nt->_sib = base->_cld;
723  base->_cld = nt;
724 
725  base = nt;
726 
727  if (p.empty())
728  {
729  nt->_mount = dir;
730  return 0;
731  }
732  }
733 
734  return -EINVAL;
735 }
736 
737 inline
738 const char *
739 File::get_mount(const char *path, cxx::Ref_ptr<File> *dir,
740  cxx::Ref_ptr<Mount_tree> *mt) throw()
741 {
742  if (!_mount_tree)
743  {
744  *dir = cxx::ref_ptr(this);
745  return path;
746  }
747 
749  Path p = _mount_tree->lookup(Path(path), mt, &mp);
750  if (mp->mount())
751  {
752  *dir = mp->mount();
753  return p.path();
754  }
755  else
756  {
757  *dir = cxx::ref_ptr(this);
758  return path;
759  }
760 }
761 
762 inline int
763 File::openat(const char *path, int flags, mode_t mode,
764  cxx::Ref_ptr<File> *f) throw()
765 {
766  cxx::Ref_ptr<File> dir;
768  path = get_mount(path, &dir, &mt);
769 
770  int res = dir->get_entry(path, flags, mode, f);
771 
772  if (res < 0)
773  return res;
774 
775  if (!(*f)->_mount_tree && mt)
776  (*f)->_mount_tree = mt;
777 
778  return res;
779 }
780 
789 class Mman
790 {
791 public:
793  virtual int mmap2(void *start, size_t len, int prot, int flags, int fd,
794  off_t offset, void **ptr) throw() = 0;
795 
797  virtual int munmap(void *start, size_t len) throw() = 0;
798 
800  virtual int mremap(void *old, size_t old_sz, size_t new_sz, int flags,
801  void **new_addr) throw() = 0;
802 
804  virtual int mprotect(const void *a, size_t sz, int prot) throw() = 0;
805 
807  virtual int msync(void *addr, size_t len, int flags) throw() = 0;
808 
810  virtual int madvise(void *addr, size_t len, int advice) throw() = 0;
811 
812  virtual ~Mman() throw() = 0;
813 };
814 
815 inline
816 Mman::~Mman() throw() {}
817 
818 class File_factory
819 {
820 private:
821  int _ref_cnt = 0;
822  int _proto = 0;
823  char const *_proto_name = 0;
824 
825  template<typename T> friend struct cxx::Default_ref_counter;
826  void add_ref() throw() { ++_ref_cnt; }
827  int remove_ref() throw() { return --_ref_cnt; }
828 
829 public:
830  explicit File_factory(int proto) : _proto(proto) {}
831  explicit File_factory(char const *proto_name) : _proto_name(proto_name) {}
832  File_factory(File_factory const &) = delete;
833  File_factory &operator = (File_factory const &) = delete;
834 
835  char const *proto_name() const { return _proto_name; }
836  int proto() const { return _proto; }
837 
838  virtual ~File_factory() throw() = 0;
839  virtual cxx::Ref_ptr<File> create(L4::Cap<void> file) = 0;
840 };
841 
842 inline File_factory::~File_factory() throw() {}
843 
844 template<typename IFACE, typename IMPL>
845 class File_factory_t : public File_factory
846 {
847 public:
848  File_factory_t() : File_factory(IFACE::Protocol) {}
849  void operator delete (void *) {}
850  cxx::Ref_ptr<File> create(L4::Cap<void> file)
851  { return cxx::ref_ptr(new IMPL(L4::cap_cast<IFACE>(file))); }
852 };
853 
868 {
869 protected:
870  File_system *_next;
871 
872 public:
873  File_system() throw() : _next(0) {}
879  virtual char const *type() const throw() = 0;
880 
896  virtual int mount(char const *source, unsigned long mountflags,
897  void const *data, cxx::Ref_ptr<File> *dir) throw() = 0;
898 
899  virtual ~File_system() throw() = 0;
900 
905  File_system *next() const throw() { return _next; }
906  File_system *&next() throw() { return _next; }
907  void next(File_system *n) throw() { _next = n; }
908 };
909 
910 inline
911 File_system::~File_system() throw()
912 {}
913 
919 class Fs
920 {
921 public:
927  virtual cxx::Ref_ptr<File> get_file(int fd) throw() = 0;
928 
930  virtual cxx::Ref_ptr<File> get_root() throw() = 0;
931 
933  virtual cxx::Ref_ptr<File> get_cwd() throw() { return get_root(); }
934 
936  virtual void set_cwd(cxx::Ref_ptr<File> const &) throw() {}
937 
943  virtual int alloc_fd(cxx::Ref_ptr<File> const &f = cxx::Ref_ptr<>::Nil) throw() = 0;
944 
951  virtual cxx::Ref_ptr<File> set_fd(int fd, cxx::Ref_ptr<File> const &f = cxx::Ref_ptr<>::Nil) throw() = 0;
952 
958  virtual cxx::Ref_ptr<File> free_fd(int fd) throw() = 0;
959 
967  int mount(char const *path, cxx::Ref_ptr<File> const &dir) throw();
968 
976  virtual int register_file_system(File_system *f) throw() = 0;
977 
985  virtual int unregister_file_system(File_system *f) throw() = 0;
986 
994  virtual File_system *get_file_system(char const *fstype) throw() = 0;
995 
999  int mount(char const *source, char const *target,
1000  char const *fstype, unsigned long mountflags,
1001  void const *data) throw();
1002 
1003  virtual int register_file_factory(cxx::Ref_ptr<File_factory> f) throw() = 0;
1004  virtual int unregister_file_factory(cxx::Ref_ptr<File_factory> f) throw() = 0;
1005  virtual cxx::Ref_ptr<File_factory> get_file_factory(int proto) throw() = 0;
1006  virtual cxx::Ref_ptr<File_factory> get_file_factory(char const *proto_name) throw() = 0;
1007 
1008  virtual ~Fs() = 0;
1009 };
1010 
1011 
1012 inline int
1013 Fs::mount(char const *path, cxx::Ref_ptr<File> const &dir) throw()
1014 {
1015  if (cxx::Ref_ptr<Mount_tree> root = get_root()->mount_tree())
1016  return Mount_tree::create_tree(root, path, dir);
1017 
1018  return -EINVAL;
1019 }
1020 
1021 inline int
1022 Fs::mount(char const *source, char const *target,
1023  char const *fstype, unsigned long mountflags,
1024  void const *data) throw()
1025 {
1026  File_system *fs = get_file_system(fstype);
1027 
1028  if (!fs)
1029  return -ENODEV;
1030 
1031  cxx::Ref_ptr<File> dir;
1032  int res = fs->mount(source, mountflags, data, &dir);
1033 
1034  if (res < 0)
1035  return res;
1036 
1037  return mount(target, dir);
1038 }
1039 
1040 inline
1041 Fs::~Fs()
1042 {}
1043 
1044 class App_api
1045 {
1046 public:
1047  virtual Cap_alloc *cap_alloc() throw() = 0;
1048  virtual void *malloc(size_t) noexcept = 0;
1049  virtual void free(void *m) noexcept = 0;
1050  virtual ~App_api() = 0;
1051 };
1052 
1053 inline
1054 App_api::~App_api()
1055 {}
1056 
1063 class Ops : public Mman, public Fs, public App_api
1064 {
1065 public:
1066  virtual ~Ops() throw() = 0;
1067 };
1068 
1069 inline
1070 Ops::~Ops() throw()
1071 {}
1072 
1073 
1074 
1075 }}
1076 
1077 #endif
1078 
POSIX File-system related functionality.
Definition: vfs.h:919
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:1063
Interface for the POSIX memory management.
Definition: vfs.h:789
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:933
Capability allocator interface.
Definition: cap_alloc:40
L4Re C++ Interfaces.
Definition: cmd_control:15
The basic interface for an open POSIX file.
Definition: vfs.h:430
L4::Cap related definitions.
L4 compiler related defines.
int mount(char const *path, cxx::Ref_ptr< File > const &dir)
Mount a given file object at the given global path in the VFS.
Definition: vfs.h:1013
virtual void set_cwd(cxx::Ref_ptr< File > const &)
Set the current working directory for the application.
Definition: vfs.h:936
virtual int set_status_flags(long flags)=0
Set file status flags (fcntl F_SETFL).
_Cap_alloc & cap_alloc
Capability allocator.
The common interface for an open POSIX file.
Definition: vfs.h:63
Interface for a POSIX file that provides special file semantics.
Definition: vfs.h:395
Interface for a POSIX file that provides regular file semantics.
Definition: vfs.h:262
Interface for a POSIX file that is a directory.
Definition: vfs.h:141
Dataspace interface.
virtual int fchmod(mode_t)=0
Change POSIX access rights on that file.
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:867