Browse Source

Merge pull request #3939 from flysand7/os2-file-type

[os2]: Split file type from mode bits et other small fixes
gingerBill 1 year ago
parent
commit
685dbddcb5

+ 64 - 14
core/os/os2/file.odin

@@ -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)
-
-File_Mode_Perm :: File_Mode(0o777) // Unix permision bits
+/*
+	Type representing the type of a file handle.
+
+	**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))

+ 4 - 5
core/os/os2/file_linux.odin

@@ -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))))
 }

+ 1 - 1
core/os/os2/file_util.odin

@@ -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

+ 4 - 7
core/os/os2/file_windows.odin

@@ -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)

+ 6 - 3
core/os/os2/path.odin

@@ -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)
 }

+ 5 - 17
core/os/os2/path_linux.odin

@@ -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
 	}

+ 6 - 10
core/os/os2/path_windows.odin

@@ -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])
-
 }

+ 3 - 2
core/os/os2/stat.odin

@@ -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)

+ 13 - 4
core/os/os2/stat_linux.odin

@@ -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
 }

+ 27 - 53
core/os/os2/stat_windows.odin

@@ -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

+ 1 - 1
core/os/os2/temp_file.odin

@@ -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

+ 1 - 1
core/sys/linux/bits.odin

@@ -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

+ 3 - 3
core/sys/linux/constants.odin

@@ -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.