diff --git a/core/os/os2/dir_windows.odin b/core/os/os2/dir_windows.odin index 6c754a677..a4dadca75 100644 --- a/core/os/os2/dir_windows.odin +++ b/core/os/os2/dir_windows.odin @@ -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 diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index a9878a563..5375258ca 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -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)) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 85f639c8b..b2350d9b5 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -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 diff --git a/core/os/os2/file_posix.odin b/core/os/os2/file_posix.odin index a251a3ae7..fd409b9d4 100644 --- a/core/os/os2/file_posix.odin +++ b/core/os/os2/file_posix.odin @@ -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 diff --git a/core/os/os2/file_posix_other.odin b/core/os/os2/file_posix_other.odin index d2946098b..8871a0062 100644 --- a/core/os/os2/file_posix_other.odin +++ b/core/os/os2/file_posix_other.odin @@ -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[:])) diff --git a/core/os/os2/file_util.odin b/core/os/os2/file_util.odin index 5934f02f5..be2f1f8c7 100644 --- a/core/os/os2/file_util.odin +++ b/core/os/os2/file_util.odin @@ -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 diff --git a/core/os/os2/file_wasi.odin b/core/os/os2/file_wasi.odin index 1d417ffb1..ec464fc52 100644 --- a/core/os/os2/file_wasi.odin +++ b/core/os/os2/file_wasi.odin @@ -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 } diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index b39e65fe2..be5aeb8ab 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -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) diff --git a/core/os/os2/path_wasi.odin b/core/os/os2/path_wasi.odin index b8240e188..f26e16158 100644 --- a/core/os/os2/path_wasi.odin +++ b/core/os/os2/path_wasi.odin @@ -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 +} diff --git a/core/os/os2/stat.odin b/core/os/os2/stat.odin index d6b524684..338bdffca 100644 --- a/core/os/os2/stat.odin +++ b/core/os/os2/stat.odin @@ -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, diff --git a/core/os/os2/stat_linux.odin b/core/os/os2/stat_linux.odin index 373765be5..6185252cf 100644 --- a/core/os/os2/stat_linux.odin +++ b/core/os/os2/stat_linux.odin @@ -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 { diff --git a/core/os/os2/stat_posix.odin b/core/os/os2/stat_posix.odin index 6ffbdf1da..4ed96b389 100644 --- a/core/os/os2/stat_posix.odin +++ b/core/os/os2/stat_posix.odin @@ -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 { diff --git a/core/os/os2/stat_windows.odin b/core/os/os2/stat_windows.odin index 3dee42be6..20a708145 100644 --- a/core/os/os2/stat_windows.odin +++ b/core/os/os2/stat_windows.odin @@ -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) } diff --git a/core/os/os2/temp_file.odin b/core/os/os2/temp_file.odin index e3e74bd11..6e7a37788 100644 --- a/core/os/os2/temp_file.odin +++ b/core/os/os2/temp_file.odin @@ -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