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 })
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)
fi.fullpath = path
+44 -5
View File
@@ -90,17 +90,56 @@ O_SPARSE :: File_Flags{.Sparse}
*/
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
stdout: ^File = nil // OS-Specific
stderr: ^File = nil // OS-Specific
@(require_results)
create :: proc(name: string) -> (^File, Error) {
return open(name, {.Read, .Write, .Create}, 0o777)
return open(name, {.Read, .Write, .Create}, Permissions_Default)
}
@(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)
}
@@ -237,7 +276,7 @@ change_directory :: proc(name: string) -> Error {
chmod :: change_mode
change_mode :: proc(name: string, mode: int) -> Error {
change_mode :: proc(name: string, mode: Permissions) -> Error {
return _chmod(name, mode)
}
@@ -255,7 +294,7 @@ fchange_directory :: proc(f: ^File) -> Error {
fchmod :: fchange_mode
fchange_mode :: proc(f: ^File, mode: int) -> Error {
fchange_mode :: proc(f: ^File, mode: Permissions) -> Error {
return _fchmod(f, mode)
}
@@ -331,7 +370,7 @@ _copy_file :: proc(dst_path, src_path: string) -> Error {
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)
_, 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")
}
_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({})
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 .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 {
return nil, _get_platform_error(errno)
}
@@ -132,7 +132,7 @@ _clone :: proc(f: ^File) -> (clone: ^File, err: Error) {
@(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)
f, err = _open(name, flags, perm)
if f != nil && err == nil {
@@ -369,15 +369,15 @@ _fchdir :: proc(f: ^File) -> Error {
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({})
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)
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
+6 -6
View File
@@ -46,7 +46,7 @@ init_std_files :: proc "contextless" () {
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 == "" {
err = .Invalid_Path
return
@@ -72,7 +72,7 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
temp_allocator := TEMP_ALLOCATOR_GUARD({})
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 {
err = _get_platform_error()
return
@@ -284,17 +284,17 @@ _fchdir :: proc(f: ^File) -> Error {
return nil
}
_fchmod :: proc(f: ^File, mode: int) -> Error {
if posix.fchmod(__fd(f), transmute(posix.mode_t)posix._mode_t(mode)) != .OK {
_fchmod :: proc(f: ^File, mode: Permissions) -> Error {
if posix.fchmod(__fd(f), transmute(posix.mode_t)posix._mode_t(transmute(u32)mode)) != .OK {
return _get_platform_error()
}
return nil
}
_chmod :: proc(name: string, mode: int) -> (err: Error) {
_chmod :: proc(name: string, mode: Permissions) -> (err: Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({})
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 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) {
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
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)
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
if truncate {
flags |= O_TRUNC
+7 -5
View File
@@ -51,8 +51,8 @@ init_std_files :: proc "contextless" () {
}
@(init)
init_preopens :: proc() {
strip_prefixes :: proc(path: string) -> string {
init_preopens :: proc "contextless" () {
strip_prefixes :: proc "contextless" (path: string) -> string {
path := path
loop: for len(path) > 0 {
switch {
@@ -69,6 +69,8 @@ init_preopens :: proc() {
return path
}
context = runtime.default_context()
n: int
n_loop: for fd := wasi.fd_t(3); ; fd += 1 {
_, 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
}
_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)
if !ok {
return nil, .Invalid_Path
@@ -373,11 +375,11 @@ _fchdir :: proc(f: ^File) -> Error {
return .Unsupported
}
_fchmod :: proc(f: ^File, mode: int) -> Error {
_fchmod :: proc(f: ^File, mode: Permissions) -> Error {
return .Unsupported
}
_chmod :: proc(name: string, mode: int) -> Error {
_chmod :: proc(name: string, mode: Permissions) -> Error {
return .Unsupported
}
+7 -8
View File
@@ -12,7 +12,6 @@ import win32 "core:sys/windows"
INVALID_HANDLE :: ~uintptr(0)
S_IWRITE :: 0o200
_ERROR_BAD_NETPATH :: 53
MAX_RW :: 1<<30
@@ -81,7 +80,7 @@ _handle :: proc "contextless" (f: ^File) -> win32.HANDLE {
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 {
err = .Not_Exist
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
if perm & S_IWRITE == 0 {
if .Write_User not_in perm {
attrs = win32.FILE_ATTRIBUTE_READONLY
if create_mode == win32.CREATE_ALWAYS {
// 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}
handle := _open_internal(name, flags, perm) or_return
return _new_file(handle, name, file_allocator())
@@ -193,7 +192,7 @@ _new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -
@(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)
flags := flags if flags != nil else {.Read}
handle := _open_internal(name, flags, perm) or_return
@@ -744,7 +743,7 @@ _fchdir :: proc(f: ^File) -> Error {
return nil
}
_fchmod :: proc(f: ^File, mode: int) -> Error {
_fchmod :: proc(f: ^File, mode: Permissions) -> Error {
if f == nil || f.impl == nil {
return nil
}
@@ -753,7 +752,7 @@ _fchmod :: proc(f: ^File, mode: int) -> Error {
return _get_platform_error()
}
attrs := d.dwFileAttributes
if mode & S_IWRITE != 0 {
if .Write_User in mode {
attrs &~= win32.FILE_ATTRIBUTE_READONLY
} else {
attrs |= win32.FILE_ATTRIBUTE_READONLY
@@ -780,7 +779,7 @@ _chdir :: proc(name: string) -> Error {
return nil
}
_chmod :: proc(name: string, mode: int) -> Error {
_chmod :: proc(name: string, mode: Permissions) -> Error {
f := open(name, {.Write}) or_return
defer close(f)
return _fchmod(f, mode)
+5 -1
View File
@@ -34,7 +34,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
return .Exist
}
clean_path := clean_path(path, temp_allocator)
clean_path := clean_path(path, temp_allocator) or_return
return internal_mkdir_all(clean_path)
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)
}
_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
size: i64 `fmt:"M"`,
mode: int `fmt:"o"`,
mode: Permissions,
type: File_Type,
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_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
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.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
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)
}
_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 {
mode |= 0o444
mode += Permissions_Write_All
} else {
mode |= 0o666
mode += Permissions_Read_Write_All
}
is_sym := false
@@ -229,7 +229,7 @@ _file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: wi
type = .Symlink
} else if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
type = .Directory
mode |= 0o111
mode += Permissions_Execute_All
} else if h != nil {
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`.
//
// 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.
// If the pattern includes an "*", the random string replaces the last "*".
// 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
for {
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 {
close(f)
attempts += 1