[pacman-dev] [PATCH 2/3] Convert package and database archive reads to use file descriptors
Dan McGee
dan at archlinux.org
Wed Oct 26 18:44:42 EDT 2011
This gives us a bit more control and over the archive reading process,
and a bit less is done behind the scenes. It also allows us to use
fstat() in preference to stat(), which should avoid some potential race
conditions.
Some reorganization is necessary to move the stat calls after the open()
calls. Error handling and cleanup in general is also improved, as we had
several potential memory and file handle leaks before in some error
paths.
Signed-off-by: Dan McGee <dan at archlinux.org>
---
lib/libalpm/be_package.c | 53 +++++++++++++++++++++++++++++---------------
lib/libalpm/be_sync.c | 55 +++++++++++++++++++++++++++++----------------
2 files changed, 70 insertions(+), 38 deletions(-)
diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c
index c20c703..36666df 100644
--- a/lib/libalpm/be_package.c
+++ b/lib/libalpm/be_package.c
@@ -23,6 +23,9 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
/* libarchive */
#include <archive.h>
@@ -355,7 +358,7 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle,
alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,
const char *pkgfile, int full)
{
- int ret, config = 0;
+ int ret, fd, config = 0;
struct archive *archive;
struct archive_entry *entry;
alpm_pkg_t *newpkg = NULL;
@@ -367,34 +370,44 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,
RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL);
}
- /* attempt to stat the package file, ensure it exists */
- if(stat(pkgfile, &st) == 0) {
- newpkg = _alpm_pkg_new();
- if(newpkg == NULL) {
- RET_ERR(handle, ALPM_ERR_MEMORY, NULL);
- }
- newpkg->filename = strdup(pkgfile);
- newpkg->size = st.st_size;
- } else {
- /* couldn't stat the pkgfile, return an error */
- RET_ERR(handle, ALPM_ERR_PKG_NOT_FOUND, NULL);
- }
-
/* try to create an archive object to read in the package */
if((archive = archive_read_new()) == NULL) {
- alpm_pkg_free(newpkg);
RET_ERR(handle, ALPM_ERR_LIBARCHIVE, NULL);
}
archive_read_support_compression_all(archive);
archive_read_support_format_all(archive);
- if(archive_read_open_filename(archive, pkgfile,
+ do {
+ fd = open(pkgfile, O_RDONLY);
+ } while(fd == -1 && errno == EINTR);
+
+ if(fd < 0 || archive_read_open_fd(archive, fd,
ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
- alpm_pkg_free(newpkg);
- RET_ERR(handle, ALPM_ERR_PKG_OPEN, NULL);
+ 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) {
+ handle->pm_errno = ALPM_ERR_PKG_NOT_FOUND;
+ } else {
+ handle->pm_errno = ALPM_ERR_PKG_OPEN;
+ }
+ goto error;
}
+ newpkg = _alpm_pkg_new();
+ if(newpkg == NULL) {
+ 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;
+
_alpm_log(handle, ALPM_LOG_DEBUG, "starting package load for %s\n", pkgfile);
/* If full is false, only read through the archive until we find our needed
@@ -476,6 +489,7 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,
}
archive_read_finish(archive);
+ close(fd);
/* internal fields for package struct */
newpkg->origin = PKG_FROM_FILE;
@@ -502,6 +516,9 @@ pkg_invalid:
error:
_alpm_pkg_free(newpkg);
archive_read_finish(archive);
+ if(fd >= 0) {
+ close(fd);
+ }
return NULL;
}
diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c
index e9e816c..24785f1 100644
--- a/lib/libalpm/be_sync.c
+++ b/lib/libalpm/be_sync.c
@@ -21,7 +21,9 @@
#include "config.h"
#include <errno.h>
+#include <sys/types.h>
#include <sys/stat.h>
+#include <fcntl.h>
#include <unistd.h>
/* libarchive */
@@ -212,6 +214,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
/* print server + filename into a buffer */
len = strlen(server) + strlen(db->treename) + 5;
+ /* TODO fix leak syncpath and umask unset */
MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
snprintf(payload.fileurl, len, "%s/%s.db", server, db->treename);
payload.handle = handle;
@@ -234,6 +237,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
/* if we downloaded a DB, we want the .sig from the same server */
/* print server + filename into a buffer (leave space for .sig) */
len = strlen(server) + strlen(db->treename) + 9;
+ /* TODO fix leak syncpath and umask unset */
MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
snprintf(payload.fileurl, len, "%s/%s.db.sig", server, db->treename);
payload.handle = handle;
@@ -411,7 +415,7 @@ static int sync_db_populate(alpm_db_t *db)
{
const char *dbpath;
size_t est_count;
- int count = 0;
+ int count = -1, fd;
struct stat buf;
struct archive *archive;
struct archive_entry *entry;
@@ -423,6 +427,11 @@ static int sync_db_populate(alpm_db_t *db)
if(db->status & DB_STATUS_MISSING) {
RET_ERR(db->handle, ALPM_ERR_DB_NOT_FOUND, -1);
}
+ dbpath = _alpm_db_path(db);
+ if(!dbpath) {
+ /* pm_errno set in _alpm_db_path() */
+ return -1;
+ }
if((archive = archive_read_new()) == NULL) {
RET_ERR(db->handle, ALPM_ERR_LIBARCHIVE, -1);
@@ -431,30 +440,31 @@ static int sync_db_populate(alpm_db_t *db)
archive_read_support_compression_all(archive);
archive_read_support_format_all(archive);
- dbpath = _alpm_db_path(db);
- if(!dbpath) {
- /* pm_errno set in _alpm_db_path() */
- return -1;
- }
-
- _alpm_log(db->handle, ALPM_LOG_DEBUG, "opening database archive %s\n", dbpath);
+ _alpm_log(db->handle, ALPM_LOG_DEBUG,
+ "opening database archive %s\n", dbpath);
+ do {
+ fd = open(dbpath, O_RDONLY);
+ } while(fd == -1 && errno == EINTR);
- if(archive_read_open_filename(archive, dbpath,
+ if(fd < 0 || archive_read_open_fd(archive, fd,
ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
- _alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), dbpath,
- archive_error_string(archive));
- archive_read_finish(archive);
- RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1);
+ 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(stat(dbpath, &buf) != 0) {
- RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1);
+ if(fstat(fd, &buf) != 0) {
+ db->handle->pm_errno = ALPM_ERR_DB_OPEN;
+ goto cleanup;
}
est_count = estimate_package_count(&buf, archive);
/* initialize hash at 66% full */
db->pkgcache = _alpm_pkghash_create(est_count * 3 / 2);
if(db->pkgcache == NULL) {
- RET_ERR(db->handle, ALPM_ERR_MEMORY, -1);
+ db->handle->pm_errno = ALPM_ERR_MEMORY;
+ goto cleanup;
}
while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
@@ -473,14 +483,19 @@ static int sync_db_populate(alpm_db_t *db)
}
count = alpm_list_count(db->pkgcache->list);
-
if(count > 0) {
- db->pkgcache->list = alpm_list_msort(db->pkgcache->list, (size_t)count, _alpm_pkg_cmp);
+ db->pkgcache->list = alpm_list_msort(db->pkgcache->list,
+ (size_t)count, _alpm_pkg_cmp);
}
- archive_read_finish(archive);
- _alpm_log(db->handle, ALPM_LOG_DEBUG, "added %d packages to package cache for db '%s'\n",
+ _alpm_log(db->handle, ALPM_LOG_DEBUG,
+ "added %d packages to package cache for db '%s'\n",
count, db->treename);
+cleanup:
+ archive_read_finish(archive);
+ if(fd >= 0) {
+ close(fd);
+ }
return count;
}
--
1.7.7
More information about the pacman-dev
mailing list