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