From e4f457869f14813c90a92447f5c93562a928adba Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Wed, 9 Sep 2020 21:39:03 -0500 Subject: [PATCH] Update: rename f_file_move to f_file_rename, add fll_file_move, and address printf(). The move function should operate as a move would expect, which includes cross-filesystem. Rename the f_file_move() to f_file_rename() and ensure the limitations are documented. The fll_file_move() calls f_file_rename() and if that fails due to being across filesystems, then call the appropriate clone and remove functions depending on whether or not the source is a file or directory. I try to avoid having any output strings in the project that is below level 3 (but level 2 may have exceptions). Rewrite parts of the directory copy and clone functions to use passed functions instead of directly printing. Cleanup some function's documentation. --- level_0/f_directory/c/directory.c | 16 +++---- level_0/f_directory/c/directory.h | 16 +++---- level_0/f_file/c/file.c | 12 ++--- level_0/f_file/c/file.h | 34 ++++++-------- level_1/fl_directory/c/directory.c | 48 ++++++++++++-------- level_1/fl_directory/c/directory.h | 56 +++++------------------ level_1/fl_directory/c/private-directory.c | 16 +++++-- level_1/fl_directory/c/private-directory.h | 41 ----------------- level_2/fll_file/c/file.c | 72 +++++++++++++++++++++++++++--- level_2/fll_file/c/file.h | 60 +++++++++++++++++++++++++ level_3/fake/c/private-build.c | 3 +- level_3/fake/c/private-fake.c | 18 ++++++++ level_3/fake/c/private-fake.h | 42 +++++++++++++++++ level_3/fake/c/private-make.c | 20 ++++++--- 14 files changed, 290 insertions(+), 164 deletions(-) diff --git a/level_0/f_directory/c/directory.c b/level_0/f_directory/c/directory.c index 0e34916..a141a1e 100644 --- a/level_0/f_directory/c/directory.c +++ b/level_0/f_directory/c/directory.c @@ -255,15 +255,15 @@ extern "C" { #endif // _di_f_directory_open_at_ #ifndef _di_f_directory_remove_ - f_return_status f_directory_remove(const f_string_t path, const int recursion_max, const bool preserve) { + f_return_status f_directory_remove(const f_string_t path, const int depth_max, const bool preserve) { #ifndef _di_level_0_parameter_checking_ - if (recursion_max < 0) return F_status_set_error(F_parameter); + if (depth_max < 0) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ int result = 0; - if (recursion_max) { - result = nftw(path, private_f_directory_remove_recursively, recursion_max, FTW_DEPTH | FTW_PHYS); + if (depth_max) { + result = nftw(path, private_f_directory_remove_recursively, depth_max, FTW_DEPTH | FTW_PHYS); if (result == 0 && !preserve) { result = remove(path); @@ -302,15 +302,15 @@ extern "C" { #endif // _di_f_directory_remove_ #ifndef _di_f_directory_remove_custom_ - f_return_status f_directory_remove_custom(const f_string_t path, const int recursion_max, const bool preserve, int (*custom) (const char *, const struct stat *, int, struct FTW *)) { + f_return_status f_directory_remove_custom(const f_string_t path, const int depth_max, const bool preserve, int (*custom) (const char *, const struct stat *, int, struct FTW *)) { #ifndef _di_level_0_parameter_checking_ - if (recursion_max < 0) return F_status_set_error(F_parameter); + if (depth_max < 0) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ int result = 0; - if (recursion_max) { - result = nftw(path, custom, recursion_max, FTW_DEPTH | FTW_PHYS); + if (depth_max) { + result = nftw(path, custom, depth_max, FTW_DEPTH | FTW_PHYS); if (result == 0 && !preserve) { result = remove(path); diff --git a/level_0/f_directory/c/directory.h b/level_0/f_directory/c/directory.h index d22f6bb..5af8a0b 100644 --- a/level_0/f_directory/c/directory.h +++ b/level_0/f_directory/c/directory.h @@ -381,13 +381,13 @@ extern "C" { * * @param path * The file path to the directory. - * @param recursion_max + * @param depth_max * Represents the max recursion depth, set to 0 to disable recursive delete. * @param preserve - * When recursion_max > 0, this designates whether or not to preserve the directory at path. + * When depth_max > 0, this designates whether or not to preserve the directory at path. * If TRUE, then only the content within the directory is deleted. * If FALSE, then the directory at path and its content are deleted. - * When recursion_max is 0, then this should only be FALSE (setting this to TRUE would be a no-op). + * When depth_max is 0, then this should only be FALSE (setting this to TRUE would be a no-op). * * @return * F_none on success. @@ -412,7 +412,7 @@ extern "C" { * @see remove() */ #ifndef _di_f_directory_remove_ - extern f_return_status f_directory_remove(const f_string_t path, const int recursion_max, const bool preserve); + extern f_return_status f_directory_remove(const f_string_t path, const int depth_max, const bool preserve); #endif // _di_f_directory_remove_ /** @@ -420,13 +420,13 @@ extern "C" { * * @param path * The file path to the directory. - * @param recursion_max + * @param depth_max * Represents the max recursion depth, set to 0 to disable recursive delete. * @param preserve - * When recursion_max > 0, this designates whether or not to preserve the directory at path. + * When depth_max > 0, this designates whether or not to preserve the directory at path. * If TRUE, then only the content within the directory is deleted. * If FALSE, then the directory at path and its content are deleted. - * When recursion_max is 0, then this should only be FALSE (setting this to TRUE would be a no-op). + * When depth_max is 0, then this should only be FALSE (setting this to TRUE would be a no-op). * @param custom * A custom function to pass to nftw() instead of using the internal one. * Such as a custom function for verbose printing of removed files. @@ -454,7 +454,7 @@ extern "C" { * @see remove() */ #ifndef _di_f_directory_remove_custom_ - extern f_return_status f_directory_remove_custom(const f_string_t path, const int recursion_max, const bool preserve, int (*custom) (const char *, const struct stat *, int, struct FTW *)); + extern f_return_status f_directory_remove_custom(const f_string_t path, const int depth_max, const bool preserve, int (*custom) (const char *, const struct stat *, int, struct FTW *)); #endif // _di_f_directory_remove_custom_ /** diff --git a/level_0/f_file/c/file.c b/level_0/f_file/c/file.c index cf422f8..ddd834b 100644 --- a/level_0/f_file/c/file.c +++ b/level_0/f_file/c/file.c @@ -1318,8 +1318,8 @@ extern "C" { } #endif // _di_f_file_mode_to_mode_ -#ifndef _di_f_file_move_ - f_return_status f_file_move(const f_string_t source, const f_string_t destination) { +#ifndef _di_f_file_rename_ + f_return_status f_file_rename(const f_string_t source, const f_string_t destination) { #ifndef _di_level_0_parameter_checking_ if (source == 0) return F_status_set_error(F_parameter); if (destination == 0) return F_status_set_error(F_parameter); @@ -1350,10 +1350,10 @@ extern "C" { return F_none; } -#endif // _di_f_file_move_ +#endif // _di_f_file_rename_ -#ifndef _di_f_file_move_at_ - f_return_status f_file_move_at(const int at_id, const int to_id, const f_string_t source, const f_string_t destination) { +#ifndef _di_f_file_rename_at_ + f_return_status f_file_rename_at(const int at_id, const int to_id, const f_string_t source, const f_string_t destination) { #ifndef _di_level_0_parameter_checking_ if (source == 0) return F_status_set_error(F_parameter); if (destination == 0) return F_status_set_error(F_parameter); @@ -1385,7 +1385,7 @@ extern "C" { return F_none; } -#endif // _di_f_file_move_at_ +#endif // _di_f_file_rename_at_ #ifndef _di_f_file_name_base_ f_return_status f_file_name_base(const f_string_t path, const f_string_length_t length, f_string_dynamic_t *name_base) { diff --git a/level_0/f_file/c/file.h b/level_0/f_file/c/file.h index dafef88..2ffe9ea 100644 --- a/level_0/f_file/c/file.h +++ b/level_0/f_file/c/file.h @@ -1446,19 +1446,16 @@ extern "C" { #endif // _di_f_file_mode_to_mode_ /** - * Move a file. + * Rename a file. * * The paths must not contain NULL except for the terminating NULL. * The paths must be NULL terminated. * - * This essentially renames a file but can also change the file's path, which is therefore a move. + * This essentially renames a file but can also change the file's path, which is identical to a move. + * However, renames only work within a filesystem and cannot be moved to another filesystem. * * If destination already exists, then according to rename(), destination will be atomically replaced. - * Which, if destination is a directory must either not exist or be empty. - * - * It is recommended to perform an existence test on destination to not have to consider the details on how rename() operates with an existing destination. - * - * @todo consider handling F_mount error internally, copying across filesystem and then removing file on success. + * Which, if destination is a directory, then that directory must either not exist or be empty. * * @param source * The path to the file to copy from. @@ -1488,24 +1485,21 @@ extern "C" { * * @see rename() */ -#ifndef _di_f_file_move_ - extern f_return_status f_file_move(const f_string_t source, const f_string_t destination); -#endif // _di_f_file_move_ +#ifndef _di_f_file_rename_ + extern f_return_status f_file_rename(const f_string_t source, const f_string_t destination); +#endif // _di_f_file_rename_ /** - * Move a file. + * Rename a file. * * The paths must not contain NULL except for the terminating NULL. * The paths must be NULL terminated. * - * This essentially renames a file but can also change the file's path, which is therefore a move. + * This essentially renames a file but can also change the file's path, which is identical to a move. + * However, renames only work within a filesystem and cannot be moved to another filesystem. * * If destination already exists, then according to rename(), destination will be atomically replaced. - * Which, if destination is a directory must either not exist or be empty. - * - * It is recommended to perform an existence test on destination to not have to consider the details on how rename() operates with an existing destination. - * - * @todo consider handling F_mount error internally, copying across filesystem and then removing file on success. + * Which, if destination is a directory, then that directory must either not exist or be empty. * * @param at_id * The parent directory, as an open directory file descriptor, in which the source is relative to. @@ -1540,9 +1534,9 @@ extern "C" { * * @see renameat() */ -#ifndef _di_f_file_move_at_ - extern f_return_status f_file_move_at(const int at_id, const int to_id, const f_string_t source, const f_string_t destination); -#endif // _di_f_file_move_at_ +#ifndef _di_f_file_rename_at_ + extern f_return_status f_file_rename_at(const int at_id, const int to_id, const f_string_t source, const f_string_t destination); +#endif // _di_f_file_rename_at_ /** * Get the base name of a file path. diff --git a/level_1/fl_directory/c/directory.c b/level_1/fl_directory/c/directory.c index 49864e9..18572b9 100644 --- a/level_1/fl_directory/c/directory.c +++ b/level_1/fl_directory/c/directory.c @@ -45,10 +45,6 @@ extern "C" { if (F_status_is_error(status)) return status; } - if (recurse.verbose) { - fprintf(recurse.verbose, "Cloned '%s' to '%s'.%c", source, destination, f_string_eol[0]); - } - f_string_static_t static_source = { source, source_length, source_length }; f_string_static_t static_destination = { destination, destination_length, destination_length }; @@ -71,11 +67,15 @@ extern "C" { } // for } - if (recurse.depth_max == 0) { - return status; + if (recurse.depth_max) { + status = private_fl_directory_clone(static_source, static_destination, role, recurse, 1); + } + + if (status == F_none && recurse.output && recurse.verbose) { + recurse.verbose(recurse.output, source, destination); } - return private_fl_directory_clone(static_source, static_destination, role, recurse, 1); + return status; } #endif // _di_fl_directory_clone_ @@ -121,7 +121,15 @@ extern "C" { return status; } - return private_fl_directory_clone(static_source, static_destination, role, recurse, 1); + if (recurse.depth_max) { + status = private_fl_directory_clone(static_source, static_destination, role, recurse, 1); + } + + if (status == F_none && recurse.output && recurse.verbose) { + recurse.verbose(recurse.output, source, destination); + } + + return status; } #endif // _di_fl_directory_clone_content_ @@ -153,10 +161,6 @@ extern "C" { if (F_status_is_error(status)) return status; } - if (recurse.verbose) { - fprintf(recurse.verbose, "Copied '%s' to '%s'.%c", source, destination, f_string_eol[0]); - } - f_string_static_t static_source = { source, source_length, source_length }; f_string_static_t static_destination = { destination, destination_length, destination_length }; @@ -179,11 +183,15 @@ extern "C" { } // for } - if (recurse.depth_max == 0) { - return status; + if (recurse.depth_max) { + status = private_fl_directory_copy(static_source, static_destination, mode, recurse, 1); + } + + if (status == F_none && recurse.output && recurse.verbose) { + recurse.verbose(recurse.output, source, destination); } - return private_fl_directory_copy(static_source, static_destination, mode, recurse, 1); + return status; } #endif // _di_fl_directory_copy_ @@ -225,11 +233,15 @@ extern "C" { } // for } - if (recurse.depth_max == 0) { - return status; + if (recurse.depth_max) { + status = private_fl_directory_copy(static_source, static_destination, mode, recurse, 1); + } + + if (status == F_none && recurse.output && recurse.verbose) { + recurse.verbose(recurse.output, source, destination); } - return private_fl_directory_copy(static_source, static_destination, mode, recurse, 1); + return status; } #endif // _di_fl_directory_copy_content_ diff --git a/level_1/fl_directory/c/directory.h b/level_1/fl_directory/c/directory.h index 924add5..0fe6b09 100644 --- a/level_1/fl_directory/c/directory.h +++ b/level_1/fl_directory/c/directory.h @@ -57,9 +57,16 @@ extern "C" { * exclusive: * If TRUE, will fail when file already exists. * If FALSE, will not fail if file already exists (existing file will be replaced). + * output: + * Set to 0 to not print on successful operation. + * Set to a valid file pointer to print to on successful operation. + * This is passed to the verbose function if that function pointer is not 0. * verbose: - * Set to 0 to not print copy operation values on successful copy. - * Set to a valid file pointer, such as f_type_output (stdout), to print on successful copy. + * Set to 0 to not print on successful operation. + * Set to address of a function to be called for printing such that: + * - The first parameter represents the file pointer from the output variable. + * - The second parameter represents the source string. + * - The third parameter represents the destination string. * failures: * A list of paths and their respective status codes for clone failures. * If 0, then this and statuses are ignored. @@ -71,11 +78,12 @@ extern "C" { f_number_unsigned_t depth_max; f_number_unsigned_t size_block; bool exclusive; - FILE *verbose; + FILE *output; + void (*verbose)(FILE *, const f_string_t, const f_string_t); f_directory_statuss_t *failures; } fl_directory_recurse_t; - #define fl_directory_recurse_t_initialize { fl_directory_recurse_depth_max, f_file_default_read_size, F_false, 0, 0 } + #define fl_directory_recurse_t_initialize { fl_directory_recurse_depth_max, f_file_default_read_size, F_false, 0, 0, 0 } #endif // _di_fl_directory_recurse_t_ /** @@ -107,16 +115,6 @@ extern "C" { * * @return * F_none on success. - * F_data_not if directory is empty. - * F_directory_descriptor (with error bit) on directory file descriptor error. - * F_directory_open (with error bit) on directory open error. - * F_directory_stream (with error bit) on directory stream error. - * F_directory_unsupported (with error bit) on directory file descriptor not supported. - * F_file_descriptor_max (with error bit) if max file descriptors was reached. - * F_file_open_max (with error bit) too many open files. - * F_memory_reallocation (with error bit) on memory reallocation error. - * F_parameter (with error bit) if a parameter is invalid. - * F_string_too_large (with error bit) if appended string length is too large to store in the buffer. * F_failure (with error bit) for any other failure, failures might be populated with individual status codes. * * Errors from (with error bit): f_directory_create(). @@ -162,16 +160,6 @@ extern "C" { * * @return * F_none on success. - * F_data_not if directory is empty. - * F_directory_descriptor (with error bit) on directory file descriptor error. - * F_directory_open (with error bit) on directory open error. - * F_directory_stream (with error bit) on directory stream error. - * F_directory_unsupported (with error bit) on directory file descriptor not supported. - * F_file_descriptor_max (with error bit) if max file descriptors was reached. - * F_file_open_max (with error bit) too many open files. - * F_memory_reallocation (with error bit) on memory reallocation error. - * F_parameter (with error bit) if a parameter is invalid. - * F_string_too_large (with error bit) if appended string length is too large to store in the buffer. * F_failure (with error bit) for any other failure, failures might be populated with individual status codes. * * Errors from (with error bit): f_directory_exists(). @@ -209,16 +197,6 @@ extern "C" { * * @return * F_none on success. - * F_data_not if directory is empty. - * F_directory_descriptor (with error bit) on directory file descriptor error. - * F_directory_open (with error bit) on directory open error. - * F_directory_stream (with error bit) on directory stream error. - * F_directory_unsupported (with error bit) on directory file descriptor not supported. - * F_file_descriptor_max (with error bit) if max file descriptors was reached. - * F_file_open_max (with error bit) too many open files. - * F_memory_reallocation (with error bit) on memory reallocation error. - * F_parameter (with error bit) if a parameter is invalid. - * F_string_too_large (with error bit) if appended string length is too large to store in the buffer. * F_failure (with error bit) for any other failure, failures might be populated with individual status codes. * * Errors from (with error bit): f_directory_create(). @@ -262,16 +240,6 @@ extern "C" { * * @return * F_none on success. - * F_data_not if directory is empty. - * F_directory_descriptor (with error bit) on directory file descriptor error. - * F_directory_open (with error bit) on directory open error. - * F_directory_stream (with error bit) on directory stream error. - * F_directory_unsupported (with error bit) on directory file descriptor not supported. - * F_file_descriptor_max (with error bit) if max file descriptors was reached. - * F_file_open_max (with error bit) too many open files. - * F_memory_reallocation (with error bit) on memory reallocation error. - * F_parameter (with error bit) if a parameter is invalid. - * F_string_too_large (with error bit) if appended string length is too large to store in the buffer. * F_failure (with error bit) for any other failure, failures might be populated with individual status codes. * * Errors from (with error bit): f_directory_exists(). diff --git a/level_1/fl_directory/c/private-directory.c b/level_1/fl_directory/c/private-directory.c index 775bad8..0a75acf 100644 --- a/level_1/fl_directory/c/private-directory.c +++ b/level_1/fl_directory/c/private-directory.c @@ -113,6 +113,10 @@ extern "C" { if (depth < recurse.depth_max) { status = private_fl_directory_clone(source_sub, destination_sub, role, recurse, depth + 1); + + if (status == F_none && recurse.output && recurse.verbose) { + recurse.verbose(recurse.output, source_sub.string, destination_sub.string); + } } } // for @@ -202,8 +206,8 @@ extern "C" { return F_failure; } - if (recurse.verbose) { - fprintf(recurse.verbose, "Cloned '%s' to '%s'.%c", path_source, path_destination, f_string_eol[0]); + if (recurse.output && recurse.verbose) { + recurse.verbose(recurse.output, path_source, path_destination); } return F_none; @@ -304,6 +308,10 @@ extern "C" { if (depth < recurse.depth_max) { status = private_fl_directory_copy(source_sub, destination_sub, mode, recurse, depth + 1); + + if (status == F_none && recurse.output && recurse.verbose) { + recurse.verbose(recurse.output, source_sub.string, destination_sub.string); + } } } // for @@ -393,8 +401,8 @@ extern "C" { return F_failure; } - if (recurse.verbose) { - fprintf(recurse.verbose, "Copied '%s' to '%s'.%c", path_source, path_destination, f_string_eol[0]); + if (recurse.output && recurse.verbose) { + recurse.verbose(recurse.output, path_source, path_destination); } return F_none; diff --git a/level_1/fl_directory/c/private-directory.h b/level_1/fl_directory/c/private-directory.h index c76154b..ef6fdcf 100644 --- a/level_1/fl_directory/c/private-directory.h +++ b/level_1/fl_directory/c/private-directory.h @@ -36,16 +36,6 @@ extern "C" { * * @return * F_none on success. - * F_data_not if directory is empty. - * F_directory_descriptor (with error bit) on directory file descriptor error. - * F_directory_open (with error bit) on directory open error. - * F_directory_stream (with error bit) on directory stream error. - * F_directory_unsupported (with error bit) on directory file descriptor not supported. - * F_file_descriptor_max (with error bit) if max file descriptors was reached. - * F_file_open_max (with error bit) too many open files. - * F_memory_reallocation (with error bit) on memory reallocation error. - * F_parameter (with error bit) if a parameter is invalid. - * F_string_too_large (with error bit) if appended string length is too large to store in the buffer. * F_failure (with error bit) for any other failure, failures might be populated with individual status codes. * * @see fl_directory_clone() @@ -77,17 +67,6 @@ extern "C" { * * @return * F_none on success. - * F_data_not if directory is empty. - * F_buffer_too_large (with error bit) if a buffer would exceed max length. - * F_directory_descriptor (with error bit) on directory file descriptor error. - * F_directory_open (with error bit) on directory open error. - * F_directory_stream (with error bit) on directory stream error. - * F_directory_unsupported (with error bit) on directory file descriptor not supported. - * F_file_descriptor_max (with error bit) if max file descriptors was reached. - * F_file_open_max (with error bit) too many open files. - * F_memory_reallocation (with error bit) on memory reallocation error. - * F_parameter (with error bit) if a parameter is invalid. - * F_string_too_large (with error bit) if appended string length is too large to store in the buffer. * F_failure (with error bit) for any other failure, failures might be populated with individual status codes. * * @see fl_directory_clone() @@ -116,16 +95,6 @@ extern "C" { * * @return * F_none on success. - * F_data_not if directory is empty. - * F_directory_descriptor (with error bit) on directory file descriptor error. - * F_directory_open (with error bit) on directory open error. - * F_directory_stream (with error bit) on directory stream error. - * F_directory_unsupported (with error bit) on directory file descriptor not supported. - * F_file_descriptor_max (with error bit) if max file descriptors was reached. - * F_file_open_max (with error bit) too many open files. - * F_memory_reallocation (with error bit) on memory reallocation error. - * F_parameter (with error bit) if a parameter is invalid. - * F_string_too_large (with error bit) if appended string length is too large to store in the buffer. * F_failure (with error bit) for any other failure, failures might be populated with individual status codes. * * @see fl_directory_copy() @@ -155,16 +124,6 @@ extern "C" { * * @return * F_none on success. - * F_data_not if directory is empty. - * F_directory_descriptor (with error bit) on directory file descriptor error. - * F_directory_open (with error bit) on directory open error. - * F_directory_stream (with error bit) on directory stream error. - * F_directory_unsupported (with error bit) on directory file descriptor not supported. - * F_file_descriptor_max (with error bit) if max file descriptors was reached. - * F_file_open_max (with error bit) too many open files. - * F_memory_reallocation (with error bit) on memory reallocation error. - * F_parameter (with error bit) if a parameter is invalid. - * F_string_too_large (with error bit) if appended string length is too large to store in the buffer. * F_failure (with error bit) for any other failure, failures might be populated with individual status codes. * * @see fl_directory_copy() diff --git a/level_2/fll_file/c/file.c b/level_2/fll_file/c/file.c index 2bbb6cf..bde11f1 100644 --- a/level_2/fll_file/c/file.c +++ b/level_2/fll_file/c/file.c @@ -66,20 +66,78 @@ extern "C" { #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_ + #ifndef _di_level_2_parameter_checking_ + if (!path) return F_status_set_error(F_parameter); + #endif // _di_level_2_parameter_checking_ return private_fll_file_mode_set_all(path, mode, depth_max, 0); } -#endif // _di_fll_file_mode_set_all__ +#endif // _di_fll_file_mode_set_all_ + +#ifndef _di_fll_file_move_ + f_return_status fll_file_move(const f_string_t source, const f_string_t destination, const f_string_length_t source_length, const f_string_length_t destination_length, const fl_directory_recurse_t recurse) { + #ifndef _di_level_2_parameter_checking_ + if (!source) return F_status_set_error(F_parameter); + if (!destination) return F_status_set_error(F_parameter); + #endif // _di_level_2_parameter_checking_ + + f_status_t status = f_file_rename(source, destination); + + if (F_status_set_fine(status) != F_mount) { + if (status == F_none && recurse.output && recurse.verbose) { + recurse.verbose(recurse.output, source, destination); + } + + return status; + } + + status = f_file_is(source, f_file_type_directory, F_false); + + if (status == F_file_found_not) { + return F_status_set_error(status); + } + + if (F_status_is_error(status)) { + return status; + } + + if (status == F_true) { + status = fl_directory_clone(source, destination, source_length, destination_length, F_true, recurse); + + if (F_status_is_error(status)) { + return status; + } + + status = f_directory_remove(source, recurse.depth_max, F_false); + + if (status == F_none && recurse.output && recurse.verbose) { + recurse.verbose(recurse.output, source, destination); + } + } + else { + status = f_file_clone(source, destination, F_true, recurse.size_block, recurse.exclusive); + + if (F_status_is_error(status)) { + return status; + } + + status = f_file_remove(source); + + if (status == F_none && recurse.output && recurse.verbose) { + recurse.verbose(recurse.output, source, destination); + } + } + + return status; + } +#endif // _di_fll_file_move_ #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); + #ifndef _di_level_2_parameter_checking_ + if (!path) 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_ + #endif // _di_level_2_parameter_checking_ return private_fll_file_role_change_all(path, uid, gid, dereference, depth_max, 0); } diff --git a/level_2/fll_file/c/file.h b/level_2/fll_file/c/file.h index c3b068f..66d70c8 100644 --- a/level_2/fll_file/c/file.h +++ b/level_2/fll_file/c/file.h @@ -86,6 +86,66 @@ extern "C" { #endif // _di_fll_file_mode_set_all_ /** + * Move a file. + * + * The paths must not contain NULL except for the terminating NULL. + * The paths must be NULL terminated. + * + * This attempts to rename a file but if the file is on another filesystem then it tries to clone the file or directory. + * If the file or directory is cloned, then the original is deleted after a successful copy. + * + * When this calls the additional functions, if the clone succeeds but the remove fails the source may exist. + * Therefore, if there is an error during remove, then the file should be checked for existence and possibly be manually removed. + * + * @param source + * The path to the file to copy from. + * @param destination + * The path to copy to. + * @param source_length + * The length of the source path. + * @param destination_length + * The length of the destination path. + * @param recurse + * The directory recurse data. + * + * @return + * F_none on success. + * F_access_denied (with error bit) on access denied. + * F_buffer (with error bit) if the buffer is invalid. + * F_busy (with error bit) if filesystem is too busy to perform write. + * F_directory (with error bit) if a supposed directory in path is not actually a directory. + * F_directory_empty_not (with error bit) if the destination is a non-empty directory. + * F_file_found_not (with error bit) if file at path was not found. + * F_file_type_directory (with error bit) if destination is a directory but source is not. + * F_filesystem_quota_block (with error bit) if filesystem's disk blocks or inodes are exhausted. + * F_link (with error bit) if source or destination has the maxiumum associated links. + * 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_prohibited (with error bit) if filesystem does not allow for making changes. + * F_read_only (with error bit) if file is read-only. + * F_space_not (with error bit) if filesystem is out of space (or filesystem quota is reached). + * F_failure (with error bit) for any other error, failures might be populated with individual status codes. + * + * Errors from (with error bit): f_directory_remove_custom(). + * Errors from (with error bit): f_file_is(). + * Errors from (with error bit): f_file_remove(). + * Errors from (with error bit): f_file_rename(). + * Errors from (with error bit): fl_directory_clone(). + * + * @see f_directory_remove() + * @see f_directory_remove_custom() + * @see f_file_is() + * @see f_file_remove() + * @see f_file_rename() + * @see fl_directory_clone() + */ +#ifndef _di_fll_file_move_ + extern f_return_status fll_file_move(const f_string_t source, const f_string_t destination, const f_string_length_t source_length, const f_string_length_t destination_length, const fl_directory_recurse_t recurse); +#endif // _di_fll_file_move_ + +/** * Change owner and/or group of a given file at the specified path. * * At least one of uid or gid must not be -1. diff --git a/level_3/fake/c/private-build.c b/level_3/fake/c/private-build.c index 26683d3..172b679 100644 --- a/level_3/fake/c/private-build.c +++ b/level_3/fake/c/private-build.c @@ -180,7 +180,8 @@ extern "C" { fl_directory_recurse_t recurse = fl_directory_recurse_t_initialize; if (data.verbosity == fake_verbosity_verbose) { - recurse.verbose = f_type_output; + recurse.output = f_type_output; + recurse.verbose = fake_verbose_print_copy; } recurse.failures = &failures; diff --git a/level_3/fake/c/private-fake.c b/level_3/fake/c/private-fake.c index 07dbb43..db4a694 100644 --- a/level_3/fake/c/private-fake.c +++ b/level_3/fake/c/private-fake.c @@ -954,6 +954,24 @@ extern "C" { } #endif // _di_fake_validate_parameter_directories_ +#ifndef _di_fake_verbose_print_clone_ + void fake_verbose_print_clone(FILE *output, const f_string_t source, const f_string_t destination) { + fprintf(output, "Cloned '%s' to '%s'.%c", source, destination, f_string_eol[0]); + } +#endif // _di_fake_verbose_print_clone_ + +#ifndef _di_fake_verbose_print_copy_ + void fake_verbose_print_copy(FILE *output, const f_string_t source, const f_string_t destination) { + fprintf(output, "Copied '%s' to '%s'.%c", source, destination, f_string_eol[0]); + } +#endif // _di_fake_verbose_print_copy_ + +#ifndef _di_fake_verbose_print_move_ + void fake_verbose_print_move(FILE *output, const f_string_t source, const f_string_t destination) { + fprintf(output, "Moved '%s' to '%s'.%c", source, destination, f_string_eol[0]); + } +#endif // _di_fake_verbose_print_move_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/fake/c/private-fake.h b/level_3/fake/c/private-fake.h index a768078..eed761f 100644 --- a/level_3/fake/c/private-fake.h +++ b/level_3/fake/c/private-fake.h @@ -153,6 +153,48 @@ extern "C" { extern f_return_status fake_validate_parameter_directories(const f_console_arguments_t arguments, const fake_data_t data) f_gcc_attribute_visibility_internal; #endif // _di_fake_validate_parameter_directories_ +/** + * Helper function for performing a verbose print for a file clone operation. + * + * @param output + * A file pointer to print to, such as stdout. + * @param source + * The source string. + * @param destination + * The destination string. + */ +#ifndef _di_fake_verbose_print_clone_ + extern void fake_verbose_print_clone(FILE *output, const f_string_t source, const f_string_t destination) f_gcc_attribute_visibility_internal; +#endif // _di_fake_verbose_print_clone_ + +/** + * Helper function for performing a verbose print for a file copy operation. + * + * @param output + * A file pointer to print to, such as stdout. + * @param source + * The source string. + * @param destination + * The destination string. + */ +#ifndef _di_fake_verbose_print_copy_ + extern void fake_verbose_print_copy(FILE *output, const f_string_t source, const f_string_t destination) f_gcc_attribute_visibility_internal; +#endif // _di_fake_verbose_print_copy_ + +/** + * Helper function for performing a verbose print for a file move operation. + * + * @param output + * A file pointer to print to, such as stdout. + * @param source + * The source string. + * @param destination + * The destination string. + */ +#ifndef _di_fake_verbose_print_move_ + extern void fake_verbose_print_move(FILE *output, const f_string_t source, const f_string_t destination) f_gcc_attribute_visibility_internal; +#endif // _di_fake_verbose_print_move_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/fake/c/private-make.c b/level_3/fake/c/private-make.c index aa292bf..64a7bf0 100644 --- a/level_3/fake/c/private-make.c +++ b/level_3/fake/c/private-make.c @@ -1798,7 +1798,8 @@ extern "C" { f_string_length_t destination_length = 0; if (data.verbosity == fake_verbosity_verbose) { - recurse.verbose = f_type_output; + recurse.output = f_type_output; + recurse.verbose = fake_verbose_print_clone; } bool existing = F_true; @@ -1893,7 +1894,8 @@ extern "C" { f_macro_mode_t_set_default_umask(mode, data.umask); if (data.verbosity == fake_verbosity_verbose) { - recurse.verbose = f_type_output; + recurse.output = f_type_output; + recurse.verbose = fake_verbose_print_copy; } bool existing = F_true; @@ -2755,8 +2757,15 @@ extern "C" { const f_array_length_t total = arguments.used -1; f_status_t status_file = F_none; + fl_directory_recurse_t recurse = fl_directory_recurse_t_initialize; + f_string_length_t destination_length = 0; + if (data.verbosity == fake_verbosity_verbose) { + recurse.output = f_type_output; + recurse.verbose = fake_verbose_print_move; + } + bool existing = F_true; // in this case, the destination could be a file, so confirm this. @@ -2792,15 +2801,12 @@ extern "C" { destination[destination_length] = 0; - status_file = f_file_move(arguments.array[i].string, destination); + status_file = fll_file_move(arguments.array[i].string, destination, arguments.array[i].used, destination_length, recurse); if (F_status_is_error(status_file)) { - fake_print_message_file(data, F_status_set_fine(status_file), "f_file_move", arguments.array[i].string, "move", F_false, F_true, data_make->print); + fake_print_message_file(data, F_status_set_fine(status_file), "fll_file_move", arguments.array[i].string, "move", F_false, F_true, data_make->print); *status = F_status_set_error(F_failure); } - else if (data.verbosity == fake_verbosity_verbose) { - printf("Moved '%s' to '%s'.%c", arguments.array[i].string, destination, f_string_eol[0]); - } } // for return; -- 1.8.3.1