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