f_file_mode_t mode_result = 0;
if (code.string[0] == f_string_ascii_plus_s.string[0] || code.string[0] == f_string_ascii_minus_s.string[0] || code.string[0] == f_string_ascii_equal_s.string[0]) {
- if (code.string[1] == f_string_ascii_r_s.string[0] || f_string_ascii_w_s.string[0] || f_string_ascii_x_s.string[0] || f_string_ascii_X_s.string[0] || f_string_ascii_s_s.string[0] ||f_string_ascii_t_s.string[0]) {
+
+ if (code.used < 2) {
+ return F_status_set_error(F_syntax);
+ }
+
+ if (code.string[1] == f_string_ascii_r_s.string[0] || code.string[1] == f_string_ascii_w_s.string[0] || code.string[1] == f_string_ascii_x_s.string[0] || code.string[1] == f_string_ascii_X_s.string[0] || code.string[1] == f_string_ascii_s_s.string[0] ||code.string[1] == f_string_ascii_t_s.string[0]) {
syntax = 1;
}
else if (code.string[1] == f_string_ascii_0_s.string[0] || code.string[1] == f_string_ascii_1_s.string[0] || code.string[1] == f_string_ascii_2_s.string[0] || code.string[1] == f_string_ascii_3_s.string[0] || code.string[1] == f_string_ascii_4_s.string[0] || code.string[1] == f_string_ascii_5_s.string[0] || code.string[1] == f_string_ascii_6_s.string[0] || code.string[1] == f_string_ascii_7_s.string[0]) {
}
}
else if (code.string[0] == f_string_ascii_u_s.string[0] || code.string[0] == f_string_ascii_g_s.string[0] || code.string[0] == f_string_ascii_o_s.string[0] || code.string[0] == f_string_ascii_a_s.string[0]) {
+
+ if (code.used < 2) {
+ return F_status_set_error(F_syntax);
+ }
+
syntax = 1;
}
else if (code.string[0] == f_string_ascii_0_s.string[0] || code.string[0] == f_string_ascii_1_s.string[0] || code.string[0] == f_string_ascii_2_s.string[0] || code.string[0] == f_string_ascii_3_s.string[0] || code.string[0] == f_string_ascii_4_s.string[0] || code.string[0] == f_string_ascii_5_s.string[0] || code.string[0] == f_string_ascii_6_s.string[0] || code.string[0] == f_string_ascii_7_s.string[0]) {
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, 4 = add when no "on", 5 = replace when no "on", and 6 = subtract when no "on".
+ bool incomplete = F_true;
f_file_mode_t mode_mask = 0;
f_file_mode_t mode_umask = 0;
mode_umask |= F_file_mode_t_block_world_d & F_file_mode_t_mask_bit_execute_d;
}
- for (f_array_length_t i = 0; syntax && code.string[i]; ++i) {
+ for (f_array_length_t i = 0; syntax && i < code.used; ++i) {
if (code.string[i] == f_string_ascii_u_s.string[0]) {
on |= 1;
replace_result |= F_file_mode_t_replace_special_d;
- if (mode_mask & F_file_mode_t_block_owner_d) {
- replace_result |= F_file_mode_t_replace_owner_d;
- }
+ // When i is 0, then '=' is applied to all blocks.
+ if (i) {
+ if (mode_mask & F_file_mode_t_block_owner_d) {
+ replace_result |= F_file_mode_t_replace_owner_d;
+ }
- if (mode_mask & F_file_mode_t_block_group_d) {
- replace_result |= F_file_mode_t_replace_group_d;
- }
+ if (mode_mask & F_file_mode_t_block_group_d) {
+ replace_result |= F_file_mode_t_replace_group_d;
+ }
- if (mode_mask & F_file_mode_t_block_world_d) {
- replace_result |= F_file_mode_t_replace_world_d;
+ if (mode_mask & F_file_mode_t_block_world_d) {
+ replace_result |= F_file_mode_t_replace_world_d;
+ }
+ }
+ else {
+ replace_result |= F_file_mode_t_replace_owner_d | F_file_mode_t_replace_group_d | F_file_mode_t_replace_world_d;
}
}
what = 0;
- for (++i; code.string[i]; ++i) {
+ for (++i; i < code.used; ++i) {
if (code.string[i] == f_string_ascii_r_s.string[0]) {
what = F_file_mode_t_mask_bit_read_d;
}
}
else if (code.string[i] == f_string_ascii_comma_s.string[0]) {
+ incomplete = F_false;
+
if (how > 3) {
mode_result -= mode_result & mode_umask;
}
if (what) {
if (how == 1 || how == 2 || how == 4 || how == 5) {
+ incomplete = F_false;
mode_result |= what & mode_mask & F_file_mode_t_mask_how_add_d;
if (mode_result & what & mode_mask & F_file_mode_t_mask_how_subtract_d) {
}
}
else if (how == 3 || how == 6) {
+ incomplete = F_false;
mode_result |= what & mode_mask & F_file_mode_t_mask_how_subtract_d;
if (mode_result & what & mode_mask & F_file_mode_t_mask_how_add_d) {
} // for
if (how > 3) {
+ incomplete = F_false;
mode_result -= mode_result & mode_umask;
}
if (!code.string[i]) break;
}
else {
- syntax = 0;
+ return F_status_set_error(F_syntax);
}
} // for
+
+ if (incomplete) {
+ return F_status_set_error(F_syntax);
+ }
}
else if (syntax == 2) {
how = 2;
i = 1;
- replace_result = F_file_mode_t_replace_standard_d;
+ replace_result = F_file_mode_t_replace_standard_d | F_file_mode_t_replace_special_d;
}
else {
how = 2;
- replace_result = F_file_mode_t_replace_standard_d | F_file_mode_t_replace_directory_d;
+ replace_result = F_file_mode_t_replace_standard_d | F_file_mode_t_replace_special_d;
}
// Seek past leading '0's.
++i;
} // while
- if (code.string[i]) {
+ if (i < code.used) {
f_array_length_t j = 0;
- for (; code.string[i + j] && j < 4; ++j) {
+ // Do not tolerate overly large numbers.
+ if (code.used - i > 4) {
+ return F_status_set_error(F_syntax);
+ }
+
+ for (; i + j < code.used; ++j) {
if (j) {
mode_result <<= 8;
}
- if (code.string[i] == f_string_ascii_0_s.string[0]) {
+ if (code.string[i + j] == f_string_ascii_0_s.string[0]) {
// Already is a zero.
}
- else if (code.string[i] == f_string_ascii_1_s.string[0] || code.string[i] == f_string_ascii_2_s.string[0] || code.string[i] == f_string_ascii_3_s.string[0] || code.string[i] == f_string_ascii_4_s.string[0] || code.string[i] == f_string_ascii_5_s.string[0] || code.string[i] == f_string_ascii_6_s.string[0] || code.string[i] == f_string_ascii_7_s.string[0]) {
+ else if (code.string[i + j] == f_string_ascii_1_s.string[0] || code.string[i + j] == f_string_ascii_2_s.string[0] || code.string[i + j] == f_string_ascii_3_s.string[0] || code.string[i + j] == f_string_ascii_4_s.string[0] || code.string[i + j] == f_string_ascii_5_s.string[0] || code.string[i + j] == f_string_ascii_6_s.string[0] || code.string[i + j] == f_string_ascii_7_s.string[0]) {
// This assumes ASCII/UTF-8.
if (how == 3) {
// Designate that this is invalid.
j = 4;
+
break;
}
} // for
if (j == 4) {
syntax = 0;
}
- else if (how == 2) {
-
- // If there are only '0's then the standard and setuid/setgid/sticky bits are to be replaced.
- if (!mode_result) {
- replace_result = F_file_mode_t_replace_standard_d | F_file_mode_t_replace_special_d;
- }
- }
}
}
* @param mode
* The determined mode.
* This uses bitwise data.
+ *
+ * See the f_file_mode_t documentation for details.
* @param replace
* The determined modes that are to be replaced, such as: F_file_mode_t_replace_owner_d.
* This uses bitwise data.
*
+ * The flags F_file_mode_t_replace_* are used to designate which mask bits are to be replaced.
+ * For example F_file_mode_t_replace_owner_d would designate that the owner bits are to be replaced.
+ * A value of 0 means that there are no replacements being made.
+ *
+ * Replacements replace the entire existing mode values where as "add" and "subtract" add or subtract modes, respectively, to the existing mode values.
+ *
* @return
* F_none on success.
*
* F_syntax (with error bit) if the string fails to follow the syntax rules.
*
* The parameters how, mode_normal, and mode_executable are all set to 0 on error.
- *
- * @see private_f_file_mode_determine()
*/
#ifndef _di_f_file_mode_from_string_
extern f_status_t f_file_mode_from_string(const f_string_static_t code, const mode_t umask, f_file_mode_t * const mode, uint8_t * const replace);
*
* The second type is f_file_mode_t, which utilizes 8-bit types with the following structure:
*
- * There should only be a single bit for each 'r', 'w', 'x', and 'X' bit (as well as 'S', 's', and 't'):
+ * The f_file_mode_t structure is a 32-bit unsigned integer designed to directly represent the special, owner, group, and world mode bits along with their respective read, write, and execute bits (setuid, setgid, and sticky for the special bits).
+ *
+ * Each bit is structured in 8-bit blocks as follows:
+ * [ special ][ owner ][ group ][ world ]
+ *
+ * Each block, from left to right, has 4 bits representing "subtract" followed by 4 bits representing "add".
+ * As an exceptional case, the first bit (left most bit) for the "special" block is not used and expected to be 0.
+ *
+ * Each of these 4-bits, respectively, represents "special", "read", "write", and "execute".
+ *
+ * Each bit maps to some character 'r', 'w', 'x', and 'X' bit (as well as 'S', 's', and 't' for each "special"):
* 'r' = read bit.
* 'w' = write bit.
* 'x' = execute bit.
* 's' = set group bit (setgid).
* 't' = sticky bit.
*
+ * There exists both an "add" and a "subtract" block so that both operations can be passed.
+ * Such as "+r,-w" meaning add read and subtract write.
+ *
+ * For replacements, additional bits and masks are provided which are intended to be used in a separate variable given that only 8-bits are needed for replacements.
+ *
+ * The replacements are, also from left to write, are broken up into the following bits of a single byte:
+ * [ unused ] [ unused ] [ unused ] [ directory ] [ special ] [ owner ] [ group ] [ world ]
+ *
+ * The directory bit is a special case bit used to declare that these bits are in respect to a directory.
+ * Directory has special representation when it comes to the execute bit, namely when the "execute only" mode is being applied.
+ * The directory bit may be applied even when there are no replacements.
+ * This can be used to designate that the "add" or "subtract" is being applied to a directory.
+ *
+ * When, say the "owner" bit is set in this replacement, this means that the owner bit is to be replaced before performing any add/subtract operations.
+ * When using the replacement variable, the "subtract" is considered a no-op and is ignored.
+ * Use only the "add" bits in conjuction with respective "replace" bits.
+ *
* The file mode macros with "f_file_mode_" prefix (has no "_t") refer to the first type (mode_t).
* The file mode macros with "f_file_mode_t" prefix refer to the second type (f_file_mode_t).
*/