summaryrefslogtreecommitdiff
path: root/src/archive.c
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2020-02-14 13:53:29 +0200
committerTimo Teräs <timo.teras@iki.fi>2020-02-14 16:53:12 +0200
commit6d11ec36e6b6e17978797ef8062d22175717f894 (patch)
tree83c81ff75a041f2025e556f50682df66e85fa8b1 /src/archive.c
parent60b87557e57ca4e23126bf8c25b1cb978e380dfd (diff)
downloadapk-tools-6d11ec36e6b6e17978797ef8062d22175717f894.tar.gz
apk-tools-6d11ec36e6b6e17978797ef8062d22175717f894.tar.bz2
apk-tools-6d11ec36e6b6e17978797ef8062d22175717f894.tar.xz
apk-tools-6d11ec36e6b6e17978797ef8062d22175717f894.zip
rename all iostream source to io_*.c
Diffstat (limited to 'src/archive.c')
-rw-r--r--src/archive.c444
1 files changed, 0 insertions, 444 deletions
diff --git a/src/archive.c b/src/archive.c
deleted file mode 100644
index 226bc23..0000000
--- a/src/archive.c
+++ /dev/null
@@ -1,444 +0,0 @@
-/* archive.c - Alpine Package Keeper (APK)
- *
- * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
- * Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation. See http://www.gnu.org/ for details.
- */
-
-#include <stdio.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <utime.h>
-#include <string.h>
-#include <unistd.h>
-#include <sysexits.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <sys/xattr.h>
-#include <sys/sysmacros.h>
-#include <limits.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "apk_defines.h"
-#include "apk_print.h"
-#include "apk_archive.h"
-#include "apk_openssl.h"
-
-struct tar_header {
- /* ustar header, Posix 1003.1 */
- char name[100]; /* 0-99 */
- char mode[8]; /* 100-107 */
- char uid[8]; /* 108-115 */
- char gid[8]; /* 116-123 */
- char size[12]; /* 124-135 */
- char mtime[12]; /* 136-147 */
- char chksum[8]; /* 148-155 */
- char typeflag; /* 156-156 */
- char linkname[100]; /* 157-256 */
- char magic[8]; /* 257-264 */
- char uname[32]; /* 265-296 */
- char gname[32]; /* 297-328 */
- char devmajor[8]; /* 329-336 */
- char devminor[8]; /* 337-344 */
- char prefix[155]; /* 345-499 */
- char padding[12]; /* 500-511 */
-};
-
-#define GET_OCTAL(s) get_octal(s, sizeof(s))
-#define PUT_OCTAL(s,v) put_octal(s, sizeof(s), v)
-
-static unsigned int get_octal(char *s, size_t l)
-{
- apk_blob_t b = APK_BLOB_PTR_LEN(s, l);
- return apk_blob_pull_uint(&b, 8);
-}
-
-static void put_octal(char *s, size_t l, size_t value)
-{
- char *ptr = &s[l - 1];
-
- *(ptr--) = '\0';
- while (value != 0 && ptr >= s) {
- *(ptr--) = '0' + (value % 8);
- value /= 8;
- }
- while (ptr >= s)
- *(ptr--) = '0';
-}
-
-static int blob_realloc(apk_blob_t *b, size_t newsize)
-{
- char *tmp;
- if (b->len >= newsize) return 0;
- tmp = realloc(b->ptr, newsize);
- if (!tmp) return -ENOMEM;
- b->ptr = tmp;
- b->len = newsize;
- return 0;
-}
-
-static void handle_extended_header(struct apk_file_info *fi, apk_blob_t hdr)
-{
- apk_blob_t name, value;
-
- while (1) {
- char *start = hdr.ptr;
- unsigned int len = apk_blob_pull_uint(&hdr, 10);
- apk_blob_pull_char(&hdr, ' ');
- if (!apk_blob_split(hdr, APK_BLOB_STR("="), &name, &hdr)) break;
- if (len < hdr.ptr - start + 1) break;
- len -= hdr.ptr - start + 1;
- if (hdr.len < len) break;
- value = APK_BLOB_PTR_LEN(hdr.ptr, len);
- hdr = APK_BLOB_PTR_LEN(hdr.ptr+len, hdr.len-len);
- apk_blob_pull_char(&hdr, '\n');
- if (APK_BLOB_IS_NULL(hdr)) break;
- value.ptr[value.len] = 0;
-
- if (apk_blob_compare(name, APK_BLOB_STR("path")) == 0) {
- fi->name = value.ptr;
- } else if (apk_blob_compare(name, APK_BLOB_STR("linkpath")) == 0) {
- fi->link_target = value.ptr;
- } else if (apk_blob_pull_blob_match(&name, APK_BLOB_STR("SCHILY.xattr."))) {
- name.ptr[name.len] = 0;
- *apk_xattr_array_add(&fi->xattrs) = (struct apk_xattr) {
- .name = name.ptr,
- .value = value,
- };
- } else if (apk_blob_pull_blob_match(&name, APK_BLOB_STR("APK-TOOLS.checksum."))) {
- int type = APK_CHECKSUM_NONE;
- if (apk_blob_compare(name, APK_BLOB_STR("SHA1")) == 0)
- type = APK_CHECKSUM_SHA1;
- else if (apk_blob_compare(name, APK_BLOB_STR("MD5")) == 0)
- type = APK_CHECKSUM_MD5;
- if (type > fi->csum.type) {
- fi->csum.type = type;
- apk_blob_pull_hexdump(&value, APK_BLOB_CSUM(fi->csum));
- if (APK_BLOB_IS_NULL(value)) fi->csum.type = APK_CHECKSUM_NONE;
- }
- }
- }
-}
-
-int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
- void *ctx, struct apk_id_cache *idc)
-{
- struct apk_file_info entry;
- struct apk_segment_istream segment;
- struct tar_header buf;
- int end = 0, r;
- size_t toskip, paxlen = 0;
- apk_blob_t pax = APK_BLOB_NULL, longname = APK_BLOB_NULL;
- char filename[sizeof buf.name + sizeof buf.prefix + 2];
-
- if (IS_ERR_OR_NULL(is)) return PTR_ERR(is) ?: -EINVAL;
-
- memset(&entry, 0, sizeof(entry));
- entry.name = buf.name;
- while ((r = apk_istream_read(is, &buf, 512)) == 512) {
- if (buf.name[0] == '\0') {
- if (end) break;
- end++;
- continue;
- }
-
- entry = (struct apk_file_info){
- .size = GET_OCTAL(buf.size),
- .uid = apk_resolve_uid(idc, buf.uname, GET_OCTAL(buf.uid)),
- .gid = apk_resolve_gid(idc, buf.gname, GET_OCTAL(buf.gid)),
- .mode = GET_OCTAL(buf.mode) & 07777,
- .mtime = GET_OCTAL(buf.mtime),
- .name = entry.name,
- .uname = buf.uname,
- .gname = buf.gname,
- .device = makedev(GET_OCTAL(buf.devmajor),
- GET_OCTAL(buf.devminor)),
- .xattrs = entry.xattrs,
- };
- if (buf.prefix[0] && buf.typeflag != 'x' && buf.typeflag != 'g') {
- snprintf(filename, sizeof filename, "%.*s/%.*s",
- (int) sizeof buf.prefix, buf.prefix,
- (int) sizeof buf.name, buf.name);
- entry.name = filename;
- }
- buf.mode[0] = 0; /* to nul terminate 100-byte buf.name */
- buf.magic[0] = 0; /* to nul terminate 100-byte buf.linkname */
- apk_xattr_array_resize(&entry.xattrs, 0);
-
- if (entry.size >= SSIZE_MAX-512) goto err;
-
- if (paxlen) {
- handle_extended_header(&entry, APK_BLOB_PTR_LEN(pax.ptr, paxlen));
- apk_fileinfo_hash_xattr(&entry);
- }
-
- toskip = (entry.size + 511) & -512;
- switch (buf.typeflag) {
- case 'L': /* GNU long name extension */
- if ((r = blob_realloc(&longname, entry.size+1)) != 0 ||
- (r = apk_istream_read(is, longname.ptr, entry.size)) != entry.size)
- goto err;
- entry.name = longname.ptr;
- entry.name[entry.size] = 0;
- toskip -= entry.size;
- break;
- case 'K': /* GNU long link target extension - ignored */
- break;
- case '0':
- case '7': /* regular file */
- entry.mode |= S_IFREG;
- break;
- case '1': /* hard link */
- entry.mode |= S_IFREG;
- if (!entry.link_target) entry.link_target = buf.linkname;
- break;
- case '2': /* symbolic link */
- entry.mode |= S_IFLNK;
- if (!entry.link_target) entry.link_target = buf.linkname;
- break;
- case '3': /* char device */
- entry.mode |= S_IFCHR;
- break;
- case '4': /* block device */
- entry.mode |= S_IFBLK;
- break;
- case '5': /* directory */
- entry.mode |= S_IFDIR;
- break;
- case '6': /* fifo */
- entry.mode |= S_IFIFO;
- break;
- case 'g': /* global pax header */
- break;
- case 'x': /* file specific pax header */
- paxlen = entry.size;
- if ((r = blob_realloc(&pax, (paxlen + 511) & -512)) != 0 ||
- (r = apk_istream_read(is, pax.ptr, paxlen)) != paxlen)
- goto err;
- toskip -= entry.size;
- break;
- default:
- break;
- }
-
- if (strnlen(entry.name, PATH_MAX) >= PATH_MAX-10 ||
- (entry.link_target && strnlen(entry.link_target, PATH_MAX) >= PATH_MAX-10)) {
- r = -ENAMETOOLONG;
- goto err;
- }
-
- if (entry.mode & S_IFMT) {
- apk_istream_segment(&segment, is, entry.size, entry.mtime);
- r = parser(ctx, &entry, &segment.is);
- if (r != 0) goto err;
- apk_istream_close(&segment.is);
-
- entry.name = buf.name;
- toskip -= entry.size;
- paxlen = 0;
- }
-
- if (toskip && (r = apk_istream_read(is, NULL, toskip)) != toskip)
- goto err;
- }
-
- /* Read remaining end-of-archive records, to ensure we read all of
- * the file. The underlying istream is likely doing checksumming. */
- if (r == 512) {
- while ((r = apk_istream_read(is, &buf, 512)) == 512) {
- if (buf.name[0] != 0) break;
- }
- }
- if (r == 0) goto ok;
-err:
- /* Check that there was no partial (or non-zero) record */
- if (r >= 0) r = -EBADMSG;
-ok:
- free(pax.ptr);
- free(longname.ptr);
- apk_fileinfo_free(&entry);
- apk_istream_close(is);
- return r;
-}
-
-int apk_tar_write_entry(struct apk_ostream *os, const struct apk_file_info *ae,
- const char *data)
-{
- struct tar_header buf;
-
- memset(&buf, 0, sizeof(buf));
- if (ae != NULL) {
- const unsigned char *src;
- int chksum, i;
-
- if (S_ISREG(ae->mode))
- buf.typeflag = '0';
- else
- return -1;
-
- if (ae->name != NULL)
- strlcpy(buf.name, ae->name, sizeof buf.name);
-
- strlcpy(buf.uname, ae->uname ?: "root", sizeof buf.uname);
- strlcpy(buf.gname, ae->gname ?: "root", sizeof buf.gname);
-
- PUT_OCTAL(buf.size, ae->size);
- PUT_OCTAL(buf.uid, ae->uid);
- PUT_OCTAL(buf.gid, ae->gid);
- PUT_OCTAL(buf.mode, ae->mode & 07777);
- PUT_OCTAL(buf.mtime, ae->mtime ?: time(NULL));
-
- /* Checksum */
- strcpy(buf.magic, "ustar ");
- memset(buf.chksum, ' ', sizeof(buf.chksum));
- src = (const unsigned char *) &buf;
- for (i = chksum = 0; i < sizeof(buf); i++)
- chksum += src[i];
- put_octal(buf.chksum, sizeof(buf.chksum)-1, chksum);
- }
-
- if (apk_ostream_write(os, &buf, sizeof(buf)) != sizeof(buf))
- return -1;
-
- if (ae == NULL) {
- /* End-of-archive is two empty headers */
- if (apk_ostream_write(os, &buf, sizeof(buf)) != sizeof(buf))
- return -1;
- } else if (data != NULL) {
- if (apk_ostream_write(os, data, ae->size) != ae->size)
- return -1;
- if (apk_tar_write_padding(os, ae) != 0)
- return -1;
- }
-
- return 0;
-}
-
-int apk_tar_write_padding(struct apk_ostream *os, const struct apk_file_info *ae)
-{
- static char padding[512];
- int pad;
-
- pad = 512 - (ae->size & 511);
- if (pad != 512 &&
- apk_ostream_write(os, padding, pad) != pad)
- return -1;
-
- return 0;
-}
-
-int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
- const char *extract_name, const char *link_target,
- struct apk_istream *is,
- apk_progress_cb cb, void *cb_ctx)
-{
- struct apk_xattr *xattr;
- const char *fn = extract_name ?: ae->name;
- int fd, r = -1, atflags = 0, ret = 0;
-
- if (unlinkat(atfd, fn, 0) != 0 && errno != ENOENT) return -errno;
-
- switch (ae->mode & S_IFMT) {
- case S_IFDIR:
- r = mkdirat(atfd, fn, ae->mode & 07777);
- if (r < 0 && errno != EEXIST)
- ret = -errno;
- break;
- case S_IFREG:
- if (ae->link_target == NULL) {
- int flags = O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC | O_EXCL;
-
- fd = openat(atfd, fn, flags, ae->mode & 07777);
- if (fd < 0) {
- ret = -errno;
- break;
- }
- r = apk_istream_splice(is, fd, ae->size, cb, cb_ctx);
- if (r != ae->size) ret = r < 0 ? r : -ENOSPC;
- close(fd);
- } else {
- r = linkat(atfd, link_target ?: ae->link_target, atfd, fn, 0);
- if (r < 0) ret = -errno;
- }
- break;
- case S_IFLNK:
- r = symlinkat(link_target ?: ae->link_target, atfd, fn);
- if (r < 0) ret = -errno;
- atflags |= AT_SYMLINK_NOFOLLOW;
- break;
- case S_IFBLK:
- case S_IFCHR:
- case S_IFIFO:
- r = mknodat(atfd, fn, ae->mode, ae->device);
- if (r < 0) ret = -errno;
- break;
- }
- if (ret) {
- apk_error("Failed to create %s: %s", ae->name, strerror(-ret));
- return ret;
- }
-
- r = fchownat(atfd, fn, ae->uid, ae->gid, atflags);
- if (r < 0) {
- apk_error("Failed to set ownership on %s: %s",
- fn, strerror(errno));
- if (!ret) ret = -errno;
- }
-
- /* chown resets suid bit so we need set it again */
- if (ae->mode & 07000) {
- r = fchmodat(atfd, fn, ae->mode & 07777, atflags);
- if (r < 0) {
- apk_error("Failed to set file permissions "
- "on %s: %s",
- fn, strerror(errno));
- if (!ret) ret = -errno;
- }
- }
-
- /* extract xattrs */
- if (!S_ISLNK(ae->mode) && ae->xattrs && ae->xattrs->num) {
- r = 0;
- fd = openat(atfd, fn, O_RDWR);
- if (fd >= 0) {
- foreach_array_item(xattr, ae->xattrs) {
- if (fsetxattr(fd, xattr->name, xattr->value.ptr, xattr->value.len, 0) < 0) {
- r = -errno;
- if (r != -ENOTSUP) break;
- }
- }
- close(fd);
- } else {
- r = -errno;
- }
- if (r) {
- if (r != -ENOTSUP)
- apk_error("Failed to set xattrs on %s: %s",
- fn, strerror(-r));
- if (!ret) ret = r;
- }
- }
-
- if (!S_ISLNK(ae->mode)) {
- /* preserve modification time */
- struct timespec times[2];
-
- times[0].tv_sec = times[1].tv_sec = ae->mtime;
- times[0].tv_nsec = times[1].tv_nsec = 0;
- r = utimensat(atfd, fn, times, atflags);
- if (r < 0) {
- apk_error("Failed to preserve modification time on %s: %s",
- fn, strerror(errno));
- if (!ret || ret == -ENOTSUP) ret = -errno;
- }
- }
-
- return ret;
-}