diff options
author | Andreas Kling <awesomekling@gmail.com> | 2018-10-28 14:11:51 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2018-10-28 14:11:51 +0100 |
commit | 97726862dd699cb0843b9d700789e30cf6625dc9 (patch) | |
tree | 07fd74e8e0e3b462ac5ab32994340c5090711348 | |
parent | 1d4af5125078b097b9ab843d53ba50a0d9b1de5e (diff) | |
download | serenity-97726862dd699cb0843b9d700789e30cf6625dc9.zip |
Add basic symlink support.
- sys$readlink + readlink()
- Add a /proc/PID/exe symlink to the process's executable.
- Print symlink contents in ls output.
- Some work on plumbing options into VFS::open().
-rw-r--r-- | Kernel/ProcFileSystem.cpp | 12 | ||||
-rw-r--r-- | Kernel/Syscall.cpp | 2 | ||||
-rw-r--r-- | Kernel/Syscall.h | 1 | ||||
-rw-r--r-- | Kernel/Task.cpp | 42 | ||||
-rw-r--r-- | Kernel/Task.h | 7 | ||||
-rw-r--r-- | Kernel/errno.h | 3 | ||||
-rw-r--r-- | LibC/dirent.cpp | 3 | ||||
-rw-r--r-- | LibC/unistd.cpp | 11 | ||||
-rw-r--r-- | LibC/unistd.h | 9 | ||||
-rw-r--r-- | Userland/cat.cpp | 2 | ||||
-rw-r--r-- | Userland/ls.cpp | 17 | ||||
-rw-r--r-- | Userland/mm.cpp | 2 | ||||
-rw-r--r-- | Userland/ps.cpp | 2 | ||||
-rw-r--r-- | Userland/sh.cpp | 2 | ||||
-rw-r--r-- | VirtualFileSystem/FileSystem.cpp | 4 | ||||
-rw-r--r-- | VirtualFileSystem/SyntheticFileSystem.cpp | 11 | ||||
-rw-r--r-- | VirtualFileSystem/SyntheticFileSystem.h | 2 | ||||
-rw-r--r-- | VirtualFileSystem/VirtualFileSystem.cpp | 41 | ||||
-rw-r--r-- | VirtualFileSystem/VirtualFileSystem.h | 11 | ||||
-rw-r--r-- | VirtualFileSystem/sys-errno.h | 2 |
20 files changed, 140 insertions, 46 deletions
diff --git a/Kernel/ProcFileSystem.cpp b/Kernel/ProcFileSystem.cpp index 225f55278f..6f8f6ebc8e 100644 --- a/Kernel/ProcFileSystem.cpp +++ b/Kernel/ProcFileSystem.cpp @@ -96,6 +96,16 @@ ByteBuffer procfs$pid_stack(Task& task) return buffer; } +ByteBuffer procfs$pid_exe(Task& task) +{ + InodeIdentifier inode; + { + InterruptDisabler disabler; + inode = task.executableInode(); + } + return VirtualFileSystem::the().absolutePath(inode).toByteBuffer(); +} + void ProcFileSystem::addProcess(Task& task) { ASSERT_INTERRUPTS_DISABLED(); @@ -105,6 +115,8 @@ void ProcFileSystem::addProcess(Task& task) m_pid2inode.set(task.pid(), dir.index()); addFile(createGeneratedFile("vm", [&task] { return procfs$pid_vm(task); }), dir.index()); addFile(createGeneratedFile("stack", [&task] { return procfs$pid_stack(task); }), dir.index()); + if (task.executableInode().isValid()) + addFile(createGeneratedFile("exe", [&task] { return procfs$pid_exe(task); }, 00120777), dir.index()); } void ProcFileSystem::removeProcess(Task& task) diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index e80bed6601..ba9884e0d5 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -116,6 +116,8 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3) return current->sys$uname((utsname*)arg1); case Syscall::SetMmapName: return current->sys$set_mmap_name((void*)arg1, (size_t)arg2, (const char*)arg3); + case Syscall::PosixReadlink: + return current->sys$readlink((const char*)arg1, (char*)arg2, (size_t)arg3); default: kprintf("int0x80: Unknown function %x requested {%x, %x, %x}\n", function, arg1, arg2, arg3); break; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 1d55e4bd2e..b35c95b233 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -35,6 +35,7 @@ enum Function { PosixChdir = 0x2003, PosixUname = 0x2004, SetMmapName = 0x2005, + PosixReadlink = 0x2006, }; void initialize(); diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index f5bc6160fc..0eb92e2458 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -234,7 +234,7 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren cwd = parentTask->m_cwd.copyRef(); } - auto handle = VirtualFileSystem::the().open(path, cwd ? cwd->inode : InodeIdentifier()); + auto handle = VirtualFileSystem::the().open(path, 0, cwd ? cwd->inode : InodeIdentifier()); if (!handle) { error = -ENOENT; // FIXME: Get a more detailed error from VFS. return nullptr; @@ -261,7 +261,7 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren } InterruptDisabler disabler; // FIXME: Get rid of this, jesus christ. This "critical" section is HUGE. - Task* t = new Task(parts.takeLast(), uid, gid, parentPID, Ring3); + Task* t = new Task(parts.takeLast(), uid, gid, parentPID, Ring3, handle->vnode()); t->m_arguments = move(taskArguments); @@ -362,13 +362,14 @@ Task* Task::createKernelTask(void (*e)(), String&& name) return task; } -Task::Task(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel ring) +Task::Task(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel ring, RetainPtr<VirtualFileSystem::Node>&& executable) : m_name(move(name)) , m_pid(next_pid++) , m_uid(uid) , m_gid(gid) , m_state(Runnable) , m_ring(ring) + , m_executable(move(executable)) , m_parentPID(parentPID) { m_fileHandles.append(nullptr); // stdin @@ -785,17 +786,39 @@ int Task::sys$close(int fd) int Task::sys$lstat(const char* path, Unix::stat* statbuf) { VALIDATE_USER_BUFFER(statbuf, sizeof(Unix::stat)); - auto handle = VirtualFileSystem::the().open(move(path), cwdInode()); + auto handle = VirtualFileSystem::the().open(move(path), O_NOFOLLOW_NOERROR, cwdInode()); if (!handle) return -1; handle->stat(statbuf); return 0; } +int Task::sys$readlink(const char* path, char* buffer, size_t size) +{ + VALIDATE_USER_BUFFER(path, strlen(path)); + VALIDATE_USER_BUFFER(buffer, size); + + auto handle = VirtualFileSystem::the().open(path, O_RDONLY | O_NOFOLLOW_NOERROR, cwdInode()); + if (!handle) + return -ENOENT; // FIXME: Get a more detailed error from VFS. + + if (!handle->metadata().isSymbolicLink()) + return -EINVAL; + + auto contents = handle->readEntireFile(); + if (!contents) + return -EIO; // FIXME: Get a more detailed error from VFS. + + memcpy(buffer, contents.pointer(), min(size, contents.size())); + if (contents.size() + 1 < size) + buffer[contents.size()] = '\0'; + return 0; +} + int Task::sys$chdir(const char* path) { VALIDATE_USER_BUFFER(path, strlen(path)); - auto handle = VirtualFileSystem::the().open(path, cwdInode()); + auto handle = VirtualFileSystem::the().open(path, 0, cwdInode()); if (!handle) return -ENOENT; // FIXME: More detailed error. if (!handle->isDirectory()) @@ -811,17 +834,20 @@ int Task::sys$getcwd(char* buffer, size_t size) return -ENOTIMPL; } -int Task::sys$open(const char* path, size_t pathLength) +int Task::sys$open(const char* path, int options) { #ifdef DEBUG_IO kprintf("Task::sys$open(): PID=%u, path=%s {%u}\n", m_pid, path, pathLength); #endif - VALIDATE_USER_BUFFER(path, pathLength); + VALIDATE_USER_BUFFER(path, strlen(path)); if (m_fileHandles.size() >= m_maxFileHandles) return -EMFILE; - auto handle = VirtualFileSystem::the().open(String(path, pathLength), cwdInode()); + auto handle = VirtualFileSystem::the().open(path, 0, cwdInode()); if (!handle) return -ENOENT; // FIXME: Detailed error. + if (options & O_DIRECTORY && !handle->isDirectory()) + return -ENOTDIR; // FIXME: This should be handled by VFS::open. + int fd = m_fileHandles.size(); handle->setFD(fd); m_fileHandles.append(move(handle)); diff --git a/Kernel/Task.h b/Kernel/Task.h index 10ea3a2dd3..c1ec246e58 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -87,7 +87,7 @@ public: uid_t sys$getuid(); gid_t sys$getgid(); pid_t sys$getpid(); - int sys$open(const char* path, size_t pathLength); + int sys$open(const char* path, int options); int sys$close(int fd); int sys$read(int fd, void* outbuf, size_t nread); int sys$lstat(const char*, Unix::stat*); @@ -108,6 +108,7 @@ public: int sys$gethostname(char* name, size_t length); int sys$get_arguments(int* argc, char*** argv); int sys$uname(utsname*); + int sys$readlink(const char*, char*, size_t); static void initialize(); @@ -134,12 +135,13 @@ public: bool isValidAddressForUser(LinearAddress) const; InodeIdentifier cwdInode() const { return m_cwd ? m_cwd->inode : InodeIdentifier(); } + InodeIdentifier executableInode() const { return m_executable ? m_executable->inode : InodeIdentifier(); } private: friend class MemoryManager; friend bool scheduleNewTask(); - Task(String&& name, uid_t, gid_t, pid_t parentPID, RingLevel); + Task(String&& name, uid_t, gid_t, pid_t parentPID, RingLevel, RetainPtr<VirtualFileSystem::Node>&& = nullptr); void allocateLDT(); @@ -171,6 +173,7 @@ private: size_t m_maxFileHandles { 16 }; RetainPtr<VirtualFileSystem::Node> m_cwd; + RetainPtr<VirtualFileSystem::Node> m_executable; struct Region : public Retainable<Region> { Region(LinearAddress, size_t, RetainPtr<Zone>&&, String&&); diff --git a/Kernel/errno.h b/Kernel/errno.h index d487ec94a2..71a874b5a4 100644 --- a/Kernel/errno.h +++ b/Kernel/errno.h @@ -35,7 +35,6 @@ #define EDOM 33 // Math argument out of domain of func #define ERANGE 34 // Math result not representable #define ENAMETOOLONG 36 // Name too long - +#define ELOOP 40 // Too many symbolic links #define EOVERFLOW 75 // Value too large for defined data type - #define ENOTIMPL 999 // Not implemented diff --git a/LibC/dirent.cpp b/LibC/dirent.cpp index bda115d456..e1e914b1f0 100644 --- a/LibC/dirent.cpp +++ b/LibC/dirent.cpp @@ -8,8 +8,7 @@ extern "C" { DIR* opendir(const char* name) { - // FIXME: Should fail if it's not a directory! - int fd = open(name); + int fd = open(name, O_RDONLY | O_DIRECTORY); if (fd == -1) return nullptr; DIR* dirp = (DIR*)malloc(sizeof(dirp)); diff --git a/LibC/unistd.cpp b/LibC/unistd.cpp index 1640ab0357..b554fcb549 100644 --- a/LibC/unistd.cpp +++ b/LibC/unistd.cpp @@ -20,10 +20,9 @@ pid_t getpid() return Syscall::invoke(Syscall::PosixGetpid); } -int open(const char* path) +int open(const char* path, int options) { - size_t length = strlen(path); - int rc = Syscall::invoke(Syscall::PosixOpen, (dword)path, (dword)length); + int rc = Syscall::invoke(Syscall::PosixOpen, (dword)path, (dword)options); __RETURN_WITH_ERRNO(rc, rc, -1); } @@ -74,5 +73,11 @@ int gethostname(char* buffer, size_t size) __RETURN_WITH_ERRNO(rc, rc, -1); } +ssize_t readlink(const char* path, char* buffer, size_t size) +{ + int rc = Syscall::invoke(Syscall::PosixReadlink, (dword)path, (dword)buffer, (dword)size); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + } diff --git a/LibC/unistd.h b/LibC/unistd.h index 74ee98ebda..e4dcfd4ca3 100644 --- a/LibC/unistd.h +++ b/LibC/unistd.h @@ -7,7 +7,7 @@ extern "C" { uid_t getuid(); gid_t getgid(); pid_t getpid(); -int open(const char* path); +int open(const char* path, int options); ssize_t read(int fd, void* buf, size_t count); int close(int fd); pid_t waitpid(pid_t, int* wstatus, int options); @@ -16,6 +16,7 @@ char* getcwd(char* buffer, size_t size); int lstat(const char* path, stat* statbuf); int sleep(unsigned seconds); int gethostname(char*, size_t); +ssize_t readlink(const char* path, char* buffer, size_t); #define WEXITSTATUS(status) (((status) & 0xff00) >> 8) #define WTERMSIG(status) ((status) & 0x7f) @@ -52,4 +53,10 @@ int gethostname(char*, size_t); #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_DIRECTORY 00200000 +#define O_NOFOLLOW 00400000 + } diff --git a/Userland/cat.cpp b/Userland/cat.cpp index fd0044a7fe..b127bf2cc9 100644 --- a/Userland/cat.cpp +++ b/Userland/cat.cpp @@ -9,7 +9,7 @@ int main(int argc, char** argv) printf("usage: cat <file>\n"); return 1; } - int fd = open(argv[1]); + int fd = open(argv[1], O_RDONLY); if (fd == -1) { printf("failed to open %s: %s\n", argv[1], strerror(errno)); return 1; diff --git a/Userland/ls.cpp b/Userland/ls.cpp index 30983147d9..ad26e020ad 100644 --- a/Userland/ls.cpp +++ b/Userland/ls.cpp @@ -65,7 +65,9 @@ int main(int c, char** v) const char* endColor = ""; if (colorize) { - if (S_ISDIR(st.st_mode)) + if (S_ISLNK(st.st_mode)) + beginColor = "\033[36;1m"; + else if (S_ISDIR(st.st_mode)) beginColor = "\033[34;1m"; else if (st.st_mode & 0111) beginColor = "\033[32;1m"; @@ -76,10 +78,19 @@ int main(int c, char** v) printf("%s%s%s", beginColor, de->d_name, endColor); - if (S_ISDIR(st.st_mode)) + if (S_ISLNK(st.st_mode)) { + char linkbuf[256]; + ssize_t nread = readlink(pathbuf, linkbuf, sizeof(linkbuf)); + if (nread < 0) { + perror("readlink failed"); + } else { + printf(" -> %s", linkbuf); + } + } else if (S_ISDIR(st.st_mode)) { printf("/"); - else if (st.st_mode & 0111) + } else if (st.st_mode & 0111) { printf("*"); + } printf("\n"); } return 0; diff --git a/Userland/mm.cpp b/Userland/mm.cpp index ee03598867..8cd674f255 100644 --- a/Userland/mm.cpp +++ b/Userland/mm.cpp @@ -3,7 +3,7 @@ int main(int c, char** v) { - int fd = open("/proc/mm"); + int fd = open("/proc/mm", O_RDONLY); if (fd == -1) { perror("failed to open /proc/mm"); return 1; diff --git a/Userland/ps.cpp b/Userland/ps.cpp index ec49c480d0..89f16a06a8 100644 --- a/Userland/ps.cpp +++ b/Userland/ps.cpp @@ -3,7 +3,7 @@ int main(int c, char** v) { - int fd = open("/proc/summary"); + int fd = open("/proc/summary", O_RDONLY); if (fd == -1) { perror("failed to open /proc/summary"); return 1; diff --git a/Userland/sh.cpp b/Userland/sh.cpp index 3f503419a6..a0e3d1f976 100644 --- a/Userland/sh.cpp +++ b/Userland/sh.cpp @@ -147,7 +147,7 @@ int main(int, char**) int linedx = 0; linebuf[0] = '\0'; - int fd = open("/dev/keyboard"); + int fd = open("/dev/keyboard", O_RDONLY); if (fd == -1) { printf("failed to open /dev/keyboard :(\n"); return 1; diff --git a/VirtualFileSystem/FileSystem.cpp b/VirtualFileSystem/FileSystem.cpp index b718fe5c35..6bb738245d 100644 --- a/VirtualFileSystem/FileSystem.cpp +++ b/VirtualFileSystem/FileSystem.cpp @@ -74,7 +74,8 @@ ByteBuffer FileSystem::readEntireInode(InodeIdentifier inode, FileHandle* handle return nullptr; } - auto contents = ByteBuffer::createUninitialized(metadata.size); + size_t initialSize = metadata.size ? metadata.size : 4096; + auto contents = ByteBuffer::createUninitialized(initialSize); Unix::ssize_t nread; byte buffer[512]; @@ -87,6 +88,7 @@ ByteBuffer FileSystem::readEntireInode(InodeIdentifier inode, FileHandle* handle memcpy(out, buffer, nread); out += nread; offset += nread; + ASSERT(offset <= initialSize); // FIXME: Support dynamically growing the buffer. } if (nread < 0) { kprintf("[fs] readInode: ERROR: %d\n", nread); diff --git a/VirtualFileSystem/SyntheticFileSystem.cpp b/VirtualFileSystem/SyntheticFileSystem.cpp index 314e43c52d..db8b34e8d5 100644 --- a/VirtualFileSystem/SyntheticFileSystem.cpp +++ b/VirtualFileSystem/SyntheticFileSystem.cpp @@ -60,12 +60,12 @@ auto SyntheticFileSystem::createTextFile(String&& name, String&& text) -> OwnPtr file->metadata.size = file->data.size(); file->metadata.uid = 100; file->metadata.gid = 200; - file->metadata.mode = 04; + file->metadata.mode = 0040644; file->metadata.mtime = mepoch; return file; } -auto SyntheticFileSystem::createGeneratedFile(String&& name, Function<ByteBuffer()>&& generator) -> OwnPtr<File> +auto SyntheticFileSystem::createGeneratedFile(String&& name, Function<ByteBuffer()>&& generator, Unix::mode_t mode) -> OwnPtr<File> { auto file = make<File>(); file->generator = move(generator); @@ -73,7 +73,7 @@ auto SyntheticFileSystem::createGeneratedFile(String&& name, Function<ByteBuffer file->metadata.size = 0; file->metadata.uid = 0; file->metadata.gid = 0; - file->metadata.mode = 0100644; + file->metadata.mode = mode; file->metadata.mtime = mepoch; return file; } @@ -146,9 +146,8 @@ bool SyntheticFileSystem::enumerateDirectoryInode(InodeIdentifier inode, Functio callback({ ".", synInode.metadata.inode }); callback({ "..", synInode.parent }); - for (auto& child : synInode.children) { + for (auto& child : synInode.children) callback({ child->name, child->metadata.inode }); - } return true; } @@ -214,8 +213,8 @@ Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::o generatedData = handle->generatorCache(); } } - auto* data = generatedData ? &generatedData : &file.data; + auto* data = generatedData ? &generatedData : &file.data; Unix::ssize_t nread = min(static_cast<Unix::off_t>(data->size() - offset), static_cast<Unix::off_t>(count)); memcpy(buffer, data->pointer() + offset, nread); if (nread == 0 && handle && handle->generatorCache()) diff --git a/VirtualFileSystem/SyntheticFileSystem.h b/VirtualFileSystem/SyntheticFileSystem.h index d9d84c962a..ed7a9d900e 100644 --- a/VirtualFileSystem/SyntheticFileSystem.h +++ b/VirtualFileSystem/SyntheticFileSystem.h @@ -40,7 +40,7 @@ protected: OwnPtr<File> createDirectory(String&& name); OwnPtr<File> createTextFile(String&& name, String&& text); - OwnPtr<File> createGeneratedFile(String&& name, Function<ByteBuffer()>&&); + OwnPtr<File> createGeneratedFile(String&& name, Function<ByteBuffer()>&&, Unix::mode_t = 0100644); InodeIdentifier addFile(OwnPtr<File>&&, InodeIndex parent = RootInodeIndex); bool removeFile(InodeIndex); diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp index f8ead5960a..5145d9a1d1 100644 --- a/VirtualFileSystem/VirtualFileSystem.cpp +++ b/VirtualFileSystem/VirtualFileSystem.cpp @@ -5,6 +5,7 @@ #include <AK/kmalloc.h> #include <AK/kstdio.h> #include <AK/ktime.h> +#include "sys-errno.h" //#define VFS_DEBUG @@ -104,7 +105,8 @@ bool VirtualFileSystem::mount(RetainPtr<FileSystem>&& fileSystem, const String& { ASSERT(fileSystem); - auto inode = resolvePath(path); + int error; + auto inode = resolvePath(path, error); if (!inode.isValid()) { kprintf("[VFS] mount can't resolve mount point '%s'\n", path.characters()); return false; @@ -172,7 +174,8 @@ void VirtualFileSystem::freeNode(Node* node) bool VirtualFileSystem::isDirectory(const String& path, InodeIdentifier base) { - auto inode = resolvePath(path, base); + int error; + auto inode = resolvePath(path, error, base); if (!inode.isValid()) return false; @@ -226,7 +229,8 @@ void VirtualFileSystem::enumerateDirectoryInode(InodeIdentifier directoryInode, void VirtualFileSystem::listDirectory(const String& path) { - auto directoryInode = resolvePath(path); + int error; + auto directoryInode = resolvePath(path, error); if (!directoryInode.isValid()) return; @@ -326,7 +330,8 @@ void VirtualFileSystem::listDirectory(const String& path) void VirtualFileSystem::listDirectoryRecursively(const String& path) { - auto directory = resolvePath(path); + int error; + auto directory = resolvePath(path, error); if (!directory.isValid()) return; @@ -351,17 +356,19 @@ bool VirtualFileSystem::touch(const String& path) { Locker locker(VirtualFileSystem::lock()); - auto inode = resolvePath(path); + int error; + auto inode = resolvePath(path, error); if (!inode.isValid()) return false; return inode.fileSystem()->setModificationTime(inode, ktime(nullptr)); } -OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, InodeIdentifier base) +OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, int options, InodeIdentifier base) { Locker locker(VirtualFileSystem::lock()); - auto inode = resolvePath(path, base); + int error; + auto inode = resolvePath(path, error, base, options); if (!inode.isValid()) return nullptr; auto vnode = getOrCreateNode(inode); @@ -397,7 +404,8 @@ InodeIdentifier VirtualFileSystem::resolveSymbolicLink(const String& basePath, I return { }; char buf[4096]; ksprintf(buf, "/%s/%s", basePath.characters(), String((const char*)symlinkContents.pointer(), symlinkContents.size()).characters()); - return resolvePath(buf); + int error; + return resolvePath(buf, error); } String VirtualFileSystem::absolutePath(InodeIdentifier inode) @@ -407,6 +415,7 @@ String VirtualFileSystem::absolutePath(InodeIdentifier inode) if (!inode.isValid()) return String(); + int error; Vector<InodeIdentifier> lineage; while (inode != m_rootNode->inode) { if (auto* mount = findMountForGuest(inode)) @@ -414,7 +423,7 @@ String VirtualFileSystem::absolutePath(InodeIdentifier inode) else lineage.append(inode); if (inode.metadata().isDirectory()) { - inode = resolvePath("..", inode); + inode = resolvePath("..", error, inode); } else inode = inode.fileSystem()->findParentOfInode(inode); ASSERT(inode.isValid()); @@ -434,7 +443,7 @@ String VirtualFileSystem::absolutePath(InodeIdentifier inode) return builder.build(); } -InodeIdentifier VirtualFileSystem::resolvePath(const String& path, InodeIdentifier base) +InodeIdentifier VirtualFileSystem::resolvePath(const String& path, int& error, InodeIdentifier base, int options) { if (path.isEmpty()) return { }; @@ -455,12 +464,14 @@ InodeIdentifier VirtualFileSystem::resolvePath(const String& path, InodeIdentifi #ifdef VFS_DEBUG kprintf("invalid metadata\n"); #endif + error = -EIO; return { }; } if (!metadata.isDirectory()) { #ifdef VFS_DEBUG kprintf("not directory\n"); #endif + error = -EIO; return { }; } inode = inode.fileSystem()->childOfDirectoryInodeWithName(inode, part); @@ -468,6 +479,7 @@ InodeIdentifier VirtualFileSystem::resolvePath(const String& path, InodeIdentifi #ifdef VFS_DEBUG kprintf("bad child\n"); #endif + error = -EIO; return { }; } #ifdef VFS_DEBUG @@ -489,6 +501,14 @@ InodeIdentifier VirtualFileSystem::resolvePath(const String& path, InodeIdentifi } metadata = inode.metadata(); if (metadata.isSymbolicLink()) { + if (i == parts.size() - 1) { + if (options & O_NOFOLLOW) { + error = -ELOOP; + return { }; + } + if (options & O_NOFOLLOW_NOERROR) + return inode; + } char buf[4096] = ""; char* p = buf; for (unsigned j = 0; j < i; ++j) { @@ -497,6 +517,7 @@ InodeIdentifier VirtualFileSystem::resolvePath(const String& path, InodeIdentifi inode = resolveSymbolicLink(buf, inode); if (!inode.isValid()) { kprintf("Symbolic link resolution failed :(\n"); + error = -ENOENT; return { }; } } diff --git a/VirtualFileSystem/VirtualFileSystem.h b/VirtualFileSystem/VirtualFileSystem.h index 099cf2c853..c697b0df4c 100644 --- a/VirtualFileSystem/VirtualFileSystem.h +++ b/VirtualFileSystem/VirtualFileSystem.h @@ -12,6 +12,13 @@ #include "Limits.h" #include "FileSystem.h" +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_DIRECTORY 00200000 +#define O_NOFOLLOW 00400000 +#define O_NOFOLLOW_NOERROR 0x4000000 + class CharacterDevice; class FileHandle; @@ -79,7 +86,7 @@ public: bool mountRoot(RetainPtr<FileSystem>&&); bool mount(RetainPtr<FileSystem>&&, const String& path); - OwnPtr<FileHandle> open(const String& path, InodeIdentifier base = InodeIdentifier()); + OwnPtr<FileHandle> open(const String& path, int options = 0, InodeIdentifier base = InodeIdentifier()); OwnPtr<FileHandle> create(const String& path, InodeIdentifier base = InodeIdentifier()); OwnPtr<FileHandle> mkdir(const String& path, InodeIdentifier base = InodeIdentifier()); @@ -98,7 +105,7 @@ private: friend class FileHandle; void enumerateDirectoryInode(InodeIdentifier, Function<bool(const FileSystem::DirectoryEntry&)>); - InodeIdentifier resolvePath(const String& path, InodeIdentifier base = InodeIdentifier()); + InodeIdentifier resolvePath(const String& path, int& error, InodeIdentifier base = InodeIdentifier(), int options = 0); InodeIdentifier resolveSymbolicLink(const String& basePath, InodeIdentifier symlinkInode); RetainPtr<Node> allocateNode(); diff --git a/VirtualFileSystem/sys-errno.h b/VirtualFileSystem/sys-errno.h index e01e73798a..7549c562b5 100644 --- a/VirtualFileSystem/sys-errno.h +++ b/VirtualFileSystem/sys-errno.h @@ -34,5 +34,5 @@ #define EPIPE 32 // Broken pipe #define EDOM 33 // Math argument out of domain of func #define ERANGE 34 // Math result not representable - +#define ELOOP 40 // Too many symbolic links #define EOVERFLOW 75 // Value too large for defined data type |