The Pedigree Project 0.1
File-allocation.cc
1/* Copyright (c) 2026, Pedigree Developers. */
2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/process/TerminationDeferral.h"
4#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
5#include "pedigree/kernel/syscallError.h"
6
7#include "File.h"
8#include "Filesystem.h"
9
10bool File::allocateRange(size_t offset, size_t length, bool keepSize) {
11 TerminationDeferral lifetime;
13 syscallError(isDirectory() ? Error::IsADirectory : Error::OperationNotSupported);
14 return false;
15 }
16 if (!length) {
17 SYSCALL_ERROR(InvalidArgument);
18 return false;
19 }
20 const uint64_t maximum = maximumFileSize();
21 if (offset > maximum || length > maximum - offset || length > ~size_t(0) - offset) {
22 SYSCALL_ERROR(FileTooLarge);
23 return false;
24 }
25 LockGuard<Mutex> writer(writeSerializationLock());
26 LockGuard<Mutex> data(dataMutationLock());
27 if (m_pFilesystem && m_pFilesystem->isReadOnly()) {
28 SYSCALL_ERROR(ReadOnlyFilesystem);
29 return false;
30 }
31 if (cacheState().executableMappings) {
32 SYSCALL_ERROR(TextFileBusy);
33 return false;
34 }
35 const size_t oldSize = getSize();
36 const size_t end = offset + length;
37 const size_t newSize = keepSize || end < oldSize ? oldSize : end;
38 if (!allowResize(oldSize, newSize) || !allocateFileRange(offset, length))
39 return false;
40 // Reservation precedes EOF publication. A failed reservation may keep blocks,
41 // but cannot expose uninitialised bytes or promise storage that was not acquired.
42 if (newSize > oldSize) {
43 if (!resizeFile(newSize))
44 return false;
45 if (useFillCache()) {
46 const size_t pageSize = PhysicalMemoryManager::getPageSize();
47 const size_t within = oldSize % pageSize;
48 if (within) {
49 const size_t pageOffset = oldSize - within;
50 const uintptr_t page = cacheState().fill.lookup(pageOffset);
51 if (page) {
52 const size_t amount =
53 newSize - oldSize < pageSize - within ? newSize - oldSize : pageSize - within;
54 ByteSet(reinterpret_cast<void*>(page + within), 0, amount);
55 cacheState().fill.markDirty(pageOffset);
56 cacheState().fill.release(pageOffset);
57 }
58 }
59 }
60 }
61 Attributes attributes;
62 attributes.modified = attributes.changed = Time::getTime();
63 updateAttributes(attributes, ModifyTime | ChangeTime);
64 publishEvent(FileEvents::Modify);
65 return true;
66}
67
68bool File::allocateFileRange(size_t, size_t) {
69 SYSCALL_ERROR(OperationNotSupported);
70 return false;
71}
void release(uintptr_t key)
Definition Cache.cc:1488
void markDirty(uintptr_t key)
Definition Cache.cc:1998
uintptr_t lookup(uintptr_t key)
Definition Cache.cc:709
bool supportsRegularFileOperations()
Definition File.cc:741
bool allocateRange(size_t offset, size_t length, bool keepSize=false)
virtual bool isDirectory()
Definition File.cc:721
virtual bool allocateFileRange(size_t offset, size_t length)
void publishEvent(FileEventMask mask, const StringView &name=StringView(), bool targetIsDirectory=false)
Definition File.cc:778
virtual bool useFillCache() const
Definition File.cc:1635
virtual uint64_t maximumFileSize() const
Definition File.cc:746
bool isReadOnly()
Definition Filesystem.h:142