mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
convert all to use sys/linux over sys/unix; new implementations for pipe, process and env
This commit is contained in:
+227
-161
@@ -1,39 +1,60 @@
|
||||
//+private
|
||||
package os2
|
||||
|
||||
import "base:runtime"
|
||||
import "core:io"
|
||||
import "core:time"
|
||||
import "core:sys/unix"
|
||||
|
||||
INVALID_HANDLE :: -1
|
||||
|
||||
_O_RDONLY :: 0o00000000
|
||||
_O_WRONLY :: 0o00000001
|
||||
_O_RDWR :: 0o00000002
|
||||
_O_CREAT :: 0o00000100
|
||||
_O_EXCL :: 0o00000200
|
||||
_O_NOCTTY :: 0o00000400
|
||||
_O_TRUNC :: 0o00001000
|
||||
_O_APPEND :: 0o00002000
|
||||
_O_NONBLOCK :: 0o00004000
|
||||
_O_LARGEFILE :: 0o00100000
|
||||
_O_DIRECTORY :: 0o00200000
|
||||
_O_NOFOLLOW :: 0o00400000
|
||||
_O_SYNC :: 0o04010000
|
||||
_O_CLOEXEC :: 0o02000000
|
||||
_O_PATH :: 0o10000000
|
||||
|
||||
_AT_FDCWD :: -100
|
||||
|
||||
_CSTRING_NAME_HEAP_THRESHOLD :: 512
|
||||
import "base:runtime"
|
||||
import "core:sys/linux"
|
||||
|
||||
_File :: struct {
|
||||
name: string,
|
||||
fd: int,
|
||||
fd: linux.Fd,
|
||||
allocator: runtime.Allocator,
|
||||
}
|
||||
|
||||
_stdin : File = {
|
||||
impl = {
|
||||
name = "/proc/self/fd/0",
|
||||
fd = 0,
|
||||
allocator = _file_allocator(),
|
||||
},
|
||||
stream = {
|
||||
procedure = _file_stream_proc,
|
||||
},
|
||||
}
|
||||
_stdout : File = {
|
||||
impl = {
|
||||
name = "/proc/self/fd/1",
|
||||
fd = 1,
|
||||
allocator = _file_allocator(),
|
||||
},
|
||||
stream = {
|
||||
procedure = _file_stream_proc,
|
||||
},
|
||||
}
|
||||
_stderr : File = {
|
||||
impl = {
|
||||
name = "/proc/self/fd/2",
|
||||
fd = 2,
|
||||
allocator = _file_allocator(),
|
||||
},
|
||||
stream = {
|
||||
procedure = _file_stream_proc,
|
||||
},
|
||||
}
|
||||
|
||||
@init
|
||||
_standard_stream_init :: proc() {
|
||||
// cannot define these manually because cyclic reference
|
||||
_stdin.stream.data = &_stdin
|
||||
_stdout.stream.data = &_stdout
|
||||
_stderr.stream.data = &_stderr
|
||||
}
|
||||
|
||||
_file_allocator :: proc() -> runtime.Allocator {
|
||||
return heap_allocator()
|
||||
}
|
||||
|
||||
_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (f: ^File, err: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
@@ -41,40 +62,48 @@ _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (f: ^File, er
|
||||
// Just default to using O_NOCTTY because needing to open a controlling
|
||||
// terminal would be incredibly rare. This has no effect on files while
|
||||
// allowing us to open serial devices.
|
||||
flags_i: int = _O_NOCTTY
|
||||
sys_flags: linux.Open_Flags = {.NOCTTY}
|
||||
switch flags & O_RDONLY|O_WRONLY|O_RDWR {
|
||||
case O_RDONLY: flags_i = _O_RDONLY
|
||||
case O_WRONLY: flags_i = _O_WRONLY
|
||||
case O_RDWR: flags_i = _O_RDWR
|
||||
case O_RDONLY:
|
||||
case O_WRONLY: sys_flags += {.WRONLY}
|
||||
case O_RDWR: sys_flags += {.RDWR}
|
||||
}
|
||||
|
||||
if .Append in flags { flags_i |= _O_APPEND }
|
||||
if .Create in flags { flags_i |= _O_CREAT }
|
||||
if .Excl in flags { flags_i |= _O_EXCL }
|
||||
if .Sync in flags { flags_i |= _O_SYNC }
|
||||
if .Trunc in flags { flags_i |= _O_TRUNC }
|
||||
if .Close_On_Exec in flags { flags_i |= _O_CLOEXEC }
|
||||
if .Append in flags { sys_flags += {.APPEND} }
|
||||
if .Create in flags { sys_flags += {.CREAT} }
|
||||
if .Excl in flags { sys_flags += {.EXCL} }
|
||||
if .Sync in flags { sys_flags += {.DSYNC} }
|
||||
if .Trunc in flags { sys_flags += {.TRUNC} }
|
||||
if .Close_On_Exec in flags { sys_flags += {.CLOEXEC} }
|
||||
|
||||
fd := unix.sys_open(name_cstr, flags_i, uint(perm))
|
||||
if fd < 0 {
|
||||
return nil, _get_platform_error(fd)
|
||||
fd, errno := linux.open(name_cstr, sys_flags, transmute(linux.Mode)(u32(perm)))
|
||||
if errno != .NONE {
|
||||
return nil, _get_platform_error(errno)
|
||||
}
|
||||
|
||||
return _new_file(uintptr(fd), name), nil
|
||||
}
|
||||
|
||||
_new_file :: proc(fd: uintptr, _: string) -> ^File {
|
||||
_new_file :: proc(fd: uintptr, _: string = "") -> ^File {
|
||||
file := new(File, file_allocator())
|
||||
file.impl.fd = int(fd)
|
||||
file.impl.allocator = file_allocator()
|
||||
file.impl.name = _get_full_path(file.impl.fd, file.impl.allocator)
|
||||
file.stream = {
|
||||
data = file,
|
||||
procedure = _file_stream_proc,
|
||||
}
|
||||
_construct_file(file, fd, "")
|
||||
return file
|
||||
}
|
||||
|
||||
_construct_file :: proc(file: ^File, fd: uintptr, _: string = "") {
|
||||
file^ = {
|
||||
impl = {
|
||||
fd = linux.Fd(fd),
|
||||
allocator = file_allocator(),
|
||||
name = _get_full_path(file.impl.fd, file.impl.allocator),
|
||||
},
|
||||
stream = {
|
||||
data = file,
|
||||
procedure = _file_stream_proc,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
_destroy :: proc(f: ^File) -> Error {
|
||||
if f == nil {
|
||||
return nil
|
||||
@@ -86,12 +115,15 @@ _destroy :: proc(f: ^File) -> Error {
|
||||
|
||||
|
||||
_close :: proc(f: ^File) -> Error {
|
||||
if f != nil {
|
||||
res := unix.sys_close(f.impl.fd)
|
||||
_destroy(f)
|
||||
return _ok_or_error(res)
|
||||
if f == nil {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
errno := linux.close(f.impl.fd)
|
||||
if errno == .EBADF { // avoid possible double free
|
||||
return _get_platform_error(errno)
|
||||
}
|
||||
_destroy(f)
|
||||
return _get_platform_error(errno)
|
||||
}
|
||||
|
||||
_fd :: proc(f: ^File) -> uintptr {
|
||||
@@ -106,20 +138,32 @@ _name :: proc(f: ^File) -> string {
|
||||
}
|
||||
|
||||
_seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Error) {
|
||||
res := unix.sys_lseek(f.impl.fd, offset, int(whence))
|
||||
if res < 0 {
|
||||
return -1, _get_platform_error(int(res))
|
||||
n, errno := linux.lseek(f.impl.fd, offset, linux.Seek_Whence(whence))
|
||||
if errno != .NONE {
|
||||
return -1, _get_platform_error(errno)
|
||||
}
|
||||
return res, nil
|
||||
return n, nil
|
||||
}
|
||||
|
||||
_read :: proc(f: ^File, p: []byte) -> (i64, Error) {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
n := unix.sys_read(f.impl.fd, &p[0], len(p))
|
||||
if n < 0 {
|
||||
return -1, _get_platform_error(n)
|
||||
n, errno := linux.read(f.impl.fd, p[:])
|
||||
if errno != .NONE {
|
||||
return -1, _get_platform_error(errno)
|
||||
}
|
||||
return i64(n), n == 0 ? io.Error.EOF : nil
|
||||
}
|
||||
|
||||
_read_at :: proc(f: ^File, p: []byte, offset: i64) -> (i64, Error) {
|
||||
if offset < 0 {
|
||||
return 0, .Invalid_Offset
|
||||
}
|
||||
|
||||
n, errno := linux.pread(f.impl.fd, p[:], offset)
|
||||
if errno != .NONE {
|
||||
return -1, _get_platform_error(errno)
|
||||
}
|
||||
if n == 0 {
|
||||
return 0, .EOF
|
||||
@@ -127,91 +171,67 @@ _read :: proc(f: ^File, p: []byte) -> (i64, Error) {
|
||||
return i64(n), nil
|
||||
}
|
||||
|
||||
_read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: i64, err: Error) {
|
||||
if offset < 0 {
|
||||
return 0, .Invalid_Offset
|
||||
}
|
||||
|
||||
b, offset := p, offset
|
||||
for len(b) > 0 {
|
||||
m := unix.sys_pread(f.impl.fd, &b[0], len(b), offset)
|
||||
if m < 0 {
|
||||
return -1, _get_platform_error(m)
|
||||
}
|
||||
if m == 0 {
|
||||
return 0, .EOF
|
||||
}
|
||||
n += i64(m)
|
||||
b = b[m:]
|
||||
offset += i64(m)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
_write :: proc(f: ^File, p: []byte) -> (i64, Error) {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
n := unix.sys_write(f.impl.fd, &p[0], uint(len(p)))
|
||||
if n < 0 {
|
||||
return -1, _get_platform_error(n)
|
||||
n, errno := linux.write(f.impl.fd, p[:])
|
||||
if errno != .NONE {
|
||||
return -1, _get_platform_error(errno)
|
||||
}
|
||||
return i64(n), nil
|
||||
}
|
||||
|
||||
_write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: i64, err: Error) {
|
||||
_write_at :: proc(f: ^File, p: []byte, offset: i64) -> (i64, Error) {
|
||||
if offset < 0 {
|
||||
return 0, .Invalid_Offset
|
||||
}
|
||||
|
||||
b, offset := p, offset
|
||||
for len(b) > 0 {
|
||||
m := unix.sys_pwrite(f.impl.fd, &b[0], len(b), offset)
|
||||
if m < 0 {
|
||||
return -1, _get_platform_error(m)
|
||||
}
|
||||
n += i64(m)
|
||||
b = b[m:]
|
||||
offset += i64(m)
|
||||
n, errno := linux.pwrite(f.impl.fd, p[:], offset)
|
||||
if errno != .NONE {
|
||||
return -1, _get_platform_error(errno)
|
||||
}
|
||||
return
|
||||
return i64(n), nil
|
||||
}
|
||||
|
||||
_file_size :: proc(f: ^File) -> (n: i64, err: Error) {
|
||||
s: _Stat = ---
|
||||
res := unix.sys_fstat(f.impl.fd, &s)
|
||||
if res < 0 {
|
||||
return -1, _get_platform_error(res)
|
||||
s: linux.Stat = ---
|
||||
errno := linux.fstat(f.impl.fd, &s)
|
||||
if errno != .NONE {
|
||||
return -1, _get_platform_error(errno)
|
||||
}
|
||||
return s.size, nil
|
||||
return i64(s.size), nil
|
||||
}
|
||||
|
||||
_sync :: proc(f: ^File) -> Error {
|
||||
return _ok_or_error(unix.sys_fsync(f.impl.fd))
|
||||
return _get_platform_error(linux.fsync(f.impl.fd))
|
||||
}
|
||||
|
||||
_flush :: proc(f: ^File) -> Error {
|
||||
return _ok_or_error(unix.sys_fsync(f.impl.fd))
|
||||
return _get_platform_error(linux.fsync(f.impl.fd))
|
||||
}
|
||||
|
||||
_truncate :: proc(f: ^File, size: i64) -> Error {
|
||||
return _ok_or_error(unix.sys_ftruncate(f.impl.fd, size))
|
||||
return _get_platform_error(linux.ftruncate(f.impl.fd, size))
|
||||
}
|
||||
|
||||
_remove :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
|
||||
fd := unix.sys_open(name_cstr, int(File_Flags.Read))
|
||||
if fd < 0 {
|
||||
return _get_platform_error(fd)
|
||||
fd, errno := linux.open(name_cstr, {.NOFOLLOW})
|
||||
#partial switch (errno) {
|
||||
case .ELOOP: /* symlink */
|
||||
case .NONE:
|
||||
defer linux.close(fd)
|
||||
if _is_dir_fd(fd) {
|
||||
return _get_platform_error(linux.rmdir(name_cstr))
|
||||
}
|
||||
case:
|
||||
return _get_platform_error(errno)
|
||||
}
|
||||
defer unix.sys_close(fd)
|
||||
|
||||
if _is_dir_fd(fd) {
|
||||
return _ok_or_error(unix.sys_rmdir(name_cstr))
|
||||
}
|
||||
return _ok_or_error(unix.sys_unlink(name_cstr))
|
||||
return _get_platform_error(linux.unlink(name_cstr))
|
||||
}
|
||||
|
||||
_rename :: proc(old_name, new_name: string) -> Error {
|
||||
@@ -219,7 +239,7 @@ _rename :: proc(old_name, new_name: string) -> Error {
|
||||
old_name_cstr := temp_cstring(old_name) or_return
|
||||
new_name_cstr := temp_cstring(new_name) or_return
|
||||
|
||||
return _ok_or_error(unix.sys_rename(old_name_cstr, new_name_cstr))
|
||||
return _get_platform_error(linux.rename(old_name_cstr, new_name_cstr))
|
||||
}
|
||||
|
||||
_link :: proc(old_name, new_name: string) -> Error {
|
||||
@@ -227,148 +247,194 @@ _link :: proc(old_name, new_name: string) -> Error {
|
||||
old_name_cstr := temp_cstring(old_name) or_return
|
||||
new_name_cstr := temp_cstring(new_name) or_return
|
||||
|
||||
return _ok_or_error(unix.sys_link(old_name_cstr, new_name_cstr))
|
||||
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
|
||||
|
||||
return _ok_or_error(unix.sys_symlink(old_name_cstr, new_name_cstr))
|
||||
return _get_platform_error(linux.symlink(old_name_cstr, new_name_cstr))
|
||||
}
|
||||
|
||||
_read_link_cstr :: proc(name_cstr: cstring, allocator: runtime.Allocator) -> (string, Error) {
|
||||
bufsz : uint = 256
|
||||
buf := make([]byte, bufsz, allocator)
|
||||
for {
|
||||
rc := unix.sys_readlink(name_cstr, &buf[0], bufsz)
|
||||
if rc < 0 {
|
||||
delete(buf)
|
||||
return "", _get_platform_error(rc)
|
||||
} else if rc == int(bufsz) {
|
||||
sz, errno := linux.readlink(name_cstr, buf[:])
|
||||
if errno != .NONE {
|
||||
delete(buf, allocator)
|
||||
return "", _get_platform_error(errno)
|
||||
} else if sz == int(bufsz) {
|
||||
bufsz *= 2
|
||||
delete(buf)
|
||||
delete(buf, allocator)
|
||||
buf = make([]byte, bufsz, allocator)
|
||||
} else {
|
||||
return string(buf[:rc]), nil
|
||||
return string(buf[:sz]), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_read_link :: proc(name: string, allocator: runtime.Allocator) -> (path: string, err: Error) {
|
||||
_read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, e: Error) {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
return _read_link_cstr(name_cstr, allocator)
|
||||
}
|
||||
|
||||
_unlink :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
return _ok_or_error(unix.sys_unlink(name_cstr))
|
||||
}
|
||||
|
||||
_chdir :: proc(name: string) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
return _ok_or_error(unix.sys_chdir(name_cstr))
|
||||
return _get_platform_error(linux.chdir(name_cstr))
|
||||
}
|
||||
|
||||
_fchdir :: proc(f: ^File) -> Error {
|
||||
return _ok_or_error(unix.sys_fchdir(f.impl.fd))
|
||||
return _get_platform_error(linux.fchdir(f.impl.fd))
|
||||
}
|
||||
|
||||
_chmod :: proc(name: string, mode: File_Mode) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
return _ok_or_error(unix.sys_chmod(name_cstr, uint(mode)))
|
||||
return _get_platform_error(linux.chmod(name_cstr, transmute(linux.Mode)(u32(mode))))
|
||||
}
|
||||
|
||||
_fchmod :: proc(f: ^File, mode: File_Mode) -> Error {
|
||||
return _ok_or_error(unix.sys_fchmod(f.impl.fd, uint(mode)))
|
||||
return _get_platform_error(linux.fchmod(f.impl.fd, transmute(linux.Mode)(u32(mode))))
|
||||
}
|
||||
|
||||
// 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
|
||||
return _ok_or_error(unix.sys_chown(name_cstr, uid, gid))
|
||||
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
|
||||
return _ok_or_error(unix.sys_lchown(name_cstr, uid, gid))
|
||||
return _get_platform_error(linux.lchown(name_cstr, linux.Uid(uid), linux.Gid(gid)))
|
||||
}
|
||||
|
||||
// NOTE: will throw error without super user priviledges
|
||||
_fchown :: proc(f: ^File, uid, gid: int) -> Error {
|
||||
return _ok_or_error(unix.sys_fchown(f.impl.fd, uid, gid))
|
||||
return _get_platform_error(linux.fchown(f.impl.fd, linux.Uid(uid), linux.Gid(gid)))
|
||||
}
|
||||
|
||||
_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr := temp_cstring(name) or_return
|
||||
times := [2]Unix_File_Time {
|
||||
{ atime._nsec, 0 },
|
||||
{ mtime._nsec, 0 },
|
||||
times := [2]linux.Time_Spec {
|
||||
{
|
||||
uint(atime._nsec) / uint(time.Second),
|
||||
uint(atime._nsec) % uint(time.Second),
|
||||
},
|
||||
{
|
||||
uint(mtime._nsec) / uint(time.Second),
|
||||
uint(mtime._nsec) % uint(time.Second),
|
||||
},
|
||||
}
|
||||
return _ok_or_error(unix.sys_utimensat(_AT_FDCWD, name_cstr, ×, 0))
|
||||
return _get_platform_error(linux.utimensat(linux.AT_FDCWD, name_cstr, ×[0], nil))
|
||||
}
|
||||
|
||||
_fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error {
|
||||
times := [2]Unix_File_Time {
|
||||
{ atime._nsec, 0 },
|
||||
{ mtime._nsec, 0 },
|
||||
times := [2]linux.Time_Spec {
|
||||
{
|
||||
uint(atime._nsec) / uint(time.Second),
|
||||
uint(atime._nsec) % uint(time.Second),
|
||||
},
|
||||
{
|
||||
uint(mtime._nsec) / uint(time.Second),
|
||||
uint(mtime._nsec) % uint(time.Second),
|
||||
},
|
||||
}
|
||||
return _ok_or_error(unix.sys_utimensat(f.impl.fd, nil, ×, 0))
|
||||
return _get_platform_error(linux.utimensat(f.impl.fd, nil, ×[0], nil))
|
||||
}
|
||||
|
||||
_exists :: proc(name: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr, _ := temp_cstring(name)
|
||||
return unix.sys_access(name_cstr, F_OK) == 0
|
||||
res, errno := linux.access(name_cstr, linux.F_OK)
|
||||
return !res && errno == .NONE
|
||||
}
|
||||
|
||||
_is_file :: proc(name: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr, _ := temp_cstring(name)
|
||||
s: _Stat
|
||||
res := unix.sys_stat(name_cstr, &s)
|
||||
if res < 0 {
|
||||
s: linux.Stat
|
||||
if linux.stat(name_cstr, &s) != .NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISREG(s.mode)
|
||||
return linux.S_ISREG(s.mode)
|
||||
}
|
||||
|
||||
_is_file_fd :: proc(fd: int) -> bool {
|
||||
s: _Stat
|
||||
res := unix.sys_fstat(fd, &s)
|
||||
if res < 0 { // error
|
||||
_is_file_fd :: proc(fd: linux.Fd) -> bool {
|
||||
s: linux.Stat
|
||||
if linux.fstat(fd, &s) != .NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISREG(s.mode)
|
||||
return linux.S_ISREG(s.mode)
|
||||
}
|
||||
|
||||
_is_dir :: proc(name: string) -> bool {
|
||||
TEMP_ALLOCATOR_GUARD()
|
||||
name_cstr, _ := temp_cstring(name)
|
||||
s: _Stat
|
||||
res := unix.sys_stat(name_cstr, &s)
|
||||
if res < 0 {
|
||||
s: linux.Stat
|
||||
if linux.stat(name_cstr, &s) != .NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISDIR(s.mode)
|
||||
return linux.S_ISDIR(s.mode)
|
||||
}
|
||||
|
||||
_is_dir_fd :: proc(fd: int) -> bool {
|
||||
s: _Stat
|
||||
res := unix.sys_fstat(fd, &s)
|
||||
if res < 0 { // error
|
||||
_is_dir_fd :: proc(fd: linux.Fd) -> bool {
|
||||
s: linux.Stat
|
||||
if linux.fstat(fd, &s) != .NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISDIR(s.mode)
|
||||
return linux.S_ISDIR(s.mode)
|
||||
}
|
||||
|
||||
/* Certain files in the Linux file system are not actual
|
||||
* files (e.g. everything in /proc/). Therefore, the
|
||||
* read_entire_file procs fail to actually read anything
|
||||
* since these "files" stat to a size of 0. Here, we just
|
||||
* read until there is nothing left.
|
||||
*/
|
||||
_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) {
|
||||
name_cstr := clone_to_cstring(name, allocator) or_return
|
||||
defer delete(name, allocator)
|
||||
return _read_entire_pseudo_file_cstring(name_cstr, allocator)
|
||||
}
|
||||
|
||||
_read_entire_pseudo_file_cstring :: proc(name: cstring, allocator: runtime.Allocator) -> ([]u8, Error) {
|
||||
fd, errno := linux.open(name, {})
|
||||
if errno != .NONE {
|
||||
return nil, _get_platform_error(errno)
|
||||
}
|
||||
defer linux.close(fd)
|
||||
|
||||
BUF_SIZE_STEP :: 128
|
||||
contents := make([dynamic]u8, 0, BUF_SIZE_STEP, allocator)
|
||||
|
||||
n: int
|
||||
i: int
|
||||
for {
|
||||
resize(&contents, i + BUF_SIZE_STEP)
|
||||
n, errno = linux.read(fd, contents[i:i+BUF_SIZE_STEP])
|
||||
if errno != .NONE {
|
||||
delete(contents)
|
||||
return nil, _get_platform_error(errno)
|
||||
}
|
||||
if n < BUF_SIZE_STEP {
|
||||
break
|
||||
}
|
||||
i += BUF_SIZE_STEP
|
||||
}
|
||||
|
||||
resize(&contents, i + n)
|
||||
|
||||
return contents[:], nil
|
||||
}
|
||||
|
||||
@(private="package")
|
||||
|
||||
Reference in New Issue
Block a user