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:
parent
4c90f9078b
commit
599cac5811
@ -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.
|
||||||
|
|
||||||
|
@ -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`)
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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')
|
||||||
|
Loading…
Reference in New Issue
Block a user