/* * Copyright (c) 2007, Haiku, Inc. * Distributed under the terms of the MIT license. * * Author: * Ɓukasz 'Sil2100' Zemczak */ #include "InstalledPackageInfo.h" #include #include #include #include #include const char * kPackagesDir = "packages"; static status_t info_prepare(const char *filename, BFile *file, BMessage *info) { if (!filename) return B_ERROR; BPath path; if (find_directory(B_USER_CONFIG_DIRECTORY, &path) != B_OK || path.Append(kPackagesDir) != B_OK || path.Append(filename) != B_OK) return B_ERROR; file->SetTo(path.Path(), B_READ_ONLY); if (file->InitCheck() != B_OK) return B_ERROR; status_t ret = info->Unflatten(file); if (ret != B_OK || info->what != P_PACKAGE_INFO) return B_ERROR; return B_OK; } const char * info_get_package_name(const char *filename) { BFile file; BMessage info; if (info_prepare(filename, &file, &info) != B_OK) return NULL; BString name; info.FindString("package_name", &name); return name.String(); } const char * info_get_package_version(const char *filename) { BFile file; BMessage info; if (info_prepare(filename, &file, &info) != B_OK) return NULL; BString version; info.FindString("package_version", &version); return version.String(); } InstalledPackageInfo::InstalledPackageInfo() : fStatus(B_NO_INIT), fIsUpToDate(false), fCreate(false), fInstalledItems(10) { } InstalledPackageInfo::InstalledPackageInfo(const char *packageName, const char *version, bool create) : fStatus(B_NO_INIT), fIsUpToDate(false), fInstalledItems(10) { SetTo(packageName, version, create); } InstalledPackageInfo::~InstalledPackageInfo() { _ClearItemList(); } status_t InstalledPackageInfo::InitCheck() { return fStatus; } status_t InstalledPackageInfo::SetTo(const char *packageName, const char *version, bool create) { _ClearItemList(); fCreate = create; fStatus = B_NO_INIT; fVersion = version; if (!packageName) return fStatus; BPath configPath; if (find_directory(B_USER_CONFIG_DIRECTORY, &configPath) != B_OK) { fStatus = B_ERROR; return fStatus; } if (fPathToInfo.SetTo(configPath.Path(), kPackagesDir) != B_OK) { fStatus = B_ERROR; return fStatus; } // Check whether the directory exists BDirectory packageDir(fPathToInfo.Path()); fStatus = packageDir.InitCheck(); if (fStatus == B_ENTRY_NOT_FOUND) { // If not, create it packageDir.SetTo(configPath.Path()); if (packageDir.CreateDirectory(kPackagesDir, &packageDir) != B_OK) { fStatus = B_ERROR; return fStatus; } } BString filename = packageName; filename << version << ".pdb"; if (fPathToInfo.Append(filename.String()) != B_OK) { fStatus = B_ERROR; return fStatus; } BFile package(fPathToInfo.Path(), B_READ_ONLY); fStatus = package.InitCheck(); if (fStatus == B_OK) { // The given package exists, so we can unflatten the data to a message // and then pass it further BMessage info; if (info.Unflatten(&package) != B_OK || info.what != P_PACKAGE_INFO) { fStatus = B_ERROR; return fStatus; } int32 count; fStatus = info.FindString("package_name", &fName); fStatus |= info.FindString("package_desc", &fDescription); fStatus |= info.FindString("package_version", &fVersion); int64 spaceNeeded = 0; fStatus |= info.FindInt64("package_size", &spaceNeeded); fSpaceNeeded = static_cast(spaceNeeded); fStatus |= info.FindInt32("file_count", &count); if (fStatus != B_OK) { fStatus = B_ERROR; return fStatus; } int32 i; BString itemPath; for (i = 0; i < count; i++) { if (info.FindString("items", i, &itemPath) != B_OK) { fStatus = B_ERROR; return fStatus; } fInstalledItems.AddItem(new BString(itemPath)); // Or maybe BPath better? } fIsUpToDate = true; } else if (fStatus == B_ENTRY_NOT_FOUND) { if (create) { fStatus = B_OK; fIsUpToDate = false; } } return fStatus; } status_t InstalledPackageInfo::AddItem(const char *itemName) { if (!itemName) return B_ERROR; return fInstalledItems.AddItem(new BString(itemName)); } status_t InstalledPackageInfo::Uninstall() { if (fStatus != B_OK) return fStatus; BString *iter; uint32 i, count = fInstalledItems.CountItems(); BEntry entry; status_t ret; // Try to remove all entries that are present in the list for (i = 0; i < count; i++) { iter = static_cast(fInstalledItems.ItemAt(count - i - 1)); fprintf(stderr, "Removing: %s (%ld/%ld)\n", iter->String(), i, count); ret = entry.SetTo(iter->String()); if (ret == B_BUSY) { // The entry's directory is locked - wait a few cycles for it to // unlock itself int32 tries = 0; for (tries = 0; tries < P_BUSY_TRIES; tries++) { ret = entry.SetTo(iter->String()); if (ret != B_BUSY) break; // Wait a moment usleep(1000); } } if (ret == B_ENTRY_NOT_FOUND) continue; else if (ret != B_OK) { fStatus = B_ERROR; return fStatus; } fprintf(stderr, "...we continue\n"); if (entry.Exists() && entry.Remove() != B_OK) { fprintf(stderr, "\n%s\n", strerror(ret)); fStatus = B_ERROR; return fStatus; } fInstalledItems.RemoveItem(count - i - 1); } if (entry.SetTo(fPathToInfo.Path()) != B_OK) { fStatus = B_ERROR; return fStatus; } if (entry.Exists() && entry.Remove() != B_OK) { fStatus = B_ERROR; return fStatus; } return fStatus; } status_t InstalledPackageInfo::Save() { // If the package info is not up to date and everything till now was // done correctly, we will save all data as a flattened BMessage to the // package info file if (fIsUpToDate || fStatus != B_OK) return fStatus; BFile package; if (fCreate) { fStatus = package.SetTo(fPathToInfo.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); } else { fStatus = package.SetTo(fPathToInfo.Path(), B_WRITE_ONLY | B_ERASE_FILE); } if (fStatus != B_OK) return fStatus; status_t ret; int32 i, count = fInstalledItems.CountItems(); BMessage info(P_PACKAGE_INFO); ret = info.AddString("package_name", fName); ret |= info.AddString("package_desc", fDescription); ret |= info.AddString("package_version", fVersion); ret |= info.AddInt64("package_size", fSpaceNeeded); ret |= info.AddInt32("file_count", count); if (ret != B_OK) { fStatus = B_ERROR; return fStatus; } BString *iter; for (i = 0; i < count; i++) { iter = static_cast(fInstalledItems.ItemAt(i)); if (info.AddString("items", *iter) != B_OK) { fStatus = B_ERROR; return fStatus; } } if (info.Flatten(&package) != B_OK) { fStatus = B_ERROR; return fStatus; } fIsUpToDate = true; return fStatus; } // #pragma mark - void InstalledPackageInfo::_ClearItemList() { // Clear the items list BString *iter; uint32 i, count = fInstalledItems.CountItems(); for (i = 0; i < count; i++) { iter = static_cast(fInstalledItems.ItemAt(0)); fInstalledItems.RemoveItem((int32)0); delete iter; } }