/** * \brief File node * \author Norman Feske * \author Christian Helmuth * \auhtor Sebastian Sumpf * \date 2013-11-11 */ /* * Copyright (C) 2013-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ #ifndef _FILE_H_ #define _FILE_H_ /* Genode includes */ #include #include "node.h" namespace Rump_fs { class File; } class Rump_fs::File : public Node { private: int _fd; int _access_mode(Mode const &mode) { switch (mode) { case STAT_ONLY: case READ_ONLY: return O_RDONLY; case WRITE_ONLY: return O_WRONLY; case READ_WRITE: return O_RDWR; default: return O_RDONLY; } } unsigned long _inode(int dir, char const *name, bool create) { int ret; if (create) { mode_t ugo = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; ret = rump_sys_mknodat(dir, name, S_IFREG | ugo, 0); if (ret == -1 && errno != EEXIST) throw No_space(); } struct stat s; ret = rump_sys_fstatat(dir, name, &s, 0); if (ret == -1) throw Lookup_failed(); return s.st_ino; } unsigned long _inode_path(char const *path) { int ret; struct stat s; ret = rump_sys_stat(path, &s); if (ret == -1) throw Lookup_failed(); return s.st_ino; } int _open(int dir, char const *name, Mode mode) { int fd = rump_sys_openat(dir, name, _access_mode(mode)); if (fd == -1) throw Lookup_failed(); return fd; } int _open_path(char const *path, Mode mode) { int fd = rump_sys_open(path, _access_mode(mode)); if (fd == -1) throw Lookup_failed(); return fd; } public: File(int dir, char const *name, Mode mode, bool create) : Node(_inode(dir, name, create)), _fd(_open(dir, name, mode)) { Node::name(name); } File(char const *path, Mode mode) : Node(_inode_path(path)), _fd(_open_path(path, mode)) { Node::name(basename(path)); } virtual ~File() { rump_sys_close(_fd); } void update_modification_time(Timestamp const time) override { struct timespec ts[2] = { { .tv_sec = 0, .tv_nsec = 0 }, { .tv_sec = time.value, .tv_nsec = 0 } }; /* silently igore error */ rump_sys_futimens(_fd, (const timespec*)&ts); } size_t read(char *dst, size_t len, seek_off_t seek_offset) override { ssize_t ret; if (seek_offset == SEEK_TAIL) ret = rump_sys_lseek(_fd, -len, SEEK_END) != -1 ? rump_sys_read(_fd, dst, len) : 0; else ret = rump_sys_pread(_fd, dst, len, seek_offset); return ret == -1 ? 0 : ret; } size_t write(char const *src, size_t len, seek_off_t seek_offset) override { ssize_t ret; if (seek_offset == SEEK_TAIL) ret = rump_sys_lseek(_fd, 0, SEEK_END) != -1 ? rump_sys_write(_fd, src, len) : 0; else ret = rump_sys_pwrite(_fd, src, len, seek_offset); return ret == -1 ? 0 : ret; } virtual Status status() override { struct stat st { }; if (rump_sys_fstat(_fd, &st) < 0) { st.st_size = 0; st.st_mtime = 0; } return { .size = (file_size_t)st.st_size, .type = File_system::Node_type::CONTINUOUS_FILE, .rwx = { .readable = (st.st_mode & S_IRUSR), .writeable = (st.st_mode & S_IWUSR), .executable = (st.st_mode & S_IXUSR) }, .inode = inode(), .modification_time = { (int64_t)st.st_mtime } }; } void truncate(file_size_t size) override { rump_sys_ftruncate(_fd, size); mark_as_updated(); } }; #endif /* _FILE_H_ */