The Pedigree Project 0.1
FatFilesystem-node-state.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/Log.h"
9
10#include "FatFilesystem.h"
11#include "FatSymlink.h"
12
13void FatFilesystem::registerNode(File* file) {
14 if ((!file->isDirectory() && !file->isSymlink()) || file->getName() == "." ||
15 file->getName() == "..")
16 return;
17
18 LockGuard<Mutex> registry(m_StateLock);
19 if (m_NodeAliases.lookup(file))
20 return;
21 const uintptr_t inode = file->getInode();
22 NodeState* state = m_NodeStates.lookup(inode);
23 if (!state) {
24 state = new NodeState;
25 state->inode = inode;
26 if (file->isDirectory()) {
27 auto* directory = static_cast<FatDirectory*>(file);
28 state->directoryCluster = directory->getDirCluster();
29 state->directoryOffset = directory->getDirOffset();
30 state->unlinked = directory->m_Unlinked;
31 } else {
32 auto* symlink = static_cast<FatSymlink*>(file);
33 state->directoryCluster = symlink->getDirCluster();
34 state->directoryOffset = symlink->getDirOffset();
35 state->unlinked = symlink->m_Unlinked;
36 }
37 m_NodeStates.insert(inode, state);
38 }
39 state->aliases.pushBack(file);
40 m_NodeAliases.insert(file, state);
41
42 // A resolver can have read the old slot before a rename reached this registry.
43 if (file->isDirectory()) {
44 auto* directory = static_cast<FatDirectory*>(file);
45 directory->setDirCluster(state->directoryCluster);
46 directory->setDirOffset(state->directoryOffset);
47 directory->m_Unlinked = state->unlinked;
48 if (state->unlinked)
49 directory->markDetached();
50 } else {
51 auto* symlink = static_cast<FatSymlink*>(file);
52 symlink->setDirCluster(state->directoryCluster);
53 symlink->setDirOffset(state->directoryOffset);
54 symlink->m_Unlinked = state->unlinked;
55 }
56}
57
58void FatFilesystem::releaseNode(File* file) {
60 NodeState* retired = nullptr;
61 {
62 LockGuard<Mutex> registry(m_StateLock);
63 NodeState* state = m_NodeAliases.lookup(file);
64 if (!state)
65 return;
66 m_NodeAliases.remove(file);
67 for (size_t i = 0; i < state->aliases.count(); ++i) {
68 if (state->aliases[i] == file) {
69 state->aliases.erase(i);
70 break;
71 }
72 }
73 if (state->aliases.count())
74 return;
75 if (m_NodeStates.lookup(state->inode) == state)
76 m_NodeStates.remove(state->inode);
77 retired = state;
78 }
79
80 // Reclamation uses only the saved allocation identity after alias removal.
81 if (retired->unlinked && !m_bReadOnly && !releaseClusterChain(retired->inode, false)) {
82 m_IoFailed = true;
83 ERROR("FAT: orphan node allocation reclamation needs a FAT retry");
84 }
85 delete retired;
86}
87
88void FatFilesystem::moveNonFileNode(File* file, uint32_t cluster, uint32_t offset) {
89 LockGuard<Mutex> registry(m_StateLock);
90 const auto moveAlias = [cluster, offset](File* alias) {
91 if (alias->isDirectory()) {
92 auto* directory = static_cast<FatDirectory*>(alias);
93 directory->setDirCluster(cluster);
94 directory->setDirOffset(offset);
95 } else {
96 auto* symlink = static_cast<FatSymlink*>(alias);
97 symlink->setDirCluster(cluster);
98 symlink->setDirOffset(offset);
99 }
100 };
101 NodeState* state = m_NodeAliases.lookup(file);
102 if (!state) {
103 moveAlias(file);
104 return;
105 }
106 state->directoryCluster = cluster;
107 state->directoryOffset = offset;
108 for (File* alias : state->aliases)
109 moveAlias(alias);
110}
111
112void FatFilesystem::unlinkNonFileNode(File* file) {
113 LockGuard<Mutex> registry(m_StateLock);
114 const auto unlinkAlias = [](File* alias) {
115 if (alias->isDirectory()) {
116 auto* directory = static_cast<FatDirectory*>(alias);
117 directory->m_Unlinked = true;
118 directory->markDetached();
119 } else {
120 static_cast<FatSymlink*>(alias)->m_Unlinked = true;
121 }
122 };
123 NodeState* state = m_NodeAliases.lookup(file);
124 if (!state) {
125 unlinkAlias(file);
126 return;
127 }
128 // Its allocation remains reserved, so stale resolvers must join this orphan.
129 state->unlinked = true;
130 for (File* alias : state->aliases)
131 unlinkAlias(alias);
132}
Mutex m_FileMutationLock
bool releaseClusterChain(uint32_t clus, bool lockFile=true)
Definition File.h:75
String getName() const
Definition File.cc:782
virtual bool isSymlink()
Definition File.cc:800
virtual bool isDirectory()
Definition File.cc:804
bool m_bReadOnly
Definition Filesystem.h:186