From 97726862dd699cb0843b9d700789e30cf6625dc9 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 28 Oct 2018 14:11:51 +0100 Subject: [PATCH] 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(). --- Kernel/ProcFileSystem.cpp | 12 +++++++ Kernel/Syscall.cpp | 2 ++ Kernel/Syscall.h | 1 + Kernel/Task.cpp | 42 ++++++++++++++++++----- Kernel/Task.h | 7 ++-- Kernel/errno.h | 3 +- LibC/dirent.cpp | 3 +- LibC/unistd.cpp | 11 ++++-- LibC/unistd.h | 9 ++++- Userland/cat.cpp | 2 +- Userland/ls.cpp | 17 +++++++-- Userland/mm.cpp | 2 +- Userland/ps.cpp | 2 +- Userland/sh.cpp | 2 +- VirtualFileSystem/FileSystem.cpp | 4 ++- VirtualFileSystem/SyntheticFileSystem.cpp | 11 +++--- VirtualFileSystem/SyntheticFileSystem.h | 2 +- VirtualFileSystem/VirtualFileSystem.cpp | 41 ++++++++++++++++------ VirtualFileSystem/VirtualFileSystem.h | 11 ++++-- VirtualFileSystem/sys-errno.h | 2 +- 20 files changed, 140 insertions(+), 46 deletions(-) diff --git a/Kernel/ProcFileSystem.cpp b/Kernel/ProcFileSystem.cpp index 225f55278f6..6f8f6ebc8e2 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 e80bed66011..ba9884e0d5a 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 1d55e4bd2eb..b35c95b2339 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 f5bc6160fc2..0eb92e2458f 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&& 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 10ea3a2dd33..c1ec246e581 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&& = nullptr); void allocateLDT(); @@ -171,6 +173,7 @@ private: size_t m_maxFileHandles { 16 }; RetainPtr m_cwd; + RetainPtr m_executable; struct Region : public Retainable { Region(LinearAddress, size_t, RetainPtr&&, String&&); diff --git a/Kernel/errno.h b/Kernel/errno.h index d487ec94a2d..71a874b5a40 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 bda115d456c..e1e914b1f0b 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 1640ab03570..b554fcb549d 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 74ee98ebdaf..e4dcfd4ca34 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 fd0044a7fed..b127bf2cc9e 100644 --- a/Userland/cat.cpp +++ b/Userland/cat.cpp @@ -9,7 +9,7 @@ int main(int argc, char** argv) printf("usage: cat \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 30983147d93..ad26e020ad5 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 ee035988677..8cd674f255a 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 ec49c480d0e..89f16a06a85 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 3f503419a63..a0e3d1f9765 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 b718fe5c35b..6bb738245d3 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 314e43c52d7..db8b34e8d5c 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&& generator) -> OwnPtr +auto SyntheticFileSystem::createGeneratedFile(String&& name, Function&& generator, Unix::mode_t mode) -> OwnPtr { auto file = make(); file->generator = move(generator); @@ -73,7 +73,7 @@ auto SyntheticFileSystem::createGeneratedFile(String&& name, Functionmetadata.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(data->size() - offset), static_cast(count)); memcpy(buffer, data->pointer() + offset, nread); if (nread == 0 && handle && handle->generatorCache()) diff --git a/VirtualFileSystem/SyntheticFileSystem.h b/VirtualFileSystem/SyntheticFileSystem.h index d9d84c962ad..ed7a9d900e2 100644 --- a/VirtualFileSystem/SyntheticFileSystem.h +++ b/VirtualFileSystem/SyntheticFileSystem.h @@ -40,7 +40,7 @@ protected: OwnPtr createDirectory(String&& name); OwnPtr createTextFile(String&& name, String&& text); - OwnPtr createGeneratedFile(String&& name, Function&&); + OwnPtr createGeneratedFile(String&& name, Function&&, Unix::mode_t = 0100644); InodeIdentifier addFile(OwnPtr&&, InodeIndex parent = RootInodeIndex); bool removeFile(InodeIndex); diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp index f8ead5960ab..5145d9a1d10 100644 --- a/VirtualFileSystem/VirtualFileSystem.cpp +++ b/VirtualFileSystem/VirtualFileSystem.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "sys-errno.h" //#define VFS_DEBUG @@ -104,7 +105,8 @@ bool VirtualFileSystem::mount(RetainPtr&& 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 VirtualFileSystem::open(const String& path, InodeIdentifier base) +OwnPtr 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 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 099cf2c853b..c697b0df4c7 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&&); bool mount(RetainPtr&&, const String& path); - OwnPtr open(const String& path, InodeIdentifier base = InodeIdentifier()); + OwnPtr open(const String& path, int options = 0, InodeIdentifier base = InodeIdentifier()); OwnPtr create(const String& path, InodeIdentifier base = InodeIdentifier()); OwnPtr mkdir(const String& path, InodeIdentifier base = InodeIdentifier()); @@ -98,7 +105,7 @@ private: friend class FileHandle; void enumerateDirectoryInode(InodeIdentifier, Function); - 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 allocateNode(); diff --git a/VirtualFileSystem/sys-errno.h b/VirtualFileSystem/sys-errno.h index e01e73798ae..7549c562b5d 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