]> Kevux Git Server - fll/commitdiff
Progress: continue work on mode changes
authorKevin Day <thekevinday@gmail.com>
Thu, 13 Aug 2020 03:41:31 +0000 (22:41 -0500)
committerKevin Day <thekevinday@gmail.com>
Thu, 13 Aug 2020 03:41:31 +0000 (22:41 -0500)
The functions were renamed and re-organized to be more consistent with the project practices.

This changeset focused on getting the number-only changes done within the time allowed.
This adds a new function for converting the f_file_mode into a mode_t for the libc chmod compatibility.

level_0/f_file/c/file.c
level_0/f_file/c/file.h
level_0/f_file/c/private-file.c
level_0/f_file/c/private-file.h
level_1/fl_directory/c/directory.c
level_1/fl_directory/c/directory.h
level_1/fl_directory/c/private-directory.c
level_3/fake/c/private-make.c
level_3/fake/data/build/fakefile

index 03efa956d1e20a1d4b8b57edd32fd81164953945..4b46545fa930ab613dd5b8afcf39a5b12568515a 100644 (file)
@@ -28,50 +28,6 @@ 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) {
-    #ifndef _di_level_0_parameter_checking_
-      if (path == 0) return F_status_set_error(F_parameter);
-    #endif // _di_level_0_parameter_checking_
-
-    return private_f_file_change_mode(path, mode);
-  }
-#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) {
-    #ifndef _di_level_0_parameter_checking_
-      if (path == 0) return F_status_set_error(F_parameter);
-    #endif // _di_level_0_parameter_checking_
-
-    return private_f_file_change_mode_at(at_id, path, mode);
-  }
-#endif // _di_f_file_change_mode_at_
-
-#ifndef _di_f_file_change_role_
-  f_return_status f_file_change_role(const f_string path, const uid_t uid, const gid_t gid, const bool dereference) {
-    #ifndef _di_level_0_parameter_checking_
-      if (path == 0) return F_status_set_error(F_parameter);
-      if (uid < 0 && gid < 0) return F_status_set_error(F_parameter);
-      if (uid < -1 || gid < -1) return F_status_set_error(F_parameter);
-    #endif // _di_level_0_parameter_checking_
-
-    return private_f_file_change_role(path, uid, gid, dereference);
-  }
-#endif // _di_f_file_change_role_
-
-#ifndef _di_f_file_change_role_at_
-  f_return_status f_file_change_role_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag) {
-    #ifndef _di_level_0_parameter_checking_
-      if (path == 0) return F_status_set_error(F_parameter);
-      if (uid < 0 && gid < 0) return F_status_set_error(F_parameter);
-      if (uid < -1 || gid < -1) return F_status_set_error(F_parameter);
-    #endif // _di_level_0_parameter_checking_
-
-    return private_f_file_change_role_at(at_id, path, uid, gid, flag);
-  }
-#endif // _di_f_file_change_role_at_
-
 #ifndef _di_f_file_clone_
   f_return_status f_file_clone(const f_string source, const f_string destination, const bool role, const f_number_unsigned size_block, const bool exclusive) {
     #ifndef _di_level_0_parameter_checking_
@@ -92,12 +48,12 @@ extern "C" {
       if (F_status_is_error(status)) return status;
 
       if (!exclusive) {
-        status = private_f_file_change_mode(destination, source_stat.st_mode);
+        status = private_f_file_mode_set(destination, source_stat.st_mode);
         if (F_status_is_error(status)) return status;
       }
 
       if (role) {
-        status = private_f_file_change_role(destination, source_stat.st_uid, source_stat.st_gid, F_false);
+        status = private_f_file_role_change(destination, source_stat.st_uid, source_stat.st_gid, F_false);
         if (F_status_is_error(status)) return status;
       }
 
@@ -112,11 +68,11 @@ extern "C" {
         return status;
       }
 
-      status = private_f_file_change_mode(destination, source_stat.st_mode);
+      status = private_f_file_mode_set(destination, source_stat.st_mode);
       if (F_status_is_error(status)) return status;
 
       if (role) {
-        status = private_f_file_change_role(destination, source_stat.st_uid, source_stat.st_gid, F_false);
+        status = private_f_file_role_change(destination, source_stat.st_uid, source_stat.st_gid, F_false);
         if (F_status_is_error(status)) return status;
       }
 
@@ -158,7 +114,7 @@ extern "C" {
       if (F_status_is_error(status)) return status;
 
       if (!exclusive) {
-        status = private_f_file_change_mode(destination, (~f_file_type_mask) & mode.regular);
+        status = private_f_file_mode_set(destination, (~f_file_type_mask) & mode.regular);
         if (F_status_is_error(status)) return status;
       }
 
@@ -173,7 +129,7 @@ extern "C" {
         }
       }
 
-      status = private_f_file_change_mode(destination, (~f_file_type_mask) & mode.directory);
+      status = private_f_file_mode_set(destination, (~f_file_type_mask) & mode.directory);
       if (F_status_is_error(status)) return status;
 
       return F_none;
@@ -208,7 +164,7 @@ extern "C" {
         }
       }
 
-      status = private_f_file_change_mode(destination, (~f_file_type_mask) & mode.fifo);
+      status = private_f_file_mode_set(destination, (~f_file_type_mask) & mode.fifo);
       if (F_status_is_error(status)) return status;
 
       return F_none;
@@ -222,7 +178,7 @@ extern "C" {
         }
       }
 
-      status = private_f_file_change_mode(destination, (~f_file_type_mask) & mode.socket);
+      status = private_f_file_mode_set(destination, (~f_file_type_mask) & mode.socket);
       if (F_status_is_error(status)) return status;
 
       return F_none;
@@ -236,7 +192,7 @@ extern "C" {
         }
       }
 
-      status = private_f_file_change_mode(destination, (~f_file_type_mask) & mode.block);
+      status = private_f_file_mode_set(destination, (~f_file_type_mask) & mode.block);
       if (F_status_is_error(status)) return status;
 
       return F_none;
@@ -568,6 +524,316 @@ extern "C" {
   }
 #endif // _di_f_file_link_read_at_
 
+#ifndef _di_f_file_mode_determine_
+  f_return_status f_file_mode_determine(const mode_t mode_file, const f_file_mode mode_change, const uint8_t mode_replace, const bool directory_is, const mode_t umask, mode_t *mode) {
+    #ifndef _di_level_0_parameter_checking_
+      if (mode == 0) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    f_file_mode change = mode_change & f_file_mode_block_special;
+
+    *mode = 0;
+
+    if (mode_replace & f_file_mode_replace_special) {
+      if (change & f_file_mode_mask_bit_set_owner & f_file_mode_mask_how_add) {
+        *mode = f_file_mode_special_set_user;
+      }
+
+      if (change & f_file_mode_mask_bit_set_group & f_file_mode_mask_how_add) {
+        *mode |= f_file_mode_special_set_group;
+      }
+
+      if (change & f_file_mode_mask_bit_sticky & f_file_mode_mask_how_add) {
+        *mode |= f_file_mode_special_sticky;
+      }
+    }
+    else {
+      *mode = mode_file & f_file_mode_special_all;
+
+      if (mode_change & f_file_mode_block_special) {
+        if (change & f_file_mode_mask_bit_set_owner & f_file_mode_mask_how_subtract) {
+          if (*mode & f_file_mode_special_set_user) {
+            *mode -= f_file_mode_special_set_user;
+          }
+        }
+        else if (change & f_file_mode_mask_bit_set_owner & f_file_mode_mask_how_add) {
+          if (!(*mode & f_file_mode_special_set_user)) {
+            *mode |= f_file_mode_special_set_user;
+          }
+        }
+
+        if (change & f_file_mode_mask_bit_set_group & f_file_mode_mask_how_subtract) {
+          if (*mode & f_file_mode_special_set_group) {
+            *mode -= f_file_mode_special_set_group;
+          }
+        }
+        else if (change & f_file_mode_mask_bit_set_group & f_file_mode_mask_how_add) {
+          if (!(*mode & f_file_mode_special_set_group)) {
+            *mode |= f_file_mode_special_set_group;
+          }
+        }
+
+        if (change & f_file_mode_mask_bit_sticky & f_file_mode_mask_how_subtract) {
+          if (*mode & f_file_mode_special_sticky) {
+            *mode -= f_file_mode_special_sticky;
+          }
+        }
+        else if (change & f_file_mode_mask_bit_sticky & f_file_mode_mask_how_add) {
+          if (!(*mode & f_file_mode_special_sticky)) {
+            *mode |= f_file_mode_special_sticky;
+          }
+        }
+      }
+    }
+
+    change = mode_change & f_file_mode_block_owner;
+
+    if (mode_replace & f_file_mode_replace_owner) {
+      if (change & f_file_mode_mask_bit_read & f_file_mode_mask_how_add) {
+        *mode |= f_file_mode_owner_r;
+      }
+
+      if (change & f_file_mode_mask_bit_write & f_file_mode_mask_how_add) {
+        *mode |= f_file_mode_owner_w;
+      }
+
+      if (change & f_file_mode_mask_bit_execute & f_file_mode_mask_how_add) {
+        *mode |= f_file_mode_owner_x;
+      }
+      else if (change & f_file_mode_mask_bit_execute_only & f_file_mode_mask_how_add) {
+        if (directory_is || (mode_file & f_file_mode_owner_x)) {
+          *mode |= f_file_mode_owner_x;
+        }
+      }
+    }
+    else {
+      *mode |= mode_file & f_file_mode_owner_rwx;
+
+      if (mode_change & f_file_mode_block_owner) {
+        if (change & f_file_mode_mask_bit_read & f_file_mode_mask_how_subtract) {
+          if (*mode & f_file_mode_owner_r) {
+            *mode -= f_file_mode_owner_r;
+          }
+        }
+        else if (change & f_file_mode_mask_bit_read & f_file_mode_mask_how_add) {
+          if (!(*mode & f_file_mode_owner_r)) {
+            *mode |= f_file_mode_owner_r;
+          }
+        }
+
+        if (change & f_file_mode_mask_bit_write & f_file_mode_mask_how_subtract) {
+          if (*mode & f_file_mode_owner_w) {
+            *mode -= f_file_mode_owner_w;
+          }
+        }
+        else if (change & f_file_mode_mask_bit_write & f_file_mode_mask_how_add) {
+          if (!(*mode & f_file_mode_owner_w)) {
+            *mode |= f_file_mode_owner_w;
+          }
+        }
+
+        if (change & f_file_mode_mask_bit_execute) {
+          change &= f_file_mode_mask_bit_execute;
+
+          if (change & f_file_mode_mask_how_subtract) {
+            if (*mode & f_file_mode_owner_x) {
+              *mode -= f_file_mode_owner_x;
+            }
+          }
+          else if (change & f_file_mode_mask_how_add) {
+            if (!(*mode & f_file_mode_owner_x)) {
+              *mode |= f_file_mode_owner_x;
+            }
+          }
+        }
+        else if (change & f_file_mode_mask_bit_execute_only) {
+          change &= f_file_mode_mask_bit_execute_only;
+
+          if (directory_is || (mode_file & f_file_mode_owner_x)) {
+            if (change & f_file_mode_mask_how_subtract) {
+              if (*mode & f_file_mode_owner_x) {
+                *mode -= f_file_mode_owner_x;
+              }
+            }
+            else if (change & f_file_mode_mask_how_add) {
+              if (!(*mode & f_file_mode_owner_x)) {
+                *mode |= f_file_mode_owner_x;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    change = mode_change & f_file_mode_block_group;
+
+    if (mode_replace & f_file_mode_replace_group) {
+      if (change & f_file_mode_mask_bit_read & f_file_mode_mask_how_add) {
+        *mode |= f_file_mode_group_r;
+      }
+
+      if (change & f_file_mode_mask_bit_write & f_file_mode_mask_how_add) {
+        *mode |= f_file_mode_group_w;
+      }
+
+      if (change & f_file_mode_mask_bit_execute & f_file_mode_mask_how_add) {
+        *mode |= f_file_mode_group_x;
+      }
+      else if (change & f_file_mode_mask_bit_execute_only & f_file_mode_mask_how_add) {
+        if (directory_is || (mode_file & f_file_mode_group_x)) {
+          *mode |= f_file_mode_group_x;
+        }
+      }
+    }
+    else {
+      *mode |= mode_file & f_file_mode_group_rwx;
+
+      if (mode_change & f_file_mode_block_group) {
+
+        if (change & f_file_mode_mask_bit_read & f_file_mode_mask_how_subtract) {
+          if (*mode & f_file_mode_group_r) {
+            *mode -= f_file_mode_group_r;
+          }
+        }
+        else if (change & f_file_mode_mask_bit_read & f_file_mode_mask_how_add) {
+          if (!(*mode & f_file_mode_group_r)) {
+            *mode |= f_file_mode_group_r;
+          }
+        }
+
+        if (change & f_file_mode_mask_bit_write & f_file_mode_mask_how_subtract) {
+          if (*mode & f_file_mode_group_w) {
+            *mode -= f_file_mode_group_w;
+          }
+        }
+        else if (change & f_file_mode_mask_bit_write & f_file_mode_mask_how_add) {
+          if (!(*mode & f_file_mode_group_w)) {
+            *mode |= f_file_mode_group_w;
+          }
+        }
+
+        if (change & f_file_mode_mask_bit_execute) {
+          change &= f_file_mode_mask_bit_execute;
+
+          if (change & f_file_mode_mask_how_subtract) {
+            if (*mode & f_file_mode_group_x) {
+              *mode -= f_file_mode_group_x;
+            }
+          }
+          else if (change & f_file_mode_mask_how_add) {
+            if (!(*mode & f_file_mode_group_x)) {
+              *mode |= f_file_mode_group_x;
+            }
+          }
+        }
+        else if (change & f_file_mode_mask_bit_execute_only) {
+          change &= f_file_mode_mask_bit_execute_only;
+
+          if (directory_is || (mode_file & f_file_mode_group_x)) {
+            if (change & f_file_mode_mask_how_subtract) {
+              if (*mode & f_file_mode_group_x) {
+                *mode -= f_file_mode_group_x;
+              }
+            }
+            else if (change & f_file_mode_mask_how_add) {
+              if (!(*mode & f_file_mode_group_x)) {
+                *mode |= f_file_mode_group_x;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    change = mode_change & f_file_mode_block_world;
+
+    if (mode_replace & f_file_mode_replace_world) {
+
+      if (change & f_file_mode_mask_bit_read & f_file_mode_mask_how_add) {
+        *mode |= f_file_mode_world_r;
+      }
+
+      if (change & f_file_mode_mask_bit_write & f_file_mode_mask_how_add) {
+        *mode |= f_file_mode_world_w;
+      }
+
+      if (change & f_file_mode_mask_bit_execute & f_file_mode_mask_how_add) {
+        *mode |= f_file_mode_world_x;
+      }
+      else if (change & f_file_mode_mask_bit_execute_only & f_file_mode_mask_how_add) {
+        if (directory_is || (mode_file & f_file_mode_world_x)) {
+          *mode |= f_file_mode_world_x;
+        }
+      }
+    }
+    else {
+      *mode |= mode_file & f_file_mode_world_rwx;
+
+      if (mode_change & f_file_mode_block_world) {
+
+        if (change & f_file_mode_mask_bit_read & f_file_mode_mask_how_subtract) {
+          if (*mode & f_file_mode_world_r) {
+            *mode -= f_file_mode_world_r;
+          }
+        }
+        else if (change & f_file_mode_mask_bit_read & f_file_mode_mask_how_add) {
+          if (!(*mode & f_file_mode_world_r)) {
+            *mode |= f_file_mode_world_r;
+          }
+        }
+
+        if (change & f_file_mode_mask_bit_write & f_file_mode_mask_how_subtract) {
+          if (*mode & f_file_mode_world_w) {
+            *mode -= f_file_mode_world_w;
+          }
+        }
+        else if (change & f_file_mode_mask_bit_write & f_file_mode_mask_how_add) {
+          if (!(*mode & f_file_mode_world_w)) {
+            *mode |= f_file_mode_world_w;
+          }
+        }
+
+        if (change & f_file_mode_mask_bit_execute) {
+          change &= f_file_mode_mask_bit_execute;
+
+          if (change & f_file_mode_mask_how_subtract) {
+            if (*mode & f_file_mode_world_x) {
+              *mode -= f_file_mode_world_x;
+            }
+          }
+          else if (change & f_file_mode_mask_how_add) {
+            if (!(*mode & f_file_mode_world_x)) {
+              *mode |= f_file_mode_world_x;
+            }
+          }
+        }
+        else if (change & f_file_mode_mask_bit_execute_only) {
+          change &= f_file_mode_mask_bit_execute_only;
+
+          if (directory_is || (mode_file & f_file_mode_world_x)) {
+            if (change & f_file_mode_mask_how_subtract) {
+              if (*mode & f_file_mode_world_x) {
+                *mode -= f_file_mode_world_x;
+              }
+            }
+            else if (change & f_file_mode_mask_how_add) {
+              if (!(*mode & f_file_mode_world_x)) {
+                *mode |= f_file_mode_world_x;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    if (mode_replace & f_file_mode_replace_umask) {
+      *mode -= *mode & umask;
+    }
+
+    return F_none;
+  }
+#endif // _di_f_file_mode_determine_
+
 #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_
@@ -583,12 +849,10 @@ extern "C" {
     *replace = 0;
 
     switch (string[0]) {
-
       case '+':
       case '-':
       case '=':
         switch (string[1]) {
-
           case 'r':
           case 'w':
           case 'x':
@@ -613,7 +877,6 @@ extern "C" {
             return F_status_set_error(F_syntax);
         }
 
-        syntax = 1;
         break;
 
       case 'u':
@@ -640,12 +903,13 @@ extern "C" {
 
     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.
+      uint8_t how = 0; // 1 = add, 2 = replace, 3 = subtract.
       bool active = F_false;
 
-      f_file_mode mask = 0;
+      f_file_mode mask = f_file_mode_block_special;
       f_file_mode what = 0;
 
+      // @todo: this needs to record all of the possible combinations of add, subtract, and assignment (=).
       for (f_string_length i = 0; syntax && i < string[i]; i++) {
 
         switch (string[i]) {
@@ -686,7 +950,7 @@ extern "C" {
             }
 
             on = 7;
-            mask = f_file_mode_block_owner | f_file_mode_block_group | f_file_mode_block_world;
+            mask = f_file_mode_block_all;
             break;
 
           case '+':
@@ -705,11 +969,24 @@ extern "C" {
 
               // only the parts designated by the mask should be replaced.
               *mode -= (*mode) & mask;
+
+              if (mask == f_file_mode_block_all) {
+                *replace = f_file_mode_replace_all;
+              }
+              else if (mask & f_file_mode_block_world) {
+                *replace |= f_file_mode_block_special & f_file_mode_block_world;
+              }
+              else if (mask & f_file_mode_block_group) {
+                *replace |= f_file_mode_block_special & f_file_mode_block_group;
+              }
+              else if (mask & f_file_mode_block_owner) {
+                *replace |= f_file_mode_block_special & f_file_mode_block_owner;
+              }
             }
 
             if (!on) {
               on = 7;
-              mask = f_file_mode_block_owner | f_file_mode_block_group | f_file_mode_block_world;
+              mask = f_file_mode_block_all;
             }
 
             for (i++; i < string[i]; i++) {
@@ -749,7 +1026,7 @@ extern "C" {
                 active = F_false;
                 on = 0;
                 how = 0;
-                mask = 0;
+                mask = f_file_mode_block_special;
                 break;
               }
               else if (string[i] == '+' || string[i] == '-' || string[i] == '=') {
@@ -769,10 +1046,12 @@ extern "C" {
                 *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;
+                *mode |= what & mask & f_file_mode_mask_how_add;
+                *replace |= f_file_mode_replace_umask;
               }
               else if (how == 6) {
-                *mode |= what & mask & f_file_mode_mask_how_umask_subtract;
+                *mode |= what & mask & f_file_mode_mask_how_subtract;
+                *replace |= f_file_mode_replace_umask;
               }
             } // for
 
@@ -785,13 +1064,13 @@ extern "C" {
       } // for
     }
     else if (syntax == 2) {
-      // 1 = add, 2 = replace, 3 = subtract, 4 = umask add, 5 = umask replace, 6 = umask subtract.
+      // 1 = add, 2 = replace, 3 = subtract.
       uint8_t how = 0;
 
-      mode_t classic = 0;
-
       f_string_length i = 0;
 
+      *replace = 0;
+
       if (string[0] == '+') {
         how = 1;
         i = 1;
@@ -800,17 +1079,23 @@ extern "C" {
         how = 3;
         i = 1;
       }
-      else if (string[0] == '=' || string[0] == '0') {
+      else if (string[0] == '=') {
         how = 2;
         i = 1;
+
+        *replace = f_file_mode_replace_standard;
       }
       else {
-        how = 5;
+        how = 2;
+
+        *replace = f_file_mode_replace_standard | f_file_mode_replace_directory;
       }
 
-      for (; string[i] == '0'; i++) {
-        // seek past leading '0's.
-      } // for
+      if (string[i] == '0') {
+        for (; string[i] == '0'; i++) {
+          // seek past leading '0's.
+        } // for
+      }
 
       if (string[i]) {
         f_string_length j = 0;
@@ -818,7 +1103,7 @@ extern "C" {
         for (; string[i + j] && j < 4; j++) {
 
           if (j) {
-            classic <<= 3;
+            *mode <<= 8;
           }
 
           switch (string[i]) {
@@ -834,11 +1119,17 @@ extern "C" {
             case '6':
             case '7':
               // this assumes ASCII/UTF-8.
-              classic |= string[i] - 0x30;
+              if (how == 3) {
+                *mode |= (string[i + j] - 0x30) << 4;
+              }
+              else {
+                *mode |= string[i + j] - 0x30;
+              }
 
               break;
 
             default:
+              // designate that this is invalid.
               j = 4;
               break;
           }
@@ -847,28 +1138,13 @@ extern "C" {
         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 if (how == 2) {
+          // if there are only '0's then the setuid/setgid/sticky bits are to be replaced.
+          if (*mode == 0) {
+            *replace = f_file_mode_replace_standard;
           }
         }
       }
-      else {
-        *replace = f_file_mode_replace_all;
-      }
     }
 
     if (syntax) {
@@ -882,7 +1158,25 @@ extern "C" {
   }
 #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_mode_set_
+  f_return_status f_file_mode_set(const f_string path, const mode_t mode) {
+    #ifndef _di_level_0_parameter_checking_
+      if (path == 0) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_f_file_mode_set(path, mode);
+  }
+#endif // _di_f_file_mode_set_
+
+#ifndef _di_f_file_mode_set_at_
+  f_return_status f_file_mode_set_at(const int at_id, const f_string path, const mode_t mode) {
+    #ifndef _di_level_0_parameter_checking_
+      if (path == 0) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_f_file_mode_set_at(at_id, path, mode);
+  }
+#endif // _di_f_file_mode_set_at_
 
 #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) {
@@ -1193,6 +1487,30 @@ extern "C" {
   }
 #endif // _di_f_file_remove_at_
 
+#ifndef _di_f_file_role_change_
+  f_return_status f_file_role_change(const f_string path, const uid_t uid, const gid_t gid, const bool dereference) {
+    #ifndef _di_level_0_parameter_checking_
+      if (path == 0) return F_status_set_error(F_parameter);
+      if (uid < 0 && gid < 0) return F_status_set_error(F_parameter);
+      if (uid < -1 || gid < -1) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_f_file_role_change(path, uid, gid, dereference);
+  }
+#endif // _di_f_file_role_change_
+
+#ifndef _di_f_file_role_change_at_
+  f_return_status f_file_role_change_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag) {
+    #ifndef _di_level_0_parameter_checking_
+      if (path == 0) return F_status_set_error(F_parameter);
+      if (uid < 0 && gid < 0) return F_status_set_error(F_parameter);
+      if (uid < -1 || gid < -1) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_f_file_role_change_at(at_id, path, uid, gid, flag);
+  }
+#endif // _di_f_file_role_change_at_
+
 #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_
index c0a8479a3ce82b0624066cd1bb5b45ce034bd92a..37c1fa24ce31539309eac2d815fd636b9fe637a6 100644 (file)
@@ -257,20 +257,23 @@ extern "C" {
  *     'S' = set user bit (setuid).
  *     's' = set group bit (setgid).
  *     't' = sticky bit.
+ *
+ *   The mode replace codes are meant to be used for the user, group, and world modes.
+ *   Generally "special" bits are preserved unless explicitly changed so there is also a "special" mode replace code as well.
+ *   The "umask" equivalent specifies that the mask should allow for umask influence.
  */
 #ifndef _di_f_file_mode_
   typedef uint32_t f_file_mode;
 
+                                               // 0000 0000 0000 0111 0000 0101 0000 0101
   #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_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_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
@@ -280,15 +283,16 @@ extern "C" {
   #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_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_special   0x7  // 0000 1000
+  #define f_file_mode_replace_umask     0x10 // 0001 0000
+  #define f_file_mode_replace_directory 0x20 // 0010 0000
 
-  #define f_file_mode_replace_all       0x7  // 0000 0111
-  #define f_file_mode_replace_umask_all 0x38 // 0011 1000
+  #define f_file_mode_replace_all      0x3f // 0011 1111
+  #define f_file_mode_replace_other    0x38 // 0011 1000
+  #define f_file_mode_replace_standard 0x7  // 0000 0111
 
   // file permission modes.
   #define f_file_mode_owner_rwx S_IRWXU
@@ -321,11 +325,14 @@ extern "C" {
   #define f_file_mode_all_w   (f_file_mode_owner_w | f_file_mode_group_w | f_file_mode_world_w)
   #define f_file_mode_all_x   (f_file_mode_owner_x | f_file_mode_group_x | f_file_mode_world_x)
 
-  // file mode sticky-bits and all bits.
-  #define f_file_mode_special_user  S_ISUID
-  #define f_file_mode_special_group S_ISGID
-  #define f_file_mode_special_world S_ISVTX
-  #define f_file_mode_special_all   (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
+  // file mode set-uid/set-gid/sticky-bits and all bits.
+  #define f_file_mode_special_set_user  S_ISUID
+  #define f_file_mode_special_set_group S_ISGID
+  #define f_file_mode_special_sticky    S_ISVTX
+  #define f_file_mode_special_all       (S_ISUID | S_ISGID | S_ISVTX)
+
+  // all permissions modes and special modes.
+  #define f_file_mode_all (f_file_mode_special_all | f_file_mode_all_rwx)
 
   // special file mode combinations.
   #define f_file_mode_user_access    (f_file_mode_owner_rwx | f_file_mode_group_rwx | f_file_mode_world_x)
@@ -360,151 +367,6 @@ extern "C" {
 #endif // _di_f_file_access_
 
 /**
- * Change mode of a given file at the specified path.
- *
- * This does not set mode based on umask(), be sure to apply umask if so desired.
- * (such as: mode & ~mask).
- *
- * @param path
- *   The path file name.
- * @param mode
- *   The new mode to use.
- *
- * @return
- *   F_none on success.
- *   F_access_denied (with error bit) on access denied.
- *   F_access_mode (with error bit) if the current user does not have access to assign the file mode.
- *   F_directory (with error bit) on invalid directory.
- *   F_file_found_not (with error bit) if file at path was not found.
- *   F_input_output (with error bit) on I/O error.
- *   F_loop (with error bit) on loop error.
- *   F_memory_out (with error bit) if out of memory.
- *   F_name (with error bit) on path name error.
- *   F_parameter (with error bit) if a parameter is invalid.
- *   F_read_only (with error bit) if file is read-only.
- *   F_failure (with error bit) for any other error.
- *
- * @see chmod()
- */
-#ifndef _di_f_file_change_mode_
-  extern f_return_status f_file_change_mode(const f_string path, const mode_t mode);
-#endif // _di_f_file_change_mode_
-
-/**
- * Change mode of a given file at the specified path.
- *
- * This does not set mode based on umask(), be sure to apply umask if so desired.
- * (such as: mode & ~mask).
- *
- * @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.
- *
- * @return
- *   F_none on success.
- *   F_access_denied (with error bit) on access denied.
- *   F_access_mode (with error bit) if the current user does not have access to assign the file mode.
- *   F_file_found_not (with error bit) if file at path was not found.
- *   F_directory (with error bit) on invalid directory.
- *   F_input_output (with error bit) on I/O error.
- *   F_loop (with error bit) on loop error.
- *   F_memory_out (with error bit) if out of memory.
- *   F_name (with error bit) on path name error.
- *   F_parameter (with error bit) if a parameter is invalid.
- *   F_read_only (with error bit) if file is read-only.
- *   F_failure (with error bit) for any other error.
- *
- * @see fchmodat()
- */
-#ifndef _di_f_file_change_mode_at_
-  extern f_return_status f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode);
-#endif // _di_f_file_change_mode_at_
-
-/**
- * Change owner and/or group of a given file at the specified path.
- *
- * At least one of uid or gid must not be -1.
- *
- * @param path
- *   The path file name.
- * @param uid
- *   The new user id to use.
- *   Set to -1 to not change.
- * @param gid
- *   The new group id to use.
- *   Set to -1 to not change.
- * @param dereference
- *   Set to TRUE to dereferenc symlinks (often is what is desired).
- *   Set to FALSE to operate on the symlink itself.
- *
- * @return
- *   F_none on success.
- *   F_access_denied (with error bit) on access denied.
- *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
- *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
- *   F_buffer (with error bit) if the buffer is invalid.
- *   F_directory (with error bit) on invalid directory.
- *   F_file_found_not (with error bit) if file at path was not found.
- *   F_input_output (with error bit) on I/O error.
- *   F_loop (with error bit) on loop error.
- *   F_memory_out (with error bit) if out of memory.
- *   F_name (with error bit) on path name error.
- *   F_parameter (with error bit) if a parameter is invalid.
- *   F_read_only (with error bit) if file is read-only.
- *   F_failure (with error bit) for any other error.
- *
- * @see chown()
- * @see lchown()
- */
-#ifndef _di_f_file_change_role_
-  extern f_return_status f_file_change_role(const f_string path, const uid_t uid, const gid_t gid, const bool dereference);
-#endif // _di_f_file_change_role_
-
-/**
- * Change owner and/or group of a given file at the specified path.
- *
- * At least one of uid or gid must not be -1.
- *
- * @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.
- *   Set to -1 to not change.
- * @param gid
- *   The new group id to use.
- *   Set to -1 to not change.
- * @param flag
- *   Any valid flag, such as f_file_at_path_empty, f_file_at_automount_no, or f_file_at_symlink_follow_no.
- *
- * @return
- *   F_none on success.
- *   F_access_denied (with error bit) on access denied.
- *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
- *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
- *   F_buffer (with error bit) if the buffer is invalid.
- *   F_directory (with error bit) on invalid directory.
- *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
- *   F_file_found_not (with error bit) if file at path was not found.
- *   F_input_output (with error bit) on I/O error.
- *   F_loop (with error bit) on loop error.
- *   F_memory_out (with error bit) if out of memory.
- *   F_name (with error bit) on path name error.
- *   F_parameter (with error bit) if a parameter is invalid.
- *   F_read_only (with error bit) if file is read-only.
- *   F_failure (with error bit) for any other error.
- *
- * @see fchownat()
- */
-#ifndef _di_f_file_change_role_at_
-  extern f_return_status f_file_change_role_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag);
-#endif // _di_f_file_change_role_at_
-
-/**
  * 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.
@@ -1282,10 +1144,37 @@ extern "C" {
 #endif // _di_f_file_link_read_at_
 
 /**
+ * Determine how the mode should be applied based on different file properties and the given mode properties.
+ *
+ * @param mode_file
+ *   The mode_t value representing the file's current mode.
+ *   This is expected to be populated from (struct stat).st_mode.
+ * @param mode_change
+ *   The file mode values to change.
+ * @param mode_replace
+ *   The mode modes that should be replaced instead of simply changed.
+ * @param directory_is
+ *   Set to TRUE if the file is a directory, FALSE otherwise.
+ * @param umask
+ *   The current umask, which will be used if necessary.
+ * @param mode
+ *   The determined mode.
+ *
+ * @return
+ *   F_none on success.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_file_mode_from_string()
+ */
+#ifndef _di_f_file_mode_determine_
+  extern f_return_status f_file_mode_determine(const mode_t mode_file, const f_file_mode mode_change, const uint8_t mode_replace, const bool directory_is, const mode_t umask, mode_t *mode);
+#endif // _di_f_file_mode_determine_
+
+/**
  * 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})'.
+ *   '([ugoa]*[-+=]{0,1}([rwxXst]|[ugo])+([,][ugoa]*[-+=]{0,1}([rwxXst]|[ugo])+)*)|([-+=]{0,1}0*[0-7]{1,4})'.
  *
  * Such that:
  *   'u' = apply to user.
@@ -1298,7 +1187,7 @@ extern "C" {
  *   'r' = read mode.
  *   'w' = write mode.
  *   'x' = execute mode.
- *   'X' = execute mode, only if already executable.
+ *   'X' = execute mode, only if already executable directory or is file with owner already has executable bit.
  *   's' = set-gid/set-uid mode.
  *   't' = sticky-bit mode.
  *   '0' = no mode.
@@ -1320,17 +1209,28 @@ extern "C" {
  *   '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.
+ *   [0]+  = set all bits to 0.
+ *   [0-7] = apply to other/world.
+ *   [0-7][0-7] = first ([1-7]) to group and second ([0-7]) to other/world.
+ *   [0-7][0-7][0-7] = first ([1-7]) to owner, second ([0-7]) to group, and third ([0-7]) to other/world.
+ *   [0-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 using digits, the umask is always ignored.
+ * When there is a leading '0' or '=' when using digits, then the special bits should be replaced.
+ * Otherwise, the current special bits are intended to be respected (designated by f_file_mode_replace_directory).
  *
- * When '+', '-', or '=' are specified without a leading 'a', 'u', 'g', or 'o', then the mode operations should be performed against the current umask.
+ * When using non-digits and '+', '-', 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.
  *
+ * There are problems with the chmod documentation (as of GNU coreutils 8.30):
+ * 1) "The operator + causes the selected file mode bits to be added to the existing file mode bits of each file; - causes them to be removed; and = causes them to be added and causes unmentioned bits to be re‐moved except that a directory's unmentioned set user and group ID bits are not affected."
+ *   - This means that "chmod =1 some_directory" would not change the setuid/setgid/sticky bits, however, in practice it does change it!
+ * 2) "For directories chmod preserves set-user-ID and set-group-ID bits unless you explicitly specify other‐wise. You can set or clear the bits with symbolic modes like u+s and g-s. To clear these bits for directories with a numeric mode requires an additional leading zero, or leading = like 00755, or =755"
+ *   - This directly contradicts quote "1" above, which effectively states "=755" would preserve the bits while quote "2" states that it clears the bits.
+ *   - This means that "chmod 1 some_directory" would not change the setuid/setgid/sticky bits, however, in practice it does change it!
+ *
+ * Considering the behavior, assume that when "=" or a leading "0" is provided, this will change the setuid/setgid/sticky bits, otherwise it preserves those bits for directories.
+ *
  * @param string
  *   A NULL terminated string designating the desired mode, following the above string syntax.
  * @param mode
@@ -1346,12 +1246,78 @@ extern "C" {
  *   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.
+ *
+ * @see private_f_file_mode_determine()
  */
 #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_
 
 /**
+ * Change mode of a given file at the specified path.
+ *
+ * This does not set mode based on umask(), be sure to apply umask if so desired.
+ * (such as: mode & ~mask).
+ *
+ * @param path
+ *   The path file name.
+ * @param mode
+ *   The new mode to use.
+ *
+ * @return
+ *   F_none on success.
+ *   F_access_denied (with error bit) on access denied.
+ *   F_access_mode (with error bit) if the current user does not have access to assign the file mode.
+ *   F_directory (with error bit) on invalid directory.
+ *   F_file_found_not (with error bit) if file at path was not found.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_loop (with error bit) on loop error.
+ *   F_memory_out (with error bit) if out of memory.
+ *   F_name (with error bit) on path name error.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_read_only (with error bit) if file is read-only.
+ *   F_failure (with error bit) for any other error.
+ *
+ * @see chmod()
+ */
+#ifndef _di_f_file_mode_set_
+  extern f_return_status f_file_mode_set(const f_string path, const mode_t mode);
+#endif // _di_f_file_mode_set_
+
+/**
+ * Change mode of a given file at the specified path.
+ *
+ * This does not set mode based on umask(), be sure to apply umask if so desired.
+ * (such as: mode & ~mask).
+ *
+ * @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.
+ *
+ * @return
+ *   F_none on success.
+ *   F_access_denied (with error bit) on access denied.
+ *   F_access_mode (with error bit) if the current user does not have access to assign the file mode.
+ *   F_file_found_not (with error bit) if file at path was not found.
+ *   F_directory (with error bit) on invalid directory.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_loop (with error bit) on loop error.
+ *   F_memory_out (with error bit) if out of memory.
+ *   F_name (with error bit) on path name error.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_read_only (with error bit) if file is read-only.
+ *   F_failure (with error bit) for any other error.
+ *
+ * @see fchmodat()
+ */
+#ifndef _di_f_file_mode_set_at_
+  extern f_return_status f_file_mode_set_at(const int at_id, const f_string path, const mode_t mode);
+#endif // _di_f_file_mode_set_at_
+
+/**
  * Get the base name of a file path.
  *
  * @param path
@@ -1610,6 +1576,87 @@ extern "C" {
 #endif // _di_f_file_remove_at_
 
 /**
+ * Change owner and/or group of a given file at the specified path.
+ *
+ * At least one of uid or gid must not be -1.
+ *
+ * @param path
+ *   The path file name.
+ * @param uid
+ *   The new user id to use.
+ *   Set to -1 to not change.
+ * @param gid
+ *   The new group id to use.
+ *   Set to -1 to not change.
+ * @param dereference
+ *   Set to TRUE to dereferenc symlinks (often is what is desired).
+ *   Set to FALSE to operate on the symlink itself.
+ *
+ * @return
+ *   F_none on success.
+ *   F_access_denied (with error bit) on access denied.
+ *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
+ *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
+ *   F_buffer (with error bit) if the buffer is invalid.
+ *   F_directory (with error bit) on invalid directory.
+ *   F_file_found_not (with error bit) if file at path was not found.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_loop (with error bit) on loop error.
+ *   F_memory_out (with error bit) if out of memory.
+ *   F_name (with error bit) on path name error.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_read_only (with error bit) if file is read-only.
+ *   F_failure (with error bit) for any other error.
+ *
+ * @see chown()
+ * @see lchown()
+ */
+#ifndef _di_f_file_role_change_
+  extern f_return_status f_file_role_change(const f_string path, const uid_t uid, const gid_t gid, const bool dereference);
+#endif // _di_f_file_role_change_
+
+/**
+ * Change owner and/or group of a given file at the specified path.
+ *
+ * At least one of uid or gid must not be -1.
+ *
+ * @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.
+ *   Set to -1 to not change.
+ * @param gid
+ *   The new group id to use.
+ *   Set to -1 to not change.
+ * @param flag
+ *   Any valid flag, such as f_file_at_path_empty, f_file_at_automount_no, or f_file_at_symlink_follow_no.
+ *
+ * @return
+ *   F_none on success.
+ *   F_access_denied (with error bit) on access denied.
+ *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
+ *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
+ *   F_buffer (with error bit) if the buffer is invalid.
+ *   F_directory (with error bit) on invalid directory.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
+ *   F_file_found_not (with error bit) if file at path was not found.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_loop (with error bit) on loop error.
+ *   F_memory_out (with error bit) if out of memory.
+ *   F_name (with error bit) on path name error.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_read_only (with error bit) if file is read-only.
+ *   F_failure (with error bit) for any other error.
+ *
+ * @see fchownat()
+ */
+#ifndef _di_f_file_role_change_at_
+  extern f_return_status f_file_role_change_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag);
+#endif // _di_f_file_role_change_at_
+
+/**
  * Given an open file descriptor, seek to a given location.
  *
  * @param id
index b592f3f63ed4bcbe6102247e8f706d318ee02b75..6b15ee697e82e3222a53c1dd0ef344fcd9492a83 100644 (file)
@@ -5,135 +5,6 @@
 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) {
-
-    if (chmod(path, mode) < 0) {
-      if (errno == EACCES) return F_status_set_error(F_access_denied);
-      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
-      if (errno == EFAULT) return F_status_set_error(F_buffer);
-      if (errno == ELOOP) return F_status_set_error(F_loop);
-      if (errno == ENOENT) return F_status_set_error(F_file_found_not);
-      if (errno == ENOMEM) return F_status_set_error(F_memory_out);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
-      if (errno == EPERM) return F_status_set_error(F_access_mode);
-      if (errno == EROFS) return F_status_set_error(F_read_only);
-      if (errno == EIO) return F_status_set_error(F_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) {
-
-    if (fchmodat(at_id, path, mode, 0) < 0) {
-      if (errno == EACCES) return F_status_set_error(F_access_denied);
-      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
-      if (errno == EFAULT) return F_status_set_error(F_buffer);
-      if (errno == ELOOP) return F_status_set_error(F_loop);
-      if (errno == ENOENT) return F_status_set_error(F_file_found_not);
-      if (errno == ENOMEM) return F_status_set_error(F_memory_out);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
-      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
-      if (errno == EPERM) return F_status_set_error(F_access_mode);
-      if (errno == EROFS) return F_status_set_error(F_read_only);
-      if (errno == EIO) return F_status_set_error(F_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_role_) || !defined(_di_f_file_copy_)
-  f_return_status private_f_file_change_role(const f_string path, const uid_t uid, const gid_t gid, const bool dereference) {
-    int result = 0;
-
-    if (dereference) {
-      if (uid != -1) {
-        result = chown(path, uid, -1);
-
-        if (result < 0 && errno == EPERM) return F_status_set_error(F_access_owner);
-      }
-
-      if (result == 0 && gid != -1) {
-        result = chown(path, -1, gid);
-
-        if (result < 0 && errno == EPERM) return F_status_set_error(F_access_group);
-      }
-    }
-    else {
-      if (uid != -1) {
-        result = lchown(path, uid, -1);
-
-        if (result < 0 && errno == EPERM) return F_status_set_error(F_access_owner);
-      }
-
-      if (gid != -1) {
-        result = lchown(path, -1, gid);
-
-        if (result < 0 && errno == EPERM) return F_status_set_error(F_access_group);
-      }
-    }
-
-    if (result < 0) {
-      if (errno == EACCES) return F_status_set_error(F_access_denied);
-      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
-      if (errno == EFAULT) return F_status_set_error(F_buffer);
-      if (errno == ELOOP) return F_status_set_error(F_loop);
-      if (errno == ENOENT) return F_status_set_error(F_file_found_not);
-      if (errno == ENOMEM) return F_status_set_error(F_memory_out);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
-      if (errno == EROFS) return F_status_set_error(F_read_only);
-      if (errno == EIO) return F_status_set_error(F_input_output);
-
-      return F_status_set_error(F_failure);
-    }
-
-    return F_none;
-  }
-#endif // !defined(_di_f_file_change_role_) || !defined(_di_f_file_copy_)
-
-#if !defined(_di_f_file_change_role_at_) || !defined(_di_f_file_copy_at_)
-  f_return_status private_f_file_change_role_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag) {
-    int result = 0;
-
-    if (uid != -1) {
-      result = fchownat(at_id, path, uid, -1, flag);
-
-      if (result < 0 && errno == EPERM) return F_status_set_error(F_access_owner);
-    }
-
-    if (gid != -1) {
-      result = fchownat(at_id, path, -1, gid, flag);
-
-      if (result < 0 && errno == EPERM) return F_status_set_error(F_access_group);
-    }
-
-    if (result < 0) {
-      if (errno == EACCES) return F_status_set_error(F_access_denied);
-      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
-      if (errno == EFAULT) return F_status_set_error(F_buffer);
-      if (errno == ELOOP) return F_status_set_error(F_loop);
-      if (errno == ENOENT) return F_status_set_error(F_file_found_not);
-      if (errno == ENOMEM) return F_status_set_error(F_memory_out);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
-      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
-      if (errno == EROFS) return F_status_set_error(F_read_only);
-      if (errno == EIO) return F_status_set_error(F_input_output);
-
-      return F_status_set_error(F_failure);
-    }
-
-    return F_none;
-  }
-#endif // !defined(_di_f_file_change_role_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(int *id) {
     if (F_status_is_error(private_f_file_flush(*id))) return F_status_set_error(F_file_synchronize);
@@ -575,6 +446,51 @@ extern "C" {
   }
 #endif // !defined(_di_f_file_link_read_at_) || !defined(_di_f_file_copy_at_)
 
+#if !defined(_di_f_file_mode_set_) || !defined(_di_f_file_copy_)
+  f_return_status private_f_file_mode_set(const f_string path, const mode_t mode) {
+
+    if (chmod(path, mode) < 0) {
+      if (errno == EACCES) return F_status_set_error(F_access_denied);
+      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+      if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == ELOOP) return F_status_set_error(F_loop);
+      if (errno == ENOENT) return F_status_set_error(F_file_found_not);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == EPERM) return F_status_set_error(F_access_mode);
+      if (errno == EROFS) return F_status_set_error(F_read_only);
+      if (errno == EIO) return F_status_set_error(F_input_output);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_none;
+  }
+#endif // !defined(_di_f_file_mode_set_) || !defined(_di_f_file_copy_)
+
+#if !defined(_di_f_file_mode_set_at_) || !defined(_di_f_file_copy_at_)
+  f_return_status private_f_file_mode_set_at(const int at_id, const f_string path, const mode_t mode) {
+
+    if (fchmodat(at_id, path, mode, 0) < 0) {
+      if (errno == EACCES) return F_status_set_error(F_access_denied);
+      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+      if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == ELOOP) return F_status_set_error(F_loop);
+      if (errno == ENOENT) return F_status_set_error(F_file_found_not);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
+      if (errno == EPERM) return F_status_set_error(F_access_mode);
+      if (errno == EROFS) return F_status_set_error(F_read_only);
+      if (errno == EIO) return F_status_set_error(F_input_output);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_none;
+  }
+#endif // !defined(_di_f_file_mode_set_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 mode_t mode, f_file *file) {
     if (mode == 0) {
@@ -650,6 +566,90 @@ extern "C" {
   }
 #endif // !defined(_di_f_file_open_at_) || !defined(_di_f_file_copy_at_)
 
+#if !defined(_di_f_file_role_change_) || !defined(_di_f_file_copy_)
+  f_return_status private_f_file_role_change(const f_string path, const uid_t uid, const gid_t gid, const bool dereference) {
+    int result = 0;
+
+    if (dereference) {
+      if (uid != -1) {
+        result = chown(path, uid, -1);
+
+        if (result < 0 && errno == EPERM) return F_status_set_error(F_access_owner);
+      }
+
+      if (result == 0 && gid != -1) {
+        result = chown(path, -1, gid);
+
+        if (result < 0 && errno == EPERM) return F_status_set_error(F_access_group);
+      }
+    }
+    else {
+      if (uid != -1) {
+        result = lchown(path, uid, -1);
+
+        if (result < 0 && errno == EPERM) return F_status_set_error(F_access_owner);
+      }
+
+      if (gid != -1) {
+        result = lchown(path, -1, gid);
+
+        if (result < 0 && errno == EPERM) return F_status_set_error(F_access_group);
+      }
+    }
+
+    if (result < 0) {
+      if (errno == EACCES) return F_status_set_error(F_access_denied);
+      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+      if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == ELOOP) return F_status_set_error(F_loop);
+      if (errno == ENOENT) return F_status_set_error(F_file_found_not);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == EROFS) return F_status_set_error(F_read_only);
+      if (errno == EIO) return F_status_set_error(F_input_output);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_none;
+  }
+#endif // !defined(_di_f_file_role_change_) || !defined(_di_f_file_copy_)
+
+#if !defined(_di_f_file_role_change_at_) || !defined(_di_f_file_copy_at_)
+  f_return_status private_f_file_role_change_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag) {
+    int result = 0;
+
+    if (uid != -1) {
+      result = fchownat(at_id, path, uid, -1, flag);
+
+      if (result < 0 && errno == EPERM) return F_status_set_error(F_access_owner);
+    }
+
+    if (gid != -1) {
+      result = fchownat(at_id, path, -1, gid, flag);
+
+      if (result < 0 && errno == EPERM) return F_status_set_error(F_access_group);
+    }
+
+    if (result < 0) {
+      if (errno == EACCES) return F_status_set_error(F_access_denied);
+      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+      if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == ELOOP) return F_status_set_error(F_loop);
+      if (errno == ENOENT) return F_status_set_error(F_file_found_not);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
+      if (errno == EROFS) return F_status_set_error(F_read_only);
+      if (errno == EIO) return F_status_set_error(F_input_output);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_none;
+  }
+#endif // !defined(_di_f_file_role_change_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, const bool dereference, struct stat *file_stat) {
 
index 7d045a580f12e10cad572207b7b92812fc5014ce..0ebfba2c75c698df477cf81801b4433416d78447 100644 (file)
@@ -16,146 +16,6 @@ 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.
- *
- * @return
- *   F_none on success.
- *   F_access_denied (with error bit) on access denied.
- *   F_access_mode (with error bit) if the current user does not have access to assign the file mode.
- *   F_directory (with error bit) on invalid directory.
- *   F_file_found_not (with error bit) if file at path was not found.
- *   F_input_output (with error bit) on I/O error.
- *   F_loop (with error bit) on loop error.
- *   F_memory_out (with error bit) if out of memory.
- *   F_name (with error bit) on path name error.
- *   F_parameter (with error bit) if a parameter is invalid.
- *   F_read_only (with error bit) if file is read-only.
- *   F_failure (with error bit) for any other error.
- *
- * @see f_file_change_mode()
- * @see f_file_copy()
- */
-#if !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_)
-  extern f_return_status private_f_file_change_mode(const f_string path, const mode_t mode) f_gcc_attribute_visibility_internal;
-#endif // !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_)
-
-/**
- * Private implementation of f_file_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.
- *
- * @return
- *   F_none on success.
- *   F_access_denied (with error bit) on access denied.
- *   F_access_mode (with error bit) if the current user does not have access to assign the file mode.
- *   F_file_found_not (with error bit) if file at path was not found.
- *   F_directory (with error bit) on invalid directory.
- *   F_input_output (with error bit) on I/O error.
- *   F_loop (with error bit) on loop error.
- *   F_memory_out (with error bit) if out of memory.
- *   F_name (with error bit) on path name error.
- *   F_parameter (with error bit) if a parameter is invalid.
- *   F_read_only (with error bit) if file is read-only.
- *   F_failure (with error bit) for any other error.
- *
- * @see f_file_change_mode_at()
- */
-#if !defined(_di_f_file_change_mode_at_)
-  extern f_return_status private_f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode) f_gcc_attribute_visibility_internal;
-#endif // !defined(_di_f_file_change_mode_at_)
-
-/**
- * Private implementation of f_file_change_role().
- *
- * Intended to be shared to each of the different implementation variations.
- *
- * @param path
- *   The path file name.
- * @param uid
- *   The new user id to use.
- * @param gid
- *   The new group id to use.
- * @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_access_denied (with error bit) on access denied.
- *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
- *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
- *   F_buffer (with error bit) if the buffer is invalid.
- *   F_directory (with error bit) on invalid directory.
- *   F_file_found_not (with error bit) if file at path was not found.
- *   F_input_output (with error bit) on I/O error.
- *   F_loop (with error bit) on loop error.
- *   F_memory_out (with error bit) if out of memory.
- *   F_name (with error bit) on path name error.
- *   F_parameter (with error bit) if a parameter is invalid.
- *   F_read_only (with error bit) if file is read-only.
- *   F_failure (with error bit) for any other error.
- *
- * @see f_file_change_role()
- * @see f_file_copy()
- */
-#if !defined(_di_f_file_change_role_) || !defined(_di_f_file_copy_)
-  extern f_return_status private_f_file_change_role(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_role_) || !defined(_di_f_file_copy_)
-
-/**
- * Private implementation of f_file_change_role_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 uid
- *   The new user id to use.
- * @param gid
- *   The new group id to use.
- * @param flag
- *   Any valid flag, such as f_file_at_path_empty, f_file_at_automount_no, or f_file_at_symlink_follow_no.
- *
- * @return
- *   F_none on success.
- *   F_access_denied (with error bit) on access denied.
- *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
- *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
- *   F_buffer (with error bit) if the buffer is invalid.
- *   F_directory (with error bit) on invalid directory.
- *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
- *   F_file_found_not (with error bit) if file at path was not found.
- *   F_input_output (with error bit) on I/O error.
- *   F_loop (with error bit) on loop error.
- *   F_memory_out (with error bit) if out of memory.
- *   F_name (with error bit) on path name error.
- *   F_parameter (with error bit) if a parameter is invalid.
- *   F_read_only (with error bit) if file is read-only.
- *   F_failure (with error bit) for any other error.
- *
- * @see f_file_change_role_at()
- */
-#if !defined(_di_f_file_change_role_at_)
-  extern f_return_status private_f_file_change_role_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag) f_gcc_attribute_visibility_internal;
-#endif // !defined(_di_f_file_change_role_at_)
-
-/**
  * Private implementation of f_file_close().
  *
  * Intended to be shared to each of the different implementation variations.
@@ -389,7 +249,9 @@ extern "C" {
 #endif // !defined(_di_f_file_copy_at_)
 
 /**
- * Create a fifo based on the given path and file mode.
+ * Private implementation of private_f_file_create_fifo().
+ *
+ * Intended to be shared to each of the different implementation variations.
  *
  * @param path
  *   The path file name.
@@ -418,7 +280,9 @@ extern "C" {
 #endif // !defined(_di_f_file_create_fifo_) || !defined(_di_f_file_copy_)
 
 /**
- * Create a fifo based on the given path and file mode.
+ * Private implementation of private_f_file_create_fifo_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.
@@ -698,6 +562,69 @@ extern "C" {
 #endif // !defined(_di_f_file_link_read_at_) || !defined(_di_f_file_copy_at_)
 
 /**
+ * Private implementation of f_file_mode_set().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param path
+ *   The path file name.
+ * @param mode
+ *   The new mode to use.
+ *
+ * @return
+ *   F_none on success.
+ *   F_access_denied (with error bit) on access denied.
+ *   F_access_mode (with error bit) if the current user does not have access to assign the file mode.
+ *   F_directory (with error bit) on invalid directory.
+ *   F_file_found_not (with error bit) if file at path was not found.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_loop (with error bit) on loop error.
+ *   F_memory_out (with error bit) if out of memory.
+ *   F_name (with error bit) on path name error.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_read_only (with error bit) if file is read-only.
+ *   F_failure (with error bit) for any other error.
+ *
+ * @see f_file_mode_set()
+ * @see f_file_copy()
+ */
+#if !defined(_di_f_file_mode_set_) || !defined(_di_f_file_copy_)
+  extern f_return_status private_f_file_mode_set(const f_string path, const mode_t mode) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_mode_set_) || !defined(_di_f_file_copy_)
+
+/**
+ * Private implementation of f_file_mode_set_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.
+ *
+ * @return
+ *   F_none on success.
+ *   F_access_denied (with error bit) on access denied.
+ *   F_access_mode (with error bit) if the current user does not have access to assign the file mode.
+ *   F_file_found_not (with error bit) if file at path was not found.
+ *   F_directory (with error bit) on invalid directory.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_loop (with error bit) on loop error.
+ *   F_memory_out (with error bit) if out of memory.
+ *   F_name (with error bit) on path name error.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_read_only (with error bit) if file is read-only.
+ *   F_failure (with error bit) for any other error.
+ *
+ * @see f_file_mode_set_at()
+ */
+#if !defined(_di_f_file_mode_set_at_)
+  extern f_return_status private_f_file_mode_set_at(const int at_id, const f_string path, const mode_t mode) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_mode_set_at_)
+
+/**
  * Private implementation of f_file_open().
  *
  * Intended to be shared to each of the different implementation variations.
@@ -755,6 +682,83 @@ extern "C" {
 #endif // !defined(_di_f_file_open_at_)
 
 /**
+ * Private implementation of f_file_role_change().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param path
+ *   The path file name.
+ * @param uid
+ *   The new user id to use.
+ * @param gid
+ *   The new group id to use.
+ * @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_access_denied (with error bit) on access denied.
+ *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
+ *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
+ *   F_buffer (with error bit) if the buffer is invalid.
+ *   F_directory (with error bit) on invalid directory.
+ *   F_file_found_not (with error bit) if file at path was not found.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_loop (with error bit) on loop error.
+ *   F_memory_out (with error bit) if out of memory.
+ *   F_name (with error bit) on path name error.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_read_only (with error bit) if file is read-only.
+ *   F_failure (with error bit) for any other error.
+ *
+ * @see f_file_role_change()
+ * @see f_file_copy()
+ */
+#if !defined(_di_f_file_role_change_) || !defined(_di_f_file_copy_)
+  extern f_return_status private_f_file_role_change(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_role_change_) || !defined(_di_f_file_copy_)
+
+/**
+ * Private implementation of f_file_role_change_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 uid
+ *   The new user id to use.
+ * @param gid
+ *   The new group id to use.
+ * @param flag
+ *   Any valid flag, such as f_file_at_path_empty, f_file_at_automount_no, or f_file_at_symlink_follow_no.
+ *
+ * @return
+ *   F_none on success.
+ *   F_access_denied (with error bit) on access denied.
+ *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
+ *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
+ *   F_buffer (with error bit) if the buffer is invalid.
+ *   F_directory (with error bit) on invalid directory.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
+ *   F_file_found_not (with error bit) if file at path was not found.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_loop (with error bit) on loop error.
+ *   F_memory_out (with error bit) if out of memory.
+ *   F_name (with error bit) on path name error.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_read_only (with error bit) if file is read-only.
+ *   F_failure (with error bit) for any other error.
+ *
+ * @see f_file_role_change_at()
+ */
+#if !defined(_di_f_file_role_change_at_)
+  extern f_return_status private_f_file_role_change_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_role_change_at_)
+
+/**
  * Private implementation of f_file_stat().
  *
  * Intended to be shared to each of the different implementation variations.
index e268c869f037fa2fef8318cca6682e885041b49c..0313d5a0b4f427456005a938837ae620707d20ad 100644 (file)
@@ -32,7 +32,7 @@ extern "C" {
         return F_status_set_error(F_directory_found);
       }
 
-      status = f_file_change_mode(destination, source_stat.st_mode);
+      status = f_file_mode_set(destination, source_stat.st_mode);
       if (F_status_is_error(status)) return status;
     }
     else {
@@ -41,7 +41,7 @@ extern "C" {
     }
 
     if (role) {
-      status = f_file_change_role(destination, source_stat.st_uid, source_stat.st_gid, F_true);
+      status = f_file_role_change(destination, source_stat.st_uid, source_stat.st_gid, F_true);
       if (F_status_is_error(status)) return status;
     }
 
@@ -137,7 +137,7 @@ extern "C" {
         return F_status_set_error(F_directory_found);
       }
 
-      status = f_file_change_mode(destination, mode.directory);
+      status = f_file_mode_set(destination, mode.directory);
       if (F_status_is_error(status)) return status;
     }
     else {
index c584a46e8988e24a245ab6355d0267f38f6eb390..71d01760887b65f72631a72119c281557f9dce2e 100644 (file)
@@ -97,8 +97,8 @@ extern "C" {
  *
  *   Errors from (with error bit): f_directory_create().
  *   Errors from (with error bit): f_directory_exists().
- *   Errors from (with error bit): f_file_change_mode().
- *   Errors from (with error bit): f_file_change_role().
+ *   Errors from (with error bit): f_file_mode_set().
+ *   Errors from (with error bit): f_file_role_change().
  *   Errors from (with error bit): f_file_stat().
  *
  * @see f_file_clone()
@@ -219,8 +219,8 @@ extern "C" {
  *
  *   Errors from (with error bit): f_directory_create().
  *   Errors from (with error bit): f_directory_exists().
- *   Errors from (with error bit): f_file_change_mode().
- *   Errors from (with error bit): f_file_change_role().
+ *   Errors from (with error bit): f_file_mode_set().
+ *   Errors from (with error bit): f_file_role_change().
  *   Errors from (with error bit): f_file_stat().
  *
  * @see f_file_copy()
index d42bae922a6e93ce390cc029966c5dc2bad4d570..77c5124d1cd22c534eff94bd3cbb69f65da49631 100644 (file)
@@ -112,7 +112,7 @@ extern "C" {
             break;
           }
 
-          status = f_file_change_mode(destination_sub.string, source_stat.st_mode);
+          status = f_file_mode_set(destination_sub.string, source_stat.st_mode);
           if (F_status_is_error(status)) break;
         }
         else {
@@ -121,7 +121,7 @@ extern "C" {
         }
 
         if (role) {
-          status = f_file_change_role(destination_sub.string, source_stat.st_uid, source_stat.st_gid, F_true);
+          status = f_file_role_change(destination_sub.string, source_stat.st_uid, source_stat.st_gid, F_true);
           if (F_status_is_error(status)) break;
         }
       }
@@ -328,7 +328,7 @@ extern "C" {
           break;
         }
 
-        status = f_file_change_mode(destination_sub.string, mode.directory);
+        status = f_file_mode_set(destination_sub.string, mode.directory);
         if (F_status_is_error(status)) break;
       }
       else {
index 598fe1c56f5c6f09cd22a9e23b4166d56b82b7f5..1a53e0fd2b2ae1489511e0694a4a55978f040bc3 100644 (file)
@@ -1479,9 +1479,9 @@ extern "C" {
       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);
+        *status = f_file_role_change(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);
+          fake_print_error_file(data, *status, "f_file_role_change", arguments.array[i].string, "change group of", F_true, F_true);
         }
       } // for
 
@@ -1496,9 +1496,9 @@ extern "C" {
 
       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);
+        *status = f_file_role_change(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);
+          fake_print_error_file(data, *status, "f_file_role_change", arguments.array[i].string, "change group of", F_true, F_true);
         }
       } // for
 
@@ -1527,18 +1527,29 @@ extern "C" {
 
       mode_t mode = 0;
 
+      struct stat stat_file;
+
       for (f_array_length i = 1; i < arguments.used; i++) {
-        // @todo: get the file mode.
+        mode = 0;
+        memset(&stat_file, 0, sizeof(struct stat));
 
-        if (replace) {
-          // @todo when replace is specified, then determine what is to be replaced when converting to mode_t.
+        *status = f_file_stat(arguments.array[i].string, F_true, &stat_file);
+        if (F_status_is_error(*status)) {
+          fake_print_error_file(data, *status, "f_file_stat", arguments.array[i].string, "change mode of", F_true, F_true);
+          break;
         }
 
-        // @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);
-        //}
+        *status = f_file_mode_determine(stat_file.st_mode, mode_rule, replace, f_macro_file_type_is_directory(stat_file.st_mode), data.umask, &mode);
+        if (F_status_is_error(*status)) {
+          fake_print_error_file(data, *status, "f_file_mode_determine", arguments.array[i].string, "change mode of", F_true, F_true);
+          break;
+        }
+
+        *status = f_file_mode_set(arguments.array[i].string, mode);
+        if (F_status_is_error(*status)) {
+          fake_print_error_file(data, *status, "f_file_mode_set", arguments.array[i].string, "change mode of", F_true, F_true);
+          break;
+        }
       } // for
 
       return;
@@ -1561,9 +1572,9 @@ extern "C" {
       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);
+        *status = f_file_role_change(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);
+          fake_print_error_file(data, *status, "f_file_role_change", arguments.array[i].string, "change owner of", F_true, F_true);
         }
       } // for
 
@@ -1578,9 +1589,9 @@ extern "C" {
 
       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);
+        *status = f_file_role_change(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);
+          fake_print_error_file(data, *status, "f_file_role_change", arguments.array[i].string, "change owner of", F_true, F_true);
         }
       } // for
 
@@ -2124,15 +2135,12 @@ extern "C" {
       }
     }
     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;
 
         for (f_array_length i = 1; i < arguments.used; i++) {
           status_file = f_file_is(arguments.array[i].string, f_file_type_regular);
 
-          printf("DEBUG: at %llu, looking at '%s', %llu\n", i, arguments.array[i].string, F_status_set_fine(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 '");
index 1128fed55e77558c11bdb5d09084a25927aae475..0d95a1860af4e34cadcef68aa1291496e84e0b88 100644 (file)
@@ -10,4 +10,5 @@ settings:
 main:
 
   #build
-  owner a b
+  touch file b
+  mode =755 b