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