X-Git-Url: http://gitweb/?a=blobdiff_plain;f=pkgutil.cc;h=b3afa5151e6f7c4a76638c100158002bf0fc9d65;hb=2dee8e17ce94c29744a8d097b2bf6b3165f52659;hp=13543659cd774ebb40b2856e9a3c9afccbe54bb5;hpb=25f9975ca5d5010bd4f5cbfbb9faa1fed71b3db4;p=pkgutils-cross.git diff --git a/pkgutil.cc b/pkgutil.cc index 1354365..b3afa51 100644 --- a/pkgutil.cc +++ b/pkgutil.cc @@ -2,6 +2,7 @@ // pkgutils // // Copyright (c) 2000-2005 Per Liden +// Copyright (c) 2006-2007 by CRUX team (http://crux.nu) // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -38,11 +39,14 @@ #include #include #include -#include #include #include #include +#define INIT_ARCHIVE(ar) \ + archive_read_support_compression_all((ar)); \ + archive_read_support_format_all((ar)) + using __gnu_cxx::stdio_filebuf; pkgutil::pkgutil(const string& name) @@ -343,8 +347,7 @@ pair pkgutil::pkg_open(const string& filename) const result.second.version = version; archive = archive_read_new(); - archive_read_support_compression_all(archive); - archive_read_support_format_all(archive); + INIT_ARCHIVE(archive); if (archive_read_open_filename(archive, const_cast(filename.c_str()), @@ -353,14 +356,13 @@ pair pkgutil::pkg_open(const string& filename) const for (i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; ++i) { - const struct stat* status; result.second.files.insert(result.second.files.end(), archive_entry_pathname(entry)); - status = archive_entry_stat(entry); + mode_t mode = archive_entry_mode(entry); - if (S_ISREG(status->st_mode) && + if (S_ISREG(mode) && archive_read_data_skip(archive) != ARCHIVE_OK) throw runtime_error_with_errno("could not read " + filename, archive_errno(archive)); } @@ -384,8 +386,7 @@ void pkgutil::pkg_install(const string& filename, const set& keep_list, unsigned int i; archive = archive_read_new(); - archive_read_support_compression_all(archive); - archive_read_support_format_all(archive); + INIT_ARCHIVE(archive); if (archive_read_open_filename(archive, const_cast(filename.c_str()), @@ -403,13 +404,13 @@ void pkgutil::pkg_install(const string& filename, const set& keep_list, // Check if file is filtered out via INSTALL if (non_install_list.find(archive_filename) != non_install_list.end()) { - const struct stat* status; + mode_t mode; cout << utilname << ": ignoring " << archive_filename << endl; - status = archive_entry_stat(entry); + mode = archive_entry_mode(entry); - if (S_ISREG(status->st_mode)) + if (S_ISREG(mode)) archive_read_data_skip(archive); continue; @@ -423,8 +424,9 @@ void pkgutil::pkg_install(const string& filename, const set& keep_list, (real_filename.c_str())); // Extract file - if (archive_read_extract(archive, entry, 0) != - ARCHIVE_OK) { + unsigned int flags = ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_UNLINK; + + if (archive_read_extract(archive, entry, flags) != ARCHIVE_OK) { // If a file fails to install we just print an error message and // continue trying to install the rest of the package. const char* msg = archive_error_string(archive); @@ -435,12 +437,10 @@ void pkgutil::pkg_install(const string& filename, const set& keep_list, // Check rejected file if (real_filename != original_filename) { bool remove_file = false; - const struct stat* status; - - status = archive_entry_stat(entry); + mode_t mode = archive_entry_mode(entry); // Directory - if (S_ISDIR(status->st_mode)) + if (S_ISDIR(mode)) remove_file = permissions_equal(real_filename, original_filename); // Other files else @@ -488,13 +488,20 @@ void pkgutil::ldconfig() const void pkgutil::pkg_footprint(string& filename) const { - unsigned int i; + unsigned int i; struct archive* archive; struct archive_entry* entry; + map hardlink_target_modes; + + // We first do a run over the archive and remember the modes + // of regular files. + // In the second run, we print the footprint - using the stored + // modes for hardlinks. + // + // FIXME the code duplication here is butt ugly archive = archive_read_new(); - archive_read_support_compression_all(archive); - archive_read_support_format_all(archive); + INIT_ARCHIVE(archive); if (archive_read_open_filename(archive, const_cast(filename.c_str()), @@ -503,17 +510,47 @@ void pkgutil::pkg_footprint(string& filename) const for (i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; ++i) { - const struct stat* status; - status = archive_entry_stat(entry); + mode_t mode = archive_entry_mode(entry); + + if (!archive_entry_hardlink(entry)) { + const char *s = archive_entry_pathname(entry); + + hardlink_target_modes[s] = mode; + } + + if (S_ISREG(mode) && archive_read_data_skip(archive)) + throw runtime_error_with_errno("could not read " + filename, archive_errno(archive)); + } + + archive_read_finish(archive); + + // Too bad, there doesn't seem to be a way to reuse our archive + // instance + archive = archive_read_new(); + INIT_ARCHIVE(archive); + + if (archive_read_open_filename(archive, + const_cast(filename.c_str()), + ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) + throw runtime_error_with_errno("could not open " + filename, archive_errno(archive)); + + for (i = 0; archive_read_next_header(archive, &entry) == + ARCHIVE_OK; ++i) { + mode_t mode = archive_entry_mode(entry); // Access permissions - if (S_ISLNK(status->st_mode)) { + if (S_ISLNK(mode)) { // Access permissions on symlinks differ among filesystems, e.g. XFS and ext2 have different. // To avoid getting different footprints we always use "lrwxrwxrwx". cout << "lrwxrwxrwx"; } else { - cout << mtos(archive_entry_mode(entry)); + const char *h = archive_entry_hardlink(entry); + + if (h) + cout << mtos(hardlink_target_modes[h]); + else + cout << mtos(mode); } cout << '\t'; @@ -540,16 +577,16 @@ void pkgutil::pkg_footprint(string& filename) const cout << '\t' << archive_entry_pathname(entry); // Special cases - if (S_ISLNK(status->st_mode)) { + if (S_ISLNK(mode)) { // Symlink cout << " -> " << archive_entry_symlink(entry); - } else if (S_ISCHR(status->st_mode) || - S_ISBLK(status->st_mode)) { + } else if (S_ISCHR(mode) || + S_ISBLK(mode)) { // Device cout << " (" << archive_entry_rdevmajor(entry) << ", " << archive_entry_rdevminor(entry) << ")"; - } else if (S_ISREG(status->st_mode) && + } else if (S_ISREG(mode) && archive_entry_size(entry) == 0) { // Empty regular file cout << " (EMPTY)"; @@ -557,17 +594,16 @@ void pkgutil::pkg_footprint(string& filename) const cout << '\n'; - if (S_ISREG(status->st_mode) && - archive_read_data_skip(archive)) - throw runtime_error_with_errno("could not read " + filename, archive_errno(archive)); - } + if (S_ISREG(mode) && archive_read_data_skip(archive)) + throw runtime_error_with_errno("could not read " + filename, archive_errno(archive)); + } - if (i == 0) { + if (i == 0) { if (archive_errno(archive) == 0) - throw runtime_error("empty package"); - else - throw runtime_error("could not read " + filename); - } + throw runtime_error("empty package"); + else + throw runtime_error("could not read " + filename); + } archive_read_finish(archive); } @@ -663,42 +699,6 @@ string mtos(mode_t mode) return s; } -int unistd_gzopen(char* pathname, int flags, mode_t mode) -{ - char* gz_mode; - - switch (flags & O_ACCMODE) { - case O_WRONLY: - gz_mode = "w"; - break; - - case O_RDONLY: - gz_mode = "r"; - break; - - case O_RDWR: - default: - errno = EINVAL; - return -1; - } - - int fd; - gzFile gz_file; - - if ((fd = open(pathname, flags, mode)) == -1) - return -1; - - if ((flags & O_CREAT) && fchmod(fd, mode)) - return -1; - - if (!(gz_file = gzdopen(fd, gz_mode))) { - errno = ENOMEM; - return -1; - } - - return (int)gz_file; -} - string trim_filename(const string& filename) { string search("//");