1 /* 2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "NameIndex.h" 8 9 #include <TypeConstants.h> 10 11 #include "DebugSupport.h" 12 #include "IndexImpl.h" 13 #include "Node.h" 14 #include "TwoKeyAVLTree.h" 15 #include "Volume.h" 16 17 18 // #pragma mark - NameIndexPrimaryKey 19 20 21 class NameIndexPrimaryKey { 22 public: 23 NameIndexPrimaryKey(const Node* entry, const char* name = NULL) 24 : 25 entry(entry), 26 name(name ? name : entry->Name()) 27 { 28 } 29 30 NameIndexPrimaryKey(const char* name) 31 : 32 entry(NULL), 33 name(name) 34 { 35 } 36 37 const Node* entry; 38 const char* name; 39 }; 40 41 42 // #pragma mark - NameIndexGetPrimaryKey 43 44 45 class NameIndexGetPrimaryKey { 46 public: 47 inline NameIndexPrimaryKey operator()(const Node* a) 48 { 49 return NameIndexPrimaryKey(a); 50 } 51 52 inline NameIndexPrimaryKey operator()(const Node* a) const 53 { 54 return NameIndexPrimaryKey(a); 55 } 56 }; 57 58 59 // #pragma mark - NameIndexPrimaryKeyCompare 60 61 62 class NameIndexPrimaryKeyCompare { 63 public: 64 inline int operator()(const NameIndexPrimaryKey &a, 65 const NameIndexPrimaryKey &b) const 66 { 67 if (a.entry != NULL && a.entry == b.entry) 68 return 0; 69 return strcmp(a.name, b.name); 70 } 71 }; 72 73 74 // #pragma mark - EntryTree 75 76 77 typedef TwoKeyAVLTree<Node*, NameIndexPrimaryKey, NameIndexPrimaryKeyCompare, 78 NameIndexGetPrimaryKey> _EntryTree; 79 80 class NameIndex::EntryTree : public _EntryTree { 81 }; 82 83 84 // #pragma mark - Iterator 85 86 87 struct NameIndex::IteratorPolicy { 88 typedef NameIndex Index; 89 typedef const char* Value; 90 typedef NameIndex::EntryTree NodeTree; 91 typedef GenericIndexIteratorTreePolicy<IteratorPolicy> TreePolicy; 92 93 static NodeTree* GetNodeTree(Index* index) 94 { 95 return index->fEntries; 96 } 97 98 static void GetNodeValue(Node* node, void* buffer, size_t* _keyLength) 99 { 100 strlcpy((char*)buffer, node->Name(), kMaxIndexKeyLength); 101 *_keyLength = strlen(node->Name()); 102 } 103 }; 104 105 106 struct NameIndex::Iterator : public GenericIndexIterator<IteratorPolicy> { 107 }; 108 109 110 // #pragma mark - NameIndex 111 112 113 NameIndex::NameIndex() 114 : 115 Index(), 116 fEntries(NULL) 117 { 118 } 119 120 121 NameIndex::~NameIndex() 122 { 123 if (IsListening()) 124 fVolume->RemoveNodeListener(this); 125 126 delete fEntries; 127 // Actually we would need to maintain a list of iterators and unset the 128 // still existing iterators here. But since the name index is deleted 129 // when the volume is unmounted, there shouldn't be any iterators left 130 // anymore. 131 } 132 133 134 status_t 135 NameIndex::Init(Volume* volume) 136 { 137 status_t error = Index::Init(volume, "name", B_STRING_TYPE, false); 138 if (error != B_OK) 139 return error; 140 141 fVolume->AddNodeListener(this, NULL); 142 143 fEntries = new(std::nothrow) EntryTree; 144 if (fEntries == NULL) 145 return B_NO_MEMORY; 146 147 return B_OK; 148 } 149 150 151 int32 152 NameIndex::CountEntries() const 153 { 154 return fEntries->CountItems(); 155 } 156 157 158 void 159 NameIndex::NodeAdded(Node* node) 160 { 161 fEntries->Insert(node); 162 163 // update live queries 164 _UpdateLiveQueries(node, NULL, node->Name()); 165 } 166 167 168 void 169 NameIndex::NodeRemoved(Node* node) 170 { 171 fEntries->Remove(node, node); 172 173 // update live queries 174 _UpdateLiveQueries(node, node->Name(), NULL); 175 } 176 177 178 void 179 NameIndex::NodeChanged(Node* node, uint32 statFields, 180 const OldNodeAttributes& oldAttributes) 181 { 182 // nothing to do -- the name remains the same 183 } 184 185 186 AbstractIndexIterator* 187 NameIndex::InternalGetIterator() 188 { 189 Iterator* iterator = new(std::nothrow) Iterator; 190 if (iterator != NULL) { 191 if (!iterator->SetTo(this, NULL, true)) { 192 delete iterator; 193 iterator = NULL; 194 } 195 } 196 return iterator; 197 } 198 199 200 AbstractIndexIterator* 201 NameIndex::InternalFind(const void* _key, size_t length) 202 { 203 if (length == 0) 204 return NULL; 205 206 const char* key = (const char*)_key; 207 208 // if the key is not null-terminated, copy it 209 char clonedKey[kMaxIndexKeyLength]; 210 if (key[length - 1] != '\0') { 211 if (length >= kMaxIndexKeyLength) 212 length = kMaxIndexKeyLength - 1; 213 214 memcpy(clonedKey, key, length); 215 clonedKey[length] = '\0'; 216 length++; 217 key = clonedKey; 218 } 219 220 Iterator* iterator = new(std::nothrow) Iterator; 221 if (iterator != NULL) { 222 if (!iterator->SetTo(this, (const char*)key)) { 223 delete iterator; 224 iterator = NULL; 225 } 226 } 227 return iterator; 228 } 229 230 231 void 232 NameIndex::_UpdateLiveQueries(Node* entry, const char* oldName, 233 const char* newName) 234 { 235 fVolume->UpdateLiveQueries(entry, Name(), Type(), 236 oldName, oldName ? strlen(oldName) : 0, 237 newName, newName ? strlen(newName) : 0); 238 } 239