From 39d5ee5b9a15695393865092e25fa1b0cbee7d1f Mon Sep 17 00:00:00 2001 From: apio Date: Sat, 31 Dec 2022 12:40:21 +0100 Subject: [PATCH] Remove dependency on strtoul() and strtoull() by making our own specialized parse_octal() function --- README.md | 2 +- src/util.c | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ac8cd35..c7bce96 100644 --- a/README.md +++ b/README.md @@ -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)). diff --git a/src/util.c b/src/util.c index 64c3be9..46a8ce6 100644 --- a/src/util.c +++ b/src/util.c @@ -1,6 +1,8 @@ #include "minitar.h" #include "tar.h" #include +#include +#include #include #include #include @@ -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.