diff --git a/src/apk_database.h b/src/apk_database.h index 3e70383..ff8eac5 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -96,7 +96,7 @@ void apk_db_close(struct apk_database *db); struct apk_package *apk_db_pkg_add_file(struct apk_database *db, const char *file); struct apk_package *apk_db_get_pkg(struct apk_database *db, csum_t sum); -void apk_db_index_write(struct apk_database *db, int fd); +void apk_db_index_write(struct apk_database *db, struct apk_ostream *os); int apk_db_add_repository(apk_database_t db, apk_blob_t repository); int apk_db_recalculate_and_commit(struct apk_database *db); diff --git a/src/apk_io.h b/src/apk_io.h index d9522f6..833257d 100644 --- a/src/apk_io.h +++ b/src/apk_io.h @@ -35,13 +35,20 @@ struct apk_istream { struct apk_bstream { size_t (*read)(void *stream, void **ptr); - void (*close)(void *stream, csum_p csum); + void (*close)(void *stream, csum_p csum, size_t *size); }; -struct apk_istream *apk_gunzip_bstream(struct apk_bstream *); +struct apk_ostream { + size_t (*write)(void *stream, const void *buf, size_t size); + void (*close)(void *stream); +}; + +struct apk_istream *apk_bstream_gunzip(struct apk_bstream *); +struct apk_ostream *apk_ostream_gzip(struct apk_ostream *); struct apk_istream *apk_istream_from_fd(int fd); struct apk_istream *apk_istream_from_file(const char *file); +struct apk_istream *apk_istream_from_file_gz(const char *file); struct apk_istream *apk_istream_from_url(const char *url); size_t apk_istream_skip(struct apk_istream *istream, size_t size); size_t apk_istream_splice(void *stream, int fd, size_t size); @@ -51,7 +58,9 @@ struct apk_bstream *apk_bstream_from_fd(int fd); struct apk_bstream *apk_bstream_from_file(const char *file); struct apk_bstream *apk_bstream_from_url(const char *url); -struct apk_istream *apk_istream_from_file_gz(const char *file); +struct apk_ostream *apk_ostream_to_fd(int fd); +struct apk_ostream *apk_ostream_to_file(const char *file, mode_t mode); +struct apk_ostream *apk_ostream_to_file_gz(const char *file, mode_t mode); apk_blob_t apk_blob_from_istream(struct apk_istream *istream, size_t size); apk_blob_t apk_blob_from_file(const char *file); diff --git a/src/apk_package.h b/src/apk_package.h index 3fddf67..fdfe5b7 100644 --- a/src/apk_package.h +++ b/src/apk_package.h @@ -54,7 +54,7 @@ struct apk_package { char *version; char *url, *description, *license; struct apk_dependency_array *depends; - unsigned int installed_size, size; + size_t installed_size, size; char *filename; /* for installed packages only */ diff --git a/src/archive.c b/src/archive.c index 6562297..201412b 100644 --- a/src/archive.c +++ b/src/archive.c @@ -23,10 +23,6 @@ #include "apk_defines.h" #include "apk_archive.h" -#ifndef GUNZIP_BINARY -#define GUNZIP_BINARY "/bin/gunzip" -#endif - struct tar_header { /* ustar header, Posix 1003.1 */ char name[100]; /* 0-99 */ @@ -182,7 +178,7 @@ int apk_parse_tar(struct apk_istream *is, apk_archive_entry_parser parser, int apk_parse_tar_gz(struct apk_bstream *bs, apk_archive_entry_parser parser, void *ctx) { - return apk_parse_tar(apk_gunzip_bstream(bs), parser, ctx); + return apk_parse_tar(apk_bstream_gunzip(bs), parser, ctx); } int apk_archive_entry_extract(const struct apk_file_info *ae, diff --git a/src/database.c b/src/database.c index c30550b..ec99ffe 100644 --- a/src/database.c +++ b/src/database.c @@ -369,7 +369,7 @@ static int apk_db_index_read(struct apk_database *db, struct apk_istream *is, in return 0; } -static int apk_db_write_fdb(struct apk_database *db, int fd) +static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os) { struct apk_package *pkg; struct apk_db_dir *dir; @@ -382,14 +382,14 @@ static int apk_db_write_fdb(struct apk_database *db, int fd) list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) { blob = apk_pkg_format_index_entry(pkg, sizeof(buf), buf); if (blob.ptr) - write(fd, blob.ptr, blob.len - 1); + os->write(os, blob.ptr, blob.len - 1); - n = 0; dir = NULL; hlist_for_each_entry(file, c2, &pkg->owned_files, pkg_files_list) { if (file->owner == NULL) continue; + n = 0; if (dir != file->dir) { dir = file->dir; n += snprintf(&buf[n], sizeof(buf)-n, @@ -409,11 +409,10 @@ static int apk_db_write_fdb(struct apk_database *db, int fd) n += snprintf(&buf[n], sizeof(buf)-n, "\n"); } - if (write(fd, buf, n) != n) + if (os->write(os, buf, n) != n) return -1; - n = 0; } - write(fd, "\n", 1); + os->write(os, "\n", 1); } return 0; @@ -425,7 +424,7 @@ struct apk_script_header { unsigned int size; }; -static int apk_db_scriptdb_write(struct apk_database *db, int fd) +static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os) { struct apk_package *pkg; struct apk_script *script; @@ -438,8 +437,11 @@ static int apk_db_scriptdb_write(struct apk_database *db, int fd) hdr.type = script->type; hdr.size = script->size; - write(fd, &hdr, sizeof(hdr)); - write(fd, script->script, script->size); + if (os->write(os, &hdr, sizeof(hdr)) != sizeof(hdr)) + return -1; + + if (os->write(os, script->script, script->size) != script->size) + return -1; } } @@ -580,32 +582,33 @@ struct write_ctx { static int apk_db_write_config(struct apk_database *db) { + struct apk_ostream *os; char buf[1024]; - int n, fd; + int n; if (db->root == NULL) return 0; fchdir(db->root_fd); - fd = creat("var/lib/apk/world", 0600); - if (fd < 0) + os = apk_ostream_to_file("var/lib/apk/world", 0600); + if (os == NULL) return -1; n = apk_deps_format(buf, sizeof(buf), db->world); - write(fd, buf, n); - close(fd); + os->write(os, buf, n); + os->close(os); - fd = creat("var/lib/apk/installed", 0600); - if (fd < 0) + os = apk_ostream_to_file("var/lib/apk/installed", 0600); + if (os == NULL) return -1; - apk_db_write_fdb(db, fd); - close(fd); + apk_db_write_fdb(db, os); + os->close(os); - fd = creat("var/lib/apk/scripts", 0600); - if (fd < 0) + os = apk_ostream_to_file("var/lib/apk/scripts", 0600); + if (os == NULL) return -1; - apk_db_scriptdb_write(db, fd); - close(fd); + apk_db_scriptdb_write(db, os); + os->close(os); return 0; } @@ -639,20 +642,23 @@ struct apk_package *apk_db_pkg_add_file(struct apk_database *db, const char *fil static int write_index_entry(apk_hash_item item, void *ctx) { - int fd = (int) ctx; + struct apk_ostream *os = (struct apk_ostream *) ctx; char buf[1024]; apk_blob_t blob; blob = apk_pkg_format_index_entry(item, sizeof(buf), buf); - if (blob.ptr) - write(fd, blob.ptr, blob.len); + if (APK_BLOB_IS_NULL(blob)) + return 0; + + if (os->write(os, blob.ptr, blob.len) != blob.len) + return -1; return 0; } -void apk_db_index_write(struct apk_database *db, int fd) +void apk_db_index_write(struct apk_database *db, struct apk_ostream *os) { - apk_hash_foreach(&db->available.packages, write_index_entry, (void *) fd); + apk_hash_foreach(&db->available.packages, write_index_entry, (void *) os); } int apk_db_add_repository(apk_database_t _db, apk_blob_t repository) @@ -884,7 +890,7 @@ int apk_db_install_pkg(struct apk_database *db, if (apk_parse_tar_gz(bs, apk_db_install_archive_entry, &ctx) != 0) goto err_close; - bs->close(bs, csum); + bs->close(bs, csum, NULL); apk_pkg_set_state(db, newpkg, APK_STATE_INSTALL); @@ -903,6 +909,6 @@ int apk_db_install_pkg(struct apk_database *db, } return r; err_close: - bs->close(bs, NULL); + bs->close(bs, NULL, NULL); return -1; } diff --git a/src/gunzip.c b/src/gunzip.c index cfee860..ce3eeed 100644 --- a/src/gunzip.c +++ b/src/gunzip.c @@ -67,7 +67,7 @@ static void gz_close(void *stream) free(gis); } -struct apk_istream *apk_gunzip_bstream(struct apk_bstream *bs) +struct apk_istream *apk_bstream_gunzip(struct apk_bstream *bs) { struct apk_gzip_istream *gis; diff --git a/src/index.c b/src/index.c index 45b7cf1..91d1ce6 100644 --- a/src/index.c +++ b/src/index.c @@ -43,12 +43,17 @@ static int index_main(int argc, char **argv) { struct apk_database db; struct counts counts = {0,0}; + struct apk_ostream *os; int i; apk_db_open(&db, NULL); for (i = 0; i < argc; i++) apk_db_pkg_add_file(&db, argv[i]); - apk_db_index_write(&db, STDOUT_FILENO); + + os = apk_ostream_to_fd(STDOUT_FILENO); + apk_db_index_write(&db, os); + os->close(os); + apk_hash_foreach(&db.available.names, warn_if_no_providers, &counts); apk_db_close(&db); diff --git a/src/io.c b/src/io.c index 2c92084..78452a9 100644 --- a/src/io.c +++ b/src/io.c @@ -23,7 +23,7 @@ struct apk_fd_istream { int fd; }; -static size_t fd_read(void *stream, void *ptr, size_t size) +static size_t fdi_read(void *stream, void *ptr, size_t size) { struct apk_fd_istream *fis = container_of(stream, struct apk_fd_istream, is); @@ -47,7 +47,7 @@ static size_t fd_read(void *stream, void *ptr, size_t size) return i; } -static void fd_close(void *stream) +static void fdi_close(void *stream) { struct apk_fd_istream *fis = container_of(stream, struct apk_fd_istream, is); @@ -68,8 +68,8 @@ struct apk_istream *apk_istream_from_fd(int fd) return NULL; *fis = (struct apk_fd_istream) { - .is.read = fd_read, - .is.close = fd_close, + .is.read = fdi_read, + .is.close = fdi_close, .fd = fd, }; @@ -148,6 +148,7 @@ struct apk_istream_bstream { struct apk_istream *is; csum_ctx_t csum_ctx; unsigned char buffer[8*1024]; + size_t size; }; static size_t is_bs_read(void *stream, void **ptr) @@ -161,12 +162,13 @@ static size_t is_bs_read(void *stream, void **ptr) return size; csum_process(&isbs->csum_ctx, isbs->buffer, size); + isbs->size += size; *ptr = isbs->buffer; return size; } -static void is_bs_close(void *stream, csum_t csum) +static void is_bs_close(void *stream, csum_t csum, size_t *size) { struct apk_istream_bstream *isbs = container_of(stream, struct apk_istream_bstream, bs); @@ -178,11 +180,15 @@ static void is_bs_close(void *stream, csum_t csum) size = isbs->is->read(isbs->is, isbs->buffer, sizeof(isbs->buffer)); csum_process(&isbs->csum_ctx, isbs->buffer, size); + isbs->size += size; } while (size == sizeof(isbs->buffer)); csum_finish(&isbs->csum_ctx, csum); } + if (size != NULL) + *size = isbs->size; + isbs->is->close(isbs->is); free(isbs); } @@ -231,7 +237,7 @@ static size_t mmap_read(void *stream, void **ptr) return size; } -static void mmap_close(void *stream, csum_t csum) +static void mmap_close(void *stream, csum_t csum, size_t *size) { struct apk_mmap_bstream *mbs = container_of(stream, struct apk_mmap_bstream, bs); @@ -243,6 +249,9 @@ static void mmap_close(void *stream, csum_t csum) csum_finish(&mbs->csum_ctx, csum); } + if (size != NULL) + *size = mbs->size; + munmap(mbs->ptr, mbs->size); free(mbs); } @@ -373,13 +382,78 @@ int apk_file_get_info(const char *filename, struct apk_file_info *fi) bs = apk_bstream_from_file(filename); if (bs != NULL) - bs->close(bs, fi->csum); + bs->close(bs, fi->csum, NULL); return 0; } struct apk_istream *apk_istream_from_file_gz(const char *file) { - return apk_gunzip_bstream(apk_bstream_from_file(file)); + return apk_bstream_gunzip(apk_bstream_from_file(file)); +} + +struct apk_fd_ostream { + struct apk_ostream os; + int fd; +}; + +static size_t fdo_write(void *stream, const void *ptr, size_t size) +{ + struct apk_fd_ostream *fos = + container_of(stream, struct apk_fd_ostream, os); + size_t i = 0, r; + + while (i < size) { + r = write(fos->fd, ptr + i, size - i); + if (r < 0) + return r; + if (r == 0) + return i; + i += r; + } + + return i; +} + +static void fdo_close(void *stream) +{ + struct apk_fd_ostream *fos = + container_of(stream, struct apk_fd_ostream, os); + + close(fos->fd); + free(fos); +} + +struct apk_ostream *apk_ostream_to_fd(int fd) +{ + struct apk_fd_ostream *fos; + + if (fd < 0) + return NULL; + + fos = malloc(sizeof(struct apk_fd_ostream)); + if (fos == NULL) + return NULL; + + *fos = (struct apk_fd_ostream) { + .os.write = fdo_write, + .os.close = fdo_close, + .fd = fd, + }; + + return &fos->os; +} + +struct apk_ostream *apk_ostream_to_file(const char *file, mode_t mode) +{ + int fd; + + fd = creat(file, mode); + if (fd < 0) + return NULL; + + fcntl(fd, F_SETFD, FD_CLOEXEC); + + return apk_ostream_to_fd(fd); } diff --git a/src/package.c b/src/package.c index d419596..8a87b14 100644 --- a/src/package.c +++ b/src/package.c @@ -331,35 +331,23 @@ struct apk_package *apk_pkg_read(struct apk_database *db, const char *file) { struct read_info_ctx ctx; struct apk_bstream *bs; - struct stat st; - int fd; ctx.pkg = apk_pkg_new(); if (ctx.pkg == NULL) return NULL; - fd = open(file, O_RDONLY); - if (fd < 0) + bs = apk_bstream_from_file(file); + if (bs == NULL) goto err; - fstat(fd, &st); - fcntl(fd, F_SETFD, FD_CLOEXEC); - - bs = apk_bstream_from_fd(fd); - if (bs == NULL) { - close(fd); - goto err; - } - ctx.db = db; - ctx.pkg->size = st.st_size; ctx.has_install = 0; if (apk_parse_tar_gz(bs, read_info_entry, &ctx) < 0) { apk_error("File %s is not an APK archive", file); - bs->close(bs, NULL); + bs->close(bs, NULL, NULL); goto err; } - bs->close(bs, ctx.pkg->csum); + bs->close(bs, ctx.pkg->csum, &ctx.pkg->size); if (ctx.pkg->name == NULL) { apk_error("File %s is corrupted", file);