aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/compress/gzip/doc.odin10
-rw-r--r--core/compress/gzip/gzip.odin12
-rw-r--r--core/crypto/hash/hash_os.odin2
-rw-r--r--core/encoding/csv/doc.odin2
-rw-r--r--core/encoding/hxa/hxa_os.odin2
-rw-r--r--core/encoding/ini/ini_os.odin2
-rw-r--r--core/encoding/xml/xml_os.odin2
-rw-r--r--core/flags/errors.odin2
-rw-r--r--core/flags/example/example.odin2
-rw-r--r--core/flags/internal_rtti.odin24
-rw-r--r--core/flags/internal_validation.odin16
-rw-r--r--core/flags/util.odin6
-rw-r--r--core/fmt/fmt_os.odin8
-rw-r--r--core/image/bmp/bmp_os.odin4
-rw-r--r--core/image/general_os.odin2
-rw-r--r--core/image/jpeg/jpeg_os.odin2
-rw-r--r--core/image/netpbm/netpbm_os.odin2
-rw-r--r--core/image/png/png_os.odin2
-rw-r--r--core/image/qoi/qoi_os.odin4
-rw-r--r--core/image/tga/tga_os.odin4
-rw-r--r--core/log/file_console_logger.odin14
-rw-r--r--core/math/big/radix_os.odin2
-rw-r--r--core/mem/virtual/doc.odin4
-rw-r--r--core/mem/virtual/file.odin2
-rw-r--r--core/net/dns_os.odin2
-rw-r--r--core/odin/parser/parse_files.odin14
-rw-r--r--core/os/allocators.odin (renamed from core/os/os2/allocators.odin)0
-rw-r--r--core/os/dir.odin (renamed from core/os/os2/dir.odin)4
-rw-r--r--core/os/dir_js.odin (renamed from core/os/os2/dir_js.odin)0
-rw-r--r--core/os/dir_linux.odin (renamed from core/os/os2/dir_linux.odin)0
-rw-r--r--core/os/dir_posix.odin (renamed from core/os/os2/dir_posix.odin)0
-rw-r--r--core/os/dir_posix_darwin.odin (renamed from core/os/os2/dir_posix_darwin.odin)0
-rw-r--r--core/os/dir_walker.odin (renamed from core/os/os2/dir_walker.odin)6
-rw-r--r--core/os/dir_wasi.odin (renamed from core/os/os2/dir_wasi.odin)0
-rw-r--r--core/os/dir_windows.odin190
-rw-r--r--core/os/doc.odin (renamed from core/os/os2/doc.odin)0
-rw-r--r--core/os/env.odin (renamed from core/os/os2/env.odin)0
-rw-r--r--core/os/env_js.odin (renamed from core/os/os2/env_js.odin)0
-rw-r--r--core/os/env_linux.odin (renamed from core/os/os2/env_linux.odin)0
-rw-r--r--core/os/env_posix.odin (renamed from core/os/os2/env_posix.odin)0
-rw-r--r--core/os/env_wasi.odin (renamed from core/os/os2/env_wasi.odin)0
-rw-r--r--core/os/env_windows.odin142
-rw-r--r--core/os/errors.odin257
-rw-r--r--core/os/errors_js.odin (renamed from core/os/os2/errors_js.odin)0
-rw-r--r--core/os/errors_linux.odin (renamed from core/os/os2/errors_linux.odin)0
-rw-r--r--core/os/errors_posix.odin (renamed from core/os/os2/errors_posix.odin)0
-rw-r--r--core/os/errors_wasi.odin (renamed from core/os/os2/errors_wasi.odin)0
-rw-r--r--core/os/errors_windows.odin (renamed from core/os/os2/errors_windows.odin)0
-rw-r--r--core/os/file.odin (renamed from core/os/os2/file.odin)0
-rw-r--r--core/os/file_js.odin (renamed from core/os/os2/file_js.odin)0
-rw-r--r--core/os/file_linux.odin (renamed from core/os/os2/file_linux.odin)0
-rw-r--r--core/os/file_posix.odin (renamed from core/os/os2/file_posix.odin)0
-rw-r--r--core/os/file_posix_darwin.odin (renamed from core/os/os2/file_posix_darwin.odin)0
-rw-r--r--core/os/file_posix_freebsd.odin (renamed from core/os/os2/file_posix_freebsd.odin)0
-rw-r--r--core/os/file_posix_netbsd.odin (renamed from core/os/os2/file_posix_netbsd.odin)0
-rw-r--r--core/os/file_posix_other.odin (renamed from core/os/os2/file_posix_other.odin)0
-rw-r--r--core/os/file_stream.odin (renamed from core/os/os2/file_stream.odin)0
-rw-r--r--core/os/file_util.odin (renamed from core/os/os2/file_util.odin)0
-rw-r--r--core/os/file_wasi.odin (renamed from core/os/os2/file_wasi.odin)0
-rw-r--r--core/os/file_windows.odin (renamed from core/os/os2/file_windows.odin)0
-rw-r--r--core/os/heap.odin (renamed from core/os/os2/heap.odin)0
-rw-r--r--core/os/heap_js.odin (renamed from core/os/os2/heap_js.odin)0
-rw-r--r--core/os/heap_linux.odin (renamed from core/os/os2/heap_linux.odin)0
-rw-r--r--core/os/heap_posix.odin (renamed from core/os/os2/heap_posix.odin)0
-rw-r--r--core/os/heap_wasi.odin (renamed from core/os/os2/heap_wasi.odin)0
-rw-r--r--core/os/heap_windows.odin (renamed from core/os/os2/heap_windows.odin)0
-rw-r--r--core/os/internal_util.odin (renamed from core/os/os2/internal_util.odin)0
-rw-r--r--core/os/old/dir_unix.odin (renamed from core/os/dir_unix.odin)0
-rw-r--r--core/os/old/dir_windows.odin114
-rw-r--r--core/os/old/env_windows.odin140
-rw-r--r--core/os/old/errors.odin318
-rw-r--r--core/os/old/os.odin (renamed from core/os/os.odin)0
-rw-r--r--core/os/old/os_darwin.odin (renamed from core/os/os_darwin.odin)0
-rw-r--r--core/os/old/os_essence.odin (renamed from core/os/os_essence.odin)0
-rw-r--r--core/os/old/os_freebsd.odin (renamed from core/os/os_freebsd.odin)0
-rw-r--r--core/os/old/os_freestanding.odin (renamed from core/os/os_freestanding.odin)0
-rw-r--r--core/os/old/os_haiku.odin (renamed from core/os/os_haiku.odin)0
-rw-r--r--core/os/old/os_js.odin (renamed from core/os/os_js.odin)0
-rw-r--r--core/os/old/os_linux.odin (renamed from core/os/os_linux.odin)0
-rw-r--r--core/os/old/os_netbsd.odin (renamed from core/os/os_netbsd.odin)0
-rw-r--r--core/os/old/os_openbsd.odin (renamed from core/os/os_openbsd.odin)0
-rw-r--r--core/os/old/os_wasi.odin (renamed from core/os/os_wasi.odin)0
-rw-r--r--core/os/old/os_windows.odin (renamed from core/os/os_windows.odin)0
-rw-r--r--core/os/old/stat.odin33
-rw-r--r--core/os/old/stat_unix.odin (renamed from core/os/stat_unix.odin)0
-rw-r--r--core/os/old/stat_windows.odin303
-rw-r--r--core/os/old/stream.odin (renamed from core/os/stream.odin)0
-rw-r--r--core/os/os2/dir_windows.odin144
-rw-r--r--core/os/os2/env_windows.odin142
-rw-r--r--core/os/os2/errors.odin147
-rw-r--r--core/os/os2/stat.odin117
-rw-r--r--core/os/os2/stat_windows.odin393
-rw-r--r--core/os/path.odin (renamed from core/os/os2/path.odin)0
-rw-r--r--core/os/path_darwin.odin (renamed from core/os/os2/path_darwin.odin)0
-rw-r--r--core/os/path_freebsd.odin (renamed from core/os/os2/path_freebsd.odin)0
-rw-r--r--core/os/path_js.odin (renamed from core/os/os2/path_js.odin)0
-rw-r--r--core/os/path_linux.odin (renamed from core/os/os2/path_linux.odin)0
-rw-r--r--core/os/path_netbsd.odin (renamed from core/os/os2/path_netbsd.odin)0
-rw-r--r--core/os/path_openbsd.odin (renamed from core/os/os2/path_openbsd.odin)0
-rw-r--r--core/os/path_posix.odin (renamed from core/os/os2/path_posix.odin)0
-rw-r--r--core/os/path_posixfs.odin (renamed from core/os/os2/path_posixfs.odin)0
-rw-r--r--core/os/path_wasi.odin (renamed from core/os/os2/path_wasi.odin)0
-rw-r--r--core/os/path_windows.odin (renamed from core/os/os2/path_windows.odin)0
-rw-r--r--core/os/pipe.odin (renamed from core/os/os2/pipe.odin)0
-rw-r--r--core/os/pipe_js.odin (renamed from core/os/os2/pipe_js.odin)0
-rw-r--r--core/os/pipe_linux.odin (renamed from core/os/os2/pipe_linux.odin)0
-rw-r--r--core/os/pipe_posix.odin (renamed from core/os/os2/pipe_posix.odin)0
-rw-r--r--core/os/pipe_wasi.odin (renamed from core/os/os2/pipe_wasi.odin)0
-rw-r--r--core/os/pipe_windows.odin (renamed from core/os/os2/pipe_windows.odin)0
-rw-r--r--core/os/process.odin (renamed from core/os/os2/process.odin)0
-rw-r--r--core/os/process_freebsd.odin (renamed from core/os/os2/process_freebsd.odin)0
-rw-r--r--core/os/process_js.odin (renamed from core/os/os2/process_js.odin)0
-rw-r--r--core/os/process_linux.odin (renamed from core/os/os2/process_linux.odin)0
-rw-r--r--core/os/process_netbsd.odin (renamed from core/os/os2/process_netbsd.odin)0
-rw-r--r--core/os/process_openbsd.odin (renamed from core/os/os2/process_openbsd.odin)0
-rw-r--r--core/os/process_posix.odin (renamed from core/os/os2/process_posix.odin)0
-rw-r--r--core/os/process_posix_darwin.odin (renamed from core/os/os2/process_posix_darwin.odin)0
-rw-r--r--core/os/process_posix_other.odin (renamed from core/os/os2/process_posix_other.odin)0
-rw-r--r--core/os/process_wasi.odin (renamed from core/os/os2/process_wasi.odin)0
-rw-r--r--core/os/process_windows.odin (renamed from core/os/os2/process_windows.odin)0
-rw-r--r--core/os/stat.odin116
-rw-r--r--core/os/stat_js.odin (renamed from core/os/os2/stat_js.odin)0
-rw-r--r--core/os/stat_linux.odin (renamed from core/os/os2/stat_linux.odin)0
-rw-r--r--core/os/stat_posix.odin (renamed from core/os/os2/stat_posix.odin)0
-rw-r--r--core/os/stat_wasi.odin (renamed from core/os/os2/stat_wasi.odin)0
-rw-r--r--core/os/stat_windows.odin422
-rw-r--r--core/os/temp_file.odin (renamed from core/os/os2/temp_file.odin)0
-rw-r--r--core/os/temp_file_js.odin (renamed from core/os/os2/temp_file_js.odin)0
-rw-r--r--core/os/temp_file_linux.odin (renamed from core/os/os2/temp_file_linux.odin)0
-rw-r--r--core/os/temp_file_posix.odin (renamed from core/os/os2/temp_file_posix.odin)0
-rw-r--r--core/os/temp_file_wasi.odin (renamed from core/os/os2/temp_file_wasi.odin)0
-rw-r--r--core/os/temp_file_windows.odin (renamed from core/os/os2/temp_file_windows.odin)0
-rw-r--r--core/os/user.odin (renamed from core/os/os2/user.odin)0
-rw-r--r--core/os/user_posix.odin (renamed from core/os/os2/user_posix.odin)0
-rw-r--r--core/os/user_windows.odin (renamed from core/os/os2/user_windows.odin)0
-rw-r--r--core/path/filepath/match.odin2
-rw-r--r--core/path/filepath/path.odin4
-rw-r--r--core/path/filepath/walk.odin8
-rw-r--r--core/prof/spall/spall.odin4
-rw-r--r--core/terminal/internal_os.odin6
-rw-r--r--core/terminal/terminal_posix.odin4
-rw-r--r--core/terminal/terminal_windows.odin6
-rw-r--r--core/testing/runner.odin36
-rw-r--r--core/testing/signal_handler_libc.odin10
-rw-r--r--core/text/i18n/i18_js.odin2
-rw-r--r--core/text/i18n/i18n_os.odin2
-rw-r--r--core/text/regex/common/os.odin2
-rw-r--r--core/text/table/doc.odin10
-rw-r--r--core/text/table/utility.odin6
-rw-r--r--core/time/timezone/tz_os.odin2
-rw-r--r--core/time/timezone/tz_unix.odin8
-rw-r--r--core/unicode/tools/generate_entity_table.odin2
-rw-r--r--examples/all/all_main.odin2
-rw-r--r--tests/core/encoding/hxa/test_core_hxa.odin2
-rw-r--r--tests/core/flags/test_core_flags.odin22
-rw-r--r--tests/core/io/test_core_io.odin14
-rw-r--r--tests/core/nbio/fs.odin8
-rw-r--r--tests/core/nbio/nbio.odin12
-rw-r--r--tests/core/normal.odin2
-rw-r--r--tests/core/os/dir.odin (renamed from tests/core/os/os2/dir.odin)22
-rw-r--r--tests/core/os/file.odin (renamed from tests/core/os/os2/file.odin)6
-rw-r--r--tests/core/os/old/os.odin (renamed from tests/core/os/os.odin)4
-rw-r--r--tests/core/os/path.odin (renamed from tests/core/os/os2/path.odin)24
-rw-r--r--tests/core/os/process.odin (renamed from tests/core/os/os2/process.odin)8
-rw-r--r--tests/core/sys/kqueue/structs.odin6
-rw-r--r--tests/documentation/documentation_tester.odin4
-rw-r--r--vendor/OpenGL/helpers.odin2
-rw-r--r--vendor/fontstash/fontstash_os.odin4
-rw-r--r--vendor/libc-shim/stdio_os.odin6
169 files changed, 1698 insertions, 1700 deletions
diff --git a/core/compress/gzip/doc.odin b/core/compress/gzip/doc.odin
index 82eaa6f35..e4b1929dd 100644
--- a/core/compress/gzip/doc.odin
+++ b/core/compress/gzip/doc.odin
@@ -2,11 +2,11 @@
A small `GZIP` unpacker.
Example:
- import "core:bytes"
- import os "core:os/os2"
- import "core:compress"
- import "core:compress/gzip"
- import "core:fmt"
+ import "core:bytes"
+ import "core:os"
+ import "core:compress"
+ import "core:compress/gzip"
+ import "core:fmt"
// Small GZIP file with fextra, fname and fcomment present.
@private
diff --git a/core/compress/gzip/gzip.odin b/core/compress/gzip/gzip.odin
index 644a625e7..aedbe3a83 100644
--- a/core/compress/gzip/gzip.odin
+++ b/core/compress/gzip/gzip.odin
@@ -14,12 +14,12 @@ package compress_gzip
to be the input to a complementary TAR implementation.
*/
-import "core:compress/zlib"
-import "core:compress"
-import os "core:os/os2"
-import "core:io"
-import "core:bytes"
-import "core:hash"
+import "core:compress/zlib"
+import "core:compress"
+import "core:os"
+import "core:io"
+import "core:bytes"
+import "core:hash"
Magic :: enum u16le {
GZIP = 0x8b << 8 | 0x1f,
diff --git a/core/crypto/hash/hash_os.odin b/core/crypto/hash/hash_os.odin
index 5155623cb..49c1a0ff8 100644
--- a/core/crypto/hash/hash_os.odin
+++ b/core/crypto/hash/hash_os.odin
@@ -3,7 +3,7 @@
package crypto_hash
import "core:io"
-import os "core:os/os2"
+import "core:os"
// `hash_file` will read the file provided by the given handle and return the
// computed digest in a newly allocated slice.
diff --git a/core/encoding/csv/doc.odin b/core/encoding/csv/doc.odin
index c6dae3005..1fb685602 100644
--- a/core/encoding/csv/doc.odin
+++ b/core/encoding/csv/doc.odin
@@ -6,7 +6,7 @@ Example:
import "core:fmt"
import "core:encoding/csv"
- import os "core:os/os2"
+ import "core:os"
// Requires keeping the entire CSV file in memory at once
iterate_csv_from_string :: proc(filename: string) {
diff --git a/core/encoding/hxa/hxa_os.odin b/core/encoding/hxa/hxa_os.odin
index c033bdca8..17ad94819 100644
--- a/core/encoding/hxa/hxa_os.odin
+++ b/core/encoding/hxa/hxa_os.odin
@@ -2,7 +2,7 @@
#+build !js
package encoding_hxa
-import os "core:os/os2"
+import "core:os"
read_from_file :: proc(filename: string, print_error := false, allocator := context.allocator, loc := #caller_location) -> (file: File, err: Read_Error) {
context.allocator = allocator
diff --git a/core/encoding/ini/ini_os.odin b/core/encoding/ini/ini_os.odin
index 619a0e2a6..22c6bf7b3 100644
--- a/core/encoding/ini/ini_os.odin
+++ b/core/encoding/ini/ini_os.odin
@@ -3,7 +3,7 @@
package encoding_ini
import "base:runtime"
-import os "core:os/os2"
+import "core:os"
load_map_from_path :: proc(path: string, allocator: runtime.Allocator, options := DEFAULT_OPTIONS) -> (m: Map, err: runtime.Allocator_Error, ok: bool) {
data, data_err := os.read_entire_file(path, allocator)
diff --git a/core/encoding/xml/xml_os.odin b/core/encoding/xml/xml_os.odin
index 8c7f6cccf..1e94572c6 100644
--- a/core/encoding/xml/xml_os.odin
+++ b/core/encoding/xml/xml_os.odin
@@ -2,7 +2,7 @@
#+build !js
package encoding_xml
-import os "core:os/os2"
+import "core:os"
// Load an XML file
load_from_file :: proc(filename: string, options := DEFAULT_OPTIONS, error_handler := default_error_handler, allocator := context.allocator) -> (doc: ^Document, err: Error) {
diff --git a/core/flags/errors.odin b/core/flags/errors.odin
index d0caa1427..efe4cb6c4 100644
--- a/core/flags/errors.odin
+++ b/core/flags/errors.odin
@@ -2,7 +2,7 @@ package flags
import "base:runtime"
import "core:net"
-import os "core:os/os2"
+import "core:os"
Parse_Error_Reason :: enum {
None,
diff --git a/core/flags/example/example.odin b/core/flags/example/example.odin
index 6e74c7dcc..6ace3d852 100644
--- a/core/flags/example/example.odin
+++ b/core/flags/example/example.odin
@@ -4,7 +4,7 @@ import "base:runtime"
import "core:flags"
import "core:fmt"
import "core:net"
-import os "core:os/os2"
+import "core:os"
import "core:time/datetime"
diff --git a/core/flags/internal_rtti.odin b/core/flags/internal_rtti.odin
index 07481a89b..d5e8726e2 100644
--- a/core/flags/internal_rtti.odin
+++ b/core/flags/internal_rtti.odin
@@ -1,18 +1,18 @@
#+private
package flags
-import "base:intrinsics"
-import "base:runtime"
-import "core:fmt"
-import "core:mem"
-import "core:net"
-@(require) import os "core:os/os2"
-import "core:reflect"
-import "core:strconv"
-import "core:strings"
-@require import "core:time"
-@require import "core:time/datetime"
-import "core:unicode/utf8"
+import "base:intrinsics"
+import "base:runtime"
+import "core:fmt"
+import "core:mem"
+import "core:net"
+@(require) import "core:os"
+import "core:reflect"
+import "core:strconv"
+import "core:strings"
+@(require) import "core:time"
+@(require) import "core:time/datetime"
+import "core:unicode/utf8"
@(optimization_mode="favor_size")
parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info: ^runtime.Type_Info) -> bool {
diff --git a/core/flags/internal_validation.odin b/core/flags/internal_validation.odin
index dc19f3084..6f9016a21 100644
--- a/core/flags/internal_validation.odin
+++ b/core/flags/internal_validation.odin
@@ -1,14 +1,14 @@
#+private
package flags
-@require import "base:runtime"
-@require import "core:container/bit_array"
-@require import "core:fmt"
-@require import "core:mem"
-@require import os "core:os/os2"
-@require import "core:reflect"
-@require import "core:strconv"
-@require import "core:strings"
+@require import "base:runtime"
+@require import "core:container/bit_array"
+@require import "core:fmt"
+@require import "core:mem"
+@require import "core:os"
+@require import "core:reflect"
+@require import "core:strconv"
+@require import "core:strings"
// This proc is used to assert that `T` meets the expectations of the library.
@(optimization_mode="favor_size", disabled=ODIN_DISABLE_ASSERT)
diff --git a/core/flags/util.odin b/core/flags/util.odin
index 20e40cab5..0d18fa196 100644
--- a/core/flags/util.odin
+++ b/core/flags/util.odin
@@ -1,9 +1,9 @@
package flags
-import "core:fmt"
-@require import os "core:os/os2"
+import "core:fmt"
+@require import "core:os"
@require import "core:path/filepath"
-import "core:strings"
+import "core:strings"
/*
Parse any arguments into an annotated struct or exit if there was an error.
diff --git a/core/fmt/fmt_os.odin b/core/fmt/fmt_os.odin
index 7ce945a0f..0305b5bac 100644
--- a/core/fmt/fmt_os.odin
+++ b/core/fmt/fmt_os.odin
@@ -3,10 +3,10 @@
#+build !orca
package fmt
-import "base:runtime"
-import os "core:os/os2"
-import "core:io"
-import "core:bufio"
+import "base:runtime"
+import "core:os"
+import "core:io"
+import "core:bufio"
// NOTE(Jeroen): The other option is to deprecate `fprint*` and make it an alias for `wprint*`, using File.stream directly.
diff --git a/core/image/bmp/bmp_os.odin b/core/image/bmp/bmp_os.odin
index 971750fda..1aa1d63de 100644
--- a/core/image/bmp/bmp_os.odin
+++ b/core/image/bmp/bmp_os.odin
@@ -1,8 +1,8 @@
#+build !js
package core_image_bmp
-import os "core:os/os2"
-import "core:bytes"
+import "core:os"
+import "core:bytes"
load :: proc{load_from_file, load_from_bytes, load_from_context}
diff --git a/core/image/general_os.odin b/core/image/general_os.odin
index e4de1c9a6..63d7c8d43 100644
--- a/core/image/general_os.odin
+++ b/core/image/general_os.odin
@@ -1,7 +1,7 @@
#+build !js
package image
-import os "core:os/os2"
+import "core:os"
load :: proc{
load_from_bytes,
diff --git a/core/image/jpeg/jpeg_os.odin b/core/image/jpeg/jpeg_os.odin
index aad172c91..6ba301d80 100644
--- a/core/image/jpeg/jpeg_os.odin
+++ b/core/image/jpeg/jpeg_os.odin
@@ -1,7 +1,7 @@
#+build !js
package jpeg
-import os "core:os/os2"
+import "core:os"
load :: proc{load_from_file, load_from_bytes, load_from_context}
diff --git a/core/image/netpbm/netpbm_os.odin b/core/image/netpbm/netpbm_os.odin
index 82ad55f35..ae9029b54 100644
--- a/core/image/netpbm/netpbm_os.odin
+++ b/core/image/netpbm/netpbm_os.odin
@@ -1,7 +1,7 @@
#+build !js
package netpbm
-import os "core:os/os2"
+import "core:os"
load :: proc {
load_from_file,
diff --git a/core/image/png/png_os.odin b/core/image/png/png_os.odin
index c6a88fa52..5fc10cec4 100644
--- a/core/image/png/png_os.odin
+++ b/core/image/png/png_os.odin
@@ -1,7 +1,7 @@
#+build !js
package png
-import os "core:os/os2"
+import "core:os"
load :: proc{load_from_file, load_from_bytes, load_from_context}
diff --git a/core/image/qoi/qoi_os.odin b/core/image/qoi/qoi_os.odin
index a65527d09..f2bf83cfc 100644
--- a/core/image/qoi/qoi_os.odin
+++ b/core/image/qoi/qoi_os.odin
@@ -1,8 +1,8 @@
#+build !js
package qoi
-import os "core:os/os2"
-import "core:bytes"
+import "core:os"
+import "core:bytes"
load :: proc{load_from_file, load_from_bytes, load_from_context}
diff --git a/core/image/tga/tga_os.odin b/core/image/tga/tga_os.odin
index 2c103b34a..ba50439de 100644
--- a/core/image/tga/tga_os.odin
+++ b/core/image/tga/tga_os.odin
@@ -1,8 +1,8 @@
#+build !js
package tga
-import os "core:os/os2"
-import "core:bytes"
+import "core:os"
+import "core:bytes"
load :: proc{load_from_file, load_from_bytes, load_from_context}
diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin
index 819d494e9..47174719f 100644
--- a/core/log/file_console_logger.odin
+++ b/core/log/file_console_logger.odin
@@ -3,13 +3,13 @@
#+build !js
package log
-import "base:runtime"
-import "core:fmt"
-import "core:strings"
-import os "core:os/os2"
-import "core:terminal"
-import "core:terminal/ansi"
-import "core:time"
+import "base:runtime"
+import "core:fmt"
+import "core:strings"
+import "core:os"
+import "core:terminal"
+import "core:terminal/ansi"
+import "core:time"
Level_Headers := [?]string{
0..<10 = "[DEBUG] --- ",
diff --git a/core/math/big/radix_os.odin b/core/math/big/radix_os.odin
index 8269a4338..50454b679 100644
--- a/core/math/big/radix_os.odin
+++ b/core/math/big/radix_os.odin
@@ -18,7 +18,7 @@ package math_big
*/
import "core:mem"
-import os "core:os/os2"
+import "core:os"
/*
We might add functions to read and write byte-encoded Ints from/to files, using `int_to_bytes_*` functions.
diff --git a/core/mem/virtual/doc.odin b/core/mem/virtual/doc.odin
index 249e22ee8..b5f0944c7 100644
--- a/core/mem/virtual/doc.odin
+++ b/core/mem/virtual/doc.odin
@@ -5,8 +5,8 @@ virtual.Arena usage
Example:
// Source: https://github.com/odin-lang/examples/blob/master/arena_allocator/arena_allocator.odin
- import "core:fmt"
- import os "core:os/os2"
+ import "core:fmt"
+ import "core:os"
// virtual package implements a multi-purpose arena allocator. If you are on a
// platform that does not support virtual memory, then there is also a similar
diff --git a/core/mem/virtual/file.odin b/core/mem/virtual/file.odin
index b156f2af4..660210bbf 100644
--- a/core/mem/virtual/file.odin
+++ b/core/mem/virtual/file.odin
@@ -2,7 +2,7 @@
#+build !js
package mem_virtual
-import os "core:os/os2"
+import "core:os"
map_file :: proc{
map_file_from_path,
diff --git a/core/net/dns_os.odin b/core/net/dns_os.odin
index 8528dad00..ad9724d37 100644
--- a/core/net/dns_os.odin
+++ b/core/net/dns_os.odin
@@ -2,7 +2,7 @@
#+private
package net
-import os "core:os/os2"
+import "core:os"
load_resolv_conf :: proc(resolv_conf_path: string, allocator := context.allocator) -> (name_servers: []Endpoint, ok: bool) {
context.allocator = allocator
diff --git a/core/odin/parser/parse_files.odin b/core/odin/parser/parse_files.odin
index 93c282d35..2ea47ca89 100644
--- a/core/odin/parser/parse_files.odin
+++ b/core/odin/parser/parse_files.odin
@@ -1,12 +1,12 @@
package odin_parser
-import "core:odin/tokenizer"
-import "core:odin/ast"
-import "core:path/filepath"
-import "core:fmt"
-import os "core:os/os2"
-import "core:slice"
-import "core:strings"
+import "core:odin/tokenizer"
+import "core:odin/ast"
+import "core:path/filepath"
+import "core:fmt"
+import "core:os"
+import "core:slice"
+import "core:strings"
collect_package :: proc(path: string) -> (pkg: ^ast.Package, success: bool) {
NO_POS :: tokenizer.Pos{}
diff --git a/core/os/os2/allocators.odin b/core/os/allocators.odin
index 36a7d72be..36a7d72be 100644
--- a/core/os/os2/allocators.odin
+++ b/core/os/allocators.odin
diff --git a/core/os/os2/dir.odin b/core/os/dir.odin
index f63754273..9ad5f451e 100644
--- a/core/os/os2/dir.odin
+++ b/core/os/dir.odin
@@ -160,8 +160,8 @@ extend its lifetime.
Example:
package main
- import "core:fmt"
- import os "core:os/os2"
+ import "core:fmt"
+ import "core:os"
main :: proc() {
f, oerr := os.open("core")
diff --git a/core/os/os2/dir_js.odin b/core/os/dir_js.odin
index d8f7c6202..d8f7c6202 100644
--- a/core/os/os2/dir_js.odin
+++ b/core/os/dir_js.odin
diff --git a/core/os/os2/dir_linux.odin b/core/os/dir_linux.odin
index 34346c02f..34346c02f 100644
--- a/core/os/os2/dir_linux.odin
+++ b/core/os/dir_linux.odin
diff --git a/core/os/os2/dir_posix.odin b/core/os/dir_posix.odin
index d9fa16f8d..d9fa16f8d 100644
--- a/core/os/os2/dir_posix.odin
+++ b/core/os/dir_posix.odin
diff --git a/core/os/os2/dir_posix_darwin.odin b/core/os/dir_posix_darwin.odin
index 3cae50d25..3cae50d25 100644
--- a/core/os/os2/dir_posix_darwin.odin
+++ b/core/os/dir_posix_darwin.odin
diff --git a/core/os/os2/dir_walker.odin b/core/os/dir_walker.odin
index ba5342cf8..4dce884a8 100644
--- a/core/os/os2/dir_walker.odin
+++ b/core/os/dir_walker.odin
@@ -136,9 +136,9 @@ If an error occurred opening a directory, you may get zero'd info struct and
Example:
package main
- import "core:fmt"
- import "core:strings"
- import os "core:os/os2"
+ import "core:fmt"
+ import "core:strings"
+ import "core:os"
main :: proc() {
w := os.walker_create("core")
diff --git a/core/os/os2/dir_wasi.odin b/core/os/dir_wasi.odin
index 9804f07fd..9804f07fd 100644
--- a/core/os/os2/dir_wasi.odin
+++ b/core/os/dir_wasi.odin
diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin
index 40f4b9e9b..a4dadca75 100644
--- a/core/os/dir_windows.odin
+++ b/core/os/dir_windows.odin
@@ -1,114 +1,144 @@
-package os
+#+private
+package os2
-import win32 "core:sys/windows"
-import "core:strings"
import "base:runtime"
+import "core:time"
+import win32 "core:sys/windows"
+
+@(private="file")
+find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
+ // Ignore "." and ".."
+ if d.cFileName[0] == '.' && d.cFileName[1] == 0 {
+ return
+ }
+ if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 {
+ return
+ }
+
+ temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
+ path := concatenate({base_path, `\`, win32_wstring_to_utf8(cstring16(raw_data(d.cFileName[:])), temp_allocator) or_else ""}, allocator) or_return
+
+ handle := win32.HANDLE(_open_internal(path, {.Read}, Permissions_Read_Write_All) or_else 0)
+ defer win32.CloseHandle(handle)
+
+ fi.fullpath = path
+ fi.name = basename(path)
+ fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
+
+ fi.type, fi.mode = _file_type_mode_from_file_attributes(d.dwFileAttributes, handle, d.dwReserved0)
+
+ 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))
+
+ if file_id_info: win32.FILE_ID_INFO; handle != nil && win32.GetFileInformationByHandleEx(handle, .FileIdInfo, &file_id_info, size_of(file_id_info)) {
+ #assert(size_of(fi.inode) == size_of(file_id_info.FileId))
+ #assert(size_of(fi.inode) == 16)
+ runtime.mem_copy_non_overlapping(&fi.inode, &file_id_info.FileId, 16)
+ }
+
+ return
+}
+
+Read_Directory_Iterator_Impl :: struct {
+ find_data: win32.WIN32_FIND_DATAW,
+ find_handle: win32.HANDLE,
+ path: string,
+ prev_fi: File_Info,
+ no_more_files: bool,
+}
+
@(require_results)
-read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Error) {
- @(require_results)
- find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) {
- // Ignore "." and ".."
- if d.cFileName[0] == '.' && d.cFileName[1] == 0 {
+_read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) {
+ for !it.impl.no_more_files {
+ err: Error
+ file_info_delete(it.impl.prev_fi, file_allocator())
+ it.impl.prev_fi = {}
+
+ fi, err = find_data_to_file_info(it.impl.path, &it.impl.find_data, file_allocator())
+ if err != nil {
+ read_directory_iterator_set_error(it, it.impl.path, err)
return
}
- if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 {
- return
- }
- path := strings.concatenate({base_path, `\`, win32.utf16_to_utf8(d.cFileName[:]) or_else ""})
- fi.fullpath = path
- fi.name = basename(path)
- fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
-
- if d.dwFileAttributes & win32.FILE_ATTRIBUTE_READONLY != 0 {
- fi.mode |= 0o444
- } else {
- fi.mode |= 0o666
- }
- is_sym := false
- if d.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_Point == 0 {
- is_sym = false
- } else {
- is_sym = d.dwReserved0 == win32.IO_REPARSE_TAG_SYMLINK || d.dwReserved0 == win32.IO_REPARSE_TAG_MOUNT_POINT
+ if fi.name != "" {
+ it.impl.prev_fi = fi
+ ok = true
+ index = it.index
+ it.index += 1
}
- if is_sym {
- fi.mode |= File_Mode_Sym_Link
- } else {
- if d.dwFileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
- fi.mode |= 0o111 | File_Mode_Dir
+ if !win32.FindNextFileW(it.impl.find_handle, &it.impl.find_data) {
+ e := _get_platform_error()
+ if pe, _ := is_platform_error(e); pe != i32(win32.ERROR_NO_MORE_FILES) {
+ read_directory_iterator_set_error(it, it.impl.path, e)
}
-
- // fi.mode |= file_type_mode(h);
+ it.impl.no_more_files = true
+ }
+ if ok {
+ return
}
+ }
+ return
+}
- windows_set_file_info_times(&fi, d)
+_read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
+ it.impl.no_more_files = false
- fi.is_dir = fi.mode & File_Mode_Dir != 0
+ if f == nil || f.impl == nil {
+ read_directory_iterator_set_error(it, "", .Invalid_File)
return
}
- if fd == 0 {
- return nil, ERROR_INVALID_HANDLE
- }
-
- context.allocator = allocator
-
- h := win32.HANDLE(fd)
+ it.f = f
+ impl := (^File_Impl)(f.impl)
- dir_fi, _ := file_info_from_get_file_information_by_handle("", h)
- if !dir_fi.is_dir {
- return nil, .Not_Dir
+ // NOTE: Allow calling `init` to target a new directory with the same iterator - reset idx.
+ if it.impl.find_handle != nil {
+ win32.FindClose(it.impl.find_handle)
}
-
- n := n
- size := n
- if n <= 0 {
- n = -1
- size = 100
+ if it.impl.path != "" {
+ delete(it.impl.path, file_allocator())
}
- runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
- wpath := cleanpath_from_handle_u16(fd, context.temp_allocator) or_return
- if len(wpath) == 0 {
+ if !is_directory(impl.name) {
+ read_directory_iterator_set_error(it, impl.name, .Invalid_Dir)
return
}
- dfi := make([dynamic]File_Info, 0, size) or_return
+ wpath := string16(impl.wname)
+ temp_allocator := TEMP_ALLOCATOR_GUARD({})
- wpath_search := make([]u16, len(wpath)+3, context.temp_allocator) or_return
+ wpath_search := make([]u16, len(wpath)+3, temp_allocator)
copy(wpath_search, wpath)
wpath_search[len(wpath)+0] = '\\'
wpath_search[len(wpath)+1] = '*'
wpath_search[len(wpath)+2] = 0
- path := cleanpath_from_buf(wpath)
- defer delete(path)
-
- find_data := &win32.WIN32_FIND_DATAW{}
- find_handle := win32.FindFirstFileW(cstring16(raw_data(wpath_search)), find_data)
- if find_handle == win32.INVALID_HANDLE_VALUE {
- err = get_last_error()
- return dfi[:], err
+ it.impl.find_handle = win32.FindFirstFileW(cstring16(raw_data(wpath_search)), &it.impl.find_data)
+ if it.impl.find_handle == win32.INVALID_HANDLE_VALUE {
+ read_directory_iterator_set_error(it, impl.name, _get_platform_error())
+ return
+ }
+ defer if it.err.err != nil {
+ win32.FindClose(it.impl.find_handle)
}
- defer win32.FindClose(find_handle)
- for n != 0 {
- fi: File_Info
- fi = find_data_to_file_info(path, find_data)
- if fi.name != "" {
- append(&dfi, fi)
- n -= 1
- }
- if !win32.FindNextFileW(find_handle, find_data) {
- e := get_last_error()
- if e == ERROR_NO_MORE_FILES {
- break
- }
- return dfi[:], e
- }
+ err: Error
+ it.impl.path, err = _cleanpath_from_buf(wpath, file_allocator())
+ if err != nil {
+ read_directory_iterator_set_error(it, impl.name, err)
}
- return dfi[:], nil
+ return
+}
+
+_read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) {
+ if it.f == nil {
+ return
+ }
+ file_info_delete(it.impl.prev_fi, file_allocator())
+ delete(it.impl.path, file_allocator())
+ win32.FindClose(it.impl.find_handle)
}
diff --git a/core/os/os2/doc.odin b/core/os/doc.odin
index 2ebdd0912..2ebdd0912 100644
--- a/core/os/os2/doc.odin
+++ b/core/os/doc.odin
diff --git a/core/os/os2/env.odin b/core/os/env.odin
index 310d45af1..310d45af1 100644
--- a/core/os/os2/env.odin
+++ b/core/os/env.odin
diff --git a/core/os/os2/env_js.odin b/core/os/env_js.odin
index c1d94ba4a..c1d94ba4a 100644
--- a/core/os/os2/env_js.odin
+++ b/core/os/env_js.odin
diff --git a/core/os/os2/env_linux.odin b/core/os/env_linux.odin
index 7855fbfed..7855fbfed 100644
--- a/core/os/os2/env_linux.odin
+++ b/core/os/env_linux.odin
diff --git a/core/os/os2/env_posix.odin b/core/os/env_posix.odin
index 72a1daf18..72a1daf18 100644
--- a/core/os/os2/env_posix.odin
+++ b/core/os/env_posix.odin
diff --git a/core/os/os2/env_wasi.odin b/core/os/env_wasi.odin
index cb40667cf..cb40667cf 100644
--- a/core/os/os2/env_wasi.odin
+++ b/core/os/env_wasi.odin
diff --git a/core/os/env_windows.odin b/core/os/env_windows.odin
index ef658b0a1..d389f8860 100644
--- a/core/os/env_windows.odin
+++ b/core/os/env_windows.odin
@@ -1,30 +1,37 @@
-package os
+#+private
+package os2
import win32 "core:sys/windows"
import "base:runtime"
-// lookup_env gets the value of the environment variable named by the key
-// If the variable is found in the environment the value (which can be empty) is returned and the boolean is true
-// Otherwise the returned value will be empty and the boolean will be false
-// NOTE: the value will be allocated with the supplied allocator
-@(require_results)
-lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
+_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
if key == "" {
return
}
- wkey := win32.utf8_to_wstring(key)
+ temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
+ wkey, _ := win32_utf8_to_wstring(key, temp_allocator)
+
n := win32.GetEnvironmentVariableW(wkey, nil, 0)
- if n == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND {
- return "", false
+ if n == 0 {
+ err := win32.GetLastError()
+ if err == win32.ERROR_ENVVAR_NOT_FOUND {
+ return "", false
+ }
+ return "", true
}
- runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
- b, _ := make([dynamic]u16, n, context.temp_allocator)
+ b := make([]u16, n+1, temp_allocator)
+
n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
- if n == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND {
+ if n == 0 {
+ err := win32.GetLastError()
+ if err == win32.ERROR_ENVVAR_NOT_FOUND {
+ return "", false
+ }
return "", false
}
- value, _ = win32.utf16_to_utf8(b[:n], allocator)
+
+ value = win32_utf16_to_utf8(string16(b[:n]), allocator) or_else ""
found = true
return
}
@@ -33,7 +40,7 @@ lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value:
// Note that it is limited to environment names and values of 512 utf-16 values each
// due to the necessary utf-8 <> utf-16 conversion.
@(require_results)
-lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
+_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
key_buf: [513]u16
wkey := win32.utf8_to_wstring(key_buf[:], key)
if wkey == nil {
@@ -57,84 +64,79 @@ lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error)
return value, nil
}
-lookup_env :: proc{lookup_env_alloc, lookup_env_buffer}
-
-// get_env retrieves the value of the environment variable named by the key
-// It returns the value, which will be empty if the variable is not present
-// To distinguish between an empty value and an unset value, use lookup_env
-// NOTE: the value will be allocated with the supplied allocator
-@(require_results)
-get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) {
- value, _ = lookup_env(key, allocator)
- return
-}
+_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf}
-@(require_results)
-get_env_buf :: proc(buf: []u8, key: string) -> (value: string) {
- value, _ = lookup_env(buf, key)
- return
-}
-get_env :: proc{get_env_alloc, get_env_buf}
-
-
-// set_env sets the value of the environment variable named by the key
-set_env :: proc(key, value: string) -> Error {
- k := win32.utf8_to_wstring(key)
- v := win32.utf8_to_wstring(value)
+_set_env :: proc(key, value: string) -> Error {
+ temp_allocator := TEMP_ALLOCATOR_GUARD({})
+ k := win32_utf8_to_wstring(key, temp_allocator) or_return
+ v := win32_utf8_to_wstring(value, temp_allocator) or_return
if !win32.SetEnvironmentVariableW(k, v) {
- return get_last_error()
+ return _get_platform_error()
}
return nil
}
-// unset_env unsets a single environment variable
-unset_env :: proc(key: string) -> Error {
- k := win32.utf8_to_wstring(key)
- if !win32.SetEnvironmentVariableW(k, nil) {
- return get_last_error()
+_unset_env :: proc(key: string) -> bool {
+ temp_allocator := TEMP_ALLOCATOR_GUARD({})
+ k, _ := win32_utf8_to_wstring(key, temp_allocator)
+ return bool(win32.SetEnvironmentVariableW(k, nil))
+}
+
+_clear_env :: proc() {
+ temp_allocator := TEMP_ALLOCATOR_GUARD({})
+ envs, _ := environ(temp_allocator)
+ for env in envs {
+ for j in 1..<len(env) {
+ if env[j] == '=' {
+ unset_env(env[0:j])
+ break
+ }
+ }
}
- return nil
}
-// environ returns a copy of strings representing the environment, in the form "key=value"
-// NOTE: the slice of strings and the strings with be allocated using the supplied allocator
-@(require_results)
-environ :: proc(allocator := context.allocator) -> []string {
- envs := ([^]win32.WCHAR)(win32.GetEnvironmentStringsW())
+_environ :: proc(allocator: runtime.Allocator) -> (environ: []string, err: Error) {
+ envs := win32.GetEnvironmentStringsW()
if envs == nil {
- return nil
+ return
}
defer win32.FreeEnvironmentStringsW(envs)
- r, err := make([dynamic]string, 0, 50, allocator)
- if err != nil {
- return nil
- }
- for from, i := 0, 0; true; i += 1 {
- if c := envs[i]; c == 0 {
+ n := 0
+ for from, i, p := 0, 0, envs; true; i += 1 {
+ c := ([^]u16)(p)[i]
+ if c == 0 {
if i <= from {
break
}
- append(&r, win32.utf16_to_utf8(envs[from:i], allocator) or_else "")
+ n += 1
from = i + 1
}
}
- return r[:]
-}
-
-
-// clear_env deletes all environment variables
-clear_env :: proc() {
- runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
- envs := environ(context.temp_allocator)
- for env in envs {
- for j in 1..<len(env) {
- if env[j] == '=' {
- unset_env(env[0:j])
+ r := make([dynamic]string, 0, n, allocator) or_return
+ defer if err != nil {
+ for e in r {
+ delete(e, allocator)
+ }
+ delete(r)
+ }
+ for from, i, p := 0, 0, envs; true; i += 1 {
+ c := ([^]u16)(p)[i]
+ if c == 0 {
+ if i <= from {
break
}
+ w := ([^]u16)(p)[from:i]
+ s := win32_utf16_to_utf8(w, allocator) or_return
+ append(&r, s)
+ from = i + 1
}
}
+
+ environ = r[:]
+ return
}
+
+
diff --git a/core/os/errors.odin b/core/os/errors.odin
index fcf70ec74..508d824b3 100644
--- a/core/os/errors.odin
+++ b/core/os/errors.odin
@@ -1,13 +1,12 @@
-package os
+package os2
-import "base:intrinsics"
-import "base:runtime"
import "core:io"
+import "base:runtime"
-Platform_Error :: _Platform_Error
-#assert(size_of(Platform_Error) <= 4)
-#assert(intrinsics.type_has_nil(Platform_Error))
-
+/*
+ General errors that are common within this package which cannot
+ be categorized by `io.Error` nor `runtime.Allocator_Error`.
+*/
General_Error :: enum u32 {
None,
@@ -22,39 +21,43 @@ General_Error :: enum u32 {
Invalid_Dir,
Invalid_Path,
Invalid_Callback,
+ Invalid_Command,
Pattern_Has_Separator,
+ Pattern_Syntax_Error, // Indicates an error in `glob` or `match` pattern.
- File_Is_Pipe,
- Not_Dir,
-
- // Environment variable not found.
+ No_HOME_Variable,
Env_Var_Not_Found,
}
+// A platform specific error
+Platform_Error :: _Platform_Error
-Errno :: Error // alias for legacy use
-
+/*
+ `Error` is a union of different classes of errors that could be returned from procedures in this package.
+*/
Error :: union #shared_nil {
General_Error,
io.Error,
runtime.Allocator_Error,
Platform_Error,
}
-#assert(size_of(Error) == 8)
+#assert(size_of(Error) == size_of(u64))
ERROR_NONE :: Error{}
-ERROR_EOF :: io.Error.EOF
+// Attempts to convert an `Error` into a platform specific error as an integer. `ok` is false if not possible
@(require_results)
-is_platform_error :: proc "contextless" (ferr: Error) -> (err: i32, ok: bool) {
+is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
v := ferr.(Platform_Error) or_else {}
return i32(v), i32(v) != 0
}
+
+// Attempts to return the error `ferr` as a string without any allocation
@(require_results)
-error_string :: proc "contextless" (ferr: Error) -> string {
+error_string :: proc(ferr: Error) -> string {
if ferr == nil {
return ""
}
@@ -62,18 +65,19 @@ error_string :: proc "contextless" (ferr: Error) -> string {
case General_Error:
switch e {
case .None: return ""
- case .Exist: return "file already exists"
- case .Not_Exist: return "file does not exist"
- case .Timeout: return "i/o timeout"
- case .Broken_Pipe: return "Broken pipe"
- case .Invalid_File: return "invalid file"
- case .Invalid_Dir: return "invalid directory"
- case .Invalid_Path: return "invalid path"
- case .Invalid_Callback: return "invalid callback"
- case .Pattern_Has_Separator: return "pattern has separator"
- case .File_Is_Pipe: return "file is pipe"
- case .Not_Dir: return "file is not directory"
- case .Env_Var_Not_Found: return "environment variable not found"
+ case .Exist: return "file already exists"
+ case .Not_Exist: return "file does not exist"
+ case .Timeout: return "i/o timeout"
+ case .Broken_Pipe: return "Broken pipe"
+ case .Invalid_File: return "invalid file"
+ case .Invalid_Dir: return "invalid directory"
+ case .Invalid_Path: return "invalid path"
+ case .Invalid_Callback: return "invalid callback"
+ case .Invalid_Command: return "invalid command"
+ case .Pattern_Has_Separator: return "pattern has separator"
+ case .Pattern_Syntax_Error: return "glob pattern syntax error"
+ case .No_HOME_Variable: return "no $HOME variable"
+ case .Env_Var_Not_Found: return "environment variable not found"
}
case io.Error:
switch e {
@@ -106,210 +110,35 @@ error_string :: proc "contextless" (ferr: Error) -> string {
case .Mode_Not_Implemented: return "allocator mode not implemented"
}
case Platform_Error:
- return _error_string(e)
+ return _error_string(i32(e))
}
return "unknown error"
}
-print_error :: proc(f: Handle, ferr: Error, msg: string) -> (n: int, err: Error) {
+/*
+ `print_error` is a utility procedure which will print an error `ferr` to a specified file `f`.
+*/
+print_error :: proc(f: ^File, ferr: Error, msg: string) {
+ temp_allocator := TEMP_ALLOCATOR_GUARD({})
err_str := error_string(ferr)
// msg + ": " + err_str + '\n'
length := len(msg) + 2 + len(err_str) + 1
- buf_ := intrinsics.alloca(length, 1)
- buf := buf_[:length]
+ buf := make([]u8, length, temp_allocator)
copy(buf, msg)
buf[len(msg)] = ':'
buf[len(msg) + 1] = ' '
copy(buf[len(msg) + 2:], err_str)
buf[length - 1] = '\n'
- return write(f, buf)
+ write(f, buf)
}
-@(require_results, private)
-_error_string :: proc "contextless" (e: Platform_Error) -> string where intrinsics.type_is_enum(Platform_Error) {
- if e == nil {
- return ""
- }
-
- when ODIN_OS == .Darwin {
- if s := string(_darwin_string_error(i32(e))); s != "" {
- return s
- }
- }
-
- when ODIN_OS != .Linux {
- @(require_results)
- binary_search :: proc "contextless" (array: $A/[]$T, key: T) -> (index: int, found: bool) #no_bounds_check {
- n := len(array)
- left, right := 0, n
- for left < right {
- mid := int(uint(left+right) >> 1)
- if array[mid] < key {
- left = mid+1
- } else {
- // equal or greater
- right = mid
- }
- }
- return left, left < n && array[left] == key
- }
-
- err := runtime.Type_Info_Enum_Value(e)
-
- ti := &runtime.type_info_base(type_info_of(Platform_Error)).variant.(runtime.Type_Info_Enum)
- if idx, ok := binary_search(ti.values, err); ok {
- return ti.names[idx]
- }
- } else {
- @(rodata, static)
- pe_strings := [Platform_Error]string{
- .NONE = "",
- .EPERM = "Operation not permitted",
- .ENOENT = "No such file or directory",
- .ESRCH = "No such process",
- .EINTR = "Interrupted system call",
- .EIO = "Input/output error",
- .ENXIO = "No such device or address",
- .E2BIG = "Argument list too long",
- .ENOEXEC = "Exec format error",
- .EBADF = "Bad file descriptor",
- .ECHILD = "No child processes",
- .EAGAIN = "Resource temporarily unavailable",
- .ENOMEM = "Cannot allocate memory",
- .EACCES = "Permission denied",
- .EFAULT = "Bad address",
- .ENOTBLK = "Block device required",
- .EBUSY = "Device or resource busy",
- .EEXIST = "File exists",
- .EXDEV = "Invalid cross-device link",
- .ENODEV = "No such device",
- .ENOTDIR = "Not a directory",
- .EISDIR = "Is a directory",
- .EINVAL = "Invalid argument",
- .ENFILE = "Too many open files in system",
- .EMFILE = "Too many open files",
- .ENOTTY = "Inappropriate ioctl for device",
- .ETXTBSY = "Text file busy",
- .EFBIG = "File too large",
- .ENOSPC = "No space left on device",
- .ESPIPE = "Illegal seek",
- .EROFS = "Read-only file system",
- .EMLINK = "Too many links",
- .EPIPE = "Broken pipe",
- .EDOM = "Numerical argument out of domain",
- .ERANGE = "Numerical result out of range",
- .EDEADLK = "Resource deadlock avoided",
- .ENAMETOOLONG = "File name too long",
- .ENOLCK = "No locks available",
- .ENOSYS = "Function not implemented",
- .ENOTEMPTY = "Directory not empty",
- .ELOOP = "Too many levels of symbolic links",
- .EUNKNOWN_41 = "Unknown Error (41)",
- .ENOMSG = "No message of desired type",
- .EIDRM = "Identifier removed",
- .ECHRNG = "Channel number out of range",
- .EL2NSYNC = "Level 2 not synchronized",
- .EL3HLT = "Level 3 halted",
- .EL3RST = "Level 3 reset",
- .ELNRNG = "Link number out of range",
- .EUNATCH = "Protocol driver not attached",
- .ENOCSI = "No CSI structure available",
- .EL2HLT = "Level 2 halted",
- .EBADE = "Invalid exchange",
- .EBADR = "Invalid request descriptor",
- .EXFULL = "Exchange full",
- .ENOANO = "No anode",
- .EBADRQC = "Invalid request code",
- .EBADSLT = "Invalid slot",
- .EUNKNOWN_58 = "Unknown Error (58)",
- .EBFONT = "Bad font file format",
- .ENOSTR = "Device not a stream",
- .ENODATA = "No data available",
- .ETIME = "Timer expired",
- .ENOSR = "Out of streams resources",
- .ENONET = "Machine is not on the network",
- .ENOPKG = "Package not installed",
- .EREMOTE = "Object is remote",
- .ENOLINK = "Link has been severed",
- .EADV = "Advertise error",
- .ESRMNT = "Srmount error",
- .ECOMM = "Communication error on send",
- .EPROTO = "Protocol error",
- .EMULTIHOP = "Multihop attempted",
- .EDOTDOT = "RFS specific error",
- .EBADMSG = "Bad message",
- .EOVERFLOW = "Value too large for defined data type",
- .ENOTUNIQ = "Name not unique on network",
- .EBADFD = "File descriptor in bad state",
- .EREMCHG = "Remote address changed",
- .ELIBACC = "Can not access a needed shared library",
- .ELIBBAD = "Accessing a corrupted shared library",
- .ELIBSCN = ".lib section in a.out corrupted",
- .ELIBMAX = "Attempting to link in too many shared libraries",
- .ELIBEXEC = "Cannot exec a shared library directly",
- .EILSEQ = "Invalid or incomplete multibyte or wide character",
- .ERESTART = "Interrupted system call should be restarted",
- .ESTRPIPE = "Streams pipe error",
- .EUSERS = "Too many users",
- .ENOTSOCK = "Socket operation on non-socket",
- .EDESTADDRREQ = "Destination address required",
- .EMSGSIZE = "Message too long",
- .EPROTOTYPE = "Protocol wrong type for socket",
- .ENOPROTOOPT = "Protocol not available",
- .EPROTONOSUPPORT = "Protocol not supported",
- .ESOCKTNOSUPPORT = "Socket type not supported",
- .EOPNOTSUPP = "Operation not supported",
- .EPFNOSUPPORT = "Protocol family not supported",
- .EAFNOSUPPORT = "Address family not supported by protocol",
- .EADDRINUSE = "Address already in use",
- .EADDRNOTAVAIL = "Cannot assign requested address",
- .ENETDOWN = "Network is down",
- .ENETUNREACH = "Network is unreachable",
- .ENETRESET = "Network dropped connection on reset",
- .ECONNABORTED = "Software caused connection abort",
- .ECONNRESET = "Connection reset by peer",
- .ENOBUFS = "No buffer space available",
- .EISCONN = "Transport endpoint is already connected",
- .ENOTCONN = "Transport endpoint is not connected",
- .ESHUTDOWN = "Cannot send after transport endpoint shutdown",
- .ETOOMANYREFS = "Too many references: cannot splice",
- .ETIMEDOUT = "Connection timed out",
- .ECONNREFUSED = "Connection refused",
- .EHOSTDOWN = "Host is down",
- .EHOSTUNREACH = "No route to host",
- .EALREADY = "Operation already in progress",
- .EINPROGRESS = "Operation now in progress",
- .ESTALE = "Stale file handle",
- .EUCLEAN = "Structure needs cleaning",
- .ENOTNAM = "Not a XENIX named type file",
- .ENAVAIL = "No XENIX semaphores available",
- .EISNAM = "Is a named type file",
- .EREMOTEIO = "Remote I/O error",
- .EDQUOT = "Disk quota exceeded",
- .ENOMEDIUM = "No medium found",
- .EMEDIUMTYPE = "Wrong medium type",
- .ECANCELED = "Operation canceled",
- .ENOKEY = "Required key not available",
- .EKEYEXPIRED = "Key has expired",
- .EKEYREVOKED = "Key has been revoked",
- .EKEYREJECTED = "Key was rejected by service",
- .EOWNERDEAD = "Owner died",
- .ENOTRECOVERABLE = "State not recoverable",
- .ERFKILL = "Operation not possible due to RF-kill",
- .EHWPOISON = "Memory page has hardware error",
- }
- if Platform_Error.NONE <= e && e <= max(Platform_Error) {
- return pe_strings[e]
- }
- }
- return "<unknown platform error>"
-}
-@(private, require_results)
+// Attempts to convert an `Error` `ferr` into an `io.Error`
+@(private)
error_to_io_error :: proc(ferr: Error) -> io.Error {
if ferr == nil {
return .None
diff --git a/core/os/os2/errors_js.odin b/core/os/errors_js.odin
index c92d36736..c92d36736 100644
--- a/core/os/os2/errors_js.odin
+++ b/core/os/errors_js.odin
diff --git a/core/os/os2/errors_linux.odin b/core/os/errors_linux.odin
index a7556c306..a7556c306 100644
--- a/core/os/os2/errors_linux.odin
+++ b/core/os/errors_linux.odin
diff --git a/core/os/os2/errors_posix.odin b/core/os/errors_posix.odin
index 8a9ca07df..8a9ca07df 100644
--- a/core/os/os2/errors_posix.odin
+++ b/core/os/errors_posix.odin
diff --git a/core/os/os2/errors_wasi.odin b/core/os/errors_wasi.odin
index b88e5b81e..b88e5b81e 100644
--- a/core/os/os2/errors_wasi.odin
+++ b/core/os/errors_wasi.odin
diff --git a/core/os/os2/errors_windows.odin b/core/os/errors_windows.odin
index 404560f98..404560f98 100644
--- a/core/os/os2/errors_windows.odin
+++ b/core/os/errors_windows.odin
diff --git a/core/os/os2/file.odin b/core/os/file.odin
index bf7ebaeb5..bf7ebaeb5 100644
--- a/core/os/os2/file.odin
+++ b/core/os/file.odin
diff --git a/core/os/os2/file_js.odin b/core/os/file_js.odin
index 91ee7f02e..91ee7f02e 100644
--- a/core/os/os2/file_js.odin
+++ b/core/os/file_js.odin
diff --git a/core/os/os2/file_linux.odin b/core/os/file_linux.odin
index f5f2ebdd7..f5f2ebdd7 100644
--- a/core/os/os2/file_linux.odin
+++ b/core/os/file_linux.odin
diff --git a/core/os/os2/file_posix.odin b/core/os/file_posix.odin
index ef53bf116..ef53bf116 100644
--- a/core/os/os2/file_posix.odin
+++ b/core/os/file_posix.odin
diff --git a/core/os/os2/file_posix_darwin.odin b/core/os/file_posix_darwin.odin
index 521fb345b..521fb345b 100644
--- a/core/os/os2/file_posix_darwin.odin
+++ b/core/os/file_posix_darwin.odin
diff --git a/core/os/os2/file_posix_freebsd.odin b/core/os/file_posix_freebsd.odin
index 05d031930..05d031930 100644
--- a/core/os/os2/file_posix_freebsd.odin
+++ b/core/os/file_posix_freebsd.odin
diff --git a/core/os/os2/file_posix_netbsd.odin b/core/os/file_posix_netbsd.odin
index f96c227ba..f96c227ba 100644
--- a/core/os/os2/file_posix_netbsd.odin
+++ b/core/os/file_posix_netbsd.odin
diff --git a/core/os/os2/file_posix_other.odin b/core/os/file_posix_other.odin
index 8871a0062..8871a0062 100644
--- a/core/os/os2/file_posix_other.odin
+++ b/core/os/file_posix_other.odin
diff --git a/core/os/os2/file_stream.odin b/core/os/file_stream.odin
index af6e50921..af6e50921 100644
--- a/core/os/os2/file_stream.odin
+++ b/core/os/file_stream.odin
diff --git a/core/os/os2/file_util.odin b/core/os/file_util.odin
index f81dc2190..f81dc2190 100644
--- a/core/os/os2/file_util.odin
+++ b/core/os/file_util.odin
diff --git a/core/os/os2/file_wasi.odin b/core/os/file_wasi.odin
index 78aa90699..78aa90699 100644
--- a/core/os/os2/file_wasi.odin
+++ b/core/os/file_wasi.odin
diff --git a/core/os/os2/file_windows.odin b/core/os/file_windows.odin
index 0e3448dd7..0e3448dd7 100644
--- a/core/os/os2/file_windows.odin
+++ b/core/os/file_windows.odin
diff --git a/core/os/os2/heap.odin b/core/os/heap.odin
index b1db54dc7..b1db54dc7 100644
--- a/core/os/os2/heap.odin
+++ b/core/os/heap.odin
diff --git a/core/os/os2/heap_js.odin b/core/os/heap_js.odin
index 15990b517..15990b517 100644
--- a/core/os/os2/heap_js.odin
+++ b/core/os/heap_js.odin
diff --git a/core/os/os2/heap_linux.odin b/core/os/heap_linux.odin
index 1d1f12726..1d1f12726 100644
--- a/core/os/os2/heap_linux.odin
+++ b/core/os/heap_linux.odin
diff --git a/core/os/os2/heap_posix.odin b/core/os/heap_posix.odin
index 1b52aed75..1b52aed75 100644
--- a/core/os/os2/heap_posix.odin
+++ b/core/os/heap_posix.odin
diff --git a/core/os/os2/heap_wasi.odin b/core/os/heap_wasi.odin
index 7da3c4845..7da3c4845 100644
--- a/core/os/os2/heap_wasi.odin
+++ b/core/os/heap_wasi.odin
diff --git a/core/os/os2/heap_windows.odin b/core/os/heap_windows.odin
index 7fd4529a0..7fd4529a0 100644
--- a/core/os/os2/heap_windows.odin
+++ b/core/os/heap_windows.odin
diff --git a/core/os/os2/internal_util.odin b/core/os/internal_util.odin
index 9616af8b0..9616af8b0 100644
--- a/core/os/os2/internal_util.odin
+++ b/core/os/internal_util.odin
diff --git a/core/os/dir_unix.odin b/core/os/old/dir_unix.odin
index c3dd844ef..c3dd844ef 100644
--- a/core/os/dir_unix.odin
+++ b/core/os/old/dir_unix.odin
diff --git a/core/os/old/dir_windows.odin b/core/os/old/dir_windows.odin
new file mode 100644
index 000000000..40f4b9e9b
--- /dev/null
+++ b/core/os/old/dir_windows.odin
@@ -0,0 +1,114 @@
+package os
+
+import win32 "core:sys/windows"
+import "core:strings"
+import "base:runtime"
+
+@(require_results)
+read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Error) {
+ @(require_results)
+ find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW) -> (fi: File_Info) {
+ // Ignore "." and ".."
+ if d.cFileName[0] == '.' && d.cFileName[1] == 0 {
+ return
+ }
+ if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 {
+ return
+ }
+ path := strings.concatenate({base_path, `\`, win32.utf16_to_utf8(d.cFileName[:]) or_else ""})
+ fi.fullpath = path
+ fi.name = basename(path)
+ fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
+
+ if d.dwFileAttributes & win32.FILE_ATTRIBUTE_READONLY != 0 {
+ fi.mode |= 0o444
+ } else {
+ fi.mode |= 0o666
+ }
+
+ is_sym := false
+ if d.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_Point == 0 {
+ is_sym = false
+ } else {
+ is_sym = d.dwReserved0 == win32.IO_REPARSE_TAG_SYMLINK || d.dwReserved0 == win32.IO_REPARSE_TAG_MOUNT_POINT
+ }
+
+ if is_sym {
+ fi.mode |= File_Mode_Sym_Link
+ } else {
+ if d.dwFileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
+ fi.mode |= 0o111 | File_Mode_Dir
+ }
+
+ // fi.mode |= file_type_mode(h);
+ }
+
+ windows_set_file_info_times(&fi, d)
+
+ fi.is_dir = fi.mode & File_Mode_Dir != 0
+ return
+ }
+
+ if fd == 0 {
+ return nil, ERROR_INVALID_HANDLE
+ }
+
+ context.allocator = allocator
+
+ h := win32.HANDLE(fd)
+
+ dir_fi, _ := file_info_from_get_file_information_by_handle("", h)
+ if !dir_fi.is_dir {
+ return nil, .Not_Dir
+ }
+
+ n := n
+ size := n
+ if n <= 0 {
+ n = -1
+ size = 100
+ }
+ runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
+
+ wpath := cleanpath_from_handle_u16(fd, context.temp_allocator) or_return
+ if len(wpath) == 0 {
+ return
+ }
+
+ dfi := make([dynamic]File_Info, 0, size) or_return
+
+ wpath_search := make([]u16, len(wpath)+3, context.temp_allocator) or_return
+ copy(wpath_search, wpath)
+ wpath_search[len(wpath)+0] = '\\'
+ wpath_search[len(wpath)+1] = '*'
+ wpath_search[len(wpath)+2] = 0
+
+ path := cleanpath_from_buf(wpath)
+ defer delete(path)
+
+ find_data := &win32.WIN32_FIND_DATAW{}
+ find_handle := win32.FindFirstFileW(cstring16(raw_data(wpath_search)), find_data)
+ if find_handle == win32.INVALID_HANDLE_VALUE {
+ err = get_last_error()
+ return dfi[:], err
+ }
+ defer win32.FindClose(find_handle)
+ for n != 0 {
+ fi: File_Info
+ fi = find_data_to_file_info(path, find_data)
+ if fi.name != "" {
+ append(&dfi, fi)
+ n -= 1
+ }
+
+ if !win32.FindNextFileW(find_handle, find_data) {
+ e := get_last_error()
+ if e == ERROR_NO_MORE_FILES {
+ break
+ }
+ return dfi[:], e
+ }
+ }
+
+ return dfi[:], nil
+}
diff --git a/core/os/old/env_windows.odin b/core/os/old/env_windows.odin
new file mode 100644
index 000000000..ef658b0a1
--- /dev/null
+++ b/core/os/old/env_windows.odin
@@ -0,0 +1,140 @@
+package os
+
+import win32 "core:sys/windows"
+import "base:runtime"
+
+// lookup_env gets the value of the environment variable named by the key
+// If the variable is found in the environment the value (which can be empty) is returned and the boolean is true
+// Otherwise the returned value will be empty and the boolean will be false
+// NOTE: the value will be allocated with the supplied allocator
+@(require_results)
+lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
+ if key == "" {
+ return
+ }
+ wkey := win32.utf8_to_wstring(key)
+ n := win32.GetEnvironmentVariableW(wkey, nil, 0)
+ if n == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND {
+ return "", false
+ }
+ runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
+
+ b, _ := make([dynamic]u16, n, context.temp_allocator)
+ n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
+ if n == 0 && get_last_error() == ERROR_ENVVAR_NOT_FOUND {
+ return "", false
+ }
+ value, _ = win32.utf16_to_utf8(b[:n], allocator)
+ found = true
+ return
+}
+
+// This version of `lookup_env` doesn't allocate and instead requires the user to provide a buffer.
+// Note that it is limited to environment names and values of 512 utf-16 values each
+// due to the necessary utf-8 <> utf-16 conversion.
+@(require_results)
+lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
+ key_buf: [513]u16
+ wkey := win32.utf8_to_wstring(key_buf[:], key)
+ if wkey == nil {
+ return "", .Buffer_Full
+ }
+
+ n2 := win32.GetEnvironmentVariableW(wkey, nil, 0)
+ if n2 == 0 {
+ return "", .Env_Var_Not_Found
+ }
+
+ val_buf: [513]u16
+ n2 = win32.GetEnvironmentVariableW(wkey, raw_data(val_buf[:]), u32(len(val_buf[:])))
+ if n2 == 0 {
+ return "", .Env_Var_Not_Found
+ } else if int(n2) > len(buf) {
+ return "", .Buffer_Full
+ }
+
+ value = win32.utf16_to_utf8(buf, val_buf[:n2])
+
+ return value, nil
+}
+lookup_env :: proc{lookup_env_alloc, lookup_env_buffer}
+
+// get_env retrieves the value of the environment variable named by the key
+// It returns the value, which will be empty if the variable is not present
+// To distinguish between an empty value and an unset value, use lookup_env
+// NOTE: the value will be allocated with the supplied allocator
+@(require_results)
+get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) {
+ value, _ = lookup_env(key, allocator)
+ return
+}
+
+@(require_results)
+get_env_buf :: proc(buf: []u8, key: string) -> (value: string) {
+ value, _ = lookup_env(buf, key)
+ return
+}
+get_env :: proc{get_env_alloc, get_env_buf}
+
+
+// set_env sets the value of the environment variable named by the key
+set_env :: proc(key, value: string) -> Error {
+ k := win32.utf8_to_wstring(key)
+ v := win32.utf8_to_wstring(value)
+
+ if !win32.SetEnvironmentVariableW(k, v) {
+ return get_last_error()
+ }
+ return nil
+}
+
+// unset_env unsets a single environment variable
+unset_env :: proc(key: string) -> Error {
+ k := win32.utf8_to_wstring(key)
+ if !win32.SetEnvironmentVariableW(k, nil) {
+ return get_last_error()
+ }
+ return nil
+}
+
+// environ returns a copy of strings representing the environment, in the form "key=value"
+// NOTE: the slice of strings and the strings with be allocated using the supplied allocator
+@(require_results)
+environ :: proc(allocator := context.allocator) -> []string {
+ envs := ([^]win32.WCHAR)(win32.GetEnvironmentStringsW())
+ if envs == nil {
+ return nil
+ }
+ defer win32.FreeEnvironmentStringsW(envs)
+
+ r, err := make([dynamic]string, 0, 50, allocator)
+ if err != nil {
+ return nil
+ }
+ for from, i := 0, 0; true; i += 1 {
+ if c := envs[i]; c == 0 {
+ if i <= from {
+ break
+ }
+ append(&r, win32.utf16_to_utf8(envs[from:i], allocator) or_else "")
+ from = i + 1
+ }
+ }
+
+ return r[:]
+}
+
+
+// clear_env deletes all environment variables
+clear_env :: proc() {
+ runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
+ envs := environ(context.temp_allocator)
+ for env in envs {
+ for j in 1..<len(env) {
+ if env[j] == '=' {
+ unset_env(env[0:j])
+ break
+ }
+ }
+ }
+}
diff --git a/core/os/old/errors.odin b/core/os/old/errors.odin
new file mode 100644
index 000000000..fcf70ec74
--- /dev/null
+++ b/core/os/old/errors.odin
@@ -0,0 +1,318 @@
+package os
+
+import "base:intrinsics"
+import "base:runtime"
+import "core:io"
+
+Platform_Error :: _Platform_Error
+#assert(size_of(Platform_Error) <= 4)
+#assert(intrinsics.type_has_nil(Platform_Error))
+
+General_Error :: enum u32 {
+ None,
+
+ Exist,
+ Not_Exist,
+
+ Timeout,
+
+ Broken_Pipe,
+
+ Invalid_File,
+ Invalid_Dir,
+ Invalid_Path,
+ Invalid_Callback,
+
+ Pattern_Has_Separator,
+
+ File_Is_Pipe,
+ Not_Dir,
+
+ // Environment variable not found.
+ Env_Var_Not_Found,
+}
+
+
+Errno :: Error // alias for legacy use
+
+Error :: union #shared_nil {
+ General_Error,
+ io.Error,
+ runtime.Allocator_Error,
+ Platform_Error,
+}
+#assert(size_of(Error) == 8)
+
+ERROR_NONE :: Error{}
+
+ERROR_EOF :: io.Error.EOF
+
+@(require_results)
+is_platform_error :: proc "contextless" (ferr: Error) -> (err: i32, ok: bool) {
+ v := ferr.(Platform_Error) or_else {}
+ return i32(v), i32(v) != 0
+}
+
+@(require_results)
+error_string :: proc "contextless" (ferr: Error) -> string {
+ if ferr == nil {
+ return ""
+ }
+ switch e in ferr {
+ case General_Error:
+ switch e {
+ case .None: return ""
+ case .Exist: return "file already exists"
+ case .Not_Exist: return "file does not exist"
+ case .Timeout: return "i/o timeout"
+ case .Broken_Pipe: return "Broken pipe"
+ case .Invalid_File: return "invalid file"
+ case .Invalid_Dir: return "invalid directory"
+ case .Invalid_Path: return "invalid path"
+ case .Invalid_Callback: return "invalid callback"
+ case .Pattern_Has_Separator: return "pattern has separator"
+ case .File_Is_Pipe: return "file is pipe"
+ case .Not_Dir: return "file is not directory"
+ case .Env_Var_Not_Found: return "environment variable not found"
+ }
+ case io.Error:
+ switch e {
+ case .None: return ""
+ case .EOF: return "eof"
+ case .Unexpected_EOF: return "unexpected eof"
+ case .Short_Write: return "short write"
+ case .Invalid_Write: return "invalid write result"
+ case .Short_Buffer: return "short buffer"
+ case .No_Progress: return "multiple read calls return no data or error"
+ case .Invalid_Whence: return "invalid whence"
+ case .Invalid_Offset: return "invalid offset"
+ case .Invalid_Unread: return "invalid unread"
+ case .Negative_Read: return "negative read"
+ case .Negative_Write: return "negative write"
+ case .Negative_Count: return "negative count"
+ case .Buffer_Full: return "buffer full"
+ case .Permission_Denied: return "permission denied"
+ case .Closed: return "file already closed"
+ case .No_Size: return "file has no definite size"
+ case .Unsupported: return "unsupported"
+ case .Unknown: //
+ }
+ case runtime.Allocator_Error:
+ switch e {
+ case .None: return ""
+ case .Out_Of_Memory: return "out of memory"
+ case .Invalid_Pointer: return "invalid allocator pointer"
+ case .Invalid_Argument: return "invalid allocator argument"
+ case .Mode_Not_Implemented: return "allocator mode not implemented"
+ }
+ case Platform_Error:
+ return _error_string(e)
+ }
+
+ return "unknown error"
+}
+
+print_error :: proc(f: Handle, ferr: Error, msg: string) -> (n: int, err: Error) {
+ err_str := error_string(ferr)
+
+ // msg + ": " + err_str + '\n'
+ length := len(msg) + 2 + len(err_str) + 1
+ buf_ := intrinsics.alloca(length, 1)
+ buf := buf_[:length]
+
+ copy(buf, msg)
+ buf[len(msg)] = ':'
+ buf[len(msg) + 1] = ' '
+ copy(buf[len(msg) + 2:], err_str)
+ buf[length - 1] = '\n'
+ return write(f, buf)
+}
+
+
+@(require_results, private)
+_error_string :: proc "contextless" (e: Platform_Error) -> string where intrinsics.type_is_enum(Platform_Error) {
+ if e == nil {
+ return ""
+ }
+
+ when ODIN_OS == .Darwin {
+ if s := string(_darwin_string_error(i32(e))); s != "" {
+ return s
+ }
+ }
+
+ when ODIN_OS != .Linux {
+ @(require_results)
+ binary_search :: proc "contextless" (array: $A/[]$T, key: T) -> (index: int, found: bool) #no_bounds_check {
+ n := len(array)
+ left, right := 0, n
+ for left < right {
+ mid := int(uint(left+right) >> 1)
+ if array[mid] < key {
+ left = mid+1
+ } else {
+ // equal or greater
+ right = mid
+ }
+ }
+ return left, left < n && array[left] == key
+ }
+
+ err := runtime.Type_Info_Enum_Value(e)
+
+ ti := &runtime.type_info_base(type_info_of(Platform_Error)).variant.(runtime.Type_Info_Enum)
+ if idx, ok := binary_search(ti.values, err); ok {
+ return ti.names[idx]
+ }
+ } else {
+ @(rodata, static)
+ pe_strings := [Platform_Error]string{
+ .NONE = "",
+ .EPERM = "Operation not permitted",
+ .ENOENT = "No such file or directory",
+ .ESRCH = "No such process",
+ .EINTR = "Interrupted system call",
+ .EIO = "Input/output error",
+ .ENXIO = "No such device or address",
+ .E2BIG = "Argument list too long",
+ .ENOEXEC = "Exec format error",
+ .EBADF = "Bad file descriptor",
+ .ECHILD = "No child processes",
+ .EAGAIN = "Resource temporarily unavailable",
+ .ENOMEM = "Cannot allocate memory",
+ .EACCES = "Permission denied",
+ .EFAULT = "Bad address",
+ .ENOTBLK = "Block device required",
+ .EBUSY = "Device or resource busy",
+ .EEXIST = "File exists",
+ .EXDEV = "Invalid cross-device link",
+ .ENODEV = "No such device",
+ .ENOTDIR = "Not a directory",
+ .EISDIR = "Is a directory",
+ .EINVAL = "Invalid argument",
+ .ENFILE = "Too many open files in system",
+ .EMFILE = "Too many open files",
+ .ENOTTY = "Inappropriate ioctl for device",
+ .ETXTBSY = "Text file busy",
+ .EFBIG = "File too large",
+ .ENOSPC = "No space left on device",
+ .ESPIPE = "Illegal seek",
+ .EROFS = "Read-only file system",
+ .EMLINK = "Too many links",
+ .EPIPE = "Broken pipe",
+ .EDOM = "Numerical argument out of domain",
+ .ERANGE = "Numerical result out of range",
+ .EDEADLK = "Resource deadlock avoided",
+ .ENAMETOOLONG = "File name too long",
+ .ENOLCK = "No locks available",
+ .ENOSYS = "Function not implemented",
+ .ENOTEMPTY = "Directory not empty",
+ .ELOOP = "Too many levels of symbolic links",
+ .EUNKNOWN_41 = "Unknown Error (41)",
+ .ENOMSG = "No message of desired type",
+ .EIDRM = "Identifier removed",
+ .ECHRNG = "Channel number out of range",
+ .EL2NSYNC = "Level 2 not synchronized",
+ .EL3HLT = "Level 3 halted",
+ .EL3RST = "Level 3 reset",
+ .ELNRNG = "Link number out of range",
+ .EUNATCH = "Protocol driver not attached",
+ .ENOCSI = "No CSI structure available",
+ .EL2HLT = "Level 2 halted",
+ .EBADE = "Invalid exchange",
+ .EBADR = "Invalid request descriptor",
+ .EXFULL = "Exchange full",
+ .ENOANO = "No anode",
+ .EBADRQC = "Invalid request code",
+ .EBADSLT = "Invalid slot",
+ .EUNKNOWN_58 = "Unknown Error (58)",
+ .EBFONT = "Bad font file format",
+ .ENOSTR = "Device not a stream",
+ .ENODATA = "No data available",
+ .ETIME = "Timer expired",
+ .ENOSR = "Out of streams resources",
+ .ENONET = "Machine is not on the network",
+ .ENOPKG = "Package not installed",
+ .EREMOTE = "Object is remote",
+ .ENOLINK = "Link has been severed",
+ .EADV = "Advertise error",
+ .ESRMNT = "Srmount error",
+ .ECOMM = "Communication error on send",
+ .EPROTO = "Protocol error",
+ .EMULTIHOP = "Multihop attempted",
+ .EDOTDOT = "RFS specific error",
+ .EBADMSG = "Bad message",
+ .EOVERFLOW = "Value too large for defined data type",
+ .ENOTUNIQ = "Name not unique on network",
+ .EBADFD = "File descriptor in bad state",
+ .EREMCHG = "Remote address changed",
+ .ELIBACC = "Can not access a needed shared library",
+ .ELIBBAD = "Accessing a corrupted shared library",
+ .ELIBSCN = ".lib section in a.out corrupted",
+ .ELIBMAX = "Attempting to link in too many shared libraries",
+ .ELIBEXEC = "Cannot exec a shared library directly",
+ .EILSEQ = "Invalid or incomplete multibyte or wide character",
+ .ERESTART = "Interrupted system call should be restarted",
+ .ESTRPIPE = "Streams pipe error",
+ .EUSERS = "Too many users",
+ .ENOTSOCK = "Socket operation on non-socket",
+ .EDESTADDRREQ = "Destination address required",
+ .EMSGSIZE = "Message too long",
+ .EPROTOTYPE = "Protocol wrong type for socket",
+ .ENOPROTOOPT = "Protocol not available",
+ .EPROTONOSUPPORT = "Protocol not supported",
+ .ESOCKTNOSUPPORT = "Socket type not supported",
+ .EOPNOTSUPP = "Operation not supported",
+ .EPFNOSUPPORT = "Protocol family not supported",
+ .EAFNOSUPPORT = "Address family not supported by protocol",
+ .EADDRINUSE = "Address already in use",
+ .EADDRNOTAVAIL = "Cannot assign requested address",
+ .ENETDOWN = "Network is down",
+ .ENETUNREACH = "Network is unreachable",
+ .ENETRESET = "Network dropped connection on reset",
+ .ECONNABORTED = "Software caused connection abort",
+ .ECONNRESET = "Connection reset by peer",
+ .ENOBUFS = "No buffer space available",
+ .EISCONN = "Transport endpoint is already connected",
+ .ENOTCONN = "Transport endpoint is not connected",
+ .ESHUTDOWN = "Cannot send after transport endpoint shutdown",
+ .ETOOMANYREFS = "Too many references: cannot splice",
+ .ETIMEDOUT = "Connection timed out",
+ .ECONNREFUSED = "Connection refused",
+ .EHOSTDOWN = "Host is down",
+ .EHOSTUNREACH = "No route to host",
+ .EALREADY = "Operation already in progress",
+ .EINPROGRESS = "Operation now in progress",
+ .ESTALE = "Stale file handle",
+ .EUCLEAN = "Structure needs cleaning",
+ .ENOTNAM = "Not a XENIX named type file",
+ .ENAVAIL = "No XENIX semaphores available",
+ .EISNAM = "Is a named type file",
+ .EREMOTEIO = "Remote I/O error",
+ .EDQUOT = "Disk quota exceeded",
+ .ENOMEDIUM = "No medium found",
+ .EMEDIUMTYPE = "Wrong medium type",
+ .ECANCELED = "Operation canceled",
+ .ENOKEY = "Required key not available",
+ .EKEYEXPIRED = "Key has expired",
+ .EKEYREVOKED = "Key has been revoked",
+ .EKEYREJECTED = "Key was rejected by service",
+ .EOWNERDEAD = "Owner died",
+ .ENOTRECOVERABLE = "State not recoverable",
+ .ERFKILL = "Operation not possible due to RF-kill",
+ .EHWPOISON = "Memory page has hardware error",
+ }
+ if Platform_Error.NONE <= e && e <= max(Platform_Error) {
+ return pe_strings[e]
+ }
+ }
+ return "<unknown platform error>"
+}
+
+@(private, require_results)
+error_to_io_error :: proc(ferr: Error) -> io.Error {
+ if ferr == nil {
+ return .None
+ }
+ return ferr.(io.Error) or_else .Unknown
+}
diff --git a/core/os/os.odin b/core/os/old/os.odin
index da7b0c151..da7b0c151 100644
--- a/core/os/os.odin
+++ b/core/os/old/os.odin
diff --git a/core/os/os_darwin.odin b/core/os/old/os_darwin.odin
index 92a636255..92a636255 100644
--- a/core/os/os_darwin.odin
+++ b/core/os/old/os_darwin.odin
diff --git a/core/os/os_essence.odin b/core/os/old/os_essence.odin
index 75c4c1156..75c4c1156 100644
--- a/core/os/os_essence.odin
+++ b/core/os/old/os_essence.odin
diff --git a/core/os/os_freebsd.odin b/core/os/old/os_freebsd.odin
index 82b5a2f0f..82b5a2f0f 100644
--- a/core/os/os_freebsd.odin
+++ b/core/os/old/os_freebsd.odin
diff --git a/core/os/os_freestanding.odin b/core/os/old/os_freestanding.odin
index c22a6d7d5..c22a6d7d5 100644
--- a/core/os/os_freestanding.odin
+++ b/core/os/old/os_freestanding.odin
diff --git a/core/os/os_haiku.odin b/core/os/old/os_haiku.odin
index ad984e33c..ad984e33c 100644
--- a/core/os/os_haiku.odin
+++ b/core/os/old/os_haiku.odin
diff --git a/core/os/os_js.odin b/core/os/old/os_js.odin
index 1870218d3..1870218d3 100644
--- a/core/os/os_js.odin
+++ b/core/os/old/os_js.odin
diff --git a/core/os/os_linux.odin b/core/os/old/os_linux.odin
index 4c32676c6..4c32676c6 100644
--- a/core/os/os_linux.odin
+++ b/core/os/old/os_linux.odin
diff --git a/core/os/os_netbsd.odin b/core/os/old/os_netbsd.odin
index 640ea46cd..640ea46cd 100644
--- a/core/os/os_netbsd.odin
+++ b/core/os/old/os_netbsd.odin
diff --git a/core/os/os_openbsd.odin b/core/os/old/os_openbsd.odin
index bf89a21f4..bf89a21f4 100644
--- a/core/os/os_openbsd.odin
+++ b/core/os/old/os_openbsd.odin
diff --git a/core/os/os_wasi.odin b/core/os/old/os_wasi.odin
index fe0a1fb3e..fe0a1fb3e 100644
--- a/core/os/os_wasi.odin
+++ b/core/os/old/os_wasi.odin
diff --git a/core/os/os_windows.odin b/core/os/old/os_windows.odin
index cb7e42f67..cb7e42f67 100644
--- a/core/os/os_windows.odin
+++ b/core/os/old/os_windows.odin
diff --git a/core/os/old/stat.odin b/core/os/old/stat.odin
new file mode 100644
index 000000000..21a4961d1
--- /dev/null
+++ b/core/os/old/stat.odin
@@ -0,0 +1,33 @@
+package os
+
+import "core:time"
+
+File_Info :: struct {
+ fullpath: string, // allocated
+ name: string, // uses `fullpath` as underlying data
+ size: i64,
+ mode: File_Mode,
+ is_dir: bool,
+ creation_time: time.Time,
+ modification_time: time.Time,
+ access_time: time.Time,
+}
+
+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
+
+File_Mode_Dir :: File_Mode(1<<16)
+File_Mode_Named_Pipe :: File_Mode(1<<17)
+File_Mode_Device :: File_Mode(1<<18)
+File_Mode_Char_Device :: File_Mode(1<<19)
+File_Mode_Sym_Link :: File_Mode(1<<20)
diff --git a/core/os/stat_unix.odin b/core/os/old/stat_unix.odin
index 648987a07..648987a07 100644
--- a/core/os/stat_unix.odin
+++ b/core/os/old/stat_unix.odin
diff --git a/core/os/old/stat_windows.odin b/core/os/old/stat_windows.odin
new file mode 100644
index 000000000..662c9f9e6
--- /dev/null
+++ b/core/os/old/stat_windows.odin
@@ -0,0 +1,303 @@
+package os
+
+import "core:time"
+import "base:runtime"
+import win32 "core:sys/windows"
+
+@(private, require_results)
+full_path_from_name :: proc(name: string, allocator := context.allocator) -> (path: string, err: Errno) {
+ context.allocator = allocator
+
+ name := name
+ if name == "" {
+ name = "."
+ }
+ runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
+ p := win32.utf8_to_utf16(name, context.temp_allocator)
+ buf := make([dynamic]u16, 100)
+ defer delete(buf)
+ for {
+ n := win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
+ if n == 0 {
+ return "", get_last_error()
+ }
+ if n <= u32(len(buf)) {
+ return win32.utf16_to_utf8(buf[:n], allocator) or_else "", nil
+ }
+ resize(&buf, len(buf)*2)
+ }
+
+ return
+}
+
+@(private, require_results)
+_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
+
+ runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_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 = get_last_error()
+ 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 = get_last_error()
+ return
+ }
+ defer win32.CloseHandle(h)
+ return file_info_from_get_file_information_by_handle(name, h)
+}
+
+
+@(require_results)
+lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) {
+ attrs := win32.FILE_FLAG_BACKUP_SEMANTICS
+ attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT
+ return _stat(name, attrs, allocator)
+}
+
+@(require_results)
+stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) {
+ attrs := win32.FILE_FLAG_BACKUP_SEMANTICS
+ return _stat(name, attrs, allocator)
+}
+
+@(require_results)
+fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, err: Errno) {
+ if fd == 0 {
+ err = ERROR_INVALID_HANDLE
+ }
+ context.allocator = allocator
+
+ path := cleanpath_from_handle(fd) or_return
+ defer if err != nil {
+ delete(path)
+ }
+
+ h := win32.HANDLE(fd)
+ switch win32.GetFileType(h) {
+ case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR:
+ fi.name = basename(path)
+ fi.mode |= file_type_mode(h)
+ err = nil
+ case:
+ fi = file_info_from_get_file_information_by_handle(path, h) or_return
+ }
+ fi.fullpath = path
+ return
+}
+
+
+@(private, require_results)
+cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
+ buf := buf
+ N := 0
+ for c, i in buf {
+ if c == 0 { break }
+ N = i+1
+ }
+ buf = buf[:N]
+
+ if len(buf) >= 4 && buf[0] == '\\' && buf[1] == '\\' && buf[2] == '?' && buf[3] == '\\' {
+ buf = buf[4:]
+
+ /*
+ NOTE(Jeroen): Properly handle UNC paths.
+ We need to turn `\\?\UNC\synology.local` into `\\synology.local`.
+ */
+ if len(buf) >= 3 && buf[0] == 'U' && buf[1] == 'N' && buf[2] == 'C' {
+ buf = buf[2:]
+ buf[0] = '\\'
+ }
+ }
+ return buf
+}
+
+@(private, require_results)
+cleanpath_from_handle :: proc(fd: Handle) -> (s: string, err: Errno) {
+ runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
+ buf := cleanpath_from_handle_u16(fd, context.temp_allocator) or_return
+ return win32.utf16_to_utf8(buf, context.allocator)
+}
+@(private, require_results)
+cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ([]u16, Errno) {
+ if fd == 0 {
+ return nil, ERROR_INVALID_HANDLE
+ }
+ h := win32.HANDLE(fd)
+
+ n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0)
+ if n == 0 {
+ return nil, get_last_error()
+ }
+ buf := make([]u16, max(n, win32.DWORD(260))+1, allocator)
+ buf_len := win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), n, 0)
+ return buf[:buf_len], nil
+}
+@(private, require_results)
+cleanpath_from_buf :: proc(buf: []u16) -> string {
+ buf := buf
+ buf = cleanpath_strip_prefix(buf)
+ return win32.utf16_to_utf8(buf, context.allocator) or_else ""
+}
+
+@(private, require_results)
+basename :: proc(name: string) -> (base: string) {
+ name := name
+ if len(name) > 3 && name[:3] == `\\?` {
+ name = name[3:]
+ }
+
+ if len(name) == 2 && name[1] == ':' {
+ return "."
+ } else if len(name) > 2 && name[1] == ':' {
+ name = name[2:]
+ }
+ i := len(name)-1
+
+ for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i -= 1 {
+ name = name[:i]
+ }
+ for i -= 1; i >= 0; i -= 1 {
+ if name[i] == '/' || name[i] == '\\' {
+ name = name[i+1:]
+ break
+ }
+ }
+ return name
+}
+
+@(private, require_results)
+file_type_mode :: proc(h: win32.HANDLE) -> File_Mode {
+ switch win32.GetFileType(h) {
+ case win32.FILE_TYPE_PIPE:
+ return File_Mode_Named_Pipe
+ case win32.FILE_TYPE_CHAR:
+ return File_Mode_Device | File_Mode_Char_Device
+ }
+ return 0
+}
+
+
+@(private, require_results)
+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)
+windows_set_file_info_times :: proc(fi: ^File_Info, d: ^$T) {
+ 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))
+}
+
+@(private, require_results)
+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
+
+ windows_set_file_info_times(&fi, d)
+
+ fi.fullpath, e = full_path_from_name(name)
+ fi.name = basename(fi.fullpath)
+
+ return
+}
+
+@(private, require_results)
+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
+
+ windows_set_file_info_times(&fi, d)
+
+ fi.fullpath, e = full_path_from_name(name)
+ fi.name = basename(fi.fullpath)
+
+ return
+}
+
+@(private, require_results)
+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 := get_last_error()
+ return {}, err
+
+ }
+
+ ti: win32.FILE_ATTRIBUTE_TAG_INFO
+ if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) {
+ err := get_last_error()
+ if err != ERROR_INVALID_PARAMETER {
+ return {}, err
+ }
+ // Indicate this is a symlink on FAT file systems
+ ti.ReparseTag = 0
+ }
+
+ fi: File_Info
+
+ fi.fullpath = path
+ fi.name = basename(path)
+ fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
+
+ fi.mode |= file_mode_from_file_attributes(ti.FileAttributes, h, ti.ReparseTag)
+ fi.is_dir = fi.mode & File_Mode_Dir != 0
+
+ windows_set_file_info_times(&fi, &d)
+
+ return fi, nil
+}
diff --git a/core/os/stream.odin b/core/os/old/stream.odin
index f4e9bcdde..f4e9bcdde 100644
--- a/core/os/stream.odin
+++ b/core/os/old/stream.odin
diff --git a/core/os/os2/dir_windows.odin b/core/os/os2/dir_windows.odin
deleted file mode 100644
index a4dadca75..000000000
--- a/core/os/os2/dir_windows.odin
+++ /dev/null
@@ -1,144 +0,0 @@
-#+private
-package os2
-
-import "base:runtime"
-import "core:time"
-import win32 "core:sys/windows"
-
-@(private="file")
-find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
- // Ignore "." and ".."
- if d.cFileName[0] == '.' && d.cFileName[1] == 0 {
- return
- }
- if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 {
- return
- }
-
- temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
- path := concatenate({base_path, `\`, win32_wstring_to_utf8(cstring16(raw_data(d.cFileName[:])), temp_allocator) or_else ""}, allocator) or_return
-
- handle := win32.HANDLE(_open_internal(path, {.Read}, Permissions_Read_Write_All) or_else 0)
- defer win32.CloseHandle(handle)
-
- fi.fullpath = path
- fi.name = basename(path)
- fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
-
- fi.type, fi.mode = _file_type_mode_from_file_attributes(d.dwFileAttributes, handle, d.dwReserved0)
-
- 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))
-
- if file_id_info: win32.FILE_ID_INFO; handle != nil && win32.GetFileInformationByHandleEx(handle, .FileIdInfo, &file_id_info, size_of(file_id_info)) {
- #assert(size_of(fi.inode) == size_of(file_id_info.FileId))
- #assert(size_of(fi.inode) == 16)
- runtime.mem_copy_non_overlapping(&fi.inode, &file_id_info.FileId, 16)
- }
-
- return
-}
-
-Read_Directory_Iterator_Impl :: struct {
- find_data: win32.WIN32_FIND_DATAW,
- find_handle: win32.HANDLE,
- path: string,
- prev_fi: File_Info,
- no_more_files: bool,
-}
-
-
-@(require_results)
-_read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) {
- for !it.impl.no_more_files {
- err: Error
- file_info_delete(it.impl.prev_fi, file_allocator())
- it.impl.prev_fi = {}
-
- fi, err = find_data_to_file_info(it.impl.path, &it.impl.find_data, file_allocator())
- if err != nil {
- read_directory_iterator_set_error(it, it.impl.path, err)
- return
- }
-
- if fi.name != "" {
- it.impl.prev_fi = fi
- ok = true
- index = it.index
- it.index += 1
- }
-
- if !win32.FindNextFileW(it.impl.find_handle, &it.impl.find_data) {
- e := _get_platform_error()
- if pe, _ := is_platform_error(e); pe != i32(win32.ERROR_NO_MORE_FILES) {
- read_directory_iterator_set_error(it, it.impl.path, e)
- }
- it.impl.no_more_files = true
- }
- if ok {
- return
- }
- }
- return
-}
-
-_read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
- it.impl.no_more_files = false
-
- if f == nil || f.impl == nil {
- read_directory_iterator_set_error(it, "", .Invalid_File)
- return
- }
-
- it.f = f
- impl := (^File_Impl)(f.impl)
-
- // NOTE: Allow calling `init` to target a new directory with the same iterator - reset idx.
- if it.impl.find_handle != nil {
- win32.FindClose(it.impl.find_handle)
- }
- if it.impl.path != "" {
- delete(it.impl.path, file_allocator())
- }
-
- if !is_directory(impl.name) {
- read_directory_iterator_set_error(it, impl.name, .Invalid_Dir)
- return
- }
-
- wpath := string16(impl.wname)
- temp_allocator := TEMP_ALLOCATOR_GUARD({})
-
- wpath_search := make([]u16, len(wpath)+3, temp_allocator)
- copy(wpath_search, wpath)
- wpath_search[len(wpath)+0] = '\\'
- wpath_search[len(wpath)+1] = '*'
- wpath_search[len(wpath)+2] = 0
-
- it.impl.find_handle = win32.FindFirstFileW(cstring16(raw_data(wpath_search)), &it.impl.find_data)
- if it.impl.find_handle == win32.INVALID_HANDLE_VALUE {
- read_directory_iterator_set_error(it, impl.name, _get_platform_error())
- return
- }
- defer if it.err.err != nil {
- win32.FindClose(it.impl.find_handle)
- }
-
- err: Error
- it.impl.path, err = _cleanpath_from_buf(wpath, file_allocator())
- if err != nil {
- read_directory_iterator_set_error(it, impl.name, err)
- }
-
- return
-}
-
-_read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) {
- if it.f == nil {
- return
- }
- file_info_delete(it.impl.prev_fi, file_allocator())
- delete(it.impl.path, file_allocator())
- win32.FindClose(it.impl.find_handle)
-}
diff --git a/core/os/os2/env_windows.odin b/core/os/os2/env_windows.odin
deleted file mode 100644
index d389f8860..000000000
--- a/core/os/os2/env_windows.odin
+++ /dev/null
@@ -1,142 +0,0 @@
-#+private
-package os2
-
-import win32 "core:sys/windows"
-import "base:runtime"
-
-_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
- if key == "" {
- return
- }
- temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
- wkey, _ := win32_utf8_to_wstring(key, temp_allocator)
-
- n := win32.GetEnvironmentVariableW(wkey, nil, 0)
- if n == 0 {
- err := win32.GetLastError()
- if err == win32.ERROR_ENVVAR_NOT_FOUND {
- return "", false
- }
- return "", true
- }
-
- b := make([]u16, n+1, temp_allocator)
-
- n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
- if n == 0 {
- err := win32.GetLastError()
- if err == win32.ERROR_ENVVAR_NOT_FOUND {
- return "", false
- }
- return "", false
- }
-
- value = win32_utf16_to_utf8(string16(b[:n]), allocator) or_else ""
- found = true
- return
-}
-
-// This version of `lookup_env` doesn't allocate and instead requires the user to provide a buffer.
-// Note that it is limited to environment names and values of 512 utf-16 values each
-// due to the necessary utf-8 <> utf-16 conversion.
-@(require_results)
-_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, err: Error) {
- key_buf: [513]u16
- wkey := win32.utf8_to_wstring(key_buf[:], key)
- if wkey == nil {
- return "", .Buffer_Full
- }
-
- n2 := win32.GetEnvironmentVariableW(wkey, nil, 0)
- if n2 == 0 {
- return "", .Env_Var_Not_Found
- }
-
- val_buf: [513]u16
- n2 = win32.GetEnvironmentVariableW(wkey, raw_data(val_buf[:]), u32(len(val_buf[:])))
- if n2 == 0 {
- return "", .Env_Var_Not_Found
- } else if int(n2) > len(buf) {
- return "", .Buffer_Full
- }
-
- value = win32.utf16_to_utf8(buf, val_buf[:n2])
-
- return value, nil
-}
-_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf}
-
-_set_env :: proc(key, value: string) -> Error {
- temp_allocator := TEMP_ALLOCATOR_GUARD({})
- k := win32_utf8_to_wstring(key, temp_allocator) or_return
- v := win32_utf8_to_wstring(value, temp_allocator) or_return
-
- if !win32.SetEnvironmentVariableW(k, v) {
- return _get_platform_error()
- }
- return nil
-}
-
-_unset_env :: proc(key: string) -> bool {
- temp_allocator := TEMP_ALLOCATOR_GUARD({})
- k, _ := win32_utf8_to_wstring(key, temp_allocator)
- return bool(win32.SetEnvironmentVariableW(k, nil))
-}
-
-_clear_env :: proc() {
- temp_allocator := TEMP_ALLOCATOR_GUARD({})
- envs, _ := environ(temp_allocator)
- for env in envs {
- for j in 1..<len(env) {
- if env[j] == '=' {
- unset_env(env[0:j])
- break
- }
- }
- }
-}
-
-_environ :: proc(allocator: runtime.Allocator) -> (environ: []string, err: Error) {
- envs := win32.GetEnvironmentStringsW()
- if envs == nil {
- return
- }
- defer win32.FreeEnvironmentStringsW(envs)
-
- n := 0
- for from, i, p := 0, 0, envs; true; i += 1 {
- c := ([^]u16)(p)[i]
- if c == 0 {
- if i <= from {
- break
- }
- n += 1
- from = i + 1
- }
- }
-
- r := make([dynamic]string, 0, n, allocator) or_return
- defer if err != nil {
- for e in r {
- delete(e, allocator)
- }
- delete(r)
- }
- for from, i, p := 0, 0, envs; true; i += 1 {
- c := ([^]u16)(p)[i]
- if c == 0 {
- if i <= from {
- break
- }
- w := ([^]u16)(p)[from:i]
- s := win32_utf16_to_utf8(w, allocator) or_return
- append(&r, s)
- from = i + 1
- }
- }
-
- environ = r[:]
- return
-}
-
-
diff --git a/core/os/os2/errors.odin b/core/os/os2/errors.odin
deleted file mode 100644
index 508d824b3..000000000
--- a/core/os/os2/errors.odin
+++ /dev/null
@@ -1,147 +0,0 @@
-package os2
-
-import "core:io"
-import "base:runtime"
-
-/*
- General errors that are common within this package which cannot
- be categorized by `io.Error` nor `runtime.Allocator_Error`.
-*/
-General_Error :: enum u32 {
- None,
-
- Exist,
- Not_Exist,
-
- Timeout,
-
- Broken_Pipe,
-
- Invalid_File,
- Invalid_Dir,
- Invalid_Path,
- Invalid_Callback,
- Invalid_Command,
-
- Pattern_Has_Separator,
- Pattern_Syntax_Error, // Indicates an error in `glob` or `match` pattern.
-
- No_HOME_Variable,
- Env_Var_Not_Found,
-}
-
-// A platform specific error
-Platform_Error :: _Platform_Error
-
-/*
- `Error` is a union of different classes of errors that could be returned from procedures in this package.
-*/
-Error :: union #shared_nil {
- General_Error,
- io.Error,
- runtime.Allocator_Error,
- Platform_Error,
-}
-#assert(size_of(Error) == size_of(u64))
-
-ERROR_NONE :: Error{}
-
-
-// Attempts to convert an `Error` into a platform specific error as an integer. `ok` is false if not possible
-@(require_results)
-is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
- v := ferr.(Platform_Error) or_else {}
- return i32(v), i32(v) != 0
-}
-
-
-// Attempts to return the error `ferr` as a string without any allocation
-@(require_results)
-error_string :: proc(ferr: Error) -> string {
- if ferr == nil {
- return ""
- }
- switch e in ferr {
- case General_Error:
- switch e {
- case .None: return ""
- case .Exist: return "file already exists"
- case .Not_Exist: return "file does not exist"
- case .Timeout: return "i/o timeout"
- case .Broken_Pipe: return "Broken pipe"
- case .Invalid_File: return "invalid file"
- case .Invalid_Dir: return "invalid directory"
- case .Invalid_Path: return "invalid path"
- case .Invalid_Callback: return "invalid callback"
- case .Invalid_Command: return "invalid command"
- case .Pattern_Has_Separator: return "pattern has separator"
- case .Pattern_Syntax_Error: return "glob pattern syntax error"
- case .No_HOME_Variable: return "no $HOME variable"
- case .Env_Var_Not_Found: return "environment variable not found"
- }
- case io.Error:
- switch e {
- case .None: return ""
- case .EOF: return "eof"
- case .Unexpected_EOF: return "unexpected eof"
- case .Short_Write: return "short write"
- case .Invalid_Write: return "invalid write result"
- case .Short_Buffer: return "short buffer"
- case .No_Progress: return "multiple read calls return no data or error"
- case .Invalid_Whence: return "invalid whence"
- case .Invalid_Offset: return "invalid offset"
- case .Invalid_Unread: return "invalid unread"
- case .Negative_Read: return "negative read"
- case .Negative_Write: return "negative write"
- case .Negative_Count: return "negative count"
- case .Buffer_Full: return "buffer full"
- case .Permission_Denied: return "permission denied"
- case .Closed: return "file already closed"
- case .No_Size: return "file has no definite size"
- case .Unsupported: return "unsupported"
- case .Unknown: //
- }
- case runtime.Allocator_Error:
- switch e {
- case .None: return ""
- case .Out_Of_Memory: return "out of memory"
- case .Invalid_Pointer: return "invalid allocator pointer"
- case .Invalid_Argument: return "invalid allocator argument"
- case .Mode_Not_Implemented: return "allocator mode not implemented"
- }
- case Platform_Error:
- return _error_string(i32(e))
- }
-
- return "unknown error"
-}
-
-/*
- `print_error` is a utility procedure which will print an error `ferr` to a specified file `f`.
-*/
-print_error :: proc(f: ^File, ferr: Error, msg: string) {
- temp_allocator := TEMP_ALLOCATOR_GUARD({})
- err_str := error_string(ferr)
-
- // msg + ": " + err_str + '\n'
- length := len(msg) + 2 + len(err_str) + 1
- buf := make([]u8, length, temp_allocator)
-
- copy(buf, msg)
- buf[len(msg)] = ':'
- buf[len(msg) + 1] = ' '
- copy(buf[len(msg) + 2:], err_str)
- buf[length - 1] = '\n'
- write(f, buf)
-}
-
-
-
-// Attempts to convert an `Error` `ferr` into an `io.Error`
-@(private)
-error_to_io_error :: proc(ferr: Error) -> io.Error {
- if ferr == nil {
- return .None
- }
- return ferr.(io.Error) or_else .Unknown
-}
diff --git a/core/os/os2/stat.odin b/core/os/os2/stat.odin
deleted file mode 100644
index 0a9ac4e57..000000000
--- a/core/os/os2/stat.odin
+++ /dev/null
@@ -1,117 +0,0 @@
-package os2
-
-import "base:runtime"
-import "core:strings"
-import "core:time"
-
-Fstat_Callback :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error)
-
-/*
- `File_Info` describes a file and is returned from `stat`, `fstat`, and `lstat`.
-*/
-File_Info :: struct {
- fullpath: string, // fullpath of the file
- name: string, // base name of the file
-
- inode: u128, // might be zero if cannot be determined
- size: i64 `fmt:"M"`, // length in bytes for regular files; system-dependent for other file types
- mode: Permissions, // file permission flags
- type: File_Type,
-
- creation_time: time.Time,
- modification_time: time.Time,
- access_time: time.Time,
-}
-
-@(require_results)
-file_info_clone :: proc(fi: File_Info, allocator: runtime.Allocator) -> (cloned: File_Info, err: runtime.Allocator_Error) {
- cloned = fi
- cloned.fullpath = strings.clone(fi.fullpath, allocator) or_return
- _, cloned.name = split_path(cloned.fullpath)
- return
-}
-
-file_info_slice_delete :: proc(infos: []File_Info, allocator: runtime.Allocator) {
- #reverse for info in infos {
- file_info_delete(info, allocator)
- }
- delete(infos, allocator)
-}
-
-file_info_delete :: proc(fi: File_Info, allocator: runtime.Allocator) {
- delete(fi.fullpath, allocator)
-}
-
-@(require_results)
-fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) {
- if f == nil {
- return {}, nil
- } else if f.stream.procedure != nil {
- fi: File_Info
- data := ([^]byte)(&fi)[:size_of(fi)]
- _, err := f.stream.procedure(f, .Fstat, data, 0, nil, allocator)
- return fi, err
- }
- return {}, .Invalid_Callback
-}
-
-/*
- `stat` returns a `File_Info` describing the named file from the file system.
- The resulting `File_Info` must be deleted with `file_info_delete`.
-*/
-@(require_results)
-stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
- return _stat(name, allocator)
-}
-
-lstat :: stat_do_not_follow_links
-
-/*
- Returns a `File_Info` describing the named file from the file system.
- If the file is a symbolic link, the `File_Info` returns describes the symbolic link,
- rather than following the link.
- The resulting `File_Info` must be deleted with `file_info_delete`.
-*/
-@(require_results)
-stat_do_not_follow_links :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
- return _lstat(name, allocator)
-}
-
-
-/*
- Returns true if two `File_Info`s are equivalent.
-*/
-@(require_results)
-same_file :: proc(fi1, fi2: File_Info) -> bool {
- return _same_file(fi1, fi2)
-}
-
-
-last_write_time :: modification_time
-last_write_time_by_name :: modification_time_by_path
-
-/*
- Returns the modification time of the file `f`.
- The resolution of the timestamp is system-dependent.
-*/
-@(require_results)
-modification_time :: proc(f: ^File) -> (time.Time, Error) {
- temp_allocator := TEMP_ALLOCATOR_GUARD({})
- fi, err := fstat(f, temp_allocator)
- return fi.modification_time, err
-}
-
-/*
- Returns the modification time of the named file `path`.
- The resolution of the timestamp is system-dependent.
-*/
-@(require_results)
-modification_time_by_path :: proc(path: string) -> (time.Time, Error) {
- temp_allocator := TEMP_ALLOCATOR_GUARD({})
- fi, err := stat(path, temp_allocator)
- return fi.modification_time, err
-}
-
-is_reserved_name :: proc(path: string) -> bool {
- return _is_reserved_name(path)
-} \ No newline at end of file
diff --git a/core/os/os2/stat_windows.odin b/core/os/os2/stat_windows.odin
deleted file mode 100644
index 651029ac3..000000000
--- a/core/os/os2/stat_windows.odin
+++ /dev/null
@@ -1,393 +0,0 @@
-#+private
-package os2
-
-import "base:runtime"
-import "core:time"
-import "core:strings"
-import win32 "core:sys/windows"
-
-_fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
- if f == nil || (^File_Impl)(f.impl).fd == nil {
- return
- }
-
- path := _cleanpath_from_handle(f, allocator) or_return
-
- h := _handle(f)
- switch win32.GetFileType(h) {
- case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR:
- fi = File_Info {
- fullpath = path,
- name = basename(path),
- type = file_type(h),
- }
- return
- }
-
- return _file_info_from_get_file_information_by_handle(path, h, allocator)
-}
-
-_stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
- return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS, allocator)
-}
-
-_lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
- return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS|win32.FILE_FLAG_OPEN_REPARSE_POINT, allocator)
-}
-
-_same_file :: proc(fi1, fi2: File_Info) -> bool {
- return fi1.fullpath == fi2.fullpath
-}
-
-full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path: string, err: Error) {
- name := name
- if name == "" {
- name = "."
- }
-
- temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
-
- p := win32_utf8_to_utf16(name, temp_allocator) or_return
-
- n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil)
- if n == 0 {
- return "", _get_platform_error()
- }
- buf := make([]u16, n+1, temp_allocator)
- n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
- if n == 0 {
- return "", _get_platform_error()
- }
- return win32_utf16_to_utf8(buf[:n], allocator)
-}
-
-internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
- if len(name) == 0 {
- return {}, .Not_Exist
- }
- temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
-
- wname := _fix_long_path(name, temp_allocator) or_return
- 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
- fi = _file_info_from_win32_file_attribute_data(&fa, name, allocator) or_return
- if fi.type == .Undetermined {
- fi.type = _file_type_from_create_file(wname, create_file_attributes)
- }
- return
- }
-
- 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 = _get_platform_error()
- return
- }
- win32.FindClose(sh)
-
- fi = _file_info_from_win32_find_data(&fd, name, allocator) or_return
- if fi.type == .Undetermined {
- fi.type = _file_type_from_create_file(wname, create_file_attributes)
- }
- return
- }
-
- h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil)
- if h == win32.INVALID_HANDLE_VALUE {
- e = _get_platform_error()
- return
- }
- defer win32.CloseHandle(h)
- return _file_info_from_get_file_information_by_handle(name, h, allocator)
-}
-
-_cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
- buf := buf
- N := 0
- for c, i in buf {
- if c == 0 { break }
- N = i+1
- }
- buf = buf[:N]
-
- if len(buf) >= 4 {
- if buf[0] == '\\' &&
- buf[1] == '\\' &&
- buf[2] == '?' &&
- buf[3] == '\\' {
- buf = buf[4:]
- }
- }
- return buf
-}
-
-_cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (string, Error) {
- if f == nil {
- return "", nil
- }
- h := _handle(f)
-
- n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0)
- if n == 0 {
- return "", _get_platform_error()
- }
-
- temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
-
- buf := make([]u16, max(n, 260)+1, temp_allocator)
- n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0)
- return _cleanpath_from_buf(string16(buf[:n]), allocator)
-}
-
-_cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) {
- if f == nil {
- return nil, nil
- }
- h := _handle(f)
-
- n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0)
- if n == 0 {
- return nil, _get_platform_error()
- }
-
- temp_allocator := TEMP_ALLOCATOR_GUARD({})
-
- buf := make([]u16, max(n, 260)+1, temp_allocator)
- n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0)
- return _cleanpath_strip_prefix(buf[:n]), nil
-}
-
-_cleanpath_from_buf :: proc(buf: string16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
- buf := transmute([]u16)buf
- buf = _cleanpath_strip_prefix(buf)
- return win32_utf16_to_utf8(buf, allocator)
-}
-
-basename :: proc(name: string) -> (base: string) {
- name := name
- if len(name) > 3 && name[:3] == `\\?` {
- name = name[3:]
- }
-
- if len(name) == 2 && name[1] == ':' {
- return "."
- } else if len(name) > 2 && name[1] == ':' {
- name = name[2:]
- }
- i := len(name)-1
-
- for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i -= 1 {
- name = name[:i]
- }
- for i -= 1; i >= 0; i -= 1 {
- if name[i] == '/' || name[i] == '\\' {
- name = name[i+1:]
- break
- }
- }
- return name
-}
-
-file_type :: proc(h: win32.HANDLE) -> File_Type {
- switch win32.GetFileType(h) {
- case win32.FILE_TYPE_PIPE: return .Named_Pipe
- case win32.FILE_TYPE_CHAR: return .Character_Device
- case win32.FILE_TYPE_DISK: return .Regular
- }
- return .Undetermined
-}
-
-_file_type_from_create_file :: proc(wname: win32.wstring, create_file_attributes: u32) -> File_Type {
- h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil)
- if h == win32.INVALID_HANDLE_VALUE {
- return .Undetermined
- }
- defer win32.CloseHandle(h)
- return file_type(h)
-}
-
-_file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (type: File_Type, mode: Permissions) {
- if file_attributes & win32.FILE_ATTRIBUTE_READONLY != 0 {
- mode += Permissions_Write_All
- } else {
- mode += Permissions_Read_Write_All
- }
-
- is_sym := false
- if file_attributes & 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 {
- type = .Symlink
- } else if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
- type = .Directory
- mode += Permissions_Execute_All
- } else if h != nil {
- type = file_type(h)
- }
- return
-}
-
-// a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC)
-time_as_filetime :: #force_inline proc(t: time.Time) -> (ft: win32.LARGE_INTEGER) {
- win := u64(t._nsec / 100) + 116444736000000000
- return win32.LARGE_INTEGER(win)
-}
-
-filetime_as_time_li :: #force_inline proc(ft: win32.LARGE_INTEGER) -> (t: time.Time) {
- return {_nsec=(i64(ft) - 116444736000000000) * 100}
-}
-
-filetime_as_time_ft :: #force_inline proc(ft: win32.FILETIME) -> (t: time.Time) {
- return filetime_as_time_li(win32.LARGE_INTEGER(ft.dwLowDateTime) + win32.LARGE_INTEGER(ft.dwHighDateTime) << 32)
-}
-
-filetime_as_time :: proc{filetime_as_time_ft, filetime_as_time_li}
-
-_file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
- fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
- type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
- fi.type = type
- fi.mode |= mode
- fi.creation_time = filetime_as_time(d.ftCreationTime)
- fi.modification_time = filetime_as_time(d.ftLastWriteTime)
- fi.access_time = filetime_as_time(d.ftLastAccessTime)
- fi.fullpath, e = full_path_from_name(name, allocator)
- fi.name = basename(fi.fullpath)
- return
-}
-
-_file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
- fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
- type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
- fi.type = type
- fi.mode |= mode
- fi.creation_time = filetime_as_time(d.ftCreationTime)
- fi.modification_time = filetime_as_time(d.ftLastWriteTime)
- fi.access_time = filetime_as_time(d.ftLastAccessTime)
- fi.fullpath, e = full_path_from_name(name, allocator)
- fi.name = basename(fi.fullpath)
- return
-}
-
-_file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE, allocator: runtime.Allocator) -> (File_Info, Error) {
- d: win32.BY_HANDLE_FILE_INFORMATION
- if !win32.GetFileInformationByHandle(h, &d) {
- return {}, _get_platform_error()
-
- }
-
- ti: win32.FILE_ATTRIBUTE_TAG_INFO
- if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) {
- err := _get_platform_error()
- if perr, ok := is_platform_error(err); ok && perr != i32(win32.ERROR_INVALID_PARAMETER) {
- return {}, err
- }
- // Indicate this is a symlink on FAT file systems
- ti.ReparseTag = 0
- }
- fi: File_Info
- fi.fullpath = path
- fi.name = basename(path)
- fi.inode = u128(u64(d.nFileIndexHigh)<<32 + u64(d.nFileIndexLow))
- fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
- type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, h, 0)
- fi.type = type
- fi.mode |= mode
- fi.creation_time = filetime_as_time(d.ftCreationTime)
- fi.modification_time = filetime_as_time(d.ftLastWriteTime)
- fi.access_time = filetime_as_time(d.ftLastAccessTime)
- return fi, nil
-}
-
-reserved_names := [?]string{
- "CON", "PRN", "AUX", "NUL",
- "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
- "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
-}
-
-_is_reserved_name :: proc(path: string) -> bool {
- if len(path) == 0 {
- return false
- }
- for reserved in reserved_names {
- if strings.equal_fold(path, reserved) {
- return true
- }
- }
- return false
-}
-
-_volume_name_len :: proc(path: string) -> (length: int) {
- if len(path) < 2 {
- return 0
- }
-
- if path[1] == ':' {
- switch path[0] {
- case 'a'..='z', 'A'..='Z':
- return 2
- }
- }
-
- /*
- See: URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
- Further allowed paths can be of the form of:
- - \\server\share or \\server\share\more\path
- - \\?\C:\...
- - \\.\PhysicalDriveX
- */
- // Any remaining kind of path has to start with two slashes.
- if !_is_path_separator(path[0]) || !_is_path_separator(path[1]) {
- return 0
- }
-
- // Device path. The volume name is the whole string
- if len(path) >= 5 && path[2] == '.' && _is_path_separator(path[3]) {
- return len(path)
- }
-
- // We're a UNC share `\\host\share`, file namespace `\\?\C:` or UNC in file namespace `\\?\\host\share`
- prefix := 2
-
- // File namespace.
- if len(path) >= 5 && path[2] == '?' && _is_path_separator(path[3]) {
- if _is_path_separator(path[4]) {
- // `\\?\\` UNC path in file namespace
- prefix = 5
- }
-
- if len(path) >= 6 && path[5] == ':' {
- switch path[4] {
- case 'a'..='z', 'A'..='Z':
- return 6
- case:
- return 0
- }
- }
- }
-
- // UNC path, minimum version of the volume is `\\h\s` for host, share.
- // Can also contain an IP address in the host position.
- slash_count := 0
- for i in prefix..<len(path) {
- // Host needs to be at least 1 character
- if _is_path_separator(path[i]) && i > 0 {
- slash_count += 1
-
- if slash_count == 2 {
- return i
- }
- }
- }
-
- return len(path)
-} \ No newline at end of file
diff --git a/core/os/os2/path.odin b/core/os/path.odin
index ac18b7562..ac18b7562 100644
--- a/core/os/os2/path.odin
+++ b/core/os/path.odin
diff --git a/core/os/os2/path_darwin.odin b/core/os/path_darwin.odin
index 65aaf1e95..65aaf1e95 100644
--- a/core/os/os2/path_darwin.odin
+++ b/core/os/path_darwin.odin
diff --git a/core/os/os2/path_freebsd.odin b/core/os/path_freebsd.odin
index e7e4f63c9..e7e4f63c9 100644
--- a/core/os/os2/path_freebsd.odin
+++ b/core/os/path_freebsd.odin
diff --git a/core/os/os2/path_js.odin b/core/os/path_js.odin
index 0c0d1424b..0c0d1424b 100644
--- a/core/os/os2/path_js.odin
+++ b/core/os/path_js.odin
diff --git a/core/os/os2/path_linux.odin b/core/os/path_linux.odin
index 1c9927843..1c9927843 100644
--- a/core/os/os2/path_linux.odin
+++ b/core/os/path_linux.odin
diff --git a/core/os/os2/path_netbsd.odin b/core/os/path_netbsd.odin
index 815102dea..815102dea 100644
--- a/core/os/os2/path_netbsd.odin
+++ b/core/os/path_netbsd.odin
diff --git a/core/os/os2/path_openbsd.odin b/core/os/path_openbsd.odin
index cbc0346d4..cbc0346d4 100644
--- a/core/os/os2/path_openbsd.odin
+++ b/core/os/path_openbsd.odin
diff --git a/core/os/os2/path_posix.odin b/core/os/path_posix.odin
index 173cb6b6d..173cb6b6d 100644
--- a/core/os/os2/path_posix.odin
+++ b/core/os/path_posix.odin
diff --git a/core/os/os2/path_posixfs.odin b/core/os/path_posixfs.odin
index 0736e73d1..0736e73d1 100644
--- a/core/os/os2/path_posixfs.odin
+++ b/core/os/path_posixfs.odin
diff --git a/core/os/os2/path_wasi.odin b/core/os/path_wasi.odin
index f26e16158..f26e16158 100644
--- a/core/os/os2/path_wasi.odin
+++ b/core/os/path_wasi.odin
diff --git a/core/os/os2/path_windows.odin b/core/os/path_windows.odin
index 275fe3e18..275fe3e18 100644
--- a/core/os/os2/path_windows.odin
+++ b/core/os/path_windows.odin
diff --git a/core/os/os2/pipe.odin b/core/os/pipe.odin
index 5d3e8368e..5d3e8368e 100644
--- a/core/os/os2/pipe.odin
+++ b/core/os/pipe.odin
diff --git a/core/os/os2/pipe_js.odin b/core/os/pipe_js.odin
index 253228f86..253228f86 100644
--- a/core/os/os2/pipe_js.odin
+++ b/core/os/pipe_js.odin
diff --git a/core/os/os2/pipe_linux.odin b/core/os/pipe_linux.odin
index bb4456e1c..bb4456e1c 100644
--- a/core/os/os2/pipe_linux.odin
+++ b/core/os/pipe_linux.odin
diff --git a/core/os/os2/pipe_posix.odin b/core/os/pipe_posix.odin
index 7c07bc068..7c07bc068 100644
--- a/core/os/os2/pipe_posix.odin
+++ b/core/os/pipe_posix.odin
diff --git a/core/os/os2/pipe_wasi.odin b/core/os/pipe_wasi.odin
index 19c11b51d..19c11b51d 100644
--- a/core/os/os2/pipe_wasi.odin
+++ b/core/os/pipe_wasi.odin
diff --git a/core/os/os2/pipe_windows.odin b/core/os/pipe_windows.odin
index d6dc47c9c..d6dc47c9c 100644
--- a/core/os/os2/pipe_windows.odin
+++ b/core/os/pipe_windows.odin
diff --git a/core/os/os2/process.odin b/core/os/process.odin
index e4fecf2a5..e4fecf2a5 100644
--- a/core/os/os2/process.odin
+++ b/core/os/process.odin
diff --git a/core/os/os2/process_freebsd.odin b/core/os/process_freebsd.odin
index 8a31eb62c..8a31eb62c 100644
--- a/core/os/os2/process_freebsd.odin
+++ b/core/os/process_freebsd.odin
diff --git a/core/os/os2/process_js.odin b/core/os/process_js.odin
index a59a79d45..a59a79d45 100644
--- a/core/os/os2/process_js.odin
+++ b/core/os/process_js.odin
diff --git a/core/os/os2/process_linux.odin b/core/os/process_linux.odin
index 4afd9f3fc..4afd9f3fc 100644
--- a/core/os/os2/process_linux.odin
+++ b/core/os/process_linux.odin
diff --git a/core/os/os2/process_netbsd.odin b/core/os/process_netbsd.odin
index b46a58e58..b46a58e58 100644
--- a/core/os/os2/process_netbsd.odin
+++ b/core/os/process_netbsd.odin
diff --git a/core/os/os2/process_openbsd.odin b/core/os/process_openbsd.odin
index 9c6605952..9c6605952 100644
--- a/core/os/os2/process_openbsd.odin
+++ b/core/os/process_openbsd.odin
diff --git a/core/os/os2/process_posix.odin b/core/os/process_posix.odin
index a48e44900..a48e44900 100644
--- a/core/os/os2/process_posix.odin
+++ b/core/os/process_posix.odin
diff --git a/core/os/os2/process_posix_darwin.odin b/core/os/process_posix_darwin.odin
index 934d23711..934d23711 100644
--- a/core/os/os2/process_posix_darwin.odin
+++ b/core/os/process_posix_darwin.odin
diff --git a/core/os/os2/process_posix_other.odin b/core/os/process_posix_other.odin
index 65da3e9e2..65da3e9e2 100644
--- a/core/os/os2/process_posix_other.odin
+++ b/core/os/process_posix_other.odin
diff --git a/core/os/os2/process_wasi.odin b/core/os/process_wasi.odin
index efb2c0228..efb2c0228 100644
--- a/core/os/os2/process_wasi.odin
+++ b/core/os/process_wasi.odin
diff --git a/core/os/os2/process_windows.odin b/core/os/process_windows.odin
index b2c87c4f4..b2c87c4f4 100644
--- a/core/os/os2/process_windows.odin
+++ b/core/os/process_windows.odin
diff --git a/core/os/stat.odin b/core/os/stat.odin
index 21a4961d1..0a9ac4e57 100644
--- a/core/os/stat.odin
+++ b/core/os/stat.odin
@@ -1,33 +1,117 @@
-package os
+package os2
+import "base:runtime"
+import "core:strings"
import "core:time"
+Fstat_Callback :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error)
+
+/*
+ `File_Info` describes a file and is returned from `stat`, `fstat`, and `lstat`.
+*/
File_Info :: struct {
- fullpath: string, // allocated
- name: string, // uses `fullpath` as underlying data
- size: i64,
- mode: File_Mode,
- is_dir: bool,
+ fullpath: string, // fullpath of the file
+ name: string, // base name of the file
+
+ inode: u128, // might be zero if cannot be determined
+ size: i64 `fmt:"M"`, // length in bytes for regular files; system-dependent for other file types
+ mode: Permissions, // file permission flags
+ type: File_Type,
+
creation_time: time.Time,
modification_time: time.Time,
access_time: time.Time,
}
-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)
+@(require_results)
+file_info_clone :: proc(fi: File_Info, allocator: runtime.Allocator) -> (cloned: File_Info, err: runtime.Allocator_Error) {
+ cloned = fi
+ cloned.fullpath = strings.clone(fi.fullpath, allocator) or_return
+ _, cloned.name = split_path(cloned.fullpath)
+ return
+}
+
+file_info_slice_delete :: proc(infos: []File_Info, allocator: runtime.Allocator) {
+ #reverse for info in infos {
+ file_info_delete(info, allocator)
}
delete(infos, allocator)
}
-file_info_delete :: proc(fi: File_Info, allocator := context.allocator) {
+file_info_delete :: proc(fi: File_Info, allocator: runtime.Allocator) {
delete(fi.fullpath, allocator)
}
-File_Mode :: distinct u32
+@(require_results)
+fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) {
+ if f == nil {
+ return {}, nil
+ } else if f.stream.procedure != nil {
+ fi: File_Info
+ data := ([^]byte)(&fi)[:size_of(fi)]
+ _, err := f.stream.procedure(f, .Fstat, data, 0, nil, allocator)
+ return fi, err
+ }
+ return {}, .Invalid_Callback
+}
+
+/*
+ `stat` returns a `File_Info` describing the named file from the file system.
+ The resulting `File_Info` must be deleted with `file_info_delete`.
+*/
+@(require_results)
+stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
+ return _stat(name, allocator)
+}
+
+lstat :: stat_do_not_follow_links
+
+/*
+ Returns a `File_Info` describing the named file from the file system.
+ If the file is a symbolic link, the `File_Info` returns describes the symbolic link,
+ rather than following the link.
+ The resulting `File_Info` must be deleted with `file_info_delete`.
+*/
+@(require_results)
+stat_do_not_follow_links :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
+ return _lstat(name, allocator)
+}
+
+
+/*
+ Returns true if two `File_Info`s are equivalent.
+*/
+@(require_results)
+same_file :: proc(fi1, fi2: File_Info) -> bool {
+ return _same_file(fi1, fi2)
+}
+
+
+last_write_time :: modification_time
+last_write_time_by_name :: modification_time_by_path
+
+/*
+ Returns the modification time of the file `f`.
+ The resolution of the timestamp is system-dependent.
+*/
+@(require_results)
+modification_time :: proc(f: ^File) -> (time.Time, Error) {
+ temp_allocator := TEMP_ALLOCATOR_GUARD({})
+ fi, err := fstat(f, temp_allocator)
+ return fi.modification_time, err
+}
+
+/*
+ Returns the modification time of the named file `path`.
+ The resolution of the timestamp is system-dependent.
+*/
+@(require_results)
+modification_time_by_path :: proc(path: string) -> (time.Time, Error) {
+ temp_allocator := TEMP_ALLOCATOR_GUARD({})
+ fi, err := stat(path, temp_allocator)
+ return fi.modification_time, err
+}
-File_Mode_Dir :: File_Mode(1<<16)
-File_Mode_Named_Pipe :: File_Mode(1<<17)
-File_Mode_Device :: File_Mode(1<<18)
-File_Mode_Char_Device :: File_Mode(1<<19)
-File_Mode_Sym_Link :: File_Mode(1<<20)
+is_reserved_name :: proc(path: string) -> bool {
+ return _is_reserved_name(path)
+} \ No newline at end of file
diff --git a/core/os/os2/stat_js.odin b/core/os/stat_js.odin
index e37864936..e37864936 100644
--- a/core/os/os2/stat_js.odin
+++ b/core/os/stat_js.odin
diff --git a/core/os/os2/stat_linux.odin b/core/os/stat_linux.odin
index dc5bccb54..dc5bccb54 100644
--- a/core/os/os2/stat_linux.odin
+++ b/core/os/stat_linux.odin
diff --git a/core/os/os2/stat_posix.odin b/core/os/stat_posix.odin
index e401ffe40..e401ffe40 100644
--- a/core/os/os2/stat_posix.odin
+++ b/core/os/stat_posix.odin
diff --git a/core/os/os2/stat_wasi.odin b/core/os/stat_wasi.odin
index f15479e22..f15479e22 100644
--- a/core/os/os2/stat_wasi.odin
+++ b/core/os/stat_wasi.odin
diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin
index 662c9f9e6..651029ac3 100644
--- a/core/os/stat_windows.odin
+++ b/core/os/stat_windows.odin
@@ -1,51 +1,82 @@
-package os
+#+private
+package os2
-import "core:time"
import "base:runtime"
+import "core:time"
+import "core:strings"
import win32 "core:sys/windows"
-@(private, require_results)
-full_path_from_name :: proc(name: string, allocator := context.allocator) -> (path: string, err: Errno) {
- context.allocator = allocator
-
- name := name
- if name == "" {
- name = "."
+_fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
+ if f == nil || (^File_Impl)(f.impl).fd == nil {
+ return
}
- runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
- p := win32.utf8_to_utf16(name, context.temp_allocator)
- buf := make([dynamic]u16, 100)
- defer delete(buf)
- for {
- n := win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
- if n == 0 {
- return "", get_last_error()
- }
- if n <= u32(len(buf)) {
- return win32.utf16_to_utf8(buf[:n], allocator) or_else "", nil
+
+ path := _cleanpath_from_handle(f, allocator) or_return
+
+ h := _handle(f)
+ switch win32.GetFileType(h) {
+ case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR:
+ fi = File_Info {
+ fullpath = path,
+ name = basename(path),
+ type = file_type(h),
}
- resize(&buf, len(buf)*2)
+ return
}
- return
+ return _file_info_from_get_file_information_by_handle(path, h, allocator)
}
-@(private, require_results)
-_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
+_stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
+ return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS, allocator)
+}
+
+_lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
+ return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS|win32.FILE_FLAG_OPEN_REPARSE_POINT, allocator)
+}
+
+_same_file :: proc(fi1, fi2: File_Info) -> bool {
+ return fi1.fullpath == fi2.fullpath
+}
+
+full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path: string, err: Error) {
+ name := name
+ if name == "" {
+ name = "."
}
- context.allocator = allocator
+ temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
+
+ p := win32_utf8_to_utf16(name, temp_allocator) or_return
+
+ n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil)
+ if n == 0 {
+ return "", _get_platform_error()
+ }
+ buf := make([]u16, n+1, temp_allocator)
+ n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
+ if n == 0 {
+ return "", _get_platform_error()
+ }
+ return win32_utf16_to_utf8(buf[:n], allocator)
+}
- runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
+internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
+ if len(name) == 0 {
+ return {}, .Not_Exist
+ }
+ temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
- wname := win32.utf8_to_wstring(fix_long_path(name), context.temp_allocator)
+ wname := _fix_long_path(name, temp_allocator) or_return
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)
+ fi = _file_info_from_win32_file_attribute_data(&fa, name, allocator) or_return
+ if fi.type == .Undetermined {
+ fi.type = _file_type_from_create_file(wname, create_file_attributes)
+ }
+ return
}
err := 0 if ok else win32.GetLastError()
@@ -54,65 +85,28 @@ _stat :: proc(name: string, create_file_attributes: u32, allocator := context.al
fd: win32.WIN32_FIND_DATAW
sh := win32.FindFirstFileW(wname, &fd)
if sh == win32.INVALID_HANDLE_VALUE {
- e = get_last_error()
+ e = _get_platform_error()
return
}
win32.FindClose(sh)
- return file_info_from_win32_find_data(&fd, name)
+ fi = _file_info_from_win32_find_data(&fd, name, allocator) or_return
+ if fi.type == .Undetermined {
+ fi.type = _file_type_from_create_file(wname, create_file_attributes)
+ }
+ return
}
h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil)
if h == win32.INVALID_HANDLE_VALUE {
- e = get_last_error()
+ e = _get_platform_error()
return
}
defer win32.CloseHandle(h)
- return file_info_from_get_file_information_by_handle(name, h)
+ return _file_info_from_get_file_information_by_handle(name, h, allocator)
}
-
-@(require_results)
-lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) {
- attrs := win32.FILE_FLAG_BACKUP_SEMANTICS
- attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT
- return _stat(name, attrs, allocator)
-}
-
-@(require_results)
-stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Errno) {
- attrs := win32.FILE_FLAG_BACKUP_SEMANTICS
- return _stat(name, attrs, allocator)
-}
-
-@(require_results)
-fstat :: proc(fd: Handle, allocator := context.allocator) -> (fi: File_Info, err: Errno) {
- if fd == 0 {
- err = ERROR_INVALID_HANDLE
- }
- context.allocator = allocator
-
- path := cleanpath_from_handle(fd) or_return
- defer if err != nil {
- delete(path)
- }
-
- h := win32.HANDLE(fd)
- switch win32.GetFileType(h) {
- case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR:
- fi.name = basename(path)
- fi.mode |= file_type_mode(h)
- err = nil
- case:
- fi = file_info_from_get_file_information_by_handle(path, h) or_return
- }
- fi.fullpath = path
- return
-}
-
-
-@(private, require_results)
-cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
+_cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
buf := buf
N := 0
for c, i in buf {
@@ -121,50 +115,59 @@ cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
}
buf = buf[:N]
- if len(buf) >= 4 && buf[0] == '\\' && buf[1] == '\\' && buf[2] == '?' && buf[3] == '\\' {
- buf = buf[4:]
-
- /*
- NOTE(Jeroen): Properly handle UNC paths.
- We need to turn `\\?\UNC\synology.local` into `\\synology.local`.
- */
- if len(buf) >= 3 && buf[0] == 'U' && buf[1] == 'N' && buf[2] == 'C' {
- buf = buf[2:]
- buf[0] = '\\'
+ if len(buf) >= 4 {
+ if buf[0] == '\\' &&
+ buf[1] == '\\' &&
+ buf[2] == '?' &&
+ buf[3] == '\\' {
+ buf = buf[4:]
}
}
return buf
}
-@(private, require_results)
-cleanpath_from_handle :: proc(fd: Handle) -> (s: string, err: Errno) {
- runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
- buf := cleanpath_from_handle_u16(fd, context.temp_allocator) or_return
- return win32.utf16_to_utf8(buf, context.allocator)
+_cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (string, Error) {
+ if f == nil {
+ return "", nil
+ }
+ h := _handle(f)
+
+ n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0)
+ if n == 0 {
+ return "", _get_platform_error()
+ }
+
+ temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
+
+ buf := make([]u16, max(n, 260)+1, temp_allocator)
+ n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0)
+ return _cleanpath_from_buf(string16(buf[:n]), allocator)
}
-@(private, require_results)
-cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ([]u16, Errno) {
- if fd == 0 {
- return nil, ERROR_INVALID_HANDLE
+
+_cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) {
+ if f == nil {
+ return nil, nil
}
- h := win32.HANDLE(fd)
+ h := _handle(f)
n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0)
if n == 0 {
- return nil, get_last_error()
+ return nil, _get_platform_error()
}
- buf := make([]u16, max(n, win32.DWORD(260))+1, allocator)
- buf_len := win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), n, 0)
- return buf[:buf_len], nil
+
+ temp_allocator := TEMP_ALLOCATOR_GUARD({})
+
+ buf := make([]u16, max(n, 260)+1, temp_allocator)
+ n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0)
+ return _cleanpath_strip_prefix(buf[:n]), nil
}
-@(private, require_results)
-cleanpath_from_buf :: proc(buf: []u16) -> string {
- buf := buf
- buf = cleanpath_strip_prefix(buf)
- return win32.utf16_to_utf8(buf, context.allocator) or_else ""
+
+_cleanpath_from_buf :: proc(buf: string16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
+ buf := transmute([]u16)buf
+ buf = _cleanpath_strip_prefix(buf)
+ return win32_utf16_to_utf8(buf, allocator)
}
-@(private, require_results)
basename :: proc(name: string) -> (base: string) {
name := name
if len(name) > 3 && name[:3] == `\\?` {
@@ -190,114 +193,201 @@ basename :: proc(name: string) -> (base: string) {
return name
}
-@(private, require_results)
-file_type_mode :: proc(h: win32.HANDLE) -> File_Mode {
+file_type :: proc(h: win32.HANDLE) -> File_Type {
switch win32.GetFileType(h) {
- case win32.FILE_TYPE_PIPE:
- return File_Mode_Named_Pipe
- case win32.FILE_TYPE_CHAR:
- return File_Mode_Device | File_Mode_Char_Device
+ case win32.FILE_TYPE_PIPE: return .Named_Pipe
+ case win32.FILE_TYPE_CHAR: return .Character_Device
+ case win32.FILE_TYPE_DISK: return .Regular
}
- return 0
+ return .Undetermined
}
+_file_type_from_create_file :: proc(wname: win32.wstring, create_file_attributes: u32) -> File_Type {
+ h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil)
+ if h == win32.INVALID_HANDLE_VALUE {
+ return .Undetermined
+ }
+ defer win32.CloseHandle(h)
+ return file_type(h)
+}
-@(private, require_results)
-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
+_file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (type: File_Type, mode: Permissions) {
+ if file_attributes & win32.FILE_ATTRIBUTE_READONLY != 0 {
+ mode += Permissions_Write_All
} else {
- mode |= 0o666
+ mode += Permissions_Read_Write_All
}
is_sym := false
- if FileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
+ if file_attributes & 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)
- }
+ type = .Symlink
+ } else if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
+ type = .Directory
+ mode += Permissions_Execute_All
+ } else if h != nil {
+ type = file_type(h)
}
-
return
}
-@(private)
-windows_set_file_info_times :: proc(fi: ^File_Info, d: ^$T) {
- 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))
+// a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC)
+time_as_filetime :: #force_inline proc(t: time.Time) -> (ft: win32.LARGE_INTEGER) {
+ win := u64(t._nsec / 100) + 116444736000000000
+ return win32.LARGE_INTEGER(win)
}
-@(private, require_results)
-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)
+filetime_as_time_li :: #force_inline proc(ft: win32.LARGE_INTEGER) -> (t: time.Time) {
+ return {_nsec=(i64(ft) - 116444736000000000) * 100}
+}
- fi.mode |= file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
- fi.is_dir = fi.mode & File_Mode_Dir != 0
+filetime_as_time_ft :: #force_inline proc(ft: win32.FILETIME) -> (t: time.Time) {
+ return filetime_as_time_li(win32.LARGE_INTEGER(ft.dwLowDateTime) + win32.LARGE_INTEGER(ft.dwHighDateTime) << 32)
+}
- windows_set_file_info_times(&fi, d)
+filetime_as_time :: proc{filetime_as_time_ft, filetime_as_time_li}
- fi.fullpath, e = full_path_from_name(name)
+_file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
+ fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
+ type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
+ fi.type = type
+ fi.mode |= mode
+ fi.creation_time = filetime_as_time(d.ftCreationTime)
+ fi.modification_time = filetime_as_time(d.ftLastWriteTime)
+ fi.access_time = filetime_as_time(d.ftLastAccessTime)
+ fi.fullpath, e = full_path_from_name(name, allocator)
fi.name = basename(fi.fullpath)
-
return
}
-@(private, require_results)
-file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) -> (fi: File_Info, e: Errno) {
+_file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
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
-
- windows_set_file_info_times(&fi, d)
-
- fi.fullpath, e = full_path_from_name(name)
+ type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
+ fi.type = type
+ fi.mode |= mode
+ fi.creation_time = filetime_as_time(d.ftCreationTime)
+ fi.modification_time = filetime_as_time(d.ftLastWriteTime)
+ fi.access_time = filetime_as_time(d.ftLastAccessTime)
+ fi.fullpath, e = full_path_from_name(name, allocator)
fi.name = basename(fi.fullpath)
-
return
}
-@(private, require_results)
-file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Errno) {
+_file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE, allocator: runtime.Allocator) -> (File_Info, Error) {
d: win32.BY_HANDLE_FILE_INFORMATION
if !win32.GetFileInformationByHandle(h, &d) {
- err := get_last_error()
- return {}, err
+ return {}, _get_platform_error()
}
ti: win32.FILE_ATTRIBUTE_TAG_INFO
if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) {
- err := get_last_error()
- if err != ERROR_INVALID_PARAMETER {
+ err := _get_platform_error()
+ if perr, ok := is_platform_error(err); ok && perr != i32(win32.ERROR_INVALID_PARAMETER) {
return {}, err
}
// Indicate this is a symlink on FAT file systems
ti.ReparseTag = 0
}
-
fi: File_Info
-
fi.fullpath = path
fi.name = basename(path)
- fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
-
- fi.mode |= file_mode_from_file_attributes(ti.FileAttributes, h, ti.ReparseTag)
- fi.is_dir = fi.mode & File_Mode_Dir != 0
+ fi.inode = u128(u64(d.nFileIndexHigh)<<32 + u64(d.nFileIndexLow))
+ fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
+ type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, h, 0)
+ fi.type = type
+ fi.mode |= mode
+ fi.creation_time = filetime_as_time(d.ftCreationTime)
+ fi.modification_time = filetime_as_time(d.ftLastWriteTime)
+ fi.access_time = filetime_as_time(d.ftLastAccessTime)
+ return fi, nil
+}
- windows_set_file_info_times(&fi, &d)
+reserved_names := [?]string{
+ "CON", "PRN", "AUX", "NUL",
+ "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
+ "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
+}
- return fi, nil
+_is_reserved_name :: proc(path: string) -> bool {
+ if len(path) == 0 {
+ return false
+ }
+ for reserved in reserved_names {
+ if strings.equal_fold(path, reserved) {
+ return true
+ }
+ }
+ return false
}
+
+_volume_name_len :: proc(path: string) -> (length: int) {
+ if len(path) < 2 {
+ return 0
+ }
+
+ if path[1] == ':' {
+ switch path[0] {
+ case 'a'..='z', 'A'..='Z':
+ return 2
+ }
+ }
+
+ /*
+ See: URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+ Further allowed paths can be of the form of:
+ - \\server\share or \\server\share\more\path
+ - \\?\C:\...
+ - \\.\PhysicalDriveX
+ */
+ // Any remaining kind of path has to start with two slashes.
+ if !_is_path_separator(path[0]) || !_is_path_separator(path[1]) {
+ return 0
+ }
+
+ // Device path. The volume name is the whole string
+ if len(path) >= 5 && path[2] == '.' && _is_path_separator(path[3]) {
+ return len(path)
+ }
+
+ // We're a UNC share `\\host\share`, file namespace `\\?\C:` or UNC in file namespace `\\?\\host\share`
+ prefix := 2
+
+ // File namespace.
+ if len(path) >= 5 && path[2] == '?' && _is_path_separator(path[3]) {
+ if _is_path_separator(path[4]) {
+ // `\\?\\` UNC path in file namespace
+ prefix = 5
+ }
+
+ if len(path) >= 6 && path[5] == ':' {
+ switch path[4] {
+ case 'a'..='z', 'A'..='Z':
+ return 6
+ case:
+ return 0
+ }
+ }
+ }
+
+ // UNC path, minimum version of the volume is `\\h\s` for host, share.
+ // Can also contain an IP address in the host position.
+ slash_count := 0
+ for i in prefix..<len(path) {
+ // Host needs to be at least 1 character
+ if _is_path_separator(path[i]) && i > 0 {
+ slash_count += 1
+
+ if slash_count == 2 {
+ return i
+ }
+ }
+ }
+
+ return len(path)
+} \ No newline at end of file
diff --git a/core/os/os2/temp_file.odin b/core/os/temp_file.odin
index 2c0236428..2c0236428 100644
--- a/core/os/os2/temp_file.odin
+++ b/core/os/temp_file.odin
diff --git a/core/os/os2/temp_file_js.odin b/core/os/temp_file_js.odin
index e1f2b3d95..e1f2b3d95 100644
--- a/core/os/os2/temp_file_js.odin
+++ b/core/os/temp_file_js.odin
diff --git a/core/os/os2/temp_file_linux.odin b/core/os/temp_file_linux.odin
index 310720cbe..310720cbe 100644
--- a/core/os/os2/temp_file_linux.odin
+++ b/core/os/temp_file_linux.odin
diff --git a/core/os/os2/temp_file_posix.odin b/core/os/temp_file_posix.odin
index b44ea13a7..b44ea13a7 100644
--- a/core/os/os2/temp_file_posix.odin
+++ b/core/os/temp_file_posix.odin
diff --git a/core/os/os2/temp_file_wasi.odin b/core/os/temp_file_wasi.odin
index d5628d300..d5628d300 100644
--- a/core/os/os2/temp_file_wasi.odin
+++ b/core/os/temp_file_wasi.odin
diff --git a/core/os/os2/temp_file_windows.odin b/core/os/temp_file_windows.odin
index 91ea284a1..91ea284a1 100644
--- a/core/os/os2/temp_file_windows.odin
+++ b/core/os/temp_file_windows.odin
diff --git a/core/os/os2/user.odin b/core/os/user.odin
index e2a4ec4d0..e2a4ec4d0 100644
--- a/core/os/os2/user.odin
+++ b/core/os/user.odin
diff --git a/core/os/os2/user_posix.odin b/core/os/user_posix.odin
index fa173f129..fa173f129 100644
--- a/core/os/os2/user_posix.odin
+++ b/core/os/user_posix.odin
diff --git a/core/os/os2/user_windows.odin b/core/os/user_windows.odin
index 75d0ba6ac..75d0ba6ac 100644
--- a/core/os/os2/user_windows.odin
+++ b/core/os/user_windows.odin
diff --git a/core/path/filepath/match.odin b/core/path/filepath/match.odin
index 00f5bcc3f..178d5f986 100644
--- a/core/path/filepath/match.odin
+++ b/core/path/filepath/match.odin
@@ -2,7 +2,7 @@
#+build !js
package filepath
-import os "core:os/os2"
+import "core:os"
// match states whether "name" matches the shell pattern
// Pattern syntax is:
diff --git a/core/path/filepath/path.odin b/core/path/filepath/path.odin
index 2f2f7996c..58dc06103 100644
--- a/core/path/filepath/path.odin
+++ b/core/path/filepath/path.odin
@@ -2,8 +2,8 @@
// To process paths such as URLs that depend on forward slashes regardless of the OS, use the slashpath package.
package filepath
-import os "core:os/os2"
-import "core:strings"
+import "core:os"
+import "core:strings"
SEPARATOR_CHARS :: `/\`
diff --git a/core/path/filepath/walk.odin b/core/path/filepath/walk.odin
index 00b063bc7..2e2a4ff54 100644
--- a/core/path/filepath/walk.odin
+++ b/core/path/filepath/walk.odin
@@ -2,7 +2,7 @@
#+build !js
package filepath
-import os "core:os/os2"
+import "core:os"
Walker :: os.Walker
@@ -43,9 +43,9 @@ If an error occurred opening a directory, you may get zero'd info struct and
Example:
package main
- import "core:fmt"
- import "core:strings"
- import os "core:os/os2"
+ import "core:fmt"
+ import "core:strings"
+ import "core:os"
main :: proc() {
w := os.walker_create("core")
diff --git a/core/prof/spall/spall.odin b/core/prof/spall/spall.odin
index b079c2eb2..281eaa82d 100644
--- a/core/prof/spall/spall.odin
+++ b/core/prof/spall/spall.odin
@@ -2,8 +2,8 @@ package spall
import "base:intrinsics"
-import os "core:os/os2"
-import "core:time"
+import "core:os"
+import "core:time"
// File Format
diff --git a/core/terminal/internal_os.odin b/core/terminal/internal_os.odin
index 841803766..127cbae54 100644
--- a/core/terminal/internal_os.odin
+++ b/core/terminal/internal_os.odin
@@ -3,9 +3,9 @@
#+private
package terminal
-import "base:runtime"
-import os "core:os/os2"
-import "core:strings"
+import "base:runtime"
+import "core:os"
+import "core:strings"
// Reference documentation:
//
diff --git a/core/terminal/terminal_posix.odin b/core/terminal/terminal_posix.odin
index 751ef85cf..83e64c6d8 100644
--- a/core/terminal/terminal_posix.odin
+++ b/core/terminal/terminal_posix.odin
@@ -2,8 +2,8 @@
#+build linux, darwin, netbsd, openbsd, freebsd, haiku
package terminal
-import "base:runtime"
-import os "core:os/os2"
+import "base:runtime"
+import "core:os"
_is_terminal :: proc "contextless" (f: ^os.File) -> bool {
return os.is_tty(f)
diff --git a/core/terminal/terminal_windows.odin b/core/terminal/terminal_windows.odin
index 78d21952b..6c77330b5 100644
--- a/core/terminal/terminal_windows.odin
+++ b/core/terminal/terminal_windows.odin
@@ -1,9 +1,9 @@
#+private
package terminal
-import "base:runtime"
-import os "core:os/os2"
-import "core:sys/windows"
+import "base:runtime"
+import "core:os"
+import "core:sys/windows"
_is_terminal :: proc "contextless" (f: ^os.File) -> bool {
return os.is_tty(f)
diff --git a/core/testing/runner.odin b/core/testing/runner.odin
index 8873bc973..8f26aa6c6 100644
--- a/core/testing/runner.odin
+++ b/core/testing/runner.odin
@@ -10,24 +10,24 @@ package testing
Feoramund: Total rewrite.
*/
-import "base:intrinsics"
-import "base:runtime"
-import "core:bytes"
-@require import "core:encoding/base64"
-@require import "core:encoding/json"
-import "core:fmt"
-import "core:io"
-@require import "core:log"
-import "core:math/rand"
-import "core:mem"
-import os "core:os/os2"
-import "core:slice"
-@require import "core:strings"
-import "core:sync/chan"
-import "core:terminal"
-import "core:terminal/ansi"
-import "core:thread"
-import "core:time"
+import "base:intrinsics"
+import "base:runtime"
+import "core:bytes"
+@(require) import "core:encoding/base64"
+@(require) import "core:encoding/json"
+import "core:fmt"
+import "core:io"
+@(require) import "core:log"
+import "core:math/rand"
+import "core:mem"
+import "core:os"
+import "core:slice"
+@(require) import "core:strings"
+import "core:sync/chan"
+import "core:terminal"
+import "core:terminal/ansi"
+import "core:thread"
+import "core:time"
// Specify how many threads to use when running tests.
TEST_THREADS : int : #config(ODIN_TEST_THREADS, 0)
diff --git a/core/testing/signal_handler_libc.odin b/core/testing/signal_handler_libc.odin
index badee802d..fb19a0115 100644
--- a/core/testing/signal_handler_libc.odin
+++ b/core/testing/signal_handler_libc.odin
@@ -11,11 +11,11 @@ package testing
blob1807: Windows Win32 API rewrite.
*/
-import "base:intrinsics"
-import "core:c/libc"
-import os "core:os/os2"
-import "core:sync"
-import "core:terminal/ansi"
+import "base:intrinsics"
+import "core:c/libc"
+import "core:os"
+import "core:sync"
+import "core:terminal/ansi"
@(private="file") stop_runner_flag: libc.sig_atomic_t
diff --git a/core/text/i18n/i18_js.odin b/core/text/i18n/i18_js.odin
index 743718942..73e8535a5 100644
--- a/core/text/i18n/i18_js.odin
+++ b/core/text/i18n/i18_js.odin
@@ -10,8 +10,6 @@ package i18n
List of contributors:
Jeroen van Rijn: Initial implementation.
*/
-import os "core:os/os2"
-
@(private)
parse_qt :: proc { parse_qt_linguist_from_bytes }
diff --git a/core/text/i18n/i18n_os.odin b/core/text/i18n/i18n_os.odin
index db82a9cf6..7a7995612 100644
--- a/core/text/i18n/i18n_os.odin
+++ b/core/text/i18n/i18n_os.odin
@@ -11,7 +11,7 @@ package i18n
Jeroen van Rijn: Initial implementation.
*/
import "base:runtime"
-import os "core:os/os2"
+import "core:os"
@(private)
read_file :: proc(filename: string, allocator: runtime.Allocator) -> (data: []u8, err: Error) {
diff --git a/core/text/regex/common/os.odin b/core/text/regex/common/os.odin
index 1d38d687c..bde57f77f 100644
--- a/core/text/regex/common/os.odin
+++ b/core/text/regex/common/os.odin
@@ -10,7 +10,7 @@ package regex_common
Feoramund: Initial implementation.
*/
-@require import os "core:os/os2"
+@require import "core:os"
when ODIN_DEBUG_REGEX {
debug_stream := os.stderr.stream
diff --git a/core/text/table/doc.odin b/core/text/table/doc.odin
index 29b60dbe2..d91763661 100644
--- a/core/text/table/doc.odin
+++ b/core/text/table/doc.odin
@@ -189,7 +189,7 @@ Example:
import "core:fmt"
import "core:io"
- import os "core:os/os2"
+ import "core:os"
import "core:text/table"
scripts :: proc(w: io.Writer) {
@@ -265,10 +265,10 @@ corners and dividers.
Example:
package main
- import "core:fmt"
- import "core:io"
- import os "core:os/os2"
- import "core:text/table"
+ import "core:fmt"
+ import "core:io"
+ import "core:os"
+ import "core:text/table"
box_drawing :: proc(w: io.Writer) {
t: table.Table
diff --git a/core/text/table/utility.odin b/core/text/table/utility.odin
index db5ae4602..675fa6b10 100644
--- a/core/text/table/utility.odin
+++ b/core/text/table/utility.odin
@@ -2,9 +2,9 @@
#+build !js
package text_table
-import "core:io"
-import os "core:os/os2"
-import "core:strings"
+import "core:io"
+import "core:os"
+import "core:strings"
stdio_writer :: proc() -> io.Writer {
return os.to_stream(os.stdout)
diff --git a/core/time/timezone/tz_os.odin b/core/time/timezone/tz_os.odin
index 2ab7cfa6c..fae4980c3 100644
--- a/core/time/timezone/tz_os.odin
+++ b/core/time/timezone/tz_os.odin
@@ -2,7 +2,7 @@
#+build !js
package timezone
-import os "core:os/os2"
+import "core:os"
import "core:time/datetime"
load_tzif_file :: proc(filename: string, region_name: string, allocator := context.allocator) -> (out: ^datetime.TZ_Region, ok: bool) {
diff --git a/core/time/timezone/tz_unix.odin b/core/time/timezone/tz_unix.odin
index 60a20e57c..3939b3265 100644
--- a/core/time/timezone/tz_unix.odin
+++ b/core/time/timezone/tz_unix.odin
@@ -2,10 +2,10 @@
#+private
package timezone
-import os "core:os/os2"
-import "core:strings"
-import "core:time/datetime"
-import "core:path/filepath"
+import "core:os"
+import "core:strings"
+import "core:time/datetime"
+import "core:path/filepath"
local_tz_name :: proc(allocator := context.allocator) -> (name: string, success: bool) {
local_str, ok := os.lookup_env("TZ", allocator)
diff --git a/core/unicode/tools/generate_entity_table.odin b/core/unicode/tools/generate_entity_table.odin
index 02958ad26..54f73370c 100644
--- a/core/unicode/tools/generate_entity_table.odin
+++ b/core/unicode/tools/generate_entity_table.odin
@@ -1,7 +1,7 @@
package xml_example
import "core:encoding/xml"
-import os "core:os/os2"
+import "core:os"
import path "core:path/filepath"
import "core:strings"
import "core:strconv"
diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin
index c5f627653..3576fc027 100644
--- a/examples/all/all_main.odin
+++ b/examples/all/all_main.odin
@@ -117,7 +117,7 @@ package all
@(require) import "core:prof/spall"
@(require) import "core:os"
-@(require) import "core:os/os2"
+@(require) import "core:os/old"
@(require) import "core:path/slashpath"
@(require) import "core:path/filepath"
diff --git a/tests/core/encoding/hxa/test_core_hxa.odin b/tests/core/encoding/hxa/test_core_hxa.odin
index 17b3ca619..a4fee030c 100644
--- a/tests/core/encoding/hxa/test_core_hxa.odin
+++ b/tests/core/encoding/hxa/test_core_hxa.odin
@@ -6,7 +6,7 @@ import "core:testing"
TEAPOT_PATH :: ODIN_ROOT + "tests/core/assets/HXA/teapot.hxa"
-import os "core:os/os2"
+import "core:os"
@test
test_read :: proc(t: ^testing.T) {
diff --git a/tests/core/flags/test_core_flags.odin b/tests/core/flags/test_core_flags.odin
index 1aee7f69c..834f6b630 100644
--- a/tests/core/flags/test_core_flags.odin
+++ b/tests/core/flags/test_core_flags.odin
@@ -1,16 +1,16 @@
package test_core_flags
-import "base:runtime"
-import "core:bytes"
-import "core:flags"
-import "core:fmt"
-@require import "core:log"
-import "core:math"
-@require import "core:net"
-import os "core:os/os2"
-import "core:strings"
-import "core:testing"
-import "core:time/datetime"
+import "base:runtime"
+import "core:bytes"
+import "core:flags"
+import "core:fmt"
+@(require) import "core:log"
+import "core:math"
+@(require) import "core:net"
+import "core:os"
+import "core:strings"
+import "core:testing"
+import "core:time/datetime"
Custom_Data :: struct {
a: int,
diff --git a/tests/core/io/test_core_io.odin b/tests/core/io/test_core_io.odin
index eb4d79317..301e7bb94 100644
--- a/tests/core/io/test_core_io.odin
+++ b/tests/core/io/test_core_io.odin
@@ -1,12 +1,12 @@
package test_core_io
-import "core:bufio"
-import "core:bytes"
-import "core:io"
-import "core:log"
-import os "core:os/os2"
-import "core:strings"
-import "core:testing"
+import "core:bufio"
+import "core:bytes"
+import "core:io"
+import "core:log"
+import "core:os"
+import "core:strings"
+import "core:testing"
Passed_Tests :: distinct io.Stream_Mode_Set
diff --git a/tests/core/nbio/fs.odin b/tests/core/nbio/fs.odin
index 6e079f96e..1b10c03c9 100644
--- a/tests/core/nbio/fs.odin
+++ b/tests/core/nbio/fs.odin
@@ -1,9 +1,9 @@
package tests_nbio
-import "core:nbio"
-import "core:testing"
-import "core:time"
-import os "core:os/os2"
+import "core:nbio"
+import "core:testing"
+import "core:time"
+import "core:os"
@(test)
close_invalid_handle :: proc(t: ^testing.T) {
diff --git a/tests/core/nbio/nbio.odin b/tests/core/nbio/nbio.odin
index 2f454f55b..6c3fd0e8c 100644
--- a/tests/core/nbio/nbio.odin
+++ b/tests/core/nbio/nbio.odin
@@ -1,11 +1,11 @@
package tests_nbio
-import "core:log"
-import "core:nbio"
-import "core:testing"
-import "core:thread"
-import "core:time"
-import os "core:os/os2"
+import "core:log"
+import "core:nbio"
+import "core:testing"
+import "core:thread"
+import "core:time"
+import "core:os"
ev :: testing.expect_value
e :: testing.expect
diff --git a/tests/core/normal.odin b/tests/core/normal.odin
index 6b31b9d56..4708ed700 100644
--- a/tests/core/normal.odin
+++ b/tests/core/normal.odin
@@ -37,7 +37,7 @@ download_assets :: proc "contextless" () {
@(require) import "net"
@(require) import "odin"
@(require) import "os"
-@(require) import "os/os2"
+@(require) import "os/old"
@(require) import "reflect"
@(require) import "runtime"
@(require) import "slice"
diff --git a/tests/core/os/os2/dir.odin b/tests/core/os/dir.odin
index 8ef333219..464abed98 100644
--- a/tests/core/os/os2/dir.odin
+++ b/tests/core/os/dir.odin
@@ -1,14 +1,14 @@
-package tests_core_os_os2
+package tests_core_os
-import os "core:os/os2"
-import "core:log"
-import "core:slice"
-import "core:testing"
-import "core:strings"
+import "core:os"
+import "core:log"
+import "core:slice"
+import "core:testing"
+import "core:strings"
@(test)
test_read_dir :: proc(t: ^testing.T) {
- path, err_join := os.join_path({#directory, "../dir"}, context.allocator)
+ path, err_join := os.join_path({#directory, "dir"}, context.allocator)
defer delete(path)
fis, err_read := os.read_all_directory_by_path(path, context.allocator)
@@ -17,7 +17,7 @@ test_read_dir :: proc(t: ^testing.T) {
slice.sort_by_key(fis, proc(fi: os.File_Info) -> string { return fi.name })
if err_read == .Unsupported {
- log.warn("os2 directory functionality is unsupported, skipping test")
+ log.warn("core:os directory functionality is unsupported, skipping test")
return
}
@@ -34,7 +34,7 @@ test_read_dir :: proc(t: ^testing.T) {
@(test)
test_walker :: proc(t: ^testing.T) {
- path, err := os.join_path({#directory, "../dir"}, context.allocator)
+ path, err := os.join_path({#directory, "dir"}, context.allocator)
defer delete(path)
testing.expect_value(t, err, nil)
@@ -46,7 +46,7 @@ test_walker :: proc(t: ^testing.T) {
@(test)
test_walker_file :: proc(t: ^testing.T) {
- path, err_join := os.join_path({#directory, "../dir"}, context.allocator)
+ path, err_join := os.join_path({#directory, "dir"}, context.allocator)
defer delete(path)
testing.expect_value(t, err_join, nil)
@@ -95,7 +95,7 @@ test_walker_internal :: proc(t: ^testing.T, w: ^os.Walker) {
}
if _, err := os.walker_error(w); err == .Unsupported {
- log.warn("os2 directory functionality is unsupported, skipping test")
+ log.warn("core:os directory functionality is unsupported, skipping test")
return
}
diff --git a/tests/core/os/os2/file.odin b/tests/core/os/file.odin
index 0152a2008..aed57c26c 100644
--- a/tests/core/os/os2/file.odin
+++ b/tests/core/os/file.odin
@@ -1,7 +1,7 @@
-package tests_core_os_os2
+package tests_core_os
-import os "core:os/os2"
-import "core:testing"
+import "core:os"
+import "core:testing"
@(test)
test_clone :: proc(t: ^testing.T) {
diff --git a/tests/core/os/os.odin b/tests/core/os/old/os.odin
index 1510bad31..9925cf708 100644
--- a/tests/core/os/os.odin
+++ b/tests/core/os/old/os.odin
@@ -1,8 +1,8 @@
-package test_core_os
+package test_core_os_old
import "core:c/libc"
import win32 "core:sys/windows"
-import "core:os"
+import os "core:os/old"
import "core:slice"
import "core:testing"
import "core:log"
diff --git a/tests/core/os/os2/path.odin b/tests/core/os/path.odin
index 868023c86..cdfaed56f 100644
--- a/tests/core/os/os2/path.odin
+++ b/tests/core/os/path.odin
@@ -1,11 +1,11 @@
-package tests_core_os_os2
+package tests_core_os
-import "core:fmt"
-import os "core:os/os2"
-import "core:log"
-import "core:testing"
-import "core:slice"
-import "core:strings"
+import "core:fmt"
+import "core:os"
+import "core:log"
+import "core:testing"
+import "core:slice"
+import "core:strings"
@(test)
test_executable :: proc(t: ^testing.T) {
@@ -351,12 +351,12 @@ glob_tests := []Glob_Test{
err = {},
},
{
- pattern = ODIN_ROOT + "tests/core/os/os2/*.odin",
+ pattern = ODIN_ROOT + "tests/core/os/*.odin",
matches = {
- ODIN_ROOT + "tests/core/os/os2/dir.odin",
- ODIN_ROOT + "tests/core/os/os2/file.odin",
- ODIN_ROOT + "tests/core/os/os2/path.odin",
- ODIN_ROOT + "tests/core/os/os2/process.odin",
+ ODIN_ROOT + "tests/core/os/dir.odin",
+ ODIN_ROOT + "tests/core/os/file.odin",
+ ODIN_ROOT + "tests/core/os/path.odin",
+ ODIN_ROOT + "tests/core/os/process.odin",
},
err = {},
},
diff --git a/tests/core/os/os2/process.odin b/tests/core/os/process.odin
index c530b4c79..adb65e95f 100644
--- a/tests/core/os/os2/process.odin
+++ b/tests/core/os/process.odin
@@ -1,9 +1,9 @@
#+build !windows
-package tests_core_os_os2
+package tests_core_os
-import os "core:os/os2"
-import "core:log"
-import "core:testing"
+import "core:os"
+import "core:log"
+import "core:testing"
@(test)
test_process_exec :: proc(t: ^testing.T) {
diff --git a/tests/core/sys/kqueue/structs.odin b/tests/core/sys/kqueue/structs.odin
index edf1fdd1e..15ec3f841 100644
--- a/tests/core/sys/kqueue/structs.odin
+++ b/tests/core/sys/kqueue/structs.odin
@@ -1,9 +1,9 @@
#+build darwin, freebsd, openbsd, netbsd
package tests_core_sys_kqueue
-import "core:strings"
-import "core:testing"
-import os "core:os/os2"
+import "core:strings"
+import "core:testing"
+import "core:os"
@(test)
structs :: proc(t: ^testing.T) {
diff --git a/tests/documentation/documentation_tester.odin b/tests/documentation/documentation_tester.odin
index 6694de709..be59d9b4d 100644
--- a/tests/documentation/documentation_tester.odin
+++ b/tests/documentation/documentation_tester.odin
@@ -1,6 +1,6 @@
package documentation_tester
-import os "core:os/os2"
+import "core:os"
import "core:fmt"
import "core:strings"
import "core:odin/ast"
@@ -267,7 +267,7 @@ write_test_suite :: proc(example_tests: []Example_Test) {
`#+private
package documentation_verification
-import os "core:os/os2"
+import "core:os"
import "core:mem"
import "core:io"
import "core:fmt"
diff --git a/vendor/OpenGL/helpers.odin b/vendor/OpenGL/helpers.odin
index bce60ee80..9c9c74d09 100644
--- a/vendor/OpenGL/helpers.odin
+++ b/vendor/OpenGL/helpers.odin
@@ -3,7 +3,7 @@ package vendor_gl
// Helper for loading shaders into a program
-import os "core:os/os2"
+import "core:os"
import "core:fmt"
import "core:strings"
@(require) import "core:time"
diff --git a/vendor/fontstash/fontstash_os.odin b/vendor/fontstash/fontstash_os.odin
index 8c259412d..d04df044c 100644
--- a/vendor/fontstash/fontstash_os.odin
+++ b/vendor/fontstash/fontstash_os.odin
@@ -1,8 +1,8 @@
#+build !js
package fontstash
-import "core:log"
-import os "core:os/os2"
+import "core:log"
+import "core:os"
// 'fontIndex' controls which font you want to load within a multi-font format such
// as TTC. Leave it as zero if you are loading a single-font format such as TTF.
diff --git a/vendor/libc-shim/stdio_os.odin b/vendor/libc-shim/stdio_os.odin
index db40fb250..f6d30a227 100644
--- a/vendor/libc-shim/stdio_os.odin
+++ b/vendor/libc-shim/stdio_os.odin
@@ -2,9 +2,9 @@
#+build !js
package odin_libc
-import "core:io"
-import "core:c"
-import os "core:os/os2"
+import "core:io"
+import "core:c"
+import "core:os"
_fopen :: proc(path, _mode: cstring) -> FILE {
flags: os.File_Flags