Add helper method for creating and opening archive object

This moves the common setup code of about 5 different callers into one
method. Error messages will now be common and shared in all places;
several paths did not have any messages at all before.

In addition, we now pick an ideal block size for the archive read based
off the larger value of our default buffer size or the st.st_blksize
field. For a filesystem such as NFS, this is often much larger than the
default 8192- values such as 32768 and 131072 are common.

Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
Dan McGee 2011-11-13 23:45:55 -06:00
parent f1ec3b9b10
commit dee8144ce5
6 changed files with 123 additions and 91 deletions

View File

@ -201,6 +201,7 @@ AC_CHECK_FUNCS([dup2 getcwd geteuid getmntinfo gettimeofday memmove memset \
mkdir realpath regcomp rmdir setenv setlocale strcasecmp \
strchr strcspn strdup strerror strndup strrchr strsep strstr \
strtol swprintf tcflush wcwidth uname])
AC_CHECK_MEMBERS([struct stat.st_blksize],,,[[#include <sys/stat.h>]])
# For the diskspace code
FS_STATS_TYPE

View File

@ -525,23 +525,14 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,
if(!(trans->flags & ALPM_TRANS_FLAG_DBONLY)) {
struct archive *archive;
struct archive_entry *entry;
int cwdfd;
struct stat buf;
int fd, cwdfd;
_alpm_log(handle, ALPM_LOG_DEBUG, "extracting files\n");
if((archive = archive_read_new()) == NULL) {
handle->pm_errno = ALPM_ERR_LIBARCHIVE;
ret = -1;
goto cleanup;
}
archive_read_support_compression_all(archive);
archive_read_support_format_all(archive);
_alpm_log(handle, ALPM_LOG_DEBUG, "archive: %s\n", pkgfile);
if(archive_read_open_filename(archive, pkgfile,
ALPM_BUFFER_SIZE) != ARCHIVE_OK) {
handle->pm_errno = ALPM_ERR_PKG_OPEN;
fd = _alpm_open_archive(db->handle, pkgfile, &buf,
&archive, ALPM_ERR_PKG_OPEN);
if(fd < 0) {
ret = -1;
goto cleanup;
}
@ -556,6 +547,8 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,
if(chdir(handle->root) != 0) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
handle->root, strerror(errno));
archive_read_finish(archive);
CLOSE(fd);
ret = -1;
goto cleanup;
}
@ -597,6 +590,7 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,
errors += extract_single_file(handle, archive, entry, newpkg, oldpkg);
}
archive_read_finish(archive);
CLOSE(fd);
/* restore the old cwd if we have it */
if(cwdfd >= 0) {

View File

@ -40,6 +40,11 @@
#include "package.h"
#include "deps.h" /* _alpm_splitdep */
struct package_changelog {
struct archive *archive;
int fd;
};
/**
* Open a package changelog for reading. Similar to fopen in functionality,
* except that the returned 'file stream' is from an archive.
@ -50,31 +55,38 @@ static void *_package_changelog_open(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
struct archive *archive = NULL;
struct package_changelog *changelog;
struct archive *archive;
struct archive_entry *entry;
const char *pkgfile = pkg->origin_data.file;
struct stat buf;
int fd;
if((archive = archive_read_new()) == NULL) {
RET_ERR(pkg->handle, ALPM_ERR_LIBARCHIVE, NULL);
}
archive_read_support_compression_all(archive);
archive_read_support_format_all(archive);
if(archive_read_open_filename(archive, pkgfile,
ALPM_BUFFER_SIZE) != ARCHIVE_OK) {
RET_ERR(pkg->handle, ALPM_ERR_PKG_OPEN, NULL);
fd = _alpm_open_archive(pkg->handle, pkgfile, &buf,
&archive, ALPM_ERR_PKG_OPEN);
if(fd < 0) {
return NULL;
}
while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
const char *entry_name = archive_entry_pathname(entry);
if(strcmp(entry_name, ".CHANGELOG") == 0) {
return archive;
changelog = malloc(sizeof(struct package_changelog));
if(!changelog) {
pkg->handle->pm_errno = ALPM_ERR_MEMORY;
archive_read_finish(archive);
CLOSE(fd);
return NULL;
}
changelog->archive = archive;
changelog->fd = fd;
return changelog;
}
}
/* we didn't find a changelog */
archive_read_finish(archive);
CLOSE(fd);
errno = ENOENT;
return NULL;
@ -92,7 +104,8 @@ static void *_package_changelog_open(alpm_pkg_t *pkg)
static size_t _package_changelog_read(void *ptr, size_t size,
const alpm_pkg_t UNUSED *pkg, void *fp)
{
ssize_t sret = archive_read_data((struct archive *)fp, ptr, size);
struct package_changelog *changelog = fp;
ssize_t sret = archive_read_data(changelog->archive, ptr, size);
/* Report error (negative values) */
if(sret < 0) {
RET_ERR(pkg->handle, ALPM_ERR_LIBARCHIVE, 0);
@ -110,7 +123,12 @@ static size_t _package_changelog_read(void *ptr, size_t size,
*/
static int _package_changelog_close(const alpm_pkg_t UNUSED *pkg, void *fp)
{
return archive_read_finish((struct archive *)fp);
int ret;
struct package_changelog *changelog = fp;
ret = archive_read_finish(changelog->archive);
CLOSE(changelog->fd);
free(changelog);
return ret;
}
/** Package file operations struct accessor. We implement this as a method
@ -370,24 +388,10 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,
RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL);
}
/* try to create an archive object to read in the package */
if((archive = archive_read_new()) == NULL) {
RET_ERR(handle, ALPM_ERR_LIBARCHIVE, NULL);
}
archive_read_support_compression_all(archive);
archive_read_support_format_all(archive);
OPEN(fd, pkgfile, O_RDONLY);
if(fd < 0 || archive_read_open_fd(archive, fd,
ALPM_BUFFER_SIZE) != ARCHIVE_OK) {
const char *err = fd < 0 ? strerror(errno) : archive_error_string(archive);
_alpm_log(handle, ALPM_LOG_ERROR,
_("could not open file %s: %s\n"), pkgfile, err);
if(fd < 0 && errno == ENOENT) {
fd = _alpm_open_archive(handle, pkgfile, &st, &archive, ALPM_ERR_PKG_OPEN);
if(fd < 0) {
if(errno == ENOENT) {
handle->pm_errno = ALPM_ERR_PKG_NOT_FOUND;
} else {
handle->pm_errno = ALPM_ERR_PKG_OPEN;
}
goto error;
}
@ -397,10 +401,6 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,
handle->pm_errno = ALPM_ERR_MEMORY;
goto error;
}
if(fstat(fd, &st) != 0) {
handle->pm_errno = ALPM_ERR_PKG_OPEN;
goto error;
}
STRDUP(newpkg->filename, pkgfile,
handle->pm_errno = ALPM_ERR_MEMORY; goto error);
newpkg->size = st.st_size;

View File

@ -433,26 +433,9 @@ static int sync_db_populate(alpm_db_t *db)
return -1;
}
if((archive = archive_read_new()) == NULL) {
RET_ERR(db->handle, ALPM_ERR_LIBARCHIVE, -1);
}
archive_read_support_compression_all(archive);
archive_read_support_format_all(archive);
_alpm_log(db->handle, ALPM_LOG_DEBUG,
"opening database archive %s\n", dbpath);
OPEN(fd, dbpath, O_RDONLY);
if(fd < 0 || archive_read_open_fd(archive, fd,
ALPM_BUFFER_SIZE) != ARCHIVE_OK) {
const char *err = fd < 0 ? strerror(errno) : archive_error_string(archive);
_alpm_log(db->handle, ALPM_LOG_ERROR,
_("could not open file %s: %s\n"), dbpath, err);
db->handle->pm_errno = ALPM_ERR_DB_OPEN;
goto cleanup;
}
if(fstat(fd, &buf) != 0) {
db->handle->pm_errno = ALPM_ERR_DB_OPEN;
fd = _alpm_open_archive(db->handle, dbpath, &buf,
&archive, ALPM_ERR_DB_OPEN);
if(fd < 0) {
goto cleanup;
}
est_count = estimate_package_count(&buf, archive);

View File

@ -232,6 +232,64 @@ size_t _alpm_strip_newline(char *str)
/* Compression functions */
/**
* Open an archive for reading and perform the necessary boilerplate.
* This takes care of creating the libarchive 'archive' struct, setting up
* compression and format options, opening a file descriptor, setting up the
* buffer size, and performing a stat on the path once opened.
* @param handle the context handle
* @param path the path of the archive to open
* @param buf space for a stat buffer for the given path
* @param archive pointer to place the created archive object
* @param error error code to set on failure to open archive
* @return -1 on failure, >=0 file descriptor on success
*/
int _alpm_open_archive(alpm_handle_t *handle, const char *path,
struct stat *buf, struct archive **archive, alpm_errno_t error)
{
int fd;
size_t bufsize = ALPM_BUFFER_SIZE;
if((*archive = archive_read_new()) == NULL) {
RET_ERR(handle, ALPM_ERR_LIBARCHIVE, -1);
}
archive_read_support_compression_all(*archive);
archive_read_support_format_all(*archive);
_alpm_log(handle, ALPM_LOG_DEBUG, "opening archive %s\n", path);
OPEN(fd, path, O_RDONLY);
if(fd < 0) {
_alpm_log(handle, ALPM_LOG_ERROR,
_("could not open file %s: %s\n"), path, strerror(errno));
archive_read_finish(*archive);
RET_ERR(handle, error, -1);
}
if(fstat(fd, buf) != 0) {
_alpm_log(handle, ALPM_LOG_ERROR,
_("could not stat file %s: %s\n"), path, strerror(errno));
archive_read_finish(*archive);
CLOSE(fd);
RET_ERR(handle, error, -1);
}
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
if(buf->st_blksize > ALPM_BUFFER_SIZE) {
bufsize = buf->st_blksize;
}
#endif
if(archive_read_open_fd(*archive, fd, bufsize) != ARCHIVE_OK) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"),
path, archive_error_string(*archive));
archive_read_finish(*archive);
CLOSE(fd);
RET_ERR(handle, error, -1);
}
return fd;
}
/**
* @brief Unpack a specific file in an archive.
*
@ -259,34 +317,26 @@ int _alpm_unpack_single(alpm_handle_t *handle, const char *archive,
* @brief Unpack a list of files in an archive.
*
* @param handle the context handle
* @param archive the archive to unpack
* @param path the archive to unpack
* @param prefix where to extract the files
* @param list a list of files within the archive to unpack or NULL for all
* @param breakfirst break after the first entry found
*
* @return 0 on success, 1 on failure
*/
int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,
int _alpm_unpack(alpm_handle_t *handle, const char *path, const char *prefix,
alpm_list_t *list, int breakfirst)
{
int ret = 0;
mode_t oldmask;
struct archive *_archive;
struct archive *archive;
struct archive_entry *entry;
int cwdfd;
struct stat buf;
int fd, cwdfd;
if((_archive = archive_read_new()) == NULL) {
RET_ERR(handle, ALPM_ERR_LIBARCHIVE, 1);
}
archive_read_support_compression_all(_archive);
archive_read_support_format_all(_archive);
if(archive_read_open_filename(_archive, archive,
ALPM_BUFFER_SIZE) != ARCHIVE_OK) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), archive,
archive_error_string(_archive));
RET_ERR(handle, ALPM_ERR_PKG_OPEN, 1);
fd = _alpm_open_archive(handle, path, &buf, &archive, ALPM_ERR_PKG_OPEN);
if(fd < 0) {
return 1;
}
oldmask = umask(0022);
@ -305,7 +355,7 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,
goto cleanup;
}
while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) {
while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
const char *entryname;
mode_t mode;
@ -321,7 +371,7 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,
char *found = alpm_list_find_str(list, entry_prefix);
free(entry_prefix);
if(!found) {
if(archive_read_data_skip(_archive) != ARCHIVE_OK) {
if(archive_read_data_skip(archive) != ARCHIVE_OK) {
ret = 1;
goto cleanup;
}
@ -339,14 +389,14 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,
}
/* Extract the archive entry. */
int readret = archive_read_extract(_archive, entry, 0);
int readret = archive_read_extract(archive, entry, 0);
if(readret == ARCHIVE_WARN) {
/* operation succeeded but a non-critical error was encountered */
_alpm_log(handle, ALPM_LOG_WARNING, _("warning given when extracting %s (%s)\n"),
entryname, archive_error_string(_archive));
entryname, archive_error_string(archive));
} else if(readret != ARCHIVE_OK) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not extract %s (%s)\n"),
entryname, archive_error_string(_archive));
entryname, archive_error_string(archive));
ret = 1;
goto cleanup;
}
@ -358,7 +408,8 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,
cleanup:
umask(oldmask);
archive_read_finish(_archive);
archive_read_finish(archive);
CLOSE(fd);
if(cwdfd >= 0) {
if(fchdir(cwdfd) != 0) {
_alpm_log(handle, ALPM_LOG_ERROR,

View File

@ -117,6 +117,9 @@ int _alpm_makepath_mode(const char *path, mode_t mode);
int _alpm_copyfile(const char *src, const char *dest);
char *_alpm_strtrim(char *str);
size_t _alpm_strip_newline(char *str);
int _alpm_open_archive(alpm_handle_t *handle, const char *path,
struct stat *buf, struct archive **archive, alpm_errno_t error);
int _alpm_unpack_single(alpm_handle_t *handle, const char *archive,
const char *prefix, const char *filename);
int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,