mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-03 05:08:14 +00:00
Merge pull request #3939 from flysand7/os2-file-type
[os2]: Split file type from mode bits et other small fixes
This commit is contained in:
+63
-13
@@ -4,20 +4,57 @@ import "core:io"
|
|||||||
import "core:time"
|
import "core:time"
|
||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Type representing a file handle.
|
||||||
|
|
||||||
|
This struct represents an OS-specific file-handle, which can be one of
|
||||||
|
the following:
|
||||||
|
- File
|
||||||
|
- Directory
|
||||||
|
- Pipe
|
||||||
|
- Named pipe
|
||||||
|
- Block Device
|
||||||
|
- Character device
|
||||||
|
- Symlink
|
||||||
|
- Socket
|
||||||
|
|
||||||
|
See `File_Type` enum for more information on file types.
|
||||||
|
*/
|
||||||
File :: struct {
|
File :: struct {
|
||||||
impl: rawptr,
|
impl: rawptr,
|
||||||
stream: io.Stream,
|
stream: io.Stream,
|
||||||
fstat: Fstat_Callback,
|
fstat: Fstat_Callback,
|
||||||
}
|
}
|
||||||
|
|
||||||
File_Mode :: distinct u32
|
/*
|
||||||
File_Mode_Dir :: File_Mode(1<<16)
|
Type representing the type of a file handle.
|
||||||
File_Mode_Named_Pipe :: File_Mode(1<<17)
|
|
||||||
File_Mode_Device :: File_Mode(1<<18)
|
|
||||||
File_Mode_Char_Device :: File_Mode(1<<19)
|
|
||||||
File_Mode_Sym_Link :: File_Mode(1<<20)
|
|
||||||
|
|
||||||
File_Mode_Perm :: File_Mode(0o777) // Unix permision bits
|
**Note(windows)**: Socket handles can not be distinguished from
|
||||||
|
files, as they are just a normal file handle that is being treated by
|
||||||
|
a special driver. Windows also makes no distinction between block and
|
||||||
|
character devices.
|
||||||
|
*/
|
||||||
|
File_Type :: enum {
|
||||||
|
// The type of a file could not be determined for the current platform.
|
||||||
|
Undetermined,
|
||||||
|
// Represents a regular file.
|
||||||
|
Regular,
|
||||||
|
// Represents a directory.
|
||||||
|
Directory,
|
||||||
|
// Represents a symbolic link.
|
||||||
|
Symlink,
|
||||||
|
// Represents a named pipe (FIFO).
|
||||||
|
Named_Pipe,
|
||||||
|
// Represents a socket.
|
||||||
|
// **Note(windows)**: Not returned on windows
|
||||||
|
Socket,
|
||||||
|
// Represents a block device.
|
||||||
|
// **Note(windows)**: On windows represents all devices.
|
||||||
|
Block_Device,
|
||||||
|
// Represents a character device.
|
||||||
|
// **Note(windows)**: Not returned on windows
|
||||||
|
Character_Device,
|
||||||
|
}
|
||||||
|
|
||||||
File_Flags :: distinct bit_set[File_Flag; uint]
|
File_Flags :: distinct bit_set[File_Flag; uint]
|
||||||
File_Flag :: enum {
|
File_Flag :: enum {
|
||||||
@@ -51,11 +88,11 @@ 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}, File_Mode(0o777))
|
return open(name, {.Read, .Write, .Create}, 0o777)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
open :: proc(name: string, flags := File_Flags{.Read}, perm := File_Mode(0o777)) -> (^File, Error) {
|
open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File, Error) {
|
||||||
return _open(name, flags, perm)
|
return _open(name, flags, perm)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,44 +198,56 @@ read_link :: proc(name: string, allocator: runtime.Allocator) -> (string, Error)
|
|||||||
|
|
||||||
|
|
||||||
chdir :: change_directory
|
chdir :: change_directory
|
||||||
|
|
||||||
change_directory :: proc(name: string) -> Error {
|
change_directory :: proc(name: string) -> Error {
|
||||||
return _chdir(name)
|
return _chdir(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
chmod :: change_mode
|
chmod :: change_mode
|
||||||
change_mode :: proc(name: string, mode: File_Mode) -> Error {
|
|
||||||
|
change_mode :: proc(name: string, mode: int) -> Error {
|
||||||
return _chmod(name, mode)
|
return _chmod(name, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
chown :: change_owner
|
chown :: change_owner
|
||||||
|
|
||||||
change_owner :: proc(name: string, uid, gid: int) -> Error {
|
change_owner :: proc(name: string, uid, gid: int) -> Error {
|
||||||
return _chown(name, uid, gid)
|
return _chown(name, uid, gid)
|
||||||
}
|
}
|
||||||
|
|
||||||
fchdir :: fchange_directory
|
fchdir :: fchange_directory
|
||||||
|
|
||||||
fchange_directory :: proc(f: ^File) -> Error {
|
fchange_directory :: proc(f: ^File) -> Error {
|
||||||
return _fchdir(f)
|
return _fchdir(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fchmod :: fchange_mode
|
fchmod :: fchange_mode
|
||||||
fchange_mode :: proc(f: ^File, mode: File_Mode) -> Error {
|
|
||||||
|
fchange_mode :: proc(f: ^File, mode: int) -> Error {
|
||||||
return _fchmod(f, mode)
|
return _fchmod(f, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fchown :: fchange_owner
|
fchown :: fchange_owner
|
||||||
|
|
||||||
fchange_owner :: proc(f: ^File, uid, gid: int) -> Error {
|
fchange_owner :: proc(f: ^File, uid, gid: int) -> Error {
|
||||||
return _fchown(f, uid, gid)
|
return _fchown(f, uid, gid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
lchown :: change_owner_do_not_follow_links
|
lchown :: change_owner_do_not_follow_links
|
||||||
|
|
||||||
change_owner_do_not_follow_links :: proc(name: string, uid, gid: int) -> Error {
|
change_owner_do_not_follow_links :: proc(name: string, uid, gid: int) -> Error {
|
||||||
return _lchown(name, uid, gid)
|
return _lchown(name, uid, gid)
|
||||||
}
|
}
|
||||||
|
|
||||||
chtimes :: change_times
|
chtimes :: change_times
|
||||||
|
|
||||||
change_times :: proc(name: string, atime, mtime: time.Time) -> Error {
|
change_times :: proc(name: string, atime, mtime: time.Time) -> Error {
|
||||||
return _chtimes(name, atime, mtime)
|
return _chtimes(name, atime, mtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
fchtimes :: fchange_times
|
fchtimes :: fchange_times
|
||||||
|
|
||||||
fchange_times :: proc(f: ^File, atime, mtime: time.Time) -> Error {
|
fchange_times :: proc(f: ^File, atime, mtime: time.Time) -> Error {
|
||||||
return _fchtimes(f, atime, mtime)
|
return _fchtimes(f, atime, mtime)
|
||||||
}
|
}
|
||||||
@@ -214,6 +263,7 @@ is_file :: proc(path: string) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is_dir :: is_directory
|
is_dir :: is_directory
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
is_directory :: proc(path: string) -> bool {
|
is_directory :: proc(path: string) -> bool {
|
||||||
return _is_dir(path)
|
return _is_dir(path)
|
||||||
@@ -226,11 +276,11 @@ copy_file :: proc(dst_path, src_path: string) -> Error {
|
|||||||
|
|
||||||
info := fstat(src, file_allocator()) or_return
|
info := fstat(src, file_allocator()) or_return
|
||||||
defer file_info_delete(info, file_allocator())
|
defer file_info_delete(info, file_allocator())
|
||||||
if info.is_directory {
|
if info.type == .Directory {
|
||||||
return .Invalid_File
|
return .Invalid_File
|
||||||
}
|
}
|
||||||
|
|
||||||
dst := open(dst_path, {.Read, .Write, .Create, .Trunc}, info.mode & File_Mode_Perm) or_return
|
dst := open(dst_path, {.Read, .Write, .Create, .Trunc}, info.mode & 0o777) 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))
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ _file_allocator :: proc() -> runtime.Allocator {
|
|||||||
return heap_allocator()
|
return heap_allocator()
|
||||||
}
|
}
|
||||||
|
|
||||||
_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (f: ^File, err: Error) {
|
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
|
||||||
TEMP_ALLOCATOR_GUARD()
|
TEMP_ALLOCATOR_GUARD()
|
||||||
name_cstr := temp_cstring(name) or_return
|
name_cstr := temp_cstring(name) or_return
|
||||||
|
|
||||||
@@ -76,7 +76,6 @@ _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (f: ^File, er
|
|||||||
case O_WRONLY: sys_flags += {.WRONLY}
|
case O_WRONLY: sys_flags += {.WRONLY}
|
||||||
case O_RDWR: sys_flags += {.RDWR}
|
case O_RDWR: sys_flags += {.RDWR}
|
||||||
}
|
}
|
||||||
|
|
||||||
if .Append in flags { sys_flags += {.APPEND} }
|
if .Append in flags { sys_flags += {.APPEND} }
|
||||||
if .Create in flags { sys_flags += {.CREAT} }
|
if .Create in flags { sys_flags += {.CREAT} }
|
||||||
if .Excl in flags { sys_flags += {.EXCL} }
|
if .Excl in flags { sys_flags += {.EXCL} }
|
||||||
@@ -84,7 +83,7 @@ _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (f: ^File, er
|
|||||||
if .Trunc in flags { sys_flags += {.TRUNC} }
|
if .Trunc in flags { sys_flags += {.TRUNC} }
|
||||||
if .Close_On_Exec in flags { sys_flags += {.CLOEXEC} }
|
if .Close_On_Exec 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)u32(perm))
|
||||||
if errno != .NONE {
|
if errno != .NONE {
|
||||||
return nil, _get_platform_error(errno)
|
return nil, _get_platform_error(errno)
|
||||||
}
|
}
|
||||||
@@ -296,13 +295,13 @@ _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: File_Mode) -> Error {
|
_chmod :: proc(name: string, mode: int) -> Error {
|
||||||
TEMP_ALLOCATOR_GUARD()
|
TEMP_ALLOCATOR_GUARD()
|
||||||
name_cstr := temp_cstring(name) or_return
|
name_cstr := temp_cstring(name) 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)(u32(mode))))
|
||||||
}
|
}
|
||||||
|
|
||||||
_fchmod :: proc(f: ^File, mode: File_Mode) -> Error {
|
_fchmod :: proc(f: ^File, mode: int) -> 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)(u32(mode))))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (d
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
write_entire_file :: proc(name: string, data: []byte, perm: File_Mode, truncate := true) -> Error {
|
write_entire_file :: proc(name: string, data: []byte, perm: int, truncate := true) -> Error {
|
||||||
flags := O_WRONLY|O_CREATE
|
flags := O_WRONLY|O_CREATE
|
||||||
if truncate {
|
if truncate {
|
||||||
flags |= O_TRUNC
|
flags |= O_TRUNC
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ _handle :: proc(f: ^File) -> win32.HANDLE {
|
|||||||
return win32.HANDLE(_fd(f))
|
return win32.HANDLE(_fd(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
_open_internal :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (handle: uintptr, err: Error) {
|
_open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: uintptr, err: Error) {
|
||||||
if len(name) == 0 {
|
if len(name) == 0 {
|
||||||
err = .Not_Exist
|
err = .Not_Exist
|
||||||
return
|
return
|
||||||
@@ -122,7 +122,7 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (han
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (f: ^File, err: Error) {
|
_open :: proc(name: string, flags: File_Flags, perm: int) -> (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), nil
|
return _new_file(handle, name), nil
|
||||||
@@ -498,7 +498,6 @@ _rename :: proc(old_path, new_path: string) -> Error {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_link :: proc(old_name, new_name: string) -> Error {
|
_link :: proc(old_name, new_name: string) -> Error {
|
||||||
o := _fix_long_path(old_name)
|
o := _fix_long_path(old_name)
|
||||||
n := _fix_long_path(new_name)
|
n := _fix_long_path(new_name)
|
||||||
@@ -635,7 +634,7 @@ _fchdir :: proc(f: ^File) -> Error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_fchmod :: proc(f: ^File, mode: File_Mode) -> Error {
|
_fchmod :: proc(f: ^File, mode: int) -> Error {
|
||||||
if f == nil || f.impl == nil {
|
if f == nil || f.impl == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -670,7 +669,7 @@ _chdir :: proc(name: string) -> Error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_chmod :: proc(name: string, mode: File_Mode) -> Error {
|
_chmod :: proc(name: string, mode: int) -> 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)
|
||||||
@@ -718,8 +717,6 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
_exists :: proc(path: string) -> bool {
|
_exists :: proc(path: string) -> bool {
|
||||||
wpath := _fix_long_path(path)
|
wpath := _fix_long_path(path)
|
||||||
attribs := win32.GetFileAttributesW(wpath)
|
attribs := win32.GetFileAttributesW(wpath)
|
||||||
|
|||||||
@@ -12,12 +12,14 @@ is_path_separator :: proc(c: byte) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mkdir :: make_directory
|
mkdir :: make_directory
|
||||||
make_directory :: proc(name: string, perm: File_Mode) -> Error {
|
|
||||||
|
make_directory :: proc(name: string, perm: int) -> Error {
|
||||||
return _mkdir(name, perm)
|
return _mkdir(name, perm)
|
||||||
}
|
}
|
||||||
|
|
||||||
mkdir_all :: make_directory_all
|
mkdir_all :: make_directory_all
|
||||||
make_directory_all :: proc(path: string, perm: File_Mode) -> Error {
|
|
||||||
|
make_directory_all :: proc(path: string, perm: int) -> Error {
|
||||||
return _mkdir_all(path, perm)
|
return _mkdir_all(path, perm)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,14 +27,15 @@ remove_all :: proc(path: string) -> Error {
|
|||||||
return _remove_all(path)
|
return _remove_all(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getwd :: get_working_directory
|
getwd :: get_working_directory
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||||
return _getwd(allocator)
|
return _getwd(allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
setwd :: set_working_directory
|
setwd :: set_working_directory
|
||||||
|
|
||||||
set_working_directory :: proc(dir: string) -> (err: Error) {
|
set_working_directory :: proc(dir: string) -> (err: Error) {
|
||||||
return _setwd(dir)
|
return _setwd(dir)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,19 +15,13 @@ _is_path_separator :: proc(c: byte) -> bool {
|
|||||||
return c == '/'
|
return c == '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
_mkdir :: proc(path: string, perm: File_Mode) -> Error {
|
_mkdir :: proc(path: string, perm: int) -> Error {
|
||||||
// TODO: These modes would require mknod, however, that would also
|
|
||||||
// require additional arguments to this function..
|
|
||||||
if perm & (File_Mode_Named_Pipe | File_Mode_Device | File_Mode_Char_Device | File_Mode_Sym_Link) != 0 {
|
|
||||||
return .Invalid_Argument
|
|
||||||
}
|
|
||||||
|
|
||||||
TEMP_ALLOCATOR_GUARD()
|
TEMP_ALLOCATOR_GUARD()
|
||||||
path_cstr := temp_cstring(path) or_return
|
path_cstr := temp_cstring(path) or_return
|
||||||
return _get_platform_error(linux.mkdir(path_cstr, transmute(linux.Mode)(u32(perm) & 0o777)))
|
return _get_platform_error(linux.mkdir(path_cstr, transmute(linux.Mode)u32(perm)))
|
||||||
}
|
}
|
||||||
|
|
||||||
_mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
|
_mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||||
mkdirat :: proc(dfd: linux.Fd, path: []u8, perm: int, has_created: ^bool) -> Error {
|
mkdirat :: proc(dfd: linux.Fd, path: []u8, perm: int, has_created: ^bool) -> Error {
|
||||||
i: int
|
i: int
|
||||||
for ; i < len(path) - 1 && path[i] != '/'; i += 1 {}
|
for ; i < len(path) - 1 && path[i] != '/'; i += 1 {}
|
||||||
@@ -38,7 +32,7 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
|
|||||||
new_dfd, errno := linux.openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS)
|
new_dfd, errno := linux.openat(dfd, cstring(&path[0]), _OPENDIR_FLAGS)
|
||||||
#partial switch errno {
|
#partial switch errno {
|
||||||
case .ENOENT:
|
case .ENOENT:
|
||||||
if errno = linux.mkdirat(dfd, cstring(&path[0]), transmute(linux.Mode)(u32(perm))); errno != .NONE {
|
if errno = linux.mkdirat(dfd, cstring(&path[0]), transmute(linux.Mode)u32(perm)); errno != .NONE {
|
||||||
return _get_platform_error(errno)
|
return _get_platform_error(errno)
|
||||||
}
|
}
|
||||||
has_created^ = true
|
has_created^ = true
|
||||||
@@ -58,12 +52,6 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
|
|||||||
}
|
}
|
||||||
unreachable()
|
unreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
if perm & (File_Mode_Named_Pipe | File_Mode_Device | File_Mode_Char_Device | File_Mode_Sym_Link) != 0 {
|
|
||||||
return .Invalid_Argument
|
|
||||||
}
|
|
||||||
|
|
||||||
TEMP_ALLOCATOR_GUARD()
|
TEMP_ALLOCATOR_GUARD()
|
||||||
// need something we can edit, and use to generate cstrings
|
// need something we can edit, and use to generate cstrings
|
||||||
path_bytes := make([]u8, len(path) + 1, temp_allocator())
|
path_bytes := make([]u8, len(path) + 1, temp_allocator())
|
||||||
@@ -85,7 +73,7 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
has_created: bool
|
has_created: bool
|
||||||
mkdirat(dfd, path_bytes, int(perm & 0o777), &has_created) or_return
|
mkdirat(dfd, path_bytes, perm, &has_created) or_return
|
||||||
if has_created {
|
if has_created {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ _is_path_separator :: proc(c: byte) -> bool {
|
|||||||
return c == '\\' || c == '/'
|
return c == '\\' || c == '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
_mkdir :: proc(name: string, perm: File_Mode) -> Error {
|
_mkdir :: proc(name: string, perm: int) -> Error {
|
||||||
if !win32.CreateDirectoryW(_fix_long_path(name), nil) {
|
if !win32.CreateDirectoryW(_fix_long_path(name), nil) {
|
||||||
return _get_platform_error()
|
return _get_platform_error()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
|
_mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||||
fix_root_directory :: proc(p: string) -> (s: string, allocated: bool, err: runtime.Allocator_Error) {
|
fix_root_directory :: proc(p: string) -> (s: string, allocated: bool, err: runtime.Allocator_Error) {
|
||||||
if len(p) == len(`\\?\c:`) {
|
if len(p) == len(`\\?\c:`) {
|
||||||
if is_path_separator(p[0]) && is_path_separator(p[1]) && p[2] == '?' && is_path_separator(p[3]) && p[5] == ':' {
|
if is_path_separator(p[0]) && is_path_separator(p[1]) && p[2] == '?' && is_path_separator(p[3]) && p[5] == ':' {
|
||||||
@@ -33,9 +33,9 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
|
|||||||
|
|
||||||
TEMP_ALLOCATOR_GUARD()
|
TEMP_ALLOCATOR_GUARD()
|
||||||
|
|
||||||
dir, err := stat(path, temp_allocator())
|
dir_stat, err := stat(path, temp_allocator())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if dir.is_directory {
|
if dir_stat.type == .Directory {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return .Exist
|
return .Exist
|
||||||
@@ -61,8 +61,8 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
|
|||||||
|
|
||||||
err = mkdir(path, perm)
|
err = mkdir(path, perm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
dir1, err1 := lstat(path, temp_allocator())
|
new_dir_stat, err1 := lstat(path, temp_allocator())
|
||||||
if err1 == nil && dir1.is_directory {
|
if err1 == nil && new_dir_stat.type == .Directory {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@@ -85,7 +85,6 @@ _setwd :: proc(dir: string) -> (err: Error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
can_use_long_paths: bool
|
can_use_long_paths: bool
|
||||||
|
|
||||||
@(init)
|
@(init)
|
||||||
@@ -96,7 +95,6 @@ init_long_path_support :: proc() {
|
|||||||
can_use_long_paths = false
|
can_use_long_paths = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_fix_long_path_slice :: proc(path: string) -> []u16 {
|
_fix_long_path_slice :: proc(path: string) -> []u16 {
|
||||||
return win32.utf8_to_utf16(_fix_long_path_internal(path))
|
return win32.utf8_to_utf16(_fix_long_path_internal(path))
|
||||||
}
|
}
|
||||||
@@ -105,7 +103,6 @@ _fix_long_path :: proc(path: string) -> win32.wstring {
|
|||||||
return win32.utf8_to_wstring(_fix_long_path_internal(path))
|
return win32.utf8_to_wstring(_fix_long_path_internal(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_fix_long_path_internal :: proc(path: string) -> string {
|
_fix_long_path_internal :: proc(path: string) -> string {
|
||||||
if can_use_long_paths {
|
if can_use_long_paths {
|
||||||
return path
|
return path
|
||||||
@@ -162,5 +159,4 @@ _fix_long_path_internal :: proc(path: string) -> string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return string(path_buf[:w])
|
return string(path_buf[:w])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ File_Info :: struct {
|
|||||||
fullpath: string,
|
fullpath: string,
|
||||||
name: string,
|
name: string,
|
||||||
size: i64,
|
size: i64,
|
||||||
mode: File_Mode,
|
mode: int,
|
||||||
is_directory: bool,
|
type: File_Type,
|
||||||
creation_time: time.Time,
|
creation_time: time.Time,
|
||||||
modification_time: time.Time,
|
modification_time: time.Time,
|
||||||
access_time: time.Time,
|
access_time: time.Time,
|
||||||
@@ -43,6 +43,7 @@ stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lstat :: stat_do_not_follow_links
|
lstat :: stat_do_not_follow_links
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
stat_do_not_follow_links :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
|
stat_do_not_follow_links :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
|
||||||
return _lstat(name, allocator)
|
return _lstat(name, allocator)
|
||||||
|
|||||||
@@ -17,20 +17,29 @@ _fstat_internal :: proc(fd: linux.Fd, allocator: runtime.Allocator) -> (File_Inf
|
|||||||
if errno != .NONE {
|
if errno != .NONE {
|
||||||
return {}, _get_platform_error(errno)
|
return {}, _get_platform_error(errno)
|
||||||
}
|
}
|
||||||
|
type := File_Type.Regular
|
||||||
|
switch s.mode & linux.S_IFMT {
|
||||||
|
case linux.S_IFBLK: type = .Block_Device
|
||||||
|
case linux.S_IFCHR: type = .Character_Device
|
||||||
|
case linux.S_IFDIR: type = .Directory
|
||||||
|
case linux.S_IFIFO: type = .Named_Pipe
|
||||||
|
case linux.S_IFLNK: type = .Symlink
|
||||||
|
case linux.S_IFREG: type = .Regular
|
||||||
|
case linux.S_IFSOCK: type = .Socket
|
||||||
|
}
|
||||||
|
mode := int(s.mode) & 0o7777
|
||||||
// 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 {
|
||||||
fullpath = _get_full_path(fd, allocator),
|
fullpath = _get_full_path(fd, allocator),
|
||||||
name = "",
|
name = "",
|
||||||
size = i64(s.size),
|
size = i64(s.size),
|
||||||
mode = 0,
|
mode = mode,
|
||||||
is_directory = linux.S_ISDIR(s.mode),
|
type = type,
|
||||||
modification_time = time.Time {i64(s.mtime.time_sec) * i64(time.Second) + i64(s.mtime.time_nsec)},
|
modification_time = time.Time {i64(s.mtime.time_sec) * i64(time.Second) + i64(s.mtime.time_nsec)},
|
||||||
access_time = time.Time {i64(s.atime.time_sec) * i64(time.Second) + i64(s.atime.time_nsec)},
|
access_time = time.Time {i64(s.atime.time_sec) * i64(time.Second) + i64(s.atime.time_nsec)},
|
||||||
creation_time = time.Time{i64(s.ctime.time_sec) * i64(time.Second) + i64(s.ctime.time_nsec)}, // regular stat does not provide this
|
creation_time = time.Time{i64(s.ctime.time_sec) * i64(time.Second) + i64(s.ctime.time_nsec)}, // regular stat does not provide this
|
||||||
}
|
}
|
||||||
fi.creation_time = fi.modification_time
|
fi.creation_time = fi.modification_time
|
||||||
|
|
||||||
fi.name = filepath.base(fi.fullpath)
|
fi.name = filepath.base(fi.fullpath)
|
||||||
return fi, nil
|
return fi, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,28 +19,29 @@ _fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) {
|
|||||||
h := _handle(f)
|
h := _handle(f)
|
||||||
switch win32.GetFileType(h) {
|
switch win32.GetFileType(h) {
|
||||||
case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR:
|
case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR:
|
||||||
fi: File_Info
|
fi := File_Info {
|
||||||
fi.fullpath = path
|
fullpath = path,
|
||||||
fi.name = basename(path)
|
name = basename(path),
|
||||||
fi.mode |= file_type_mode(h)
|
type = file_type(h),
|
||||||
|
}
|
||||||
return fi, nil
|
return fi, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return _file_info_from_get_file_information_by_handle(path, h, allocator)
|
return _file_info_from_get_file_information_by_handle(path, h, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
_stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
|
_stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
|
||||||
return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS, allocator)
|
return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
_lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
|
_lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
|
||||||
return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS|win32.FILE_FLAG_OPEN_REPARSE_POINT, allocator)
|
return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS|win32.FILE_FLAG_OPEN_REPARSE_POINT, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
_same_file :: proc(fi1, fi2: File_Info) -> bool {
|
_same_file :: proc(fi1, fi2: File_Info) -> bool {
|
||||||
return fi1.fullpath == fi2.fullpath
|
return fi1.fullpath == fi2.fullpath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path: string, err: Error) {
|
full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path: string, err: Error) {
|
||||||
name := name
|
name := name
|
||||||
if name == "" {
|
if name == "" {
|
||||||
@@ -62,7 +63,6 @@ full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path
|
|||||||
return win32.utf16_to_utf8(buf[:n], allocator)
|
return win32.utf16_to_utf8(buf[:n], allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
|
internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
|
||||||
if len(name) == 0 {
|
if len(name) == 0 {
|
||||||
return {}, .Not_Exist
|
return {}, .Not_Exist
|
||||||
@@ -99,7 +99,6 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runt
|
|||||||
return _file_info_from_get_file_information_by_handle(name, h, allocator)
|
return _file_info_from_get_file_information_by_handle(name, h, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
|
_cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
|
||||||
buf := buf
|
buf := buf
|
||||||
N := 0
|
N := 0
|
||||||
@@ -120,7 +119,6 @@ _cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
|
|||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (string, Error) {
|
_cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (string, Error) {
|
||||||
if f == nil {
|
if f == nil {
|
||||||
return "", nil
|
return "", nil
|
||||||
@@ -159,7 +157,6 @@ _cleanpath_from_buf :: proc(buf: []u16, allocator: runtime.Allocator) -> (string
|
|||||||
return win32.utf16_to_utf8(buf, allocator)
|
return win32.utf16_to_utf8(buf, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
basename :: proc(name: string) -> (base: string) {
|
basename :: proc(name: string) -> (base: string) {
|
||||||
name := name
|
name := name
|
||||||
if len(name) > 3 && name[:3] == `\\?` {
|
if len(name) > 3 && name[:3] == `\\?` {
|
||||||
@@ -185,83 +182,67 @@ basename :: proc(name: string) -> (base: string) {
|
|||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file_type :: proc(h: win32.HANDLE) -> File_Type {
|
||||||
file_type_mode :: proc(h: win32.HANDLE) -> File_Mode {
|
|
||||||
switch win32.GetFileType(h) {
|
switch win32.GetFileType(h) {
|
||||||
case win32.FILE_TYPE_PIPE:
|
case win32.FILE_TYPE_PIPE: return .Named_Pipe
|
||||||
return File_Mode_Named_Pipe
|
case win32.FILE_TYPE_CHAR: return .Character_Device
|
||||||
case win32.FILE_TYPE_CHAR:
|
case win32.FILE_TYPE_DISK: return .Regular
|
||||||
return File_Mode_Device | File_Mode_Char_Device
|
|
||||||
}
|
}
|
||||||
return 0
|
return .Undetermined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (type: File_Type, mode: int) {
|
||||||
|
|
||||||
_file_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (mode: File_Mode) {
|
|
||||||
if file_attributes & win32.FILE_ATTRIBUTE_READONLY != 0 {
|
if file_attributes & win32.FILE_ATTRIBUTE_READONLY != 0 {
|
||||||
mode |= 0o444
|
mode |= 0o444
|
||||||
} else {
|
} else {
|
||||||
mode |= 0o666
|
mode |= 0o666
|
||||||
}
|
}
|
||||||
|
|
||||||
is_sym := false
|
is_sym := false
|
||||||
if file_attributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
|
if file_attributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
|
||||||
is_sym = false
|
is_sym = false
|
||||||
} else {
|
} else {
|
||||||
is_sym = ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT
|
is_sym = ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_sym {
|
if is_sym {
|
||||||
mode |= File_Mode_Sym_Link
|
type = .Symlink
|
||||||
} else {
|
} else {
|
||||||
if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||||
mode |= 0o111 | File_Mode_Dir
|
type = .Directory
|
||||||
|
mode |= 0o111
|
||||||
}
|
}
|
||||||
|
|
||||||
if h != nil {
|
if h != nil {
|
||||||
mode |= file_type_mode(h)
|
type = file_type(h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
|
_file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
|
||||||
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
|
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
|
||||||
|
type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
|
||||||
fi.mode |= _file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
|
fi.type = type
|
||||||
fi.is_directory = fi.mode & File_Mode_Dir != 0
|
fi.mode |= mode
|
||||||
|
|
||||||
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
||||||
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
||||||
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
||||||
|
|
||||||
fi.fullpath, e = full_path_from_name(name, allocator)
|
fi.fullpath, e = full_path_from_name(name, allocator)
|
||||||
fi.name = basename(fi.fullpath)
|
fi.name = basename(fi.fullpath)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
|
_file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
|
||||||
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
|
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
|
||||||
|
type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
|
||||||
fi.mode |= _file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
|
fi.type = type
|
||||||
fi.is_directory = fi.mode & File_Mode_Dir != 0
|
fi.mode |= mode
|
||||||
|
|
||||||
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
||||||
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
||||||
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
||||||
|
|
||||||
fi.fullpath, e = full_path_from_name(name, allocator)
|
fi.fullpath, e = full_path_from_name(name, allocator)
|
||||||
fi.name = basename(fi.fullpath)
|
fi.name = basename(fi.fullpath)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE, allocator: runtime.Allocator) -> (File_Info, Error) {
|
_file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE, allocator: runtime.Allocator) -> (File_Info, Error) {
|
||||||
d: win32.BY_HANDLE_FILE_INFORMATION
|
d: win32.BY_HANDLE_FILE_INFORMATION
|
||||||
if !win32.GetFileInformationByHandle(h, &d) {
|
if !win32.GetFileInformationByHandle(h, &d) {
|
||||||
@@ -278,25 +259,19 @@ _file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HA
|
|||||||
// Indicate this is a symlink on FAT file systems
|
// Indicate this is a symlink on FAT file systems
|
||||||
ti.ReparseTag = 0
|
ti.ReparseTag = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fi: File_Info
|
fi: File_Info
|
||||||
|
|
||||||
fi.fullpath = path
|
fi.fullpath = path
|
||||||
fi.name = basename(path)
|
fi.name = basename(path)
|
||||||
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
|
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
|
||||||
|
type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
|
||||||
fi.mode |= _file_mode_from_file_attributes(ti.FileAttributes, h, ti.ReparseTag)
|
fi.type = type
|
||||||
fi.is_directory = fi.mode & File_Mode_Dir != 0
|
fi.mode |= mode
|
||||||
|
|
||||||
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime))
|
||||||
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
|
||||||
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
|
||||||
|
|
||||||
return fi, nil
|
return fi, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
reserved_names := [?]string{
|
reserved_names := [?]string{
|
||||||
"CON", "PRN", "AUX", "NUL",
|
"CON", "PRN", "AUX", "NUL",
|
||||||
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
||||||
@@ -357,7 +332,6 @@ _volume_name_len :: proc(path: string) -> int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_is_abs :: proc(path: string) -> bool {
|
_is_abs :: proc(path: string) -> bool {
|
||||||
if _is_reserved_name(path) {
|
if _is_reserved_name(path) {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -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}, File_Mode(0o666))
|
f, err = open(name, {.Read, .Write, .Create, .Excl}, 0o666)
|
||||||
if err == .Exist {
|
if err == .Exist {
|
||||||
close(f)
|
close(f)
|
||||||
attempts += 1
|
attempts += 1
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ Mode_Bits :: enum {
|
|||||||
ISVTX = 9, // 0o0001000
|
ISVTX = 9, // 0o0001000
|
||||||
ISGID = 10, // 0o0002000
|
ISGID = 10, // 0o0002000
|
||||||
ISUID = 11, // 0o0004000
|
ISUID = 11, // 0o0004000
|
||||||
IFFIFO = 12, // 0o0010000
|
IFIFO = 12, // 0o0010000
|
||||||
IFCHR = 13, // 0o0020000
|
IFCHR = 13, // 0o0020000
|
||||||
IFDIR = 14, // 0o0040000
|
IFDIR = 14, // 0o0040000
|
||||||
IFREG = 15, // 0o0100000
|
IFREG = 15, // 0o0100000
|
||||||
|
|||||||
@@ -39,11 +39,11 @@ PRIO_MIN :: -20
|
|||||||
SIGRTMIN :: Signal(32)
|
SIGRTMIN :: Signal(32)
|
||||||
SIGRTMAX :: Signal(64)
|
SIGRTMAX :: Signal(64)
|
||||||
|
|
||||||
S_IFMT :: Mode{.IFREG, .IFDIR, .IFCHR, .IFFIFO}
|
S_IFMT :: Mode{.IFREG, .IFDIR, .IFCHR, .IFIFO}
|
||||||
S_IFSOCK :: Mode{.IFREG, .IFDIR}
|
S_IFSOCK :: Mode{.IFREG, .IFDIR}
|
||||||
S_IFLNK :: Mode{.IFREG, .IFCHR}
|
S_IFLNK :: Mode{.IFREG, .IFCHR}
|
||||||
S_IFBLK :: Mode{.IFDIR, .IFCHR}
|
S_IFBLK :: Mode{.IFDIR, .IFCHR}
|
||||||
S_IFFIFO :: Mode{.IFFIFO}
|
S_IFIFO :: Mode{.IFIFO}
|
||||||
S_IFCHR :: Mode{.IFCHR}
|
S_IFCHR :: Mode{.IFCHR}
|
||||||
S_IFDIR :: Mode{.IFDIR}
|
S_IFDIR :: Mode{.IFDIR}
|
||||||
S_IFREG :: Mode{.IFREG}
|
S_IFREG :: Mode{.IFREG}
|
||||||
@@ -51,7 +51,7 @@ S_IFREG :: Mode{.IFREG}
|
|||||||
/*
|
/*
|
||||||
Checks the Mode bits to see if the file is a named pipe (FIFO).
|
Checks the Mode bits to see if the file is a named pipe (FIFO).
|
||||||
*/
|
*/
|
||||||
S_ISFIFO :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFFIFO == (m & S_IFMT))}
|
S_ISFIFO :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFIFO == (m & S_IFMT))}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check the Mode bits to see if the file is a character device.
|
Check the Mode bits to see if the file is a character device.
|
||||||
|
|||||||
Reference in New Issue
Block a user