mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-05 10:14:05 +00:00
Merge pull request #5095 from Lperlind/temp-collisions
os2: Resolve temp allocator collisions
This commit is contained in:
@@ -8,43 +8,13 @@ file_allocator :: proc() -> runtime.Allocator {
|
||||
return heap_allocator()
|
||||
}
|
||||
|
||||
temp_allocator_proc :: runtime.arena_allocator_proc
|
||||
|
||||
@(private="file")
|
||||
MAX_TEMP_ARENA_COUNT :: 2
|
||||
|
||||
@(private="file")
|
||||
MAX_TEMP_ARENA_COLLISIONS :: MAX_TEMP_ARENA_COUNT - 1
|
||||
@(private="file", thread_local)
|
||||
global_default_temp_allocator_arenas: [MAX_TEMP_ARENA_COUNT]runtime.Arena
|
||||
|
||||
@(private="file", thread_local)
|
||||
global_default_temp_allocator_index: uint
|
||||
|
||||
|
||||
@(require_results)
|
||||
temp_allocator :: proc() -> runtime.Allocator {
|
||||
arena := &global_default_temp_allocator_arenas[global_default_temp_allocator_index]
|
||||
if arena.backing_allocator.procedure == nil {
|
||||
arena.backing_allocator = heap_allocator()
|
||||
}
|
||||
|
||||
return runtime.Allocator{
|
||||
procedure = temp_allocator_proc,
|
||||
data = arena,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
temp_allocator_temp_begin :: proc(loc := #caller_location) -> (temp: runtime.Arena_Temp) {
|
||||
temp = runtime.arena_temp_begin(&global_default_temp_allocator_arenas[global_default_temp_allocator_index], loc)
|
||||
return
|
||||
}
|
||||
|
||||
temp_allocator_temp_end :: proc(temp: runtime.Arena_Temp, loc := #caller_location) {
|
||||
runtime.arena_temp_end(temp, loc)
|
||||
}
|
||||
|
||||
@(fini, private)
|
||||
temp_allocator_fini :: proc() {
|
||||
for &arena in global_default_temp_allocator_arenas {
|
||||
@@ -53,18 +23,49 @@ temp_allocator_fini :: proc() {
|
||||
global_default_temp_allocator_arenas = {}
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD_END :: proc(temp: runtime.Arena_Temp, loc := #caller_location) {
|
||||
runtime.arena_temp_end(temp, loc)
|
||||
if temp.arena != nil {
|
||||
global_default_temp_allocator_index = (global_default_temp_allocator_index-1)%MAX_TEMP_ARENA_COUNT
|
||||
}
|
||||
Temp_Allocator :: struct {
|
||||
using arena: ^runtime.Arena,
|
||||
using allocator: runtime.Allocator,
|
||||
tmp: runtime.Arena_Temp,
|
||||
loc: runtime.Source_Code_Location,
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD_END :: proc(temp: Temp_Allocator) {
|
||||
runtime.arena_temp_end(temp.tmp, temp.loc)
|
||||
}
|
||||
|
||||
@(deferred_out=TEMP_ALLOCATOR_GUARD_END)
|
||||
TEMP_ALLOCATOR_GUARD :: #force_inline proc(loc := #caller_location) -> (runtime.Arena_Temp, runtime.Source_Code_Location) {
|
||||
global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT
|
||||
tmp := temp_allocator_temp_begin(loc)
|
||||
return tmp, loc
|
||||
TEMP_ALLOCATOR_GUARD :: #force_inline proc(collisions: []runtime.Allocator, loc := #caller_location) -> Temp_Allocator {
|
||||
assert(len(collisions) <= MAX_TEMP_ARENA_COLLISIONS, "Maximum collision count exceeded. MAX_TEMP_ARENA_COUNT must be increased!")
|
||||
good_arena: ^runtime.Arena
|
||||
for i in 0..<MAX_TEMP_ARENA_COUNT {
|
||||
good_arena = &global_default_temp_allocator_arenas[i]
|
||||
for c in collisions {
|
||||
if good_arena == c.data {
|
||||
good_arena = nil
|
||||
}
|
||||
}
|
||||
if good_arena != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
assert(good_arena != nil)
|
||||
if good_arena.backing_allocator.procedure == nil {
|
||||
good_arena.backing_allocator = heap_allocator()
|
||||
}
|
||||
tmp := runtime.arena_temp_begin(good_arena, loc)
|
||||
return { good_arena, runtime.arena_allocator(good_arena), tmp, loc }
|
||||
}
|
||||
|
||||
temp_allocator_begin :: runtime.arena_temp_begin
|
||||
temp_allocator_end :: runtime.arena_temp_end
|
||||
@(deferred_out=_temp_allocator_end)
|
||||
temp_allocator_scope :: proc(tmp: Temp_Allocator) -> (runtime.Arena_Temp) {
|
||||
return temp_allocator_begin(tmp.arena)
|
||||
}
|
||||
@(private="file")
|
||||
_temp_allocator_end :: proc(tmp: runtime.Arena_Temp) {
|
||||
temp_allocator_end(tmp)
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
|
||||
@@ -18,12 +18,12 @@ read_directory :: proc(f: ^File, n: int, allocator: runtime.Allocator) -> (files
|
||||
size = 100
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
it := read_directory_iterator_create(f)
|
||||
defer _read_directory_iterator_destroy(&it)
|
||||
|
||||
dfi := make([dynamic]File_Info, 0, size, temp_allocator())
|
||||
dfi := make([dynamic]File_Info, 0, size, temp_allocator)
|
||||
defer if err != nil {
|
||||
for fi in dfi {
|
||||
file_info_delete(fi, allocator)
|
||||
@@ -202,13 +202,13 @@ copy_directory :: proc(dst, src: string, dst_perm := 0o755) -> Error {
|
||||
return err
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
file_infos := read_all_directory_by_path(src, temp_allocator()) or_return
|
||||
file_infos := read_all_directory_by_path(src, temp_allocator) or_return
|
||||
for fi in file_infos {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator_scope(temp_allocator)
|
||||
|
||||
dst_path := join_path({dst, fi.name}, temp_allocator()) or_return
|
||||
dst_path := join_path({dst, fi.name}, temp_allocator) or_return
|
||||
src_path := fi.fullpath
|
||||
|
||||
if fi.type == .Directory {
|
||||
@@ -218,4 +218,4 @@ copy_directory :: proc(dst, src: string, dst_perm := 0o755) -> Error {
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,8 @@ _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info
|
||||
it.impl.prev_fi = fi
|
||||
|
||||
if err != nil {
|
||||
path, _ := _get_full_path(entry_fd, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
path, _ := _get_full_path(entry_fd, temp_allocator)
|
||||
read_directory_iterator_set_error(it, path, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,9 @@ find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, al
|
||||
if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 {
|
||||
return
|
||||
}
|
||||
path := concatenate({base_path, `\`, win32_wstring_to_utf8(raw_data(d.cFileName[:]), temp_allocator()) or_else ""}, allocator) or_return
|
||||
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
path := concatenate({base_path, `\`, win32_wstring_to_utf8(raw_data(d.cFileName[:]), temp_allocator) or_else ""}, allocator) or_return
|
||||
|
||||
handle := win32.HANDLE(_open_internal(path, {.Read}, 0o666) or_else 0)
|
||||
defer win32.CloseHandle(handle)
|
||||
@@ -49,8 +51,6 @@ Read_Directory_Iterator_Impl :: struct {
|
||||
|
||||
@(require_results)
|
||||
_read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
|
||||
for !it.impl.no_more_files {
|
||||
err: Error
|
||||
file_info_delete(it.impl.prev_fi, file_allocator())
|
||||
@@ -116,9 +116,9 @@ _read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
|
||||
wpath = impl.wname[:i]
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
wpath_search := make([]u16, len(wpath)+3, temp_allocator())
|
||||
wpath_search := make([]u16, len(wpath)+3, temp_allocator)
|
||||
copy(wpath_search, wpath)
|
||||
wpath_search[len(wpath)+0] = '\\'
|
||||
wpath_search[len(wpath)+1] = '*'
|
||||
|
||||
@@ -12,9 +12,9 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
|
||||
return
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
ckey := strings.clone_to_cstring(key, temp_allocator())
|
||||
ckey := strings.clone_to_cstring(key, temp_allocator)
|
||||
cval := posix.getenv(ckey)
|
||||
if cval == nil {
|
||||
return
|
||||
@@ -27,10 +27,10 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
|
||||
}
|
||||
|
||||
_set_env :: proc(key, value: string) -> (err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
ckey := strings.clone_to_cstring(key, temp_allocator()) or_return
|
||||
cval := strings.clone_to_cstring(value, temp_allocator()) or_return
|
||||
ckey := strings.clone_to_cstring(key, temp_allocator) or_return
|
||||
cval := strings.clone_to_cstring(value, temp_allocator) or_return
|
||||
|
||||
if posix.setenv(ckey, cval, true) != nil {
|
||||
err = _get_platform_error_from_errno()
|
||||
@@ -39,9 +39,9 @@ _set_env :: proc(key, value: string) -> (err: Error) {
|
||||
}
|
||||
|
||||
_unset_env :: proc(key: string) -> (ok: bool) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
ckey := strings.clone_to_cstring(key, temp_allocator())
|
||||
ckey := strings.clone_to_cstring(key, temp_allocator)
|
||||
|
||||
ok = posix.unsetenv(ckey) == .OK
|
||||
return
|
||||
|
||||
@@ -39,9 +39,9 @@ build_env :: proc() -> (err: Error) {
|
||||
g_env_buf = make([]byte, size_of_envs, file_allocator()) or_return
|
||||
defer if err != nil { delete(g_env_buf, file_allocator()) }
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
envs := make([]cstring, num_envs, temp_allocator()) or_return
|
||||
envs := make([]cstring, num_envs, temp_allocator) or_return
|
||||
|
||||
_err = wasi.environ_get(raw_data(envs), raw_data(g_env_buf))
|
||||
if _err != nil {
|
||||
|
||||
@@ -8,8 +8,8 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
|
||||
if key == "" {
|
||||
return
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
wkey, _ := win32_utf8_to_wstring(key, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
wkey, _ := win32_utf8_to_wstring(key, temp_allocator)
|
||||
|
||||
n := win32.GetEnvironmentVariableW(wkey, nil, 0)
|
||||
if n == 0 {
|
||||
@@ -20,7 +20,7 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
|
||||
return "", true
|
||||
}
|
||||
|
||||
b := make([]u16, n+1, temp_allocator())
|
||||
b := make([]u16, n+1, temp_allocator)
|
||||
|
||||
n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
|
||||
if n == 0 {
|
||||
@@ -37,9 +37,9 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string
|
||||
}
|
||||
|
||||
_set_env :: proc(key, value: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
k := win32_utf8_to_wstring(key, temp_allocator()) or_return
|
||||
v := win32_utf8_to_wstring(value, temp_allocator()) or_return
|
||||
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()
|
||||
@@ -48,14 +48,14 @@ _set_env :: proc(key, value: string) -> Error {
|
||||
}
|
||||
|
||||
_unset_env :: proc(key: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
k, _ := win32_utf8_to_wstring(key, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
k, _ := win32_utf8_to_wstring(key, temp_allocator)
|
||||
return bool(win32.SetEnvironmentVariableW(k, nil))
|
||||
}
|
||||
|
||||
_clear_env :: proc() {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
envs, _ := environ(temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
envs, _ := environ(temp_allocator)
|
||||
for env in envs {
|
||||
for j in 1..<len(env) {
|
||||
if env[j] == '=' {
|
||||
|
||||
@@ -108,12 +108,12 @@ error_string :: proc(ferr: Error) -> string {
|
||||
}
|
||||
|
||||
print_error :: proc(f: ^File, ferr: Error, msg: string) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
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())
|
||||
buf := make([]u8, length, temp_allocator)
|
||||
|
||||
copy(buf, msg)
|
||||
buf[len(msg)] = ':'
|
||||
|
||||
@@ -291,8 +291,8 @@ exists :: proc(path: string) -> bool {
|
||||
|
||||
@(require_results)
|
||||
is_file :: proc(path: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
fi, err := stat(path, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
fi, err := stat(path, temp_allocator)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -303,8 +303,8 @@ is_dir :: is_directory
|
||||
|
||||
@(require_results)
|
||||
is_directory :: proc(path: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
fi, err := stat(path, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
fi, err := stat(path, temp_allocator)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -66,8 +66,8 @@ _standard_stream_init :: proc() {
|
||||
}
|
||||
|
||||
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
// Just default to using O_NOCTTY because needing to open a controlling
|
||||
// terminal would be incredibly rare. This has no effect on files while
|
||||
@@ -299,8 +299,8 @@ _truncate :: proc(f: ^File, size: i64) -> Error {
|
||||
}
|
||||
|
||||
_remove :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
if fd, errno := linux.open(name_cstr, _OPENDIR_FLAGS + {.NOFOLLOW}); errno == .NONE {
|
||||
linux.close(fd)
|
||||
@@ -311,25 +311,25 @@ _remove :: proc(name: string) -> Error {
|
||||
}
|
||||
|
||||
_rename :: proc(old_name, new_name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
old_name_cstr := temp_cstring(old_name) or_return
|
||||
new_name_cstr := temp_cstring(new_name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
old_name_cstr := clone_to_cstring(old_name, temp_allocator) or_return
|
||||
new_name_cstr := clone_to_cstring(new_name, temp_allocator) or_return
|
||||
|
||||
return _get_platform_error(linux.rename(old_name_cstr, new_name_cstr))
|
||||
}
|
||||
|
||||
_link :: proc(old_name, new_name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
old_name_cstr := temp_cstring(old_name) or_return
|
||||
new_name_cstr := temp_cstring(new_name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
old_name_cstr := clone_to_cstring(old_name, temp_allocator) or_return
|
||||
new_name_cstr := clone_to_cstring(new_name, temp_allocator) or_return
|
||||
|
||||
return _get_platform_error(linux.link(old_name_cstr, new_name_cstr))
|
||||
}
|
||||
|
||||
_symlink :: proc(old_name, new_name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
old_name_cstr := temp_cstring(old_name) or_return
|
||||
new_name_cstr := temp_cstring(new_name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
old_name_cstr := clone_to_cstring(old_name, temp_allocator) or_return
|
||||
new_name_cstr := clone_to_cstring(new_name, temp_allocator) or_return
|
||||
return _get_platform_error(linux.symlink(old_name_cstr, new_name_cstr))
|
||||
}
|
||||
|
||||
@@ -352,14 +352,14 @@ _read_link_cstr :: proc(name_cstr: cstring, allocator: runtime.Allocator) -> (st
|
||||
}
|
||||
|
||||
_read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, e: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
return _read_link_cstr(name_cstr, allocator)
|
||||
}
|
||||
|
||||
_chdir :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
return _get_platform_error(linux.chdir(name_cstr))
|
||||
}
|
||||
|
||||
@@ -369,8 +369,8 @@ _fchdir :: proc(f: ^File) -> Error {
|
||||
}
|
||||
|
||||
_chmod :: proc(name: string, mode: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
return _get_platform_error(linux.chmod(name_cstr, transmute(linux.Mode)(u32(mode))))
|
||||
}
|
||||
|
||||
@@ -381,15 +381,15 @@ _fchmod :: proc(f: ^File, mode: int) -> Error {
|
||||
|
||||
// NOTE: will throw error without super user priviledges
|
||||
_chown :: proc(name: string, uid, gid: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
return _get_platform_error(linux.chown(name_cstr, linux.Uid(uid), linux.Gid(gid)))
|
||||
}
|
||||
|
||||
// NOTE: will throw error without super user priviledges
|
||||
_lchown :: proc(name: string, uid, gid: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
return _get_platform_error(linux.lchown(name_cstr, linux.Uid(uid), linux.Gid(gid)))
|
||||
}
|
||||
|
||||
@@ -400,8 +400,8 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error {
|
||||
}
|
||||
|
||||
_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
times := [2]linux.Time_Spec {
|
||||
{
|
||||
uint(atime._nsec) / uint(time.Second),
|
||||
@@ -431,8 +431,8 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
|
||||
}
|
||||
|
||||
_exists :: proc(name: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr, _ := temp_cstring(name)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
name_cstr, _ := clone_to_cstring(name, temp_allocator)
|
||||
return linux.access(name_cstr, linux.F_OK) == .NONE
|
||||
}
|
||||
|
||||
@@ -440,8 +440,8 @@ _exists :: proc(name: string) -> bool {
|
||||
_read_entire_pseudo_file :: proc { _read_entire_pseudo_file_string, _read_entire_pseudo_file_cstring }
|
||||
|
||||
_read_entire_pseudo_file_string :: proc(name: string, allocator: runtime.Allocator) -> (b: []u8, e: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := clone_to_cstring(name, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
return _read_entire_pseudo_file_cstring(name_cstr, allocator)
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,8 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
|
||||
if .Trunc in flags { sys_flags += {.TRUNC} }
|
||||
if .Inheritable in flags { sys_flags -= {.CLOEXEC} }
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
fd := posix.open(cname, sys_flags, transmute(posix.mode_t)posix._mode_t(perm))
|
||||
if fd < 0 {
|
||||
@@ -183,39 +183,39 @@ _truncate :: proc(f: ^File, size: i64) -> Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
_remove :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
_remove :: proc(name: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
if posix.remove(cname) != 0 {
|
||||
return _get_platform_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_rename :: proc(old_path, new_path: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cold := temp_cstring(old_path)
|
||||
cnew := temp_cstring(new_path)
|
||||
_rename :: proc(old_path, new_path: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cold := clone_to_cstring(old_path, temp_allocator) or_return
|
||||
cnew := clone_to_cstring(new_path, temp_allocator) or_return
|
||||
if posix.rename(cold, cnew) != 0 {
|
||||
return _get_platform_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_link :: proc(old_name, new_name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cold := temp_cstring(old_name)
|
||||
cnew := temp_cstring(new_name)
|
||||
_link :: proc(old_name, new_name: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cold := clone_to_cstring(old_name, temp_allocator) or_return
|
||||
cnew := clone_to_cstring(new_name, temp_allocator) or_return
|
||||
if posix.link(cold, cnew) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_symlink :: proc(old_name, new_name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cold := temp_cstring(old_name)
|
||||
cnew := temp_cstring(new_name)
|
||||
_symlink :: proc(old_name, new_name: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cold := clone_to_cstring(old_name, temp_allocator) or_return
|
||||
cnew := clone_to_cstring(new_name, temp_allocator) or_return
|
||||
if posix.symlink(cold, cnew) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
@@ -223,8 +223,8 @@ _symlink :: proc(old_name, new_name: string) -> Error {
|
||||
}
|
||||
|
||||
_read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
buf: [dynamic]byte
|
||||
buf.allocator = allocator
|
||||
@@ -268,9 +268,9 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er
|
||||
}
|
||||
}
|
||||
|
||||
_chdir :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
_chdir :: proc(name: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
if posix.chdir(cname) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
@@ -291,9 +291,9 @@ _fchmod :: proc(f: ^File, mode: int) -> Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
_chmod :: proc(name: string, mode: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
_chmod :: proc(name: string, mode: int) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
if posix.chmod(cname, transmute(posix.mode_t)posix._mode_t(mode)) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
@@ -307,9 +307,9 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
_chown :: proc(name: string, uid, gid: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
_chown :: proc(name: string, uid, gid: int) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
if posix.chown(cname, posix.uid_t(uid), posix.gid_t(gid)) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
@@ -317,15 +317,15 @@ _chown :: proc(name: string, uid, gid: int) -> Error {
|
||||
}
|
||||
|
||||
_lchown :: proc(name: string, uid, gid: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
if posix.lchown(cname, posix.uid_t(uid), posix.gid_t(gid)) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
|
||||
_chtimes :: proc(name: string, atime, mtime: time.Time) -> (err: Error) {
|
||||
times := [2]posix.timeval{
|
||||
{
|
||||
tv_sec = posix.time_t(atime._nsec/1e9), /* seconds */
|
||||
@@ -337,8 +337,8 @@ _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
|
||||
},
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
if posix.utimes(cname, ×) != .OK {
|
||||
return _get_platform_error()
|
||||
@@ -365,8 +365,9 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
|
||||
}
|
||||
|
||||
_exists :: proc(path: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cpath := temp_cstring(path)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cpath, err := clone_to_cstring(path, temp_allocator)
|
||||
if err != nil { return false }
|
||||
return posix.access(cpath) == .OK
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import "base:runtime"
|
||||
import "core:sys/posix"
|
||||
|
||||
_posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
cname := clone_to_cstring(name, temp_allocator)
|
||||
|
||||
buf: [posix.PATH_MAX]byte
|
||||
path = posix.realpath(cname, raw_data(buf[:]))
|
||||
|
||||
@@ -109,9 +109,9 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: u
|
||||
err = .Not_Exist
|
||||
return
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
path := _fix_long_path(name, temp_allocator()) or_return
|
||||
path := _fix_long_path(name, temp_allocator) or_return
|
||||
access: u32
|
||||
switch flags & {.Read, .Write} {
|
||||
case {.Read}: access = win32.FILE_GENERIC_READ
|
||||
@@ -580,8 +580,8 @@ _truncate :: proc(f: ^File, size: i64) -> Error {
|
||||
}
|
||||
|
||||
_remove :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
p := _fix_long_path(name, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
p := _fix_long_path(name, temp_allocator) or_return
|
||||
err, err1: Error
|
||||
if !win32.DeleteFileW(p) {
|
||||
err = _get_platform_error()
|
||||
@@ -618,9 +618,9 @@ _remove :: proc(name: string) -> Error {
|
||||
}
|
||||
|
||||
_rename :: proc(old_path, new_path: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
from := _fix_long_path(old_path, temp_allocator()) or_return
|
||||
to := _fix_long_path(new_path, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
from := _fix_long_path(old_path, temp_allocator) or_return
|
||||
to := _fix_long_path(new_path, temp_allocator) or_return
|
||||
if win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING) {
|
||||
return nil
|
||||
}
|
||||
@@ -629,9 +629,9 @@ _rename :: proc(old_path, new_path: string) -> Error {
|
||||
}
|
||||
|
||||
_link :: proc(old_name, new_name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
o := _fix_long_path(old_name, temp_allocator()) or_return
|
||||
n := _fix_long_path(new_name, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
o := _fix_long_path(old_name, temp_allocator) or_return
|
||||
n := _fix_long_path(new_name, temp_allocator) or_return
|
||||
if win32.CreateHardLinkW(n, o, nil) {
|
||||
return nil
|
||||
}
|
||||
@@ -692,9 +692,9 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st
|
||||
return "", _get_platform_error()
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := make([]u16, n+1, temp_allocator())
|
||||
buf := make([]u16, n+1, temp_allocator)
|
||||
n = win32.GetFinalPathNameByHandleW(handle, raw_data(buf), u32(len(buf)), win32.VOLUME_NAME_DOS)
|
||||
if n == 0 {
|
||||
return "", _get_platform_error()
|
||||
@@ -718,9 +718,9 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er
|
||||
@thread_local
|
||||
rdb_buf: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]byte
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
p := _fix_long_path(name, temp_allocator()) or_return
|
||||
p := _fix_long_path(name, temp_allocator) or_return
|
||||
handle := _open_sym_link(p) or_return
|
||||
defer win32.CloseHandle(handle)
|
||||
|
||||
@@ -785,8 +785,8 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error {
|
||||
}
|
||||
|
||||
_chdir :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
p := _fix_long_path(name, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
p := _fix_long_path(name, temp_allocator) or_return
|
||||
if !win32.SetCurrentDirectoryW(p) {
|
||||
return _get_platform_error()
|
||||
}
|
||||
@@ -834,8 +834,8 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
|
||||
}
|
||||
|
||||
_exists :: proc(path: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
wpath, _ := _fix_long_path(path, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
wpath, _ := _fix_long_path(path, temp_allocator)
|
||||
attribs := win32.GetFileAttributesW(wpath)
|
||||
return attribs != win32.INVALID_FILE_ATTRIBUTES
|
||||
}
|
||||
|
||||
@@ -43,11 +43,6 @@ clone_to_cstring :: proc(s: string, allocator: runtime.Allocator) -> (res: cstri
|
||||
return cstring(&buf[0]), nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
temp_cstring :: proc(s: string) -> (cstring, runtime.Allocator_Error) #optional_allocator_error {
|
||||
return clone_to_cstring(s, temp_allocator())
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
string_from_null_terminated_bytes :: proc(b: []byte) -> (res: string) {
|
||||
s := string(b)
|
||||
|
||||
@@ -119,11 +119,11 @@ clean_path :: proc(path: string, allocator: runtime.Allocator) -> (cleaned: stri
|
||||
return strings.clone(".", allocator)
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
// The extra byte is to simplify appending path elements by letting the
|
||||
// loop to end each with a separator. We'll trim the last one when we're done.
|
||||
buffer := make([]u8, len(path) + 1, temp_allocator()) or_return
|
||||
buffer := make([]u8, len(path) + 1, temp_allocator) or_return
|
||||
|
||||
// This is the only point where Windows and POSIX differ, as Windows has
|
||||
// alphabet-based volumes for root paths.
|
||||
@@ -326,8 +326,8 @@ For example, `join_path({"/home", "foo", "bar.txt"})` will result in `"/home/foo
|
||||
join_path :: proc(elems: []string, allocator: runtime.Allocator) -> (joined: string, err: Error) {
|
||||
for e, i in elems {
|
||||
if e != "" {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
p := strings.join(elems[i:], Path_Separator_String, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
p := strings.join(elems[i:], Path_Separator_String, temp_allocator) or_return
|
||||
return clean_path(p, allocator)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ _is_path_separator :: proc(c: byte) -> bool {
|
||||
}
|
||||
|
||||
_mkdir :: proc(path: string, perm: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
path_cstr := temp_cstring(path) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
path_cstr := clone_to_cstring(path, temp_allocator) or_return
|
||||
return _get_platform_error(linux.mkdir(path_cstr, transmute(linux.Mode)u32(perm)))
|
||||
}
|
||||
|
||||
@@ -52,9 +52,9 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
}
|
||||
return _get_platform_error(errno)
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
// need something we can edit, and use to generate cstrings
|
||||
path_bytes := make([]u8, len(path) + 1, temp_allocator())
|
||||
path_bytes := make([]u8, len(path) + 1, temp_allocator)
|
||||
|
||||
// zero terminate the byte slice to make it a valid cstring
|
||||
copy(path_bytes, path)
|
||||
@@ -129,8 +129,8 @@ _remove_all :: proc(path: string) -> Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
path_cstr := temp_cstring(path) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
path_cstr := clone_to_cstring(path, temp_allocator) or_return
|
||||
|
||||
fd, errno := linux.open(path_cstr, _OPENDIR_FLAGS)
|
||||
#partial switch errno {
|
||||
@@ -168,14 +168,16 @@ _get_working_directory :: proc(allocator: runtime.Allocator) -> (string, Error)
|
||||
}
|
||||
|
||||
_set_working_directory :: proc(dir: string) -> Error {
|
||||
dir_cstr := temp_cstring(dir) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
dir_cstr := clone_to_cstring(dir, temp_allocator) or_return
|
||||
return _get_platform_error(linux.chdir(dir_cstr))
|
||||
}
|
||||
|
||||
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := make([dynamic]byte, 1024, temp_allocator()) or_return
|
||||
buf := make([dynamic]byte, 1024, temp_allocator) or_return
|
||||
for {
|
||||
n, errno := linux.readlink("/proc/self/exe", buf[:])
|
||||
if errno != .NONE {
|
||||
|
||||
@@ -5,9 +5,9 @@ import "base:runtime"
|
||||
import "core:sys/posix"
|
||||
|
||||
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := make([dynamic]byte, 1024, temp_allocator()) or_return
|
||||
buf := make([dynamic]byte, 1024, temp_allocator) or_return
|
||||
for {
|
||||
n := posix.readlink("/proc/curproc/exe", raw_data(buf), len(buf))
|
||||
if n < 0 {
|
||||
|
||||
@@ -35,11 +35,11 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err
|
||||
return real(arg, allocator)
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := strings.builder_make(temp_allocator())
|
||||
buf := strings.builder_make(temp_allocator)
|
||||
|
||||
paths := get_env("PATH", temp_allocator())
|
||||
paths := get_env("PATH", temp_allocator)
|
||||
for dir in strings.split_iterator(&paths, ":") {
|
||||
strings.builder_reset(&buf)
|
||||
strings.write_string(&buf, dir)
|
||||
|
||||
@@ -14,9 +14,9 @@ _is_path_separator :: proc(c: byte) -> bool {
|
||||
return c == _Path_Separator
|
||||
}
|
||||
|
||||
_mkdir :: proc(name: string, perm: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name)
|
||||
_mkdir :: proc(name: string, perm: int) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
if posix.mkdir(cname, transmute(posix.mode_t)posix._mode_t(perm)) != .OK {
|
||||
return _get_platform_error()
|
||||
}
|
||||
@@ -28,13 +28,13 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
return .Invalid_Path
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
if exists(path) {
|
||||
return .Exist
|
||||
}
|
||||
|
||||
clean_path := clean_path(path, temp_allocator()) or_return
|
||||
clean_path := clean_path(path, temp_allocator) or_return
|
||||
return internal_mkdir_all(clean_path, perm)
|
||||
|
||||
internal_mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
@@ -52,9 +52,9 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
}
|
||||
}
|
||||
|
||||
_remove_all :: proc(path: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cpath := temp_cstring(path)
|
||||
_remove_all :: proc(path: string) -> (err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cpath := clone_to_cstring(path, temp_allocator) or_return
|
||||
|
||||
dir := posix.opendir(cpath)
|
||||
if dir == nil {
|
||||
@@ -78,7 +78,7 @@ _remove_all :: proc(path: string) -> Error {
|
||||
continue
|
||||
}
|
||||
|
||||
fullpath, _ := concatenate({path, "/", string(cname), "\x00"}, temp_allocator())
|
||||
fullpath, _ := concatenate({path, "/", string(cname), "\x00"}, temp_allocator)
|
||||
if entry.d_type == .DIR {
|
||||
_remove_all(fullpath[:len(fullpath)-1]) or_return
|
||||
} else {
|
||||
@@ -95,10 +95,10 @@ _remove_all :: proc(path: string) -> Error {
|
||||
}
|
||||
|
||||
_get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf: [dynamic]byte
|
||||
buf.allocator = temp_allocator()
|
||||
buf.allocator = temp_allocator
|
||||
size := uint(posix.PATH_MAX)
|
||||
|
||||
cwd: cstring
|
||||
@@ -116,8 +116,8 @@ _get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, er
|
||||
}
|
||||
|
||||
_set_working_directory :: proc(dir: string) -> (err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cdir := temp_cstring(dir)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
cdir := clone_to_cstring(dir, temp_allocator) or_return
|
||||
if posix.chdir(cdir) != .OK {
|
||||
err = _get_platform_error()
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ _get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absol
|
||||
if rel == "" {
|
||||
rel = "."
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
rel_cstr := strings.clone_to_cstring(rel, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
rel_cstr := strings.clone_to_cstring(rel, temp_allocator)
|
||||
path_ptr := posix.realpath(rel_cstr, nil)
|
||||
if path_ptr == nil {
|
||||
return "", Platform_Error(posix.errno())
|
||||
|
||||
@@ -28,13 +28,13 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
return .Invalid_Path
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
if exists(path) {
|
||||
return .Exist
|
||||
}
|
||||
|
||||
clean_path := clean_path(path, temp_allocator())
|
||||
clean_path := clean_path(path, temp_allocator)
|
||||
return internal_mkdir_all(clean_path)
|
||||
|
||||
internal_mkdir_all :: proc(path: string) -> Error {
|
||||
|
||||
@@ -14,8 +14,8 @@ _is_path_separator :: proc(c: byte) -> bool {
|
||||
}
|
||||
|
||||
_mkdir :: proc(name: string, perm: int) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
if !win32.CreateDirectoryW(_fix_long_path(name, temp_allocator()) or_return, nil) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
if !win32.CreateDirectoryW(_fix_long_path(name, temp_allocator) or_return, nil) {
|
||||
return _get_platform_error()
|
||||
}
|
||||
return nil
|
||||
@@ -33,9 +33,9 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
return p, false, nil
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
dir_stat, err := stat(path, temp_allocator())
|
||||
dir_stat, err := stat(path, temp_allocator)
|
||||
if err == nil {
|
||||
if dir_stat.type == .Directory {
|
||||
return nil
|
||||
@@ -63,7 +63,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
|
||||
|
||||
err = mkdir(path, perm)
|
||||
if err != nil {
|
||||
new_dir_stat, err1 := lstat(path, temp_allocator())
|
||||
new_dir_stat, err1 := lstat(path, temp_allocator)
|
||||
if err1 == nil && new_dir_stat.type == .Directory {
|
||||
return nil
|
||||
}
|
||||
@@ -82,8 +82,8 @@ _remove_all :: proc(path: string) -> Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
dir := win32_utf8_to_wstring(path, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
dir := win32_utf8_to_wstring(path, temp_allocator) or_return
|
||||
|
||||
empty: [1]u16
|
||||
|
||||
@@ -109,10 +109,10 @@ _remove_all :: proc(path: string) -> Error {
|
||||
_get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
win32.AcquireSRWLockExclusive(&cwd_lock)
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
sz_utf16 := win32.GetCurrentDirectoryW(0, nil)
|
||||
dir_buf_wstr := make([]u16, sz_utf16, temp_allocator()) or_return
|
||||
dir_buf_wstr := make([]u16, sz_utf16, temp_allocator) or_return
|
||||
|
||||
sz_utf16 = win32.GetCurrentDirectoryW(win32.DWORD(len(dir_buf_wstr)), raw_data(dir_buf_wstr))
|
||||
assert(int(sz_utf16)+1 == len(dir_buf_wstr)) // the second time, it _excludes_ the NUL.
|
||||
@@ -123,8 +123,8 @@ _get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, er
|
||||
}
|
||||
|
||||
_set_working_directory :: proc(dir: string) -> (err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
wstr := win32_utf8_to_wstring(dir, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
wstr := win32_utf8_to_wstring(dir, temp_allocator) or_return
|
||||
|
||||
win32.AcquireSRWLockExclusive(&cwd_lock)
|
||||
|
||||
@@ -138,9 +138,9 @@ _set_working_directory :: proc(dir: string) -> (err: Error) {
|
||||
}
|
||||
|
||||
_get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := make([dynamic]u16, 512, temp_allocator()) or_return
|
||||
buf := make([dynamic]u16, 512, temp_allocator) or_return
|
||||
for {
|
||||
ret := win32.GetModuleFileNameW(nil, raw_data(buf), win32.DWORD(len(buf)))
|
||||
if ret == 0 {
|
||||
@@ -222,10 +222,10 @@ _fix_long_path_internal :: proc(path: string) -> string {
|
||||
return path
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
PREFIX :: `\\?`
|
||||
path_buf := make([]byte, len(PREFIX)+len(path)+1, temp_allocator())
|
||||
path_buf := make([]byte, len(PREFIX)+len(path)+1, temp_allocator)
|
||||
copy(path_buf, PREFIX)
|
||||
n := len(path)
|
||||
r, w := 0, len(PREFIX)
|
||||
@@ -297,14 +297,14 @@ _get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absol
|
||||
if rel == "" {
|
||||
rel = "."
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
rel_utf16 := win32.utf8_to_utf16(rel, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
rel_utf16 := win32.utf8_to_utf16(rel, temp_allocator)
|
||||
n := win32.GetFullPathNameW(raw_data(rel_utf16), 0, nil, nil)
|
||||
if n == 0 {
|
||||
return "", Platform_Error(win32.GetLastError())
|
||||
}
|
||||
|
||||
buf := make([]u16, n, temp_allocator()) or_return
|
||||
buf := make([]u16, n, temp_allocator) or_return
|
||||
n = win32.GetFullPathNameW(raw_data(rel_utf16), u32(n), raw_data(buf), nil)
|
||||
if n == 0 {
|
||||
return "", Platform_Error(win32.GetLastError())
|
||||
|
||||
@@ -50,7 +50,7 @@ _get_ppid :: proc() -> int {
|
||||
|
||||
@(private="package")
|
||||
_process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
dir_fd, errno := linux.open("/proc/", _OPENDIR_FLAGS)
|
||||
#partial switch errno {
|
||||
@@ -68,9 +68,9 @@ _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error)
|
||||
}
|
||||
defer linux.close(dir_fd)
|
||||
|
||||
dynamic_list := make([dynamic]int, temp_allocator()) or_return
|
||||
dynamic_list := make([dynamic]int, temp_allocator) or_return
|
||||
|
||||
buf := make([dynamic]u8, 128, 128, temp_allocator()) or_return
|
||||
buf := make([dynamic]u8, 128, 128, temp_allocator) or_return
|
||||
loop: for {
|
||||
buflen: int
|
||||
buflen, errno = linux.getdents(dir_fd, buf[:])
|
||||
@@ -100,7 +100,7 @@ _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error)
|
||||
|
||||
@(private="package")
|
||||
_process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
info.pid = pid
|
||||
|
||||
@@ -126,7 +126,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
|
||||
passwd_bytes: []u8
|
||||
passwd_err: Error
|
||||
passwd_bytes, passwd_err = _read_entire_pseudo_file_cstring("/etc/passwd", temp_allocator())
|
||||
passwd_bytes, passwd_err = _read_entire_pseudo_file_cstring("/etc/passwd", temp_allocator)
|
||||
if passwd_err != nil {
|
||||
err = passwd_err
|
||||
break username_if
|
||||
@@ -168,7 +168,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
strings.write_int(&path_builder, pid)
|
||||
strings.write_string(&path_builder, "/cmdline")
|
||||
|
||||
cmdline_bytes, cmdline_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator())
|
||||
cmdline_bytes, cmdline_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator)
|
||||
if cmdline_err != nil || len(cmdline_bytes) == 0 {
|
||||
err = cmdline_err
|
||||
break cmdline_if
|
||||
@@ -189,7 +189,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
strings.write_int(&path_builder, pid)
|
||||
strings.write_string(&path_builder, "/cwd")
|
||||
|
||||
cwd, cwd_err = _read_link_cstr(strings.to_cstring(&path_builder) or_return, temp_allocator()) // allowed to fail
|
||||
cwd, cwd_err = _read_link_cstr(strings.to_cstring(&path_builder) or_return, temp_allocator) // allowed to fail
|
||||
if cwd_err == nil && .Working_Dir in selection {
|
||||
info.working_dir = strings.clone(cwd, allocator) or_return
|
||||
info.fields += {.Working_Dir}
|
||||
@@ -245,7 +245,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
strings.write_int(&path_builder, pid)
|
||||
strings.write_string(&path_builder, "/stat")
|
||||
|
||||
proc_stat_bytes, stat_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator())
|
||||
proc_stat_bytes, stat_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator)
|
||||
if stat_err != nil {
|
||||
err = stat_err
|
||||
break stat_if
|
||||
@@ -284,7 +284,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
Nice,
|
||||
//... etc,
|
||||
}
|
||||
stat_fields := strings.split(stats, " ", temp_allocator()) or_return
|
||||
stat_fields := strings.split(stats, " ", temp_allocator) or_return
|
||||
|
||||
if len(stat_fields) <= int(Fields.Nice) {
|
||||
break stat_if
|
||||
@@ -327,7 +327,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
strings.write_int(&path_builder, pid)
|
||||
strings.write_string(&path_builder, "/exe")
|
||||
|
||||
if exe_bytes, exe_err := _read_link(strings.to_string(path_builder), temp_allocator()); exe_err == nil {
|
||||
if exe_bytes, exe_err := _read_link(strings.to_string(path_builder), temp_allocator); exe_err == nil {
|
||||
info.executable_path = strings.clone(string(exe_bytes), allocator) or_return
|
||||
info.fields += {.Executable_Path}
|
||||
} else {
|
||||
@@ -341,7 +341,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
strings.write_int(&path_builder, pid)
|
||||
strings.write_string(&path_builder, "/environ")
|
||||
|
||||
if env_bytes, env_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator()); env_err == nil {
|
||||
if env_bytes, env_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator); env_err == nil {
|
||||
env := string(env_bytes)
|
||||
|
||||
env_list := make([dynamic]string, allocator) or_return
|
||||
@@ -392,7 +392,7 @@ _process_open :: proc(pid: int, _: Process_Open_Flags) -> (process: Process, err
|
||||
|
||||
@(private="package")
|
||||
_process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
if len(desc.command) == 0 {
|
||||
return process, .Invalid_Command
|
||||
@@ -401,7 +401,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
dir_fd := linux.AT_FDCWD
|
||||
errno: linux.Errno
|
||||
if desc.working_dir != "" {
|
||||
dir_cstr := temp_cstring(desc.working_dir) or_return
|
||||
dir_cstr := clone_to_cstring(desc.working_dir, temp_allocator) or_return
|
||||
if dir_fd, errno = linux.open(dir_cstr, _OPENDIR_FLAGS); errno != .NONE {
|
||||
return process, _get_platform_error(errno)
|
||||
}
|
||||
@@ -414,10 +414,10 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
exe_path: cstring
|
||||
executable_name := desc.command[0]
|
||||
if strings.index_byte(executable_name, '/') < 0 {
|
||||
path_env := get_env("PATH", temp_allocator())
|
||||
path_dirs := split_path_list(path_env, temp_allocator()) or_return
|
||||
path_env := get_env("PATH", temp_allocator)
|
||||
path_dirs := split_path_list(path_env, temp_allocator) or_return
|
||||
|
||||
exe_builder := strings.builder_make(temp_allocator()) or_return
|
||||
exe_builder := strings.builder_make(temp_allocator) or_return
|
||||
|
||||
found: bool
|
||||
for dir in path_dirs {
|
||||
@@ -444,7 +444,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
exe_path = temp_cstring(executable_name) or_return
|
||||
exe_path = clone_to_cstring(executable_name, temp_allocator) or_return
|
||||
if linux.access(exe_path, linux.X_OK) != .NONE {
|
||||
return process, .Not_Exist
|
||||
}
|
||||
@@ -452,20 +452,20 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
|
||||
// args and environment need to be a list of cstrings
|
||||
// that are terminated by a nil pointer.
|
||||
cargs := make([]cstring, len(desc.command) + 1, temp_allocator()) or_return
|
||||
cargs := make([]cstring, len(desc.command) + 1, temp_allocator) or_return
|
||||
for command, i in desc.command {
|
||||
cargs[i] = temp_cstring(command) or_return
|
||||
cargs[i] = clone_to_cstring(command, temp_allocator) or_return
|
||||
}
|
||||
|
||||
// Use current process' environment if description didn't provide it.
|
||||
env: [^]cstring
|
||||
if desc.env == nil {
|
||||
// take this process's current environment
|
||||
env = raw_data(export_cstring_environment(temp_allocator()))
|
||||
env = raw_data(export_cstring_environment(temp_allocator))
|
||||
} else {
|
||||
cenv := make([]cstring, len(desc.env) + 1, temp_allocator()) or_return
|
||||
cenv := make([]cstring, len(desc.env) + 1, temp_allocator) or_return
|
||||
for env, i in desc.env {
|
||||
cenv[i] = temp_cstring(env) or_return
|
||||
cenv[i] = clone_to_cstring(env, temp_allocator) or_return
|
||||
}
|
||||
env = &cenv[0]
|
||||
}
|
||||
@@ -593,7 +593,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
}
|
||||
|
||||
_process_state_update_times :: proc(state: ^Process_State) -> (err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
stat_path_buf: [48]u8
|
||||
path_builder := strings.builder_from_bytes(stat_path_buf[:])
|
||||
@@ -602,7 +602,7 @@ _process_state_update_times :: proc(state: ^Process_State) -> (err: Error) {
|
||||
strings.write_string(&path_builder, "/stat")
|
||||
|
||||
stat_buf: []u8
|
||||
stat_buf, err = _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator())
|
||||
stat_buf, err = _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -52,14 +52,14 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
return
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
// search PATH if just a plain name is provided.
|
||||
exe_builder := strings.builder_make(temp_allocator())
|
||||
exe_builder := strings.builder_make(temp_allocator)
|
||||
exe_name := desc.command[0]
|
||||
if strings.index_byte(exe_name, '/') < 0 {
|
||||
path_env := get_env("PATH", temp_allocator())
|
||||
path_dirs := split_path_list(path_env, temp_allocator()) or_return
|
||||
path_env := get_env("PATH", temp_allocator)
|
||||
path_dirs := split_path_list(path_env, temp_allocator) or_return
|
||||
|
||||
found: bool
|
||||
for dir in path_dirs {
|
||||
@@ -108,12 +108,12 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
}
|
||||
|
||||
cwd: cstring; if desc.working_dir != "" {
|
||||
cwd = temp_cstring(desc.working_dir)
|
||||
cwd = clone_to_cstring(desc.working_dir, temp_allocator) or_return
|
||||
}
|
||||
|
||||
cmd := make([]cstring, len(desc.command) + 1, temp_allocator())
|
||||
cmd := make([]cstring, len(desc.command) + 1, temp_allocator)
|
||||
for part, i in desc.command {
|
||||
cmd[i] = temp_cstring(part)
|
||||
cmd[i] = clone_to_cstring(part, temp_allocator) or_return
|
||||
}
|
||||
|
||||
env: [^]cstring
|
||||
@@ -121,9 +121,9 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
// take this process's current environment
|
||||
env = posix.environ
|
||||
} else {
|
||||
cenv := make([]cstring, len(desc.env) + 1, temp_allocator())
|
||||
cenv := make([]cstring, len(desc.env) + 1, temp_allocator)
|
||||
for env, i in desc.env {
|
||||
cenv[i] = temp_cstring(env)
|
||||
cenv[i] = clone_to_cstring(env, temp_allocator) or_return
|
||||
}
|
||||
env = raw_data(cenv)
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
}
|
||||
|
||||
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
info.pid = pid
|
||||
|
||||
// Thought on errors is: allocation failures return immediately (also why the non-allocation stuff is done first),
|
||||
@@ -127,7 +128,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
break args
|
||||
}
|
||||
|
||||
buf := runtime.make_aligned([]byte, length, 4, temp_allocator())
|
||||
buf := runtime.make_aligned([]byte, length, 4, temp_allocator)
|
||||
if sysctl(raw_data(mib), 3, raw_data(buf), &length, nil, 0) != .OK {
|
||||
if err == nil {
|
||||
err = _get_platform_error()
|
||||
@@ -239,9 +240,9 @@ _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error)
|
||||
return
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buffer := make([]i32, ret, temp_allocator())
|
||||
buffer := make([]i32, ret, temp_allocator)
|
||||
ret = darwin.proc_listallpids(raw_data(buffer), ret*size_of(i32))
|
||||
if ret < 0 {
|
||||
err = _get_platform_error()
|
||||
|
||||
@@ -162,9 +162,10 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
if selection >= {.Command_Line, .Command_Args} {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return
|
||||
temp_allocator_scope(temp_allocator)
|
||||
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
@@ -179,9 +180,9 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
}
|
||||
}
|
||||
if .Environment in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator_scope(temp_allocator)
|
||||
env_len := process_params.EnvironmentSize / 2
|
||||
envs_w := make([]u16, env_len, temp_allocator()) or_return
|
||||
envs_w := make([]u16, env_len, temp_allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.Environment, envs_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
@@ -190,8 +191,8 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
|
||||
info.fields += {.Environment}
|
||||
}
|
||||
if .Working_Dir in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return
|
||||
temp_allocator_scope(temp_allocator)
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
@@ -272,9 +273,10 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
|
||||
if err != nil {
|
||||
break read_peb
|
||||
}
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
if selection >= {.Command_Line, .Command_Args} {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return
|
||||
temp_allocator_scope(temp_allocator)
|
||||
cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
@@ -289,9 +291,9 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
|
||||
}
|
||||
}
|
||||
if .Environment in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator_scope(temp_allocator)
|
||||
env_len := process_params.EnvironmentSize / 2
|
||||
envs_w := make([]u16, env_len, temp_allocator()) or_return
|
||||
envs_w := make([]u16, env_len, temp_allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.Environment, envs_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
@@ -300,8 +302,8 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
|
||||
info.fields += {.Environment}
|
||||
}
|
||||
if .Working_Dir in selection {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return
|
||||
temp_allocator_scope(temp_allocator)
|
||||
cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator) or_return
|
||||
_, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w)
|
||||
if err != nil {
|
||||
break read_peb
|
||||
@@ -419,15 +421,15 @@ _process_open :: proc(pid: int, flags: Process_Open_Flags) -> (process: Process,
|
||||
|
||||
@(private="package")
|
||||
_process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
command_line := _build_command_line(desc.command, temp_allocator())
|
||||
command_line_w := win32_utf8_to_wstring(command_line, temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
command_line := _build_command_line(desc.command, temp_allocator)
|
||||
command_line_w := win32_utf8_to_wstring(command_line, temp_allocator) or_return
|
||||
environment := desc.env
|
||||
if desc.env == nil {
|
||||
environment = environ(temp_allocator()) or_return
|
||||
environment = environ(temp_allocator) or_return
|
||||
}
|
||||
environment_block := _build_environment_block(environment, temp_allocator())
|
||||
environment_block_w := win32_utf8_to_utf16(environment_block, temp_allocator()) or_return
|
||||
environment_block := _build_environment_block(environment, temp_allocator)
|
||||
environment_block_w := win32_utf8_to_utf16(environment_block, temp_allocator) or_return
|
||||
|
||||
stderr_handle: win32.HANDLE
|
||||
stdout_handle: win32.HANDLE
|
||||
@@ -474,7 +476,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
|
||||
stdin_handle = win32.HANDLE((^File_Impl)(desc.stdin.impl).fd)
|
||||
}
|
||||
|
||||
working_dir_w := (win32_utf8_to_wstring(desc.working_dir, temp_allocator()) or_else nil) if len(desc.working_dir) > 0 else nil
|
||||
working_dir_w := (win32_utf8_to_wstring(desc.working_dir, temp_allocator) or_else nil) if len(desc.working_dir) > 0 else nil
|
||||
process_info: win32.PROCESS_INFORMATION
|
||||
ok := win32.CreateProcessW(
|
||||
nil,
|
||||
@@ -612,7 +614,7 @@ _process_exe_by_pid :: proc(pid: int, allocator: runtime.Allocator) -> (exe_path
|
||||
}
|
||||
|
||||
_get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Allocator) -> (full_username: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
token_handle: win32.HANDLE
|
||||
if !win32.OpenProcessToken(process_handle, win32.TOKEN_QUERY, &token_handle) {
|
||||
err = _get_platform_error()
|
||||
@@ -627,7 +629,7 @@ _get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Alloc
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
token_user := (^win32.TOKEN_USER)(raw_data(make([]u8, token_user_size, temp_allocator()) or_return))
|
||||
token_user := (^win32.TOKEN_USER)(raw_data(make([]u8, token_user_size, temp_allocator) or_return))
|
||||
if !win32.GetTokenInformation(token_handle, .TokenUser, token_user, token_user_size, &token_user_size) {
|
||||
err = _get_platform_error()
|
||||
return
|
||||
@@ -643,8 +645,8 @@ _get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Alloc
|
||||
err = _get_platform_error()
|
||||
return
|
||||
}
|
||||
username := win32_utf16_to_utf8(username_w[:username_chrs], temp_allocator()) or_return
|
||||
domain := win32_utf16_to_utf8(domain_w[:domain_chrs], temp_allocator()) or_return
|
||||
username := win32_utf16_to_utf8(username_w[:username_chrs], temp_allocator) or_return
|
||||
domain := win32_utf16_to_utf8(domain_w[:domain_chrs], temp_allocator) or_return
|
||||
return strings.concatenate({domain, "\\", username}, allocator)
|
||||
}
|
||||
|
||||
|
||||
@@ -73,14 +73,14 @@ last_write_time_by_name :: modification_time_by_path
|
||||
|
||||
@(require_results)
|
||||
modification_time :: proc(f: ^File) -> (time.Time, Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
fi, err := fstat(f, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
fi, err := fstat(f, temp_allocator)
|
||||
return fi.modification_time, err
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
modification_time_by_path :: proc(path: string) -> (time.Time, Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
fi, err := stat(path, temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
fi, err := stat(path, temp_allocator)
|
||||
return fi.modification_time, err
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ _fstat_internal :: proc(fd: linux.Fd, allocator: runtime.Allocator) -> (fi: File
|
||||
|
||||
// NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath
|
||||
_stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
fd, errno := linux.open(name_cstr, {})
|
||||
if errno != .NONE {
|
||||
@@ -59,8 +59,8 @@ _stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err
|
||||
}
|
||||
|
||||
_lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
name_cstr := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
fd, errno := linux.open(name_cstr, {.PATH, .NOFOLLOW})
|
||||
if errno != .NONE {
|
||||
|
||||
@@ -69,8 +69,8 @@ _stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err
|
||||
return
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
cname := temp_cstring(name) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
cname := clone_to_cstring(name, temp_allocator) or_return
|
||||
|
||||
fd := posix.open(cname, {})
|
||||
if fd == -1 {
|
||||
@@ -96,33 +96,34 @@ _lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, er
|
||||
return
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
// NOTE: can't use realpath or open (+ fcntl F_GETPATH) here because it tries to resolve symlinks.
|
||||
|
||||
// NOTE: This might not be correct when given "/symlink/foo.txt",
|
||||
// you would want that to resolve "/symlink", but not resolve "foo.txt".
|
||||
|
||||
fullpath := clean_path(name, temp_allocator()) or_return
|
||||
fullpath := clean_path(name, temp_allocator) or_return
|
||||
assert(len(fullpath) > 0)
|
||||
switch {
|
||||
case fullpath[0] == '/':
|
||||
// nothing.
|
||||
case fullpath == ".":
|
||||
fullpath = getwd(temp_allocator()) or_return
|
||||
fullpath = getwd(temp_allocator) or_return
|
||||
case len(fullpath) > 1 && fullpath[0] == '.' && fullpath[1] == '/':
|
||||
fullpath = fullpath[2:]
|
||||
fallthrough
|
||||
case:
|
||||
fullpath = concatenate({
|
||||
getwd(temp_allocator()) or_return,
|
||||
getwd(temp_allocator) or_return,
|
||||
"/",
|
||||
fullpath,
|
||||
}, temp_allocator()) or_return
|
||||
}, temp_allocator) or_return
|
||||
}
|
||||
|
||||
stat: posix.stat_t
|
||||
if posix.lstat(temp_cstring(fullpath), &stat) != .OK {
|
||||
c_fullpath := clone_to_cstring(fullpath, temp_allocator) or_return
|
||||
if posix.lstat(c_fullpath, &stat) != .OK {
|
||||
err = _get_platform_error()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -45,15 +45,15 @@ full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path
|
||||
name = "."
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
p := win32_utf8_to_utf16(name, temp_allocator()) or_return
|
||||
p := win32_utf8_to_utf16(name, temp_allocator) or_return
|
||||
|
||||
n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil)
|
||||
if n == 0 {
|
||||
return "", _get_platform_error()
|
||||
}
|
||||
buf := make([]u16, n+1, temp_allocator())
|
||||
buf := make([]u16, n+1, temp_allocator)
|
||||
n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
|
||||
if n == 0 {
|
||||
return "", _get_platform_error()
|
||||
@@ -65,9 +65,9 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runt
|
||||
if len(name) == 0 {
|
||||
return {}, .Not_Exist
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
wname := _fix_long_path(name, temp_allocator()) or_return
|
||||
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 {
|
||||
@@ -137,9 +137,9 @@ _cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (strin
|
||||
return "", _get_platform_error()
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
buf := make([]u16, max(n, 260)+1, temp_allocator())
|
||||
buf := make([]u16, max(n, 260)+1, temp_allocator)
|
||||
n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0)
|
||||
return _cleanpath_from_buf(buf[:n], allocator)
|
||||
}
|
||||
@@ -155,9 +155,9 @@ _cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) {
|
||||
return nil, _get_platform_error()
|
||||
}
|
||||
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
buf := make([]u16, max(n, 260)+1, temp_allocator())
|
||||
buf := make([]u16, max(n, 260)+1, temp_allocator)
|
||||
n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0)
|
||||
return _cleanpath_strip_prefix(buf[:n]), nil
|
||||
}
|
||||
|
||||
@@ -15,13 +15,13 @@ MAX_ATTEMPTS :: 1<<13 // Should be enough for everyone, right?
|
||||
// The caller must `close` the file once finished with.
|
||||
@(require_results)
|
||||
create_temp_file :: proc(dir, pattern: string) -> (f: ^File, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
dir := dir if dir != "" else temp_directory(temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
dir := dir if dir != "" else temp_directory(temp_allocator) or_return
|
||||
prefix, suffix := _prefix_and_suffix(pattern) or_return
|
||||
prefix = temp_join_path(dir, prefix) or_return
|
||||
|
||||
rand_buf: [10]byte
|
||||
name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator())
|
||||
name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator)
|
||||
|
||||
attempts := 0
|
||||
for {
|
||||
@@ -47,13 +47,13 @@ mkdir_temp :: make_directory_temp
|
||||
// If `dir` is an empty tring, `temp_directory()` will be used.
|
||||
@(require_results)
|
||||
make_directory_temp :: proc(dir, pattern: string, allocator: runtime.Allocator) -> (temp_path: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
dir := dir if dir != "" else temp_directory(temp_allocator()) or_return
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
dir := dir if dir != "" else temp_directory(temp_allocator) or_return
|
||||
prefix, suffix := _prefix_and_suffix(pattern) or_return
|
||||
prefix = temp_join_path(dir, prefix) or_return
|
||||
|
||||
rand_buf: [10]byte
|
||||
name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator())
|
||||
name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator)
|
||||
|
||||
attempts := 0
|
||||
for {
|
||||
@@ -70,7 +70,7 @@ make_directory_temp :: proc(dir, pattern: string, allocator: runtime.Allocator)
|
||||
return "", err
|
||||
}
|
||||
if err == .Not_Exist {
|
||||
if _, serr := stat(dir, temp_allocator()); serr == .Not_Exist {
|
||||
if _, serr := stat(dir, temp_allocator); serr == .Not_Exist {
|
||||
return "", serr
|
||||
}
|
||||
}
|
||||
@@ -89,9 +89,11 @@ temp_directory :: proc(allocator: runtime.Allocator) -> (string, Error) {
|
||||
|
||||
@(private="file")
|
||||
temp_join_path :: proc(dir, name: string) -> (string, runtime.Allocator_Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
if len(dir) > 0 && is_path_separator(dir[len(dir)-1]) {
|
||||
return concatenate({dir, name}, temp_allocator(),)
|
||||
return concatenate({dir, name}, temp_allocator,)
|
||||
}
|
||||
|
||||
return concatenate({dir, Path_Separator_String, name}, temp_allocator())
|
||||
return concatenate({dir, Path_Separator_String, name}, temp_allocator)
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ package os2
|
||||
import "base:runtime"
|
||||
|
||||
_temp_dir :: proc(allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
tmpdir := get_env("TMPDIR", temp_allocator())
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
tmpdir := get_env("TMPDIR", temp_allocator)
|
||||
if tmpdir == "" {
|
||||
tmpdir = "/tmp"
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ _temp_dir :: proc(allocator: runtime.Allocator) -> (string, runtime.Allocator_Er
|
||||
if n == 0 {
|
||||
return "", nil
|
||||
}
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
b := make([]u16, max(win32.MAX_PATH, n), temp_allocator())
|
||||
b := make([]u16, max(win32.MAX_PATH, n), temp_allocator)
|
||||
n = win32.GetTempPathW(u32(len(b)), raw_data(b))
|
||||
|
||||
if n == 3 && b[1] == ':' && b[2] == '\\' {
|
||||
|
||||
@@ -4,27 +4,27 @@ import "base:runtime"
|
||||
|
||||
@(require_results)
|
||||
user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
#partial switch ODIN_OS {
|
||||
case .Windows:
|
||||
dir = get_env("LocalAppData", temp_allocator())
|
||||
dir = get_env("LocalAppData", temp_allocator)
|
||||
if dir != "" {
|
||||
dir = clone_string(dir, allocator) or_return
|
||||
dir = clone_string(dir, temp_allocator) or_return
|
||||
}
|
||||
case .Darwin:
|
||||
dir = get_env("HOME", temp_allocator())
|
||||
dir = get_env("HOME", temp_allocator)
|
||||
if dir != "" {
|
||||
dir = concatenate({dir, "/Library/Caches"}, allocator) or_return
|
||||
dir = concatenate({dir, "/Library/Caches"}, temp_allocator) or_return
|
||||
}
|
||||
case: // All other UNIX systems
|
||||
dir = get_env("XDG_CACHE_HOME", allocator)
|
||||
if dir == "" {
|
||||
dir = get_env("HOME", temp_allocator())
|
||||
dir = get_env("HOME", temp_allocator)
|
||||
if dir == "" {
|
||||
return
|
||||
}
|
||||
dir = concatenate({dir, "/.cache"}, allocator) or_return
|
||||
dir = concatenate({dir, "/.cache"}, temp_allocator) or_return
|
||||
}
|
||||
}
|
||||
if dir == "" {
|
||||
@@ -35,23 +35,23 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error
|
||||
|
||||
@(require_results)
|
||||
user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
|
||||
#partial switch ODIN_OS {
|
||||
case .Windows:
|
||||
dir = get_env("AppData", temp_allocator())
|
||||
dir = get_env("AppData", temp_allocator)
|
||||
if dir != "" {
|
||||
dir = clone_string(dir, allocator) or_return
|
||||
}
|
||||
case .Darwin:
|
||||
dir = get_env("HOME", temp_allocator())
|
||||
dir = get_env("HOME", temp_allocator)
|
||||
if dir != "" {
|
||||
dir = concatenate({dir, "/.config"}, allocator) or_return
|
||||
}
|
||||
case: // All other UNIX systems
|
||||
dir = get_env("XDG_CONFIG_HOME", allocator)
|
||||
if dir == "" {
|
||||
dir = get_env("HOME", temp_allocator())
|
||||
dir = get_env("HOME", temp_allocator)
|
||||
if dir == "" {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user