1/* 2 * Copyright 2009-2011, 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 = B_OK; 38 if (PackageLeafNode* packageNode = _ActivePackageNode()) 39 error = packageNode->VFSInit(deviceID, fID); 40 41 if (error == B_OK) 42 Node::VFSInit(deviceID); 43 44 return error; 45} 46 47 48void 49UnpackingLeafNode::VFSUninit() 50{ 51 if (PackageLeafNode* packageNode = _ActivePackageNode()) 52 packageNode->VFSUninit(); 53 54 Node::VFSUninit(); 55} 56 57 58mode_t 59UnpackingLeafNode::Mode() const 60{ 61 if (PackageLeafNode* packageNode = _ActivePackageNode()) 62 return packageNode->Mode(); 63 return S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; 64} 65 66 67uid_t 68UnpackingLeafNode::UserID() const 69{ 70 if (PackageLeafNode* packageNode = _ActivePackageNode()) 71 return packageNode->UserID(); 72 return 0; 73} 74 75 76gid_t 77UnpackingLeafNode::GroupID() const 78{ 79 if (PackageLeafNode* packageNode = _ActivePackageNode()) 80 return packageNode->GroupID(); 81 return 0; 82} 83 84 85timespec 86UnpackingLeafNode::ModifiedTime() const 87{ 88 if (PackageLeafNode* packageNode = _ActivePackageNode()) 89 return packageNode->ModifiedTime(); 90 91 timespec time = { 0, 0 }; 92 return time; 93} 94 95 96off_t 97UnpackingLeafNode::FileSize() const 98{ 99 if (PackageLeafNode* packageNode = _ActivePackageNode()) 100 return packageNode->FileSize(); 101 return 0; 102} 103 104 105Node* 106UnpackingLeafNode::GetNode() 107{ 108 return this; 109} 110 111 112status_t 113UnpackingLeafNode::AddPackageNode(PackageNode* packageNode) 114{ 115 ASSERT(fFinalPackageNode == NULL); 116 117 if (S_ISDIR(packageNode->Mode())) 118 return B_BAD_VALUE; 119 120 PackageLeafNode* packageLeafNode 121 = dynamic_cast<PackageLeafNode*>(packageNode); 122 123 PackageLeafNode* headNode = fPackageNodes.Head(); 124 bool isNewest = headNode == NULL 125 || packageLeafNode->ModifiedTime() > headNode->ModifiedTime(); 126 127 if (isNewest) { 128 fPackageNodes.Add(packageLeafNode); 129 } else { 130 // add after the head 131 fPackageNodes.RemoveHead(); 132 fPackageNodes.Add(packageLeafNode); 133 fPackageNodes.Add(headNode); 134 } 135 136 return B_OK; 137} 138 139 140void 141UnpackingLeafNode::RemovePackageNode(PackageNode* packageNode) 142{ 143 ASSERT(fFinalPackageNode == NULL); 144 145 bool isNewest = packageNode == fPackageNodes.Head(); 146 fPackageNodes.Remove(dynamic_cast<PackageLeafNode*>(packageNode)); 147 148 // when removing the newest node, we need to find the next node (the list 149 // is not sorted) 150 PackageLeafNode* newestNode = fPackageNodes.Head(); 151 if (isNewest && newestNode != NULL) { 152 PackageLeafNodeList::Iterator it = fPackageNodes.GetIterator(); 153 it.Next(); 154 // skip the first one 155 while (PackageLeafNode* otherNode = it.Next()) { 156 if (otherNode->ModifiedTime() > newestNode->ModifiedTime()) 157 newestNode = otherNode; 158 } 159 160 // re-add the newest node to the head 161 fPackageNodes.Remove(newestNode); 162 fPackageNodes.Add(newestNode); 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->ModifiedTime() > headNode->ModifiedTime(); 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(), 0); 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 (PackageLeafNode* packageNode = _ActivePackageNode()) 242 return packageNode->Read(offset, buffer, bufferSize); 243 return B_ERROR; 244} 245 246 247status_t 248UnpackingLeafNode::Read(io_request* request) 249{ 250 if (PackageLeafNode* packageNode = _ActivePackageNode()) 251 return packageNode->Read(request); 252 return EBADF; 253} 254 255 256status_t 257UnpackingLeafNode::ReadSymlink(void* buffer, size_t* bufferSize) 258{ 259 PackageLeafNode* packageNode = _ActivePackageNode(); 260 if (packageNode == NULL) 261 return B_BAD_VALUE; 262 263 const char* linkPath = packageNode->SymlinkPath(); 264 if (linkPath == NULL) { 265 *bufferSize = 0; 266 return B_OK; 267 } 268 269 size_t toCopy = std::min(strlen(linkPath), *bufferSize); 270 memcpy(buffer, linkPath, toCopy); 271 *bufferSize = toCopy; 272 273 return B_OK; 274} 275 276 277status_t 278UnpackingLeafNode::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) 279{ 280 return UnpackingAttributeDirectoryCookie::Open(_ActivePackageNode(), 281 _cookie); 282} 283 284 285status_t 286UnpackingLeafNode::OpenAttribute(const char* name, int openMode, 287 AttributeCookie*& _cookie) 288{ 289 return UnpackingAttributeCookie::Open(_ActivePackageNode(), name, openMode, 290 _cookie); 291} 292 293 294status_t 295UnpackingLeafNode::IndexAttribute(AttributeIndexer* indexer) 296{ 297 return UnpackingAttributeCookie::IndexAttribute(_ActivePackageNode(), 298 indexer); 299} 300 301 302void* 303UnpackingLeafNode::IndexCookieForAttribute(const char* name) const 304{ 305 if (PackageLeafNode* packageNode = _ActivePackageNode()) 306 return packageNode->IndexCookieForAttribute(name); 307 return NULL; 308} 309 310 311PackageLeafNode* 312UnpackingLeafNode::_ActivePackageNode() const 313{ 314 if (PackageLeafNode* packageNode = fPackageNodes.Head()) 315 return packageNode; 316 return fFinalPackageNode; 317} 318