xref: /haiku/src/add-ons/kernel/file_systems/netfs/server/Volume.cpp (revision 2069f565e8ed3556b30cf2f5e3aa54450128b8c2)
1 // Volume.cpp
2 
3 #include <new>
4 
5 #include <string.h>
6 #include <sys/stat.h>
7 
8 #include <Directory.h>
9 #include <fs_info.h>
10 #include <HashMap.h>
11 
12 #include "Directory.h"
13 #include "FDManager.h"
14 #include "Entry.h"
15 #include "Node.h"
16 #include "Volume.h"
17 
18 // NodeMap
19 struct Volume::NodeMap : HashMap<HashKey64<ino_t>, Node*> {
20 };
21 
22 // EntryKey
23 //
24 // NOTE: This class doesn't make a copy of the name string it is constructed
25 // with. So, when entering the key in a map, one must make sure, that the
26 // string stays valid as long as the entry is in the map.
27 struct Volume::EntryKey {
28 	EntryKey() {}
29 
30 	EntryKey(ino_t directoryID, const char* name)
31 		: directoryID(directoryID),
32 		  name(name)
33 	{
34 	}
35 
36 	EntryKey(Entry* entry)
37 		: directoryID(entry->GetDirectoryID()),
38 		  name(entry->GetName())
39 	{
40 	}
41 
42 	EntryKey(const EntryKey& other)
43 		: directoryID(other.directoryID),
44 		  name(other.name)
45 	{
46 	}
47 
48 	uint32 GetHashCode() const
49 	{
50 		uint32 hash = (uint32)directoryID;
51 		hash = 31 * hash + (uint32)(directoryID >> 32);
52 		hash = 31 * hash + string_hash(name);
53 		return hash;
54 	}
55 
56 	EntryKey& operator=(const EntryKey& other)
57 	{
58 		directoryID = other.directoryID;
59 		name = other.name;
60 		return *this;
61 	}
62 
63 	bool operator==(const EntryKey& other) const
64 	{
65 		if (directoryID != other.directoryID)
66 			return false;
67 
68 		if (name)
69 			return (other.name && strcmp(name, other.name) == 0);
70 
71 		return !other.name;
72 	}
73 
74 	bool operator!=(const EntryKey& other) const
75 	{
76 		return !(*this == other);
77 	}
78 
79 	ino_t		directoryID;
80 	const char*	name;
81 };
82 
83 // EntryMap
84 struct Volume::EntryMap : HashMap<EntryKey, Entry*> {
85 };
86 
87 
88 // constructor
89 Volume::Volume(dev_t id)
90 	: fID(id),
91 	  fRootDir(NULL),
92 	  fFSFlags(0),
93 	  fNodes(NULL),
94 	  fEntries(NULL)
95 {
96 }
97 
98 // destructor
99 Volume::~Volume()
100 {
101 	// delete all entries
102 	if (fEntries) {
103 		for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();) {
104 			Entry* entry = it.Next().value;
105 			delete entry;
106 		}
107 		delete fEntries;
108 	}
109 
110 	// delete all nodes
111 	if (fNodes) {
112 		// remove the root dir -- we delete it separately
113 		if (fRootDir)
114 			RemoveNode(fRootDir);
115 
116 		// delete the nodes
117 		for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();) {
118 			Node* node = it.Next().value;
119 			delete node;
120 		}
121 
122 		delete fNodes;
123 	}
124 
125 	// delete the root dir
126 	delete fRootDir;
127 }
128 
129 // Init
130 status_t
131 Volume::Init()
132 {
133 	// create the node map
134 	fNodes = new(std::nothrow) NodeMap;
135 	if (!fNodes)
136 		return B_NO_MEMORY;
137 	if (fNodes->InitCheck() != B_OK)
138 		return fNodes->InitCheck();
139 
140 	// create the entry map
141 	fEntries = new(std::nothrow) EntryMap;
142 	if (!fEntries)
143 		return B_NO_MEMORY;
144 	if (fEntries->InitCheck() != B_OK)
145 		return fEntries->InitCheck();
146 
147 	// get a volume info
148 	fs_info info;
149 	status_t error = fs_stat_dev(fID, &info);
150 	if (error != B_OK)
151 		return error;
152 	fFSFlags = info.flags;
153 
154 	// open the root directory
155 	node_ref rootRef;
156 	rootRef.device = fID;
157 	rootRef.node = info.root;
158 	BDirectory rootDir;
159 	error = FDManager::SetDirectory(&rootDir, &rootRef);
160 	if (error != B_OK)
161 		return error;
162 
163 	// stat the root dir
164 	struct stat st;
165 	error = rootDir.GetStat(&st);
166 	if (error != B_OK)
167 		return error;
168 
169 	// create the root dir
170 	fRootDir = new(std::nothrow) Directory(this, st);
171 	if (!fRootDir)
172 		return B_NO_MEMORY;
173 
174 	// the root dir is added by the VolumeManager
175 
176 	return B_OK;
177 }
178 
179 // GetID
180 dev_t
181 Volume::GetID() const
182 {
183 	return fID;
184 }
185 
186 // GetRootDirectory
187 Directory*
188 Volume::GetRootDirectory() const
189 {
190 	return fRootDir;
191 }
192 
193 // GetRootID
194 ino_t
195 Volume::GetRootID() const
196 {
197 	return fRootDir->GetID();
198 }
199 
200 // KnowsQuery
201 bool
202 Volume::KnowsQuery() const
203 {
204 	return (fFSFlags & B_FS_HAS_QUERY);
205 }
206 
207 
208 // AddNode
209 status_t
210 Volume::AddNode(Node* node)
211 {
212 	if (!node || node->GetVolume() != this || GetNode(node->GetID()))
213 		return B_BAD_VALUE;
214 
215 	return fNodes->Put(node->GetID(), node);
216 }
217 
218 // RemoveNode
219 bool
220 Volume::RemoveNode(Node* node)
221 {
222 	if (node && GetNode(node->GetID()) == node) {
223 		fNodes->Remove(node->GetID());
224 		return true;
225 	}
226 
227 	return false;
228 }
229 
230 // GetNode
231 Node*
232 Volume::GetNode(ino_t nodeID)
233 {
234 	return fNodes->Get(nodeID);
235 }
236 
237 // GetFirstNode
238 Node*
239 Volume::GetFirstNode() const
240 {
241 	NodeMap::Iterator it = fNodes->GetIterator();
242 	if (it.HasNext())
243 		return it.Next().value;
244 	return NULL;
245 }
246 
247 // AddEntry
248 status_t
249 Volume::AddEntry(Entry* entry)
250 {
251 	if (!entry || entry->GetVolume() != this
252 		|| GetEntry(entry->GetDirectoryID(), entry->GetName())) {
253 		return B_BAD_VALUE;
254 	}
255 
256 	return fEntries->Put(EntryKey(entry), entry);
257 }
258 
259 // RemoveEntry
260 bool
261 Volume::RemoveEntry(Entry* entry)
262 {
263 	if (entry && GetEntry(entry->GetDirectoryID(), entry->GetName()) == entry) {
264 		fEntries->Remove(EntryKey(entry));
265 		return true;
266 	}
267 
268 	return false;
269 }
270 
271 // GetEntry
272 Entry*
273 Volume::GetEntry(ino_t dirID, const char* name)
274 {
275 	return fEntries->Get(EntryKey(dirID, name));
276 }
277 
278 // GetFirstEntry
279 Entry*
280 Volume::GetFirstEntry() const
281 {
282 	EntryMap::Iterator it = fEntries->GetIterator();
283 	if (it.HasNext())
284 		return it.Next().value;
285 	return NULL;
286 }
287 
288