diff options
-rw-r--r-- | src/apk_io.h | 7 | ||||
-rw-r--r-- | src/archive.c | 13 | ||||
-rw-r--r-- | src/database.c | 3 | ||||
-rw-r--r-- | src/fetch.c | 8 | ||||
-rw-r--r-- | src/gunzip.c | 8 | ||||
-rw-r--r-- | src/io.c | 58 | ||||
-rw-r--r-- | src/url.c | 36 |
7 files changed, 122 insertions, 11 deletions
diff --git a/src/apk_io.h b/src/apk_io.h index 6e2e37c..b0e15a4 100644 --- a/src/apk_io.h +++ b/src/apk_io.h @@ -33,6 +33,11 @@ struct apk_xattr { }; APK_ARRAY(apk_xattr_array, struct apk_xattr); +struct apk_file_meta { + time_t mtime, atime; +}; +void apk_file_meta_to_fd(int fd, struct apk_file_meta *meta); + struct apk_file_info { char *name; char *link_target; @@ -50,6 +55,7 @@ struct apk_file_info { }; struct apk_istream { + void (*get_meta)(void *stream, struct apk_file_meta *meta); ssize_t (*read)(void *stream, void *ptr, size_t size); void (*close)(void *stream); }; @@ -59,6 +65,7 @@ struct apk_istream { struct apk_bstream { unsigned int flags; + void (*get_meta)(void *stream, struct apk_file_meta *meta); apk_blob_t (*read)(void *stream, apk_blob_t token); void (*close)(void *stream, size_t *size); }; diff --git a/src/archive.c b/src/archive.c index e58f6d5..ecb276a 100644 --- a/src/archive.c +++ b/src/archive.c @@ -84,8 +84,19 @@ struct apk_tar_entry_istream { size_t bytes_left; EVP_MD_CTX mdctx; struct apk_checksum *csum; + time_t mtime; }; +static void tar_entry_get_meta(void *stream, struct apk_file_meta *meta) +{ + struct apk_tar_entry_istream *teis = + container_of(stream, struct apk_tar_entry_istream, is); + *meta = (struct apk_file_meta) { + .atime = teis->mtime, + .mtime = teis->mtime, + }; +} + static ssize_t tar_entry_read(void *stream, void *ptr, size_t size) { struct apk_tar_entry_istream *teis = @@ -175,6 +186,7 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser, { struct apk_file_info entry; struct apk_tar_entry_istream teis = { + .is.get_meta = tar_entry_get_meta, .is.read = tar_entry_read, .is.close = tar_entry_close, .tar_is = is, @@ -213,6 +225,7 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser, buf.mode[0] = 0; /* to nul terminate 100-byte buf.name */ buf.magic[0] = 0; /* to nul terminate 100-byte buf.linkname */ teis.csum = NULL; + teis.mtime = entry.mtime; apk_xattr_array_resize(&entry.xattrs, 0); if (paxlen) { diff --git a/src/database.c b/src/database.c index ed7f10b..8a56401 100644 --- a/src/database.c +++ b/src/database.c @@ -655,7 +655,10 @@ int apk_cache_download(struct apk_database *db, struct apk_repository *repo, } else fd = -1, r = PTR_ERR(is) ?: -EIO; if (fd >= 0) { + struct apk_file_meta meta; r = apk_istream_splice(is, fd, APK_SPLICE_ALL, cb, cb_ctx); + is->get_meta(is, &meta); + apk_file_meta_to_fd(fd, &meta); close(fd); } } diff --git a/src/fetch.c b/src/fetch.c index 43e4dbf..3bb7934 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -175,9 +175,13 @@ static int fetch_package(apk_hash_item item, void *pctx) } r = apk_istream_splice(is, fd, pkg->size, progress_cb, ctx); - is->close(is); - if (fd != STDOUT_FILENO) + if (fd != STDOUT_FILENO) { + struct apk_file_meta meta; + is->get_meta(is, &meta); + apk_file_meta_to_fd(fd, &meta); close(fd); + } + is->close(is); if (r != pkg->size) { unlinkat(ctx->outdir_fd, filename, 0); diff --git a/src/gunzip.c b/src/gunzip.c index 366094f..d1eb0cb 100644 --- a/src/gunzip.c +++ b/src/gunzip.c @@ -30,6 +30,13 @@ struct apk_gzip_istream { apk_blob_t cbarg; }; +static void gzi_get_meta(void *stream, struct apk_file_meta *meta) +{ + struct apk_gzip_istream *gis = + container_of(stream, struct apk_gzip_istream, is); + gis->bs->get_meta(gis->bs, meta); +} + static ssize_t gzi_read(void *stream, void *ptr, size_t size) { struct apk_gzip_istream *gis = @@ -155,6 +162,7 @@ struct apk_istream *apk_bstream_gunzip_mpart(struct apk_bstream *bs, if (!gis) goto err; *gis = (struct apk_gzip_istream) { + .is.get_meta = gzi_get_meta, .is.read = gzi_read, .is.close = gzi_close, .bs = bs, @@ -33,6 +33,27 @@ #define HAVE_FGETGRENT_R #endif +static void apk_file_meta_from_fd(int fd, struct apk_file_meta *meta) +{ + struct stat st; + + if (fstat(fd, &st) == 0) { + meta->mtime = st.st_mtime; + meta->atime = st.st_atime; + } else { + memset(meta, 0, sizeof(*meta)); + } +} + +void apk_file_meta_to_fd(int fd, struct apk_file_meta *meta) +{ + struct timespec times[2] = { + { .tv_sec = meta->atime, .tv_nsec = meta->atime ? 0 : UTIME_OMIT }, + { .tv_sec = meta->mtime, .tv_nsec = meta->mtime ? 0 : UTIME_OMIT } + }; + futimens(fd, times); +} + struct apk_fd_istream { struct apk_istream is; int fd; @@ -40,6 +61,13 @@ struct apk_fd_istream { int (*translate_status)(int status); }; +static void fdi_get_meta(void *stream, struct apk_file_meta *meta) +{ + struct apk_fd_istream *fis = + container_of(stream, struct apk_fd_istream, is); + apk_file_meta_from_fd(fis->fd, meta); +} + static ssize_t fdi_read(void *stream, void *ptr, size_t size) { struct apk_fd_istream *fis = @@ -95,6 +123,7 @@ struct apk_istream *apk_istream_from_fd_pid(int fd, pid_t pid, int (*translate_s } *fis = (struct apk_fd_istream) { + .is.get_meta = fdi_get_meta, .is.read = fdi_read, .is.close = fdi_close, .fd = fd, @@ -207,6 +236,13 @@ struct apk_istream_bstream { size_t size; }; +static void is_bs_get_meta(void *stream, struct apk_file_meta *meta) +{ + struct apk_istream_bstream *isbs = + container_of(stream, struct apk_istream_bstream, bs); + return isbs->is->get_meta(isbs->is, meta); +} + static apk_blob_t is_bs_read(void *stream, apk_blob_t token) { struct apk_istream_bstream *isbs = @@ -284,6 +320,7 @@ struct apk_bstream *apk_bstream_from_istream(struct apk_istream *istream) if (isbs == NULL) return ERR_PTR(-ENOMEM); isbs->bs = (struct apk_bstream) { + .get_meta = is_bs_get_meta, .read = is_bs_read, .close = is_bs_close, }; @@ -302,6 +339,13 @@ struct apk_mmap_bstream { apk_blob_t left; }; +static void mmap_get_meta(void *stream, struct apk_file_meta *meta) +{ + struct apk_mmap_bstream *mbs = + container_of(stream, struct apk_mmap_bstream, bs); + return apk_file_meta_from_fd(mbs->fd, meta); +} + static apk_blob_t mmap_read(void *stream, apk_blob_t token) { struct apk_mmap_bstream *mbs = @@ -351,6 +395,7 @@ static struct apk_bstream *apk_mmap_bstream_from_fd(int fd) mbs->bs = (struct apk_bstream) { .flags = APK_BSTREAM_SINGLE_READ, + .get_meta = mmap_get_meta, .read = mmap_read, .close = mmap_close, }; @@ -397,6 +442,13 @@ struct apk_tee_bstream { void *cb_ctx; }; +static void tee_get_meta(void *stream, struct apk_file_meta *meta) +{ + struct apk_tee_bstream *tbs = + container_of(stream, struct apk_tee_bstream, bs); + tbs->inner_bs->get_meta(tbs->inner_bs, meta); +} + static apk_blob_t tee_read(void *stream, apk_blob_t token) { struct apk_tee_bstream *tbs = @@ -415,9 +467,14 @@ static apk_blob_t tee_read(void *stream, apk_blob_t token) static void tee_close(void *stream, size_t *size) { + struct apk_file_meta meta; struct apk_tee_bstream *tbs = container_of(stream, struct apk_tee_bstream, bs); + /* copy info */ + tbs->inner_bs->get_meta(tbs->inner_bs, &meta); + apk_file_meta_to_fd(tbs->fd, &meta); + tbs->inner_bs->close(tbs->inner_bs, NULL); if (size != NULL) *size = tbs->size; @@ -449,6 +506,7 @@ struct apk_bstream *apk_bstream_tee(struct apk_bstream *from, int atfd, const ch } tbs->bs = (struct apk_bstream) { + .get_meta = tee_get_meta, .read = tee_read, .close = tee_close, }; @@ -36,6 +36,7 @@ const char *apk_url_local_file(const char *url) struct apk_fetch_istream { struct apk_istream is; fetchIO *fetchIO; + struct url_stat urlstat; }; static int fetch_maperror(int ec) @@ -66,6 +67,16 @@ static int fetch_maperror(int ec) return map[ec]; } +static void fetch_get_meta(void *stream, struct apk_file_meta *meta) +{ + struct apk_fetch_istream *fis = container_of(stream, struct apk_fetch_istream, is); + + *meta = (struct apk_file_meta) { + .atime = fis->urlstat.atime, + .mtime = fis->urlstat.mtime, + }; +} + static ssize_t fetch_read(void *stream, void *ptr, size_t size) { struct apk_fetch_istream *fis = container_of(stream, struct apk_fetch_istream, is); @@ -95,28 +106,35 @@ static struct apk_istream *apk_istream_fetch(const char *url, time_t since) { struct apk_fetch_istream *fis; struct url *u; - fetchIO *io; + fetchIO *io = NULL; + int rc = -ENOMEM; u = fetchParseURL(url); - if (!u) return ERR_PTR(-ENOMEM); - u->last_modified = since; - io = fetchGet(u, "i"); - fetchFreeURL(u); - if (!io) return ERR_PTR(fetch_maperror(fetchLastErrCode)); - fis = malloc(sizeof(*fis)); - if (!fis) goto err; + if (!fis || !u) goto err; + + u->last_modified = since; + io = fetchXGet(u, &fis->urlstat, "i"); + if (!io) { + rc = fetch_maperror(fetchLastErrCode); + goto err; + } *fis = (struct apk_fetch_istream) { + .is.get_meta = fetch_get_meta, .is.read = fetch_read, .is.close = fetch_close, .fetchIO = io, + .urlstat = fis->urlstat, }; + fetchFreeURL(u); return &fis->is; err: + if (u) fetchFreeURL(u); if (io) fetchIO_close(io); - return ERR_PTR(-ENOMEM); + if (fis) free(fis); + return ERR_PTR(rc); } struct apk_istream *apk_istream_from_fd_url_if_modified(int atfd, const char *url, time_t since) |