21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/process/Process.h"
23#include "pedigree/kernel/process/TerminationDeferral.h"
24#include "pedigree/kernel/process/Thread.h"
25#include "pedigree/kernel/processor/Processor.h"
26#include "pedigree/kernel/processor/ProcessorInformation.h"
27#include "pedigree/kernel/syscallError.h"
28#include "pedigree/kernel/utilities/new"
30#include "modules/Module.h"
31#include "modules/system/vfs/Symlink.h"
33String RamFs::m_VolumeLabel(
"ramfs");
36class RamSymlink final :
public Symlink {
38 RamSymlink(
const String& name, uintptr_t inode,
RamFs& filesystem,
File* parent,
40 :
Symlink(name, 0, 0, 0, inode, &filesystem, target.length(), parent), m_OwnerPid(0) {
50 if (!
static_cast<RamFs*
>(getFilesystem())->getProcessOwnership())
60 uint64_t
readBytewise(uint64_t location, uint64_t size, uintptr_t buffer,
bool)
override {
61 if (location >= m_sTarget.length())
63 size_t amount = m_sTarget.length() - location;
66 MemoryCopy(
reinterpret_cast<void*
>(buffer), m_sTarget.cstr() + location, amount);
74bool canModifyRamNode(
File* file) {
78 return static_cast<RamSymlink*
>(file)->canWrite();
79 return static_cast<RamFile*
>(file)->canWrite();
82void initialiseCreatedNode(
File& file, uint32_t mode) {
85 uint32_t permissions = mode & FILE_AMASK;
87 permissions |= FILE_UR;
89 permissions |= FILE_UW;
91 permissions |= FILE_UX;
93 permissions |= FILE_GR;
95 permissions |= FILE_GW;
97 permissions |= FILE_GX;
99 permissions |= FILE_OR;
101 permissions |= FILE_OW;
103 permissions |= FILE_OX;
104 file.setPermissions(permissions);
109 if (Process::currentFilesystemCredentials(credentials)) {
110 file.setUid(credentials.uid);
111 file.setGid(credentials.gid);
119 :
File(name, 0, 0, 0, inode, pParentFS, 0, pParent),
125 setPermissions(0777);
140 Attributes attributes = File::getAttributes();
141 attributes.links = m_LinkCount;
142 attributes.blocks =
static_cast<uint64_t
>(m_BlockOffsets.
count()) * (
getBlockSize() / 512);
146bool RamFile::addLink() {
148 size_t count = m_LinkCount;
149 if (count == ~
static_cast<size_t>(0)) {
150 SYSCALL_ERROR(TooManyLinks);
153 if (m_LinkCount.compareAndSwap(count, count + 1)) {
159void RamFile::removeLink() {
161 size_t count = m_LinkCount;
163 if (m_LinkCount.compareAndSwap(count, count - 1)) {
171 return m_ExtendedAttributes.get(name, buffer, capacity, required);
174XattrStatus RamFile::listExtendedAttributes(
void* buffer,
size_t capacity,
size_t& required) {
175 return m_ExtendedAttributes.list(buffer, capacity, required);
178XattrStatus RamFile::setExtendedAttribute(
const StringView& name,
const void* value,
size_t length,
182 return XattrStatus::Denied;
183 const auto status = m_ExtendedAttributes.set(name, value, length, flags);
184 if (status == XattrStatus::Success)
189XattrStatus RamFile::removeExtendedAttribute(
const StringView& name) {
192 return XattrStatus::Denied;
193 const auto status = m_ExtendedAttributes.remove(name);
194 if (status == XattrStatus::Success)
206 : file(file), size(size), boundary(size - size % file.
getBlockSize()), tail(0) {}
209 file.m_FileBlocks.
release(boundary);
213 discarded.get()->commit();
215 for (
size_t i = 0; i < file.m_BlockOffsets.
count();) {
216 if (file.m_BlockOffsets[i] >= cutoff) {
217 file.m_BlockOffsets[i] = file.m_BlockOffsets[file.m_BlockOffsets.
count() - 1];
224 ByteSet(
reinterpret_cast<void*
>(tail + size - boundary), 0,
237 SYSCALL_ERROR(PermissionDenied);
240 ShrinkPlan* plan =
new ShrinkPlan(*
this, context.newSize);
243 SYSCALL_ERROR(OutOfMemory);
248 const size_t cutoff = plan->boundary + (context.newSize % blockSize ? blockSize : 0);
250 context.mappingLoanCount, plan->discarded);
251 if (status != Cache::DiscardStatus::Ready) {
252 syscallError(status == Cache::DiscardStatus::NoMemory ? Error::OutOfMemory
253 : status ==
Cache::DiscardStatus::Busy ? Error::DeviceBusy
254 : status ==
Cache::DiscardStatus::Invalid ? Error::InvalidArgument
258 if (context.newSize % blockSize)
259 plan->tail = m_FileBlocks.
lookup(plan->boundary);
262 prepared = pedigree_std::move(owner);
266bool RamFile::resizeFile(
size_t size) {
268 SYSCALL_ERROR(PermissionDenied);
272 const size_t oldSize = getSize();
274 for (
size_t i = 0; i < m_BlockOffsets.
count();) {
275 const uint64_t offset = m_BlockOffsets[i];
276 const uintptr_t buffer = m_FileBlocks.
lookup(offset);
277 if (size <= oldSize && offset >= size) {
281 m_FileBlocks.
evict(offset);
283 m_BlockOffsets[i] = m_BlockOffsets[m_BlockOffsets.
count() - 1];
287 const size_t boundary = size < oldSize ? size : oldSize;
289 if (offset <= boundary && boundary - offset < blockSize) {
290 const size_t within = boundary - offset;
291 ByteSet(
reinterpret_cast<void*
>(buffer + within), 0, blockSize - within);
301bool RamFile::canWrite() {
302 RamFs* pParent =
static_cast<RamFs*
>(getFilesystem());
303 if (!pParent->getProcessOwnership()) {
309 return pid == m_nOwnerPid;
317 uintptr_t buffer = m_FileBlocks.
lookup(location);
320 bool didExist =
false;
321 buffer = m_FileBlocks.
insert(location, &didExist);
326 ByteSet(
reinterpret_cast<void*
>(buffer), 0,
getBlockSize());
330 buffer = m_FileBlocks.
lookup(location);
336 return m_FileBlocks.
pin(location);
340 return m_FileBlocks.
lookup(location);
344 m_FileBlocks.
release(location);
348 :
Directory(name, 0, 0, 0, inode, pFs, 0, pParent), m_DirectoryLock() {
350 setPermissions(0777);
357 return m_ExtendedAttributes.get(name, buffer, capacity, required);
360XattrStatus RamDir::listExtendedAttributes(
void* buffer,
size_t capacity,
size_t& required) {
361 return m_ExtendedAttributes.list(buffer, capacity, required);
364XattrStatus RamDir::setExtendedAttribute(
const StringView& name,
const void* value,
size_t length,
367 const auto status = m_ExtendedAttributes.set(name, value, length, flags);
368 if (status == XattrStatus::Success)
373XattrStatus RamDir::removeExtendedAttribute(
const StringView& name) {
375 const auto status = m_ExtendedAttributes.remove(name);
376 if (status == XattrStatus::Success)
381bool RamDir::addEntry(
String filename,
File* pFile) {
385bool RamDir::removeEntry(
const String& filename,
File* pFile) {
387 if (!canModifyRamNode(pFile)) {
388 SYSCALL_ERROR(PermissionDenied);
395bool RamDir::removeFromParent(
RamDir* parent,
const String& filename) {
396 if (parent ==
this) {
397 SYSCALL_ERROR(InvalidArgument);
404 SYSCALL_ERROR(IoError);
408 SYSCALL_ERROR(NotEmpty);
411 if (!parent->removeEntry(filename,
this))
417RamFs::RamFs() : m_pRoot(0), m_bProcessOwners(false), m_NextInode(0) {}
426 return SyncStatus::Success;
429uintptr_t RamFs::allocateInode() {
431 uintptr_t previous = m_NextInode;
432 if (previous == ~
static_cast<uintptr_t
>(0)) {
433 SYSCALL_ERROR(NoSpaceLeftOnDevice);
436 if (m_NextInode.compareAndSwap(previous, previous + 1))
442 uintptr_t inode = allocateInode();
452 SYSCALL_ERROR(NotADirectory);
456 uintptr_t inode = allocateInode();
459 File* f =
new RamFile(filename, inode,
this, parent);
461 SYSCALL_ERROR(OutOfMemory);
464 initialiseCreatedNode(*f, mask);
467 if (!p->addEntry(filename, f)) {
476 SYSCALL_ERROR(NotADirectory);
480 uintptr_t inode = allocateInode();
483 RamDir* pDir =
new RamDir(filename, inode,
this, parent);
485 SYSCALL_ERROR(OutOfMemory);
488 initialiseCreatedNode(*pDir, mask);
491 if (!pParent->addEntry(filename, pDir)) {
500 SYSCALL_ERROR(NotADirectory);
503 if (!value.length()) {
504 SYSCALL_ERROR(DoesNotExist);
507 uintptr_t inode = allocateInode();
510 auto* link =
new RamSymlink(filename, inode, *
this, parent, value);
512 SYSCALL_ERROR(OutOfMemory);
515 initialiseCreatedNode(*link, 0777);
516 if (!
static_cast<RamDir*
>(parent)->addEntry(filename, link)) {
525 SYSCALL_ERROR(NotADirectory);
529 SYSCALL_ERROR(PermissionDenied);
532 if (target->
isSymlink() || target->getFilesystem() !=
this) {
533 SYSCALL_ERROR(OperationNotSupported);
537 auto* file =
static_cast<RamFile*
>(target);
538 if (!file->addLink()) {
541 if (!
static_cast<RamDir*
>(parent)->addEntry(filename, target)) {
552 return static_cast<RamDir*
>(file)->removeFromParent(p, filename);
554 if (!p->removeEntry(filename, file)) {
558 static_cast<RamFile*
>(file)->removeLink();
566 if (m_bProcessOwners &&
567 (!canModifyRamNode(source) || (replaced && !canModifyRamNode(replaced)))) {
568 SYSCALL_ERROR(PermissionDenied);
578static void destroy() {}
580MODULE_INFO_NON_UNLOADABLE(
"ramfs", &entry, &destroy,
"vfs");
bool evict(uintptr_t key)
void release(uintptr_t key)
uintptr_t insert(uintptr_t key, bool *alreadyExisted=nullptr)
DiscardStatus prepareDiscardFrom(uintptr_t cutoff, const DiscardReference *references, size_t count, UniquePointer< PreparedDiscard > &result)
void markNoLongerEditing(uintptr_t key, size_t length=0)
uintptr_t lookup(uintptr_t key)
MUST_USE_RESULT bool pin(uintptr_t key)
bool addDirectoryEntry(const String &name, File *pTarget)
Mutex & namespaceMutationLock()
bool removeDirectoryEntry(const HashedStringView &name, File *expected)
ReadStatus isEmpty(bool &empty)
virtual uint64_t readBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
void setCreationTime(Time::Timestamp t)
virtual bool isDirectory()
virtual size_t getBlockSize() const
static ProcessorInformation & information()
XattrStatus getExtendedAttribute(const StringView &name, void *buffer, size_t capacity, size_t &required) override
XattrStatus getExtendedAttribute(const StringView &name, void *buffer, size_t capacity, size_t &required) override
virtual uintptr_t readBlock(uint64_t location) override
uintptr_t acquireCachedBlock(uint64_t location, bool retryChanged) override
virtual void truncate() override
virtual bool pinBlock(uint64_t location) override
virtual void unpinBlock(uint64_t location) override
SyncStatus sync() override
virtual bool renameNode(Directory *oldParent, const String &oldName, File *source, Directory *newParent, const String &newName, File *replaced) override
virtual bool removeNode(File *parent, const String &filename, File *file) override
virtual bool createFile(File *parent, const String &filename, uint32_t mask) override
virtual bool createDirectory(File *parent, const String &filename, uint32_t mask) override
virtual bool initialise(Disk *pDisk) override
virtual bool createSymlink(File *parent, const String &filename, const String &value) override
virtual bool createLink(File *parent, const String &filename, File *target) override
static UniquePointer< T > adopt(T *pointer)
void pushBack(const T &value)