From: Kevin Day Date: Sun, 9 Feb 2025 06:42:07 +0000 (-0600) Subject: Progress: Continue working on completing the remove program and update with FLL changes. X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=67bd9fcf0f44e1e77084849be61aa63e9ccbe217;p=kevux-tools Progress: Continue working on completing the remove program and update with FLL changes. There is a lot of work on the recursion behavior. These changes were interrupted and I need to relook at them and get back to where I was. There are likely partially complete changes that puts this code in a bad state, in terms of execution. Update with the latest FLL changes. --- diff --git a/data/build/remove/settings b/data/build/remove/settings index d7c7ab2..67ce870 100644 --- a/data/build/remove/settings +++ b/data/build/remove/settings @@ -44,9 +44,9 @@ build_libraries-individual_thread -lf_thread build_libraries-level -lfll_2 -lfll_1 -lfll_0 build_libraries-monolithic -lfll -build_sources_library common.c common/define.c common/enumeration.c common/print.c common/string.c common/type.c convert.c operate.c print/error.c print/message.c print/simulate.c print/verbose.c print/warning.c remove.c signal.c thread.c +build_sources_library common.c common/define.c common/enumeration.c common/print.c common/string.c common/type.c convert.c operate.c preprocess.c print/error.c print/message.c print/simulate.c print/verbose.c print/warning.c remove.c signal.c thread.c -build_sources_headers common.h common/define.h common/enumeration.h common/print.h common/string.h common/type.h convert.h operate.h print/error.h print/message.h print/simulate.h print/verbose.h print/warning.h remove.h signal.h thread.h +build_sources_headers common.h common/define.h common/enumeration.h common/print.h common/string.h common/type.h convert.h operate.h preprocess.h print/error.h print/message.h print/simulate.h print/verbose.h print/warning.h remove.h signal.h thread.h build_sources_documentation man diff --git a/data/build/stand_alone/configs/remove-config.h b/data/build/stand_alone/configs/remove-config.h index 5682108..2051ad6 100644 --- a/data/build/stand_alone/configs/remove-config.h +++ b/data/build/stand_alone/configs/remove-config.h @@ -471,6 +471,16 @@ #define _di_f_fll_idss_delete_callback_ #define _di_f_fll_idss_destroy_callback_ #define _di_f_fll_idss_t_ +//#define _di_f_gid_t_ +//#define _di_f_gids_t_ +#define _di_f_gidss_delete_callback_ +#define _di_f_gidss_destroy_callback_ +#define _di_f_gidss_t_ +//#define _di_f_id_t_ +//#define _di_f_ids_t_ +#define _di_f_idss_delete_callback_ +#define _di_f_idss_destroy_callback_ +#define _di_f_idss_t_ //#define _di_f_int128_t_ #define _di_f_int128s_t_ #define _di_f_int128ss_delete_callback_ @@ -1309,6 +1319,11 @@ //#define _di_f_type_file_flag_d_ //#define _di_f_type_number_64_t_ //#define _di_f_type_sizes_d_ +//#define _di_f_uid_t_ +//#define _di_f_uids_t_ +#define _di_f_uidss_delete_callback_ +#define _di_f_uidss_destroy_callback_ +#define _di_f_uidss_t_ //#define _di_f_uint128_t_ #define _di_f_uint128s_t_ #define _di_f_uint128ss_delete_callback_ @@ -1540,6 +1555,7 @@ #define _di_f_utf_unicode_string_to_ #define _di_f_utf_unicode_to_ #define _di_f_utf_width_e_ +#define _di_f_void_call_t_ //#define _di_fl_conversion_data_base_10_c_ #define _di_fl_conversion_data_base_12_c_ #define _di_fl_conversion_data_base_16_c_ @@ -1572,6 +1588,7 @@ #define _di_fl_directory_path_pop_ #define _di_fl_directory_path_push_ #define _di_fl_directory_path_push_dynamic_ +#define _di_fl_print_call_t_ //#define _di_fl_print_debug_s_ //#define _di_fl_print_error_s_ //#define _di_fl_print_format_ diff --git a/data/build/stand_alone/configs/tacocat-config.h b/data/build/stand_alone/configs/tacocat-config.h index bc9be3e..e9e5934 100644 --- a/data/build/stand_alone/configs/tacocat-config.h +++ b/data/build/stand_alone/configs/tacocat-config.h @@ -425,6 +425,16 @@ #define _di_f_fll_idss_delete_callback_ #define _di_f_fll_idss_destroy_callback_ #define _di_f_fll_idss_t_ +#define _di_f_gid_t_ +#define _di_f_gids_t_ +#define _di_f_gidss_delete_callback_ +#define _di_f_gidss_destroy_callback_ +#define _di_f_gidss_t_ +#define _di_f_id_t_ +#define _di_f_ids_t_ +#define _di_f_idss_delete_callback_ +#define _di_f_idss_destroy_callback_ +#define _di_f_idss_t_ #define _di_f_fss_apply_delimit_ #define _di_f_fss_apply_delimit_range_ //#define _di_f_fss_complete_e_ @@ -1516,6 +1526,11 @@ //#define _di_f_type_file_flag_d_ //#define _di_f_type_number_64_t_ //#define _di_f_type_sizes_d_ +#define _di_f_uid_t_ +#define _di_f_uids_t_ +#define _di_f_uidss_delete_callback_ +#define _di_f_uidss_destroy_callback_ +#define _di_f_uidss_t_ //#define _di_f_uint128_t_ #define _di_f_uint128s_t_ #define _di_f_uint128ss_delete_callback_ @@ -1747,6 +1762,7 @@ #define _di_f_utf_unicode_string_to_ #define _di_f_utf_unicode_to_ #define _di_f_utf_width_e_ +#define _di_f_void_call_t_ //#define _di_fl_conversion_data_base_10_c_ #define _di_fl_conversion_data_base_12_c_ #define _di_fl_conversion_data_base_16_c_ @@ -1799,6 +1815,7 @@ //#define _di_fl_fss_payload_header_map_ #define _di_fl_fss_payload_header_maps_ //#define _di_fl_fss_payload_header_state_t_ +#define _di_fl_print_call_t_ //#define _di_fl_print_debug_s_ //#define _di_fl_print_error_s_ //#define _di_fl_print_format_ diff --git a/data/build/stand_alone/settings/settings.remove b/data/build/stand_alone/settings/settings.remove index 1c33013..3984eb3 100644 --- a/data/build/stand_alone/settings/settings.remove +++ b/data/build/stand_alone/settings/settings.remove @@ -71,7 +71,7 @@ build_sources_program fll/level_2/error.c fll/level_2/private-error.c fll/level_ build_sources_program fll/level_2/print.c build_sources_program fll/level_2/program.c fll/level_2/program/common.c fll/level_2/program/print.c fll/level_2/private-program.c -build_sources_program program/kevux/tools/remove/main/common.c program/kevux/tools/remove/main/common/define.c program/kevux/tools/remove/main/common/enumeration.c program/kevux/tools/remove/main/common/print.c program/kevux/tools/remove/main/common/string.c program/kevux/tools/remove/main/common/type.c program/kevux/tools/remove/main/convert.c program/kevux/tools/remove/main/operate.c program/kevux/tools/remove/main/print/error.c program/kevux/tools/remove/main/print/message.c program/kevux/tools/remove/main/print/simulate.c program/kevux/tools/remove/main/print/verbose.c program/kevux/tools/remove/main/print/warning.c program/kevux/tools/remove/main/remove.c program/kevux/tools/remove/main/signal.c program/kevux/tools/remove/main/thread.c +build_sources_program program/kevux/tools/remove/main/common.c program/kevux/tools/remove/main/common/define.c program/kevux/tools/remove/main/common/enumeration.c program/kevux/tools/remove/main/common/print.c program/kevux/tools/remove/main/common/string.c program/kevux/tools/remove/main/common/type.c program/kevux/tools/remove/main/convert.c program/kevux/tools/remove/main/operate.c program/kevux/tools/remove/main/preprocess.c program/kevux/tools/remove/main/print/error.c program/kevux/tools/remove/main/print/message.c program/kevux/tools/remove/main/print/simulate.c program/kevux/tools/remove/main/print/verbose.c program/kevux/tools/remove/main/print/warning.c program/kevux/tools/remove/main/remove.c program/kevux/tools/remove/main/signal.c program/kevux/tools/remove/main/thread.c build_sources_program program/kevux/tools/remove/remove/config.c program/kevux/tools/remove/remove/remove.c program/kevux/tools/remove/remove/main.c program/kevux/tools/remove/remove/string.c diff --git a/sources/c/program/kevux/tools/remove/main/common.c b/sources/c/program/kevux/tools/remove/main/common.c index cd70e2f..14578b6 100644 --- a/sources/c/program/kevux/tools/remove/main/common.c +++ b/sources/c/program/kevux/tools/remove/main/common.c @@ -583,6 +583,7 @@ extern "C" { return; } + // @todo this needs to detect duplicate paths and also make not of shared paths on recursive removal to avoid trying to double+ remove. for (i = 0; i < main->program.parameters.remaining.used; ++i, ++main->setting.files.used) { index = main->program.parameters.remaining.array[i]; diff --git a/sources/c/program/kevux/tools/remove/main/common/type.c b/sources/c/program/kevux/tools/remove/main/common/type.c index cea4e01..af691fc 100644 --- a/sources/c/program/kevux/tools/remove/main/common/type.c +++ b/sources/c/program/kevux/tools/remove/main/common/type.c @@ -43,8 +43,6 @@ extern "C" { f_memory_array_resize(0, sizeof(uint32_t), (void **) &setting->groups.array, &setting->groups.used, &setting->groups.size); f_memory_array_resize(0, sizeof(uint32_t), (void **) &setting->users.array, &setting->users.used, &setting->users.size); - - f_directory_recurse_do_delete(&setting->recurse); } #endif // _di_kt_remove_setting_delete_ diff --git a/sources/c/program/kevux/tools/remove/main/common/type.h b/sources/c/program/kevux/tools/remove/main/common/type.h index 4acc34c..82cc2a0 100644 --- a/sources/c/program/kevux/tools/remove/main/common/type.h +++ b/sources/c/program/kevux/tools/remove/main/common/type.h @@ -160,6 +160,36 @@ extern "C" { #endif // _di_kt_remove_cache_t_ /** + * The main program callbacks. + * + * print_help: Print help. + * process_normal: Process normally (data from parameters and files). + * process_operate_file: Process an individual file, returning F_done to designate handled, and F_okay for letting parent continue handling. + * process_operate_file_simulate: Simulate process of an individual file, returning F_done to designate handled, and F_okay for letting parent continue handling. + */ +#ifndef _di_kt_remove_callback_t_ + typedef f_status_t (*print_help_call_t)(fl_print_t * const print, const f_color_context_t context); + typedef void (*process_normal_call_t)(kt_remove_main_t * const main); + typedef void (*process_operate_file_call_t)(kt_remove_main_t * const main, const f_string_static_t path, const struct stat statistics, uint16_t * const flag); + typedef void (*process_operate_file_simulate_call_t)(kt_remove_main_t * const main, const f_string_static_t path, const struct stat statistics, const uint16_t flag_operate, uint16_t * const flag); + + typedef struct { + print_help_call_t print_help; + process_normal_call_t process_normal; + process_operate_file_call_t process_operate_file; + process_operate_file_simulate_call_t process_operate_file_simulate; + } kt_remove_callback_t; + + #define kt_remove_callback_t_initialize \ + { \ + 0, \ + 0, \ + 0, \ + 0, \ + } +#endif // _di_kt_remove_callback_t_ + +/** * The main program settings. * * This is passed to the program-specific main entry point to designate program settings. @@ -179,13 +209,8 @@ extern "C" { * changed: An array of changed on dates used for comparison. * updated: An array of last updated dates used for comparison. * modes: An array of modes used for comparison. - * groups: An array of Group IDs (gid_t) represented via an unsigned 32-bit integer. - * users: An array of Group IDs (uid_t) represented via an unsigned 32-bit integer. - * - * print_help: Print help. - * process_normal: Process normally (data from parameters and files). - * process_operate_file: Process an individual file, returning F_done to designate handled, and F_okay for letting parent continue handling. - * process_operate_file_simulate: Simulate process of an individual file, returning F_done to designate handled, and F_okay for letting parent continue handling. + * groups: An array of Group IDs. + * users: An array of User IDs. */ #ifndef _di_kt_remove_setting_t_ typedef struct { @@ -200,18 +225,11 @@ extern "C" { kt_remove_dates_t changed; kt_remove_dates_t updated; kt_remove_modes_t modes; - f_uint32s_t groups; - f_uint32s_t users; - - f_directory_recurse_do_t recurse; + f_gids_t groups; + f_uids_t users; const f_string_static_t *program_name; const f_string_static_t *program_name_long; - - f_status_t (*print_help)(fl_print_t * const print, const f_color_context_t context); - void (*process_normal)(kt_remove_main_t * const main); - void (*process_operate_file)(kt_remove_main_t * const main, const f_string_static_t path, const struct stat statistics, uint16_t * const flag); - void (*process_operate_file_simulate)(kt_remove_main_t * const main, const f_string_static_t path, const struct stat statistics, const uint16_t flag_operate, uint16_t * const flag); } kt_remove_setting_t; #define kt_remove_setting_t_initialize \ @@ -224,13 +242,8 @@ extern "C" { kt_remove_dates_t_initialize, \ kt_remove_dates_t_initialize, \ kt_remove_modes_t_initialize, \ - f_uint32s_t_initialize, \ - f_uint32s_t_initialize, \ - f_directory_recurse_do_t_initialize, \ - 0, \ - 0, \ - 0, \ - 0, \ + f_gids_t_initialize, \ + f_uids_t_initialize, \ 0, \ 0, \ } @@ -239,21 +252,25 @@ extern "C" { /** * The main program data as a single structure. * + * cache: The program cache. + * call: The program callbacks. * program: The main program data. * setting: The settings data. */ #ifndef _di_kt_remove_main_t_ struct kt_remove_main_t_ { + kt_remove_cache_t cache; + kt_remove_callback_t call; fll_program_data_t program; kt_remove_setting_t setting; - kt_remove_cache_t cache; }; #define kt_remove_main_t_initialize \ { \ + kt_remove_cache_t_initialize, \ + kt_remove_callback_t_initialize, \ fll_program_data_t_initialize, \ kt_remove_setting_t_initialize, \ - kt_remove_cache_t_initialize, \ } #endif // _di_kt_remove_main_t_ diff --git a/sources/c/program/kevux/tools/remove/main/convert.c b/sources/c/program/kevux/tools/remove/main/convert.c index 83f1ba4..f5f4bfc 100644 --- a/sources/c/program/kevux/tools/remove/main/convert.c +++ b/sources/c/program/kevux/tools/remove/main/convert.c @@ -487,7 +487,7 @@ extern "C" { main->setting.state.status = f_rip_dynamic_nulless(buffer, &main->cache.buffer); if (F_status_is_error_not(main->setting.state.status)) { - uid_t uid = 0; + f_uid_t uid = f_uid_t_initialize; main->setting.state.status = f_account_id_by_name(main->cache.buffer, &uid); diff --git a/sources/c/program/kevux/tools/remove/main/operate.c b/sources/c/program/kevux/tools/remove/main/operate.c index 52fa1ef..6631add 100644 --- a/sources/c/program/kevux/tools/remove/main/operate.c +++ b/sources/c/program/kevux/tools/remove/main/operate.c @@ -17,117 +17,75 @@ extern "C" { if (kt_remove_signal_check(main)) return; - const uint16_t flag_operate = kt_remove_operate_file_preprocess(main, path, 0); - if (F_status_is_error(main->setting.state.status)) return; + const uint16_t flag_operate = kt_remove_preprocess_file(main, path, 0); - if (!(main->setting.flag & kt_remove_main_flag_simulate_d)) { - if (flag_operate & kt_remove_flag_file_operate_directory_d) { - kt_remove_operate_file_directory(main, path, flag_operate); - } - else { - kt_remove_operate_file_normal(main, path, flag_operate); - } - - if (F_status_is_error(main->setting.state.status)) return; + if (F_status_is_error_not(main->setting.state.status) && !(main->setting.flag & kt_remove_main_flag_simulate_d)) { + main->setting.state.status = flag_operate & kt_remove_flag_file_operate_directory_d + ? kt_remove_operate_file_recurse(main, path, flag_operate) + : kt_remove_operate_file_remove(main, path, flag_operate); } - main->setting.state.status = F_okay; + if (F_status_is_error_not(main->setting.state.status)) { + main->setting.state.status = F_okay; + } } #endif // _di_kt_remove_operate_file_ -#ifndef _di_kt_remove_operate_file_directory_ - void kt_remove_operate_file_directory(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate) { - - if (!kt_remove_operate_shall_remove(flag_operate)) { - main->setting.state.status = (flag_operate & kt_remove_flag_file_operate_remove_fail_d) ? F_status_set_error(F_no) : F_no; - - return; - } - - main->setting.recurse.state.custom = (void *) main; - main->setting.recurse.state.code = flag_operate; - main->setting.recurse.flag = f_directory_recurse_do_flag_list_e | f_directory_recurse_do_flag_after_e; - - // @todo consider this in recursion and maybe provide a new parameter follow_recurse for this. - /*if (flag_operate & kt_remove_flag_file_operate_follow_d) { - main->setting.recurse.flag |= f_directory_recurse_do_flag_dereference_e; - }*/ +#ifndef _di_kt_remove_operate_file_recurse_ + f_status_t kt_remove_operate_file_recurse(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate) { - fl_directory_do(path, &main->setting.recurse); - if (F_status_is_error(main->setting.state.status)) return; + if (!kt_remove_operate_shall_remove(flag_operate)) return (flag_operate & kt_remove_flag_file_operate_remove_fail_d) ? F_status_set_error(F_no) : F_no; - main->setting.state.status = F_yes; - } -#endif // _di_kt_remove_operate_file_directory_ + f_directory_recurse_do_t recurse = f_directory_recurse_do_t_initialize; -#ifndef _di_kt_remove_operate_file_directory_recurse_action_ - void kt_remove_operate_file_directory_recurse_action(void * const void_recurse, const f_string_static_t name, const uint16_t flag) { + recurse.state.custom = (void *) main; + recurse.state.code = flag_operate; + recurse.state.interrupt = &kt_remove_signal_check_recurse; - if (!void_recurse) return; + recurse.flag = f_directory_recurse_do_flag_list_e; + recurse.depth_max = kt_remove_depth_max_d; - f_directory_recurse_do_t * const recurse = (f_directory_recurse_do_t *) void_recurse; + recurse.action = &kt_remove_operate_file_recurse_action; + recurse.handle = &kt_remove_operate_file_recurse_handle; - if (!recurse->state.custom) return; + fl_directory_do(path, &recurse); - kt_remove_main_t * const main = (kt_remove_main_t *) recurse->state.custom; + const f_status_t status = f_directory_recurse_do_delete(&recurse); - if (main) { - recurse->state.status = F_status_set_error(F_parameter); - } - else if (flag == f_directory_recurse_do_flag_list_e) { - // @todo check all listing to determine if any directory is to be recursed or not. - if (recurse->listing.block.used || recurse->listing.character.used || recurse->listing.directory.used || recurse->listing.regular.used || recurse->listing.link.used || recurse->listing.fifo.used || recurse->listing.socket.used || recurse->listing.unknown.used) { - if (!(main->setting.recurse.state.code & kt_remove_flag_file_operate_recurse_d)) { - // @todo error out on trying to remove non-empty directory without recursion. - recurse->state.status = F_status_set_error(F_recurse_not); - } - } - else { - if (main->setting.recurse.state.code & kt_remove_flag_file_operate_remove_d) { - recurse->state.status = f_directory_remove(name, 0, F_false); - - if (F_status_is_error_not(recurse->state.status)) { - recurse->state.status = F_done; - } - } - else { - recurse->state.status = F_done; - } - } - } - else if (flag & f_directory_recurse_do_flag_after_e) { - kt_remove_operate_file(main, name); - recurse->state.status = main->setting.state.status; - } + return F_status_is_error(recurse.state.status) + ? recurse.state.status + : F_status_is_error(status) + ? status + : F_yes; } -#endif // _di_kt_remove_operate_file_directory_recurse_action_ +#endif // _di_kt_remove_operate_file_recurse_ -#ifndef _di_kt_remove_operate_file_directory_recurse_handle_ - void kt_remove_operate_file_directory_recurse_handle(void * const void_recurse, const f_string_static_t name, const uint16_t flag) { +#ifndef _di_kt_remove_operate_file_recurse_action_ + void kt_remove_operate_file_recurse_action(f_directory_recurse_do_t * const recurse, const f_string_static_t name, const uint16_t flag) { - if (!void_recurse) return; + if (!recurse || !recurse->state.custom || F_status_set_fine(recurse->state.status) == F_interrupt) return; + if (!kt_remove_operate_shall_remove(recurse->state.code) || !(flag & f_directory_recurse_do_flag_action_e)) return; - f_directory_recurse_do_t * const recurse = (f_directory_recurse_do_t *) void_recurse; + recurse->state.status = kt_remove_operate_file_remove((kt_remove_main_t *) recurse->state.custom, name, recurse->state.code); + } +#endif // _di_kt_remove_operate_file_recurse_action_ - // Do not print any errors on interrupts. - if (F_status_set_fine(recurse->state.status) == F_interrupt) return; +#ifndef _di_kt_remove_operate_file_recurse_handle_ + void kt_remove_operate_file_recurse_handle(f_directory_recurse_do_t * const recurse, const f_string_static_t name, const uint16_t flag) { - if (!recurse->state.custom) return; + if (!recurse || !recurse->state.custom || F_status_set_fine(recurse->state.status) == F_interrupt) return; kt_remove_main_t * const main = (kt_remove_main_t *) recurse->state.custom; - if (!main) return; + // @todo print error messages // Arguments to fl_recurse_do() are invalid (parameter checking). if (flag == f_directory_recurse_do_flag_top_e) { - // @todo print error message. - return; } // The top-level path is an empty string or an error occurred while processing the top-level path. if (flag == (f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e)) { - // @todo print error message. // @todo note that F_directory_not (with error bit) is returned if the top-level path is not a directory. return; @@ -135,7 +93,6 @@ extern "C" { // The top-level path is an empty string or an error occurred while processing the top-level path. if (flag == (f_directory_recurse_do_flag_top_e | f_directory_recurse_do_flag_path_e | f_directory_recurse_do_flag_before_e)) { - // @todo print error message. // @todo note that F_directory_not (with error bit) is returned if the top-level path does not exist. return; @@ -143,391 +100,51 @@ extern "C" { // An error happened during directory list loading. if (flag == (f_directory_recurse_do_flag_list_e | f_directory_recurse_do_flag_path_e)) { - // @todo print error message. - return; } - - main->setting.state.status = recurse->state.status; - //kt_remove_print_error_recursion_max(&main->program.error); // recurse->state.code is the top-level operate flag. //kt_remove_print_error_operate_file_directory_recurse(&main->program.error, macro_fake_f(fl_directory_do), flag_operate, *recurse->path_top, recurse->path_cache, f_file_operation_delete_s, F_true); } -#endif // _di_kt_remove_operate_file_directory_recurse_handle_ +#endif // _di_kt_remove_operate_file_recurse_handle_ -#ifndef _di_kt_remove_operate_file_normal_ - void kt_remove_operate_file_normal(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate) { +#ifndef _di_kt_remove_operate_file_remove_normal_ + f_status_t kt_remove_operate_file_remove(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate) { - if (!kt_remove_operate_shall_remove(flag_operate)) { - main->setting.state.status = (flag_operate & kt_remove_flag_file_operate_remove_fail_d) ? F_status_set_error(F_no) : F_no; + if (!main) return F_status_set_error(F_parameter); + if (!kt_remove_operate_shall_remove(flag_operate)) return (flag_operate & kt_remove_flag_file_operate_remove_fail_d) ? F_status_set_error(F_no) : F_no; - return; - } + f_status_t status = F_no; - // @todo consider providing a "follow deep" parameter for recursively following until a non-link is reached. if (flag_operate & kt_remove_flag_file_operate_follow_d) { main->cache.buffer.used = 0; - main->setting.state.status = f_file_link_read(path, F_false, &main->cache.buffer); - - if (F_status_is_error(main->setting.state.status)) { - kt_remove_print_error_file(&main->program.error, macro_kt_remove_f(f_file_remove), path, f_file_operation_stat_s, fll_error_file_type_link_e); - - return; - } - - main->setting.state.status = f_file_remove(main->cache.buffer); - - if (F_status_is_error(main->setting.state.status)) { - kt_remove_print_error_file(&main->program.error, macro_kt_remove_f(f_file_remove), main->cache.buffer, f_file_operation_delete_s, fll_error_file_type_file_e); - - return; - } - } - else { - main->setting.state.status = f_file_remove(path); - - if (F_status_is_error(main->setting.state.status)) { - kt_remove_print_error_file(&main->program.error, macro_kt_remove_f(f_file_remove), path, f_file_operation_delete_s, fll_error_file_type_file_e); - - return; - } - } - - main->setting.state.status = F_yes; - } -#endif // _di_kt_remove_operate_file_normal_ - -#ifndef _di_kt_remove_operate_file_preprocess_ - uint16_t kt_remove_operate_file_preprocess(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate) { - - if (!main) return 0; - - if (!path.used) { - main->setting.state.status = F_data_not; - - return 0; - } - - if (kt_remove_signal_check(main)) return 0; - - kt_remove_print_simulate_operate_file(&main->program.output, path); - - main->setting.state.status = f_file_exists(path, main->setting.flag & kt_remove_main_flag_follow_d); - - uint16_t flag_out = (main->setting.flag & kt_remove_main_flag_option_used_d) ? 0 : kt_remove_flag_file_operate_remove_d; - - if (main->setting.state.status == F_true) { - const f_status_t status = f_file_is(path, F_file_type_link_d, F_false); + status = f_file_link_read(path, F_false, &main->cache.buffer); if (F_status_is_error(status)) { - main->setting.state.status = status; - - if (!(main->setting.flag & kt_remove_main_flag_simulate_d)) { - remove_print_warning_file_reason(&main->program.warning, path, kt_remove_print_reason_stat_fail_s); - } - - return 0; - } - - if (status == F_true) { - flag_out |= kt_remove_flag_file_operate_link_d; - } - } - - kt_remove_print_simulate_operate_file_exists(&main->program.output, path, flag_out); - - if (main->setting.state.status == F_false) { - if (!(main->setting.flag & kt_remove_main_flag_simulate_d)) { - remove_print_warning_file_reason(&main->program.warning, path, kt_remove_print_reason_not_found_s); - } - - return 0; - } - - if (F_status_is_error(main->setting.state.status)) { - if (!(main->setting.flag & kt_remove_main_flag_simulate_d)) { - remove_print_warning_file_reason(&main->program.warning, path, kt_remove_print_reason_no_access_s); - } - - return 0; - } - - if (main->setting.state.status == F_false) { - kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_remove_s, F_false); - - return 0; - } - - if (kt_remove_signal_check(main)) return 0; - - f_number_unsigned_t i = 0; - - if (main->setting.flag & kt_remove_main_flag_follow_d) { - flag_out |= kt_remove_flag_file_operate_follow_d; - } - - struct stat statistics; - - memset(&statistics, 0, sizeof(struct stat)); - - main->setting.state.status = f_file_stat(path, main->setting.flag & kt_remove_main_flag_follow_d, &statistics); - - kt_remove_print_simulate_operate_file_stat(&main->program.output, statistics); - - if (F_status_is_error(main->setting.state.status)) { - if (!(main->setting.flag & kt_remove_main_flag_simulate_d)) { - remove_print_warning_file_reason(&main->program.warning, path, kt_remove_print_reason_stat_fail_s); - } - - return flag_out; - } - - if (main->setting.flag & kt_remove_main_flag_block_d) { - if (macro_f_file_type_is_block(statistics.st_mode)) { - flag_out |= kt_remove_flag_file_operate_remove_d; - } - } - - if (main->setting.flag & kt_remove_main_flag_character_d) { - if (macro_f_file_type_is_character(statistics.st_mode)) { - flag_out |= kt_remove_flag_file_operate_remove_d; - } - } - - if (macro_f_file_type_is_directory(statistics.st_mode)) { - flag_out |= kt_remove_flag_file_operate_directory_d; - - if (main->setting.flag & kt_remove_main_flag_directory_d) { - flag_out |= kt_remove_flag_file_operate_remove_d; - } - } - - if (main->setting.flag & kt_remove_main_flag_fifo_d) { - if (macro_f_file_type_is_fifo(statistics.st_mode)) { - flag_out |= kt_remove_flag_file_operate_remove_d; - } - } - - if (main->setting.flag & kt_remove_main_flag_link_d) { - if (macro_f_file_type_is_link(statistics.st_mode)) { - flag_out |= kt_remove_flag_file_operate_remove_d; - } - } - - if (main->setting.flag & kt_remove_main_flag_regular_d) { - if (macro_f_file_type_is_regular(statistics.st_mode)) { - flag_out |= kt_remove_flag_file_operate_remove_d; - } - } - - if (main->setting.flag & kt_remove_main_flag_socket_d) { - if (macro_f_file_type_is_socket(statistics.st_mode)) { - flag_out |= kt_remove_flag_file_operate_remove_d; - } - } - - if (main->setting.flag & kt_remove_main_flag_user_d) { - for (i = 0; i < main->setting.users.used; ++i) { - - if (kt_remove_signal_check(main)) return flag_out; - if (statistics.st_uid == (uid_t) main->setting.users.array[i]) break; - } // for - - if (i < main->setting.users.used) { - flag_out |= kt_remove_flag_file_operate_remove_d; - } - } - - if (main->setting.flag & kt_remove_main_flag_same_d) { - if (statistics.st_uid != geteuid()) { - flag_out |= kt_remove_flag_file_operate_remove_d; - } - } - - if (main->setting.flag & kt_remove_main_flag_different_d) { - if (statistics.st_uid == geteuid()) { - flag_out |= kt_remove_flag_file_operate_remove_d; - } - } - - if (main->setting.flag & kt_remove_main_flag_group_d) { - for (i = 0; i < main->setting.groups.used; ++i) { - - if (kt_remove_signal_check(main)) return flag_out; - if (statistics.st_gid == (gid_t) main->setting.groups.array[i]) break; - } // for - - if (i < main->setting.groups.used) { - flag_out |= kt_remove_flag_file_operate_remove_d; - } - } - - if (main->setting.flag & kt_remove_main_flag_mode_d) { - const mode_t mode = statistics.st_mode & F_file_mode_all_d; - - for (i = 0; i < main->setting.modes.used; ++i) { - - if (kt_remove_signal_check(main)) return flag_out; - - if (main->setting.modes.array[i].type == kt_remove_flag_mode_different_d) { - if (main->setting.modes.array[i].mode & ~mode) break; - } - else if (main->setting.modes.array[i].type == kt_remove_flag_mode_same_d) { - if (main->setting.modes.array[i].mode == mode) break; - } - else if (main->setting.modes.array[i].type == kt_remove_flag_mode_similar_d) { - if (main->setting.modes.array[i].mode & mode) break; - } - else if (main->setting.modes.array[i].type == kt_remove_flag_mode_not_d) { - if (main->setting.modes.array[i].mode != mode) break; - } - } // for - - if (i < main->setting.modes.used) { - flag_out |= kt_remove_flag_file_operate_remove_d; - } - } - - if (flag_out & kt_remove_flag_file_operate_directory_d) { - flag_out |= kt_remove_flag_file_operate_recurse_d; - - main->setting.state.status = f_directory_empty(path); - if (F_status_is_error(main->setting.state.status)) return flag_out; - - if (main->setting.state.status) { - flag_out |= kt_remove_flag_file_operate_empty_d; - } - - if (main->setting.flag & kt_remove_main_flag_empty_all_d) { - if (main->setting.state.status) { - if (main->setting.flag & kt_remove_main_flag_empty_not_fail_d) { - flag_out |= kt_remove_flag_file_operate_remove_fail_d; - } - else if (main->setting.flag & kt_remove_main_flag_empty_not_d) { - flag_out |= kt_remove_flag_file_operate_remove_not_d; - } - } - else { - if (main->setting.flag & kt_remove_main_flag_empty_only_fail_d) { - flag_out |= kt_remove_flag_file_operate_remove_fail_d; - } - else if (main->setting.flag & kt_remove_main_flag_empty_only_d || !(main->setting.flag & kt_remove_main_flag_recurse_d)) { - flag_out |= kt_remove_flag_file_operate_remove_not_d; - } - } - } - else if (!main->setting.state.status) { - if (!(main->setting.flag & kt_remove_main_flag_recurse_d)) { - flag_out |= kt_remove_flag_file_operate_remove_not_d; - } - } - } - - if (main->setting.flag & kt_remove_main_flag_force_d) { - kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_force_s, F_true); - - flag_out |= kt_remove_flag_file_operate_remove_d; - } - - if (flag_out & kt_remove_flag_file_operate_directory_d) { - kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_recurse_s, (main->setting.flag & kt_remove_main_flag_recurse_d) && !(flag_operate & kt_remove_flag_file_operate_parent_d)); - } + kt_remove_print_error_file(&main->program.error, macro_kt_remove_f(f_file_remove), path, f_file_operation_stat_s, fll_error_file_type_link_e); - if (main->setting.flag & kt_remove_main_flag_prompt_all_d) { - if (main->setting.flag & (kt_remove_main_flag_prompt_each_d | kt_remove_main_flag_prompt_never_d)) { - kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_prompt_s, main->setting.flag & kt_remove_main_flag_prompt_each_d); - } - else if (main->setting.flag & kt_remove_main_flag_prompt_follow_d) { - kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_prompt_s, (main->setting.flag & kt_remove_main_flag_follow_d) && (flag_out & kt_remove_flag_file_operate_link_d)); - } - else { - kt_remove_print_simulate_operate_prompt_once(&main->program.output, main->setting.files.used > 2 || main->setting.flag & kt_remove_main_flag_recurse_d); + return status; } } - kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_remove_s, kt_remove_operate_shall_remove(flag_out)); - - if (main->setting.process_operate_file_simulate) { - main->setting.state.status = F_okay; - - main->setting.process_operate_file_simulate(main, path, statistics, flag_operate, &flag_out); - if (F_status_is_error(main->setting.state.status)) return flag_out; - - if (main->setting.state.status == F_done) { - main->setting.state.status = F_okay; + status = (flag_operate & f_directory_recurse_do_flag_directory_e) + ? f_directory_remove((flag_operate & kt_remove_flag_file_operate_follow_d) ? main->cache.buffer : path, 0, F_false) + : f_file_remove((flag_operate & kt_remove_flag_file_operate_follow_d) ? main->cache.buffer : path); - return flag_out; - } + if (F_status_is_error(status)) { + kt_remove_print_error_file(&main->program.error, macro_kt_remove_f(f_file_remove), (flag_operate & kt_remove_flag_file_operate_follow_d) ? main->cache.buffer : path, f_file_operation_delete_s, fll_error_file_type_file_e); } - - // At this point, the remove situation should be known so recurse into parent or child paths as appropriate before returning. - if (flag_out & kt_remove_flag_file_operate_directory_d) { - main->setting.state.status = F_okay; - - if (main->setting.flag & kt_remove_main_flag_tree_d) { - f_range_t range = macro_f_range_t_initialize_2(path.used); - - if (range.stop > range.start) { - main->setting.state.status = f_string_dynamic_seek_to_back(path, f_string_ascii_slash_forward_s.string[0], &range); - - if (F_status_is_error_not(main->setting.state.status) && F_status_set_fine(main->setting.state.status) == F_okay && range.stop > range.start) { - --range.stop; - - for (i = 0; i < main->cache.tree.used; ++i) { - if (f_compare_dynamic_partial_dynamic(main->cache.tree.array[i], path, range) == F_equal_to) break; - } // for - - if (i == main->cache.tree.used) { - main->setting.state.status = f_memory_array_increase(kt_remove_allocation_small_d, sizeof(f_string_dynamic_t), (void **) &main->cache.tree.array, &main->cache.tree.used, &main->cache.tree.size); - - if (F_status_is_error(main->setting.state.status)) { - kt_remove_print_error(&main->program.error, macro_kt_remove_f(f_memory_array_increase)); - - return flag_out; - } - - main->cache.tree.array[main->cache.tree.used].used = 0; - - main->setting.state.status = f_string_dynamic_partial_append(path, range, &main->cache.tree.array[main->cache.tree.used]); - - if (F_status_is_error(main->setting.state.status)) { - kt_remove_print_error(&main->program.error, macro_kt_remove_f(f_string_dynamic_partial_append)); - - return flag_out; - } - - ++main->cache.tree.used; - - f_print_dynamic(f_string_eol_s, main->program.output.to); - - kt_remove_operate_file_preprocess(main, main->cache.tree.array[main->cache.tree.used - 1], kt_remove_flag_file_operate_parent_d); - } - } - else if (F_status_is_error(main->setting.state.status)) { - kt_remove_print_error_file(&main->program.error, macro_kt_remove_f(f_string_dynamic_seek_to_back), path, f_file_operation_process_s, fll_error_file_type_path_e); - - return flag_out; - } - } - } - - if (!(flag_operate & kt_remove_flag_file_operate_parent_d)) { - const uint16_t flag_child = kt_remove_flag_file_operate_child_d; - - // @todo call this function on every child path, but this is not the kt_remove_operate_file_directory_recurse_action() call. - } + else { + status = F_yes; } - main->setting.state.status = F_okay; - - return flag_out; + return status; } -#endif // _di_kt_remove_operate_file_preprocess_ +#endif // _di_kt_remove_operate_file_remove_normal_ #ifndef _di_kt_remove_operate_shall_remove_ f_status_t kt_remove_operate_shall_remove(const uint16_t flag) { diff --git a/sources/c/program/kevux/tools/remove/main/operate.h b/sources/c/program/kevux/tools/remove/main/operate.h index e29191b..a3c6036 100644 --- a/sources/c/program/kevux/tools/remove/main/operate.h +++ b/sources/c/program/kevux/tools/remove/main/operate.h @@ -29,9 +29,10 @@ extern "C" { * * Errors (with error bit) from: f_string_dynamic_append(). * - * Errors (with error bit) from: kt_remove_operate_file_directory(). - * Errors (with error bit) from: kt_remove_operate_file_normal(). - * Errors (with error bit) from: kt_remove_operate_file_preprocess(). + * Errors (with error bit) from: kt_remove_operate_file_recurse(). + * Errors (with error bit) from: kt_remove_operate_file_remove_delete(). + * Errors (with error bit) from: kt_remove_operate_file_remove(). + * Errors (with error bit) from: kt_remove_preprocess_file(). * @param path * The path to the file to operate on. * @@ -41,9 +42,10 @@ extern "C" { * * @see f_string_dynamic_append() * - * @see kt_remove_operate_file_directory() - * @see kt_remove_operate_file_normal() - * @see kt_remove_operate_file_preprocess() + * @see kt_remove_operate_file_recurse() + * @see kt_remove_operate_file_remove_delete() + * @see kt_remove_operate_file_remove() + * @see kt_remove_preprocess_file() */ #ifndef _di_kt_remove_operate_file_ extern void kt_remove_operate_file(kt_remove_main_t * const main, const f_string_static_t path); @@ -57,25 +59,30 @@ extern "C" { * * Must not be NULL. * - * This alters main.setting.state.status: - * F_yes on success and file remove. - * F_no on success and file not removed. - * F_data_not on success but path is an empty string. - * - * F_no (with error bit) on failure and file is not to be removed or cannot be removed. - * F_recurse (with error bit) on max recursion depth reached. - * - * Errors (with error bit) from: f_file_remove(). + * This does not directly alter main.setting.state.status. * @param path * The path to the file to operate on. * @param flag_operate * The operate file specific flags from kt_remove_flag_file_operate_*_e. * + * @return + * F_yes on success and file remove. + * F_no on success and file not removed. + * F_data_not on success but path is an empty string. + * + * F_no (with error bit) on failure and file is not to be removed or cannot be removed. + * F_recurse (with error bit) on max recursion depth reached. + * + * Errors (with error bit) from: f_directory_recurse_do_delete() + * Errors (with error bit) from: fl_directory_do() + * + * @see f_directory_recurse_do_delete() * @see f_file_remove() + * @see fl_directory_do() */ -#ifndef _di_kt_remove_operate_file_directory_ - extern void kt_remove_operate_file_directory(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate); -#endif // _di_kt_remove_operate_file_directory_ +#ifndef _di_kt_remove_operate_file_recurse_ + extern f_status_t kt_remove_operate_file_recurse(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate); +#endif // _di_kt_remove_operate_file_recurse_ /** * Perform directory recurse for a single file operation action. @@ -84,7 +91,6 @@ extern "C" { * The directory recurse data. * * Must not be NULL. - * Must be of type f_directory_recurse_do_t. * @param name * The name of the file or directory the action is being performed on. * Does not have the parent directory path. @@ -95,9 +101,9 @@ extern "C" { * @see f_directory_remove() * @see fl_directory_do() */ -#ifndef _di_kt_remove_operate_file_directory_recurse_action_ - extern void kt_remove_operate_file_directory_recurse_action(void * const recurse, const f_string_static_t name, const uint16_t flag); -#endif // _di_kt_remove_operate_file_directory_recurse_action_ +#ifndef _di_kt_remove_operate_file_recurse_action_ + extern void kt_remove_operate_file_recurse_action(f_directory_recurse_do_t * const recurse, const f_string_static_t name, const uint16_t flag); +#endif // _di_kt_remove_operate_file_recurse_action_ /** * Handle errors while performing directory recurse for a single file operation action. @@ -106,7 +112,6 @@ extern "C" { * The directory recurse data. * * Must not be NULL. - * Must be of type f_directory_recurse_do_t. * @param name * The name of the file or directory the action is being performed on. * Does not have the parent directory path. @@ -116,66 +121,41 @@ extern "C" { * * @see fl_directory_do() */ -#ifndef _di_kt_remove_operate_file_directory_recurse_handle_ - extern void kt_remove_operate_file_directory_recurse_handle(void * const recurse, const f_string_static_t name, const uint16_t flag); -#endif // _di_kt_remove_operate_file_directory_recurse_handle_ +#ifndef _di_kt_remove_operate_file_recurse_handle_ + extern void kt_remove_operate_file_recurse_handle(f_directory_recurse_do_t * const recurse, const f_string_static_t name, const uint16_t flag); +#endif // _di_kt_remove_operate_file_recurse_handle_ /** * Perform actual file removal for non-directory files. * - * @param main - * The main program and settings data. - * - * Must not be NULL. - * - * This alters main.setting.state.status: - * F_no on success but file is not to be removed. - * F_yes on success and file is removed. - * - * F_no (with error bit) on failure and file is not to be removed or cannot be removed. - * - * Errors (with error bit) from: f_file_link_read(). - * Errors (with error bit) from: f_file_remove(). - * @param path - * The path to the file to operate on. - * @param flag_operate - * The operate file specific flags from kt_remove_flag_file_operate_*_e. - * - * @see f_file_link_read() - * @see f_file_remove() - */ -#ifndef _di_kt_remove_operate_file_normal_ - extern void kt_remove_operate_file_normal(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate); -#endif // _di_kt_remove_operate_file_normal_ - -/** - * Perform pre-processing (including simulation) of the file operation. + * This returns status rather than altering the main.setting.state.status so that it can safely be called within recursive functions. * * @param main * The main program and settings data. * * Must not be NULL. * - * This alters main.setting.state.status: - * F_okay on success. - * F_data_not on success but file is an empty string. - * - * Errors (with error bit) from: f_file_link_read(). - * Errors (with error bit) from: f_file_remove(). + * This does not alter main.setting.state.status. * @param path * The path to the file to operate on. * @param flag_operate * The operate file specific flags from kt_remove_flag_file_operate_*_e. * * @return - * The resulting flags determined by the pre-process. + * F_no on success but file is not to be removed. + * F_yes on success and file is removed. + * + * F_no (with error bit) on failure and file is not to be removed or cannot be removed. + * + * Errors (with error bit) from: f_file_link_read(). + * Errors (with error bit) from: f_file_remove(). * * @see f_file_link_read() * @see f_file_remove() */ -#ifndef _di_kt_remove_operate_file_preprocess_ - extern uint16_t kt_remove_operate_file_preprocess(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate); -#endif // _di_kt_remove_operate_file_preprocess_ +#ifndef _di_kt_remove_operate_file_remove_normal_ + extern f_status_t kt_remove_operate_file_remove(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate); +#endif // _di_kt_remove_operate_file_remove_normal_ /** * Determine whether or not a file shall be removed based on the given flag. diff --git a/sources/c/program/kevux/tools/remove/main/preprocess.c b/sources/c/program/kevux/tools/remove/main/preprocess.c new file mode 100644 index 0000000..b0cb627 --- /dev/null +++ b/sources/c/program/kevux/tools/remove/main/preprocess.c @@ -0,0 +1,376 @@ +#include "remove.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_kt_remove_preprocess_file_ + uint16_t kt_remove_preprocess_file(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate) { + + if (!main) return 0; + + if (!path.used) { + main->setting.state.status = F_data_not; + + return 0; + } + + if (kt_remove_signal_check(main)) return 0; + + kt_remove_print_simulate_operate_file(&main->program.output, path); + + main->setting.state.status = f_file_exists(path, main->setting.flag & kt_remove_main_flag_follow_d); + + uint16_t flag_out = (main->setting.flag & kt_remove_main_flag_option_used_d) ? 0 : kt_remove_flag_file_operate_remove_d; + + if (main->setting.state.status == F_true) { + const f_status_t status = f_file_is(path, F_file_type_link_d, F_false); + + if (F_status_is_error(status)) { + main->setting.state.status = status; + + if (!(main->setting.flag & kt_remove_main_flag_simulate_d)) { + remove_print_warning_file_reason(&main->program.warning, path, kt_remove_print_reason_stat_fail_s); + } + + return 0; + } + + if (status == F_true) { + flag_out |= kt_remove_flag_file_operate_link_d; + } + } + + kt_remove_print_simulate_operate_file_exists(&main->program.output, path, flag_out); + + if (main->setting.state.status == F_false) { + if (!(main->setting.flag & kt_remove_main_flag_simulate_d)) { + remove_print_warning_file_reason(&main->program.warning, path, kt_remove_print_reason_not_found_s); + } + + return 0; + } + + if (F_status_is_error(main->setting.state.status)) { + if (!(main->setting.flag & kt_remove_main_flag_simulate_d)) { + remove_print_warning_file_reason(&main->program.warning, path, kt_remove_print_reason_no_access_s); + } + + return 0; + } + + if (main->setting.state.status == F_false) { + kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_remove_s, F_false); + + return 0; + } + + if (kt_remove_signal_check(main)) return 0; + + if (main->setting.flag & kt_remove_main_flag_follow_d) { + flag_out |= kt_remove_flag_file_operate_follow_d; + } + + f_number_unsigned_t i = 0; + + struct stat statistics; + + memset(&statistics, 0, sizeof(struct stat)); + + main->setting.state.status = f_file_stat(path, main->setting.flag & kt_remove_main_flag_follow_d, &statistics); + + kt_remove_print_simulate_operate_file_stat(&main->program.output, statistics); + + if (F_status_is_error(main->setting.state.status)) { + if (!(main->setting.flag & kt_remove_main_flag_simulate_d)) { + remove_print_warning_file_reason(&main->program.warning, path, kt_remove_print_reason_stat_fail_s); + } + + return flag_out; + } + + if (main->setting.flag & kt_remove_main_flag_block_d) { + if (macro_f_file_type_is_block(statistics.st_mode)) { + flag_out |= kt_remove_flag_file_operate_remove_d; + } + } + + if (main->setting.flag & kt_remove_main_flag_character_d) { + if (macro_f_file_type_is_character(statistics.st_mode)) { + flag_out |= kt_remove_flag_file_operate_remove_d; + } + } + + if (macro_f_file_type_is_directory(statistics.st_mode)) { + flag_out |= kt_remove_flag_file_operate_directory_d; + + if (main->setting.flag & kt_remove_main_flag_directory_d) { + flag_out |= kt_remove_flag_file_operate_remove_d; + } + } + + if (main->setting.flag & kt_remove_main_flag_fifo_d) { + if (macro_f_file_type_is_fifo(statistics.st_mode)) { + flag_out |= kt_remove_flag_file_operate_remove_d; + } + } + + if (main->setting.flag & kt_remove_main_flag_link_d) { + if (macro_f_file_type_is_link(statistics.st_mode)) { + flag_out |= kt_remove_flag_file_operate_remove_d; + } + } + + if (main->setting.flag & kt_remove_main_flag_regular_d) { + if (macro_f_file_type_is_regular(statistics.st_mode)) { + flag_out |= kt_remove_flag_file_operate_remove_d; + } + } + + if (main->setting.flag & kt_remove_main_flag_socket_d) { + if (macro_f_file_type_is_socket(statistics.st_mode)) { + flag_out |= kt_remove_flag_file_operate_remove_d; + } + } + + if (main->setting.flag & kt_remove_main_flag_user_d) { + for (i = 0; i < main->setting.users.used; ++i) { + + if (kt_remove_signal_check(main)) return flag_out; + if (statistics.st_uid == (uid_t) main->setting.users.array[i]) break; + } // for + + if (i < main->setting.users.used) { + flag_out |= kt_remove_flag_file_operate_remove_d; + } + } + + if (main->setting.flag & kt_remove_main_flag_same_d) { + if (statistics.st_uid != geteuid()) { + flag_out |= kt_remove_flag_file_operate_remove_d; + } + } + + if (main->setting.flag & kt_remove_main_flag_different_d) { + if (statistics.st_uid == geteuid()) { + flag_out |= kt_remove_flag_file_operate_remove_d; + } + } + + if (main->setting.flag & kt_remove_main_flag_group_d) { + for (i = 0; i < main->setting.groups.used; ++i) { + + if (kt_remove_signal_check(main)) return flag_out; + if (statistics.st_gid == (gid_t) main->setting.groups.array[i]) break; + } // for + + if (i < main->setting.groups.used) { + flag_out |= kt_remove_flag_file_operate_remove_d; + } + } + + if (main->setting.flag & kt_remove_main_flag_mode_d) { + const mode_t mode = statistics.st_mode & F_file_mode_all_d; + + for (i = 0; i < main->setting.modes.used; ++i) { + + if (kt_remove_signal_check(main)) return flag_out; + + if (main->setting.modes.array[i].type == kt_remove_flag_mode_different_d) { + if (main->setting.modes.array[i].mode & ~mode) break; + } + else if (main->setting.modes.array[i].type == kt_remove_flag_mode_same_d) { + if (main->setting.modes.array[i].mode == mode) break; + } + else if (main->setting.modes.array[i].type == kt_remove_flag_mode_similar_d) { + if (main->setting.modes.array[i].mode & mode) break; + } + else if (main->setting.modes.array[i].type == kt_remove_flag_mode_not_d) { + if (main->setting.modes.array[i].mode != mode) break; + } + } // for + + if (i < main->setting.modes.used) { + flag_out |= kt_remove_flag_file_operate_remove_d; + } + } + + if (flag_out & kt_remove_flag_file_operate_directory_d) { + flag_out |= kt_remove_flag_file_operate_recurse_d; + + main->setting.state.status = f_directory_empty(path); + if (F_status_is_error(main->setting.state.status)) return flag_out; + + if (main->setting.state.status) { + flag_out |= kt_remove_flag_file_operate_empty_d; + } + + if (main->setting.flag & kt_remove_main_flag_empty_all_d) { + if (main->setting.state.status) { + if (main->setting.flag & kt_remove_main_flag_empty_not_fail_d) { + flag_out |= kt_remove_flag_file_operate_remove_fail_d; + } + else if (main->setting.flag & kt_remove_main_flag_empty_not_d) { + flag_out |= kt_remove_flag_file_operate_remove_not_d; + } + } + else { + if (main->setting.flag & kt_remove_main_flag_empty_only_fail_d) { + flag_out |= kt_remove_flag_file_operate_remove_fail_d; + } + else if (main->setting.flag & kt_remove_main_flag_empty_only_d || !(main->setting.flag & kt_remove_main_flag_recurse_d)) { + flag_out |= kt_remove_flag_file_operate_remove_not_d; + } + } + } + else if (!main->setting.state.status) { + if (!(main->setting.flag & kt_remove_main_flag_recurse_d)) { + flag_out |= kt_remove_flag_file_operate_remove_not_d; + } + } + } + + if (main->setting.flag & kt_remove_main_flag_force_d) { + kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_force_s, F_true); + + flag_out |= kt_remove_flag_file_operate_remove_d; + } + + if (flag_out & kt_remove_flag_file_operate_directory_d) { + kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_recurse_s, (main->setting.flag & kt_remove_main_flag_recurse_d) && !(flag_operate & kt_remove_flag_file_operate_parent_d)); + } + + if (main->setting.flag & kt_remove_main_flag_prompt_all_d) { + if (main->setting.flag & (kt_remove_main_flag_prompt_each_d | kt_remove_main_flag_prompt_never_d)) { + kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_prompt_s, main->setting.flag & kt_remove_main_flag_prompt_each_d); + } + else if (main->setting.flag & kt_remove_main_flag_prompt_follow_d) { + kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_prompt_s, (main->setting.flag & kt_remove_main_flag_follow_d) && (flag_out & kt_remove_flag_file_operate_link_d)); + } + else { + kt_remove_print_simulate_operate_prompt_once(&main->program.output, main->setting.files.used > 2 || main->setting.flag & kt_remove_main_flag_recurse_d); + } + } + + kt_remove_print_simulate_operate_boolean(&main->program.output, kt_remove_remove_s, kt_remove_operate_shall_remove(flag_out)); + + if (main->call.process_operate_file_simulate) { + main->setting.state.status = F_okay; + + main->call.process_operate_file_simulate(main, path, statistics, flag_operate, &flag_out); + if (F_status_is_error(main->setting.state.status)) return flag_out; + + if (main->setting.state.status == F_done) { + main->setting.state.status = F_okay; + + return flag_out; + } + } + + // At this point, the remove situation should be known so recurse into parent or child paths as appropriate before returning. + if (flag_out & kt_remove_flag_file_operate_directory_d) { + main->setting.state.status = F_okay; + + if (main->setting.flag & kt_remove_main_flag_tree_d) { + f_range_t range = macro_f_range_t_initialize_2(path.used); + + if (range.stop > range.start) { + main->setting.state.status = f_string_dynamic_seek_to_back(path, f_string_ascii_slash_forward_s.string[0], &range); + + if (F_status_is_error_not(main->setting.state.status) && F_status_set_fine(main->setting.state.status) == F_okay && range.stop > range.start) { + --range.stop; + + for (i = 0; i < main->cache.tree.used; ++i) { + if (f_compare_dynamic_partial_dynamic(main->cache.tree.array[i], path, range) == F_equal_to) break; + } // for + + if (i == main->cache.tree.used) { + main->setting.state.status = f_memory_array_increase(kt_remove_allocation_small_d, sizeof(f_string_dynamic_t), (void **) &main->cache.tree.array, &main->cache.tree.used, &main->cache.tree.size); + + if (F_status_is_error(main->setting.state.status)) { + kt_remove_print_error(&main->program.error, macro_kt_remove_f(f_memory_array_increase)); + + return flag_out; + } + + main->cache.tree.array[main->cache.tree.used].used = 0; + + main->setting.state.status = f_string_dynamic_partial_append(path, range, &main->cache.tree.array[main->cache.tree.used]); + + if (F_status_is_error(main->setting.state.status)) { + kt_remove_print_error(&main->program.error, macro_kt_remove_f(f_string_dynamic_partial_append)); + + return flag_out; + } + + ++main->cache.tree.used; + + f_print_dynamic(f_string_eol_s, main->program.output.to); + + kt_remove_preprocess_file(main, main->cache.tree.array[main->cache.tree.used - 1], kt_remove_flag_file_operate_parent_d); + } + } + else if (F_status_is_error(main->setting.state.status)) { + kt_remove_print_error_file(&main->program.error, macro_kt_remove_f(f_string_dynamic_seek_to_back), path, f_file_operation_process_s, fll_error_file_type_path_e); + + return flag_out; + } + } + } + + if (main->setting.flag & kt_remove_main_flag_recurse_d && !(flag_operate & kt_remove_flag_file_operate_parent_d)) { + main->setting.state.status = kt_remove_preprocess_file_recurse(main, path, flag_out | kt_remove_flag_file_operate_child_d); + } + } + + if (F_status_is_error_not(main->setting.state.status)) { + main->setting.state.status = F_okay; + } + + return flag_out; + } +#endif // _di_kt_remove_preprocess_file_ + +#ifndef _di_kt_remove_preprocess_file_recurse_ + f_status_t kt_remove_preprocess_file_recurse(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate) { + + if (!kt_remove_operate_shall_remove(flag_operate)) return (flag_operate & kt_remove_flag_file_operate_remove_fail_d) ? F_status_set_error(F_no) : F_no; + + f_directory_recurse_do_t recurse = f_directory_recurse_do_t_initialize; + + recurse.state.custom = (void *) main; + recurse.state.code = flag_operate; + recurse.state.interrupt = &kt_remove_signal_check_recurse; + + recurse.flag = f_directory_recurse_do_flag_list_e; + recurse.depth_max = kt_remove_depth_max_d; + + recurse.action = &kt_remove_preprocess_file_recurse_action; + recurse.handle = &kt_remove_operate_file_recurse_handle; + + fl_directory_do(path, &recurse); + + const f_status_t status = f_directory_recurse_do_delete(&recurse); + + return F_status_is_error(recurse.state.status) + ? recurse.state.status + : F_status_is_error(status) + ? status + : F_yes; + } +#endif // _di_kt_remove_preprocess_file_recurse_ + +#ifndef _di_kt_remove_preprocess_file_recurse_action_ + void kt_remove_preprocess_file_recurse_action(f_directory_recurse_do_t * const recurse, const f_string_static_t name, const uint16_t flag) { + + if (!recurse || !recurse->state.custom || F_status_set_fine(recurse->state.status) == F_interrupt) return; + + if (flag & f_directory_recurse_do_flag_action_e) { + kt_remove_preprocess_file((kt_remove_main_t *) recurse->state.custom, name, recurse->state.code); + } + } +#endif // _di_kt_remove_preprocess_file_recurse_action_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/program/kevux/tools/remove/main/preprocess.h b/sources/c/program/kevux/tools/remove/main/preprocess.h new file mode 100644 index 0000000..acd81af --- /dev/null +++ b/sources/c/program/kevux/tools/remove/main/preprocess.h @@ -0,0 +1,102 @@ +/** + * Kevux Tools - Remove + * + * Project: Kevux Tools + * API Version: 0.5 + * Licenses: lgpl-2.1-or-later + */ +#ifndef _kt_remove_main_preprocess_h +#define _kt_remove_main_preprocess_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Perform pre-processing (including simulation) of the file operation. + * + * @param main + * The main program and settings data. + * + * Must not be NULL. + * + * This alters main.setting.state.status: + * F_okay on success. + * F_data_not on success but file is an empty string. + * + * Errors (with error bit) from: f_file_link_read(). + * Errors (with error bit) from: f_file_remove(). + * @param path + * The path to the file to operate on. + * @param flag_operate + * The operate file specific flags from kt_remove_flag_file_operate_*_e. + * + * @return + * The resulting flags determined by the pre-process. + * + * @see f_file_link_read() + * @see f_file_remove() + */ +#ifndef _di_kt_remove_preprocess_file_ + extern uint16_t kt_remove_preprocess_file(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate); +#endif // _di_kt_remove_preprocess_file_ + +/** + * Perform actual file removal for directory files. + * + * @param main + * The main program and settings data. + * + * Must not be NULL. + * + * This does not directly alter main.setting.state.status. + * @param path + * The path to the file to operate on. + * @param flag_operate + * The operate file specific flags from kt_remove_flag_file_operate_*_e. + * + * @return + * F_yes on success and file remove. + * F_no on success and file not removed. + * F_data_not on success but path is an empty string. + * + * F_no (with error bit) on failure and file is not to be removed or cannot be removed. + * F_recurse (with error bit) on max recursion depth reached. + * + * Errors (with error bit) from: f_directory_recurse_do_delete() + * Errors (with error bit) from: fl_directory_do() + * + * @see f_directory_recurse_do_delete() + * @see f_file_remove() + * @see fl_directory_do() + */ +#ifndef _di_kt_remove_preprocess_file_recurse_ + extern f_status_t kt_remove_preprocess_file_recurse(kt_remove_main_t * const main, const f_string_static_t path, const uint16_t flag_operate); +#endif // _di_kt_remove_preprocess_file_recurse_ + +/** + * Perform directory recursion for a single file operation action. + * + * @param recurse + * The directory recurse data. + * + * Must not be NULL. + * @param name + * The name of the file or directory the action is being performed on. + * Does not have the parent directory path. + * May be empty at the top level. + * @param flag + * A flag representing the particular directory action being performed. + * + * @see f_directory_remove() + * @see fl_directory_do() + */ +#ifndef _di_kt_remove_preprocess_file_recurse_action_ + extern void kt_remove_preprocess_file_recurse_action(f_directory_recurse_do_t * const recurse, const f_string_static_t name, const uint16_t flag); +#endif // _di_kt_remove_preprocess_file_recurse_action_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _kt_remove_main_preprocess_h diff --git a/sources/c/program/kevux/tools/remove/main/print/error.c b/sources/c/program/kevux/tools/remove/main/print/error.c index d625de2..a72a929 100644 --- a/sources/c/program/kevux/tools/remove/main/print/error.c +++ b/sources/c/program/kevux/tools/remove/main/print/error.c @@ -75,7 +75,7 @@ extern "C" { f_file_stream_lock(print->to); fl_print_format("%[%QMax recursion of", print->to, print->set->error, print->prefix, print->set->error, f_string_eol_s); - fl_print_format("%[%ul%]", print->to, print->set->notable, main->setting.recurse.depth_max, print->set->notable); + fl_print_format("%[%ul%]", print->to, print->set->notable, kt_remove_depth_max_d, print->set->notable); fl_print_format(" at '%[%Q%]'.%]%r", print->to, print->set->notable, path, print->set->notable, f_string_eol_s); f_file_stream_unlock(print->to); diff --git a/sources/c/program/kevux/tools/remove/main/remove.c b/sources/c/program/kevux/tools/remove/main/remove.c index df0546c..3bea4f9 100644 --- a/sources/c/program/kevux/tools/remove/main/remove.c +++ b/sources/c/program/kevux/tools/remove/main/remove.c @@ -13,8 +13,8 @@ extern "C" { if (main->setting.flag & kt_remove_main_flag_version_copyright_help_d) { if (main->setting.flag & kt_remove_main_flag_help_d) { - if (main->setting.print_help) { - main->setting.print_help(&main->program.output, main->program.context); + if (main->call.print_help) { + main->call.print_help(&main->program.output, main->program.context); } } else if (main->setting.flag & kt_remove_main_flag_version_d) { @@ -31,8 +31,8 @@ extern "C" { return; } - if (main->setting.process_normal) { - main->setting.process_normal(main); + if (main->call.process_normal) { + main->call.process_normal(main); } if (kt_remove_signal_check(main)) { diff --git a/sources/c/program/kevux/tools/remove/main/remove.h b/sources/c/program/kevux/tools/remove/main/remove.h index c2da234..fd8f6ba 100644 --- a/sources/c/program/kevux/tools/remove/main/remove.h +++ b/sources/c/program/kevux/tools/remove/main/remove.h @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include diff --git a/sources/c/program/kevux/tools/remove/main/signal.c b/sources/c/program/kevux/tools/remove/main/signal.c index 65d1595..805d7c4 100644 --- a/sources/c/program/kevux/tools/remove/main/signal.c +++ b/sources/c/program/kevux/tools/remove/main/signal.c @@ -39,6 +39,21 @@ extern "C" { } #endif // !defined(_di_kt_remove_signal_check_) && !defined(_di_thread_support_) +#ifndef _di_kt_remove_signal_check_recurse_ + void kt_remove_signal_check_recurse(f_state_t * const state, void * const internal) { + + if (!state || !internal) return; + + f_directory_recurse_do_t * const recurse = (f_directory_recurse_do_t *) internal; + + if (!recurse->state.custom) return; + + if (kt_remove_signal_check((kt_remove_main_t *) recurse->state.custom)) { + recurse->state.status = F_status_set_error(F_interrupt); + } + } +#endif // _di_kt_remove_signal_check_recurse_ + #if !defined(_di_kt_remove_signal_handler_) && !defined(_di_thread_support_) void kt_remove_signal_handler(kt_remove_main_t * const main) { diff --git a/sources/c/program/kevux/tools/remove/main/signal.h b/sources/c/program/kevux/tools/remove/main/signal.h index 884c584..77be44c 100644 --- a/sources/c/program/kevux/tools/remove/main/signal.h +++ b/sources/c/program/kevux/tools/remove/main/signal.h @@ -47,6 +47,33 @@ extern "C" { #endif // _di_kt_remove_signal_check_ /** + * Check to see if a signal is received, for a recursive directory function. + * + * This is intended to be passed as a state.interrupt function for use in the fl_directory_do() recursion process. + * + * @param state + * The state data. + * + * Must not be NULL. + * + * This does not directly alter state.status. + * @param internal + * The directory recurse data. + * + * Must not be NULL. + * + * Must be of type f_directory_recurse_do_t. + * + * This alters recurse.state.status: + * F_interrupt (with error bit) on interrupt signal received. + * + * @see kt_remove_signal_check() + */ +#ifndef _di_kt_remove_signal_check_recurse_ + extern void kt_remove_signal_check_recurse(f_state_t * const state, void * const internal); +#endif // _di_kt_remove_signal_check_recurse_ + +/** * Signal handler for signals/interrupts. * * This blocks until an expected signal is recieved. diff --git a/sources/c/program/kevux/tools/remove/remove/main.c b/sources/c/program/kevux/tools/remove/remove/main.c index a0ab500..751df4e 100644 --- a/sources/c/program/kevux/tools/remove/remove/main.c +++ b/sources/c/program/kevux/tools/remove/remove/main.c @@ -23,11 +23,9 @@ int main(const int argc, const f_string_t *argv, const f_string_t *envp) { data.setting.state.data = (void *) &data; data.setting.program_name = &kt_remove_program_name_s; data.setting.program_name_long = &kt_remove_program_name_long_s; - data.setting.print_help = &kt_remove_print_message_help; - data.setting.process_normal = &kt_remove_process_normal_operate; - data.setting.recurse.action = &kt_remove_operate_file_directory_recurse_action; - data.setting.recurse.handle = &kt_remove_operate_file_directory_recurse_handle; - data.setting.recurse.depth_max = kt_remove_depth_max_d; + + data.call.print_help = &kt_remove_print_message_help; + data.call.process_normal = &kt_remove_process_normal_operate; #ifdef _en_kt_default_to_utc_ data.setting.flag |= kt_remove_flag_utc_d;