The Pedigree Project 0.1
Directory.h
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#ifndef DIRECTORY_H
21#define DIRECTORY_H
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/compiler.h"
24#include "pedigree/kernel/process/ConditionVariable.h"
25#include "pedigree/kernel/process/Mutex.h"
26
27#include <config.h>
28#if THREADS && !defined(STANDALONE_MUTEXES)
29#include "pedigree/kernel/process/TerminationDeferral.h"
30#endif
31#include "pedigree/kernel/processor/types.h"
32#include "pedigree/kernel/time/Time.h"
33#include "pedigree/kernel/utilities/HashTable.h"
34#include "pedigree/kernel/utilities/LazyEvaluate.h"
35#include "pedigree/kernel/utilities/Pointers.h"
36#include "pedigree/kernel/utilities/String.h"
37#include "pedigree/kernel/utilities/StringView.h"
38#include "pedigree/kernel/utilities/Vector.h"
39#include "pedigree/kernel/utilities/utility.h"
40
41#include "File.h"
42
50class EXPORTED_PUBLIC Directory : public File {
51 friend class Filesystem;
52
53 public:
54 enum class LookupStatus { Found, NotFound, IoError, Retry };
55
56 enum class ReadStatus { Complete, Stopped, IoError };
57
58 enum class AddStatus { Added, Exists, IoError, Detached };
59
60 enum class EntryType : uint8_t {
61 Unknown,
62 Regular,
64 Symlink,
65 Fifo,
66 Socket,
67 CharacterDevice,
68 BlockDevice
69 };
70
72 StringView name;
73 uintptr_t inode;
74 EntryType type;
75 uint64_t currentCookie;
76 uint64_t nextCookie;
77 };
78
79 using DirectoryEntryEmitter = bool (*)(void*, const DirectoryEntryView&);
80
81 class EXPORTED_PUBLIC ChildLease {
82 public:
83 ChildLease();
85
86 File* get() const {
87 return m_pFile;
88 }
89
90 explicit operator bool() const {
91 return m_pFile != nullptr;
92 }
93
94 void reset();
95
96 void swap(ChildLease& other);
97
98 private:
99 friend class Directory;
100 friend class Filesystem;
101 friend class Symlink;
102
103 ChildLease(const ChildLease&) = delete;
104 ChildLease& operator=(const ChildLease&) = delete;
105 ChildLease(ChildLease&&) = delete;
106 ChildLease& operator=(ChildLease&&) = delete;
107
108 void adopt(File* file);
109
110 File* m_pFile;
111#if THREADS && !defined(STANDALONE_MUTEXES)
112 // A lease's deferral follows its lexical lifetime. Dynamically arming an
113 // older object would cross any newer guard's strict LIFO scope.
114 TerminationDeferral m_TerminationDeferral;
115#endif
116 };
117
118 class EXPORTED_PUBLIC NameReservation {
119 public:
122
123 explicit operator bool() const {
124 return m_pDirectory != nullptr;
125 }
126
127 void complete(LookupStatus result);
128
129 private:
130 friend class Directory;
131 friend class Filesystem;
132
133 NameReservation(const NameReservation&) = delete;
134 NameReservation& operator=(const NameReservation&) = delete;
136 NameReservation& operator=(NameReservation&&) = delete;
137
138 Directory* m_pDirectory;
139 String m_Name;
140 void* m_pToken;
141 bool m_OwnsNamespaceLock;
142#if THREADS && !defined(STANDALONE_MUTEXES)
143 TerminationDeferral m_TerminationDeferral;
144#endif
145 };
146
148 static Directory* fromFile(File* pF) {
149 if (!pF->isDirectory())
150 FATAL("Casting non-directory File to Directory!");
151 return reinterpret_cast<Directory*>(pF);
152 }
153
155 Directory();
156
158 private:
159 Directory(const Directory& file);
160 Directory& operator=(const Directory&);
161
162 public:
164 Directory(const String& name, Time::Timestamp accessedTime, Time::Timestamp modifiedTime,
165 Time::Timestamp creationTime, uintptr_t inode, class Filesystem* pFs, size_t size,
166 File* pParent);
168 virtual ~Directory();
169
171 virtual bool isDirectory() {
172 return true;
173 }
174
176 File* getChild(size_t n);
177
179 bool isDetached() const {
180 return __atomic_load_n(&m_Detached, __ATOMIC_ACQUIRE);
181 }
182
184 size_t getNumChildren();
185
191 ReadStatus enumerate(uint64_t& cookie, DirectoryEntryEmitter emitter, void* context);
192
194 ReadStatus isEmpty(bool& empty);
195
197 virtual void cacheDirectoryContents();
198
200 virtual bool isCachePopulated() const;
201
203 File* lookup(const HashedStringView& s) const;
204
212 MUST_USE_RESULT bool lookupRetained(const HashedStringView& s, ChildLease& child) const;
213
215 MUST_USE_RESULT LookupStatus lookupChild(const HashedStringView& s, ChildLease& child) const;
216
218 MUST_USE_RESULT LookupStatus lookupChildAt(uint64_t cookie, const HashedStringView& name,
219 ChildLease& child) const;
220
222 void remove(const HashedStringView& s);
223
232 Directory* getReparsePoint() const;
233
235 void setReparsePoint(Directory* pTarget);
236
244 AddStatus addEphemeralFile(File* pFile);
245
251 bool empty();
252
256 void emptyCache();
257
258#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
259 enum class RetainedLookupPhase { BeforeLookup, AfterRetain };
260 using RetainedLookupHook = void (*)(Directory*, File*, RetainedLookupPhase);
261 static void setRetainedLookupHookForHostedTest(RetainedLookupHook hook);
262 const void* cacheLockAddressForHostedTest() const {
263 return static_cast<const void*>(&m_CacheLock);
264 }
265 bool tryCacheLockForHostedTest() const;
266#endif
267#if HOSTED
268 size_t inFlightUsersForHostedTest(const HashedStringView& name) const;
269#endif
270
271 protected:
275
277
278 // No copy construction (UniqueArray)
279 NOT_COPYABLE_OR_ASSIGNABLE(DirectoryEntryMetadata);
280
281 // These two should always be known at metadata creation time.
282 Directory* pDirectory;
283 String filename;
284
285 // Space for anything else to be stored by the filesystem.
286 UniqueArray<char> opaque;
287 };
288
290 virtual LookupStatus resolveChild(const StringView& name, File*& child);
291
293 virtual bool cacheResolvedChildren() const {
294 return true;
295 }
296
302 virtual LookupStatus resolveChildAt(uint64_t cookie, const StringView& name, File*& child);
303
305 virtual ReadStatus readDirectory(uint64_t& cookie, DirectoryEntryEmitter emitter, void* context);
306
307 private:
308 static File* evaluateEntry(const DirectoryEntryMetadata& meta);
309 static void destroyEntry(File* file);
310
311 virtual bool isBytewise() const {
312 // This will cause read()/write() to fail as readBytewise/writeBytewise
313 // are not overridden and remain as their default implementation, which
314 // errors out.
315 return true;
316 }
317
318 protected:
320
321 private:
323 typedef HashTable<String, uint64_t, HashedStringView> DirectoryEntryGenerationCache;
324 typedef HashTable<String, bool, HashedStringView> EphemeralEntryCache;
325
328
329 ConditionVariable changed;
330 size_t users;
331 LookupStatus result;
332 bool complete;
333 bool invalidated;
334 };
335
337
340
343
346
349
352 uint64_t m_NextCacheGeneration;
353
356
362
365
367 Directory* m_ReparseTarget = nullptr;
368
370 uintptr_t m_ParentInode;
371
374
377
378#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
379 static RetainedLookupHook m_RetainedLookupHook;
380#endif
381
382 protected:
384 virtual const DirectoryEntryCache& getCache() {
385 return m_Cache;
386 }
387
389 void markCachePopulated();
390
392 bool addDirectoryEntry(const String& name, File* pTarget);
393
395 bool addDirectoryEntry(const String& name, DirectoryEntryMetadata&& meta);
396
398 bool reserveDirectoryEntry(const HashedStringView& name, NameReservation& reservation);
399
401 bool addCachedDirectoryEntry(NameReservation& reservation, File* pTarget);
402
404 void invalidateDirectoryEntry(const HashedStringView& name);
405
407 bool removeDirectoryEntry(const HashedStringView& name, File* expected);
408
411 return m_NamespaceMutationLock;
412 }
413
414 void markDetached();
415
417 void preallocateDirectoryEntries(size_t count);
418
420 virtual File* convertToFile(const DirectoryEntryMetadata& meta);
421
422 private:
424 bool reserveRenameEntry(const String& name, NameReservation& reservation);
425 void moveReservedEntry(NameReservation& sourceReservation, Directory* destination,
426 NameReservation& destinationReservation, File* source);
427 // Keep cookies non-negative when exposed through POSIX's signed off_t.
428 static constexpr uint64_t ResidentCookie = static_cast<uint64_t>(1) << 62;
429
430 uint64_t nextCacheGeneration();
431 bool removeEphemeralFileLocked(const HashedStringView& name, File* expected);
432 void finishNameReservation(NameReservation& reservation, LookupStatus result);
433 bool addResidentDirectoryEntry(NameReservation& reservation, File* pTarget, bool ephemeral);
434 bool addResidentDirectoryEntry(NameReservation& reservation, DirectoryEntry* entry,
435 bool ephemeral, File* createdTarget = nullptr);
436 void tombstoneResidentLocked(const HashedStringView& name);
437 File* cachedFileLocked(const HashedStringView& name) const;
438 static EntryType entryType(File* file);
439 LookupStatus lookupChildInternal(const HashedStringView& name, uint64_t cookie, bool hasCookie,
440 ChildLease& child) const;
441 struct EnumerationContext;
442 static bool emitBackingEntry(void* context, const DirectoryEntryView& entry);
443};
444
446
447#endif
static Directory * fromFile(File *pF)
Definition Directory.h:148
EphemeralEntryCache m_EphemeralEntries
Definition Directory.h:348
InFlightLookupCache m_InFlightLookups
Definition Directory.h:355
virtual bool isBytewise() const
Definition Directory.h:311
virtual bool cacheResolvedChildren() const
Definition Directory.h:293
uintptr_t m_ParentInode
Definition Directory.h:370
Mutex & namespaceMutationLock()
Definition Directory.h:410
bool m_bCachePopulated
Definition Directory.h:361
virtual bool isDirectory()
Definition Directory.h:171
bool isDetached() const
Definition Directory.h:179
bool m_Detached
Definition Directory.h:364
virtual const DirectoryEntryCache & getCache()
Definition Directory.h:384
Mutex m_NamespaceMutationLock
Definition Directory.h:376
Vector< String > m_ResidentOrder
Definition Directory.h:345
DirectoryEntryGenerationCache m_CacheGenerations
Definition Directory.h:351
Directory(const Directory &file)
Mutex m_CacheLock
Definition Directory.h:373
DirectoryEntryCache m_Cache
Definition Directory.h:339
DirectoryEntryCache m_ResidentEntries
Definition Directory.h:342
Definition File.h:74
virtual bool isDirectory()
Definition File.cc:721
Definition Mutex.h:56
A vector / dynamic array.
Definition Vector.h:33