aboutsummaryrefslogtreecommitdiff
path: root/tar/write_header.c
diff options
context:
space:
mode:
Diffstat (limited to 'tar/write_header.c')
-rw-r--r--tar/write_header.c248
1 files changed, 0 insertions, 248 deletions
diff --git a/tar/write_header.c b/tar/write_header.c
deleted file mode 100644
index 80db327..0000000
--- a/tar/write_header.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/* SPDX-License-Identifier: GPL-3.0-or-later */
-#include "util.h"
-#include "tar.h"
-
-#include <sys/sysmacros.h>
-#include <string.h>
-#include <stdio.h>
-
-static unsigned long pax_hdr_counter = 0;
-static char buffer[4096];
-
-static void write_octal(char *dst, unsigned int value, int digits)
-{
- char temp[64];
-
- sprintf(temp, "%0*o ", digits, value);
- memcpy(dst, temp, strlen(temp));
-}
-
-static int name_to_tar_header(tar_header_t *hdr, const char *path)
-{
- size_t len = strlen(path);
- const char *ptr;
-
- if ((len + 1) <= sizeof(hdr->name)) {
- memcpy(hdr->name, path, len);
- return 0;
- }
-
- for (ptr = path; ; ++ptr) {
- ptr = strchr(ptr, '/');
- if (ptr == NULL)
- return -1;
-
- len = ptr - path;
- if (len >= sizeof(hdr->prefix))
- continue;
- if (strlen(ptr + 1) >= sizeof(hdr->name))
- continue;
- break;
- }
-
- memcpy(hdr->prefix, path, ptr - path);
- memcpy(hdr->name, ptr + 1, strlen(ptr + 1));
- return 0;
-}
-
-static void init_header(tar_header_t *hdr, const struct stat *sb,
- const char *name, const char *slink_target)
-{
- memset(hdr, 0, sizeof(*hdr));
-
- name_to_tar_header(hdr, name);
- memcpy(hdr->magic, TAR_MAGIC, sizeof(hdr->magic));
- memcpy(hdr->version, TAR_VERSION, sizeof(hdr->version));
- write_octal(hdr->mode, sb->st_mode & ~S_IFMT, 6);
- write_octal(hdr->uid, sb->st_uid, 6);
- write_octal(hdr->gid, sb->st_gid, 6);
- write_octal(hdr->mtime, sb->st_mtime, 11);
- write_octal(hdr->size, 0, 11);
- write_octal(hdr->devmajor, 0, 6);
- write_octal(hdr->devminor, 0, 6);
-
- switch (sb->st_mode & S_IFMT) {
- case S_IFREG:
- write_octal(hdr->size, sb->st_size & 077777777777L, 11);
- break;
- case S_IFLNK:
- if (sb->st_size < (off_t)sizeof(hdr->linkname))
- strcpy(hdr->linkname, slink_target);
- break;
- case S_IFCHR:
- case S_IFBLK:
- write_octal(hdr->devmajor, major(sb->st_rdev), 6);
- write_octal(hdr->devminor, minor(sb->st_rdev), 6);
- break;
- }
-
- sprintf(hdr->uname, "%u", sb->st_uid);
- sprintf(hdr->gname, "%u", sb->st_gid);
-}
-
-static void update_checksum(tar_header_t *hdr)
-{
- unsigned int chksum = 0;
- size_t i;
-
- memset(hdr->chksum, ' ', sizeof(hdr->chksum));
-
- for (i = 0; i < sizeof(*hdr); ++i)
- chksum += ((unsigned char *)hdr)[i];
-
- write_octal(hdr->chksum, chksum, 6);
- hdr->chksum[6] = '\0';
- hdr->chksum[7] = ' ';
-}
-
-static bool need_pax_header(const struct stat *sb, const char *name)
-{
- tar_header_t tmp;
-
- if (sb->st_uid > 0777777 || sb->st_gid > 0777777)
- return true;
-
- if (S_ISREG(sb->st_mode) && sb->st_size > 077777777777L)
- return true;
-
- if (S_ISLNK(sb->st_mode) && sb->st_size >= (off_t)sizeof(tmp.linkname))
- return true;
-
- if (name_to_tar_header(&tmp, name))
- return true;
-
- return false;
-}
-
-static char *write_pax_entry(char *dst, const char *key, const char *value)
-{
- size_t i, len, prefix = 0, oldprefix;
-
- do {
- len = prefix + 1 + strlen(key) + 1 + strlen(value) + 1;
-
- oldprefix = prefix;
- prefix = 1;
-
- for (i = len; i >= 10; i /= 10)
- ++prefix;
- } while (oldprefix != prefix);
-
- sprintf(dst, "%zu %s=%s\n", len, key, value);
-
- return dst + len;
-}
-
-static int write_pax_header(int fd, const struct stat *sb, const char *name,
- const char *slink_target)
-{
- char temp[64], *ptr;
- struct stat fakesb;
- tar_header_t hdr;
- ssize_t ret;
- size_t len;
-
- memset(buffer, 0, sizeof(buffer));
- memset(&fakesb, 0, sizeof(fakesb));
- fakesb.st_mode = S_IFREG | 0644;
-
- sprintf(temp, "pax%lu", pax_hdr_counter);
- init_header(&hdr, &fakesb, temp, NULL);
- hdr.typeflag = TAR_TYPE_PAX;
-
- sprintf(temp, "%u", sb->st_uid);
- ptr = buffer;
- ptr = write_pax_entry(ptr, "uid", temp);
- ptr = write_pax_entry(ptr, "uname", temp);
-
- sprintf(temp, "%lu", sb->st_mtime);
- ptr = write_pax_entry(ptr, "mtime", temp);
-
- sprintf(temp, "%u", sb->st_gid);
- ptr = write_pax_entry(ptr, "gid", temp);
- ptr = write_pax_entry(ptr, "gname", temp);
-
- ptr = write_pax_entry(ptr, "path", name);
-
- if (S_ISLNK(sb->st_mode)) {
- ptr = write_pax_entry(ptr, "linkpath", slink_target);
- } else if (S_ISREG(sb->st_mode)) {
- sprintf(temp, "%lu", sb->st_size);
- ptr = write_pax_entry(ptr, "size", temp);
- }
-
- len = strlen(buffer);
- write_octal(hdr.size, len, 11);
- update_checksum(&hdr);
-
- ret = write_retry(fd, &hdr, sizeof(hdr));
- if (ret < 0)
- goto fail_wr;
- if ((size_t)ret < sizeof(hdr))
- goto fail_trunc;
-
- ret = write_retry(fd, buffer, len);
- if (ret < 0)
- goto fail_wr;
- if ((size_t)ret < len)
- goto fail_trunc;
-
- return padd_file(fd, len, 512);
-fail_wr:
- perror("writing pax header");
- return -1;
-fail_trunc:
- fputs("writing pax header: truncated write\n", stderr);
- return -1;
-}
-
-int write_tar_header(int fd, const struct stat *sb, const char *name,
- const char *slink_target)
-{
- const char *reason;
- tar_header_t hdr;
- ssize_t ret;
-
- if (need_pax_header(sb, name)) {
- if (write_pax_header(fd, sb, name, slink_target))
- return -1;
-
- sprintf(buffer, "pax%lu_data", pax_hdr_counter++);
- name = buffer;
- }
-
- init_header(&hdr, sb, name, slink_target);
-
- switch (sb->st_mode & S_IFMT) {
- case S_IFCHR: hdr.typeflag = TAR_TYPE_CHARDEV; break;
- case S_IFBLK: hdr.typeflag = TAR_TYPE_BLOCKDEV; break;
- case S_IFLNK: hdr.typeflag = TAR_TYPE_SLINK; break;
- case S_IFREG: hdr.typeflag = TAR_TYPE_FILE; break;
- case S_IFDIR: hdr.typeflag = TAR_TYPE_DIR; break;
- case S_IFIFO: hdr.typeflag = TAR_TYPE_FIFO; break;
- case S_IFSOCK:
- reason = "cannot pack socket";
- goto out_skip;
- default:
- reason = "unknown type";
- goto out_skip;
- }
-
- update_checksum(&hdr);
-
- ret = write_retry(fd, &hdr, sizeof(hdr));
-
- if (ret < 0) {
- perror("writing header record");
- } else if ((size_t)ret < sizeof(hdr)) {
- fputs("writing header record: truncated write\n", stderr);
- ret = -1;
- } else {
- ret = 0;
- }
-
- return ret;
-out_skip:
- fprintf(stderr, "WARNING: skipping '%s' (%s)\n", name, reason);
- return 1;
-}