/* * Copyright 2009-2013, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "package.h" #include "PackageInfoPrinter.h" using namespace BPackageKit; using BPackageKit::BHPKG::BErrorOutput; using BPackageKit::BHPKG::BPackageInfoAttributeValue; using BPackageKit::BHPKG::BStandardErrorOutput; struct VersionPolicyV1 { typedef BPackageKit::BHPKG::V1::BPackageContentHandler PackageContentHandler; typedef BPackageKit::BHPKG::V1::BPackageEntry PackageEntry; typedef BPackageKit::BHPKG::V1::BPackageEntryAttribute PackageEntryAttribute; typedef BPackageKit::BHPKG::V1::BPackageReader PackageReader; static inline uint64 PackageDataSize( const BPackageKit::BHPKG::V1::BPackageData& data) { return data.UncompressedSize(); } static inline status_t InitReader(PackageReader& packageReader, const char* fileName) { return packageReader.Init(fileName); } }; struct VersionPolicyV2 { typedef BPackageKit::BHPKG::BPackageContentHandler PackageContentHandler; typedef BPackageKit::BHPKG::BPackageEntry PackageEntry; typedef BPackageKit::BHPKG::BPackageEntryAttribute PackageEntryAttribute; typedef BPackageKit::BHPKG::BPackageReader PackageReader; static inline uint64 PackageDataSize( const BPackageKit::BHPKG::BPackageData& data) { return data.Size(); } static inline status_t InitReader(PackageReader& packageReader, const char* fileName) { return packageReader.Init(fileName, BPackageKit::BHPKG ::B_HPKG_READER_DONT_PRINT_VERSION_MISMATCH_MESSAGE); } }; enum ListMode { LIST_ALL, LIST_PATHS_ONLY, LIST_META_INFO_ONLY }; template struct PackageContentListHandler : VersionPolicy::PackageContentHandler { PackageContentListHandler(bool listEntries, bool listAttributes) : fPrinter(), fLevel(0), fListEntries(listEntries), fListAttribute(listEntries && listAttributes) { } virtual status_t HandleEntry(typename VersionPolicy::PackageEntry* entry) { if (!fListEntries) return B_OK; fLevel++; int indentation = (fLevel - 1) * 2; printf("%*s", indentation, ""); // name and size printf("%-*s", indentation < 32 ? 32 - indentation : 0, entry->Name()); printf(" %8llu", (unsigned long long)VersionPolicy::PackageDataSize(entry->Data())); // time struct tm* time = localtime(&entry->ModifiedTime().tv_sec); printf(" %04d-%02d-%02d %02d:%02d:%02d", 1900 + time->tm_year, time->tm_mon + 1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); // file type mode_t mode = entry->Mode(); if (S_ISREG(mode)) printf(" -"); else if (S_ISDIR(mode)) printf(" d"); else if (S_ISLNK(mode)) printf(" l"); else printf(" ?"); // permissions char buffer[4]; printf("%s", _PermissionString(buffer, mode >> 6, (mode & S_ISUID) != 0)); printf("%s", _PermissionString(buffer, mode >> 3, (mode & S_ISGID) != 0)); printf("%s", _PermissionString(buffer, mode, false)); // print the symlink path if (S_ISLNK(mode)) printf(" -> %s", entry->SymlinkPath()); printf("\n"); return B_OK; } virtual status_t HandleEntryAttribute( typename VersionPolicy::PackageEntry* entry, typename VersionPolicy::PackageEntryAttribute* attribute) { if (!fListAttribute) return B_OK; int indentation = fLevel * 2; printf("%*s<", indentation, ""); printf("%-*s %8llu", indentation < 31 ? 31 - indentation : 0, attribute->Name(), (unsigned long long)VersionPolicy::PackageDataSize( attribute->Data())); uint32 type = attribute->Type(); if (isprint(type & 0xff) && isprint((type >> 8) & 0xff) && isprint((type >> 16) & 0xff) && isprint(type >> 24)) { printf(" '%c%c%c%c'", int(type >> 24), int((type >> 16) & 0xff), int((type >> 8) & 0xff), int(type & 0xff)); } else printf(" %#" B_PRIx32, type); printf(">\n"); return B_OK; } virtual status_t HandleEntryDone( typename VersionPolicy::PackageEntry* entry) { if (!fListEntries) return B_OK; fLevel--; return B_OK; } virtual status_t HandlePackageAttribute( const BPackageInfoAttributeValue& value) { if (value.attributeID == B_PACKAGE_INFO_NAME) printf("package-attributes:\n"); if (!fPrinter.PrintAttribute(value)) { printf("*** Invalid package attribute section: unexpected " "package attribute id %d encountered\n", value.attributeID); return B_BAD_DATA; } return B_OK; } virtual void HandleErrorOccurred() { } private: static const char* _PermissionString(char* buffer, uint32 mode, bool sticky) { buffer[0] = (mode & 0x4) != 0 ? 'r' : '-'; buffer[1] = (mode & 0x2) != 0 ? 'w' : '-'; if ((mode & 0x1) != 0) buffer[2] = sticky ? 's' : 'x'; else buffer[2] = '-'; buffer[3] = '\0'; return buffer; } static void _PrintPackageVersion(const BPackageVersionData& version) { printf("%s", BPackageVersion(version).ToString().String()); } private: PackageInfoPrinter fPrinter; int fLevel; bool fListEntries; bool fListAttribute; }; template struct PackageContentListPathsHandler : VersionPolicy::PackageContentHandler { PackageContentListPathsHandler() : fPathComponents() { } virtual status_t HandleEntry(typename VersionPolicy::PackageEntry* entry) { fPathComponents.Add(entry->Name()); printf("%s\n", fPathComponents.Join("/").String()); return B_OK; } virtual status_t HandleEntryAttribute( typename VersionPolicy::PackageEntry* entry, typename VersionPolicy::PackageEntryAttribute* attribute) { return B_OK; } virtual status_t HandleEntryDone( typename VersionPolicy::PackageEntry* entry) { fPathComponents.Remove(fPathComponents.CountStrings() - 1); return B_OK; } virtual status_t HandlePackageAttribute( const BPackageInfoAttributeValue& value) { return B_OK; } virtual void HandleErrorOccurred() { } private: BStringList fPathComponents; }; template static void do_list(const char* packageFileName, bool listAttributes, ListMode listMode, bool ignoreVersionError) { // open package BStandardErrorOutput errorOutput; typename VersionPolicy::PackageReader packageReader(&errorOutput); status_t error = VersionPolicy::InitReader(packageReader, packageFileName); if (error != B_OK) { if (ignoreVersionError && error == B_MISMATCHED_VALUES) return; exit(1); } // list switch (listMode) { case LIST_PATHS_ONLY: { PackageContentListPathsHandler handler; error = packageReader.ParseContent(&handler); break; } case LIST_ALL: case LIST_META_INFO_ONLY: { PackageContentListHandler handler( listMode != LIST_META_INFO_ONLY, listAttributes); error = packageReader.ParseContent(&handler); } } if (error != B_OK) exit(1); exit(0); } int command_list(int argc, const char* const* argv) { ListMode listMode = LIST_ALL; bool listAttributes = false; while (true) { static struct option sLongOptions[] = { { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; opterr = 0; // don't print errors int c = getopt_long(argc, (char**)argv, "+ahip", sLongOptions, NULL); if (c == -1) break; switch (c) { case 'a': listAttributes = true; break; case 'i': listMode = LIST_META_INFO_ONLY; break; case 'h': print_usage_and_exit(false); break; case 'p': listMode = LIST_PATHS_ONLY; break; default: print_usage_and_exit(true); break; } } // One argument should remain -- the package file name. if (optind + 1 != argc) print_usage_and_exit(true); const char* packageFileName = argv[optind++]; // If the file doesn't look like a package file, try to load it as a // package info file. if (!BString(packageFileName).EndsWith(".hpkg")) { struct ErrorListener : BPackageInfo::ParseErrorListener { virtual void OnError(const BString& msg, int line, int col) { fprintf(stderr, "%s:%d:%d: %s\n", fPath, line, col, msg.String()); } const char* fPath; } errorListener; errorListener.fPath = packageFileName; BPackageInfo info; if (info.ReadFromConfigFile(BEntry(packageFileName), &errorListener) != B_OK) { return 1; } printf("package-attributes:\n"); PackageInfoPrinter().PrintPackageInfo(info); return 0; } BHPKG::BStandardErrorOutput errorOutput; // current package file format version do_list(packageFileName, listAttributes, listMode, true); do_list(packageFileName, listAttributes, listMode, false); return 0; }