feat: Add support for symbolic links

All the pieces were in place, we just needed to put them together.

Sorry, but sub-500 LoC isn't gonna work anymore...
This commit is contained in:
apio 2023-01-26 22:12:42 +01:00
parent 4c90f9078b
commit 599cac5811
Signed by: apio
GPG Key ID: B8A7D06E42258954
5 changed files with 26 additions and 5 deletions

View File

@ -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 (pretty much only requires a basic subset of the C FILE API, apart from other simple functions). No third-party dependencies, only a minimally capable standard C library (pretty much only requires a basic subset of the C FILE API, apart from other simple 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)). Aims to be bloat-free (currently just above 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. 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.

View File

@ -75,7 +75,9 @@ This enum lists all supported file types:
`MTAR_DIRECTORY`: Directories `MTAR_DIRECTORY`: Directories
Other file types supported in tar archives, such as block/character devices, FIFOs, or symlinks, are not supported and minitar will throw an error when encountering one of them. This behavior can be controlled by passing `-DMINITAR_IGNORE_UNSUPPORTED_TYPES=ON` to CMake when configuring, which will make minitar silently ignore such entries instead of panicking. `MTAR_SYMLINK`: Symbolic links
Other file types supported in tar archives, such as block/character devices, FIFOs, or hard links, are not supported and minitar will throw an error when encountering one of them. This behavior can be controlled by passing `-DMINITAR_IGNORE_UNSUPPORTED_TYPES=ON` to CMake when configuring, which will make minitar silently ignore such entries instead of panicking.
### minitar_entry_metadata ### minitar_entry_metadata
`struct minitar_entry_metadata` `struct minitar_entry_metadata`
@ -86,6 +88,8 @@ This structure represents an entry's metadata, with the following fields:
`name`: A string representing the base name of the entry (the last component of its path). (`char[]`) `name`: A string representing the base name of the entry (the last component of its path). (`char[]`)
`link`: A string representing the file being linked to. (Only applies to symlinks) (`char[]`)
`mode`: An integer representing the permissions of the entry. (`mode_t`) `mode`: An integer representing the permissions of the entry. (`mode_t`)
`uid`: An integer representing the user ID of the entry's owner. (`uid_t`) `uid`: An integer representing the user ID of the entry's owner. (`uid_t`)

View File

@ -6,6 +6,7 @@
* untar.c: Example utility which extracts files from a tar archive (POSIX only). * untar.c: Example utility which extracts files from a tar archive (POSIX only).
*/ */
#define _XOPEN_SOURCE 700
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <minitar.h> #include <minitar.h>
@ -85,6 +86,18 @@ int main(int argc, char** argv)
printf("untar %s\n", entry.metadata.path); printf("untar %s\n", entry.metadata.path);
} }
else if (entry.metadata.type == MTAR_SYMLINK)
{
int status = symlink(entry.metadata.link, entry.metadata.path);
if (status != 0)
{
fprintf(stderr, "Failed to create symlink %s: %s\n", entry.metadata.path, strerror(errno));
break;
}
printf("symlink %s -> %s\n", entry.metadata.path, entry.metadata.link);
}
} }
else else
break; break;

View File

@ -20,7 +20,8 @@ struct minitar
enum minitar_file_type enum minitar_file_type
{ {
MTAR_REGULAR, MTAR_REGULAR,
MTAR_DIRECTORY MTAR_DIRECTORY,
MTAR_SYMLINK
}; };
struct minitar_entry_internal struct minitar_entry_internal
@ -32,6 +33,7 @@ struct minitar_entry_metadata
{ {
char path[257]; char path[257];
char name[128]; char name[128];
char link[101];
mode_t mode; mode_t mode;
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;

View File

@ -162,6 +162,8 @@ void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct
metadata->path[256] = '\0'; metadata->path[256] = '\0';
} }
minitar_strlcpy(metadata->link, hdr->linkname, 101);
minitar_parse_basename(metadata->path, metadata->name, sizeof(metadata->name)); 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 // Numeric fields in tar archives are stored as octal-encoded ASCII strings. Weird decision (supposedly for
@ -185,7 +187,7 @@ void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct
case '\0': case '\0':
case '0': metadata->type = MTAR_REGULAR; break; case '0': metadata->type = MTAR_REGULAR; break;
case '1': minitar_handle_panic("Links to other files within a tar archive are unsupported"); case '1': minitar_handle_panic("Links to other files within a tar archive are unsupported");
case '2': minitar_handle_panic("Symbolic links are unsupported"); case '2': metadata->type = MTAR_SYMLINK; break;
case '3': minitar_handle_panic("Character devices are unsupported"); case '3': minitar_handle_panic("Character devices are unsupported");
case '4': minitar_handle_panic("Block devices are unsupported"); case '4': minitar_handle_panic("Block devices are unsupported");
case '5': metadata->type = MTAR_DIRECTORY; break; case '5': metadata->type = MTAR_DIRECTORY; break;
@ -226,7 +228,7 @@ uint32_t minitar_checksum_header(const struct tar_header* hdr)
int minitar_validate_header(const struct tar_header* hdr) int minitar_validate_header(const struct tar_header* hdr)
{ {
#ifdef MINITAR_IGNORE_UNSUPPORTED_TYPES #ifdef MINITAR_IGNORE_UNSUPPORTED_TYPES
if (hdr->typeflag != '\0' && hdr->typeflag != '0' && hdr->typeflag != '5') return 0; if (hdr->typeflag != '\0' && hdr->typeflag != '0' && hdr->typeflag != '2' && hdr->typeflag != '5') return 0;
#else #else
if (hdr->typeflag != '\0' && hdr->typeflag != '0' && hdr->typeflag != '1' && hdr->typeflag != '2' && 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') hdr->typeflag != '3' && hdr->typeflag != '4' && hdr->typeflag != '5' && hdr->typeflag != '6')