From b8e52189d5374ef79a62ba97770395fcad8b5b24 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Fri, 1 Apr 2016 11:42:31 +0200 Subject: [PATCH] lib/vfs: new permissions errors New errors STAT_ERR_NO_PERM, DIRENT_ERR_NO_PERM, and READLINK_NO_PERM to distinguish lookup errors from permissions or other errors. Issue #1751 --- repos/libports/src/lib/libc/vfs_plugin.cc | 5 +++- repos/os/include/vfs/directory_service.h | 7 ++--- repos/ports/src/lib/libc_noux/plugin.cc | 31 +++++++++++++++-------- 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/repos/libports/src/lib/libc/vfs_plugin.cc b/repos/libports/src/lib/libc/vfs_plugin.cc index 483f92f129..4cb3db66e4 100644 --- a/repos/libports/src/lib/libc/vfs_plugin.cc +++ b/repos/libports/src/lib/libc/vfs_plugin.cc @@ -385,6 +385,7 @@ int Libc::Vfs_plugin::stat(char const *path, struct stat *buf) switch (_root_dir.stat(path, stat)) { case Result::STAT_ERR_NO_ENTRY: errno = ENOENT; return -1; + case Result::STAT_ERR_NO_PERM: errno = EACCES; return -1; case Result::STAT_OK: break; } @@ -459,7 +460,8 @@ ssize_t Libc::Vfs_plugin::getdirentries(Libc::File_descriptor *fd, char *buf, unsigned const index = handle->seek() / sizeof(Vfs::Directory_service::Dirent); switch (handle->ds().dirent(fd->fd_path, index, dirent_out)) { - case Result::DIRENT_ERR_INVALID_PATH: /* XXX errno */ return -1; + case Result::DIRENT_ERR_INVALID_PATH: errno = ENOENT; return -1; + case Result::DIRENT_ERR_NO_PERM: errno = EACCES; return -1; case Result::DIRENT_OK: break; } @@ -745,6 +747,7 @@ ssize_t Libc::Vfs_plugin::readlink(const char *path, char *buf, size_t buf_size) switch (_root_dir.readlink(path, buf, buf_size, out_len)) { case Result::READLINK_ERR_NO_ENTRY: errno = ENOENT; return -1; + case Result::READLINK_ERR_NO_PERM: errno = EACCES; return -1; case Result::READLINK_OK: break; }; diff --git a/repos/os/include/vfs/directory_service.h b/repos/os/include/vfs/directory_service.h index 5bf21f6f28..50747f5de7 100644 --- a/repos/os/include/vfs/directory_service.h +++ b/repos/os/include/vfs/directory_service.h @@ -94,7 +94,8 @@ struct Vfs::Directory_service unsigned device; }; - enum Stat_result { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS, STAT_OK }; + enum Stat_result { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS, + STAT_ERR_NO_PERM, STAT_OK }; virtual Stat_result stat(char const *path, Stat &) = 0; @@ -103,7 +104,7 @@ struct Vfs::Directory_service ** Dirent ** ************/ - enum Dirent_result { DIRENT_ERR_INVALID_PATH, DIRENT_OK }; + enum Dirent_result { DIRENT_ERR_INVALID_PATH, DIRENT_ERR_NO_PERM, DIRENT_OK }; enum { DIRENT_MAX_NAME_LEN = 128 }; @@ -141,7 +142,7 @@ struct Vfs::Directory_service ** Readlink ** **************/ - enum Readlink_result { READLINK_ERR_NO_ENTRY, READLINK_OK }; + enum Readlink_result { READLINK_ERR_NO_ENTRY, READLINK_ERR_NO_PERM, READLINK_OK }; virtual Readlink_result readlink(char const *path, char *buf, file_size buf_size, file_size &out_len) = 0; diff --git a/repos/ports/src/lib/libc_noux/plugin.cc b/repos/ports/src/lib/libc_noux/plugin.cc index 57524bbc3f..7f6d2d5b13 100644 --- a/repos/ports/src/lib/libc_noux/plugin.cc +++ b/repos/ports/src/lib/libc_noux/plugin.cc @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -1087,10 +1087,10 @@ namespace { if (verbose) PWRN("stat syscall failed for path \"%s\"", path); switch (sysio()->error.stat) { - case Vfs::Directory_service::STAT_OK: /* never reached */ - case Vfs::Directory_service::STAT_ERR_NO_ENTRY: errno = ENOENT; break; + case Vfs::Directory_service::STAT_ERR_NO_ENTRY: errno = ENOENT; return -1; + case Vfs::Directory_service::STAT_ERR_NO_PERM: errno = EACCES; return -1; + case Vfs::Directory_service::STAT_OK: break; /* never reached */ } - return -1; } _sysio_to_stat_struct(sysio(), buf); @@ -1165,9 +1165,16 @@ namespace { Genode::strncpy(sysio()->symlink_in.oldpath, oldpath, sizeof(sysio()->symlink_in.oldpath)); Genode::strncpy(sysio()->symlink_in.newpath, newpath, sizeof(sysio()->symlink_in.newpath)); if (!noux_syscall(Noux::Session::SYSCALL_SYMLINK)) { - PERR("symlink error"); - /* XXX set errno */ - return -1; + PWRN("symlink syscall failed for path \"%s\"", newpath); + typedef Vfs::Directory_service::Symlink_result Result; + switch (sysio()->error.symlink) { + case Result::SYMLINK_ERR_NO_ENTRY: errno = ENOENT; return -1; + case Result::SYMLINK_ERR_EXISTS: errno = EEXIST; return -1; + case Result::SYMLINK_ERR_NO_SPACE: errno = ENOSPC; return -1; + case Result::SYMLINK_ERR_NO_PERM: errno = EPERM; return -1; + case Result::SYMLINK_ERR_NAME_TOO_LONG: errno = ENAMETOOLONG; return -1; + case Result::SYMLINK_OK: break; + } } return 0; @@ -1707,9 +1714,13 @@ namespace { sysio()->readlink_in.bufsiz = bufsiz; if (!noux_syscall(Noux::Session::SYSCALL_READLINK)) { - PWRN("readlink syscall failed for \"%s\"", path); - /* XXX set errno */ - return -1; + PWRN("readlink syscall failed for path \"%s\"", path); + typedef Vfs::Directory_service::Readlink_result Result; + switch (sysio()->error.readlink) { + case Result::READLINK_ERR_NO_ENTRY: errno = ENOENT; return -1; + case Result::READLINK_ERR_NO_PERM: errno = EPERM; return -1; + case Result::READLINK_OK: break; + } } ssize_t size = Genode::min((size_t)sysio()->readlink_out.count, bufsiz);