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:
gingerBill
2024-07-19 11:37:54 +01:00
committed by GitHub
13 changed files with 137 additions and 120 deletions

View File

@@ -4,20 +4,57 @@ import "core:io"
import "core:time"
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 {
impl: rawptr,
stream: io.Stream,
fstat: Fstat_Callback,
}
File_Mode :: distinct u32
File_Mode_Dir :: File_Mode(1<<16)
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)
/*
Type representing the type of a file handle.
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_Flag :: enum {
@@ -51,11 +88,11 @@ stderr: ^File = nil // OS-Specific
@(require_results)
create :: proc(name: string) -> (^File, Error) {
return open(name, {.Read, .Write, .Create}, File_Mode(0o777))
return open(name, {.Read, .Write, .Create}, 0o777)
}
@(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)
}
@@ -161,44 +198,56 @@ read_link :: proc(name: string, allocator: runtime.Allocator) -> (string, Error)
chdir :: change_directory
change_directory :: proc(name: string) -> Error {
return _chdir(name)
}
chmod :: change_mode
change_mode :: proc(name: string, mode: File_Mode) -> Error {
change_mode :: proc(name: string, mode: int) -> Error {
return _chmod(name, mode)
}
chown :: change_owner
change_owner :: proc(name: string, uid, gid: int) -> Error {
return _chown(name, uid, gid)
}
fchdir :: fchange_directory
fchange_directory :: proc(f: ^File) -> Error {
return _fchdir(f)
}
fchmod :: fchange_mode
fchange_mode :: proc(f: ^File, mode: File_Mode) -> Error {
fchange_mode :: proc(f: ^File, mode: int) -> Error {
return _fchmod(f, mode)
}
fchown :: fchange_owner
fchange_owner :: proc(f: ^File, uid, gid: int) -> Error {
return _fchown(f, uid, gid)
}
lchown :: change_owner_do_not_follow_links
change_owner_do_not_follow_links :: proc(name: string, uid, gid: int) -> Error {
return _lchown(name, uid, gid)
}
chtimes :: change_times
change_times :: proc(name: string, atime, mtime: time.Time) -> Error {
return _chtimes(name, atime, mtime)
}
fchtimes :: fchange_times
fchange_times :: proc(f: ^File, atime, mtime: time.Time) -> Error {
return _fchtimes(f, atime, mtime)
}
@@ -214,6 +263,7 @@ is_file :: proc(path: string) -> bool {
}
is_dir :: is_directory
@(require_results)
is_directory :: proc(path: string) -> bool {
return _is_dir(path)
@@ -226,11 +276,11 @@ copy_file :: proc(dst_path, src_path: string) -> Error {
info := fstat(src, file_allocator()) or_return
defer file_info_delete(info, file_allocator())
if info.is_directory {
if info.type == .Directory {
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)
_, err := io.copy(to_writer(dst), to_reader(src))

View File

@@ -63,7 +63,7 @@ _file_allocator :: proc() -> runtime.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()
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_RDWR: sys_flags += {.RDWR}
}
if .Append in flags { sys_flags += {.APPEND} }
if .Create in flags { sys_flags += {.CREAT} }
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 .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 {
return nil, _get_platform_error(errno)
}
@@ -296,13 +295,13 @@ _fchdir :: proc(f: ^File) -> Error {
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()
name_cstr := temp_cstring(name) or_return
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)
return _get_platform_error(linux.fchmod(impl.fd, transmute(linux.Mode)(u32(mode))))
}

View File

@@ -138,7 +138,7 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (d
}
@(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
if truncate {
flags |= O_TRUNC

View File

@@ -55,7 +55,7 @@ _handle :: proc(f: ^File) -> win32.HANDLE {
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 {
err = .Not_Exist
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}
handle := _open_internal(name, flags, perm) or_return
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 {
o := _fix_long_path(old_name)
n := _fix_long_path(new_name)
@@ -635,7 +634,7 @@ _fchdir :: proc(f: ^File) -> Error {
return nil
}
_fchmod :: proc(f: ^File, mode: File_Mode) -> Error {
_fchmod :: proc(f: ^File, mode: int) -> Error {
if f == nil || f.impl == nil {
return nil
}
@@ -670,7 +669,7 @@ _chdir :: proc(name: string) -> Error {
return nil
}
_chmod :: proc(name: string, mode: File_Mode) -> Error {
_chmod :: proc(name: string, mode: int) -> Error {
f := open(name, {.Write}) or_return
defer close(f)
return _fchmod(f, mode)
@@ -718,8 +717,6 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
return nil
}
_exists :: proc(path: string) -> bool {
wpath := _fix_long_path(path)
attribs := win32.GetFileAttributesW(wpath)

View File

@@ -12,12 +12,14 @@ is_path_separator :: proc(c: byte) -> bool {
}
mkdir :: make_directory
make_directory :: proc(name: string, perm: File_Mode) -> Error {
make_directory :: proc(name: string, perm: int) -> Error {
return _mkdir(name, perm)
}
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)
}
@@ -25,14 +27,15 @@ remove_all :: proc(path: string) -> Error {
return _remove_all(path)
}
getwd :: get_working_directory
@(require_results)
get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
return _getwd(allocator)
}
setwd :: set_working_directory
set_working_directory :: proc(dir: string) -> (err: Error) {
return _setwd(dir)
}

View File

@@ -15,19 +15,13 @@ _is_path_separator :: proc(c: byte) -> bool {
return c == '/'
}
_mkdir :: proc(path: string, perm: File_Mode) -> 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
}
_mkdir :: proc(path: string, perm: int) -> Error {
TEMP_ALLOCATOR_GUARD()
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 {
i: int
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)
#partial switch errno {
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)
}
has_created^ = true
@@ -58,12 +52,6 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
}
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()
// need something we can edit, and use to generate cstrings
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
mkdirat(dfd, path_bytes, int(perm & 0o777), &has_created) or_return
mkdirat(dfd, path_bytes, perm, &has_created) or_return
if has_created {
return nil
}

View File

@@ -12,14 +12,14 @@ _is_path_separator :: proc(c: byte) -> bool {
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) {
return _get_platform_error()
}
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) {
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] == ':' {
@@ -33,9 +33,9 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
TEMP_ALLOCATOR_GUARD()
dir, err := stat(path, temp_allocator())
dir_stat, err := stat(path, temp_allocator())
if err == nil {
if dir.is_directory {
if dir_stat.type == .Directory {
return nil
}
return .Exist
@@ -61,8 +61,8 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
err = mkdir(path, perm)
if err != nil {
dir1, err1 := lstat(path, temp_allocator())
if err1 == nil && dir1.is_directory {
new_dir_stat, err1 := lstat(path, temp_allocator())
if err1 == nil && new_dir_stat.type == .Directory {
return nil
}
return err
@@ -85,7 +85,6 @@ _setwd :: proc(dir: string) -> (err: Error) {
return nil
}
can_use_long_paths: bool
@(init)
@@ -96,7 +95,6 @@ init_long_path_support :: proc() {
can_use_long_paths = false
}
_fix_long_path_slice :: proc(path: string) -> []u16 {
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))
}
_fix_long_path_internal :: proc(path: string) -> string {
if can_use_long_paths {
return path
@@ -162,5 +159,4 @@ _fix_long_path_internal :: proc(path: string) -> string {
}
return string(path_buf[:w])
}

View File

@@ -9,8 +9,8 @@ File_Info :: struct {
fullpath: string,
name: string,
size: i64,
mode: File_Mode,
is_directory: bool,
mode: int,
type: File_Type,
creation_time: time.Time,
modification_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
@(require_results)
stat_do_not_follow_links :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
return _lstat(name, allocator)

View File

@@ -17,20 +17,29 @@ _fstat_internal :: proc(fd: linux.Fd, allocator: runtime.Allocator) -> (File_Inf
if errno != .NONE {
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
fi := File_Info {
fullpath = _get_full_path(fd, allocator),
name = "",
size = i64(s.size),
mode = 0,
is_directory = linux.S_ISDIR(s.mode),
mode = mode,
type = type,
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)},
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.name = filepath.base(fi.fullpath)
return fi, nil
}

View File

@@ -19,28 +19,29 @@ _fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) {
h := _handle(f)
switch win32.GetFileType(h) {
case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR:
fi: File_Info
fi.fullpath = path
fi.name = basename(path)
fi.mode |= file_type_mode(h)
fi := File_Info {
fullpath = path,
name = basename(path),
type = file_type(h),
}
return fi, nil
}
return _file_info_from_get_file_information_by_handle(path, h, allocator)
}
_stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS, allocator)
}
_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)
}
_same_file :: proc(fi1, fi2: File_Info) -> bool {
return fi1.fullpath == fi2.fullpath
}
full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path: string, err: Error) {
name := 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)
}
internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
if len(name) == 0 {
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)
}
_cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
buf := buf
N := 0
@@ -120,7 +119,6 @@ _cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
return buf
}
_cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (string, Error) {
if f == nil {
return "", nil
@@ -159,7 +157,6 @@ _cleanpath_from_buf :: proc(buf: []u16, allocator: runtime.Allocator) -> (string
return win32.utf16_to_utf8(buf, allocator)
}
basename :: proc(name: string) -> (base: string) {
name := name
if len(name) > 3 && name[:3] == `\\?` {
@@ -185,83 +182,67 @@ basename :: proc(name: string) -> (base: string) {
return name
}
file_type_mode :: proc(h: win32.HANDLE) -> File_Mode {
file_type :: proc(h: win32.HANDLE) -> File_Type {
switch win32.GetFileType(h) {
case win32.FILE_TYPE_PIPE:
return File_Mode_Named_Pipe
case win32.FILE_TYPE_CHAR:
return File_Mode_Device | File_Mode_Char_Device
case win32.FILE_TYPE_PIPE: return .Named_Pipe
case win32.FILE_TYPE_CHAR: return .Character_Device
case win32.FILE_TYPE_DISK: return .Regular
}
return 0
return .Undetermined
}
_file_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (mode: File_Mode) {
_file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (type: File_Type, mode: int) {
if file_attributes & win32.FILE_ATTRIBUTE_READONLY != 0 {
mode |= 0o444
} else {
mode |= 0o666
}
is_sym := false
if file_attributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
is_sym = false
} else {
is_sym = ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT
}
if is_sym {
mode |= File_Mode_Sym_Link
type = .Symlink
} else {
if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
mode |= 0o111 | File_Mode_Dir
type = .Directory
mode |= 0o111
}
if h != nil {
mode |= file_type_mode(h)
type = file_type(h)
}
}
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) {
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
fi.mode |= _file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
fi.is_directory = fi.mode & File_Mode_Dir != 0
type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
fi.type = type
fi.mode |= mode
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.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
fi.fullpath, e = full_path_from_name(name, allocator)
fi.name = basename(fi.fullpath)
return
}
_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.mode |= _file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
fi.is_directory = fi.mode & File_Mode_Dir != 0
type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
fi.type = type
fi.mode |= mode
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.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
fi.fullpath, e = full_path_from_name(name, allocator)
fi.name = basename(fi.fullpath)
return
}
_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
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
ti.ReparseTag = 0
}
fi: File_Info
fi.fullpath = path
fi.name = basename(path)
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
fi.mode |= _file_mode_from_file_attributes(ti.FileAttributes, h, ti.ReparseTag)
fi.is_directory = fi.mode & File_Mode_Dir != 0
type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
fi.type = type
fi.mode |= mode
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.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
return fi, nil
}
reserved_names := [?]string{
"CON", "PRN", "AUX", "NUL",
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
@@ -357,7 +332,6 @@ _volume_name_len :: proc(path: string) -> int {
return 0
}
_is_abs :: proc(path: string) -> bool {
if _is_reserved_name(path) {
return true

View File

@@ -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}, File_Mode(0o666))
f, err = open(name, {.Read, .Write, .Create, .Excl}, 0o666)
if err == .Exist {
close(f)
attempts += 1

View File

@@ -244,7 +244,7 @@ Mode_Bits :: enum {
ISVTX = 9, // 0o0001000
ISGID = 10, // 0o0002000
ISUID = 11, // 0o0004000
IFFIFO = 12, // 0o0010000
IFIFO = 12, // 0o0010000
IFCHR = 13, // 0o0020000
IFDIR = 14, // 0o0040000
IFREG = 15, // 0o0100000

View File

@@ -39,11 +39,11 @@ PRIO_MIN :: -20
SIGRTMIN :: Signal(32)
SIGRTMAX :: Signal(64)
S_IFMT :: Mode{.IFREG, .IFDIR, .IFCHR, .IFFIFO}
S_IFMT :: Mode{.IFREG, .IFDIR, .IFCHR, .IFIFO}
S_IFSOCK :: Mode{.IFREG, .IFDIR}
S_IFLNK :: Mode{.IFREG, .IFCHR}
S_IFBLK :: Mode{.IFDIR, .IFCHR}
S_IFFIFO :: Mode{.IFFIFO}
S_IFIFO :: Mode{.IFIFO}
S_IFCHR :: Mode{.IFCHR}
S_IFDIR :: Mode{.IFDIR}
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).
*/
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.