From: Kevin Day Date: Fri, 29 May 2020 00:23:59 +0000 (-0500) Subject: Progress: add more directory and file related functions, other changes X-Git-Tag: 0.5.0~234 X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=12a51ff696b3aa6e42bdeea6c808d94c494ed5ad;p=fll Progress: add more directory and file related functions, other changes This was started with the intention of providing all of the *_at() functions. However, the POSIX spec seems to fall short in many areas making this more difficult than this should be. I partially rolled back some of the planned changes and this changeset is the result. I have observed that the function return documentation needs to be updated, but this will be done at a later time. There will need to be some intensive testing later on but for now I am committing and moving forward. --- diff --git a/level_0/f_directory/c/directory.c b/level_0/f_directory/c/directory.c index dd36634..e90d673 100644 --- a/level_0/f_directory/c/directory.c +++ b/level_0/f_directory/c/directory.c @@ -43,7 +43,7 @@ extern "C" { if (errno == EEXIST) return F_status_set_error(F_file_found); if (errno == ENAMETOOLONG) return F_status_set_error(F_name); if (errno == EFAULT) return F_status_set_error(F_buffer); - if (errno == EINVAL || errno == EBADF) return F_status_set_error(F_parameter); + if (errno == EINVAL) return F_status_set_error(F_parameter); if (errno == ELOOP) return F_status_set_error(F_loop); if (errno == EMLINK) return F_status_set_error(F_directory_link_max); if (errno == ENOENT) return F_status_set_error(F_file_found_not); @@ -52,6 +52,7 @@ extern "C" { if (errno == ENOTDIR) return F_status_set_error(F_directory); if (errno == EPERM) return F_status_set_error(F_prohibited); if (errno == EROFS) return F_status_set_error(F_read_only); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); return F_status_set_error(F_failure); } @@ -85,6 +86,32 @@ extern "C" { } #endif // _di_f_directory_exists_ +#ifndef _di_f_directory_exists_at_ + f_return_status f_directory_exists_at(const int at_id, const f_string path, const int flag) { + struct stat file_stat; + + memset(&file_stat, 0, sizeof(struct stat)); + + if (fstatat(at_id, path, &file_stat, flag) < 0) { + if (errno == ENAMETOOLONG) return F_status_set_error(F_name); + if (errno == EFAULT) return F_status_set_error(F_buffer); + if (errno == ENOMEM) return F_status_set_error(F_memory_out); + if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow); + if (errno == ENOTDIR) return F_false; + if (errno == ENOENT) return F_file_found_not; + if (errno == EACCES) return F_status_set_error(F_access_denied); + if (errno == ELOOP) return F_status_set_error(F_loop); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); + + return F_status_set_error(F_file_stat); + } + + if ((file_stat.st_mode & S_IFMT) == S_IFDIR) return F_true; + + return F_false; + } +#endif // _di_f_directory_exists_at_ + #ifndef _di_f_directory_is_ f_return_status f_directory_is(const f_string path) { struct stat file_stat; @@ -111,12 +138,12 @@ extern "C" { #endif // _di_f_directory_is_ #ifndef _di_f_directory_is_at_ - f_return_status f_directory_is_at(const int file_id, const f_string path, const bool follow) { + f_return_status f_directory_is_at(const int at_id, const f_string path, const int flag) { struct stat file_stat; memset(&file_stat, 0, sizeof(struct stat)); - if (fstatat(file_id, path, &file_stat, follow ? 0 : AT_SYMLINK_NOFOLLOW) < 0) { + if (fstatat(at_id, path, &file_stat, flag) < 0) { if (errno == ENAMETOOLONG) return F_status_set_error(F_name); if (errno == EFAULT) return F_status_set_error(F_buffer); if (errno == ENOMEM) return F_status_set_error(F_memory_out); @@ -125,6 +152,7 @@ extern "C" { if (errno == ENOENT) return F_file_found_not; if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == ELOOP) return F_status_set_error(F_loop); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); return F_status_set_error(F_file_stat); } @@ -190,6 +218,82 @@ extern "C" { } #endif // _di_f_directory_list_ +#ifndef _di_f_directory_open_ + f_return_status f_directory_open(const f_string path, const bool dereference, int *id) { + #ifndef _di_level_0_parameter_checking_ + if (id == 0) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + int flag = f_directory_flag_directory | f_directory_flag_close_execute | f_directory_flag_path; + + if (dereference) { + flag |= f_directory_flag_no_follow; + } + + *id = open(path, flag); + + if (*id < 0) { + if (errno == EACCES) return F_status_set_error(F_access_denied); + if (errno == ENAMETOOLONG) return F_status_set_error(F_name); + if (errno == EFAULT) return F_status_set_error(F_buffer); + if (errno == EFBIG || errno == EOVERFLOW) return F_status_set_error(F_number_overflow); + if (errno == EINTR) return F_status_set_error(F_interrupted); + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == ELOOP) return F_status_set_error(F_loop); + if (errno == ENFILE) return F_status_set_error(F_file_open_max); + if (errno == ENOENT) return F_status_set_error(F_directory_found_not); + if (errno == ENOTDIR) return F_status_set_error(F_file_type_not_directory); + if (errno == ENOMEM) return F_status_set_error(F_memory_out); + if (errno == ENOSPC) return F_status_set_error(F_space_not); + if (errno == EPERM) return F_status_set_error(F_prohibited); + if (errno == EROFS) return F_status_set_error(F_read_only); + + return F_status_set_error(F_failure); + } + + return F_none; + } +#endif // _di_f_directory_open_ + +#ifndef _di_f_directory_open_at_ + f_return_status f_directory_open_at(const int at_id, const f_string path, const bool dereference, int *id) { + #ifndef _di_level_0_parameter_checking_ + if (at_id <= 0) return F_status_set_error(F_parameter); + if (id == 0) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + int flag = f_directory_flag_directory | f_directory_flag_close_execute | f_directory_flag_path; + + if (dereference) { + flag |= f_directory_flag_no_follow; + } + + *id = openat(at_id, path, flag); + + if (*id < 0) { + if (errno == EACCES) return F_status_set_error(F_access_denied); + if (errno == ENAMETOOLONG) return F_status_set_error(F_name); + if (errno == EFAULT) return F_status_set_error(F_buffer); + if (errno == EFBIG || errno == EOVERFLOW) return F_status_set_error(F_number_overflow); + if (errno == EINTR) return F_status_set_error(F_interrupted); + if (errno == EINVAL) return F_status_set_error(F_parameter); + if (errno == ELOOP) return F_status_set_error(F_loop); + if (errno == ENFILE) return F_status_set_error(F_file_open_max); + if (errno == ENOENT) return F_status_set_error(F_directory_found_not); + if (errno == ENOTDIR) return F_status_set_error(F_file_type_not_directory); + if (errno == ENOMEM) return F_status_set_error(F_memory_out); + if (errno == ENOSPC) return F_status_set_error(F_space_not); + if (errno == EPERM) return F_status_set_error(F_prohibited); + if (errno == EROFS) return F_status_set_error(F_read_only); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); + + return F_status_set_error(F_failure); + } + + return F_none; + } +#endif // _di_f_directory_open_at_ + #ifndef _di_f_directory_remove_ f_return_status f_directory_remove(const f_string path, const int recursion_max, const bool preserve) { #ifndef _di_level_0_parameter_checking_ diff --git a/level_0/f_directory/c/directory.h b/level_0/f_directory/c/directory.h index 8b84d43..1a4075a 100644 --- a/level_0/f_directory/c/directory.h +++ b/level_0/f_directory/c/directory.h @@ -41,18 +41,59 @@ extern "C" { #endif /** + * Directory AT_* define related functionality. + */ +#ifndef _di_f_directory_at_ + #define f_directory_at_current_working -100 + #define f_directory_at_symlink_follow 0x400 + #define f_directory_at_symlink_follow_no 0x100 + #define f_directory_at_remove_directory 0x200 + #define f_directory_at_automount_no 0x800 + #define f_directory_at_path_empty 0x1000 + #define f_directory_at_statx_sync_type 0x6000 + #define f_directory_at_statx_sync_as_stat 0x0000 + #define f_directory_at_statx_sync_force 0x2000 + #define f_directory_at_statx_sync_no 0x4000 +#endif // _di_f_directory_at_ + +/** + * Directory flag related functionality. + */ +#ifndef _di_f_directory_flag_ + + // directory open flags + #define f_directory_flag_append O_APPEND + #define f_directory_flag_asynchronous O_ASYNC + #define f_directory_flag_create O_CREAT + #define f_directory_flag_close_execute O_CLOEXEC + #define f_directory_flag_direct O_DIRECT + #define f_directory_flag_directory O_DIRECTORY + #define f_directory_flag_exclusive O_EXCL + #define f_directory_flag_large_file O_LARGEFILE + #define f_directory_flag_no_access_time O_NOATIME + #define f_directory_flag_no_follow O_NOFOLLOW + #define f_directory_flag_no_tty O_NOCTTY + #define f_directory_flag_non_blocking O_NONBLOCK + #define f_directory_flag_path 010000000 + #define f_directory_flag_read_only O_RDONLY + #define f_directory_flag_read_write O_RDWR + #define f_directory_flag_synchronous O_SYNC + #define f_directory_flag_synchronous_direct O_DSYNC + #define f_directory_flag_temporary O_TMPFILE + #define f_directory_flag_truncate O_TRUNC + #define f_directory_flag_write_only O_WRONLY +#endif // _di_f_directory_flag_ + +/** * Provide limitations and related defines. * - * The name max 255 because the directory name size is 256. - * The last 1 is for the NULL character. - * * The directory max descriptors is more of a default than a rule. * This is generally used for nftw() recursive operations to reduce the number of open file descriptors during recursion. */ #ifndef _di_f_directory_limitations_ #define f_directory_default_allocation_step f_memory_default_allocation_step - #define f_directory_name_max 255 + #define f_directory_name_max NAME_MAX #define f_directory_descriptors_max 255 #endif // _di_f_directory_limitations_ @@ -91,7 +132,7 @@ extern "C" { * Create a directory at the given path within the directories specified by the file descriptor. * * @param at_id - * The file descriptor in which the directory will be created within. + * The parent directory, as an open directory file descriptor, in which path is relative to. * @param path * The path file name. * @param mode @@ -113,8 +154,9 @@ extern "C" { * F_name (with error bit) on path name error. * F_directory_link_max (with error bit) max links limit reached or exceeded. * 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. * - * @see mkdir() + * @see mkdirat() */ #ifndef _di_f_directory_create_at_ extern f_return_status f_directory_create_at(const int at_id, const f_string path, const mode_t mode); @@ -137,13 +179,41 @@ extern "C" { * F_loop (with error bit) if a loop occurred. * F_parameter (with error bit) if a parameter is invalid. * - * @see fstat() + * @see stat() */ #ifndef _di_f_directory_exists_ extern f_return_status f_directory_exists(const f_string path); #endif // _di_f_directory_exists_ /** + * Identify whether or not a file exists at the given path and if that file is a directory or a symlink to a directory. + * + * @param at_id + * The parent directory, as an open directory file descriptor, in which path is relative to. + * @param path + * The path file name. + * @param flag + * Any valid flag, such as f_directory_at_path_empty, f_directory_at_automount_no, or f_directory_at_symlink_follow_no. + * + * @return + * F_true if path was found and path is a directory (or a symlink to a directory). + * F_false if path was found and path is not a directory. + * F_file_found_not if the path was not found. + * F_name (with error bit) if the name is somehow invalid. + * F_memory_out (with error bit) if out of memory. + * F_number_overflow (with error bit) on overflow error. + * F_access_denied (with error bit) if access to the file was denied. + * F_loop (with error bit) if a loop occurred. + * F_parameter (with error bit) if a parameter is invalid. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. + * + * @see fstatat() + */ +#ifndef _di_f_directory_exists_at_ + extern f_return_status f_directory_exists_at(const int at_id, const f_string path, const int flag); +#endif // _di_f_directory_exists_at_ + +/** * Identify whether or not a file exists at the given path and if that file is a directory. * * @param path @@ -160,7 +230,7 @@ extern "C" { * F_loop (with error bit) if a loop occurred. * F_parameter (with error bit) if a parameter is invalid. * - * @see fstat() + * @see stat() */ #ifndef _di_f_directory_is_ extern f_return_status f_directory_is(const f_string path); @@ -169,13 +239,12 @@ extern "C" { /** * Identify whether or not a file exists at the given path within the parent directory and if that file is a directory. * - * @param file_id - * The file descriptor representing the parent directory to search within. + * @param at_id + * The parent directory, as an open directory file descriptor, in which path is relative to. * @param path * The path file name. - * @param follow - * Set to TRUE to follow symbolic links when determining if path is a file. - * Set to FALSE to not follow. + * @param flag + * Any valid flag, such as f_directory_at_path_empty, f_directory_at_automount_no, or f_directory_at_symlink_follow_no. * * @return * F_true if path was found and path is a directory. @@ -187,11 +256,12 @@ extern "C" { * F_access_denied (with error bit) if access to the file was denied. * F_loop (with error bit) if a loop occurred. * F_parameter (with error bit) if a parameter is invalid. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see fstatat() */ #ifndef _di_f_directory_is_at_ - extern f_return_status f_directory_is_at(const int file_id, const f_string path, const bool follow); + extern f_return_status f_directory_is_at(const int at_id, const f_string path, const int flag); #endif // _di_f_directory_is_at_ /** @@ -227,6 +297,58 @@ extern "C" { #endif // _di_f_directory_list_ /** + * Open the directory specified by path. + * + * This opens with O_PATH and O_CLOEXEC. + * + * @param path + * The path file name. + * @param dereference + * Set to TRUE to dereferenc symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. + * @param id + * The file descriptor. + * This is updated with the result of open() or openat(). + * + * @return + * F_none on success. + * F_failure (with error bit) if failed to read directory information. + * F_parameter (with error bit) if a parameter is invalid. + * + * @see open() + */ +#ifndef _di_f_directory_open_ + extern f_return_status private_f_directory_open(const f_string path, const bool dereference, int *id) f_gcc_attribute_visibility_internal; +#endif // _di_f_directory_open_ + +/** + * Open the directory specified by path. + * + * This opens with O_PATH and O_CLOEXEC. + * + * @param at_id + * The parent directory, as an open directory file descriptor, in which path is relative to. + * @param path + * The path file name. + * @param dereference + * Set to TRUE to dereferenc symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. + * @param id + * The file descriptor. + * This is updated with the result of open() or openat(). + * + * @return + * F_none on success. + * F_failure (with error bit) if failed to read directory information. + * F_parameter (with error bit) if a parameter is invalid. + * + * @see openat() + */ +#ifndef _di_f_directory_open_at_ + extern f_return_status private_f_directory_open_at(const int at_id, const f_string path, const bool dereference, int *id) f_gcc_attribute_visibility_internal; +#endif // _di_f_directory_open_at_ + +/** * Remove a directory and possibly its contents. * * @param path diff --git a/level_0/f_file/c/file.c b/level_0/f_file/c/file.c index c60e7da..dfb1678 100644 --- a/level_0/f_file/c/file.c +++ b/level_0/f_file/c/file.c @@ -31,23 +31,93 @@ extern "C" { #endif // _di_f_file_change_mode_ #ifndef _di_f_file_change_mode_at_ - f_return_status f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode, const int flags) { - return private_f_file_change_mode_at(at_id, path, mode, flags); + f_return_status f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode) { + return private_f_file_change_mode_at(at_id, path, mode); } #endif // _di_f_file_change_mode_at_ #ifndef _di_f_file_change_owner_ f_return_status f_file_change_owner(const f_string path, const uid_t uid, const gid_t gid, const bool dereference) { + #ifndef _di_level_0_parameter_checking_ + if (uid < 0 && gid < 0) 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_ + return private_f_file_change_owner(path, uid, gid, dereference); } #endif // _di_f_file_change_owner_ #ifndef _di_f_file_change_owner_at_ - f_return_status f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flags) { - return private_f_file_change_owner_at(at_id, path, uid, gid, flags); + f_return_status f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag) { + #ifndef _di_level_0_parameter_checking_ + if (uid < 0 && gid < 0) 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_ + + return private_f_file_change_owner_at(at_id, path, uid, gid, flag); } #endif // _di_f_file_change_owner_at_ +#ifndef _di_f_file_clone_ + f_return_status f_file_clone(const f_string source, const f_string destination, const bool role, const f_number_unsigned size_block, const bool exclusive) { + f_status status = F_none; + struct stat source_stat; + + memset(&source_stat, 0, sizeof(struct stat)); + + status = private_f_file_stat(source, F_false, &source_stat); + if (F_status_is_error(status)) return status; + + if (f_macro_file_type_is_regular(source_stat.st_mode)) { + status = private_f_file_create(destination, source_stat.st_mode, exclusive); + if (F_status_is_error(status)) return status; + + if (!exclusive) { + status = private_f_file_change_mode(destination, source_stat.st_mode); + if (F_status_is_error(status)) return status; + } + + if (role) { + status = private_f_file_change_owner(destination, source_stat.st_uid, source_stat.st_gid, F_false); + if (F_status_is_error(status)) return status; + } + + return private_f_file_copy_content(source, destination, size_block == 0 ? f_file_default_read_size : size_block); + } + else if (f_macro_file_type_is_link(source_stat.st_mode)) { + status = private_f_file_link(destination, source); + if (F_status_set_fine(status) == F_file_found) { + if (exclusive) return status; + } + else if (F_status_is_error(status)) { + return status; + } + + status = private_f_file_change_mode(destination, source_stat.st_mode); + if (F_status_is_error(status)) return status; + + if (role) { + status = private_f_file_change_owner(destination, source_stat.st_uid, source_stat.st_gid, F_false); + if (F_status_is_error(status)) return status; + } + + return F_none; + } + + return F_unsupported; + } +#endif // _di_f_file_clone_ + +#ifndef _di_f_file_close_ + f_return_status f_file_close(int *id) { + #ifndef _di_level_0_parameter_checking_ + if (id == 0) return F_status_set_error(F_parameter); + #endif // _di_level_0_parameter_checking_ + + return private_f_file_close(id); + } +#endif // _di_f_file_close_ + #ifndef _di_f_file_copy_ f_return_status f_file_copy(const f_string source, const f_string destination, const mode_t mode, const f_number_unsigned size_block, const bool exclusive) { f_status status = F_none; @@ -154,66 +224,6 @@ extern "C" { } #endif // _di_f_file_copy_ -#ifndef _di_f_file_clone_ - f_return_status f_file_clone(const f_string source, const f_string destination, const f_number_unsigned size_block, const bool exclusive, const bool roles) { - f_status status = F_none; - struct stat source_stat; - - memset(&source_stat, 0, sizeof(struct stat)); - - status = private_f_file_stat(source, F_false, &source_stat); - if (F_status_is_error(status)) return status; - - if (f_macro_file_type_is_regular(source_stat.st_mode)) { - status = private_f_file_create(destination, source_stat.st_mode, exclusive); - if (F_status_is_error(status)) return status; - - if (!exclusive) { - status = private_f_file_change_mode(destination, source_stat.st_mode); - if (F_status_is_error(status)) return status; - } - - if (roles) { - status = private_f_file_change_owner(destination, source_stat.st_uid, source_stat.st_gid, F_false); - if (F_status_is_error(status)) return status; - } - - return private_f_file_copy_content(source, destination, size_block == 0 ? f_file_default_read_size : size_block); - } - else if (f_macro_file_type_is_link(source_stat.st_mode)) { - status = private_f_file_link(destination, source); - if (F_status_set_fine(status) == F_file_found) { - if (exclusive) return status; - } - else if (F_status_is_error(status)) { - return status; - } - - status = private_f_file_change_mode(destination, source_stat.st_mode); - if (F_status_is_error(status)) return status; - - if (roles) { - status = private_f_file_change_owner(destination, source_stat.st_uid, source_stat.st_gid, F_false); - if (F_status_is_error(status)) return status; - } - - return F_none; - } - - return F_unsupported; - } -#endif // _di_f_file_clone_ - -#ifndef _di_f_file_close_ - f_return_status f_file_close(int *id) { - #ifndef _di_level_0_parameter_checking_ - if (id == 0) return F_status_set_error(F_parameter); - #endif // _di_level_0_parameter_checking_ - - return private_f_file_close(id); - } -#endif // _di_f_file_close_ - #ifndef _di_f_file_create_ f_return_status f_file_create(const f_string path, const mode_t mode, const bool exclusive) { return private_f_file_create(path, mode, exclusive); @@ -320,6 +330,7 @@ extern "C" { if (errno == ENOENT) return F_file_found_not; if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == ELOOP) return F_status_set_error(F_loop); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); return F_status_set_error(F_file_stat); } @@ -375,9 +386,9 @@ extern "C" { #endif // _di_f_file_link_hard_ #ifndef _di_f_file_link_hard_at_ - f_return_status f_file_link_hard_at(const int at_id_target, const int at_id_point, const f_string target, const f_string point, const int flags) { + f_return_status f_file_link_hard_at(const int at_id_target, const int at_id_point, const f_string target, const f_string point, const int flag) { - if (linkat(at_id_target, target, at_id_point, point, flags) < 0) { + if (linkat(at_id_target, target, at_id_point, point, flag) < 0) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == EDQUOT) return F_status_set_error(F_filesystem_quota_block); if (errno == EEXIST) return F_status_set_error(F_file_found); @@ -389,7 +400,7 @@ extern "C" { if (errno == ELOOP) return F_status_set_error(F_loop); if (errno == ENOENT) return F_status_set_error(F_file_found_not); if (errno == ENOTDIR) return F_status_set_error(F_directory); - if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); if (errno == ENOMEM) return F_status_set_error(F_memory_out); if (errno == ENOSPC) return F_status_set_error(F_space_not); if (errno == EPERM) return F_status_set_error(F_prohibited); @@ -465,6 +476,7 @@ extern "C" { if (errno == ENOENT) return F_file_found_not; if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == ELOOP) return F_status_set_error(F_loop); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); return F_status_set_error(F_file_stat); } @@ -681,9 +693,9 @@ extern "C" { #endif // _di_f_file_remove_ #ifndef _di_f_file_remove_at_ - f_return_status f_file_remove_at(const int at_id, const f_string path, const int flags) { + f_return_status f_file_remove_at(const int at_id, const f_string path, const int flag) { - if (unlinkat(at_id, path, flags) < 0) { + if (unlinkat(at_id, path, flag) < 0) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == EBUSY) return F_status_set_error(F_busy); if (errno == EIO) return F_status_set_error(F_input_output); @@ -696,6 +708,7 @@ extern "C" { if (errno == ENOTDIR) return F_status_set_error(F_directory); if (errno == EPERM) return F_status_set_error(F_prohibited); if (errno == EROFS) return F_status_set_error(F_read_only); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); return F_status_set_error(F_failure); } @@ -800,13 +813,13 @@ extern "C" { #endif // _di_f_file_stat_ #ifndef _di_f_file_stat_at_ - f_return_status f_file_stat_at(const int at_id, const f_string path, const int flags, struct stat *file_stat) { + f_return_status f_file_stat_at(const int at_id, const f_string path, const int flag, struct stat *file_stat) { #ifndef _di_level_0_parameter_checking_ if (at_id <= 0) return F_status_set_error(F_parameter); if (file_stat == 0) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ - return private_f_file_stat_at(at_id, path, flags, file_stat); + return private_f_file_stat_at(at_id, path, flag, file_stat); } #endif // _di_f_file_stat_at_ diff --git a/level_0/f_file/c/file.h b/level_0/f_file/c/file.h index 87914dc..b18c04a 100644 --- a/level_0/f_file/c/file.h +++ b/level_0/f_file/c/file.h @@ -97,25 +97,41 @@ extern "C" { * Commonly used file related properties. * * id: File descriptor. - * flags: Flags used for opening the file. + * flag: Flags used for opening the file. * size_read: The default number of 1-byte characters to read at a time and is often used for the read buffer size. * size_write: The default number of 1-byte characters to read at a time and is often used for the write buffer size. */ #ifndef _di_f_file_ typedef struct { int id; - int flags; + int flag; size_t size_read; size_t size_write; } f_file; - #define f_file_initialize { 0, O_RDONLY, f_file_default_read_size, f_file_default_write_size } + #define f_file_initialize { 0, f_file_flag_read_only, f_file_default_read_size, f_file_default_write_size } #endif // _di_f_file_ /** - * File mode relation functionality. + * File AT_* define related functionality. */ -#ifndef _di_f_file_modes_ +#ifndef _di_f_file_at_ + #define f_file_at_current_working -100 + #define f_file_at_symlink_follow 0x400 + #define f_file_at_symlink_follow_no 0x100 + #define f_file_at_remove_directory 0x200 + #define f_file_at_automount_no 0x800 + #define f_file_at_path_empty 0x1000 + #define f_file_at_statx_sync_type 0x6000 + #define f_file_at_statx_sync_as_stat 0x0000 + #define f_file_at_statx_sync_force 0x2000 + #define f_file_at_statx_sync_no 0x4000 +#endif // _di_f_file_at_ + +/** + * File flag related functionality. + */ +#ifndef _di_f_file_flag_ // file open flags #define f_file_flag_append O_APPEND @@ -130,7 +146,7 @@ extern "C" { #define f_file_flag_no_follow O_NOFOLLOW #define f_file_flag_no_tty O_NOCTTY #define f_file_flag_non_blocking O_NONBLOCK - #define f_file_flag_path O_PATH + #define f_file_flag_path 010000000 #define f_file_flag_read_only O_RDONLY #define f_file_flag_read_write O_RDWR #define f_file_flag_synchronous O_SYNC @@ -213,6 +229,12 @@ extern "C" { #define f_file_flag_large_async_create_new_ro (O_LARGEFILE | O_ASYNC | O_CREAT | O_EXCL | O_RDONLY) #define f_file_flag_large_async_create_new_wo (O_LARGEFILE | O_ASYNC | O_CREAT | O_EXCL | O_WRONLY) #define f_file_flag_large_async_create_new_rw (O_LARGEFILE | O_ASYNC | O_CREAT | O_EXCL | O_RDRW) +#endif // _di_f_file_flag_ + +/** + * File mode related functionality. + */ +#ifndef _di_f_file_mode_ // file permission modes. #define f_file_mode_owner_rwx S_IRWXU @@ -257,7 +279,7 @@ extern "C" { #define f_file_mode_user_file (f_file_mode_owner_rw | f_file_mode_group_rw) #define f_file_mode_user_program (f_file_mode_owner_rx | f_file_mode_group_rx) #define f_file_mode_user_protected (f_file_mode_owner_r | f_file_mode_group_r) -#endif // _di_f_file_modes_ +#endif // _di_f_file_mode_ /** * Check if a file can be accessed. @@ -326,10 +348,6 @@ extern "C" { * The path file name. * @param mode * The new mode to use. - * @param flags - * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. - * Warning: chmod on a symolic link is currently not supported in POSIX. - * Therefore AT_SYMLINK_NO_FOLLOW does nothing at this time and is assumed to always be TRUE. * * @return * F_none on success. @@ -345,10 +363,10 @@ extern "C" { * F_input_output (with error bit) on I/O error. * F_failure (with error bit) for any other (mkdir()) error. * - * @see chmod() + * @see fchmodat() */ #ifndef _di_f_file_change_mode_at_ - extern f_return_status f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode, const int flags); + extern f_return_status f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode); #endif // _di_f_file_change_mode_at_ /** @@ -365,18 +383,23 @@ extern "C" { * Set to FALSE to operate on the symlink itself. * * @return - * F_true if file exists. - * F_false if file does not exist. + * F_none on success. * F_parameter (with error bit) if a parameter is invalid. + * F_access_denied (with error bit) on access denied. * F_name (with error bit) if the filename is too long. + * F_buffer (with error bit) if the buffer is invalid. + * F_loop (with error bit) on loop error. + * F_file_found_not (with error bit) if file at path was not found. * F_memory_out (with error bit) if out of memory. - * F_number_overflow (with error bit) on overflow error. * F_directory (with error bit) on invalid directory. - * F_access_denied (with error bit) on access denied. - * F_loop (with error bit) on loop error. - * F_false (with error bit) on unknown/unhandled errors. + * F_access_owner (with error bit) if the current user does not have access to assign the specified owner. + * F_access_group (with error bit) if the current user does not have access to assign the specified group. + * F_read_only (with error bit) if file is read-only. + * F_input_output (with error bit) on I/O error. + * F_failure (with error bit) for any other (chown() or lchown()) error. * * @see chown() + * @see lchown() */ #ifndef _di_f_file_change_owner_ extern f_return_status f_file_change_owner(const f_string path, const uid_t uid, const gid_t gid, const bool dereference); @@ -393,29 +416,34 @@ extern "C" { * The new user id to use. * @param gid * The new group id to use. - * @param flags - * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. + * @param flag + * Any valid flag, such as f_file_at_path_empty, f_file_at_automount_no, or f_file_at_symlink_follow_no. * * @return - * F_true if file exists. - * F_false if file does not exist. + * F_none on success. * F_parameter (with error bit) if a parameter is invalid. + * F_access_denied (with error bit) on access denied. * F_name (with error bit) if the filename is too long. + * F_buffer (with error bit) if the buffer is invalid. + * F_loop (with error bit) on loop error. + * F_file_found_not (with error bit) if file at path was not found. * F_memory_out (with error bit) if out of memory. - * F_number_overflow (with error bit) on overflow error. * F_directory (with error bit) on invalid directory. - * F_access_denied (with error bit) on access denied. - * F_loop (with error bit) on loop error. - * F_false (with error bit) on unknown/unhandled errors. + * F_access_owner (with error bit) if the current user does not have access to assign the specified owner. + * F_access_group (with error bit) if the current user does not have access to assign the specified group. + * F_read_only (with error bit) if file is read-only. + * F_input_output (with error bit) on I/O error. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. + * F_failure (with error bit) for any other (chown() or lchown()) error. * - * @see chown() + * @see fchownat() */ #ifndef _di_f_file_change_owner_at_ - extern f_return_status f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flags); + extern f_return_status f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag); #endif // _di_f_file_change_owner_at_ /** - * Copy a file. + * Copy a file, 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. @@ -424,15 +452,17 @@ extern "C" { * * This does not copy unknown file types. * - * This does not set mode based on umask(), be sure to apply umask if so desired. - * (such as: mode & ~mask). + * @todo provide a return status for when owner/role cannot be assigned. + * This will be returned when complete so that caller can decide if this is an error or not. * * @param source * The path to the file to copy from. * @param destination * The path to copy to. - * @param mode - * The file mode assigned to the destination file. + * @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. * Set to 0 to use default block read size. @@ -463,12 +493,37 @@ extern "C" { * F_file_read (with error bit) on file read error. * F_file_write (with error bit) on file write error. */ -#ifndef _di_f_file_copy_ - extern f_return_status f_file_copy(const f_string source, const f_string destination, const mode_t mode, const f_number_unsigned size_block, const bool exclusive); -#endif // _di_f_file_copy_ +#ifndef _di_f_file_clone_ + extern f_return_status f_file_clone(const f_string source, const f_string destination, const bool role, const f_number_unsigned size_block, const bool exclusive); +#endif // _di_f_file_clone_ /** - * Copy a file, as well as its file mode and possibly the owner and group. + * Close an open file. + * + * Will flush before closing. + * + * @param id + * The file descriptor. + * + * @return + * F_none on success. + * F_parameter (with error bit) if a parameter is invalid. + * F_file_descriptor (with error bit) if file descriptor is invalid. + * F_interrupted (with error bit) if interrupt was received. + * F_input_output (with error bit) on I/O error. + * F_filesystem_quota_block (with error bit) if filesystem's disk blocks or inodes are exhausted. + * F_space_not (with error bit) if filesystem is out of space (or filesystem quota is reached). + * F_file_synchronize (with error bit) on flush failure. + * F_file_close (with error bit) if fclose() failed for any other reason. + * + * @see fclose() + */ +#ifndef _di_f_file_close_ + extern f_return_status f_file_close(int *id); +#endif // _di_f_file_close_ + +/** + * Copy a file. * * The paths must not contain NULL except for the terminating NULL. * The paths must be NULL terminated. @@ -477,23 +532,21 @@ extern "C" { * * This does not copy unknown file types. * - * @todo provide a return status for when owner/role cannot be assigned. - * This will be returned when complete so that caller can decide if this is an error or not. + * This does not set mode based on umask(), be sure to apply umask if so desired. + * (such as: mode & ~mask). * * @param source * The path to the file to copy from. * @param destination * The path to copy to. + * @param mode + * The file mode assigned to the destination file. * @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 roles - * 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.) * * @return * F_none on success. @@ -518,34 +571,9 @@ extern "C" { * F_file_read (with error bit) on file read error. * F_file_write (with error bit) on file write error. */ -#ifndef _di_f_file_clone_ - extern f_return_status f_file_clone(const f_string source, const f_string destination, const f_number_unsigned size_block, const bool exclusive, const bool roles); -#endif // _di_f_file_clone_ - -/** - * Close an open file. - * - * Will flush before closing. - * - * @param id - * The file descriptor. - * - * @return - * F_none on success. - * F_parameter (with error bit) if a parameter is invalid. - * F_file_descriptor (with error bit) if file descriptor is invalid. - * F_interrupted (with error bit) if interrupt was received. - * F_input_output (with error bit) on I/O error. - * F_filesystem_quota_block (with error bit) if filesystem's disk blocks or inodes are exhausted. - * F_space_not (with error bit) if filesystem is out of space (or filesystem quota is reached). - * F_file_synchronize (with error bit) on flush failure. - * F_file_close (with error bit) if fclose() failed for any other reason. - * - * @see fclose() - */ -#ifndef _di_f_file_close_ - extern f_return_status f_file_close(int *id); -#endif // _di_f_file_close_ +#ifndef _di_f_file_copy_ + extern f_return_status f_file_copy(const f_string source, const f_string destination, const mode_t mode, const f_number_unsigned size_block, const bool exclusive); +#endif // _di_f_file_copy_ /** * Create a file based on the given path and file mode. @@ -699,7 +727,7 @@ extern "C" { * 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_unsupported (with error bit) for unsupported file types. - * F_file_descriptor (with error bit) for bad file descriptor. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see makedev() * @see mknodat() @@ -763,7 +791,7 @@ extern "C" { * 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_unsupported (with error bit) for unsupported file types. - * F_file_descriptor (with error bit) for bad file descriptor. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see mkfifoat() */ @@ -832,7 +860,7 @@ extern "C" { * 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_unsupported (with error bit) for unsupported file types. - * F_file_descriptor (with error bit) for bad file descriptor. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see mknodat() */ @@ -876,8 +904,8 @@ extern "C" { * The parent directory, as an open directory file descriptor, in which path is relative to. * @param path * The path file name. - * @param flags - * Additional flags to pass, such as AT_EACCESS or AT_SYMLINK_NOFOLLOW. + * @param flag + * Additional flag to pass, such as AT_EACCESS or AT_SYMLINK_NOFOLLOW. * * @return * F_true if file exists. @@ -1045,7 +1073,7 @@ extern "C" { * F_prohibited (with error bit) if filesystem does not allow for creating or linking. * F_read_only (with error bit) if filesystem is read-only. * F_busy (with error bit) if filesystem is too busy to perforrm write. - * F_file_descriptor (with error bit) if file descriptor is invalid. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * F_failure (with error bit) for any other (symlinkat()) error. * * @see symlinkat() @@ -1102,8 +1130,8 @@ extern "C" { * A path that the link points to. * @param point * A path to the link that does the pointing. - * @param flags - * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. + * @param flag + * Any valid flag, such as f_file_at_path_empty, f_file_at_automount_no, or f_file_at_symlink_follow_no. * * @return * F_none on success. @@ -1122,13 +1150,13 @@ extern "C" { * F_prohibited (with error bit) if filesystem does not allow for creating or linking. * F_read_only (with error bit) if filesystem is read-only. * F_busy (with error bit) if filesystem is too busy to perforrm write. - * F_file_descriptor (with error bit) if file descriptor is invalid. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * F_failure (with error bit) for any other (linkat()) error. * * @see linkat() */ #ifndef _di_f_file_link_hard_at_ - extern f_return_status f_file_link_hard_at(const int at_id_target, const int at_id_point, const f_string target, const f_string point, const int flags); + extern f_return_status f_file_link_hard_at(const int at_id_target, const int at_id_point, const f_string target, const f_string point, const int flag); #endif // _di_f_file_link_hard_at_ /** @@ -1193,7 +1221,7 @@ extern "C" { * F_file_found_not (with error bit) if the file at path was not found. * F_memory_out (with error bit) if out of memory. * F_directory (with error bit) if a supposed directory in path is not actually a directory. - * F_file_descriptor (with error bit) if file descriptor is invalid. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * F_failure (with error bit) for any other (readlinkat()) error. * * @see readlinkat() @@ -1249,7 +1277,7 @@ extern "C" { * F_none on success. * F_file_found_not (with error bit) if the file was not found. * F_file_open (with error bit) if the file is already open. - * F_file_descriptor (with error bit) if unable to load the file descriptor (the file pointer may still be valid). + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * F_parameter (with error bit) if a parameter is invalid. * * @see openat() @@ -1387,8 +1415,8 @@ extern "C" { * The parent directory, as an open directory file descriptor, in which path is relative to. * @param path * The path file name. - * @param flags - * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. + * @param flag + * Any valid flag, such as f_file_at_path_empty, f_file_at_automount_no, or f_file_at_symlink_follow_no. * * @return * F_none on success. @@ -1409,7 +1437,7 @@ extern "C" { * @see unlinkat() */ #ifndef _di_f_file_remove_at_ - extern f_return_status f_file_remove_at(const int at_id, const f_string path, const int flags); + extern f_return_status f_file_remove_at(const int at_id, const f_string path, const int flag); #endif // _di_f_file_remove_at_ /** @@ -1558,8 +1586,8 @@ extern "C" { * The parent directory, as an open directory file descriptor, in which path is relative to. * @param path * The path to the file. - * @param flags - * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. + * @param flag + * Any valid flag, such as f_file_at_path_empty, f_file_at_automount_no, or f_file_at_symlink_follow_no. * @param file_stat * The statistics read. * @@ -1577,7 +1605,7 @@ extern "C" { * @see fstatat() */ #ifndef _di_f_file_stat_at_ - extern f_return_status f_file_stat_at(const int at_id, const f_string path, const int flags, struct stat *file_stat); + extern f_return_status f_file_stat_at(const int at_id, const f_string path, const int flag, struct stat *file_stat); #endif // _di_f_file_stat_at_ /** diff --git a/level_0/f_file/c/private-file.c b/level_0/f_file/c/private-file.c index 493089d..482610b 100644 --- a/level_0/f_file/c/private-file.c +++ b/level_0/f_file/c/private-file.c @@ -28,9 +28,9 @@ extern "C" { #endif // !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_) #if !defined(_di_f_file_change_mode_at_) || !defined(_di_f_file_copy_at_) - f_return_status private_f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode, const int flags) { + f_return_status private_f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode) { - if (fchmodat(at_id, path, mode, flags) < 0) { + if (fchmodat(at_id, path, mode, 0) < 0) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == ENAMETOOLONG) return F_status_set_error(F_name); if (errno == EFAULT) return F_status_set_error(F_buffer); @@ -38,7 +38,7 @@ extern "C" { 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 == ENOTDIR) return F_status_set_error(F_directory); - if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); if (errno == EPERM) return F_status_set_error(F_prohibited); if (errno == EROFS) return F_status_set_error(F_read_only); if (errno == EIO) return F_status_set_error(F_input_output); @@ -52,8 +52,36 @@ extern "C" { #if !defined(_di_f_file_change_owner_) || !defined(_di_f_file_copy_) f_return_status private_f_file_change_owner(const f_string path, const uid_t uid, const gid_t gid, const bool dereference) { + int result = 0; + + if (dereference) { + if (uid != -1) { + result = chown(path, uid, -1); + + if (result < 0 && errno == EPERM) return F_status_set_error(F_access_owner); + } + + if (result == 0 && gid != -1) { + result = chown(path, -1, gid); - if ((dereference ? chown(path, uid, gid) : lchown(path, uid, gid)) < 0) { + if (errno == EPERM) return F_status_set_error(F_access_group); + } + } + else { + if (uid != -1) { + result = lchown(path, uid, -1); + + if (result < 0 && errno == EPERM) return F_status_set_error(F_access_owner); + } + + if (gid != -1) { + result = lchown(path, -1, gid); + + if (result < 0 && errno == EPERM) return F_status_set_error(F_access_group); + } + } + + if (result < 0) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == ENAMETOOLONG) return F_status_set_error(F_name); if (errno == EFAULT) return F_status_set_error(F_buffer); @@ -61,7 +89,6 @@ extern "C" { 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 == ENOTDIR) return F_status_set_error(F_directory); - if (errno == EPERM) return F_status_set_error(F_prohibited); if (errno == EROFS) return F_status_set_error(F_read_only); if (errno == EIO) return F_status_set_error(F_input_output); @@ -73,9 +100,22 @@ extern "C" { #endif // !defined(_di_f_file_change_owner_) || !defined(_di_f_file_copy_) #if !defined(_di_f_file_change_owner_at_) || !defined(_di_f_file_copy_at_) - f_return_status private_f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flags) { + f_return_status private_f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag) { + int result = 0; - if (fchownat(at_id, path, uid, gid, flags) < 0) { + if (uid != -1) { + result = fchownat(at_id, path, uid, -1, flag); + + if (result < 0 && errno == EPERM) return F_status_set_error(F_access_owner); + } + + if (gid != -1) { + result = fchownat(at_id, path, -1, gid, flag); + + if (result < 0 && errno == EPERM) return F_status_set_error(F_access_group); + } + + if (result < 0) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == ENAMETOOLONG) return F_status_set_error(F_name); if (errno == EFAULT) return F_status_set_error(F_buffer); @@ -83,8 +123,7 @@ extern "C" { 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 == ENOTDIR) return F_status_set_error(F_directory); - if (errno == EBADF) return F_status_set_error(F_file_descriptor); - if (errno == EPERM) return F_status_set_error(F_prohibited); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); if (errno == EROFS) return F_status_set_error(F_read_only); if (errno == EIO) return F_status_set_error(F_input_output); @@ -100,7 +139,7 @@ extern "C" { if (F_status_is_error(private_f_file_flush(*id))) return F_status_set_error(F_file_synchronize); if (close(*id) < 0) { - if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); if (errno == EINTR) return F_status_set_error(F_interrupted); if (errno == EIO) return F_status_set_error(F_input_output); if (errno == ENOSPC) return F_status_set_error(F_space_not); @@ -119,8 +158,8 @@ extern "C" { f_file file_source = f_file_initialize; f_file file_destination = f_file_initialize; - file_source.flags = f_file_flag_read_only; - file_destination.flags = f_file_flag_write_only | f_file_flag_no_follow; + file_source.flag = f_file_flag_read_only; + file_destination.flag = f_file_flag_write_only | f_file_flag_no_follow; f_status status = private_f_file_open(source, 0, &file_source); if (F_status_is_error(status)) return status; @@ -157,14 +196,57 @@ extern "C" { } #endif // !defined(_di_f_file_copy_) || !defined(_di_f_file_clone_) +#if !defined(_di_f_file_copy_at_) || !defined(_di_f_file_clone_at_) + f_return_status private_f_file_copy_content_at(const int at_id, const f_string source, const f_string destination, const f_number_unsigned size_block) { + f_file file_source = f_file_initialize; + f_file file_destination = f_file_initialize; + + file_source.flag = f_file_flag_read_only; + file_destination.flag = f_file_flag_write_only | f_file_flag_no_follow; + + f_status status = private_f_file_open_at(at_id, source, 0, &file_source); + if (F_status_is_error(status)) return status; + + status = private_f_file_open_at(at_id, destination, 0, &file_destination); + if (F_status_is_error(status)) { + private_f_file_close(&file_source.id); + return status; + } + + ssize_t size_read = 0; + ssize_t size_write = 0; + char *buffer[size_block]; + + memset(buffer, 0, size_block); + + while ((size_read = read(file_source.id, buffer, size_block)) > 0) { + size_write = write(file_destination.id, buffer, size_read); + + if (size_write < 0 || size_write != size_read) { + private_f_file_close(&file_destination.id); + private_f_file_close(&file_source.id); + + return F_status_set_error(F_file_write); + } + } // while + + private_f_file_close(&file_destination.id); + private_f_file_close(&file_source.id); + + if (size_read < 0) return F_status_set_error(F_file_read); + + return F_none; + } +#endif // !defined(_di_f_file_copy_at_) || !defined(_di_f_file_clone_at_) + #if !defined(_di_f_file_create_) || !defined(_di_f_file_copy_) f_return_status private_f_file_create(const f_string path, const mode_t mode, const bool exclusive) { f_file file = f_file_initialize; - file.flags = O_CLOEXEC | O_CREAT | O_WRONLY; + file.flag = f_file_flag_close_execute | f_file_flag_create | f_file_flag_write_only; if (exclusive) { - file.flags |= O_EXCL; + file.flag |= f_file_flag_exclusive; } f_status status = private_f_file_open(path, mode, &file); @@ -181,10 +263,10 @@ extern "C" { f_return_status private_f_file_create_at(const int at_id, const f_string path, const mode_t mode, const bool exclusive) { f_file file = f_file_initialize; - file.flags = O_CLOEXEC | O_CREAT | O_WRONLY; + file.flag = f_file_flag_close_execute | f_file_flag_create | f_file_flag_write_only; if (exclusive) { - file.flags |= O_EXCL; + file.flag |= f_file_flag_exclusive; } f_status status = private_f_file_open_at(at_id, path, mode, &file); @@ -232,7 +314,7 @@ extern "C" { if (errno == EEXIST) return F_status_set_error(F_file_found); if (errno == ENAMETOOLONG) return F_status_set_error(F_name); if (errno == EFAULT) return F_status_set_error(F_buffer); - if (errno == EINVAL || errno == EBADF) return F_status_set_error(F_parameter); + if (errno == EINVAL) return F_status_set_error(F_parameter); if (errno == ELOOP) return F_status_set_error(F_loop); if (errno == EMLINK) return F_status_set_error(F_directory_link_max); if (errno == ENOENT) return F_status_set_error(F_file_found_not); @@ -241,6 +323,7 @@ extern "C" { if (errno == ENOTDIR) return F_status_set_error(F_directory); if (errno == EPERM) return F_status_set_error(F_prohibited); if (errno == EROFS) return F_status_set_error(F_read_only); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); return F_status_set_error(F_failure); } @@ -283,7 +366,7 @@ extern "C" { if (errno == ENOTDIR) return F_status_set_error(F_directory); if (errno == EPERM) return F_status_set_error(F_prohibited); if (errno == EROFS) return F_status_set_error(F_read_only); - if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); return F_status_set_error(F_failure); } @@ -329,7 +412,7 @@ extern "C" { if (errno == EFAULT) return F_status_set_error(F_buffer); if (errno == EINVAL) return F_status_set_error(F_parameter); if (errno == ELOOP) return F_status_set_error(F_loop); - if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); if (errno == ENOENT) return F_status_set_error(F_file_found_not); if (errno == ENOTDIR) return F_status_set_error(F_directory); if (errno == ENOMEM) return F_status_set_error(F_memory_out); @@ -405,7 +488,7 @@ extern "C" { if (errno == ELOOP) return F_status_set_error(F_loop); if (errno == ENOENT) return F_status_set_error(F_file_found_not); if (errno == ENOTDIR) return F_status_set_error(F_directory); - if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); if (errno == ENOMEM) return F_status_set_error(F_memory_out); if (errno == ENOSPC) return F_status_set_error(F_space_not); if (errno == EPERM) return F_status_set_error(F_prohibited); @@ -473,7 +556,7 @@ extern "C" { target->used = link_stat.st_size; - if (readlink(path, target->string, target->used) < 0) { + if (readlinkat(at_id, path, target->string, target->used) < 0) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == EFAULT) return F_status_set_error(F_buffer); if (errno == EINVAL) return F_status_set_error(F_parameter); @@ -483,7 +566,7 @@ extern "C" { 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 == ENOTDIR) return F_status_set_error(F_directory); - if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); return F_status_set_error(F_failure); } @@ -495,10 +578,10 @@ extern "C" { #if !defined(_di_f_file_open_) || !defined(_di_f_file_copy_) f_return_status private_f_file_open(const f_string path, const mode_t mode, f_file *file) { if (mode == 0) { - file->id = open(path, file->flags); + file->id = open(path, file->flag); } else { - file->id = open(path, file->flags, mode); + file->id = open(path, file->flag, mode); } if (file->id < 0) { @@ -513,12 +596,14 @@ extern "C" { if (errno == ELOOP) return F_status_set_error(F_loop); if (errno == ENFILE) return F_status_set_error(F_file_open_max); if (errno == ENOENT) return F_status_set_error(F_file_found_not); - if (errno == ENOTDIR) return F_status_set_error(F_directory); + if (errno == ENOTDIR) return F_status_set_error(F_file_type_not_directory); if (errno == ENOMEM) return F_status_set_error(F_memory_out); if (errno == ENOSPC) return F_status_set_error(F_space_not); if (errno == EPERM) return F_status_set_error(F_prohibited); if (errno == EROFS) return F_status_set_error(F_read_only); if (errno == ETXTBSY) return F_status_set_error(F_busy); + if (errno == EISDIR) return F_status_set_error(F_directory); + if (errno == EOPNOTSUPP) return F_status_set_error(F_unsupported); return F_status_set_error(F_failure); } @@ -530,10 +615,10 @@ extern "C" { #if !defined(_di_f_file_open_at_) || !defined(_di_f_file_copy_at_) f_return_status private_f_file_open_at(const int at_id, const f_string path, const mode_t mode, f_file *file) { if (mode == 0) { - file->id = openat(at_id, path, file->flags); + file->id = openat(at_id, path, file->flag); } else { - file->id = openat(at_id, path, file->flags, mode); + file->id = openat(at_id, path, file->flag, mode); } if (file->id < 0) { @@ -547,14 +632,16 @@ extern "C" { if (errno == EINVAL) return F_status_set_error(F_parameter); if (errno == ELOOP) return F_status_set_error(F_loop); if (errno == ENFILE) return F_status_set_error(F_file_open_max); - if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); if (errno == ENOENT) return F_status_set_error(F_file_found_not); - if (errno == ENOTDIR) return F_status_set_error(F_directory); + if (errno == ENOTDIR) return F_status_set_error(F_file_type_not_directory); if (errno == ENOMEM) return F_status_set_error(F_memory_out); if (errno == ENOSPC) return F_status_set_error(F_space_not); if (errno == EPERM) return F_status_set_error(F_prohibited); if (errno == EROFS) return F_status_set_error(F_read_only); if (errno == ETXTBSY) return F_status_set_error(F_busy); + if (errno == EISDIR) return F_status_set_error(F_directory); + if (errno == EOPNOTSUPP) return F_status_set_error(F_unsupported); return F_status_set_error(F_failure); } @@ -584,9 +671,9 @@ extern "C" { #endif // !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_) #if !defined(_di_f_file_stat_at_) || !defined(_di_f_file_copy_at_) - f_return_status private_f_file_stat_at(const int at_id, const f_string path, const int flags, struct stat *file_stat) { + f_return_status private_f_file_stat_at(const int at_id, const f_string path, const int flag, struct stat *file_stat) { - if (fstatat(at_id, path, file_stat, flags) < 0) { + if (fstatat(at_id, path, file_stat, flag) < 0) { if (errno == ENAMETOOLONG) return F_status_set_error(F_name); if (errno == EFAULT) return F_status_set_error(F_buffer); if (errno == ENOMEM) return F_status_set_error(F_memory_out); @@ -595,7 +682,7 @@ extern "C" { if (errno == ENOENT) return F_status_set_error(F_file_found_not); if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == ELOOP) return F_status_set_error(F_loop); - if (errno == EBADF) return F_status_set_error(F_file_descriptor); + if (errno == EBADF) return F_status_set_error(F_directory_descriptor); if (errno == ENOENT) return F_status_set_error(F_file_found_not); return F_status_set_error(F_file_stat); diff --git a/level_0/f_file/c/private-file.h b/level_0/f_file/c/private-file.h index 940d20f..67a6e39 100644 --- a/level_0/f_file/c/private-file.h +++ b/level_0/f_file/c/private-file.h @@ -57,10 +57,6 @@ extern "C" { * The path file name. * @param mode * The new mode to use. - * @param flags - * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. - * Warning: chmod on a symolic link is currently not supported in POSIX. - * Therefore AT_SYMLINK_NO_FOLLOW does nothing at this time and is assumed to always be TRUE. * * @return * F_none on success. @@ -77,11 +73,10 @@ extern "C" { * F_failure (with error bit) for any other (mkdir()) error. * * @see f_file_change_mode_at() - * @see f_file_copy_at() */ -#if !defined(_di_f_file_change_mode_at_) || !defined(_di_f_file_copy_at_) - extern f_return_status private_f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode, const int flags) f_gcc_attribute_visibility_internal; -#endif // !defined(_di_f_file_change_mode_at_) || !defined(_di_f_file_copy_at_) +#if !defined(_di_f_file_change_mode_at_) + extern f_return_status private_f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_f_file_change_mode_at_) /** * Private implementation of f_file_change_owner(). @@ -103,14 +98,17 @@ extern "C" { * F_parameter (with error bit) if a parameter is invalid. * F_access_denied (with error bit) on access denied. * F_name (with error bit) if the filename is too long. + * F_buffer (with error bit) if the buffer is invalid. * F_loop (with error bit) on loop error. * F_file_found_not (with error bit) if file at path was not found. * F_memory_out (with error bit) if out of memory. * F_directory (with error bit) on invalid directory. - * F_prohibited (with error bit) if filesystem does not allow for file changes. + * F_access_owner (with error bit) if the current user does not have access to assign the specified owner. + * F_access_group (with error bit) if the current user does not have access to assign the specified group. * F_read_only (with error bit) if file is read-only. * F_input_output (with error bit) on I/O error. - * F_failure (with error bit) for any other (mkdir()) error. + * F_failure (with error bit) for any other (chown() or lchown()) error. + * * * @see f_file_change_owner() * @see f_file_copy() @@ -132,7 +130,7 @@ extern "C" { * The new user id to use. * @param gid * The new group id to use. - * @param flags + * @param flag * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. * * @return @@ -140,21 +138,23 @@ extern "C" { * F_parameter (with error bit) if a parameter is invalid. * F_access_denied (with error bit) on access denied. * F_name (with error bit) if the filename is too long. + * F_buffer (with error bit) if the buffer is invalid. * F_loop (with error bit) on loop error. * F_file_found_not (with error bit) if file at path was not found. * F_memory_out (with error bit) if out of memory. * F_directory (with error bit) on invalid directory. - * F_prohibited (with error bit) if filesystem does not allow for file changes. + * F_access_owner (with error bit) if the current user does not have access to assign the specified owner. + * F_access_group (with error bit) if the current user does not have access to assign the specified group. * F_read_only (with error bit) if file is read-only. * F_input_output (with error bit) on I/O error. - * F_failure (with error bit) for any other (mkdir()) error. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. + * F_failure (with error bit) for any other (chown() or lchown()) error. * * @see f_file_change_owner_at() - * @see f_file_copy_at() */ -#if !defined(_di_f_file_change_owner_at_) || !defined(_di_f_file_copy_at_) - extern f_return_status private_f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flags) f_gcc_attribute_visibility_internal; -#endif // !defined(_di_f_file_change_owner_at_) || !defined(_di_f_file_copy_at_) +#if !defined(_di_f_file_change_owner_at_) + extern f_return_status private_f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_f_file_change_owner_at_) /** * Private implementation of f_file_close(). @@ -242,7 +242,7 @@ extern "C" { * @param file * The data related to the file being opened. * This will be updated with the file descriptor. - * This will be updated with the create flags (ignoring and overriding existing file.flags). + * This will be updated with the create flag (ignoring and overriding existing file.flag). * @param exclusive * If TRUE, will fail when file already exists. * If FALSE, will not fail if file already exists. @@ -284,7 +284,7 @@ extern "C" { * @param file * The data related to the file being opened. * This will be updated with the file descriptor. - * This will be updated with the create flags (ignoring and overriding existing file.flags). + * This will be updated with the create flag (ignoring and overriding existing file.flag). * @param path * The path file name. * @param mode @@ -313,12 +313,11 @@ extern "C" { * 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. * - * @see f_file_copy_at() * @see f_file_create_at() */ -#if !defined(_di_f_file_create_at_) || !defined(_di_f_file_copy_at_) +#if !defined(_di_f_file_create_at_) extern f_return_status private_f_file_create_at(const int at_id, const f_string path, const mode_t mode, const bool exclusive) f_gcc_attribute_visibility_internal; -#endif // !defined(_di_f_file_create_at_) || !defined(_di_f_file_copy_at_) +#endif // !defined(_di_f_file_create_at_) /** * Private implementation for creating directories. @@ -383,7 +382,6 @@ extern "C" { * F_directory_link_max (with error bit) max links limit reached or exceeded. * F_directory (with error bit) if a supposed directory in path is not actually a directory. * - * @see f_file_copy_at() * @see mkdirat() */ #if !defined(_di_f_file_copy_at_) @@ -441,7 +439,7 @@ extern "C" { * 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_unsupported (with error bit) for unsupported file types. - * F_file_descriptor (with error bit) for bad file descriptor. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see mkfifoat() */ @@ -521,7 +519,7 @@ extern "C" { * 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_unsupported (with error bit) for unsupported file types. - * F_file_descriptor (with error bit) for bad file descriptor. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see f_file_create_device_at() * @see f_file_create_node_at() @@ -621,15 +619,14 @@ extern "C" { * F_prohibited (with error bit) if filesystem does not allow for creating or linking. * F_read_only (with error bit) if filesystem is read-only. * F_busy (with error bit) if filesystem is too busy to perforrm write. - * F_file_descriptor (with error bit) if file descriptor is invalid. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * F_failure (with error bit) for any other (symlink()) error. * - * @see f_file_copy_at() * @see f_file_link_at() */ -#if !defined(_di_f_file_link_at_) || !defined(_di_f_file_copy_at_) +#if !defined(_di_f_file_link_at_) extern f_return_status private_f_file_link_at(const int at_id, const f_string target, const f_string point) f_gcc_attribute_visibility_internal; -#endif // !defined(_di_f_file_link_at_) || !defined(_di_f_file_copy_at_) +#endif // !defined(_di_f_file_link_at_) /** * Private implementation of f_file_link_read(). @@ -691,7 +688,7 @@ extern "C" { * F_file_found_not (with error bit) if the file at path was not found. * F_memory_out (with error bit) if out of memory. * F_directory (with error bit) if a supposed directory in path is not actually a directory. - * F_file_descriptor (with error bit) if file descriptor is invalid. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * F_failure (with error bit) for any other (readlinkat()) error. * * @see f_file_link_read_at() @@ -748,15 +745,14 @@ extern "C" { * F_none on success. * F_file_found_not (with error bit) if the file was not found. * F_file_open (with error bit) if the file is already open. - * F_file_descriptor (with error bit) if unable to load the file descriptor (the file pointer may still be valid). + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * F_parameter (with error bit) if a parameter is invalid. * - * @see f_file_copy_at() * @see f_file_open_at() */ -#if !defined(_di_f_file_open_at_) || !defined(_di_f_file_copy_at_) +#if !defined(_di_f_file_open_at_) extern f_return_status private_f_file_open_at(const int at_id, const f_string path, const mode_t mode, f_file *file) f_gcc_attribute_visibility_internal; -#endif // !defined(_di_f_file_open_at_) || !defined(_di_f_file_copy_at_) +#endif // !defined(_di_f_file_open_at_) /** * Private implementation of f_file_close(). @@ -798,7 +794,7 @@ extern "C" { * The parent directory, as an open directory file descriptor, in which path is relative to. * @param file_name * The name of the file. - * @param flags + * @param flag * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. * @param file_stat * The statistics read. @@ -815,12 +811,11 @@ extern "C" { * F_loop (with error bit) if a loop occurred. * F_parameter (with error bit) if a parameter is invalid. * - * @see f_file_copy_at() * @see f_file_stat_at() */ -#if !defined(_di_f_file_stat_at_) || !defined(_di_f_file_copy_at_) - extern f_return_status private_f_file_stat_at(const int at_id, const f_string file_name, const int flags, struct stat *file_stat) f_gcc_attribute_visibility_internal; -#endif // !defined(_di_f_file_stat_at_) || !defined(_di_f_file_copy_at_) +#if !defined(_di_f_file_stat_at_) + extern f_return_status private_f_file_stat_at(const int at_id, const f_string file_name, const int flag, struct stat *file_stat) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_f_file_stat_at_) /** * Private implementation of f_file_close(). diff --git a/level_0/f_status/c/status.h b/level_0/f_status/c/status.h index 80a2caf..7ba3de7 100644 --- a/level_0/f_status/c/status.h +++ b/level_0/f_status/c/status.h @@ -362,6 +362,7 @@ extern "C" { #endif // _di_F_status_compare_ #ifndef _di_F_status_access_ + F_access, F_access_denied, F_access_denied_execute, F_access_denied_group, @@ -378,6 +379,9 @@ extern "C" { F_access_granted_user, F_access_granted_world, F_access_granted_write, + F_access_group, + F_access_mode, + F_access_owner, #endif // _di_F_status_access_ // Required. diff --git a/level_1/fl_directory/c/directory.c b/level_1/fl_directory/c/directory.c index 0952843..3b4a502 100644 --- a/level_1/fl_directory/c/directory.c +++ b/level_1/fl_directory/c/directory.c @@ -5,27 +5,36 @@ extern "C" { #endif -#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) { +#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; status = f_directory_exists(source); if (F_status_is_error(status)) return status; if (status == F_false) return F_status_set_error(F_directory); - f_directory_listing listing = f_directory_listing_initialize; + const f_string_static static_source = { source, source_length, source_length }; + const f_string_static static_destination = { destination, destination_length, destination_length }; + + status = private_fl_directory_clone(static_source, static_destination, role, size_block, exclusive, failures); + + return F_none; + } +#endif // _di_fl_directory_clone_ + +#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; - status = private_fl_directory_list(source, 0, 0, F_false, &listing); + 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 = private_fl_directory_copy(static_source, static_destination, mode, size_block, exclusive, failures); - f_macro_directory_listing_destroy(status, listing); - if (F_status_is_error(status)) return status; - return F_none; } #endif // _di_fl_directory_copy_ @@ -40,6 +49,19 @@ extern "C" { } #endif // _di_fl_directory_list_ +#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_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_ + #ifndef _di_fl_directory_path_pop_ f_return_status fl_directory_path_pop(f_string_static *path) { #ifndef _di_level_0_parameter_checking_ diff --git a/level_1/fl_directory/c/directory.h b/level_1/fl_directory/c/directory.h index ee8fd50..c637c16 100644 --- a/level_1/fl_directory/c/directory.h +++ b/level_1/fl_directory/c/directory.h @@ -45,11 +45,13 @@ extern "C" { #endif /** - * Copy a directory and its contents. + * Copy a file, 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. @@ -64,17 +66,16 @@ extern "C" { * The length of the source path. * @param destination_length * The length of the destination path. - * @param mode - * The directory modes. + * @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. - * Set to 0 to use default block read size. + * 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 copy failures. - * If 0, then this and statuses is ignored. + * If TRUE, will fail when parent directory already exists. + * If FALSE, will not fail if parent directory already exists (existing directory will be updated). * * @return * F_none on success. @@ -83,6 +84,8 @@ extern "C" { * 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. @@ -97,41 +100,47 @@ 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 f_directory_create() + * @see f_file_clone() * @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_ +#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 file, as well as its file mode and possibly the owner and group. + * Copy a directory and its contents. * * 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. - * This will be returned when complete so that caller can decide if this is an error or not. - * * Symbolic links are not followed, they are copied as the symbolic link itself. * * This does not copy unknown file types. * * @param source - * The path to the directory to copy from. + * The source file path. + * Must be NULL terminated. * @param destination - * The path to copy to. + * 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. - * Must be greater than 0. + * Set to 0 to use default block read size. * @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). - * @param roles - * 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.) + * 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. @@ -140,6 +149,8 @@ extern "C" { * 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. @@ -154,14 +165,14 @@ 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 f_file_copy() * @see read() */ -#ifndef _di_fl_directory_clone_ - extern f_return_status fl_directory_clone(const f_string source, const f_string destination, const f_number_unsigned size_block, const bool exclusive, const bool roles); -#endif // _di_fl_directory_clone_ +#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. @@ -206,6 +217,48 @@ extern "C" { #endif // _di_fl_directory_list_ /** + * For some given path, print the names of each file and/or directory inside the directory, stored as a directory listing. + * + * Allows specifying a custom filter and custom sort. + * + * @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. + * + * @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. + * + * @see alphasort() + * @see opendir() + * @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_ + +/** * Append a path string onto the destination path. * * This ensures that there is a trailing '/' after pop. diff --git a/level_1/fl_directory/c/private-directory.c b/level_1/fl_directory/c/private-directory.c index 503f326..cf893d6 100644 --- a/level_1/fl_directory/c/private-directory.c +++ b/level_1/fl_directory/c/private-directory.c @@ -5,11 +5,229 @@ extern "C" { #endif +#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_directory_listing listing = f_directory_listing_initialize; + + status = private_fl_directory_list(source.string, 0, 0, F_false, &listing); + if (F_status_is_error(status)) { + f_macro_directory_listing_delete_simple(listing); + return status; + } + + status = F_none; + + f_array_length i = 0; + + int directory_fd = 0; + f_string_length failures_used = failures ? failures->used : 0; + + for (; F_status_is_fine(status) && i < listing.block.used; i++) { + status = private_fl_directory_clone_file(listing.block.array[i], source, destination, role, size_block, exclusive, failures); + } // for + + f_macro_string_dynamics_delete_simple(listing.block); + + for (i = 0; F_status_is_fine(status) && i < listing.character.used; i++) { + status = private_fl_directory_clone_file(listing.character.array[i], source, destination, role, size_block, exclusive, failures); + } // for + + f_macro_string_dynamics_delete_simple(listing.character); + + for (i = 0; F_status_is_fine(status) && i < listing.regular.used; i++) { + status = private_fl_directory_clone_file(listing.regular.array[i], source, destination, role, size_block, exclusive, failures); + } // for + + f_macro_string_dynamics_delete_simple(listing.regular); + + for (i = 0; F_status_is_fine(status) && i < listing.link.used; i++) { + status = private_fl_directory_clone_file(listing.link.array[i], source, destination, role, size_block, exclusive, failures); + } // for + + f_macro_string_dynamics_delete_simple(listing.link); + + for (i = 0; F_status_is_fine(status) && i < listing.socket.used; i++) { + status = private_fl_directory_clone_file(listing.socket.array[i], source, destination, role, size_block, exclusive, failures); + } // for + + f_macro_string_dynamics_delete_simple(listing.socket); + + for (i = 0; F_status_is_fine(status) && i < listing.unknown.used; i++) { + status = private_fl_directory_clone_file(listing.unknown.array[i], source, destination, role, size_block, exclusive, failures); + } // for + + f_macro_string_dynamics_delete_simple(listing.unknown); + + for (i = 0; F_status_is_fine(status) && i < listing.directory.used; i++) { + f_string_static source_sub = f_string_static_initialize; + f_string_static destination_sub = f_string_static_initialize; + + source_sub.used = source.used + listing.directory.array[i].used + 1; + source_sub.size = source_sub.used; + + destination_sub.used = destination.used + listing.directory.array[i].used + 1; + destination_sub.size = destination_sub.used; + + char path_source_sub[source_sub.used + 1]; + char path_destination_sub[destination_sub.used + 1]; + + memcpy(path_source_sub, source.string, source.used); + memcpy(path_source_sub + source.used + 1, listing.directory.array[i].string, listing.directory.array[i].used); + + memcpy(path_destination_sub, destination.string, destination.used); + memcpy(path_destination_sub + destination.used + 1, listing.directory.array[i].string, listing.directory.array[i].used); + + path_source_sub[source.used] = f_path_separator[0]; + path_source_sub[source_sub.used] = 0; + + path_destination_sub[destination.used] = f_path_separator[0]; + path_destination_sub[destination_sub.used] = 0; + + source_sub.string = path_source_sub; + destination_sub.string = path_destination_sub; + + status = private_fl_directory_clone(source_sub, destination_sub, role, size_block, exclusive, failures); + } // for + + f_macro_string_dynamics_delete_simple(listing.directory); + + if (F_status_is_error(status)) return status; + + if (failures && failures_used < failures->used) return F_failure; + + return F_none; + } +#endif // !defined(_di_fl_directory_clone_) + +#if !defined(_di_fl_directory_clone_file_) + f_return_status private_fl_directory_clone_file(const f_string_static file, 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) { + char path_source[source.used + file.used + 2]; + char path_destination[destination.used + file.used + 2]; + + memcpy(path_source, source.string, source.used); + memcpy(path_source + source.used + 1, file.string, file.used); + path_source[source.used] = f_path_separator[0]; + path_source[source.used + file.used + 1] = 0; + + memcpy(path_destination, destination.string, destination.used); + memcpy(path_destination + destination.used + 1, file.string, file.used); + path_destination[destination.used] = f_path_separator[0]; + path_destination[destination.used + file.used + 1] = 0; + + f_status status = f_file_clone(path_source, path_destination, role, size_block, exclusive); + + if (F_status_is_error(status) || status == F_unsupported) { + if (status == F_status_set_error(F_memory_allocation) || status == F_status_set_error(F_memory_reallocation)) { + return F_status_set_error(status); + } + + if (!failures) return F_failure; + + const f_status status_failure = status; + + if (failures->used + 1 > failures->size) { + if (failures->size + f_memory_default_allocation_step > f_array_length_size) { + if (failures->size + 1 > f_array_length_size) { + return F_status_set_error(F_buffer_too_large); + } + + f_macro_directory_statuss_resize(status, (*failures), failures->used + 1); + if (F_status_is_error(status)) return status; + } + else { + f_macro_directory_statuss_resize(status, (*failures), failures->used + f_memory_default_allocation_step); + if (F_status_is_error(status)) return status; + } + } + + f_directory_status failure = f_directory_status_initialize; + f_string_length size = 0; + + // identify if failure was because of source or destination. + 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)) { + if (status == F_status_set_error(F_string_too_large)) { + size = f_string_length_size - 1; + } + else { + size = source.used + file.used + 1; + } + + f_macro_directory_status_resize(status, failure, size + 1); + if (F_status_is_error(status)) return status; + + memcpy(failure.path.string, path_source, size); + failure.path.string[size] = 0; + } + else { + if (status == F_status_set_error(F_string_too_large)) { + size = f_string_length_size - 1; + } + else { + size = destination.used + file.used + 1; + } + + f_macro_directory_status_resize(status, failure, size + 1); + if (F_status_is_error(status)) return status; + + memcpy(failure.path.string, path_destination, size); + failure.path.string[size] = 0; + } + + failures->array[failures->used].path.string = failure.path.string; + failures->array[failures->used].path.used = size; + failures->array[failures->used].path.size = size + 1; + failures->array[failures->used].status = status_failure; + failures->used++; + + return F_failure; + } + + return F_none; + } +#endif // !defined(_di_fl_directory_clone_file_) + #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_none; + f_status status = f_directory_exists(source.string); - 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); @@ -121,7 +339,7 @@ extern "C" { } #endif // !defined(_di_fl_directory_copy_) -#if !defined(_di_fl_directory_copy_) +#if !defined(_di_fl_directory_copy_file_) f_return_status private_fl_directory_copy_file(const f_string_static file, const f_string_static source, const f_string_static destination, const mode_t mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) { char path_source[source.used + file.used + 2]; char path_destination[destination.used + file.used + 2]; @@ -211,7 +429,7 @@ extern "C" { return F_none; } -#endif // !defined(_di_fl_directory_copy_) +#endif // !defined(_di_fl_directory_copy_file_) #if !defined(_di_fl_directory_list_) f_return_status private_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) { diff --git a/level_1/fl_directory/c/private-directory.h b/level_1/fl_directory/c/private-directory.h index 779043b..b8f4068 100644 --- a/level_1/fl_directory/c/private-directory.h +++ b/level_1/fl_directory/c/private-directory.h @@ -15,6 +15,121 @@ extern "C" { #endif /** + * Private implementation of fl_directory_clone(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param source + * The source file path. + * Must be NULL terminated. + * @param destination + * The destination file path. + * Must be NULL terminated. + * @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. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. + * + * @see fl_directory_clone() + */ +#if !defined(_di_fl_directory_clone_) + extern 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_gcc_attribute_visibility_internal; +#endif // !defined(_di_fl_directory_clone_) + +/** + * A special function intended to be used directly by private_fl_directory_clone(). + * + * Will only clone a single file and record any detected errors. + * + * @param file + * The name of the file within source to clone into destination. + * Must be NULL terminated. + * @param source + * The source file path. + * Must be NULL terminated. + * @param destination + * The destination file path. + * Must be NULL terminated. + * @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. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. + * + * @see fl_directory_clone() + */ +#if !defined(_di_fl_directory_clone_file_) + extern f_return_status private_fl_directory_clone_file(const f_string_static file, 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_gcc_attribute_visibility_internal; +#endif // !defined(_di_fl_directory_clone_file_) + +/** * Private implementation of fl_directory_copy(). * * Intended to be shared to each of the different implementation variations. @@ -39,9 +154,28 @@ extern "C" { * * @return * F_none on success. - * F_failure on handled error (failures and statuses is updated with failure and status code). + * 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. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see fl_directory_copy() */ @@ -77,15 +211,34 @@ extern "C" { * * @return * F_none on success. - * F_failure on handled error (failures and statuses is updated with failure and status code). + * 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. + * F_directory_descriptor (with error bit) for bad directory descriptor for at_id. * * @see fl_directory_copy() */ -#if !defined(_di_fl_directory_copy_) +#if !defined(_di_fl_directory_copy_file_) extern f_return_status private_fl_directory_copy_file(const f_string_static file, const f_string_static source, const f_string_static destination, const mode_t mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) f_gcc_attribute_visibility_internal; -#endif // !defined(_di_fl_directory_copy_) +#endif // !defined(_di_fl_directory_copy_file_) /** * A special function intended to be used directly by fl_directory_list(). diff --git a/level_1/fl_status/c/status.c b/level_1/fl_status/c/status.c index 8771ce7..dbbddf1 100644 --- a/level_1/fl_status/c/status.c +++ b/level_1/fl_status/c/status.c @@ -803,6 +803,9 @@ extern "C" { #endif // _di_F_status_compare_ #ifndef _di_F_status_access_ + case F_access: + *string = FL_status_string_access; + break; case F_access_denied: *string = FL_status_string_access_denied; break; @@ -851,6 +854,15 @@ extern "C" { case F_access_granted_super: *string = FL_status_string_access_granted_super; break; + case F_access_group: + *string = FL_status_string_access_group; + break; + case F_access_mode: + *string = FL_status_string_access_mode; + break; + case F_access_owner: + *string = FL_status_string_access_owner; + break; #endif // _di_F_status_access_ case F_status_code_last: diff --git a/level_1/fl_status/c/status.h b/level_1/fl_status/c/status.h index 138f808..ea95a8c 100644 --- a/level_1/fl_status/c/status.h +++ b/level_1/fl_status/c/status.h @@ -579,14 +579,15 @@ extern "C" { #endif // _di_F_status_compare_ #ifndef _di_F_status_access_ - #define FL_status_string_access_denied "F_access_denied" - #define FL_status_string_access_denied_user "F_access_denied_user" - #define FL_status_string_access_denied_group "F_access_denied_group" - #define FL_status_string_access_denied_world "F_access_denied_world" - #define FL_status_string_access_denied_read "F_access_denied_read" - #define FL_status_string_access_denied_write "F_access_denied_write" - #define FL_status_string_access_denied_execute "F_access_denied_execute" - #define FL_status_string_access_denied_super "F_access_denied_super" + #define FL_status_string_access "F_access" + #define FL_status_string_access_denied "F_access_denied" + #define FL_status_string_access_denied_user "F_access_denied_user" + #define FL_status_string_access_denied_group "F_access_denied_group" + #define FL_status_string_access_denied_world "F_access_denied_world" + #define FL_status_string_access_denied_read "F_access_denied_read" + #define FL_status_string_access_denied_write "F_access_denied_write" + #define FL_status_string_access_denied_execute "F_access_denied_execute" + #define FL_status_string_access_denied_super "F_access_denied_super" #define FL_status_string_access_granted "F_access_granted" #define FL_status_string_access_granted_user "F_access_granted_user" #define FL_status_string_access_granted_group "F_access_granted_group" @@ -595,7 +596,11 @@ extern "C" { #define FL_status_string_access_granted_write "F_access_granted_write" #define FL_status_string_access_granted_execute "F_access_granted_execute" #define FL_status_string_access_granted_super "F_access_granted_super" + #define FL_status_string_access_group "F_access_group" + #define FL_status_string_access_mode "F_access_mode" + #define FL_status_string_access_owner "F_access_owner" + #define FL_status_string_access_length 8 #define FL_status_string_access_denied_length 15 #define FL_status_string_access_denied_user_length 20 #define FL_status_string_access_denied_group_length 21 @@ -612,6 +617,9 @@ extern "C" { #define FL_status_string_access_granted_write_length 22 #define FL_status_string_access_granted_execute_length 24 #define FL_status_string_access_granted_super_length 22 + #define FL_status_string_access_group_length 14 + #define FL_status_string_access_mode_length 13 + #define FL_status_string_access_owner_length 14 #endif // _di_F_status_access_ #define FL_status_string_status_code_last "F_status_code_last" diff --git a/level_2/fll_status/c/status.c b/level_2/fll_status/c/status.c index a173598..c60a9c8 100644 --- a/level_2/fll_status/c/status.c +++ b/level_2/fll_status/c/status.c @@ -1308,6 +1308,11 @@ extern "C" { #endif // _di_F_status_compare_ #ifndef _di_F_status_access_ + if (fl_string_compare(string, FL_status_string_access, length, FL_status_string_access_length) == F_equal_to) { + *code = F_access; + return F_none; + } + if (fl_string_compare(string, FL_status_string_access_denied, length, FL_status_string_access_denied_length) == F_equal_to) { *code = F_access_denied; return F_none; @@ -1387,6 +1392,21 @@ extern "C" { *code = F_access_granted_super; return F_none; } + + if (fl_string_compare(string, FL_status_string_access_group, length, FL_status_string_access_group_length) == F_equal_to) { + *code = F_access_mode; + return F_none; + } + + if (fl_string_compare(string, FL_status_string_access_mode, length, FL_status_string_access_mode_length) == F_equal_to) { + *code = F_access_group; + return F_none; + } + + if (fl_string_compare(string, FL_status_string_access_owner, length, FL_status_string_access_owner_length) == F_equal_to) { + *code = F_access_owner; + return F_none; + } #endif // _di_F_status_access_ if (fl_string_compare(string, FL_status_string_status_code_last, length, FL_status_string_status_code_last_length) == F_equal_to) { diff --git a/level_3/fss_basic_list_write/c/fss_basic_list_write.c b/level_3/fss_basic_list_write/c/fss_basic_list_write.c index 7c5ca16..d55e9ab 100644 --- a/level_3/fss_basic_list_write/c/fss_basic_list_write.c +++ b/level_3/fss_basic_list_write/c/fss_basic_list_write.c @@ -140,7 +140,7 @@ extern "C" { if (data->parameters[fss_basic_list_write_parameter_file].result == f_console_result_additional) { f_file output = f_file_initialize; - output.flags = f_file_flag_append_wo; + output.flag = f_file_flag_append_wo; status = f_file_open(arguments.argv[data->parameters[fss_basic_list_write_parameter_file].additional.array[0]], 0, &output); diff --git a/level_3/fss_basic_write/c/fss_basic_write.c b/level_3/fss_basic_write/c/fss_basic_write.c index 7a20c0f..ac90e9b 100644 --- a/level_3/fss_basic_write/c/fss_basic_write.c +++ b/level_3/fss_basic_write/c/fss_basic_write.c @@ -140,7 +140,7 @@ extern "C" { if (data->parameters[fss_basic_write_parameter_file].result == f_console_result_additional) { f_file output = f_file_initialize; - output.flags = f_file_flag_append_wo; + output.flag = f_file_flag_append_wo; status = f_file_open(arguments.argv[data->parameters[fss_basic_write_parameter_file].additional.array[0]], 0, &output); diff --git a/level_3/fss_extended_write/c/fss_extended_write.c b/level_3/fss_extended_write/c/fss_extended_write.c index eb42499..890f041 100644 --- a/level_3/fss_extended_write/c/fss_extended_write.c +++ b/level_3/fss_extended_write/c/fss_extended_write.c @@ -205,7 +205,7 @@ extern "C" { if (data->parameters[fss_extended_write_parameter_file].result == f_console_result_additional) { f_file output = f_file_initialize; - output.flags = f_file_flag_append_wo; + output.flag = f_file_flag_append_wo; status = f_file_open(arguments.argv[data->parameters[fss_extended_write_parameter_file].additional.array[0]], 0, &output);