Implement file move functions.
- There will need to be future changes to allow for moving across filesystems.
- This move across filesystems may need to be an fll_file_move() so that it can either do a directory clone or a file clone.
Fix a typo 'perforrm', which should instead be 'perform'.
Add 'F_mount' status code.
Implement the move section operation.
* 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 perforrm write.
+ * 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_descriptor (with error bit) for bad directory descriptor for at_id.
* F_file_found (with error bit) if a file aleady exists at the path.
* 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 perforrm write.
+ * 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_descriptor (with error bit) for bad directory descriptor for at_id.
* F_file_found (with error bit) if a file aleady exists at the path (when calling utimensat()).
}
#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_level_0_parameter_checking_
+ if (source == 0) return F_status_set_error(F_parameter);
+ if (destination == 0) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ if (rename(source, destination) < 0) {
+ if (errno == EACCES) return F_status_set_error(F_access_denied);
+ if (errno == EBUSY) return F_status_set_error(F_busy);
+ if (errno == EDQUOT) return F_status_set_error(F_filesystem_quota_block);
+ if (errno == EFAULT) return F_status_set_error(F_buffer);
+ if (errno == EINVAL) return F_status_set_error(F_parameter);
+ if (errno == EISDIR) return F_status_set_error(F_file_type_directory);
+ if (errno == ELOOP) return F_status_set_error(F_loop);
+ if (errno == EMLINK) return F_status_set_error(F_link);
+ if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+ if (errno == ENOENT) return F_status_set_error(F_file_found_not);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+ if (errno == ENOSPC) return F_status_set_error(F_space_not);
+ if (errno == ENOTDIR) return F_status_set_error(F_directory);
+ if (errno == ENOTEMPTY) return F_status_set_error(F_directory_empty_not);
+ if (errno == EEXIST) return F_status_set_error(F_directory_empty_not);
+ if (errno == EPERM) return F_status_set_error(F_prohibited);
+ if (errno == EROFS) return F_status_set_error(F_read_only);
+ if (errno == EXDEV) return F_status_set_error(F_mount);
+
+ return F_status_set_error(F_failure);
+ }
+
+ return F_none;
+ }
+#endif // _di_f_file_move_
+
+#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_level_0_parameter_checking_
+ if (source == 0) return F_status_set_error(F_parameter);
+ if (destination == 0) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ if (renameat(at_id, source, to_id, destination) < 0) {
+ if (errno == EACCES) return F_status_set_error(F_access_denied);
+ if (errno == EBUSY) return F_status_set_error(F_busy);
+ if (errno == EDQUOT) return F_status_set_error(F_filesystem_quota_block);
+ if (errno == EFAULT) return F_status_set_error(F_buffer);
+ if (errno == EINVAL) return F_status_set_error(F_parameter);
+ if (errno == EISDIR) return F_status_set_error(F_file_type_directory);
+ if (errno == ELOOP) return F_status_set_error(F_loop);
+ if (errno == EMLINK) return F_status_set_error(F_link);
+ if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+ if (errno == ENOENT) return F_status_set_error(F_file_found_not);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+ if (errno == ENOSPC) return F_status_set_error(F_space_not);
+ if (errno == ENOTDIR) return F_status_set_error(F_directory);
+ if (errno == ENOTEMPTY) return F_status_set_error(F_directory_empty_not);
+ if (errno == EEXIST) return F_status_set_error(F_directory_empty_not);
+ if (errno == EPERM) return F_status_set_error(F_prohibited);
+ if (errno == EROFS) return F_status_set_error(F_read_only);
+ if (errno == EXDEV) return F_status_set_error(F_mount);
+ if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
+
+ return F_status_set_error(F_failure);
+ }
+
+ return F_none;
+ }
+#endif // _di_f_file_move_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) {
#ifndef _di_level_0_parameter_checking_
* F_access_group (with error bit) if the current user does not have access to assign the specified group.
* F_access_mode (with error bit) if the current user does not have access to assign the file mode.
* F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
- * F_busy (with error bit) if filesystem is too busy to perforrm write.
+ * 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_file_found (with error bit) if a file was found while exclusive is TRUE.
* F_file_open_max (with error bit) when system-wide max open files is reached.
* @return
* F_none on success.
* F_access_denied (with error bit) on access denied.
- * F_busy (with error bit) if filesystem is too busy to perforrm write.
+ * 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_file_found (with error bit) if a file was found while exclusive is TRUE.
* F_file_open_max (with error bit) when system-wide max open files is reached.
* @return
* F_none on success.
* F_access_denied (with error bit) on access denied.
- * F_busy (with error bit) if filesystem is too busy to perforrm write.
+ * 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_file_found (with error bit) if a file was found while exclusive is TRUE.
* F_file_open_max (with error bit) when system-wide max open files is reached.
* @return
* F_none on success.
* F_access_denied (with error bit) on access denied.
- * F_busy (with error bit) if filesystem is too busy to perforrm write.
+ * 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_file_found (with error bit) if a file was found while exclusive is TRUE.
* F_file_open_max (with error bit) when system-wide max open files is reached.
* 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 perforrm write.
+ * F_busy (with error bit) if filesystem is too busy to perform write.
* F_file_found (with error bit) if a file aleady exists at the path.
* F_file_found_not (with error bit) if a parent path in point does not exist or is a broken symlink.
* F_filesystem_quota_block (with error bit) if filesystem's disk blocks or inodes are exhausted.
* @return
* F_none on success.
* F_access_denied (with error bit) on access denied.
- * F_busy (with error bit) if filesystem is too busy to perforrm write.
+ * F_busy (with error bit) if filesystem is too busy to perform write.
* F_buffer (with error bit) if the buffer is invalid.
* F_directory (with error bit) if a supposed directory in path is not actually a directory.
* F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
* 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 perforrm write.
+ * 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_file_found (with error bit) if a file aleady exists at the path.
* F_file_found_not (with error bit) if a parent path in point does not exist or is a broken symlink.
* 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 perforrm write.
+ * 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_descriptor (with error bit) for bad directory descriptor for at_id.
* F_file_found (with error bit) if a file aleady exists at the path.
#endif // _di_f_file_mode_to_mode_
/**
+ * Move 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.
+ *
+ * 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.
+ *
+ * @param source
+ * The path to the file to copy from.
+ * @param destination
+ * The path to copy to.
+ *
+ * @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_mount (with error bit) if source and destination are not within the same mounted filesystems.
+ * 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.
+ *
+ * @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_
+
+/**
+ * Move 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.
+ *
+ * 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.
+ *
+ * @param at_id
+ * The parent directory, as an open directory file descriptor, in which the source is relative to.
+ * @param to_id
+ * The parent directory, as an open directory file descriptor, in which the destination is relative to.
+ * @param source
+ * The path to the file to copy from.
+ * @param destination
+ * The path to copy to.
+ *
+ * @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_descriptor (with error bit) for bad directory descriptor for at_id or to_id.
+ * 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_mount (with error bit) if source and destination are not within the same mounted filesystems.
+ * 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.
+ *
+ * @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_
+
+/**
* Get the base name of a file path.
*
* @param path
* 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 perforrm write.
+ * 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_descriptor (with error bit) for bad directory descriptor for at_id.
* F_file_found (with error bit) if a file aleady exists at the path.
* 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 perforrm write.
+ * 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_descriptor (with error bit) for bad directory descriptor for at_id.
* F_file_found (with error bit) if a file aleady exists at the path (when calling utimensat()).
* @return
* F_none on success.
* F_access_denied (with error bit) on access denied.
- * F_busy (with error bit) if filesystem is too busy to perforrm write.
+ * 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_file_found (with error bit) if a file was found while exclusive is TRUE.
* F_file_open_max (with error bit) when system-wide max open files is reached.
* @return
* F_none on success.
* F_access_denied (with error bit) on access denied.
- * F_busy (with error bit) if filesystem is too busy to perforrm write.
+ * 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_file_found (with error bit) if a file was found while exclusive is TRUE.
* F_file_open_max (with error bit) when system-wide max open files is reached.
* @return
* F_none on success.
* F_access_denied (with error bit) on access denied.
- * F_busy (with error bit) if filesystem is too busy to perforrm write.
+ * 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_file_found (with error bit) if a file was found while exclusive is TRUE.
* F_file_open_max (with error bit) when system-wide max open files is reached.
* 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 perforrm write.
+ * F_busy (with error bit) if filesystem is too busy to perform write.
* F_file_found (with error bit) if a file aleady exists at the path.
* F_file_found_not (with error bit) if a parent path in point does not exist or is a broken symlink.
* F_filesystem_quota_block (with error bit) if filesystem's disk blocks or inodes are exhausted.
* @return
* F_none on success.
* F_access_denied (with error bit) on access denied.
- * F_busy (with error bit) if filesystem is too busy to perforrm write.
+ * F_busy (with error bit) if filesystem is too busy to perform write.
* F_buffer (with error bit) if the buffer is invalid.
* F_directory (with error bit) if a supposed directory in path is not actually a directory.
* F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
F_loop,
F_maybe,
F_memory_out,
+ F_mount,
F_name,
F_parameter,
F_pipe,
case F_memory_out:
*string = FL_status_string_memory_out;
break;
+ case F_mount:
+ *string = FL_status_string_mount;
+ break;
case F_name:
*string = FL_status_string_name;
break;
#define FL_status_string_loop "F_loop"
#define FL_status_string_maybe "F_maybe"
#define FL_status_string_memory_out "F_memory_out"
+ #define FL_status_string_mount "F_mount"
#define FL_status_string_name "F_name"
#define FL_status_string_parameter "F_parameter"
#define FL_status_string_pipe "F_pipe"
#define FL_status_string_loop_length 6
#define FL_status_string_maybe_length 7
#define FL_status_string_memory_out_length 12
+ #define FL_status_string_mount_length 7
#define FL_status_string_name_length 6
#define FL_status_string_parameter_length 11
#define FL_status_string_pipe_length 6
return F_none;
}
+ if (fl_string_compare(string, FL_status_string_mount, length, FL_status_string_mount_length) == F_equal_to) {
+ *code = F_mount;
+ return F_none;
+ }
+
if (fl_string_compare(string, FL_status_string_name, length, FL_status_string_name_length) == F_equal_to) {
*code = F_name;
return F_none;
f_string_length_t destination_length = 0;
- f_mode_t mode = f_mode_t_initialize;f_macro_mode_t_set_default_umask(mode, data.umask);
+ f_mode_t mode = f_mode_t_initialize;
+
+ f_macro_mode_t_set_default_umask(mode, data.umask);
if (data.verbosity == fake_verbosity_verbose) {
recurse.verbose = f_type_output;
const f_array_length_t total = arguments.used -1;
f_status_t status_file = F_none;
+ f_string_length_t destination_length = 0;
+
+ bool existing = F_true;
+
+ // in this case, the destination could be a file, so confirm this.
+ if (arguments.used == 2) {
+ status_file = f_directory_is(arguments.array[total].string);
+
+ if (F_status_is_error(status_file)) {
+ fake_print_message_file(data, F_status_set_fine(status_file), "f_directory_is", arguments.array[1].string, "identify", F_false, F_true, data_make->print);
+ *status = F_status_set_error(F_failure);
+ return;
+ }
+
+ if (status_file == F_false || status_file == F_file_found_not) {
+ existing = F_false;
+ }
+ }
+
for (f_array_length_t i = 0; i < total; i++) {
- status_file = f_directory_is(arguments.array[i].string);
+ destination_length = arguments.array[total].used;
- if (status_file == F_true) {
- // @todo: *status = fl_directory_copy();
+ if (existing) {
+ destination_length += arguments.array[i].used + 1;
}
- else if (status_file == F_true) {
- // @todo: *status = f_file_copy();
+
+ char destination[destination_length + 1];
+
+ memcpy(destination, arguments.array[total].string, arguments.array[total].used);
+
+ if (existing) {
+ memcpy(destination + arguments.array[total].used + 1, arguments.array[i].string, arguments.array[i].used);
+ destination[arguments.array[total].used] = f_path_separator[0];
}
- else if (F_status_is_error(status_file)) {
- // @todo
+
+ destination[destination_length] = 0;
+
+ status_file = f_file_move(arguments.array[i].string, destination);
+
+ 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);
*status = F_status_set_error(F_failure);
- break;
+ }
+ else if (data.verbosity == fake_verbosity_verbose) {
+ printf("Moved '%s' to '%s'.%c", arguments.array[i].string, destination, f_string_eol[0]);
}
} // for