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 19struct 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. 27struct 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 84struct Volume::EntryMap : HashMap<EntryKey, Entry*> { 85}; 86 87 88// constructor 89Volume::Volume(dev_t id) 90 : fID(id), 91 fRootDir(NULL), 92 fFSFlags(0), 93 fNodes(NULL), 94 fEntries(NULL) 95{ 96} 97 98// destructor 99Volume::~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 130status_t 131Volume::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 180dev_t 181Volume::GetID() const 182{ 183 return fID; 184} 185 186// GetRootDirectory 187Directory* 188Volume::GetRootDirectory() const 189{ 190 return fRootDir; 191} 192 193// GetRootID 194ino_t 195Volume::GetRootID() const 196{ 197 return fRootDir->GetID(); 198} 199 200// KnowsQuery 201bool 202Volume::KnowsQuery() const 203{ 204 return (fFSFlags & B_FS_HAS_QUERY); 205} 206 207 208// AddNode 209status_t 210Volume::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 219bool 220Volume::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 231Node* 232Volume::GetNode(ino_t nodeID) 233{ 234 return fNodes->Get(nodeID); 235} 236 237// GetFirstNode 238Node* 239Volume::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 248status_t 249Volume::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 260bool 261Volume::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 272Entry* 273Volume::GetEntry(ino_t dirID, const char* name) 274{ 275 return fEntries->Get(EntryKey(dirID, name)); 276} 277 278// GetFirstEntry 279Entry* 280Volume::GetFirstEntry() const 281{ 282 EntryMap::Iterator it = fEntries->GetIterator(); 283 if (it.HasNext()) 284 return it.Next().value; 285 return NULL; 286} 287 288