Switched from libtar to libarchive.

This commit is contained in:
Matthias-Christian Ott 2006-11-15 20:32:56 +01:00 committed by Tilman Sauerbeck
parent 4f05762e7e
commit c3434674df
2 changed files with 91 additions and 58 deletions

View File

@ -25,33 +25,20 @@ MANDIR = /usr/man
ETCDIR = /etc ETCDIR = /etc
VERSION = 5.21 VERSION = 5.21
LIBTAR_VERSION = 1.2.11
CXXFLAGS += -DNDEBUG CXXFLAGS += -DNDEBUG
CXXFLAGS += -O2 -Wall -pedantic -D_GNU_SOURCE -DVERSION=\"$(VERSION)\" \ CXXFLAGS += -O2 -Wall -pedantic -D_GNU_SOURCE -DVERSION=\"$(VERSION)\" \
-Ilibtar-$(LIBTAR_VERSION)/lib -Ilibtar-$(LIBTAR_VERSION)/listhash \
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
LDFLAGS += -static -Llibtar-$(LIBTAR_VERSION)/lib -ltar -lz LDFLAGS += -static -larchive -lz -lbz2
OBJECTS = main.o pkgutil.o pkgadd.o pkgrm.o pkginfo.o OBJECTS = main.o pkgutil.o pkgadd.o pkgrm.o pkginfo.o
MANPAGES = pkgadd.8 pkgrm.8 pkginfo.8 pkgmk.8 rejmerge.8 MANPAGES = pkgadd.8 pkgrm.8 pkginfo.8 pkgmk.8 rejmerge.8
LIBTAR = libtar-$(LIBTAR_VERSION)/lib/libtar.a
all: pkgadd pkgmk rejmerge man all: pkgadd pkgmk rejmerge man
$(LIBTAR): pkgadd: .depend $(OBJECTS)
(tar xzf libtar-$(LIBTAR_VERSION).tar.gz; \
cd libtar-$(LIBTAR_VERSION); \
patch -p1 < ../libtar-$(LIBTAR_VERSION)-fix_mem_leak.patch; \
patch -p1 < ../libtar-$(LIBTAR_VERSION)-reduce_mem_usage.patch; \
patch -p1 < ../libtar-$(LIBTAR_VERSION)-fix_linkname_overflow.patch; \
LDFLAGS="" ./configure --disable-encap --disable-encap-install; \
make)
pkgadd: $(LIBTAR) .depend $(OBJECTS)
$(CXX) $(OBJECTS) -o $@ $(LDFLAGS) $(CXX) $(OBJECTS) -o $@ $(LDFLAGS)
pkgmk: pkgmk.in pkgmk: pkgmk.in
@ -108,6 +95,5 @@ clean:
distclean: clean distclean: clean
rm -f pkgadd pkginfo pkgrm pkgmk rejmerge rm -f pkgadd pkginfo pkgrm pkgmk rejmerge
rm -rf libtar-$(LIBTAR_VERSION)
# End of file # End of file

View File

@ -40,17 +40,11 @@
#include <fcntl.h> #include <fcntl.h>
#include <zlib.h> #include <zlib.h>
#include <libgen.h> #include <libgen.h>
#include <libtar.h> #include <archive.h>
#include <archive_entry.h>
using __gnu_cxx::stdio_filebuf; using __gnu_cxx::stdio_filebuf;
static tartype_t gztype = {
(openfunc_t)unistd_gzopen,
(closefunc_t)gzclose,
(readfunc_t)gzread,
(writefunc_t)gzwrite
};
pkgutil::pkgutil(const string& name) pkgutil::pkgutil(const string& name)
: utilname(name) : utilname(name)
{ {
@ -333,7 +327,8 @@ pair<string, pkgutil::pkginfo_t> pkgutil::pkg_open(const string& filename) const
{ {
pair<string, pkginfo_t> result; pair<string, pkginfo_t> result;
unsigned int i; unsigned int i;
TAR* t; struct archive* archive;
struct archive_entry* entry;
// Extract name and version from filename // Extract name and version from filename
string basename(filename, filename.rfind('/') + 1); string basename(filename, filename.rfind('/') + 1);
@ -347,47 +342,75 @@ pair<string, pkgutil::pkginfo_t> pkgutil::pkg_open(const string& filename) const
result.first = name; result.first = name;
result.second.version = version; result.second.version = version;
if (tar_open(&t, const_cast<char*>(filename.c_str()), &gztype, O_RDONLY, 0, TAR_GNU) == -1) archive = archive_read_new();
archive_read_support_compression_all(archive);
archive_read_support_format_all(archive);
if (archive_read_open_filename(archive,
const_cast<char*>(filename.c_str()),
ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK)
throw runtime_error_with_errno("could not open " + filename); throw runtime_error_with_errno("could not open " + filename);
for (i = 0; !th_read(t); ++i) { for (i = 0; archive_read_next_header(archive, &entry) ==
result.second.files.insert(result.second.files.end(), th_get_pathname(t)); ARCHIVE_OK; ++i) {
if (TH_ISREG(t) && tar_skip_regfile(t)) const struct stat* status;
result.second.files.insert(result.second.files.end(),
archive_entry_pathname(entry));
status = archive_entry_stat(entry);
if (S_ISREG(status->st_mode) &&
archive_read_data_skip(archive) != ARCHIVE_OK)
throw runtime_error_with_errno("could not read " + filename); throw runtime_error_with_errno("could not read " + filename);
} }
if (i == 0) { if (i == 0) {
if (errno == 0) if (archive_errno(archive) == 0)
throw runtime_error("empty package"); throw runtime_error("empty package");
else else
throw runtime_error("could not read " + filename); throw runtime_error("could not read " + filename);
} }
tar_close(t); archive_read_finish(archive);
return result; return result;
} }
void pkgutil::pkg_install(const string& filename, const set<string>& keep_list, const set<string>& non_install_list) const void pkgutil::pkg_install(const string& filename, const set<string>& keep_list, const set<string>& non_install_list) const
{ {
TAR* t; struct archive* archive;
struct archive_entry* entry;
unsigned int i; unsigned int i;
if (tar_open(&t, const_cast<char*>(filename.c_str()), &gztype, O_RDONLY, 0, TAR_GNU) == -1) archive = archive_read_new();
archive_read_support_compression_all(archive);
archive_read_support_format_all(archive);
if (archive_read_open_filename(archive,
const_cast<char*>(filename.c_str()),
ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK)
throw runtime_error_with_errno("could not open " + filename); throw runtime_error_with_errno("could not open " + filename);
for (i = 0; !th_read(t); ++i) { chdir(root.c_str());
string archive_filename = th_get_pathname(t);
for (i = 0; archive_read_next_header(archive, &entry) ==
ARCHIVE_OK; ++i) {
string archive_filename = archive_entry_pathname(entry);
string reject_dir = trim_filename(root + string("/") + string(PKG_REJECTED)); string reject_dir = trim_filename(root + string("/") + string(PKG_REJECTED));
string original_filename = trim_filename(root + string("/") + archive_filename); string original_filename = trim_filename(root + string("/") + archive_filename);
string real_filename = original_filename; string real_filename = original_filename;
// Check if file is filtered out via INSTALL // Check if file is filtered out via INSTALL
if (non_install_list.find(archive_filename) != non_install_list.end()) { if (non_install_list.find(archive_filename) != non_install_list.end()) {
const struct stat* status;
cout << utilname << ": ignoring " << archive_filename << endl; cout << utilname << ": ignoring " << archive_filename << endl;
if (TH_ISREG(t)) status = archive_entry_stat(entry);
tar_skip_regfile(t);
if (S_ISREG(status->st_mode))
archive_read_data_skip(archive);
continue; continue;
} }
@ -396,11 +419,15 @@ void pkgutil::pkg_install(const string& filename, const set<string>& keep_list,
if (file_exists(real_filename) && keep_list.find(archive_filename) != keep_list.end()) if (file_exists(real_filename) && keep_list.find(archive_filename) != keep_list.end())
real_filename = trim_filename(reject_dir + string("/") + archive_filename); real_filename = trim_filename(reject_dir + string("/") + archive_filename);
archive_entry_set_pathname(entry, const_cast<char*>
(real_filename.c_str()));
// Extract file // Extract file
if (tar_extract_file(t, const_cast<char*>(real_filename.c_str()))) { if (archive_read_extract(archive, entry, 0) !=
ARCHIVE_OK) {
// If a file fails to install we just print an error message and // If a file fails to install we just print an error message and
// continue trying to install the rest of the package. // 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; cerr << utilname << ": could not install " + archive_filename << ": " << msg << endl;
continue; continue;
} }
@ -408,9 +435,12 @@ void pkgutil::pkg_install(const string& filename, const set<string>& keep_list,
// Check rejected file // Check rejected file
if (real_filename != original_filename) { if (real_filename != original_filename) {
bool remove_file = false; bool remove_file = false;
const struct stat* status;
status = archive_entry_stat(entry);
// Directory // Directory
if (TH_ISDIR(t)) if (S_ISDIR(status->st_mode))
remove_file = permissions_equal(real_filename, original_filename); remove_file = permissions_equal(real_filename, original_filename);
// Other files // Other files
else else
@ -426,13 +456,13 @@ void pkgutil::pkg_install(const string& filename, const set<string>& keep_list,
} }
if (i == 0) { if (i == 0) {
if (errno == 0) if (archive_errno(archive) == 0)
throw runtime_error("empty package"); throw runtime_error("empty package");
else else
throw runtime_error("could not read " + filename); throw runtime_error("could not read " + filename);
} }
tar_close(t); archive_read_finish(archive);
} }
void pkgutil::ldconfig() const void pkgutil::ldconfig() const
@ -459,25 +489,37 @@ void pkgutil::ldconfig() const
void pkgutil::pkg_footprint(string& filename) const void pkgutil::pkg_footprint(string& filename) const
{ {
unsigned int i; unsigned int i;
TAR* t; struct archive* archive;
struct archive_entry* entry;
if (tar_open(&t, const_cast<char*>(filename.c_str()), &gztype, O_RDONLY, 0, TAR_GNU) == -1) archive = archive_read_new();
archive_read_support_compression_all(archive);
archive_read_support_format_all(archive);
if (archive_read_open_filename(archive,
const_cast<char*>(filename.c_str()),
ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK)
throw runtime_error_with_errno("could not open " + filename); throw runtime_error_with_errno("could not open " + filename);
for (i = 0; !th_read(t); ++i) { for (i = 0; archive_read_next_header(archive, &entry) ==
ARCHIVE_OK; ++i) {
const struct stat* status;
status = archive_entry_stat(entry);
// Access permissions // Access permissions
if (TH_ISSYM(t)) { if (S_ISLNK(status->st_mode)) {
// Access permissions on symlinks differ among filesystems, e.g. XFS and ext2 have different. // Access permissions on symlinks differ among filesystems, e.g. XFS and ext2 have different.
// To avoid getting different footprints we always use "lrwxrwxrwx". // To avoid getting different footprints we always use "lrwxrwxrwx".
cout << "lrwxrwxrwx"; cout << "lrwxrwxrwx";
} else { } else {
cout << mtos(th_get_mode(t)); cout << mtos(archive_entry_mode(entry));
} }
cout << '\t'; cout << '\t';
// User // User
uid_t uid = th_get_uid(t); uid_t uid = archive_entry_uid(entry);
struct passwd* pw = getpwuid(uid); struct passwd* pw = getpwuid(uid);
if (pw) if (pw)
cout << pw->pw_name; cout << pw->pw_name;
@ -487,7 +529,7 @@ void pkgutil::pkg_footprint(string& filename) const
cout << '/'; cout << '/';
// Group // Group
gid_t gid = th_get_gid(t); gid_t gid = archive_entry_gid(entry);
struct group* gr = getgrgid(gid); struct group* gr = getgrgid(gid);
if (gr) if (gr)
cout << gr->gr_name; cout << gr->gr_name;
@ -495,34 +537,39 @@ void pkgutil::pkg_footprint(string& filename) const
cout << gid; cout << gid;
// Filename // Filename
cout << '\t' << th_get_pathname(t); cout << '\t' << archive_entry_pathname(entry);
// Special cases // Special cases
if (TH_ISSYM(t)) { if (S_ISLNK(status->st_mode)) {
// Symlink // Symlink
cout << " -> " << th_get_linkname(t); cout << " -> " << archive_entry_symlink(entry);
} else if (TH_ISCHR(t) || TH_ISBLK(t)) { } else if (S_ISCHR(status->st_mode) ||
S_ISBLK(status->st_mode)) {
// Device // Device
cout << " (" << th_get_devmajor(t) << ", " << th_get_devminor(t) << ")"; cout << " (" << archive_entry_rdevmajor(entry)
} else if (TH_ISREG(t) && !th_get_size(t)) { << ", " << archive_entry_rdevminor(entry)
<< ")";
} else if (S_ISREG(status->st_mode) &&
archive_entry_size(entry) == 0) {
// Empty regular file // Empty regular file
cout << " (EMPTY)"; cout << " (EMPTY)";
} }
cout << '\n'; cout << '\n';
if (TH_ISREG(t) && tar_skip_regfile(t)) if (S_ISREG(status->st_mode) &&
archive_read_data_skip(archive))
throw runtime_error_with_errno("could not read " + filename); throw runtime_error_with_errno("could not read " + filename);
} }
if (i == 0) { if (i == 0) {
if (errno == 0) if (archive_errno(archive) == 0)
throw runtime_error("empty package"); throw runtime_error("empty package");
else else
throw runtime_error("could not read " + filename); throw runtime_error("could not read " + filename);
} }
tar_close(t); archive_read_finish(archive);
} }
void pkgutil::print_version() const void pkgutil::print_version() const