xref: /haiku/src/kits/package/PackageRoster.cpp (revision 1b6bc2675fe3691538c8764ab016593f3b06ca53)
1 /*
2  * Copyright 2011, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Oliver Tappe <zooey@hirschkaefer.de>
7  */
8 
9 
10 #include <package/PackageRoster.h>
11 
12 #include <errno.h>
13 #include <sys/stat.h>
14 
15 #include <Directory.h>
16 #include <Entry.h>
17 #include <Path.h>
18 #include <String.h>
19 #include <StringList.h>
20 
21 #include <package/PackageInfo.h>
22 #include <package/PackageInfoContentHandler.h>
23 #include <package/PackageInfoSet.h>
24 #include <package/RepositoryCache.h>
25 #include <package/RepositoryConfig.h>
26 
27 #include <package/hpkg/PackageReader.h>
28 
29 
30 namespace BPackageKit {
31 
32 
33 using namespace BHPKG;
34 
35 
36 BPackageRoster::BPackageRoster()
37 {
38 }
39 
40 
41 BPackageRoster::~BPackageRoster()
42 {
43 }
44 
45 
46 status_t
47 BPackageRoster::GetCommonRepositoryConfigPath(BPath* path, bool create) const
48 {
49 	return _GetRepositoryPath(path, create, B_COMMON_SETTINGS_DIRECTORY);
50 }
51 
52 
53 status_t
54 BPackageRoster::GetUserRepositoryConfigPath(BPath* path, bool create) const
55 {
56 	return _GetRepositoryPath(path, create, B_USER_SETTINGS_DIRECTORY);
57 }
58 
59 
60 status_t
61 BPackageRoster::GetCommonRepositoryCachePath(BPath* path, bool create) const
62 {
63 	return _GetRepositoryPath(path, create, B_COMMON_CACHE_DIRECTORY);
64 }
65 
66 
67 status_t
68 BPackageRoster::GetUserRepositoryCachePath(BPath* path, bool create) const
69 {
70 	return _GetRepositoryPath(path, create, B_USER_CACHE_DIRECTORY);
71 }
72 
73 
74 status_t
75 BPackageRoster::VisitCommonRepositoryConfigs(BRepositoryConfigVisitor& visitor)
76 {
77 	BPath commonRepositoryConfigPath;
78 	status_t result
79 		= GetCommonRepositoryConfigPath(&commonRepositoryConfigPath);
80 	if (result != B_OK)
81 		return result;
82 
83 	return _VisitRepositoryConfigs(commonRepositoryConfigPath, visitor);
84 }
85 
86 
87 status_t
88 BPackageRoster::VisitUserRepositoryConfigs(BRepositoryConfigVisitor& visitor)
89 {
90 	BPath userRepositoryConfigPath;
91 	status_t result = GetUserRepositoryConfigPath(&userRepositoryConfigPath);
92 	if (result != B_OK)
93 		return result;
94 
95 	return _VisitRepositoryConfigs(userRepositoryConfigPath, visitor);
96 }
97 
98 
99 status_t
100 BPackageRoster::GetRepositoryNames(BStringList& names)
101 {
102 	struct RepositoryNameCollector : public BRepositoryConfigVisitor {
103 		RepositoryNameCollector(BStringList& _names)
104 			: names(_names)
105 		{
106 		}
107 		status_t operator()(const BEntry& entry)
108 		{
109 			char name[B_FILE_NAME_LENGTH];
110 			status_t result = entry.GetName(name);
111 			if (result != B_OK)
112 				return result;
113 			int32 count = names.CountStrings();
114 			for (int i = 0; i < count; ++i) {
115 				if (names.StringAt(i).Compare(name) == 0)
116 					return B_OK;
117 			}
118 			names.Add(name);
119 			return B_OK;
120 		}
121 		BStringList& names;
122 	};
123 	RepositoryNameCollector repositoryNameCollector(names);
124 	status_t result = VisitUserRepositoryConfigs(repositoryNameCollector);
125 	if (result != B_OK)
126 		return result;
127 
128 	return VisitCommonRepositoryConfigs(repositoryNameCollector);
129 }
130 
131 
132 status_t
133 BPackageRoster::GetRepositoryCache(const BString& name,
134 	BRepositoryCache* repositoryCache)
135 {
136 	if (repositoryCache == NULL)
137 		return B_BAD_VALUE;
138 
139 	// user path has higher precedence than common path
140 	BPath path;
141 	status_t result = GetUserRepositoryCachePath(&path);
142 	if (result != B_OK)
143 		return result;
144 	path.Append(name.String());
145 
146 	BEntry repoCacheEntry(path.Path());
147 	if (repoCacheEntry.Exists())
148 		return repositoryCache->SetTo(repoCacheEntry);
149 
150 	if ((result = GetCommonRepositoryCachePath(&path, true)) != B_OK)
151 		return result;
152 	path.Append(name.String());
153 
154 	repoCacheEntry.SetTo(path.Path());
155 	return repositoryCache->SetTo(repoCacheEntry);
156 }
157 
158 
159 status_t
160 BPackageRoster::GetRepositoryConfig(const BString& name,
161 	BRepositoryConfig* repositoryConfig)
162 {
163 	if (repositoryConfig == NULL)
164 		return B_BAD_VALUE;
165 
166 	// user path has higher precedence than common path
167 	BPath path;
168 	status_t result = GetUserRepositoryConfigPath(&path);
169 	if (result != B_OK)
170 		return result;
171 	path.Append(name.String());
172 
173 	BEntry repoConfigEntry(path.Path());
174 	if (repoConfigEntry.Exists())
175 		return repositoryConfig->SetTo(repoConfigEntry);
176 
177 	if ((result = GetCommonRepositoryConfigPath(&path, true)) != B_OK)
178 		return result;
179 	path.Append(name.String());
180 
181 	repoConfigEntry.SetTo(path.Path());
182 	return repositoryConfig->SetTo(repoConfigEntry);
183 }
184 
185 
186 status_t
187 BPackageRoster::GetActivePackages(BPackageInstallationLocation location,
188 	BPackageInfoSet& packageInfos)
189 {
190 // This method makes sense only on an installed Haiku, but not for the build
191 // tools.
192 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
193 	// check the given location
194 	directory_which packagesDirectory;
195 	switch (location) {
196 		case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM:
197 			packagesDirectory = B_SYSTEM_PACKAGES_DIRECTORY;
198 			break;
199 		case B_PACKAGE_INSTALLATION_LOCATION_COMMON:
200 			packagesDirectory = B_COMMON_PACKAGES_DIRECTORY;
201 			break;
202 		case B_PACKAGE_INSTALLATION_LOCATION_HOME:
203 			packagesDirectory = B_USER_PACKAGES_DIRECTORY;
204 			break;
205 		default:
206 			return B_BAD_VALUE;
207 	}
208 
209 	// find the package links directory
210 	BPath packageLinksPath;
211 	status_t error = find_directory(B_PACKAGE_LINKS_DIRECTORY,
212 		&packageLinksPath);
213 	if (error != B_OK)
214 		return error;
215 
216 	// find and open the packages directory
217 	BPath packagesDirPath;
218 	error = find_directory(packagesDirectory, &packagesDirPath);
219 	if (error != B_OK)
220 		return error;
221 
222 	BDirectory directory;
223 	error = directory.SetTo(packagesDirPath.Path());
224 	if (error != B_OK)
225 		return error;
226 
227 	// TODO: Implement that correctly be reading the activation files/directory!
228 
229 	// iterate through the packages
230 	char buffer[sizeof(dirent) + B_FILE_NAME_LENGTH];
231 	dirent* entry = (dirent*)&buffer;
232 	while (directory.GetNextDirents(entry, sizeof(buffer), 1) == 1) {
233 		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
234 			continue;
235 
236 		// get the full package file path
237 		BPath packagePath;
238 		error = packagePath.SetTo(packagesDirPath.Path(), entry->d_name);
239 		if (error != B_OK)
240 			continue;
241 
242 		// read the package info from the file
243 		BPackageReader packageReader(NULL);
244 		error = packageReader.Init(packagePath.Path());
245 		if (error != B_OK)
246 			continue;
247 
248 		BPackageInfo info;
249 		BPackageInfoContentHandler handler(info);
250 		error = packageReader.ParseContent(&handler);
251 		if (error != B_OK || info.InitCheck() != B_OK)
252 			continue;
253 
254 		// check whether the package is really active by verifying that a
255 		// package link exists for it
256 		BString packageLinkName(info.Name());
257 		packageLinkName << '-' << info.Version().ToString();
258 		BPath packageLinkPath;
259 		struct stat st;
260 		if (packageLinkPath.SetTo(packageLinksPath.Path(), packageLinkName)
261 				!= B_OK
262 			|| lstat(packageLinkPath.Path(), &st) != 0) {
263 			continue;
264 		}
265 
266 		// add the info
267 		error = packageInfos.AddInfo(info);
268 		if (error != B_OK)
269 			return error;
270 	}
271 
272 	return B_OK;
273 #else
274 	return B_NOT_SUPPORTED;
275 #endif
276 }
277 
278 
279 status_t
280 BPackageRoster::_GetRepositoryPath(BPath* path, bool create,
281 	directory_which whichDir) const
282 {
283 	if (path == NULL)
284 		return B_BAD_VALUE;
285 
286 	status_t result = find_directory(whichDir, path);
287 	if (result != B_OK)
288 		return result;
289 	if ((result = path->Append("package-repositories")) != B_OK)
290 		return result;
291 
292 	if (create) {
293 		BEntry entry(path->Path(), true);
294 		if (!entry.Exists()) {
295 			if (mkdir(path->Path(), 0755) != 0)
296 				return errno;
297 		}
298 	}
299 
300 	return B_OK;
301 }
302 
303 
304 status_t
305 BPackageRoster::_VisitRepositoryConfigs(const BPath& path,
306 	BRepositoryConfigVisitor& visitor)
307 {
308 	BDirectory directory(path.Path());
309 	status_t result = directory.InitCheck();
310 	if (result == B_ENTRY_NOT_FOUND)
311 		return B_OK;
312 	if (result != B_OK)
313 		return result;
314 
315 	BEntry entry;
316 	while (directory.GetNextEntry(&entry, true) == B_OK) {
317 		if ((result = visitor(entry)) != B_OK)
318 			return result;
319 	}
320 
321 	return B_OK;
322 }
323 
324 
325 }	// namespace BPackageKit
326