1 /* 2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "PackageFSRoot.h" 8 9 #include <AutoDeleter.h> 10 11 #include <vfs.h> 12 13 #include "DebugSupport.h" 14 #include "PackageLinksDirectory.h" 15 #include "StringConstants.h" 16 17 18 //#define TRACE_DEPENDENCIES_ENABLED 19 #ifdef TRACE_DEPENDENCIES_ENABLED 20 # define TRACE_DEPENDENCIES(x...) TPRINT(x) 21 #else 22 # define TRACE_DEPENDENCIES(x...) do {} while (false) 23 #endif 24 25 26 mutex PackageFSRoot::sRootListLock = MUTEX_INITIALIZER("packagefs root list"); 27 PackageFSRoot::RootList PackageFSRoot::sRootList; 28 29 30 PackageFSRoot::PackageFSRoot(dev_t deviceID, ino_t nodeID) 31 : 32 fDeviceID(deviceID), 33 fNodeID(nodeID), 34 fSystemVolume(NULL), 35 fPackageLinksDirectory(NULL) 36 { 37 rw_lock_init(&fLock, "packagefs root"); 38 } 39 40 41 PackageFSRoot::~PackageFSRoot() 42 { 43 if (fPackageLinksDirectory != NULL) 44 fPackageLinksDirectory->ReleaseReference(); 45 46 rw_lock_destroy(&fLock); 47 } 48 49 50 /*static*/ status_t 51 PackageFSRoot::GlobalInit() 52 { 53 return B_OK; 54 } 55 56 57 /*static*/ void 58 PackageFSRoot::GlobalUninit() 59 { 60 } 61 62 63 status_t 64 PackageFSRoot::Init() 65 { 66 // create package links directory 67 fPackageLinksDirectory = new(std::nothrow) PackageLinksDirectory; 68 if (fPackageLinksDirectory == NULL) 69 return B_NO_MEMORY; 70 71 status_t error = fPackageLinksDirectory->Init(NULL, 72 StringConstants::Get().kPackageLinksDirectoryName); 73 if (error != B_OK) 74 RETURN_ERROR(error); 75 76 error = fResolvables.Init(); 77 if (error != B_OK) 78 RETURN_ERROR(error); 79 80 error = fDependencies.Init(); 81 if (error != B_OK) 82 RETURN_ERROR(error); 83 84 return B_OK; 85 } 86 87 88 /*static*/ status_t 89 PackageFSRoot::RegisterVolume(Volume* volume) 90 { 91 // Unless the volume is custom mounted, we stat the supposed root directory. 92 // Get the volume mount point relative path to the root directory depending 93 // on the mount type. 94 const char* relativeRootPath = NULL; 95 96 switch (volume->MountType()) { 97 case PACKAGE_FS_MOUNT_TYPE_SYSTEM: 98 case PACKAGE_FS_MOUNT_TYPE_COMMON: 99 relativeRootPath = ".."; 100 break; 101 case PACKAGE_FS_MOUNT_TYPE_HOME: 102 relativeRootPath = "../.."; 103 break; 104 case PACKAGE_FS_MOUNT_TYPE_CUSTOM: 105 default: 106 break; 107 } 108 109 if (relativeRootPath != NULL) { 110 struct vnode* vnode; 111 status_t error = vfs_entry_ref_to_vnode(volume->MountPointDeviceID(), 112 volume->MountPointNodeID(), relativeRootPath, &vnode); 113 if (error != B_OK) { 114 dprintf("packagefs: Failed to get root directory \"%s\": %s\n", 115 relativeRootPath, strerror(error)); 116 RETURN_ERROR(error); 117 } 118 CObjectDeleter<struct vnode> vnodePutter(vnode, &vfs_put_vnode); 119 120 // stat it 121 struct stat st; 122 error = vfs_stat_vnode(vnode, &st); 123 if (error != B_OK) { 124 dprintf("packagefs: Failed to stat root directory \"%s\": %s\n", 125 relativeRootPath, strerror(error)); 126 RETURN_ERROR(error); 127 } 128 129 // get/create the root 130 PackageFSRoot* root; 131 error = PackageFSRoot::_GetOrCreateRoot(st.st_dev, st.st_ino, root); 132 if (error != B_OK) 133 RETURN_ERROR(error); 134 135 // add the volume 136 error = root->_AddVolume(volume); 137 if (error != B_OK) { 138 _PutRoot(root); 139 RETURN_ERROR(error); 140 } 141 142 return B_OK; 143 } 144 145 // custom mount -- always create a new root 146 PackageFSRoot* root = new(std::nothrow) PackageFSRoot(-1, 0); 147 if (root == NULL) 148 return B_NO_MEMORY; 149 ObjectDeleter<PackageFSRoot> rootDeleter(root); 150 151 status_t error = root->Init(); 152 if (error != B_OK) 153 RETURN_ERROR(error); 154 155 // add the volume 156 error = root->_AddVolume(volume); 157 if (error != B_OK) { 158 _PutRoot(root); 159 RETURN_ERROR(error); 160 } 161 162 // We don't add the root to the list. 163 rootDeleter.Detach(); 164 return B_OK; 165 } 166 167 168 void 169 PackageFSRoot::UnregisterVolume(Volume* volume) 170 { 171 _RemoveVolume(volume); 172 _PutRoot(this); 173 } 174 175 176 status_t 177 PackageFSRoot::AddPackage(Package* package) 178 { 179 PackageFSRootWriteLocker writeLocker(this); 180 181 status_t error = _AddPackage(package); 182 if (error != B_OK) { 183 _RemovePackage(package); 184 RETURN_ERROR(error); 185 } 186 187 return B_OK; 188 } 189 190 191 void 192 PackageFSRoot::RemovePackage(Package* package) 193 { 194 PackageFSRootWriteLocker writeLocker(this); 195 196 _RemovePackage(package); 197 } 198 199 200 Volume* 201 PackageFSRoot::SystemVolume() const 202 { 203 PackageFSRootReadLocker readLocker(this); 204 return fSystemVolume; 205 } 206 207 208 status_t 209 PackageFSRoot::_AddVolume(Volume* volume) 210 { 211 PackageFSRootWriteLocker writeLocker(this); 212 213 volume->SetPackageFSRoot(this); 214 215 fVolumes.Add(volume); 216 // TODO: Correct order? 217 218 if (fSystemVolume == NULL && volume->MountType() 219 == PACKAGE_FS_MOUNT_TYPE_SYSTEM) { 220 fSystemVolume = volume; 221 } 222 223 return B_OK; 224 } 225 226 227 void 228 PackageFSRoot::_RemoveVolume(Volume* volume) 229 { 230 PackageFSRootWriteLocker writeLocker(this); 231 232 if (volume == fSystemVolume) 233 fSystemVolume = NULL; 234 235 fVolumes.Remove(volume); 236 237 volume->SetPackageFSRoot(NULL); 238 } 239 240 241 status_t 242 PackageFSRoot::_AddPackage(Package* package) 243 { 244 TRACE_DEPENDENCIES("adding package \"%s\"\n", package->Name().Data()); 245 246 ResolvableDependencyList dependenciesToUpdate; 247 248 // register resolvables 249 for (ResolvableList::ConstIterator it 250 = package->Resolvables().GetIterator(); 251 Resolvable* resolvable = it.Next();) { 252 TRACE_DEPENDENCIES(" adding resolvable \"%s\"\n", 253 resolvable->Name().Data()); 254 255 if (ResolvableFamily* family 256 = fResolvables.Lookup(resolvable->Name())) { 257 family->AddResolvable(resolvable, dependenciesToUpdate); 258 } else { 259 family = new(std::nothrow) ResolvableFamily; 260 if (family == NULL) 261 return B_NO_MEMORY; 262 263 family->AddResolvable(resolvable, dependenciesToUpdate); 264 fResolvables.Insert(family); 265 266 // add pre-existing dependencies for that resolvable 267 if (DependencyFamily* dependencyFamily 268 = fDependencies.Lookup(resolvable->Name())) { 269 dependencyFamily->AddDependenciesToList(dependenciesToUpdate); 270 } 271 } 272 } 273 274 // register dependencies 275 for (DependencyList::ConstIterator it 276 = package->Dependencies().GetIterator(); 277 Dependency* dependency = it.Next();) { 278 TRACE_DEPENDENCIES(" adding dependency \"%s\"\n", 279 dependency->Name().Data()); 280 281 if (DependencyFamily* family 282 = fDependencies.Lookup(dependency->Name())) { 283 family->AddDependency(dependency); 284 } else { 285 family = new(std::nothrow) DependencyFamily; 286 if (family == NULL) 287 return B_NO_MEMORY; 288 289 family->AddDependency(dependency); 290 fDependencies.Insert(family); 291 } 292 293 dependenciesToUpdate.Add(dependency); 294 } 295 296 status_t error = fPackageLinksDirectory->AddPackage(package); 297 if (error != B_OK) 298 RETURN_ERROR(error); 299 300 _ResolveDependencies(dependenciesToUpdate); 301 302 return B_OK; 303 } 304 305 306 void 307 PackageFSRoot::_RemovePackage(Package* package) 308 { 309 TRACE_DEPENDENCIES("removing package \"%s\"\n", package->Name().Data()); 310 311 fPackageLinksDirectory->RemovePackage(package); 312 313 // unregister dependencies 314 for (DependencyList::ConstIterator it 315 = package->Dependencies().GetIterator(); 316 Dependency* dependency = it.Next();) { 317 if (DependencyFamily* family = dependency->Family()) { 318 TRACE_DEPENDENCIES(" removing dependency \"%s\"\n", 319 dependency->Name().Data()); 320 321 if (family->IsLastDependency(dependency)) { 322 fDependencies.Remove(family); 323 family->RemoveDependency(dependency); 324 delete family; 325 } else 326 family->RemoveDependency(dependency); 327 } 328 329 if (Resolvable* resolvable = dependency->Resolvable()) 330 resolvable->RemoveDependency(dependency); 331 } 332 333 // unregister resolvables 334 ResolvableDependencyList dependenciesToUpdate; 335 336 for (ResolvableList::ConstIterator it 337 = package->Resolvables().GetIterator(); 338 Resolvable* resolvable = it.Next();) { 339 if (ResolvableFamily* family = resolvable->Family()) { 340 TRACE_DEPENDENCIES(" removing resolvable \"%s\"\n", 341 resolvable->Name().Data()); 342 343 if (family->IsLastResolvable(resolvable)) { 344 fResolvables.Remove(family); 345 family->RemoveResolvable(resolvable, dependenciesToUpdate); 346 delete family; 347 } else 348 family->RemoveResolvable(resolvable, dependenciesToUpdate); 349 } 350 } 351 352 _ResolveDependencies(dependenciesToUpdate); 353 } 354 355 356 void 357 PackageFSRoot::_ResolveDependencies(ResolvableDependencyList& dependencies) 358 { 359 if (dependencies.IsEmpty()) 360 return; 361 362 while (Dependency* dependency = dependencies.RemoveHead()) { 363 Package* package = dependency->Package(); 364 _ResolveDependency(dependency); 365 366 // also resolve all other dependencies for that package 367 for (ResolvableDependencyList::Iterator it = dependencies.GetIterator(); 368 (dependency = it.Next()) != NULL;) { 369 if (dependency->Package() == package) { 370 it.Remove(); 371 _ResolveDependency(dependency); 372 } 373 } 374 375 fPackageLinksDirectory->UpdatePackageDependencies(package); 376 } 377 } 378 379 380 void 381 PackageFSRoot::_ResolveDependency(Dependency* dependency) 382 { 383 TRACE_DEPENDENCIES(" resolving dependency \"%s\" (package \"%s\")\n", 384 dependency->Name().Data(), dependency->Package()->Name().Data()); 385 386 // get the resolvable family for the dependency 387 ResolvableFamily* resolvableFamily 388 = fResolvables.Lookup(dependency->Name()); 389 if (resolvableFamily == NULL) { 390 TRACE_DEPENDENCIES(" -> dependency \"%s\" unresolved\n", 391 dependency->Name().Data()); 392 return; 393 } 394 395 // let the family resolve the dependency 396 if (!resolvableFamily->ResolveDependency(dependency)) { 397 TRACE_DEPENDENCIES(" -> dependency \"%s\" unresolved (version " 398 "mismatch)\n", dependency->Name().Data()); 399 } 400 } 401 402 403 /*static*/ status_t 404 PackageFSRoot::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, 405 PackageFSRoot*& _root) 406 { 407 // first check the list, if the root already exists 408 MutexLocker rootListLocker(sRootListLock); 409 410 if (PackageFSRoot* root = _FindRootLocked(deviceID, nodeID)) { 411 root->AcquireReference(); 412 _root = root; 413 return B_OK; 414 } 415 416 rootListLocker.Unlock(); 417 418 // create a new root 419 PackageFSRoot* root = new(std::nothrow) PackageFSRoot(deviceID, nodeID); 420 if (root == NULL) 421 return B_NO_MEMORY; 422 ObjectDeleter<PackageFSRoot> rootDeleter(root); 423 424 status_t error = root->Init(); 425 if (error != B_OK) 426 RETURN_ERROR(error); 427 428 // add the root -- first recheck whether someone else added the root in the 429 // meantime 430 rootListLocker.Lock(); 431 432 if (PackageFSRoot* otherRoot = _FindRootLocked(deviceID, nodeID)) { 433 // indeed, someone was faster 434 otherRoot->AcquireReference(); 435 _root = otherRoot; 436 return B_OK; 437 } 438 439 sRootList.Add(root); 440 441 _root = rootDeleter.Detach(); 442 return B_OK; 443 } 444 445 446 /*static*/ PackageFSRoot* 447 PackageFSRoot::_FindRootLocked(dev_t deviceID, ino_t nodeID) 448 { 449 for (RootList::Iterator it = sRootList.GetIterator(); 450 PackageFSRoot* root = it.Next();) { 451 if (root->DeviceID() == deviceID && root->NodeID() == nodeID) 452 return root; 453 } 454 455 return NULL; 456 } 457 458 459 /*static*/ void 460 PackageFSRoot::_PutRoot(PackageFSRoot* root) 461 { 462 // Only non-custom roots are in the global list. 463 if (!root->IsCustom()) { 464 MutexLocker rootListLocker(sRootListLock); 465 466 // When releasing the last reference, remove the root from the list. 467 if (root->CountReferences() == 1) 468 sRootList.Remove(root); 469 470 rootListLocker.Unlock(); 471 } 472 473 root->ReleaseReference(); 474 } 475