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 <AutoDeleterDrivers.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( 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 relativeRootPath = ".."; 99 break; 100 case PACKAGE_FS_MOUNT_TYPE_HOME: 101 relativeRootPath = "../.."; 102 break; 103 case PACKAGE_FS_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 VnodePutter vnodePutter(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 167 void 168 PackageFSRoot::UnregisterVolume(Volume* volume) 169 { 170 _RemoveVolume(volume); 171 _PutRoot(this); 172 } 173 174 175 status_t 176 PackageFSRoot::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 190 void 191 PackageFSRoot::RemovePackage(Package* package) 192 { 193 PackageFSRootWriteLocker writeLocker(this); 194 195 _RemovePackage(package); 196 } 197 198 199 Volume* 200 PackageFSRoot::SystemVolume() const 201 { 202 PackageFSRootReadLocker readLocker(this); 203 return fSystemVolume; 204 } 205 206 207 status_t 208 PackageFSRoot::_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() 218 == PACKAGE_FS_MOUNT_TYPE_SYSTEM) { 219 fSystemVolume = volume; 220 } 221 222 return B_OK; 223 } 224 225 226 void 227 PackageFSRoot::_RemoveVolume(Volume* volume) 228 { 229 PackageFSRootWriteLocker writeLocker(this); 230 231 if (volume == fSystemVolume) 232 fSystemVolume = NULL; 233 234 fVolumes.Remove(volume); 235 236 volume->SetPackageFSRoot(NULL); 237 } 238 239 240 status_t 241 PackageFSRoot::_AddPackage(Package* package) 242 { 243 TRACE_DEPENDENCIES("adding package \"%s\"\n", package->Name().Data()); 244 245 ResolvableDependencyList dependenciesToUpdate; 246 247 // register resolvables 248 for (ResolvableList::ConstIterator it 249 = package->Resolvables().GetIterator(); 250 Resolvable* resolvable = it.Next();) { 251 TRACE_DEPENDENCIES(" adding resolvable \"%s\"\n", 252 resolvable->Name().Data()); 253 254 if (ResolvableFamily* family 255 = fResolvables.Lookup(resolvable->Name())) { 256 family->AddResolvable(resolvable, dependenciesToUpdate); 257 } else { 258 family = new(std::nothrow) ResolvableFamily; 259 if (family == NULL) 260 return B_NO_MEMORY; 261 262 family->AddResolvable(resolvable, dependenciesToUpdate); 263 fResolvables.Insert(family); 264 265 // add pre-existing dependencies for that resolvable 266 if (DependencyFamily* dependencyFamily 267 = fDependencies.Lookup(resolvable->Name())) { 268 dependencyFamily->AddDependenciesToList(dependenciesToUpdate); 269 } 270 } 271 } 272 273 // register dependencies 274 for (DependencyList::ConstIterator it 275 = package->Dependencies().GetIterator(); 276 Dependency* dependency = it.Next();) { 277 TRACE_DEPENDENCIES(" adding dependency \"%s\"\n", 278 dependency->Name().Data()); 279 280 if (DependencyFamily* family 281 = fDependencies.Lookup(dependency->Name())) { 282 family->AddDependency(dependency); 283 } else { 284 family = new(std::nothrow) DependencyFamily; 285 if (family == NULL) 286 return B_NO_MEMORY; 287 288 family->AddDependency(dependency); 289 fDependencies.Insert(family); 290 } 291 292 dependenciesToUpdate.Add(dependency); 293 } 294 295 status_t error = fPackageLinksDirectory->AddPackage(package); 296 if (error != B_OK) 297 RETURN_ERROR(error); 298 299 _ResolveDependencies(dependenciesToUpdate); 300 301 return B_OK; 302 } 303 304 305 void 306 PackageFSRoot::_RemovePackage(Package* package) 307 { 308 TRACE_DEPENDENCIES("removing package \"%s\"\n", package->Name().Data()); 309 310 fPackageLinksDirectory->RemovePackage(package); 311 312 // unregister dependencies 313 for (DependencyList::ConstIterator it 314 = package->Dependencies().GetIterator(); 315 Dependency* dependency = it.Next();) { 316 if (DependencyFamily* family = dependency->Family()) { 317 TRACE_DEPENDENCIES(" removing dependency \"%s\"\n", 318 dependency->Name().Data()); 319 320 if (family->IsLastDependency(dependency)) { 321 fDependencies.Remove(family); 322 family->RemoveDependency(dependency); 323 delete family; 324 } else 325 family->RemoveDependency(dependency); 326 } 327 328 if (Resolvable* resolvable = dependency->Resolvable()) 329 resolvable->RemoveDependency(dependency); 330 } 331 332 // unregister resolvables 333 ResolvableDependencyList dependenciesToUpdate; 334 335 for (ResolvableList::ConstIterator it 336 = package->Resolvables().GetIterator(); 337 Resolvable* resolvable = it.Next();) { 338 if (ResolvableFamily* family = resolvable->Family()) { 339 TRACE_DEPENDENCIES(" removing resolvable \"%s\"\n", 340 resolvable->Name().Data()); 341 342 if (family->IsLastResolvable(resolvable)) { 343 fResolvables.Remove(family); 344 family->RemoveResolvable(resolvable, dependenciesToUpdate); 345 delete family; 346 } else 347 family->RemoveResolvable(resolvable, dependenciesToUpdate); 348 } 349 } 350 351 _ResolveDependencies(dependenciesToUpdate); 352 } 353 354 355 void 356 PackageFSRoot::_ResolveDependencies(ResolvableDependencyList& dependencies) 357 { 358 if (dependencies.IsEmpty()) 359 return; 360 361 while (Dependency* dependency = dependencies.RemoveHead()) { 362 Package* package = dependency->Package(); 363 _ResolveDependency(dependency); 364 365 // also resolve all other dependencies for that package 366 for (ResolvableDependencyList::Iterator it = dependencies.GetIterator(); 367 (dependency = it.Next()) != NULL;) { 368 if (dependency->Package() == package) { 369 it.Remove(); 370 _ResolveDependency(dependency); 371 } 372 } 373 374 fPackageLinksDirectory->UpdatePackageDependencies(package); 375 } 376 } 377 378 379 void 380 PackageFSRoot::_ResolveDependency(Dependency* dependency) 381 { 382 TRACE_DEPENDENCIES(" resolving dependency \"%s\" (package \"%s\")\n", 383 dependency->Name().Data(), dependency->Package()->Name().Data()); 384 385 // get the resolvable family for the dependency 386 ResolvableFamily* resolvableFamily 387 = fResolvables.Lookup(dependency->Name()); 388 if (resolvableFamily == NULL) { 389 TRACE_DEPENDENCIES(" -> dependency \"%s\" unresolved\n", 390 dependency->Name().Data()); 391 return; 392 } 393 394 // let the family resolve the dependency 395 if (!resolvableFamily->ResolveDependency(dependency)) { 396 TRACE_DEPENDENCIES(" -> dependency \"%s\" unresolved (version " 397 "mismatch)\n", dependency->Name().Data()); 398 } 399 } 400 401 402 /*static*/ status_t 403 PackageFSRoot::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, 404 PackageFSRoot*& _root) 405 { 406 // first check the list, if the root already exists 407 MutexLocker rootListLocker(sRootListLock); 408 409 if (PackageFSRoot* root = _FindRootLocked(deviceID, nodeID)) { 410 root->AcquireReference(); 411 _root = root; 412 return B_OK; 413 } 414 415 rootListLocker.Unlock(); 416 417 // create a new root 418 PackageFSRoot* root = new(std::nothrow) PackageFSRoot(deviceID, nodeID); 419 if (root == NULL) 420 return B_NO_MEMORY; 421 ObjectDeleter<PackageFSRoot> rootDeleter(root); 422 423 status_t error = root->Init(); 424 if (error != B_OK) 425 RETURN_ERROR(error); 426 427 // add the root -- first recheck whether someone else added the root in the 428 // meantime 429 rootListLocker.Lock(); 430 431 if (PackageFSRoot* otherRoot = _FindRootLocked(deviceID, nodeID)) { 432 // indeed, someone was faster 433 otherRoot->AcquireReference(); 434 _root = otherRoot; 435 return B_OK; 436 } 437 438 sRootList.Add(root); 439 440 _root = rootDeleter.Detach(); 441 return B_OK; 442 } 443 444 445 /*static*/ PackageFSRoot* 446 PackageFSRoot::_FindRootLocked(dev_t deviceID, ino_t nodeID) 447 { 448 for (RootList::Iterator it = sRootList.GetIterator(); 449 PackageFSRoot* root = it.Next();) { 450 if (root->DeviceID() == deviceID && root->NodeID() == nodeID) 451 return root; 452 } 453 454 return NULL; 455 } 456 457 458 /*static*/ void 459 PackageFSRoot::_PutRoot(PackageFSRoot* root) 460 { 461 // Only non-custom roots are in the global list. 462 if (!root->IsCustom()) { 463 MutexLocker rootListLocker(sRootListLock); 464 465 // When releasing the last reference, remove the root from the list. 466 if (root->CountReferences() == 1) 467 sRootList.Remove(root); 468 469 rootListLocker.Unlock(); 470 } 471 472 root->ReleaseReference(); 473 } 474