From b37ab92a7f469e71711aad72d799dd9240b5fcad Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Fri, 29 May 2020 20:00:41 -0500 Subject: [PATCH] Update: todo documentation, directory copy and clone functions, update comment documentation Update the todo.txt documentation. There needs to be directory copy and clone functions for copy the contents of a source directory and not the directory itself. To that end, add new *_contents() copy functions. The comment documentation for clone was never updated and is incorrect. --- documents/todo.txt | 13 +- level_1/fl_directory/c/directory.c | 187 +++++++++++++++++++++++++---- level_1/fl_directory/c/directory.h | 177 ++++++++++++++++++++------- level_1/fl_directory/c/private-directory.c | 120 +++++++++--------- level_1/fl_directory/c/private-directory.h | 4 - level_1/fl_string/c/string.c | 32 +++++ level_1/fl_string/c/string.h | 23 ++++ 7 files changed, 423 insertions(+), 133 deletions(-) diff --git a/documents/todo.txt b/documents/todo.txt index 8365f80..22b0322 100644 --- a/documents/todo.txt +++ b/documents/todo.txt @@ -5,7 +5,7 @@ This file contains FLL-wide todo notes. In which case, the language can be hardcoded in as a single language. Later versions after this first locale support will then consider supporting multiple languages not necessarily compiled in. -- Create an fss simple content type (such that data->contents.array[at].start can be used instead of data->contents.array[at].array[0].start). +- Consider creating an fss simple content type (such that data->contents.array[at].start can be used instead of data->contents.array[at].array[0].start). - FSS needs to allow escaping of comments, "\# " would escape a comment, every backslash after that would be literal. @@ -29,11 +29,9 @@ This file contains FLL-wide todo notes. - implement the "data" unit that using the metric system more appropriately, such that a data is a single byte. 1 megadata in base 10 is (10^6)*8 = # of bits, and 1 megadata in base 16 s (16^6)*8 = # of bits. -- console processing code needs to ignore unknown codes (namely, negative/positive numbes like: -3 or +4) (do not consider these parameters). +- console processing code needs to ignore unknown codes (namely, negative/positive numbers like: -3 or +4) (do not consider these parameters). -- rename f_not_equal_to to f_equal_to_not (and do similar changes). - -- Research/Implement optimizaton by using pointers to reduce the complecity of processing multi-depth structures, such as fss_nest: +- Research/Implement optimizaton by using pointers to reduce the complexity of processing multi-depth structures, such as fss_nest: this: nests->array[nests->used].array[index].array[0] = xxx; could become: @@ -104,3 +102,8 @@ Go though all source code and ensure that, for all non-exceptional cases, any dy Then document this behavior. The status code processing code are all out of alphabetic order and need cleanup. + +Go back through all existing f_file and f_directory code, updating return codes and respective documentation. +Update f_utf_file and create a f_utf_directory? + +Remove empty projects and cleanup private functions. diff --git a/level_1/fl_directory/c/directory.c b/level_1/fl_directory/c/directory.c index 3b4a502..b737924 100644 --- a/level_1/fl_directory/c/directory.c +++ b/level_1/fl_directory/c/directory.c @@ -7,60 +7,197 @@ extern "C" { #ifndef _di_fl_directory_clone_ f_return_status fl_directory_clone(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const bool role, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) { - f_status status = F_none; + f_status status = f_directory_exists(source); - status = f_directory_exists(source); if (F_status_is_error(status)) return status; if (status == F_false) return F_status_set_error(F_directory); - const f_string_static static_source = { source, source_length, source_length }; - const f_string_static static_destination = { destination, destination_length, destination_length }; + struct stat source_stat; - status = private_fl_directory_clone(static_source, static_destination, role, size_block, exclusive, failures); + memset(&source_stat, 0, sizeof(struct stat)); - return F_none; + status = f_file_stat(source, F_false, &source_stat); + if (F_status_is_error(status)) return status; + + status = f_directory_exists(destination); + if (F_status_is_error(status)) return status; + + if (status == F_true) { + if (exclusive) { + return F_status_set_error(F_directory_found); + } + + status = f_file_change_mode(destination, source_stat.st_mode); + if (F_status_is_error(status)) return status; + } + else { + status = f_directory_create(destination, source_stat.st_mode); + if (F_status_is_error(status)) return status; + } + + if (role) { + status = f_file_change_owner(destination, source_stat.st_uid, source_stat.st_gid, F_true); + if (F_status_is_error(status)) return status; + } + + f_string_static static_source = { source, source_length, source_length }; + f_string_static static_destination = { destination, destination_length, destination_length }; + + // do not allow null termination or trailing path separators in the string's length calculation. + { + f_string_length i = source_length; + + for (; i > 0; i--, static_source.used--) { + if (source[i - 1] == 0) continue; + if (source[i - 1] == f_path_separator[0]) continue; + break; + } // for + + i = destination_length; + + for (; i > 0; i--, static_destination.used--) { + if (destination[i - 1] == 0) continue; + if (destination[i - 1] == f_path_separator[0]) continue; + break; + } // for + } + + return private_fl_directory_clone(static_source, static_destination, role, size_block, exclusive, failures); } #endif // _di_fl_directory_clone_ +#ifndef _di_fl_directory_clone_content_ + f_return_status fl_directory_clone_content(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const bool role, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) { + f_status status = f_directory_exists(source); + + if (F_status_is_error(status)) return status; + if (status == F_false) return F_status_set_error(F_directory); + + status = f_directory_exists(destination); + if (F_status_is_error(status)) return status; + if (status == F_false) return F_status_set_error(F_directory); + + f_string_static static_source = { source, source_length, source_length }; + f_string_static static_destination = { destination, destination_length, destination_length }; + + // do not allow null termination or trailing path separators in the string's length calculation. + { + f_string_length i = source_length; + + for (; i > 0; i--, static_source.used--) { + if (source[i - 1] == 0) continue; + if (source[i - 1] == f_path_separator[0]) continue; + break; + } // for + + i = destination_length; + + for (; i > 0; i--, static_destination.used--) { + if (destination[i - 1] == 0) continue; + if (destination[i - 1] == f_path_separator[0]) continue; + break; + } // for + } + + return private_fl_directory_clone(static_source, static_destination, role, size_block, exclusive, failures); + } +#endif // _di_fl_directory_clone_content_ + #ifndef _di_fl_directory_copy_ f_return_status fl_directory_copy(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) { - f_status status = F_none; + f_status status = f_directory_exists(source); - status = f_directory_exists(source); if (F_status_is_error(status)) return status; if (status == F_false) return F_status_set_error(F_directory); - const f_string_static static_source = { source, source_length, source_length }; - const f_string_static static_destination = { destination, destination_length, destination_length }; + status = f_directory_exists(destination); + if (F_status_is_error(status)) return status; - status = private_fl_directory_copy(static_source, static_destination, mode, size_block, exclusive, failures); + if (status == F_true) { + if (exclusive) { + return F_status_set_error(F_directory_found); + } - return F_none; + status = f_file_change_mode(destination, mode.directory); + if (F_status_is_error(status)) return status; + } + else { + status = f_directory_create(destination, mode.directory); + if (F_status_is_error(status)) return status; + } + + f_string_static static_source = { source, source_length, source_length }; + f_string_static static_destination = { destination, destination_length, destination_length }; + + // do not allow null termination or trailing path separators in the string's length calculation. + { + f_string_length i = source_length; + + for (; i > 0; i--, static_source.used--) { + if (source[i - 1] == 0) continue; + if (source[i - 1] == f_path_separator[0]) continue; + break; + } // for + + i = destination_length; + + for (; i > 0; i--, static_destination.used--) { + if (destination[i - 1] == 0) continue; + if (destination[i - 1] == f_path_separator[0]) continue; + break; + } // for + } + + return private_fl_directory_copy(static_source, static_destination, mode, size_block, exclusive, failures); } #endif // _di_fl_directory_copy_ -#ifndef _di_fl_directory_list_ - f_return_status fl_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), const bool dereference, f_directory_listing *listing) { - #ifndef _di_level_2_parameter_checking_ - if (listing == 0) return F_status_set_error(F_parameter); - #endif // _di_level_2_parameter_checking_ +#ifndef _di_fl_directory_copy_content_ + f_return_status fl_directory_copy_content(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) { + f_status status = f_directory_exists(source); - return private_fl_directory_list(path, filter, sort, dereference, listing); + if (F_status_is_error(status)) return status; + if (status == F_false) return F_status_set_error(F_directory); + + status = f_directory_exists(destination); + if (F_status_is_error(status)) return status; + if (status == F_false) return F_status_set_error(F_directory); + + f_string_static static_source = { source, source_length, source_length }; + f_string_static static_destination = { destination, destination_length, destination_length }; + + // do not allow null termination or trailing path separators in the string's length calculation. + { + f_string_length i = source_length; + + for (; i > 0; i--, static_source.used--) { + if (source[i - 1] == 0) continue; + if (source[i - 1] == f_path_separator[0]) continue; + break; + } // for + + i = destination_length; + + for (; i > 0; i--, static_destination.used--) { + if (destination[i - 1] == 0) continue; + if (destination[i - 1] == f_path_separator[0]) continue; + break; + } // for + } + + return private_fl_directory_copy(static_source, static_destination, mode, size_block, exclusive, failures); } -#endif // _di_fl_directory_list_ +#endif // _di_fl_directory_copy_content_ -#ifndef _di_fl_directory_list_at_ - f_return_status fl_directory_list_at(const int at_id, const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), const bool dereference, f_directory_listing *listing) { +#ifndef _di_fl_directory_list_ + f_return_status fl_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), const bool dereference, f_directory_listing *listing) { #ifndef _di_level_2_parameter_checking_ if (listing == 0) return F_status_set_error(F_parameter); #endif // _di_level_2_parameter_checking_ - // @todo implement a directoy list that passes at_id to scandirat(). - // but... DIR * appears to be needed, can I just instead pass the path string instead? (char *). - return private_fl_directory_list(path, filter, sort, dereference, listing); } -#endif // _di_fl_directory_list_at_ +#endif // _di_fl_directory_list_ #ifndef _di_fl_directory_path_pop_ f_return_status fl_directory_path_pop(f_string_static *path) { diff --git a/level_1/fl_directory/c/directory.h b/level_1/fl_directory/c/directory.h index c637c16..d848c6c 100644 --- a/level_1/fl_directory/c/directory.h +++ b/level_1/fl_directory/c/directory.h @@ -45,13 +45,11 @@ extern "C" { #endif /** - * Copy a file, as well as its file mode and possibly the owner and group. + * Copy a directory and its contents, as well as its file mode and possibly the owner and group.. * * The paths must not contain NULL except for the terminating NULL. * The paths must be NULL terminated. * - * @todo provide a return status for when owner/role cannot be assigned. - * * Symbolic links are not followed, they are copied as the symbolic link itself. * * This does not copy unknown file types. @@ -74,8 +72,11 @@ extern "C" { * The default number of chunks to read at a time with each chunk being 1-byte. * Must be greater than 0. * @param exclusive - * If TRUE, will fail when parent directory already exists. - * If FALSE, will not fail if parent directory already exists (existing directory will be updated). + * If TRUE, will fail when file already exists. + * If FALSE, will not fail if file already exists (existing file will be replaced). + * @param failures + * A list of paths and their respective status codes for clone failures. + * If 0, then this and statuses is ignored. * * @return * F_none on success. @@ -100,17 +101,80 @@ extern "C" { * F_busy (with error bit) if filesystem is too busy to perforrm write. * F_file_read (with error bit) on file read error. * F_file_write (with error bit) on file write error. - * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * - * @see f_directory_create() * @see f_file_clone() - * @see read() */ #ifndef _di_fl_directory_clone_ extern f_return_status fl_directory_clone(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const bool role, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures); #endif // _di_fl_directory_clone_ /** + * Copy a directory contents, as well as its file mode and possibly the owner and group. + * + * When cloning the contents of a directory, both the source and the destination paths must already exist and be directories, regardless of exclusive boolean. + * + * The paths must not contain NULL except for the terminating NULL. + * The paths must be NULL terminated. + * + * Symbolic links are not followed, they are copied as the symbolic link itself. + * + * This does not copy unknown file types. + * + * @param source + * The source file path. + * Must be NULL terminated. + * @param destination + * The destination file path. + * Must be NULL terminated. + * @param source_length + * The length of the source path. + * @param destination_length + * The length of the destination path. + * @param role + * If TRUE, will copy the owner and group ids. + * If FALSE, will not copy the owner and group ids. + * (In both cases the file mode is copied.) + * @param size_block + * The default number of chunks to read at a time with each chunk being 1-byte. + * Must be greater than 0. + * @param exclusive + * If TRUE, will fail when file already exists. + * If FALSE, will not fail if file already exists (existing file will be replaced). + * @param failures + * A list of paths and their respective status codes for clone failures. + * If 0, then this and statuses is ignored. + * + * @return + * F_none on success. + * F_parameter (with error bit) if a parameter is invalid. + * F_access_denied (with error bit) on access denied. + * F_loop (with error bit) on loop error. + * F_file_found (with error bit) if a file was found while exclusive is TRUE. + * F_memory_out (with error bit) if out of memory. + * F_memory_allocation (with error bit) on memory allocation error. + * F_memory_reallocation (with error bit) on memory re-allocation error. + * F_prohibited (with error bit) if filesystem does not allow for removing. + * F_read_only (with error bit) if file is read-only. + * F_failure (with error bit) for any other (mkdir()) error. + * F_filesystem_quota_block (with error bit) if filesystem's disk blocks or inodes are exhausted. + * F_filesystem_quota_reached (with error bit) quota reached of filesystem is out of space. + * F_file_found (with error bit) of a directory aleady exists at the path. + * F_name (with error bit) on path name error. + * F_directory (with error bit) if a supposed directory in path is not actually a directory. + * F_number_overflow (with error bit) on overflow error. + * F_interrupted (with error bit) when program received an interrupt signal, halting create. + * F_file_open_max (with error bit) when system-wide max open files is reached. + * F_busy (with error bit) if filesystem is too busy to perforrm write. + * F_file_read (with error bit) on file read error. + * F_file_write (with error bit) on file write error. + * + * @see f_file_clone() + */ +#ifndef _di_fl_directory_clone_content_ + extern f_return_status fl_directory_clone_content(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const bool role, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures); +#endif // _di_fl_directory_clone_content_ + +/** * Copy a directory and its contents. * * The paths must not contain NULL except for the terminating NULL. @@ -138,6 +202,9 @@ extern "C" { * @param exclusive * If TRUE, will fail when file already exists. * If FALSE, will not fail if file already exists (existing file will be replaced). + * @param exclusive + * If TRUE, will fail when file already exists. + * If FALSE, will not fail if file already exists (existing file will be replaced). * @param failures * A list of paths and their respective status codes for copy failures. * If 0, then this and statuses is ignored. @@ -165,56 +232,76 @@ extern "C" { * F_busy (with error bit) if filesystem is too busy to perforrm write. * F_file_read (with error bit) on file read error. * F_file_write (with error bit) on file write error. - * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see f_file_copy() - * @see read() */ #ifndef _di_fl_directory_copy_ extern f_return_status fl_directory_copy(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures); #endif // _di_fl_directory_copy_ /** - * For some given path, print the names of each file and/or directory inside the directory, stored as a directory listing. + * Copy a directory contents. * - * Allows specifying a custom filter and custom sort. + * When copying the contents of a directory, both the source and the destination paths must already exist and be directories, regardless of exclusive boolean. * - * @param path - * Filesystem path to the directory. - * @param filter - * A filter function of the form: int xxx(const struct direct *). - * Set to 0 to not use (NULL). - * @param sort - * A sort function of the form: int xxx(const struct direct *, const struct direct *). - * Set to 0 to not use (NULL). - * There are two pre-made libc functions available for this: alphasort() and versionsort(). - * @param dereference - * Set to TRUE to dereferenc symlinks (often is what is desired). - * Set to FALSE to operate on the symlink itself. - * @param listing - * Will be populated with the names of all top-level paths found within the given directory. + * The paths must not contain NULL except for the terminating NULL. + * The paths must be NULL terminated. + * + * Symbolic links are not followed, they are copied as the symbolic link itself. + * + * This does not copy unknown file types. + * + * @param source + * The source file path. + * Must be NULL terminated. + * @param destination + * The destination file path. + * Must be NULL terminated. + * @param source_length + * The length of the source path. + * @param destination_length + * The length of the destination path. + * @param mode + * The directory modes. + * @param size_block + * The default number of chunks to read at a time with each chunk being 1-byte. + * Set to 0 to use default block read size. + * @param exclusive + * If TRUE, will fail when file already exists. + * If FALSE, will not fail if file already exists (existing file will be replaced). + * @param failures + * A list of paths and their respective status codes for copy failures. + * If 0, then this and statuses is ignored. * * @return * F_none on success. - * F_data_not if directory is empty (@fixme: unlikely due to '.' and '..' probably always being returned.). - * F_failure (with error bit) if failed to read directory information. * F_parameter (with error bit) if a parameter is invalid. - * F_memory_reallocation (with error bit) on memory reallocation error. - * F_directory_open (with error bit) on directory open error. - * F_directory_descriptor (with error bit) on directory file descriptor 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_access_denied (with error bit) on access denied. + * F_loop (with error bit) on loop error. + * F_file_found (with error bit) if a file was found while exclusive is TRUE. + * F_memory_out (with error bit) if out of memory. + * F_memory_allocation (with error bit) on memory allocation error. + * F_memory_reallocation (with error bit) on memory re-allocation error. + * F_prohibited (with error bit) if filesystem does not allow for removing. + * F_read_only (with error bit) if file is read-only. + * F_failure (with error bit) for any other (mkdir()) error. + * F_filesystem_quota_block (with error bit) if filesystem's disk blocks or inodes are exhausted. + * F_filesystem_quota_reached (with error bit) quota reached of filesystem is out of space. + * F_file_found (with error bit) of a directory aleady exists at the path. + * F_name (with error bit) on path name error. + * F_directory (with error bit) if a supposed directory in path is not actually a directory. + * F_number_overflow (with error bit) on overflow error. + * F_interrupted (with error bit) when program received an interrupt signal, halting create. + * F_file_open_max (with error bit) when system-wide max open files is reached. + * F_busy (with error bit) if filesystem is too busy to perforrm write. + * F_file_read (with error bit) on file read error. + * F_file_write (with error bit) on file write error. * - * @see alphasort() - * @see opendir() - * @see scandir() - * @see versionsort() + * @see f_file_copy() */ -#ifndef _di_fl_directory_list_ - extern f_return_status fl_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), const bool dereference, f_directory_listing *listing); -#endif // _di_fl_directory_list_ +#ifndef _di_fl_directory_copy_content_ + extern f_return_status fl_directory_copy_content(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures); +#endif // _di_fl_directory_copy_content_ /** * For some given path, print the names of each file and/or directory inside the directory, stored as a directory listing. @@ -254,9 +341,9 @@ extern "C" { * @see scandir() * @see versionsort() */ -#ifndef _di_fl_directory_list_at_ - extern f_return_status fl_directory_list_at(const int at_id, const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), const bool dereference, f_directory_listing *listing); -#endif // _di_fl_directory_list_at_ +#ifndef _di_fl_directory_list_ + extern f_return_status fl_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), const bool dereference, f_directory_listing *listing); +#endif // _di_fl_directory_list_ /** * Append a path string onto the destination path. diff --git a/level_1/fl_directory/c/private-directory.c b/level_1/fl_directory/c/private-directory.c index cf893d6..b043b13 100644 --- a/level_1/fl_directory/c/private-directory.c +++ b/level_1/fl_directory/c/private-directory.c @@ -7,39 +7,7 @@ extern "C" { #if !defined(_di_fl_directory_clone_) f_return_status private_fl_directory_clone(const f_string_static source, const f_string_static destination, const bool role, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) { - f_status status = f_directory_exists(source.string); - - if (F_status_is_error(status)) return status; - if (status == F_false) return F_status_set_error(F_directory); - - struct stat source_stat; - - memset(&source_stat, 0, sizeof(struct stat)); - - status = f_file_stat(source.string, F_false, &source_stat); - if (F_status_is_error(status)) return status; - - status = f_directory_exists(destination.string); - if (F_status_is_error(status)) return status; - - if (status == F_true) { - if (exclusive) { - return F_status_set_error(F_directory_found); - } - - status = f_file_change_mode(destination.string, source_stat.st_mode); - if (F_status_is_error(status)) return status; - } - else { - status = f_directory_create(destination.string, source_stat.st_mode); - if (F_status_is_error(status)) return status; - } - - if (role) { - status = f_file_change_owner(destination.string, source_stat.st_uid, source_stat.st_gid, F_true); - if (F_status_is_error(status)) return status; - } - + f_status status = F_none; f_directory_listing listing = f_directory_listing_initialize; status = private_fl_directory_list(source.string, 0, 0, F_false, &listing); @@ -119,6 +87,45 @@ extern "C" { source_sub.string = path_source_sub; destination_sub.string = path_destination_sub; + status = f_directory_exists(source_sub.string); + if (F_status_is_error(status)) break; + + if (status == F_false) { + status = F_status_set_error(F_directory); + break; + } + + { + struct stat source_stat; + + memset(&source_stat, 0, sizeof(struct stat)); + + status = f_file_stat(source_sub.string, F_false, &source_stat); + if (F_status_is_error(status)) break; + + status = f_directory_exists(destination_sub.string); + if (F_status_is_error(status)) break; + + if (status == F_true) { + if (exclusive) { + status = F_status_set_error(F_directory_found); + break; + } + + status = f_file_change_mode(destination_sub.string, source_stat.st_mode); + if (F_status_is_error(status)) break; + } + else { + status = f_directory_create(destination_sub.string, source_stat.st_mode); + if (F_status_is_error(status)) break; + } + + if (role) { + status = f_file_change_owner(destination_sub.string, source_stat.st_uid, source_stat.st_gid, F_true); + if (F_status_is_error(status)) break; + } + } + status = private_fl_directory_clone(source_sub, destination_sub, role, size_block, exclusive, failures); } // for @@ -226,27 +233,7 @@ extern "C" { #if !defined(_di_fl_directory_copy_) f_return_status private_fl_directory_copy(const f_string_static source, const f_string_static destination, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) { - f_status status = f_directory_exists(source.string); - - if (F_status_is_error(status)) return status; - if (status == F_false) return F_status_set_error(F_directory); - - status = f_directory_exists(destination.string); - if (F_status_is_error(status)) return status; - - if (status == F_true) { - if (exclusive) { - return F_status_set_error(F_directory_found); - } - - status = f_file_change_mode(destination.string, mode.directory); - if (F_status_is_error(status)) return status; - } - else { - status = f_directory_create(destination.string, mode.directory); - if (F_status_is_error(status)) return status; - } - + f_status status = F_none; f_directory_listing listing = f_directory_listing_initialize; status = private_fl_directory_list(source.string, 0, 0, F_false, &listing); @@ -326,6 +313,31 @@ extern "C" { source_sub.string = path_source_sub; destination_sub.string = path_destination_sub; + status = f_directory_exists(source_sub.string); + if (F_status_is_error(status)) break; + + if (status == F_false) { + status = F_status_set_error(F_directory); + break; + } + + status = f_directory_exists(destination_sub.string); + if (F_status_is_error(status)) break; + + if (status == F_true) { + if (exclusive) { + status = F_status_set_error(F_directory_found); + break; + } + + status = f_file_change_mode(destination_sub.string, mode.directory); + if (F_status_is_error(status)) break; + } + else { + status = f_directory_create(destination_sub.string, mode.directory); + if (F_status_is_error(status)) break; + } + status = private_fl_directory_copy(source_sub, destination_sub, mode, size_block, exclusive, failures); } // for diff --git a/level_1/fl_directory/c/private-directory.h b/level_1/fl_directory/c/private-directory.h index b8f4068..698faa8 100644 --- a/level_1/fl_directory/c/private-directory.h +++ b/level_1/fl_directory/c/private-directory.h @@ -62,7 +62,6 @@ extern "C" { * F_busy (with error bit) if filesystem is too busy to perforrm write. * F_file_read (with error bit) on file read error. * F_file_write (with error bit) on file write error. - * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see fl_directory_clone() */ @@ -121,7 +120,6 @@ extern "C" { * F_busy (with error bit) if filesystem is too busy to perforrm write. * F_file_read (with error bit) on file read error. * F_file_write (with error bit) on file write error. - * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see fl_directory_clone() */ @@ -175,7 +173,6 @@ extern "C" { * F_busy (with error bit) if filesystem is too busy to perforrm write. * F_file_read (with error bit) on file read error. * F_file_write (with error bit) on file write error. - * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see fl_directory_copy() */ @@ -232,7 +229,6 @@ extern "C" { * F_busy (with error bit) if filesystem is too busy to perforrm write. * F_file_read (with error bit) on file read error. * F_file_write (with error bit) on file write error. - * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see fl_directory_copy() */ diff --git a/level_1/fl_string/c/string.c b/level_1/fl_string/c/string.c index cc5cbba..d4eeb4a 100644 --- a/level_1/fl_string/c/string.c +++ b/level_1/fl_string/c/string.c @@ -1062,6 +1062,38 @@ extern "C" { } #endif // _di_fl_string_dynamic_terminate_ +#ifndef _di_fl_string_dynamic_terminate_after_ + f_return_status fl_string_dynamic_terminate_after(f_string_dynamic *destination) { + #ifndef _di_level_1_parameter_checking_ + if (destination == 0) return F_status_set_error(F_parameter); + if (destination->used > destination->size) return F_status_set_error(F_parameter); + #endif // _di_level_1_parameter_checking_ + + if (destination->used > 0) { + for (f_string_length i = destination->used; i > 0; i--, destination->used--) { + if (destination->string[i] == 0) continue; + break; + } // for + } + + if (destination->used + 1 > f_string_length_size) return F_status_set_error(F_string_too_large); + + const f_string_length total = destination->used + 1; + + if (total > destination->size) { + f_status status = F_none; + + f_macro_string_dynamic_resize(status, (*destination), total); + if (F_status_is_error(status)) return status; + } + + destination->string[destination->used] = 0; + destination->used = total - 1; + + return F_none; + } +#endif // _di_fl_string_dynamic_terminate_after_ + #ifndef _di_fl_string_mash_ f_return_status fl_string_mash(const f_string glue, const f_string_length glue_length, const f_string source, const f_string_length length, f_string_dynamic *destination) { #ifndef _di_level_1_parameter_checking_ diff --git a/level_1/fl_string/c/string.h b/level_1/fl_string/c/string.h index d8ed5a6..5a21c5c 100644 --- a/level_1/fl_string/c/string.h +++ b/level_1/fl_string/c/string.h @@ -1191,6 +1191,29 @@ extern "C" { #endif // _di_fl_string_dynamic_terminate_ /** + * Guarantee that an end of string (NULL) exists at the end of the string. + * + * This ensures that the terminating NULL not only exists but is not counted in destination.used. + * + * This is intended to be used for anything requiring NULL terminated strings whose used length cannot be counted. + * This will reallocate more space if necessary. + * + * If destination size is 0, then it will be reallocated and have the NULL assigned at index 0. + * + * @param destination + * The new string, which will be allocated or reallocated as necessary. + * + * @return + * F_none on success. + * F_parameter (with error bit) if a parameter is invalid. + * F_memory_reallocation (with error bit) on memory reallocation error. + * F_string_too_large (with error bit) if string is too large to fit into the buffer. + */ +#ifndef _di_fl_string_dynamic_terminate_after_ + extern f_return_status fl_string_dynamic_terminate_after(f_string_dynamic *destination); +#endif // _di_fl_string_dynamic_terminate_after_ + +/** * Append the source string onto the destination with the glue in between. * * If the destination string is empty, then no glue is appended. -- 1.8.3.1