From 8b8e3ef7a504dfa4b2a337292247e0bc1abc11d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Fri, 2 Aug 2013 12:42:12 +0200 Subject: [PATCH] noux: calculate inode value from path There are programms that use struct stat's st_ino field to check certain conditions. Since we are using multiple filesystems in a noux session we cannot use the inode number which the actual filesystem provides. Therefore we calculate a random inode number by hashing the stated path. Fixes #299. --- ports/src/noux/io_channel.h | 8 ++++++ ports/src/noux/main.cc | 49 +++++++++++++++++++++++++++++++-- ports/src/noux/vfs_io_channel.h | 9 +++++- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/ports/src/noux/io_channel.h b/ports/src/noux/io_channel.h index e803353b7..38778453f 100644 --- a/ports/src/noux/io_channel.h +++ b/ports/src/noux/io_channel.h @@ -168,6 +168,14 @@ namespace Noux { h; h = h->next()) h->handle_interrupt(); } + + /** + * Get the path of the file associated with the I/O channel + * + * This function is used to simplify the implemenation of SYSCALL_FSTAT + * and is only implemented by Vfs_io_channel. + */ + virtual bool path(char *path, size_t len) { return false; } }; } diff --git a/ports/src/noux/main.cc b/ports/src/noux/main.cc index 9394ce77f..4a7c6e5ab 100644 --- a/ports/src/noux/main.cc +++ b/ports/src/noux/main.cc @@ -114,6 +114,23 @@ namespace Noux { return false; } }; + + /** + * This function is used to generate inode values from the given + * path using the FNV-1a algorithm. + */ + inline uint32_t hash_path(const char *path, size_t len) + { + const unsigned char * p = reinterpret_cast(path); + uint32_t hash = 2166136261U; + + for (size_t i = 0; i < len; i++) { + hash ^= p[i]; + hash *= 16777619; + } + + return hash; + } }; @@ -195,23 +212,51 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc) case SYSCALL_STAT: case SYSCALL_LSTAT: /* XXX implement difference between 'lstat' and 'stat' */ { + /** + * We calculate the inode by hashing the path because there is + * no inode registry in noux. + */ + size_t path_len = strlen(_sysio->stat_in.path); + uint32_t path_hash = hash_path(_sysio->stat_in.path, path_len); + bool result = root_dir()->stat(_sysio, _sysio->stat_in.path); /** - * Instead of using the uid/gid given by the actual file system + * Instead of using the uid/gid given by the actual file system * we use the ones specificed in the config. */ if (result) { _sysio->stat_out.st.uid = user_info()->uid; _sysio->stat_out.st.gid = user_info()->gid; + + _sysio->stat_out.st.inode = path_hash; } return result; } case SYSCALL_FSTAT: + { + Shared_pointer io = _lookup_channel(_sysio->fstat_in.fd); - return _lookup_channel(_sysio->fstat_in.fd)->fstat(_sysio); + bool result = io->fstat(_sysio); + + if (result) { + Sysio::Path path; + + /** + * Only actual fd's are valid fstat targets. + */ + if (io->path(path, sizeof (path))) { + size_t path_len = strlen(path); + uint32_t path_hash = hash_path(path, path_len); + + _sysio->stat_out.st.inode = path_hash; + } + } + + return result; + } case SYSCALL_FCNTL: diff --git a/ports/src/noux/vfs_io_channel.h b/ports/src/noux/vfs_io_channel.h index e7b42e0b8..1e09e9730 100644 --- a/ports/src/noux/vfs_io_channel.h +++ b/ports/src/noux/vfs_io_channel.h @@ -172,6 +172,14 @@ namespace Noux { return _fh->fs()->check_unblock(_fh, rd, wr, ex); } + bool path(char *path, size_t len) + { + strncpy(path, _path.base(), len); + path[len - 1] = '\0'; + + return true; + } + /************************************** ** Signal_dispatcher_base interface ** **************************************/ @@ -183,7 +191,6 @@ namespace Noux { { Io_channel::invoke_all_notifiers(); } - }; }