2 * Copyright 2007-2009, Haiku, Inc.
3 * Distributed under the terms of the MIT license.
6 * Ćukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
10 #include "PackageItem.h"
16 #include <ByteOrder.h>
18 #include <Directory.h>
19 #include <FindDirectory.h>
30 #undef B_TRANSLATION_CONTEXT
31 #define B_TRANSLATION_CONTEXT "PackageItem"
37 static const uint32 kDefaultMode
= 0777;
38 static const uint8 padding
[7] = { 0, 0, 0, 0, 0, 0, 0 };
49 inflate_data(uint8
*in
, uint32 inSize
, uint8
*out
, uint32 outSize
)
51 parser_debug("inflate_data() called - input_size: %ld, output_size: %ld\n",
54 stream
.zalloc
= Z_NULL
;
55 stream
.zfree
= Z_NULL
;
56 stream
.opaque
= Z_NULL
;
57 stream
.avail_in
= inSize
;
61 ret
= inflateInit(&stream
);
63 parser_debug("inflatInit failed\n");
67 stream
.avail_out
= outSize
;
68 stream
.next_out
= out
;
70 ret
= inflate(&stream
, Z_NO_FLUSH
);
71 if (ret
!= Z_STREAM_END
) {
72 // Uncompressed file size in package info corrupted
73 parser_debug("Left: %d\n", stream
.avail_out
);
83 inflate_file_to_file(BFile
*in
, uint64 in_size
, BFile
*out
, uint64 out_size
)
86 stream
.zalloc
= Z_NULL
;
87 stream
.zfree
= Z_NULL
;
88 stream
.opaque
= Z_NULL
;
90 stream
.next_in
= Z_NULL
;
93 uint8 buffer_out
[P_CHUNK_SIZE
], buffer_in
[P_CHUNK_SIZE
];
94 uint64 bytes_read
= 0, read
= P_CHUNK_SIZE
, write
= 0;
96 ret
= inflateInit(&stream
);
98 parser_debug("inflate_file_to_file: inflateInit failed\n");
103 bytes_read
+= P_CHUNK_SIZE
;
104 if (bytes_read
> in_size
) {
105 read
= in_size
- (bytes_read
- P_CHUNK_SIZE
);
106 bytes_read
= in_size
;
109 stream
.avail_in
= in
->Read(buffer_in
, read
);
110 if (stream
.avail_in
!= read
) {
111 parser_debug("inflate_file_to_file: read failed\n");
112 (void)inflateEnd(&stream
);
115 stream
.next_in
= buffer_in
;
118 stream
.avail_out
= P_CHUNK_SIZE
;
119 stream
.next_out
= buffer_out
;
121 ret
= inflate(&stream
, Z_NO_FLUSH
);
122 if (ret
!= Z_OK
&& ret
!= Z_STREAM_END
&& ret
!= Z_BUF_ERROR
) {
123 parser_debug("inflate_file_to_file: inflate failed with '%s'\n",
125 (void)inflateEnd(&stream
);
129 write
= P_CHUNK_SIZE
- stream
.avail_out
;
130 if (static_cast<uint64
>(out
->Write(buffer_out
, write
)) != write
) {
131 parser_debug("inflate_file_to_file: write failed\n");
132 (void)inflateEnd(&stream
);
135 } while (stream
.avail_out
== 0);
136 } while (bytes_read
!= in_size
);
138 (void)inflateEnd(&stream
);
144 // #pragma mark - PackageItem
147 PackageItem::PackageItem(BFile
* parent
, const BString
& path
, uint8 type
,
148 uint32 ctime
, uint32 mtime
, uint64 offset
, uint64 size
)
150 SetTo(parent
, path
, type
, ctime
, mtime
, offset
, size
);
154 PackageItem::~PackageItem()
160 PackageItem::SetTo(BFile
* parent
, const BString
& path
, uint8 type
, uint32 ctime
,
161 uint32 mtime
, uint64 offset
, uint64 size
)
169 fCreationTime
= ctime
;
170 fModificationTime
= mtime
;
175 PackageItem::InitPath(const char* path
, BPath
* destination
)
179 if (fPathType
== P_INSTALL_PATH
) {
181 printf("InitPath - relative: %s + %s\n", path
, fPath
.String());
183 parser_debug("InitPath path is NULL\n");
186 ret
= destination
->SetTo(path
, fPath
.String());
187 } else if (fPathType
== P_SYSTEM_PATH
) {
189 printf("InitPath - absolute: %s\n", fPath
.String());
192 ret
= destination
->SetTo(fPath
.String());
195 printf("InitPath - volume: %s + %s\n", path
, fPath
.String());
197 parser_debug("InitPath path is NULL\n");
201 BVolume
volume(dev_for_path(path
));
202 ret
= volume
.InitCheck();
205 ret
= volume
.GetRootDirectory(&temp
);
207 BPath
mountPoint(&temp
, NULL
);
208 ret
= destination
->SetTo(mountPoint
.Path(), fPath
.String());
214 fprintf(stderr
, "InitPath(%s): %s\n", path
, strerror(ret
));
218 BString
pathString(destination
->Path());
220 // Hardcoded paths, the .pkg files hardcode this to the same
221 if (pathString
.FindFirst("non-packaged") < 0) {
222 bool wasRewritten
= false;
224 if (pathString
.StartsWith("/boot/beos/system")) {
225 BPath systemNonPackagedDir
;
226 find_directory(B_SYSTEM_NONPACKAGED_DIRECTORY
,
227 &systemNonPackagedDir
);
228 pathString
.ReplaceFirst("/boot/beos/system",
229 systemNonPackagedDir
.Path());
231 } else if (pathString
.StartsWith("/boot/system")) {
232 BPath systemNonPackagedDir
;
233 find_directory(B_SYSTEM_NONPACKAGED_DIRECTORY
,
234 &systemNonPackagedDir
);
235 pathString
.ReplaceFirst("/boot/system",
236 systemNonPackagedDir
.Path());
238 } else if (pathString
.StartsWith("/boot/home/config")) {
239 BPath userNonPackagedDir
;
240 find_directory(B_USER_NONPACKAGED_DIRECTORY
, &userNonPackagedDir
);
241 pathString
.ReplaceFirst("/boot/home/config",
242 userNonPackagedDir
.Path());
248 printf("rewritten: %s\n", pathString
.String());
249 destination
->SetTo(pathString
.String());
258 PackageItem::HandleAttributes(BPath
*destination
, BNode
*node
,
263 BVolume
volume(dev_for_path(destination
->Path()));
264 if (volume
.KnowsAttr()) {
265 parser_debug("We have an offset\n");
269 ret
= fPackage
->InitCheck();
273 // We need to parse the data section now
274 fPackage
->Seek(fOffset
, SEEK_SET
);
276 if (fPackage
->Read(buffer
, 7) != 7 || memcmp(buffer
, header
, 5))
278 parser_debug("Header validated!\n");
282 uint8
*attrData
= new uint8
[P_CHUNK_SIZE
];
283 uint64 dataSize
= P_CHUNK_SIZE
;
284 uint8
*temp
= new uint8
[P_CHUNK_SIZE
];
285 uint64 tempSize
= P_CHUNK_SIZE
;
287 uint64 attrCSize
= 0, attrOSize
= 0;
288 uint32 attrType
= 0; // type_code type
289 bool attrStarted
= false, done
= false;
291 while (fPackage
->Read(buffer
, 7) == 7) {
292 if (!memcmp(buffer
, "FBeA", 5))
295 ret
= ParseAttribute(buffer
, node
, &attrName
, &nameSize
, &attrType
,
296 &attrData
, &dataSize
, &temp
, &tempSize
, &attrCSize
, &attrOSize
,
297 &attrStarted
, &done
);
298 if (ret
!= B_OK
|| done
) {
300 parser_debug("_ParseAttribute failed for %s\n",
301 destination
->Path());
316 PackageItem::ParseAttribute(uint8
* buffer
, BNode
* node
, char** attrName
,
317 uint32
* nameSize
, uint32
* attrType
, uint8
** attrData
, uint64
* dataSize
,
318 uint8
** temp
, uint64
* tempSize
, uint64
* attrCSize
, uint64
* attrOSize
,
319 bool* attrStarted
, bool* done
)
324 if (!memcmp(buffer
, "BeAI", 5)) {
325 parser_debug(" Attribute started.\n");
332 } else if (!memcmp(buffer
, "BeAN", 5)) {
338 parser_debug(" BeAN.\n");
339 fPackage
->Read(&length
, 4);
340 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
341 B_SWAP_BENDIAN_TO_HOST
);
343 if (*nameSize
< (length
+ 1)) {
345 *nameSize
= length
+ 1;
346 *attrName
= new char[*nameSize
];
348 fPackage
->Read(*attrName
, length
);
349 (*attrName
)[length
] = 0;
351 parser_debug(" (%ld) = %s\n", length
, *attrName
);
352 } else if (!memcmp(buffer
, "BeAT", 5)) {
358 parser_debug(" BeAT.\n");
359 fPackage
->Read(attrType
, 4);
360 swap_data(B_UINT32_TYPE
, attrType
, sizeof(*attrType
),
361 B_SWAP_BENDIAN_TO_HOST
);
362 } else if (!memcmp(buffer
, "BeAD", 5)) {
368 parser_debug(" BeAD.\n");
369 fPackage
->Read(attrCSize
, 8);
370 swap_data(B_UINT64_TYPE
, attrCSize
, sizeof(*attrCSize
),
371 B_SWAP_BENDIAN_TO_HOST
);
373 fPackage
->Read(attrOSize
, 8);
374 swap_data(B_UINT64_TYPE
, attrOSize
, sizeof(*attrOSize
),
375 B_SWAP_BENDIAN_TO_HOST
);
377 fPackage
->Seek(4, SEEK_CUR
); // TODO: Check what this means
379 if (*tempSize
< *attrCSize
) {
381 *tempSize
= *attrCSize
;
382 *temp
= new uint8
[*tempSize
];
384 if (*dataSize
< *attrOSize
) {
386 *dataSize
= *attrOSize
;
387 *attrData
= new uint8
[*dataSize
];
390 if (fPackage
->Read(*temp
, *attrCSize
)
391 != static_cast<ssize_t
>(*attrCSize
)) {
396 parser_debug(" Data read successfuly. Inflating!\n");
397 ret
= inflate_data(*temp
, *tempSize
, *attrData
, *dataSize
);
400 } else if (!memcmp(buffer
, padding
, 7)) {
406 parser_debug(" Padding.\n");
407 ssize_t wrote
= node
->WriteAttr(*attrName
, *attrType
, 0, *attrData
,
409 if (wrote
!= static_cast<ssize_t
>(*attrOSize
)) {
410 parser_debug("Failed to write attribute %s %s\n", *attrName
, strerror(wrote
));
414 *attrStarted
= false;
420 parser_debug(" > Attribute added.\n");
422 parser_debug(" Unknown attribute\n");
431 PackageItem::SkipAttribute(uint8
* buffer
, bool* attrStarted
, bool* done
)
436 if (!memcmp(buffer
, "BeAI", 5)) {
437 parser_debug(" Attribute started.\n");
439 } else if (!memcmp(buffer
, "BeAN", 5)) {
445 parser_debug(" BeAN.\n");
446 fPackage
->Read(&length
, 4);
447 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
448 B_SWAP_BENDIAN_TO_HOST
);
450 fPackage
->Seek(length
, SEEK_CUR
);
451 } else if (!memcmp(buffer
, "BeAT", 5)) {
457 parser_debug(" BeAT.\n");
458 fPackage
->Seek(4, SEEK_CUR
);
459 } else if (!memcmp(buffer
, "BeAD", 5)) {
465 parser_debug(" BeAD.\n");
467 fPackage
->Read(&length64
, 8);
468 swap_data(B_UINT64_TYPE
, &length64
, sizeof(length64
),
469 B_SWAP_BENDIAN_TO_HOST
);
471 fPackage
->Seek(12 + length64
, SEEK_CUR
);
473 parser_debug(" Data skipped successfuly.\n");
474 } else if (!memcmp(buffer
, padding
, 7)) {
480 parser_debug(" Padding.\n");
481 *attrStarted
= false;
482 parser_debug(" > Attribute skipped.\n");
484 parser_debug(" Unknown attribute\n");
493 PackageItem::ParseData(uint8
* buffer
, BFile
* file
, uint64 originalSize
,
498 if (!memcmp(buffer
, "FiMF", 5)) {
499 parser_debug(" Found file data.\n");
500 uint64 compressed
, original
;
501 fPackage
->Read(&compressed
, 8);
502 swap_data(B_UINT64_TYPE
, &compressed
, sizeof(uint64
),
503 B_SWAP_BENDIAN_TO_HOST
);
505 fPackage
->Read(&original
, 8);
506 swap_data(B_UINT64_TYPE
, &original
, sizeof(uint64
),
507 B_SWAP_BENDIAN_TO_HOST
);
508 parser_debug(" Still good... (%llu : %llu)\n", original
,
511 if (original
!= originalSize
) {
512 parser_debug(" File size mismatch\n");
513 return B_ERROR
; // File size mismatch
515 parser_debug(" Still good...\n");
517 if (fPackage
->Read(buffer
, 4) != 4) {
518 parser_debug(" Read(buffer, 4) failed\n");
521 parser_debug(" Still good...\n");
523 ret
= inflate_file_to_file(fPackage
, compressed
, file
, original
);
525 parser_debug(" inflate_file_to_file failed\n");
528 parser_debug(" File data inflation complete!\n");
529 } else if (!memcmp(buffer
, padding
, 7)) {
533 parser_debug("_ParseData unknown tag\n");
541 // #pragma mark - PackageScript
544 PackageScript::PackageScript(BFile
* parent
, const BString
& path
, uint8 type
,
545 uint64 offset
, uint64 size
, uint64 originalSize
)
547 PackageItem(parent
, path
, type
, 0, 0, offset
, size
),
548 fOriginalSize(originalSize
),
555 PackageScript::DoInstall(const char* path
, ItemState
* state
)
558 parser_debug("Script: DoInstall() called!\n");
561 parser_debug("We have an offset\n");
565 ret
= fPackage
->InitCheck();
569 // We need to parse the data section now
570 fPackage
->Seek(fOffset
, SEEK_SET
);
572 bool attrStarted
= false, done
= false;
574 uint8 section
= P_ATTRIBUTE
;
576 while (fPackage
->Read(buffer
, 7) == 7) {
577 if (!memcmp(buffer
, "FBeA", 5)) {
578 parser_debug("-> Attribute\n");
579 section
= P_ATTRIBUTE
;
581 } else if (!memcmp(buffer
, "FiDa", 5)) {
582 parser_debug("-> File data\n");
589 ret
= SkipAttribute(buffer
, &attrStarted
, &done
);
595 ret
= _ParseScript(buffer
, fOriginalSize
, script
, &done
);
597 // Rewrite Deskbar entry targets. NOTE: It would
598 // also work to Replace("/config/be", "/config...")
599 // but it would be less save. For example, an app
600 // could have a folder named "config/be..." inside
601 // its installation folder.
602 // TODO: Use find_paths() or we are no better than
605 "/boot/beos/system/",
609 "~/config/settings/deskbar/menu");
611 "/boot/home/config/be",
612 "/boot/home/config/settings/deskbar/menu");
613 // Rewrite all sorts of other old BeOS paths
616 "/boot/system/preferences");
619 "/boot/system/non-packaged/apps");
621 "~/config/add-ons/Screen\\ Savers",
622 "~/config/non-packaged/add-ons/Screen\\ Savers");
623 // TODO: More. These should also be put into a
624 // common source location, since it can also be used
625 // for the retargetting of install file locations.
626 // Packages seem to declare which system paths they
627 // use, and then package items can reference one of
628 // those global paths by index. A more elegent solution
629 // compared to what happens now in InitPath() would be
630 // to replace those global package paths. Or maybe
631 // that's more fragile... but a common source for
632 // the rewriting of BeOS paths is needed.
635 printf("%s\n", script
.String());
637 BPath workingDirectory
;
639 ret
= InitPath(path
, &workingDirectory
);
641 ret
= workingDirectory
.SetTo(".");
643 ret
= _RunScript(workingDirectory
.Path(), script
);
652 if (ret
!= B_OK
|| done
)
657 parser_debug("Ret: %ld %s\n", ret
, strerror(ret
));
663 PackageScript::ItemKind()
665 return P_KIND_SCRIPT
;
670 PackageScript::_ParseScript(uint8
*buffer
, uint64 originalSize
,
671 BString
& _script
, bool *done
)
675 if (!memcmp(buffer
, "FiMF", 5)) {
676 parser_debug(" Found file (script) data.\n");
677 uint64 compressed
, original
;
678 fPackage
->Read(&compressed
, 8);
679 swap_data(B_UINT64_TYPE
, &compressed
, sizeof(uint64
),
680 B_SWAP_BENDIAN_TO_HOST
);
682 fPackage
->Read(&original
, 8);
683 swap_data(B_UINT64_TYPE
, &original
, sizeof(uint64
),
684 B_SWAP_BENDIAN_TO_HOST
);
685 parser_debug(" Still good... (%llu : %llu)\n", original
,
688 if (original
!= originalSize
) {
689 parser_debug(" File size mismatch\n");
690 return B_ERROR
; // File size mismatch
692 parser_debug(" Still good...\n");
694 if (fPackage
->Read(buffer
, 4) != 4) {
695 parser_debug(" Read(buffer, 4) failed\n");
698 parser_debug(" Still good...\n");
700 uint8
*temp
= new uint8
[compressed
];
701 if (fPackage
->Read(temp
, compressed
) != (int64
)compressed
) {
702 parser_debug(" Read(temp, compressed) failed\n");
707 uint8
* script
= new uint8
[original
];
708 ret
= inflate_data(temp
, compressed
, script
, original
);
710 parser_debug(" inflate_data failed\n");
716 _script
.SetTo((char*)script
, originalSize
);
720 parser_debug(" Script data inflation complete!\n");
721 } else if (!memcmp(buffer
, padding
, 7)) {
725 parser_debug("_ParseData unknown tag\n");
734 PackageScript::_RunScript(const char* workingDirectory
, const BString
& script
)
736 // This function written by Peter Folk <pfolk@uni.uiuc.edu>
737 // and published in the BeDevTalk FAQ, modified for use in the
739 // http://www.abisoft.com/faq/BeDevTalk_FAQ.html#FAQ-209
741 // Change current working directory to install path
742 char oldWorkingDirectory
[B_PATH_NAME_LENGTH
];
743 getcwd(oldWorkingDirectory
, sizeof(oldWorkingDirectory
));
744 chdir(workingDirectory
);
748 int old_out
= dup(1);
749 int old_err
= dup(2);
753 /* Create new pipe FDs as stdin, stdout, stderr */
754 pipe(filedes
); dup2(filedes
[0], 0); close(filedes
[0]);
755 int in
= filedes
[1]; // Write to in, appears on cmd's stdin
756 pipe(filedes
); dup2(filedes
[1], 1); close(filedes
[1]);
757 pipe(filedes
); dup2(filedes
[1], 2); close(filedes
[1]);
759 const char **argv
= new const char * [3];
760 argv
[0] = strdup("/bin/sh");
761 argv
[1] = strdup("-s");
765 fThreadId
= load_image(2, argv
, (const char**)environ
);
768 for (i
= 0; i
< 2; i
++)
772 if (fThreadId
< B_OK
)
775 // thread id is now suspended.
776 setpgid(fThreadId
, fThreadId
);
779 close(0); dup(old_in
); close(old_in
);
780 close(1); dup(old_out
); close(old_out
);
781 close(2); dup(old_err
); close(old_err
);
783 set_thread_priority(fThreadId
, B_LOW_PRIORITY
);
784 resume_thread(fThreadId
);
787 if (write(in
, script
.String(), script
.Length() - 1) != script
.Length() - 1
788 || write(in
, "\nexit\n", 6) != 6) {
789 parser_debug("Writing script failed\n");
790 kill_thread(fThreadId
);
794 // Restore current working directory
795 chdir(oldWorkingDirectory
);
801 // #pragma mark - PackageDirectory
804 PackageDirectory::PackageDirectory(BFile
* parent
, const BString
& path
,
805 uint8 type
, uint32 ctime
, uint32 mtime
, uint64 offset
, uint64 size
)
807 PackageItem(parent
, path
, type
, ctime
, mtime
, offset
, size
)
813 PackageDirectory::DoInstall(const char* path
, ItemState
* state
)
815 BPath
&destination
= state
->destination
;
817 parser_debug("Directory: %s DoInstall() called!\n", fPath
.String());
819 ret
= InitPath(path
, &destination
);
820 parser_debug("Ret: %ld %s\n", ret
, strerror(ret
));
824 // Since Haiku is single-user right now, we give the newly
825 // created directory default permissions
826 ret
= create_directory(destination
.Path(), kDefaultMode
);
827 parser_debug("Create dir ret: %ld %s\n", ret
, strerror(ret
));
830 BDirectory
dir(destination
.Path());
831 parser_debug("Directory created!\n");
834 dir
.SetCreationTime(static_cast<time_t>(fCreationTime
));
836 if (fModificationTime
)
837 dir
.SetModificationTime(static_cast<time_t>(fModificationTime
));
839 // Since directories can only have attributes in the offset section,
840 // we can check here whether it is necessary to continue
842 ret
= HandleAttributes(&destination
, &dir
, "FoDa");
844 parser_debug("Ret: %ld %s\n", ret
, strerror(ret
));
850 PackageDirectory::ItemKind()
852 return P_KIND_DIRECTORY
;
856 // #pragma mark - PackageFile
859 PackageFile::PackageFile(BFile
*parent
, const BString
&path
, uint8 type
,
860 uint32 ctime
, uint32 mtime
, uint64 offset
, uint64 size
,
861 uint64 originalSize
, uint32 platform
, const BString
&mime
,
862 const BString
&signature
, uint32 mode
)
864 PackageItem(parent
, path
, type
, ctime
, mtime
, offset
, size
),
865 fOriginalSize(originalSize
),
869 fSignature(signature
)
875 PackageFile::DoInstall(const char* path
, ItemState
* state
)
880 BPath
& destination
= state
->destination
;
882 parser_debug("File: %s DoInstall() called!\n", fPath
.String());
885 if (state
->status
== B_NO_INIT
|| destination
.InitCheck() != B_OK
) {
886 ret
= InitPath(path
, &destination
);
890 ret
= file
.SetTo(destination
.Path(),
891 B_WRITE_ONLY
| B_CREATE_FILE
| B_FAIL_IF_EXISTS
);
892 if (ret
== B_ENTRY_NOT_FOUND
) {
894 destination
.GetParent(&directory
);
895 if (create_directory(directory
.Path(), kDefaultMode
) != B_OK
)
898 ret
= file
.SetTo(destination
.Path(), B_WRITE_ONLY
| B_CREATE_FILE
);
899 } else if (ret
== B_FILE_EXISTS
)
900 state
->status
= B_FILE_EXISTS
;
906 if (state
->status
== B_FILE_EXISTS
) {
907 switch (state
->policy
) {
908 case P_EXISTS_OVERWRITE
:
909 ret
= file
.SetTo(destination
.Path(),
910 B_WRITE_ONLY
| B_ERASE_FILE
);
926 parser_debug(" File created!\n");
928 // Set the file permissions, creation and modification times
929 ret
= file
.SetPermissions(static_cast<mode_t
>(fMode
));
930 if (fCreationTime
&& ret
== B_OK
)
931 ret
= file
.SetCreationTime(static_cast<time_t>(fCreationTime
));
932 if (fModificationTime
&& ret
== B_OK
)
933 ret
= file
.SetModificationTime(static_cast<time_t>(fModificationTime
));
938 // Set the mimetype and application signature if present
939 BNodeInfo
info(&file
);
940 if (fMimeType
.Length() > 0) {
941 ret
= info
.SetType(fMimeType
.String());
945 if (fSignature
.Length() > 0) {
946 ret
= info
.SetPreferredApp(fSignature
.String());
952 parser_debug("We have an offset\n");
956 ret
= fPackage
->InitCheck();
960 // We need to parse the data section now
961 fPackage
->Seek(fOffset
, SEEK_SET
);
966 uint8
*attrData
= new uint8
[P_CHUNK_SIZE
];
967 uint64 dataSize
= P_CHUNK_SIZE
;
968 uint8
*temp
= new uint8
[P_CHUNK_SIZE
];
969 uint64 tempSize
= P_CHUNK_SIZE
;
971 uint64 attrCSize
= 0, attrOSize
= 0;
972 uint32 attrType
= 0; // type_code type
973 bool attrStarted
= false, done
= false;
975 uint8 section
= P_ATTRIBUTE
;
977 while (fPackage
->Read(buffer
, 7) == 7) {
978 if (!memcmp(buffer
, "FBeA", 5)) {
979 parser_debug("-> Attribute\n");
980 section
= P_ATTRIBUTE
;
982 } else if (!memcmp(buffer
, "FiDa", 5)) {
983 parser_debug("-> File data\n");
990 ret
= ParseAttribute(buffer
, &file
, &attrName
, &nameSize
,
991 &attrType
, &attrData
, &dataSize
, &temp
, &tempSize
,
992 &attrCSize
, &attrOSize
, &attrStarted
, &done
);
996 ret
= ParseData(buffer
, &file
, fOriginalSize
, &done
);
1003 if (ret
!= B_OK
|| done
)
1016 PackageFile::ItemKind()
1025 PackageLink::PackageLink(BFile
*parent
, const BString
&path
,
1026 const BString
&link
, uint8 type
, uint32 ctime
, uint32 mtime
,
1027 uint32 mode
, uint64 offset
, uint64 size
)
1029 PackageItem(parent
, path
, type
, ctime
, mtime
, offset
, size
),
1037 PackageLink::DoInstall(const char *path
, ItemState
*state
)
1042 status_t ret
= B_OK
;
1044 parser_debug("Symlink: %s DoInstall() called!\n", fPath
.String());
1046 BPath
&destination
= state
->destination
;
1047 BDirectory
*dir
= &state
->parent
;
1049 if (state
->status
== B_NO_INIT
|| destination
.InitCheck() != B_OK
1050 || dir
->InitCheck() != B_OK
) {
1051 // Not yet initialized
1052 ret
= InitPath(path
, &destination
);
1056 BString
linkName(destination
.Leaf());
1057 parser_debug("%s:%s:%s\n", fPath
.String(), destination
.Path(),
1061 ret
= destination
.GetParent(&dirPath
);
1062 ret
= dir
->SetTo(dirPath
.Path());
1064 if (ret
== B_ENTRY_NOT_FOUND
) {
1065 ret
= create_directory(dirPath
.Path(), kDefaultMode
);
1067 parser_debug("create_directory()) failed\n");
1072 parser_debug("destination InitCheck failed %s for %s\n",
1073 strerror(ret
), dirPath
.Path());
1077 ret
= dir
->CreateSymLink(destination
.Path(), fLink
.String(), &symlink
);
1078 if (ret
== B_FILE_EXISTS
) {
1079 // We need to check if the existing symlink is pointing at the same path
1080 // as our new one - if not, let's prompt the user
1081 symlink
.SetTo(destination
.Path());
1084 ret
= symlink
.MakeLinkedPath(dir
, &oldLink
);
1085 chdir(dirPath
.Path());
1087 if (ret
== B_BAD_VALUE
|| oldLink
!= fLink
.String())
1088 state
->status
= ret
= B_FILE_EXISTS
;
1094 if (state
->status
== B_FILE_EXISTS
) {
1095 switch (state
->policy
) {
1096 case P_EXISTS_OVERWRITE
:
1099 ret
= entry
.SetTo(destination
.Path());
1104 ret
= dir
->CreateSymLink(destination
.Path(), fLink
.String(),
1111 ret
= B_FILE_EXISTS
;
1120 parser_debug("CreateSymLink failed\n");
1124 parser_debug(" Symlink created!\n");
1126 ret
= symlink
.SetPermissions(static_cast<mode_t
>(fMode
));
1128 if (fCreationTime
&& ret
== B_OK
)
1129 ret
= symlink
.SetCreationTime(static_cast<time_t>(fCreationTime
));
1131 if (fModificationTime
&& ret
== B_OK
) {
1132 ret
= symlink
.SetModificationTime(static_cast<time_t>(
1133 fModificationTime
));
1137 parser_debug("Failed to set symlink attributes\n");
1142 // Symlinks also seem to have attributes - so parse them
1143 ret
= HandleAttributes(&destination
, &symlink
, "LnDa");
1151 PackageLink::ItemKind()
1153 return P_KIND_SYM_LINK
;