xref: /haiku/src/add-ons/kernel/file_systems/packagefs/volume/PackageFSRoot.cpp (revision f73f5d4c42a01ece688cbb57b5d332cc0f68b2c6)
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 #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(NULL,
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 		case PACKAGE_FS_MOUNT_TYPE_COMMON:
99 			relativeRootPath = "..";
100 			break;
101 		case PACKAGE_FS_MOUNT_TYPE_HOME:
102 			relativeRootPath = "../..";
103 			break;
104 		case PACKAGE_FS_MOUNT_TYPE_CUSTOM:
105 		default:
106 			break;
107 	}
108 
109 	if (relativeRootPath != NULL) {
110 		struct vnode* vnode;
111 		status_t error = vfs_entry_ref_to_vnode(volume->MountPointDeviceID(),
112 			volume->MountPointNodeID(), relativeRootPath, &vnode);
113 		if (error != B_OK) {
114 			dprintf("packagefs: Failed to get root directory \"%s\": %s\n",
115 				relativeRootPath, strerror(error));
116 			RETURN_ERROR(error);
117 		}
118 		CObjectDeleter<struct vnode> vnodePutter(vnode, &vfs_put_vnode);
119 
120 		// stat it
121 		struct stat st;
122 		error = vfs_stat_vnode(vnode, &st);
123 		if (error != B_OK) {
124 			dprintf("packagefs: Failed to stat root directory \"%s\": %s\n",
125 				relativeRootPath, strerror(error));
126 			RETURN_ERROR(error);
127 		}
128 
129 		// get/create the root
130 		PackageFSRoot* root;
131 		error = PackageFSRoot::_GetOrCreateRoot(st.st_dev, st.st_ino, root);
132 		if (error != B_OK)
133 			RETURN_ERROR(error);
134 
135 		// add the volume
136 		error = root->_AddVolume(volume);
137 		if (error != B_OK) {
138 			_PutRoot(root);
139 			RETURN_ERROR(error);
140 		}
141 
142 		return B_OK;
143 	}
144 
145 	// custom mount -- always create a new root
146 	PackageFSRoot* root = new(std::nothrow) PackageFSRoot(-1, 0);
147 	if (root == NULL)
148 		return B_NO_MEMORY;
149 	ObjectDeleter<PackageFSRoot> rootDeleter(root);
150 
151 	status_t error = root->Init();
152 	if (error != B_OK)
153 		RETURN_ERROR(error);
154 
155 	// add the volume
156 	error = root->_AddVolume(volume);
157 	if (error != B_OK) {
158 		_PutRoot(root);
159 		RETURN_ERROR(error);
160 	}
161 
162 	// We don't add the root to the list.
163 	rootDeleter.Detach();
164 	return B_OK;
165 }
166 
167 
168 void
169 PackageFSRoot::UnregisterVolume(Volume* volume)
170 {
171 	_RemoveVolume(volume);
172 	_PutRoot(this);
173 }
174 
175 
176 status_t
177 PackageFSRoot::AddPackage(Package* package)
178 {
179 	PackageFSRootWriteLocker writeLocker(this);
180 
181 	status_t error = _AddPackage(package);
182 	if (error != B_OK) {
183 		_RemovePackage(package);
184 		RETURN_ERROR(error);
185 	}
186 
187 	return B_OK;
188 }
189 
190 
191 void
192 PackageFSRoot::RemovePackage(Package* package)
193 {
194 	PackageFSRootWriteLocker writeLocker(this);
195 
196 	_RemovePackage(package);
197 }
198 
199 
200 Volume*
201 PackageFSRoot::SystemVolume() const
202 {
203 	PackageFSRootReadLocker readLocker(this);
204 	return fSystemVolume;
205 }
206 
207 
208 status_t
209 PackageFSRoot::_AddVolume(Volume* volume)
210 {
211 	PackageFSRootWriteLocker writeLocker(this);
212 
213 	volume->SetPackageFSRoot(this);
214 
215 	fVolumes.Add(volume);
216 		// TODO: Correct order?
217 
218 	if (fSystemVolume == NULL && volume->MountType()
219 			== PACKAGE_FS_MOUNT_TYPE_SYSTEM) {
220 		fSystemVolume = volume;
221 	}
222 
223 	return B_OK;
224 }
225 
226 
227 void
228 PackageFSRoot::_RemoveVolume(Volume* volume)
229 {
230 	PackageFSRootWriteLocker writeLocker(this);
231 
232 	if (volume == fSystemVolume)
233 		fSystemVolume = NULL;
234 
235 	fVolumes.Remove(volume);
236 
237 	volume->SetPackageFSRoot(NULL);
238 }
239 
240 
241 status_t
242 PackageFSRoot::_AddPackage(Package* package)
243 {
244 	TRACE_DEPENDENCIES("adding package \"%s\"\n", package->Name().Data());
245 
246 	ResolvableDependencyList dependenciesToUpdate;
247 
248 	// register resolvables
249 	for (ResolvableList::ConstIterator it
250 				= package->Resolvables().GetIterator();
251 			Resolvable* resolvable = it.Next();) {
252 		TRACE_DEPENDENCIES("  adding resolvable \"%s\"\n",
253 			resolvable->Name().Data());
254 
255 		if (ResolvableFamily* family
256 				= fResolvables.Lookup(resolvable->Name())) {
257 			family->AddResolvable(resolvable, dependenciesToUpdate);
258 		} else {
259 			family = new(std::nothrow) ResolvableFamily;
260 			if (family == NULL)
261 				return B_NO_MEMORY;
262 
263 			family->AddResolvable(resolvable, dependenciesToUpdate);
264 			fResolvables.Insert(family);
265 
266 			// add pre-existing dependencies for that resolvable
267 			if (DependencyFamily* dependencyFamily
268 					= fDependencies.Lookup(resolvable->Name())) {
269 				dependencyFamily->AddDependenciesToList(dependenciesToUpdate);
270 			}
271 		}
272 	}
273 
274 	// register dependencies
275 	for (DependencyList::ConstIterator it
276 				= package->Dependencies().GetIterator();
277 			Dependency* dependency = it.Next();) {
278 		TRACE_DEPENDENCIES("  adding dependency \"%s\"\n",
279 			dependency->Name().Data());
280 
281 		if (DependencyFamily* family
282 				= fDependencies.Lookup(dependency->Name())) {
283 			family->AddDependency(dependency);
284 		} else {
285 			family = new(std::nothrow) DependencyFamily;
286 			if (family == NULL)
287 				return B_NO_MEMORY;
288 
289 			family->AddDependency(dependency);
290 			fDependencies.Insert(family);
291 		}
292 
293 		dependenciesToUpdate.Add(dependency);
294 	}
295 
296 	status_t error = fPackageLinksDirectory->AddPackage(package);
297 	if (error != B_OK)
298 		RETURN_ERROR(error);
299 
300 	_ResolveDependencies(dependenciesToUpdate);
301 
302 	return B_OK;
303 }
304 
305 
306 void
307 PackageFSRoot::_RemovePackage(Package* package)
308 {
309 	TRACE_DEPENDENCIES("removing package \"%s\"\n", package->Name().Data());
310 
311 	fPackageLinksDirectory->RemovePackage(package);
312 
313 	// unregister dependencies
314 	for (DependencyList::ConstIterator it
315 				= package->Dependencies().GetIterator();
316 			Dependency* dependency = it.Next();) {
317 		if (DependencyFamily* family = dependency->Family()) {
318 			TRACE_DEPENDENCIES("  removing dependency \"%s\"\n",
319 				dependency->Name().Data());
320 
321 			if (family->IsLastDependency(dependency)) {
322 				fDependencies.Remove(family);
323 				family->RemoveDependency(dependency);
324 				delete family;
325 			} else
326 				family->RemoveDependency(dependency);
327 		}
328 
329 		if (Resolvable* resolvable = dependency->Resolvable())
330 			resolvable->RemoveDependency(dependency);
331 	}
332 
333 	// unregister resolvables
334 	ResolvableDependencyList dependenciesToUpdate;
335 
336 	for (ResolvableList::ConstIterator it
337 				= package->Resolvables().GetIterator();
338 			Resolvable* resolvable = it.Next();) {
339 		if (ResolvableFamily* family = resolvable->Family()) {
340 			TRACE_DEPENDENCIES("  removing resolvable \"%s\"\n",
341 				resolvable->Name().Data());
342 
343 			if (family->IsLastResolvable(resolvable)) {
344 				fResolvables.Remove(family);
345 				family->RemoveResolvable(resolvable, dependenciesToUpdate);
346 				delete family;
347 			} else
348 				family->RemoveResolvable(resolvable, dependenciesToUpdate);
349 		}
350 	}
351 
352 	_ResolveDependencies(dependenciesToUpdate);
353 }
354 
355 
356 void
357 PackageFSRoot::_ResolveDependencies(ResolvableDependencyList& dependencies)
358 {
359 	if (dependencies.IsEmpty())
360 		return;
361 
362 	while (Dependency* dependency = dependencies.RemoveHead()) {
363 		Package* package = dependency->Package();
364 		_ResolveDependency(dependency);
365 
366 		// also resolve all other dependencies for that package
367 		for (ResolvableDependencyList::Iterator it = dependencies.GetIterator();
368 				(dependency = it.Next()) != NULL;) {
369 			if (dependency->Package() == package) {
370 				it.Remove();
371 				_ResolveDependency(dependency);
372 			}
373 		}
374 
375 		fPackageLinksDirectory->UpdatePackageDependencies(package);
376 	}
377 }
378 
379 
380 void
381 PackageFSRoot::_ResolveDependency(Dependency* dependency)
382 {
383 	TRACE_DEPENDENCIES("  resolving dependency \"%s\" (package \"%s\")\n",
384 		dependency->Name().Data(), dependency->Package()->Name().Data());
385 
386 	// get the resolvable family for the dependency
387 	ResolvableFamily* resolvableFamily
388 		= fResolvables.Lookup(dependency->Name());
389 	if (resolvableFamily == NULL) {
390 		TRACE_DEPENDENCIES("    -> dependency \"%s\" unresolved\n",
391 			dependency->Name().Data());
392 		return;
393 	}
394 
395 	// let the family resolve the dependency
396 	if (!resolvableFamily->ResolveDependency(dependency)) {
397 		TRACE_DEPENDENCIES("    -> dependency \"%s\" unresolved (version "
398 			"mismatch)\n", dependency->Name().Data());
399 	}
400 }
401 
402 
403 /*static*/ status_t
404 PackageFSRoot::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID,
405 	PackageFSRoot*& _root)
406 {
407 	// first check the list, if the root already exists
408 	MutexLocker rootListLocker(sRootListLock);
409 
410 	if (PackageFSRoot* root = _FindRootLocked(deviceID, nodeID)) {
411 		root->AcquireReference();
412 		_root = root;
413 		return B_OK;
414 	}
415 
416 	rootListLocker.Unlock();
417 
418 	// create a new root
419 	PackageFSRoot* root = new(std::nothrow) PackageFSRoot(deviceID, nodeID);
420 	if (root == NULL)
421 		return B_NO_MEMORY;
422 	ObjectDeleter<PackageFSRoot> rootDeleter(root);
423 
424 	status_t error = root->Init();
425 	if (error != B_OK)
426 		RETURN_ERROR(error);
427 
428 	// add the root -- first recheck whether someone else added the root in the
429 	// meantime
430 	rootListLocker.Lock();
431 
432 	if (PackageFSRoot* otherRoot = _FindRootLocked(deviceID, nodeID)) {
433 		// indeed, someone was faster
434 		otherRoot->AcquireReference();
435 		_root = otherRoot;
436 		return B_OK;
437 	}
438 
439 	sRootList.Add(root);
440 
441 	_root = rootDeleter.Detach();
442 	return B_OK;
443 }
444 
445 
446 /*static*/ PackageFSRoot*
447 PackageFSRoot::_FindRootLocked(dev_t deviceID, ino_t nodeID)
448 {
449 	for (RootList::Iterator it = sRootList.GetIterator();
450 			PackageFSRoot* root = it.Next();) {
451 		if (root->DeviceID() == deviceID && root->NodeID() == nodeID)
452 			return root;
453 	}
454 
455 	return NULL;
456 }
457 
458 
459 /*static*/ void
460 PackageFSRoot::_PutRoot(PackageFSRoot* root)
461 {
462 	// Only non-custom roots are in the global list.
463 	if (!root->IsCustom()) {
464 		MutexLocker rootListLocker(sRootListLock);
465 
466 		// When releasing the last reference, remove the root from the list.
467 		if (root->CountReferences() == 1)
468 			sRootList.Remove(root);
469 
470 		rootListLocker.Unlock();
471 	}
472 
473 	root->ReleaseReference();
474 }
475