From 71f3b5601a52d8ffbba35b2eac7c90b4eaa3dc02 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Thu, 13 Aug 2020 21:11:20 -0500 Subject: [PATCH] Progress: get the change file mode functions in an acceptable state. Finish writing the file change mode and related functions. Due to significant gaps in development and the notable complexity of the ugo+rwxXst modes, this is implemented in what appears to be good enough for now. There are likely hidden logic flaws or incomplete/missing logic. This adds an @fixme to more thoroughly review this and possible fix this at a later date. For now, this allows moving forward to avoid spending too much time on this one area. --- level_0/f_file/c/file.c | 174 ++++++++++++++++++++++----------------- level_0/f_file/c/file.h | 39 +++++---- level_3/fake/c/private-make.c | 4 +- level_3/fake/data/build/fakefile | 4 +- 4 files changed, 120 insertions(+), 101 deletions(-) diff --git a/level_0/f_file/c/file.c b/level_0/f_file/c/file.c index 4b46545..b57f85a 100644 --- a/level_0/f_file/c/file.c +++ b/level_0/f_file/c/file.c @@ -525,7 +525,7 @@ extern "C" { #endif // _di_f_file_link_read_at_ #ifndef _di_f_file_mode_determine_ - f_return_status f_file_mode_determine(const mode_t mode_file, const f_file_mode mode_change, const uint8_t mode_replace, const bool directory_is, const mode_t umask, mode_t *mode) { + f_return_status f_file_mode_determine(const mode_t mode_file, const f_file_mode mode_change, const uint8_t mode_replace, const bool directory_is, mode_t *mode) { #ifndef _di_level_0_parameter_checking_ if (mode == 0) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ @@ -826,16 +826,12 @@ extern "C" { } } - if (mode_replace & f_file_mode_replace_umask) { - *mode -= *mode & umask; - } - return F_none; } #endif // _di_f_file_mode_determine_ #ifndef _di_f_file_mode_from_string_ - f_return_status f_file_mode_from_string(const f_string string, f_file_mode *mode, uint8_t *replace) { + f_return_status f_file_mode_from_string(const f_string string, const mode_t umask, f_file_mode *mode, uint8_t *replace) { #ifndef _di_level_0_parameter_checking_ if (string == 0) return F_status_set_error(F_parameter); if (string[0] == 0) return F_status_set_error(F_parameter); @@ -904,60 +900,86 @@ extern "C" { if (syntax == 1) { uint8_t on = 0; // 1 = user, 2 = group, 4 = world/sticky, 7 = all. uint8_t how = 0; // 1 = add, 2 = replace, 3 = subtract. - bool active = F_false; - f_file_mode mask = f_file_mode_block_special; + f_file_mode mode_mask = 0; + f_file_mode mode_umask = 0; f_file_mode what = 0; - // @todo: this needs to record all of the possible combinations of add, subtract, and assignment (=). - for (f_string_length i = 0; syntax && i < string[i]; i++) { + // translate the umask into an f_file_mode umask equivalent. + if (umask & f_file_mode_special_set_user) { + mode_umask = f_file_mode_block_special & f_file_mode_mask_bit_set_owner; + } + + if (umask & f_file_mode_special_set_group) { + mode_umask |= f_file_mode_block_special & f_file_mode_mask_bit_set_group; + } + + if (umask & f_file_mode_special_sticky) { + mode_umask |= f_file_mode_block_special & f_file_mode_mask_bit_sticky; + } + + if (umask & f_file_mode_owner_r) { + mode_umask |= f_file_mode_block_owner & f_file_mode_mask_bit_read; + } + + if (umask & f_file_mode_owner_w) { + mode_umask |= f_file_mode_block_owner & f_file_mode_mask_bit_write; + } + + if (umask & f_file_mode_owner_x) { + mode_umask |= f_file_mode_block_owner & f_file_mode_mask_bit_execute; + } + + if (umask & f_file_mode_group_r) { + mode_umask |= f_file_mode_block_group & f_file_mode_mask_bit_read; + } + + if (umask & f_file_mode_group_w) { + mode_umask |= f_file_mode_block_group & f_file_mode_mask_bit_write; + } + + if (umask & f_file_mode_group_x) { + mode_umask |= f_file_mode_block_group & f_file_mode_mask_bit_execute; + } + + if (umask & f_file_mode_world_r) { + mode_umask |= f_file_mode_block_world & f_file_mode_mask_bit_read; + } + + if (umask & f_file_mode_world_w) { + mode_umask |= f_file_mode_block_world & f_file_mode_mask_bit_write; + } + + if (umask & f_file_mode_world_x) { + mode_umask |= f_file_mode_block_world & f_file_mode_mask_bit_execute; + } + + for (f_string_length i = 0; syntax && string[i]; i++) { switch (string[i]) { case 'o': - if (active) { - syntax = 0; - break; - } - - on = 1; - mask |= f_file_mode_block_world; + on |= 1; + mode_mask |= f_file_mode_block_world; break; case 'g': - if (active) { - syntax = 0; - break; - } - - on = 2; - mask |= f_file_mode_block_group; + on |= 2; + mode_mask |= f_file_mode_block_group; break; case 'u': - if (active) { - syntax = 0; - break; - } - - on = 4; - mask |= f_file_mode_block_owner; + on |= 4; + mode_mask |= f_file_mode_block_owner; break; case 'a': - if (active) { - syntax = 0; - break; - } - on = 7; - mask = f_file_mode_block_all; + mode_mask = f_file_mode_block_standard; break; case '+': case '-': case '=': - active = F_true; - if (string[i] == '+') { how = on ? 1 : 4; } @@ -967,29 +989,31 @@ extern "C" { else { how = on ? 2 : 5; - // only the parts designated by the mask should be replaced. - *mode -= (*mode) & mask; + // clear by mask to prepare for replacement, which includes clearing the special block. + mode_mask |= f_file_mode_block_special; + *mode -= (*mode) & mode_mask; - if (mask == f_file_mode_block_all) { - *replace = f_file_mode_replace_all; - } - else if (mask & f_file_mode_block_world) { - *replace |= f_file_mode_block_special & f_file_mode_block_world; + *replace |= f_file_mode_replace_special; + + if (mode_mask & f_file_mode_block_owner) { + *replace |= f_file_mode_replace_owner; } - else if (mask & f_file_mode_block_group) { - *replace |= f_file_mode_block_special & f_file_mode_block_group; + + if (mode_mask & f_file_mode_block_group) { + *replace |= f_file_mode_replace_group; } - else if (mask & f_file_mode_block_owner) { - *replace |= f_file_mode_block_special & f_file_mode_block_owner; + + if (mode_mask & f_file_mode_block_world) { + *replace |= f_file_mode_replace_world; } } if (!on) { on = 7; - mask = f_file_mode_block_all; + mode_mask = f_file_mode_block_all; } - for (i++; i < string[i]; i++) { + for (i++; string[i]; i++) { if (string[i] == 'r') { what = f_file_mode_mask_bit_read; @@ -1004,6 +1028,8 @@ extern "C" { what = f_file_mode_mask_bit_execute_only; } else if (string[i] == 's') { + mode_mask |= f_file_mode_block_special; + if (on & 4) { what = f_file_mode_mask_bit_set_owner; } @@ -1015,6 +1041,8 @@ extern "C" { } } else if (string[i] == 't') { + mode_mask |= f_file_mode_block_special; + if (on & 1) { what = f_file_mode_mask_bit_sticky; } @@ -1023,15 +1051,13 @@ extern "C" { } } else if (string[i] == ',') { - active = F_false; + if (how > 3) { + *mode -= *mode & mode_umask; + } + on = 0; how = 0; - mask = f_file_mode_block_special; - break; - } - else if (string[i] == '+' || string[i] == '-' || string[i] == '=') { - // have the outer loop resume at this character after it increments. - i--; + mode_mask = 0; break; } else { @@ -1039,27 +1065,23 @@ extern "C" { break; } - if (how == 1 || how == 2) { - *mode |= what & mask & f_file_mode_mask_how_add; + if (how == 1 || how == 2 || how == 4 || how == 5) { + *mode |= what & mode_mask & f_file_mode_mask_how_add; } - else if (how == 3) { - *mode |= what & mask & f_file_mode_mask_how_subtract; - } - else if (how == 4 || how == 5) { - *mode |= what & mask & f_file_mode_mask_how_add; - *replace |= f_file_mode_replace_umask; - } - else if (how == 6) { - *mode |= what & mask & f_file_mode_mask_how_subtract; - *replace |= f_file_mode_replace_umask; + else if (how == 3 || how == 6) { + *mode |= what & mode_mask & f_file_mode_mask_how_subtract; } } // for + if (how > 3) { + *mode -= *mode & mode_umask; + } + break; - default: - syntax = 0; - break; + default: + syntax = 0; + break; } } // for } @@ -1139,9 +1161,9 @@ extern "C" { syntax = 0; } else if (how == 2) { - // if there are only '0's then the setuid/setgid/sticky bits are to be replaced. + // if there are only '0's then the standard and setuid/setgid/sticky bits are to be replaced. if (*mode == 0) { - *replace = f_file_mode_replace_standard; + *replace = f_file_mode_replace_standard | f_file_mode_replace_special; } } } diff --git a/level_0/f_file/c/file.h b/level_0/f_file/c/file.h index 37c1fa2..d286e2b 100644 --- a/level_0/f_file/c/file.h +++ b/level_0/f_file/c/file.h @@ -247,7 +247,6 @@ extern "C" { * File mode related functionality. * * The f_file_mode type properties are 8-bit types with the following structure: - * @todo finish documentation. * * There should only be a single bit for each 'r', 'w', 'x', and 'X' bit (as well as 'S', 's', and 't'): * 'r' = read bit. @@ -257,20 +256,17 @@ extern "C" { * 'S' = set user bit (setuid). * 's' = set group bit (setgid). * 't' = sticky bit. - * - * The mode replace codes are meant to be used for the user, group, and world modes. - * Generally "special" bits are preserved unless explicitly changed so there is also a "special" mode replace code as well. - * The "umask" equivalent specifies that the mask should allow for umask influence. */ #ifndef _di_f_file_mode_ typedef uint32_t f_file_mode; - // 0000 0000 0000 0111 0000 0101 0000 0101 - #define f_file_mode_block_special 0x77000000 // 0111 0111 0000 0000 0000 0000 0000 0000 - #define f_file_mode_block_owner 0x00ff0000 // 0000 0000 1111 1111 0000 0000 0000 0000 - #define f_file_mode_block_group 0x0000ff00 // 0000 0000 0000 0000 1111 1111 0000 0000 - #define f_file_mode_block_world 0x000000ff // 0000 0000 0000 0000 0000 0000 1111 1111 - #define f_file_mode_block_all 0x77ffffff // 0111 0111 1111 1111 1111 1111 1111 1111 + #define f_file_mode_block_special 0x77000000 // 0111 0111 0000 0000 0000 0000 0000 0000 + #define f_file_mode_block_owner 0x00ff0000 // 0000 0000 1111 1111 0000 0000 0000 0000 + #define f_file_mode_block_group 0x0000ff00 // 0000 0000 0000 0000 1111 1111 0000 0000 + #define f_file_mode_block_world 0x000000ff // 0000 0000 0000 0000 0000 0000 1111 1111 + + #define f_file_mode_block_all 0x77ffffff // 0111 0111 1111 1111 1111 1111 1111 1111 + #define f_file_mode_block_standard 0x00ffffff // 0000 0000 1111 1111 1111 1111 1111 1111 #define f_file_mode_mask_how_add 0x070f0f0f // 0000 0111 0000 1111 0000 1111 0000 1111 #define f_file_mode_mask_how_subtract 0x70f0f0f0 // 0111 0000 1111 0000 1111 0000 1111 0000 @@ -286,12 +282,11 @@ extern "C" { #define f_file_mode_replace_owner 0x1 // 0000 0001 #define f_file_mode_replace_group 0x2 // 0000 0010 #define f_file_mode_replace_world 0x4 // 0000 0100 - #define f_file_mode_replace_special 0x7 // 0000 1000 - #define f_file_mode_replace_umask 0x10 // 0001 0000 - #define f_file_mode_replace_directory 0x20 // 0010 0000 + #define f_file_mode_replace_special 0x8 // 0000 1000 + #define f_file_mode_replace_directory 0x10 // 0001 0000 - #define f_file_mode_replace_all 0x3f // 0011 1111 - #define f_file_mode_replace_other 0x38 // 0011 1000 + #define f_file_mode_replace_all 0x1f // 0001 1111 + #define f_file_mode_replace_other 0x18 // 0001 1000 #define f_file_mode_replace_standard 0x7 // 0000 0111 // file permission modes. @@ -1146,6 +1141,8 @@ extern "C" { /** * Determine how the mode should be applied based on different file properties and the given mode properties. * + * This does not set mode based on umask(), which is already applied if f_file_mode_from_string() was used to create mode_change. + * * @param mode_file * The mode_t value representing the file's current mode. * This is expected to be populated from (struct stat).st_mode. @@ -1155,8 +1152,6 @@ extern "C" { * The mode modes that should be replaced instead of simply changed. * @param directory_is * Set to TRUE if the file is a directory, FALSE otherwise. - * @param umask - * The current umask, which will be used if necessary. * @param mode * The determined mode. * @@ -1167,7 +1162,7 @@ extern "C" { * @see f_file_mode_from_string() */ #ifndef _di_f_file_mode_determine_ - extern f_return_status f_file_mode_determine(const mode_t mode_file, const f_file_mode mode_change, const uint8_t mode_replace, const bool directory_is, const mode_t umask, mode_t *mode); + extern f_return_status f_file_mode_determine(const mode_t mode_file, const f_file_mode mode_change, const uint8_t mode_replace, const bool directory_is, mode_t *mode); #endif // _di_f_file_mode_determine_ /** @@ -1231,8 +1226,12 @@ extern "C" { * * Considering the behavior, assume that when "=" or a leading "0" is provided, this will change the setuid/setgid/sticky bits, otherwise it preserves those bits for directories. * + * @fixme the possibilities are a bit extensive and this needs additional review; remove this fixme when this review is completed. + * * @param string * A NULL terminated string designating the desired mode, following the above string syntax. + * @param umask + * The umask to be applied to the file mode, when applicable. * @param mode * The determined mode. * This uses bitwise data. @@ -1250,7 +1249,7 @@ extern "C" { * @see private_f_file_mode_determine() */ #ifndef _di_f_file_mode_from_string_ - extern f_return_status f_file_mode_from_string(const f_string string, f_file_mode *mode, uint8_t *replace); + extern f_return_status f_file_mode_from_string(const f_string string, const mode_t umask, f_file_mode *mode, uint8_t *replace); #endif // _di_f_file_mode_from_string_ /** diff --git a/level_3/fake/c/private-make.c b/level_3/fake/c/private-make.c index 1a53e0f..1d1f515 100644 --- a/level_3/fake/c/private-make.c +++ b/level_3/fake/c/private-make.c @@ -99,7 +99,7 @@ extern "C" { return F_status_set_error(F_parameter); } - f_status status = f_file_mode_from_string(buffer.string, mode, replace); + f_status status = f_file_mode_from_string(buffer.string, data.umask, mode, replace); if (F_status_is_error(status)) { if (data.verbosity != fake_verbosity_quiet) { @@ -1539,7 +1539,7 @@ extern "C" { break; } - *status = f_file_mode_determine(stat_file.st_mode, mode_rule, replace, f_macro_file_type_is_directory(stat_file.st_mode), data.umask, &mode); + *status = f_file_mode_determine(stat_file.st_mode, mode_rule, replace, f_macro_file_type_is_directory(stat_file.st_mode), &mode); if (F_status_is_error(*status)) { fake_print_error_file(data, *status, "f_file_mode_determine", arguments.array[i].string, "change mode of", F_true, F_true); break; diff --git a/level_3/fake/data/build/fakefile b/level_3/fake/data/build/fakefile index 0d95a18..2ae1288 100644 --- a/level_3/fake/data/build/fakefile +++ b/level_3/fake/data/build/fakefile @@ -9,6 +9,4 @@ settings: main: - #build - touch file b - mode =755 b + build -- 1.8.3.1