The Pedigree Project 0.1
MountView-entries.cc
1/* Copyright (c) 2026, Pedigree Developers. */
2#include "pedigree/kernel/process/FilesystemAccess.h"
3#include "pedigree/kernel/syscallError.h"
4
5#include "MountView-internal.h"
6
7namespace {
8bool validParent(const FilesystemPathRef& parent, const String& name, const VfsMountView* view) {
9 if (!parent || parent->provider() != view || !parent->node()->isDirectory()) {
10 SYSCALL_ERROR(NotADirectory);
11 return false;
12 }
13 if (!name.length() || name == "." || name == "..") {
14 SYSCALL_ERROR(InvalidArgument);
15 return false;
16 }
17 for (size_t i = 0; i < name.length(); ++i) {
18 if (name[i] == '/') {
19 SYSCALL_ERROR(InvalidArgument);
20 return false;
21 }
22 }
23 if (Directory::fromFile(parent->node())->isDetached()) {
24 SYSCALL_ERROR(DoesNotExist);
25 return false;
26 }
27 if (!view->writable(parent)) {
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 auto* owner = fromPath(parent);
56 if (owner && owner != this) {
57 return owner->createFile(parent, name, mask);
58 }
59 VFS::NamespaceMutation writer(m_Vfs);
60 return validParent(parent, name, this) &&
61 checkFilesystemAccess(parent, FilesystemAccess::MakeReg, &writer) &&
62 absent(parent, name) &&
63 parent->node()->getFilesystem()->createFile(parent->node(), name, mask);
64}
65bool VfsMountView::createDirectory(const FilesystemPathRef& parent, const String& name,
66 uint32_t mask) {
67 auto* owner = fromPath(parent);
68 if (owner && owner != this) {
69 return owner->createDirectory(parent, name, mask);
70 }
71 VFS::NamespaceMutation writer(m_Vfs);
72 return validParent(parent, name, this) &&
73 checkFilesystemAccess(parent, FilesystemAccess::MakeDir, &writer) &&
74 absent(parent, name) &&
75 parent->node()->getFilesystem()->createDirectory(parent->node(), name, mask);
76}
77bool VfsMountView::createSymlink(const FilesystemPathRef& parent, const String& name,
78 const String& value) {
79 auto* owner = fromPath(parent);
80 if (owner && owner != this) {
81 return owner->createSymlink(parent, name, value);
82 }
83 VFS::NamespaceMutation writer(m_Vfs);
84 return validParent(parent, name, this) &&
85 checkFilesystemAccess(parent, FilesystemAccess::MakeSym, &writer) &&
86 absent(parent, name) &&
87 parent->node()->getFilesystem()->createSymlink(parent->node(), name, value);
88}
89bool VfsMountView::createLink(const FilesystemPathRef& parent, const String& name,
90 const FilesystemPathRef& target) {
91 auto* owner = fromPath(parent);
92 if (owner && owner != this) {
93 return owner->createLink(parent, name, target);
94 }
95 VFS::NamespaceMutation writer(m_Vfs);
96 if (!validParent(parent, name, this))
97 return false;
98 auto* source = m_State->path(target);
99 auto* destination = m_State->path(parent);
100 if (!source || source->attachment.get() != destination->attachment.get()) {
101 SYSCALL_ERROR(CrossDeviceLink);
102 return false;
103 }
104 // Directory ancestry must remain a tree for both path walking and pivot.
105 if (target->node()->isDirectory()) {
106 SYSCALL_ERROR(NotEnoughPermissions);
107 return false;
108 }
109 if (target->node()->isPipe() || target->node()->isFifo() || target->node()->isSocket()) {
110 SYSCALL_ERROR(OperationNotSupported);
111 return false;
112 }
113 if (!authorizeLink(parent, target, writer)) {
114 return false;
115 }
116 return absent(parent, name) &&
117 parent->node()->getFilesystem()->createLink(parent->node(), name, target->node());
118}
119bool VfsMountView::remove(const FilesystemPathRef& parent, const String& name, File* expected) {
120 auto* owner = fromPath(parent);
121 if (owner && owner != this) {
122 return owner->remove(parent, name, expected);
123 }
124 return validParent(parent, name, this) &&
125 parent->node()->getFilesystem()->removeChild(parent->node(), name, expected, &parent);
126}
127bool VfsMountView::rename(const FilesystemPathRef& oldParent, const String& oldName,
128 const FilesystemPathRef& newParent, const String& newName, bool noReplace,
129 bool sourceMustBeDirectory) {
130 auto* owner = fromPath(oldParent);
131 if (owner && owner != this) {
132 return owner->rename(oldParent, oldName, newParent, newName, noReplace, sourceMustBeDirectory);
133 }
134 if (!validParent(oldParent, oldName, this) || !validParent(newParent, newName, this))
135 return false;
136 if (m_State->path(oldParent)->attachment.get() != m_State->path(newParent)->attachment.get()) {
137 SYSCALL_ERROR(CrossDeviceLink);
138 return false;
139 }
140 return oldParent->node()->getFilesystem()->renameChildren(
141 oldParent->node(), oldName, newParent->node(), newName, noReplace, sourceMustBeDirectory,
142 &oldParent, &newParent);
143}
144
145Directory::AddStatus VfsMountView::createEphemeral(const FilesystemPathRef& parent, File* node,
146 uint64_t access) {
147 auto* owner = fromPath(parent);
148 if (owner && owner != this) {
149 return owner->createEphemeral(parent, node, access);
150 }
151 VFS::NamespaceMutation writer(m_Vfs);
152 if (!node || !validParent(parent, node->getName(), this) ||
153 !checkFilesystemAccess(parent, access, &writer)) {
154 return Directory::AddStatus::IoError;
155 }
156 return Directory::fromFile(parent->node())->addEphemeralFile(node);
157}
static Directory * fromFile(File *pF)
Definition Directory.h:151
AddStatus addEphemeralFile(File *pFile)
Add an ephemeral file to the directory.
Definition Directory.cc:924
bool isDetached() const
Definition Directory.h:182
MUST_USE_RESULT LookupStatus lookupChild(const HashedStringView &s, ChildLease &child) const
Definition Directory.cc:355
Definition File.h:75
virtual bool isSocket() const
Definition File.cc:816
virtual bool isDirectory()
Definition File.cc:804
virtual bool isFifo() const
Definition File.cc:812
virtual bool isPipe() const
Definition File.cc:808
bool removeChild(File *parent, const String &filename, File *expected, const FilesystemPathRef *parentPath=nullptr)
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 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:1502