xref: /haiku/src/add-ons/kernel/file_systems/netfs/client/VirtualDir.cpp (revision c90684742e7361651849be4116d0e5de3a817194)
1 // VirtualDir.cpp
2 
3 #include "VirtualDir.h"
4 
5 #include <string.h>
6 
7 #include <AutoDeleter.h>
8 
9 // constructor
10 VirtualDirEntry::VirtualDirEntry()
11 	: fName(),
12 	  fNode(NULL)
13 {
14 }
15 
16 // destructor
17 VirtualDirEntry::~VirtualDirEntry()
18 {
19 }
20 
21 // SetTo
22 status_t
23 VirtualDirEntry::SetTo(const char* name, Node* node)
24 {
25 	if (!name || strlen(name) == 0 || !node)
26 		return B_BAD_VALUE;
27 
28 	if (!fName.SetTo(name))
29 		return B_NO_MEMORY;
30 	fNode = node;
31 
32 	return B_OK;
33 }
34 
35 // GetName
36 const char*
37 VirtualDirEntry::GetName() const
38 {
39 	return fName.GetString();
40 }
41 
42 // GetNode
43 Node*
44 VirtualDirEntry::GetNode() const
45 {
46 	return fNode;
47 }
48 
49 
50 // #pragma mark -
51 
52 // constructor
53 VirtualDirIterator::VirtualDirIterator()
54 	: fDirectory(NULL),
55 	  fCurrentEntry(NULL),
56 	  fState(STATE_DOT)
57 {
58 }
59 
60 // destructor
61 VirtualDirIterator::~VirtualDirIterator()
62 {
63 	SetDirectory(NULL);
64 }
65 
66 // SetDirectory
67 void
68 VirtualDirIterator::SetDirectory(VirtualDir* directory, bool onlyChildren)
69 {
70 	// unset the old directory
71 	if (fDirectory)
72 		fDirectory->RemoveDirIterator(this);
73 
74 	// set the new directory
75 	fDirectory = directory;
76 	if (fDirectory) {
77 		fDirectory->AddDirIterator(this);
78 
79 		if (onlyChildren) {
80 			fCurrentEntry = fDirectory->GetFirstEntry();
81 			fState = STATE_OTHERS;
82 		} else {
83 			fCurrentEntry = NULL;
84 			fState = STATE_DOT;
85 		}
86 	}
87 }
88 
89 // GetCurrentEntry
90 bool
91 VirtualDirIterator::GetCurrentEntry(const char** name, Node** node)
92 {
93 	if (!fDirectory)
94 		return false;
95 	switch (fState) {
96 		case STATE_DOT:
97 			*name = ".";
98 			*node = fDirectory;
99 			return true;
100 		case STATE_DOT_DOT:
101 			*name = "..";
102 			*node = fDirectory->GetParent();
103 			if (!*node)
104 				*node = fDirectory;
105 			return true;
106 		default:
107 			if (!fCurrentEntry)
108 				return false;
109 			*name = fCurrentEntry->GetName();
110 			*node = fCurrentEntry->GetNode();
111 			return true;
112 	}
113 }
114 
115 // GetCurrentEntry
116 VirtualDirEntry*
117 VirtualDirIterator::GetCurrentEntry() const
118 {
119 	return fCurrentEntry;
120 }
121 
122 // NextEntry
123 void
124 VirtualDirIterator::NextEntry()
125 {
126 	if (!fDirectory)
127 		return;
128 	switch (fState) {
129 		case STATE_DOT:
130 			fState = STATE_DOT_DOT;
131 			break;
132 		case STATE_DOT_DOT:
133 			fState = STATE_OTHERS;
134 			fCurrentEntry = fDirectory->GetFirstEntry();
135 			break;
136 		default:
137 			if (fCurrentEntry)
138 				fCurrentEntry = fDirectory->GetNextEntry(fCurrentEntry);
139 			break;
140 	}
141 }
142 
143 // Rewind
144 void
145 VirtualDirIterator::Rewind()
146 {
147 	fState = STATE_DOT;
148 	fCurrentEntry = NULL;
149 }
150 
151 
152 // #pragma mark -
153 
154 // constructor
155 VirtualDir::VirtualDir(Volume* volume, vnode_id nodeID)
156 	: Node(volume, nodeID),
157 	  fParent(NULL),
158 	  fCreationTime(0),
159 	  fEntries(),
160 	  fEntryList(),
161 	  fIterators()
162 {
163 }
164 
165 // destructor
166 VirtualDir::~VirtualDir()
167 {
168 	while (VirtualDirEntry* entry = GetFirstEntry())
169 		RemoveEntry(entry->GetName());
170 }
171 
172 // InitCheck
173 status_t
174 VirtualDir::InitCheck() const
175 {
176 	return fEntries.InitCheck();
177 }
178 
179 // SetParent
180 void
181 VirtualDir::SetParent(VirtualDir* parent)
182 {
183 	fParent = parent;
184 }
185 
186 // GetParent
187 VirtualDir*
188 VirtualDir::GetParent() const
189 {
190 	return fParent;
191 }
192 
193 // GetCreationTime
194 time_t
195 VirtualDir::GetCreationTime() const
196 {
197 	return fCreationTime;
198 }
199 
200 // AddEntry
201 status_t
202 VirtualDir::AddEntry(const char* name, Node* child)
203 {
204 	if (!name || !child || fEntries.ContainsKey(name))
205 		return B_BAD_VALUE;
206 
207 	// create an entry
208 	VirtualDirEntry* entry = new(std::nothrow) VirtualDirEntry;
209 	if (!entry)
210 		return B_NO_MEMORY;
211 	ObjectDeleter<VirtualDirEntry> entryDeleter(entry);
212 	status_t error = entry->SetTo(name, child);
213 	if (error != B_OK)
214 		return error;
215 
216 	// add the entry
217 	error = fEntries.Put(name, entry);
218 	if (error != B_OK)
219 		return error;
220 	fEntryList.Insert(entry);
221 	entryDeleter.Detach();
222 
223 	// TODO: That's not so nice. Check whether better to move the fParent
224 	// property to Node.
225 	if (VirtualDir* childDir = dynamic_cast<VirtualDir*>(child))
226 		childDir->SetParent(this);
227 
228 	return error;
229 }
230 
231 // RemoveEntry
232 Node*
233 VirtualDir::RemoveEntry(const char* name)
234 {
235 	if (!name)
236 		return NULL;
237 
238 	Node* child = NULL;
239 	VirtualDirEntry* entry = fEntries.Remove(name);
240 	if (entry) {
241 		child = entry->GetNode();
242 		// update the directory iterators pointing to the removed entry
243 		for (VirtualDirIterator* iterator = fIterators.First();
244 			 iterator;
245 			 iterator = fIterators.GetNext(iterator)) {
246 			if (iterator->GetCurrentEntry() == entry)
247 				iterator->NextEntry();
248 		}
249 
250 		// remove the entry completely
251 		fEntryList.Remove(entry);
252 		delete entry;
253 
254 		// TODO: See AddEntry().
255 		if (VirtualDir* childDir = dynamic_cast<VirtualDir*>(child))
256 			childDir->SetParent(NULL);
257 	}
258 	return child;
259 }
260 
261 // GetEntry
262 VirtualDirEntry*
263 VirtualDir::GetEntry(const char* name) const
264 {
265 	if (!name)
266 		return NULL;
267 
268 	return fEntries.Get(name);
269 }
270 
271 // GetChildNode
272 Node*
273 VirtualDir::GetChildNode(const char* name) const
274 {
275 	if (VirtualDirEntry* entry = GetEntry(name))
276 		return entry->GetNode();
277 	return NULL;
278 }
279 
280 // GetFirstEntry
281 VirtualDirEntry*
282 VirtualDir::GetFirstEntry() const
283 {
284 	return fEntryList.First();
285 }
286 
287 // GetNextEntry
288 VirtualDirEntry*
289 VirtualDir::GetNextEntry(VirtualDirEntry* entry) const
290 {
291 	if (!entry)
292 		return NULL;
293 	return fEntryList.GetNext(entry);
294 }
295 
296 // AddDirIterator
297 void
298 VirtualDir::AddDirIterator(VirtualDirIterator* iterator)
299 {
300 	if (!iterator)
301 		return;
302 
303 	fIterators.Insert(iterator);
304 }
305 
306 // RemoveDirIterator
307 void
308 VirtualDir::RemoveDirIterator(VirtualDirIterator* iterator)
309 {
310 	if (!iterator)
311 		return;
312 
313 	fIterators.Remove(iterator);
314 }
315