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 if (!tryAcquireFilesystemOperation(operation)) {
14 return false;
15 }
17 syscallError(isDirectory() ? Error::IsADirectory : Error::OperationNotSupported);
18 return false;
19 }
20 if (!length) {
21 SYSCALL_ERROR(InvalidArgument);
22 return false;
23 }
24 const uint64_t maximum = maximumFileSize();
25 if (offset > maximum || length > maximum - offset || length > ~size_t(0) - offset) {
26 SYSCALL_ERROR(FileTooLarge);
27 return false;
28 }
29 LockGuard<Mutex> writer(writeSerializationLock());
30 LockGuard<Mutex> data(dataMutationLock());
31 if (m_pFilesystem && m_pFilesystem->isReadOnly()) {
32 SYSCALL_ERROR(ReadOnlyFilesystem);
33 return false;
34 }
35 if (cacheState().executableMappings) {
36 SYSCALL_ERROR(TextFileBusy);
37 return false;
38 }
39 const size_t oldSize = getSize();
40 const size_t end = offset + length;
41 const size_t newSize = keepSize || end < oldSize ? oldSize : end;
42 if (!allowResize(oldSize, newSize) || !allocateFileRange(offset, length))
43 return false;
44 // Reservation precedes EOF publication. A failed reservation may keep blocks,
45 // but cannot expose uninitialised bytes or promise storage that was not acquired.
46 if (newSize > oldSize) {
47 if (!resizeFile(newSize))
48 return false;
49 if (useFillCache()) {
50 const size_t pageSize = PhysicalMemoryManager::getPageSize();
51 const size_t within = oldSize % pageSize;
52 if (within) {
53 const size_t pageOffset = oldSize - within;
54 const uintptr_t page = cacheState().fill.lookup(pageOffset);
55 if (page) {
56 const size_t amount =
57 newSize - oldSize < pageSize - within ? newSize - oldSize : pageSize - within;
58 ByteSet(reinterpret_cast<void*>(page + within), 0, amount);
59 cacheState().fill.markDirty(pageOffset);
60 cacheState().fill.release(pageOffset);
61 }
62 }
63 }
64 }
65 Attributes attributes;
66 attributes.modified = attributes.changed = Time::getTime();
67 updateAttributes(attributes, ModifyTime | ChangeTime);
68 publishEvent(FileEvents::Modify);
69 return true;
70}
71
72bool File::allocateFileRange(size_t, size_t) {
73 SYSCALL_ERROR(OperationNotSupported);
74 return false;
75}
void release(uintptr_t key)
Definition Cache.cc:1570
void markDirty(uintptr_t key)
Definition Cache.cc:2135
uintptr_t lookup(uintptr_t key)
Definition Cache.cc:737
bool supportsRegularFileOperations()
Definition File.cc:824
bool allocateRange(size_t offset, size_t length, bool keepSize=false)
virtual bool isDirectory()
Definition File.cc:804
virtual bool allocateFileRange(size_t offset, size_t length)
void publishEvent(FileEventMask mask, const StringView &name=StringView(), bool targetIsDirectory=false)
Definition File.cc:861
virtual bool useFillCache() const
Definition File.cc:1746
virtual uint64_t maximumFileSize() const
Definition File.cc:829
bool isReadOnly()
Definition Filesystem.h:150