aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaytan Laats <laytanlaats@hotmail.com>2024-08-03 00:21:06 +0200
committerLaytan Laats <laytanlaats@hotmail.com>2024-08-03 00:26:46 +0200
commit99d9e8f8b1028c4208e2788f77044d2e1d2a8667 (patch)
tree870085ca077e5bf6dc5d6d0903a74bc86120e9f2
parent772dce7e42524f54ec780450fd82a7f8e2c478f5 (diff)
fix os.read_dir with symlinks
-rw-r--r--core/os/dir_bsd.odin73
-rw-r--r--core/os/dir_linux.odin72
-rw-r--r--core/os/dir_openbsd.odin71
-rw-r--r--core/os/dir_unix.odin (renamed from core/os/dir_darwin.odin)28
-rw-r--r--tests/core/normal.odin1
l---------tests/core/os/dir/alink.txt1
-rw-r--r--tests/core/os/dir/b.txt0
-rw-r--r--tests/core/os/dir/sub/.gitkeep0
-rw-r--r--tests/core/os/os.odin35
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")
+}
+