浏览代码

os2 linux begin

CiD- 3 年之前
父节点
当前提交
e51bb4ef12
共有 3 个文件被更改,包括 486 次插入4 次删除
  1. 236 0
      core/os/os2/file_linux.odin
  2. 116 0
      core/os/os2/stat_linux.odin
  3. 134 4
      core/sys/unix/syscalls_linux.odin

+ 236 - 0
core/os/os2/file_linux.odin

@@ -0,0 +1,236 @@
+//+private
+package os2
+
+import "core:io"
+import "core:time"
+import "core:sys/unix"
+
+
+_get_platform_error :: proc(res: int) -> Error {
+	errno := unix.get_errno(res)
+	return Platform_Error{i32(errno)}
+}
+
+_ok_or_error :: proc(res: int) -> Error {
+	return res >= 0 ? nil : _get_platform_error(res)
+}
+
+_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) {
+	cstr := strings.clone_to_cstring(path, context.temp_allocator)
+	handle := Handle(unix.sys_open(cstr, int(flags), int(perm)))
+	if handle < 0 {
+		return Handle(-1), _get_platform_error(int(handle))
+	}
+	return handle, nil
+}
+
+_close :: proc(fd: Handle) -> Error {
+	res := unix.sys_close(int(fd))
+	return _ok_or_error(res)
+}
+
+_name :: proc(fd: Handle, allocator := context.allocator) -> string {
+	//TODO
+	return ""
+}
+
+_seek :: proc(fd: Handle, offset: i64, whence: Seek_From) -> (ret: i64, err: Error) {
+	res := unix.sys_lseek(int(fd), offset, int(whence))
+	if res < 0 {
+		return -1, _get_platform_error(int(res))
+	}
+	return res, nil
+}
+
+_read :: proc(fd: Handle, p: []byte) -> (n: int, err: Error) {
+	if len(p) == 0 {
+		return 0, nil
+	}
+	n = unix.sys_read(fd, &data[0], c.size_t(len(data)))
+	if n < 0 {
+		return -1, unix.get_errno(n)
+	}
+	return bytes_read, nil
+}
+
+_read_at :: proc(fd: Handle, p: []byte, offset: i64) -> (n: int, err: Error) {
+	if offset < 0 {
+		return 0, .Invalid_Offset
+	}
+	
+	curr_offset, err := _seek(fd, 0, .Current)
+	if err != nil {
+		return 0, err
+	}
+	defer _seek(fd, curr_offset, .Start)
+	_seek(fd, offset, .Start)
+
+	b := p
+	for len(b) > 0 {
+		m := _read(fd, b) or_return
+		n += m
+		b = b[m:]
+	}
+	return
+}
+
+_read_from :: proc(fd: Handle, r: io.Reader) -> (n: i64, err: Error) {
+	//TODO
+	return
+}
+
+_write :: proc(fd: Handle, p: []byte) -> (n: int, err: Error) {
+	if len(p) == 0 {
+		return 0, nil
+	}
+	n = unix.sys_write(fd, &p[0], uint(len(p)))
+	if n < 0 {
+		return -1, _get_platform_error(n)
+	}
+	return int(n), nil
+}
+
+_write_at :: proc(fd: Handle, p: []byte, offset: i64) -> (n: int, err: Error) {
+	if offset < 0 {
+		return 0, .Invalid_Offset
+	}
+	
+	curr_offset, err := _seek(fd, 0, .Current)
+	if err != nil {
+		return 0, err
+	}
+	defer _seek(fd, curr_offset, .Start)
+	_seek(fd, offset, .Start)
+
+	b := p
+	for len(b) > 0 {
+		m := _write(fd, b) or_return
+		n += m
+		b = b[m:]
+	}
+	return
+}
+
+_write_to :: proc(fd: Handle, w: io.Writer) -> (n: i64, err: Error) {
+	//TODO
+	return
+}
+
+_file_size :: proc(fd: Handle) -> (n: i64, err: Error) {
+	s, err := _fstat(fd) or_return
+	if err != nil {
+		return 0, err
+	}
+	return max(s.size, 0), nil
+}
+
+_sync :: proc(fd: Handle) -> Error {
+	return _ok_or_error(unix.sys_fsync(int(fd)))
+}
+
+_flush :: proc(fd: Handle) -> Error {
+	return _ok_or_error(unix.sys_fsync(int(fd)))
+}
+
+_truncate :: proc(fd: Handle, size: i64) -> Error {
+	return _ok_or_error(unix.sys_ftruncate(int(fd), size))
+}
+
+_remove :: proc(name: string) -> Error {
+	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
+	if _is_dir(name) {
+		return _ok_or_error(unix.sys_rmdir(path_cstr))
+	}
+	return _ok_or_error(unix.sys_unlink(path_cstr))
+}
+
+_rename :: proc(old_path, new_path: string) -> Error {
+	old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator)
+	new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator)
+	return _ok_or_error(unix.sys_rename(old_path_cstr, new_path_cstr))
+}
+
+_link :: proc(old_name, new_name: string) -> Error {
+	old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator)
+	new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator)
+	return _ok_or_error(unix.sys_link(old_name_cstr, new_name_cstr))
+}
+
+_symlink :: proc(old_name, new_name: string) -> Error {
+	old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator)
+	new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator)
+	return _ok_or_error(unix.sys_symlink(old_name_cstr, new_name_cstr))
+}
+
+_read_link :: proc(name: string, allocator := context.allocator) -> (string, Error) {
+	path_cstr := strings.clone_to_cstring(path)
+	defer delete(path_cstr)
+
+	bufsz : uint = 256
+	buf := make([]byte, bufsz, allocator)
+	for {
+		rc := unix.sys_readlink(path_cstr, &(buf[0]), bufsz)
+		if rc < 0 {
+			delete(buf)
+			return "", unix.get_errno(rc)
+		} else if rc == int(bufsz) {
+			bufsz *= 2
+			delete(buf)
+			buf = make([]byte, bufsz, allocator)
+		} else {
+			return strings.string_from_ptr(&buf[0], rc), nil
+		}
+	}
+}
+
+_unlink :: proc(path: string) -> Error {
+	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
+	return _ok_or_error(unix.sys_unlink(path_cstr))
+}
+
+_chdir :: proc(fd: Handle) -> Error {
+	return _ok_or_error(unix.sys_fchdir(int(fd)))
+}
+
+_chmod :: proc(fd: Handle, mode: File_Mode) -> Error {
+	//TODO
+	return nil
+}
+
+_chown :: proc(fd: Handle, uid, gid: int) -> Error {
+	//TODO
+	return nil
+}
+
+_lchown :: proc(name: string, uid, gid: int) -> Error {
+	//TODO
+	return nil
+}
+
+_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
+	//TODO
+	return nil
+}
+
+_exists :: proc(path: string) -> bool {
+	path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
+	return unix.sys_access(path_cstr, F_OK) == 0
+}
+
+_is_file :: proc(fd: Handle) -> bool {
+	s: OS_Stat
+	res := unix.sys_fstat(int(fd), rawptr(&s))
+	if res < 0 { // error
+		return false
+	}
+	return S_ISREG(s.mode)
+}
+
+_is_dir :: proc(fd: Handle) -> bool {
+	s: OS_Stat
+	res := unix.sys_fstat(int(fd), rawptr(&s))
+	if res < 0 { // error
+		return false
+	}
+	return S_ISDIR(s.mode)
+}

+ 116 - 0
core/os/os2/stat_linux.odin

@@ -0,0 +1,116 @@
+//+private
+package os2
+
+import "core:time"
+import "core:sys/unix"
+
+// File type
+S_IFMT   :: 0o170000 // Type of file mask
+S_IFIFO  :: 0o010000 // Named pipe (fifo)
+S_IFCHR  :: 0o020000 // Character special
+S_IFDIR  :: 0o040000 // Directory
+S_IFBLK  :: 0o060000 // Block special
+S_IFREG  :: 0o100000 // Regular
+S_IFLNK  :: 0o120000 // Symbolic link
+S_IFSOCK :: 0o140000 // Socket
+
+// File mode
+// Read, write, execute/search by owner
+S_IRWXU :: 0o0700 // RWX mask for owner
+S_IRUSR :: 0o0400 // R for owner
+S_IWUSR :: 0o0200 // W for owner
+S_IXUSR :: 0o0100 // X for owner
+
+	// Read, write, execute/search by group
+S_IRWXG :: 0o0070 // RWX mask for group
+S_IRGRP :: 0o0040 // R for group
+S_IWGRP :: 0o0020 // W for group
+S_IXGRP :: 0o0010 // X for group
+
+	// Read, write, execute/search by others
+S_IRWXO :: 0o0007 // RWX mask for other
+S_IROTH :: 0o0004 // R for other
+S_IWOTH :: 0o0002 // W for other
+S_IXOTH :: 0o0001 // X for other
+
+S_ISUID :: 0o4000 // Set user id on execution
+S_ISGID :: 0o2000 // Set group id on execution
+S_ISVTX :: 0o1000 // Directory restrcted delete
+
+
+S_ISLNK  :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK  }
+S_ISREG  :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG  }
+S_ISDIR  :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR  }
+S_ISCHR  :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR  }
+S_ISBLK  :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK  }
+S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO  }
+S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK }
+
+F_OK :: 0 // Test for file existance
+X_OK :: 1 // Test for execute permission
+W_OK :: 2 // Test for write permission
+R_OK :: 4 // Test for read permission
+
+@private
+OS_Stat :: struct {
+	device_id:     u64, // ID of device containing file
+	serial:        u64, // File serial number
+	nlink:         u64, // Number of hard links
+	mode:          u32, // Mode of the file
+	uid:           u32, // User ID of the file's owner
+	gid:           u32, // Group ID of the file's group
+	_padding:      i32, // 32 bits of padding
+	rdev:          u64, // Device ID, if device
+	size:          i64, // Size of the file, in bytes
+	block_size:    i64, // Optimal bllocksize for I/O
+	blocks:        i64, // Number of 512-byte blocks allocated
+
+	last_access:   Unix_File_Time, // Time of last access
+	modified:      Unix_File_Time, // Time of last modification
+	status_change: Unix_File_Time, // Time of last status change
+
+	_reserve1,
+	_reserve2,
+	_reserve3:     i64,
+}
+
+_fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) {
+}
+
+_stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
+}
+
+_lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
+	cstr := strings.clone_to_cstring(path)
+	defer delete(cstr)
+
+	s: OS_Stat
+	result := unix.sys_lstat(cstr, &s)
+	if result < 0 {
+		return {}, unix.get_errno(result)
+	}
+
+	fi := File_Info {
+		fullpath = "",
+		name = "",
+		size = s.size,
+		mode = 0,
+		is_dir = S_ISDIR(s.mode),
+		creation_time = nil, // linux does not track this
+		//TODO
+		modification_time = nil,
+		access_time = nil,
+	}
+	
+	return fi, nil
+}
+
+_same_file :: proc(fi1, fi2: File_Info) -> bool {
+	return fi1.fullpath == fi2.fullpath
+}
+
+_stat_internal :: proc(name: string) -> (s: OS_Stat, res: int) {
+	name_cstr = strings.clone_to_cstring(name, context.temp_allocator)
+	res = unix.sys_stat(name_cstr, &s)
+	return
+}

+ 134 - 4
core/sys/unix/syscalls_linux.odin

@@ -15,7 +15,7 @@ import "core:intrinsics"
 //  386: arch/x86/entry/syscalls/sycall_32.tbl
 //  arm: arch/arm/tools/syscall.tbl
 
-when ODIN_ARCH == .amd64 {
+when ODIN_ARCH == "amd64" {
 	SYS_read : uintptr : 0
 	SYS_write : uintptr : 1
 	SYS_open : uintptr : 2
@@ -374,7 +374,7 @@ when ODIN_ARCH == .amd64 {
 	SYS_landlock_add_rule : uintptr : 445
 	SYS_landlock_restrict_self : uintptr : 446
 	SYS_memfd_secret : uintptr : 447
-} else when ODIN_ARCH == .arm64 {
+} else when ODIN_ARCH == "arm64" {
 	SYS_io_setup : uintptr : 0
 	SYS_io_destroy : uintptr : 1
 	SYS_io_submit : uintptr : 2
@@ -675,7 +675,7 @@ when ODIN_ARCH == .amd64 {
 	SYS_landlock_create_ruleset : uintptr : 444
 	SYS_landlock_add_rule : uintptr : 445
 	SYS_landlock_restrict_self : uintptr : 446
-} else when ODIN_ARCH == .i386 {
+} else when ODIN_ARCH == "386" {
 	SYS_restart_syscall : uintptr : 0
 	SYS_exit : uintptr : 1
 	SYS_fork : uintptr : 2
@@ -1112,7 +1112,7 @@ when ODIN_ARCH == .amd64 {
 	SYS_landlock_add_rule : uintptr : 445
 	SYS_landlock_restrict_self : uintptr : 446
 	SYS_memfd_secret : uintptr : 447
-} else when false /*ODIN_ARCH == .arm*/ { // TODO
+} else when ODIN_ARCH == "arm" {
 	SYS_restart_syscall : uintptr : 0
 	SYS_exit : uintptr : 1
 	SYS_fork : uintptr : 2
@@ -1516,6 +1516,10 @@ when ODIN_ARCH == .amd64 {
 	#panic("Unsupported architecture")
 }
 
+AT_FDCWD            :: -100
+AT_REMOVEDIR        :: uintptr(0x200)
+AT_SYMLINK_NOFOLLOW :: uintptr(0x100)
+
 sys_gettid :: proc "contextless" () -> int {
 	return cast(int)intrinsics.syscall(SYS_gettid)
 }
@@ -1523,3 +1527,129 @@ sys_gettid :: proc "contextless" () -> int {
 sys_getrandom :: proc "contextless" (buf: ^byte, buflen: int, flags: uint) -> int {
 	return cast(int)intrinsics.syscall(SYS_getrandom, buf, cast(uintptr)(buflen), cast(uintptr)(flags))
 }
+
+sys_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> int {
+	when ODIN_ARCH != "arm64" {
+		res := int(intrinsics.syscall(SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode)))
+	} else { // NOTE: arm64 does not have open
+		res := int(intrinsics.syscall(SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode))))
+	}
+	return -1 if res < 0 else res
+}
+
+sys_close :: proc(fd: int) -> int {
+	return int(intrinsics.syscall(SYS_close, uintptr(fd)))
+}
+
+sys_read :: proc(fd: int, buf: rawptr, size: uint) -> int {
+	return int(intrinsics.syscall(SYS_read, uintptr(fd), uintptr(buf), uintptr(size)))
+}
+
+sys_write :: proc(fd: int, buf: rawptr, size: uint) -> int {
+	return int(intrinsics.syscall(SYS_write, uintptr(fd), uintptr(buf), uintptr(size)))
+}
+
+sys_lseek :: proc(fd: int, offset: i64, whence: int) -> i64 {
+	when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" {
+		return i64(intrinsics.syscall(SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence)))
+	} else {
+		low := uintptr(offset & 0xFFFFFFFF)
+		high := uintptr(offset >> 32)
+		result: i64
+		res := i64(intrinsics.syscall(SYS__llseek, uintptr(fd), high, low, &result, uintptr(whence)))
+		return -1 if res < 0 else result
+	}
+}
+
+sys_stat :: proc(path: cstring, stat: rawptr) -> int {
+	when ODIN_ARCH == "amd64" {
+		return int(intrinsics.syscall(SYS_stat, uintptr(rawptr(path)), uintptr(stat)))
+	} else when ODIN_ARCH != "arm64" {
+		return int(intrinsics.syscall(SYS_stat64, uintptr(rawptr(path)), uintptr(stat)))
+	} else { // NOTE: arm64 does not have stat
+		return int(intrinsics.syscall(SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), 0))
+	}
+}
+
+sys_fstat :: proc(fd: int, stat: rawptr) -> int {
+	when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" {
+		return int(intrinsics.syscall(SYS_fstat, uintptr(fd), uintptr(stat)))
+	} else {
+		return int(intrinsics.syscall(SYS_fstat64, uintptr(fd), uintptr(stat)))
+	}
+}
+
+sys_lstat :: proc(path: cstring, stat: rawptr) -> int {
+	when ODIN_ARCH == "amd64" {
+		return int(intrinsics.syscall(SYS_lstat, uintptr(rawptr(path)), uintptr(stat)))
+	} else when ODIN_ARCH != "arm64" {
+		return int(intrinsics.syscall(SYS_lstat64, uintptr(rawptr(path)), uintptr(stat)))
+	} else { // NOTE: arm64 does not have any lstat
+		return int(intrinsics.syscall(SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW))
+	}
+}
+
+sys_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int {
+	when ODIN_ARCH != "arm64" {
+		return int(intrinsics.syscall(SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
+	} else { // NOTE: arm64 does not have readlink
+		return int(intrinsics.syscall(SYS_readlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
+	}
+}
+
+sys_access :: proc(path: cstring, mask: int) -> int {
+	when ODIN_ARCH != "arm64" {
+		return int(intrinsics.syscall(SYS_access, uintptr(rawptr(path)), uintptr(mask)))
+	} else { // NOTE: arm64 does not have access
+		return int(intrinsics.syscall(SYS_faccessat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mask)))
+	}
+}
+
+sys_getcwd :: proc(buf: rawptr, size: uint) -> int {
+	return int(intrinsics.syscall(SYS_getcwd, uintptr(buf), uintptr(size)))
+}
+
+sys_chdir :: proc(path: cstring) -> int {
+	return int(intrinsics.syscall(SYS_chdir, uintptr(rawptr(path))))
+}
+
+sys_rename :: proc(old, new: cstring) -> int {
+	when ODIN_ARCH != "arm64" {
+		return int(intrinsics.syscall(SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new))))
+	} else { // NOTE: arm64 does not have rename
+		return int(intrinsics.syscall(SYS_renameat, uintptr(AT_FDCWD), uintptr(rawptr(old)), uintptr(rawptr(new))))
+	}
+}
+
+sys_unlink :: proc(path: cstring) -> int {
+	when ODIN_ARCH != "arm64" {
+		return int(intrinsics.syscall(SYS_unlink, uintptr(rawptr(path))))
+	} else { // NOTE: arm64 does not have unlink
+		return int(intrinsics.syscall(SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path), 0)))
+	}
+}
+
+sys_rmdir :: proc(path: cstring) -> int {
+	when ODIN_ARCH != "arm64" {
+		return int(intrinsics.syscall(SYS_rmdir, uintptr(rawptr(path))))
+	} else { // NOTE: arm64 does not have rmdir
+		return int(intrinsics.syscall(SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), AT_REMOVEDIR))
+	}
+}
+
+sys_mkdir :: proc(path: cstring, mode: u32 = 0o775) -> int {
+	when ODIN_ARCH != "arm64" {
+		return int(intrinsics.syscall(SYS_mkdir, uintptr(rawptr(path)), uintptr(mode)))
+	} else { // NOTE: arm64 does not have mkdir
+		return int(intrinsics.syscall(SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode)))
+	}
+}
+
+//TODO: ftruncate, symlink, readlink, fchdir, fchmod, chown, fchown, lchown
+
+get_errno :: proc(res: int) -> i32 {
+	if res < 0 && res > -4096 {
+		return i32(-res)
+	}
+	return 0
+}