From 48dcd7adde696ac8c38fabadd52b91cf6585c469 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Thu, 21 May 2020 00:08:09 -0500 Subject: [PATCH] Progress: major redesigns with file and directory handling, this changeset is incomplete In the process of writing the directory copy, I realized I needed to improve the file and directory management. This triggered me to rethink how I was handling files and directories to some extend. If memory serves me correctly, the POSIX 2008 was either too new or non-existent when I first wrote some of this. Updating to use the newer POSIX functionality and changes seems worth this major change. Add additional file functionality. Lots of re-organization and redesign. I still haven't finished this and would rather commit now, with incomplete code randomly throughout, than risk losing any changes. In particular, the fl_utf_file is where I need to resume. I need to then update all of the level 3 programs to use the new file/directory handling code. After that I need to finish writing the directory copy, which should include investigating and implementing file copy operations for more than regular files and symbolic links. I also need to remember to investigate copying hard links as a hard link instead of as a duplicate file. --- build/level_0/settings | 2 +- build/level_1/settings | 4 +- build/level_2/settings | 4 +- build/monolithic/settings | 4 +- documents/todo.txt | 20 +- level_0/f_directory/c/directory.c | 323 +++----- level_0/f_directory/c/directory.h | 99 ++- level_0/f_directory/c/private-directory.h | 2 - level_0/f_file/c/file.c | 840 ++++++++++--------- level_0/f_file/c/file.h | 897 +++++++++++++++------ level_0/f_file/c/private-file.c | 497 ++++++++---- level_0/f_file/c/private-file.h | 411 +++++++++- level_0/f_file/data/build/dependencies | 2 + level_0/f_status/c/status.h | 12 +- level_0/f_string/c/string.h | 72 +- level_0/f_utf/c/utf.h | 67 +- level_1/fl_directory/c/directory.c | 43 + level_1/fl_directory/c/directory.h | 194 +++++ level_1/fl_directory/c/private-directory.c | 251 ++++++ level_1/fl_directory/c/private-directory.h | 79 ++ level_1/fl_directory/data/build/defines | 2 + level_1/fl_directory/data/build/dependencies | 6 + level_1/fl_directory/data/build/settings | 30 + level_1/fl_file/c/file.c | 131 --- level_1/fl_file/c/file.h | 84 -- level_1/fl_fss/c/fss.c | 42 +- level_1/fl_fss/c/fss.h | 4 +- level_1/fl_status/c/status.c | 36 +- level_1/fl_status/c/status.h | 36 +- level_1/fl_utf_file/c/private-utf_file.c | 11 + level_1/fl_utf_file/c/private-utf_file.h | 22 + level_1/fl_utf_file/c/utf_file.c | 207 ++++- level_1/fl_utf_file/c/utf_file.h | 141 +++- level_1/fl_utf_file/data/build/dependencies | 2 +- level_1/fl_utf_file/data/build/settings | 4 +- level_2/fll_directory/c/directory.c | 142 ---- level_2/fll_directory/c/directory.h | 38 - level_2/fll_status/c/status.c | 56 +- level_3/fake/c/private-build.c | 4 +- level_3/fake/c/private-clean.c | 4 +- level_3/fake/c/private-skeleton.c | 4 +- level_3/firewall/c/private-firewall.c | 17 +- level_3/firewall/c/private-firewall.h | 3 - .../fss_basic_list_read/c/fss_basic_list_read.h | 4 +- level_3/fss_basic_read/c/fss_basic_read.h | 4 +- .../c/fss_extended_list_read.h | 4 +- level_3/fss_extended_read/c/fss_extended_read.h | 4 +- level_3/init/c/private-init.c | 6 +- 48 files changed, 3263 insertions(+), 1608 deletions(-) create mode 100644 level_1/fl_directory/c/directory.c create mode 100644 level_1/fl_directory/c/directory.h create mode 100644 level_1/fl_directory/c/private-directory.c create mode 100644 level_1/fl_directory/c/private-directory.h create mode 100644 level_1/fl_directory/data/build/defines create mode 100644 level_1/fl_directory/data/build/dependencies create mode 100644 level_1/fl_directory/data/build/settings create mode 100644 level_1/fl_utf_file/c/private-utf_file.c create mode 100644 level_1/fl_utf_file/c/private-utf_file.h diff --git a/build/level_0/settings b/build/level_0/settings index 5f1c31d..6527947 100644 --- a/build/level_0/settings +++ b/build/level_0/settings @@ -14,7 +14,7 @@ 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 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_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 build_shared yes build_static yes diff --git a/build/level_1/settings b/build/level_1/settings index bc4aba0..feeadf3 100644 --- a/build/level_1/settings +++ b/build/level_1/settings @@ -12,9 +12,9 @@ build_linker ar build_libraries -lc build_libraries_fll -lfll_0 build_libraries_fll-level -lfll_0 -build_sources_library color.c console.c file.c fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c print.c serialized.c private-serialized.c socket.c status.c string.c private-string.c utf.c private-utf.c utf_file.c +build_sources_library color.c console.c directory.c private-directory.c file.c fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c print.c serialized.c private-serialized.c socket.c status.c string.c private-string.c utf.c private-utf.c utf_file.c build_sources_program -build_sources_headers color.h console.h file.h fss.h fss_basic.h fss_basic_list.h fss_status.h fss_extended.h fss_extended_list.h fss_macro.h print.h serialized.h socket.h status.h string.h utf.h utf_file.h +build_sources_headers color.h console.h directory.h file.h fss.h fss_basic.h fss_basic_list.h fss_status.h fss_extended.h fss_extended_list.h fss_macro.h print.h serialized.h socket.h status.h string.h utf.h utf_file.h build_shared yes build_static yes diff --git a/build/level_2/settings b/build/level_2/settings index 77c3525..bc0aa1b 100644 --- a/build/level_2/settings +++ b/build/level_2/settings @@ -12,9 +12,9 @@ build_linker ar build_libraries -lc build_libraries_fll -lfll_0 -lfll_1 build_libraries_fll-level -lfll_0 -lfll_1 -build_sources_library directory.c execute.c private-execute.c file.c fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c fss_status.c program.c status.c +build_sources_library execute.c private-execute.c file.c fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c fss_status.c program.c status.c build_sources_program -build_sources_headers directory.h execute.h file.h fss.h fss_basic.h fss_basic_list.h fss_extended.h fss_extended_list.h fss_status.h program.h status.h +build_sources_headers execute.h file.h fss.h fss_basic.h fss_basic_list.h fss_extended.h fss_extended_list.h fss_status.h program.h status.h build_shared yes build_static yes diff --git a/build/monolithic/settings b/build/monolithic/settings index 2d894a6..a07ef81 100644 --- a/build/monolithic/settings +++ b/build/monolithic/settings @@ -11,9 +11,9 @@ build_compiler gcc 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/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_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/directory.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_1/private-utf_file.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_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/directory.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/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 build_sources_settings build_shared yes diff --git a/documents/todo.txt b/documents/todo.txt index eebce3d..8365f80 100644 --- a/documents/todo.txt +++ b/documents/todo.txt @@ -1,28 +1,10 @@ This file contains FLL-wide todo notes. -- The FSS processing code uses 64-bit data types for string lengths. - This puts a hard limit on the size of files supported. - Expand this to support larger ranges. - Possible options include a second 64-bit type, such that the size is 128-bit. - This could also be two 128-bit types, resulting in a range of 256-bit. - Ultimately research needs to be done on how other open-source projects handle this and a good examples will be filesystems, like the e2fsutils project or compression tools like tar and bz2. - - Custom language support needs to be looked into to allow for the project to support multiple languages. Given that this project focuses on KISS principles, the project is targeted towards programs for specific users. In which case, the language can be hardcoded in as a single language. Later versions after this first locale support will then consider supporting multiple languages not necessarily compiled in. -- Implement support for new standard parameter "+e"/"++exit_code", which designates that the exit code is to be stored in the following environment variable. - This allows storing the full error code, which is not generally suppoted by bash. - -- Implement "%llu" defines so that when number is of a different type, the correct '%llu' equivalent can be used. - There needs to be an '%lllu' equivalent fo 128-byte. - A better approach might be to define a custom printf()/fprintf() replacement functions that handle a new set of parameters, including color codes. - Example: - f_print(context, "%f1 Something %nu %fr$fn", number_type); - Where context can be NULL to do nothing on color prints, %f1 could be some color, %fr is color reset, %fn is newline, and %nu is the number (unsigned) to print. - This is just a random example and does not reflect the codes to be used. - - Create an fss simple content type (such that data->contents.array[at].start can be used instead of data->contents.array[at].array[0].start). - FSS needs to allow escaping of comments, "\# " would escape a comment, every backslash after that would be literal. @@ -120,3 +102,5 @@ A new wiki-like syntax meant to be simpler: Go though all source code and ensure that, for all non-exceptional cases, any dynamic strings appends to existing buffers instead of overwriting them (based on buffer->used). Then document this behavior. + +The status code processing code are all out of alphabetic order and need cleanup. diff --git a/level_0/f_directory/c/directory.c b/level_0/f_directory/c/directory.c index f8cdd96..9614348 100644 --- a/level_0/f_directory/c/directory.c +++ b/level_0/f_directory/c/directory.c @@ -6,47 +6,22 @@ extern "C" { #endif #ifndef _di_f_directory_create_ - f_return_status f_directory_create(const f_string path, const mode_t modes) { - if (mkdir(path, modes) < 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 == EINVAL) { - return f_status_set_error(f_invalid_parameter); - } - else if (errno == ELOOP) { - return f_status_set_error(f_loop); - } - else if (errno == EMLINK) { - return f_status_set_error(f_directory_error_link_max); - } - 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 == ENOSPC) { - return f_status_set_error(f_filesystem_quota_reached); - } - 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); - } + f_return_status f_directory_create(const f_string path, const mode_t mode) { + if (mkdir(path, mode) < 0) { + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == EDQUOT) return f_status_set_error(f_filesystem_quota_blocks); + if (errno == EEXIST) return f_status_set_error(f_file_found); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == EINVAL) return f_status_set_error(f_invalid_parameter); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == EMLINK) return f_status_set_error(f_directory_error_link_max); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOSPC) return f_status_set_error(f_no_space); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + 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); } @@ -55,53 +30,27 @@ extern "C" { } #endif // _di_f_directory_create_ -/* @todo #ifndef _di_f_directory_create_at_ - f_return_status f_directory_create_at(const int at_id, const f_string path, const mode_t modes) { + f_return_status f_directory_create_at(const int at_id, const f_string path, const mode_t mode) { #ifndef _di_level_0_parameter_checking_ if (at_id <= 0) return f_status_set_error(f_invalid_parameter); #endif // _di_level_0_parameter_checking_ - if (mkdirat(path, modes) < 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 == EINVAL || errno == EBADF) { - return f_status_set_error(f_invalid_parameter); - } - else if (errno == ELOOP) { - return f_status_set_error(f_loop); - } - else if (errno == EMLINK) { - return f_status_set_error(f_directory_error_link_max); - } - 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 == ENOSPC) { - return f_status_set_error(f_filesystem_quota_reached); - } - 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); - } + if (mkdirat(at_id, path, mode) < 0) { + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == EDQUOT) return f_status_set_error(f_filesystem_quota_blocks); + if (errno == EEXIST) return f_status_set_error(f_file_found); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == EINVAL || errno == EBADF) return f_status_set_error(f_invalid_parameter); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == EMLINK) return f_status_set_error(f_directory_error_link_max); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOSPC) return f_status_set_error(f_no_space); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + 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); } @@ -109,36 +58,47 @@ extern "C" { return f_none; } #endif // _di_f_directory_create_at_ -*/ + +#ifndef _di_f_directory_exists_ + f_return_status f_directory_exists(const f_string path) { + struct stat file_stat; + + memset(&file_stat, 0, sizeof(struct stat)); + + if (stat(path, &file_stat) < 0) { + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == ENOTDIR) return f_false; + if (errno == ENOENT) return f_file_not_found; + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ELOOP) return f_status_set_error(f_loop); + + return f_status_set_error(f_file_error_stat); + } + + if ((file_stat.st_mode & S_IFMT) == S_IFDIR) return f_true; + + return f_false; + } +#endif // _di_f_directory_exists_ #ifndef _di_f_directory_is_ f_return_status f_directory_is(const f_string path) { struct stat file_stat; - memset(&file_stat, 0, sizeof(struct stat)); + memset(&file_stat, AT_SYMLINK_NOFOLLOW, sizeof(struct 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_false; - } - else if (errno == ENOENT) { - return 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); - } + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == ENOTDIR) return f_false; + if (errno == ENOENT) return f_file_not_found; + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ELOOP) return f_status_set_error(f_loop); return f_status_set_error(f_file_error_stat); } @@ -156,27 +116,14 @@ extern "C" { 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) { - 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_false; - } - else if (errno == ENOENT) { - return 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); - } + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == ENOTDIR) return f_false; + if (errno == ENOENT) return f_file_not_found; + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ELOOP) return f_status_set_error(f_loop); return f_status_set_error(f_file_error_stat); } @@ -265,51 +212,22 @@ extern "C" { } if (result < 0) { - if (errno == EACCES) { - return f_status_set_error(f_access_denied); - } - else if (errno == EBUSY) { - return f_status_set_error(f_busy); - } - else if (errno == EIO) { - return f_status_set_error(f_error_input_output); - } - else if (errno == EISDIR) { - return f_status_set_error(f_file_is_type_directory); - } - else if (errno == ELOOP) { - return f_status_set_error(f_loop); - } - else if (errno == ENAMETOOLONG || errno == EFAULT) { - return f_status_set_error(f_invalid_name); - } - 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 == EOVERFLOW) { - return f_status_set_error(f_number_overflow); - } - else if (errno == EMFILE) { - return f_status_set_error(f_file_max_descriptors); - } - else if (errno == ENFILE) { - return f_status_set_error(f_file_max_open); - } - else if (errno == EINVAL) { - return f_status_set_error(f_invalid_parameter); - } + 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_error_input_output); + if (errno == EISDIR) return f_status_set_error(f_file_is_type_directory); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == EPERM) return f_status_set_error(f_prohibited); + if (errno == EROFS) return f_status_set_error(f_read_only); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == EMFILE) return f_status_set_error(f_file_max_descriptors); + if (errno == ENFILE) return f_status_set_error(f_file_max_open); + if (errno == EINVAL) return f_status_set_error(f_invalid_parameter); return f_status_set_error(f_failure); } @@ -341,51 +259,22 @@ extern "C" { } if (result < 0) { - if (errno == EACCES) { - return f_status_set_error(f_access_denied); - } - else if (errno == EBUSY) { - return f_status_set_error(f_busy); - } - else if (errno == EIO) { - return f_status_set_error(f_error_input_output); - } - else if (errno == EISDIR) { - return f_status_set_error(f_file_is_type_directory); - } - else if (errno == ELOOP) { - return f_status_set_error(f_loop); - } - else if (errno == ENAMETOOLONG || errno == EFAULT) { - return f_status_set_error(f_invalid_name); - } - 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 == EOVERFLOW) { - return f_status_set_error(f_number_overflow); - } - else if (errno == EMFILE) { - return f_status_set_error(f_file_max_descriptors); - } - else if (errno == ENFILE) { - return f_status_set_error(f_file_max_open); - } - else if (errno == EINVAL) { - return f_status_set_error(f_invalid_parameter); - } + 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_error_input_output); + if (errno == EISDIR) return f_status_set_error(f_file_is_type_directory); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == EPERM) return f_status_set_error(f_prohibited); + if (errno == EROFS) return f_status_set_error(f_read_only); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == EMFILE) return f_status_set_error(f_file_max_descriptors); + if (errno == ENFILE) return f_status_set_error(f_file_max_open); + if (errno == EINVAL) return f_status_set_error(f_invalid_parameter); return f_status_set_error(f_failure); } diff --git a/level_0/f_directory/c/directory.h b/level_0/f_directory/c/directory.h index 77a3215..2432bd3 100644 --- a/level_0/f_directory/c/directory.h +++ b/level_0/f_directory/c/directory.h @@ -45,13 +45,14 @@ extern "C" { * The name max 255 because the directory name size is 256. * The last 1 is for the NULL character. * - * The directory max recursion is more of a default than a rule. + * 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_max_recursion 2048 + #define f_directory_name_max 255 + #define f_directory_descriptors_max 255 #endif // _di_f_directory_limitations_ /** @@ -124,6 +125,55 @@ extern "C" { #endif // _di_f_directory_listing_ /** + * A structure representing a set of modes intended to be used by directory operations. + * + * A small set of macros are provider to help simplify assigning modes. + * + * The pipe (S_IFIFO) is intentionally not supported. + */ +#ifndef _di_f_directory_mode_ + typedef struct { + f_string_dynamics block; // S_IFBLK + f_string_dynamics character; // S_IFCHR + f_string_dynamics directory; // S_IFDIR + f_string_dynamics file; // S_IFREG + f_string_dynamics link; // S_IFLNK + f_string_dynamics socket; // S_IFSOCK + f_string_dynamics unknown; + } f_directory_mode; + + #define f_directory_mode_initialize { \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + } + + #define f_macro_directory_mode_set_all(modes, mode) \ + modes.block = mode; \ + modes.character = mode; \ + modes.directory = mode; \ + modes.file = mode; \ + modes.link = mode; \ + modes.socket = mode; \ + modes.unknown = mode; + + #define f_macro_directory_mode_set_common(modes, mode_directory, mode_file, mode_link) \ + modes.directory = mode_directory; \ + modes.file = mode_file; \ + modes.link = mode_link; + + #define f_macro_directory_mode_set_uncommon(modes, mode_block, mode_character, mode_socket, mode_unknown) \ + modes.block = mode_block; \ + modes.character = mode_character; \ + modes.socket = mode_socket; \ + modes.unknown = mode_unknown; +#endif // _di_f_directory_mode_ + +/** * A structure representing a directory. * * @todo review this and decide to keep and use it or just remove it. @@ -145,8 +195,8 @@ extern "C" { * * @param path * The path file name. - * @param modes - * The directory modes to use when creating. + * @param mode + * The directory mode to use when creating. * * @return * f_none on success. @@ -159,7 +209,7 @@ extern "C" { * 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_no_space (with error bit) if filesystem is out of space (or filesystem quota is reached). * 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_directory_error_link_max (with error bit) max links limit reached or exceeded. @@ -168,7 +218,7 @@ extern "C" { * @see mkdir() */ #ifndef _di_f_directory_create_ - extern f_return_status f_directory_create(const f_string path, const mode_t modes); + extern f_return_status f_directory_create(const f_string path, const mode_t mode); #endif // _di_f_directory_create_ /** @@ -178,8 +228,8 @@ extern "C" { * The file descriptor in which the directory will be created within. * @param path * The path file name. - * @param modes - * The directory modes to use when creating. + * @param mode + * The directory mode to use when creating. * * @return * f_none on success. @@ -192,19 +242,42 @@ extern "C" { * 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_no_space (with error bit) if filesystem is out of space (or filesystem quota is reached). * 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_directory_error_link_max (with error bit) max links limit reached or exceeded. * f_invalid_directory (with error bit) if a supposed directory in path is not actually a directory. * * @see mkdir() - * + */ #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 modes); + extern f_return_status f_directory_create_at(const int at_id, const f_string path, const mode_t mode); #endif // _di_f_directory_create_at_ /** + * 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 path + * The path file name. + * + * @return + * t_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_not_found if the path was not found. + * 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_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 fstat() + */ +#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. * * @param path @@ -212,7 +285,7 @@ extern "C" { * * @return * t_true if path was found and path is a directory. - * f_false if path was found and path is not a directory. + * f_false if path was found and path is not a directory (this includes symlinks). * f_file_not_found if the path was not found. * f_invalid_name (with error bit) if the name is somehow invalid. * f_out_of_memory (with error bit) if out of memory. diff --git a/level_0/f_directory/c/private-directory.h b/level_0/f_directory/c/private-directory.h index 79f80cc..fdfca22 100644 --- a/level_0/f_directory/c/private-directory.h +++ b/level_0/f_directory/c/private-directory.h @@ -36,8 +36,6 @@ extern "C" { * Check errno for details. * * @see f_directory_remove() - * @see nftw() - * @see remove() */ #if !defined(_di_f_directory_remove_) extern int private_f_directory_remove_recursively(const char *path, const struct stat *file_stat, int type, struct FTW *entity) f_gcc_attribute_visibility_internal; diff --git a/level_0/f_file/c/file.c b/level_0/f_file/c/file.c index 0dedbf3..f47c90b 100644 --- a/level_0/f_file/c/file.c +++ b/level_0/f_file/c/file.c @@ -12,28 +12,14 @@ extern "C" { #endif // _di_level_0_parameter_checking_ if (access(path, F_OK)) { - if (errno == ENOENT) { - return f_false; - } - - 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 == EACCES) { - return f_status_set_error(f_access_denied); - } - else if (errno == ELOOP) { - return f_status_set_error(f_loop); - } + if (errno == ENOENT) return f_false; + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ELOOP) return f_status_set_error(f_loop); return f_status_set_error(f_false); } @@ -42,12 +28,30 @@ extern "C" { } #endif // _di_f_file_access_ +#ifndef _di_f_file_change_mode_ + f_return_status f_file_change_mode(const f_string path, const mode_t mode, const bool dereference) { + return private_f_file_change_mode(path, mode, dereference); + } +#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); + } +#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) { - return private_f_file_change_owner(path, uid, gid); + f_return_status f_file_change_owner(const f_string path, const uid_t uid, const gid_t gid, const bool dereference) { + 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); + } +#endif // _di_f_file_change_owner_at_ + #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_ @@ -55,47 +59,40 @@ extern "C" { #endif // _di_level_0_parameter_checking_ f_status status = f_none; + struct stat source_stat; - status = private_f_file_create(destination, mode, exclusive); - if (f_status_is_error(status)) return status; - - f_file file_source = f_file_initialize; - f_file file_destination = f_file_initialize; - - file_destination.mode = f_file_write_create; + memset(&source_stat, 0, sizeof(struct stat)); - status = private_f_file_open(&file_source, source); + status = private_f_file_stat(source, &source_stat, f_false); 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; - } - - 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 (f_macro_file_type_is_file(source_stat.st_mode)) { + status = private_f_file_create(destination, mode, exclusive, f_false); + if (f_status_is_error(status)) return status; - if (size_write < 0 || size_write != size_read) { - private_f_file_close(&file_destination); - private_f_file_close(&file_source); + if (!exclusive) { + status = private_f_file_change_mode(destination, mode, f_false); + if (f_status_is_error(status)) return status; + } - return f_status_set_error(f_file_error_write); + return private_f_file_copy_content(source, destination, 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; } - } // while - private_f_file_close(&file_destination); - private_f_file_close(&file_source); + status = private_f_file_change_mode(destination, mode, f_false); + if (f_status_is_error(status)) return status; - if (size_read < 0) return f_status_set_error(f_file_error_read); + return f_none; + } - return f_none; + return f_unsupported; } #endif // _di_f_file_copy_ @@ -110,170 +107,191 @@ extern "C" { 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); + status = private_f_file_stat(source, &source_stat, f_false); 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 (roles) { - status = private_f_file_change_owner(destination, source_stat.st_uid, source_stat.st_gid); + if (f_macro_file_type_is_file(source_stat.st_mode)) { + status = private_f_file_create(destination, source_stat.st_mode, exclusive, f_false); if (f_status_is_error(status)) return status; - } - f_file file_source = f_file_initialize; - f_file file_destination = f_file_initialize; - - file_destination.mode = f_file_write_create; + if (!exclusive) { + status = private_f_file_change_mode(destination, source_stat.st_mode, f_false); + if (f_status_is_error(status)) return status; + } - status = private_f_file_open(&file_source, source); - 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; + } - status = private_f_file_open(&file_destination, destination); - if (f_status_is_error(status)) { - private_f_file_close(&file_source); - return status; + return private_f_file_copy_content(source, destination, 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; + } - 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); + status = private_f_file_change_mode(destination, source_stat.st_mode, f_false); + if (f_status_is_error(status)) return status; - return f_status_set_error(f_file_error_write); + 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; } - } // 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; + } - return f_none; + return f_unsupported; } #endif // _di_f_file_clone_ #ifndef _di_f_file_close_ - f_return_status f_file_close(f_file *file) { + f_return_status f_file_close(int *id) { #ifndef _di_level_0_parameter_checking_ - if (file == 0) return f_status_set_error(f_invalid_parameter); + if (id == 0) return f_status_set_error(f_invalid_parameter); #endif // _di_level_0_parameter_checking_ - return private_f_file_close(file); + return private_f_file_close(id); } #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); + f_return_status f_file_create(const f_string path, const mode_t mode, const bool exclusive, const bool dereference) { + return private_f_file_create(path, mode, exclusive, dereference); } #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_ - if (directory_file_descriptor == 0) return f_status_set_error(f_invalid_parameter); - if (path == 0) return f_status_set_error(f_invalid_parameter); - #endif // _di_level_0_parameter_checking_ +#ifndef _di_f_file_create_at_ + f_return_status f_file_create_at(const int at_id, const f_string path, const mode_t mode, const bool exclusive, const bool dereference) { + return private_f_file_create_at(at_id, path, mode, exclusive, dereference); + } +#endif // _di_f_file_create_at_ - if (faccessat(directory_file_descriptor, path, F_OK, flags)) { - if (errno == ENOENT) { - return f_false; - } +#ifndef _di_f_file_exists_ + f_return_status f_file_exists(const f_string path) { + struct stat file_stat; - 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 == EACCES) { - return f_status_set_error(f_access_denied); - } - else if (errno == ELOOP) { - return f_status_set_error(f_loop); - } - else if (errno == EBADF) { - return f_status_set_error(f_invalid_descriptor); - } - else if (errno == EINVAL) { - return f_status_set_error(f_invalid_parameter); - } + memset(&file_stat, 0, sizeof(struct stat)); - return f_status_set_error(f_false); + if (stat(path, &file_stat) < 0) { + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == ENOENT) return f_false; + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ELOOP) return f_status_set_error(f_loop); + + return f_status_set_error(f_file_error_stat); } return f_true; } -#endif // _di_f_file_exists_at_ +#endif // _di_f_file_exists_ -#ifndef _di_f_file_flush_ - f_return_status f_file_flush(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_ +#ifndef _di_f_file_exists_at_ + f_return_status f_file_exists_at(const int at_id, const f_string path, const bool follow) { + struct stat file_stat; + + memset(&file_stat, 0, sizeof(struct stat)); - if (file->address == 0) return f_status_set_error(f_file_not_open); + if (fstatat(at_id, path, &file_stat, follow ? 0 : AT_SYMLINK_NOFOLLOW) < 0) { + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == ENOENT) return f_file_not_found; + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ELOOP) return f_status_set_error(f_loop); - if (fflush(file->address) == 0) return f_none; + return f_status_set_error(f_file_error_stat); + } - return f_status_set_error(f_file_error_flush); + return f_true; + } +#endif // _di_f_file_exists_at_ + +#ifndef _di_f_file_flush_ + f_return_status f_file_flush(const int id) { + return private_f_file_flush(id); } #endif // _di_f_file_flush_ -#ifndef _di_f_file_exists_ - f_return_status f_file_exists(const f_string path) { - struct stat file_stat; +#ifndef _di_f_file_link_ + f_return_status f_file_link(const f_string target, const f_string point) { + return private_f_file_link(target, point); + } +#endif // _di_f_file_link_ - memset(&file_stat, 0, sizeof(struct stat)); +#ifndef _di_f_file_link_at_ + f_return_status f_file_link_at(const int at_id, const f_string target, const f_string point) { + return private_f_file_link_at(at_id, target, point); + } +#endif // _di_f_file_link_at_ + +#ifndef _di_f_file_link_hard_ + f_return_status f_file_link_hard(const f_string target, const f_string point) { + + if (link(target, point) < 0) { + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == EDQUOT) return f_status_set_error(f_filesystem_quota_blocks); + if (errno == EEXIST) return f_status_set_error(f_file_found); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_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_invalid_parameter); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOSPC) return f_status_set_error(f_no_space); + 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 (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_false; - } - 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_failure); + } - return f_status_set_error(f_file_error_stat); + return f_none; + } +#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) { + + if (linkat(at_id_target, target, at_id_point, point, flags) < 0) { + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == EDQUOT) return f_status_set_error(f_filesystem_quota_blocks); + if (errno == EEXIST) return f_status_set_error(f_file_found); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_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_invalid_parameter); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == EBADF) return f_status_set_error(f_file_error_descriptor); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOSPC) return f_status_set_error(f_no_space); + 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); + + return f_status_set_error(f_failure); } - return f_true; + return f_none; } -#endif // _di_f_file_exists_ +#endif // _di_f_file_link_hard_at_ #ifndef _di_f_file_is_ f_return_status f_file_is(const f_string path, const int type) { @@ -282,27 +300,14 @@ extern "C" { memset(&file_stat, 0, sizeof(struct 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_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); - } + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == ENOENT) return f_file_not_found; + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ELOOP) return f_status_set_error(f_loop); return f_status_set_error(f_file_error_stat); } @@ -314,33 +319,20 @@ extern "C" { #endif // _di_f_file_is_ #ifndef _di_f_file_is_at_ - f_return_status f_file_is_at(const int file_id, const f_string path, const int type, const bool follow) { + f_return_status f_file_is_at(const int at_id, const f_string path, const int type, const bool follow) { 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 (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_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); - } + if (fstatat(at_id, path, &file_stat, follow ? 0 : AT_SYMLINK_NOFOLLOW) < 0) { + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == ENOENT) return f_file_not_found; + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ELOOP) return f_status_set_error(f_loop); return f_status_set_error(f_file_error_stat); } @@ -352,15 +344,25 @@ extern "C" { #endif // _di_f_file_is_at_ #ifndef _di_f_file_open_ - f_return_status f_file_open(f_file *file, const f_string path) { + f_return_status f_file_open(const f_string path, const int flags, const mode_t mode, 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_open(file, path); + return private_f_file_open(path, mode, flags, file); } #endif // _di_f_file_open_ +#ifndef _di_f_file_open_at_ + f_return_status f_file_open_at(const int at_id, const f_string path, const int flags, const mode_t mode, 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_open_at(at_id, path, flags, mode, file); + } +#endif // _di_f_file_open_at_ + #ifndef _di_f_file_read_ f_return_status f_file_read(f_file *file, f_string_dynamic *buffer) { #ifndef _di_level_0_parameter_checking_ @@ -370,86 +372,103 @@ extern "C" { if (buffer->used >= buffer->size) 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); + if (file->id <= 0) return f_status_set_error(f_file_not_open); - int result = fread(buffer->string + buffer->used, file->size_chunk, file->size_block, file->address); + f_status status = f_none; + ssize_t size_read = 0; - if (file->address == 0) return f_status_set_error(f_file_error_read); - if (ferror(file->address) != 0) return f_status_set_error(f_file_error_read); + // use a custom buffer so that memory is allocated post-read instead of pre-read. + const f_string_length buffer_size = file->size_chunk * file->size_block; + char buffer_read[buffer_size]; - if (file->size_chunk > 1) { - buffer->used += result * file->size_chunk; - } - else { - buffer->used += result; + memset(&buffer_read, 0, sizeof(buffer_size)); + + while ((size_read = read(file->id, buffer_read, buffer_size)) > 0) { + if (buffer->used + size_read > buffer->size) { + if (buffer->size + size_read > f_string_length_size) { + return f_status_set_error(f_string_too_large); + } + + f_macro_string_dynamic_resize(status, (*buffer), buffer->size + size_read); + if (f_status_is_error(status)) return status; + } + + memcpy(buffer->string + buffer->used, buffer_read, buffer_size); + buffer->used += size_read; + } // while + + if (size_read == 0) { + return f_none_on_eof; } - if (feof(file->address)) return f_none_on_eof; + if (size_read < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) return f_status_set_error(f_block); + if (errno == EBADF) return f_status_set_error(f_file_error_descriptor); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == EINTR) return f_status_set_error(f_interrupted); + if (errno == EINVAL) return f_status_set_error(f_invalid_parameter); + if (errno == EIO) return f_status_set_error(f_error_input_output); + if (errno == EISDIR) return f_status_set_error(f_file_is_type_directory); + + return f_status_set_error(f_failure); + } return f_none; } #endif // _di_f_file_read_ -#ifndef _di_f_file_read_at_ - f_return_status f_file_read_at(f_file *file, f_string_dynamic *buffer, const f_file_position position) { +#ifndef _di_f_file_read_block_ + f_return_status f_file_read_block(f_file *file, f_string_dynamic *buffer) { #ifndef _di_level_0_parameter_checking_ if (file == 0) return f_status_set_error(f_invalid_parameter); if (file->size_chunk == 0) return f_status_set_error(f_invalid_parameter); if (file->size_block == 0) return f_status_set_error(f_invalid_parameter); if (buffer->used >= buffer->size) return f_status_set_error(f_invalid_parameter); - - // when the available buffer size is smaller than the total elements, then there is not enough allocated memory available to read the file. - if (position.total > 0) { - if (buffer->used + position.total > buffer->size) return f_status_set_error(f_invalid_parameter); - } - else { - if (buffer->used + (file->size_chunk * file->size_block) > buffer->size) 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); + if (file->id <= 0) return f_status_set_error(f_file_not_open); - // first seek to 'where' we need to begin the read. - long current_file_position = ftell(file->address); + f_status status = f_none; + ssize_t size_read = 0; - if (current_file_position == -1) return f_status_set_error(f_file_error_seek); + const f_string_length buffer_size = file->size_chunk * file->size_block; + char buffer_read[buffer_size]; - int result = 0; + memset(&buffer_read, 0, sizeof(buffer_size)); - if (current_file_position > position.start) { - result = f_macro_file_seek_to(file->address, file->size_chunk * (0 - (current_file_position - position.start))); - } - else if (current_file_position < position.start) { - result = f_macro_file_seek_to(file->address, file->size_chunk * (position.start - current_file_position)); - } + if ((size_read = read(file->id, buffer_read, buffer_size)) > 0) { + if (buffer->used + size_read > buffer->size) { + if (buffer->size + size_read > f_string_length_size) { + return f_status_set_error(f_string_too_large); + } - if (result != 0) return f_status_set_error(f_file_error_seek); + f_macro_string_dynamic_resize(status, (*buffer), buffer->size + size_read); + if (f_status_is_error(status)) return status; + } - // now do the actual read - if (position.total == 0) { - result = fread(buffer->string + buffer->used, file->size_chunk, file->size_block, file->address); - } - else { - result = fread(buffer->string + buffer->used, file->size_chunk, position.total, file->address); + memcpy(buffer->string + buffer->used, buffer_read, buffer_size); + buffer->used += size_read; } - if (file->address == 0) return f_status_set_error(f_file_error_read); - if (ferror(file->address) != 0) return f_status_set_error(f_file_error_read); + if (size_read == 0) { + return f_none_on_eof; + } - f_number_unsigned bytes_total; + if (size_read < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) return f_status_set_error(f_block); + if (errno == EBADF) return f_status_set_error(f_file_error_descriptor); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == EINTR) return f_status_set_error(f_interrupted); + if (errno == EINVAL) return f_status_set_error(f_invalid_parameter); + if (errno == EIO) return f_status_set_error(f_error_input_output); + if (errno == EISDIR) return f_status_set_error(f_file_is_type_directory); - if (file->size_chunk > 1) { - buffer->used += result * file->size_chunk; - } - else { - buffer->used += result; + return f_status_set_error(f_failure); } - if (feof(file->address)) return f_none_on_eof; - return f_none; } -#endif // _di_f_file_read_at_ +#endif // _di_f_file_read_block_ #ifndef _di_f_file_read_until_ f_return_status f_file_read_until(f_file *file, f_string_dynamic *buffer, const f_string_length total) { @@ -458,38 +477,54 @@ extern "C" { if (file->size_chunk == 0) return f_status_set_error(f_invalid_parameter); if (file->size_block == 0) return f_status_set_error(f_invalid_parameter); if (buffer->used >= buffer->size) return f_status_set_error(f_invalid_parameter); - - // when the available buffer size is smaller than the total elements, then there is not enough allocated memory available to read the file. - if (total > 0) { - if (buffer->used + total > buffer->size) return f_status_set_error(f_invalid_parameter); - } - else { - if (buffer->used + (file->size_chunk * file->size_block) > buffer->size) 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); + if (file->id <= 0) return f_status_set_error(f_file_not_open); - int result; + f_status status = f_none; + ssize_t size_read = 0; - if (total == 0) { - result = fread(buffer->string + buffer->used, file->size_chunk, file->size_block, file->address); - } - else { - result = fread(buffer->string + buffer->used, file->size_chunk, total, file->address); + f_string_length buffer_size = file->size_chunk * file->size_block; + f_string_length buffer_count = 0; + + if (total < buffer_size) { + buffer_size = total; } - if (file->address == 0) return f_status_set_error(f_file_error_read); - if (ferror(file->address) != 0) return f_status_set_error(f_file_error_read); + char buffer_read[buffer_size]; - if (file->size_chunk > 1) { - buffer->used += result * file->size_chunk; + memset(&buffer_read, 0, sizeof(buffer_size)); + + if ((size_read = read(file->id, buffer_read, buffer_size)) > 0) { + if (buffer->used + size_read > buffer->size) { + if (buffer->size + size_read > f_string_length_size) { + return f_status_set_error(f_string_too_large); + } + + f_macro_string_dynamic_resize(status, (*buffer), buffer->size + size_read); + if (f_status_is_error(status)) return status; + } + + memcpy(buffer->string + buffer->used, buffer_read, buffer_size); + buffer->used += size_read; + buffer_count += size_read; } - else { - buffer->used += result; + + if (size_read == 0) { + return f_none_on_eof; } - if (feof(file->address)) return f_none_on_eof; + if (size_read < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) return f_status_set_error(f_block); + if (errno == EBADF) return f_status_set_error(f_file_error_descriptor); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == EINTR) return f_status_set_error(f_interrupted); + if (errno == EINVAL) return f_status_set_error(f_invalid_parameter); + if (errno == EIO) return f_status_set_error(f_error_input_output); + if (errno == EISDIR) return f_status_set_error(f_file_is_type_directory); + + return f_status_set_error(f_failure); + } return f_none; } @@ -497,40 +532,20 @@ extern "C" { #ifndef _di_f_file_remove_ f_return_status f_file_remove(const f_string path) { + if (unlink(path) < 0) { - if (errno == EACCES) { - return f_status_set_error(f_access_denied); - } - else if (errno == EBUSY) { - return f_status_set_error(f_busy); - } - else if (errno == EIO) { - return f_status_set_error(f_error_input_output); - } - else if (errno == EISDIR) { - return f_status_set_error(f_file_is_type_directory); - } - else if (errno == ELOOP) { - return f_status_set_error(f_loop); - } - else if (errno == ENAMETOOLONG || errno == EFAULT) { - return f_status_set_error(f_invalid_name); - } - 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); - } + 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_error_input_output); + if (errno == EISDIR) return f_status_set_error(f_file_is_type_directory); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + 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); } @@ -539,84 +554,145 @@ extern "C" { } #endif // _di_f_file_remove_ -#ifndef _di_f_file_stat_ - f_return_status f_file_stat(const f_string path, struct stat *file_stat) { - return private_f_file_stat(path, file_stat); +#ifndef _di_f_file_remove_at_ + f_return_status f_file_remove_at(const int at_id, const f_string path, const int flags) { + + if (unlinkat(at_id, path, flags) < 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_error_input_output); + if (errno == EISDIR) return f_status_set_error(f_file_is_type_directory); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + 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_file_stat_ +#endif // _di_f_file_remove_at_ -#ifndef _di_f_file_stat_at_ - f_return_status f_file_stat_at(const int file_id, const f_string path, struct stat *file_stat, const int flags) { +#ifndef _di_f_file_seek_ + f_return_status f_file_seek(const int id, const int whence, const f_string_length offset, f_string_length *seeked) { #ifndef _di_level_0_parameter_checking_ - if (file_id <= 0) return f_status_set_error(f_invalid_parameter); + if (id <= 0) return f_status_set_error(f_invalid_parameter); + if (whence < 0) return f_status_set_error(f_invalid_parameter); #endif // _di_level_0_parameter_checking_ - if (fstatat(file_id, path, file_stat, flags) < 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_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); - } + *seeked = lseek(id, offset, whence); - return f_status_set_error(f_file_error_stat); + if (*seeked < 0) { + if (errno == EBADF) return f_status_set_error(f_file_error_descriptor); + if (errno == EINVAL) return f_status_set_error(f_invalid_parameter); + if (errno == ENXIO) return f_status_set_error(f_out_of_bound); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == ESPIPE) return f_status_set_error(f_file_is_type_pipe); + + return f_status_set_error(f_failure); } return f_none; } -#endif // _di_f_file_stat_by_at_ +#endif // _di_f_file_seek_ -#ifndef _di_f_file_stat_by_id_ - f_return_status f_file_stat_by_id(const int file_id, struct stat *file_stat) { +#ifndef _di_f_file_size_ + f_return_status f_file_size(const f_string path, const bool dereference, f_string_length *size) { #ifndef _di_level_0_parameter_checking_ - if (file_id <= 0) return f_status_set_error(f_invalid_parameter); + if (size == 0) return f_status_set_error(f_invalid_parameter); #endif // _di_level_0_parameter_checking_ - int result = fstat(file_id, file_stat); + struct stat file_stat; - if (result < 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_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); - } + memset(&file_stat, 0, sizeof(struct stat)); - return f_status_set_error(f_file_error_stat); - } + f_status status = private_f_file_stat(path, dereference, &file_stat); + + if (f_status_is_error(status)) return status; + + *size = file_stat.st_size; + + return f_none; + } +#endif // _di_f_file_size_ + +#ifndef _di_f_file_size_at_ + f_return_status f_file_size_at(const int at_id, const f_string path, const bool dereference, f_string_length *size) { + #ifndef _di_level_0_parameter_checking_ + if (at_id <= 0) return f_status_set_error(f_invalid_parameter); + if (size == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ + + struct stat file_stat; + + memset(&file_stat, 0, sizeof(struct stat)); + + f_status status = private_f_file_stat_at(at_id, path, dereference, &file_stat); + + if (f_status_is_error(status)) return status; + + *size = file_stat.st_size; return f_none; } +#endif // _di_f_file_size_at_ + +#ifndef _di_f_file_size_by_id_ + f_return_status f_file_size_by_id(const int id, f_string_length *size) { + #ifndef _di_level_0_parameter_checking_ + if (id <= 0) return f_status_set_error(f_invalid_parameter); + if (size == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ + + struct stat file_stat; + + memset(&file_stat, 0, sizeof(struct stat)); + + f_status status = private_f_file_stat_by_id(id, &file_stat); + + if (f_status_is_error(status)) return status; + + *size = file_stat.st_size; + + return f_none; + } +#endif // _di_f_file_size_by_id_ + +#ifndef _di_f_file_stat_ + f_return_status f_file_stat(const f_string path, const bool dereference, struct stat *file_stat) { + #ifndef _di_level_0_parameter_checking_ + if (file_stat == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ + + return private_f_file_stat(path, dereference, file_stat); + } +#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) { + #ifndef _di_level_0_parameter_checking_ + if (at_id <= 0) return f_status_set_error(f_invalid_parameter); + if (file_stat == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ + + return private_f_file_stat_at(at_id, path, flags, file_stat); + } +#endif // _di_f_file_stat_at_ + +#ifndef _di_f_file_stat_by_id_ + f_return_status f_file_stat_by_id(const int id, struct stat *file_stat) { + #ifndef _di_level_0_parameter_checking_ + if (id <= 0) return f_status_set_error(f_invalid_parameter); + if (file_stat == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ + + return private_f_file_stat_by_id(id, file_stat); + } #endif // _di_f_file_stat_by_id_ #ifdef __cplusplus diff --git a/level_0/f_file/c/file.h b/level_0/f_file/c/file.h index 05018e2..f5658ae 100644 --- a/level_0/f_file/c/file.h +++ b/level_0/f_file/c/file.h @@ -34,27 +34,11 @@ extern "C" { * Provide common file-typ specific data types. */ #ifndef _di_f_file_types_ - typedef int f_file_id; - typedef f_string f_file_mode; - typedef mode_t f_file_mask; - #define f_file_default_read_size 8192 // default to 8k read sizes. #define f_file_default_write_size 8192 // default to 8k write sizes. #endif // _di_f_file_types_ /** - * Provide classic string-based file modes. - */ -#ifndef _di_f_file_oldstyle_modes_ - #define f_file_read_only "r" - #define f_file_read_write "r+" - #define f_file_read_write_create "rw" - #define f_file_read_write_append "a+" - #define f_file_write_create "w" - #define f_file_write_append "a" -#endif // _di_f_file_oldstyle_modes_ - -/** * Provide macros for file-seek operations. * * The fseek() function parameters can be confusing, so provide a hopefully more readibly code via these macros. @@ -102,129 +86,118 @@ extern "C" { * Commonly used file related properties. * * id: File descriptor. - * address: A pointer to a file (generally opened). - * mode: How the file is to be accessed (or is being accessed). * size_chunk: Number of bytes to consider a character, a value of 1 means 1-byte (aka: uint8_t) (for normal string handling this should be sizeof(f_string)). * size_block: The default number of chunks to read at a time (use (size_chunk * size_block) to determine total number of bytes). */ #ifndef _di_f_file_ typedef struct { - f_file_id id; - FILE * address; - f_file_mode mode; - size_t size_chunk; - f_number_unsigned size_block; + int id; + size_t size_chunk; + size_t size_block; } f_file; - #define f_file_initialize { 0, 0, (f_file_mode) f_file_read_only, 1, f_file_default_read_size } + #define f_file_initialize { 0, 1, f_file_default_read_size } #endif // _di_f_file_ /** - * Store file positions. - * - * This is commonly used to instruct functions how to buffer and use a file. - * - * start: The positions where to begin reading the file. - * total: The total number of elements to read from the file into the buffer (set to 0 to read entire file). - */ -#ifndef _di_f_file_position_ - typedef struct { - f_string_length start; - f_string_length total; - } f_file_position; - - #define f_file_position_initialize { 0, 0 } -#endif // _di_f_file_position_ - -/** * File mode relation functionality. */ #ifndef _di_f_file_modes_ - // file open modes - #define f_file_mode_read_only O_RDONLY - #define f_file_mode_write_only O_WRONLY - #define f_file_mode_read_write O_RDWR - #define f_file_mode_create O_CREAT - #define f_file_mode_exclusive O_EXCL - #define f_file_mode_no_tty O_NOCTTY - #define f_file_mode_truncate O_TRUNC - #define f_file_mode_append O_APPEND - #define f_file_mode_non_blocking O_NONBLOCK - #define f_file_mode_synchronous O_SYNC - #define f_file_mode_no_follow O_NOFOLLOW - #define f_file_mode_directory O_DIRECTORY - #define f_file_mode_direct_io O_DIRECT - #define f_file_mode_asynchronous O_ASYNC - #define f_file_mode_large_file O_LARGEFILE - - // file open modes pre-combined with create - #define f_file_mode_create_ro (O_CREAT | O_RDONLY) - #define f_file_mode_create_wo (O_CREAT | O_WRONLY) - #define f_file_mode_create_rw (O_CREAT | O_RDRW) - - // file open modes pre-combined will fail if file exists - #define f_file_mode_create_new_ro (O_CREAT | O_EXCL | O_RDONLY) - #define f_file_mode_create_new_wo (O_CREAT | O_EXCL | O_WRONLY) - #define f_file_mode_create_new_rw (O_CREAT | O_EXCL | O_RDRW) - - // file open modes pre-combined with synchronous io - #define f_file_mode_sync_ro (O_SYNC | O_RDONLY) - #define f_file_mode_sync_wo (O_SYNC | O_WRONLY) - #define f_file_mode_sync_rw (O_SYNC | O_RDRW) - #define f_file_mode_sync_create_ro (O_SYNC | O_CREAT | O_RDONLY) - #define f_file_mode_sync_create_wo (O_SYNC | O_CREAT | O_WRONLY) - #define f_file_mode_sync_create_rw (O_SYNC | O_CREAT | O_RDRW) - #define f_file_mode_sync_create_new_ro (O_SYNC | O_CREAT | O_EXCL | O_RDONLY) - #define f_file_mode_sync_create_new_wo (O_SYNC | O_CREAT | O_EXCL | O_WRONLY) - #define f_file_mode_sync_create_new_rw (O_SYNC | O_CREAT | O_EXCL | O_RDRW) - - // file open modes pre-combined with asynchronous io - #define f_file_mode_async_ro (O_ASYNC | O_RDONLY) - #define f_file_mode_async_wo (O_ASYNC | O_WRONLY) - #define f_file_mode_async_rw (O_ASYNC | O_RDRW) - #define f_file_mode_async_create_ro (O_ASYNC | O_CREAT | O_RDONLY) - #define f_file_mode_async_create_wo (O_ASYNC | O_CREAT | O_WRONLY) - #define f_file_mode_async_create_rw (O_ASYNC | O_CREAT | O_RDRW) - #define f_file_mode_async_create_new_ro (O_ASYNC | O_CREAT | O_EXCL | O_RDONLY) - #define f_file_mode_async_create_new_wo (O_ASYNC | O_CREAT | O_EXCL | O_WRONLY) - #define f_file_mode_async_create_new_rw (O_ASYNC | O_CREAT | O_EXCL | O_RDRW) - - // file open modes pre-combined with direct io (which works synchronously) - #define f_file_mode_direct_ro (O_DIRECT | O_RDONLY) - #define f_file_mode_direct_wo (O_DIRECT | O_WRONLY) - #define f_file_mode_direct_rw (O_DIRECT | O_RDRW) - #define f_file_mode_direct_create_ro (O_DIRECT | O_CREAT | O_RDONLY) - #define f_file_mode_direct_create_wo (O_DIRECT | O_CREAT | O_WRONLY) - #define f_file_mode_direct_create_rw (O_DIRECT | O_CREAT | O_RDRW) - #define f_file_mode_direct_create_new_ro (O_DIRECT | O_CREAT | O_EXCL | O_RDONLY) - #define f_file_mode_direct_create_new_wo (O_DIRECT | O_CREAT | O_EXCL | O_WRONLY) - #define f_file_mode_direct_create_new_rw (O_DIRECT | O_CREAT | O_EXCL | O_RDRW) - - // file open modes pre-combined with large_file - #define f_file_mode_large_ro (O_LARGEFILE | O_RDONLY) - #define f_file_mode_large_wo (O_LARGEFILE | O_WRONLY) - #define f_file_mode_large_rw (O_LARGEFILE | O_RDRW) - #define f_file_mode_large_sync_ro (O_LARGEFILE | O_SYNC | O_RDONLY) - #define f_file_mode_large_sync_wo (O_LARGEFILE | O_SYNC | O_WRONLY) - #define f_file_mode_large_sync_rw (O_LARGEFILE | O_SYNC | O_RDRW) - #define f_file_mode_large_sync_create_ro (O_LARGEFILE | O_SYNC | O_CREAT | O_RDONLY) - #define f_file_mode_large_sync_create_wo (O_LARGEFILE | O_SYNC | O_CREAT | O_WRONLY) - #define f_file_mode_large_sync_create_rw (O_LARGEFILE | O_SYNC | O_CREAT | O_RDRW) - #define f_file_mode_large_sync_create_new_ro (O_LARGEFILE | O_SYNC | O_CREAT | O_EXCL | O_RDONLY) - #define f_file_mode_large_sync_create_new_wo (O_LARGEFILE | O_SYNC | O_CREAT | O_EXCL | O_WRONLY) - #define f_file_mode_large_sync_create_new_rw (O_LARGEFILE | O_SYNC | O_CREAT | O_EXCL | O_RDRW) - #define f_file_mode_large_async_ro (O_LARGEFILE | O_ASYNC | O_RDONLY) - #define f_file_mode_large_async_wo (O_LARGEFILE | O_ASYNC | O_WRONLY) - #define f_file_mode_large_async_rw (O_LARGEFILE | O_ASYNC | O_RDRW) - #define f_file_mode_large_async_create_ro (O_LARGEFILE | O_ASYNC | O_CREAT | O_RDONLY) - #define f_file_mode_large_async_create_wo (O_LARGEFILE | O_ASYNC | O_CREAT | O_WRONLY) - #define f_file_mode_large_async_create_rw (O_LARGEFILE | O_ASYNC | O_CREAT | O_RDRW) - #define f_file_mode_large_async_create_new_ro (O_LARGEFILE | O_ASYNC | O_CREAT | O_EXCL | O_RDONLY) - #define f_file_mode_large_async_create_new_wo (O_LARGEFILE | O_ASYNC | O_CREAT | O_EXCL | O_WRONLY) - #define f_file_mode_large_async_create_new_rw (O_LARGEFILE | O_ASYNC | O_CREAT | O_EXCL | O_RDRW) - - // file permission modes + // file open flags + #define f_file_flag_append O_APPEND + #define f_file_flag_asynchronous O_ASYNC + #define f_file_flag_create O_CREAT + #define f_file_flag_close_execute O_CLOEXEC + #define f_file_flag_direct O_DIRECT + #define f_file_flag_directory O_DIRECTORY + #define f_file_flag_exclusive O_EXCL + #define f_file_flag_large_file O_LARGEFILE + #define f_file_flag_no_access_time O_NOATIME + #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_read_only O_RDONLY + #define f_file_flag_read_write O_RDWR + #define f_file_flag_synchronous O_SYNC + #define f_file_flag_synchronous_direct O_DSYNC + #define f_file_flag_temporary O_TMPFILE + #define f_file_flag_truncate O_TRUNC + #define f_file_flag_write_only O_WRONLY + + // file open flags pre-combined with create. + #define f_file_flag_create_ro (O_CREAT | O_RDONLY) + #define f_file_flag_create_wo (O_CREAT | O_WRONLY) + #define f_file_flag_create_rw (O_CREAT | O_RDRW) + + // file open flags pre-combined will fail if file exists. + #define f_file_flag_create_new_ro (O_CREAT | O_EXCL | O_RDONLY) + #define f_file_flag_create_new_wo (O_CREAT | O_EXCL | O_WRONLY) + #define f_file_flag_create_new_rw (O_CREAT | O_EXCL | O_RDRW) + + // file open flags pre-combined will truncate any existing files to 0. + #define f_file_flag_truncate_ro (O_CREAT | O_TRUNC | O_RDONLY) + #define f_file_flag_truncate_rw (O_CREAT | O_TRUNC | O_RDRW) + #define f_file_flag_truncate_wo (O_CREAT | O_TRUNC | O_WRONLY) + + // file open flags pre-combined with synchronous io. + #define f_file_flag_sync_ro (O_SYNC | O_RDONLY) + #define f_file_flag_sync_wo (O_SYNC | O_WRONLY) + #define f_file_flag_sync_rw (O_SYNC | O_RDRW) + #define f_file_flag_sync_create_ro (O_SYNC | O_CREAT | O_RDONLY) + #define f_file_flag_sync_create_wo (O_SYNC | O_CREAT | O_WRONLY) + #define f_file_flag_sync_create_rw (O_SYNC | O_CREAT | O_RDRW) + #define f_file_flag_sync_create_new_ro (O_SYNC | O_CREAT | O_EXCL | O_RDONLY) + #define f_file_flag_sync_create_new_wo (O_SYNC | O_CREAT | O_EXCL | O_WRONLY) + #define f_file_flag_sync_create_new_rw (O_SYNC | O_CREAT | O_EXCL | O_RDRW) + + // file open flags pre-combined with asynchronous io. + #define f_file_flag_async_ro (O_ASYNC | O_RDONLY) + #define f_file_flag_async_wo (O_ASYNC | O_WRONLY) + #define f_file_flag_async_rw (O_ASYNC | O_RDRW) + #define f_file_flag_async_create_ro (O_ASYNC | O_CREAT | O_RDONLY) + #define f_file_flag_async_create_wo (O_ASYNC | O_CREAT | O_WRONLY) + #define f_file_flag_async_create_rw (O_ASYNC | O_CREAT | O_RDRW) + #define f_file_flag_async_create_new_ro (O_ASYNC | O_CREAT | O_EXCL | O_RDONLY) + #define f_file_flag_async_create_new_wo (O_ASYNC | O_CREAT | O_EXCL | O_WRONLY) + #define f_file_flag_async_create_new_rw (O_ASYNC | O_CREAT | O_EXCL | O_RDRW) + + // file open flags pre-combined with direct io (which works synchronously). + #define f_file_flag_direct_ro (O_DIRECT | O_RDONLY) + #define f_file_flag_direct_wo (O_DIRECT | O_WRONLY) + #define f_file_flag_direct_rw (O_DIRECT | O_RDRW) + #define f_file_flag_direct_create_ro (O_DIRECT | O_CREAT | O_RDONLY) + #define f_file_flag_direct_create_wo (O_DIRECT | O_CREAT | O_WRONLY) + #define f_file_flag_direct_create_rw (O_DIRECT | O_CREAT | O_RDRW) + #define f_file_flag_direct_create_new_ro (O_DIRECT | O_CREAT | O_EXCL | O_RDONLY) + #define f_file_flag_direct_create_new_wo (O_DIRECT | O_CREAT | O_EXCL | O_WRONLY) + #define f_file_flag_direct_create_new_rw (O_DIRECT | O_CREAT | O_EXCL | O_RDRW) + + // file open flags pre-combined with large_file. + #define f_file_flag_large_ro (O_LARGEFILE | O_RDONLY) + #define f_file_flag_large_wo (O_LARGEFILE | O_WRONLY) + #define f_file_flag_large_rw (O_LARGEFILE | O_RDRW) + #define f_file_flag_large_sync_ro (O_LARGEFILE | O_SYNC | O_RDONLY) + #define f_file_flag_large_sync_wo (O_LARGEFILE | O_SYNC | O_WRONLY) + #define f_file_flag_large_sync_rw (O_LARGEFILE | O_SYNC | O_RDRW) + #define f_file_flag_large_sync_create_ro (O_LARGEFILE | O_SYNC | O_CREAT | O_RDONLY) + #define f_file_flag_large_sync_create_wo (O_LARGEFILE | O_SYNC | O_CREAT | O_WRONLY) + #define f_file_flag_large_sync_create_rw (O_LARGEFILE | O_SYNC | O_CREAT | O_RDRW) + #define f_file_flag_large_sync_create_new_ro (O_LARGEFILE | O_SYNC | O_CREAT | O_EXCL | O_RDONLY) + #define f_file_flag_large_sync_create_new_wo (O_LARGEFILE | O_SYNC | O_CREAT | O_EXCL | O_WRONLY) + #define f_file_flag_large_sync_create_new_rw (O_LARGEFILE | O_SYNC | O_CREAT | O_EXCL | O_RDRW) + #define f_file_flag_large_async_ro (O_LARGEFILE | O_ASYNC | O_RDONLY) + #define f_file_flag_large_async_wo (O_LARGEFILE | O_ASYNC | O_WRONLY) + #define f_file_flag_large_async_rw (O_LARGEFILE | O_ASYNC | O_RDRW) + #define f_file_flag_large_async_create_ro (O_LARGEFILE | O_ASYNC | O_CREAT | O_RDONLY) + #define f_file_flag_large_async_create_wo (O_LARGEFILE | O_ASYNC | O_CREAT | O_WRONLY) + #define f_file_flag_large_async_create_rw (O_LARGEFILE | O_ASYNC | O_CREAT | O_RDRW) + #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) + + // file permission modes. #define f_file_mode_owner_rwx S_IRWXU #define f_file_mode_owner_r S_IRUSR #define f_file_mode_owner_w S_IWUSR @@ -270,18 +243,67 @@ extern "C" { #endif // _di_f_file_modes_ /** - * Macro for resetting the file position and the total elements to the size of the file. + * Change mode of a given file at the specified path. + * + * @param path + * The path file name. + * @param mode + * The new mode to use. + * @param dereference + * Set to TRUE to dereferenc symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. * - * @todo review why this is being done this way and consider renaming, changing, or removing this. + * @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 chmod() */ -#ifndef _di_f_macro_file_reset_position_ - #define f_macro_file_reset_position(position, file) \ - if (position.total == 0) { \ - fseek(file.address, 0L, SEEK_END); \ - position.total = ftell(file.address); \ - fseek(file.address, 0L, SEEK_SET); \ - } -#endif // _di_f_macro_file_reset_position_ +#ifndef _di_f_file_change_mode_ + extern f_return_status f_file_change_mode(const f_string path, const mode_t mode, const bool dereference); +#endif // _di_f_file_change_mode_ + +/** + * Change mode of a given file at the specified path. + * + * @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 mode + * The new mode to use. + * @param flags + * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. + * + * @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 chmod() + */ +#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); +#endif // _di_f_file_change_mode_at_ /** * Change owner and group of a given file at the specified path. @@ -292,6 +314,9 @@ extern "C" { * The new user id to use. * @param gid * The new group id to use. + * @param dereference + * Set to TRUE to dereferenc symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. * * @return * f_true if file exists. @@ -308,10 +333,42 @@ extern "C" { * @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); + extern f_return_status f_file_change_owner(const f_string path, const uid_t uid, const gid_t gid, const bool dereference); #endif // _di_f_file_change_owner_ /** + * Change owner and group of a given file at the specified path. + * + * @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 uid + * 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. + * + * @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_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); +#endif // _di_f_file_change_owner_at_ + +/** * Check if a file can be accessed. * * @param path @@ -365,7 +422,7 @@ extern "C" { * 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_no_space (with error bit) if filesystem is out of space (or filesystem quota is reached). * 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. @@ -375,11 +432,6 @@ extern "C" { * 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); @@ -420,7 +472,7 @@ extern "C" { * 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_no_space (with error bit) if filesystem is out of space (or filesystem quota is reached). * 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. @@ -430,29 +482,52 @@ extern "C" { * 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_ /** + * Close an open file. + * + * Will flush before closing. + * + * @param id + * The file descriptor. + * + * @return + * f_none on success. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_file_error_descriptor (with error bit) if file descriptor is invalid. + * f_interrupted (with error bit) if interrupt was received. + * f_error_input_output (with error bit) on I/O error. + * f_filesystem_quota_blocks (with error bit) if filesystem's disk blocks or inodes are exhausted. + * f_no_space (with error bit) if filesystem is out of space (or filesystem quota is reached). + * f_file_error_synchronize (with error bit) on flush failure. + * f_file_error_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_ + +/** * Create a file based on the given path and file mode. * * The file will not be open after calling this. - * This is useful for creating empty files. * * @param path - * Full path to the file (including entire filename). + * The path file name. * @param mode - * The file mode. + * The file mode to open in. * @param exclusive * If TRUE, will fail when file already exists. * If FALSE, will not fail if file already exists. + * @param dereference + * Set to TRUE to dereferenc symlinks (often is what is desired). + * Set to FALSE to fail if the path is a symbolic link. + * This does not write symbolic links. (@todo add function f_create_link() for creating symbolic links.) * * @return * f_none on success. @@ -465,7 +540,7 @@ extern "C" { * 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_no_space (with error bit) if filesystem is out of space (or filesystem quota is reached). * 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. @@ -477,36 +552,88 @@ extern "C" { * @see open() */ #ifndef _di_f_file_create_ - extern f_return_status f_file_create(f_string path, const mode_t mode, const bool exclusive); + extern f_return_status f_file_create(const f_string path, const mode_t mode, const bool exclusive, const bool dereference); #endif // _di_f_file_create_ /** - * Close an opened file. + * Create a file based on the given path and file mode. * - * If the file descriptor is defined, then fsync() is called before closing. + * The file will not be open after calling this. * - * @param file - * The file to close. + * @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 mode + * The file mode to open in. + * @param exclusive + * If TRUE, will fail when file already exists. + * If FALSE, will not fail if file already exists. + * @param dereference + * Set to TRUE to dereferenc symlinks (often is what is desired). + * Set to FALSE to fail if the path is a symbolic link. + * This does not write symbolic links. (@todo add function f_create_link() for creating symbolic links.) * * @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. + * 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_no_space (with error bit) if filesystem is out of space (or filesystem quota is reached). + * 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 fsync() - * @see fclose() + * @see openat() */ -#ifndef _di_f_file_close_ - extern f_return_status f_file_close(f_file *file); -#endif // _di_f_file_close_ +#ifndef _di_f_file_create_at_ + extern f_return_status f_file_create_at(const int at_id, const f_string path, const mode_t mode, const bool exclusive, const bool dereference); +#endif // _di_f_file_create_at_ + +/** + * Identify whether or not a file exists at the given path. + * + * This does not require access on the file itself. + * This only requires access via the parent directories in the path. + * + * @param path + * The path file name. + * + * @return + * t_true if path was found. + * f_false if path was not found. + * 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_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 stat() + */ +#ifndef _di_f_file_exists_ + extern f_return_status f_file_exists(const f_string path); +#endif // _di_f_file_exists_ /** - * Check if a file exists at a given directory. + * Identify whether or not a file exists at the given path. * - * @param directory_file_descriptor - * The file descriptor of the directory. + * This does not require access on the file itself. + * This only requires access via the parent directories in the path. + * + * @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 flags @@ -523,58 +650,36 @@ extern "C" { * 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 fstatat() */ #ifndef _di_f_file_exists_at_ - extern f_return_status f_file_exists_at(const int directory_file_descriptor, const f_string path, const int flags); + extern f_return_status f_file_exists_at(const int at_id, const f_string path, const bool follow); #endif // _di_f_file_exists_at_ /** * Flush the file. * - * This calls fflush(). - * - * @param file - * The file to flush. + * @param id + * The file descriptor. * * @return * f_none is returned on success. - * f_file_not_open (with error bit) if the file is not open. - * f_file_error_flush (with error bit) if the flush failed. * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_file_error_descriptor (with error bit) if file descriptor is invalid. + * f_error_input_output (with error bit) on I/O error. + * f_filesystem_quota_blocks (with error bit) if filesystem's disk blocks or inodes are exhausted. + * f_no_space (with error bit) if filesystem is out of space (or filesystem quota is reached). + * f_unsupported (with error bit) if the file system or file type does not support flushing. + * f_failure (with error bit) on any other failure. * - * @see fflush() + * @see fsync() */ #ifndef _di_f_file_flush_ - extern f_return_status f_file_flush(f_file *file); + extern f_return_status f_file_flush(const int id); #endif // _di_f_file_flush_ /** - * Identify whether or not a file exists at the given path. - * - * This does not require access on the file itself. - * This only requires access via the parent directories in the path. - * - * @param path - * The path file name. - * - * @return - * t_true if path was found. - * f_false if path was not found. - * 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_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 stat() - */ -#ifndef _di_f_file_exists_ - extern f_return_status f_file_exists(const f_string path); -#endif // _di_f_file_exists_ - -/** * Identify whether or not a file exists at the given path and if that file is a specific type. * * This does not require access on the file itself. @@ -606,8 +711,8 @@ extern "C" { /** * Identify whether or not a file exists at the given path within the parent directory and if that file is a specific type. * - * @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 type @@ -631,19 +736,106 @@ extern "C" { * @see fstatat() */ #ifndef _di_f_file_is_at_ - extern f_return_status f_file_is_at(const int file_id, const f_string path, const int type, const bool follow); + extern f_return_status f_file_is_at(const int at_id, const f_string path, const int type, const bool follow); #endif // _di_f_file_is_at_ /** + * Create a symbolic link to a file. + * + * This will not replace existing files/links. + * This does not validate the existence of target. + * + * @param target + * A path that the link points to. + * @param point + * A path to the link that does the pointing. + * + * @return + * + * @see symlink() + */ +#ifndef _di_f_file_link_ + extern f_return_status f_file_link(const f_string target, const f_string point); +#endif // _di_f_file_link_ + +/** + * Create a symbolic link to a file. + * + * This will not replace existing files/links. + * This does not validate the existence of target. + * + * @param at_id + * The parent directory, as an open directory file descriptor, in which point path is relative to. + * @param target + * A path that the link points to. + * @param point + * A path to the link that does the pointing. + * + * @return + * + * @see symlinkat() + */ +#ifndef _di_f_file_link_at_ + extern f_return_status f_file_link_at(const int at_id, const f_string target, const f_string point); +#endif // _di_f_file_link_at_ + +/** + * Create a hard link to a file. + * + * This will not replace existing files/links. + * + * @param target + * A path that the link points to. + * @param point + * A path to the link that does the pointing. + * + * @return + * + * @see link() + */ +#ifndef _di_f_file_link_hard_ + extern f_return_status f_file_link_hard(const f_string target, const f_string point); +#endif // _di_f_file_link_hard_ + +/** + * Create a hard link to a file. + * + * This will not replace existing files/links. + * + * @param at_id_target + * The parent directory, as an open directory file descriptor, in which target path is relative to. + * @param at_id_point + * The parent directory, as an open directory file descriptor, in which point path is relative to. + * @param target + * 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. + * + * @return + * + * @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); +#endif // _di_f_file_link_hard_at_ + +/** * Open a particular file and save its stream. * * This will open the file and obtain the file descriptor. * + * @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 mode + * The file mode to open in. + * Set to 0 to not use. * @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. @@ -652,87 +844,129 @@ extern "C" { * 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 fopen() + * @see open() */ #ifndef _di_f_file_open_ - extern f_return_status f_file_open(f_file *file, const f_string path); + extern f_return_status f_file_open(const f_string path, const int flags, const mode_t mode, f_file *file); #endif // _di_f_file_open_ /** - * Read until a single block is filled or EOF is reached. + * Open a particular file and save its stream. * - * This does not allocate space to the buffer, so be sure enough space exists (file->size_chunk * file->size_block). + * This will open the file and obtain the file descriptor. + * + * @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 flags + * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. + * @param mode + * The file mode to open in. + * Set to 0 to not use. + * @param file + * The data related to the file being opened. + * This will be updated with the file descriptor and file address. + * + * @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 openat() + */ +#ifndef _di_f_file_open_at_ + extern f_return_status f_file_open_at(const int at_id, const f_string path, const int flags, const mode_t mode, f_file *file); +#endif // _di_f_file_open_at_ + +/** + * Read until EOF is reached. + * + * To check how much was read into the buffer, record buffer->used before execution and compare to buffer->used after execution. * * @param file * The file to read. + * The file must already be open. * @param buffer * The buffer the file is being read into. + * The contents of the file is appended into this buffer. * * @return * f_none on success. * f_none_on_eof on success and EOF was reached. - * 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. + * f_block (with error bit) if file descriptor is set to non-block and the read would result in a blocking operation. + * f_file_error_descriptor (with error bit) if the file descriptor is invalid. + * f_invalid_buffer (with error bit) if the buffer is invalid. + * f_interrupted (with error bit) if interrupt was received. + * f_error_input_output (with error bit) on I/O error. + * f_file_not_open (with error bit) if file is not open. + * f_file_is_type_directory (with error bit) if file descriptor represents a directory. * - * @see fread() + * @see read() */ #ifndef _di_f_file_read_ extern f_return_status f_file_read(f_file *file, f_string_dynamic *buffer); #endif // _di_f_file_read_ /** - * Read until a single block is filled or EOF is reached, specified by the given range within the file, storing it in the buffer. - * - * This does not allocate space to the buffer, so be sure enough space exists (file->size_chunk * file->size_block). + * Read until a single block is filled or EOF is reached. * - * Will auto-seek file position to position.start. - * (The file is assumed to already be in the position.start position.) + * To check how much was read into the buffer, record buffer->used before execution and compare to buffer->used after execution. * * @param file * The file to read. + * The file must already be open. * @param buffer * The buffer the file is being read into. - * @param position - * The file position information. - * When position.total_elemenets is set to 0, this will read until the entire buffer is filled or the EOF is reached. + * The contents of the file is appended into this buffer. * * @return * f_none on success. * f_none_on_eof on success and EOF was reached. - * f_file_not_open (with error bit) if file is not open. * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_block (with error bit) if file descriptor is set to non-block and the read would result in a blocking operation. + * f_file_error_descriptor (with error bit) if the file descriptor is invalid. + * f_invalid_buffer (with error bit) if the buffer is invalid. + * f_interrupted (with error bit) if interrupt was received. + * f_error_input_output (with error bit) on I/O error. + * f_file_not_open (with error bit) if file is not open. + * f_file_is_type_directory (with error bit) if file descriptor represents a directory. * - * @see f_file_read_until() + * @see read() */ -#ifndef _di_f_file_read_at_ - extern f_return_status f_file_read_at(f_file *file, f_string_dynamic *buffer, const f_file_position position); -#endif // _di_f_file_read_at_ +#ifndef _di_f_file_read_ + extern f_return_status f_file_read_block(f_file *file, f_string_dynamic *buffer); +#endif // _di_f_file_read_ /** - * Read until a single block is filled or EOF is reached, appending it to the buffer. - * - * This does not allocate space to the buffer, so be sure enough space exists (file->size_chunk * file->size_block). + * Read until a given number or EOF is reached, storing it in the buffer. * - * Will not auto-seek file position. + * To check how much was read into the buffer, record buffer->used before execution and compare to buffer->used after execution. * * @param file * The file to read. + * The file must already be open. * @param buffer * The buffer the file is being read into. * @param total - * The total elements to read. - * When set to 0, this will read until the entire buffer is filled or the EOF is reached. + * The total bytes to read, unless EOF is reached first. * * @return * f_none on success. * f_none_on_eof on success and EOF was reached. - * f_file_not_open (with error bit) if file is not open. - * f_file_error_seek (with error bit) if file seek failed. - * f_file_error_read (with error bit) if file read failed. * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_block (with error bit) if file descriptor is set to non-block and the read would result in a blocking operation. + * f_file_error_descriptor (with error bit) if the file descriptor is invalid. + * f_invalid_buffer (with error bit) if the buffer is invalid. + * f_interrupted (with error bit) if interrupt was received. + * f_error_input_output (with error bit) on I/O error. + * f_file_not_open (with error bit) if file is not open. + * f_file_is_type_directory (with error bit) if file descriptor represents a directory. * - * @see f_file_read_at() + * @see read */ #ifndef _di_f_file_read_until_ extern f_return_status f_file_read_until(f_file *file, f_string_dynamic *buffer, const f_string_length total); @@ -767,21 +1001,75 @@ extern "C" { #endif // _di_f_file_remove_ /** - * Read statistics of a file. + * Remove a file. * - * This will not re-read the file statistics., file_status must not be allocated. - * This is because fstatat() will allocate to this variable. + * @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 flags + * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. * - * This is essentially a wrapper to fstatat() converting any error codes into the FLL format. + * @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_busy (with error bit) if file is busy. + * f_error_input_output (with error bit) if an I/O error occurred. + * f_file_is_type_directory (with error bit) file is a directory (directories cannot be removed via this function). + * f_loop (with error bit) on loop error. + * f_invalid_name (with error bit) on path name error. + * f_file_not_found (with error bit) if file not found. + * f_out_of_memory (with error bit) if out of memory. + * f_invalid_directory (with error bit) if a supposed directory in path is not actually a directory. + * 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 (unlink()) error. + * + * @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); +#endif // _di_f_file_remove_at_ + +/** + * Given an open file descriptor, seek * - * @param file_id + * @param id * The file descriptor. - * @param file_name - * The name of the file. - * @param file_stat - * The statistics read. - * @param flags - * Any valid flag used by fstatat(), such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. + * @param whence + * One of: SEEK_SET, SEEK_CUR, SEEK_END, SEEK_DATA, SEEK_HOLE. + * @param offset + * The offset to use, based off of whence. + * @param seeked + * This gets update to represent the total amount seeked. + * To be compared against offset. + * + * @return + * f_none on success. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_file_error_descriptor (with error bit) if the file descriptor is invalid. + * f_out_of_bound (with error bit) if SEEK_DATA or SEEK_HOLE is specified as whence and offset is beyond the end of file. + * f_number_overflow (with error bit) on overflow for offset. + * f_file_is_type_pipe (with error bit) if file descriptor represents a pipe, socket, or FIFO. + * f_failure (with error bit) on any other error. + * + * @see lseek + */ +#ifndef _di_f_file_seek_ + extern f_return_status f_file_seek(const int id, const int whence, const f_string_length offset, f_string_length *seeked); +#endif // _di_f_file_seek_ + +/** + * Read the size of file. + * + * @param path + * The path to the file. + * @param dereference + * Set to TRUE to dereferenc symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. + * @param size + * This gets set to the size of the file. * * @return * f_none on success. @@ -794,22 +1082,75 @@ extern "C" { * f_loop (with error bit) if a loop occurred. * f_invalid_parameter (with error bit) if a parameter is invalid. * - * @see fstatat() + * @see f_file_stat() */ -#ifndef _di_f_file_stat_at_ - extern f_return_status f_file_stat_at(const int file_id, const f_string file_name, struct stat *file_stat, const int flags); -#endif // _di_f_file_stat_at_ +#ifndef _di_f_file_size_ + extern f_return_status f_file_size(const f_string path, const bool dereference, f_string_length *size); +#endif // _di_f_file_size_ /** - * Read statistics of a file. + * Read the size of file. + * + * @param at_id + * The parent directory, as an open directory file descriptor, in which path is relative to. + * @param path + * The path to the file. + * @param dereference + * Set to TRUE to dereferenc symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. + * @param size + * This gets set to the size of the file. + * + * @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. * - * This will not re-read the file statistics., file_status must not be allocated. - * This is because stat() will allocate to this variable. + * @see f_file_stat_at() + */ +#ifndef _di_f_file_size_at_ + extern f_return_status f_file_size_at(const int at_id, const f_string path, const bool dereference, f_string_length *size); +#endif // _di_f_file_size_at_ + +/** + * Read size of a file relative to the path represented by the file descriptor id. * - * This is essentially a wrapper to stat() converting any error codes into the FLL format. + * @param id + * The file descriptor. + * @param size + * This gets set to the size of the file. * - * @param file_name - * The name of the file. + * @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_by_id() + */ +#ifndef _di_f_file_size_by_id_ + extern f_return_status f_file_size_by_id(const int id, f_string_length *size); +#endif // _di_f_file_size_by_id_ + +/** + * Read statistics of a file. + * + * @param path + * The path to the file. + * @param dereference + * Set to TRUE to dereferenc symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. * @param file_stat * The statistics read. * @@ -827,18 +1168,42 @@ extern "C" { * @see stat() */ #ifndef _di_f_file_stat_ - extern f_return_status f_file_stat(const f_string file_name, struct stat *file_stat); + extern f_return_status f_file_stat(const f_string path, const bool dereference, struct stat *file_stat); #endif // _di_f_file_stat_ /** - * Read statistics of a file. + * Read statistics of a file relative to the path represented by the file descriptor id. + * + * @param at_id + * 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 file_stat + * The statistics read. * - * This will not re-read the file statistics., file_status must not be allocated. - * This is because fstat() will allocate to this variable. + * @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. * - * This is essentially a wrapper to fstat() converting any error codes into the FLL format. + * @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); +#endif // _di_f_file_stat_at_ + +/** + * Read statistics of a file using a file descriptor id. * - * @param file_id + * @param id * The file descriptor. * @param file_stat * The statistics read. @@ -857,7 +1222,7 @@ extern "C" { * @see fstat() */ #ifndef _di_f_file_stat_by_id_ - extern f_return_status f_file_stat_by_id(const int file_id, struct stat *file_stat); + extern f_return_status f_file_stat_by_id(const int id, struct stat *file_stat); #endif // _di_f_file_stat_by_id_ #ifdef __cplusplus diff --git a/level_0/f_file/c/private-file.c b/level_0/f_file/c/private-file.c index 0526fe7..a7a5bac 100644 --- a/level_0/f_file/c/private-file.c +++ b/level_0/f_file/c/private-file.c @@ -5,36 +5,65 @@ extern "C" { #endif +#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, const bool dereference) { + + if ((dereference ? chmod(path, mode) : lchmod(path, mode)) < 0) { + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_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_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_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) { + + if (fchmodat(at_id, path, mode, flags) < 0) { + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == EBADF) return f_status_set_error(f_file_error_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_error_input_output); + + return f_status_set_error(f_failure); + } + + return f_none; + } +#endif // !defined(_di_f_file_change_mode_at_) || !defined(_di_f_file_copy_at_) + #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); - } + f_return_status private_f_file_change_owner(const f_string path, const uid_t uid, const gid_t gid, const bool dereference) { + + if ((dereference ? chown(path, uid, gid) : lchown(path, uid, gid)) < 0) { + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_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_error_input_output); return f_status_set_error(f_failure); } @@ -43,170 +72,291 @@ extern "C" { } #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); - } +#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) { + + if (fchownat(at_id, path, uid, gid, flags) < 0) { + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == EBADF) return f_status_set_error(f_file_error_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_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_) +#endif // !defined(_di_f_file_change_owner_at_) || !defined(_di_f_file_copy_at_) #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); + f_return_status private_f_file_close(int *id) { + if (f_status_is_error(private_f_file_flush(*id))) return f_status_set_error(f_file_error_synchronize); - // 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 (close(*id) < 0) { + if (errno == EBADF) return f_status_set_error(f_file_error_descriptor); + if (errno == EINTR) return f_status_set_error(f_interrupted); + if (errno == EIO) return f_status_set_error(f_error_input_output); + if (errno == ENOSPC) return f_status_set_error(f_no_space); + if (errno == EDQUOT) return f_status_set_error(f_filesystem_quota_blocks); - if (fclose(file->address) == 0) { - file->address = 0; - return f_none; + return f_status_set_error(f_file_error_close); } - return f_status_set_error(f_file_error_close); + *id = 0; + return f_none; } #endif // !defined(_di_f_file_close_) || !defined(_di_f_file_copy_) +#if !defined(_di_f_file_copy_) || !defined(_di_f_file_clone_) + f_return_status private_f_file_copy_content(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; + + f_status status = private_f_file_open(source, f_file_flag_read_only, 0, &file_source); + if (f_status_is_error(status)) return status; + + status = private_f_file_open(destination, f_file_flag_write_only | f_file_flag_no_follow, 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_error_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_error_read); + + return f_none; + } +#endif // !defined(_di_f_file_copy_) || !defined(_di_f_file_clone_) + #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) { + f_return_status private_f_file_create(const f_string path, const mode_t mode, const bool exclusive, const bool dereference) { int flags = O_CLOEXEC | O_CREAT | O_WRONLY; if (exclusive) { flags |= O_EXCL; } - int result = open(path, flags, mode); + if (!dereference) { + flags |= O_NOFOLLOW; + } - 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); - } + f_file file = f_file_initialize; + f_status status = private_f_file_open(path, mode, flags, &file); + + if (file.id > 0) { + return private_f_file_close(&file.id); + } + + return status; + } +#endif // !defined(_di_f_file_create_) || !defined(_di_f_file_copy_) + +#if !defined(_di_f_file_create_at_) || !defined(_di_f_file_copy_at_) + f_return_status private_f_file_create_at(const int at_id, const f_string path, const mode_t mode, const bool exclusive, const bool dereference) { + int flags = O_CLOEXEC | O_CREAT | O_WRONLY; + + if (exclusive) { + flags |= O_EXCL; + } + + if (!dereference) { + flags |= O_NOFOLLOW; + } + + f_file file = f_file_initialize; + f_status status = private_f_file_open_at(at_id, path, flags, mode, &file); + + if (file.id > 0) { + return private_f_file_close(&file.id); + } + + return status; + } +#endif // !defined(_di_f_file_create_at_) || !defined(_di_f_file_copy_at_) + +#if !defined(_di_f_file_flush_) || !defined(_di_f_file_close_) || !defined(_di_f_file_copy_) + f_return_status private_f_file_flush(const int id) { + + if (fsync(id) < 0) { + if (errno == EBADF) return f_status_set_error(f_file_error_descriptor); + if (errno == EIO) return f_status_set_error(f_error_input_output); + if (errno == ENOSPC) return f_status_set_error(f_no_space); + if (errno == EROFS) return f_status_set_error(f_unsupported); + if (errno == EDQUOT) return f_status_set_error(f_filesystem_quota_blocks); return f_status_set_error(f_failure); } - close(result); + return f_none; + } +#endif // !defined(_di_f_file_flush_) || !defined(_di_f_file_close_) || !defined(_di_f_file_copy_) + +#if !defined(_di_f_file_link_) || !defined(_di_f_file_copy_) + f_return_status private_f_file_link(const f_string target, const f_string point) { + + if (symlink(target, point) < 0) { + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == EDQUOT) return f_status_set_error(f_filesystem_quota_blocks); + if (errno == EEXIST) return f_status_set_error(f_file_found); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_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_invalid_parameter); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOSPC) return f_status_set_error(f_no_space); + 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); + + return f_status_set_error(f_failure); + } return f_none; } -#endif // !defined(_di_f_file_create_) || !defined(_di_f_file_copy_) +#endif // !defined(_di_f_file_link_) || !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); +#if !defined(_di_f_file_link_at_) || !defined(_di_f_file_copy_at_) + f_return_status private_f_file_link_at(const int at_id, const f_string target, const f_string point) { - file->address = fopen(path, file->mode); + if (symlinkat(target, at_id, point) < 0) { + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == EDQUOT) return f_status_set_error(f_filesystem_quota_blocks); + if (errno == EEXIST) return f_status_set_error(f_file_found); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_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_invalid_parameter); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == EBADF) return f_status_set_error(f_file_error_descriptor); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOSPC) return f_status_set_error(f_no_space); + 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 (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); + return f_status_set_error(f_failure); + } + + return f_none; + } +#endif // !defined(_di_f_file_link_at_) || !defined(_di_f_file_copy_at_) + +#if !defined(_di_f_file_open_) || !defined(_di_f_file_copy_) + f_return_status private_f_file_open(const f_string path, const int flags, const mode_t mode, f_file *file) { + if (mode == 0) { + file->id = open(path, flags); + } + else { + file->id = open(path, flags, mode); + } - file->id = fileno(file->address); + if (file->id < 0) { + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == EDQUOT) return f_status_set_error(f_filesystem_quota_blocks); + if (errno == EEXIST) return f_status_set_error(f_file_found); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_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_invalid_parameter); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENFILE) return f_status_set_error(f_file_max_open); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOSPC) return f_status_set_error(f_no_space); + 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 (file->id == -1) return f_status_set_error(f_file_error_descriptor); + return f_status_set_error(f_failure); + } return f_none; } #endif // !defined(_di_f_file_open_) || !defined(_di_f_file_copy_) +#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 int flags, const mode_t mode, f_file *file) { + if (mode == 0) { + file->id = openat(at_id, path, flags); + } + else { + file->id = openat(at_id, path, flags, mode); + } + + if (file->id < 0) { + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == EDQUOT) return f_status_set_error(f_filesystem_quota_blocks); + if (errno == EEXIST) return f_status_set_error(f_file_found); + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_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_invalid_parameter); + if (errno == ELOOP) return f_status_set_error(f_loop); + if (errno == ENFILE) return f_status_set_error(f_file_max_open); + if (errno == EBADF) return f_status_set_error(f_file_error_descriptor); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == ENOSPC) return f_status_set_error(f_no_space); + 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); + + return f_status_set_error(f_failure); + } + + return f_none; + } +#endif // !defined(_di_f_file_open_at_) || !defined(_di_f_file_copy_at_) + #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); - } + f_return_status private_f_file_stat(const f_string path, const bool dereference, struct stat *file_stat) { + + if ((dereference ? stat(path, file_stat) : lstat(path, file_stat)) < 0) { + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + if (errno == EACCES) return f_status_set_error(f_access_denied); + if (errno == ELOOP) return f_status_set_error(f_loop); return f_status_set_error(f_file_error_stat); } @@ -215,6 +365,49 @@ 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) { + + if (fstatat(at_id, path, file_stat, flags) < 0) { + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + 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_error_descriptor); + if (errno == ENOENT) return f_status_set_error(f_file_not_found); + + return f_status_set_error(f_file_error_stat); + } + + return f_none; + } +#endif // !defined(_di_f_file_stat_at_) || !defined(_di_f_file_copy_at_) + +#if !defined(_di_f_file_stat_by_id_) || !defined(_di_f_file_size_by_id_) + f_return_status private_f_file_stat_by_id(const int id, struct stat *file_stat) { + int result = fstat(id, file_stat); + + if (result < 0) { + if (errno == ENAMETOOLONG) return f_status_set_error(f_invalid_name); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == ENOMEM) return f_status_set_error(f_out_of_memory); + if (errno == EOVERFLOW) return f_status_set_error(f_number_overflow); + if (errno == ENOTDIR) return f_status_set_error(f_invalid_directory); + if (errno == ENOENT) return f_file_not_found; + if (errno == EACCES) return f_status_set_error(f_access_denied); + 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_by_id_) || !defined(_di_f_file_size_by_id_) + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_0/f_file/c/private-file.h b/level_0/f_file/c/private-file.h index 1c27926..48f8301 100644 --- a/level_0/f_file/c/private-file.h +++ b/level_0/f_file/c/private-file.h @@ -16,6 +16,73 @@ extern "C" { #endif /** + * 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. + * @param dereference + * Set to TRUE to dereference symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. + * + * @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() + */ +#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, const bool dereference) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_) + +/** + * Private implementation of f_file_change_mode_at(). + * + * Intended to be shared to each of the different implementation variations. + * + * @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 mode + * The new mode to use. + * @param flags + * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. + * + * @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_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_) + +/** * Private implementation of f_file_change_owner(). * * Intended to be shared to each of the different implementation variations. @@ -26,6 +93,9 @@ extern "C" { * The new user id to use. * @param gid * The new group id to use. + * @param dereference + * Set to TRUE to dereference symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. * * @return * f_none on success. @@ -42,21 +112,26 @@ extern "C" { * 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; + extern f_return_status private_f_file_change_owner(const f_string path, const uid_t uid, const gid_t gid, const bool dereference) f_gcc_attribute_visibility_internal; #endif // !defined(_di_f_file_change_owner_) || !defined(_di_f_file_copy_) /** - * Private implementation of f_file_change_mode(). + * Private implementation of f_file_change_owner_at(). * * Intended to be shared to each of the different implementation variations. * + * @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 mode - * The new mode to use. + * @param uid + * 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. * * @return * f_none on success. @@ -72,25 +147,99 @@ extern "C" { * 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() + * @see f_file_change_owner_at() */ -#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_) +#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_) /** - * Private implementation of f_file_create(). + * Private implementation of f_file_close(). * * Intended to be shared to each of the different implementation variations. * - * @param path - * Full path to the file (including entire filename). + * @param id + * The file descriptor. + * + * @return + * f_none on success. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_file_error_descriptor (with error bit) if file descriptor is invalid. + * f_interrupted (with error bit) if interrupt was received. + * f_error_input_output (with error bit) on I/O 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_error_synchronize (with error bit) on flush failure. + * f_file_error_close (with error bit) if fclose() failed for any other reason. + * + * @see f_file_close() + */ +#if !defined(_di_f_file_close_) || !defined(_di_f_file_copy_) + extern f_return_status private_f_file_close(int *id) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_f_file_close_) || !defined(_di_f_file_copy_) + +/** + * 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. + * 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. + * 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_no_space (with error bit) if filesystem is out of space (or filesystem quota is reached). + * 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_copy() + * @see f_file_clone() + */ +#if !defined(_di_f_file_copy_) || !defined(_di_f_file_clone_) + extern f_return_status private_f_file_copy_content(const f_string source, const f_string destination, const f_number_unsigned size_block) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_f_file_copy_) || !defined(_di_f_file_clone_) + +/** + * Private implementation of f_file_create(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param path + * The path file name. + * @param mode + * The file mode to open in. + * @param flags + * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. + * @param file + * The data related to the file being opened. + * This will be updated with the file descriptor and file address. * * @return * f_none on success. @@ -113,22 +262,131 @@ extern "C" { * 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; + extern f_return_status private_f_file_create(const f_string path, const mode_t mode, const bool exclusive, const bool dereference) f_gcc_attribute_visibility_internal; #endif // !defined(_di_f_file_create_) || !defined(_di_f_file_copy_) /** - * Private implementation of f_file_open(). + * Private implementation of f_file_create_at(). * * Intended to be shared to each of the different implementation variations. * + * @param at_id + * The parent directory, as an open directory file descriptor, in which path is relative to. * @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. + * @param mode + * The file mode to open in. + * @param flags + * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. + * + * @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_at() + */ +#if !defined(_di_f_file_create_at_) || !defined(_di_f_file_copy_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, const bool dereference) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_f_file_create_at_) || !defined(_di_f_file_copy_at_) + +/** + * Private implementation of f_file_link(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param target + * A path that the link points to. + * @param point + * A path to the link that does the pointing. + * + * @return + * + * @see f_file_link() + */ +#if !defined(_di_f_file_link_) || !defined(_di_f_file_copy_) + extern f_return_status private_f_file_link(const f_string target, const f_string point) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_f_file_link_) || !defined(_di_f_file_copy_) + +/** + * Private implementation of f_file_link_at(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param at_id + * The parent directory, as an open directory file descriptor, in which point point path is relative to. + * @param target + * A path that the link points to. + * @param point + * A path to the link that does the pointing. + * + * @return + * + * @see f_file_link_at() + */ +#if !defined(_di_f_file_link_at_) || !defined(_di_f_file_copy_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_) + +/** + * Private implementation of f_file_flush(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param id + * The file descriptor. + * + * @return + * f_none is returned on success. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_file_error_descriptor (with error bit) if file descriptor is invalid. + * f_error_input_output (with error bit) on I/O error. + * f_filesystem_quota_blocks (with error bit) if filesystem's disk blocks or inodes are exhausted. + * f_no_space (with error bit) if filesystem is out of space (or filesystem quota is reached). + * f_unsupported (with error bit) if the file system or file type does not support flushing. + * f_failure (with error bit) on any other failure. + * + * @see f_file_flush() + */ +#if !defined(_di_f_file_flush_) || !defined(_di_f_file_close_) || !defined(_di_f_file_copy_) + extern f_return_status private_f_file_flush(const int id) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_f_file_flush_) || !defined(_di_f_file_close_) || !defined(_di_f_file_copy_) + +/** + * Private implementation of f_file_open(). + * + * Intended to be shared to each of the different implementation variations. + * + * @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 mode + * The file mode to open in. + * Set to 0 to not use. + * @param file + * The data related to the file being opened. + * This will be updated with the file descriptor and file address. * * @return * f_none on success. @@ -138,34 +396,59 @@ extern "C" { * 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; + extern f_return_status private_f_file_open(const f_string path, const int flags, const mode_t mode, f_file *file) f_gcc_attribute_visibility_internal; #endif // !defined(_di_f_file_open_) || !defined(_di_f_file_copy_) /** - * Private implementation of f_file_close(). + * Private implementation of f_file_open_at(). * * Intended to be shared to each of the different implementation variations. * + * @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 flags + * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. + * @param mode + * The file mode to open in. + * Set to 0 to not use. * @param file - * The file to close. + * The data related to the file being opened. + * This will be updated with the file descriptor and file address. * * @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_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_close() - * @see fsync() - * @see fclose() + * @see f_file_open_at() */ -#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_) +#if !defined(_di_f_file_open_at_) || !defined(_di_f_file_copy_at_) + extern f_return_status private_f_file_open_at(const int at_id, const f_string path, const int flags, 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_) + +/** + * Create a link to a file. + * + * This will not replace existing files/links. + * + * @param target + * A path that the link points to. + * @param point + * A path to the link that does the pointing. + * + * @return + * + * @see f_file_link() + */ +#if !defined(_di_f_file_link_) || !defined(_di_f_file_copy_) + extern f_return_status private_f_file_link(const f_string target, const f_string point); +#endif // !defined(_di_f_file_link_) || !defined(_di_f_file_copy_) /** * Private implementation of f_file_close(). @@ -174,6 +457,9 @@ extern "C" { * * @param file_name * The name of the file. + * @param dereference + * Set to TRUE to dereference symlinks (often is what is desired). + * Set to FALSE to operate on the symlink itself. * @param file_stat * The statistics read. * @@ -189,12 +475,71 @@ extern "C" { * 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; + extern f_return_status private_f_file_stat(const f_string file_name, const bool dereference, struct stat *file_stat) f_gcc_attribute_visibility_internal; #endif // !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_) +/** + * Private implementation of f_file_close(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param at_id + * 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 + * Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW. + * @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_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_) + +/** + * Private implementation of f_file_close(). + * + * Intended to be shared to each of the different implementation variations. + * + * @param id + * The file descriptor. + * @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_size_by_id() + * @see f_file_stat_by_id() + */ +#if !defined(_di_f_file_stat_by_id_) || !defined(_di_f_file_size_by_id_) + extern f_return_status private_f_file_stat_by_id(const int id, struct stat *file_stat) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_f_file_stat_by_id_) || !defined(_di_f_file_size_by_id_) + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_0/f_file/data/build/dependencies b/level_0/f_file/data/build/dependencies index 2060b72..d8175f5 100644 --- a/level_0/f_file/data/build/dependencies +++ b/level_0/f_file/data/build/dependencies @@ -1,2 +1,4 @@ f_type f_status +f_memory +f_string diff --git a/level_0/f_status/c/status.h b/level_0/f_status/c/status.h index 1902e77..2c2edff 100644 --- a/level_0/f_status/c/status.h +++ b/level_0/f_status/c/status.h @@ -134,6 +134,7 @@ extern "C" { #ifndef _di_f_status_basic_ f_none = 197, // Start at 197 to allow compatibility with the reserved bash return codes (keep in mind fss return codes can be larger than 255). + f_block, f_critical, f_does_not_exist, f_dummy, @@ -147,6 +148,8 @@ extern "C" { f_maybe, f_not_connected, f_no_data, + f_no_space, + f_out_of_bound, f_out_of_memory, f_prohibited, f_read_only, @@ -266,6 +269,7 @@ extern "C" { #endif // _di_f_status_fork_ #ifndef _di_f_status_file_ + f_file_closed, f_file_error, f_file_error_allocation, f_file_error_close, @@ -280,8 +284,8 @@ extern "C" { f_file_error_stat, f_file_error_synchronize, f_file_error_write, + f_file_empty, f_file_found, - f_file_is_empty, f_file_is_type_block, f_file_is_type_character, f_file_is_type_directory, @@ -303,6 +307,7 @@ extern "C" { f_file_not_utf, f_file_max_descriptors, f_file_max_open, + f_file_utf, #endif // _di_f_status_file_ #ifndef _di_f_status_filesystem_ @@ -324,10 +329,13 @@ extern "C" { f_directory_error_synchronize, f_directory_error_unsupported, f_directory_error_write, - f_directory_is_empty, + f_directory_closed, + f_directory_empty, + f_directory_found, f_directory_not_found, f_directory_not_open, f_directory_not_utf, + f_directory_utf, #endif // _di_f_status_directory_ #ifndef _di_f_status_socket_ diff --git a/level_0/f_string/c/string.h b/level_0/f_string/c/string.h index 2b2afc3..394d3c9 100644 --- a/level_0/f_string/c/string.h +++ b/level_0/f_string/c/string.h @@ -165,9 +165,9 @@ extern "C" { #endif // _di_f_string_range_ /** - * An array of string locations. + * An array of string ranges. * - * array: the array of string locations. + * array: the array of string ranges. * size: total amount of allocated space. * used: total number of allocated spaces used. */ @@ -181,21 +181,73 @@ extern "C" { #define f_string_ranges_initialize {0, 0, 0} - #define f_macro_string_ranges_clear(locations) f_macro_memory_structure_clear(locations) + #define f_macro_string_ranges_clear(ranges) f_macro_memory_structure_clear(ranges) - #define f_macro_string_ranges_new(status, locations, length) f_macro_memory_structure_new(status, locations, f_string_range, length) + #define f_macro_string_ranges_new(status, ranges, length) f_macro_memory_structure_new(status, ranges, f_string_range, length) - #define f_macro_string_ranges_delete(status, locations) f_macro_memory_structure_delete(status, locations, f_string_range) - #define f_macro_string_ranges_destroy(status, locations) f_macro_memory_structure_destroy(status, locations, f_string_range) + #define f_macro_string_ranges_delete(status, ranges) f_macro_memory_structure_delete(status, ranges, f_string_range) + #define f_macro_string_ranges_destroy(status, ranges) f_macro_memory_structure_destroy(status, ranges, f_string_range) - #define f_macro_string_ranges_delete_simple(locations) f_macro_memory_structure_delete_simple(locations, f_string_range) - #define f_macro_string_ranges_destroy_simple(locations) f_macro_memory_structure_destroy_simple(locations, f_string_range) + #define f_macro_string_ranges_delete_simple(ranges) f_macro_memory_structure_delete_simple(ranges, f_string_range) + #define f_macro_string_ranges_destroy_simple(ranges) f_macro_memory_structure_destroy_simple(ranges, f_string_range) - #define f_macro_string_ranges_resize(status, locations, new_length) f_macro_memory_structure_resize(status, locations, f_string_range, new_length) - #define f_macro_string_ranges_adjust(status, locations, new_length) f_macro_memory_structure_adjust(status, locations, f_string_range, new_length) + #define f_macro_string_ranges_resize(status, ranges, new_length) f_macro_memory_structure_resize(status, ranges, f_string_range, new_length) + #define f_macro_string_ranges_adjust(status, ranges, new_length) f_macro_memory_structure_adjust(status, ranges, f_string_range, new_length) #endif // _di_f_string_ranges_ /** + * Store string quantity. + * + * Similar to f_string_range, except total is relative to start and is not an absolute stop position. + * + * Two common uses for when total is 0 is: + * 1) Exactly that, process a total of 0 strings bytes. + * 2) Process with no limit, aka infinite. + * + * start: The position where the string starts (based on some string/buffer). + * total: The total number of elements within that string/buffer the quantity represents. + */ +#ifndef _di_f_string_quantity_ + typedef struct { + f_string_length start; + f_string_length total; + } f_string_quantity; + + #define f_string_quantity_initialize { 0, 0 } +#endif // _di_f_string_quantity_ + +/** + * An array of string quantities. + * + * array: the array of string quantities. + * size: total amount of allocated space. + * used: total number of allocated spaces used. + */ +#ifndef _di_f_string_quantitys_ + typedef struct { + f_string_quantity *array; + + f_array_length size; + f_array_length used; + } f_string_quantitys; + + #define f_string_quantitys_initialize {0, 0, 0} + + #define f_macro_string_quantitys_clear(quantitys) f_macro_memory_structure_clear(quantitys) + + #define f_macro_string_quantitys_new(status, quantitys, length) f_macro_memory_structure_new(status, quantitys, f_string_quantity, length) + + #define f_macro_string_quantitys_delete(status, quantitys) f_macro_memory_structure_delete(status, quantitys, f_string_quantity) + #define f_macro_string_quantitys_destroy(status, quantitys) f_macro_memory_structure_destroy(status, quantitys, f_string_quantity) + + #define f_macro_string_quantitys_delete_simple(quantitys) f_macro_memory_structure_delete_simple(quantitys, f_string_quantity) + #define f_macro_string_quantitys_destroy_simple(quantitys) f_macro_memory_structure_destroy_simple(quantitys, f_string_quantity) + + #define f_macro_string_quantitys_resize(status, quantitys, new_length) f_macro_memory_structure_resize(status, quantitys, f_string_quantity, new_length) + #define f_macro_string_quantitys_adjust(status, quantitys, new_length) f_macro_memory_structure_adjust(status, quantitys, f_string_quantity, new_length) +#endif // _di_f_string_quantitys_ + +/** * A string that is analogous to f_string_dynamic but intended for static-only uses. * * The f_string_static type should never be directly allocated or deallocated. diff --git a/level_0/f_utf/c/utf.h b/level_0/f_utf/c/utf.h index f030854..000ddf2 100644 --- a/level_0/f_utf/c/utf.h +++ b/level_0/f_utf/c/utf.h @@ -230,7 +230,7 @@ extern "C" { #endif // _di_f_utf_string_range_ /** - * An array of string locations. + * An array of string ranges. * * size: total amount of allocated space. * used: total number of allocated spaces used. @@ -245,18 +245,71 @@ extern "C" { #define f_utf_string_ranges_initialize {0, 0, 0} - #define f_clear_utf_string_ranges(locations) f_macro_memory_structure_clear(locations) + #define f_clear_utf_string_ranges(ranges) f_macro_memory_structure_clear(ranges) - #define f_macro_utf_string_range_news(status, locations, length) f_macro_memory_structure_new(status, locations, f_utf_string_range, length) + #define f_macro_utf_string_range_news(status, ranges, length) f_macro_memory_structure_new(status, ranges, f_utf_string_range, length) - #define f_macro_utf_string_range_deletes(status, locations) f_macro_memory_structure_delete(status, locations, f_utf_string_range) - #define f_macro_utf_string_range_destroys(status, locations) f_macro_memory_structure_destroy(status, locations, f_utf_string_range) + #define f_macro_utf_string_range_deletes(status, ranges) f_macro_memory_structure_delete(status, ranges, f_utf_string_range) + #define f_macro_utf_string_range_destroys(status, ranges) f_macro_memory_structure_destroy(status, ranges, f_utf_string_range) - #define f_macro_utf_string_range_resizes(status, locations, new_length) f_macro_memory_structure_resize(status, locations, f_utf_string_range, new_length) - #define f_macro_utf_string_range_adjusts(status, locations, new_length) f_macro_memory_structure_adjust(status, locations, f_utf_string_range, new_length) + #define f_macro_utf_string_range_resizes(status, ranges, new_length) f_macro_memory_structure_resize(status, ranges, f_utf_string_range, new_length) + #define f_macro_utf_string_range_adjusts(status, ranges, new_length) f_macro_memory_structure_adjust(status, ranges, f_utf_string_range, new_length) #endif // _di_f_utf_string_ranges_ /** + * Store string quantity. + * + * Similar to f_utf_string_range, except total is relative to start and is not an absolute stop position. + * + * Two common uses for when total is 0 is: + * 1) Exactly that, process a total of 0 strings bytes. + * 2) Process with no limit, aka infinite. + * + * start: The position where the string starts (based on some string/buffer). + * total: The total number of elements within that string/buffer the quantity represents. + */ +#ifndef _di_f_utf_string_quantity_ + typedef struct { + f_utf_string_length start; + f_utf_string_length total; + } f_utf_string_quantity; + + #define f_utf_string_quantity_initialize { 0, 0 } +#endif // _di_f_utf_string_quantity_ + +/** + * An array of string quantities. + * + * array: the array of string quantities. + * size: total amount of allocated space. + * used: total number of allocated spaces used. + */ +#ifndef _di_f_utf_string_quantitys_ + typedef struct { + f_utf_string_quantity *array; + + f_array_length size; + f_array_length used; + } f_utf_string_quantitys; + + #define f_utf_string_quantitys_initialize {0, 0, 0} + + #define f_macro_utf_string_quantitys_clear(quantitys) f_macro_memory_structure_clear(quantitys) + + #define f_macro_utf_string_quantitys_new(status, quantitys, length) f_macro_memory_structure_new(status, quantitys, f_utf_string_quantity, length) + + #define f_macro_utf_string_quantitys_delete(status, quantitys) f_macro_memory_structure_delete(status, quantitys, f_utf_string_quantity) + #define f_macro_utf_string_quantitys_destroy(status, quantitys) f_macro_memory_structure_destroy(status, quantitys, f_utf_string_quantity) + + #define f_macro_utf_string_quantitys_delete_simple(quantitys) f_macro_memory_structure_delete_simple(quantitys, f_utf_string_quantity) + #define f_macro_utf_string_quantitys_destroy_simple(quantitys) f_macro_memory_structure_destroy_simple(quantitys, f_utf_string_quantity) + + #define f_macro_utf_string_quantitys_resize(status, quantitys, new_length) f_macro_memory_structure_resize(status, quantitys, f_utf_string_quantity, new_length) + #define f_macro_utf_string_quantitys_adjust(status, quantitys, new_length) f_macro_memory_structure_adjust(status, quantitys, f_utf_string_quantity, new_length) +#endif // _di_f_utf_string_quantitys_ + + +/** * A string that is analogous to f_utf_string_dynamic but intended for static-only uses. * * The f_utf_string_static type should never be directly allocated or deallocated. diff --git a/level_1/fl_directory/c/directory.c b/level_1/fl_directory/c/directory.c new file mode 100644 index 0000000..b600d5f --- /dev/null +++ b/level_1/fl_directory/c/directory.c @@ -0,0 +1,43 @@ +#include +#include "private-directory.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_f_directory_copy_ + f_return_status f_directory_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; + /* +@todo + status = f_directory_exists(source); + if (f_status_is_error(status)) return status; + if (status == f_false) return f_status_set_error(f_invalid_directory); + + status = f_directory_exists(destination); + if (f_status_is_error(status)) return status; + + if (exclusive) { + } + else { + } + + status = private_fl_directory_list(source, 0, 0, listing);*/ + + return f_none; + } +#endif // _di_f_directory_copy_ + +#ifndef _di_fl_directory_list_ + f_return_status fl_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_directory_listing *listing) { + #ifndef _di_level_2_parameter_checking_ + if (listing == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_2_parameter_checking_ + + return private_fl_directory_list(path, filter, sort, listing); + } +#endif // _di_fl_directory_list_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_directory/c/directory.h b/level_1/fl_directory/c/directory.h new file mode 100644 index 0000000..8caffe0 --- /dev/null +++ b/level_1/fl_directory/c/directory.h @@ -0,0 +1,194 @@ +/** + * FLL - Level 1 + * + * Project: Directory + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * Provides operations for directory handling. + */ +#ifndef _FL_directory_h +#define _FL_directory_h + +// libc includes +#include +#include +#include +#include +#include +#include +#include +#include + +// work-around for out-dated systems. +#ifndef __USE_XOPEN_EXTENDED + #define __USE_XOPEN_EXTENDED + #include + #undef __USE_XOPEN_EXTENDED +#else + #include +#endif // __USE_XOPEN_EXTENDED + +// fll-0 includes +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Copy a directory and its contents. + * + * The paths must not contain NULL except for the terminating NULL. + * The paths must be NULL terminated. + * + * Symbolic links are not followed, they are copied as the symbolic link itself. + * + * @param source + * The path to the directory to copy from. + * @param destination + * The path to copy to. + * @param mode + * The file mode assigned to the destination file (based on each file type). + * @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 parent directory already exists. + * If FALSE, will not fail if parent directory already exists (existing directory will be updated). + * + * @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_directory_create() + * @see f_file_copy() + * @see read() + */ +#ifndef _di_fl_directory_copy_ + extern f_return_status fl_directory_copy(const f_string source, const f_string destination, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive); +#endif // _di_fl_directory_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. + * + * Symbolic links are not followed, they are copied as the symbolic link itself. + * + * @param source + * The path to the directory 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 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.) + * + * @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_directory_create() + * @see f_file_clone() + * @see read() + */ +#ifndef _di_fl_directory_clone_ + extern f_return_status fl_directory_clone(const f_string source, const f_string destination, const f_number_unsigned size_block, const bool exclusive, const bool roles); +#endif // _di_fl_directory_clone_ + +/** + * 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 listing + * Will be populated with the names of all top-level paths found within the given directory. + * + * @return + * f_none on success. + * f_no_data 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_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_reallocation (with error bit) on memory reallocation error. + * f_directory_error_open (with error bit) on directory open error. + * f_directory_error_descriptor (with error bit) on directory file descriptor error. + * f_directory_error_stream (with error bit) on directory stream error. + * f_directory_error_unsupported (with error bit) on directory file descriptor not supported. + * f_file_max_descriptors (with error bit) if max file descriptors was reached. + * f_file_max_open (with error bit) too many open files. + * + * @see alphasort() + * @see opendir() + * @see scandir() + * @see versionsort() + */ +#ifndef _di_fl_directory_list_ + extern f_return_status fl_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_directory_listing *listing); +#endif // _di_fl_directory_list_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _FL_directory_h diff --git a/level_1/fl_directory/c/private-directory.c b/level_1/fl_directory/c/private-directory.c new file mode 100644 index 0000000..f7074d2 --- /dev/null +++ b/level_1/fl_directory/c/private-directory.c @@ -0,0 +1,251 @@ +#include +#include "private-directory.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_f_directory_copy_ + f_return_status private_f_directory_copy(const f_string source, const f_string destination, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive) { + 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_invalid_directory); + + status = f_directory_exists(destination); + if (f_status_is_error(status)) return status; + + if (status == f_true) { + if (exclusive) { + return f_status_set_error(f_directory_found); + } + + status = f_file_change_mode(destination, mode.directory, f_false); + if (f_status_is_error(status)) return status; + } + else { + status = f_directory_create(destination, mode); + if (f_status_is_error(status)) return status; + } + + f_directory_listing listing = f_directory_listing_initialize; + + status = private_fl_directory_list(source, 0, 0, &listing); + if (f_status_is_error(status)) { + f_macro_directory_listing_delete_simple(listing); + return status; + } + + f_array_length i = 0; + int directory_fd = 0; + + for (; i < listing.block.used; i++) { + // @todo + } // for + + f_macro_string_dynamics_delete_simple(listing.block); + + for (; i < listing.character.used; i++) { + // @todo + } // for + + f_macro_string_dynamics_delete_simple(listing.character); + + for (; i < listing.file.used; i++) { + // @todo + } // for + + f_macro_string_dynamics_delete_simple(listing.file); + + for (; i < listing.link.used; i++) { + // @todo + } // for + + f_macro_string_dynamics_delete_simple(listing.link); + + for (; i < listing.socket.used; i++) { + // @todo + } // for + + f_macro_string_dynamics_delete_simple(listing.socket); + + for (; i < listing.unknown.used; i++) { + // @todo + } // for + + f_macro_string_dynamics_delete_simple(listing.unknown); + + // @todo copy all file types and clear the set when finished. + + // @todo: recurse through each directory, calling this private function. + // @todo: use a create at directory operation. + // @todo: build the full path and use that in a recursive function. + f_string_dynamic path_full = f_string_dynamic_initialize; + + for (; i < listing.directory.used; i++) { + // @todo + } // for + + f_macro_string_dynamics_delete_simple(listing.directory); + return f_none; + } +#endif // _di_f_directory_copy_ + +#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 **), f_directory_listing *listing) { + struct dirent **entity = 0; + + f_string_length size = 0; + f_status status = f_none; + + DIR *parent = opendir(path); + + if (parent == 0) { + if (errno == ENOMEM) { + return f_status_set_error(f_out_of_memory); + } + else if (errno == ENOMEM) { + return f_status_set_error(f_out_of_memory); + } + else if (errno == EMFILE) { + return f_status_set_error(f_file_max_descriptors); + } + else if (errno == ENFILE) { + return f_status_set_error(f_file_max_open); + } + else if (errno == ENOTDIR) { + return f_status_set_error(f_invalid_directory); + } + else if (errno == ENOENT) { + return f_status_set_error(f_directory_not_found); + } + else if (errno == EACCES) { + return f_status_set_error(f_access_denied); + } + + return f_status_set_error(f_directory_error_open); + } + + int parent_fd = dirfd(parent); + + if (parent_fd < 0) { + closedir(parent); + + if (errno == EINVAL) { + return f_status_set_error(f_directory_error_stream); + } + else if (errno == ENOTSUP) { + return f_status_set_error(f_directory_error_unsupported); + } + + return f_status_set_error(f_directory_error_descriptor); + } + + const size_t length = scandir(path, &entity, filter, sort); + + if (length == -1) { + closedir(parent); + + if (errno == ENOMEM) return f_status_set_error(f_error_allocation); + else return f_status_set_error(f_failure); + } + + f_string_dynamics *names = 0; + f_string_length total = 0; + struct stat file_stat; + int mode = 0; + size_t i = 0; + + for (; i < length; i++) { + size = strnlen(entity[i]->d_name, f_directory_name_max); + + // There is no reason to include "." and ".." in the directory listing. + if (strncmp(entity[i]->d_name, "..", 3) == 0 || strncmp(entity[i]->d_name, ".", 2) == 0) { + f_memory_delete((void **) & entity[i], sizeof(char *), 1); + continue; + } + + 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; + + mode = f_macro_file_type_get(file_stat.st_mode); + + if (mode == f_file_type_block) { + names = &listing->block; + } + else if (mode == f_file_type_character) { + names = &listing->character; + } + else if (mode == f_file_type_directory) { + names = &listing->directory; + } + else if (mode == f_file_type_file) { + names = &listing->file; + } + else if (mode == f_file_type_link) { + names = &listing->link; + } + else if (mode == f_file_type_pipe) { + names = &listing->pipe; + } + else if (mode == f_file_type_socket) { + names = &listing->socket; + } + else { + names = &listing->unknown; + } + + if (names->used >= names->size) { + f_macro_string_dynamics_resize(status, (*names), names->size + f_directory_default_allocation_step); + if (f_status_is_error(status)) break; + } + + f_macro_string_dynamic_new(status, names->array[names->used], size); + if (f_status_is_error(status)) break; + + if (names->array[names->used].used > 0 && names->array[names->used].string[names->array[names->used].used - 1] != 0) { + if (names->array[names->used].used + 1 > f_string_length_size) { + status = f_status_set_error(f_string_too_large); + break; + } + + total = names->array[names->used].used + 1; + if (total > names->array[names->used].size) { + f_status status = f_none; + + f_macro_string_dynamic_resize(status, (*destination), total); + if (f_status_is_error(status)) break; + } + + names->array[names->used].string[names->array[names->used].used] = 0; + names->array[names->used].used = total; + } + + memcpy(names->array[names->used].string, entity[i]->d_name, size); + names->array[names->used].used = size; + names->used++; + + f_memory_delete((void **) & entity[i], sizeof(char *), 1); + } // for + + closedir(parent); + + for (; i < length; i++) { + f_memory_delete((void **) & entity[i], sizeof(char *), 1); + } // for + + f_memory_delete((void **) & entity, sizeof(struct dirent *), 1); + + if (f_status_is_error(status)) return status; + if (length == 0) return f_no_data; + + return f_none; + } +#endif // !defined(_di_fl_directory_list_) + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_directory/c/private-directory.h b/level_1/fl_directory/c/private-directory.h new file mode 100644 index 0000000..bf0ce6f --- /dev/null +++ b/level_1/fl_directory/c/private-directory.h @@ -0,0 +1,79 @@ +/** + * FLL - Level 1 + * + * Project: Directory + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * Provides operations for directory handling. + */ +#ifndef _PRIVATE_F_directory_h +#define _PRIVATE_F_directory_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A special function intended to be used directly by fl_directory_copy() + * + * @param path + * The file path. + * @param file_stat + * The file stat. + * @param type + * The file type. + * @param entity + * The FTW entity. + * + * @return + * 0 on success. + * -1 on failure. + * Check errno for details. + * + * @see fl_directory_copy() + */ +#if !defined(_di_fl_directory_copy_) + f_return_status private_fl_directory_copy(const f_string source, const f_string destination, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_fl_directory_copy_) + + +/** + * A special function intended to be used directly by fl_directory_list(). + * + * @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 listing + * Will be populated with the names of all top-level paths found within the given directory. + * + * @return + * f_none on success. + * f_no_data 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_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_reallocation (with error bit) on memory reallocation error. + * f_directory_error_open (with error bit) on directory open error. + * f_directory_error_descriptor (with error bit) on directory file descriptor error. + * f_directory_error_stream (with error bit) on directory stream error. + * f_directory_error_unsupported (with error bit) on directory file descriptor not supported. + * f_file_max_descriptors (with error bit) if max file descriptors was reached. + * f_file_max_open (with error bit) too many open files. + * + * @see fl_directory_list() + */ +#if !defined(_di_fl_directory_list_) + extern f_return_status private_fl_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_directory_listing *listing) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_fl_directory_list_) + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_F_directory_h diff --git a/level_1/fl_directory/data/build/defines b/level_1/fl_directory/data/build/defines new file mode 100644 index 0000000..c665317 --- /dev/null +++ b/level_1/fl_directory/data/build/defines @@ -0,0 +1,2 @@ +# fss-0000 + diff --git a/level_1/fl_directory/data/build/dependencies b/level_1/fl_directory/data/build/dependencies new file mode 100644 index 0000000..1e76143 --- /dev/null +++ b/level_1/fl_directory/data/build/dependencies @@ -0,0 +1,6 @@ +f_type +f_status +f_memory +f_string +f_file +f_directory diff --git a/level_1/fl_directory/data/build/settings b/level_1/fl_directory/data/build/settings new file mode 100644 index 0000000..3e20c08 --- /dev/null +++ b/level_1/fl_directory/data/build/settings @@ -0,0 +1,30 @@ +# fss-0000 + +project_name fl_directory +project_level 0 + +version_major 0 +version_minor 5 +version_micro 0 + +build_compiler gcc +build_linker ar +build_libraries -lc +build_libraries_fll -lf_file -lf_directory -lf_memory +build_sources_library directory.c private-directory.c +build_sources_program +build_sources_headers directory.h +build_sources_bash +build_sources_settings +build_shared yes +build_static yes + +defines_all +defines_static +defines_shared + +flags_all -z now -g +flags_shared +flags_static +flags_library -fPIC +flags_program -fPIE diff --git a/level_1/fl_file/c/file.c b/level_1/fl_file/c/file.c index 50340c2..5afcac9 100644 --- a/level_1/fl_file/c/file.c +++ b/level_1/fl_file/c/file.c @@ -4,137 +4,6 @@ extern "C" { #endif -#ifndef _di_fl_file_read_ - f_return_status fl_file_read(f_file *file, f_string_dynamic *buffer) { - #ifndef _di_level_1_parameter_checking_ - if (file == 0) return f_status_set_error(f_invalid_parameter); - if (buffer == 0) return f_status_set_error(f_invalid_parameter); - #endif // _di_level_1_parameter_checking_ - - if (file->address == 0) return f_status_set_error(f_file_not_open); - - const f_number_unsigned bytes_total = file->size_block * file->size_chunk; - - f_status status = f_none; - f_string_length size = 0; - - size = file->size_block; - - for (;;) { - if (buffer->used + bytes_total > buffer->size) { - if (buffer->used + bytes_total > f_string_length_size) return f_status_set_error(f_string_too_large); - - f_macro_string_dynamic_resize(status, (*buffer), buffer->used + bytes_total); - - if (f_status_is_error(status)) return status; - } - - status = f_file_read(file, buffer); - - if (f_status_is_error(status)) return status; - if (status == f_none_on_eof) break; - - size += file->size_block; - } // for - - return status; - } -#endif // _di_fl_file_read_ - -#ifndef _di_fl_file_read_position - f_return_status fl_file_read_position(f_file *file, f_string_dynamic *buffer, const f_file_position position) { - #ifndef _di_level_1_parameter_checking_ - if (file == 0) return f_status_set_error(f_invalid_parameter); - if (buffer == 0) return f_status_set_error(f_invalid_parameter); - #endif // _di_level_1_parameter_checking_ - - if (file->address == 0) return f_status_set_error(f_file_not_open); - - f_status status = f_none; - bool infinite = f_false; - - f_number_unsigned bytes_total; - - // when total is 0, this means the file read will until EOF is reached. - if (position.total == 0) { - infinite = f_true; - bytes_total = file->size_block * file->size_chunk; - } - else { - bytes_total = position.total * file->size_chunk; - } - - if (buffer->used + bytes_total > buffer->size) { - if (buffer->used + bytes_total > f_string_length_size) return f_status_set_error(f_string_too_large); - - f_macro_string_dynamic_resize(status, (*buffer), buffer->used + bytes_total); - - if (f_status_is_error(status)) return status; - } - - status = f_file_read_at(file, buffer, position); - - if (f_status_is_error(status)) return status; - if (status == f_none_on_eof) return status; - - while (infinite) { - if (buffer->used + bytes_total > buffer->size) { - if (buffer->used + bytes_total > f_string_length_size) return f_status_set_error(f_string_too_large); - - f_macro_string_dynamic_resize(status, (*buffer), buffer->used + bytes_total); - - if (f_status_is_error(status)) return status; - } - - status = f_file_read_until(file, buffer, 0); - - if (f_status_is_error(status)) return status; - if (status == f_none_on_eof) break; - } // while - - return status; - } -#endif // _di_fl_file_read_position - -#ifndef _di_fl_file_write_ - f_return_status fl_file_write(f_file *file, const f_string_static buffer) { - #ifndef _di_level_1_parameter_checking_ - if (file == 0) return f_status_set_error(f_invalid_parameter); - #endif // _di_level_1_parameter_checking_ - - if (file->address == 0) return f_status_set_error(f_file_not_open); - - size_t written = 0; - - written = fwrite(buffer.string, file->size_chunk, buffer.used, file->address); - - if (written < buffer.used * file->size_chunk) return f_status_set_error(f_file_error_write); - - return f_none; - } -#endif // _di_fl_file_write_ - -#ifndef _di_fl_file_write_position_ - f_return_status fl_file_write_position(f_file *file, const f_string_static buffer, const f_string_range position) { - #ifndef _di_level_1_parameter_checking_ - if (file == 0) return f_status_set_error(f_invalid_parameter); - if (position.start < position.stop) return f_status_set_error(f_invalid_parameter); - #endif // _di_level_1_parameter_checking_ - - if (file->address == 0) return f_file_not_open; - - size_t written = 0; - - const f_string_length total = buffer.used - (position.stop - position.start + 1); - - written = fwrite(buffer.string + position.start, file->size_chunk, total, file->address); - - if (written < total * file->size_chunk) return f_status_set_error(f_file_error_write); - - return f_none; - } -#endif // _di_fl_file_write_position_ - #ifdef __cplusplus } // extern "C" #endif diff --git a/level_1/fl_file/c/file.h b/level_1/fl_file/c/file.h index 109e0d3..259da36 100644 --- a/level_1/fl_file/c/file.h +++ b/level_1/fl_file/c/file.h @@ -19,90 +19,6 @@ extern "C" { #endif -/** - * Load entire file into buffer. - * - * @param file - * The file to read from. - * @param buffer - * The buffer to load the file into. - * - * @return - * f_none on success. - * f_none_on_eof on success and EOF was reached. - * f_file_not_open (with error bit) if file is not open. - * f_file_error_seek (with error bit) if file seek failed. - * f_file_error_read (with error bit) if file read failed. - * f_invalid_parameter (with error bit) if a parameter is invalid. - * f_error_reallocation (with error bit) on memory reallocation error. - * f_string_too_large (with error bit) if string is too large to fit into the buffer. - */ -#ifndef _di_fl_file_read_ - extern f_return_status fl_file_read(f_file *file, f_string_dynamic *buffer); -#endif // _di_fl_file_read_ - -/** - * Load file into buffer, based on specified positions. - * - * @param file - * The file to read from. - * @param buffer - * The buffer to save the file. - * @param position - * The file position to base reading off of. - * - * @return - * f_none on success. - * f_none_on_eof on success and EOF was reached. - * f_file_not_open (with error bit) if file is not open. - * f_file_error_seek (with error bit) if file seek failed. - * f_file_error_read (with error bit) if file read failed. - * f_invalid_parameter (with error bit) if a parameter is invalid. - * f_error_reallocation (with error bit) on memory reallocation error. - * f_string_too_large (with error bit) if string is too large to fit into the buffer. - */ -#ifndef _di_fl_file_read_position_ - extern f_return_status fl_file_read_position(f_file *file, f_string_dynamic *buffer, const f_file_position position); -#endif // _di_fl_file_read_position - -/** - * Save entire buffer into file. - * - * @param file - * The file to save to. - * @param buffer - * The buffer to save to the file. - * - * @return - * f_none on success. - * f_file_not_open (with error bit) if file is not open. - * f_file_error_write (with error bit) if write failed. - * f_invalid_parameter (with error bit) if a parameter is invalid. - */ -#ifndef _di_fl_file_write_ - extern f_return_status fl_file_write(f_file *file, const f_string_static buffer); -#endif // _di_fl_file_write_ - -/** - * Save entire buffer into file, based on specified positions. - * - * @param file - * The file to save to. - * @param buffer - * The buffer to save to the file. - * @param position - * The file position to base writing off of. - * - * @return - * f_none on success. - * f_file_not_open (with error bit) if file is not open. - * f_file_error_write (with error bit) if write failed. - * f_invalid_parameter (with error bit) if a parameter is invalid. - */ -#ifndef _di_fl_file_write_position_ - extern f_return_status fl_file_write_position(f_file *file, const f_string_static buffer, const f_string_range position); -#endif // _di_fl_file_write_position_ - #ifdef __cplusplus } // extern "C" #endif diff --git a/level_1/fl_fss/c/fss.c b/level_1/fl_fss/c/fss.c index 2613e35..c470630 100644 --- a/level_1/fl_fss/c/fss.c +++ b/level_1/fl_fss/c/fss.c @@ -172,43 +172,27 @@ extern "C" { #ifndef _di_level_1_parameter_checking_ if (file == 0) return f_status_set_error(f_invalid_parameter); if (header == 0) return f_status_set_error(f_invalid_parameter); - if (file->address == 0) return f_status_set_error(f_file_not_open); - if (ferror(file->address) != 0) return f_status_set_error(f_file_error); + if (file->id == 0) return f_status_set_error(f_file_not_open); + if (file->id < 0) return f_status_set_error(f_file_error); #endif // _di_level_1_parameter_checking_ - clearerr(file->address); - - f_status status = f_none; - f_string_dynamic buffer = f_string_dynamic_initialize; - f_file_position position = f_file_position_initialize; - - // make sure we are in the proper length in the file { - int seek_result = f_macro_file_seek_begin(file->address, 0); - - if (seek_result != 0) return f_status_set_error(f_file_error_seek); - } - - // 1: Prepare the buffer to handle a size of f_fss_max_header_length - position.total = f_fss_max_header_length; - - f_macro_string_dynamic_adjust(status, buffer, position.total + 1); - - if (f_status_is_error(status)) { - return status; + f_string_length seeked = 0; + if (f_status_is_error(f_file_seek(file->id, SEEK_SET, 0, &seeked))) { + return f_status_set_error(f_file_error_seek); + } } - // 2: buffer the file - status = f_file_read_at(file, &buffer, position); + f_status status = f_none; + f_string_dynamic buffer = f_string_dynamic_initialize; - if (f_status_is_error(status)) { - return status; - } + f_macro_string_dynamic_resize(status, buffer, f_fss_max_header_length + 1); + if (f_status_is_error(status)) return status; - // 3: Now attempt to process the file for the header - status = fl_fss_identify(buffer, header); + status = f_file_read_until(file, &buffer, f_fss_max_header_length + 1); + if (f_status_is_error(status)) return status; - return status; + return fl_fss_identify(buffer, header); } #endif // _di_fl_fss_identify_file_ diff --git a/level_1/fl_fss/c/fss.h b/level_1/fl_fss/c/fss.h index effa5d6..1ffe919 100644 --- a/level_1/fl_fss/c/fss.h +++ b/level_1/fl_fss/c/fss.h @@ -86,11 +86,11 @@ extern "C" { * f_none on success. * f_invalid_parameter (with error bit) if a parameter is invalid. * - * Errors from (with error bit): f_file_read_at(). + * Errors from (with error bit): f_file_read_quantity(). * Errors from (with error bit): fl_fss_identify() * File errors (with error bit): f_file_error_seek, f_file_not_open. * - * @see f_file_read_at() + * @see f_file_read_quantity() * @see fl_fss_identify() */ #ifndef _di_fl_fss_identify_file_ diff --git a/level_1/fl_status/c/status.c b/level_1/fl_status/c/status.c index f825007..41d71d9 100644 --- a/level_1/fl_status/c/status.c +++ b/level_1/fl_status/c/status.c @@ -228,6 +228,9 @@ extern "C" { case f_warn: *string = fl_status_string_warn; break; + case f_block: + *string = fl_status_string_block; + break; case f_critical: *string = fl_status_string_critical; break; @@ -240,6 +243,12 @@ extern "C" { case f_no_data: *string = fl_status_string_no_data; break; + case f_no_space: + *string = fl_status_string_no_space; + break; + case f_out_of_bound: + *string = fl_status_string_out_of_bound; + break; case f_out_of_memory: *string = fl_status_string_out_of_memory; break; @@ -567,6 +576,9 @@ extern "C" { #endif // _di_fl_status_fork_ #ifndef _di_fl_status_file_ + case f_file_closed: + *string = fl_status_string_file_closed; + break; case f_file_error_seek: *string = fl_status_string_file_seek_error; break; @@ -597,12 +609,12 @@ extern "C" { case f_file_not_found: *string = fl_status_string_file_not_found; break; + case f_file_empty: + *string = fl_status_string_file_empty; + break; case f_file_found: *string = fl_status_string_file_found; break; - case f_file_is_empty: - *string = fl_status_string_file_is_empty; - break; case f_file_is_type_block: *string = fl_status_string_file_is_type_block; break; @@ -678,6 +690,9 @@ extern "C" { case f_file_max_open: *string = fl_status_string_file_max_open; break; + case f_file_utf: + *string = fl_status_string_file_utf; + break; #endif // _di_fl_status_file_ #ifndef _di_f_status_filesystem_ @@ -720,12 +735,18 @@ extern "C" { case f_directory_error_descriptor: *string = fl_status_string_directory_descriptor_error; break; + case f_directory_closed: + *string = fl_status_string_directory_closed; + break; + case f_directory_empty: + *string = fl_status_string_directory_empty; + break; + case f_directory_found: + *string = fl_status_string_directory_found; + break; case f_directory_not_found: *string = fl_status_string_directory_not_found; break; - case f_directory_is_empty: - *string = fl_status_string_directory_is_empty; - break; case f_directory_not_open: *string = fl_status_string_directory_not_open; break; @@ -741,6 +762,9 @@ extern "C" { case f_directory_error_stream: *string = fl_status_string_directory_error_stream; break; + case f_directory_utf: + *string = fl_status_string_directory_utf; + break; #endif // _di_fl_status_directory_ #ifndef _di_fl_status_socket_ diff --git a/level_1/fl_status/c/status.h b/level_1/fl_status/c/status.h index 40d5338..66a705d 100644 --- a/level_1/fl_status/c/status.h +++ b/level_1/fl_status/c/status.h @@ -236,6 +236,9 @@ extern "C" { #define fl_status_string_warn "f_warn" #define fl_status_string_warn_length 6 + #define fl_status_string_block "f_block" + #define fl_status_string_block_length 7 + #define fl_status_string_critical "f_critical" #define fl_status_string_critical_length 10 @@ -248,6 +251,12 @@ extern "C" { #define fl_status_string_no_data "f_no_data" #define fl_status_string_no_data_length 9 + #define fl_status_string_no_space "f_no_space" + #define fl_status_string_no_space_length 10 + + #define fl_status_string_out_of_bound "f_out_of_bound" + #define fl_status_string_out_of_bound_length 14 + #define fl_status_string_out_of_memory "f_out_of_memory" #define fl_status_string_out_of_memory_length 15 @@ -567,6 +576,9 @@ extern "C" { #endif // _di_fl_status_fork_ #ifndef _di_fl_status_file_ + #define fl_status_string_file_closed "f_file_closed" + #define fl_status_string_file_closed_length 13 + #define fl_status_string_file_seek_error "f_file_error_seek" #define fl_status_string_file_seek_error_length 17 @@ -597,12 +609,12 @@ extern "C" { #define fl_status_string_file_not_found "f_file_not_found" #define fl_status_string_file_not_found_length 16 + #define fl_status_string_file_empty "f_file_empty" + #define fl_status_string_file_empty_length 12 + #define fl_status_string_file_found "f_file_found" #define fl_status_string_file_found_length 12 - #define fl_status_string_file_is_empty "f_file_is_empty" - #define fl_status_string_file_is_empty_length 15 - #define fl_status_string_file_is_type_block "f_file_is_type_block" #define fl_status_string_file_is_type_block_length 20 @@ -677,6 +689,9 @@ extern "C" { #define fl_status_string_file_max_open "f_file_max_open" #define fl_status_string_file_max_open_length 15 + + #define fl_status_string_file_utf "f_file_utf" + #define fl_status_string_file_utf_length 10 #endif // _di_fl_status_file_ #ifndef _di_f_status_filesystem_ @@ -691,6 +706,9 @@ extern "C" { #endif // _di_f_status_filesystem_ #ifndef _di_fl_status_directory_ + #define fl_status_string_directory_closed "f_directory_closed" + #define fl_status_string_directory_closed_length 18 + #define fl_status_string_directory_read_error "f_directory_error_read" #define fl_status_string_directory_read_error_length 22 @@ -718,12 +736,15 @@ extern "C" { #define fl_status_string_directory_descriptor_error "f_directory_error_descriptor" #define fl_status_string_directory_descriptor_error_length 28 + #define fl_status_string_directory_empty "f_directory_empty" + #define fl_status_string_directory_empty_length 17 + + #define fl_status_string_directory_found "f_directory_found" + #define fl_status_string_directory_found_length 17 + #define fl_status_string_directory_not_found "f_directory_not_found" #define fl_status_string_directory_not_found_length 21 - #define fl_status_string_directory_is_empty "f_directory_is_empty" - #define fl_status_string_directory_is_empty_length 20 - #define fl_status_string_directory_not_open "f_directory_not_open" #define fl_status_string_directory_not_open_length 20 @@ -738,6 +759,9 @@ extern "C" { #define fl_status_string_directory_error_stream "f_directory_error_stream" #define fl_status_string_directory_error_stream_length 19 + + #define fl_status_string_directory_utf "f_directory_utf" + #define fl_status_string_directory_utf_length 15 #endif // _di_fl_status_directory_ #ifndef _di_fl_status_socket_ diff --git a/level_1/fl_utf_file/c/private-utf_file.c b/level_1/fl_utf_file/c/private-utf_file.c new file mode 100644 index 0000000..342afd4 --- /dev/null +++ b/level_1/fl_utf_file/c/private-utf_file.c @@ -0,0 +1,11 @@ +#include +#include "private-utf_file.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_utf_file/c/private-utf_file.h b/level_1/fl_utf_file/c/private-utf_file.h new file mode 100644 index 0000000..a5d487e --- /dev/null +++ b/level_1/fl_utf_file/c/private-utf_file.h @@ -0,0 +1,22 @@ +/** + * FLL - Level 1 + * + * Project: Utf File + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * UTF-8 File Operations. + */ +#ifndef _PRIVATE_FL_utf_file_h +#define _PRIVATE_FL_utf_file_h + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_FL_utf_file_h diff --git a/level_1/fl_utf_file/c/utf_file.c b/level_1/fl_utf_file/c/utf_file.c index d3205aa..7800435 100644 --- a/level_1/fl_utf_file/c/utf_file.c +++ b/level_1/fl_utf_file/c/utf_file.c @@ -1,9 +1,194 @@ #include +#include "private-utf_file.h" #ifdef __cplusplus extern "C" { #endif +#ifndef _di_f_file_read_ + f_return_status f_file_read(f_file *file, f_string_dynamic *buffer) { + #ifndef _di_level_0_parameter_checking_ + if (file == 0) return f_status_set_error(f_invalid_parameter); + if (file->size_chunk == 0) return f_status_set_error(f_invalid_parameter); + if (file->size_block == 0) return f_status_set_error(f_invalid_parameter); + if (buffer->used >= buffer->size) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ + + if (file->id <= 0) return f_status_set_error(f_file_not_open); + + f_status status = f_none; + ssize_t size_read = 0; + + // use a custom buffer so that memory is allocated post-read instead of pre-read. + const f_string_length buffer_size = file->size_chunk * file->size_block; + char buffer_read[buffer_size]; + + memset(&buffer_read, 0, sizeof(buffer_size)); + + while ((size_read = read(file->id, buffer_read, buffer_size)) > 0) { + if (buffer->used + size_read > buffer->size) { + if (buffer->size + size_read > f_string_length_size) { + return f_status_set_error(f_string_too_large); + } + + f_macro_string_dynamic_resize(status, (*buffer), buffer->size + size_read); + if (f_status_is_error(status)) return status; + } + + memcpy(buffer->string + buffer->used, buffer_read, buffer_size); + buffer->used += size_read; + } // while + + if (size_read == 0) { + return f_none_on_eof; + } + + if (size_read < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) return f_status_set_error(f_block); + if (errno == EBADF) return f_status_set_error(f_file_error_descriptor); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == EINTR) return f_status_set_error(f_interrupted); + if (errno == EINVAL) return f_status_set_error(f_invalid_parameter); + if (errno == EIO) return f_status_set_error(f_error_input_output); + if (errno == EISDIR) return f_status_set_error(f_file_is_type_directory); + + return f_status_set_error(f_failure); + } + + return f_none; + } +#endif // _di_f_file_read_ + +#ifndef _di_f_file_read_block_ + f_return_status f_file_read_block(f_file *file, f_string_dynamic *buffer) { + #ifndef _di_level_0_parameter_checking_ + if (file == 0) return f_status_set_error(f_invalid_parameter); + if (file->size_chunk == 0) return f_status_set_error(f_invalid_parameter); + if (file->size_block == 0) return f_status_set_error(f_invalid_parameter); + if (buffer->used >= buffer->size) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ + + if (file->id <= 0) return f_status_set_error(f_file_not_open); + + f_status status = f_none; + ssize_t size_read = 0; + + const f_string_length buffer_size = file->size_chunk * file->size_block; + char buffer_read[buffer_size]; + + memset(&buffer_read, 0, sizeof(buffer_size)); + + if ((size_read = read(file->id, buffer_read, buffer_size)) > 0) { + if (buffer->used + size_read > buffer->size) { + if (buffer->size + size_read > f_string_length_size) { + return f_status_set_error(f_string_too_large); + } + + f_macro_string_dynamic_resize(status, (*buffer), buffer->size + size_read); + if (f_status_is_error(status)) return status; + } + + memcpy(buffer->string + buffer->used, buffer_read, buffer_size); + buffer->used += size_read; + } + + if (size_read == 0) { + return f_none_on_eof; + } + + if (size_read < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) return f_status_set_error(f_block); + if (errno == EBADF) return f_status_set_error(f_file_error_descriptor); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == EINTR) return f_status_set_error(f_interrupted); + if (errno == EINVAL) return f_status_set_error(f_invalid_parameter); + if (errno == EIO) return f_status_set_error(f_error_input_output); + if (errno == EISDIR) return f_status_set_error(f_file_is_type_directory); + + return f_status_set_error(f_failure); + } + + return f_none; + } +#endif // _di_f_file_read_block_ + +#ifndef _di_f_file_read_until_ + f_return_status f_file_read_until(f_file *file, f_string_dynamic *buffer, const f_string_length total) { + #ifndef _di_level_0_parameter_checking_ + if (file == 0) return f_status_set_error(f_invalid_parameter); + if (file->size_chunk == 0) return f_status_set_error(f_invalid_parameter); + if (file->size_block == 0) return f_status_set_error(f_invalid_parameter); + if (buffer->used >= buffer->size) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ + + if (file->id <= 0) return f_status_set_error(f_file_not_open); + + f_status status = f_none; + ssize_t size_read = 0; + + f_string_length buffer_size = file->size_chunk * file->size_block; + f_string_length buffer_count = 0; + + if (total < buffer_size) { + buffer_size = total; + } + + char buffer_read[buffer_size]; + + memset(&buffer_read, 0, sizeof(buffer_size)); + + if ((size_read = read(file->id, buffer_read, buffer_size)) > 0) { + if (buffer->used + size_read > buffer->size) { + if (buffer->size + size_read > f_string_length_size) { + return f_status_set_error(f_string_too_large); + } + + f_macro_string_dynamic_resize(status, (*buffer), buffer->size + size_read); + if (f_status_is_error(status)) return status; + } + + memcpy(buffer->string + buffer->used, buffer_read, buffer_size); + buffer->used += size_read; + buffer_count += size_read; + } + + if (size_read == 0) { + return f_none_on_eof; + } + + if (size_read < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) return f_status_set_error(f_block); + if (errno == EBADF) return f_status_set_error(f_file_error_descriptor); + if (errno == EFAULT) return f_status_set_error(f_invalid_buffer); + if (errno == EINTR) return f_status_set_error(f_interrupted); + if (errno == EINVAL) return f_status_set_error(f_invalid_parameter); + if (errno == EIO) return f_status_set_error(f_error_input_output); + if (errno == EISDIR) return f_status_set_error(f_file_is_type_directory); + + return f_status_set_error(f_failure); + } + + return f_none; + } +#endif // _di_f_file_read_until_ + + + + + + + + + + + + + + + + + + #ifndef _di_fl_utf_file_read_ f_return_status fl_utf_file_read(f_file *file, f_utf_string_dynamic *buffer) { #ifndef _di_level_1_parameter_checking_ @@ -75,7 +260,7 @@ extern "C" { #endif // _di_fl_utf_file_read_ #ifndef _di_fl_utf_file_read_position - f_return_status fl_utf_file_read_position(f_file *file, f_utf_string_dynamic *buffer, const f_file_position position) { + f_return_status fl_utf_file_read_position(f_file *file, f_utf_string_dynamic *buffer, const f_string_quantity quantity) { #ifndef _di_level_1_parameter_checking_ if (file == 0) return f_status_set_error(f_invalid_parameter); if (buffer == 0) return f_status_set_error(f_invalid_parameter); @@ -87,15 +272,15 @@ extern "C" { // first seek to 'where' we need to begin the read. { - long current_file_position = ftell(file->address); + long current_file_quantity = ftell(file->address); - if (current_file_position == -1) return f_status_set_error(f_file_error_seek); + if (current_file_quantity == -1) return f_status_set_error(f_file_error_seek); - if (current_file_position > position.start) { - result = f_macro_file_seek_to(file->address, file->size_chunk * (0 - (current_file_position - position.start))); + if (current_file_quantity > quantity.start) { + result = f_macro_file_seek_to(file->address, file->size_chunk * (0 - (current_file_quantity - quantity.start))); } - else if (current_file_position < position.start) { - result = f_macro_file_seek_to(file->address, file->size_chunk * (position.start - current_file_position)); + else if (current_file_quantity < quantity.start) { + result = f_macro_file_seek_to(file->address, file->size_chunk * (quantity.start - current_file_quantity)); } if (result != 0) return f_status_set_error(f_file_error_seek); @@ -110,12 +295,12 @@ extern "C" { f_number_unsigned bytes_total; // when total is 0, this means the file read will until EOF is reached. - if (position.total == 0) { + if (quantity.total == 0) { infinite = f_true; bytes_total = file->size_block * file->size_chunk; } else { - bytes_total = position.total * file->size_chunk; + bytes_total = quantity.total * file->size_chunk; } uint8_t width = 0; @@ -131,11 +316,11 @@ extern "C" { if (f_status_is_error(status)) return status; } - if (position.total == 0) { + if (quantity.total == 0) { result = fread(buffer->string + buffer->used, file->size_chunk, file->size_block, file->address); } else { - result = fread(buffer->string + buffer->used, file->size_chunk, position.total, file->address); + result = fread(buffer->string + buffer->used, file->size_chunk, quantity.total, file->address); } if (file->address == 0) return f_status_set_error(f_file_error_read); diff --git a/level_1/fl_utf_file/c/utf_file.h b/level_1/fl_utf_file/c/utf_file.h index 9c8b212..171e7c6 100644 --- a/level_1/fl_utf_file/c/utf_file.h +++ b/level_1/fl_utf_file/c/utf_file.h @@ -5,7 +5,7 @@ * API Version: 0.5 * Licenses: lgplv2.1 * - * File Operations. + * UTF-8 File Operations. */ #ifndef _FL_utf_file_h #define _FL_utf_file_h @@ -14,16 +14,149 @@ #include // fll-0 includes -#include +#include #include #include #include +#include #ifdef __cplusplus extern "C" { #endif /** + * Read until EOF is reached. + * + * To check how much was read into the buffer, record buffer->used before execution and compare to buffer->used after execution. + * + * @param file + * The file to read. + * The file must already be open. + * @param buffer + * The buffer the file is being read into. + * The contents of the file is appended into this buffer. + * + * @return + * f_none on success. + * f_none_on_eof on success and EOF was reached. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_block (with error bit) if file descriptor is set to non-block and the read would result in a blocking operation. + * f_file_error_descriptor (with error bit) if the file descriptor is invalid. + * f_invalid_buffer (with error bit) if the buffer is invalid. + * f_interrupted (with error bit) if interrupt was received. + * f_error_input_output (with error bit) on I/O error. + * f_file_not_open (with error bit) if file is not open. + * f_file_is_type_directory (with error bit) if file descriptor represents a directory. + * f_incomplete_utf_on_eof (with error bit) if UTF-8 character was incomplete at the end of the file. + * + * @see read() + */ +#ifndef _di_fl_utf_file_read_ + extern f_return_status fl_utf_file_read(f_file *file, f_utf_string_dynamic *buffer); +#endif // _di_fl_utf_file_read_ + +/** + * Read until a single block is filled or EOF is reached. + * + * To check how much was read into the buffer, record buffer->used before execution and compare to buffer->used after execution. + * + * @param file + * The file to read. + * The file must already be open. + * @param buffer + * The buffer the file is being read into. + * The contents of the file is appended into this buffer. + * + * @return + * f_none on success. + * f_none_on_eof on success and EOF was reached. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_block (with error bit) if file descriptor is set to non-block and the read would result in a blocking operation. + * f_file_error_descriptor (with error bit) if the file descriptor is invalid. + * f_invalid_buffer (with error bit) if the buffer is invalid. + * f_interrupted (with error bit) if interrupt was received. + * f_error_input_output (with error bit) on I/O error. + * f_file_not_open (with error bit) if file is not open. + * f_file_is_type_directory (with error bit) if file descriptor represents a directory. + * f_incomplete_utf_on_eof (with error bit) if UTF-8 character was incomplete at the end of the file. + * + * @see read() + */ +#ifndef _di_f_utf_file_read_ + extern f_return_status f_utf_file_read_block(f_file *file, f_utf_string_dynamic *buffer); +#endif // _di_f_utf_file_read_ + +/** + * Read until a given number or EOF is reached, storing it in the buffer. + * + * To check how much was read into the buffer, record buffer->used before execution and compare to buffer->used after execution. + * + * @param file + * The file to read. + * The file must already be open. + * @param buffer + * The buffer the file is being read into. + * @param total + * The total bytes to read, unless EOF is reached first. + * + * @return + * f_none on success. + * f_none_on_eof on success and EOF was reached. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_block (with error bit) if file descriptor is set to non-block and the read would result in a blocking operation. + * f_file_error_descriptor (with error bit) if the file descriptor is invalid. + * f_invalid_buffer (with error bit) if the buffer is invalid. + * f_interrupted (with error bit) if interrupt was received. + * f_error_input_output (with error bit) on I/O error. + * f_file_not_open (with error bit) if file is not open. + * f_file_is_type_directory (with error bit) if file descriptor represents a directory. + * f_incomplete_utf_on_eof (with error bit) if UTF-8 character was incomplete at the end of the file. + * + * @see read + */ +#ifndef _di_f_utf_file_read_until_ + extern f_return_status f_utf_file_read_until(f_file *file, f_utf_string_dynamic *buffer, const f_utf_string_length total); +#endif // _di_f_utf_file_read_until_ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/** * Load entire file into the UTF-8 buffer. * * This does not validate the UTF-8 codes. @@ -57,7 +190,7 @@ extern "C" { * The file to read from. * @param buffer * The buffer to save the file. - * @param position + * @param quantity * The file position to base reading off of. * * @return @@ -72,7 +205,7 @@ extern "C" { * f_incomplete_utf_on_eof (with error bit) if UTF-8 character was incomplete at the end of the file. */ #ifndef _di_fl_utf_file_read_position_ - extern f_return_status fl_utf_file_read_position(f_file *file, f_utf_string_dynamic *buffer, const f_file_position position); + extern f_return_status fl_utf_file_read_position(f_file *file, f_utf_string_dynamic *buffer, const f_string_quantity quantity); #endif // _di_fl_utf_file_read_position /** diff --git a/level_1/fl_utf_file/data/build/dependencies b/level_1/fl_utf_file/data/build/dependencies index 9d424c7..fed74d0 100644 --- a/level_1/fl_utf_file/data/build/dependencies +++ b/level_1/fl_utf_file/data/build/dependencies @@ -2,5 +2,5 @@ f_type f_status f_memory f_string -f_file f_utf +f_file diff --git a/level_1/fl_utf_file/data/build/settings b/level_1/fl_utf_file/data/build/settings index e0cb76d..c92d72a 100644 --- a/level_1/fl_utf_file/data/build/settings +++ b/level_1/fl_utf_file/data/build/settings @@ -11,8 +11,8 @@ build_compiler gcc build_linker ar build_libraries -lc build_libraries_fll -lf_file -lf_utf -lf_memory -build_sources_library utf_file.c -build_sources_program +build_sources_library utf_file.c private-utf_file.c +build_sources_program build_sources_headers utf_file.h build_sources_bash build_sources_settings diff --git a/level_2/fll_directory/c/directory.c b/level_2/fll_directory/c/directory.c index caa0ae0..a3f6cec 100644 --- a/level_2/fll_directory/c/directory.c +++ b/level_2/fll_directory/c/directory.c @@ -4,148 +4,6 @@ extern "C" { #endif -#ifndef _di_fll_directory_list_ - f_return_status fll_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_directory_listing *listing) { - #ifndef _di_level_2_parameter_checking_ - if (listing == 0) return f_status_set_error(f_invalid_parameter); - #endif // _di_level_2_parameter_checking_ - - struct dirent **entity = 0; - - f_string_length size = 0; - f_status status = f_none; - - DIR *parent = opendir(path); - - if (parent == 0) { - if (errno == ENOMEM) { - return f_status_set_error(f_out_of_memory); - } - else if (errno == ENOMEM) { - return f_status_set_error(f_out_of_memory); - } - else if (errno == EMFILE) { - return f_status_set_error(f_file_max_descriptors); - } - else if (errno == ENFILE) { - return f_status_set_error(f_file_max_open); - } - else if (errno == ENOTDIR) { - return f_status_set_error(f_invalid_directory); - } - else if (errno == ENOENT) { - return f_status_set_error(f_directory_not_found); - } - else if (errno == EACCES) { - return f_status_set_error(f_access_denied); - } - - return f_status_set_error(f_directory_error_open); - } - - int parent_fd = dirfd(parent); - - if (parent_fd < 0) { - closedir(parent); - - if (errno == EINVAL) { - return f_status_set_error(f_directory_error_stream); - } - else if (errno == ENOTSUP) { - return f_status_set_error(f_directory_error_unsupported); - } - - return f_status_set_error(f_directory_error_descriptor); - } - - const size_t length = scandir(path, &entity, filter, sort); - - if (length == -1) { - closedir(parent); - - if (errno == ENOMEM) return f_status_set_error(f_error_allocation); - else return f_status_set_error(f_failure); - } - - f_string_dynamics *names = 0; - struct stat file_stat; - int mode = 0; - size_t i = 0; - - for (; i < length; i++) { - size = strnlen(entity[i]->d_name, f_directory_name_max); - - // There is no reason to include "." and ".." in the directory listing. - if (strncmp(entity[i]->d_name, "..", 3) == 0 || strncmp(entity[i]->d_name, ".", 2) == 0) { - f_memory_delete((void **) & entity[i], sizeof(char *), 1); - continue; - } - - 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; - - mode = f_macro_file_type_get(file_stat.st_mode); - - if (mode == f_file_type_block) { - names = &listing->block; - } - else if (mode == f_file_type_character) { - names = &listing->character; - } - else if (mode == f_file_type_directory) { - names = &listing->directory; - } - else if (mode == f_file_type_file) { - names = &listing->file; - } - else if (mode == f_file_type_link) { - names = &listing->link; - } - else if (mode == f_file_type_pipe) { - names = &listing->pipe; - } - else if (mode == f_file_type_socket) { - names = &listing->socket; - } - else { - names = &listing->unknown; - } - - if (names->used >= names->size) { - f_macro_string_dynamics_resize(status, (*names), names->size + f_directory_default_allocation_step); - if (f_status_is_error(status)) break; - } - - f_macro_string_dynamic_new(status, names->array[names->used], size); - if (f_status_is_error(status)) break; - - fl_string_dynamic_terminate(&names->array[names->used]); - if (f_status_is_error(status)) break; - - memcpy(names->array[names->used].string, entity[i]->d_name, size); - names->array[names->used].used = size; - names->used++; - - f_memory_delete((void **) & entity[i], sizeof(char *), 1); - } // for - - closedir(parent); - - for (; i < length; i++) { - f_memory_delete((void **) & entity[i], sizeof(char *), 1); - } // for - - f_memory_delete((void **) & entity, sizeof(struct dirent *), 1); - - if (f_status_is_error(status)) return status; - if (length == 0) return f_no_data; - - return f_none; - } -#endif // _di_fll_directory_list_ - #ifdef __cplusplus } // extern "C" #endif diff --git a/level_2/fll_directory/c/directory.h b/level_2/fll_directory/c/directory.h index e1b4af1..6872ba5 100644 --- a/level_2/fll_directory/c/directory.h +++ b/level_2/fll_directory/c/directory.h @@ -33,44 +33,6 @@ extern "C" { #endif -/** - * 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 listing - * Will be populated with the names of all top-level paths found within the given directory. - * - * @return - * f_none on success. - * f_no_data 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_invalid_parameter (with error bit) if a parameter is invalid. - * f_error_reallocation (with error bit) on memory reallocation error. - * f_directory_error_open (with error bit) on directory open error. - * f_directory_error_descriptor (with error bit) on directory file descriptor error. - * f_directory_error_stream (with error bit) on directory stream error. - * f_directory_error_unsupported (with error bit) on directory file descriptor not supported. - * f_file_max_descriptors (with error bit) if max file descriptors was reached. - * f_file_max_open (with error bit) too many open files. - * - * @see alphasort() - * @see scandir() - * @see versionsort() - */ -#ifndef _di_fll_directory_list_ - extern f_return_status fll_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_directory_listing *listing); -#endif // _di_fll_directory_list_ - #ifdef __cplusplus } // extern "C" #endif diff --git a/level_2/fll_status/c/status.c b/level_2/fll_status/c/status.c index fc8ec3c..e75176b 100644 --- a/level_2/fll_status/c/status.c +++ b/level_2/fll_status/c/status.c @@ -381,6 +381,11 @@ extern "C" { return f_none; } + if (fl_string_compare(string, fl_status_string_block, length, fl_status_string_block_length) == f_equal_to) { + *code = f_block; + return f_none; + } + if (fl_string_compare(string, fl_status_string_critical, length, fl_status_string_critical_length) == f_equal_to) { *code = f_critical; return f_none; @@ -401,6 +406,16 @@ extern "C" { return f_none; } + if (fl_string_compare(string, fl_status_string_no_space, length, fl_status_string_no_space_length) == f_equal_to) { + *code = f_no_space; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_out_of_bound, length, fl_status_string_out_of_bound_length) == f_equal_to) { + *code = f_out_of_bound; + return f_none; + } + if (fl_string_compare(string, fl_status_string_out_of_memory, length, fl_status_string_out_of_memory_length) == f_equal_to) { *code = f_out_of_memory; return f_none; @@ -922,6 +937,11 @@ extern "C" { #endif // _di_fll_status_fork_ #ifndef _di_fll_status_file_ + if (fl_string_compare(string, fl_status_string_file_closed, length, fl_status_string_file_closed_length) == f_equal_to) { + *code = f_file_closed; + return f_none; + } + if (fl_string_compare(string, fl_status_string_file_seek_error, length, fl_status_string_file_seek_error_length) == f_equal_to) { *code = f_file_error_seek; return f_none; @@ -972,13 +992,13 @@ extern "C" { return f_none; } - if (fl_string_compare(string, fl_status_string_file_found, length, fl_status_string_file_found_length) == f_equal_to) { - *code = f_file_found; + if (fl_string_compare(string, fl_status_string_file_empty, length, fl_status_string_file_empty_length) == f_equal_to) { + *code = f_file_empty; return f_none; } - if (fl_string_compare(string, fl_status_string_file_is_empty, length, fl_status_string_file_is_empty_length) == f_equal_to) { - *code = f_file_is_empty; + if (fl_string_compare(string, fl_status_string_file_found, length, fl_status_string_file_found_length) == f_equal_to) { + *code = f_file_found; return f_none; } @@ -1106,6 +1126,11 @@ extern "C" { *code = f_file_max_open; return f_none; } + + if (fl_string_compare(string, fl_status_string_file_utf, length, fl_status_string_file_utf_length) == f_equal_to) { + *code = f_file_utf; + return f_none; + } #endif // _di_fll_status_file_ #ifndef _di_f_status_filesystem_ @@ -1126,6 +1151,11 @@ extern "C" { #endif // _di_f_status_filesystem_ #ifndef _di_fll_status_directory_ + if (fl_string_compare(string, fl_status_string_directory_closed, length, fl_status_string_directory_closed_length) == f_equal_to) { + *code = f_directory_closed; + return f_none; + } + if (fl_string_compare(string, fl_status_string_directory_read_error, length, fl_status_string_directory_read_error_length) == f_equal_to) { *code = f_directory_error_read; return f_none; @@ -1171,13 +1201,18 @@ extern "C" { return f_none; } - if (fl_string_compare(string, fl_status_string_directory_not_found, length, fl_status_string_directory_not_found_length) == f_equal_to) { - *code = f_directory_not_found; + if (fl_string_compare(string, fl_status_string_directory_found, length, fl_status_string_directory_found_length) == f_equal_to) { + *code = f_directory_found; return f_none; } - if (fl_string_compare(string, fl_status_string_directory_is_empty, length, fl_status_string_directory_is_empty_length) == f_equal_to) { - *code = f_directory_is_empty; + if (fl_string_compare(string, fl_status_string_directory_empty, length, fl_status_string_directory_empty_length) == f_equal_to) { + *code = f_directory_empty; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_directory_not_found, length, fl_status_string_directory_not_found_length) == f_equal_to) { + *code = f_directory_not_found; return f_none; } @@ -1205,6 +1240,11 @@ extern "C" { *code = f_directory_error_stream; return f_none; } + + if (fl_string_compare(string, fl_status_string_directory_utf, length, fl_status_string_directory_utf_length) == f_equal_to) { + *code = f_directory_utf; + return f_none; + } #endif // _di_fll_status_directory_ #ifndef _di_fll_status_socket_ diff --git a/level_3/fake/c/private-build.c b/level_3/fake/c/private-build.c index bcaa06e..667dfb1 100644 --- a/level_3/fake/c/private-build.c +++ b/level_3/fake/c/private-build.c @@ -402,8 +402,8 @@ extern "C" { status = f_file_open(&file, data.file_data_build_settings.string); if (status == f_none) { - name_function = "fl_file_read_position"; - status = fl_file_read(&file, &buffer); + name_function = "f_file_read"; + status = f_file_read(&file, &buffer); f_file_close(&file); } diff --git a/level_3/fake/c/private-clean.c b/level_3/fake/c/private-clean.c index 74bc98e..4a9abd8 100644 --- a/level_3/fake/c/private-clean.c +++ b/level_3/fake/c/private-clean.c @@ -18,10 +18,10 @@ extern "C" { } if (data.verbosity == fake_verbosity_verbose) { - status = f_directory_remove_custom(data.path_build.string, f_directory_max_recursion, f_true, fake_clean_remove_recursively_verbosely); + status = f_directory_remove_custom(data.path_build.string, f_directory_descriptors_max, f_true, fake_clean_remove_recursively_verbosely); } else { - status = f_directory_remove(data.path_build.string, f_directory_max_recursion, f_true); + status = f_directory_remove(data.path_build.string, f_directory_descriptors_max, f_true); } if (f_status_is_error(status)) { diff --git a/level_3/fake/c/private-skeleton.c b/level_3/fake/c/private-skeleton.c index b9c0fd2..0848a4c 100644 --- a/level_3/fake/c/private-skeleton.c +++ b/level_3/fake/c/private-skeleton.c @@ -91,7 +91,7 @@ extern "C" { if (path.used == 0) return f_none; - status = f_directory_is(path.string); + status = f_directory_exists(path.string); if (status == f_true) { if (data.verbosity == fake_verbosity_verbose) { printf("Directory '%s' already exists.%c", path.string, f_string_eol); @@ -132,7 +132,7 @@ extern "C" { } } else if (f_status_is_error(status)) { - fake_print_error_file(data.context, data.verbosity, f_status_set_fine(status), "f_directory_is", path.string, "create", f_false, f_true); + fake_print_error_file(data.context, data.verbosity, f_status_set_fine(status), "f_directory_exists", path.string, "create", f_false, f_true); return status; } diff --git a/level_3/firewall/c/private-firewall.c b/level_3/firewall/c/private-firewall.c index 473338b..afc27fb 100644 --- a/level_3/firewall/c/private-firewall.c +++ b/level_3/firewall/c/private-firewall.c @@ -566,7 +566,6 @@ f_return_status firewall_perform_commands(const firewall_local_data local, const f_file file = f_file_initialize; f_string_dynamic file_path = f_string_dynamic_initialize; f_string_dynamic local_buffer = f_string_dynamic_initialize; - f_file_position file_position = f_file_position_initialize; f_fss_objects basic_objects = f_fss_objects_initialize; f_fss_contents basic_contents = f_fss_objects_initialize; @@ -613,13 +612,7 @@ f_return_status firewall_perform_commands(const firewall_local_data local, const f_file_close(&file); } else { - if (file_position.total == 0) { - fseek(file.address, 0, SEEK_END); - file_position.total = ftell(file.address); - fseek(file.address, 0, SEEK_SET); - } - - status = fl_file_read_position(&file, &local_buffer, file_position); + status = f_file_read(&file, &local_buffer); f_file_close(&file); @@ -1374,10 +1367,7 @@ f_return_status firewall_buffer_rules(const f_string filename, const bool option return status; } - f_macro_file_reset_position(local->file_position, file) - - fflush(stdout); - status = fl_file_read_position(&file, &local->buffer, local->file_position); + status = f_file_read(&file, &local->buffer); f_file_close(&file); @@ -1478,9 +1468,6 @@ f_return_status firewall_delete_local_data(firewall_local_data *local) { local->is_stop = f_false; local->is_lock = f_false; - local->file_position.start = 0; - local->file_position.total = 0; - local->device = 0; local->chain = 0; diff --git a/level_3/firewall/c/private-firewall.h b/level_3/firewall/c/private-firewall.h index b3bda84..2127eee 100644 --- a/level_3/firewall/c/private-firewall.h +++ b/level_3/firewall/c/private-firewall.h @@ -18,8 +18,6 @@ typedef struct { bool is_stop; bool is_lock; - f_file_position file_position; - f_array_length device; f_string_dynamic buffer; @@ -37,7 +35,6 @@ typedef struct { f_false, \ f_false, \ f_false, \ - f_file_position_initialize, \ 0, \ f_string_dynamic_initialize, \ 0, \ diff --git a/level_3/fss_basic_list_read/c/fss_basic_list_read.h b/level_3/fss_basic_list_read/c/fss_basic_list_read.h index 409e8ca..34b53a8 100644 --- a/level_3/fss_basic_list_read/c/fss_basic_list_read.h +++ b/level_3/fss_basic_list_read/c/fss_basic_list_read.h @@ -124,7 +124,7 @@ extern "C" { f_string_dynamic buffer; f_fss_objects objects; f_fss_contents contents; - f_file_position file_position; + f_string_quantity quantity; f_string_lengths remaining; bool process_pipe; @@ -137,7 +137,7 @@ extern "C" { f_string_dynamic_initialize, \ f_fss_objects_initialize, \ f_fss_contents_initialize, \ - f_file_position_initialize, \ + f_string_quantity_initialize, \ f_string_lengths_initialize, \ f_false, \ fl_color_context_initialize, \ diff --git a/level_3/fss_basic_read/c/fss_basic_read.h b/level_3/fss_basic_read/c/fss_basic_read.h index b98fa3e..e822289 100644 --- a/level_3/fss_basic_read/c/fss_basic_read.h +++ b/level_3/fss_basic_read/c/fss_basic_read.h @@ -124,7 +124,7 @@ extern "C" { f_string_dynamic buffer; f_fss_objects objects; f_fss_contents contents; - f_file_position file_position; + f_string_quantity quantity; f_string_lengths remaining; bool process_pipe; @@ -137,7 +137,7 @@ extern "C" { f_string_dynamic_initialize, \ f_fss_objects_initialize, \ f_fss_contents_initialize, \ - f_file_position_initialize, \ + f_string_quantity_initialize, \ f_string_lengths_initialize, \ f_false, \ fl_color_context_initialize, \ diff --git a/level_3/fss_extended_list_read/c/fss_extended_list_read.h b/level_3/fss_extended_list_read/c/fss_extended_list_read.h index 5fdc8e6..e842bb4 100644 --- a/level_3/fss_extended_list_read/c/fss_extended_list_read.h +++ b/level_3/fss_extended_list_read/c/fss_extended_list_read.h @@ -123,7 +123,7 @@ extern "C" { f_string_dynamic buffer; f_fss_nest nest; - f_file_position file_position; + f_string_quantity quantity; f_string_lengths remaining; bool process_pipe; @@ -135,7 +135,7 @@ extern "C" { f_console_parameter_initialize_fss_extended_list_read, \ f_string_dynamic_initialize, \ f_fss_nest_initialize, \ - f_file_position_initialize, \ + f_quantity_initialize, \ f_string_lengths_initialize, \ f_false, \ fl_color_context_initialize, \ diff --git a/level_3/fss_extended_read/c/fss_extended_read.h b/level_3/fss_extended_read/c/fss_extended_read.h index 4dc0ec8..b76c105 100644 --- a/level_3/fss_extended_read/c/fss_extended_read.h +++ b/level_3/fss_extended_read/c/fss_extended_read.h @@ -124,7 +124,7 @@ extern "C" { f_string_dynamic buffer; f_fss_objects objects; f_fss_contents contents; - f_file_position file_position; + f_string_quantity quantity; f_string_lengths remaining; bool process_pipe; @@ -137,7 +137,7 @@ extern "C" { f_string_dynamic_initialize, \ f_fss_objects_initialize, \ f_fss_contents_initialize, \ - f_file_position_initialize, \ + f_string_quantity_initialize, \ f_string_lengths_initialize, \ f_false, \ fl_color_context_initialize, \ diff --git a/level_3/init/c/private-init.c b/level_3/init/c/private-init.c index 7d43bbe..09b99ef 100644 --- a/level_3/init/c/private-init.c +++ b/level_3/init/c/private-init.c @@ -8,7 +8,7 @@ f_return_status init_rule_buffer(const init_data data, const f_string filename, f_string_dynamic *buffer, f_fss_objects *objects, f_fss_contents *contents) { f_file file = f_file_initialize; f_status status = f_none; - f_file_position file_position = f_file_position_initialize; + f_string_quantity quantity = f_string_quantity_initialize; status = f_file_open(&file, filename); @@ -38,10 +38,10 @@ return f_status_set_error(status); } - f_macro_file_reset_position(file_position, file) + f_macro_file_reset_position(quantity, file) fflush(stdout); - status = fl_file_read_position(&file, buffer, file_position); + status = fl_file_read_position(&file, buffer, quantity); f_file_close(&file); -- 1.8.3.1