Add additional f_file functions, move commonly shared code into private f_file files.
The f_directory functions were incorrectly using sizeof().
build_libraries -lc
build_libraries_fll
build_libraries_fll-level
-build_sources_library console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c memory.c path.c pipe.c print.c utf.c private-utf.c
+build_sources_library console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c private-file.c memory.c path.c pipe.c print.c utf.c private-utf.c
build_sources_program
build_sources_headers color.h console.h conversion.h directory.h environment.h file.h fss.h memory.h path_fll.h path_filesystem.h path.h pipe.h print.h serialized.h socket.h status.h string.h type.h type_array.h utf.h
build_shared yes
build_linker ar
build_libraries -lc
build_libraries_fll
-build_sources_library level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/memory.c level_0/path.c level_0/pipe.c level_0/print.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/file.c level_1/fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/print.c level_1/serialized.c level_1/private-serialized.c level_1/socket.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_2/directory.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/program.c level_2/status.c
+build_sources_library level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/private-file.c level_0/memory.c level_0/path.c level_0/pipe.c level_0/print.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/file.c level_1/fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/print.c level_1/serialized.c level_1/private-serialized.c level_1/socket.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_2/directory.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/program.c level_2/status.c
build_sources_program
build_sources_headers level_0/color.h level_0/console.h level_0/conversion.h level_0/directory.h level_0/environment.h level_0/file.h level_0/fss.h level_0/memory.h level_0/path_fll.h level_0/path_filesystem.h level_0/path.h level_0/pipe.h level_0/print.h level_0/serialized.h level_0/socket.h level_0/status.h level_0/string.h level_0/type.h level_0/type_array.h level_0/utf.h level_1/color.h level_1/console.h level_1/file.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_status.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/print.h level_1/serialized.h level_1/socket.h level_1/status.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/directory.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/program.h level_2/status.h
build_sources_bash
f_return_status f_directory_is(const f_string path) {
struct stat file_stat;
- memset(&file_stat, 0, sizeof(file_stat));
+ memset(&file_stat, 0, sizeof(struct stat));
if (stat(path, &file_stat) < 0) {
if (errno == ENAMETOOLONG || errno == EFAULT) {
f_return_status f_directory_is_at(const int file_id, const f_string path, const bool follow) {
struct stat file_stat;
- memset(&file_stat, 0, sizeof(file_stat));
+ memset(&file_stat, 0, sizeof(struct stat));
if (fstatat(file_id, path, &file_stat, follow ? 0 : AT_SYMLINK_NOFOLLOW) < 0) {
if (errno == ENAMETOOLONG || errno == EFAULT) {
-/**
- * FLL - Level 0
- *
- * Project: File
- * API Version: 0.5
- * Licenses: lgplv2.1
- *
- * Provides structures and data types for a file I/O.
- * Provides operations for opening/closing files.
- */
#include <level_0/file.h>
+#include "private-file.h"
#ifdef __cplusplus
extern "C" {
}
#endif // _di_f_file_access_
-#ifndef _di_f_file_create_
- f_return_status f_file_create(f_string path, const mode_t mode, const bool exclusive) {
- int flags = O_CLOEXEC | O_CREAT | O_WRONLY;
+#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) {
+ return private_f_file_change_owner(path, uid, gid);
+ }
+#endif // _di_f_file_change_owner_
+
+#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) {
+ #ifndef _di_level_0_parameter_checking_
+ if (size_block == 0) return f_status_set_error(f_invalid_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ f_status status = f_none;
+
+ status = private_f_file_create(destination, mode, exclusive);
+ if (f_status_is_error(status)) return status;
- if (exclusive) {
- flags |= O_EXCL;
+ f_file file_source = f_file_initialize;
+ f_file file_destination = f_file_initialize;
+
+ file_destination.mode = f_file_write_create;
+
+ status = private_f_file_open(&file_source, source);
+ if (f_status_is_error(status)) return status;
+
+ status = private_f_file_open(&file_destination, destination);
+ if (f_status_is_error(status)) {
+ private_f_file_close(&file_source);
+ return status;
}
- int result = open(path, flags, mode);
+ ssize_t size_read = 0;
+ ssize_t size_write = 0;
+ char *buffer[size_block];
- if (result < 0) {
- if (errno == EACCES) {
- return f_status_set_error(f_access_denied);
- }
- else if (errno == EDQUOT) {
- return f_status_set_error(f_filesystem_quota_blocks);
- }
- else if (errno == EEXIST) {
- return f_status_set_error(f_file_found);
- }
- else if (errno == ENAMETOOLONG || errno == EFAULT) {
- return f_status_set_error(f_invalid_name);
- }
- else if (errno == EFBIG || errno == EOVERFLOW) {
- return f_status_set_error(f_number_overflow);
- }
- else if (errno == EINTR) {
- return f_status_set_error(f_interrupted);
- }
- else if (errno == EINVAL) {
- return f_status_set_error(f_invalid_parameter);
- }
- else if (errno == ELOOP) {
- return f_status_set_error(f_loop);
- }
- else if (errno == ENFILE) {
- return f_status_set_error(f_file_max_open);
- }
- else if (errno == ENOENT || errno == ENOTDIR) {
- return f_status_set_error(f_invalid_directory);
- }
- else if (errno == ENOMEM) {
- return f_status_set_error(f_out_of_memory);
- }
- else if (errno == ENOSPC) {
- return f_status_set_error(f_filesystem_quota_reached);
- }
- else if (errno == EPERM) {
- return f_status_set_error(f_prohibited);
- }
- else if (errno == EROFS) {
- return f_status_set_error(f_read_only);
- }
- else if (errno == ETXTBSY) {
- return f_status_set_error(f_busy);
+ 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);
+ private_f_file_close(&file_source);
+
+ return f_status_set_error(f_file_error_write);
}
+ } // while
- return f_status_set_error(f_failure);
- }
+ private_f_file_close(&file_destination);
+ private_f_file_close(&file_source);
- close(result);
+ if (size_read < 0) return f_status_set_error(f_file_error_read);
return f_none;
}
-#endif // _di_f_file_create_
+#endif // _di_f_file_copy_
-#ifndef _di_f_file_close_
- f_return_status f_file_close(f_file *file) {
+#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) {
#ifndef _di_level_0_parameter_checking_
- if (file == 0) return f_status_set_error(f_invalid_parameter);
+ if (size_block == 0) return f_status_set_error(f_invalid_parameter);
#endif // _di_level_0_parameter_checking_
- if (file->address == 0) return f_status_set_error(f_file_not_open);
+ f_status status = f_none;
+ struct stat source_stat;
+
+ memset(&source_stat, 0, sizeof(struct stat));
+
+ status = private_f_file_stat(source, &source_stat);
+ if (f_status_is_error(status)) return status;
+
+ status = private_f_file_create(destination, source_stat.st_mode, exclusive);
+ if (f_status_is_error(status)) return status;
+
+ // guarantee the file mode is updated (create does not set mode for existing files).
+ status = private_f_file_change_mode(destination, source_stat.st_mode);
+ if (f_status_is_error(status)) return status;
- // if we were given a file descriptor as well, make sure to flush all changes to the disk that are not flushed by the 'fflush()' command
- if (file->id) {
- // make sure all unfinished data gets completed.
- if (fsync(file->id) != 0) return f_status_set_error(f_file_error_synchronize);
+ if (roles) {
+ status = private_f_file_change_owner(destination, source_stat.st_uid, source_stat.st_gid);
+ if (f_status_is_error(status)) return status;
}
- if (fclose(file->address) == 0) {
- file->address = 0;
- return f_none;
+ f_file file_source = f_file_initialize;
+ f_file file_destination = f_file_initialize;
+
+ file_destination.mode = f_file_write_create;
+
+ status = private_f_file_open(&file_source, source);
+ if (f_status_is_error(status)) return status;
+
+ status = private_f_file_open(&file_destination, destination);
+ if (f_status_is_error(status)) {
+ private_f_file_close(&file_source);
+ return status;
}
- return f_status_set_error(f_file_error_close);
+ 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);
+ private_f_file_close(&file_source);
+
+ return f_status_set_error(f_file_error_write);
+ }
+ } // while
+
+ private_f_file_close(&file_destination);
+ private_f_file_close(&file_source);
+
+ if (size_read < 0) return f_status_set_error(f_file_error_read);
+
+ return f_none;
+ }
+#endif // _di_f_file_clone_
+
+#ifndef _di_f_file_close_
+ f_return_status f_file_close(f_file *file) {
+ #ifndef _di_level_0_parameter_checking_
+ if (file == 0) return f_status_set_error(f_invalid_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ return private_f_file_close(file);
}
#endif // _di_f_file_close_
+#ifndef _di_f_file_create_
+ f_return_status f_file_create(f_string path, const mode_t mode, const bool exclusive) {
+ return private_f_file_create(path, mode, exclusive);
+ }
+#endif // _di_f_file_create_
+
#ifndef _di_f_file_exists_at_
f_return_status f_file_exists_at(const int directory_file_descriptor, const f_string path, const int flags) {
#ifndef _di_level_0_parameter_checking_
f_return_status f_file_exists(const f_string path) {
struct stat file_stat;
- memset(&file_stat, 0, sizeof(file_stat));
+ memset(&file_stat, 0, sizeof(struct stat));
if (stat(path, &file_stat) < 0) {
if (errno == ENAMETOOLONG || errno == EFAULT) {
f_return_status f_file_is(const f_string path, const int type) {
struct stat file_stat;
- memset(&file_stat, 0, sizeof(file_stat));
+ memset(&file_stat, 0, sizeof(struct stat));
if (stat(path, &file_stat) < 0) {
if (errno == ENAMETOOLONG || errno == EFAULT) {
f_return_status f_file_is_at(const int file_id, const f_string path, const int type, const bool follow) {
struct stat file_stat;
- memset(&file_stat, 0, sizeof(file_stat));
+ memset(&file_stat, 0, sizeof(struct stat));
if (fstatat(file_id, path, &file_stat, follow ? 0 : AT_SYMLINK_NOFOLLOW) < 0) {
if (errno == ENAMETOOLONG || errno == EFAULT) {
if (file == 0) return f_status_set_error(f_invalid_parameter);
#endif // _di_level_0_parameter_checking_
- // if file->mode is unset, then this may cause a segfault.
- if (file->mode == 0) return f_status_set_error(f_invalid_parameter);
-
- file->address = fopen(path, file->mode);
-
- if (file->address == 0) return f_status_set_error(f_file_not_found);
- if (ferror(file->address) != 0) return f_status_set_error(f_file_error_open);
-
- file->id = fileno(file->address);
-
- if (file->id == -1) return f_status_set_error(f_file_error_descriptor);
-
- return f_none;
+ return private_f_file_open(file, path);
}
#endif // _di_f_file_open_
#ifndef _di_f_file_stat_
f_return_status f_file_stat(const f_string path, struct stat *file_stat) {
- if (stat(path, file_stat) < 0) {
- if (errno == ENAMETOOLONG || errno == EFAULT) {
- return f_status_set_error(f_invalid_name);
- }
- else if (errno == ENOMEM) {
- return f_status_set_error(f_out_of_memory);
- }
- else if (errno == EOVERFLOW) {
- return f_status_set_error(f_number_overflow);
- }
- else if (errno == ENOTDIR) {
- return f_status_set_error(f_invalid_directory);
- }
- else if (errno == ENOENT) {
- return f_status_set_error(f_file_not_found);
- }
- else if (errno == EACCES) {
- return f_status_set_error(f_access_denied);
- }
- else if (errno == ELOOP) {
- return f_status_set_error(f_loop);
- }
-
- return f_status_set_error(f_file_error_stat);
- }
-
- return f_none;
+ return private_f_file_stat(path, file_stat);
}
#endif // _di_f_file_stat_
#define f_file_default_read_size 8192 // default to 8k read sizes.
#define f_file_default_write_size 8192 // default to 8k write sizes.
- #define f_file_max_path_length 1024
#endif // _di_f_file_types_
/**
#endif // _di_f_macro_file_reset_position_
/**
+ * Change owner and group of a given file at the specified path.
+ *
+ * @param path
+ * The path file name.
+ * @param uid
+ * The new user id to use.
+ * @param gid
+ * The new group id to use.
+ *
+ * @return
+ * f_true if file exists.
+ * f_false if file does not exist.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ * f_invalid_name (with error bit) if the filename is too long.
+ * f_out_of_memory (with error bit) if out of memory.
+ * f_number_overflow (with error bit) on overflow error.
+ * f_invalid_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.
+ *
+ * @see chown()
+ */
+#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);
+#endif // _di_f_file_change_owner_
+
+/**
* Check if a file can be accessed.
*
* @param path
#endif // _di_f_file_access_
/**
+ * Copy a file.
+ *
+ * The paths must not contain NULL except for the terminating NULL.
+ * The paths must be NULL terminated.
+ *
+ * @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.
+ * 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).
+ *
+ * @return
+ * f_none on success.
+ * f_invalid_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_out_of_memory (with error bit) if out of memory.
+ * 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_blocks (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_invalid_name (with error bit) on path name error.
+ * f_invalid_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_max_open (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_error_read (with error bit) on file read error.
+ * f_file_error_write (with error bit) on file write error.
+ *
+ * @see f_file_create()
+ * @see f_file_open()
+ * @see f_file_close()
+ * @see read()
+ */
+#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_
+
+/**
+ * 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.
+ * 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 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 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.
+ * f_invalid_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_out_of_memory (with error bit) if out of memory.
+ * 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_blocks (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_invalid_name (with error bit) on path name error.
+ * f_invalid_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_max_open (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_error_read (with error bit) on file read error.
+ * f_file_error_write (with error bit) on file write error.
+ *
+ * @see f_file_create()
+ * @see f_file_open()
+ * @see f_file_close()
+ * @see read()
+ */
+#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_
+
+/**
* Create a file based on the given path and file mode.
*
* The file will not be open after calling this.
* f_file_not_open (with error bit) if file is not open.
* f_file_error_read (with error bit) if file read failed.
* f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see fread()
*/
#ifndef _di_f_file_read_
extern f_return_status f_file_read(f_file *file, f_string_dynamic *buffer);
--- /dev/null
+#include <level_0/file.h>
+#include "private-file.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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) {
+ if (chown(path, uid, gid) < 0) {
+ if (errno == EACCES) {
+ return f_status_set_error(f_access_denied);
+ }
+ else if (errno == ENAMETOOLONG || errno == EFAULT) {
+ return f_status_set_error(f_invalid_name);
+ }
+ else if (errno == ELOOP) {
+ return f_status_set_error(f_loop);
+ }
+ else if (errno == ENOENT) {
+ return f_status_set_error(f_file_not_found);
+ }
+ else if (errno == ENOMEM) {
+ return f_status_set_error(f_out_of_memory);
+ }
+ else if (errno == ENOTDIR) {
+ return f_status_set_error(f_invalid_directory);
+ }
+ else if (errno == EPERM) {
+ return f_status_set_error(f_prohibited);
+ }
+ else if (errno == EROFS) {
+ return f_status_set_error(f_read_only);
+ }
+ else if (errno == EIO) {
+ return f_status_set_error(f_error_input_output);
+ }
+
+ return f_status_set_error(f_failure);
+ }
+
+ return f_none;
+ }
+#endif // !defined(_di_f_file_change_owner_) || !defined(_di_f_file_copy_)
+
+#if !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_)
+ f_return_status private_f_file_change_mode(const f_string path, const mode_t mode) {
+ if (chmod(path, mode) < 0) {
+ if (errno == EACCES) {
+ return f_status_set_error(f_access_denied);
+ }
+ else if (errno == ENAMETOOLONG || errno == EFAULT) {
+ return f_status_set_error(f_invalid_name);
+ }
+ else if (errno == ELOOP) {
+ return f_status_set_error(f_loop);
+ }
+ else if (errno == ENOENT) {
+ return f_status_set_error(f_file_not_found);
+ }
+ else if (errno == ENOMEM) {
+ return f_status_set_error(f_out_of_memory);
+ }
+ else if (errno == ENOTDIR) {
+ return f_status_set_error(f_invalid_directory);
+ }
+ else if (errno == EPERM) {
+ return f_status_set_error(f_prohibited);
+ }
+ else if (errno == EROFS) {
+ return f_status_set_error(f_read_only);
+ }
+ else if (errno == EIO) {
+ return f_status_set_error(f_error_input_output);
+ }
+
+ return f_status_set_error(f_failure);
+ }
+
+ return f_none;
+ }
+#endif // !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_)
+
+#if !defined(_di_f_file_close_) || !defined(_di_f_file_copy_)
+ f_return_status private_f_file_close(f_file *file) {
+ if (file->address == 0) return f_status_set_error(f_file_not_open);
+
+ // if given a file descriptor, flush all changes to the disk that are not flushed by the 'fflush()' command.
+ if (file->id) {
+ if (fsync(file->id) != 0) return f_status_set_error(f_file_error_synchronize);
+ }
+
+ if (fclose(file->address) == 0) {
+ file->address = 0;
+ return f_none;
+ }
+
+ return f_status_set_error(f_file_error_close);
+ }
+#endif // !defined(_di_f_file_close_) || !defined(_di_f_file_copy_)
+
+#if !defined(_di_f_file_create_) || !defined(_di_f_file_copy_)
+ f_return_status private_f_file_create(f_string path, const mode_t mode, const bool exclusive) {
+ int flags = O_CLOEXEC | O_CREAT | O_WRONLY;
+
+ if (exclusive) {
+ flags |= O_EXCL;
+ }
+
+ int result = open(path, flags, mode);
+
+ if (result < 0) {
+ if (errno == EACCES) {
+ return f_status_set_error(f_access_denied);
+ }
+ else if (errno == EDQUOT) {
+ return f_status_set_error(f_filesystem_quota_blocks);
+ }
+ else if (errno == EEXIST) {
+ return f_status_set_error(f_file_found);
+ }
+ else if (errno == ENAMETOOLONG || errno == EFAULT) {
+ return f_status_set_error(f_invalid_name);
+ }
+ else if (errno == EFBIG || errno == EOVERFLOW) {
+ return f_status_set_error(f_number_overflow);
+ }
+ else if (errno == EINTR) {
+ return f_status_set_error(f_interrupted);
+ }
+ else if (errno == EINVAL) {
+ return f_status_set_error(f_invalid_parameter);
+ }
+ else if (errno == ELOOP) {
+ return f_status_set_error(f_loop);
+ }
+ else if (errno == ENFILE) {
+ return f_status_set_error(f_file_max_open);
+ }
+ else if (errno == ENOENT || errno == ENOTDIR) {
+ return f_status_set_error(f_invalid_directory);
+ }
+ else if (errno == ENOMEM) {
+ return f_status_set_error(f_out_of_memory);
+ }
+ else if (errno == ENOSPC) {
+ return f_status_set_error(f_filesystem_quota_reached);
+ }
+ else if (errno == EPERM) {
+ return f_status_set_error(f_prohibited);
+ }
+ else if (errno == EROFS) {
+ return f_status_set_error(f_read_only);
+ }
+ else if (errno == ETXTBSY) {
+ return f_status_set_error(f_busy);
+ }
+
+ return f_status_set_error(f_failure);
+ }
+
+ close(result);
+
+ return f_none;
+ }
+#endif // !defined(_di_f_file_create_) || !defined(_di_f_file_copy_)
+
+#if !defined(_di_f_file_open_) || !defined(_di_f_file_copy_)
+ f_return_status private_f_file_open(f_file *file, const f_string path) {
+ // if file->mode is unset, then this may cause a segfault.
+ if (file->mode == 0) return f_status_set_error(f_invalid_parameter);
+
+ file->address = fopen(path, file->mode);
+
+ if (file->address == 0) return f_status_set_error(f_file_not_found);
+ if (ferror(file->address) != 0) return f_status_set_error(f_file_error_open);
+
+ file->id = fileno(file->address);
+
+ if (file->id == -1) return f_status_set_error(f_file_error_descriptor);
+
+ return f_none;
+ }
+#endif // !defined(_di_f_file_open_) || !defined(_di_f_file_copy_)
+
+#if !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_)
+ f_return_status private_f_file_stat(const f_string path, struct stat *file_stat) {
+ if (stat(path, file_stat) < 0) {
+ if (errno == ENAMETOOLONG || errno == EFAULT) {
+ return f_status_set_error(f_invalid_name);
+ }
+ else if (errno == ENOMEM) {
+ return f_status_set_error(f_out_of_memory);
+ }
+ else if (errno == EOVERFLOW) {
+ return f_status_set_error(f_number_overflow);
+ }
+ else if (errno == ENOTDIR) {
+ return f_status_set_error(f_invalid_directory);
+ }
+ else if (errno == ENOENT) {
+ return f_status_set_error(f_file_not_found);
+ }
+ else if (errno == EACCES) {
+ return f_status_set_error(f_access_denied);
+ }
+ else if (errno == ELOOP) {
+ return f_status_set_error(f_loop);
+ }
+
+ return f_status_set_error(f_file_error_stat);
+ }
+
+ return f_none;
+ }
+#endif // !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: File
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * Provides structures and data types for a file I/O.
+ * Provides operations for opening/closing files.
+ */
+#ifndef _PRIVATE_F_file_h
+#define _PRIVATE_F_file_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Private implementation of f_file_change_owner().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param path
+ * The path file name.
+ * @param uid
+ * The new user id to use.
+ * @param gid
+ * The new group id to use.
+ *
+ * @return
+ * f_none on success.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ * f_access_denied (with error bit) on access denied.
+ * f_invalid_name (with error bit) if the filename is too long.
+ * f_loop (with error bit) on loop error.
+ * f_file_not_found (with error bit) if file at path was not found.
+ * f_out_of_memory (with error bit) if out of memory.
+ * f_invalid_directory (with error bit) on invalid directory.
+ * f_prohibited (with error bit) if filesystem does not allow for file changes.
+ * f_read_only (with error bit) if file is read-only.
+ * f_error_input_output (with error bit) on I/O error.
+ * f_failure (with error bit) for any other (mkdir()) error.
+ *
+ * @see f_file_change_owner()
+ * @see chown()
+ */
+#if !defined(_di_f_file_change_owner_) || !defined(_di_f_file_copy_)
+ extern f_return_status private_f_file_change_owner(const f_string path, const uid_t uid, const gid_t gid) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_change_owner_) || !defined(_di_f_file_copy_)
+
+/**
+ * Private implementation of f_file_change_mode().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param path
+ * The path file name.
+ * @param mode
+ * The new mode to use.
+ *
+ * @return
+ * f_none on success.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ * f_access_denied (with error bit) on access denied.
+ * f_invalid_name (with error bit) if the filename is too long.
+ * f_loop (with error bit) on loop error.
+ * f_file_not_found (with error bit) if file at path was not found.
+ * f_out_of_memory (with error bit) if out of memory.
+ * f_invalid_directory (with error bit) on invalid directory.
+ * f_prohibited (with error bit) if filesystem does not allow for file changes.
+ * f_read_only (with error bit) if file is read-only.
+ * f_error_input_output (with error bit) on I/O error.
+ * f_failure (with error bit) for any other (mkdir()) error.
+ *
+ * @see f_file_change_mode()
+ * @see chmod()
+ */
+#if !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_)
+ extern f_return_status private_f_file_change_mode(const f_string path, const mode_t mode) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_)
+
+/**
+ * Private implementation of f_file_create().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param path
+ * Full path to the file (including entire filename).
+ * @param mode
+ * The file mode.
+ * @param exclusive
+ * If TRUE, will fail when file already exists.
+ * If FALSE, will not fail if file already exists.
+ *
+ * @return
+ * f_none on success.
+ * f_invalid_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_out_of_memory (with error bit) if out of memory.
+ * 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_blocks (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_invalid_name (with error bit) on path name error.
+ * f_invalid_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_max_open (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_create()
+ * @see open()
+ */
+#if !defined(_di_f_file_create_) || !defined(_di_f_file_copy_)
+ extern f_return_status private_f_file_create(f_string path, const mode_t mode, const bool exclusive) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_create_) || !defined(_di_f_file_copy_)
+
+/**
+ * Private implementation of f_file_open().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param file
+ * The data related to the file being opened.
+ * This will be updated with the file descriptor and file address.
+ * @param path
+ * The path file name.
+ *
+ * @return
+ * f_none on success.
+ * f_file_not_found (with error bit) if the file was not found.
+ * f_file_error_open (with error bit) if the file is already open.
+ * f_file_error_descriptor (with error bit) if unable to load the file descriptor (the file pointer may still be valid).
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_file_open()
+ * @see fopen()
+ */
+#if !defined(_di_f_file_open_) || !defined(_di_f_file_copy_)
+ extern f_return_status private_f_file_open(f_file *file, const f_string path) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_open_) || !defined(_di_f_file_copy_)
+
+/**
+ * Private implementation of f_file_close().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param file
+ * The file to close.
+ *
+ * @return
+ * f_none on success.
+ * f_file_not_open (with error bit) if the file is not open.
+ * f_file_error_synchronize (with error bit) on fsync() failure.
+ * f_file_error_close (with error bit) if fclose() failed.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_file_close()
+ * @see fsync()
+ * @see fclose()
+ */
+#if !defined(_di_f_file_close_) || !defined(_di_f_file_copy_)
+ extern f_return_status private_f_file_close(f_file *file) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_close_) || !defined(_di_f_file_copy_)
+
+/**
+ * Private implementation of f_file_close().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param file_name
+ * The name of the file.
+ * @param file_stat
+ * The statistics read.
+ *
+ * @return
+ * f_none on success.
+ * f_invalid_name (with error bit) if the name is somehow invalid.
+ * f_out_of_memory (with error bit) if out of memory.
+ * f_number_overflow (with error bit) on overflow error.
+ * f_invalid_directory (with error bit) on invalid directory.
+ * f_file_not_found (with error bit) if the file was not found.
+ * f_access_denied (with error bit) if access to the file was denied.
+ * f_loop (with error bit) if a loop occurred.
+ * f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_file_stat()
+ * @see stat()
+ */
+#if !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_)
+ extern f_return_status private_f_file_stat(const f_string file_name, struct stat *file_stat) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_F_file_h
build_linker ar
build_libraries -lc
build_libraries_fll
-build_sources_library file.c
+build_sources_library file.c private-file.c
build_sources_program
build_sources_headers file.h
build_sources_bash
continue;
}
- memset(&file_stat, 0, sizeof(file_stat));
+ memset(&file_stat, 0, sizeof(struct stat));
status = f_file_stat_at(parent_fd, entity[i]->d_name, &file_stat, 0);
if (f_status_is_error(status)) break;