From 063543feaa0c40dbeeaed9fbaf4ad05651468483 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Mon, 7 Sep 2020 00:20:55 -0500 Subject: [PATCH] Progress: featureless make. Implement recursive change owner, change groups, and change modes functions. These are implemented in the fll_file project. Then utilize these for the recursive owners, groups, and modes section operations. Fix specification where I forgot to rename "archiver" to "indexer". In documentation it is "indexer" and not "index" for the indexer program whereas "index" is a section operation name. Fix documentation where I forgot to rename "archive" to "index". A bug in fl_directory_list() was discovered where the parameter check for path is incorrect. --- build/level_2/settings | 2 +- build/monolithic/settings | 2 +- level_0/f_file/c/file.c | 16 +-- level_0/f_file/c/file.h | 5 +- level_0/f_file/c/private-file.h | 4 +- level_1/fl_directory/c/directory.c | 4 +- level_2/fll_file/c/file.c | 22 ++++ level_2/fll_file/c/file.h | 79 +++++++++++++ level_2/fll_file/c/private-file.c | 194 +++++++++++++++++++++++++++++++ level_2/fll_file/c/private-file.h | 94 +++++++++++++++ level_2/fll_file/data/build/dependencies | 3 + level_2/fll_file/data/build/settings | 4 +- level_3/fake/c/fake.h | 1 + level_3/fake/c/private-make.c | 95 +++++++++++---- level_3/fake/c/private-make.h | 2 + level_3/fake/c/private-print.c | 22 ++++ level_3/fake/c/private-skeleton.c | 4 +- level_3/fake/documents/fakefile.txt | 13 +-- level_3/fake/specifications/fakefile.txt | 2 +- 19 files changed, 515 insertions(+), 53 deletions(-) create mode 100644 level_2/fll_file/c/private-file.c create mode 100644 level_2/fll_file/c/private-file.h diff --git a/build/level_2/settings b/build/level_2/settings index 546d33a..be4d73d 100644 --- a/build/level_2/settings +++ b/build/level_2/settings @@ -20,7 +20,7 @@ build_indexer ar build_language c build_libraries -lc build_libraries-level -lfll_1 -lfll_0 -build_sources_library execute.c private-execute.c file.c fss.c private-fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c fss_status.c path.c program.c status.c +build_sources_library execute.c private-execute.c file.c private-file.c fss.c private-fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c fss_status.c path.c program.c status.c build_sources_program build_sources_headers execute.h file.h fss.h fss_basic.h fss_basic_list.h fss_extended.h fss_extended_list.h fss_status.h path.h program.h status.h build_sources_script diff --git a/build/monolithic/settings b/build/monolithic/settings index 88f4862..3bc7f4f 100644 --- a/build/monolithic/settings +++ b/build/monolithic/settings @@ -20,7 +20,7 @@ build_indexer ar build_language c build_libraries -lc build_libraries-monolithic -build_sources_library level_0/account.c level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/private-file.c level_0/fss.c level_0/iki.c level_0/memory.c level_0/path.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/serialize.c level_0/private-serialize.c level_0/socket.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/conversion.c level_1/directory.c level_1/private-directory.c level_1/environment.c level_1/private-fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/iki.c level_1/print.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_1/private-utf_file.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/fss.c level_2/private-fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/path.c level_2/program.c level_2/status.c +build_sources_library level_0/account.c level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/private-file.c level_0/fss.c level_0/iki.c level_0/memory.c level_0/path.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/serialize.c level_0/private-serialize.c level_0/socket.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/conversion.c level_1/directory.c level_1/private-directory.c level_1/environment.c level_1/private-fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/iki.c level_1/print.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_1/private-utf_file.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/private-file.c level_2/fss.c level_2/private-fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/path.c level_2/program.c level_2/status.c build_sources_program build_sources_headers level_0/account.h level_0/color.h level_0/console.h level_0/conversion.h level_0/directory.h level_0/directory_type.h level_0/environment.h level_0/file.h level_0/fss.h level_0/fss-common.h level_0/fss-named.h level_0/fss-nest.h level_0/fss-quoted.h level_0/fss-set.h level_0/iki.h level_0/iki-common.h level_0/memory.h level_0/memory-structure.h level_0/path.h level_0/pipe.h level_0/print.h level_0/serialize.h level_0/socket.h level_0/status.h level_0/status_array.h level_0/string.h level_0/string_common.h level_0/string_dynamic.h level_0/string_map.h level_0/string_quantity.h level_0/string_range.h level_0/type.h level_0/type_array.h level_0/utf.h level_0/utf-common.h level_1/color.h level_1/console.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/fss_status.h level_1/iki.h level_1/print.h level_1/status.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/path.h level_2/program.h level_2/status.h build_sources_script diff --git a/level_0/f_file/c/file.c b/level_0/f_file/c/file.c index 924e27a..79bb6e2 100644 --- a/level_0/f_file/c/file.c +++ b/level_0/f_file/c/file.c @@ -378,7 +378,7 @@ extern "C" { #endif // _di_f_file_group_read_ #ifndef _di_f_file_is_ - f_return_status f_file_is(const f_string_t path, const int type) { + f_return_status f_file_is(const f_string_t path, const int type, const bool dereference) { #ifndef _di_level_0_parameter_checking_ if (path == 0) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ @@ -387,18 +387,8 @@ extern "C" { memset(&file_stat, 0, sizeof(struct stat)); - if (stat(path, &file_stat) < 0) { - if (errno == ENAMETOOLONG) return F_status_set_error(F_name); - if (errno == EFAULT) return F_status_set_error(F_buffer); - if (errno == ENOMEM) return F_status_set_error(F_memory_out); - if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow); - if (errno == ENOTDIR) return F_status_set_error(F_directory); - if (errno == ENOENT) return F_file_found_not; - if (errno == EACCES) return F_status_set_error(F_access_denied); - if (errno == ELOOP) return F_status_set_error(F_loop); - - return F_status_set_error(F_file_stat); - } + f_status_t status = private_f_file_stat(path, dereference, &file_stat); + if (F_status_is_error(status)) return status; if (f_macro_file_type_get(file_stat.st_mode) == type) return F_true; diff --git a/level_0/f_file/c/file.h b/level_0/f_file/c/file.h index 58245ad..b14f4ab 100644 --- a/level_0/f_file/c/file.h +++ b/level_0/f_file/c/file.h @@ -916,6 +916,9 @@ extern "C" { * The path file name. * @param type * The type of the file. + * @param dereference + * Set to TRUE to dereference symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. * * @return * F_true if path was found and path is type. @@ -932,7 +935,7 @@ extern "C" { * @see stat() */ #ifndef _di_f_file_is_ - extern f_return_status f_file_is(const f_string_t path, const int type); + extern f_return_status f_file_is(const f_string_t path, const int type, const bool dereference); #endif // _di_f_file_is_ /** diff --git a/level_0/f_file/c/private-file.h b/level_0/f_file/c/private-file.h index 8057114..05ce890 100644 --- a/level_0/f_file/c/private-file.h +++ b/level_0/f_file/c/private-file.h @@ -787,9 +787,9 @@ extern "C" { * @see f_file_exists() * @see f_file_touch() */ -#if !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_) || !defined(_di_f_file_exists_) || !defined(_di_f_file_touch_) +#if !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_) || !defined(_di_f_file_exists_) || !defined(_di_f_file_is_) || !defined(_di_f_file_touch_) extern f_return_status private_f_file_stat(const f_string_t file_name, const bool dereference, struct stat *file_stat) f_gcc_attribute_visibility_internal; -#endif // !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_) || !defined(_di_f_file_exists_) || !defined(_di_f_file_touch_) +#endif // !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_) || !defined(_di_f_file_exists_) || !defined(_di_f_file_is_) || !defined(_di_f_file_touch_) /** * Private implementation of f_file_stat_at(). diff --git a/level_1/fl_directory/c/directory.c b/level_1/fl_directory/c/directory.c index f27ea3f..aeac554 100644 --- a/level_1/fl_directory/c/directory.c +++ b/level_1/fl_directory/c/directory.c @@ -220,8 +220,8 @@ extern "C" { #ifndef _di_fl_directory_list_ f_return_status fl_directory_list(const f_string_t path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), const bool dereference, f_directory_listing_t *listing) { #ifndef _di_level_1_parameter_checking_ - if (path) return F_status_set_error(F_parameter); - if (listing == 0) return F_status_set_error(F_parameter); + if (!path) return F_status_set_error(F_parameter); + if (!listing) return F_status_set_error(F_parameter); #endif // _di_level_1_parameter_checking_ return private_fl_directory_list(path, filter, sort, dereference, listing); diff --git a/level_2/fll_file/c/file.c b/level_2/fll_file/c/file.c index d2b9ed3..2bbb6cf 100644 --- a/level_2/fll_file/c/file.c +++ b/level_2/fll_file/c/file.c @@ -1,4 +1,5 @@ #include "file.h" +#include "private-file.h" #ifdef __cplusplus extern "C" { @@ -63,6 +64,27 @@ extern "C" { } #endif // _di_fll_file_error_print_ +#ifndef _di_fll_file_mode_set_all_ + f_return_status fll_file_mode_set_all(const f_string_t path, const mode_t mode, const f_number_unsigned_t depth_max) { + #ifndef _di_level_0_parameter_checking_ + if (path == 0) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + return private_fll_file_mode_set_all(path, mode, depth_max, 0); + } +#endif // _di_fll_file_mode_set_all__ + +#ifndef _di_fll_file_role_change_all_ + f_return_status fll_file_role_change_all(const f_string_t path, const uid_t uid, const gid_t gid, const bool dereference, const f_number_unsigned_t depth_max) { + #ifndef _di_level_0_parameter_checking_ + if (path == 0) return F_status_set_error(F_parameter); + if (uid == -1 && gid == -1) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + return private_fll_file_role_change_all(path, uid, gid, dereference, depth_max, 0); + } +#endif // _di_fll_file_role_change_all_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_2/fll_file/c/file.h b/level_2/fll_file/c/file.h index e45fe4d..dbc4cae 100644 --- a/level_2/fll_file/c/file.h +++ b/level_2/fll_file/c/file.h @@ -18,9 +18,12 @@ #include #include #include +#include +#include // fll-1 includes #include +#include #ifdef __cplusplus extern "C" { @@ -49,6 +52,82 @@ extern "C" { extern f_return_status fll_file_error_print(FILE *file, const fl_color_context_t context, const f_string_t function_name, const f_string_t file_name, const f_status_t status); #endif // _di_fll_file_error_print_ +/** + * Change mode of a given file or directory at the specified path. + * + * This does not set mode based on umask(), be sure to apply umask if so desired. + * (such as: mode & ~mask). + * + * If the file is a directory then recurse into that directory and apply mode to all files within. + * + * @param path + * The path file name. + * @param mode + * The new mode to use. + * @param depth_max + * The max recursion depth. + * + * @return + * F_none on success. + * F_access_denied (with error bit) on access denied. + * F_access_mode (with error bit) if the current user does not have access to assign the file mode. + * F_directory (with error bit) on invalid directory. + * F_file_found_not (with error bit) if file at path was not found. + * F_input_output (with error bit) on I/O error. + * F_loop (with error bit) on loop error. + * F_memory_out (with error bit) if out of memory. + * F_name (with error bit) on path name error. + * F_parameter (with error bit) if a parameter is invalid. + * F_read_only (with error bit) if file is read-only. + * F_recurse (with error bit) if recursion failed, due to max depth reached. + * F_failure (with error bit) for any other error. + */ +#ifndef _di_fll_file_mode_set_all_ + extern f_return_status fll_file_mode_set_all(const f_string_t path, const mode_t mode, const f_number_unsigned_t depth_max); +#endif // _di_fll_file_mode_set_all_ + +/** + * Change owner and/or group of a given file at the specified path. + * + * At least one of uid or gid must not be -1. + * + * If the file is a directory then recurse into that directory and apply mode to all files within. + * + * @param path + * The path file name. + * @param uid + * The new user id to use. + * Set to -1 to not change. + * @param gid + * The new group id to use. + * Set to -1 to not change. + * @param dereference + * Set to TRUE to dereferenc symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. + * @param depth_max + * The max recursion depth. + * + * @return + * F_none on success. + * F_access_denied (with error bit) on access denied. + * F_access_group (with error bit) if the current user does not have access to assign the specified group. + * F_access_owner (with error bit) if the current user does not have access to assign the specified owner. + * F_buffer (with error bit) if the buffer is invalid. + * F_directory (with error bit) on invalid directory. + * F_file_found_not (with error bit) if file at path was not found. + * F_input_output (with error bit) on I/O error. + * F_loop (with error bit) on loop error. + * F_memory_out (with error bit) if out of memory. + * F_name (with error bit) on path name error. + * F_parameter (with error bit) if a parameter is invalid. + * F_read_only (with error bit) if file is read-only. + * F_recurse (with error bit) if recursion failed, due to max depth reached. + * F_failure (with error bit) for any other error. + */ +#ifndef _di_fll_file_role_change_all_ + extern f_return_status fll_file_role_change_all(const f_string_t path, const uid_t uid, const gid_t gid, const bool dereference, const f_number_unsigned_t depth_max); +#endif // _di_fll_file_role_change_all_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_2/fll_file/c/private-file.c b/level_2/fll_file/c/private-file.c new file mode 100644 index 0000000..d8106ae --- /dev/null +++ b/level_2/fll_file/c/private-file.c @@ -0,0 +1,194 @@ +#include "file.h" +#include "private-file.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(_di_fll_file_mode_set_all_) + f_return_status private_fll_file_mode_set_all(const f_string_t path, const mode_t mode, const f_number_unsigned_t depth_max, const f_number_unsigned_t depth) { + + if (depth >= depth_max) return F_status_set_error(F_recurse); + + f_status_t status = F_none; + + status = f_directory_is(path); + if (F_status_is_error(status)) return status; + + if (status == F_false) { + return f_file_mode_set(path, mode); + } + + f_directory_listing_t listing = f_directory_listing_t_initialize; + + status = fl_directory_list(path, 0, 0, F_false, &listing); + + if (F_status_is_error(status)) { + f_macro_directory_listing_t_delete_simple(listing); + return status; + } + + status = F_none; + + const f_string_length_t path_length = strnlen(path, f_path_max); + + { + f_string_dynamics_t *list[] = { + &listing.block, + &listing.character, + &listing.regular, + &listing.link, + &listing.fifo, + &listing.socket, + &listing.unknown, + }; + + uint8_t i = 0; + f_array_length_t j = 0; + + for (; i < 7; i++) { + for (j = 0; F_status_is_fine(status) && j < list[i]->used; j++) { + const f_string_length_t length = path_length + list[i]->array[j].used + 1; + + char path_sub[length + 1]; + + memcpy(path_sub, path, path_length); + memcpy(path_sub + path_length + 1, list[i]->array[j].string, list[i]->array[j].used); + + path_sub[path_length] = f_path_separator[0]; + path_sub[length] = 0; + + status = f_file_mode_set(path_sub, mode); + } // for + + f_macro_string_dynamics_t_delete_simple((*list[i])); + } // for + } + + f_macro_string_dynamics_t_delete_simple(listing.unknown); + + for (f_array_length_t i = 0; F_status_is_fine(status) && i < listing.directory.used; i++) { + const f_string_length_t length = path_length + listing.directory.array[i].used + 1; + + char path_sub[length + 1]; + + memcpy(path_sub, path, path_length); + memcpy(path_sub + path_length + 1, listing.directory.array[i].string, listing.directory.array[i].used); + + path_sub[path_length] = f_path_separator[0]; + path_sub[length] = 0; + + status = f_directory_exists(path_sub); + if (F_status_is_error(status)) break; + + if (status == F_false) { + status = F_status_set_error(F_directory); + break; + } + + status = private_fll_file_mode_set_all(path_sub, mode, depth_max, depth + 1); + if (F_status_is_error(status)) break; + } // for + + f_macro_string_dynamics_t_delete_simple(listing.directory); + + if (F_status_is_error(status)) return status; + + return f_file_mode_set(path, mode); + } +#endif // !defined(_di_fll_file_mode_set_all_) + +#if !defined(_di_fll_file_role_change_all_) + f_return_status private_fll_file_role_change_all(const f_string_t path, const uid_t uid, const gid_t gid, const bool dereference, const f_number_unsigned_t depth_max, const f_number_unsigned_t depth) { + + if (depth >= depth_max) return F_status_set_error(F_recurse); + + f_status_t status = F_none; + + status = f_directory_is(path); + if (F_status_is_error(status)) return status; + + if (status == F_false) { + return f_file_role_change(path, uid, gid, dereference); + } + + f_directory_listing_t listing = f_directory_listing_t_initialize; + + status = fl_directory_list(path, 0, 0, F_false, &listing); + + if (F_status_is_error(status)) { + f_macro_directory_listing_t_delete_simple(listing); + return status; + } + + status = F_none; + + const f_string_length_t path_length = strnlen(path, f_path_max); + + { + f_string_dynamics_t *list[] = { + &listing.block, + &listing.character, + &listing.regular, + &listing.link, + &listing.fifo, + &listing.socket, + &listing.unknown, + }; + + uint8_t i = 0; + f_array_length_t j = 0; + + for (; i < 7; i++) { + for (j = 0; F_status_is_fine(status) && j < list[i]->used; j++) { + const f_string_length_t length = path_length + list[i]->array[j].used + 1; + + char path_sub[length + 1]; + + memcpy(path_sub, path, path_length); + memcpy(path_sub + path_length + 1, list[i]->array[j].string, list[i]->array[j].used); + + path_sub[path_length] = f_path_separator[0]; + path_sub[length] = 0; + + status = f_file_role_change(path_sub, uid, gid, dereference); + } // for + + f_macro_string_dynamics_t_delete_simple((*list[i])); + } // for + } + + for (f_array_length_t i = 0; F_status_is_fine(status) && i < listing.directory.used; i++) { + const f_string_length_t length = path_length + listing.directory.array[i].used + 1; + + char path_sub[length + 1]; + + memcpy(path_sub, path, path_length); + memcpy(path_sub + path_length + 1, listing.directory.array[i].string, listing.directory.array[i].used); + + path_sub[path_length] = f_path_separator[0]; + path_sub[length] = 0; + + status = f_directory_exists(path_sub); + if (F_status_is_error(status)) break; + + if (status == F_false) { + status = F_status_set_error(F_directory); + break; + } + + status = private_fll_file_role_change_all(path_sub, uid, gid, dereference, depth_max, depth + 1); + if (F_status_is_error(status)) break; + } // for + + f_macro_string_dynamics_t_delete_simple(listing.directory); + + if (F_status_is_error(status)) return status; + + return f_file_role_change(path, uid, gid, dereference); + } +#endif // !defined(_di_fll_file_role_change_all_) + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_2/fll_file/c/private-file.h b/level_2/fll_file/c/private-file.h new file mode 100644 index 0000000..d8018e4 --- /dev/null +++ b/level_2/fll_file/c/private-file.h @@ -0,0 +1,94 @@ +/** + * FLL - Level 2 + * + * Project: File + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * Provides structures and data types for a file I/O. + * Provides operations for opening/closing files. + */ +#ifndef _PRIVATE_FLL_file_h +#define _PRIVATE_FLL_file_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Private implementation of fll_file_mode_set_all(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param path + * The path file name. + * @param mode + * The new mode to use. + * @param depth_max + * The max recursion depth. + * @param depth + * The current depth. + * + * @return + * F_none on success. + * F_access_denied (with error bit) on access denied. + * F_access_mode (with error bit) if the current user does not have access to assign the file mode. + * F_directory (with error bit) on invalid directory. + * F_file_found_not (with error bit) if file at path was not found. + * F_input_output (with error bit) on I/O error. + * F_loop (with error bit) on loop error. + * F_memory_out (with error bit) if out of memory. + * F_name (with error bit) on path name error. + * F_parameter (with error bit) if a parameter is invalid. + * F_read_only (with error bit) if file is read-only. + * F_recurse (with error bit) if recursion failed, due to max depth reached. + * F_failure (with error bit) for any other error. + */ +#if !defined(_di_fll_file_mode_set_all_) + extern f_return_status private_fll_file_mode_set_all(const f_string_t path, const mode_t mode, const f_number_unsigned_t depth_max, const f_number_unsigned_t depth) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_fll_file_mode_set_all_) + +/** + * Private implementation of fll_file_role_change_all(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param path + * The path file name. + * @param uid + * The new user id to use. + * @param gid + * The new group id to use. + * @param dereference + * Set to TRUE to dereference symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. + * @param depth_max + * The max recursion depth. + * @param depth + * The current depth. + * + * @return + * F_none on success. + * F_access_denied (with error bit) on access denied. + * F_access_group (with error bit) if the current user does not have access to assign the specified group. + * F_access_owner (with error bit) if the current user does not have access to assign the specified owner. + * F_buffer (with error bit) if the buffer is invalid. + * F_directory (with error bit) on invalid directory. + * F_file_found_not (with error bit) if file at path was not found. + * F_input_output (with error bit) on I/O error. + * F_loop (with error bit) on loop error. + * F_memory_out (with error bit) if out of memory. + * F_name (with error bit) on path name error. + * F_parameter (with error bit) if a parameter is invalid. + * F_read_only (with error bit) if file is read-only. + * F_failure (with error bit) for any other error. + */ +#if !defined(_di_fll_file_role_change_all_) + extern f_return_status private_fll_file_role_change_all(const f_string_t path, const uid_t uid, const gid_t gid, const bool dereference, const f_number_unsigned_t depth_max, const f_number_unsigned_t depth) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_fll_file_role_change_all_) + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_FLL_file_h diff --git a/level_2/fll_file/data/build/dependencies b/level_2/fll_file/data/build/dependencies index 0759aad..3d952dc 100644 --- a/level_2/fll_file/data/build/dependencies +++ b/level_2/fll_file/data/build/dependencies @@ -4,4 +4,7 @@ f_type f_status f_memory f_string +f_directory +f_file fl_color +fl_directory diff --git a/level_2/fll_file/data/build/settings b/level_2/fll_file/data/build/settings index 93b342a..0b6f635 100644 --- a/level_2/fll_file/data/build/settings +++ b/level_2/fll_file/data/build/settings @@ -19,8 +19,8 @@ build_compiler gcc build_indexer ar build_language c build_libraries -lc -build_libraries-individual -lfl_color -lf_print -lf_file -lf_memory -build_sources_library file.c +build_libraries-individual -lfl_color -lfl_directory -lf_print -lf_file -lf_directory -lf_memory +build_sources_library file.c private-file.c build_sources_program build_sources_headers file.h build_sources_script diff --git a/level_3/fake/c/fake.h b/level_3/fake/c/fake.h index da8ab33..28f1519 100644 --- a/level_3/fake/c/fake.h +++ b/level_3/fake/c/fake.h @@ -73,6 +73,7 @@ // fll-2 includes #include +#include #include #include #include diff --git a/level_3/fake/c/private-make.c b/level_3/fake/c/private-make.c index 245513e..8e9fcb1 100644 --- a/level_3/fake/c/private-make.c +++ b/level_3/fake/c/private-make.c @@ -1958,10 +1958,24 @@ extern "C" { *status = fake_make_get_id_group(data, data_make->print, arguments.array[0], &id); if (F_status_is_error(*status)) return; + f_status_t status_file = F_none; + for (f_array_length_t i = 1; i < arguments.used; i++) { - *status = f_file_role_change(arguments.array[i].string, -1, id, F_false); + status_file = fake_make_assure_inside_project(data, arguments.array[i], data_make); + + if (F_status_is_error(status_file)) { + *status = status_file; + + fake_print_message_section_operation_path_outside(data, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string, data_make->print); + + continue; + } + + status_file = f_file_role_change(arguments.array[i].string, -1, id, F_false); + + if (F_status_is_error(status_file)) { + *status = status_file; - if (F_status_is_error(*status)) { fake_print_message_file(data, *status, "f_file_role_change", arguments.array[i].string, "change group of", F_true, F_true, data_make->print); } else if (data.verbosity == fake_verbosity_verbose) { @@ -1978,12 +1992,25 @@ extern "C" { *status = fake_make_get_id_group(data, data_make->print, arguments.array[0], &id); if (F_status_is_error(*status)) return; + f_status_t status_file = F_none; + for (f_array_length_t i = 1; i < arguments.used; i++) { - // @todo: recursive. - *status = f_file_role_change(arguments.array[i].string, -1, id, F_false); + status_file = fake_make_assure_inside_project(data, arguments.array[i], data_make); - if (F_status_is_error(*status)) { - fake_print_message_file(data, *status, "f_file_role_change", arguments.array[i].string, "change group of", F_true, F_true, data_make->print); + if (F_status_is_error(status_file)) { + *status = status_file; + + fake_print_message_section_operation_path_outside(data, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string, data_make->print); + + continue; + } + + status_file = fll_file_role_change_all(arguments.array[i].string, -1, id, F_false, fake_make_operation_recursion_depth_max); + + if (F_status_is_error(status_file)) { + *status = status_file; + + fake_print_message_file(data, F_status_set_fine(*status), "fll_file_role_change_all", arguments.array[i].string, "change group of", F_true, F_true, data_make->print); } else if (data.verbosity == fake_verbosity_verbose) { printf("Changed group of '%s' to %llu.%c", arguments.array[i].string, id, f_string_eol[0]); @@ -2527,7 +2554,6 @@ extern "C" { mode_t mode_file = 0; for (f_array_length_t i = 1; i < arguments.used; i++) { - // @todo recursive. mode = 0; *status = f_file_mode_read(arguments.array[i].string, &mode_file); @@ -2542,9 +2568,9 @@ extern "C" { break; } - *status = f_file_mode_set(arguments.array[i].string, mode); + *status = fll_file_mode_set_all(arguments.array[i].string, mode, fake_make_operation_recursion_depth_max); if (F_status_is_error(*status)) { - fake_print_message_file(data, F_status_set_fine(*status), "f_file_mode_set", arguments.array[i].string, "change mode of", F_true, F_true, data_make->print); + fake_print_message_file(data, F_status_set_fine(*status), "fll_file_mode_set_all", arguments.array[i].string, "change mode of", F_true, F_true, data_make->print); break; } @@ -2588,14 +2614,28 @@ extern "C" { *status = fake_make_get_id_owner(data, data_make->print, arguments.array[0], &id); if (F_status_is_error(*status)) return; + f_status_t status_file = F_none; + for (f_array_length_t i = 1; i < arguments.used; i++) { - *status = f_file_role_change(arguments.array[i].string, id, -1, F_false); - if (F_status_is_error(*status)) { + status_file = fake_make_assure_inside_project(data, arguments.array[i], data_make); + + if (F_status_is_error(status_file)) { + *status = status_file; + + fake_print_message_section_operation_path_outside(data, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string, data_make->print); + + continue; + } + + status_file = f_file_role_change(arguments.array[i].string, id, -1, F_false); + + if (F_status_is_error(status_file)) { + *status = status_file; + fake_print_message_file(data, F_status_set_fine(*status), "f_file_role_change", arguments.array[i].string, "change owner of", F_true, F_true, data_make->print); break; } - - if (data.verbosity == fake_verbosity_verbose) { + else if (data.verbosity == fake_verbosity_verbose) { printf("Changed owner of '%s' to %d.%c", arguments.array[i].string, id, f_string_eol[0]); } } // for @@ -2609,14 +2649,27 @@ extern "C" { *status = fake_make_get_id_owner(data, data_make->print, arguments.array[0], &id); if (F_status_is_error(*status)) return; + f_status_t status_file = F_none; + for (f_array_length_t i = 1; i < arguments.used; i++) { - // @todo recursive. - *status = f_file_role_change(arguments.array[i].string, id, -1, F_false); - if (F_status_is_error(*status)) { - fake_print_message_file(data, F_status_set_fine(*status), "f_file_role_change", arguments.array[i].string, "change owner of", F_true, F_true, data_make->print); + status_file = fake_make_assure_inside_project(data, arguments.array[i], data_make); + + if (F_status_is_error(status_file)) { + *status = status_file; + + fake_print_message_section_operation_path_outside(data, F_status_set_fine(*status), "fake_make_assure_inside_project", data_make->path_cache.used ? data_make->path_cache.string : arguments.array[i].string, data_make->print); + + continue; } - if (data.verbosity == fake_verbosity_verbose) { + status_file = fll_file_role_change_all(arguments.array[i].string, id, -1, F_false, fake_make_operation_recursion_depth_max); + + if (F_status_is_error(status_file)) { + *status = status_file; + + fake_print_message_file(data, F_status_set_fine(*status), "fll_file_role_change_all", arguments.array[i].string, "change owner of", F_true, F_true, data_make->print); + } + else if (data.verbosity == fake_verbosity_verbose) { printf("Changed owner of '%s' to %o.%c", arguments.array[i].string, id, f_string_eol[0]); } } // for @@ -3093,7 +3146,7 @@ extern "C" { path_file[data.path_data_build.used + arguments.array[0].used] = 0; - f_status_t status_file = f_file_is(path_file, f_file_type_regular); + f_status_t status_file = f_file_is(path_file, f_file_type_regular, F_false); if (status_file == F_file_found_not) { if (data.verbosity != fake_verbosity_quiet && data_make->print.to) { @@ -3362,7 +3415,7 @@ extern "C" { f_status_t status_file = F_none; for (f_array_length_t i = 1; i < arguments.used; i++) { - status_file = f_file_is(arguments.array[i].string, f_file_type_regular); + status_file = f_file_is(arguments.array[i].string, f_file_type_regular, F_false); if (status_file == F_file_found_not) { if (data.verbosity != fake_verbosity_quiet && data_make->print.to) { @@ -3877,7 +3930,7 @@ extern "C" { } else if (arguments.used) { if (arguments.array[0].used) { - f_status_t status_file = f_file_is(arguments.array[0].string, f_file_type_directory); + f_status_t status_file = f_file_is(arguments.array[0].string, f_file_type_directory, F_false); if (status_file == F_file_found_not) { if (data.verbosity != fake_verbosity_quiet && data_make->print.to) { diff --git a/level_3/fake/c/private-make.h b/level_3/fake/c/private-make.h index 04f9d11..5baa17f 100644 --- a/level_3/fake/c/private-make.h +++ b/level_3/fake/c/private-make.h @@ -248,6 +248,8 @@ extern "C" { fake_make_operation_fail_type_warn, fake_make_operation_fail_type_ignore, }; + + #define fake_make_operation_recursion_depth_max 65535 #endif // _di_fake_make_operation_ // @todo each one of these should be made available to be passed to the program as "$parameter_define[X]" for multi-value (define) or "$parameter_no_color" for single-value (no_color). diff --git a/level_3/fake/c/private-print.c b/level_3/fake/c/private-print.c index 0baf69f..4b6c09c 100644 --- a/level_3/fake/c/private-print.c +++ b/level_3/fake/c/private-print.c @@ -500,6 +500,28 @@ extern "C" { return F_false; } + if (status == F_access_owner) { + if (data.verbosity != fake_verbosity_quiet) { + fprintf(print.to, "%c", f_string_eol[0]); + fl_color_print(print.to, print.context, data.context.reset, "%s: Currrent user is not allowed to use the given owner while trying to %s %s '", print.prefix, operation, file_or_directory); + fl_color_print(print.to, data.context.notable, data.context.reset, "%s", name); + fl_color_print_line(print.to, print.context, data.context.reset, "'."); + } + + return F_false; + } + + if (status == F_access_group) { + if (data.verbosity != fake_verbosity_quiet) { + fprintf(print.to, "%c", f_string_eol[0]); + fl_color_print(print.to, print.context, data.context.reset, "%s: Currrent user is not allowed to use the given group while trying to %s %s '", print.prefix, operation, file_or_directory); + fl_color_print(print.to, data.context.notable, data.context.reset, "%s", name); + fl_color_print_line(print.to, print.context, data.context.reset, "'."); + } + + return F_false; + } + if (is_file) { if (status == F_directory_found_not) { if (data.verbosity != fake_verbosity_quiet) { diff --git a/level_3/fake/c/private-skeleton.c b/level_3/fake/c/private-skeleton.c index 254c2fa..95eedaa 100644 --- a/level_3/fake/c/private-skeleton.c +++ b/level_3/fake/c/private-skeleton.c @@ -179,7 +179,7 @@ extern "C" { if (path.used == 0) return F_none; - status = f_file_is(path.string, f_file_type_regular); + status = f_file_is(path.string, f_file_type_regular, F_false); if (status == F_true) { if (data.verbosity == fake_verbosity_verbose) { printf("File '%s' already exists.%c", path.string, f_string_eol[0]); @@ -190,7 +190,7 @@ extern "C" { // symbolic links might also be fine. if (status == F_false) { - status = f_file_is(path.string, f_file_type_link); + status = f_file_is(path.string, f_file_type_link, F_false); if (status == F_true) { if (data.verbosity == fake_verbosity_verbose) { diff --git a/level_3/fake/documents/fakefile.txt b/level_3/fake/documents/fakefile.txt index 5e7ca58..b985a92 100644 --- a/level_3/fake/documents/fakefile.txt +++ b/level_3/fake/documents/fakefile.txt @@ -41,7 +41,7 @@ Fakefile Documentation: The return code for programs can still be retrieved through using the reserved iki vaiable "return". - - index\: + - indexer\: This represents the name of the indexer program to use, such as "ar". When specified and "load_build" is "true", then this will override the "build_indexer" specified in the loaded build settings. @@ -65,12 +65,6 @@ Fakefile Documentation: This is processed top-down until the end of the list is reached. The following operations are available\: - - archive\: - Execute the linker program, such as "ar". - This uses "archive" instead of "link" to avoid confusion between this and generating a symbolic link to some file. - - All Content are passed as arguments to the respective "ar" program. - - build\: Run the fake build operation as if "fake build" was run instead of "fake make". Command line arguments are automatically passed to the fake build operation. @@ -217,6 +211,11 @@ Fakefile Documentation: for example, "if defined parameter verbose silent" would test if both the "verbose" and the "silent" variables are defined via the "parameter" setting. for example, "if defined environment PWD SHELL" would test if both the "PWD" and the "SHELL" variables are defined via the "environment" variables. + - index\: + Execute the linker program, such as "ar". + + All Content are passed as arguments to the respective "ar" program. + - link\: Create a symbolic link from some point to some target. diff --git a/level_3/fake/specifications/fakefile.txt b/level_3/fake/specifications/fakefile.txt index d73bad5..38e185f 100644 --- a/level_3/fake/specifications/fakefile.txt +++ b/level_3/fake/specifications/fakefile.txt @@ -25,11 +25,11 @@ Fakefile Specification: - main: contains a list of Operation Objects and Content in FSS-0001 (Extended) format. The Settings Objects are\: - - archiver: Only one Content, which must only be a valid filename. - compiler: Only one Content, which must only be a valid filename. - define: First Content represents variable name (case-sensitive), remaining Content represents varaiable value for IKI substitution. - environment: Zero or more Content representing valid environment variable names (alpha-numeric with underscore, but cannot begin with a number). - fail: Only one Content, which must be either "exit", "warn" or "ignore" (quotes not required) (case-sensitive). + - indexer: Only one Content, which must only be a valid filename. - load_build: Only one Content, which must be either "yes" or "no" (quotes not required) (case-sensitive). - parameter: First Content represents variable name (case-sensitive), remaining Content represents varaiable value for IKI substitution. -- 1.8.3.1