xref: /haiku/src/apps/packageinstaller/InstalledPackageInfo.cpp (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
1 /*
2  * Copyright (c) 2007, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Author:
6  *		Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
7  */
8 
9 
10 #include "InstalledPackageInfo.h"
11 
12 #include <stdio.h>
13 #include <string.h>
14 
15 #include <Directory.h>
16 #include <Entry.h>
17 #include <FindDirectory.h>
18 
19 
20 const char * kPackagesDir = "packages";
21 
22 
23 static status_t
24 info_prepare(const char *filename, BFile *file, BMessage *info)
25 {
26 	if (!filename)
27 		return B_ERROR;
28 
29 	BPath path;
30 	if (find_directory(B_USER_CONFIG_DIRECTORY, &path) != B_OK
31 			|| path.Append(kPackagesDir) != B_OK
32 			|| path.Append(filename) != B_OK)
33 		return B_ERROR;
34 
35 	file->SetTo(path.Path(), B_READ_ONLY);
36 	if (file->InitCheck() != B_OK)
37 		return B_ERROR;
38 
39 	status_t ret = info->Unflatten(file);
40   if (ret != B_OK || info->what != P_PACKAGE_INFO)
41 		return B_ERROR;
42 
43 	return B_OK;
44 }
45 
46 
47 const char *
48 info_get_package_name(const char *filename)
49 {
50 	BFile file;
51 	BMessage info;
52 	if (info_prepare(filename, &file, &info) != B_OK)
53 		return NULL;
54 	BString name;
55 	info.FindString("package_name", &name);
56 	return name.String();
57 }
58 
59 
60 const char *
61 info_get_package_version(const char *filename)
62 {
63 	BFile file;
64 	BMessage info;
65 	if (info_prepare(filename, &file, &info) != B_OK)
66 		return NULL;
67 	BString version;
68 	info.FindString("package_version", &version);
69 	return version.String();
70 }
71 
72 
73 InstalledPackageInfo::InstalledPackageInfo()
74 	:
75 	fStatus(B_NO_INIT),
76 	fIsUpToDate(false),
77 	fCreate(false),
78 	fInstalledItems(10)
79 {
80 }
81 
82 
83 InstalledPackageInfo::InstalledPackageInfo(const char *packageName,
84 		const char *version, bool create)
85 	:
86 	fStatus(B_NO_INIT),
87 	fIsUpToDate(false),
88 	fInstalledItems(10)
89 {
90 	SetTo(packageName, version, create);
91 }
92 
93 
94 InstalledPackageInfo::~InstalledPackageInfo()
95 {
96 	_ClearItemList();
97 }
98 
99 
100 status_t
101 InstalledPackageInfo::InitCheck()
102 {
103 	return fStatus;
104 }
105 
106 
107 status_t
108 InstalledPackageInfo::SetTo(const char *packageName, const char *version,
109 		bool create)
110 {
111 	_ClearItemList();
112 	fCreate = create;
113 	fStatus = B_NO_INIT;
114 	fVersion = version;
115 
116 	if (!packageName)
117 		return fStatus;
118 
119 	BPath configPath;
120 	if (find_directory(B_USER_CONFIG_DIRECTORY, &configPath) != B_OK) {
121 		fStatus = B_ERROR;
122 		return fStatus;
123 	}
124 
125 	if (fPathToInfo.SetTo(configPath.Path(), kPackagesDir) != B_OK) {
126 		fStatus = B_ERROR;
127 		return fStatus;
128 	}
129 
130 	// Check whether the directory exists
131 	BDirectory packageDir(fPathToInfo.Path());
132 	fStatus = packageDir.InitCheck();
133 	if (fStatus == B_ENTRY_NOT_FOUND) {
134 		// If not, create it
135 		packageDir.SetTo(configPath.Path());
136 		if (packageDir.CreateDirectory(kPackagesDir, &packageDir) != B_OK) {
137 			fStatus = B_ERROR;
138 			return fStatus;
139 		}
140 	}
141 
142 	BString filename = packageName;
143 	filename << version << ".pdb";
144 	if (fPathToInfo.Append(filename.String()) != B_OK) {
145 		fStatus = B_ERROR;
146 		return fStatus;
147 	}
148 
149 	BFile package(fPathToInfo.Path(), B_READ_ONLY);
150 	fStatus = package.InitCheck();
151 	if (fStatus == B_OK) {
152 		// The given package exists, so we can unflatten the data to a message
153 		// and then pass it further
154 		BMessage info;
155 		if (info.Unflatten(&package) != B_OK || info.what != P_PACKAGE_INFO) {
156 			fStatus = B_ERROR;
157 			return fStatus;
158 		}
159 
160 		int32 count;
161 		fStatus = info.FindString("package_name", &fName);
162 		fStatus |= info.FindString("package_desc", &fDescription);
163 		fStatus |= info.FindString("package_version", &fVersion);
164 		int64 spaceNeeded = 0;
165 		fStatus |= info.FindInt64("package_size", &spaceNeeded);
166 		fSpaceNeeded = static_cast<uint64>(spaceNeeded);
167 		fStatus |= info.FindInt32("file_count", &count);
168 		if (fStatus != B_OK) {
169 			fStatus = B_ERROR;
170 			return fStatus;
171 		}
172 
173 		int32 i;
174 		BString itemPath;
175 		for (i = 0; i < count; i++) {
176 			if (info.FindString("items", i, &itemPath) != B_OK) {
177 				fStatus = B_ERROR;
178 				return fStatus;
179 			}
180 			fInstalledItems.AddItem(new BString(itemPath)); // Or maybe BPath better?
181 		}
182 		fIsUpToDate = true;
183 	}
184 	else if (fStatus == B_ENTRY_NOT_FOUND) {
185 		if (create) {
186 			fStatus = B_OK;
187 			fIsUpToDate = false;
188 		}
189 	}
190 
191 	return fStatus;
192 }
193 
194 
195 status_t
196 InstalledPackageInfo::AddItem(const char *itemName)
197 {
198 	if (!itemName)
199 		return B_ERROR;
200 
201 	return fInstalledItems.AddItem(new BString(itemName));
202 }
203 
204 
205 status_t
206 InstalledPackageInfo::Uninstall()
207 {
208 	if (fStatus != B_OK)
209 		return fStatus;
210 
211 	BString *iter;
212 	uint32 i, count = fInstalledItems.CountItems();
213 	BEntry entry;
214 	status_t ret;
215 
216 	// Try to remove all entries that are present in the list
217 	for (i = 0; i < count; i++) {
218 		iter = static_cast<BString *>(fInstalledItems.ItemAt(count - i - 1));
219 		fprintf(stderr, "Removing: %s (%ld/%ld)\n", iter->String(), i, count);
220 		ret = entry.SetTo(iter->String());
221 		if (ret == B_BUSY) {
222 			// The entry's directory is locked - wait a few cycles for it to
223 			// unlock itself
224 			int32 tries = 0;
225 			for (tries = 0; tries < P_BUSY_TRIES; tries++) {
226 				ret = entry.SetTo(iter->String());
227 				if (ret != B_BUSY)
228 					break;
229 				// Wait a moment
230 				usleep(1000);
231 			}
232 		}
233 
234 		if (ret == B_ENTRY_NOT_FOUND)
235 			continue;
236 		else if (ret != B_OK) {
237 			fStatus = B_ERROR;
238 			return fStatus;
239 		}
240 
241 		fprintf(stderr, "...we continue\n");
242 
243 		if (entry.Exists() && entry.Remove() != B_OK) {
244 			fprintf(stderr, "\n%s\n", strerror(ret));
245 			fStatus = B_ERROR;
246 			return fStatus;
247 		}
248 		fInstalledItems.RemoveItem(count - i - 1);
249 	}
250 
251 	if (entry.SetTo(fPathToInfo.Path()) != B_OK) {
252 		fStatus = B_ERROR;
253 		return fStatus;
254 	}
255 	if (entry.Exists() && entry.Remove() != B_OK) {
256 		fStatus = B_ERROR;
257 		return fStatus;
258 	}
259 
260 	return fStatus;
261 }
262 
263 
264 status_t
265 InstalledPackageInfo::Save()
266 {
267 	// If the package info is not up to date and everything till now was
268 	// done correctly, we will save all data as a flattened BMessage to the
269 	// package info file
270 	if (fIsUpToDate || fStatus != B_OK)
271 		return fStatus;
272 
273 	BFile package;
274 	if (fCreate) {
275 		fStatus = package.SetTo(fPathToInfo.Path(), B_WRITE_ONLY | B_CREATE_FILE
276 			| B_ERASE_FILE);
277 	}
278 	else {
279 		fStatus = package.SetTo(fPathToInfo.Path(), B_WRITE_ONLY | B_ERASE_FILE);
280 	}
281 
282 	if (fStatus != B_OK)
283 		return fStatus;
284 
285 	status_t ret;
286 	int32 i, count = fInstalledItems.CountItems();
287 	BMessage info(P_PACKAGE_INFO);
288 	ret = info.AddString("package_name", fName);
289 	ret |= info.AddString("package_desc", fDescription);
290 	ret |= info.AddString("package_version", fVersion);
291 	ret |= info.AddInt64("package_size", fSpaceNeeded);
292 	ret |= info.AddInt32("file_count", count);
293 	if (ret != B_OK) {
294 		fStatus = B_ERROR;
295 		return fStatus;
296 	}
297 
298 	BString *iter;
299 	for (i = 0; i < count; i++) {
300 		iter = static_cast<BString *>(fInstalledItems.ItemAt(i));
301 		if (info.AddString("items", *iter) != B_OK) {
302 			fStatus = B_ERROR;
303 			return fStatus;
304 		}
305 	}
306 
307 	if (info.Flatten(&package) != B_OK) {
308 		fStatus = B_ERROR;
309 		return fStatus;
310 	}
311 	fIsUpToDate = true;
312 
313 	return fStatus;
314 }
315 
316 
317 // #pragma mark -
318 
319 
320 void
321 InstalledPackageInfo::_ClearItemList()
322 {
323 	// Clear the items list
324 	BString *iter;
325 	uint32 i, count = fInstalledItems.CountItems();
326 	for (i = 0; i < count; i++) {
327 		iter = static_cast<BString *>(fInstalledItems.ItemAt(0));
328 		fInstalledItems.RemoveItem((int32)0);
329 		delete iter;
330 	}
331 }
332 
333