Change to Permissions bit_set from relying on octal numbering for os2

This commit is contained in:
gingerBill
2025-10-31 14:45:53 +00:00
parent d374dc3c99
commit b9df67f8c5
14 changed files with 88 additions and 44 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, al
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
path := concatenate({base_path, `\`, win32_wstring_to_utf8(cstring16(raw_data(d.cFileName[:])), temp_allocator) or_else ""}, allocator) or_return path := concatenate({base_path, `\`, win32_wstring_to_utf8(cstring16(raw_data(d.cFileName[:])), temp_allocator) or_else ""}, allocator) or_return
handle := win32.HANDLE(_open_internal(path, {.Read}, 0o666) or_else 0) handle := win32.HANDLE(_open_internal(path, {.Read}, Permissions_Read_Write_All) or_else 0)
defer win32.CloseHandle(handle) defer win32.CloseHandle(handle)
fi.fullpath = path fi.fullpath = path
+44 -5
View File
@@ -90,17 +90,56 @@ O_SPARSE :: File_Flags{.Sparse}
*/ */
O_INHERITABLE :: File_Flags{.Inheritable} O_INHERITABLE :: File_Flags{.Inheritable}
Permissions :: distinct bit_set[Permission_Flag; u32]
Permission_Flag :: enum u32 {
Execute_Other = 0,
Write_Other = 1,
Read_Other = 2,
Execute_Group = 3,
Write_Group = 4,
Read_Group = 5,
Execute_User = 6,
Write_User = 7,
Read_User = 8,
}
Permissions_Execute_All :: Permissions{.Execute_User, .Execute_Group, .Execute_Other}
Permissions_Write_All :: Permissions{.Write_User, .Write_Group, .Write_Other}
Permissions_Read_All :: Permissions{.Read_User, .Read_Group, .Read_Other}
Permissions_Read_Write_All :: Permissions_Read_All + Permissions_Write_All
Permissions_All :: Permissions_Read_All + Permissions_Write_All + Permissions_Execute_All
Permissions_Default_File :: Permissions_Read_All + Permissions_Write_All
Permissions_Default_Directory :: Permissions_Read_All + Permissions_Write_All + Permissions_Execute_All
Permissions_Default :: Permissions_Default_Directory
perm :: proc{
perm_number,
}
@(require_results)
perm_number :: proc "contextless" (perm: int) -> Permissions {
return transmute(Permissions)u32(perm & 0o777)
}
stdin: ^File = nil // OS-Specific stdin: ^File = nil // OS-Specific
stdout: ^File = nil // OS-Specific stdout: ^File = nil // OS-Specific
stderr: ^File = nil // OS-Specific stderr: ^File = nil // OS-Specific
@(require_results) @(require_results)
create :: proc(name: string) -> (^File, Error) { create :: proc(name: string) -> (^File, Error) {
return open(name, {.Read, .Write, .Create}, 0o777) return open(name, {.Read, .Write, .Create}, Permissions_Default)
} }
@(require_results) @(require_results)
open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File, Error) { open :: proc(name: string, flags := File_Flags{.Read}, perm := Permissions_Default) -> (^File, Error) {
return _open(name, flags, perm) return _open(name, flags, perm)
} }
@@ -237,7 +276,7 @@ change_directory :: proc(name: string) -> Error {
chmod :: change_mode chmod :: change_mode
change_mode :: proc(name: string, mode: int) -> Error { change_mode :: proc(name: string, mode: Permissions) -> Error {
return _chmod(name, mode) return _chmod(name, mode)
} }
@@ -255,7 +294,7 @@ fchange_directory :: proc(f: ^File) -> Error {
fchmod :: fchange_mode fchmod :: fchange_mode
fchange_mode :: proc(f: ^File, mode: int) -> Error { fchange_mode :: proc(f: ^File, mode: Permissions) -> Error {
return _fchmod(f, mode) return _fchmod(f, mode)
} }
@@ -331,7 +370,7 @@ _copy_file :: proc(dst_path, src_path: string) -> Error {
return .Invalid_File return .Invalid_File
} }
dst := open(dst_path, {.Read, .Write, .Create, .Trunc}, info.mode & 0o777) or_return dst := open(dst_path, {.Read, .Write, .Create, .Trunc}, info.mode & Permissions_All) or_return
defer close(dst) defer close(dst)
_, err := io.copy(to_writer(dst), to_reader(src)) _, err := io.copy(to_writer(dst), to_reader(src))
+7 -7
View File
@@ -65,7 +65,7 @@ _standard_stream_init :: proc "contextless" () {
stderr = new_std(&files[2], 2, "/proc/self/fd/2") stderr = new_std(&files[2], 2, "/proc/self/fd/2")
} }
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { _open :: proc(name: string, flags: File_Flags, perm: Permissions) -> (f: ^File, err: Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({}) temp_allocator := TEMP_ALLOCATOR_GUARD({})
name_cstr := clone_to_cstring(name, temp_allocator) or_return name_cstr := clone_to_cstring(name, temp_allocator) or_return
@@ -88,7 +88,7 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
if .Trunc in flags { sys_flags += {.TRUNC} } if .Trunc in flags { sys_flags += {.TRUNC} }
if .Inheritable in flags { sys_flags -= {.CLOEXEC} } if .Inheritable in flags { sys_flags -= {.CLOEXEC} }
fd, errno := linux.open(name_cstr, sys_flags, transmute(linux.Mode)u32(perm)) fd, errno := linux.open(name_cstr, sys_flags, transmute(linux.Mode)transmute(u32)perm)
if errno != .NONE { if errno != .NONE {
return nil, _get_platform_error(errno) return nil, _get_platform_error(errno)
} }
@@ -132,7 +132,7 @@ _clone :: proc(f: ^File) -> (clone: ^File, err: Error) {
@(require_results) @(require_results)
_open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (f: ^File, err: Error) { _open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm: Permissions) -> (f: ^File, err: Error) {
assert(buffer_size > 0) assert(buffer_size > 0)
f, err = _open(name, flags, perm) f, err = _open(name, flags, perm)
if f != nil && err == nil { if f != nil && err == nil {
@@ -369,15 +369,15 @@ _fchdir :: proc(f: ^File) -> Error {
return _get_platform_error(linux.fchdir(impl.fd)) return _get_platform_error(linux.fchdir(impl.fd))
} }
_chmod :: proc(name: string, mode: int) -> Error { _chmod :: proc(name: string, mode: Permissions) -> Error {
temp_allocator := TEMP_ALLOCATOR_GUARD({}) temp_allocator := TEMP_ALLOCATOR_GUARD({})
name_cstr := clone_to_cstring(name, temp_allocator) or_return name_cstr := clone_to_cstring(name, temp_allocator) or_return
return _get_platform_error(linux.chmod(name_cstr, transmute(linux.Mode)(u32(mode)))) return _get_platform_error(linux.chmod(name_cstr, transmute(linux.Mode)transmute(u32)mode))
} }
_fchmod :: proc(f: ^File, mode: int) -> Error { _fchmod :: proc(f: ^File, mode: Permissions) -> Error {
impl := (^File_Impl)(f.impl) impl := (^File_Impl)(f.impl)
return _get_platform_error(linux.fchmod(impl.fd, transmute(linux.Mode)(u32(mode)))) return _get_platform_error(linux.fchmod(impl.fd, transmute(linux.Mode)transmute(u32)mode))
} }
// NOTE: will throw error without super user priviledges // NOTE: will throw error without super user priviledges
+6 -6
View File
@@ -46,7 +46,7 @@ init_std_files :: proc "contextless" () {
stderr = new_std(&files[2], posix.STDERR_FILENO, "/dev/stderr") stderr = new_std(&files[2], posix.STDERR_FILENO, "/dev/stderr")
} }
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { _open :: proc(name: string, flags: File_Flags, perm: Permissions) -> (f: ^File, err: Error) {
if name == "" { if name == "" {
err = .Invalid_Path err = .Invalid_Path
return return
@@ -72,7 +72,7 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
temp_allocator := TEMP_ALLOCATOR_GUARD({}) temp_allocator := TEMP_ALLOCATOR_GUARD({})
cname := clone_to_cstring(name, temp_allocator) or_return cname := clone_to_cstring(name, temp_allocator) or_return
fd := posix.open(cname, sys_flags, transmute(posix.mode_t)posix._mode_t(perm)) fd := posix.open(cname, sys_flags, transmute(posix.mode_t)posix._mode_t(transmute(u32)perm))
if fd < 0 { if fd < 0 {
err = _get_platform_error() err = _get_platform_error()
return return
@@ -284,17 +284,17 @@ _fchdir :: proc(f: ^File) -> Error {
return nil return nil
} }
_fchmod :: proc(f: ^File, mode: int) -> Error { _fchmod :: proc(f: ^File, mode: Permissions) -> Error {
if posix.fchmod(__fd(f), transmute(posix.mode_t)posix._mode_t(mode)) != .OK { if posix.fchmod(__fd(f), transmute(posix.mode_t)posix._mode_t(transmute(u32)mode)) != .OK {
return _get_platform_error() return _get_platform_error()
} }
return nil return nil
} }
_chmod :: proc(name: string, mode: int) -> (err: Error) { _chmod :: proc(name: string, mode: Permissions) -> (err: Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({}) temp_allocator := TEMP_ALLOCATOR_GUARD({})
cname := clone_to_cstring(name, temp_allocator) or_return cname := clone_to_cstring(name, temp_allocator) or_return
if posix.chmod(cname, transmute(posix.mode_t)posix._mode_t(mode)) != .OK { if posix.chmod(cname, transmute(posix.mode_t)posix._mode_t(transmute(u32)mode)) != .OK {
return _get_platform_error() return _get_platform_error()
} }
return nil return nil
+1 -1
View File
@@ -8,7 +8,7 @@ import "core:sys/posix"
_posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) { _posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
cname := clone_to_cstring(name, temp_allocator) cname := clone_to_cstring(name, temp_allocator) or_return
buf: [posix.PATH_MAX]byte buf: [posix.PATH_MAX]byte
path = posix.realpath(cname, raw_data(buf[:])) path = posix.realpath(cname, raw_data(buf[:]))
+1 -1
View File
@@ -161,7 +161,7 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator, loc :
} }
@(require_results) @(require_results)
write_entire_file :: proc(name: string, data: []byte, perm: int = 0o644, truncate := true) -> Error { write_entire_file :: proc(name: string, data: []byte, perm := Permissions_Read_All + {.Write_User}, truncate := true) -> Error {
flags := O_WRONLY|O_CREATE flags := O_WRONLY|O_CREATE
if truncate { if truncate {
flags |= O_TRUNC flags |= O_TRUNC
+7 -5
View File
@@ -51,8 +51,8 @@ init_std_files :: proc "contextless" () {
} }
@(init) @(init)
init_preopens :: proc() { init_preopens :: proc "contextless" () {
strip_prefixes :: proc(path: string) -> string { strip_prefixes :: proc "contextless" (path: string) -> string {
path := path path := path
loop: for len(path) > 0 { loop: for len(path) > 0 {
switch { switch {
@@ -69,6 +69,8 @@ init_preopens :: proc() {
return path return path
} }
context = runtime.default_context()
n: int n: int
n_loop: for fd := wasi.fd_t(3); ; fd += 1 { n_loop: for fd := wasi.fd_t(3); ; fd += 1 {
_, err := wasi.fd_prestat_get(fd) _, err := wasi.fd_prestat_get(fd)
@@ -171,7 +173,7 @@ match_preopen :: proc(path: string) -> (wasi.fd_t, string, bool) {
return match.fd, relative, true return match.fd, relative, true
} }
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { _open :: proc(name: string, flags: File_Flags, perm: Permissions) -> (f: ^File, err: Error) {
dir_fd, relative, ok := match_preopen(name) dir_fd, relative, ok := match_preopen(name)
if !ok { if !ok {
return nil, .Invalid_Path return nil, .Invalid_Path
@@ -373,11 +375,11 @@ _fchdir :: proc(f: ^File) -> Error {
return .Unsupported return .Unsupported
} }
_fchmod :: proc(f: ^File, mode: int) -> Error { _fchmod :: proc(f: ^File, mode: Permissions) -> Error {
return .Unsupported return .Unsupported
} }
_chmod :: proc(name: string, mode: int) -> Error { _chmod :: proc(name: string, mode: Permissions) -> Error {
return .Unsupported return .Unsupported
} }
+7 -8
View File
@@ -12,7 +12,6 @@ import win32 "core:sys/windows"
INVALID_HANDLE :: ~uintptr(0) INVALID_HANDLE :: ~uintptr(0)
S_IWRITE :: 0o200
_ERROR_BAD_NETPATH :: 53 _ERROR_BAD_NETPATH :: 53
MAX_RW :: 1<<30 MAX_RW :: 1<<30
@@ -81,7 +80,7 @@ _handle :: proc "contextless" (f: ^File) -> win32.HANDLE {
return win32.HANDLE(_fd(f)) return win32.HANDLE(_fd(f))
} }
_open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: uintptr, err: Error) { _open_internal :: proc(name: string, flags: File_Flags, perm: Permissions) -> (handle: uintptr, err: Error) {
if len(name) == 0 { if len(name) == 0 {
err = .Not_Exist err = .Not_Exist
return return
@@ -122,7 +121,7 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: u
} }
attrs: u32 = win32.FILE_ATTRIBUTE_NORMAL|win32.FILE_FLAG_BACKUP_SEMANTICS attrs: u32 = win32.FILE_ATTRIBUTE_NORMAL|win32.FILE_FLAG_BACKUP_SEMANTICS
if perm & S_IWRITE == 0 { if .Write_User not_in perm {
attrs = win32.FILE_ATTRIBUTE_READONLY attrs = win32.FILE_ATTRIBUTE_READONLY
if create_mode == win32.CREATE_ALWAYS { if create_mode == win32.CREATE_ALWAYS {
// NOTE(bill): Open has just asked to create a file in read-only mode. // NOTE(bill): Open has just asked to create a file in read-only mode.
@@ -150,7 +149,7 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: u
} }
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { _open :: proc(name: string, flags: File_Flags, perm: Permissions) -> (f: ^File, err: Error) {
flags := flags if flags != nil else {.Read} flags := flags if flags != nil else {.Read}
handle := _open_internal(name, flags, perm) or_return handle := _open_internal(name, flags, perm) or_return
return _new_file(handle, name, file_allocator()) return _new_file(handle, name, file_allocator())
@@ -193,7 +192,7 @@ _new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -
@(require_results) @(require_results)
_open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (f: ^File, err: Error) { _open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm: Permissions) -> (f: ^File, err: Error) {
assert(buffer_size > 0) assert(buffer_size > 0)
flags := flags if flags != nil else {.Read} flags := flags if flags != nil else {.Read}
handle := _open_internal(name, flags, perm) or_return handle := _open_internal(name, flags, perm) or_return
@@ -744,7 +743,7 @@ _fchdir :: proc(f: ^File) -> Error {
return nil return nil
} }
_fchmod :: proc(f: ^File, mode: int) -> Error { _fchmod :: proc(f: ^File, mode: Permissions) -> Error {
if f == nil || f.impl == nil { if f == nil || f.impl == nil {
return nil return nil
} }
@@ -753,7 +752,7 @@ _fchmod :: proc(f: ^File, mode: int) -> Error {
return _get_platform_error() return _get_platform_error()
} }
attrs := d.dwFileAttributes attrs := d.dwFileAttributes
if mode & S_IWRITE != 0 { if .Write_User in mode {
attrs &~= win32.FILE_ATTRIBUTE_READONLY attrs &~= win32.FILE_ATTRIBUTE_READONLY
} else { } else {
attrs |= win32.FILE_ATTRIBUTE_READONLY attrs |= win32.FILE_ATTRIBUTE_READONLY
@@ -780,7 +779,7 @@ _chdir :: proc(name: string) -> Error {
return nil return nil
} }
_chmod :: proc(name: string, mode: int) -> Error { _chmod :: proc(name: string, mode: Permissions) -> Error {
f := open(name, {.Write}) or_return f := open(name, {.Write}) or_return
defer close(f) defer close(f)
return _fchmod(f, mode) return _fchmod(f, mode)
+5 -1
View File
@@ -34,7 +34,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
return .Exist return .Exist
} }
clean_path := clean_path(path, temp_allocator) clean_path := clean_path(path, temp_allocator) or_return
return internal_mkdir_all(clean_path) return internal_mkdir_all(clean_path)
internal_mkdir_all :: proc(path: string) -> Error { internal_mkdir_all :: proc(path: string) -> Error {
@@ -114,3 +114,7 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err
return concatenate({"/", arg}, allocator) return concatenate({"/", arg}, allocator)
} }
_get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absolute_path: string, err: Error) {
return "", .Unsupported
}
+1 -1
View File
@@ -12,7 +12,7 @@ File_Info :: struct {
inode: u128, // might be zero if cannot be determined inode: u128, // might be zero if cannot be determined
size: i64 `fmt:"M"`, size: i64 `fmt:"M"`,
mode: int `fmt:"o"`, mode: Permissions,
type: File_Type, type: File_Type,
creation_time: time.Time, creation_time: time.Time,
+1 -1
View File
@@ -26,7 +26,7 @@ _fstat_internal :: proc(fd: linux.Fd, allocator: runtime.Allocator) -> (fi: File
case linux.S_IFREG: type = .Regular case linux.S_IFREG: type = .Regular
case linux.S_IFSOCK: type = .Socket case linux.S_IFSOCK: type = .Socket
} }
mode := int(0o7777 & transmute(u32)s.mode) mode := transmute(Permissions)(0o7777 & transmute(u32)s.mode)
// TODO: As of Linux 4.11, the new statx syscall can retrieve creation_time // TODO: As of Linux 4.11, the new statx syscall can retrieve creation_time
fi = File_Info { fi = File_Info {
+1 -1
View File
@@ -14,7 +14,7 @@ internal_stat :: proc(stat: posix.stat_t, fullpath: string) -> (fi: File_Info) {
fi.inode = u128(stat.st_ino) fi.inode = u128(stat.st_ino)
fi.size = i64(stat.st_size) fi.size = i64(stat.st_size)
fi.mode = int(transmute(posix._mode_t)(stat.st_mode - posix.S_IFMT)) fi.mode = transmute(Permissions)u32(transmute(posix._mode_t)(stat.st_mode - posix.S_IFMT))
fi.type = .Undetermined fi.type = .Undetermined
switch { switch {
+4 -4
View File
@@ -211,11 +211,11 @@ _file_type_from_create_file :: proc(wname: win32.wstring, create_file_attributes
return file_type(h) return file_type(h)
} }
_file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (type: File_Type, mode: int) { _file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (type: File_Type, mode: Permissions) {
if file_attributes & win32.FILE_ATTRIBUTE_READONLY != 0 { if file_attributes & win32.FILE_ATTRIBUTE_READONLY != 0 {
mode |= 0o444 mode += Permissions_Write_All
} else { } else {
mode |= 0o666 mode += Permissions_Read_Write_All
} }
is_sym := false is_sym := false
@@ -229,7 +229,7 @@ _file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: wi
type = .Symlink type = .Symlink
} else if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 { } else if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
type = .Directory type = .Directory
mode |= 0o111 mode += Permissions_Execute_All
} else if h != nil { } else if h != nil {
type = file_type(h) type = file_type(h)
} }
+2 -2
View File
@@ -7,7 +7,7 @@ MAX_ATTEMPTS :: 1<<13 // Should be enough for everyone, right?
// Creates a new temperatory file in the directory `dir`. // Creates a new temperatory file in the directory `dir`.
// //
// Opens the file for reading and writing, with 0o666 permissions, and returns the new `^File`. // Opens the file for reading and writing, with `Permissions_Read_Write_All` permissions, and returns the new `^File`.
// The filename is generated by taking a pattern, and adding a randomized string to the end. // The filename is generated by taking a pattern, and adding a randomized string to the end.
// If the pattern includes an "*", the random string replaces the last "*". // If the pattern includes an "*", the random string replaces the last "*".
// If `dir` is an empty string, `temp_directory()` will be used. // If `dir` is an empty string, `temp_directory()` will be used.
@@ -26,7 +26,7 @@ create_temp_file :: proc(dir, pattern: string) -> (f: ^File, err: Error) {
attempts := 0 attempts := 0
for { for {
name := concatenate_strings_from_buffer(name_buf[:], prefix, random_string(rand_buf[:]), suffix) name := concatenate_strings_from_buffer(name_buf[:], prefix, random_string(rand_buf[:]), suffix)
f, err = open(name, {.Read, .Write, .Create, .Excl}, 0o666) f, err = open(name, {.Read, .Write, .Create, .Excl}, Permissions_Read_Write_All)
if err == .Exist { if err == .Exist {
close(f) close(f)
attempts += 1 attempts += 1