The Pedigree Project 0.1
FatFilesystem-chain.cc
1/*
2 * Copyright (c) 2026, Pedigree Developers
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted.
6 */
7
8#include "pedigree/kernel/syscallError.h"
9
10#include "FatFilesystem.h"
11
12bool FatFilesystem::chainExtent(File* file, uint32_t& count, uint32_t& last) {
13 count = 0;
14 last = 0;
15 FatFile::State* state = nullptr;
16 const uint64_t revision = __atomic_load_n(&m_ChainRevision, __ATOMIC_ACQUIRE);
17 const uintptr_t inode = file->getInode();
18 if (!file->isDirectory() && !file->isSymlink()) {
19 state = static_cast<FatFile*>(file)->m_State;
20 if (state->chainRevision == revision &&
21 (state->clusters.count() ? state->clusters[0] == inode : inode == 0)) {
22 count = static_cast<uint32_t>(state->clusters.count());
23 last = count ? state->clusters[count - 1] : 0;
24 return true;
25 }
26 state->chainRevision = 0;
27 state->clusters.clear();
28 }
29 if (inode > UINT32_MAX)
30 return false;
31
32 uint32_t cluster = static_cast<uint32_t>(inode);
33 while (cluster) {
34 if (cluster < 2 || uint64_t(cluster) >= uint64_t(m_ClusterCount) + 2 || isEof(cluster) ||
35 count >= m_ClusterCount)
36 return false;
37 const uint32_t next = getClusterEntry(cluster);
38 if (!next)
39 return false;
40 if (state) {
41 if (!state->clusters.tryReserve(size_t(count) + 1)) {
42 SYSCALL_ERROR(OutOfMemory);
43 return false;
44 }
45 state->clusters.pushBack(cluster);
46 }
47 ++count;
48 last = cluster;
49 if (isEof(next))
50 break;
51 cluster = next;
52 }
53
54 // A concurrent allocation must leave this snapshot stale, never stamp it current.
55 if (state)
56 state->chainRevision = revision;
57 return true;
58}
59
60uint32_t FatFilesystem::fileClusterAt(File* file, size_t index) {
61 uint32_t count = 0, last = 0;
62 if (!chainExtent(file, count, last) || index >= count)
63 return 0;
64 if (!file->isDirectory() && !file->isSymlink())
65 return static_cast<FatFile*>(file)->m_State->clusters[index];
66
67 uint32_t cluster = static_cast<uint32_t>(file->getInode());
68 for (size_t position = 0; position < index; ++position) {
69 cluster = getClusterEntry(cluster);
70 if (cluster < 2 || uint64_t(cluster) >= uint64_t(m_ClusterCount) + 2 || isEof(cluster))
71 return 0;
72 }
73 return cluster;
74}
uint32_t m_ClusterCount
bool isEof(uint32_t cluster) const
uint32_t getClusterEntry(uint32_t cluster, bool bLock=true)
Definition File.h:75
virtual bool isSymlink()
Definition File.cc:800
virtual bool isDirectory()
Definition File.cc:804
void pushBack(const T &value)
Definition Vector.h:275
void clear(bool freeMem=false)
Definition Vector.h:378
size_t count() const
Definition Vector.h:270