mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 16:18:52 +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:
+37
-23
@@ -1,6 +1,8 @@
|
||||
#+private
|
||||
package os2
|
||||
|
||||
import "base:runtime"
|
||||
import "core:slice"
|
||||
import "base:intrinsics"
|
||||
import "core:sys/wasm/wasi"
|
||||
|
||||
@@ -8,7 +10,6 @@ Read_Directory_Iterator_Impl :: struct {
|
||||
fullpath: [dynamic]byte,
|
||||
buf: []byte,
|
||||
off: int,
|
||||
idx: int,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
@@ -17,8 +18,8 @@ _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info
|
||||
|
||||
buf := it.impl.buf[it.impl.off:]
|
||||
|
||||
index = it.impl.idx
|
||||
it.impl.idx += 1
|
||||
index = it.index
|
||||
it.index += 1
|
||||
|
||||
for {
|
||||
if len(buf) < size_of(wasi.dirent_t) {
|
||||
@@ -28,10 +29,7 @@ _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info
|
||||
entry := intrinsics.unaligned_load((^wasi.dirent_t)(raw_data(buf)))
|
||||
buf = buf[size_of(wasi.dirent_t):]
|
||||
|
||||
if len(buf) < int(entry.d_namlen) {
|
||||
// shouldn't be possible.
|
||||
return
|
||||
}
|
||||
assert(len(buf) < int(entry.d_namlen))
|
||||
|
||||
name := string(buf[:entry.d_namlen])
|
||||
buf = buf[entry.d_namlen:]
|
||||
@@ -43,7 +41,8 @@ _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info
|
||||
|
||||
n := len(fimpl.name)+1
|
||||
if alloc_err := non_zero_resize(&it.impl.fullpath, n+len(name)); alloc_err != nil {
|
||||
// Can't really tell caller we had an error, sad.
|
||||
read_directory_iterator_set_error(it, name, alloc_err)
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
copy(it.impl.fullpath[n:], name)
|
||||
@@ -55,6 +54,7 @@ _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info
|
||||
ino = entry.d_ino,
|
||||
filetype = entry.d_type,
|
||||
}
|
||||
read_directory_iterator_set_error(it, string(it.impl.fullpath[:]), _get_platform_error(err))
|
||||
}
|
||||
|
||||
fi = internal_stat(stat, string(it.impl.fullpath[:]))
|
||||
@@ -63,27 +63,35 @@ _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info
|
||||
}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
_read_directory_iterator_create :: proc(f: ^File) -> (iter: Read_Directory_Iterator, err: 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.off = 0
|
||||
|
||||
if f == nil || f.impl == nil {
|
||||
err = .Invalid_File
|
||||
read_directory_iterator_set_error(it, "", .Invalid_File)
|
||||
return
|
||||
}
|
||||
|
||||
impl := (^File_Impl)(f.impl)
|
||||
iter.f = f
|
||||
|
||||
buf: [dynamic]byte
|
||||
// NOTE: Allow calling `init` to target a new directory with the same iterator.
|
||||
if it.impl.buf != nil {
|
||||
buf = slice.into_dynamic(it.impl.buf)
|
||||
}
|
||||
buf.allocator = file_allocator()
|
||||
defer if err != nil { delete(buf) }
|
||||
|
||||
// NOTE: this is very grug.
|
||||
defer if it.err.err != nil { delete(buf) }
|
||||
|
||||
for {
|
||||
non_zero_resize(&buf, 512 if len(buf) == 0 else len(buf)*2) or_return
|
||||
if err := non_zero_resize(&buf, 512 if len(buf) == 0 else len(buf)*2); err != nil {
|
||||
read_directory_iterator_set_error(it, name(f), err)
|
||||
return
|
||||
}
|
||||
|
||||
n, _err := wasi.fd_readdir(__fd(f), buf[:], 0)
|
||||
if _err != nil {
|
||||
err = _get_platform_error(_err)
|
||||
n, err := wasi.fd_readdir(__fd(f), buf[:], 0)
|
||||
if err != nil {
|
||||
read_directory_iterator_set_error(it, name(f), _get_platform_error(err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -94,11 +102,18 @@ _read_directory_iterator_create :: proc(f: ^File) -> (iter: Read_Directory_Itera
|
||||
|
||||
assert(n == len(buf))
|
||||
}
|
||||
iter.impl.buf = buf[:]
|
||||
it.impl.buf = buf[:]
|
||||
|
||||
iter.impl.fullpath = make([dynamic]byte, 0, len(impl.name)+128, file_allocator()) or_return
|
||||
append(&iter.impl.fullpath, impl.name)
|
||||
append(&iter.impl.fullpath, "/")
|
||||
// NOTE: Allow calling `init` to target a new directory with the same iterator.
|
||||
it.impl.fullpath.allocator = file_allocator()
|
||||
clear(&it.impl.fullpath)
|
||||
if err := reserve(&it.impl.fullpath, len(impl.name)+128); err != nil {
|
||||
read_directory_iterator_set_error(it, name(f), err)
|
||||
return
|
||||
}
|
||||
|
||||
append(&it.impl.fullpath, impl.name)
|
||||
append(&it.impl.fullpath, "/")
|
||||
|
||||
return
|
||||
}
|
||||
@@ -106,5 +121,4 @@ _read_directory_iterator_create :: proc(f: ^File) -> (iter: Read_Directory_Itera
|
||||
_read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) {
|
||||
delete(it.impl.buf, file_allocator())
|
||||
delete(it.impl.fullpath)
|
||||
it^ = {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user