It turns out I need custom functions for processing the mode like the chmod program works.
During the process of writing this I discovered several different ways chmod accepts arguments that I wasn't aware.
As a result I changed my logic repeatedly and this code is in a very much incomplete state.
This is being committed primarily to avoid losing any data (more so than usual).
There will be a lot of clean up when I get back to completing this.
build_linker ar
build_libraries -lc
build_libraries-level
-build_sources_library console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c private-file.c fss.c iki.c memory.c path.c private-path.c pipe.c print.c serialize.c private-serialize.c socket.c utf.c private-utf.c
+build_sources_library account.c console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c private-file.c fss.c iki.c memory.c path.c private-path.c pipe.c print.c serialize.c private-serialize.c socket.c utf.c private-utf.c
build_sources_program
-build_sources_headers color.h console.h conversion.h directory.h directory_type.h environment.h file.h fss.h fss-common.h fss-named.h fss-nest.h fss-quoted.h fss-set.h iki.h iki-common.h memory.h memory-structure.h path.h pipe.h print.h serialize.h socket.h status.h status_array.h string.h string_common.h string_dynamic.h string_map.h string_quantity.h string_range.h type.h type_array.h utf.h utf-common.h
+build_sources_headers account.h color.h console.h conversion.h directory.h directory_type.h environment.h file.h fss.h fss-common.h fss-named.h fss-nest.h fss-quoted.h fss-set.h iki.h iki-common.h memory.h memory-structure.h path.h pipe.h print.h serialize.h socket.h status.h status_array.h string.h string_common.h string_dynamic.h string_map.h string_quantity.h string_range.h type.h type_array.h utf.h utf-common.h
build_sources_script
build_sources_setting
build_script yes
build_linker ar
build_libraries -lc
build_libraries-monolithic
-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/fss.c level_0/iki.c level_0/memory.c level_0/path.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/serialize.c level_0/private-serialize.c level_0/socket.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/conversion.c level_1/directory.c level_1/private-directory.c level_1/environment.c level_1/private-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/iki.c level_1/print.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/private-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/path.c level_2/program.c level_2/status.c
+build_sources_library level_0/account.c 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/fss.c level_0/iki.c level_0/memory.c level_0/path.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/serialize.c level_0/private-serialize.c level_0/socket.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/conversion.c level_1/directory.c level_1/private-directory.c level_1/environment.c level_1/private-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/iki.c level_1/print.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/private-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/path.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/directory_type.h level_0/environment.h level_0/file.h level_0/fss.h level_0/fss-common.h level_0/fss-named.h level_0/fss-nest.h level_0/fss-quoted.h level_0/fss-set.h level_0/iki.h level_0/iki-common.h level_0/memory.h level_0/memory-structure.h level_0/path.h level_0/pipe.h level_0/print.h level_0/serialize.h level_0/socket.h level_0/status.h level_0/status_array.h level_0/string.h level_0/string_common.h level_0/string_dynamic.h level_0/string_map.h level_0/string_quantity.h level_0/string_range.h level_0/type.h level_0/type_array.h level_0/utf.h level_0/utf-common.h level_1/color.h level_1/console.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/fss_status.h level_1/iki.h level_1/print.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/path.h level_2/program.h level_2/status.h
+build_sources_headers level_0/account.h level_0/color.h level_0/console.h level_0/conversion.h level_0/directory.h level_0/directory_type.h level_0/environment.h level_0/file.h level_0/fss.h level_0/fss-common.h level_0/fss-named.h level_0/fss-nest.h level_0/fss-quoted.h level_0/fss-set.h level_0/iki.h level_0/iki-common.h level_0/memory.h level_0/memory-structure.h level_0/path.h level_0/pipe.h level_0/print.h level_0/serialize.h level_0/socket.h level_0/status.h level_0/status_array.h level_0/string.h level_0/string_common.h level_0/string_dynamic.h level_0/string_map.h level_0/string_quantity.h level_0/string_range.h level_0/type.h level_0/type_array.h level_0/utf.h level_0/utf-common.h level_1/color.h level_1/console.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/fss_status.h level_1/iki.h level_1/print.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/path.h level_2/program.h level_2/status.h
build_sources_script
build_sources_setting
build_script yes
# Instead this provides a functional example on what commands to perform to perform the bootstrap.
#
# This only accepts a two arguments (both are required):
-# 1) One of "individual", "level", "monolithic", "fake-individual", "fake-level", or "fake-monolithic"..
+# 1) One of "individual", "level", "monolithic", "fake-individual", "fake-level", or "fake-monolithic".
# 2) The version number of the project, such as "0.5.0".
#
# This will create a directory at he present working directory of the script caller called "fll" where everything will be installed.
bash build/scripts/package.sh build -i
if [[ $? -eq 0 ]] ; then
- for i in f_type f_status f_memory f_string f_utf f_color f_console f_conversion f_directory f_environment f_file f_fss f_iki f_path f_pipe f_print f_serialize f_socket fl_color fl_console fl_conversion fl_directory fl_environment fl_fss fl_iki fl_print fl_status fl_string fl_utf fl_utf_file fll_execute fll_file fll_fss fll_path fll_program fll_status ; do
+ for i in f_type f_status f_memory f_string f_utf f_account f_color f_console f_conversion f_directory f_environment f_file f_fss f_iki f_path f_pipe f_print f_serialize f_socket fl_color fl_console fl_conversion fl_directory fl_environment fl_fss fl_iki fl_print fl_status fl_string fl_utf fl_utf_file fll_execute fll_file fll_fss fll_path fll_program fll_status ; do
echo && echo "Processing $i." &&
cd package/individual/$i-$2/ &&
--- /dev/null
+#include <level_0/account.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_f_account_id_group_by_name_
+ f_return_status f_account_id_group_by_name(const f_string name, gid_t *id) {
+ f_status status = F_none;
+
+ const size_t length_max = sysconf(_SC_GETPW_R_SIZE_MAX);
+
+ // note: pointer seems pointless except that it is used to determine if the name was found.
+ struct group grp;
+ struct group *pointer;
+
+ size_t length = length_max;
+
+ {
+ if (length == -1) {
+ length = f_account_pwd_length_fallback_first;
+ }
+
+ // must be set to 0 to avoid problems due to the design of getgrnam()/getgrnam_r().
+ errno = 0;
+
+ char buffer[length];
+ int result = getgrnam_r(name, &grp, buffer, length, &pointer);
+
+ if (result) {
+ if (errno == EINTR) return F_status_set_error(F_interrupted);
+ if (errno == EIO) return F_status_set_error(F_input_output);
+ if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
+ if (errno == ENFILE) return F_status_set_error(F_file_open_max);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+
+ if (errno == ERANGE) {
+ if (length_max > 0) return F_status_set_error(F_buffer_too_small);
+ }
+ else {
+ return F_status_set_error(F_failure);
+ }
+ }
+ else {
+ if (!pointer) {
+ return F_exist_not;
+ }
+
+ *id = grp.gr_gid;
+
+ return F_none;
+ }
+ }
+
+ length = f_account_pwd_length_fallback_second;
+
+ char buffer[f_account_pwd_length_fallback_second];
+
+ int result = getgrnam_r(name, &grp, buffer, length, &pointer);
+
+ if (result) {
+ if (errno == EINTR) return F_status_set_error(F_interrupted);
+ if (errno == EIO) return F_status_set_error(F_input_output);
+ if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
+ if (errno == ENFILE) return F_status_set_error(F_file_open_max);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+ if (errno == ERANGE) return F_status_set_error(F_buffer_too_small);
+
+ return F_status_set_error(F_failure);
+ }
+
+ if (!pointer) {
+ return F_exist_not;
+ }
+
+ *id = grp.gr_gid;
+
+ return F_none;
+ }
+#endif // _di_f_account_id_group_by_name_
+
+#ifndef _di_f_account_id_user_by_name_
+ f_return_status f_account_id_user_by_name(const f_string name, uid_t *id) {
+ f_status status = F_none;
+
+ const size_t length_max = sysconf(_SC_GETPW_R_SIZE_MAX);
+
+ // note: pointer seems pointless except that it is used to determine if the name was found.
+ struct passwd password;
+ struct passwd *pointer;
+
+ size_t length = length_max;
+
+ {
+ if (length == -1) {
+ length = f_account_pwd_length_fallback_first;
+ }
+
+ // must be set to 0 to avoid problems due to the design of getpwnam()/getpwnam_r().
+ errno = 0;
+
+ char buffer[length];
+ int result = getpwnam_r(name, &password, buffer, length, &pointer);
+
+ if (result) {
+ if (errno == EINTR) return F_status_set_error(F_interrupted);
+ if (errno == EIO) return F_status_set_error(F_input_output);
+ if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
+ if (errno == ENFILE) return F_status_set_error(F_file_open_max);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+
+ if (errno == ERANGE) {
+ if (length_max > 0) return F_status_set_error(F_buffer_too_small);
+ }
+ else {
+ return F_status_set_error(F_failure);
+ }
+ }
+ else {
+ if (!pointer) {
+ return F_exist_not;
+ }
+
+ *id = password.pw_uid;
+
+ return F_none;
+ }
+ }
+
+ length = f_account_pwd_length_fallback_second;
+
+ char buffer[f_account_pwd_length_fallback_second];
+
+ int result = getpwnam_r(name, &password, buffer, length, &pointer);
+
+ if (result) {
+ if (errno == EINTR) return F_status_set_error(F_interrupted);
+ if (errno == EIO) return F_status_set_error(F_input_output);
+ if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
+ if (errno == ENFILE) return F_status_set_error(F_file_open_max);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+ if (errno == ERANGE) return F_status_set_error(F_buffer_too_small);
+
+ return F_status_set_error(F_failure);
+ }
+
+ if (!pointer) {
+ return F_exist_not;
+ }
+
+ *id = password.pw_uid;
+
+ return F_none;
+ }
+#endif // _di_f_account_id_user_by_name_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Pipe
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * Provides account related functionality (users, groups, roles, etc..).
+ *
+ * @todo POSIX as of POSIX.1-2001, at least getpwnam() does not call "not found" an error.
+ * For now, using getpwnam_r() in place of getpwnam() (and similar) seems the safest way to avoid this bad design.
+ */
+#ifndef _F_account_h
+#define _F_account_h
+
+// libc includes
+#include <sys/types.h>
+#include <grp.h>
+#include <pwd.h>
+#include <unistd.h>
+
+// fll-0 includes
+#include <level_0/type.h>
+#include <level_0/status.h>
+#include <level_0/memory.h>
+#include <level_0/string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Custom defines for f_account.
+ *
+ * f_account_pwd_length_fallback_first: provide a fallback max length for when sysconf(_SC_GETPW_R_SIZE_MAX) return -1 (aka: infinite).
+ * f_account_pwd_length_fallback_second: provide a fallback max length for when f_account_pwd_length_fallback_first is too small.
+ */
+#ifndef _di_f_account_defines_
+ #define f_account_pwd_length_fallback_first 8192
+ #define f_account_pwd_length_fallback_second 32767
+#endif // _di_f_account_defines_
+
+/**
+ * Get the group account id by the group name.
+ *
+ * @param name
+ * The group name.
+ * @param id
+ * The id associated with the given name.
+ *
+ * @return
+ * F_none on success.
+ * F_buffer_too_small (with error bit) if the buffer is too small to store the account data.
+ * F_exist_non if no group by that name exists.
+ * F_file_descriptor_max (with error bit) if max file descriptors was reached.
+ * F_file_open_max (with error bit) too many open files.
+ * F_input_output (with error bit) if an I/O error occurred.
+ * F_interrupted (with error bit) when program received an interrupt signal, halting operation.
+ * F_memory_out (with error bit) if out of memory.
+ * F_parameter (with error bit) if a parameter is invalid.
+ * F_failure (with error bit) on any other failure.
+ *
+ * @see getgrnam_r()
+ */
+#ifndef _di_f_account_id_group_by_name_
+ extern f_return_status f_account_id_group_by_name(const f_string name, gid_t *id);
+#endif // _di_f_account_id_group_by_name_
+
+/**
+ * Get the user account id by the user name.
+ *
+ * @param name
+ * The user name.
+ * @param id
+ * The id associated with the given name.
+ *
+ * @return
+ * F_none on success.
+ * F_buffer_too_small (with error bit) if the buffer is too small to store the account data.
+ * F_exist_non if no user by that name exists.
+ * F_file_descriptor_max (with error bit) if max file descriptors was reached.
+ * F_file_open_max (with error bit) too many open files.
+ * F_input_output (with error bit) if an I/O error occurred.
+ * F_interrupted (with error bit) when program received an interrupt signal, halting operation.
+ * F_memory_out (with error bit) if out of memory.
+ * F_parameter (with error bit) if a parameter is invalid.
+ * F_failure (with error bit) on any other failure.
+ *
+ * @see getpwnam_r()
+ */
+#ifndef _di_f_account_id_user_by_name_
+ extern f_return_status f_account_id_user_by_name(const f_string name, uid_t *id);
+#endif // _di_f_account_id_user_by_name_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _F_account_h
--- /dev/null
+# fss-0000
+
--- /dev/null
+# fss-0000
+
+f_type
+f_status
+f_memory
+f_string
--- /dev/null
+# fss-0001
+
+project_name f_account
+
+version_major 0
+version_minor 5
+version_micro 0
+version_target major
+
+environment
+
+process_pre
+process_post
+
+modes individual
+modes_default individual
+
+build_compiler gcc
+build_language c
+build_linker ar
+build_libraries -lc
+build_libraries-individual
+build_sources_library account.c
+build_sources_program
+build_sources_headers account.h
+build_sources_script
+build_sources_setting
+build_script yes
+build_shared yes
+build_static yes
+
+path_headers level_0
+path_library_script script
+path_library_shared shared
+path_library_static static
+path_program_script script
+path_program_shared shared
+path_program_static static
+
+search_exclusive yes
+search_shared yes
+search_static yes
+
+defines_all
+defines_static
+defines_shared
+
+flags_all -z now -g
+flags_shared
+flags_static
+flags_library -fPIC
+flags_program -fPIE
}
#endif // _di_f_file_flush_
+#ifndef _di_f_file_is_
+ f_return_status f_file_is(const f_string path, const int type) {
+ #ifndef _di_level_0_parameter_checking_
+ if (path == 0) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ 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_name);
+ if (errno == EFAULT) return F_status_set_error(F_buffer);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+ if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
+ if (errno == ENOTDIR) return F_status_set_error(F_directory);
+ if (errno == ENOENT) return F_file_found_not;
+ if (errno == EACCES) return F_status_set_error(F_access_denied);
+ if (errno == ELOOP) return F_status_set_error(F_loop);
+
+ return F_status_set_error(F_file_stat);
+ }
+
+ if (f_macro_file_type_get(file_stat.st_mode) == type) return F_true;
+
+ return F_false;
+ }
+#endif // _di_f_file_is_
+
+#ifndef _di_f_file_is_at_
+ f_return_status f_file_is_at(const int at_id, const f_string path, const int type, const int flag) {
+ #ifndef _di_level_0_parameter_checking_
+ if (path == 0) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ struct stat file_stat;
+
+ memset(&file_stat, 0, sizeof(struct stat));
+
+ if (fstatat(at_id, path, &file_stat, flag) < 0) {
+ if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+ if (errno == EFAULT) return F_status_set_error(F_buffer);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+ if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
+ if (errno == ENOTDIR) return F_status_set_error(F_directory);
+ if (errno == ENOENT) return F_file_found_not;
+ if (errno == EACCES) return F_status_set_error(F_access_denied);
+ if (errno == ELOOP) return F_status_set_error(F_loop);
+ if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
+
+ return F_status_set_error(F_file_stat);
+ }
+
+ if (file_stat.st_mode == (S_IFMT & S_IFDIR)) return F_true;
+
+ return F_false;
+ }
+#endif // _di_f_file_is_at_
+
#ifndef _di_f_file_link_
f_return_status f_file_link(const f_string target, const f_string point) {
#ifndef _di_level_0_parameter_checking_
}
#endif // _di_f_file_link_read_at_
-#ifndef _di_f_file_is_
- f_return_status f_file_is(const f_string path, const int type) {
+#ifndef _di_f_file_mode_from_string_
+ f_return_status f_file_mode_from_string(const f_string string, f_file_mode *mode, uint8_t *replace) {
#ifndef _di_level_0_parameter_checking_
- if (path == 0) return F_status_set_error(F_parameter);
+ if (string == 0) return F_status_set_error(F_parameter);
+ if (string[0] == 0) return F_status_set_error(F_parameter);
+ if (mode == 0) return F_status_set_error(F_parameter);
+ if (replace == 0) return F_status_set_error(F_parameter);
#endif // _di_level_0_parameter_checking_
- struct stat file_stat;
-
- memset(&file_stat, 0, sizeof(struct stat));
+ uint8_t syntax = 0;
+
+ *mode = 0;
+ *replace = 0;
+
+ switch (string[0]) {
+
+ case '+':
+ case '-':
+ case '=':
+ switch (string[1]) {
+
+ case 'r':
+ case 'w':
+ case 'x':
+ case 'X':
+ case 's':
+ case 't':
+ syntax = 1;
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ syntax = 2;
+ break;
+
+ default:
+ return F_status_set_error(F_syntax);
+ }
- if (stat(path, &file_stat) < 0) {
- if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
- if (errno == EFAULT) return F_status_set_error(F_buffer);
- if (errno == ENOMEM) return F_status_set_error(F_memory_out);
- if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
- if (errno == ENOTDIR) return F_status_set_error(F_directory);
- if (errno == ENOENT) return F_file_found_not;
- if (errno == EACCES) return F_status_set_error(F_access_denied);
- if (errno == ELOOP) return F_status_set_error(F_loop);
+ syntax = 1;
+ break;
+
+ case 'u':
+ case 'g':
+ case 'o':
+ case 'a':
+ syntax = 1;
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ syntax = 2;
+ break;
+
+ default:
+ return F_status_set_error(F_syntax);
+ }
- return F_status_set_error(F_file_stat);
+ if (syntax == 1) {
+ uint8_t on = 0; // 1 = user, 2 = group, 4 = world/sticky, 7 = all.
+ uint8_t how = 0; // 1 = add, 2 = replace, 3 = subtract, 4 = umask add, 5 = umask replace, 6 = umask subtract.
+ bool active = F_false;
+
+ f_file_mode mask = 0;
+ f_file_mode what = 0;
+
+ for (f_string_length i = 0; syntax && i < string[i]; i++) {
+
+ switch (string[i]) {
+ case 'o':
+ if (active) {
+ syntax = 0;
+ break;
+ }
+
+ on = 1;
+ mask |= f_file_mode_block_world;
+ break;
+
+ case 'g':
+ if (active) {
+ syntax = 0;
+ break;
+ }
+
+ on = 2;
+ mask |= f_file_mode_block_group;
+ break;
+
+ case 'u':
+ if (active) {
+ syntax = 0;
+ break;
+ }
+
+ on = 4;
+ mask |= f_file_mode_block_owner;
+ break;
+
+ case 'a':
+ if (active) {
+ syntax = 0;
+ break;
+ }
+
+ on = 7;
+ mask = f_file_mode_block_owner | f_file_mode_block_group | f_file_mode_block_world;
+ break;
+
+ case '+':
+ case '-':
+ case '=':
+ active = F_true;
+
+ if (string[i] == '+') {
+ how = on ? 1 : 4;
+ }
+ else if (string[i] == '-') {
+ how = on ? 3 : 6;
+ }
+ else {
+ how = on ? 2 : 5;
+
+ // only the parts designated by the mask should be replaced.
+ *mode -= (*mode) & mask;
+ }
+
+ if (!on) {
+ on = 7;
+ mask = f_file_mode_block_owner | f_file_mode_block_group | f_file_mode_block_world;
+ }
+
+ for (i++; i < string[i]; i++) {
+
+ if (string[i] == 'r') {
+ what = f_file_mode_mask_bit_read;
+ }
+ else if (string[i] == 'w') {
+ what = f_file_mode_mask_bit_write;
+ }
+ else if (string[i] == 'x') {
+ what = f_file_mode_mask_bit_execute;
+ }
+ else if (string[i] == 'X') {
+ what = f_file_mode_mask_bit_execute_only;
+ }
+ else if (string[i] == 's') {
+ if (on & 4) {
+ what = f_file_mode_mask_bit_set_owner;
+ }
+ else if (on & 2) {
+ what = f_file_mode_mask_bit_set_group;
+ }
+ else {
+ what = 0;
+ }
+ }
+ else if (string[i] == 't') {
+ if (on & 1) {
+ what = f_file_mode_mask_bit_sticky;
+ }
+ else {
+ what = 0;
+ }
+ }
+ else if (string[i] == ',') {
+ active = F_false;
+ on = 0;
+ how = 0;
+ mask = 0;
+ break;
+ }
+ else if (string[i] == '+' || string[i] == '-' || string[i] == '=') {
+ // have the outer loop resume at this character after it increments.
+ i--;
+ break;
+ }
+ else {
+ syntax = 0;
+ break;
+ }
+
+ if (how == 1 || how == 2) {
+ *mode |= what & mask & f_file_mode_mask_how_add;
+ }
+ else if (how == 3) {
+ *mode |= what & mask & f_file_mode_mask_how_subtract;
+ }
+ else if (how == 4 || how == 5) {
+ *mode |= what & mask & f_file_mode_mask_how_umask_add;
+ }
+ else if (how == 6) {
+ *mode |= what & mask & f_file_mode_mask_how_umask_subtract;
+ }
+ } // for
+
+ break;
+
+ default:
+ syntax = 0;
+ break;
+ }
+ } // for
}
+ else if (syntax == 2) {
+ // 1 = add, 2 = replace, 3 = subtract, 4 = umask add, 5 = umask replace, 6 = umask subtract.
+ uint8_t how = 0;
- if (f_macro_file_type_get(file_stat.st_mode) == type) return F_true;
+ mode_t classic = 0;
- return F_false;
- }
-#endif // _di_f_file_is_
+ f_string_length i = 0;
-#ifndef _di_f_file_is_at_
- f_return_status f_file_is_at(const int at_id, const f_string path, const int type, const int flag) {
- #ifndef _di_level_0_parameter_checking_
- if (path == 0) return F_status_set_error(F_parameter);
- #endif // _di_level_0_parameter_checking_
+ if (string[0] == '+') {
+ how = 1;
+ i = 1;
+ }
+ else if (string[0] == '-') {
+ how = 3;
+ i = 1;
+ }
+ else if (string[0] == '=' || string[0] == '0') {
+ how = 2;
+ i = 1;
+ }
+ else {
+ how = 5;
+ }
- struct stat file_stat;
+ for (; string[i] == '0'; i++) {
+ // seek past leading '0's.
+ } // for
- memset(&file_stat, 0, sizeof(struct stat));
+ if (string[i]) {
+ f_string_length j = 0;
- if (fstatat(at_id, path, &file_stat, flag) < 0) {
- if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
- if (errno == EFAULT) return F_status_set_error(F_buffer);
- if (errno == ENOMEM) return F_status_set_error(F_memory_out);
- if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
- if (errno == ENOTDIR) return F_status_set_error(F_directory);
- if (errno == ENOENT) return F_file_found_not;
- if (errno == EACCES) return F_status_set_error(F_access_denied);
- if (errno == ELOOP) return F_status_set_error(F_loop);
- if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
+ for (; string[i + j] && j < 4; j++) {
- return F_status_set_error(F_file_stat);
+ if (j) {
+ classic <<= 3;
+ }
+
+ switch (string[i]) {
+ case '0':
+ // already is a zero.
+ break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ // this assumes ASCII/UTF-8.
+ classic |= string[i] - 0x30;
+
+ break;
+
+ default:
+ j = 4;
+ break;
+ }
+ } // for
+
+ if (j == 4) {
+ syntax = 0;
+ }
+
+ // @fixme: classic is a different structure than mode masks, properly expand. (maybe just use f_file_mode instead of classic and shift by 6 instead of 3.)
+ if (syntax) {
+ if (how == 1) {
+ *mode = classic & f_file_mode_mask_how_add;
+ }
+ else if (how == 2) {
+ *mode = classic & f_file_mode_mask_how_add;
+ *replace = f_file_mode_replace_all;
+ }
+ else if (how == 3) {
+ *mode = classic & f_file_mode_mask_how_subtract;
+ }
+ else if (how == 5) {
+ *mode = classic & f_file_mode_mask_how_add;
+ *replace = f_file_mode_replace_umask_all;
+ }
+ }
+ }
+ else {
+ *replace = f_file_mode_replace_all;
+ }
}
- if (file_stat.st_mode == (S_IFMT & S_IFDIR)) return F_true;
+ if (syntax) {
+ return F_none;
+ }
- return F_false;
+ *mode = 0;
+ *replace = 0;
+
+ return F_status_set_error(F_syntax);
}
-#endif // _di_f_file_is_at_
+#endif // _di_f_file_mode_from_string_
+
+// @todo: needs f_file_mode_to_mode_t() to convert f_file_mode to a mode_t (requires f_file_mode, a source mode_t, and a destination mode_t).
#ifndef _di_f_file_name_base_
f_return_status f_file_name_base(const f_string path, const f_string_length length, f_string_dynamic *name_base) {
/**
* File mode related functionality.
+ *
+ * The f_file_mode type properties are 8-bit types with the following structure:
+ * @todo finish documentation.
+ *
+ * There should only be a single bit for each 'r', 'w', 'x', and 'X' bit (as well as 'S', 's', and 't'):
+ * 'r' = read bit.
+ * 'w' = write bit.
+ * 'x' = execute bit.
+ * 'X' = execute only if already execute bit.
+ * 'S' = set user bit (setuid).
+ * 's' = set group bit (setgid).
+ * 't' = sticky bit.
*/
#ifndef _di_f_file_mode_
+ typedef uint32_t f_file_mode;
+
+ #define f_file_mode_block_special 0x77000000 // 0111 0111 0000 0000 0000 0000 0000 0000
+ #define f_file_mode_block_owner 0x00ff0000 // 0000 0000 1111 1111 0000 0000 0000 0000
+ #define f_file_mode_block_group 0x0000ff00 // 0000 0000 0000 0000 1111 1111 0000 0000
+ #define f_file_mode_block_world 0x000000ff // 0000 0000 0000 0000 0000 0000 1111 1111
+ #define f_file_mode_block_all 0x77ffffff // 0111 0111 1111 1111 1111 1111 1111 1111
+
+ #define f_file_mode_mask_how_add 0x070f0f0f // 0000 0111 0000 1111 0000 1111 0000 1111
+ #define f_file_mode_mask_how_subtract 0x70f0f0f0 // 0111 0000 1111 0000 1111 0000 1111 0000
+ #define f_file_mode_mask_how_umask_add 0x0f0f0f0f // 0000 1111 0000 1111 0000 1111 0000 1111
+ #define f_file_mode_mask_how_umask_subtract 0x78f0f0f0 // 0111 1000 1111 0000 1111 0000 1111 0000
+
+ #define f_file_mode_mask_bit_execute 0x00111111 // 0000 0000 0001 0001 0001 0001 0001 0001
+ #define f_file_mode_mask_bit_execute_only 0x00888888 // 0000 0000 1000 1000 1000 1000 1000 1000
+ #define f_file_mode_mask_bit_read 0x00444444 // 0000 0000 0100 0100 0100 0100 0100 0100
+ #define f_file_mode_mask_bit_set_group 0x22000000 // 0010 0010 0000 0000 0000 0000 0000 0000
+ #define f_file_mode_mask_bit_set_owner 0x44000000 // 0100 0100 0000 0000 0000 0000 0000 0000
+ #define f_file_mode_mask_bit_sticky 0x11000000 // 0001 0001 0000 0000 0000 0000 0000 0000
+ #define f_file_mode_mask_bit_write 0x00222222 // 0000 0000 0010 0010 0010 0010 0010 0010
+
+ #define f_file_mode_replace_owner 0x1 // 0000 0001
+ #define f_file_mode_replace_group 0x2 // 0000 0010
+ #define f_file_mode_replace_world 0x4 // 0000 0100
+ #define f_file_mode_replace_umask_owner 0x8 // 0000 1000
+ #define f_file_mode_replace_umask_group 0x10 // 0001 0000
+ #define f_file_mode_replace_umask_world 0x20 // 0010 0000
+
+ #define f_file_mode_replace_all 0x7 // 0000 0111
+ #define f_file_mode_replace_umask_all 0x38 // 0011 1000
// file permission modes.
#define f_file_mode_owner_rwx S_IRWXU
#endif // _di_f_file_is_at_
/**
- * Get the base name of a file path.
- *
- * @param path
- * The path file name.
- * Need not be NULL terminated.
- * @param length
- * The length of the path string.
- * @param name_base
- * The resulting base name as per basename().
- * The base name is appended onto this.
- *
- * @return
- * F_none on success.
- * F_memory_reallocation (with error bit) on memory reallocation error.
- * F_parameter (with error bit) if a parameter is invalid.
- * F_string_too_large (with error bit) if string is too large to store in the buffer.
- *
- * @see basename()
- */
-#ifndef _di_f_file_name_base_
- extern f_return_status f_file_name_base(const f_string path, const f_string_length length, f_string_dynamic *name_base);
-#endif // _di_f_file_name_base_
-
-/**
- * Get the directory name of a file path.
- *
- * @param path
- * The path file name.
- * Need not be NULL terminated.
- * @param length
- * The length of the path string.
- * @param name_directory
- * The resulting base name as per dirname().
- * The directory name is appended onto this.
- *
- * @return
- * F_none on success.
- * F_memory_reallocation (with error bit) on memory reallocation error.
- * F_parameter (with error bit) if a parameter is invalid.
- * F_string_too_large (with error bit) if string is too large to store in the buffer.
- *
- * @see dirname()
- */
-#ifndef _di_f_file_name_directory_
- extern f_return_status f_file_name_directory(const f_string path, const f_string_length length, f_string_dynamic *name_directory);
-#endif // _di_f_file_name_directory_
-
-/**
* Create a symbolic link to a file.
*
* This will not replace existing files/links.
#endif // _di_f_file_link_read_at_
/**
+ * Get the file mode id from a string syntax.
+ *
+ * The string syntax is defined as follows:
+ * '([ugoa]*[-+=]{0,1}([rwxXst]|[ugo])+([,][ugoa]*[-+=]{0,1}([rwxXst]|[ugo])+)*)|([-+=]0*[0-7]{1,4})'.
+ *
+ * Such that:
+ * 'u' = apply to user.
+ * 'g' = apply to group.
+ * 'o' = apply to other/world.
+ * 'a' = apply to all (user, group, and other/world).
+ * '-' = remove the specified modes.
+ * '+' = add the specified modes.
+ * '=' = overwrite all existing modes with this set.
+ * 'r' = read mode.
+ * 'w' = write mode.
+ * 'x' = execute mode.
+ * 'X' = execute mode, only if already executable.
+ * 's' = set-gid/set-uid mode.
+ * 't' = sticky-bit mode.
+ * '0' = no mode.
+ * '1' = execute mode.
+ * '2' = write mode.
+ * '3' = execute and write mode.
+ * '4' = read mode.
+ * '5' = execute and read mode.
+ * '6' = read and write mode.
+ * '7' = execute, read, and write mode.
+ *
+ * When there are 4 digits with a non-zero leading digit (such as 2000 or 002000):
+ * '1' = sticky-bit mode.
+ * '2' = set-gid mode.
+ * '3' = sticky-bit and set-gid mode.
+ * '4' = set-uid mode.
+ * '5' = sticky-bit and set-uid mode.
+ * '6' = set-uid and set-gid mode.
+ * '7' = sticky-bit, set-uid, and set-gid mode.
+ *
+ * When using digits, each set of 0-7 represents the following:
+ * [1-7] = apply to other/world.
+ * [1-7][0-7] = first ([1-7]) to group and second ([0-7]) to other/world.
+ * [1-7][0-7][0-7] = first ([1-7]) to owner, second ([0-7]) to group, and third ([0-7]) to other/world.
+ * [1-7][0-7][0-7][0-7] = first ([1-7]) to stick/set-uid/set-gid, second ([0-7]) to owner, third ([0-7]) to owner, and fourth ([0-7]) to other/world.
+ *
+ * When there is a leading 0 when using digits, then this mask will ignore the current umask settings.
+ * Otherwise, the current umask is intended to be respected.
+ *
+ * When '+', '-', or '=' are specified without a leading 'a', 'u', 'g', or 'o', then the mode operations should be performed against the current umask.
+ * These are designated with the umask hows, such as f_file_mode_how_umask_replace.
+ *
+ * @param string
+ * A NULL terminated string designating the desired mode, following the above string syntax.
+ * @param mode
+ * The determined mode.
+ * This uses bitwise data.
+ * @param replace
+ * The determined modes that are to be replaced, such as: f_file_mode_replace_owner.
+ * This uses bitwise data.
+ *
+ * @return
+ * F_none on success.
+ * F_parameter (with error bit) if a parameter is invalid.
+ * F_syntax (with error bit) if the string fails to follow the syntax rules.
+ *
+ * The parameters how, mode_normal, and mode_executable are all set to 0 on error.
+ */
+#ifndef _di_f_file_mode_from_string_
+ extern f_return_status f_file_mode_from_string(const f_string string, f_file_mode *mode, uint8_t *replace);
+#endif // _di_f_file_mode_from_string_
+
+/**
+ * Get the base name of a file path.
+ *
+ * @param path
+ * The path file name.
+ * Need not be NULL terminated.
+ * @param length
+ * The length of the path string.
+ * @param name_base
+ * The resulting base name as per basename().
+ * The base name is appended onto this.
+ *
+ * @return
+ * F_none on success.
+ * F_memory_reallocation (with error bit) on memory reallocation error.
+ * F_parameter (with error bit) if a parameter is invalid.
+ * F_string_too_large (with error bit) if string is too large to store in the buffer.
+ *
+ * @see basename()
+ */
+#ifndef _di_f_file_name_base_
+ extern f_return_status f_file_name_base(const f_string path, const f_string_length length, f_string_dynamic *name_base);
+#endif // _di_f_file_name_base_
+
+/**
+ * Get the directory name of a file path.
+ *
+ * @param path
+ * The path file name.
+ * Need not be NULL terminated.
+ * @param length
+ * The length of the path string.
+ * @param name_directory
+ * The resulting base name as per dirname().
+ * The directory name is appended onto this.
+ *
+ * @return
+ * F_none on success.
+ * F_memory_reallocation (with error bit) on memory reallocation error.
+ * F_parameter (with error bit) if a parameter is invalid.
+ * F_string_too_large (with error bit) if string is too large to store in the buffer.
+ *
+ * @see dirname()
+ */
+#ifndef _di_f_file_name_directory_
+ extern f_return_status f_file_name_directory(const f_string path, const f_string_length length, f_string_dynamic *name_directory);
+#endif // _di_f_file_name_directory_
+
+/**
* Open a particular file and save its stream.
*
* This will open the file and obtain the file descriptor.
#endif // _di_f_file_stat_by_id_
/**
- * Write until entire buffer is written.
- *
- * @param file
- * The file to write to.
- * The file must already be open.
- * @param buffer
- * The buffer to write to the file.
- * @param written
- * The total bytes written.
- * Set pointer to 0 to not use.
- *
- * @return
- * F_none on success.
- * F_none_stop on success but no data was written (written == 0) (not an error and often happens if file type is not a regular file).
- * F_block (with error bit) if file descriptor is set to non-block and the write would result in a blocking operation.
- * F_buffer (with error bit) if the buffer is invalid.
- * F_file (with error bit) if file descriptor is in an error state.
- * F_file_closed (with error bit) if file is not open.
- * F_file_descriptor (with error bit) if the file descriptor is invalid.
- * F_file_type_directory (with error bit) if file descriptor represents a directory.
- * F_input_output (with error bit) on I/O error.
- * F_interrupted (with error bit) if interrupt was received.
- * F_parameter (with error bit) if a parameter is invalid.
- *
- * @see write()
- */
-#ifndef _di_f_file_write_
- extern f_return_status f_file_write(const f_file file, const f_string_static buffer, f_string_length *written);
-#endif // _di_f_file_write_
-
-/**
* Update the files access and modification timestamp, creating the file if it does not already exist.
*
* When the file is created, it is created as a regular file.
#endif // _di_f_file_type_at_
/**
+ * Write until entire buffer is written.
+ *
+ * @param file
+ * The file to write to.
+ * The file must already be open.
+ * @param buffer
+ * The buffer to write to the file.
+ * @param written
+ * The total bytes written.
+ * Set pointer to 0 to not use.
+ *
+ * @return
+ * F_none on success.
+ * F_none_stop on success but no data was written (written == 0) (not an error and often happens if file type is not a regular file).
+ * F_block (with error bit) if file descriptor is set to non-block and the write would result in a blocking operation.
+ * F_buffer (with error bit) if the buffer is invalid.
+ * F_file (with error bit) if file descriptor is in an error state.
+ * F_file_closed (with error bit) if file is not open.
+ * F_file_descriptor (with error bit) if the file descriptor is invalid.
+ * F_file_type_directory (with error bit) if file descriptor represents a directory.
+ * F_input_output (with error bit) on I/O error.
+ * F_interrupted (with error bit) if interrupt was received.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see write()
+ */
+#ifndef _di_f_file_write_
+ extern f_return_status f_file_write(const f_file file, const f_string_static buffer, f_string_length *written);
+#endif // _di_f_file_write_
+
+/**
* Write until a single block is filled or entire buffer is written.
*
* To check how much was write into the buffer, record buffer->used before execution and compare to buffer->used after execution.
#include <sys/stat.h>
// fll-0 includes
-#include <level_0/status.h>
#include <level_0/type.h>
+#include <level_0/status.h>
#ifdef __cplusplus
extern "C" {
#include <level_0/memory.h>
#include <level_0/string.h>
#include <level_0/utf.h>
+#include <level_0/account.h>
#include <level_0/console.h>
#include <level_0/directory.h>
#include <level_0/environment.h>
}
#endif // _di_fake_make_assure_inside_project_
+#ifndef _di_fake_make_get_id_group_
+ f_return_status fake_make_get_id_group(const fake_data data, const f_string_static buffer, gid_t *id) {
+ const f_string_range range = f_macro_string_range_initialize(buffer.used);
+
+ f_number_unsigned number = 0;
+
+ f_status status = fl_conversion_string_to_number_unsigned(buffer.string, &number, range);
+
+ if (F_status_is_error(status)) {
+ status = F_status_set_fine(status);
+
+ if (status == F_number) {
+ status = f_account_id_group_by_name(buffer.string, id);
+
+ if (F_status_is_error(status)) {
+ fake_print_error(data, status, "f_account_id_group_by_name", F_true);
+ return F_status_set_error(status);
+ }
+ else if (status == F_exist_not) {
+ if (data.verbosity != fake_verbosity_quiet) {
+ fprintf(f_type_error, "%c", f_string_eol[0]);
+ fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: The group name '");
+ fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", buffer.string);
+ fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' was not found.");
+ }
+
+ return F_status_set_error(F_failure);
+ }
+
+ return F_none;
+ }
+
+ fake_print_error(data, status, "fl_conversion_string_to_number_unsigned", F_true);
+ return F_status_set_error(status);
+ }
+ else if (number > f_type_size_32_unsigned) {
+ if (data.verbosity != fake_verbosity_quiet) {
+ fprintf(f_type_error, "%c", f_string_eol[0]);
+ fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: The number '");
+ fl_color_print(f_type_error, data.context.notable, data.context.reset, "%llu", number);
+ fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' is too large.");
+ }
+ }
+
+ *id = (gid_t) number;
+ return status;
+ }
+#endif // _di_fake_make_get_id_group_
+
+#ifndef _di_fake_make_get_id_mode_
+ f_return_status fake_make_get_id_mode(const fake_data data, const f_string_static buffer, f_file_mode *mode, uint8_t *replace) {
+ if (!buffer.used) {
+ fake_print_error(data, F_parameter, "fake_make_get_id_mode", F_true);
+ return F_status_set_error(F_parameter);
+ }
+
+ f_status status = f_file_mode_from_string(buffer.string, mode, replace);
+
+ if (F_status_is_error(status)) {
+ if (data.verbosity != fake_verbosity_quiet) {
+ if (F_status_set_fine(status) == F_syntax) {
+ fprintf(f_type_error, "%c", f_string_eol[0]);
+ fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: The mode '");
+ fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", buffer.string);
+ fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' is invalid.");
+ }
+ else {
+ fake_print_error(data, status, "f_file_mode_from_string", F_true);
+ }
+ }
+
+ return status;
+ }
+
+ return F_none;
+ }
+#endif // _di_fake_make_get_id_mode_
+
+#ifndef _di_fake_make_get_id_owner_
+ f_return_status fake_make_get_id_owner(const fake_data data, const f_string_static buffer, uid_t *id) {
+ const f_string_range range = f_macro_string_range_initialize(buffer.used);
+
+ f_number_unsigned number = 0;
+
+ f_status status = fl_conversion_string_to_number_unsigned(buffer.string, &number, range);
+
+ if (F_status_is_error(status)) {
+ status = F_status_set_fine(status);
+
+ if (status == F_number) {
+ status = f_account_id_user_by_name(buffer.string, id);
+
+ if (F_status_is_error(status)) {
+ fake_print_error(data, status, "f_account_id_user_by_name", F_true);
+ return F_status_set_error(status);
+ }
+ else if (status == F_exist_not) {
+ if (data.verbosity != fake_verbosity_quiet) {
+ fprintf(f_type_error, "%c", f_string_eol[0]);
+ fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: The user name '");
+ fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", buffer.string);
+ fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' was not found.");
+ }
+
+ return F_status_set_error(F_failure);
+ }
+
+ return F_none;
+ }
+
+ fake_print_error(data, status, "fl_conversion_string_to_number_unsigned", F_true);
+ return F_status_set_error(status);
+ }
+ else if (number > f_type_size_32_unsigned) {
+ if (data.verbosity != fake_verbosity_quiet) {
+ fprintf(f_type_error, "%c", f_string_eol[0]);
+ fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: The number '");
+ fl_color_print(f_type_error, data.context.notable, data.context.reset, "%llu", number);
+ fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' is too large.");
+ }
+ }
+
+ *id = (uid_t) number;
+ return status;
+ }
+#endif // _di_fake_make_get_id_owner_
+
#ifndef _di_fake_make_load_fakefile_
void fake_make_load_fakefile(const fake_data data, fake_make_data *data_make, f_status *status) {
if (F_status_is_error(*status)) return;
f_macro_string_static_initialize(fake_make_operation_else, fake_make_operation_else_length),
f_macro_string_static_initialize(fake_make_operation_fail, fake_make_operation_fail_length),
f_macro_string_static_initialize(fake_make_operation_group, fake_make_operation_group_length),
+ f_macro_string_static_initialize(fake_make_operation_group, fake_make_operation_groups_length),
f_macro_string_static_initialize(fake_make_operation_if, fake_make_operation_if_length),
f_macro_string_static_initialize(fake_make_operation_link, fake_make_operation_link_length),
f_macro_string_static_initialize(fake_make_operation_mode, fake_make_operation_mode_length),
+ f_macro_string_static_initialize(fake_make_operation_mode, fake_make_operation_modes_length),
f_macro_string_static_initialize(fake_make_operation_operate, fake_make_operation_operate_length),
f_macro_string_static_initialize(fake_make_operation_owner, fake_make_operation_owner_length),
+ f_macro_string_static_initialize(fake_make_operation_owner, fake_make_operation_owners_length),
f_macro_string_static_initialize(fake_make_operation_pop, fake_make_operation_pop_length),
f_macro_string_static_initialize(fake_make_operation_print, fake_make_operation_print_length),
f_macro_string_static_initialize(fake_make_operation_run, fake_make_operation_run_length),
f_macro_string_range_initialize(fake_make_operation_else_length),
f_macro_string_range_initialize(fake_make_operation_fail_length),
f_macro_string_range_initialize(fake_make_operation_group_length),
+ f_macro_string_range_initialize(fake_make_operation_groups_length),
f_macro_string_range_initialize(fake_make_operation_if_length),
f_macro_string_range_initialize(fake_make_operation_link_length),
f_macro_string_range_initialize(fake_make_operation_mode_length),
+ f_macro_string_range_initialize(fake_make_operation_modes_length),
f_macro_string_range_initialize(fake_make_operation_operate_length),
f_macro_string_range_initialize(fake_make_operation_owner_length),
+ f_macro_string_range_initialize(fake_make_operation_owners_length),
f_macro_string_range_initialize(fake_make_operation_pop_length),
f_macro_string_range_initialize(fake_make_operation_print_length),
f_macro_string_range_initialize(fake_make_operation_run_length),
fake_make_operation_type_else,
fake_make_operation_type_fail,
fake_make_operation_type_group,
+ fake_make_operation_type_groups,
fake_make_operation_type_if,
fake_make_operation_type_link,
fake_make_operation_type_mode,
+ fake_make_operation_type_modes,
fake_make_operation_type_operate,
fake_make_operation_type_owner,
+ fake_make_operation_type_owners,
fake_make_operation_type_pop,
fake_make_operation_type_print,
fake_make_operation_type_run,
}
if (operation == fake_make_operation_type_group) {
- // fake_make_assure_inside_project
- // *status = fll_execute_arguments_add(values[i], lengths[i], &arguments);
- //fake_build_arguments_standard_add(data, data_build, F_true, F_true, &arguments, status);
- //fake_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status);
+ gid_t id = 0;
+
+ *status = fake_make_get_id_group(data, arguments.array[0], &id);
+ if (F_status_is_error(*status)) return;
+
+ for (f_array_length i = 1; i < arguments.used; i++) {
+ *status = f_file_change_role(arguments.array[i].string, -1, id, F_false);
+ if (F_status_is_error(*status)) {
+ fake_print_error_file(data, *status, "f_file_change_role", arguments.array[i].string, "change group of", F_true, F_true);
+ }
+ } // for
+
+ return;
+ }
+
+ if (operation == fake_make_operation_type_groups) {
+ gid_t id = 0;
+
+ *status = fake_make_get_id_group(data, arguments.array[0], &id);
+ if (F_status_is_error(*status)) return;
+
+ for (f_array_length i = 1; i < arguments.used; i++) {
+ // @todo: recursive.
+ *status = f_file_change_role(arguments.array[i].string, -1, id, F_false);
+ if (F_status_is_error(*status)) {
+ fake_print_error_file(data, *status, "f_file_change_role", arguments.array[i].string, "change group of", F_true, F_true);
+ }
+ } // for
+
return;
}
}
if (operation == fake_make_operation_type_mode) {
- // fake_make_assure_inside_project
- // *status = fll_execute_arguments_add(values[i], lengths[i], &arguments);
- //fake_build_arguments_standard_add(data, data_build, F_true, F_true, &arguments, status);
- //fake_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status);
+ f_file_mode mode_rule = 0;
+ uint8_t replace = 0;
+
+ *status = fake_make_get_id_mode(data, arguments.array[0], &mode_rule, &replace);
+ if (F_status_is_error(*status)) return;
+
+ mode_t mode = 0;
+
+ for (f_array_length i = 1; i < arguments.used; i++) {
+ // @todo: get the file mode.
+
+ if (replace) {
+ // @todo when replace is specified, then determine what is to be replaced when converting to mode_t.
+ }
+
+ // @todo: check the zeroing logic, read each file's mode, and updat accordingly.
+ //*status = f_file_change_mode(arguments.array[i].string, mode);
+ //if (F_status_is_error(*status)) {
+ // fake_print_error_file(data, *status, "f_file_change_mode", arguments.array[i].string, "change mode of", F_true, F_true);
+ //}
+ } // for
+
+ return;
+ }
+
+ if (operation == fake_make_operation_type_modes) {
+ // @todo
return;
}
}
if (operation == fake_make_operation_type_owner) {
- // fake_make_assure_inside_project
- // *status = fll_execute_arguments_add(values[i], lengths[i], &arguments);
- //fake_build_arguments_standard_add(data, data_build, F_true, F_true, &arguments, status);
- //fake_build_execute(data, data_build, data_build.setting.build_compiler, arguments, status);
+ uid_t id = 0;
+
+ *status = fake_make_get_id_owner(data, arguments.array[0], &id);
+ if (F_status_is_error(*status)) return;
+
+ for (f_array_length i = 1; i < arguments.used; i++) {
+ *status = f_file_change_role(arguments.array[i].string, id, -1, F_false);
+ if (F_status_is_error(*status)) {
+ fake_print_error_file(data, *status, "f_file_change_role", arguments.array[i].string, "change owner of", F_true, F_true);
+ }
+ } // for
+
+ return;
+ }
+
+ if (operation == fake_make_operation_type_owners) {
+ uid_t id = 0;
+
+ *status = fake_make_get_id_owner(data, arguments.array[0], &id);
+ if (F_status_is_error(*status)) return;
+
+ for (f_array_length i = 1; i < arguments.used; i++) {
+ // @todo recursive.
+ *status = f_file_change_role(arguments.array[i].string, id, -1, F_false);
+ if (F_status_is_error(*status)) {
+ fake_print_error_file(data, *status, "f_file_change_role", arguments.array[i].string, "change owner of", F_true, F_true);
+ }
+ } // for
+
return;
}
if (arguments.array[0].used) {
f_status status_file = f_file_is(arguments.array[0].string, f_file_type_regular);
- if (F_status_is_error(status_file)) {
+ if (status_file == F_file_found_not) {
printf("%c", f_string_eol[0]);
fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: Failed to find file '");
fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", arguments.array[0].string);
fl_color_print_line(f_type_error, data.context.error, data.context.reset, "'.");
+ *status = F_status_set_error(status_file);
+ }
+ else if (F_status_is_error(status_file)) {
+ fake_print_error_file(data, *status, "f_file_is", data.file_data_build_fakefile.string, "find", F_true, F_true);
*status = status_file;
}
*status = F_status_set_error(F_failure);
}
}
- else if (operation == fake_make_operation_type_group || operation == fake_make_operation_type_mode || operation == fake_make_operation_type_owner) {
- if (arguments.used > 3) {
- printf("%c", f_string_eol[0]);
- fl_color_print_line(f_type_error, data.context.error, data.context.reset, "ERROR: Has too many arguments.");
-
- *status = F_status_set_error(F_failure);
- }
- else if (arguments.used > 1) {
- f_status status_file = f_file_is(arguments.array[1].string, f_file_type_regular);
-
- if (F_status_is_error(status_file)) {
- printf("%c", f_string_eol[0]);
- fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: Failed to find file '");
- fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", arguments.array[1].string);
- fl_color_print_line(f_type_error, data.context.error, data.context.reset, "'.");
-
- *status = status_file;
- }
+ else if (operation == fake_make_operation_type_group || operation == fake_make_operation_type_groups || operation == fake_make_operation_type_mode || operation == fake_make_operation_type_modes || operation == fake_make_operation_type_owner || operation == fake_make_operation_type_owners) {
+ printf("DEBUG: arguments.used = %llu\n");
+ if (arguments.used > 1) {
+ f_status status_file = F_none;
- if (!status_file) {
- printf("%c", f_string_eol[0]);
- fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: The file '");
- fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", arguments.array[1].string);
- fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' must be a regular file.");
+ for (f_array_length i = 1; i < arguments.used; i++) {
+ status_file = f_file_is(arguments.array[i].string, f_file_type_regular);
- *status = F_status_set_error(F_failure);
- }
+ printf("DEBUG: at %llu, looking at '%s', %llu\n", i, arguments.array[i].string, F_status_set_fine(status_file));
- if (arguments.used == 3) {
- if (fl_string_dynamic_compare_string(fake_make_operation_argument_recursive, arguments.array[2], fake_make_operation_argument_recursive_length) == F_equal_to_not) {
+ if (status_file == F_file_found_not) {
printf("%c", f_string_eol[0]);
- fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: Third argument must be either '");
- fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", fake_make_operation_argument_recursive);
- fl_color_print_line(f_type_error, data.context.error, data.context.reset, "' or not provided at all.");
+ fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: Failed to find file '");
+ fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", arguments.array[i].string);
+ fl_color_print_line(f_type_error, data.context.error, data.context.reset, "'.");
- *status = F_status_set_error(F_failure);
+ *status = status_file;
+ }
+ else if (F_status_is_error(status_file)) {
+ fake_print_error_file(data, *status, "f_file_is", arguments.array[i].string, "find", F_true, F_true);
+ *status = status_file;
}
}
}
if (arguments.array[0].used) {
f_status status_file = f_file_is(arguments.array[0].string, f_file_type_directory);
- if (F_status_is_error(status_file)) {
+ if (status_file == F_file_found_not) {
printf("%c", f_string_eol[0]);
fl_color_print(f_type_error, data.context.error, data.context.reset, "ERROR: Failed to find file '");
fl_color_print(f_type_error, data.context.notable, data.context.reset, "%s", arguments.array[0].string);
*status = status_file;
}
+ else if (F_status_is_error(status_file)) {
+ fake_print_error_file(data, *status, "f_file_is", data.file_data_build_fakefile.string, "find", F_true, F_true);
+ *status = status_file;
+ }
if (!status_file) {
printf("%c", f_string_eol[0]);
#define fake_make_operation_else "else"
#define fake_make_operation_fail "fail"
#define fake_make_operation_group "group"
+ #define fake_make_operation_groups "groups"
#define fake_make_operation_if "if"
#define fake_make_operation_link "link"
#define fake_make_operation_mode "mode"
+ #define fake_make_operation_modes "modes"
#define fake_make_operation_operate "operate"
#define fake_make_operation_owner "owner"
+ #define fake_make_operation_owners "owners"
#define fake_make_operation_pop "pop"
#define fake_make_operation_print "print"
#define fake_make_operation_run "run"
#define fake_make_operation_else_length 4
#define fake_make_operation_fail_length 4
#define fake_make_operation_group_length 5
+ #define fake_make_operation_groups_length 6
#define fake_make_operation_if_length 2
#define fake_make_operation_link_length 4
#define fake_make_operation_mode_length 4
+ #define fake_make_operation_modes_length 5
#define fake_make_operation_operate_length 7
#define fake_make_operation_owner_length 5
+ #define fake_make_operation_owners_length 6
#define fake_make_operation_pop_length 3
#define fake_make_operation_print_length 5
#define fake_make_operation_run_length 3
fake_make_operation_type_else,
fake_make_operation_type_fail,
fake_make_operation_type_group,
+ fake_make_operation_type_groups,
fake_make_operation_type_if,
fake_make_operation_type_link,
fake_make_operation_type_mode,
+ fake_make_operation_type_modes,
fake_make_operation_type_operate,
fake_make_operation_type_owner,
+ fake_make_operation_type_owners,
fake_make_operation_type_pop,
fake_make_operation_type_print,
fake_make_operation_type_run,
fake_make_operation_type_touch,
};
- #define fake_make_operation_total 23
+ #define fake_make_operation_total 26
#define fake_make_operation_argument_file "file"
#define fake_make_operation_argument_directory "directory"
#endif // _di_fake_make_assure_inside_project_
/**
+ * Get the group id from either a string representing the number or a string representing the name.
+ *
+ * @param data
+ * The program data.
+ * @param buffer
+ * The string containing the name or number.
+ * @param id
+ * The detected group id.
+ *
+ * @return
+ * F_none on success.
+ * F_exist_not if there is no group by the given name.
+ *
+ * Status codes (with error bit) are returned on any problem.
+ */
+#ifndef _di_fake_make_get_id_group_
+ f_return_status fake_make_get_id_group(const fake_data data, const f_string_static buffer, gid_t *id) f_gcc_attribute_visibility_internal;
+#endif // _di_fake_make_get_id_group_
+
+/**
+ * Get the mode id from either a string representing the number or a string representing the mode.
+ *
+ * @param data
+ * The program data.
+ * @param buffer
+ * The string containing the name or number.
+ * @param mode
+ * The determined mode.
+ * This uses bitwise data.
+ * @param replace
+ * The determined modes that are to be replaced, such as: f_file_mode_replace_owner.
+ * This uses bitwise data.
+ *
+ * @return
+ * F_none on success.
+ * F_exist_not if there is no mode by the given name.
+ *
+ * Status codes (with error bit) are returned on any problem.
+ */
+#ifndef _di_fake_make_get_id_mode_
+ f_return_status fake_make_get_id_mode(const fake_data data, const f_string_static buffer, f_file_mode *mode, uint8_t *replace) f_gcc_attribute_visibility_internal;
+#endif // _di_fake_make_get_id_mode_
+
+/**
+ * Get the user id from either a string representing the number or a string representing the name.
+ *
+ * @param data
+ * The program data.
+ * @param buffer
+ * The string containing the name or number.
+ * @param id
+ * The detected user id.
+ *
+ * @return
+ * F_none on success.
+ * F_exist_not if there is no user by the given name.
+ *
+ * Status codes (with error bit) are returned on any problem.
+ */
+#ifndef _di_fake_make_get_id_owner_
+ f_return_status fake_make_get_id_owner(const fake_data data, const f_string_static buffer, uid_t *id) f_gcc_attribute_visibility_internal;
+#endif // _di_fake_make_get_id_owner_
+
+/**
* Find the fake file, load it, validate it, and process it.
*
* This will process any additional files as necessary, such as the build settings file.
f_memory
f_string
f_utf
+f_account
f_color
f_console
f_conversion
main:
- build
+ #build
+ owner a b
build_language c
build_linker ar
build_libraries -lc
-build_libraries-individual -lfll_program -lfll_path -lfll_execute -lfl_environment -lfll_fss -lfl_utf -lfl_string -lfl_status -lfl_iki -lfl_fss -lfl_directory -lfl_conversion -lfl_console -lfl_color -lf_print -lf_path -lf_iki -lf_file -lf_fss -lf_environment -lf_directory -lf_conversion -lf_console -lf_utf -lf_memory
+build_libraries-individual -lfll_program -lfll_path -lfll_execute -lfl_environment -lfll_fss -lfl_utf -lfl_string -lfl_status -lfl_iki -lfl_fss -lfl_directory -lfl_conversion -lfl_console -lfl_color -lf_account -lf_print -lf_path -lf_iki -lf_file -lf_fss -lf_environment -lf_directory -lf_conversion -lf_console -lf_utf -lf_memory
build_libraries-level -lfll_2 -lfll_1 -lfll_0
build_libraries-monolithic -lfll
build_sources_library fake.c private-fake.c private-clean.c private-build.c private-make.c private-print.c private-skeleton.c
The first Content represents the group to assign.
The second Content represents the file to assign the group to.
- An optional third Content may be specified.
- This third Content, if specified, may only be "recursive".
- When specified, this will recursively apply the role to all files within the given file, if that file is a directory file path.
+ - groups\:
+ Identical to group operation, except this will recursively apply the mode to all files within the given file, if that file is a directory file path.
- if\:
Performs a programmatic "if" condition.
The first Content represents the mode to assign.
The second Content represents the file to assign the mode to.
- An optional third Content may be specified.
- This third Content, if specified, may only be "recursive".
- When specified, this will recursively apply the mode to all files within the given file, if that file is a directory file path.
+ - modes\:
+ Identical to mode operation, except this will recursively apply the mode to all files within the given file, if that file is a directory file path.
- operate\:
Begin execution of another Section.
The first Content represents the role to assign.
The second Content represents the file to assign the role to.
- An optional third Content may be specified.
- This third Content, if specified, may only be "recursive".
- When specified, this will recursively apply the role to all files within the given file, if that file is a directory file path.
+ - owners\:
+ Identical to owner operation, except this will recursively apply the mode to all files within the given file, if that file is a directory file path.
- pop\:
Pop a directory path of the path stack, thereby changing to the previous directory on the stack.
- delete: Two or three Content. First Content is either "file" or "directory" (case-sensitive), second Content is path to file, and third Content is "recursive" (case-sensitive) or is not provided.
- else: Zero Content.
- fail: One Content. First Content must be one of "exit", "warn", or "ignore" (case-sensitive).
- - group: Two or three Content. First Content is group name or number, second Content is path to file, and third Content is "recursive" (case-sensitive) or is not provided.
+ - group: Two or more Content. First Content is group name or number, remaining Content are paths to files.
+ - groups: Two or more Content. First Content is group name or number, remaining Content are paths to files.
- if: One or more Content. First Content is the condition, remaining Content are specific to the condition.
- link: Two Content. First Content is the link target file and second Content is the pointer file (the link).
- - mode: Two or three Content. First Content is group name or number, second Content is path to file, and third Content is "recursive" (case-sensitive) or is not provided.
+ - mode: Two or more Content. First Content is group name or number, remaining Content are paths to files.
+ - modes: Two or more Content. First Content is group name or number, remaining Content are paths to files.
- operate: One Content. First Content is the name of a valid Section Object, except for the reserved Section Objects.
- - owner: Two or Three Content. First Content is group name or number, second Content is path to file, and third Content is "recursive" (case-sensitive) or is not provided.
+ - owner: Two or more Content. First Content is group name or number, remaining Content are paths to files.
+ - owners: Two or more Content. First Content is group name or number, remaining Content are paths to files.
- pop: Zero Content.
- print: Zero or more Content.
- run: One or more Content. First Content is the name of the program (or script) and all remaining Content are passed as arguments to the named program (or script).