BTRFS: Implement BTree::Path and change _Find.
[haiku.git] / src / apps / packageinstaller / PackageInfo.cpp
blob55aa9ec15b3f91b67ab213e65f9ec51c6fe20a73
1 /*
2 * Copyright (c) 2007-2010, Haiku, Inc.
3 * Distributed under the terms of the MIT license.
5 * Author:
6 * Ɓukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
7 */
10 #include "PackageInfo.h"
12 #include <Alert.h>
13 #include <ByteOrder.h>
14 #include <Catalog.h>
15 #include <FindDirectory.h>
16 #include <Locale.h>
17 #include <Path.h>
18 #include <kernel/OS.h>
21 #undef B_TRANSLATION_CONTEXT
22 #define B_TRANSLATION_CONTEXT "PackageInfo"
24 #define RETURN_AND_SET_STATUS(err) fStatus = err; \
25 fprintf(stderr, "err at %s():%d: %x\n", __FUNCTION__, __LINE__, err); \
26 return fStatus;
28 const uint32 kSkipOffset = 33;
30 // Section constants
31 enum {
32 P_GROUPS_SECTION = 0,
33 P_PATH_SECTION,
34 P_USER_PATH_SECTION,
35 P_LICENSE_SECTION
39 // Element constants
40 enum {
41 P_NONE = 0,
42 P_FILE,
43 P_DIRECTORY,
44 P_LINK,
45 P_SCRIPT
48 typedef enum {
49 B_BEBOX_PLATFORM = 0,
50 B_MAC_PLATFORM,
51 B_AT_CLONE_PLATFORM,
52 B_ENIAC_PLATFORM,
53 B_APPLE_II_PLATFORM,
54 B_CRAY_PLATFORM,
55 B_LISA_PLATFORM,
56 B_TI_994A_PLATFORM,
57 B_TIMEX_SINCLAIR_PLATFORM,
58 B_ORAC_1_PLATFORM,
59 B_HAL_PLATFORM,
60 B_INVALID_PLATFORM
61 } platform_type;
64 PackageInfo::PackageInfo()
66 fStatus(B_NO_INIT),
67 fPackageFile(0),
68 fDescription(B_TRANSLATE("No package available.")),
69 fProfiles(2),
70 fHasImage(false)
75 PackageInfo::PackageInfo(const entry_ref *ref)
77 fStatus(B_NO_INIT),
78 fPackageFile(new BFile(ref, B_READ_ONLY)),
79 fDescription(B_TRANSLATE("No package selected.")),
80 fProfiles(2),
81 fHasImage(false)
83 fStatus = Parse();
87 PackageInfo::~PackageInfo()
89 pkg_profile *iter = 0;
90 while (1) {
91 iter = static_cast<pkg_profile *>(fProfiles.RemoveItem((int32)0));
92 if (iter == NULL)
93 break;
95 delete iter;
98 PackageItem *file = 0;
99 while (true) {
100 file = static_cast<PackageItem *>(fFiles.RemoveItem((int32)0));
101 if (file == NULL)
102 break;
104 delete file;
107 while (true) {
108 file = static_cast<PackageScript *>(fScripts.RemoveItem((int32)0));
109 if (file == NULL)
110 break;
112 delete file;
115 delete fPackageFile;
119 status_t
120 PackageInfo::Parse()
122 // TODO: Clean up
123 if (!fPackageFile || fPackageFile->InitCheck() != B_OK) {
124 RETURN_AND_SET_STATUS(B_ERROR);
127 // Check for the presence of the first AlB tag - as the 'magic number'.
128 // This also ensures that the file header section is present - which
129 // is a crucial pkg section
130 char buffer[16];
131 fPackageFile->Read(buffer, 8);
132 if (buffer[0] != 'A' || buffer[1] != 'l' || buffer[2] != 'B'
133 || buffer[3] != 0x1a) {
134 RETURN_AND_SET_STATUS(B_ERROR);
137 fHasImage = false;
139 // Parse all known parts of the given .pkg file
141 uint32 i;
142 int8 bytesRead;
143 off_t actualSize = 0;
144 fPackageFile->GetSize(&actualSize);
145 uint64 fileSize = 0;
147 const char padding[7] = { 0, 0, 0, 0, 0, 0, 0 };
149 platform_type thisPlatform = B_INVALID_PLATFORM;
150 cpu_topology_node_info topologyRoot;
151 uint32 topologyNodeCount = 1;
152 if (get_cpu_topology_info(&topologyRoot, &topologyNodeCount) == B_OK) {
153 switch (topologyRoot.data.root.platform) {
154 case B_CPU_x86:
155 thisPlatform = B_AT_CLONE_PLATFORM;
156 break;
158 default:
159 break;
163 uint64 infoOffset = 0, groupsOffset = 0;
164 uint64 length = 0;
166 // Parse the file header
167 while (true) {
168 bytesRead = fPackageFile->Read(buffer, 7);
169 if (bytesRead != 7) {
170 RETURN_AND_SET_STATUS(B_ERROR);
173 if (!memcmp(buffer, "PhIn", 5)) {
174 } else if (!memcmp(buffer, "FVer", 5)) {
175 // Not used right now
176 fPackageFile->Seek(4, SEEK_CUR);
177 parser_debug("FVer\n");
178 } else if (!memcmp(buffer, "AFla", 5)) {
179 // Not used right now TODO: Check what this tag is for
180 fPackageFile->Seek(8, SEEK_CUR);
181 parser_debug("AFla\n");
182 } else if (!memcmp(buffer, "FSiz", 5)) {
183 fPackageFile->Read(&fileSize, 8);
184 swap_data(B_UINT64_TYPE, &fileSize, sizeof(uint64),
185 B_SWAP_BENDIAN_TO_HOST);
186 parser_debug("FSiz %llu\n", fileSize);
187 } else if (!memcmp(buffer, "COff", 5)) {
188 fPackageFile->Read(&infoOffset, 8);
189 swap_data(B_UINT64_TYPE, &infoOffset, sizeof(uint64),
190 B_SWAP_BENDIAN_TO_HOST);
191 parser_debug("COff %llu\n", infoOffset);
192 } else if (!memcmp(buffer, "AOff", 5)) {
193 fPackageFile->Read(&groupsOffset, 8);
194 swap_data(B_UINT64_TYPE, &groupsOffset, sizeof(uint64),
195 B_SWAP_BENDIAN_TO_HOST);
196 parser_debug("AOff %llu\n", groupsOffset);
197 } else if (!memcmp(buffer, padding, 7)) {
198 // This means the end of this section - we should move to the
199 // groups section.
200 if (groupsOffset) {
201 fPackageFile->Seek(groupsOffset, SEEK_SET);
203 parser_debug("End!\n");
204 break;
205 } else {
206 RETURN_AND_SET_STATUS(B_ERROR);
210 fPackageFile->Read(buffer, 7);
211 if (memcmp(buffer, "PkgA", 5) || !groupsOffset || !infoOffset) {
212 RETURN_AND_SET_STATUS(B_ERROR);
215 // Section header identifying constant byte sequences:
216 const char groupsMarker[7] = { 0, 0, 0, 1, 0, 0, 4 };
217 const char idMarker[7] = { 0, 0, 0, 2, 0, 0, 4 };
218 const char pathMarker[7] = { 0, 0, 0, 3, 0, 0, 4 };
219 const char upathMarker[7] = { 0, 0, 0, 4, 0, 0, 4 };
220 const char licenseMarker[7] = { 0, 0, 0, 18, 0, 0, 4 };
221 const char descMarker[7] = { 0, 0, 0, 5, 0, 0, 2 };
222 const char helpMarker[7] = { 0, 0, 0, 10, 0, 0, 3 };
224 const char splashScreenMarker[7] = { 0, 0, 0, 8, 0, 0, 3 };
225 const char disclaimerMarker[7] = { 0, 0, 0, 7, 0, 0, 3 };
227 const char nameMarker[7] = { 0, 0, 0, 13, 0, 0, 2 };
228 const char versionMarker[7] = { 0, 0, 0, 14, 0, 0, 2 };
229 const char devMarker[7] = { 0, 0, 0, 15, 0, 0, 2 };
230 const char shortDescMarker[7] = { 0, 0, 0, 17, 0, 0, 2 };
232 int8 section = P_GROUPS_SECTION, installDirectoryFlag = 0;
234 pkg_profile group;
235 BList groups(3), userPaths(3), systemPaths(10);
236 bool groupStarted = false;
237 parser_debug("Package Info reached!\n");
238 // TODO: Maybe checking whether the needed number of bytes are read
239 // everytime would be a good idea
241 // Parse the package info section
242 while (true) {
243 bytesRead = fPackageFile->Read(buffer, 7);
244 if (bytesRead != 7) {
245 parser_debug("EOF!\n");
246 break;
249 if (!memcmp(buffer, groupsMarker, 7)) {
250 section = P_GROUPS_SECTION;
251 parser_debug("Got to Groups section\n");
252 continue;
253 } else if (!memcmp(buffer, pathMarker, 7)) {
254 section = P_PATH_SECTION;
255 parser_debug("Got to System Paths\n");
256 continue;
257 } else if (!memcmp(buffer, upathMarker, 7)) {
258 section = P_USER_PATH_SECTION;
259 parser_debug("Got to User Paths\n");
260 continue;
261 } else if (!memcmp(buffer, licenseMarker, 7)) {
262 section = P_LICENSE_SECTION;
263 parser_debug("Got to License\n");
264 continue;
265 // After this, non sectioned tags follow
266 } else if (!memcmp(buffer, disclaimerMarker, 7)) {
267 uint64 length;
268 fPackageFile->Read(&length, 8);
269 swap_data(B_UINT64_TYPE, &length, sizeof(uint64),
270 B_SWAP_BENDIAN_TO_HOST);
272 uint64 original;
273 if (fPackageFile->Read(&original, 8) != 8) {
274 RETURN_AND_SET_STATUS(B_ERROR);
276 swap_data(B_UINT64_TYPE, &original, sizeof(uint64),
277 B_SWAP_BENDIAN_TO_HOST);
279 fPackageFile->Seek(4, SEEK_CUR);
281 uint8 *compressed = new uint8[length];
282 if (fPackageFile->Read(compressed, length)
283 != static_cast<int64>(length)) {
284 delete[] compressed;
285 RETURN_AND_SET_STATUS(B_ERROR);
288 uint8 *disclaimer = new uint8[original + 1];
289 status_t ret = inflate_data(compressed, length, disclaimer,
290 original);
291 disclaimer[original] = 0;
292 delete[] compressed;
293 if (ret != B_OK) {
294 delete[] disclaimer;
295 RETURN_AND_SET_STATUS(B_ERROR);
298 fDisclaimer = (char *)disclaimer;
299 delete[] disclaimer;
301 continue;
302 } else if (!memcmp(buffer, splashScreenMarker, 7)) {
303 uint64 length;
304 fPackageFile->Read(&length, 8);
305 swap_data(B_UINT64_TYPE, &length, sizeof(uint64),
306 B_SWAP_BENDIAN_TO_HOST);
308 uint64 original;
309 if (fPackageFile->Read(&original, 8) != 8) {
310 RETURN_AND_SET_STATUS(B_ERROR);
312 swap_data(B_UINT64_TYPE, &original, sizeof(uint64),
313 B_SWAP_BENDIAN_TO_HOST);
315 fPackageFile->Seek(4, SEEK_CUR);
317 uint8 *compressed = new uint8[length];
318 if (fPackageFile->Read(compressed, length)
319 != static_cast<int64>(length)) {
320 delete[] compressed;
321 RETURN_AND_SET_STATUS(B_ERROR);
324 fImage.SetSize(original);
325 status_t ret = inflate_data(compressed, length,
326 static_cast<uint8 *>(const_cast<void *>(fImage.Buffer())),
327 original);
328 delete[] compressed;
329 if (ret != B_OK) {
330 RETURN_AND_SET_STATUS(B_ERROR);
332 fHasImage = true;
333 continue;
336 switch (section) {
337 case P_PATH_SECTION:
339 if (!memcmp(buffer, "DPat", 5)) {
340 parser_debug("DPat\n");
341 continue;
342 } else if (!memcmp(buffer, "FDst", 5)) {
343 parser_debug("FDst - ");
344 directory_which dir;
345 if (fPackageFile->Read(&dir, 4) != 4) {
346 RETURN_AND_SET_STATUS(B_ERROR);
348 swap_data(B_UINT32_TYPE, &dir, sizeof(uint32),
349 B_SWAP_BENDIAN_TO_HOST);
350 BPath *path = new BPath();
351 status_t ret = find_directory(dir, path);
352 if (ret != B_OK) {
353 delete path;
354 RETURN_AND_SET_STATUS(B_ERROR);
357 parser_debug("%s\n", path->Path());
359 systemPaths.AddItem(path);
360 } else if (!memcmp(buffer, "PaNa", 5)) {
361 parser_debug("PaNa\n");
362 if (fPackageFile->Read(&length, 4) != 4) {
363 RETURN_AND_SET_STATUS(B_ERROR);
365 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
366 B_SWAP_BENDIAN_TO_HOST);
367 // Since its a default, system path, we can ignore the path
368 // name - all information needed is beside the FDst tag.
369 fPackageFile->Seek(length, SEEK_CUR);
370 } else if (!memcmp(buffer, padding, 7)) {
371 parser_debug("Padding!\n");
372 continue;
373 } else {
374 RETURN_AND_SET_STATUS(B_ERROR);
376 break;
379 case P_GROUPS_SECTION:
381 if (!memcmp(buffer, "IGrp", 5)) {
382 // Creata a new group
383 groupStarted = true;
384 group = pkg_profile();
385 parser_debug("IGrp\n");
386 } else if (!memcmp(buffer, "GrpN", 5)) {
387 if (!groupStarted) {
388 RETURN_AND_SET_STATUS(B_ERROR);
391 parser_debug("GrpN\n");
392 fPackageFile->Read(&length, 4);
393 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
394 B_SWAP_BENDIAN_TO_HOST);
396 char *name = new char[length + 1];
397 fPackageFile->Read(name, length);
398 name[length] = 0;
399 group.name = name;
400 delete[] name;
401 } else if (!memcmp(buffer, "GrpD", 5)) {
402 if (!groupStarted) {
403 RETURN_AND_SET_STATUS(B_ERROR);
406 parser_debug("GrpD\n");
407 fPackageFile->Read(&length, 4);
408 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
409 B_SWAP_BENDIAN_TO_HOST);
411 char *desc = new char[length + 1];
412 fPackageFile->Read(desc, length);
413 desc[length] = 0;
414 group.description = desc;
415 delete[] desc;
416 } else if (!memcmp(buffer, "GrHt", 5)) {
417 if (!groupStarted) {
418 RETURN_AND_SET_STATUS(B_ERROR);
421 parser_debug("GrHt\n");
422 // For now, we don't need group help
423 fPackageFile->Read(&length, 4);
424 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
425 B_SWAP_BENDIAN_TO_HOST);
426 fPackageFile->Seek(length, SEEK_CUR);
427 } else if (!memcmp(buffer, padding, 5)) {
428 if (!groupStarted) {
429 parser_debug("No group - padding!\n");
430 continue;
433 fProfiles.AddItem(new pkg_profile(group));
434 parser_debug("Group added: %s %s\n", group.name.String(),
435 group.description.String());
437 groupStarted = false;
438 } else if (!memcmp(buffer, "GrId", 5)) {
439 uint32 id;
440 fPackageFile->Read(&id, 4);
441 swap_data(B_UINT32_TYPE, &id, sizeof(uint32),
442 B_SWAP_BENDIAN_TO_HOST);
444 parser_debug("GrId\n");
446 if (id == 0xffffffff)
447 groups.AddItem(NULL);
448 else
449 groups.AddItem(fProfiles.ItemAt(id));
450 } else if (!memcmp(buffer, idMarker, 7)
451 || !memcmp(buffer, groupsMarker, 7)) {
452 parser_debug("Marker, jumping!\n");
453 continue;
454 } else {
455 RETURN_AND_SET_STATUS(B_ERROR);
457 break;
460 case P_LICENSE_SECTION:
462 if (!memcmp(buffer, "Lic?", 5)) {
463 parser_debug("Lic?\n");
464 // This tag informs whether a license is present in the
465 // package or not. Since we don't care about licenses right
466 // now, just skip this section
467 fPackageFile->Seek(4, SEEK_CUR);
468 } else if (!memcmp(buffer, "LicP", 5)) {
469 parser_debug("LicP\n");
470 fPackageFile->Read(&length, 4);
471 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
472 B_SWAP_BENDIAN_TO_HOST);
474 fPackageFile->Seek(length, SEEK_CUR);
475 } else if (!memcmp(buffer, padding, 7)) {
476 continue;
477 } else if (!memcmp(buffer, descMarker, 7)) {
478 parser_debug("Description text reached\n");
479 fPackageFile->Read(&length, 4);
480 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
481 B_SWAP_BENDIAN_TO_HOST);
483 char *description = new char[length + 1];
484 fPackageFile->Read(description, length);
485 description[length] = 0;
486 fDescription = description;
488 // Truncate all leading newlines
489 for (i = 0; i < length; i++) {
490 if (fDescription[i] != '\n')
491 break;
493 fDescription.Remove(0, i);
495 delete[] description;
496 parser_debug("Description text reached\n");
498 // After this, there's a known size sequence of bytes, which
499 // meaning is yet to be determined.
501 // One is already known. The byte (or just its least
502 // significant bit) at offset 21 from the description text
503 // is responsible for the install folder existence
504 // information. If it is 0, there is no install folder, if
505 // it is 1 (or the least significant bit is set) it means
506 // we should install all 0xffffffff files/directories to
507 // the first directory existing in the package
508 fPackageFile->Seek(21, SEEK_CUR);
509 if (fPackageFile->Read(&installDirectoryFlag, 1) != 1) {
510 RETURN_AND_SET_STATUS(B_ERROR);
513 fPackageFile->Seek(11, SEEK_CUR);
514 } else if (!memcmp(buffer, nameMarker, 7)) {
515 parser_debug("Package name reached\n");
516 fPackageFile->Read(&length, 4);
517 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
518 B_SWAP_BENDIAN_TO_HOST);
520 char *name = new char[length + 1];
521 fPackageFile->Read(name, length);
522 name[length] = 0;
523 fName = name;
524 delete[] name;
525 } else if (!memcmp(buffer, versionMarker, 7)) {
526 parser_debug("Package version reached\n");
527 fPackageFile->Read(&length, 4);
528 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
529 B_SWAP_BENDIAN_TO_HOST);
531 char *version = new char[length + 1];
532 fPackageFile->Read(version, length);
533 version[length] = 0;
534 fVersion = version;
535 delete[] version;
536 } else if (!memcmp(buffer, devMarker, 7)) {
537 parser_debug("Package developer reached\n");
538 fPackageFile->Read(&length, 4);
539 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
540 B_SWAP_BENDIAN_TO_HOST);
542 char *dev = new char[length + 1];
543 fPackageFile->Read(dev, length);
544 dev[length] = 0;
545 fDeveloper = dev;
546 delete[] dev;
547 } else if (!memcmp(buffer, shortDescMarker, 7)) {
548 parser_debug("Package short description reached\n");
549 fPackageFile->Read(&length, 4);
550 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
551 B_SWAP_BENDIAN_TO_HOST);
553 char *desc = new char[length + 1];
554 fPackageFile->Read(desc, length);
555 desc[length] = 0;
556 fShortDesc = desc;
557 delete[] desc;
558 } else if (!memcmp(buffer, helpMarker, 7)) {
559 // The help text is a stored in deflated state, preceded by a 64 bit
560 // compressed size, 64 bit inflated size and a 32 bit integer
561 // Since there was no discussion whether we need this help text,
562 // it will be skipped
563 parser_debug("Help text reached\n");
564 //uint64 length64;
565 fPackageFile->Read(&length, 8);
566 swap_data(B_UINT64_TYPE, &length, sizeof(uint64),
567 B_SWAP_BENDIAN_TO_HOST);
569 fPackageFile->Seek(12 + length, SEEK_CUR);
571 break;
574 case P_USER_PATH_SECTION:
576 if (!memcmp(buffer, "DPat", 5)) {
577 parser_debug("DPat\n");
578 continue;
579 } else if (!memcmp(buffer, "DQue", 5)) {
580 parser_debug("DQue\n");
581 continue;
582 } else if (!memcmp(buffer, "DQTi", 5)) {
583 parser_debug("DQTi\n");
584 uint32 length;
585 if (fPackageFile->Read(&length, 4) != 4) {
586 RETURN_AND_SET_STATUS(B_ERROR);
588 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
589 B_SWAP_BENDIAN_TO_HOST);
590 char *ti = new char[length + 1];
591 fPackageFile->Read(ti, length);
592 ti[length] = 0;
593 parser_debug("DQTi - %s\n", ti);
594 delete[] ti;
595 } else if (!memcmp(buffer, "DQSz", 5)) {
596 parser_debug("DQSz\n");
597 uint64 size;
598 if (fPackageFile->Read(&size, 8) != 8) {
599 RETURN_AND_SET_STATUS(B_ERROR);
601 swap_data(B_UINT64_TYPE, &size, sizeof(uint64),
602 B_SWAP_BENDIAN_TO_HOST);
603 parser_debug("DQSz - %Ld\n", size);
604 } else if (!memcmp(buffer, "DQMi", 5)) {
605 // TODO actually check if the query finds a file with
606 // size found previously
607 parser_debug("DQMi\n");
608 uint32 length;
609 if (fPackageFile->Read(&length, 4) != 4) {
610 RETURN_AND_SET_STATUS(B_ERROR);
612 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
613 B_SWAP_BENDIAN_TO_HOST);
614 char *signature = new char[length + 1];
615 fPackageFile->Read(signature, length);
616 signature[length] = 0;
617 parser_debug("DQMi - %s\n", signature);
618 delete[] signature;
619 } else if (!memcmp(buffer, "PaNa", 5)) {
620 parser_debug("PaNa\n");
621 fPackageFile->Read(&length, 4);
622 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
623 B_SWAP_BENDIAN_TO_HOST);
625 char *pathname = new char[length + 1];
626 fPackageFile->Read(pathname, length);
627 pathname[length] = 0;
628 BString *path = new BString(pathname);
629 if (length > 0 && pathname[length - 1] == '/')
630 path->Remove(length - 1, 1);
631 userPaths.AddItem(path);
632 delete[] pathname;
633 } else if (!memcmp(buffer, padding, 7)) {
634 parser_debug("Padding!\n");
635 continue;
636 } else {
637 parser_debug("Unknown user path section %s\n", buffer);
638 RETURN_AND_SET_STATUS(B_ERROR);
640 break;
645 BString nameString, mimeString, signatureString, linkString;
646 BString itemPath = "", installDirectory = "";
647 uint32 directoryCount = 0;
649 uint8 element = P_NONE;
650 uint32 itemGroups = 0, path = 0, cust = 0, ctime = 0, mtime = 0;
651 uint32 platform = 0xffffffff;
652 uint64 offset = 0, size = 0, originalSize = 0, mode = 0;
653 uint8 pathType = P_INSTALL_PATH;
654 status_t ret;
656 fPackageFile->Seek(infoOffset, SEEK_SET);
658 // Parse package file data
659 while (true) {
660 bytesRead = fPackageFile->Read(buffer, 7);
661 if (bytesRead != 7) {
662 RETURN_AND_SET_STATUS(B_ERROR);
665 #define INIT_VARS(tag, type) \
666 parser_debug(tag "\n"); \
667 element = type; \
668 mimeString = ""; \
669 nameString = ""; \
670 linkString = ""; \
671 signatureString = ""; \
672 itemGroups = 0; \
673 ctime = 0; \
674 mtime = 0; \
675 offset = 0; \
676 cust = 0; \
677 mode = 0; \
678 platform = 0xffffffff; \
679 size = 0; \
680 originalSize = 0
682 if (!memcmp(buffer, "FilI", 5)) {
683 INIT_VARS("FilI", P_FILE);
684 } else if (!memcmp(buffer, "FldI", 5)) {
685 INIT_VARS("FldI", P_DIRECTORY);
686 } else if (!memcmp(buffer, "LnkI", 5)) {
687 INIT_VARS("LnkI", P_LINK);
688 } else if (!memcmp(buffer, "ScrI", 5)) {
689 INIT_VARS("ScrI", P_SCRIPT);
690 } else if (!memcmp(buffer, "Name", 5)) {
691 if (element == P_NONE) {
692 RETURN_AND_SET_STATUS(B_ERROR);
695 parser_debug("Name\n");
696 fPackageFile->Read(&length, 4);
697 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
698 B_SWAP_BENDIAN_TO_HOST);
700 char *name = new char[length + 1];
701 fPackageFile->Read(name, length);
702 name[length] = 0;
704 nameString = name;
705 delete[] name;
706 } else if (!memcmp(buffer, "Grps", 5)) {
707 if (element == P_NONE) {
708 RETURN_AND_SET_STATUS(B_ERROR);
711 parser_debug("Grps\n");
712 fPackageFile->Read(&itemGroups, 4);
713 swap_data(B_UINT32_TYPE, &itemGroups, sizeof(uint32),
714 B_SWAP_BENDIAN_TO_HOST);
715 } else if (!memcmp(buffer, "Dest", 5)) {
716 if (element == P_NONE) {
717 RETURN_AND_SET_STATUS(B_ERROR);
720 parser_debug("Dest\n");
721 fPackageFile->Read(&path, 4);
722 swap_data(B_UINT32_TYPE, &path, sizeof(uint32),
723 B_SWAP_BENDIAN_TO_HOST);
724 } else if (!memcmp(buffer, "Cust", 5)) {
725 if (element == P_NONE) {
726 RETURN_AND_SET_STATUS(B_ERROR);
729 parser_debug("Cust\n");
730 fPackageFile->Read(&cust, 4);
731 swap_data(B_UINT32_TYPE, &cust, sizeof(uint32),
732 B_SWAP_BENDIAN_TO_HOST);
733 } else if (!memcmp(buffer, "Repl", 5)) {
734 if (element == P_NONE) {
735 RETURN_AND_SET_STATUS(B_ERROR);
738 parser_debug("Repl\n");
739 fPackageFile->Seek(4, SEEK_CUR);
740 // TODO: Should the replace philosophy depend on this flag? For now
741 // I always leave the decision to the user
742 } else if (!memcmp(buffer, "Plat", 5)) {
743 if (element == P_NONE) {
744 RETURN_AND_SET_STATUS(B_ERROR);
747 parser_debug("Plat\n");
748 fPackageFile->Read(&platform, 4);
749 swap_data(B_UINT32_TYPE, &platform, sizeof(uint32),
750 B_SWAP_BENDIAN_TO_HOST);
751 } else if (!memcmp(buffer, "CTim", 5)) {
752 if (element == P_NONE) {
753 RETURN_AND_SET_STATUS(B_ERROR);
756 parser_debug("CTim\n");
757 fPackageFile->Read(&ctime, 4);
758 swap_data(B_UINT32_TYPE, &ctime, sizeof(uint32),
759 B_SWAP_BENDIAN_TO_HOST);
760 } else if (!memcmp(buffer, "MTim", 5)) {
761 if (element == P_NONE) {
762 RETURN_AND_SET_STATUS(B_ERROR);
765 parser_debug("MTim\n");
766 fPackageFile->Read(&mtime, 4);
767 swap_data(B_UINT32_TYPE, &mtime, sizeof(uint32),
768 B_SWAP_BENDIAN_TO_HOST);
769 } else if (!memcmp(buffer, "OffT", 5)) {
770 if (element == P_NONE) {
771 RETURN_AND_SET_STATUS(B_ERROR);
774 parser_debug("OffT\n");
775 fPackageFile->Read(&offset, 8);
776 swap_data(B_UINT64_TYPE, &offset, sizeof(uint64),
777 B_SWAP_BENDIAN_TO_HOST);
778 } else if (!memcmp(buffer, "Mime", 5)) {
779 if (element != P_FILE) {
780 RETURN_AND_SET_STATUS(B_ERROR);
783 fPackageFile->Read(&length, 4);
784 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
785 B_SWAP_BENDIAN_TO_HOST);
787 char *mime = new char[length + 1];
788 fPackageFile->Read(mime, length);
789 mime[length] = 0;
790 parser_debug("Mime: %s\n", mime);
792 mimeString = mime;
793 delete[] mime;
794 } else if (!memcmp(buffer, "CmpS", 5)) {
795 if (element == P_NONE) {
796 RETURN_AND_SET_STATUS(B_ERROR);
799 parser_debug("CmpS\n");
800 fPackageFile->Read(&size, 8);
801 swap_data(B_UINT64_TYPE, &size, sizeof(uint64),
802 B_SWAP_BENDIAN_TO_HOST);
803 } else if (!memcmp(buffer, "OrgS", 5)) {
804 if (element != P_FILE && element != P_LINK && element != P_SCRIPT) {
805 RETURN_AND_SET_STATUS(B_ERROR);
808 parser_debug("OrgS\n");
809 fPackageFile->Read(&originalSize, 8);
810 swap_data(B_UINT64_TYPE, &originalSize, sizeof(uint64),
811 B_SWAP_BENDIAN_TO_HOST);
812 } else if (!memcmp(buffer, "VrsI", 5)) {
813 if (element != P_FILE) {
814 RETURN_AND_SET_STATUS(B_ERROR);
817 parser_debug("VrsI\n");
818 fPackageFile->Seek(24, SEEK_CUR);
819 // TODO
820 // Also, check what those empty 20 bytes mean
821 } else if (!memcmp(buffer, "Mode", 5)) {
822 if (element != P_FILE && element != P_LINK) {
823 RETURN_AND_SET_STATUS(B_ERROR);
826 parser_debug("Mode\n");
827 fPackageFile->Read(&mode, 4);
828 swap_data(B_UINT32_TYPE, &mode, sizeof(uint32),
829 B_SWAP_BENDIAN_TO_HOST);
830 } else if (!memcmp(buffer, "FDat", 5)) {
831 if (element != P_DIRECTORY) {
832 RETURN_AND_SET_STATUS(B_ERROR);
835 parser_debug("FDat\n");
836 } else if (!memcmp(buffer, "ASig", 5)) {
837 if (element != P_FILE) {
838 RETURN_AND_SET_STATUS(B_ERROR);
841 fPackageFile->Read(&length, 4);
842 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
843 B_SWAP_BENDIAN_TO_HOST);
845 char *signature = new char[length + 1];
846 fPackageFile->Read(signature, length);
847 signature[length] = 0;
848 parser_debug("Signature: %s\n", signature);
850 signatureString = signature;
851 delete[] signature;
852 } else if (!memcmp(buffer, "Link", 5)) {
853 if (element != P_LINK) {
854 RETURN_AND_SET_STATUS(B_ERROR);
857 fPackageFile->Read(&length, 4);
858 swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
859 B_SWAP_BENDIAN_TO_HOST);
861 char *link = new char[length + 1];
862 fPackageFile->Read(link, length);
863 link[length] = 0;
864 parser_debug("Link: %s\n", link);
866 linkString = link;
867 delete[] link;
868 } else if (!memcmp(buffer, padding, 7)) {
869 PackageItem *item = NULL;
871 parser_debug("Padding!\n");
872 if (platform != 0xffffffff
873 && static_cast<platform_type>(platform) != thisPlatform) {
874 // If the file/directory/item's platform is different than the
875 // target platform (or different than the 'any' constant),
876 // ignore this file
877 } else if (element == P_FILE) {
878 if (itemGroups && offset && size) {
879 BString dest = "";
880 uint8 localType = pathType;
882 if (path == 0xfffffffe)
883 dest << itemPath << "/" << nameString.String();
884 else if (path == 0xffffffff) {
885 localType = P_INSTALL_PATH;
886 dest = installDirectory;
887 dest << nameString;
888 } else {
889 if (cust) {
890 BString *def = static_cast<BString *>(
891 userPaths.ItemAt(path));
892 if (!def) {
893 RETURN_AND_SET_STATUS(B_ERROR);
895 if ((*def)[0] == '/')
896 localType = P_SYSTEM_PATH;
897 else
898 localType = P_USER_PATH;
900 dest << *def << "/" << nameString;
901 } else {
902 BPath *def = static_cast<BPath *>(
903 systemPaths.ItemAt(path));
904 if (!def) {
905 RETURN_AND_SET_STATUS(B_ERROR);
907 localType = P_SYSTEM_PATH;
909 dest << def->Path() << "/" << nameString;
913 parser_debug("Adding file: %s!\n", dest.String());
915 item = new PackageFile(fPackageFile, dest, localType, ctime,
916 mtime, offset, size, originalSize, 0, mimeString,
917 signatureString, mode);
919 } else if (element == P_DIRECTORY) {
920 if (itemGroups) {
921 if (installDirectoryFlag != 0) {
922 if (installDirectoryFlag < 0) {
923 // Normal directory
924 if (path == 0xfffffffe) {
925 // Install to current directory
926 itemPath << "/" << nameString.String();
927 directoryCount++;
928 } else if (path == 0xffffffff) {
929 // Install to install directory
930 pathType = P_INSTALL_PATH;
931 itemPath = installDirectory;
932 itemPath << nameString;
933 directoryCount = 1;
934 } else {
935 // Install to defined directory
936 if (cust) {
937 BString *def = static_cast<BString *>(
938 userPaths.ItemAt(path));
939 if (!def) {
940 RETURN_AND_SET_STATUS(B_ERROR);
942 if ((*def)[0] == '/')
943 pathType = P_SYSTEM_PATH;
944 else
945 pathType = P_USER_PATH;
947 itemPath = *def;
948 } else {
949 BPath *def = static_cast<BPath *>(
950 systemPaths.ItemAt(path));
951 if (!def) {
952 RETURN_AND_SET_STATUS(B_ERROR);
954 pathType = P_SYSTEM_PATH;
956 itemPath = def->Path();
959 itemPath << "/" << nameString;
960 directoryCount = 1;
962 } else {
963 // Install directory
964 if (path != 0xffffffff) {
965 RETURN_AND_SET_STATUS(B_ERROR);
968 installDirectory = nameString;
969 installDirectory << "/";
970 pathType = P_INSTALL_PATH;
971 itemPath = nameString;
973 installDirectoryFlag = -1;
976 parser_debug("Adding the directory %s!\n",
977 itemPath.String());
979 item = new PackageDirectory(fPackageFile, itemPath,
980 pathType, ctime, mtime, offset, size);
981 } else
982 installDirectoryFlag = -1;
984 } else if (element == P_LINK) {
985 if (itemGroups && linkString.Length()) {
986 BString dest = "";
987 uint8 localType = pathType;
989 if (path == 0xfffffffe)
990 dest << itemPath << "/" << nameString.String();
991 else if (path == 0xffffffff) {
992 localType = P_INSTALL_PATH;
993 dest = installDirectory;
994 dest << nameString;
995 } else {
996 if (cust) {
997 BString *def = static_cast<BString *>(
998 userPaths.ItemAt(path));
999 if (!def) {
1000 RETURN_AND_SET_STATUS(B_ERROR);
1002 if ((*def)[0] == '/')
1003 localType = P_SYSTEM_PATH;
1004 else
1005 localType = P_USER_PATH;
1007 dest << *def << "/" << nameString;
1008 } else {
1009 BPath *def = static_cast<BPath *>(systemPaths.ItemAt(path));
1010 if (!def) {
1011 RETURN_AND_SET_STATUS(B_ERROR);
1013 localType = P_SYSTEM_PATH;
1015 dest << def->Path() << "/" << nameString;
1019 parser_debug("Adding link: %s! (type %s)\n", dest.String(),
1020 pathType == P_SYSTEM_PATH
1021 ? "System" : localType == P_INSTALL_PATH
1022 ? "Install" : "User");
1024 item = new PackageLink(fPackageFile, dest, linkString,
1025 localType, ctime, mtime, mode, offset, size);
1027 } else if (element == P_SCRIPT) {
1028 parser_debug("Adding the script %s!\n",
1029 nameString.String());
1031 BString workingDirectory;
1032 uint8 localType = P_SYSTEM_PATH;
1033 if (path == 1)
1034 workingDirectory << itemPath;
1035 else if (path == 0xffffffff) {
1036 workingDirectory << installDirectory;
1037 localType = P_INSTALL_PATH;
1040 fScripts.AddItem(new PackageScript(fPackageFile,
1041 workingDirectory, localType, offset, size, originalSize));
1042 } else {
1043 // If the directory tree count is equal to zero, this means all
1044 // directory trees have been closed and a padding sequence means the
1045 // end of the section
1046 if (directoryCount == 0)
1047 break;
1048 ret = itemPath.FindLast('/');
1049 if (ret == B_ERROR) {
1050 itemPath = "";
1052 else {
1053 itemPath.Truncate(ret);
1055 directoryCount--;
1058 if (item) {
1059 _AddItem(item, originalSize, itemGroups, path, cust);
1062 element = P_NONE;
1063 } else if (!memcmp(buffer, "PkgA", 5)) {
1064 parser_debug("PkgA\n");
1065 break;
1066 } else if (!memcmp(buffer, "PtcI", 5)) {
1067 parser_debug("PtcI\n");
1068 break;
1069 } else {
1070 fprintf(stderr, "Unknown file tag %s\n", buffer);
1071 RETURN_AND_SET_STATUS(B_ERROR);
1075 if (static_cast<uint64>(actualSize) != fileSize) {
1076 // Inform the user of a possible error
1077 int32 selection;
1078 BAlert *warning = new BAlert("filesize_wrong",
1079 B_TRANSLATE("There seems to be a file size mismatch in the "
1080 "package file. The package might be corrupted or have been "
1081 "modified after its creation. Do you still wish to continue?"),
1082 B_TRANSLATE("Continue"),
1083 B_TRANSLATE("Abort"), NULL,
1084 B_WIDTH_AS_USUAL, B_WARNING_ALERT);
1085 warning->SetShortcut(1, B_ESCAPE);
1086 selection = warning->Go();
1088 if (selection == 1) {
1089 RETURN_AND_SET_STATUS(B_ERROR);
1093 if (!groups.IsEmpty())
1094 fProfiles = groups;
1096 return B_OK;
1100 void
1101 PackageInfo::_AddItem(PackageItem *item, uint64 size, uint32 groups,
1102 uint32 path, uint32 cust)
1104 // Add the item to all groups it resides in
1105 uint32 i, n = fProfiles.CountItems(), mask = 1;
1106 pkg_profile *profile;
1108 fFiles.AddItem(item);
1110 for (i = 0;i < n;i++) {
1111 if (groups & mask) {
1112 profile = static_cast<pkg_profile *>(fProfiles.ItemAt(i));
1113 profile->items.AddItem(item);
1114 profile->space_needed += size;
1115 // If there is at least one non-predefined destination element
1116 // in the package, we give the user the ability to select the
1117 // installation directory.
1118 // If there are only predefined path files in the package, but
1119 // such defined by the user, the user will be able to select
1120 // the destination volume
1121 if (path == 0xffffffff)
1122 profile->path_type = P_INSTALL_PATH;
1123 else if (path < 0xfffffffe &&
1124 profile->path_type != P_INSTALL_PATH) {
1125 if (cust) {
1126 profile->path_type = P_USER_PATH;
1130 mask = mask << 1;