From 23c313d9cf17b3bb688153ff9c16a078a2f0f4d9 Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 25 Dec 2022 12:50:57 +0100 Subject: [PATCH] Get rid of libgen.h in favor of our own basename :) --- CMakeLists.txt | 2 +- README.md | 2 +- src/util.c | 42 +++++++++++++++++++++++++++++++++--------- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ad6be5d..61cfea9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.8..3.22) -project(minitar LANGUAGES C VERSION 1.2.0) +project(minitar LANGUAGES C VERSION 1.2.1) set(SOURCES src/tar.c diff --git a/README.md b/README.md index 5bf04cf..cde98f3 100644 --- a/README.md +++ b/README.md @@ -4,7 +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) or [strndup](https://linux.die.net/man/3/strndup)), but that still needs some work (minitar still depends on some POSIX functions, such as [basename](https://linux.die.net/man/3/basename) (not present on Windows)). +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 :) diff --git a/src/util.c b/src/util.c index a19b51b..b8c2bc0 100644 --- a/src/util.c +++ b/src/util.c @@ -1,7 +1,6 @@ #define _IN_MINITAR #include "minitar.h" #include "tar.h" -#include #include #include #include @@ -49,6 +48,7 @@ static char* minitar_strndup(const char* orig, size_t max) } // Our own replacement for strdup(). +// https://linux.die.net/man/3/strdup static char* minitar_strdup(const char* orig) { size_t len = strlen(orig); @@ -58,6 +58,31 @@ static char* minitar_strdup(const char* orig) 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 +// are always POSIX (I believe?), we can use a replacement that does exactly the same thing as the original basename(). +// https://linux.die.net/man/3/basename +static char* minitar_basename(char* path) +{ + // If path is NULL, or the string's length is 0, return . + if (!path) return dot; + size_t len = strlen(path); + if (!len) return dot; + + // Strip trailing slashes. + char* it = path + len - 1; + while (*it == '/' && it != path) { it--; } + *(it + 1) = 0; + if (it == path) return path; + + // Return path from the first character if there are no more slashes, or from the first character after the last + // slash. + char* beg = strrchr(path, '/'); + if (!beg) return path; + return beg + 1; +} + // strcat, but for characters :) static void minitar_append_char(char* str, char c) { @@ -81,15 +106,16 @@ 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; } -static char* minitar_get_basename(const char* path) +static void minitar_parse_basename(const char* path, char* out, size_t max) { char* copy = minitar_strdup(path); if (!copy) minitar_panic("Failed to allocate memory"); - char* base_name = basename(copy); - char* base_name_copy = minitar_strdup(base_name); - if (!base_name_copy) minitar_panic("Failed to allocate memory"); + + char* bname = minitar_basename(copy); + + minitar_strlcpy(out, bname, max); + free(copy); - return base_name_copy; } void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct minitar_entry_metadata* metadata) @@ -107,9 +133,7 @@ void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct metadata->path[256] = '\0'; } - char* bname = minitar_get_basename(metadata->path); - minitar_strlcpy(metadata->name, bname, sizeof(metadata->name)); - free(bname); + minitar_parse_basename(metadata->path, metadata->name, sizeof(metadata->name)); // Numeric fields in tar archives are stored as octal-encoded ASCII strings. Weird decision (supposedly for // portability), which means we have to parse these strings (the size and mtime fields aren't even null-terminated!)