]> Kevux Git Server - fll/commitdiff
Update: todo documentation, directory copy and clone functions, update comment docume...
authorKevin Day <thekevinday@gmail.com>
Sat, 30 May 2020 01:00:41 +0000 (20:00 -0500)
committerKevin Day <thekevinday@gmail.com>
Sat, 30 May 2020 05:00:41 +0000 (00:00 -0500)
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
level_1/fl_directory/c/directory.c
level_1/fl_directory/c/directory.h
level_1/fl_directory/c/private-directory.c
level_1/fl_directory/c/private-directory.h
level_1/fl_string/c/string.c
level_1/fl_string/c/string.h

index 8365f802972d6e93bbf51900ccb89a332afb4b81..22b03227f64ab7cf36315c54c905b784df5e844b 100644 (file)
@@ -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.
index 3b4a5026bad03132ef6062dde7dab4ffb16db711..b7379240c661a97b3a6c3f6c9641f8694a975977 100644 (file)
@@ -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) {
index c637c16fc20b598a485d2053d1c6286a0761d9ee..d848c6cf73672bfe72b5bb8f9c0d81a5109c36b9 100644 (file)
@@ -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.
index cf893d6f6cbe07da974f3856558e569a7a2bcfb1..b043b131f7f2b6f1f54662351e923674208f7480 100644 (file)
@@ -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
 
index b8f4068b5d2f2150e9f9dac46a8d0e62e56dae3f..698faa8f016a382cec7d8c74843cb8fdb36463ea 100644 (file)
@@ -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()
  */
index cc5cbba7f1481ca370bc8d9f8d521422a777b138..d4eeb4a776e9905c4761ae7072392cfe49a4d823 100644 (file)
@@ -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_
index d8ed5a601a38190d1377e8bc66942975c939c886..5a21c5c45d25c23103606184f767fa00e43c6bc6 100644 (file)
@@ -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.