X-Git-Url: http://gitweb/?a=blobdiff_plain;f=pkgutil.cc;h=1bbb83d518fd7e49f0c3655ca76d5e18b3e6121f;hb=refs%2Fheads%2F3.2-aarch64;hp=bdc1563541bdabd2c65da2bce8b6a9ffca2fff5d;hpb=22131995295a9db9be7b461cbcefe65d8ffe9df1;p=pkgutils-cross.git diff --git a/pkgutil.cc b/pkgutil.cc index bdc1563..1bbb83d 100644 --- a/pkgutil.cc +++ b/pkgutil.cc @@ -2,6 +2,7 @@ // pkgutils // // Copyright (c) 2000-2005 Per Liden +// Copyright (c) 2006-2013 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,18 +39,19 @@ #include #include #include -#include #include -#include +#include +#include -using __gnu_cxx::stdio_filebuf; +#define INIT_ARCHIVE(ar) \ + archive_read_support_filter_gzip((ar)); \ + archive_read_support_filter_bzip2((ar)); \ + archive_read_support_filter_xz((ar)); \ + archive_read_support_format_tar((ar)) + +#define DEFAULT_BYTES_PER_BLOCK (20 * 512) -static tartype_t gztype = { - (openfunc_t)unistd_gzopen, - (closefunc_t)gzclose, - (readfunc_t)gzread, - (writefunc_t)gzwrite -}; +using __gnu_cxx::stdio_filebuf; pkgutil::pkgutil(const string& name) : utilname(name) @@ -333,7 +335,8 @@ pair pkgutil::pkg_open(const string& filename) const { pair result; unsigned int i; - TAR* t; + struct archive* archive; + struct archive_entry* entry; // Extract name and version from filename string basename(filename, filename.rfind('/') + 1); @@ -347,47 +350,75 @@ pair pkgutil::pkg_open(const string& filename) const result.first = name; result.second.version = version; - if (tar_open(&t, const_cast(filename.c_str()), &gztype, O_RDONLY, 0, TAR_GNU) == -1) - throw runtime_error_with_errno("could not open " + filename); + archive = archive_read_new(); + INIT_ARCHIVE(archive); + + if (archive_read_open_filename(archive, + filename.c_str(), + 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) { + + result.second.files.insert(result.second.files.end(), + archive_entry_pathname(entry)); - for (i = 0; !th_read(t); ++i) { - result.second.files.insert(result.second.files.end(), th_get_pathname(t)); - if (TH_ISREG(t) && tar_skip_regfile(t)) - throw runtime_error_with_errno("could not read " + filename); + mode_t mode = archive_entry_mode(entry); + + if (S_ISREG(mode) && + archive_read_data_skip(archive) != ARCHIVE_OK) + throw runtime_error_with_errno("could not read " + filename, archive_errno(archive)); } if (i == 0) { - if (errno == 0) + if (archive_errno(archive) == 0) throw runtime_error("empty package"); else throw runtime_error("could not read " + filename); } - tar_close(t); + archive_read_free(archive); return result; } void pkgutil::pkg_install(const string& filename, const set& keep_list, const set& non_install_list) const { - TAR* t; + struct archive* archive; + struct archive_entry* entry; unsigned int i; + char buf[PATH_MAX]; + string absroot; - if (tar_open(&t, const_cast(filename.c_str()), &gztype, O_RDONLY, 0, TAR_GNU) == -1) - throw runtime_error_with_errno("could not open " + filename); + archive = archive_read_new(); + INIT_ARCHIVE(archive); + + if (archive_read_open_filename(archive, + filename.c_str(), + DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) + throw runtime_error_with_errno("could not open " + filename, archive_errno(archive)); - for (i = 0; !th_read(t); ++i) { - string archive_filename = th_get_pathname(t); - string reject_dir = trim_filename(root + string("/") + string(PKG_REJECTED)); - string original_filename = trim_filename(root + string("/") + archive_filename); + chdir(root.c_str()); + absroot = getcwd(buf, sizeof(buf)); + + for (i = 0; archive_read_next_header(archive, &entry) == + ARCHIVE_OK; ++i) { + string archive_filename = archive_entry_pathname(entry); + string reject_dir = trim_filename(absroot + string("/") + string(PKG_REJECTED)); + string original_filename = trim_filename(absroot + string("/") + archive_filename); string real_filename = original_filename; // Check if file is filtered out via INSTALL if (non_install_list.find(archive_filename) != non_install_list.end()) { + mode_t mode; + cout << utilname << ": ignoring " << archive_filename << endl; - if (TH_ISREG(t)) - tar_skip_regfile(t); + mode = archive_entry_mode(entry); + + if (S_ISREG(mode)) + archive_read_data_skip(archive); continue; } @@ -396,11 +427,16 @@ void pkgutil::pkg_install(const string& filename, const set& keep_list, if (file_exists(real_filename) && keep_list.find(archive_filename) != keep_list.end()) real_filename = trim_filename(reject_dir + string("/") + archive_filename); + archive_entry_set_pathname(entry, const_cast + (real_filename.c_str())); + // Extract file - if (tar_extract_file(t, const_cast(real_filename.c_str()))) { + unsigned int flags = ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME | 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 = strerror(errno); + const char* msg = archive_error_string(archive); cerr << utilname << ": could not install " + archive_filename << ": " << msg << endl; continue; } @@ -408,9 +444,10 @@ void pkgutil::pkg_install(const string& filename, const set& keep_list, // Check rejected file if (real_filename != original_filename) { bool remove_file = false; + mode_t mode = archive_entry_mode(entry); // Directory - if (TH_ISDIR(t)) + if (S_ISDIR(mode)) remove_file = permissions_equal(real_filename, original_filename); // Other files else @@ -426,13 +463,13 @@ void pkgutil::pkg_install(const string& filename, const set& keep_list, } if (i == 0) { - if (errno == 0) + if (archive_errno(archive) == 0) throw runtime_error("empty package"); else throw runtime_error("could not read " + filename); } - tar_close(t); + archive_read_free(archive); } void pkgutil::ldconfig() const @@ -458,26 +495,75 @@ void pkgutil::ldconfig() const void pkgutil::pkg_footprint(string& filename) const { - unsigned int i; - TAR* t; + 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(); + INIT_ARCHIVE(archive); + + if (archive_read_open_filename(archive, + filename.c_str(), + DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) + throw runtime_error_with_errno("could not open " + filename, archive_errno(archive)); - if (tar_open(&t, const_cast(filename.c_str()), &gztype, O_RDONLY, 0, TAR_GNU) == -1) - throw runtime_error_with_errno("could not open " + filename); + for (i = 0; archive_read_next_header(archive, &entry) == + ARCHIVE_OK; ++i) { + + 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_free(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, + filename.c_str(), + 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); - for (i = 0; !th_read(t); ++i) { // Access permissions - if (TH_ISSYM(t)) { + 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(th_get_mode(t)); + const char *h = archive_entry_hardlink(entry); + + if (h) + cout << mtos(hardlink_target_modes[h]); + else + cout << mtos(mode); } cout << '\t'; // User - uid_t uid = th_get_uid(t); + uid_t uid = archive_entry_uid(entry); struct passwd* pw = getpwuid(uid); if (pw) cout << pw->pw_name; @@ -487,7 +573,7 @@ void pkgutil::pkg_footprint(string& filename) const cout << '/'; // Group - gid_t gid = th_get_gid(t); + gid_t gid = archive_entry_gid(entry); struct group* gr = getgrgid(gid); if (gr) cout << gr->gr_name; @@ -495,34 +581,38 @@ void pkgutil::pkg_footprint(string& filename) const cout << gid; // Filename - cout << '\t' << th_get_pathname(t); + cout << '\t' << archive_entry_pathname(entry); // Special cases - if (TH_ISSYM(t)) { + if (S_ISLNK(mode)) { // Symlink - cout << " -> " << th_get_linkname(t); - } else if (TH_ISCHR(t) || TH_ISBLK(t)) { + cout << " -> " << archive_entry_symlink(entry); + } else if (S_ISCHR(mode) || + S_ISBLK(mode)) { // Device - cout << " (" << th_get_devmajor(t) << ", " << th_get_devminor(t) << ")"; - } else if (TH_ISREG(t) && !th_get_size(t)) { + cout << " (" << archive_entry_rdevmajor(entry) + << ", " << archive_entry_rdevminor(entry) + << ")"; + } else if (S_ISREG(mode) && + archive_entry_size(entry) == 0) { // Empty regular file cout << " (EMPTY)"; } cout << '\n'; - if (TH_ISREG(t) && tar_skip_regfile(t)) - throw runtime_error_with_errno("could not read " + filename); - } + 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 (errno == 0) - throw runtime_error("empty package"); - else - throw runtime_error("could not read " + filename); - } + if (i == 0) { + if (archive_errno(archive) == 0) + throw runtime_error("empty package"); + else + throw runtime_error("could not read " + filename); + } - tar_close(t); + archive_read_free(archive); } void pkgutil::print_version() const @@ -616,42 +706,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("//");