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
PackageFSRoot(dev_t deviceID,ino_t nodeID)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
~PackageFSRoot()41 PackageFSRoot::~PackageFSRoot()
42 {
43 if (fPackageLinksDirectory != NULL)
44 fPackageLinksDirectory->ReleaseReference();
45
46 rw_lock_destroy(&fLock);
47 }
48
49
50 /*static*/ status_t
GlobalInit()51 PackageFSRoot::GlobalInit()
52 {
53 return B_OK;
54 }
55
56
57 /*static*/ void
GlobalUninit()58 PackageFSRoot::GlobalUninit()
59 {
60 }
61
62
63 status_t
Init()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
RegisterVolume(Volume * volume)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
UnregisterVolume(Volume * volume)168 PackageFSRoot::UnregisterVolume(Volume* volume)
169 {
170 _RemoveVolume(volume);
171 _PutRoot(this);
172 }
173
174
175 status_t
AddPackage(Package * package)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
RemovePackage(Package * package)191 PackageFSRoot::RemovePackage(Package* package)
192 {
193 PackageFSRootWriteLocker writeLocker(this);
194
195 _RemovePackage(package);
196 }
197
198
199 Volume*
SystemVolume() const200 PackageFSRoot::SystemVolume() const
201 {
202 PackageFSRootReadLocker readLocker(this);
203 return fSystemVolume;
204 }
205
206
207 status_t
_AddVolume(Volume * volume)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
_RemoveVolume(Volume * volume)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
_AddPackage(Package * package)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
_RemovePackage(Package * package)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
_ResolveDependencies(ResolvableDependencyList & dependencies)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
_ResolveDependency(Dependency * dependency)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
_GetOrCreateRoot(dev_t deviceID,ino_t nodeID,PackageFSRoot * & _root)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*
_FindRootLocked(dev_t deviceID,ino_t nodeID)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
_PutRoot(PackageFSRoot * root)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