mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-04 05:20:30 +00:00
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().
This commit is contained in:
parent
1d4af51250
commit
97726862dd
Notes:
sideshowbarker
2024-07-19 18:36:54 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/97726862dd6
20 changed files with 140 additions and 46 deletions
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -35,6 +35,7 @@ enum Function {
|
|||
PosixChdir = 0x2003,
|
||||
PosixUname = 0x2004,
|
||||
SetMmapName = 0x2005,
|
||||
PosixReadlink = 0x2006,
|
||||
};
|
||||
|
||||
void initialize();
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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&&);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 { };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue