4 * (c) 2010 Technische Universität Dresden
5 * This file is part of TUD:OS and distributed under the terms of the
6 * GNU Lesser General Public License 2.1.
7 * Please see the COPYING-LGPL-2.1 file for details.
10 #include <l4/l4re_vfs/backend>
11 #include <l4/cxx/string>
12 #include <l4/cxx/avl_tree>
22 using namespace L4Re::Vfs;
28 File_data() : _buf(0), _size(0) {}
30 unsigned long put(unsigned long offset,
31 unsigned long bufsize, void *srcbuf);
32 unsigned long get(unsigned long offset,
33 unsigned long bufsize, void *dstbuf);
35 unsigned long size() const { return _size; }
37 ~File_data() throw() { free(_buf); }
45 File_data::put(unsigned long offset, unsigned long bufsize, void *srcbuf)
47 if (offset + bufsize > _size)
49 _size = offset + bufsize;
50 _buf = realloc(_buf, _size);
56 memcpy((char *)_buf + offset, srcbuf, bufsize);
61 File_data::get(unsigned long offset, unsigned long bufsize, void *dstbuf)
63 unsigned long s = bufsize;
68 if (offset + bufsize > _size)
71 memcpy(dstbuf, (char *)_buf + offset, s);
76 class Node : public cxx::Avl_tree_node
79 Node(const char *path, mode_t mode)
80 : _ref_cnt(0), _path(strdup(path))
81 { _info.st_mode = mode; }
83 const char *path() const { return _path; }
84 struct stat64 *info() { return &_info; }
86 void add_ref() throw() { ++_ref_cnt; }
87 int remove_ref() throw() { return --_ref_cnt; }
89 bool is_dir() const { return S_ISDIR(_info.st_mode); }
91 virtual ~Node() { free(_path); }
101 typedef cxx::String Key_type;
102 static Key_type key_of(Node const *n)
103 { return n->path(); }
106 struct Path_avl_tree_compare
108 bool operator () (const char *l, const char *r) const
109 { return strcmp(l, r) < 0; }
110 bool operator () (const cxx::String l, const cxx::String r) const
111 { return strncmp(l.start(), r.start(), cxx::min(l.len(), r.len())) < 0; }
114 class Pers_file : public Node
117 Pers_file(const char *name, mode_t mode)
118 : Node(name, (mode & 0777) | __S_IFREG) {}
119 File_data const &data() const { return _data; }
120 File_data &data() { return _data; }
125 class Pers_dir : public Node
128 Pers_dir(const char *name, mode_t mode)
129 : Node(name, (mode & 0777) | __S_IFDIR) {}
130 Ref_ptr<Node> find_path(cxx::String);
131 int add_node(Ref_ptr<Node> const &);
134 typedef cxx::Avl_tree<Node, Node_get_key, Path_avl_tree_compare> Tree;
138 Ref_ptr<Node> Pers_dir::find_path(cxx::String path)
140 return cxx::ref_ptr(_tree.find_node(path));
143 int Pers_dir::add_node(Ref_ptr<Node> const &n)
146 e = _tree.insert(n.ptr()).second;
152 class Tmpfs_dir : public Be_file
155 explicit Tmpfs_dir(Ref_ptr<Pers_dir> const &d) throw()
157 int get_entry(const char *, int, mode_t, Ref_ptr<File> *) throw();
158 int fstat64(struct stat64 *buf) const throw();
159 int mkdir(const char *, mode_t) throw();
160 int unlink(const char *) throw();
161 int rename(const char *, const char *) throw();
164 int walk_path(cxx::String const &_s,
165 Ref_ptr<Node> *ret, cxx::String *remaining = 0);
167 Ref_ptr<Pers_dir> _dir;
170 class Tmpfs_file : public Be_file
173 explicit Tmpfs_file(Ref_ptr<Pers_file> const &f) throw()
174 : Be_file(), _file(f), _pos(0) {}
176 ssize_t readv(const struct iovec*, int iovcnt) throw();
177 ssize_t writev(const struct iovec*, int iovcnt) throw();
178 off64_t lseek64(off64_t, int) throw();
179 int fstat64(struct stat64 *buf) const throw();
182 Ref_ptr<Pers_file> _file;
186 ssize_t Tmpfs_file::readv(const struct iovec *v, int iovcnt) throw()
193 for (int i = 0; i < iovcnt; ++i)
195 sum += _file->data().get(_pos, v[i].iov_len, v[i].iov_base);
196 _pos += v[i].iov_len;
201 ssize_t Tmpfs_file::writev(const struct iovec *v, int iovcnt) throw()
207 for (int i = 0; i < iovcnt; ++i)
209 sum += _file->data().put(_pos, v[i].iov_len, v[i].iov_base);
210 _pos += v[i].iov_len;
215 int Tmpfs_file::fstat64(struct stat64 *buf) const throw()
217 memcpy(buf, _file->info(), sizeof(*buf));
222 off64_t Tmpfs_file::lseek64(off64_t offset, int whence) throw()
226 case SEEK_SET: _pos = offset; break;
227 case SEEK_CUR: _pos += offset; break;
228 case SEEK_END: _pos = _file->data().size() + offset; break;
229 default: return -EINVAL;
240 Tmpfs_dir::get_entry(const char *name, int flags, mode_t mode,
241 Ref_ptr<File> *file) throw()
250 cxx::String n = name;
252 int e = walk_path(n, &path, &n);
257 if (!(flags & O_CREAT) && e < 0)
260 if ((flags & O_CREAT) && e == -ENOENT)
262 Ref_ptr<Node> node(new Pers_file(n.start(), mode));
263 // when ENOENT is return, path is always a directory
264 int e = cxx::ref_ptr_static_cast<Pers_dir>(path)->add_node(node);
271 *file = new Tmpfs_dir(cxx::ref_ptr_static_cast<Pers_dir>(path));
273 *file = new Tmpfs_file(cxx::ref_ptr_static_cast<Pers_file>(path));
283 Tmpfs_dir::fstat64(struct stat64 *buf) const throw()
285 memcpy(buf, _dir->info(), sizeof(*buf));
290 Tmpfs_dir::walk_path(cxx::String const &_s,
291 Ref_ptr<Node> *ret, cxx::String *remaining)
293 Ref_ptr<Pers_dir> p = _dir;
299 cxx::String::Index sep = s.find("/");
301 n = p->find_path(s.head(sep - s.start()));
307 *remaining = s.head(sep - s.start());
321 s = s.substr(sep + 1);
323 p = cxx::ref_ptr_static_cast<Pers_dir>(n);
332 Tmpfs_dir::mkdir(const char *name, mode_t mode) throw()
334 Ref_ptr<Node> node = _dir;
335 cxx::String p = cxx::String(name);
336 cxx::String path, last = p;
337 cxx::String::Index s = p.rfind("/");
341 last = p.substr(s + 1, p.end() - s);
343 int e = walk_path(path, &node);
351 Ref_ptr<Pers_dir> dnode = cxx::ref_ptr_static_cast<Pers_dir>(node);
353 Ref_ptr<Pers_dir> dir(new Pers_dir(last.start(), mode));
354 return dnode->add_node(dir);
358 Tmpfs_dir::unlink(const char *name) throw()
360 printf("Unimplemented: %s(%s)\n", __func__, name);
365 Tmpfs_dir::rename(const char *old, const char *newn) throw()
367 printf("Unimplemented: %s(%s, %s)\n", __func__, old, newn);
373 class Tmpfs_fs : public Be_file_system
376 Tmpfs_fs() : Be_file_system("tmpfs") {}
377 int mount(char const *source, unsigned long mountflags,
378 void const *data, cxx::Ref_ptr<File> *dir) throw()
383 *dir = cxx::ref_ptr(new Tmpfs_dir(cxx::ref_ptr(new Pers_dir("root", 0777))));
390 static Tmpfs_fs _tmpfs;