#include <sys/stat.h>
#include <sys/ioctl.h>
-#include <errno.h>
+#include <dirent.h>
#include <cstdio>
-
namespace {
using namespace L4Re::Vfs;
public:
Node(const char *path, mode_t mode)
: _ref_cnt(0), _path(strdup(path))
- { _info.st_mode = mode; }
+ {
+ memset(&_info, 0, sizeof(_info));
+ _info.st_mode = mode;
+ }
const char *path() const { return _path; }
struct stat64 *info() { return &_info; }
class Pers_dir : public Node
{
+private:
+ typedef cxx::Avl_tree<Node, Node_get_key, Path_avl_tree_compare> Tree;
+ Tree _tree;
+
public:
Pers_dir(const char *name, mode_t mode)
: Node(name, (mode & 0777) | __S_IFDIR) {}
Ref_ptr<Node> find_path(cxx::String);
- int add_node(Ref_ptr<Node> const &);
+ bool add_node(Ref_ptr<Node> const &);
-private:
- typedef cxx::Avl_tree<Node, Node_get_key, Path_avl_tree_compare> Tree;
- Tree _tree;
+ typedef Tree::Const_iterator Const_iterator;
+ Const_iterator begin() const { return _tree.begin(); }
+ Const_iterator end() const { return _tree.end(); }
};
Ref_ptr<Node> Pers_dir::find_path(cxx::String path)
return cxx::ref_ptr(_tree.find_node(path));
}
-int Pers_dir::add_node(Ref_ptr<Node> const &n)
+bool Pers_dir::add_node(Ref_ptr<Node> const &n)
{
- int e;
- e = _tree.insert(n.ptr()).second;
- if (!e)
+ bool e = _tree.insert(n.ptr()).second;
+ if (e)
n->add_ref();
return e;
}
{
public:
explicit Tmpfs_dir(Ref_ptr<Pers_dir> const &d) throw()
- : _dir(d) {}
+ : _dir(d), _getdents_state(false) {}
int get_entry(const char *, int, mode_t, Ref_ptr<File> *) throw();
+ ssize_t getdents(char *, size_t) throw();
int fstat64(struct stat64 *buf) const throw();
+ int utime(const struct utimbuf *) throw();
+ int fchmod(mode_t) throw();
int mkdir(const char *, mode_t) throw();
int unlink(const char *) throw();
int rename(const char *, const char *) throw();
Ref_ptr<Node> *ret, cxx::String *remaining = 0);
Ref_ptr<Pers_dir> _dir;
+ bool _getdents_state;
+ Pers_dir::Const_iterator _getdents_iter;
};
-class Tmpfs_file : public Be_file
+class Tmpfs_file : public Be_file_pos
{
public:
explicit Tmpfs_file(Ref_ptr<Pers_file> const &f) throw()
- : Be_file(), _file(f), _pos(0) {}
+ : Be_file_pos(), _file(f) {}
- ssize_t readv(const struct iovec*, int iovcnt) throw();
- ssize_t writev(const struct iovec*, int iovcnt) throw();
- off64_t lseek64(off64_t, int) throw();
+ off64_t size() const throw();
int fstat64(struct stat64 *buf) const throw();
int ioctl(unsigned long, va_list) throw();
+ int utime(const struct utimbuf *) throw();
+ int fchmod(mode_t) throw();
private:
+ ssize_t preadv(const struct iovec *v, int iovcnt, off64_t p) throw();
+ ssize_t pwritev(const struct iovec *v, int iovcnt, off64_t p) throw();
Ref_ptr<Pers_file> _file;
- off64_t _pos;
};
-ssize_t Tmpfs_file::readv(const struct iovec *v, int iovcnt) throw()
+ssize_t Tmpfs_file::preadv(const struct iovec *v, int iovcnt, off64_t p) throw()
{
if (iovcnt < 0)
return -EINVAL;
-
ssize_t sum = 0;
for (int i = 0; i < iovcnt; ++i)
{
- sum += _file->data().get(_pos, v[i].iov_len, v[i].iov_base);
- _pos += v[i].iov_len;
+ sum += _file->data().get(p, v[i].iov_len, v[i].iov_base);
+ p += v[i].iov_len;
}
return sum;
}
-ssize_t Tmpfs_file::writev(const struct iovec *v, int iovcnt) throw()
+ssize_t Tmpfs_file::pwritev(const struct iovec *v, int iovcnt, off64_t p) throw()
{
if (iovcnt < 0)
return -EINVAL;
ssize_t sum = 0;
for (int i = 0; i < iovcnt; ++i)
{
- sum += _file->data().put(_pos, v[i].iov_len, v[i].iov_base);
- _pos += v[i].iov_len;
+ sum += _file->data().put(p, v[i].iov_len, v[i].iov_base);
+ p += v[i].iov_len;
}
return sum;
}
int Tmpfs_file::fstat64(struct stat64 *buf) const throw()
{
+ _file->info()->st_size = _file->data().size();
memcpy(buf, _file->info(), sizeof(*buf));
return 0;
}
-off64_t Tmpfs_file::lseek64(off64_t offset, int whence) throw()
-{
- switch (whence)
- {
- case SEEK_SET: _pos = offset; break;
- case SEEK_CUR: _pos += offset; break;
- case SEEK_END: _pos = _file->data().size() + offset; break;
- default: return -EINVAL;
- };
-
- if (_pos < 0)
- return -EINVAL;
-
- return _pos;
-}
+off64_t Tmpfs_file::size() const throw()
+{ return _file->data().size(); }
int
Tmpfs_file::ioctl(unsigned long v, va_list args) throw()
{
case FIONREAD: // return amount of data still available
int *available = va_arg(args, int *);
- *available = _file->data().size() - _pos;
+ *available = _file->data().size() - pos();
return 0;
};
return -EINVAL;
}
+int
+Tmpfs_file::utime(const struct utimbuf *times) throw()
+{
+ _file->info()->st_atime = times->actime;
+ _file->info()->st_mtime = times->modtime;
+ return 0;
+}
+int
+Tmpfs_file::fchmod(mode_t m) throw()
+{
+ _file->info()->st_mode = m;
+ return 0;
+}
int
{
Ref_ptr<Node> node(new Pers_file(n.start(), mode));
// when ENOENT is return, path is always a directory
- int e = cxx::ref_ptr_static_cast<Pers_dir>(path)->add_node(node);
- if (e)
- return e;
+ bool e = cxx::ref_ptr_static_cast<Pers_dir>(path)->add_node(node);
+ if (!e)
+ return -ENOMEM;
path = node;
}
return 0;
}
+ssize_t
+Tmpfs_dir::getdents(char *buf, size_t sz) throw()
+{
+ struct dirent64 *d = (struct dirent64 *)buf;
+ ssize_t ret = 0;
+
+ if (!_getdents_state)
+ {
+ _getdents_iter = _dir->begin();
+ _getdents_state = true;
+ }
+ else if (_getdents_iter == _dir->end())
+ {
+ _getdents_state = false;
+ return 0;
+ }
+
+ for (; _getdents_iter != _dir->end(); ++_getdents_iter)
+ {
+ unsigned l = strlen(_getdents_iter->path()) + 1;
+ if (l > sizeof(d->d_name))
+ l = sizeof(d->d_name);
+
+ unsigned n = offsetof (struct dirent64, d_name) + l;
+ n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
+
+ if (n > sz)
+ break;
+
+ d->d_ino = 1;
+ d->d_off = 0;
+ memcpy(d->d_name, _getdents_iter->path(), l);
+ d->d_reclen = n;
+ d->d_type = DT_REG;
+ ret += n;
+ sz -= n;
+ d = (struct dirent64 *)((unsigned long)d + n);
+ }
+
+ return ret;
+}
+
int
Tmpfs_dir::fstat64(struct stat64 *buf) const throw()
{
return 0;
}
+int
+Tmpfs_dir::utime(const struct utimbuf *times) throw()
+{
+ _dir->info()->st_atime = times->actime;
+ _dir->info()->st_mtime = times->modtime;
+ return 0;
+}
+
+int
+Tmpfs_dir::fchmod(mode_t m) throw()
+{
+ _dir->info()->st_mode = m;
+ return 0;
+}
+
int
Tmpfs_dir::walk_path(cxx::String const &_s,
Ref_ptr<Node> *ret, cxx::String *remaining)
while (1)
{
+ if (s.len() == 0)
+ {
+ *ret = p;
+ return 0;
+ }
+
cxx::String::Index sep = s.find("/");
+ if (sep - s.start() == 1 && *s.start() == '.')
+ {
+ s = s.substr(s.start() + 2);
+ continue;
+ }
+
n = p->find_path(s.head(sep - s.start()));
if (!n)
cxx::String p = cxx::String(name);
cxx::String path, last = p;
cxx::String::Index s = p.rfind("/");
+
+ // trim /'s at the end
+ while (p.len() && s == p.end() - 1)
+ {
+ p.len(p.len() - 1);
+ s = p.rfind("/");
+ }
+
+ //printf("MKDIR '%s' p=%p %p\n", name, p.start(), s);
+
if (s != p.end())
{
path = p.head(s);
if (!node->is_dir())
return -ENOTDIR;
+ // due to path walking we can end up with an empty name
+ if (p.len() == 0 || p == cxx::String("."))
+ return 0;
+
Ref_ptr<Pers_dir> dnode = cxx::ref_ptr_static_cast<Pers_dir>(node);
Ref_ptr<Pers_dir> dir(new Pers_dir(last.start(), mode));
- return dnode->add_node(dir);
+ return dnode->add_node(dir) ? 0 : -EEXIST;
}
int
Tmpfs_dir::unlink(const char *name) throw()
{
- printf("Unimplemented: %s(%s)\n", __func__, name);
+ cxx::Ref_ptr<Node> n;
+
+ int e = walk_path(name, &n);
+ if (e < 0)
+ return -ENOENT;
+
+ printf("Unimplemented (if file exists): %s(%s)\n", __func__, name);
return -ENOMEM;
}
}
};
-static Tmpfs_fs _tmpfs;
+static Tmpfs_fs _tmpfs L4RE_VFS_FILE_SYSTEM_ATTRIBUTE;
}