xref: /haiku/src/add-ons/kernel/file_systems/packagefs/volume/PackageFSRoot.cpp (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
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