Compare commits

...

13 commits

Author SHA1 Message Date
f89e5f7640 Test/fix symlink test/extract in v1 file format
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 11s
2024-09-30 19:17:57 +09:00
0ae80168e3 Fix v1 archive decompression
Previous implementation sent too many bytes to decompressor if size was
less than 1024.
2024-09-30 19:17:57 +09:00
d93f62a0cb Remove unnecessary printf used for testing 2024-09-30 19:17:57 +09:00
8f33d62392 Impl. extract with decompressor file format v1 2024-09-30 19:17:57 +09:00
52bbfa4e65 v1 extract skip non-specified args if exists 2024-09-30 19:17:57 +09:00
8bedc750ba Impl. setting stored UID/GID if EUID 0 2024-09-30 19:17:57 +09:00
aaebe09347 "Fix" Linux/Mac/Unix usage 2024-09-30 19:17:57 +09:00
0a776cae37 Impl. simple test/extract new file format (WIP)
TODO:
    Extract symlinks in new format (implemented but untested).
    Extract compressed files in new format.
2024-09-30 19:17:57 +09:00
f472ad1a6b Split up handling of archive file based on version 2024-09-30 19:17:57 +09:00
dcd2e531e6 Fix typo 2024-09-30 19:17:57 +09:00
ef49b37648 Fix typo in file format specification version 1 2024-09-30 19:17:57 +09:00
6ad609e7fc Create file format for format version 1
This is in preparation of improving compression by concatenating files
together before compressing them to reduce the per-file overhead.
2024-09-30 19:17:57 +09:00
b098fd6d69 Error if "-C <dir>" where "dir" doesn't exist
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 5s
2024-09-30 19:16:29 +09:00
8 changed files with 1092 additions and 16 deletions

View file

@ -76,3 +76,109 @@ Following the file-count bytes, the following bytes are added for each file:
1. 8 bytes 64-bit unsigned integer "size of filename in this archive file"
in big-endian.
2. X bytes file data (length defined by previous value).
## Format Version 1
File extension is "*.simplearchive" but this isn't really checked.
First 18 bytes of file will be (in ascii):
SIMPLE_ARCHIVE_VER
Next 2 bytes is a 16-bit unsigned integer "version" in big-endian. It will be:
0x00 0x01
Next 4 bytes are bit-flags.
1. The first byte
1. The first bit is set if de/compressor is set for this archive.
The remaining unused flags in the previous bit-flags bytes are reserved for
future revisions and are currently ignored.
If the previous "de/compressor is set" flag is enabled, then the next section is
added:
1. 2 bytes is 16-bit unsigned integer "compressor cmd+args" in big-endian. This
does not include the NULL at the end of the string.
2. X bytes of "compressor cmd+args" (length defined by previous value). Is a
NULL-terminated string.
3. 2 bytes is 16-bit unsigned integer "decompressor cmd+args" in big-endian.
This does not include the NULL at the end of the string.
4. X bytes of "decompressor cmd+args" (length defined by previous value). Is a
NULL-terminated string.
The next 4 bytes is a 32-bit unsigned integer "link count" in big-endian which
will indicate the number of symbolic links in this archive.
Following the link-count bytes, the following bytes are added for each symlink:
1. 2 bytes bit-flags:
1. The first byte.
1. The first bit is UNSET if relative links are preferred, and is SET if
absolute links are preferred.
2. The second byte.
1. Currently unused.
2. 2 bytes 16-bit unsigned integer "link name" in big-endian. This does not
include the NULL at the end of the string. Must not be zero.
3. X bytes of link-name (length defined by previous value). Is a NULL-terminated
string.
4. 2 bytes is 16-bit unsigned integer "link target absolute path" in
big-endian. This does not include the NULL at the end of the string.
5. X bytes of link-target-absolute-path (length defined by previous value).
Is a NULL-terminated string. If the previous "size" value is 0, then
this entry does not exist and should be skipped.
6. 2 bytes is 16-bit unsigned integer "link target relative path" in
big-endian. This does not include the NULL at the end of the string.
7. X bytes of link-target-relative-path (length defined by previous value).
Is a NULL-terminated string. If the previous "size" value is 0, then
this entry does not exist and should be skipped.
After the symlink related data, the next 4 bytes is a 32-bit unsigned integer
"chunk count" in big-endian which will indicate the number of chunks in this
archive.
Following the chunk-count bytes, the following bytes are added for each chunk:
1. 2 bytes that are a 16-bit unsigned integer "file count" in big-endian.
The following bytes are added for each file within the current chunk:
1. 2 bytes that are a 16-bit unsigned integer "filename length" in big-endian.
This does not include the NULL at the end of the string.
2. X bytes of filename (length defined by previous value). Is a NULL-terminated
string.
3. 4 bytes bit-flags.
1. The first byte.
1. The first bit is "user read permission".
2. The second bit is "user write permission".
3. The third bit is "user execute permission".
4. The fourth bit is "group read permission".
5. The fifth bit is "group write permission".
6. The sixth bit is "group execute permission".
7. The seventh bit is "other read permission".
8. The eighth bit is "other write permission".
2. The second byte.
1. The first bit is "other execute permission".
3. The third byte.
1. Currently unused.
4. The fourth byte.
1. Currently unused.
4. Two 4-byte unsigned integers in big-endian for UID and GID.
1. A 32-bit unsigned integer in big endian that specifies the UID of the
file. Note that during extraction, if the user is not root, then this
value will be ignored.
2. A 32-bit unsigned integer in big endian that specifies the GID of the
file. Note that during extraction, if the user is not root, then this
value will be ignored.
5. A 64-bit unsigned integer in big endian for the "size of file".
After the files' metadata are the current chunk's data:
1. A 64-bit unsigned integer in big endian for the "size of chunk".
2. X bytes of data for the current chunk of the previously specified size. If
not using de/compressor, this section is the previously mentioned files
concatenated with each other. If using de/compressor, this section is the
previously mentioned files concatenated and compressed into a single blob of
data.

BIN
file_format_1_example_0 Normal file

Binary file not shown.

BIN
file_format_1_example_1 Normal file

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -69,6 +69,14 @@ int simple_archiver_write_all(FILE *out_f, SDArchiverState *state,
int simple_archiver_parse_archive_info(FILE *in_f, int_fast8_t do_extract,
const SDArchiverState *state);
/// Returns zero on success.
int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
const SDArchiverState *state);
/// Returns zero on success.
int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
const SDArchiverState *state);
/// Returns zero on success.
int simple_archiver_de_compress(int pipe_fd_in[2], int pipe_fd_out[2],
const char *cmd, void *pid_out);

View file

@ -67,12 +67,13 @@ int main(int argc, const char **argv) {
}
}
SDArchiverParsedStatus parsed_status;
__attribute__((cleanup(simple_archiver_list_free)))
SDArchiverLinkedList *filenames =
simple_archiver_parsed_to_filenames(&parsed);
if (!filenames) {
fprintf(stderr,
"ERROR: Failed to resolve filenames from positional arguments!\n");
simple_archiver_parsed_to_filenames(&parsed, &parsed_status);
if (!filenames || parsed_status != SDAPS_SUCCESS) {
fprintf(stderr, "ERROR: %s!\n",
simple_archiver_parsed_status_to_str(parsed_status));
return 8;
}

View file

@ -131,6 +131,17 @@ int list_remove_same_str_fn(void *data, void *ud) {
return 0;
}
char *simple_archiver_parsed_status_to_str(SDArchiverParsedStatus status) {
switch (status) {
case SDAPS_SUCCESS:
return "Success";
case SDAPS_NO_USER_CWD:
return "No user current working directory (-C <dir>)";
default:
return "Unknown error";
}
}
void simple_archiver_print_usage(void) {
fprintf(stderr, "Usage flags:\n");
fprintf(stderr, "-c : create archive file\n");
@ -367,7 +378,7 @@ void simple_archiver_free_parsed(SDArchiverParsed *parsed) {
}
SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
const SDArchiverParsed *parsed) {
const SDArchiverParsed *parsed, SDArchiverParsedStatus *status_out) {
SDArchiverLinkedList *files_list = simple_archiver_list_init();
__attribute__((cleanup(simple_archiver_hash_map_free)))
SDArchiverHashMap *hash_map = simple_archiver_hash_map_init();
@ -381,6 +392,9 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
original_cwd = realpath(".", NULL);
if (chdir(parsed->user_cwd)) {
simple_archiver_list_free(&files_list);
if (status_out) {
*status_out = SDAPS_NO_USER_CWD;
}
return NULL;
}
}
@ -607,5 +621,8 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
}
}
if (status_out) {
*status_out = SDAPS_SUCCESS;
}
return files_list;
}

View file

@ -59,6 +59,14 @@ typedef struct SDArchiverFileInfo {
char *link_dest;
} SDArchiverFileInfo;
typedef enum SDArchiverParsedStatus {
SDAPS_SUCCESS,
SDAPS_NO_USER_CWD,
} SDArchiverParsedStatus;
/// Returned c-string does not need to be free'd.
char *simple_archiver_parsed_status_to_str(SDArchiverParsedStatus status);
void simple_archiver_print_usage(void);
SDArchiverParsed simple_archiver_create_parsed(void);
@ -74,6 +82,6 @@ void simple_archiver_free_parsed(SDArchiverParsed *parsed);
/// Each entry in the linked list is an SDArchiverFileInfo object.
SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
const SDArchiverParsed *parsed);
const SDArchiverParsed *parsed, SDArchiverParsedStatus *status_out);
#endif