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 {
EntryKeyVolume::EntryKey28 EntryKey() {}
29
EntryKeyVolume::EntryKey30 EntryKey(ino_t directoryID, const char* name)
31 : directoryID(directoryID),
32 name(name)
33 {
34 }
35
EntryKeyVolume::EntryKey36 EntryKey(Entry* entry)
37 : directoryID(entry->GetDirectoryID()),
38 name(entry->GetName())
39 {
40 }
41
EntryKeyVolume::EntryKey42 EntryKey(const EntryKey& other)
43 : directoryID(other.directoryID),
44 name(other.name)
45 {
46 }
47
GetHashCodeVolume::EntryKey48 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
operator =Volume::EntryKey56 EntryKey& operator=(const EntryKey& other)
57 {
58 directoryID = other.directoryID;
59 name = other.name;
60 return *this;
61 }
62
operator ==Volume::EntryKey63 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
operator !=Volume::EntryKey74 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
Volume(dev_t id)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
~Volume()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
Init()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
GetID() const181 Volume::GetID() const
182 {
183 return fID;
184 }
185
186 // GetRootDirectory
187 Directory*
GetRootDirectory() const188 Volume::GetRootDirectory() const
189 {
190 return fRootDir;
191 }
192
193 // GetRootID
194 ino_t
GetRootID() const195 Volume::GetRootID() const
196 {
197 return fRootDir->GetID();
198 }
199
200 // KnowsQuery
201 bool
KnowsQuery() const202 Volume::KnowsQuery() const
203 {
204 return (fFSFlags & B_FS_HAS_QUERY);
205 }
206
207
208 // AddNode
209 status_t
AddNode(Node * node)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
RemoveNode(Node * node)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*
GetNode(ino_t nodeID)232 Volume::GetNode(ino_t nodeID)
233 {
234 return fNodes->Get(nodeID);
235 }
236
237 // GetFirstNode
238 Node*
GetFirstNode() const239 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
AddEntry(Entry * entry)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
RemoveEntry(Entry * entry)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*
GetEntry(ino_t dirID,const char * name)273 Volume::GetEntry(ino_t dirID, const char* name)
274 {
275 return fEntries->Get(EntryKey(dirID, name));
276 }
277
278 // GetFirstEntry
279 Entry*
GetFirstEntry() const280 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