vfs: check userland buffers before reading them.
[haiku.git] / src / kits / package / PackageInfo.cpp
blobd52457961c6663a923f1a193bc6fa2ada14a4e54
1 /*
2 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
3 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 */
8 #include <package/PackageInfo.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
14 #include <new>
16 #include <File.h>
17 #include <Entry.h>
18 #include <Message.h>
19 #include <package/hpkg/NoErrorOutput.h>
20 #include <package/hpkg/PackageReader.h>
21 #include <package/hpkg/v1/PackageInfoContentHandler.h>
22 #include <package/hpkg/v1/PackageReader.h>
23 #include <package/PackageInfoContentHandler.h>
25 #include "PackageInfoParser.h"
26 #include "PackageInfoStringBuilder.h"
29 namespace BPackageKit {
32 const char* const BPackageInfo::kElementNames[B_PACKAGE_INFO_ENUM_COUNT] = {
33 "name",
34 "summary",
35 "description",
36 "vendor",
37 "packager",
38 "architecture",
39 "version",
40 "copyrights",
41 "licenses",
42 "provides",
43 "requires",
44 "supplements",
45 "conflicts",
46 "freshens",
47 "replaces",
48 "flags",
49 "urls",
50 "source-urls",
51 "checksum", // not being parsed, computed externally
52 NULL, // install-path -- not settable via .PackageInfo
53 "base-package",
54 "global-writable-files",
55 "user-settings-files",
56 "users",
57 "groups",
58 "post-install-scripts"
62 const char* const
63 BPackageInfo::kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
64 "any",
65 "x86",
66 "x86_gcc2",
67 "source",
68 "x86_64",
69 "ppc",
70 "arm",
71 "m68k"
75 const char* const BPackageInfo::kWritableFileUpdateTypes[
76 B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT] = {
77 "keep-old",
78 "manual",
79 "auto-merge",
83 // #pragma mark - FieldName
86 struct BPackageInfo::FieldName {
87 FieldName(const char* prefix, const char* suffix)
89 size_t prefixLength = strlen(prefix);
90 size_t suffixLength = strlen(suffix);
91 if (prefixLength + suffixLength >= sizeof(fFieldName)) {
92 fFieldName[0] = '\0';
93 return;
96 memcpy(fFieldName, prefix, prefixLength);
97 memcpy(fFieldName + prefixLength, suffix, suffixLength);
98 fFieldName[prefixLength + suffixLength] = '\0';
101 bool ReplaceSuffix(size_t prefixLength, const char* suffix)
103 size_t suffixLength = strlen(suffix);
104 if (prefixLength + suffixLength >= sizeof(fFieldName)) {
105 fFieldName[0] = '\0';
106 return false;
109 memcpy(fFieldName + prefixLength, suffix, suffixLength);
110 fFieldName[prefixLength + suffixLength] = '\0';
111 return true;
114 bool IsValid() const
116 return fFieldName[0] != '\0';
119 operator const char*()
121 return fFieldName;
124 private:
125 char fFieldName[64];
129 // #pragma mark - PackageFileLocation
132 struct BPackageInfo::PackageFileLocation {
133 PackageFileLocation(const char* path)
135 fPath(path),
136 fFD(-1)
140 PackageFileLocation(int fd)
142 fPath(NULL),
143 fFD(fd)
147 const char* Path() const
149 return fPath;
152 int FD() const
154 return fFD;
157 private:
158 const char* fPath;
159 int fFD;
163 // #pragma mark - BPackageInfo
166 BPackageInfo::BPackageInfo()
168 BArchivable(),
169 fFlags(0),
170 fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
171 fCopyrightList(4),
172 fLicenseList(4),
173 fURLList(4),
174 fSourceURLList(4),
175 fGlobalWritableFileInfos(4, true),
176 fUserSettingsFileInfos(4, true),
177 fUsers(4, true),
178 fGroups(4),
179 fPostInstallScripts(4),
180 fProvidesList(20, true),
181 fRequiresList(20, true),
182 fSupplementsList(20, true),
183 fConflictsList(4, true),
184 fFreshensList(4, true),
185 fReplacesList(4)
190 BPackageInfo::BPackageInfo(BMessage* archive, status_t* _error)
192 BArchivable(archive),
193 fFlags(0),
194 fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
195 fCopyrightList(4),
196 fLicenseList(4),
197 fURLList(4),
198 fSourceURLList(4),
199 fGlobalWritableFileInfos(4, true),
200 fUserSettingsFileInfos(4, true),
201 fUsers(4, true),
202 fGroups(4),
203 fPostInstallScripts(4),
204 fProvidesList(20, true),
205 fRequiresList(20, true),
206 fSupplementsList(20, true),
207 fConflictsList(4, true),
208 fFreshensList(4, true),
209 fReplacesList(4)
211 status_t error;
212 int32 architecture;
213 if ((error = archive->FindString("name", &fName)) == B_OK
214 && (error = archive->FindString("summary", &fSummary)) == B_OK
215 && (error = archive->FindString("description", &fDescription)) == B_OK
216 && (error = archive->FindString("vendor", &fVendor)) == B_OK
217 && (error = archive->FindString("packager", &fPackager)) == B_OK
218 && (error = archive->FindString("basePackage", &fBasePackage)) == B_OK
219 && (error = archive->FindUInt32("flags", &fFlags)) == B_OK
220 && (error = archive->FindInt32("architecture", &architecture)) == B_OK
221 && (error = _ExtractVersion(archive, "version", 0, fVersion)) == B_OK
222 && (error = _ExtractStringList(archive, "copyrights", fCopyrightList))
223 == B_OK
224 && (error = _ExtractStringList(archive, "licenses", fLicenseList))
225 == B_OK
226 && (error = _ExtractStringList(archive, "urls", fURLList)) == B_OK
227 && (error = _ExtractStringList(archive, "source-urls", fSourceURLList))
228 == B_OK
229 && (error = _ExtractGlobalWritableFileInfos(archive,
230 "global-writable-files", fGlobalWritableFileInfos)) == B_OK
231 && (error = _ExtractUserSettingsFileInfos(archive, "user-settings-files",
232 fUserSettingsFileInfos)) == B_OK
233 && (error = _ExtractUsers(archive, "users", fUsers)) == B_OK
234 && (error = _ExtractStringList(archive, "groups", fGroups)) == B_OK
235 && (error = _ExtractStringList(archive, "post-install-scripts",
236 fPostInstallScripts)) == B_OK
237 && (error = _ExtractResolvables(archive, "provides", fProvidesList))
238 == B_OK
239 && (error = _ExtractResolvableExpressions(archive, "requires",
240 fRequiresList)) == B_OK
241 && (error = _ExtractResolvableExpressions(archive, "supplements",
242 fSupplementsList)) == B_OK
243 && (error = _ExtractResolvableExpressions(archive, "conflicts",
244 fConflictsList)) == B_OK
245 && (error = _ExtractResolvableExpressions(archive, "freshens",
246 fFreshensList)) == B_OK
247 && (error = _ExtractStringList(archive, "replaces", fReplacesList))
248 == B_OK
249 && (error = archive->FindString("checksum", &fChecksum)) == B_OK
250 && (error = archive->FindString("install-path", &fInstallPath)) == B_OK
251 && (error = archive->FindString("file-name", &fFileName)) == B_OK) {
252 if (architecture >= 0
253 && architecture <= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
254 fArchitecture = (BPackageArchitecture)architecture;
255 } else
256 error = B_BAD_DATA;
259 if (_error != NULL)
260 *_error = error;
264 BPackageInfo::~BPackageInfo()
269 status_t
270 BPackageInfo::ReadFromConfigFile(const BEntry& packageInfoEntry,
271 ParseErrorListener* listener)
273 status_t result = packageInfoEntry.InitCheck();
274 if (result != B_OK)
275 return result;
277 BFile file(&packageInfoEntry, B_READ_ONLY);
278 if ((result = file.InitCheck()) != B_OK)
279 return result;
281 return ReadFromConfigFile(file, listener);
285 status_t
286 BPackageInfo::ReadFromConfigFile(BFile& packageInfoFile,
287 ParseErrorListener* listener)
289 off_t size;
290 status_t result = packageInfoFile.GetSize(&size);
291 if (result != B_OK)
292 return result;
294 BString packageInfoString;
295 char* buffer = packageInfoString.LockBuffer(size);
296 if (buffer == NULL)
297 return B_NO_MEMORY;
299 if ((result = packageInfoFile.Read(buffer, size)) < size) {
300 packageInfoString.UnlockBuffer(0);
301 return result >= 0 ? B_IO_ERROR : result;
304 buffer[size] = '\0';
305 packageInfoString.UnlockBuffer(size);
307 return ReadFromConfigString(packageInfoString, listener);
311 status_t
312 BPackageInfo::ReadFromConfigString(const BString& packageInfoString,
313 ParseErrorListener* listener)
315 Clear();
317 Parser parser(listener);
318 return parser.Parse(packageInfoString, this);
322 status_t
323 BPackageInfo::ReadFromPackageFile(const char* path)
325 return _ReadFromPackageFile(PackageFileLocation(path));
329 status_t
330 BPackageInfo::ReadFromPackageFile(int fd)
332 return _ReadFromPackageFile(PackageFileLocation(fd));
336 status_t
337 BPackageInfo::InitCheck() const
339 if (fName.Length() == 0 || fSummary.Length() == 0
340 || fDescription.Length() == 0 || fVendor.Length() == 0
341 || fPackager.Length() == 0
342 || fArchitecture == B_PACKAGE_ARCHITECTURE_ENUM_COUNT
343 || fVersion.InitCheck() != B_OK
344 || fCopyrightList.IsEmpty() || fLicenseList.IsEmpty()
345 || fProvidesList.IsEmpty())
346 return B_NO_INIT;
348 // check global writable files
349 int32 globalWritableFileCount = fGlobalWritableFileInfos.CountItems();
350 for (int32 i = 0; i < globalWritableFileCount; i++) {
351 const BGlobalWritableFileInfo* info
352 = fGlobalWritableFileInfos.ItemAt(i);
353 status_t error = info->InitCheck();
354 if (error != B_OK)
355 return error;
358 // check user settings files
359 int32 userSettingsFileCount = fUserSettingsFileInfos.CountItems();
360 for (int32 i = 0; i < userSettingsFileCount; i++) {
361 const BUserSettingsFileInfo* info = fUserSettingsFileInfos.ItemAt(i);
362 status_t error = info->InitCheck();
363 if (error != B_OK)
364 return error;
367 // check users
368 int32 userCount = fUsers.CountItems();
369 for (int32 i = 0; i < userCount; i++) {
370 const BUser* user = fUsers.ItemAt(i);
371 status_t error = user->InitCheck();
372 if (error != B_OK)
373 return B_NO_INIT;
375 // make sure the user's groups are specified as groups
376 const BStringList& userGroups = user->Groups();
377 int32 groupCount = userGroups.CountStrings();
378 for (int32 k = 0; k < groupCount; k++) {
379 const BString& group = userGroups.StringAt(k);
380 if (!fGroups.HasString(group))
381 return B_BAD_VALUE;
385 // check groups
386 int32 groupCount = fGroups.CountStrings();
387 for (int32 i = 0; i< groupCount; i++) {
388 if (!BUser::IsValidUserName(fGroups.StringAt(i)))
389 return B_BAD_VALUE;
392 return B_OK;
396 const BString&
397 BPackageInfo::Name() const
399 return fName;
403 const BString&
404 BPackageInfo::Summary() const
406 return fSummary;
410 const BString&
411 BPackageInfo::Description() const
413 return fDescription;
417 const BString&
418 BPackageInfo::Vendor() const
420 return fVendor;
424 const BString&
425 BPackageInfo::Packager() const
427 return fPackager;
431 const BString&
432 BPackageInfo::BasePackage() const
434 return fBasePackage;
438 const BString&
439 BPackageInfo::Checksum() const
441 return fChecksum;
445 const BString&
446 BPackageInfo::InstallPath() const
448 return fInstallPath;
452 BString
453 BPackageInfo::FileName() const
455 return fFileName.IsEmpty() ? CanonicalFileName() : fFileName;
459 uint32
460 BPackageInfo::Flags() const
462 return fFlags;
466 BPackageArchitecture
467 BPackageInfo::Architecture() const
469 return fArchitecture;
473 const char*
474 BPackageInfo::ArchitectureName() const
476 if ((int)fArchitecture < 0
477 || fArchitecture >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
478 return NULL;
480 return kArchitectureNames[fArchitecture];
484 const BPackageVersion&
485 BPackageInfo::Version() const
487 return fVersion;
491 const BStringList&
492 BPackageInfo::CopyrightList() const
494 return fCopyrightList;
498 const BStringList&
499 BPackageInfo::LicenseList() const
501 return fLicenseList;
505 const BStringList&
506 BPackageInfo::URLList() const
508 return fURLList;
512 const BStringList&
513 BPackageInfo::SourceURLList() const
515 return fSourceURLList;
519 const BObjectList<BGlobalWritableFileInfo>&
520 BPackageInfo::GlobalWritableFileInfos() const
522 return fGlobalWritableFileInfos;
526 const BObjectList<BUserSettingsFileInfo>&
527 BPackageInfo::UserSettingsFileInfos() const
529 return fUserSettingsFileInfos;
533 const BObjectList<BUser>&
534 BPackageInfo::Users() const
536 return fUsers;
540 const BStringList&
541 BPackageInfo::Groups() const
543 return fGroups;
547 const BStringList&
548 BPackageInfo::PostInstallScripts() const
550 return fPostInstallScripts;
554 const BObjectList<BPackageResolvable>&
555 BPackageInfo::ProvidesList() const
557 return fProvidesList;
561 const BObjectList<BPackageResolvableExpression>&
562 BPackageInfo::RequiresList() const
564 return fRequiresList;
568 const BObjectList<BPackageResolvableExpression>&
569 BPackageInfo::SupplementsList() const
571 return fSupplementsList;
575 const BObjectList<BPackageResolvableExpression>&
576 BPackageInfo::ConflictsList() const
578 return fConflictsList;
582 const BObjectList<BPackageResolvableExpression>&
583 BPackageInfo::FreshensList() const
585 return fFreshensList;
589 const BStringList&
590 BPackageInfo::ReplacesList() const
592 return fReplacesList;
596 BString
597 BPackageInfo::CanonicalFileName() const
599 if (InitCheck() != B_OK)
600 return BString();
602 return BString().SetToFormat("%s-%s-%s.hpkg", fName.String(),
603 fVersion.ToString().String(), kArchitectureNames[fArchitecture]);
607 bool
608 BPackageInfo::Matches(const BPackageResolvableExpression& expression) const
610 // check for an explicit match on the package
611 if (expression.Name().StartsWith("pkg:")) {
612 return fName == expression.Name().String() + 4
613 && expression.Matches(fVersion, fVersion);
616 // search for a matching provides
617 int32 count = fProvidesList.CountItems();
618 for (int32 i = 0; i < count; i++) {
619 const BPackageResolvable* provides = fProvidesList.ItemAt(i);
620 if (expression.Matches(*provides))
621 return true;
624 return false;
628 void
629 BPackageInfo::SetName(const BString& name)
631 fName = name;
632 fName.ToLower();
636 void
637 BPackageInfo::SetSummary(const BString& summary)
639 fSummary = summary;
643 void
644 BPackageInfo::SetDescription(const BString& description)
646 fDescription = description;
650 void
651 BPackageInfo::SetVendor(const BString& vendor)
653 fVendor = vendor;
657 void
658 BPackageInfo::SetPackager(const BString& packager)
660 fPackager = packager;
664 void
665 BPackageInfo::SetBasePackage(const BString& basePackage)
667 fBasePackage = basePackage;
671 void
672 BPackageInfo::SetChecksum(const BString& checksum)
674 fChecksum = checksum;
678 void
679 BPackageInfo::SetInstallPath(const BString& installPath)
681 fInstallPath = installPath;
685 void
686 BPackageInfo::SetFileName(const BString& fileName)
688 fFileName = fileName;
692 void
693 BPackageInfo::SetVersion(const BPackageVersion& version)
695 fVersion = version;
699 void
700 BPackageInfo::SetFlags(uint32 flags)
702 fFlags = flags;
706 void
707 BPackageInfo::SetArchitecture(BPackageArchitecture architecture)
709 fArchitecture = architecture;
713 void
714 BPackageInfo::ClearCopyrightList()
716 fCopyrightList.MakeEmpty();
720 status_t
721 BPackageInfo::AddCopyright(const BString& copyright)
723 return fCopyrightList.Add(copyright) ? B_OK : B_ERROR;
727 void
728 BPackageInfo::ClearLicenseList()
730 fLicenseList.MakeEmpty();
734 status_t
735 BPackageInfo::AddLicense(const BString& license)
737 return fLicenseList.Add(license) ? B_OK : B_ERROR;
741 void
742 BPackageInfo::ClearURLList()
744 fURLList.MakeEmpty();
748 status_t
749 BPackageInfo::AddURL(const BString& url)
751 return fURLList.Add(url) ? B_OK : B_NO_MEMORY;
755 void
756 BPackageInfo::ClearSourceURLList()
758 fSourceURLList.MakeEmpty();
762 status_t
763 BPackageInfo::AddSourceURL(const BString& url)
765 return fSourceURLList.Add(url) ? B_OK : B_NO_MEMORY;
769 void
770 BPackageInfo::ClearGlobalWritableFileInfos()
772 fGlobalWritableFileInfos.MakeEmpty();
776 status_t
777 BPackageInfo::AddGlobalWritableFileInfo(const BGlobalWritableFileInfo& info)
779 BGlobalWritableFileInfo* newInfo
780 = new (std::nothrow) BGlobalWritableFileInfo(info);
781 if (newInfo == NULL || !fGlobalWritableFileInfos.AddItem(newInfo)) {
782 delete newInfo;
783 return B_NO_MEMORY;
786 return B_OK;
790 void
791 BPackageInfo::ClearUserSettingsFileInfos()
793 fUserSettingsFileInfos.MakeEmpty();
797 status_t
798 BPackageInfo::AddUserSettingsFileInfo(const BUserSettingsFileInfo& info)
800 BUserSettingsFileInfo* newInfo
801 = new (std::nothrow) BUserSettingsFileInfo(info);
802 if (newInfo == NULL || !fUserSettingsFileInfos.AddItem(newInfo)) {
803 delete newInfo;
804 return B_NO_MEMORY;
807 return B_OK;
811 void
812 BPackageInfo::ClearUsers()
814 fUsers.MakeEmpty();
818 status_t
819 BPackageInfo::AddUser(const BUser& user)
821 BUser* newUser = new (std::nothrow) BUser(user);
822 if (newUser == NULL || !fUsers.AddItem(newUser)) {
823 delete newUser;
824 return B_NO_MEMORY;
827 return B_OK;
831 void
832 BPackageInfo::ClearGroups()
834 fGroups.MakeEmpty();
838 status_t
839 BPackageInfo::AddGroup(const BString& group)
841 return fGroups.Add(group) ? B_OK : B_NO_MEMORY;
845 void
846 BPackageInfo::ClearPostInstallScripts()
848 fPostInstallScripts.MakeEmpty();
852 status_t
853 BPackageInfo::AddPostInstallScript(const BString& path)
855 return fPostInstallScripts.Add(path) ? B_OK : B_NO_MEMORY;
859 void
860 BPackageInfo::ClearProvidesList()
862 fProvidesList.MakeEmpty();
866 status_t
867 BPackageInfo::AddProvides(const BPackageResolvable& provides)
869 BPackageResolvable* newProvides
870 = new (std::nothrow) BPackageResolvable(provides);
871 if (newProvides == NULL)
872 return B_NO_MEMORY;
874 return fProvidesList.AddItem(newProvides) ? B_OK : B_ERROR;
878 void
879 BPackageInfo::ClearRequiresList()
881 fRequiresList.MakeEmpty();
885 status_t
886 BPackageInfo::AddRequires(const BPackageResolvableExpression& requires)
888 BPackageResolvableExpression* newRequires
889 = new (std::nothrow) BPackageResolvableExpression(requires);
890 if (newRequires == NULL)
891 return B_NO_MEMORY;
893 return fRequiresList.AddItem(newRequires) ? B_OK : B_ERROR;
897 void
898 BPackageInfo::ClearSupplementsList()
900 fSupplementsList.MakeEmpty();
904 status_t
905 BPackageInfo::AddSupplements(const BPackageResolvableExpression& supplements)
907 BPackageResolvableExpression* newSupplements
908 = new (std::nothrow) BPackageResolvableExpression(supplements);
909 if (newSupplements == NULL)
910 return B_NO_MEMORY;
912 return fSupplementsList.AddItem(newSupplements) ? B_OK : B_ERROR;
916 void
917 BPackageInfo::ClearConflictsList()
919 fConflictsList.MakeEmpty();
923 status_t
924 BPackageInfo::AddConflicts(const BPackageResolvableExpression& conflicts)
926 BPackageResolvableExpression* newConflicts
927 = new (std::nothrow) BPackageResolvableExpression(conflicts);
928 if (newConflicts == NULL)
929 return B_NO_MEMORY;
931 return fConflictsList.AddItem(newConflicts) ? B_OK : B_ERROR;
935 void
936 BPackageInfo::ClearFreshensList()
938 fFreshensList.MakeEmpty();
942 status_t
943 BPackageInfo::AddFreshens(const BPackageResolvableExpression& freshens)
945 BPackageResolvableExpression* newFreshens
946 = new (std::nothrow) BPackageResolvableExpression(freshens);
947 if (newFreshens == NULL)
948 return B_NO_MEMORY;
950 return fFreshensList.AddItem(newFreshens) ? B_OK : B_ERROR;
954 void
955 BPackageInfo::ClearReplacesList()
957 fReplacesList.MakeEmpty();
961 status_t
962 BPackageInfo::AddReplaces(const BString& replaces)
964 return fReplacesList.Add(BString(replaces).ToLower()) ? B_OK : B_ERROR;
968 void
969 BPackageInfo::Clear()
971 fName.Truncate(0);
972 fSummary.Truncate(0);
973 fDescription.Truncate(0);
974 fVendor.Truncate(0);
975 fPackager.Truncate(0);
976 fBasePackage.Truncate(0);
977 fChecksum.Truncate(0);
978 fInstallPath.Truncate(0);
979 fFileName.Truncate(0);
980 fFlags = 0;
981 fArchitecture = B_PACKAGE_ARCHITECTURE_ENUM_COUNT;
982 fVersion.Clear();
983 fCopyrightList.MakeEmpty();
984 fLicenseList.MakeEmpty();
985 fURLList.MakeEmpty();
986 fSourceURLList.MakeEmpty();
987 fGlobalWritableFileInfos.MakeEmpty();
988 fUserSettingsFileInfos.MakeEmpty();
989 fUsers.MakeEmpty();
990 fGroups.MakeEmpty();
991 fPostInstallScripts.MakeEmpty();
992 fRequiresList.MakeEmpty();
993 fProvidesList.MakeEmpty();
994 fSupplementsList.MakeEmpty();
995 fConflictsList.MakeEmpty();
996 fFreshensList.MakeEmpty();
997 fReplacesList.MakeEmpty();
1001 status_t
1002 BPackageInfo::Archive(BMessage* archive, bool deep) const
1004 status_t error = BArchivable::Archive(archive, deep);
1005 if (error != B_OK)
1006 return error;
1008 if ((error = archive->AddString("name", fName)) != B_OK
1009 || (error = archive->AddString("summary", fSummary)) != B_OK
1010 || (error = archive->AddString("description", fDescription)) != B_OK
1011 || (error = archive->AddString("vendor", fVendor)) != B_OK
1012 || (error = archive->AddString("packager", fPackager)) != B_OK
1013 || (error = archive->AddString("basePackage", fBasePackage)) != B_OK
1014 || (error = archive->AddUInt32("flags", fFlags)) != B_OK
1015 || (error = archive->AddInt32("architecture", fArchitecture)) != B_OK
1016 || (error = _AddVersion(archive, "version", fVersion)) != B_OK
1017 || (error = archive->AddStrings("copyrights", fCopyrightList))
1018 != B_OK
1019 || (error = archive->AddStrings("licenses", fLicenseList)) != B_OK
1020 || (error = archive->AddStrings("urls", fURLList)) != B_OK
1021 || (error = archive->AddStrings("source-urls", fSourceURLList))
1022 != B_OK
1023 || (error = _AddGlobalWritableFileInfos(archive,
1024 "global-writable-files", fGlobalWritableFileInfos)) != B_OK
1025 || (error = _AddUserSettingsFileInfos(archive,
1026 "user-settings-files", fUserSettingsFileInfos)) != B_OK
1027 || (error = _AddUsers(archive, "users", fUsers)) != B_OK
1028 || (error = archive->AddStrings("groups", fGroups)) != B_OK
1029 || (error = archive->AddStrings("post-install-scripts",
1030 fPostInstallScripts)) != B_OK
1031 || (error = _AddResolvables(archive, "provides", fProvidesList)) != B_OK
1032 || (error = _AddResolvableExpressions(archive, "requires",
1033 fRequiresList)) != B_OK
1034 || (error = _AddResolvableExpressions(archive, "supplements",
1035 fSupplementsList)) != B_OK
1036 || (error = _AddResolvableExpressions(archive, "conflicts",
1037 fConflictsList)) != B_OK
1038 || (error = _AddResolvableExpressions(archive, "freshens",
1039 fFreshensList)) != B_OK
1040 || (error = archive->AddStrings("replaces", fReplacesList)) != B_OK
1041 || (error = archive->AddString("checksum", fChecksum)) != B_OK
1042 || (error = archive->AddString("install-path", fInstallPath)) != B_OK
1043 || (error = archive->AddString("file-name", fFileName)) != B_OK) {
1044 return error;
1047 return B_OK;
1051 /*static*/ BArchivable*
1052 BPackageInfo::Instantiate(BMessage* archive)
1054 if (validate_instantiation(archive, "BPackageInfo"))
1055 return new(std::nothrow) BPackageInfo(archive);
1056 return NULL;
1060 status_t
1061 BPackageInfo::GetConfigString(BString& _string) const
1063 return StringBuilder()
1064 .Write("name", fName)
1065 .Write("version", fVersion)
1066 .Write("summary", fSummary)
1067 .Write("description", fDescription)
1068 .Write("vendor", fVendor)
1069 .Write("packager", fPackager)
1070 .Write("architecture", kArchitectureNames[fArchitecture])
1071 .Write("copyrights", fCopyrightList)
1072 .Write("licenses", fLicenseList)
1073 .Write("urls", fURLList)
1074 .Write("source-urls", fSourceURLList)
1075 .Write("global-writable-files", fGlobalWritableFileInfos)
1076 .Write("user-settings-files", fUserSettingsFileInfos)
1077 .Write("users", fUsers)
1078 .Write("groups", fGroups)
1079 .Write("post-install-scripts", fPostInstallScripts)
1080 .Write("provides", fProvidesList)
1081 .BeginRequires(fBasePackage)
1082 .Write("requires", fRequiresList)
1083 .EndRequires()
1084 .Write("supplements", fSupplementsList)
1085 .Write("conflicts", fConflictsList)
1086 .Write("freshens", fFreshensList)
1087 .Write("replaces", fReplacesList)
1088 .WriteFlags("flags", fFlags)
1089 .Write("checksum", fChecksum)
1090 .GetString(_string);
1091 // Note: fInstallPath and fFileName can not be specified via .PackageInfo.
1095 BString
1096 BPackageInfo::ToString() const
1098 BString string;
1099 GetConfigString(string);
1100 return string;
1104 /*static*/ status_t
1105 BPackageInfo::GetArchitectureByName(const BString& name,
1106 BPackageArchitecture& _architecture)
1108 for (int i = 0; i < B_PACKAGE_ARCHITECTURE_ENUM_COUNT; ++i) {
1109 if (name.ICompare(kArchitectureNames[i]) == 0) {
1110 _architecture = (BPackageArchitecture)i;
1111 return B_OK;
1114 return B_NAME_NOT_FOUND;
1118 /*static*/ status_t
1119 BPackageInfo::ParseVersionString(const BString& string, bool revisionIsOptional,
1120 BPackageVersion& _version, ParseErrorListener* listener)
1122 return Parser(listener).ParseVersion(string, revisionIsOptional, _version);
1126 /*static*/ status_t
1127 BPackageInfo::ParseResolvableExpressionString(const BString& string,
1128 BPackageResolvableExpression& _expression, ParseErrorListener* listener)
1130 return Parser(listener).ParseResolvableExpression(string, _expression);
1134 status_t
1135 BPackageInfo::_ReadFromPackageFile(const PackageFileLocation& fileLocation)
1137 BHPKG::BNoErrorOutput errorOutput;
1139 // try current package file format version
1141 BHPKG::BPackageReader packageReader(&errorOutput);
1142 status_t error = fileLocation.Path() != NULL
1143 ? packageReader.Init(fileLocation.Path())
1144 : packageReader.Init(fileLocation.FD(), false);
1145 if (error == B_OK) {
1146 BPackageInfoContentHandler handler(*this);
1147 return packageReader.ParseContent(&handler);
1150 if (error != B_MISMATCHED_VALUES)
1151 return error;
1154 // try package file format version 1
1155 BHPKG::V1::BPackageReader packageReader(&errorOutput);
1156 status_t error = fileLocation.Path() != NULL
1157 ? packageReader.Init(fileLocation.Path())
1158 : packageReader.Init(fileLocation.FD(), false);
1159 if (error != B_OK)
1160 return error;
1162 BHPKG::V1::BPackageInfoContentHandler handler(*this);
1163 return packageReader.ParseContent(&handler);
1167 /*static*/ status_t
1168 BPackageInfo::_AddVersion(BMessage* archive, const char* field,
1169 const BPackageVersion& version)
1171 // Storing BPackageVersion::ToString() would be nice, but the corresponding
1172 // constructor only works for valid versions and we might want to store
1173 // invalid versions as well.
1175 // major
1176 size_t fieldLength = strlen(field);
1177 FieldName fieldName(field, ":major");
1178 if (!fieldName.IsValid())
1179 return B_BAD_VALUE;
1181 status_t error = archive->AddString(fieldName, version.Major());
1182 if (error != B_OK)
1183 return error;
1185 // minor
1186 if (!fieldName.ReplaceSuffix(fieldLength, ":minor"))
1187 return B_BAD_VALUE;
1189 error = archive->AddString(fieldName, version.Minor());
1190 if (error != B_OK)
1191 return error;
1193 // micro
1194 if (!fieldName.ReplaceSuffix(fieldLength, ":micro"))
1195 return B_BAD_VALUE;
1197 error = archive->AddString(fieldName, version.Micro());
1198 if (error != B_OK)
1199 return error;
1201 // pre-release
1202 if (!fieldName.ReplaceSuffix(fieldLength, ":pre"))
1203 return B_BAD_VALUE;
1205 error = archive->AddString(fieldName, version.PreRelease());
1206 if (error != B_OK)
1207 return error;
1209 // revision
1210 if (!fieldName.ReplaceSuffix(fieldLength, ":revision"))
1211 return B_BAD_VALUE;
1213 return archive->AddUInt32(fieldName, version.Revision());
1217 /*static*/ status_t
1218 BPackageInfo::_AddResolvables(BMessage* archive, const char* field,
1219 const ResolvableList& resolvables)
1221 // construct the field names we need
1222 FieldName nameField(field, ":name");
1223 FieldName typeField(field, ":type");
1224 FieldName versionField(field, ":version");
1225 FieldName compatibleVersionField(field, ":compat");
1227 if (!nameField.IsValid() || !typeField.IsValid() || !versionField.IsValid()
1228 || !compatibleVersionField.IsValid()) {
1229 return B_BAD_VALUE;
1232 // add fields
1233 int32 count = resolvables.CountItems();
1234 for (int32 i = 0; i < count; i++) {
1235 const BPackageResolvable* resolvable = resolvables.ItemAt(i);
1236 status_t error;
1237 if ((error = archive->AddString(nameField, resolvable->Name())) != B_OK
1238 || (error = _AddVersion(archive, versionField,
1239 resolvable->Version())) != B_OK
1240 || (error = _AddVersion(archive, compatibleVersionField,
1241 resolvable->CompatibleVersion())) != B_OK) {
1242 return error;
1246 return B_OK;
1250 /*static*/ status_t
1251 BPackageInfo::_AddResolvableExpressions(BMessage* archive, const char* field,
1252 const ResolvableExpressionList& expressions)
1254 // construct the field names we need
1255 FieldName nameField(field, ":name");
1256 FieldName operatorField(field, ":operator");
1257 FieldName versionField(field, ":version");
1259 if (!nameField.IsValid() || !operatorField.IsValid()
1260 || !versionField.IsValid()) {
1261 return B_BAD_VALUE;
1264 // add fields
1265 int32 count = expressions.CountItems();
1266 for (int32 i = 0; i < count; i++) {
1267 const BPackageResolvableExpression* expression = expressions.ItemAt(i);
1268 status_t error;
1269 if ((error = archive->AddString(nameField, expression->Name())) != B_OK
1270 || (error = archive->AddInt32(operatorField,
1271 expression->Operator())) != B_OK
1272 || (error = _AddVersion(archive, versionField,
1273 expression->Version())) != B_OK) {
1274 return error;
1278 return B_OK;
1282 /*static*/ status_t
1283 BPackageInfo::_AddGlobalWritableFileInfos(BMessage* archive, const char* field,
1284 const GlobalWritableFileInfoList& infos)
1286 // construct the field names we need
1287 FieldName pathField(field, ":path");
1288 FieldName updateTypeField(field, ":updateType");
1289 FieldName isDirectoryField(field, ":isDirectory");
1291 if (!pathField.IsValid() || !updateTypeField.IsValid()
1292 || !isDirectoryField.IsValid()) {
1293 return B_BAD_VALUE;
1296 // add fields
1297 int32 count = infos.CountItems();
1298 for (int32 i = 0; i < count; i++) {
1299 const BGlobalWritableFileInfo* info = infos.ItemAt(i);
1300 status_t error;
1301 if ((error = archive->AddString(pathField, info->Path())) != B_OK
1302 || (error = archive->AddInt32(updateTypeField, info->UpdateType()))
1303 != B_OK
1304 || (error = archive->AddBool(isDirectoryField,
1305 info->IsDirectory())) != B_OK) {
1306 return error;
1310 return B_OK;
1314 /*static*/ status_t
1315 BPackageInfo::_AddUserSettingsFileInfos(BMessage* archive, const char* field,
1316 const UserSettingsFileInfoList& infos)
1318 // construct the field names we need
1319 FieldName pathField(field, ":path");
1320 FieldName templatePathField(field, ":templatePath");
1321 FieldName isDirectoryField(field, ":isDirectory");
1323 if (!pathField.IsValid() || !templatePathField.IsValid()
1324 || !isDirectoryField.IsValid()) {
1325 return B_BAD_VALUE;
1328 // add fields
1329 int32 count = infos.CountItems();
1330 for (int32 i = 0; i < count; i++) {
1331 const BUserSettingsFileInfo* info = infos.ItemAt(i);
1332 status_t error;
1333 if ((error = archive->AddString(pathField, info->Path())) != B_OK
1334 || (error = archive->AddString(templatePathField,
1335 info->TemplatePath())) != B_OK
1336 || (error = archive->AddBool(isDirectoryField,
1337 info->IsDirectory())) != B_OK) {
1338 return error;
1342 return B_OK;
1346 /*static*/ status_t
1347 BPackageInfo::_AddUsers(BMessage* archive, const char* field,
1348 const UserList& users)
1350 // construct the field names we need
1351 FieldName nameField(field, ":name");
1352 FieldName realNameField(field, ":realName");
1353 FieldName homeField(field, ":home");
1354 FieldName shellField(field, ":shell");
1355 FieldName groupsField(field, ":groups");
1357 if (!nameField.IsValid() || !realNameField.IsValid() || !homeField.IsValid()
1358 || !shellField.IsValid() || !groupsField.IsValid())
1359 return B_BAD_VALUE;
1361 // add fields
1362 int32 count = users.CountItems();
1363 for (int32 i = 0; i < count; i++) {
1364 const BUser* user = users.ItemAt(i);
1365 BString groups = user->Groups().Join(" ");
1366 if (groups.IsEmpty() && !user->Groups().IsEmpty())
1367 return B_NO_MEMORY;
1369 status_t error;
1370 if ((error = archive->AddString(nameField, user->Name())) != B_OK
1371 || (error = archive->AddString(realNameField, user->RealName()))
1372 != B_OK
1373 || (error = archive->AddString(homeField, user->Home())) != B_OK
1374 || (error = archive->AddString(shellField, user->Shell())) != B_OK
1375 || (error = archive->AddString(groupsField, groups)) != B_OK) {
1376 return error;
1380 return B_OK;
1384 /*static*/ status_t
1385 BPackageInfo::_ExtractVersion(BMessage* archive, const char* field, int32 index,
1386 BPackageVersion& _version)
1388 // major
1389 size_t fieldLength = strlen(field);
1390 FieldName fieldName(field, ":major");
1391 if (!fieldName.IsValid())
1392 return B_BAD_VALUE;
1394 BString major;
1395 status_t error = archive->FindString(fieldName, index, &major);
1396 if (error != B_OK)
1397 return error;
1399 // minor
1400 if (!fieldName.ReplaceSuffix(fieldLength, ":minor"))
1401 return B_BAD_VALUE;
1403 BString minor;
1404 error = archive->FindString(fieldName, index, &minor);
1405 if (error != B_OK)
1406 return error;
1408 // micro
1409 if (!fieldName.ReplaceSuffix(fieldLength, ":micro"))
1410 return B_BAD_VALUE;
1412 BString micro;
1413 error = archive->FindString(fieldName, index, &micro);
1414 if (error != B_OK)
1415 return error;
1417 // pre-release
1418 if (!fieldName.ReplaceSuffix(fieldLength, ":pre"))
1419 return B_BAD_VALUE;
1421 BString preRelease;
1422 error = archive->FindString(fieldName, index, &preRelease);
1423 if (error != B_OK)
1424 return error;
1426 // revision
1427 if (!fieldName.ReplaceSuffix(fieldLength, ":revision"))
1428 return B_BAD_VALUE;
1430 uint32 revision;
1431 error = archive->FindUInt32(fieldName, index, &revision);
1432 if (error != B_OK)
1433 return error;
1435 _version.SetTo(major, minor, micro, preRelease, revision);
1436 return B_OK;
1440 /*static*/ status_t
1441 BPackageInfo::_ExtractStringList(BMessage* archive, const char* field,
1442 BStringList& _list)
1444 status_t error = archive->FindStrings(field, &_list);
1445 return error == B_NAME_NOT_FOUND ? B_OK : error;
1446 // If the field doesn't exist, that's OK.
1450 /*static*/ status_t
1451 BPackageInfo::_ExtractResolvables(BMessage* archive, const char* field,
1452 ResolvableList& _resolvables)
1454 // construct the field names we need
1455 FieldName nameField(field, ":name");
1456 FieldName typeField(field, ":type");
1457 FieldName versionField(field, ":version");
1458 FieldName compatibleVersionField(field, ":compat");
1460 if (!nameField.IsValid() || !typeField.IsValid() || !versionField.IsValid()
1461 || !compatibleVersionField.IsValid()) {
1462 return B_BAD_VALUE;
1465 // get the number of items
1466 type_code type;
1467 int32 count;
1468 if (archive->GetInfo(nameField, &type, &count) != B_OK) {
1469 // the field is missing
1470 return B_OK;
1473 // extract fields
1474 for (int32 i = 0; i < count; i++) {
1475 BString name;
1476 status_t error = archive->FindString(nameField, i, &name);
1477 if (error != B_OK)
1478 return error;
1480 BPackageVersion version;
1481 error = _ExtractVersion(archive, versionField, i, version);
1482 if (error != B_OK)
1483 return error;
1485 BPackageVersion compatibleVersion;
1486 error = _ExtractVersion(archive, compatibleVersionField, i,
1487 compatibleVersion);
1488 if (error != B_OK)
1489 return error;
1491 BPackageResolvable* resolvable = new(std::nothrow) BPackageResolvable(
1492 name, version, compatibleVersion);
1493 if (resolvable == NULL || !_resolvables.AddItem(resolvable)) {
1494 delete resolvable;
1495 return B_NO_MEMORY;
1499 return B_OK;
1503 /*static*/ status_t
1504 BPackageInfo::_ExtractResolvableExpressions(BMessage* archive,
1505 const char* field, ResolvableExpressionList& _expressions)
1507 // construct the field names we need
1508 FieldName nameField(field, ":name");
1509 FieldName operatorField(field, ":operator");
1510 FieldName versionField(field, ":version");
1512 if (!nameField.IsValid() || !operatorField.IsValid()
1513 || !versionField.IsValid()) {
1514 return B_BAD_VALUE;
1517 // get the number of items
1518 type_code type;
1519 int32 count;
1520 if (archive->GetInfo(nameField, &type, &count) != B_OK) {
1521 // the field is missing
1522 return B_OK;
1525 // extract fields
1526 for (int32 i = 0; i < count; i++) {
1527 BString name;
1528 status_t error = archive->FindString(nameField, i, &name);
1529 if (error != B_OK)
1530 return error;
1532 int32 operatorType;
1533 error = archive->FindInt32(operatorField, i, &operatorType);
1534 if (error != B_OK)
1535 return error;
1536 if (operatorType < 0
1537 || operatorType > B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT) {
1538 return B_BAD_DATA;
1541 BPackageVersion version;
1542 error = _ExtractVersion(archive, versionField, i, version);
1543 if (error != B_OK)
1544 return error;
1546 BPackageResolvableExpression* expression
1547 = new(std::nothrow) BPackageResolvableExpression(name,
1548 (BPackageResolvableOperator)operatorType, version);
1549 if (expression == NULL || !_expressions.AddItem(expression)) {
1550 delete expression;
1551 return B_NO_MEMORY;
1555 return B_OK;
1559 /*static*/ status_t
1560 BPackageInfo::_ExtractGlobalWritableFileInfos(BMessage* archive,
1561 const char* field, GlobalWritableFileInfoList& _infos)
1563 // construct the field names we need
1564 FieldName pathField(field, ":path");
1565 FieldName updateTypeField(field, ":updateType");
1566 FieldName isDirectoryField(field, ":isDirectory");
1568 if (!pathField.IsValid() || !updateTypeField.IsValid()
1569 || !isDirectoryField.IsValid()) {
1570 return B_BAD_VALUE;
1573 // get the number of items
1574 type_code type;
1575 int32 count;
1576 if (archive->GetInfo(pathField, &type, &count) != B_OK) {
1577 // the field is missing
1578 return B_OK;
1581 // extract fields
1582 for (int32 i = 0; i < count; i++) {
1583 BString path;
1584 status_t error = archive->FindString(pathField, i, &path);
1585 if (error != B_OK)
1586 return error;
1588 int32 updateType;
1589 error = archive->FindInt32(updateTypeField, i, &updateType);
1590 if (error != B_OK)
1591 return error;
1592 if (updateType < 0
1593 || updateType > B_WRITABLE_FILE_UPDATE_TYPE_ENUM_COUNT) {
1594 return B_BAD_DATA;
1597 bool isDirectory;
1598 error = archive->FindBool(isDirectoryField, i, &isDirectory);
1599 if (error != B_OK)
1600 return error;
1602 BGlobalWritableFileInfo* info
1603 = new(std::nothrow) BGlobalWritableFileInfo(path,
1604 (BWritableFileUpdateType)updateType, isDirectory);
1605 if (info == NULL || !_infos.AddItem(info)) {
1606 delete info;
1607 return B_NO_MEMORY;
1611 return B_OK;
1615 /*static*/ status_t
1616 BPackageInfo::_ExtractUserSettingsFileInfos(BMessage* archive,
1617 const char* field, UserSettingsFileInfoList& _infos)
1619 // construct the field names we need
1620 FieldName pathField(field, ":path");
1621 FieldName templatePathField(field, ":templatePath");
1622 FieldName isDirectoryField(field, ":isDirectory");
1624 if (!pathField.IsValid() || !templatePathField.IsValid()
1625 || !isDirectoryField.IsValid()) {
1626 return B_BAD_VALUE;
1629 // get the number of items
1630 type_code type;
1631 int32 count;
1632 if (archive->GetInfo(pathField, &type, &count) != B_OK) {
1633 // the field is missing
1634 return B_OK;
1637 // extract fields
1638 for (int32 i = 0; i < count; i++) {
1639 BString path;
1640 status_t error = archive->FindString(pathField, i, &path);
1641 if (error != B_OK)
1642 return error;
1644 BString templatePath;
1645 error = archive->FindString(templatePathField, i, &templatePath);
1646 if (error != B_OK)
1647 return error;
1649 bool isDirectory;
1650 error = archive->FindBool(isDirectoryField, i, &isDirectory);
1651 if (error != B_OK)
1652 return error;
1654 BUserSettingsFileInfo* info = isDirectory
1655 ? new(std::nothrow) BUserSettingsFileInfo(path, true)
1656 : new(std::nothrow) BUserSettingsFileInfo(path, templatePath);
1657 if (info == NULL || !_infos.AddItem(info)) {
1658 delete info;
1659 return B_NO_MEMORY;
1663 return B_OK;
1667 /*static*/ status_t
1668 BPackageInfo::_ExtractUsers(BMessage* archive, const char* field,
1669 UserList& _users)
1671 // construct the field names we need
1672 FieldName nameField(field, ":name");
1673 FieldName realNameField(field, ":realName");
1674 FieldName homeField(field, ":home");
1675 FieldName shellField(field, ":shell");
1676 FieldName groupsField(field, ":groups");
1678 if (!nameField.IsValid() || !realNameField.IsValid() || !homeField.IsValid()
1679 || !shellField.IsValid() || !groupsField.IsValid())
1680 return B_BAD_VALUE;
1682 // get the number of items
1683 type_code type;
1684 int32 count;
1685 if (archive->GetInfo(nameField, &type, &count) != B_OK) {
1686 // the field is missing
1687 return B_OK;
1690 // extract fields
1691 for (int32 i = 0; i < count; i++) {
1692 BString name;
1693 status_t error = archive->FindString(nameField, i, &name);
1694 if (error != B_OK)
1695 return error;
1697 BString realName;
1698 error = archive->FindString(realNameField, i, &realName);
1699 if (error != B_OK)
1700 return error;
1702 BString home;
1703 error = archive->FindString(homeField, i, &home);
1704 if (error != B_OK)
1705 return error;
1707 BString shell;
1708 error = archive->FindString(shellField, i, &shell);
1709 if (error != B_OK)
1710 return error;
1712 BString groupsString;
1713 error = archive->FindString(groupsField, i, &groupsString);
1714 if (error != B_OK)
1715 return error;
1717 BStringList groups;
1718 if (!groupsString.IsEmpty() && !groupsString.Split(" ", false, groups))
1719 return B_NO_MEMORY;
1721 BUser* user = new(std::nothrow) BUser(name, realName, home, shell,
1722 groups);
1723 if (user == NULL || !_users.AddItem(user)) {
1724 delete user;
1725 return B_NO_MEMORY;
1729 return B_OK;
1733 } // namespace BPackageKit