xref: /haiku/src/add-ons/kernel/file_systems/packagefs/volume/PackagesDirectory.cpp (revision ab4411e89a079bc0a40d901995f3418d998c51b3)
1 /*
2  * Copyright 2009-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "PackagesDirectory.h"
8 
9 #include <errno.h>
10 
11 #include <fs/KPath.h>
12 #include <team.h>
13 #include <vfs.h>
14 
15 #include "DebugSupport.h"
16 
17 
18 PackagesDirectory::PackagesDirectory()
19 	:
20 	fStateName(),
21 	fPath(NULL),
22 	fDirFD(-1),
23 	fNodeRef(),
24 	fHashNext(NULL)
25 {
26 }
27 
28 
29 PackagesDirectory::~PackagesDirectory()
30 {
31 	if (fDirFD >= 0)
32 		close(fDirFD);
33 
34 	free(fPath);
35 }
36 
37 
38 /*static*/ bool
39 PackagesDirectory::IsNewer(const PackagesDirectory* a,
40 	const PackagesDirectory* b)
41 {
42 	if (b->fStateName.IsEmpty())
43 		return false;
44 	if (a->fStateName.IsEmpty())
45 		return true;
46 	return strcmp(a->fStateName, b->fStateName) > 0;
47 }
48 
49 
50 status_t
51 PackagesDirectory::Init(const char* path, dev_t mountPointDeviceID,
52 	ino_t mountPointNodeID, struct stat& _st)
53 {
54 	// Open the directory. We want the path be interpreted depending on from
55 	// where it came (kernel or userland), but we always want a FD in the
56 	// kernel I/O context. There's no VFS service method to do that for us,
57 	// so we need to do that ourselves.
58 	bool calledFromKernel
59 		= team_get_current_team_id() == team_get_kernel_team_id();
60 		// Not entirely correct, but good enough for now. The only
61 		// alternative is to have that information passed in as well.
62 
63 	struct vnode* vnode;
64 	status_t error;
65 	if (path != NULL) {
66 		error = vfs_get_vnode_from_path(path, calledFromKernel, &vnode);
67 	} else {
68 		// No path given -- use the "packages" directory at our mount point.
69 		error = vfs_entry_ref_to_vnode(mountPointDeviceID, mountPointNodeID,
70 			"packages", &vnode);
71 	}
72 	if (error != B_OK) {
73 		ERROR("Failed to open packages directory \"%s\"\n", strerror(error));
74 		RETURN_ERROR(error);
75 	}
76 
77 	return _Init(vnode, _st);
78 }
79 
80 
81 status_t
82 PackagesDirectory::InitOldState(dev_t adminDirDeviceID, ino_t adminDirNodeID,
83 	const char* stateName)
84 {
85 	if (!fStateName.SetTo(stateName))
86 		RETURN_ERROR(B_NO_MEMORY);
87 
88 	struct vnode* vnode;
89 	status_t error = vfs_entry_ref_to_vnode(adminDirDeviceID, adminDirNodeID,
90 		stateName, &vnode);
91 	if (error != B_OK) {
92 		ERROR("Failed to open old state directory \"%s\"\n", strerror(error));
93 		RETURN_ERROR(error);
94 	}
95 
96 	struct stat st;
97 	return _Init(vnode, st);
98 }
99 
100 
101 status_t
102 PackagesDirectory::_Init(struct vnode* vnode, struct stat& _st)
103 {
104 	fDirFD = vfs_open_vnode(vnode, O_RDONLY, true);
105 
106 	if (fDirFD < 0) {
107 		ERROR("Failed to open packages directory \"%s\"\n", strerror(fDirFD));
108 		vfs_put_vnode(vnode);
109 		RETURN_ERROR(fDirFD);
110 	}
111 	// Our vnode reference has been transferred to the FD.
112 
113 	// Is it a directory at all?
114 	struct stat& st = _st;
115 	if (fstat(fDirFD, &st) < 0)
116 		RETURN_ERROR(errno);
117 
118 	fNodeRef.device = st.st_dev;
119 	fNodeRef.node = st.st_ino;
120 
121 	// get a normalized path
122 	KPath normalizedPath;
123 	if (normalizedPath.InitCheck() != B_OK)
124 		RETURN_ERROR(normalizedPath.InitCheck());
125 
126 	char* normalizedPathBuffer = normalizedPath.LockBuffer();
127 	status_t error = vfs_entry_ref_to_path(fNodeRef.device, fNodeRef.node, NULL,
128 		true, normalizedPathBuffer, normalizedPath.BufferSize());
129 	if (error != B_OK)
130 		RETURN_ERROR(error);
131 
132 	fPath = strdup(normalizedPathBuffer);
133 	if (fPath == NULL)
134 		RETURN_ERROR(B_NO_MEMORY);
135 
136 	return B_OK;
137 }
138