BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / file_systems / nfs4 / DirectoryCache.cpp
blob168f54ccdfc0be1811d324bb3cc560ea4b5217db
1 /*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Paweł Dziepak, pdziepak@quarnos.org
7 */
10 #include "DirectoryCache.h"
12 #include <fs_cache.h>
13 #include <NodeMonitor.h>
15 #include "Inode.h"
19 NameCacheEntry::NameCacheEntry(const char* name, ino_t node)
21 fNode(node),
22 fName(strdup(name))
24 ASSERT(name != NULL);
28 NameCacheEntry::NameCacheEntry(const NameCacheEntry& entry)
30 fNode(entry.fNode),
31 fName(strdup(entry.fName))
36 NameCacheEntry::~NameCacheEntry()
38 free(const_cast<char*>(fName));
42 DirectoryCacheSnapshot::DirectoryCacheSnapshot()
44 mutex_init(&fLock, NULL);
48 DirectoryCacheSnapshot::DirectoryCacheSnapshot(
49 const DirectoryCacheSnapshot& snapshot)
51 mutex_init(&fLock, NULL);
53 MutexLocker _(snapshot.fLock);
54 NameCacheEntry* entry = snapshot.fEntries.Head();
55 NameCacheEntry* new_entry;
56 while (entry) {
57 new_entry = new NameCacheEntry(*entry);
58 if (new_entry == NULL)
59 break;
61 fEntries.Add(new_entry);
63 entry = snapshot.fEntries.GetNext(entry);
68 DirectoryCacheSnapshot::~DirectoryCacheSnapshot()
70 while (!fEntries.IsEmpty()) {
71 NameCacheEntry* current = fEntries.RemoveHead();
72 delete current;
75 mutex_destroy(&fLock);
79 DirectoryCache::DirectoryCache(Inode* inode, bool attr)
81 fExpirationTime(inode->fFileSystem->GetConfiguration().fDirectoryCacheTime),
82 fDirectoryCache(NULL),
83 fInode(inode),
84 fAttrDir(attr),
85 fTrashed(true)
87 ASSERT(inode != NULL);
89 mutex_init(&fLock, NULL);
93 DirectoryCache::~DirectoryCache()
95 mutex_destroy(&fLock);
99 void
100 DirectoryCache::Reset()
102 Trash();
103 fExpireTime = system_time() + fExpirationTime;
104 fTrashed = false;
108 void
109 DirectoryCache::Trash()
111 while (!fNameCache.IsEmpty()) {
112 NameCacheEntry* current = fNameCache.RemoveHead();
113 entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(),
114 current->fName);
115 delete current;
118 _SetSnapshot(NULL);
120 fTrashed = true;
124 status_t
125 DirectoryCache::AddEntry(const char* name, ino_t node, bool created)
127 ASSERT(name != NULL);
129 NameCacheEntry* entry = new(std::nothrow) NameCacheEntry(name, node);
130 if (entry == NULL)
131 return B_NO_MEMORY;
132 if (entry->fName == NULL) {
133 delete entry;
134 return B_NO_MEMORY;
137 fNameCache.Add(entry);
139 if (created && fDirectoryCache != NULL) {
140 MutexLocker _(fDirectoryCache->fLock);
141 NameCacheEntry* entry = new(std::nothrow) NameCacheEntry(name, node);
142 if (entry == NULL)
143 return B_NO_MEMORY;
144 if (entry->fName == NULL) {
145 delete entry;
146 return B_NO_MEMORY;
149 fDirectoryCache->fEntries.Add(entry);
152 if (!fAttrDir) {
153 return entry_cache_add(fInode->GetFileSystem()->DevId(), fInode->ID(),
154 name, node);
157 return B_OK;
161 void
162 DirectoryCache::RemoveEntry(const char* name)
164 ASSERT(name != NULL);
166 SinglyLinkedList<NameCacheEntry>::Iterator iterator
167 = fNameCache.GetIterator();
168 NameCacheEntry* previous = NULL;
169 NameCacheEntry* current = iterator.Next();
170 while (current != NULL) {
171 if (strcmp(current->fName, name) == 0) {
172 fNameCache.Remove(previous, current);
173 delete current;
174 break;
177 previous = current;
178 current = iterator.Next();
181 if (fDirectoryCache != NULL) {
182 MutexLocker _(fDirectoryCache->fLock);
183 iterator = fDirectoryCache->fEntries.GetIterator();
184 previous = NULL;
185 current = iterator.Next();
186 while (current != NULL) {
187 if (strcmp(current->fName, name) == 0) {
188 fDirectoryCache->fEntries.Remove(previous, current);
189 delete current;
190 break;
193 previous = current;
194 current = iterator.Next();
198 if (!fAttrDir) {
199 entry_cache_remove(fInode->GetFileSystem()->DevId(), fInode->ID(),
200 name);
205 void
206 DirectoryCache::_SetSnapshot(DirectoryCacheSnapshot* snapshot)
208 if (fDirectoryCache != NULL)
209 fDirectoryCache->ReleaseReference();
210 fDirectoryCache = snapshot;
214 status_t
215 DirectoryCache::_LoadSnapshot(bool trash)
217 DirectoryCacheSnapshot* oldSnapshot = fDirectoryCache;
218 if (oldSnapshot != NULL)
219 oldSnapshot->AcquireReference();
221 if (trash)
222 Trash();
224 DirectoryCacheSnapshot* newSnapshot;
225 status_t result = fInode->GetDirSnapshot(&newSnapshot, NULL, &fChange,
226 fAttrDir);
227 if (result != B_OK) {
228 if (oldSnapshot != NULL)
229 oldSnapshot->ReleaseReference();
230 return result;
232 newSnapshot->AcquireReference();
234 _SetSnapshot(newSnapshot);
235 fExpireTime = system_time() + fExpirationTime;
237 fTrashed = false;
239 if (oldSnapshot != NULL)
240 NotifyChanges(oldSnapshot, newSnapshot);
242 if (oldSnapshot != NULL)
243 oldSnapshot->ReleaseReference();
245 newSnapshot->ReleaseReference();
246 return B_OK;
250 status_t
251 DirectoryCache::Revalidate()
253 if (fExpireTime > system_time())
254 return B_OK;
256 uint64 change;
257 if (fInode->GetChangeInfo(&change, fAttrDir) != B_OK) {
258 Trash();
259 return B_ERROR;
262 if (change == fChange) {
263 fExpireTime = system_time() + fExpirationTime;
264 return B_OK;
267 return _LoadSnapshot(true);
271 void
272 DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot,
273 DirectoryCacheSnapshot* newSnapshot)
275 ASSERT(newSnapshot != NULL);
276 ASSERT(oldSnapshot != NULL);
278 MutexLocker _(newSnapshot->fLock);
280 SinglyLinkedList<NameCacheEntry>::Iterator oldIt
281 = oldSnapshot->fEntries.GetIterator();
282 NameCacheEntry* oldCurrent;
284 SinglyLinkedList<NameCacheEntry>::Iterator newIt
285 = newSnapshot->fEntries.GetIterator();
286 NameCacheEntry* newCurrent = newIt.Next();
287 while (newCurrent != NULL) {
288 oldIt = oldSnapshot->fEntries.GetIterator();
289 oldCurrent = oldIt.Next();
291 bool found = false;
292 NameCacheEntry* prev = NULL;
293 while (oldCurrent != NULL) {
294 if (oldCurrent->fNode == newCurrent->fNode
295 && strcmp(oldCurrent->fName, newCurrent->fName) == 0) {
296 found = true;
297 break;
300 prev = oldCurrent;
301 oldCurrent = oldIt.Next();
304 if (!found) {
305 if (fAttrDir) {
306 notify_attribute_changed(fInode->GetFileSystem()->DevId(),
307 fInode->ID(), newCurrent->fName, B_ATTR_CREATED);
308 } else {
309 notify_entry_created(fInode->GetFileSystem()->DevId(),
310 fInode->ID(), newCurrent->fName, newCurrent->fNode);
312 } else
313 oldSnapshot->fEntries.Remove(prev, oldCurrent);
315 newCurrent = newIt.Next();
318 oldIt = oldSnapshot->fEntries.GetIterator();
319 oldCurrent = oldIt.Next();
321 while (oldCurrent != NULL) {
322 if (fAttrDir) {
323 notify_attribute_changed(fInode->GetFileSystem()->DevId(),
324 fInode->ID(), oldCurrent->fName, B_ATTR_REMOVED);
325 } else {
326 notify_entry_removed(fInode->GetFileSystem()->DevId(), fInode->ID(),
327 oldCurrent->fName, oldCurrent->fNode);
329 oldCurrent = oldIt.Next();