mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-31 18:32:12 +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:
@@ -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))
|
||||
|
||||
@@ -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))))
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user