summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2018-10-28 14:11:51 +0100
committerAndreas Kling <awesomekling@gmail.com>2018-10-28 14:11:51 +0100
commit97726862dd699cb0843b9d700789e30cf6625dc9 (patch)
tree07fd74e8e0e3b462ac5ab32994340c5090711348
parent1d4af5125078b097b9ab843d53ba50a0d9b1de5e (diff)
downloadserenity-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.cpp12
-rw-r--r--Kernel/Syscall.cpp2
-rw-r--r--Kernel/Syscall.h1
-rw-r--r--Kernel/Task.cpp42
-rw-r--r--Kernel/Task.h7
-rw-r--r--Kernel/errno.h3
-rw-r--r--LibC/dirent.cpp3
-rw-r--r--LibC/unistd.cpp11
-rw-r--r--LibC/unistd.h9
-rw-r--r--Userland/cat.cpp2
-rw-r--r--Userland/ls.cpp17
-rw-r--r--Userland/mm.cpp2
-rw-r--r--Userland/ps.cpp2
-rw-r--r--Userland/sh.cpp2
-rw-r--r--VirtualFileSystem/FileSystem.cpp4
-rw-r--r--VirtualFileSystem/SyntheticFileSystem.cpp11
-rw-r--r--VirtualFileSystem/SyntheticFileSystem.h2
-rw-r--r--VirtualFileSystem/VirtualFileSystem.cpp41
-rw-r--r--VirtualFileSystem/VirtualFileSystem.h11
-rw-r--r--VirtualFileSystem/sys-errno.h2
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