mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
os/os2: recursive directory walker, expose errors in read_directory, file clone
Adds a directory walker, a method of exposing and retrieving errors from the existing read directory iterator, allows reusing of the existing read directory iterator, and adds a file clone procedure
This commit is contained in:
+32
-14
@@ -8,12 +8,11 @@ Read_Directory_Iterator_Impl :: struct {
|
||||
dirent_backing: []u8,
|
||||
dirent_buflen: int,
|
||||
dirent_off: int,
|
||||
index: int,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
_read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) {
|
||||
scan_entries :: proc(dfd: linux.Fd, entries: []u8, offset: ^int) -> (fd: linux.Fd, file_name: string) {
|
||||
scan_entries :: proc(it: ^Read_Directory_Iterator, dfd: linux.Fd, entries: []u8, offset: ^int) -> (fd: linux.Fd, file_name: string) {
|
||||
for d in linux.dirent_iterate_buf(entries, offset) {
|
||||
file_name = linux.dirent_name(d)
|
||||
if file_name == "." || file_name == ".." {
|
||||
@@ -24,18 +23,21 @@ _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info
|
||||
entry_fd, errno := linux.openat(dfd, file_name_cstr, {.NOFOLLOW, .PATH})
|
||||
if errno == .NONE {
|
||||
return entry_fd, file_name
|
||||
} else {
|
||||
read_directory_iterator_set_error(it, file_name, _get_platform_error(errno))
|
||||
}
|
||||
}
|
||||
|
||||
return -1, ""
|
||||
}
|
||||
|
||||
index = it.impl.index
|
||||
it.impl.index += 1
|
||||
index = it.index
|
||||
it.index += 1
|
||||
|
||||
dfd := linux.Fd(_fd(it.f))
|
||||
|
||||
entries := it.impl.dirent_backing[:it.impl.dirent_buflen]
|
||||
entry_fd, file_name := scan_entries(dfd, entries, &it.impl.dirent_off)
|
||||
entry_fd, file_name := scan_entries(it, dfd, entries, &it.impl.dirent_off)
|
||||
|
||||
for entry_fd == -1 {
|
||||
if len(it.impl.dirent_backing) == 0 {
|
||||
@@ -58,44 +60,60 @@ _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info
|
||||
it.impl.dirent_buflen = buflen
|
||||
entries = it.impl.dirent_backing[:buflen]
|
||||
break loop
|
||||
case: // error
|
||||
case:
|
||||
read_directory_iterator_set_error(it, name(it.f), _get_platform_error(errno))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
entry_fd, file_name = scan_entries(dfd, entries, &it.impl.dirent_off)
|
||||
entry_fd, file_name = scan_entries(it, dfd, entries, &it.impl.dirent_off)
|
||||
}
|
||||
defer linux.close(entry_fd)
|
||||
|
||||
// PERF: reuse the fullpath string like on posix and wasi.
|
||||
file_info_delete(it.impl.prev_fi, file_allocator())
|
||||
fi, _ = _fstat_internal(entry_fd, file_allocator())
|
||||
|
||||
err: Error
|
||||
fi, err = _fstat_internal(entry_fd, file_allocator())
|
||||
it.impl.prev_fi = fi
|
||||
|
||||
if err != nil {
|
||||
path, _ := _get_full_path(entry_fd, temp_allocator())
|
||||
read_directory_iterator_set_error(it, path, err)
|
||||
}
|
||||
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
_read_directory_iterator_create :: proc(f: ^File) -> (Read_Directory_Iterator, Error) {
|
||||
_read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
|
||||
// NOTE: Allow calling `init` to target a new directory with the same iterator.
|
||||
it.impl.dirent_buflen = 0
|
||||
it.impl.dirent_off = 0
|
||||
|
||||
if f == nil || f.impl == nil {
|
||||
return {}, .Invalid_File
|
||||
read_directory_iterator_set_error(it, "", .Invalid_File)
|
||||
return
|
||||
}
|
||||
|
||||
stat: linux.Stat
|
||||
errno := linux.fstat(linux.Fd(fd(f)), &stat)
|
||||
if errno != .NONE {
|
||||
return {}, _get_platform_error(errno)
|
||||
read_directory_iterator_set_error(it, name(f), _get_platform_error(errno))
|
||||
return
|
||||
}
|
||||
|
||||
if (stat.mode & linux.S_IFMT) != linux.S_IFDIR {
|
||||
return {}, .Invalid_Dir
|
||||
read_directory_iterator_set_error(it, name(f), .Invalid_Dir)
|
||||
return
|
||||
}
|
||||
return {f = f}, nil
|
||||
}
|
||||
|
||||
_read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) {
|
||||
if it == nil {
|
||||
return
|
||||
}
|
||||
|
||||
delete(it.impl.dirent_backing, file_allocator())
|
||||
file_info_delete(it.impl.prev_fi, file_allocator())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user