Compare commits
No commits in common. "main" and "1.5.0" have entirely different histories.
@ -1,8 +1,8 @@
|
|||||||
cmake_minimum_required(VERSION 3.8..3.22)
|
cmake_minimum_required(VERSION 3.8..3.22)
|
||||||
|
|
||||||
project(minitar LANGUAGES C VERSION 1.7.6)
|
project(minitar LANGUAGES C VERSION 1.5.0)
|
||||||
|
|
||||||
option(MINITAR_IGNORE_UNSUPPORTED_TYPES "Skip past entries that have unsupported types instead of panicking (deprecated)" OFF)
|
option(MINITAR_IGNORE_UNSUPPORTED_TYPES "Skip past entries that have unsupported types instead of panicking" OFF)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
src/tar.c
|
src/tar.c
|
||||||
@ -12,7 +12,7 @@ set(SOURCES
|
|||||||
add_library(minitar STATIC ${SOURCES})
|
add_library(minitar STATIC ${SOURCES})
|
||||||
|
|
||||||
if(MINITAR_IGNORE_UNSUPPORTED_TYPES)
|
if(MINITAR_IGNORE_UNSUPPORTED_TYPES)
|
||||||
message(WARNING "MINITAR_IGNORE_UNSUPPORTED_TYPES is deprecated, since there are no unsupported types anymore")
|
target_compile_definitions(minitar PRIVATE MINITAR_IGNORE_UNSUPPORTED_TYPES)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(minitar PUBLIC ${CMAKE_CURRENT_LIST_DIR}) # for minitar.h
|
target_include_directories(minitar PUBLIC ${CMAKE_CURRENT_LIST_DIR}) # for minitar.h
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
# minitar
|
# minitar
|
||||||
|
|
||||||
Tiny and easy-to-use C library to read/write tar (specifically, the [ustar](https://www.ibm.com/docs/en/zos/2.3.0?topic=formats-tar-format-tar-archives#taf) variant, which is a bit old but simple, and newer tar variants (pax, GNU tar) are mostly backwards-compatible with it) archives.
|
Tiny and easy-to-use C library to parse tar (specifically, the newer [USTAR](https://www.ibm.com/docs/en/zos/2.3.0?topic=formats-tar-format-tar-archives#taf) variant, which is the one pretty much everybody uses) archives.
|
||||||
|
|
||||||
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 a bit 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)).
|
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.
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ See [examples](examples/) for more examples using minitar.
|
|||||||
|
|
||||||
## Project structure
|
## Project structure
|
||||||
|
|
||||||
The user-facing API (functions defined in `minitar.h` and documented in [API.md](docs/API.md)) is implemented in `src/tar.c`. Utility and internally-used functions live in `src/util.c`.
|
The user-facing API (functions defined in `minitar.h` and documented in this README) is implemented in `src/tar.c`. Utility and internally-used functions live in `src/util.c`.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
10
changelog.sh
10
changelog.sh
@ -1,10 +0,0 @@
|
|||||||
#!/usr/bin/sh
|
|
||||||
|
|
||||||
# Small shell script to automatically generate release changelogs.
|
|
||||||
|
|
||||||
echo "New features:"
|
|
||||||
git log --pretty=format:%s $1..HEAD | grep "feat:" | sed 's/feat\:/*/g'
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "Fixes:"
|
|
||||||
git log --pretty=format:%s $1..HEAD | grep "fix:" | sed 's/fix\:/*/g'
|
|
77
docs/API.md
77
docs/API.md
@ -1,17 +1,10 @@
|
|||||||
# minitar API documentation
|
# minitar API documentation
|
||||||
|
|
||||||
Functions/types suffixed with `_w` or that contain `write` in their names are part of the newer API for writing to archives. Other types/functions are part of the (older) API for reading archives.
|
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
### minitar_open
|
### minitar_open
|
||||||
`int minitar_open(const char* pathname, struct minitar* mp)`
|
`int minitar_open(const char* pathname, struct minitar* mp)`
|
||||||
|
|
||||||
Initializes the caller-provided `mp` [handle](API.md#minitar) by opening the archive pointed to by `pathname` for reading. Returns 0 on success, anything else is failure.
|
Initializes the caller-provided `mp` structure by opening the archive pointed to by `pathname` for reading. Returns 0 on success, anything else is failure.
|
||||||
|
|
||||||
### minitar_open_w
|
|
||||||
`int minitar_open_w(const char* pathname, struct minitar_w* mp, enum minitar_write_mode mode)`
|
|
||||||
|
|
||||||
Initializes the caller-provided `mp` [handle](API.md#minitar_w) by opening the archive pointed to by `pathname` for writing (in case `pathname` already exists, mode selects if the existing file is overwritten or if new entries are appended to it). Returns 0 on success, anything else is failure.
|
|
||||||
|
|
||||||
### minitar_read_entry
|
### minitar_read_entry
|
||||||
`int minitar_read_entry(struct minitar* mp, struct minitar_entry* out)`
|
`int minitar_read_entry(struct minitar* mp, struct minitar_entry* out)`
|
||||||
@ -24,30 +17,6 @@ To read the contents of an entry, you should allocate a buffer large enough to h
|
|||||||
|
|
||||||
This function returns 0 on success and -1 on end-of-file (when all entries have been read).
|
This function returns 0 on success and -1 on end-of-file (when all entries have been read).
|
||||||
|
|
||||||
### minitar_write_file_entry
|
|
||||||
`int minitar_write_file_entry(struct minitar_w* mp, const struct minitar_entry_metadata* metadata, char* buf)`
|
|
||||||
|
|
||||||
Writes a regular file entry into a `struct minitar_w` which should be initialized by a previous call to `minitar_open_w()`.
|
|
||||||
|
|
||||||
This function writes both a header (generated from the metadata) and the file contents in `buf`, which should be `metadata.size` bytes long.
|
|
||||||
|
|
||||||
This function will only write entries for regular files (metadata.type == `MTAR_REGULAR`). It will ignore the `type` field and write the "regular file" type into the tar archive.
|
|
||||||
|
|
||||||
To write any other kind of entry (directories, special files), use `minitar_write_special_entry`.
|
|
||||||
|
|
||||||
This function returns 0 on success.
|
|
||||||
|
|
||||||
### minitar_write_special_entry
|
|
||||||
`int minitar_write_special_entry(struct minitar_w* mp, const struct minitar_entry_metadata* metadata)`
|
|
||||||
|
|
||||||
Writes a special file entry (anything that does not have contents, so directories or special files) into a `struct minitar_w` which should be initialized by a previous call to `minitar_open_w()`.
|
|
||||||
|
|
||||||
This function only writes a header (generated from the metadata). The `size` field is written as 0, no matter what its original value was.
|
|
||||||
|
|
||||||
This function does not write entries for regular files (metadata.type == `MTAR_REGULAR`). Trying to do so will result in minitar panicking (see [error handling](../README.md#error-handling)). To write regular files, use `minitar_write_file_entry`.
|
|
||||||
|
|
||||||
This function returns 0 on success.
|
|
||||||
|
|
||||||
### minitar_rewind
|
### minitar_rewind
|
||||||
`void minitar_rewind(struct minitar* mp)`
|
`void minitar_rewind(struct minitar* mp)`
|
||||||
|
|
||||||
@ -76,7 +45,7 @@ Same as `minitar_find_by_name()`, but matches the full path inside the archive i
|
|||||||
Same as `minitar_find_by_name()`, but matches the file type instead of the name. As with `minitar_find_by_name()`, this function starts searching from the current archive position and calling it in a loop until it returns -1 will find all matching entries.
|
Same as `minitar_find_by_name()`, but matches the file type instead of the name. As with `minitar_find_by_name()`, this function starts searching from the current archive position and calling it in a loop until it returns -1 will find all matching entries.
|
||||||
|
|
||||||
### minitar_read_contents
|
### minitar_read_contents
|
||||||
`size_t minitar_read_contents(struct minitar* mp, const struct minitar_entry* entry, char* buf, size_t max)`
|
`size_t minitar_read_contents(struct minitar* mp, struct minitar_entry* entry, char* buf, size_t max)`
|
||||||
|
|
||||||
Reads up to `max` bytes of an entry's contents from the archive stream `mp` and stores them into `buf`.
|
Reads up to `max` bytes of an entry's contents from the archive stream `mp` and stores them into `buf`.
|
||||||
|
|
||||||
@ -84,7 +53,7 @@ This function can be called as many times as desired, and at any given point in
|
|||||||
|
|
||||||
This function returns the number of bytes read, or 0 on error. 0 might also be a successful return value (if `max` is 0 or the entry's size is 0, for example), which means `errno` should be checked to see if 0 means error or simply 0 bytes read.
|
This function returns the number of bytes read, or 0 on error. 0 might also be a successful return value (if `max` is 0 or the entry's size is 0, for example), which means `errno` should be checked to see if 0 means error or simply 0 bytes read.
|
||||||
|
|
||||||
`minitar_read_contents()` will never read more than `metadata.size`, regardless of the value in `max`. (so, if `max == SIZE_MAX`, `minitar_read_contents()` will always read `metadata.size` bytes).
|
`minitar_read_contents()` only reads up to `metadata.size`, regardless of the value in `max`.
|
||||||
|
|
||||||
The contents are not null-terminated. If you want null-termination (keep in mind the contents might not be ASCII and might contain null bytes before the end), just do `buf[nread] = 0;`. In that case, the value of `max` should be one less than the size of the buffer, to make sure the zero byte is not written past the end of `buf` if `max` bytes are read.
|
The contents are not null-terminated. If you want null-termination (keep in mind the contents might not be ASCII and might contain null bytes before the end), just do `buf[nread] = 0;`. In that case, the value of `max` should be one less than the size of the buffer, to make sure the zero byte is not written past the end of `buf` if `max` bytes are read.
|
||||||
|
|
||||||
@ -95,13 +64,6 @@ Closes the tar archive file `mp` points to. The pointer passed to `minitar_close
|
|||||||
|
|
||||||
Returns 0 on success, everything else is failure and you should check `errno`.
|
Returns 0 on success, everything else is failure and you should check `errno`.
|
||||||
|
|
||||||
### minitar_close_w
|
|
||||||
`int minitar_close_w(struct minitar_w* mp)`
|
|
||||||
|
|
||||||
Closes the tar archive file `mp` points to. The pointer passed to `minitar_close_w()` should be initialized by a previous call to `minitar_open_w()`.
|
|
||||||
|
|
||||||
Returns 0 on success, everything else is failure and you should check `errno`.
|
|
||||||
|
|
||||||
## Types
|
## Types
|
||||||
|
|
||||||
### minitar_file_type
|
### minitar_file_type
|
||||||
@ -115,22 +77,7 @@ This enum lists all supported file types:
|
|||||||
|
|
||||||
`MTAR_SYMLINK`: Symbolic links
|
`MTAR_SYMLINK`: Symbolic links
|
||||||
|
|
||||||
`MTAR_HARDLINK`: Hard 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.
|
||||||
|
|
||||||
`MTAR_FIFO`: FIFO special files
|
|
||||||
|
|
||||||
`MTAR_BLKDEV`: Block devices
|
|
||||||
|
|
||||||
`MTAR_CHRDEV`: Character devices
|
|
||||||
|
|
||||||
### minitar_write_mode
|
|
||||||
`enum minitar_write_mode`
|
|
||||||
|
|
||||||
This enum tells `minitar_open_w` what to do if the chosen archive path already exists:
|
|
||||||
|
|
||||||
`MTAR_OVERWRITE`: Overwrite the archive
|
|
||||||
|
|
||||||
`MTAR_APPEND`: Add new entries to the end of it
|
|
||||||
|
|
||||||
### minitar_entry_metadata
|
### minitar_entry_metadata
|
||||||
`struct minitar_entry_metadata`
|
`struct minitar_entry_metadata`
|
||||||
@ -141,7 +88,7 @@ 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/hard links) (`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`)
|
||||||
|
|
||||||
@ -159,10 +106,6 @@ This structure represents an entry's metadata, with the following fields:
|
|||||||
|
|
||||||
`gname`: A string representing the group name of the entry's owner. (`char[]`)
|
`gname`: A string representing the group name of the entry's owner. (`char[]`)
|
||||||
|
|
||||||
`devmajor`: An integer representing the major number of a device. (`unsigned int`)
|
|
||||||
|
|
||||||
`devminor`: An integer representing the minor number of a device. (`unsigned int`)
|
|
||||||
|
|
||||||
### minitar_entry
|
### minitar_entry
|
||||||
`struct minitar_entry`
|
`struct minitar_entry`
|
||||||
|
|
||||||
@ -171,13 +114,3 @@ An entry in a tar archive. Fields:
|
|||||||
`metadata`: The entry's metadata. (`struct minitar_entry_metadata`)
|
`metadata`: The entry's metadata. (`struct minitar_entry_metadata`)
|
||||||
|
|
||||||
`_internal`: Reserved for internal use. (`struct minitar_entry_internal`)
|
`_internal`: Reserved for internal use. (`struct minitar_entry_internal`)
|
||||||
|
|
||||||
### minitar
|
|
||||||
`struct minitar`
|
|
||||||
|
|
||||||
An archive handle for the "reading" API. To write to an archive, use `struct minitar_w` and `minitar_open_w()` instead.
|
|
||||||
|
|
||||||
### minitar_w
|
|
||||||
`struct minitar_w`
|
|
||||||
|
|
||||||
An archive handle for the "writing" API. To read from an archive, use `struct minitar` and `minitar_open()` instead.
|
|
@ -4,9 +4,4 @@ target_link_libraries(list PRIVATE minitar)
|
|||||||
add_executable(untar EXCLUDE_FROM_ALL untar.c)
|
add_executable(untar EXCLUDE_FROM_ALL untar.c)
|
||||||
target_link_libraries(untar PRIVATE minitar)
|
target_link_libraries(untar PRIVATE minitar)
|
||||||
|
|
||||||
add_executable(pack EXCLUDE_FROM_ALL pack.c)
|
add_custom_target(examples DEPENDS list untar)
|
||||||
target_link_libraries(pack PRIVATE minitar)
|
|
||||||
|
|
||||||
add_custom_target(examples DEPENDS list untar pack)
|
|
||||||
add_custom_target(examples-posix DEPENDS list untar pack)
|
|
||||||
add_custom_target(examples-windows DEPENDS list)
|
|
@ -24,7 +24,7 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
struct minitar_entry entry;
|
struct minitar_entry entry;
|
||||||
do {
|
do {
|
||||||
if (minitar_read_entry(&mp, &entry) == 0) { printf("%s (%s, %zu bytes, mode %o)\n", entry.metadata.path, entry.metadata.name, entry.metadata.size, entry.metadata.mode); }
|
if (minitar_read_entry(&mp, &entry) == 0) { printf("%s\n", entry.metadata.path); }
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
} while (1);
|
} while (1);
|
||||||
|
100
examples/pack.c
100
examples/pack.c
@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2023, apio.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*
|
|
||||||
* pack.c: Example utility which creates a tar archive (POSIX only).
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define _XOPEN_SOURCE 700
|
|
||||||
#include <minitar.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
if (argc < 3)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Usage: %s [output] files\n", argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
struct minitar_w mp;
|
|
||||||
if (minitar_open_w(argv[1], &mp, MTAR_OVERWRITE) != 0)
|
|
||||||
{
|
|
||||||
perror(argv[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
int exit_status = 0;
|
|
||||||
int arg = 2;
|
|
||||||
while (arg < argc)
|
|
||||||
{
|
|
||||||
FILE* fp = fopen(argv[arg], "r");
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
perror("fopen");
|
|
||||||
exit_status = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the file length.
|
|
||||||
fseek(fp, 0, SEEK_END);
|
|
||||||
size_t length = ftell(fp);
|
|
||||||
fseek(fp, 0, SEEK_SET);
|
|
||||||
|
|
||||||
char* buf = malloc(length);
|
|
||||||
if (!buf)
|
|
||||||
{
|
|
||||||
perror("malloc");
|
|
||||||
fclose(fp);
|
|
||||||
exit_status = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fread(buf, 1, length, fp);
|
|
||||||
if (ferror(fp))
|
|
||||||
{
|
|
||||||
perror("fread");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct stat st;
|
|
||||||
int rc = fstat(fileno(fp), &st);
|
|
||||||
if (rc < 0)
|
|
||||||
{
|
|
||||||
perror("fstat");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct minitar_entry_metadata metadata;
|
|
||||||
strncpy(metadata.path, argv[arg], sizeof(metadata.path));
|
|
||||||
metadata.uid = st.st_uid;
|
|
||||||
metadata.gid = st.st_gid;
|
|
||||||
metadata.mtime = st.st_mtime;
|
|
||||||
metadata.size = length;
|
|
||||||
metadata.type = MTAR_REGULAR;
|
|
||||||
metadata.mode = st.st_mode & ~S_IFMT;
|
|
||||||
|
|
||||||
rc = minitar_write_file_entry(&mp, &metadata, buf);
|
|
||||||
free(buf);
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
if (rc != 0)
|
|
||||||
{
|
|
||||||
perror("write entry failed");
|
|
||||||
exit_status = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
arg++;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
err:
|
|
||||||
free(buf);
|
|
||||||
fclose(fp);
|
|
||||||
exit_status = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
minitar_close_w(&mp);
|
|
||||||
return exit_status;
|
|
||||||
}
|
|
121
examples/untar.c
121
examples/untar.c
@ -9,46 +9,15 @@
|
|||||||
#define _XOPEN_SOURCE 700
|
#define _XOPEN_SOURCE 700
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <libgen.h>
|
|
||||||
#include <minitar.h>
|
#include <minitar.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/sysmacros.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
static int create_parent_recursively(const char* path)
|
|
||||||
{
|
|
||||||
char* path_copy = strdup(path);
|
|
||||||
if (!path_copy) return -1;
|
|
||||||
|
|
||||||
char* parent = dirname(path_copy);
|
|
||||||
|
|
||||||
create:
|
|
||||||
if (mkdir(parent, 0755) < 0)
|
|
||||||
{
|
|
||||||
if (errno == ENOENT)
|
|
||||||
{
|
|
||||||
create_parent_recursively(parent);
|
|
||||||
goto create;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errno == EEXIST) goto success;
|
|
||||||
|
|
||||||
free(path_copy);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
success:
|
|
||||||
free(path_copy);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int untar_file(const struct minitar_entry* entry, const void* buf)
|
static int untar_file(const struct minitar_entry* entry, const void* buf)
|
||||||
{
|
{
|
||||||
if (create_parent_recursively(entry->metadata.path) < 0) return 1;
|
|
||||||
|
|
||||||
int fd = open(entry->metadata.path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0644);
|
int fd = open(entry->metadata.path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0644);
|
||||||
if (fd < 0) return 1;
|
if (fd < 0) return 1;
|
||||||
|
|
||||||
@ -61,8 +30,6 @@ static int untar_file(const struct minitar_entry* entry, const void* buf)
|
|||||||
|
|
||||||
static int untar_directory(const struct minitar_entry* entry)
|
static int untar_directory(const struct minitar_entry* entry)
|
||||||
{
|
{
|
||||||
if (create_parent_recursively(entry->metadata.path) < 0) return 1;
|
|
||||||
|
|
||||||
if (mkdir(entry->metadata.path, entry->metadata.mode) < 0) return 1;
|
if (mkdir(entry->metadata.path, entry->metadata.mode) < 0) return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -81,19 +48,16 @@ int main(int argc, char** argv)
|
|||||||
perror(argv[1]);
|
perror(argv[1]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int exit_status = 0;
|
|
||||||
struct minitar_entry entry;
|
struct minitar_entry entry;
|
||||||
do {
|
do {
|
||||||
if (minitar_read_entry(&mp, &entry) == 0)
|
if (minitar_read_entry(&mp, &entry) == 0)
|
||||||
{
|
{
|
||||||
if (entry.metadata.type == MTAR_DIRECTORY)
|
if (entry.metadata.type == MTAR_DIRECTORY)
|
||||||
{
|
{
|
||||||
if (!strcmp(entry.metadata.name, ".") || !strcmp(entry.metadata.name, "..")) continue;
|
|
||||||
int status = untar_directory(&entry);
|
int status = untar_directory(&entry);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Failed to create directory %s: %s\n", entry.metadata.path, strerror(errno));
|
fprintf(stderr, "Failed to create directory %s: %s\n", entry.metadata.path, strerror(errno));
|
||||||
exit_status = 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +69,6 @@ int main(int argc, char** argv)
|
|||||||
if (!ptr)
|
if (!ptr)
|
||||||
{
|
{
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
exit_status = 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +81,6 @@ int main(int argc, char** argv)
|
|||||||
if (status != 0)
|
if (status != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Failed to extract file %s: %s\n", entry.metadata.path, strerror(errno));
|
fprintf(stderr, "Failed to extract file %s: %s\n", entry.metadata.path, strerror(errno));
|
||||||
exit_status = 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,102 +88,19 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
else if (entry.metadata.type == MTAR_SYMLINK)
|
else if (entry.metadata.type == MTAR_SYMLINK)
|
||||||
{
|
{
|
||||||
if (create_parent_recursively(entry.metadata.path) < 0) goto symlink_err;
|
|
||||||
|
|
||||||
int status = symlink(entry.metadata.link, entry.metadata.path);
|
int status = symlink(entry.metadata.link, entry.metadata.path);
|
||||||
|
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
{
|
{
|
||||||
symlink_err:
|
|
||||||
fprintf(stderr, "Failed to create symlink %s: %s\n", entry.metadata.path, strerror(errno));
|
fprintf(stderr, "Failed to create symlink %s: %s\n", entry.metadata.path, strerror(errno));
|
||||||
exit_status = 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("symlink %s -> %s\n", entry.metadata.path, entry.metadata.link);
|
printf("symlink %s -> %s\n", entry.metadata.path, entry.metadata.link);
|
||||||
}
|
}
|
||||||
else if (entry.metadata.type == MTAR_HARDLINK)
|
|
||||||
{
|
|
||||||
if (create_parent_recursively(entry.metadata.path) < 0) goto hardlink_err;
|
|
||||||
|
|
||||||
int status = link(entry.metadata.link, entry.metadata.path);
|
|
||||||
|
|
||||||
if (status != 0)
|
|
||||||
{
|
|
||||||
hardlink_err:
|
|
||||||
fprintf(stderr, "Failed to create hard link %s: %s\n", entry.metadata.path, strerror(errno));
|
|
||||||
exit_status = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("link %s -> %s\n", entry.metadata.path, entry.metadata.link);
|
|
||||||
}
|
|
||||||
else if (entry.metadata.type == MTAR_FIFO)
|
|
||||||
{
|
|
||||||
#ifndef __luna__
|
|
||||||
if (create_parent_recursively(entry.metadata.path) < 0) goto fifo_err;
|
|
||||||
|
|
||||||
int status = mknod(entry.metadata.path, entry.metadata.mode | S_IFIFO, 0);
|
|
||||||
|
|
||||||
if (status != 0)
|
|
||||||
{
|
|
||||||
fifo_err:
|
|
||||||
fprintf(stderr, "Failed to create FIFO %s: %s\n", entry.metadata.path, strerror(errno));
|
|
||||||
exit_status = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
printf("fifo %s\n", entry.metadata.path);
|
|
||||||
}
|
|
||||||
else if (entry.metadata.type == MTAR_BLKDEV)
|
|
||||||
{
|
|
||||||
#ifndef __luna__
|
|
||||||
if (create_parent_recursively(entry.metadata.path) < 0) goto blkdev_err;
|
|
||||||
|
|
||||||
int status = mknod(entry.metadata.path, entry.metadata.mode | S_IFBLK,
|
|
||||||
makedev(entry.metadata.devmajor, entry.metadata.devminor));
|
|
||||||
|
|
||||||
if (status != 0)
|
|
||||||
{
|
|
||||||
blkdev_err:
|
|
||||||
fprintf(stderr, "Failed to create block device %s: %s\n", entry.metadata.path, strerror(errno));
|
|
||||||
exit_status = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
printf("blkdev %s (%u:%u)\n", entry.metadata.path, entry.metadata.devmajor, entry.metadata.devminor);
|
|
||||||
}
|
|
||||||
else if (entry.metadata.type == MTAR_CHRDEV)
|
|
||||||
{
|
|
||||||
#ifndef __luna__
|
|
||||||
if (create_parent_recursively(entry.metadata.path) < 0) goto chrdev_err;
|
|
||||||
|
|
||||||
int status = mknod(entry.metadata.path, entry.metadata.mode | S_IFCHR,
|
|
||||||
makedev(entry.metadata.devmajor, entry.metadata.devminor));
|
|
||||||
|
|
||||||
if (status != 0)
|
|
||||||
{
|
|
||||||
chrdev_err:
|
|
||||||
fprintf(stderr, "Failed to create character device %s: %s\n", entry.metadata.path, strerror(errno));
|
|
||||||
exit_status = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
printf("chrdev %s (%u:%u)\n", entry.metadata.path, entry.metadata.devmajor, entry.metadata.devminor);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(stderr, "error: unknown entry type: %d", entry.metadata.type);
|
|
||||||
exit_status = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
} while (1);
|
} while (1);
|
||||||
minitar_close(&mp);
|
minitar_close(&mp);
|
||||||
return exit_status;
|
|
||||||
}
|
}
|
33
minitar.h
33
minitar.h
@ -10,41 +10,18 @@
|
|||||||
#define MINITAR_H
|
#define MINITAR_H
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
typedef unsigned int mode_t;
|
|
||||||
typedef unsigned int gid_t;
|
|
||||||
typedef unsigned int uid_t;
|
|
||||||
#else
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#endif
|
|
||||||
|
|
||||||
struct minitar
|
struct minitar
|
||||||
{
|
{
|
||||||
FILE* stream;
|
FILE* stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct minitar_w
|
|
||||||
{
|
|
||||||
FILE* stream;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum minitar_write_mode
|
|
||||||
{
|
|
||||||
MTAR_APPEND,
|
|
||||||
MTAR_OVERWRITE
|
|
||||||
};
|
|
||||||
|
|
||||||
enum minitar_file_type
|
enum minitar_file_type
|
||||||
{
|
{
|
||||||
MTAR_REGULAR,
|
MTAR_REGULAR,
|
||||||
MTAR_DIRECTORY,
|
MTAR_DIRECTORY,
|
||||||
MTAR_SYMLINK,
|
MTAR_SYMLINK
|
||||||
MTAR_HARDLINK,
|
|
||||||
MTAR_FIFO,
|
|
||||||
MTAR_CHRDEV,
|
|
||||||
MTAR_BLKDEV
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct minitar_entry_internal
|
struct minitar_entry_internal
|
||||||
@ -55,7 +32,7 @@ struct minitar_entry_internal
|
|||||||
struct minitar_entry_metadata
|
struct minitar_entry_metadata
|
||||||
{
|
{
|
||||||
char path[257];
|
char path[257];
|
||||||
char name[101];
|
char name[128];
|
||||||
char link[101];
|
char link[101];
|
||||||
mode_t mode;
|
mode_t mode;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
@ -65,8 +42,6 @@ struct minitar_entry_metadata
|
|||||||
enum minitar_file_type type;
|
enum minitar_file_type type;
|
||||||
char uname[32];
|
char uname[32];
|
||||||
char gname[32];
|
char gname[32];
|
||||||
unsigned devminor;
|
|
||||||
unsigned devmajor;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct minitar_entry
|
struct minitar_entry
|
||||||
@ -81,17 +56,13 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int minitar_open(const char* pathname, struct minitar* out);
|
int minitar_open(const char* pathname, struct minitar* out);
|
||||||
int minitar_open_w(const char* pathname, struct minitar_w* out, enum minitar_write_mode mode);
|
|
||||||
int minitar_read_entry(struct minitar* mp, struct minitar_entry* out);
|
int minitar_read_entry(struct minitar* mp, struct minitar_entry* out);
|
||||||
int minitar_write_file_entry(struct minitar_w* mp, const struct minitar_entry_metadata* metadata, char* buf);
|
|
||||||
int minitar_write_special_entry(struct minitar_w* mp, const struct minitar_entry_metadata* metadata);
|
|
||||||
void minitar_rewind(struct minitar* mp);
|
void minitar_rewind(struct minitar* mp);
|
||||||
int minitar_find_by_name(struct minitar* mp, const char* name, struct minitar_entry* out);
|
int minitar_find_by_name(struct minitar* mp, const char* name, struct minitar_entry* out);
|
||||||
int minitar_find_by_path(struct minitar* mp, const char* path, struct minitar_entry* out);
|
int minitar_find_by_path(struct minitar* mp, const char* path, struct minitar_entry* out);
|
||||||
int minitar_find_any_of(struct minitar* mp, enum minitar_file_type type, struct minitar_entry* out);
|
int minitar_find_any_of(struct minitar* mp, enum minitar_file_type type, struct minitar_entry* out);
|
||||||
size_t minitar_read_contents(struct minitar* mp, const struct minitar_entry* entry, char* buf, size_t max);
|
size_t minitar_read_contents(struct minitar* mp, const struct minitar_entry* entry, char* buf, size_t max);
|
||||||
int minitar_close(struct minitar* mp);
|
int minitar_close(struct minitar* mp);
|
||||||
int minitar_close_w(struct minitar_w* mp);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
69
src/tar.c
69
src/tar.c
@ -11,18 +11,10 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef __TINYC__
|
|
||||||
#include <stdnoreturn.h>
|
|
||||||
#else
|
|
||||||
#define noreturn _Noreturn
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// all of these are defined in util.c
|
// all of these are defined in util.c
|
||||||
int minitar_read_header(struct minitar*, struct tar_header*);
|
int minitar_read_header(struct minitar*, struct tar_header*);
|
||||||
noreturn void minitar_handle_panic(const char*);
|
|
||||||
int minitar_validate_header(const struct tar_header*);
|
int minitar_validate_header(const struct tar_header*);
|
||||||
void minitar_parse_metadata_from_tar_header(const struct tar_header*, struct minitar_entry_metadata*);
|
void minitar_parse_metadata_from_tar_header(const struct tar_header*, struct minitar_entry_metadata*);
|
||||||
void minitar_construct_header_from_metadata(struct tar_header*, const struct minitar_entry_metadata*);
|
|
||||||
size_t minitar_align_up_to_block_size(size_t);
|
size_t minitar_align_up_to_block_size(size_t);
|
||||||
|
|
||||||
int minitar_open(const char* pathname, struct minitar* out)
|
int minitar_open(const char* pathname, struct minitar* out)
|
||||||
@ -35,31 +27,11 @@ int minitar_open(const char* pathname, struct minitar* out)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int minitar_open_w(const char* pathname, struct minitar_w* out, enum minitar_write_mode mode)
|
|
||||||
{
|
|
||||||
const char* mode_string;
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case MTAR_APPEND: mode_string = "ab"; break;
|
|
||||||
case MTAR_OVERWRITE: mode_string = "wb"; break;
|
|
||||||
default: minitar_handle_panic("mode passed to minitar_open_w is not supported");
|
|
||||||
}
|
|
||||||
FILE* fp = fopen(pathname, mode_string);
|
|
||||||
if (!fp) return -1;
|
|
||||||
out->stream = fp;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int minitar_close(struct minitar* mp)
|
int minitar_close(struct minitar* mp)
|
||||||
{
|
{
|
||||||
return fclose(mp->stream);
|
return fclose(mp->stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
int minitar_close_w(struct minitar_w* mp)
|
|
||||||
{
|
|
||||||
return fclose(mp->stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to read a valid header, and construct an entry from it. If the 512-byte block at the current read offset is not a
|
// Try to read a valid header, and construct an entry from it. If the 512-byte block at the current read offset is not a
|
||||||
// valid header, valid is set to 0 so we can try again with the next block. In any other case, valid is set to 1. This
|
// valid header, valid is set to 0 so we can try again with the next block. In any other case, valid is set to 1. This
|
||||||
// helps distinguish valid return values, EOF, and invalid headers that we should just skip.
|
// helps distinguish valid return values, EOF, and invalid headers that we should just skip.
|
||||||
@ -102,47 +74,6 @@ int minitar_read_entry(struct minitar* mp, struct minitar_entry* out)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int minitar_write_file_entry(struct minitar_w* mp, const struct minitar_entry_metadata* metadata, char* buf)
|
|
||||||
{
|
|
||||||
struct minitar_entry_metadata meta = *metadata;
|
|
||||||
meta.type = MTAR_REGULAR;
|
|
||||||
|
|
||||||
struct tar_header hdr;
|
|
||||||
minitar_construct_header_from_metadata(&hdr, &meta);
|
|
||||||
// Write the header.
|
|
||||||
size_t nwrite = fwrite(&hdr, sizeof(hdr), 1, mp->stream);
|
|
||||||
if (nwrite == 0 && ferror(mp->stream)) return -1;
|
|
||||||
|
|
||||||
// Write the file data.
|
|
||||||
nwrite = fwrite(buf, 1, meta.size, mp->stream);
|
|
||||||
if (nwrite == 0 && ferror(mp->stream)) return -1;
|
|
||||||
|
|
||||||
char zeroes[512];
|
|
||||||
memset(zeroes, 0, sizeof(zeroes));
|
|
||||||
|
|
||||||
// Pad with zeroes to finish a block (512 bytes).
|
|
||||||
size_t nzero = minitar_align_up_to_block_size(meta.size) - meta.size;
|
|
||||||
nwrite = fwrite(zeroes, 1, nzero, mp->stream);
|
|
||||||
if (nwrite == 0 && ferror(mp->stream)) return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int minitar_write_special_entry(struct minitar_w* mp, const struct minitar_entry_metadata* metadata)
|
|
||||||
{
|
|
||||||
struct minitar_entry_metadata meta = *metadata;
|
|
||||||
if (meta.type == MTAR_REGULAR)
|
|
||||||
minitar_handle_panic("Trying to write a special entry, yet MTAR_REGULAR passed as the entry type");
|
|
||||||
meta.size = 0;
|
|
||||||
|
|
||||||
struct tar_header hdr;
|
|
||||||
minitar_construct_header_from_metadata(&hdr, &meta);
|
|
||||||
size_t nwrite = fwrite(&hdr, sizeof(hdr), 1, mp->stream);
|
|
||||||
if (nwrite == 0 && ferror(mp->stream)) return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void minitar_rewind(struct minitar* mp)
|
void minitar_rewind(struct minitar* mp)
|
||||||
{
|
{
|
||||||
rewind(mp->stream);
|
rewind(mp->stream);
|
||||||
|
74
src/util.c
74
src/util.c
@ -13,6 +13,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#ifndef __TINYC__
|
#ifndef __TINYC__
|
||||||
#include <stdnoreturn.h>
|
#include <stdnoreturn.h>
|
||||||
@ -20,7 +21,7 @@
|
|||||||
#define noreturn _Noreturn
|
#define noreturn _Noreturn
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(__TINYC__)
|
#if !defined(_MSC_VER) && !defined(__TINYC__)
|
||||||
#define WEAK __attribute__((weak))
|
#define WEAK __attribute__((weak))
|
||||||
#else
|
#else
|
||||||
#define WEAK
|
#define WEAK
|
||||||
@ -173,8 +174,6 @@ void minitar_parse_metadata_from_tar_header(const struct tar_header* hdr, struct
|
|||||||
metadata->uid = (uid_t)minitar_parse_octal(hdr->uid);
|
metadata->uid = (uid_t)minitar_parse_octal(hdr->uid);
|
||||||
metadata->gid = (gid_t)minitar_parse_octal(hdr->gid);
|
metadata->gid = (gid_t)minitar_parse_octal(hdr->gid);
|
||||||
|
|
||||||
// These two fields aren't null-terminated.
|
|
||||||
|
|
||||||
char* sizeptr = minitar_static_dup(hdr->size, 12);
|
char* sizeptr = minitar_static_dup(hdr->size, 12);
|
||||||
metadata->size = (size_t)minitar_parse_octal(sizeptr);
|
metadata->size = (size_t)minitar_parse_octal(sizeptr);
|
||||||
|
|
||||||
@ -187,24 +186,17 @@ 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': metadata->type = MTAR_HARDLINK; break;
|
case '1': minitar_handle_panic("Links to other files within a tar archive are unsupported");
|
||||||
case '2': metadata->type = MTAR_SYMLINK; break;
|
case '2': metadata->type = MTAR_SYMLINK; break;
|
||||||
case '3': metadata->type = MTAR_CHRDEV; break;
|
case '3': minitar_handle_panic("Character devices are unsupported");
|
||||||
case '4': metadata->type = MTAR_BLKDEV; break;
|
case '4': minitar_handle_panic("Block devices are unsupported");
|
||||||
case '5': metadata->type = MTAR_DIRECTORY; break;
|
case '5': metadata->type = MTAR_DIRECTORY; break;
|
||||||
case '6': metadata->type = MTAR_FIFO; break;
|
case '6': minitar_handle_panic("FIFOs are unsupported");
|
||||||
// This case should have been previously handled by minitar_validate_header().
|
|
||||||
default: minitar_handle_panic("Unknown entry type in tar header");
|
default: minitar_handle_panic("Unknown entry type in tar header");
|
||||||
}
|
}
|
||||||
|
|
||||||
minitar_strlcpy(metadata->uname, hdr->uname, 32);
|
minitar_strlcpy(metadata->uname, hdr->uname, 32);
|
||||||
minitar_strlcpy(metadata->gname, hdr->gname, 32);
|
minitar_strlcpy(metadata->gname, hdr->gname, 32);
|
||||||
|
|
||||||
if (metadata->type == MTAR_CHRDEV || metadata->type == MTAR_BLKDEV)
|
|
||||||
{
|
|
||||||
metadata->devminor = minitar_parse_octal(hdr->devminor);
|
|
||||||
metadata->devmajor = minitar_parse_octal(hdr->devmajor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t minitar_checksum_header(const struct tar_header* hdr)
|
uint32_t minitar_checksum_header(const struct tar_header* hdr)
|
||||||
@ -233,61 +225,15 @@ uint32_t minitar_checksum_header(const struct tar_header* hdr)
|
|||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void minitar_construct_header_from_metadata(struct tar_header* hdr, const struct minitar_entry_metadata* metadata)
|
|
||||||
{
|
|
||||||
if (strlen(metadata->path) > 100)
|
|
||||||
{
|
|
||||||
minitar_handle_panic("FIXME: pathnames over 100 (using the prefix field) are unsupported for now");
|
|
||||||
}
|
|
||||||
|
|
||||||
// We intentionally want strncpy to not write a null terminator here if the path field is 100 bytes long.
|
|
||||||
strncpy(hdr->name, metadata->path, 100);
|
|
||||||
|
|
||||||
snprintf(hdr->mode, 8, "%.7o", metadata->mode);
|
|
||||||
snprintf(hdr->uid, 8, "%.7o", metadata->uid);
|
|
||||||
snprintf(hdr->gid, 8, "%.7o", metadata->gid);
|
|
||||||
|
|
||||||
// snprintf will write the null terminator past the size field. We don't care, as we will overwrite that zero later.
|
|
||||||
snprintf(hdr->size, 13, "%.12zo", metadata->size);
|
|
||||||
// Same here.
|
|
||||||
snprintf(hdr->mtime, 13, "%.12llo", (long long)metadata->mtime);
|
|
||||||
|
|
||||||
switch (metadata->type)
|
|
||||||
{
|
|
||||||
case MTAR_REGULAR: hdr->typeflag = '0'; break;
|
|
||||||
case MTAR_HARDLINK: hdr->typeflag = '1'; break;
|
|
||||||
case MTAR_SYMLINK: hdr->typeflag = '2'; break;
|
|
||||||
case MTAR_CHRDEV: hdr->typeflag = '3'; break;
|
|
||||||
case MTAR_BLKDEV: hdr->typeflag = '4'; break;
|
|
||||||
case MTAR_DIRECTORY: hdr->typeflag = '5'; break;
|
|
||||||
case MTAR_FIFO: hdr->typeflag = '6'; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(hdr->linkname, metadata->link, 100);
|
|
||||||
|
|
||||||
memcpy(hdr->magic, "ustar", 6);
|
|
||||||
|
|
||||||
hdr->version[0] = '0';
|
|
||||||
hdr->version[1] = '0';
|
|
||||||
|
|
||||||
strncpy(hdr->uname, metadata->uname, 32);
|
|
||||||
strncpy(hdr->gname, metadata->gname, 32);
|
|
||||||
|
|
||||||
snprintf(hdr->devmajor, 8, "%.7o", metadata->devmajor);
|
|
||||||
snprintf(hdr->devminor, 8, "%.7o", metadata->devminor);
|
|
||||||
|
|
||||||
memset(hdr->prefix, 0, sizeof(hdr->prefix));
|
|
||||||
memset(hdr->padding, 0, sizeof(hdr->padding));
|
|
||||||
|
|
||||||
uint32_t checksum = minitar_checksum_header(hdr);
|
|
||||||
snprintf(hdr->chksum, 8, "%.7o", checksum);
|
|
||||||
}
|
|
||||||
|
|
||||||
int minitar_validate_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 != '2' && hdr->typeflag != '5') return 0;
|
||||||
|
#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')
|
||||||
return 0;
|
return 0;
|
||||||
|
#endif
|
||||||
// FIXME: Warn on checksum mismatch unless header is all blanks?
|
// FIXME: Warn on checksum mismatch unless header is all blanks?
|
||||||
if (minitar_checksum_header(hdr) != minitar_parse_octal(hdr->chksum)) return 0;
|
if (minitar_checksum_header(hdr) != minitar_parse_octal(hdr->chksum)) return 0;
|
||||||
return !strncmp(hdr->magic, "ustar", 5);
|
return !strncmp(hdr->magic, "ustar", 5);
|
||||||
|
Loading…
Reference in New Issue
Block a user