Remove dependency on strtoul() and strtoull() by making our own specialized parse_octal() function

This commit is contained in:
apio 2022-12-31 12:40:21 +01:00
parent 165352cdca
commit 39d5ee5b9a
Signed by: apio
GPG Key ID: B8A7D06E42258954
2 changed files with 35 additions and 8 deletions

View File

@ -2,7 +2,7 @@
Tiny and easy-to-use C library to parse tar (specifically, the newer [USTAR](https://www.ibm.com/docs/en/zos/2.3.0?topic=formats-tar-format-tar-archives#taf) variant, which is the one pretty much everybody uses) archives.
No third-party dependencies, only a minimally capable standard C library (file IO, number parsing, malloc() and friends, string functions).
No third-party dependencies, only a minimally capable standard C library (file IO, string functions).
Aims to be bloat-free (currently less than 500 LoC), fast and optimized, and as portable between systems as possible (has its own implementation of some non-standard functions, such as [strlcpy](https://linux.die.net/man/3/strlcpy) or [basename](https://linux.die.net/man/3/basename)).

View File

@ -1,6 +1,8 @@
#include "minitar.h"
#include "tar.h"
#include <assert.h>
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -70,6 +72,33 @@ static char* minitar_basename(char* path)
return beg + 1;
}
static uint64_t parse_digit(char c)
{
return c - '0';
}
static int is_valid_octal_digit(char c)
{
if (!isdigit(c)) return 0;
if (parse_digit(c) >= 8ull) return 0;
return 1;
}
static uint64_t minitar_parse_octal(const char* str)
{
uint64_t result = 0;
while (isspace(*str)) str++;
while (is_valid_octal_digit(*str))
{
result = (result * 8ull) + parse_digit(*str);
str++;
}
return result;
}
// strcat, but for characters :)
static void minitar_append_char(char* str, char c)
{
@ -137,17 +166,15 @@ void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct
// portability), which means we have to parse these strings (the size and mtime fields aren't even null-terminated!)
// to get the far more user-friendlier integer values stored in our metadata structure.
metadata->mode = (mode_t)strtoul(hdr->mode, NULL, 8);
metadata->uid = (uid_t)strtoul(hdr->uid, NULL, 8);
metadata->gid = (gid_t)strtoul(hdr->gid, NULL, 8);
// FIXME: Maybe avoid heap allocations (strndup) for simply parsing non-null-terminated fields?
metadata->mode = (mode_t)minitar_parse_octal(hdr->mode);
metadata->uid = (uid_t)minitar_parse_octal(hdr->uid);
metadata->gid = (gid_t)minitar_parse_octal(hdr->gid);
char* sizeptr = minitar_static_dup(hdr->size, 12);
metadata->size = (size_t)strtoull(sizeptr, NULL, 8);
metadata->size = (size_t)minitar_parse_octal(sizeptr);
char* timeptr = minitar_static_dup(hdr->mtime, 12);
metadata->mtime = (time_t)strtoull(timeptr, NULL, 8);
metadata->mtime = (time_t)minitar_parse_octal(timeptr);
// The type is stored as a character instead of an integer.