From: Stephen Seo Date: Mon, 23 Dec 2024 08:40:47 +0000 (+0900) Subject: Impl force file/dir permissions X-Git-Tag: 1.10^2~19 X-Git-Url: https://git.seodisparate.com/tbm-server-edit-full.png?a=commitdiff_plain;h=d0b19295e0bcef16c9fbe5a01844ea78f0432a65;p=SimpleArchiver Impl force file/dir permissions Added "--force-file-permissions" and "--force-dir-permissions". Also added "--force-uid" and "--force-gid". --- diff --git a/src/archiver.c b/src/archiver.c index 64869e8..0517af1 100644 --- a/src/archiver.c +++ b/src/archiver.c @@ -447,32 +447,37 @@ int write_files_fn(void *data, void *ud) { return 1; } - if ((stat_buf.st_mode & S_IRUSR) != 0) { - ((uint8_t *)temp_to_write->buf)[0] |= 0x2; - } - if ((stat_buf.st_mode & S_IWUSR) != 0) { - ((uint8_t *)temp_to_write->buf)[0] |= 0x4; - } - if ((stat_buf.st_mode & S_IXUSR) != 0) { - ((uint8_t *)temp_to_write->buf)[0] |= 0x8; - } - if ((stat_buf.st_mode & S_IRGRP) != 0) { - ((uint8_t *)temp_to_write->buf)[0] |= 0x10; - } - if ((stat_buf.st_mode & S_IWGRP) != 0) { - ((uint8_t *)temp_to_write->buf)[0] |= 0x20; - } - if ((stat_buf.st_mode & S_IXGRP) != 0) { - ((uint8_t *)temp_to_write->buf)[0] |= 0x40; - } - if ((stat_buf.st_mode & S_IROTH) != 0) { - ((uint8_t *)temp_to_write->buf)[0] |= 0x80; - } - if ((stat_buf.st_mode & S_IWOTH) != 0) { - ((uint8_t *)temp_to_write->buf)[1] |= 0x1; - } - if ((stat_buf.st_mode & S_IXOTH) != 0) { - ((uint8_t *)temp_to_write->buf)[1] |= 0x2; + if (state->parsed->flags & 0x1000) { + ((uint8_t *)temp_to_write->buf)[0] |= (state->parsed->file_permissions & 0x7F) << 1; + ((uint8_t *)temp_to_write->buf)[1] |= (state->parsed->file_permissions & 0x18) >> 7; + } else { + if ((stat_buf.st_mode & S_IRUSR) != 0) { + ((uint8_t *)temp_to_write->buf)[0] |= 0x2; + } + if ((stat_buf.st_mode & S_IWUSR) != 0) { + ((uint8_t *)temp_to_write->buf)[0] |= 0x4; + } + if ((stat_buf.st_mode & S_IXUSR) != 0) { + ((uint8_t *)temp_to_write->buf)[0] |= 0x8; + } + if ((stat_buf.st_mode & S_IRGRP) != 0) { + ((uint8_t *)temp_to_write->buf)[0] |= 0x10; + } + if ((stat_buf.st_mode & S_IWGRP) != 0) { + ((uint8_t *)temp_to_write->buf)[0] |= 0x20; + } + if ((stat_buf.st_mode & S_IXGRP) != 0) { + ((uint8_t *)temp_to_write->buf)[0] |= 0x40; + } + if ((stat_buf.st_mode & S_IROTH) != 0) { + ((uint8_t *)temp_to_write->buf)[0] |= 0x80; + } + if ((stat_buf.st_mode & S_IWOTH) != 0) { + ((uint8_t *)temp_to_write->buf)[1] |= 0x1; + } + if ((stat_buf.st_mode & S_IXOTH) != 0) { + ((uint8_t *)temp_to_write->buf)[1] |= 0x2; + } } simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write); @@ -616,6 +621,13 @@ int write_files_fn(void *data, void *ud) { ((uint8_t *)temp_to_write->buf)[0] |= 0xE; #endif + if (state->parsed->flags & 0x1000) { + ((uint8_t *)temp_to_write->buf)[0] = (uint8_t)((state->parsed->file_permissions & 0x7F) << 1); + + ((uint8_t *)temp_to_write->buf)[1] &= 0xC; + ((uint8_t *)temp_to_write->buf)[1] |= (uint8_t)((state->parsed->file_permissions & 0x18) >> 7); + } + simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write); // Write file length. @@ -1625,17 +1637,21 @@ int symlinks_and_files_from_files(void *data, void *ud) { const char *user_cwd = ptr_array[2]; SDArchiverPHeap *pheap = ptr_array[3]; SDArchiverLinkedList *dirs_list = ptr_array[4]; + const SDArchiverState *state = ptr_array[5]; if (file_info->filename) { if (file_info->link_dest) { + // Is a symbolic link. simple_archiver_list_add( symlinks_list, file_info->filename, simple_archiver_helper_datastructure_cleanup_nop); } else if (dirs_list && (file_info->flags & 1) != 0) { + // Is a directory. simple_archiver_list_add( dirs_list, file_info->filename, simple_archiver_helper_datastructure_cleanup_nop); } else { + // Is a file. SDArchiverInternalFileInfo *file_info_struct = malloc(sizeof(SDArchiverInternalFileInfo)); file_info_struct->filename = strdup(file_info->filename); @@ -1699,6 +1715,21 @@ int symlinks_and_files_from_files(void *data, void *ud) { file_info_struct->uid = stat_buf.st_uid; file_info_struct->gid = stat_buf.st_gid; #endif + if (state->parsed->flags & 0x1000) { + file_info_struct->bit_flags[0] = 0; + file_info_struct->bit_flags[1] &= 0xFE; + + file_info_struct->bit_flags[0] |= + state->parsed->file_permissions & 0xFF; + file_info_struct->bit_flags[1] |= + (state->parsed->file_permissions & 0x100) >> 8; + } + if (state->parsed->flags & 0x400) { + file_info_struct->uid = state->parsed->uid; + } + if (state->parsed->flags & 0x800) { + file_info_struct->gid = state->parsed->gid; + } __attribute__((cleanup(simple_archiver_helper_cleanup_FILE))) FILE *fd = fopen(file_info_struct->filename, "rb"); if (!fd) { @@ -1781,7 +1812,9 @@ void simple_archiver_internal_paths_to_files_map(SDArchiverHashMap *files_map, int internal_write_dir_entries(void *data, void *ud) { const char *dir = data; - FILE *out_f = ud; + void **ptrs = ud; + FILE *out_f = ptrs[0]; + const SDArchiverState *state = ptrs[1]; fprintf(stderr, " %s\n", dir); @@ -1820,29 +1853,33 @@ int internal_write_dir_entries(void *data, void *ud) { uint8_t u8 = 0; - if ((stat_buf.st_mode & S_IRUSR) != 0) { - u8 |= 1; - } - if ((stat_buf.st_mode & S_IWUSR) != 0) { - u8 |= 2; - } - if ((stat_buf.st_mode & S_IXUSR) != 0) { - u8 |= 4; - } - if ((stat_buf.st_mode & S_IRGRP) != 0) { - u8 |= 8; - } - if ((stat_buf.st_mode & S_IWGRP) != 0) { - u8 |= 0x10; - } - if ((stat_buf.st_mode & S_IXGRP) != 0) { - u8 |= 0x20; - } - if ((stat_buf.st_mode & S_IROTH) != 0) { - u8 |= 0x40; - } - if ((stat_buf.st_mode & S_IWOTH) != 0) { - u8 |= 0x80; + if (state && state->parsed->flags & 0x2000) { + u8 = state->parsed->dir_permissions & 0xFF; + } else { + if ((stat_buf.st_mode & S_IRUSR) != 0) { + u8 |= 1; + } + if ((stat_buf.st_mode & S_IWUSR) != 0) { + u8 |= 2; + } + if ((stat_buf.st_mode & S_IXUSR) != 0) { + u8 |= 4; + } + if ((stat_buf.st_mode & S_IRGRP) != 0) { + u8 |= 8; + } + if ((stat_buf.st_mode & S_IWGRP) != 0) { + u8 |= 0x10; + } + if ((stat_buf.st_mode & S_IXGRP) != 0) { + u8 |= 0x20; + } + if ((stat_buf.st_mode & S_IROTH) != 0) { + u8 |= 0x40; + } + if ((stat_buf.st_mode & S_IWOTH) != 0) { + u8 |= 0x80; + } } if(fwrite(&u8, 1, 1, out_f) != 1) { @@ -1853,8 +1890,12 @@ int internal_write_dir_entries(void *data, void *ud) { } u8 = 0; - if ((stat_buf.st_mode & S_IXOTH) != 0) { - u8 |= 1; + if (state && state->parsed->flags & 0x2000) { + u8 = (state->parsed->dir_permissions & 0x100) >> 8; + } else { + if ((stat_buf.st_mode & S_IXOTH) != 0) { + u8 |= 1; + } } if (fwrite(&u8, 1, 1, out_f) != 1) { @@ -1882,6 +1923,20 @@ int internal_write_dir_entries(void *data, void *ud) { return 0; } +mode_t simple_archiver_internal_permissions_to_mode_t(uint_fast16_t permissions) +{ + return + ((permissions & 1) ? S_IRUSR : 0) + | ((permissions & 2) ? S_IWUSR : 0) + | ((permissions & 4) ? S_IXUSR : 0) + | ((permissions & 8) ? S_IRGRP : 0) + | ((permissions & 0x10) ? S_IWGRP : 0) + | ((permissions & 0x20) ? S_IXGRP : 0) + | ((permissions & 0x40) ? S_IROTH : 0) + | ((permissions & 0x80) ? S_IWOTH : 0) + | ((permissions & 0x100) ? S_IXOTH : 0); +} + char *simple_archiver_error_to_string(enum SDArchiverStateReturns error) { switch (error) { case SDAS_SUCCESS: @@ -2137,12 +2192,13 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state, ? simple_archiver_priority_heap_init_less_fn(greater_fn) : NULL; - ptr_array = malloc(sizeof(void *) * 5); + ptr_array = malloc(sizeof(void *) * 6); ptr_array[0] = symlinks_list; ptr_array[1] = files_list; ptr_array[2] = (void *)state->parsed->user_cwd; ptr_array[3] = files_pheap; ptr_array[4] = NULL; + ptr_array[5] = state; if (simple_archiver_list_get(filenames, symlinks_and_files_from_files, ptr_array)) { @@ -2599,11 +2655,15 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state, return SDAS_FAILED_TO_WRITE; } // UID and GID. + + // Forced UID/GID is already handled by "symlinks_and_files_from_files". + u32 = file_info_struct->uid; simple_archiver_helper_32_bit_be(&u32); if (fwrite(&u32, 4, 1, out_f) != 1) { return SDAS_FAILED_TO_WRITE; } + u32 = file_info_struct->gid; simple_archiver_helper_32_bit_be(&u32); if (fwrite(&u32, 4, 1, out_f) != 1) { @@ -2996,12 +3056,13 @@ int simple_archiver_write_v2(FILE *out_f, SDArchiverState *state, ? simple_archiver_priority_heap_init_less_fn(greater_fn) : NULL; - ptr_array = malloc(sizeof(void *) * 5); + ptr_array = malloc(sizeof(void *) * 6); ptr_array[0] = symlinks_list; ptr_array[1] = files_list; ptr_array[2] = (void *)state->parsed->user_cwd; ptr_array[3] = files_pheap; ptr_array[4] = dirs_list; + ptr_array[5] = state; if (simple_archiver_list_get(filenames, symlinks_and_files_from_files, ptr_array)) { @@ -3472,6 +3533,9 @@ int simple_archiver_write_v2(FILE *out_f, SDArchiverState *state, return SDAS_FAILED_TO_WRITE; } // UID and GID. + + // Forced UID/GID is already handled by "symlinks_and_files_from_files". + u32 = file_info_struct->uid; simple_archiver_helper_32_bit_be(&u32); if (fwrite(&u32, 4, 1, out_f) != 1) { @@ -3852,9 +3916,17 @@ int simple_archiver_write_v2(FILE *out_f, SDArchiverState *state, return SDAS_FAILED_TO_WRITE; } - if (simple_archiver_list_get(dirs_list, internal_write_dir_entries, out_f)) { + void **void_ptrs = malloc(sizeof(void*) * 2); + void_ptrs[0] = out_f; + void_ptrs[1] = state; + + if (simple_archiver_list_get(dirs_list, + internal_write_dir_entries, + void_ptrs)) { + free(void_ptrs); return SDAS_INTERNAL_ERROR; } + free(void_ptrs); return SDAS_SUCCESS; } @@ -4244,6 +4316,15 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract, #endif + if (state && state->parsed->flags & 0x1000 && do_extract) { + fprintf(stderr, + "NOTICE: Forcing permissions as specified by " + "\"--force-file-permissions\"!\n"); + permissions = + simple_archiver_internal_permissions_to_mode_t( + state->parsed->file_permissions); + } + if ((buf[0] & 1) == 0) { // Not a sybolic link. if (fread(&u64, 8, 1, in_f) != 1) { @@ -4268,7 +4349,15 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract, if (do_extract && !skip && !skip_due_to_map) { fprintf(stderr, " Extracting...\n"); - simple_archiver_helper_make_dirs((const char *)out_f_name); + simple_archiver_helper_make_dirs_perms( + (const char *)out_f_name, + (state->parsed->flags & 0x2000) + ? simple_archiver_internal_permissions_to_mode_t( + state->parsed->dir_permissions) + : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH), + (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(), + (state->parsed->flags & 0x800) ? state->parsed->gid : getgid()); + out_f = fopen(out_f_name, "wb"); if (!out_f) { fprintf(stderr, @@ -4621,7 +4710,14 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract, } if (do_extract && !skip) { - simple_archiver_helper_make_dirs((const char *)out_f_name); + simple_archiver_helper_make_dirs_perms( + (const char *)out_f_name, + (state->parsed->flags & 0x2000) + ? simple_archiver_internal_permissions_to_mode_t( + state->parsed->dir_permissions) + : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH), + (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(), + (state->parsed->flags & 0x800) ? state->parsed->gid : getgid()); if (abs_path && rel_path) { if (abs_preferred) { #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \ @@ -5000,7 +5096,14 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract, #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX - simple_archiver_helper_make_dirs(link_name); + simple_archiver_helper_make_dirs_perms( + link_name, + (state->parsed->flags & 0x2000) + ? simple_archiver_internal_permissions_to_mode_t( + state->parsed->dir_permissions) + : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH), + (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(), + (state->parsed->flags & 0x800) ? state->parsed->gid : getgid()); int_fast8_t link_create_retry = 0; V1_SYMLINK_CREATE_RETRY_0: ret = symlink(path, link_name); @@ -5073,7 +5176,14 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract, #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX - simple_archiver_helper_make_dirs(link_name); + simple_archiver_helper_make_dirs_perms( + link_name, + (state->parsed->flags & 0x2000) + ? simple_archiver_internal_permissions_to_mode_t( + state->parsed->dir_permissions) + : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH), + (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(), + (state->parsed->flags & 0x800) ? state->parsed->gid : getgid()); int_fast8_t link_create_retry = 0; V1_SYMLINK_CREATE_RETRY_1: ret = symlink(path, link_name); @@ -5114,6 +5224,21 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract, errno); } } + if (state->parsed->flags & 0x400 || state->parsed->flags & 0x800) { + ret = fchownat( + AT_FDCWD, + link_name, + state->parsed->flags & 0x400 ? state->parsed->uid : getuid(), + state->parsed->flags & 0x800 ? state->parsed->gid : getgid(), + AT_SYMLINK_NOFOLLOW); + if (ret == -1) { + fprintf(stderr, + "WARNING: Failed to force set UID/GID of symlink \"%s\"" + "(errno %d)!\n", + link_name, + errno); + } + } link_extracted = 1; fprintf(stderr, " %s -> %s\n", link_name, path); V1_SYMLINK_CREATE_AFTER_1: @@ -5222,14 +5347,22 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract, } memcpy(&u32, buf, 4); simple_archiver_helper_32_bit_be(&u32); - file_info->uid = u32; + if (state && (state->parsed->flags & 0x400)) { + file_info->uid = state->parsed->uid; + } else { + file_info->uid = u32; + } if (fread(buf, 1, 4, in_f) != 4) { return SDAS_INVALID_FILE; } memcpy(&u32, buf, 4); simple_archiver_helper_32_bit_be(&u32); - file_info->gid = u32; + if (state && (state->parsed->flags & 0x800)) { + file_info->gid = state->parsed->gid; + } else { + file_info->gid = u32; + } if (fread(buf, 1, 8, in_f) != 8) { return SDAS_INVALID_FILE; @@ -5388,8 +5521,16 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract, #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX - mode_t permissions = - permissions_from_bits_version_1(file_info->bit_flags, 0); + mode_t permissions; + if (state->parsed->flags & 0x1000) { + permissions = + simple_archiver_internal_permissions_to_mode_t( + state->parsed->file_permissions); + } else { + permissions = permissions_from_bits_version_1( + file_info->bit_flags, + 0); + } #endif if ((state->parsed->flags & 8) == 0) { // Check if file already exists. @@ -5411,7 +5552,14 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract, } } - simple_archiver_helper_make_dirs(file_info->filename); + simple_archiver_helper_make_dirs_perms( + file_info->filename, + (state->parsed->flags & 0x2000) + ? simple_archiver_internal_permissions_to_mode_t( + state->parsed->dir_permissions) + : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH), + (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(), + (state->parsed->flags & 0x800) ? state->parsed->gid : getgid()); int ret = read_decomp_to_out_file( file_info->filename, pipe_outof_read, (char *)buf, SIMPLE_ARCHIVER_BUFFER_SIZE, file_info->file_size, @@ -5510,8 +5658,18 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract, #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX - mode_t permissions = + mode_t permissions; + + if (state->parsed->flags & 0x1000) { + permissions = simple_archiver_internal_permissions_to_mode_t( + state->parsed->file_permissions); + fprintf(stderr, + "NOTICE: Forcing permissions as specified by " + "\"--force-file-permissions\"!\n"); + } else { + permissions = permissions_from_bits_version_1(file_info->bit_flags, 0); + } #endif if ((state->parsed->flags & 8) == 0) { // Check if file already exists. @@ -5530,7 +5688,14 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract, continue; } } - simple_archiver_helper_make_dirs(file_info->filename); + simple_archiver_helper_make_dirs_perms( + file_info->filename, + (state->parsed->flags & 0x2000) + ? simple_archiver_internal_permissions_to_mode_t( + state->parsed->dir_permissions) + : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH), + (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(), + (state->parsed->flags & 0x800) ? state->parsed->gid : getgid()); __attribute__((cleanup(simple_archiver_helper_cleanup_FILE))) FILE *out_fd = fopen(file_info->filename, "wb"); int ret = read_fd_to_out_fd(in_f, out_fd, (char *)buf, @@ -5544,6 +5709,9 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract, SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX if (chmod(file_info->filename, permissions) == -1) { + fprintf(stderr, + "ERROR Failed to set permissions of file \"%s\"!\n", + file_info->filename); return SDAS_INTERNAL_ERROR; } else if (geteuid() == 0 && chown(file_info->filename, file_info->uid, @@ -5708,10 +5876,13 @@ int simple_archiver_parse_archive_version_2(FILE *in_f, int_fast8_t do_extract, //fprintf(stderr, "DEBUG: abs_path is \"%s\"!\n", abs_path); int ret = simple_archiver_helper_make_dirs_perms( - abs_path, - permissions_from_bits_version_1(perms_flags, 0), - uid, - gid); + abs_path, + state && (state->parsed->flags & 0x2000) + ? simple_archiver_internal_permissions_to_mode_t( + state->parsed->dir_permissions) + : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH), + state && (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(), + state && (state->parsed->flags & 0x800) ? state->parsed->gid : getgid()); if (ret != 0) { fprintf(stderr, "ERROR: Failed to make dirs (%d)!\n", ret); return SDAS_INTERNAL_ERROR; diff --git a/src/parser.c b/src/parser.c index 51eb858..d46e603 100644 --- a/src/parser.c +++ b/src/parser.c @@ -193,6 +193,18 @@ void simple_archiver_print_usage(void) { fprintf(stderr, "--no-preserve-empty-dirs : do NOT preserve empty dirs (only for file" " format 2 and onwards)\n"); + fprintf(stderr, + "--force-uid : Force set UID on archive creation/extraction\n"); + fprintf(stderr, + "--force-gid : Force set GID on archive creation/extraction\n"); + fprintf(stderr, + "--force-file-permissions <3-octal-values> : Force set permissions " + "for files on archive creation/extraction\n" + " Must be three octal characters like \"755\" or \"440\"\n"); + fprintf(stderr, + "--force-dir-permissions <3-octal-values> : Force set permissions " + "for directories on archive creation/extraction\n" + " Must be three octal characters like \"755\" or \"440\"\n"); fprintf(stderr, "-- : specifies remaining arguments are files to archive/extract\n"); fprintf( @@ -215,6 +227,10 @@ SDArchiverParsed simple_archiver_create_parsed(void) { parsed.user_cwd = NULL; parsed.write_version = 2; parsed.minimum_chunk_size = 4194304; + parsed.uid = 0; + parsed.gid = 0; + parsed.file_permissions = 0; + parsed.dir_permissions = 0; return parsed; } @@ -371,6 +387,116 @@ int simple_archiver_parse_args(int argc, const char **argv, out->flags &= 0xFFFFFFBF; } else if (strcmp(argv[0], "--no-preserve-empty-dirs") == 0) { out->flags |= 0x200; + } else if (strcmp(argv[0], "--force-uid") == 0) { + if (argc < 2) { + fprintf(stderr, "ERROR: --force-uid expects an integer argument!\n"); + simple_archiver_print_usage(); + return 1; + } + unsigned long long uid = strtoull(argv[1], NULL, 10); + if (uid == 0 && strcmp(argv[1], "0") != 0) { + fprintf(stderr, "ERROR: Failed to parse --force-uid !\n"); + simple_archiver_print_usage(); + return 1; + } else if (uid > 0xFFFFFFFF) { + fprintf(stderr, + "ERROR: UID Is too large (expecting unsigned 32-bit " + "value)!\n"); + simple_archiver_print_usage(); + return 1; + } + out->uid = (uint32_t)uid; + out->flags |= 0x400; + --argc; + ++argv; + } else if (strcmp(argv[0], "--force-gid") == 0) { + if (argc < 2) { + fprintf(stderr, "ERROR: --force-gid expects an integer argument!\n"); + simple_archiver_print_usage(); + return 1; + } + unsigned long long gid = strtoull(argv[1], NULL, 10); + if (gid == 0 && strcmp(argv[1], "0") != 0) { + fprintf(stderr, "ERROR: Failed to parse --force-gid !\n"); + simple_archiver_print_usage(); + return 1; + } else if (gid > 0xFFFFFFFF) { + fprintf(stderr, + "ERROR: GID Is too large (expecting unsigned 32-bit " + "value)!\n"); + simple_archiver_print_usage(); + return 1; + } + out->gid = (uint32_t)gid; + out->flags |= 0x800; + --argc; + ++argv; + } else if (strcmp(argv[0], "--force-file-permissions") == 0) { + if (argc < 2 + || strlen(argv[1]) != 3 + || (!(argv[1][0] >= '0' && argv[1][0] <= '7')) + || (!(argv[1][1] >= '0' && argv[1][1] <= '7')) + || (!(argv[1][2] >= '0' && argv[1][2] <= '7')) + ) { + fprintf(stderr, + "ERROR: --force-file-permissions expects 3 octal values " + "(e.g. \"755\" or \"440\")!\n"); + simple_archiver_print_usage(); + return 1; + } + + uint_fast8_t value = (uint_fast8_t)(argv[1][0] - '0'); + out->file_permissions |= (value & 4) ? 1 : 0; + out->file_permissions |= (value & 2) ? 2 : 0; + out->file_permissions |= (value & 1) ? 4 : 0; + + value = (uint_fast8_t)(argv[1][1] - '0'); + out->file_permissions |= (value & 4) ? 8 : 0; + out->file_permissions |= (value & 2) ? 0x10 : 0; + out->file_permissions |= (value & 1) ? 0x20 : 0; + + value = (uint_fast8_t)(argv[1][2] - '0'); + out->file_permissions |= (value & 4) ? 0x40 : 0; + out->file_permissions |= (value & 2) ? 0x80 : 0; + out->file_permissions |= (value & 1) ? 0x100 : 0; + + out->flags |= 0x1000; + + --argc; + ++argv; + } else if (strcmp(argv[0], "--force-dir-permissions") == 0) { + if (argc < 2 + || strlen(argv[1]) != 3 + || (!(argv[1][0] >= '0' && argv[1][0] <= '7')) + || (!(argv[1][1] >= '0' && argv[1][1] <= '7')) + || (!(argv[1][2] >= '0' && argv[1][2] <= '7')) + ) { + fprintf(stderr, + "ERROR: --force-dir-permissions expects 3 octal values " + "(e.g. \"755\" or \"440\")!\n"); + simple_archiver_print_usage(); + return 1; + } + + uint_fast8_t value = (uint_fast8_t)(argv[1][0] - '0'); + out->dir_permissions |= (value & 4) ? 1 : 0; + out->dir_permissions |= (value & 2) ? 2 : 0; + out->dir_permissions |= (value & 1) ? 4 : 0; + + value = (uint_fast8_t)(argv[1][1] - '0'); + out->dir_permissions |= (value & 4) ? 8 : 0; + out->dir_permissions |= (value & 2) ? 0x10 : 0; + out->dir_permissions |= (value & 1) ? 0x20 : 0; + + value = (uint_fast8_t)(argv[1][2] - '0'); + out->dir_permissions |= (value & 4) ? 0x40 : 0; + out->dir_permissions |= (value & 2) ? 0x80 : 0; + out->dir_permissions |= (value & 1) ? 0x100 : 0; + + out->flags |= 0x2000; + + --argc; + ++argv; } else if (argv[0][0] == '-' && argv[0][1] == '-' && argv[0][2] == 0) { is_remaining_args = 1; } else if (argv[0][0] != '-') { diff --git a/src/parser.h b/src/parser.h index e4d6416..4660f5e 100644 --- a/src/parser.h +++ b/src/parser.h @@ -39,6 +39,10 @@ typedef struct SDArchiverParsed { /// 0b 1xxx xxxx - No safe links. /// 0b xxxx xxx1 xxxx xxxx - Preserve symlink target. /// 0b xxxx xx1x xxxx xxxx - Ignore empty directories if set. + /// 0b xxxx x1xx xxxx xxxx - Force set UID. + /// 0b xxxx 1xxx xxxx xxxx - Force set GID. + /// 0b xxx1 xxxx xxxx xxxx - Force set file permissions. + /// 0b xx1x xxxx xxxx xxxx - Force set directory permissions. uint32_t flags; /// Null-terminated string. char *filename; @@ -59,6 +63,19 @@ typedef struct SDArchiverParsed { uint32_t write_version; /// The minimum size of a chunk in bytes (the last chunk may be less). uint64_t minimum_chunk_size; + uint32_t uid; + uint32_t gid; + /// 0b xxxx xxxx xxx1 - user read + /// 0b xxxx xxxx xx1x - user write + /// 0b xxxx xxxx x1xx - user execute + /// 0b xxxx xxxx 1xxx - group read + /// 0b xxxx xxx1 xxxx - group write + /// 0b xxxx xx1x xxxx - group execute + /// 0b xxxx x1xx xxxx - other read + /// 0b xxxx 1xxx xxxx - other write + /// 0b xxx1 xxxx xxxx - other execute + uint_fast16_t file_permissions; + uint_fast16_t dir_permissions; } SDArchiverParsed; typedef struct SDArchiverFileInfo {