minitar/src/util.c

137 lines
4.4 KiB
C
Raw Normal View History

2022-11-21 18:17:29 +00:00
// FIXME: What if strndup is not available? On non-POSIX, for example...
2022-11-06 10:22:27 +00:00
#define _POSIX_C_SOURCE 200809L // for strndup
#define _IN_MINITAR
2022-11-06 10:02:26 +00:00
#include "minitar.h"
#include "tar.h"
#include <libgen.h>
2022-11-05 19:10:48 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <stdnoreturn.h>
#include <string.h>
// Default implementation for minitar_handle_panic(). Since it's declared weak, any other definition will silently
// override this one :)
__attribute__((weak)) noreturn void minitar_handle_panic(const char* message)
2022-11-05 19:10:48 +00:00
{
fprintf(stderr, "minitar: %s\n", message);
abort();
}
noreturn void minitar_panic(const char* message)
{
minitar_handle_panic(message);
}
2022-11-21 18:15:52 +00:00
size_t minitar_strlcpy(char* dest, const char* src, size_t size)
{
size_t len, full_len;
len = full_len = strlen(src);
if (size == 0) return len;
if (len > (size - 1)) len = size - 1;
for (size_t i = 0; i < len; ++i) { *((char*)dest + i) = *((const char*)src + i); }
dest[len] = 0;
return full_len;
}
void minitar_append_char(char* str, char c)
{
size_t len = strlen(str);
str[len] = c;
str[len + 1] = 0;
}
size_t minitar_is_block_aligned(size_t size)
{
return (size % 512 == 0);
}
size_t minitar_align_down_to_block(size_t size)
{
return size - (size % 512);
}
size_t minitar_get_size_in_blocks(size_t size)
{
return minitar_is_block_aligned(size) ? size : minitar_align_down_to_block(size) + 512;
}
void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct minitar_entry_metadata* metadata)
2022-11-05 19:10:48 +00:00
{
2022-11-06 10:02:26 +00:00
if (!strlen(hdr->prefix))
2022-11-05 19:10:48 +00:00
{
size_t size = minitar_strlcpy(metadata->path, hdr->name, 100);
if (size >= 100) metadata->path[100] = '\0';
else
metadata->path[size] = '\0';
2022-11-06 10:02:26 +00:00
}
else
{
minitar_strlcpy(metadata->path, hdr->prefix, 155);
minitar_append_char(metadata->path, '/');
strncat(metadata->path, hdr->name, 100);
metadata->path[256] = '\0';
2022-11-05 19:10:48 +00:00
}
char* mut_path = strdup(metadata->path);
if (!mut_path) minitar_panic("Failed to allocate memory");
char* bname = basename(mut_path);
minitar_strlcpy(metadata->name, bname, sizeof(metadata->name));
free(mut_path);
metadata->mode = (mode_t)strtoul(hdr->mode, NULL, 8);
2022-11-05 19:10:48 +00:00
metadata->uid = (uid_t)strtoul(hdr->uid, NULL, 8);
metadata->gid = (gid_t)strtoul(hdr->gid, NULL, 8);
char* sizeptr = strndup(
hdr->size, 12); // The hdr->size field is not null-terminated, yet strndup returns a null-terminated string.
if (!sizeptr) minitar_panic("Failed to allocate memory");
2022-11-05 19:10:48 +00:00
metadata->size = (size_t)strtoull(sizeptr, NULL, 8);
free(sizeptr);
char* timeptr = strndup(
hdr->mtime, 12); // The hdr->mtime field is not null-terminated, yet strndup returns a null-terminated string.
if (!timeptr) minitar_panic("Failed to allocate memory");
metadata->mtime = (time_t)strtoull(timeptr, NULL, 8);
2022-11-05 19:10:48 +00:00
free(timeptr);
2022-11-06 10:02:26 +00:00
switch (hdr->typeflag)
2022-11-05 19:10:48 +00:00
{
2022-11-06 10:02:26 +00:00
case '\0':
case '0': metadata->type = MTAR_REGULAR; break;
case '1': minitar_panic("Links to other files within a tar archive are unsupported");
case '2': minitar_panic("Symbolic links are unsupported");
case '3': metadata->type = MTAR_CHRDEV; break;
case '4': metadata->type = MTAR_BLKDEV; break;
case '5': metadata->type = MTAR_DIRECTORY; break;
case '6': minitar_panic("FIFOs are unsupported");
default: minitar_panic("Unknown entry type in tar header");
2022-11-05 19:10:48 +00:00
}
2022-11-21 18:15:52 +00:00
minitar_strlcpy(metadata->uname, hdr->uname, 32);
minitar_strlcpy(metadata->gname, hdr->gname, 32);
2022-11-05 19:10:48 +00:00
}
2022-11-21 16:38:08 +00:00
int minitar_validate_header(const struct tar_header* hdr)
2022-11-05 19:10:48 +00:00
{
if (hdr->typeflag != '\0' && hdr->typeflag != '0' && hdr->typeflag != '1' && hdr->typeflag != '2' &&
hdr->typeflag != '3' && hdr->typeflag != '4' && hdr->typeflag != '5' && hdr->typeflag != '6')
return 0;
2022-11-05 19:10:48 +00:00
return !strncmp(hdr->magic, "ustar", 5);
}
int minitar_read_header(struct minitar* mp, struct tar_header* hdr)
{
size_t rc = fread(hdr, 1, sizeof *hdr, mp->stream);
2022-11-06 10:02:26 +00:00
if (rc == 0 && feof(mp->stream)) return 0;
if (rc == 0 && ferror(mp->stream)) minitar_panic("Error while reading file header from tar archive");
if (rc < sizeof *hdr) minitar_panic("Valid tar files should be split in 512-byte blocks");
2022-11-05 19:10:48 +00:00
return 1;
}
2022-11-21 16:38:08 +00:00
struct minitar_entry* minitar_dup_entry(const struct minitar_entry* original)
2022-11-05 19:10:48 +00:00
{
struct minitar_entry* new = malloc(sizeof *original);
2022-11-06 10:02:26 +00:00
if (!new) return NULL;
2022-11-05 19:10:48 +00:00
memcpy(new, original, sizeof *new);
return new;
}