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