// 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
#include <sys/param.h>
#include <unistd.h>
#include <fcntl.h>
-#include <zlib.h>
#include <libgen.h>
#include <archive.h>
#include <archive_entry.h>
+#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)
+
using __gnu_cxx::stdio_filebuf;
pkgutil::pkgutil(const string& name)
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<char*>(filename.c_str()),
- ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK)
+ 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) ==
throw runtime_error("could not read " + filename);
}
- archive_read_finish(archive);
+ archive_read_free(archive);
return result;
}
struct archive* archive;
struct archive_entry* entry;
unsigned int i;
+ char buf[PATH_MAX];
+ string absroot;
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<char*>(filename.c_str()),
- ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK)
+ filename.c_str(),
+ DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK)
throw runtime_error_with_errno("could not open " + filename, archive_errno(archive));
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(root + string("/") + string(PKG_REJECTED));
- string original_filename = trim_filename(root + string("/") + archive_filename);
+ 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
(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_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 = archive_error_string(archive);
throw runtime_error("could not read " + filename);
}
- archive_read_finish(archive);
+ archive_read_free(archive);
}
void pkgutil::ldconfig() const
struct archive* archive;
struct archive_entry* entry;
+ map<string, mode_t> 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<char*>(filename.c_str()),
- ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK)
+ 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);
+
+ 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) ==
// To avoid getting different footprints we always use "lrwxrwxrwx".
cout << "lrwxrwxrwx";
} else {
- cout << mtos(mode);
+ const char *h = archive_entry_hardlink(entry);
+
+ if (h)
+ cout << mtos(hardlink_target_modes[h]);
+ else
+ cout << mtos(mode);
}
cout << '\t';
throw runtime_error("could not read " + filename);
}
- archive_read_finish(archive);
+ archive_read_free(archive);
}
void pkgutil::print_version() const
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("//");