Add os.stat, os.lstat, os.fstat, filepath.walk

This commit is contained in:
gingerBill
2020-09-28 12:28:02 +01:00
parent 2ebb94fa72
commit 9ae3879956
6 changed files with 170 additions and 32 deletions
+1 -1
View File
@@ -57,7 +57,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
h := win32.HANDLE(fd);
dir_fi, _ := stat_from_file_information("", h);
dir_fi, _ := file_info_from_get_file_information_by_handle("", h);
if !dir_fi.is_dir {
return nil, ERROR_FILE_IS_NOT_DIR;
}
+9 -2
View File
@@ -14,8 +14,15 @@ File_Info :: struct {
access_time: time.Time,
}
file_info_delete :: proc(fi: File_Info) {
delete(fi.fullpath);
file_info_slice_delete :: proc(infos: []File_Info, allocator := context.allocator) {
for i := len(infos)-1; i >= 0; i -= 1 {
file_info_delete(infos[i], allocator);
}
delete(infos, allocator);
}
file_info_delete :: proc(fi: File_Info, allocator := context.allocator) {
delete(fi.fullpath, allocator);
}
File_Mode :: distinct u32;
+148 -26
View File
@@ -3,10 +3,88 @@ package os
import "core:time"
import win32 "core:sys/windows"
stat :: proc(fd: Handle) -> (File_Info, Errno) {
@(private)
full_path_from_name :: proc(name: string, allocator := context.allocator) -> (path: string, err: Errno) {
name := name;
if name == "" {
name = ".";
}
p := win32.utf8_to_utf16(name, context.temp_allocator);
defer delete(p);
buf := make([dynamic]u16, 100, allocator);
for {
n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil);
if n == 0 {
delete(buf);
return "", Errno(win32.GetLastError());
}
if n <= u32(len(buf)) {
return win32.utf16_to_utf8(buf[:n]), ERROR_NONE;
}
resize(&buf, len(buf)*2);
}
return;
}
@(private)
_stat :: proc(name: string, create_file_attributes: u32, allocator := context.allocator) -> (fi: File_Info, e: Errno) {
if len(name) == 0 {
return {}, ERROR_PATH_NOT_FOUND;
}
context.allocator = allocator;
wname := win32.utf8_to_wstring(fix_long_path(name), context.temp_allocator);
fa: win32.WIN32_FILE_ATTRIBUTE_DATA;
ok := win32.GetFileAttributesExW(wname, win32.GetFileExInfoStandard, &fa);
if ok && fa.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
// Not a symlink
return file_info_from_win32_file_attribute_data(&fa, name);
}
err := 0 if ok else win32.GetLastError();
if err == win32.ERROR_SHARING_VIOLATION {
fd: win32.WIN32_FIND_DATAW;
sh := win32.FindFirstFileW(wname, &fd);
if sh == win32.INVALID_HANDLE_VALUE {
e = Errno(win32.GetLastError());
return;
}
win32.FindClose(sh);
return file_info_from_win32_find_data(&fd, name);
}
h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil);
if h == win32.INVALID_HANDLE_VALUE {
e = Errno(win32.GetLastError());
return;
}
defer win32.CloseHandle(h);
return file_info_from_get_file_information_by_handle(name, h);
}
lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) {
attrs := u32(win32.FILE_FLAG_BACKUP_SEMANTICS);
attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT;
return _stat(name, attrs, allocator);
}
stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) {
attrs := u32(win32.FILE_FLAG_BACKUP_SEMANTICS);
return _stat(name, attrs, allocator);
}
fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Errno) {
if fd == 0 {
return {}, ERROR_INVALID_HANDLE;
}
context.allocator = allocator;
path, err := cleanpath_from_handle(fd);
if err != ERROR_NONE {
return {}, err;
@@ -22,7 +100,7 @@ stat :: proc(fd: Handle) -> (File_Info, Errno) {
return fi, ERROR_NONE;
}
return stat_from_file_information(path, h);
return file_info_from_get_file_information_by_handle(path, h);
}
@@ -137,8 +215,73 @@ file_type_mode :: proc(h: win32.HANDLE) -> File_Mode {
return 0;
}
@(private)
stat_from_file_information :: proc(path: string, h: win32.HANDLE) -> (File_Info, Errno) {
file_mode_from_file_attributes :: proc(FileAttributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (mode: File_Mode) {
if FileAttributes & win32.FILE_ATTRIBUTE_READONLY != 0 {
mode |= 0o444;
} else {
mode |= 0o666;
}
is_sym := false;
if FileAttributes & 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;
} else {
if FileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
mode |= 0o111 | File_Mode_Dir;
}
if h != nil {
mode |= file_type_mode(h);
}
}
return;
}
@(private)
file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string) -> (fi: File_Info, e: Errno) {
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow);
fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0);
fi.is_dir = fi.mode & File_Mode_Dir != 0;
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);
fi.name = basename(fi.fullpath);
return;
}
@(private)
file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) -> (fi: File_Info, e: Errno) {
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow);
fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0);
fi.is_dir = fi.mode & File_Mode_Dir != 0;
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);
fi.name = basename(fi.fullpath);
return;
}
@(private)
file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Errno) {
d: win32.BY_HANDLE_FILE_INFORMATION;
if !win32.GetFileInformationByHandle(h, &d) {
err := Errno(win32.GetLastError());
@@ -162,34 +305,13 @@ stat_from_file_information :: proc(path: string, h: win32.HANDLE) -> (File_Info,
fi.name = basename(path);
fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow);
if ti.FileAttributes & win32.FILE_ATTRIBUTE_READONLY != 0 {
fi.mode |= 0o444;
} else {
fi.mode |= 0o666;
}
is_sym := false;
if ti.FileAttributes & win32.FILE_ATTRIBUTE_REPARSE_Point == 0 {
is_sym = false;
} else {
is_sym = ti.ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ti.ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT;
}
if is_sym {
fi.mode |= File_Mode_Sym_Link;
} else {
if ti.FileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
fi.mode |= 0o111 | File_Mode_Dir;
}
fi.mode |= file_type_mode(h);
}
fi.mode |= file_mode_from_file_attributes(ti.FileAttributes, h, ti.ReparseTag);
fi.is_dir = fi.mode & File_Mode_Dir != 0;
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.is_dir = fi.mode & File_Mode_Dir != 0;
return fi, ERROR_NONE;
}
+3 -3
View File
@@ -83,8 +83,8 @@ scan_chunk :: proc(pattern: string) -> (star: bool, chunk, rest: string) {
pattern = pattern[1:];
star = true;
}
in_range := false;
i: int;
in_range, i := false, 0;
scan_loop: for i = 0; i < len(pattern); i += 1 {
switch pattern[i] {
@@ -272,7 +272,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string) -> (m: [dynamic]s
}
defer os.close(d);
fi, ferr := os.stat(d);
fi, ferr := os.fstat(d);
if ferr != 0 {
os.file_info_delete(fi);
return;
+2
View File
@@ -68,6 +68,8 @@ full_path :: proc(name: string, allocator := context.allocator) -> (path: string
}
resize(&buf, len(buf)*2);
}
return;
}
+7
View File
@@ -189,22 +189,29 @@ ERROR_PATH_NOT_FOUND: DWORD : 3;
ERROR_ACCESS_DENIED: DWORD : 5;
ERROR_INVALID_HANDLE: DWORD : 6;
ERROR_NO_MORE_FILES: DWORD : 18;
ERROR_SHARING_VIOLATION: DWORD : 32;
ERROR_LOCK_VIOLATION: DWORD : 33;
ERROR_HANDLE_EOF: DWORD : 38;
ERROR_NOT_SUPPORTED: DWORD : 50;
ERROR_FILE_EXISTS: DWORD : 80;
ERROR_INVALID_PARAMETER: DWORD : 87;
ERROR_BROKEN_PIPE: DWORD : 109;
ERROR_CALL_NOT_IMPLEMENTED: DWORD : 120;
ERROR_INSUFFICIENT_BUFFER: DWORD : 122;
ERROR_INVALID_NAME: DWORD : 123;
ERROR_LOCK_FAILED: DWORD : 167;
ERROR_ALREADY_EXISTS: DWORD : 183;
ERROR_NO_DATA: DWORD : 232;
ERROR_ENVVAR_NOT_FOUND: DWORD : 203;
ERROR_OPERATION_ABORTED: DWORD : 995;
ERROR_IO_PENDING: DWORD : 997;
ERROR_TIMEOUT: DWORD : 0x5B4;
ERROR_NO_UNICODE_TRANSLATION: DWORD : 1113;
E_NOTIMPL :: HRESULT(-0x7fff_bfff); // 0x8000_4001
INVALID_HANDLE :: HANDLE(~uintptr(0));
INVALID_HANDLE_VALUE :: INVALID_HANDLE;
FACILITY_NT_BIT: DWORD : 0x1000_0000;