[libc-commits] [libc] feat(filemode): implement class and helper functions to handle file modes for an opened file (PR #220906)

David Dada via libc-commits libc-commits at lists.llvm.org
Wed Sep 9 12:49:17 PDT 2026


https://github.com/obadafidii updated https://github.com/llvm/llvm-project/pull/220906

>From e3dc3a646ef6c422e75810881826e211aebb7a3b Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Thu, 3 Sep 2026 13:21:11 +0100
Subject: [PATCH 01/16] feat(filemode): implement class and helper functions to
 handle file modes for an opened file

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/file_mode.h | 125 ++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)
 create mode 100644 libc/src/__support/File/file_mode.h

diff --git a/libc/src/__support/File/file_mode.h b/libc/src/__support/File/file_mode.h
new file mode 100644
index 0000000000000..6b837ea46f652
--- /dev/null
+++ b/libc/src/__support/File/file_mode.h
@@ -0,0 +1,125 @@
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H
+#define LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H
+#include <cstdint>
+
+namespace LIBC_NAMESPACE_DECL {
+
+// FileMode class handles everything regarding the mode of the file, be it's opening mode or content type.
+class FileMode {
+public:
+  // FileMode constructor accepts the mode string as an argument.
+  // It performs validation against several rules and records the `file_mode` property to
+  // the specific mode.
+  explicit FileMode(const char *mode) : file_mode_(0) {
+    // First character in |mode| should be 'a', 'r' or 'w'.
+    if (*mode != 'a' && *mode != 'r' && *mode != 'w')
+      return;
+
+    // There should be exactly one main mode ('a', 'r' or 'w') character.
+    // If there are more than one main mode characters listed, then
+    // we will consider |mode| as incorrect and return 0;
+    int main_mode_count = 0;
+
+    for (; *mode != '\0'; ++mode) {
+      switch (*mode) {
+      case 'r':
+        file_mode_ |= static_cast<Mode>(OpenMode::READ);
+        ++main_mode_count;
+        break;
+      case 'w':
+        file_mode_ |= static_cast<Mode>(OpenMode::WRITE);
+        ++main_mode_count;
+        break;
+      case '+':
+        file_mode_ |= static_cast<Mode>(OpenMode::PLUS);
+        break;
+      case 'b':
+        file_mode_ |= static_cast<Mode>(ContentType::BINARY);
+        break;
+      case 'a':
+        file_mode_ |= static_cast<Mode>(OpenMode::APPEND);
+        ++main_mode_count;
+        break;
+      case 'x':
+        file_mode_ |= static_cast<Mode>(CreateType::EXCLUSIVE);
+        break;
+      default:
+        file_mode_ = 0;
+      }
+    }
+
+    if (main_mode_count != 1)
+      file_mode_ = 0;
+  }
+
+  // helper function to show if file allows writing
+  bool write_allowed() const {
+    return (file_mode_ & static_cast<Mode>(OpenMode::WRITE)) != 0;
+  }
+
+  // helper function to show if file allows reading
+  bool read_allowed() const {
+    return (file_mode_ & static_cast<Mode>(OpenMode::READ)) != 0;
+  }
+
+  // helper function to show if file allows appending
+  bool append_allowed() const {
+    return (file_mode_ & static_cast<Mode>(OpenMode::APPEND)) != 0;
+  }
+
+  // helper function to denote if the file is in binary format.
+  bool is_binary_format() const {
+    return (file_mode_ & static_cast<Mode>(ContentType::BINARY)) != 0;
+  }
+
+  // '+' means update is allowed
+  // TODO: ask michael if I need to give it a better name like "update_allowed" or just continue with the
+  // old convention.
+  bool is_plus() const {
+    return (file_mode_ & static_cast<Mode>(OpenMode::PLUS)) != 0;
+  }
+
+  // checks if a file was created for writing
+  bool is_exclusive_create() const {
+    return (file_mode_ & static_cast<Mode>(CreateType::EXCLUSIVE)) != 0;
+  }
+
+private:
+  // Mode is a generic or abstract mode bit for all kinds of modes
+  // (open-mode, 'content-mode', 'create-modes')
+  using Mode = uint32_t;
+
+  // Denotes the mode of the file.
+  //
+  // The three different types of flags below are to be used with '|' operator.
+  // Their values correspond to mutually exclusive bits in a 32-bit unsigned
+  // integer value. A flag set can include both READ and WRITE if the file
+  // is opened in update mode (ie. if the file was opened with a '+' the mode
+  // string.)
+  enum class OpenMode: Mode {
+    READ = 0x1,
+    WRITE = 0x2,
+    APPEND = 0x4,
+    PLUS = 0x8,
+  };
+
+  // Denotes a file opened in binary mode (which is specified by including
+  // the 'b' character in teh mode string.)
+  enum class ContentType: Mode {
+    BINARY = 0x10,
+  };
+
+  // Denotes a file to be created for writing.
+  enum class CreateType: Mode {
+    EXCLUSIVE = 0x100,
+  };
+
+  // This property tracks the mode for the particular file instance (i.e currently opened file)
+  int file_mode_;
+};
+
+
+}
+
+#endif // LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H

>From b0470fe313766fcb4fac92b63d41d39314a90f75 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Thu, 3 Sep 2026 14:08:49 +0100
Subject: [PATCH 02/16] feat(lint): lint file mode class to conform to
 standards

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/file_mode.h | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/libc/src/__support/File/file_mode.h b/libc/src/__support/File/file_mode.h
index 6b837ea46f652..707a448c5955d 100644
--- a/libc/src/__support/File/file_mode.h
+++ b/libc/src/__support/File/file_mode.h
@@ -5,12 +5,13 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-// FileMode class handles everything regarding the mode of the file, be it's opening mode or content type.
+// FileMode class handles everything regarding the mode of the file, be it's
+// opening mode or content type.
 class FileMode {
 public:
   // FileMode constructor accepts the mode string as an argument.
-  // It performs validation against several rules and records the `file_mode` property to
-  // the specific mode.
+  // It performs validation against several rules and records the `file_mode`
+  // property to the specific mode.
   explicit FileMode(const char *mode) : file_mode_(0) {
     // First character in |mode| should be 'a', 'r' or 'w'.
     if (*mode != 'a' && *mode != 'r' && *mode != 'w')
@@ -74,8 +75,8 @@ class FileMode {
   }
 
   // '+' means update is allowed
-  // TODO: ask michael if I need to give it a better name like "update_allowed" or just continue with the
-  // old convention.
+  // TODO: ask michael if I need to give it a better name like "update_allowed"
+  // or just continue with the old convention.
   bool is_plus() const {
     return (file_mode_ & static_cast<Mode>(OpenMode::PLUS)) != 0;
   }
@@ -97,7 +98,7 @@ class FileMode {
   // integer value. A flag set can include both READ and WRITE if the file
   // is opened in update mode (ie. if the file was opened with a '+' the mode
   // string.)
-  enum class OpenMode: Mode {
+  enum class OpenMode : Mode {
     READ = 0x1,
     WRITE = 0x2,
     APPEND = 0x4,
@@ -106,20 +107,20 @@ class FileMode {
 
   // Denotes a file opened in binary mode (which is specified by including
   // the 'b' character in teh mode string.)
-  enum class ContentType: Mode {
+  enum class ContentType : Mode {
     BINARY = 0x10,
   };
 
   // Denotes a file to be created for writing.
-  enum class CreateType: Mode {
+  enum class CreateType : Mode {
     EXCLUSIVE = 0x100,
   };
 
-  // This property tracks the mode for the particular file instance (i.e currently opened file)
+  // This property tracks the mode for the particular file instance (i.e
+  // currently opened file)
   int file_mode_;
 };
 
-
-}
+} // namespace LIBC_NAMESPACE_DECL
 
 #endif // LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H

>From d208bddb974f3c55dcbcc35a17523eaccff20c79 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 14:31:48 +0100
Subject: [PATCH 03/16] feat(file_mode): update write_allowed and read_allowed
 method to use new api

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/file.h | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h
index 67879e6c9933e..08f8b93b8f215 100644
--- a/libc/src/__support/File/file.h
+++ b/libc/src/__support/File/file.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_LIBC_SRC___SUPPORT_FILE_FILE_H
 #define LLVM_LIBC_SRC___SUPPORT_FILE_FILE_H
 
+#include "file_mode.h"
 #include "hdr/stdint_proxy.h"
 #include "hdr/stdio_macros.h"
 #include "hdr/types/off_t.h"
@@ -122,8 +123,12 @@ class File {
   bool own_buf;
 
   // The mode in which the file was opened.
+  //TODO: old way of doing things
+  // clean up when totally done with pr
   ModeFlags mode;
 
+  FileMode file_mode;
+
   // Current read or write pointer.
   size_t pos;
 
@@ -155,14 +160,13 @@ class File {
 
 protected:
   constexpr bool write_allowed() const {
-    return mode & (static_cast<ModeFlags>(OpenMode::WRITE) |
-                   static_cast<ModeFlags>(OpenMode::APPEND) |
-                   static_cast<ModeFlags>(OpenMode::PLUS));
+    return file_mode.write_allowed() ||
+        file_mode.append_allowed() ||
+          file_mode.is_plus(); //TODO: if micheal agrees for me to convert it change it here
   }
 
   constexpr bool read_allowed() const {
-    return mode & (static_cast<ModeFlags>(OpenMode::READ) |
-                   static_cast<ModeFlags>(OpenMode::PLUS));
+    return file_mode.read_allowed() || file_mode.is_plus();
   }
 
   void reset_stream_state_unlocked(ModeFlags new_mode) {

>From 91f4a23232fb9d2992a69286e74241002513c86e Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 16:47:57 +0100
Subject: [PATCH 04/16] feat: add method to check validity of a file mode

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/file_mode.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libc/src/__support/File/file_mode.h b/libc/src/__support/File/file_mode.h
index 707a448c5955d..92647decd2e76 100644
--- a/libc/src/__support/File/file_mode.h
+++ b/libc/src/__support/File/file_mode.h
@@ -1,7 +1,8 @@
 
 #ifndef LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H
 #define LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H
-#include <cstdint>
+
+#include "hdr/stdint_proxy.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
@@ -54,6 +55,8 @@ class FileMode {
       file_mode_ = 0;
   }
 
+  bool is_valid() const { return file_mode_ != 0; }
+
   // helper function to show if file allows writing
   bool write_allowed() const {
     return (file_mode_ & static_cast<Mode>(OpenMode::WRITE)) != 0;

>From 86ef8ab5c1b9efc429df6ce9e9dfedb2bfa822e9 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 16:49:02 +0100
Subject: [PATCH 05/16] add config header for namespace resolution

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/file_mode.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libc/src/__support/File/file_mode.h b/libc/src/__support/File/file_mode.h
index 92647decd2e76..e7f46d6172833 100644
--- a/libc/src/__support/File/file_mode.h
+++ b/libc/src/__support/File/file_mode.h
@@ -3,6 +3,7 @@
 #define LLVM_LIBC_SRC___SUPPORT_FILE_FILE_MODE_H
 
 #include "hdr/stdint_proxy.h"
+#include "src/__support/macros/config.h"
 
 namespace LIBC_NAMESPACE_DECL {
 

>From e97d27a9e2d28d37a0e75790be6b4820e5f0d27e Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 16:50:49 +0100
Subject: [PATCH 06/16] feat: make FileMode constructor a constexpr

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/file_mode.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/__support/File/file_mode.h b/libc/src/__support/File/file_mode.h
index e7f46d6172833..88ca0f5a2aa21 100644
--- a/libc/src/__support/File/file_mode.h
+++ b/libc/src/__support/File/file_mode.h
@@ -14,7 +14,7 @@ class FileMode {
   // FileMode constructor accepts the mode string as an argument.
   // It performs validation against several rules and records the `file_mode`
   // property to the specific mode.
-  explicit FileMode(const char *mode) : file_mode_(0) {
+  constexpr FileMode(const char *mode) : file_mode_(0) {
     // First character in |mode| should be 'a', 'r' or 'w'.
     if (*mode != 'a' && *mode != 'r' && *mode != 'w')
       return;

>From 85003b267932ad24be42eff1f569321c7854944d Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 16:53:22 +0100
Subject: [PATCH 07/16] feat(file.h): refactor File class to use FileMode to
 handle mode related operations

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/file.h | 50 ++++++----------------------------
 1 file changed, 8 insertions(+), 42 deletions(-)

diff --git a/libc/src/__support/File/file.h b/libc/src/__support/File/file.h
index 6e06e0d6d28bd..a0ea9b7e9d156 100644
--- a/libc/src/__support/File/file.h
+++ b/libc/src/__support/File/file.h
@@ -68,31 +68,6 @@ class File {
   using SeekFunc = ErrorOr<off_t>(File *, off_t, int);
   using CloseFunc = int(File *);
 
-  using ModeFlags = uint32_t;
-
-  // The three different types of flags below are to be used with '|' operator.
-  // Their values correspond to mutually exclusive bits in a 32-bit unsigned
-  // integer value. A flag set can include both READ and WRITE if the file
-  // is opened in update mode (ie. if the file was opened with a '+' the mode
-  // string.)
-  enum class OpenMode : ModeFlags {
-    READ = 0x1,
-    WRITE = 0x2,
-    APPEND = 0x4,
-    PLUS = 0x8,
-  };
-
-  // Denotes a file opened in binary mode (which is specified by including
-  // the 'b' character in teh mode string.)
-  enum class ContentType : ModeFlags {
-    BINARY = 0x10,
-  };
-
-  // Denotes a file to be created for writing.
-  enum class CreateType : ModeFlags {
-    EXCLUSIVE = 0x100,
-  };
-
   // This is a convenience RAII class to lock and unlock file objects.
   class FileLock {
     File *file;
@@ -135,12 +110,7 @@ class File {
   // free-ed when close method is called on the stream.
   bool own_buf;
 
-  // The mode in which the file was opened.
-  //TODO: old way of doing things
-  // clean up when totally done with pr
-  ModeFlags mode;
-
-  FileMode file_mode;
+  FileMode mode;
 
   // Current read or write pointer.
   size_t pos;
@@ -160,16 +130,16 @@ class File {
 
 protected:
   constexpr bool write_allowed() const {
-    return file_mode.write_allowed() ||
-        file_mode.append_allowed() ||
-          file_mode.is_plus(); //TODO: if micheal agrees for me to convert it change it here
+    return mode.write_allowed() || mode.append_allowed() ||
+           mode.is_plus(); // TODO: if micheal agrees for me to convert it
+                           // change it here
   }
 
   constexpr bool read_allowed() const {
-    return file_mode.read_allowed() || file_mode.is_plus();
+    return mode.read_allowed() || mode.is_plus();
   }
 
-  void reset_stream_state_unlocked(ModeFlags new_mode) {
+  void reset_stream_state_unlocked(FileMode new_mode) {
     mode = new_mode;
     pos = 0;
     prev_op = FileOp::NONE;
@@ -191,12 +161,12 @@ class File {
   // the set_buffer method and allocate a buffer.
   constexpr File(WriteFunc *wf, ReadFunc *rf, SeekFunc *sf, CloseFunc *cf,
                  uint8_t *buffer, size_t buffer_size, int buffer_mode,
-                 bool owned, ModeFlags modeflags)
+                 bool owned, FileMode mode)
       : platform_write(wf), platform_read(rf), platform_seek(sf),
         platform_close(cf), mutex(/*timed=*/false, /*recursive=*/false,
                                   /*robust=*/false, /*pshared=*/false),
         ungetc_buf{}, buf(buffer), bufsize(buffer_size), bufmode(buffer_mode),
-        own_buf(owned), mode(modeflags), pos(0), prev_op(FileOp::NONE),
+        own_buf(owned), mode(mode), pos(0), prev_op(FileOp::NONE),
         read_limit(0), eof(false), err(false),
         orientation(Orientation::UNORIENTED), mbstate(), prev(nullptr),
         next(nullptr) {
@@ -356,10 +326,6 @@ class File {
     return try_set_orientation_unlocked(o);
   }
 
-  // Returns an bit map of flags corresponding to enumerations of
-  // OpenMode, ContentType and CreateType.
-  static ModeFlags mode_flags(const char *mode);
-
 private:
   FileIOResult write_unlocked_impl(const void *data, size_t len);
   FileIOResult read_unlocked_impl(void *data, size_t len);

>From 400aa53c132cb130c0187e376d6c5c78ad9b3b22 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 16:56:51 +0100
Subject: [PATCH 08/16] feat(file.cpp): remove  modeFlags function

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/file.cpp | 45 --------------------------------
 1 file changed, 45 deletions(-)

diff --git a/libc/src/__support/File/file.cpp b/libc/src/__support/File/file.cpp
index fb8268a297a1a..d0366100525ac 100644
--- a/libc/src/__support/File/file.cpp
+++ b/libc/src/__support/File/file.cpp
@@ -510,51 +510,6 @@ int File::set_buffer(void *buffer, size_t size, int buffer_mode) {
   return 0;
 }
 
-File::ModeFlags File::mode_flags(const char *mode) {
-  // First character in |mode| should be 'a', 'r' or 'w'.
-  if (*mode != 'a' && *mode != 'r' && *mode != 'w')
-    return 0;
-
-  // There should be exaclty one main mode ('a', 'r' or 'w') character.
-  // If there are more than one main mode characters listed, then
-  // we will consider |mode| as incorrect and return 0;
-  int main_mode_count = 0;
-
-  ModeFlags flags = 0;
-  for (; *mode != '\0'; ++mode) {
-    switch (*mode) {
-    case 'r':
-      flags |= static_cast<ModeFlags>(OpenMode::READ);
-      ++main_mode_count;
-      break;
-    case 'w':
-      flags |= static_cast<ModeFlags>(OpenMode::WRITE);
-      ++main_mode_count;
-      break;
-    case '+':
-      flags |= static_cast<ModeFlags>(OpenMode::PLUS);
-      break;
-    case 'b':
-      flags |= static_cast<ModeFlags>(ContentType::BINARY);
-      break;
-    case 'a':
-      flags |= static_cast<ModeFlags>(OpenMode::APPEND);
-      ++main_mode_count;
-      break;
-    case 'x':
-      flags |= static_cast<ModeFlags>(CreateType::EXCLUSIVE);
-      break;
-    default:
-      return 0;
-    }
-  }
-
-  if (main_mode_count != 1)
-    return 0;
-
-  return flags;
-}
-
 FileIOResult File::write_unlocked(const wchar_t *ws, size_t len) {
   switch (orientation) {
   case Orientation::BYTE:

>From 5d8d1901a32b77faaf25506c2137c290c22fbecd Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 17:00:04 +0100
Subject: [PATCH 09/16] feat(linux-file): update linux file constructor to
 accept FileMode instance instead of ModeFlags

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/linux/file.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libc/src/__support/File/linux/file.h b/libc/src/__support/File/linux/file.h
index 700db415156ae..539957b8b22c8 100644
--- a/libc/src/__support/File/linux/file.h
+++ b/libc/src/__support/File/linux/file.h
@@ -8,6 +8,7 @@
 
 #include "hdr/types/off_t.h"
 #include "src/__support/File/file.h"
+#include "src/__support/File/file_mode.h"
 #include "src/__support/macros/config.h"
 
 namespace LIBC_NAMESPACE_DECL {
@@ -22,10 +23,9 @@ class LinuxFile : public File {
 
 public:
   constexpr LinuxFile(int file_descriptor, uint8_t *buffer, size_t buffer_size,
-                      int buffer_mode, bool owned, File::ModeFlags modeflags)
+                      int buffer_mode, bool owned, FileMode mode)
       : File(&linux_file_write, &linux_file_read, &linux_file_seek,
-             &linux_file_close, buffer, buffer_size, buffer_mode, owned,
-             modeflags),
+             &linux_file_close, buffer, buffer_size, buffer_mode, owned, mode),
         fd(file_descriptor) {}
 
   int get_fd() const { return fd; }

>From 17152f2ddfb93c338208dacbd7c5fd90bb589f87 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 17:04:28 +0100
Subject: [PATCH 10/16] feat: create new method to map c-mode flags to linux
 open flags

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/linux/file.cpp | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp
index 613fadc5b1f3e..ce92ca818a3fb 100644
--- a/libc/src/__support/File/linux/file.cpp
+++ b/libc/src/__support/File/linux/file.cpp
@@ -14,6 +14,7 @@
 #include "hdr/types/off_t.h"
 #include "src/__support/CPP/new.h"
 #include "src/__support/File/file.h"
+#include "src/__support/File/file_mode.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/close.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/dup2.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/fcntl.h"
@@ -68,6 +69,30 @@ int linux_file_close(File *f) {
   return retval;
 }
 
+static int map_c_mode_flags_to_linux_open_flags(FileMode mode) {
+  FileMode file_mode(mode);
+
+  if (file_mode.append_allowed()) {
+    open_flags = O_CREAT | O_APPEND;
+    if (file_mode.is_plus())
+      open_flags |= O_RDWR;
+    else
+      open_flags |= O_WRONLY;
+  } else if (file_mode.write_allowed()) {
+    open_flags = O_CREAT | O_TRUNC;
+    if (file_mode.is_plus())
+      open_flags |= O_RDWR;
+    else
+      open_flags |= O_WRONLY;
+  } else {
+    if (file_mode.is_plus())
+      open_flags |= O_RDWR;
+    else
+      open_flags |= O_RDONLY;
+  }
+  return open_flags;
+}
+
 static int mode_flags_to_open_flags(File::ModeFlags modeflags) {
   using ModeFlags = File::ModeFlags;
   int open_flags = 0;

>From 3cc1aed286b95db440ea9a83a795b86c35d40a63 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 17:08:12 +0100
Subject: [PATCH 11/16] refactor openfile function to work with FileMode
 instead of ModeFlags

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/linux/file.cpp | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp
index ce92ca818a3fb..0b39f2f8e21cb 100644
--- a/libc/src/__support/File/linux/file.cpp
+++ b/libc/src/__support/File/linux/file.cpp
@@ -93,6 +93,7 @@ static int map_c_mode_flags_to_linux_open_flags(FileMode mode) {
   return open_flags;
 }
 
+// TODO: clean up
 static int mode_flags_to_open_flags(File::ModeFlags modeflags) {
   using ModeFlags = File::ModeFlags;
   int open_flags = 0;
@@ -118,11 +119,12 @@ static int mode_flags_to_open_flags(File::ModeFlags modeflags) {
 }
 
 ErrorOr<File *> openfile(const char *path, const char *mode) {
-  auto modeflags = File::mode_flags(mode);
-  if (modeflags == 0) {
+  FileMode file_mode(mode);
+
+  if (!file_mode.is_valid()) {
     return Error(EINVAL);
   }
-  int open_flags = mode_flags_to_open_flags(modeflags);
+  int open_flags = map_c_mode_flags_to_linux_open_flags(file_mode);
 
   // File created will have 0666 permissions.
   constexpr mode_t OPEN_MODE =
@@ -141,7 +143,7 @@ ErrorOr<File *> openfile(const char *path, const char *mode) {
   }
   AllocChecker ac;
   auto *file = new (ac) LinuxFile(fd.value(), buffer, File::DEFAULT_BUFFER_SIZE,
-                                  _IOFBF, true, modeflags);
+                                  _IOFBF, true, file_mode);
   if (!ac)
     return Error(ENOMEM);
   File::add_file(file);

>From e28986fb0a868511189fbe9e85a5a260c93b76af Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 17:14:46 +0100
Subject: [PATCH 12/16] refactor create_file_from_fd to use FileMode instance
 for handling file mode

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/linux/file.cpp | 28 ++++++++++----------------
 1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp
index 0b39f2f8e21cb..e5510d931ee4e 100644
--- a/libc/src/__support/File/linux/file.cpp
+++ b/libc/src/__support/File/linux/file.cpp
@@ -151,9 +151,9 @@ ErrorOr<File *> openfile(const char *path, const char *mode) {
 }
 
 ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode) {
-  using ModeFlags = File::ModeFlags;
-  ModeFlags modeflags = File::mode_flags(mode);
-  if (modeflags == 0) {
+  FileMode file_mode(mode);
+
+  if (!file_mode.is_valid()) {
     return Error(EINVAL);
   }
 
@@ -163,25 +163,19 @@ ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode) {
   }
   int fd_flags = result.value();
 
-  using OpenMode = File::OpenMode;
-  using ModeFlags = File::ModeFlags;
+  constexpr int REQUIRES_WRITE = file_mode.write_allowed() |
+                                 file_mode.append_allowed() |
+                                 file_mode.is_plus();
 
-  constexpr ModeFlags REQUIRES_WRITE =
-      static_cast<ModeFlags>(OpenMode::WRITE) |
-      static_cast<ModeFlags>(OpenMode::APPEND) |
-      static_cast<ModeFlags>(OpenMode::PLUS);
+  constexpr int REQUIRES_READ = file_mode.write_allowed() | file_mode.is_plus();
 
-  constexpr ModeFlags REQUIRES_READ = static_cast<ModeFlags>(OpenMode::READ) |
-                                      static_cast<ModeFlags>(OpenMode::PLUS);
-
-  if (((fd_flags & O_ACCMODE) == O_RDONLY && (modeflags & REQUIRES_WRITE)) ||
-      ((fd_flags & O_ACCMODE) == O_WRONLY && (modeflags & REQUIRES_READ))) {
+  if (((fd_flags & O_ACCMODE) == O_RDONLY && REQUIRES_WRITE) ||
+      ((fd_flags & O_ACCMODE) == O_WRONLY && REQUIRES_READ)) {
     return Error(EINVAL);
   }
 
   bool do_seek = false;
-  if ((modeflags & static_cast<ModeFlags>(OpenMode::APPEND)) &&
-      !(fd_flags & O_APPEND)) {
+  if (file_mode.append_allowed() && !(fd_flags & O_APPEND)) {
     do_seek = true;
     if (!linux_syscalls::fcntl(fd, F_SETFL,
                                reinterpret_cast<void *>(fd_flags | O_APPEND))
@@ -200,7 +194,7 @@ ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode) {
   }
   AllocChecker ac;
   auto *file = new (ac)
-      LinuxFile(fd, buffer, File::DEFAULT_BUFFER_SIZE, _IOFBF, true, modeflags);
+      LinuxFile(fd, buffer, File::DEFAULT_BUFFER_SIZE, _IOFBF, true, file_mode);
   if (!ac) {
     return Error(ENOMEM);
   }

>From 8b11ddd5101184b65abee156d74241c036257c56 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 17:22:52 +0100
Subject: [PATCH 13/16] refactor reopen_unlocked to use FileMode implementation
 and initialize open_flags in c to linux open flags map function

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/linux/file.cpp | 46 +++++++++++---------------
 1 file changed, 20 insertions(+), 26 deletions(-)

diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp
index e5510d931ee4e..95aefa366fab1 100644
--- a/libc/src/__support/File/linux/file.cpp
+++ b/libc/src/__support/File/linux/file.cpp
@@ -72,6 +72,8 @@ int linux_file_close(File *f) {
 static int map_c_mode_flags_to_linux_open_flags(FileMode mode) {
   FileMode file_mode(mode);
 
+  int open_flags = 0;
+
   if (file_mode.append_allowed()) {
     open_flags = O_CREAT | O_APPEND;
     if (file_mode.is_plus())
@@ -211,23 +213,21 @@ ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode) {
 }
 
 int LinuxFile::reopen_unlocked(const char *path, const char *mode) {
-  flush_unlocked();
-
-  auto modeflags = File::mode_flags(mode);
+  FileMode file_mode(mode);
 
   if (path != nullptr) {
     int old_fd = get_fd();
 
-    if (modeflags == 0) {
+    if (!file_mode.is_valid()) {
       if (old_fd >= 0) {
         linux_syscalls::close(old_fd);
         set_fd(-1);
       }
-      reset_stream_state_unlocked(modeflags);
+      reset_stream_state_unlocked(file_mode);
       return EINVAL;
     }
 
-    int open_flags = mode_flags_to_open_flags(modeflags);
+    int open_flags = map_c_mode_flags_to_linux_open_flags(file_mode);
 
     constexpr mode_t OPEN_MODE =
         S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
@@ -244,7 +244,7 @@ int LinuxFile::reopen_unlocked(const char *path, const char *mode) {
 
         set_fd(-1);
       }
-      reset_stream_state_unlocked(modeflags);
+      reset_stream_state_unlocked(file_mode);
       return new_fd.error();
     }
 
@@ -254,23 +254,23 @@ int LinuxFile::reopen_unlocked(const char *path, const char *mode) {
       auto dup_result = linux_syscalls::dup2(new_fd.value(), old_fd);
       if (!dup_result) {
         linux_syscalls::close(new_fd.value());
-        reset_stream_state_unlocked(modeflags);
+        reset_stream_state_unlocked(file_mode);
         return dup_result.error();
       }
       auto close_result = linux_syscalls::close(new_fd.value());
       if (!close_result) {
-        reset_stream_state_unlocked(modeflags);
+        reset_stream_state_unlocked(file_mode);
         return close_result.error();
       }
     } else {
       set_fd(new_fd.value());
     }
 
-    reset_stream_state_unlocked(modeflags);
+    reset_stream_state_unlocked(file_mode);
     return 0;
   }
 
-  if (modeflags == 0)
+  if (!file_mode.is_valid())
     return EINVAL;
 
   if (fd < 0)
@@ -281,34 +281,28 @@ int LinuxFile::reopen_unlocked(const char *path, const char *mode) {
     return EBADF;
   int fd_flags = result.value();
 
-  using OpenMode = File::OpenMode;
-  using ModeFlags = File::ModeFlags;
-
-  constexpr ModeFlags REQUIRES_WRITE =
-      static_cast<ModeFlags>(OpenMode::WRITE) |
-      static_cast<ModeFlags>(OpenMode::APPEND) |
-      static_cast<ModeFlags>(OpenMode::PLUS);
+  constexpr int REQUIRES_WRITE = file_mode.write_allowed() |
+                                 file_mode.append_allowed() |
+                                 file_mode.is_plus();
 
-  constexpr ModeFlags REQUIRES_READ = static_cast<ModeFlags>(OpenMode::READ) |
-                                      static_cast<ModeFlags>(OpenMode::PLUS);
+  constexpr int REQUIRES_READ = file_mode.write_allowed() | file_mode.is_plus();
 
-  if (((fd_flags & O_ACCMODE) == O_RDONLY && (modeflags & REQUIRES_WRITE)) ||
-      ((fd_flags & O_ACCMODE) == O_WRONLY && (modeflags & REQUIRES_READ))) {
+  if (((fd_flags & O_ACCMODE) == O_RDONLY && REQUIRES_WRITE) ||
+      ((fd_flags & O_ACCMODE) == O_WRONLY && REQUIRES_READ)) {
     return EBADF;
   }
 
   bool do_seek = false;
-  bool is_append = modeflags & static_cast<ModeFlags>(OpenMode::APPEND);
   bool has_append_flag = fd_flags & O_APPEND;
 
-  if (is_append && !has_append_flag) {
+  if (file_mode.append_allowed() && !has_append_flag) {
     if (!linux_syscalls::fcntl(fd, F_SETFL,
                                reinterpret_cast<void *>(fd_flags | O_APPEND))
              .has_value()) {
       return EBADF;
     }
     do_seek = true;
-  } else if (!is_append && has_append_flag) {
+  } else if (!file_mode.append_allowed() && has_append_flag) {
     if (!linux_syscalls::fcntl(fd, F_SETFL,
                                reinterpret_cast<void *>(fd_flags & ~O_APPEND))
              .has_value()) {
@@ -316,7 +310,7 @@ int LinuxFile::reopen_unlocked(const char *path, const char *mode) {
     }
   }
 
-  reset_stream_state_unlocked(modeflags);
+  reset_stream_state_unlocked(file_mode);
 
   if (do_seek) {
     auto seek_result = linux_file_seek(this, 0, SEEK_END);

>From e72c2fc0ca0fffb891acdf4d2e761cc1a6bfa6f8 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 17:59:37 +0100
Subject: [PATCH 14/16] remove old method

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/linux/file.cpp | 25 -------------------------
 1 file changed, 25 deletions(-)

diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp
index 95aefa366fab1..5e74c2143231f 100644
--- a/libc/src/__support/File/linux/file.cpp
+++ b/libc/src/__support/File/linux/file.cpp
@@ -95,31 +95,6 @@ static int map_c_mode_flags_to_linux_open_flags(FileMode mode) {
   return open_flags;
 }
 
-// TODO: clean up
-static int mode_flags_to_open_flags(File::ModeFlags modeflags) {
-  using ModeFlags = File::ModeFlags;
-  int open_flags = 0;
-  if (modeflags & ModeFlags(File::OpenMode::APPEND)) {
-    open_flags = O_CREAT | O_APPEND;
-    if (modeflags & ModeFlags(File::OpenMode::PLUS))
-      open_flags |= O_RDWR;
-    else
-      open_flags |= O_WRONLY;
-  } else if (modeflags & ModeFlags(File::OpenMode::WRITE)) {
-    open_flags = O_CREAT | O_TRUNC;
-    if (modeflags & ModeFlags(File::OpenMode::PLUS))
-      open_flags |= O_RDWR;
-    else
-      open_flags |= O_WRONLY;
-  } else {
-    if (modeflags & ModeFlags(File::OpenMode::PLUS))
-      open_flags |= O_RDWR;
-    else
-      open_flags |= O_RDONLY;
-  }
-  return open_flags;
-}
-
 ErrorOr<File *> openfile(const char *path, const char *mode) {
   FileMode file_mode(mode);
 

>From 5084e697f2043595435f08928969f91c214f8241 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 20:13:26 +0100
Subject: [PATCH 15/16] fix error in getting constant

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/linux/file.cpp | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp
index 5e74c2143231f..259fc7a87ea3f 100644
--- a/libc/src/__support/File/linux/file.cpp
+++ b/libc/src/__support/File/linux/file.cpp
@@ -140,11 +140,10 @@ ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode) {
   }
   int fd_flags = result.value();
 
-  constexpr int REQUIRES_WRITE = file_mode.write_allowed() |
-                                 file_mode.append_allowed() |
-                                 file_mode.is_plus();
+  int REQUIRES_WRITE = file_mode.write_allowed() ||
+                       file_mode.append_allowed() || file_mode.is_plus();
 
-  constexpr int REQUIRES_READ = file_mode.write_allowed() | file_mode.is_plus();
+  int REQUIRES_READ = file_mode.write_allowed() || file_mode.is_plus();
 
   if (((fd_flags & O_ACCMODE) == O_RDONLY && REQUIRES_WRITE) ||
       ((fd_flags & O_ACCMODE) == O_WRONLY && REQUIRES_READ)) {
@@ -256,11 +255,10 @@ int LinuxFile::reopen_unlocked(const char *path, const char *mode) {
     return EBADF;
   int fd_flags = result.value();
 
-  constexpr int REQUIRES_WRITE = file_mode.write_allowed() |
-                                 file_mode.append_allowed() |
-                                 file_mode.is_plus();
+  int REQUIRES_WRITE = file_mode.write_allowed() ||
+                       file_mode.append_allowed() || file_mode.is_plus();
 
-  constexpr int REQUIRES_READ = file_mode.write_allowed() | file_mode.is_plus();
+  int REQUIRES_READ = file_mode.write_allowed() || file_mode.is_plus();
 
   if (((fd_flags & O_ACCMODE) == O_RDONLY && REQUIRES_WRITE) ||
       ((fd_flags & O_ACCMODE) == O_WRONLY && REQUIRES_READ)) {

>From db720c24d27f0ae18e4bbc4dc13878665c47f617 Mon Sep 17 00:00:00 2001
From: tdadadavid <davidtofunmidada at gmail.com>
Date: Wed, 9 Sep 2026 20:48:51 +0100
Subject: [PATCH 16/16] convert int to boolean and fix REQUIRES_READ flag

Signed-off-by: tdadadavid <davidtofunmidada at gmail.com>
---
 libc/src/__support/File/linux/file.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libc/src/__support/File/linux/file.cpp b/libc/src/__support/File/linux/file.cpp
index 259fc7a87ea3f..08eb7c6d733fd 100644
--- a/libc/src/__support/File/linux/file.cpp
+++ b/libc/src/__support/File/linux/file.cpp
@@ -140,10 +140,10 @@ ErrorOr<LinuxFile *> create_file_from_fd(int fd, const char *mode) {
   }
   int fd_flags = result.value();
 
-  int REQUIRES_WRITE = file_mode.write_allowed() ||
-                       file_mode.append_allowed() || file_mode.is_plus();
+  const bool REQUIRES_WRITE = file_mode.write_allowed() ||
+                              file_mode.append_allowed() || file_mode.is_plus();
 
-  int REQUIRES_READ = file_mode.write_allowed() || file_mode.is_plus();
+  const bool REQUIRES_READ = file_mode.read_allowed() || file_mode.is_plus();
 
   if (((fd_flags & O_ACCMODE) == O_RDONLY && REQUIRES_WRITE) ||
       ((fd_flags & O_ACCMODE) == O_WRONLY && REQUIRES_READ)) {



More information about the libc-commits mailing list