The Pedigree Project 0.1
MountView-entries.cc
1/* Copyright (c) 2026, Pedigree Developers. */
2#include "pedigree/kernel/syscallError.h"
3
4#include "MountView-internal.h"
5
6namespace {
7bool validParent(const FilesystemPathRef& parent, const String& name, const VfsMountView* view) {
8 if (!parent || parent->provider() != view || !parent->node()->isDirectory()) {
9 SYSCALL_ERROR(NotADirectory);
10 return false;
11 }
12 if (!name.length() || name == "." || name == "..") {
13 SYSCALL_ERROR(InvalidArgument);
14 return false;
15 }
16 for (size_t i = 0; i < name.length(); ++i) {
17 if (name[i] == '/') {
18 SYSCALL_ERROR(InvalidArgument);
19 return false;
20 }
21 }
22 if (Directory::fromFile(parent->node())->isDetached()) {
23 SYSCALL_ERROR(DoesNotExist);
24 return false;
25 }
26 if (parent->node()->getFilesystem()->isReadOnly()) {
27 SYSCALL_ERROR(ReadOnlyFilesystem);
28 return false;
29 }
30 return VFS::checkAccess(parent->node(), false, true, true);
31}
32bool absent(const FilesystemPathRef& parent, const String& name) {
33 Directory::ChildLease existing;
34 auto status = Directory::fromFile(parent->node())->lookupChild(HashedStringView(name), existing);
35 if (status == Directory::LookupStatus::NotFound)
36 return true;
37 syscallError(status == Directory::LookupStatus::Found ? Error::FileExists
38 : status == Directory::LookupStatus::Retry ? Error::NoMoreProcesses
39 : Error::IoError);
40 return false;
41}
42} // namespace
43
44bool VfsMountView::isMountpoint(File* node) const {
45 if (!m_State || !node)
46 return false;
47 LockGuard<Mutex> guard(m_State->graph);
48 for (auto* row = m_State->attachments; row; row = row->next)
49 if (row->covered && row->covered->get() == node)
50 return true;
51 return false;
52}
53
54bool VfsMountView::createFile(const FilesystemPathRef& parent, const String& name, uint32_t mask) {
55 return validParent(parent, name, this) && absent(parent, name) &&
56 parent->node()->getFilesystem()->createFile(parent->node(), name, mask);
57}
58bool VfsMountView::createDirectory(const FilesystemPathRef& parent, const String& name,
59 uint32_t mask) {
60 return validParent(parent, name, this) && absent(parent, name) &&
61 parent->node()->getFilesystem()->createDirectory(parent->node(), name, mask);
62}
63bool VfsMountView::createSymlink(const FilesystemPathRef& parent, const String& name,
64 const String& value) {
65 return validParent(parent, name, this) && absent(parent, name) &&
66 parent->node()->getFilesystem()->createSymlink(parent->node(), name, value);
67}
68bool VfsMountView::createLink(const FilesystemPathRef& parent, const String& name,
69 const FilesystemPathRef& target) {
70 if (!validParent(parent, name, this))
71 return false;
72 auto* source = m_State->path(target);
73 auto* destination = m_State->path(parent);
74 if (!source || source->attachment.get() != destination->attachment.get()) {
75 SYSCALL_ERROR(CrossDeviceLink);
76 return false;
77 }
78 // Directory ancestry must remain a tree for both path walking and pivot.
79 if (target->node()->isDirectory()) {
80 SYSCALL_ERROR(NotEnoughPermissions);
81 return false;
82 }
83 if (target->node()->isPipe() || target->node()->isFifo() || target->node()->isSocket()) {
84 SYSCALL_ERROR(OperationNotSupported);
85 return false;
86 }
87 return absent(parent, name) &&
88 parent->node()->getFilesystem()->createLink(parent->node(), name, target->node());
89}
90bool VfsMountView::remove(const FilesystemPathRef& parent, const String& name, File* expected) {
91 return validParent(parent, name, this) &&
92 parent->node()->getFilesystem()->removeChild(parent->node(), name, expected);
93}
94bool VfsMountView::rename(const FilesystemPathRef& oldParent, const String& oldName,
95 const FilesystemPathRef& newParent, const String& newName, bool noReplace,
96 bool sourceMustBeDirectory) {
97 if (!validParent(oldParent, oldName, this) || !validParent(newParent, newName, this))
98 return false;
99 if (m_State->path(oldParent)->attachment.get() != m_State->path(newParent)->attachment.get()) {
100 SYSCALL_ERROR(CrossDeviceLink);
101 return false;
102 }
103 return oldParent->node()->getFilesystem()->renameChildren(
104 oldParent->node(), oldName, newParent->node(), newName, noReplace, sourceMustBeDirectory);
105}
static Directory * fromFile(File *pF)
Definition Directory.h:148
bool isDetached() const
Definition Directory.h:179
MUST_USE_RESULT LookupStatus lookupChild(const HashedStringView &s, ChildLease &child) const
Definition Directory.cc:345
Definition File.h:74
virtual bool isSocket() const
Definition File.cc:733
virtual bool isDirectory()
Definition File.cc:721
virtual bool isFifo() const
Definition File.cc:729
virtual bool isPipe() const
Definition File.cc:725
bool removeChild(File *parent, const String &filename, File *expected)
bool createSymlink(const StringView &path, const String &value, File *pStartNode=0)
bool createDirectory(const StringView &path, uint32_t mask, File *pStartNode=0)
bool createLink(const StringView &path, File *target, File *pStartNode=0)
bool isReadOnly()
Definition Filesystem.h:142
bool createFile(const StringView &path, uint32_t mask, File *pStartNode=0)
T * get() const
static bool checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)
Definition VFS.cc:1392