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 // Transfers the tracked-file reference, leaving the stack's deferral local.
97 File* releaseOwnership();
98
99 void swap(ChildLease& other);
100
101 private:
102 friend class Directory;
103 friend class Filesystem;
104 friend class Symlink;
105
106 ChildLease(const ChildLease&) = delete;
107 ChildLease& operator=(const ChildLease&) = delete;
108 ChildLease(ChildLease&&) = delete;
109 ChildLease& operator=(ChildLease&&) = delete;
110
111 void adopt(File* file);
112
113 File* m_pFile;
114#if THREADS && !defined(STANDALONE_MUTEXES)
115 // A lease's deferral follows its lexical lifetime. Dynamically arming an
116 // older object would cross any newer guard's strict LIFO scope.
117 TerminationDeferral m_TerminationDeferral;
118#endif
119 };
120
121 class EXPORTED_PUBLIC NameReservation {
122 public:
125
126 explicit operator bool() const {
127 return m_pDirectory != nullptr;
128 }
129
130 void complete(LookupStatus result);
131
132 private:
133 friend class Directory;
134 friend class Filesystem;
135
136 NameReservation(const NameReservation&) = delete;
137 NameReservation& operator=(const NameReservation&) = delete;
139 NameReservation& operator=(NameReservation&&) = delete;
140
141 Directory* m_pDirectory;
142 String m_Name;
143 void* m_pToken;
144 bool m_OwnsNamespaceLock;
145#if THREADS && !defined(STANDALONE_MUTEXES)
146 TerminationDeferral m_TerminationDeferral;
147#endif
148 };
149
151 static Directory* fromFile(File* pF) {
152 if (!pF->isDirectory())
153 FATAL("Casting non-directory File to Directory!");
154 return reinterpret_cast<Directory*>(pF);
155 }
156
158 Directory();
159
161 private:
162 Directory(const Directory& file);
163 Directory& operator=(const Directory&);
164
165 public:
167 Directory(const String& name, Time::Timestamp accessedTime, Time::Timestamp modifiedTime,
168 Time::Timestamp creationTime, uintptr_t inode, class Filesystem* pFs, size_t size,
169 File* pParent);
171 virtual ~Directory();
172
174 virtual bool isDirectory() {
175 return true;
176 }
177
179 File* getChild(size_t n);
180
182 bool isDetached() const {
183 return __atomic_load_n(&m_Detached, __ATOMIC_ACQUIRE);
184 }
185
187 size_t getNumChildren();
188
194 ReadStatus enumerate(uint64_t& cookie, DirectoryEntryEmitter emitter, void* context);
195
197 ReadStatus isEmpty(bool& empty);
198
200 virtual void cacheDirectoryContents();
201
203 virtual bool isCachePopulated() const;
204
206 File* lookup(const HashedStringView& s) const;
207
215 MUST_USE_RESULT bool lookupRetained(const HashedStringView& s, ChildLease& child) const;
216
218 MUST_USE_RESULT LookupStatus lookupChild(const HashedStringView& s, ChildLease& child) const;
219
221 MUST_USE_RESULT LookupStatus lookupChildAt(uint64_t cookie, const HashedStringView& name,
222 ChildLease& child) const;
223
225 void remove(const HashedStringView& s);
226
235 Directory* getReparsePoint() const;
236
238 void setReparsePoint(Directory* pTarget);
239
247 AddStatus addEphemeralFile(File* pFile);
248
250 void removeEphemeralFiles();
251
257 bool empty();
258
262 void emptyCache();
263
264#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
265 enum class RetainedLookupPhase { BeforeLookup, AfterRetain };
266 using RetainedLookupHook = void (*)(Directory*, File*, RetainedLookupPhase);
267 static void setRetainedLookupHookForHostedTest(RetainedLookupHook hook);
268 const void* cacheLockAddressForHostedTest() const {
269 return static_cast<const void*>(&m_CacheLock);
270 }
271 bool tryCacheLockForHostedTest() const;
272#endif
273#if HOSTED
274 size_t inFlightUsersForHostedTest(const HashedStringView& name) const;
275#endif
276
277 protected:
281
283
284 // No copy construction (UniqueArray)
285 NOT_COPYABLE_OR_ASSIGNABLE(DirectoryEntryMetadata);
286
287 // These two should always be known at metadata creation time.
288 Directory* pDirectory;
289 String filename;
290
291 // Space for anything else to be stored by the filesystem.
292 UniqueArray<char> opaque;
293 };
294
296 virtual LookupStatus resolveChild(const StringView& name, File*& child);
297
299 virtual bool cacheResolvedChildren() const {
300 return true;
301 }
302
308 virtual LookupStatus resolveChildAt(uint64_t cookie, const StringView& name, File*& child);
309
311 virtual ReadStatus readDirectory(uint64_t& cookie, DirectoryEntryEmitter emitter, void* context);
312
313 private:
314 static File* evaluateEntry(const DirectoryEntryMetadata& meta);
315 static void destroyEntry(File* file);
316
317 virtual bool isBytewise() const {
318 // This will cause read()/write() to fail as readBytewise/writeBytewise
319 // are not overridden and remain as their default implementation, which
320 // errors out.
321 return true;
322 }
323
324 protected:
326
327 private:
329 typedef HashTable<String, uint64_t, HashedStringView> DirectoryEntryGenerationCache;
330 typedef HashTable<String, bool, HashedStringView> EphemeralEntryCache;
331
334
335 ConditionVariable changed;
336 size_t users;
337 LookupStatus result;
338 bool complete;
339 bool invalidated;
340 };
341
343
346
349
352
355
358 uint64_t m_NextCacheGeneration;
359
362
368
371
373 Directory* m_ReparseTarget = nullptr;
374
376 uintptr_t m_ParentInode;
377
380
383
384#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
385 static RetainedLookupHook m_RetainedLookupHook;
386#endif
387
388 protected:
390 virtual const DirectoryEntryCache& getCache() {
391 return m_Cache;
392 }
393
395 void markCachePopulated();
396
398 bool addDirectoryEntry(const String& name, File* pTarget);
399
401 bool addDirectoryEntry(const String& name, DirectoryEntryMetadata&& meta);
402
404 bool reserveDirectoryEntry(const HashedStringView& name, NameReservation& reservation);
405
407 bool addCachedDirectoryEntry(NameReservation& reservation, File* pTarget);
408
410 void invalidateDirectoryEntry(const HashedStringView& name);
411
413 bool removeDirectoryEntry(const HashedStringView& name, File* expected);
414
417 return m_NamespaceMutationLock;
418 }
419
420 void markDetached();
421
423 void preallocateDirectoryEntries(size_t count);
424
426 virtual File* convertToFile(const DirectoryEntryMetadata& meta);
427
428 private:
430 bool reserveRenameEntry(const String& name, NameReservation& reservation);
431 void moveReservedEntry(NameReservation& sourceReservation, Directory* destination,
432 NameReservation& destinationReservation, File* source);
433 // Keep cookies non-negative when exposed through POSIX's signed off_t.
434 static constexpr uint64_t ResidentCookie = static_cast<uint64_t>(1) << 62;
435
436 uint64_t nextCacheGeneration();
437 bool removeEphemeralFileLocked(const HashedStringView& name, File* expected);
438 void finishNameReservation(NameReservation& reservation, LookupStatus result);
439 bool addResidentDirectoryEntry(NameReservation& reservation, File* pTarget, bool ephemeral);
440 bool addResidentDirectoryEntry(NameReservation& reservation, DirectoryEntry* entry,
441 bool ephemeral, File* createdTarget = nullptr);
442 void tombstoneResidentLocked(const HashedStringView& name);
443 File* cachedFileLocked(const HashedStringView& name) const;
444 static EntryType entryType(File* file);
445 LookupStatus lookupChildInternal(const HashedStringView& name, uint64_t cookie, bool hasCookie,
446 ChildLease& child) const;
447 struct EnumerationContext;
448 static bool emitBackingEntry(void* context, const DirectoryEntryView& entry);
449};
450
452
453#endif
static Directory * fromFile(File *pF)
Definition Directory.h:151
EphemeralEntryCache m_EphemeralEntries
Definition Directory.h:354
InFlightLookupCache m_InFlightLookups
Definition Directory.h:361
virtual bool isBytewise() const
Definition Directory.h:317
virtual bool cacheResolvedChildren() const
Definition Directory.h:299
uintptr_t m_ParentInode
Definition Directory.h:376
Mutex & namespaceMutationLock()
Definition Directory.h:416
bool m_bCachePopulated
Definition Directory.h:367
virtual bool isDirectory()
Definition Directory.h:174
bool isDetached() const
Definition Directory.h:182
bool m_Detached
Definition Directory.h:370
virtual const DirectoryEntryCache & getCache()
Definition Directory.h:390
Mutex m_NamespaceMutationLock
Definition Directory.h:382
Vector< String > m_ResidentOrder
Definition Directory.h:351
DirectoryEntryGenerationCache m_CacheGenerations
Definition Directory.h:357
Directory(const Directory &file)
Mutex m_CacheLock
Definition Directory.h:379
DirectoryEntryCache m_Cache
Definition Directory.h:345
DirectoryEntryCache m_ResidentEntries
Definition Directory.h:348
Definition File.h:75
virtual bool isDirectory()
Definition File.cc:804
Definition Mutex.h:56
A vector / dynamic array.
Definition Vector.h:33