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