1 /* 2 * Copyright 2009-2013, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "UnpackingLeafNode.h" 8 9 #include <string.h> 10 11 #include <algorithm> 12 #include <new> 13 14 #include "ClassCache.h" 15 #include "UnpackingAttributeCookie.h" 16 #include "UnpackingAttributeDirectoryCookie.h" 17 #include "Utils.h" 18 19 20 CLASS_CACHE(UnpackingLeafNode); 21 22 23 UnpackingLeafNode::UnpackingLeafNode(ino_t id) 24 : 25 Node(id), 26 fFinalPackageNode(NULL) 27 { 28 } 29 30 31 UnpackingLeafNode::~UnpackingLeafNode() 32 { 33 if (fFinalPackageNode != NULL) 34 fFinalPackageNode->ReleaseReference(); 35 } 36 37 38 status_t 39 UnpackingLeafNode::VFSInit(dev_t deviceID) 40 { 41 status_t error = NodeInitVFS(deviceID, fID, _ActivePackageNode()); 42 if (error == B_OK) 43 Node::VFSInit(deviceID); 44 45 return error; 46 } 47 48 49 void 50 UnpackingLeafNode::VFSUninit() 51 { 52 NodeUninitVFS(_ActivePackageNode(), fFlags); 53 Node::VFSUninit(); 54 } 55 56 57 mode_t 58 UnpackingLeafNode::Mode() const 59 { 60 if (PackageLeafNode* packageNode = _ActivePackageNode()) 61 return packageNode->Mode(); 62 return S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; 63 } 64 65 66 uid_t 67 UnpackingLeafNode::UserID() const 68 { 69 if (PackageLeafNode* packageNode = _ActivePackageNode()) 70 return packageNode->UserID(); 71 return 0; 72 } 73 74 75 gid_t 76 UnpackingLeafNode::GroupID() const 77 { 78 if (PackageLeafNode* packageNode = _ActivePackageNode()) 79 return packageNode->GroupID(); 80 return 0; 81 } 82 83 84 timespec 85 UnpackingLeafNode::ModifiedTime() const 86 { 87 if (PackageLeafNode* packageNode = _ActivePackageNode()) 88 return packageNode->ModifiedTime(); 89 90 timespec time = { 0, 0 }; 91 return time; 92 } 93 94 95 off_t 96 UnpackingLeafNode::FileSize() const 97 { 98 if (PackageLeafNode* packageNode = _ActivePackageNode()) { 99 if (S_ISLNK(packageNode->Mode())) 100 return strlen(packageNode->SymlinkPath()); 101 return packageNode->FileSize(); 102 } 103 return 0; 104 } 105 106 107 Node* 108 UnpackingLeafNode::GetNode() 109 { 110 return this; 111 } 112 113 114 status_t 115 UnpackingLeafNode::AddPackageNode(PackageNode* packageNode, dev_t deviceID) 116 { 117 ASSERT(fFinalPackageNode == NULL); 118 119 if (S_ISDIR(packageNode->Mode())) 120 return B_IS_A_DIRECTORY; 121 122 PackageLeafNode* packageLeafNode 123 = dynamic_cast<PackageLeafNode*>(packageNode); 124 125 PackageLeafNode* headNode = fPackageNodes.Head(); 126 bool overridesHead = headNode == NULL 127 || packageLeafNode->HasPrecedenceOver(headNode); 128 129 if (overridesHead) { 130 fPackageNodes.Add(packageLeafNode); 131 NodeReinitVFS(deviceID, fID, packageLeafNode, headNode, fFlags); 132 } else { 133 // add after the head 134 fPackageNodes.RemoveHead(); 135 fPackageNodes.Add(packageLeafNode); 136 fPackageNodes.Add(headNode); 137 } 138 139 return B_OK; 140 } 141 142 143 void 144 UnpackingLeafNode::RemovePackageNode(PackageNode* packageNode, dev_t deviceID) 145 { 146 ASSERT(fFinalPackageNode == NULL); 147 148 bool isNewest = packageNode == fPackageNodes.Head(); 149 fPackageNodes.Remove(dynamic_cast<PackageLeafNode*>(packageNode)); 150 151 // when removing the newest node, we need to find the next node (the list 152 // is not sorted) 153 PackageLeafNode* newestNode = fPackageNodes.Head(); 154 if (isNewest && newestNode != NULL) { 155 PackageLeafNodeList::ConstIterator it = fPackageNodes.GetIterator(); 156 it.Next(); 157 // skip the first one 158 while (PackageLeafNode* otherNode = it.Next()) { 159 if (otherNode->HasPrecedenceOver(newestNode)) 160 newestNode = otherNode; 161 } 162 163 // re-add the newest node to the head 164 fPackageNodes.Remove(newestNode); 165 fPackageNodes.Add(newestNode); 166 NodeReinitVFS(deviceID, fID, newestNode, packageNode, fFlags); 167 } 168 } 169 170 171 PackageNode* 172 UnpackingLeafNode::GetPackageNode() 173 { 174 return _ActivePackageNode(); 175 } 176 177 178 bool 179 UnpackingLeafNode::IsOnlyPackageNode(PackageNode* node) const 180 { 181 ASSERT(fFinalPackageNode == NULL); 182 183 PackageLeafNode* head = fPackageNodes.Head(); 184 return node == head && fPackageNodes.GetNext(head) == NULL; 185 } 186 187 188 bool 189 UnpackingLeafNode::WillBeFirstPackageNode(PackageNode* packageNode) const 190 { 191 PackageLeafNode* packageLeafNode 192 = dynamic_cast<PackageLeafNode*>(packageNode); 193 if (packageLeafNode == NULL) 194 return false; 195 196 PackageLeafNode* headNode = fPackageNodes.Head(); 197 return headNode == NULL 198 || packageLeafNode->HasPrecedenceOver(headNode); 199 } 200 201 void 202 UnpackingLeafNode::PrepareForRemoval() 203 { 204 ASSERT(fFinalPackageNode == NULL); 205 206 fFinalPackageNode = fPackageNodes.Head(); 207 if (fFinalPackageNode != NULL) { 208 fFinalPackageNode->AcquireReference(); 209 fPackageNodes.MakeEmpty(); 210 } 211 } 212 213 214 status_t 215 UnpackingLeafNode::CloneTransferPackageNodes(ino_t id, UnpackingNode*& _newNode) 216 { 217 ASSERT(fFinalPackageNode == NULL); 218 219 UnpackingLeafNode* clone = new UnpackingLeafNode(id); 220 if (clone == NULL) 221 return B_NO_MEMORY; 222 223 status_t error = clone->Init(Name()); 224 if (error != B_OK) { 225 delete clone; 226 return error; 227 } 228 229 // We keep the old head as fFinalPackageNode, which will make us to behave 230 // exactly as before with respect to FS operations. 231 fFinalPackageNode = fPackageNodes.Head(); 232 if (fFinalPackageNode != NULL) { 233 fFinalPackageNode->AcquireReference(); 234 clone->fPackageNodes.MoveFrom(&fPackageNodes); 235 } 236 237 _newNode = clone; 238 return B_OK; 239 } 240 241 242 status_t 243 UnpackingLeafNode::Read(off_t offset, void* buffer, size_t* bufferSize) 244 { 245 if (HasVFSInitError()) 246 return B_ERROR; 247 248 if (PackageLeafNode* packageNode = _ActivePackageNode()) 249 return packageNode->Read(offset, buffer, bufferSize); 250 return B_ERROR; 251 } 252 253 254 status_t 255 UnpackingLeafNode::Read(io_request* request) 256 { 257 if (HasVFSInitError()) 258 return B_ERROR; 259 260 if (PackageLeafNode* packageNode = _ActivePackageNode()) 261 return packageNode->Read(request); 262 return EBADF; 263 } 264 265 266 status_t 267 UnpackingLeafNode::ReadSymlink(void* buffer, size_t* bufferSize) 268 { 269 if (HasVFSInitError()) 270 return B_ERROR; 271 272 PackageLeafNode* packageNode = _ActivePackageNode(); 273 if (packageNode == NULL) 274 return B_BAD_VALUE; 275 276 const String& linkPath = packageNode->SymlinkPath(); 277 if (linkPath[0] == '\0') { 278 *bufferSize = 0; 279 return B_OK; 280 } 281 282 size_t linkLength = strnlen(linkPath, B_PATH_NAME_LENGTH); 283 284 size_t bytesToCopy = std::min(linkLength, *bufferSize); 285 286 *bufferSize = linkLength; 287 288 memcpy(buffer, linkPath, bytesToCopy); 289 return B_OK; 290 } 291 292 293 status_t 294 UnpackingLeafNode::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) 295 { 296 if (HasVFSInitError()) 297 return B_ERROR; 298 299 return UnpackingAttributeDirectoryCookie::Open(_ActivePackageNode(), 300 _cookie); 301 } 302 303 304 status_t 305 UnpackingLeafNode::OpenAttribute(const StringKey& name, int openMode, 306 AttributeCookie*& _cookie) 307 { 308 if (HasVFSInitError()) 309 return B_ERROR; 310 311 return UnpackingAttributeCookie::Open(_ActivePackageNode(), name, openMode, 312 _cookie); 313 } 314 315 316 status_t 317 UnpackingLeafNode::IndexAttribute(AttributeIndexer* indexer) 318 { 319 return UnpackingAttributeCookie::IndexAttribute(_ActivePackageNode(), 320 indexer); 321 } 322 323 324 void* 325 UnpackingLeafNode::IndexCookieForAttribute(const StringKey& name) const 326 { 327 if (PackageLeafNode* packageNode = _ActivePackageNode()) 328 return packageNode->IndexCookieForAttribute(name); 329 return NULL; 330 } 331 332 333 PackageLeafNode* 334 UnpackingLeafNode::_ActivePackageNode() const 335 { 336 if (PackageLeafNode* packageNode = fPackageNodes.Head()) 337 return packageNode; 338 return fFinalPackageNode; 339 } 340