From 89bc9907251bbadae9eb67b7472d41f538ff7a2c Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 25 Dec 2022 13:31:11 +0100 Subject: [PATCH] More optimization and heap elimination --- README.md | 4 +--- src/util.c | 34 +++++++++++++--------------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index cde98f3..9310a3d 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,7 @@ Tiny and easy-to-use C library to parse tar (specifically, the newer [USTAR](htt No third-party dependencies, only a minimally capable standard C library (file IO, number parsing, malloc() and friends, string functions). -Aims to be 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), [strndup](https://linux.die.net/man/3/strndup) or [basename](https://linux.die.net/man/3/basename)). - -Very minimal and bloat-free, currently less than 500 lines :) +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)). Does not include support for compressed archives. You'll have to pass those through another program or library to decompress them before minitar can handle them. diff --git a/src/util.c b/src/util.c index 8cbc51b..15be7c5 100644 --- a/src/util.c +++ b/src/util.c @@ -45,19 +45,6 @@ static size_t minitar_strlcpy(char* dest, const char* src, size_t size) return full_len; } -// strdup() but copies at most max bytes of orig, always null-terminating the result. This function is non-standard and -// as such, we provide our own implementation, to be as portable as possible. -// https://linux.die.net/man/3/strndup -static char* minitar_strndup(const char* orig, size_t max) -{ - size_t len = strnlen(orig, max); - char* ptr = - calloc(len + 1, 1); // Use calloc so everything is automatically zeroed and we get a null-terminator for free :) - if (!ptr) return NULL; - for (size_t i = 0; i < len; ++i) { *(ptr + i) = *(orig + i); } - return ptr; -} - static char dot[] = "."; // POSIX function to extract the basename from a path. Not present on non-POSIX, but since paths inside a tar archive @@ -101,6 +88,17 @@ static size_t minitar_align_down_to_block_size(size_t size) return size - (size % 512); } +// Return a static string formed by 'size' bytes copied from str, and a null terminator. This function is useful for +// when you have a fixed-size field without a null-terminator, and you need a null-terminated string to pass to a +// library function. The pointer returned WILL be overwritten by subsequent calls to this function. +static char* minitar_static_dup(const char* str, size_t size) +{ + static char result[1024]; + memcpy(result, str, size); + result[size] = 0; + return result; +} + size_t minitar_align_up_to_block_size(size_t size) { return minitar_is_aligned_to_block_size(size) ? size : minitar_align_down_to_block_size(size) + 512; @@ -144,17 +142,11 @@ void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct // FIXME: Maybe avoid heap allocations (strndup) for simply parsing non-null-terminated fields? - char* sizeptr = minitar_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"); + char* sizeptr = minitar_static_dup(hdr->size, 12); metadata->size = (size_t)strtoull(sizeptr, NULL, 8); - free(sizeptr); - char* timeptr = minitar_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"); + char* timeptr = minitar_static_dup(hdr->mtime, 12); metadata->mtime = (time_t)strtoull(timeptr, NULL, 8); - free(timeptr); // The type is stored as a character instead of an integer.