diff options
| author | Laytan Laats <laytanlaats@hotmail.com> | 2024-08-03 00:21:06 +0200 |
|---|---|---|
| committer | Laytan Laats <laytanlaats@hotmail.com> | 2024-08-03 00:26:46 +0200 |
| commit | 99d9e8f8b1028c4208e2788f77044d2e1d2a8667 (patch) | |
| tree | 870085ca077e5bf6dc5d6d0903a74bc86120e9f2 | |
| parent | 772dce7e42524f54ec780450fd82a7f8e2c478f5 (diff) | |
fix os.read_dir with symlinks
| -rw-r--r-- | core/os/dir_bsd.odin | 73 | ||||
| -rw-r--r-- | core/os/dir_linux.odin | 72 | ||||
| -rw-r--r-- | core/os/dir_openbsd.odin | 71 | ||||
| -rw-r--r-- | core/os/dir_unix.odin (renamed from core/os/dir_darwin.odin) | 28 | ||||
| -rw-r--r-- | tests/core/normal.odin | 1 | ||||
| l--------- | tests/core/os/dir/alink.txt | 1 | ||||
| -rw-r--r-- | tests/core/os/dir/b.txt | 0 | ||||
| -rw-r--r-- | tests/core/os/dir/sub/.gitkeep | 0 | ||||
| -rw-r--r-- | tests/core/os/os.odin | 35 |
9 files changed, 52 insertions, 229 deletions
diff --git a/core/os/dir_bsd.odin b/core/os/dir_bsd.odin deleted file mode 100644 index c0dc8ad1f..000000000 --- a/core/os/dir_bsd.odin +++ /dev/null @@ -1,73 +0,0 @@ -//+build freebsd, netbsd -package os - -import "core:mem" - -read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { - dirp: Dir - dirp, err = _fdopendir(fd) - if err != ERROR_NONE { - return - } - - defer _closedir(dirp) - - dirpath: string - dirpath, err = absolute_path_from_handle(fd) - - if err != ERROR_NONE { - return - } - - defer delete(dirpath) - - n := n - size := n - if n <= 0 { - n = -1 - size = 100 - } - - dfi := make([dynamic]File_Info, 0, size, allocator) - - for { - entry: Dirent - end_of_stream: bool - entry, err, end_of_stream = _readdir(dirp) - if err != ERROR_NONE { - for fi_ in dfi { - file_info_delete(fi_, allocator) - } - delete(dfi) - return - } else if end_of_stream { - break - } - - fi_: File_Info - filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] }) - - if filename == "." || filename == ".." { - continue - } - - fullpath := make([]byte, len(dirpath)+1+len(filename), context.temp_allocator) - copy(fullpath, dirpath) - copy(fullpath[len(dirpath):], "/") - copy(fullpath[len(dirpath)+1:], filename) - defer delete(fullpath, context.temp_allocator) - - fi_, err = stat(string(fullpath), allocator) - if err != ERROR_NONE { - for fi__ in dfi { - file_info_delete(fi__, allocator) - } - delete(dfi) - return - } - - append(&dfi, fi_) - } - - return dfi[:], ERROR_NONE -} diff --git a/core/os/dir_linux.odin b/core/os/dir_linux.odin deleted file mode 100644 index 3a51d7c70..000000000 --- a/core/os/dir_linux.odin +++ /dev/null @@ -1,72 +0,0 @@ -package os - -import "core:strings" -import "core:mem" -import "base:runtime" - -read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { - dirp: Dir - dirp, err = _fdopendir(fd) - if err != ERROR_NONE { - return - } - - defer _closedir(dirp) - - dirpath: string - dirpath, err = absolute_path_from_handle(fd) - - if err != ERROR_NONE { - return - } - - defer delete(dirpath) - - n := n - size := n - if n <= 0 { - n = -1 - size = 100 - } - - dfi := make([dynamic]File_Info, 0, size, allocator) - - for { - entry: Dirent - end_of_stream: bool - entry, err, end_of_stream = _readdir(dirp) - if err != ERROR_NONE { - for fi_ in dfi { - file_info_delete(fi_, allocator) - } - delete(dfi) - return - } else if end_of_stream { - break - } - - fi_: File_Info - filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] }) - - if filename == "." || filename == ".." { - continue - } - - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) - fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator) - defer delete(fullpath, context.temp_allocator) - - fi_, err = stat(fullpath, allocator) - if err != ERROR_NONE { - for fi__ in dfi { - file_info_delete(fi__, allocator) - } - delete(dfi) - return - } - - append(&dfi, fi_) - } - - return dfi[:], ERROR_NONE -} diff --git a/core/os/dir_openbsd.odin b/core/os/dir_openbsd.odin deleted file mode 100644 index 465fd35ae..000000000 --- a/core/os/dir_openbsd.odin +++ /dev/null @@ -1,71 +0,0 @@ -package os - -import "core:strings" -import "core:mem" - -read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { - dirp: Dir - dirp, err = _fdopendir(fd) - if err != ERROR_NONE { - return - } - - defer _closedir(dirp) - - // XXX OpenBSD - dirpath: string - dirpath, err = absolute_path_from_handle(fd) - - if err != ERROR_NONE { - return - } - - defer delete(dirpath) - - n := n - size := n - if n <= 0 { - n = -1 - size = 100 - } - - dfi := make([dynamic]File_Info, 0, size, allocator) - - for { - entry: Dirent - end_of_stream: bool - entry, err, end_of_stream = _readdir(dirp) - if err != ERROR_NONE { - for fi_ in dfi { - file_info_delete(fi_, allocator) - } - delete(dfi) - return - } else if end_of_stream { - break - } - - fi_: File_Info - filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] }) - - if filename == "." || filename == ".." { - continue - } - - fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator) - defer delete(fullpath, context.temp_allocator) - - fi_, err = stat(fullpath, allocator) - if err != ERROR_NONE { - for fi__ in dfi { - file_info_delete(fi__, allocator) - } - delete(dfi) - return - } - - append(&dfi, fi_) - } - - return dfi[:], ERROR_NONE -} diff --git a/core/os/dir_darwin.odin b/core/os/dir_unix.odin index 7d0f2936d..58cd873ae 100644 --- a/core/os/dir_darwin.odin +++ b/core/os/dir_unix.odin @@ -1,7 +1,7 @@ +//+build darwin, linux, netbsd, freebsd, openbsd package os import "core:strings" -import "core:mem" read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { dirp: Dir @@ -28,39 +28,41 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F } dfi := make([dynamic]File_Info, 0, size, allocator) + defer if err != ERROR_NONE { + for fi_ in dfi { + file_info_delete(fi_, allocator) + } + delete(dfi) + } for { entry: Dirent end_of_stream: bool entry, err, end_of_stream = _readdir(dirp) if err != ERROR_NONE { - for fi_ in dfi { - file_info_delete(fi_, allocator) - } - delete(dfi) return } else if end_of_stream { break } fi_: File_Info - filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] }) + filename := string(cstring(&entry.name[0])) if filename == "." || filename == ".." { continue } - fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator) - defer delete(fullpath, context.temp_allocator) + fullpath := strings.join({ dirpath, filename }, "/", allocator) - fi_, err = stat(fullpath, allocator) + s: OS_Stat + s, err = _lstat(fullpath) if err != ERROR_NONE { - for fi__ in dfi { - file_info_delete(fi__, allocator) - } - delete(dfi) + delete(fullpath, allocator) return } + _fill_file_info_from_stat(&fi_, s) + fi_.fullpath = fullpath + fi_.name = path_base(fi_.fullpath) append(&dfi, fi_) } diff --git a/tests/core/normal.odin b/tests/core/normal.odin index 7d5795273..8cd3b3917 100644 --- a/tests/core/normal.odin +++ b/tests/core/normal.odin @@ -30,6 +30,7 @@ download_assets :: proc() { @(require) import "mem" @(require) import "net" @(require) import "odin" +@(require) import "os" @(require) import "path/filepath" @(require) import "reflect" @(require) import "runtime" diff --git a/tests/core/os/dir/alink.txt b/tests/core/os/dir/alink.txt new file mode 120000 index 000000000..1891a26c0 --- /dev/null +++ b/tests/core/os/dir/alink.txt @@ -0,0 +1 @@ +./a.txt
\ No newline at end of file diff --git a/tests/core/os/dir/b.txt b/tests/core/os/dir/b.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/core/os/dir/b.txt diff --git a/tests/core/os/dir/sub/.gitkeep b/tests/core/os/dir/sub/.gitkeep new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/core/os/dir/sub/.gitkeep diff --git a/tests/core/os/os.odin b/tests/core/os/os.odin new file mode 100644 index 000000000..fd4fd28a8 --- /dev/null +++ b/tests/core/os/os.odin @@ -0,0 +1,35 @@ +package tests_core_os + +import "core:os" +import "core:slice" + +import "core:testing" + +@(test) +read_dir :: proc(t: ^testing.T) { + fd, errno := os.open(#directory + "/dir") + testing.expect_value(t, errno, os.ERROR_NONE) + defer os.close(fd) + + dir, errno2 := os.read_dir(fd, -1) + testing.expect_value(t, errno2, os.ERROR_NONE) + defer os.file_info_slice_delete(dir) + + slice.sort_by_key(dir, proc(fi: os.File_Info) -> string { return fi.name }) + + testing.expect_value(t, len(dir), 3) + + testing.expect_value(t, dir[0].name, "alink.txt") + testing.expect(t, !dir[0].is_dir, "is a directory") + when ODIN_OS == .Windows { + testing.expect(t, dir[0].mode & os.File_Mode_Sym_Link != 0, "not a symlink") + } else { + testing.expect(t, os.S_ISLNK(auto_cast dir[0].mode), "not a symlink") + } + + testing.expect_value(t, dir[1].name, "b.txt") + + testing.expect_value(t, dir[2].name, "sub") + testing.expect(t, dir[2].is_dir, "is not a directory") +} + |