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).
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.

View File

@ -75,7 +75,9 @@ This enum lists all supported file types:
`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
`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[]`)
`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`)
`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).
*/
#define _XOPEN_SOURCE 700
#include <errno.h>
#include <fcntl.h>
#include <minitar.h>
@ -85,6 +86,18 @@ int main(int argc, char** argv)
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
break;

View File

@ -20,7 +20,8 @@ struct minitar
enum minitar_file_type
{
MTAR_REGULAR,
MTAR_DIRECTORY
MTAR_DIRECTORY,
MTAR_SYMLINK
};
struct minitar_entry_internal
@ -32,6 +33,7 @@ struct minitar_entry_metadata
{
char path[257];
char name[128];
char link[101];
mode_t mode;
uid_t uid;
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';
}
minitar_strlcpy(metadata->link, hdr->linkname, 101);
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
@ -185,7 +187,7 @@ void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct
case '\0':
case '0': metadata->type = MTAR_REGULAR; break;
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 '4': minitar_handle_panic("Block devices are unsupported");
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)
{
#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
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')