diff --git a/pkgutil.cc b/pkgutil.cc index bf1a0aa..3465402 100644 --- a/pkgutil.cc +++ b/pkgutil.cc @@ -391,6 +438,7 @@ void pkgutil::pkg_install(const string& filename, const set& keep_list, unsigned int i; char buf[PATH_MAX]; string absroot; + set reject_dir_list; archive = archive_read_new(); INIT_ARCHIVE(archive); @@ -403,6 +451,10 @@ void pkgutil::pkg_install(const string& filename, const set& keep_list, chdir(root.c_str()); absroot = getcwd(buf, sizeof(buf)); +#ifndef NDEBUG + cerr << utilname << ": Installing files:" << endl; +#endif + for (i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; ++i) { string archive_filename = archive_entry_pathname(entry); @@ -445,6 +497,10 @@ void pkgutil::pkg_install(const string& filename, const set& keep_list, continue; } +#ifndef NDEBUG + cout << archive_filename << endl; +#endif + // Check rejected file if (real_filename != original_filename) { bool remove_file = false; @@ -461,8 +517,29 @@ void pkgutil::pkg_install(const string& filename, const set& keep_list, // Remove rejected file or signal about its existence if (remove_file) file_remove(reject_dir, real_filename); - else + else { cout << utilname << ": rejecting " << archive_filename << ", keeping existing version" << endl; + + if (0 != archive_filename.length() + && '/' != archive_filename[archive_filename.length() - 1] + && '/' != archive_filename[0]) { + string::size_type delim_pos = archive_filename.find_last_of('/'); + string cur_file = archive_filename; + while (string::npos != delim_pos) { + cur_file = cur_file.substr(0, 1 + delim_pos); +#ifndef NDEBUG + cout << "processing directory " << cur_file << endl; +#endif + if (reject_dir_list.end() == reject_dir_list.find(cur_file)) { +#ifndef NDEBUG + cout << "found new rejected directory " << cur_file << endl; +#endif + reject_dir_list.insert(reject_dir_list.end(), cur_file); + } + delim_pos = cur_file.find_last_of('/', delim_pos - 1); + } + } + } } } @@ -474,6 +551,55 @@ void pkgutil::pkg_install(const string& filename, const set& keep_list, } archive_read_free(archive); + + if (0 != reject_dir_list.size()) { +#ifndef NDEBUG + cerr << endl; + cerr << "Rejected directory list:" << endl; + copy(reject_dir_list.begin(), reject_dir_list.end(), ostream_iterator(cerr, "\n")); + cerr << endl; +#endif + 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) { + string archive_filename = archive_entry_pathname(entry); + + if (reject_dir_list.end() == reject_dir_list.find(archive_filename)) + continue; +#ifndef NDEBUG + cout << "extracting permissions for rejected directory " << archive_filename << endl; +#endif + + string reject_dir = trim_filename(absroot + string("/") + string(PKG_REJECTED)); + string reject_filename = trim_filename(reject_dir + string("/") + archive_filename); + + archive_entry_set_pathname(entry, const_cast + (reject_filename.c_str())); + + // Extract file + 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, + // unless this is not an upgrade. + const char* msg = archive_error_string(archive); + cerr << utilname << ": could not install rejected " + archive_filename << ": " << msg << endl; + if (!upgrade) + throw runtime_error("extract error: " + archive_filename + ": " + msg); + continue; + } + } + + archive_read_free(archive); + } } void pkgutil::ldconfig() const