Browse Source

finish up stat, lstat and fstat

CiD- 3 years ago
parent
commit
6456618891
2 changed files with 34 additions and 20 deletions
  1. 3 1
      core/os/os2/file_linux.odin
  2. 31 19
      core/os/os2/stat_linux.odin

+ 3 - 1
core/os/os2/file_linux.odin

@@ -22,8 +22,10 @@ _O_APPEND    :: 0o2000
 _O_NONBLOCK  :: 0o4000
 _O_LARGEFILE :: 0o100000
 _O_DIRECTORY :: 0o200000
+_O_NOFOLLOW  :: 0o400000
 _O_SYNC      :: 0o4010000
 _O_CLOEXEC   :: 0o2000000
+_O_PATH      :: 0o10000000
 
 _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) {
 	cstr := strings.clone_to_cstring(name, context.temp_allocator)
@@ -66,7 +68,7 @@ _name :: proc(fd: Handle, allocator := context.allocator) -> string {
 
 	realpath: string
 	err: Error
-	if realpath, err = _read_link_cstr(cstring(&buf[0])); err != nil || realpath[0] != '/' {
+	if realpath, err = _read_link_cstr(cstring(&buf[0]), allocator); err != nil || realpath[0] != '/' {
 		return ""
 	}
 	return realpath

+ 31 - 19
core/os/os2/stat_linux.odin

@@ -82,39 +82,51 @@ OS_Stat :: struct {
 	_reserve3:     i64,
 }
 
-_fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) {
-	return File_Info{}, nil
-}
-
-_stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
-	return File_Info{}, nil
-}
-
-_lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
-	cstr := strings.clone_to_cstring(name)
-	defer delete(cstr)
 
+_fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) {
 	s: OS_Stat
-	result := unix.sys_lstat(cstr, &s)
+	result := unix.sys_fstat(int(fd), &s)
 	if result < 0 {
-		return {}, _get_platform_error(int(unix.get_errno(result)))
+		return {}, _get_platform_error(result)
 	}
 
+	// TODO: As of Linux 4.11, the new statx syscall can retrieve creation_time
 	fi := File_Info {
-		fullpath = "",
+		fullpath = _name(fd, allocator),
 		name = "",
 		size = s.size,
 		mode = 0,
 		is_dir = S_ISDIR(s.mode),
-		creation_time = time.Time{0}, // linux does not track this
-		//TODO
-		modification_time = time.Time{0},
-		access_time = time.Time{0},
+		modification_time = time.Time {s.modified.seconds},
+		access_time = time.Time {s.last_access.seconds},
+		creation_time = time.Time{0}, // regular stat does not provide this
 	}
-	
+
+	fi.name = filepath.base(fi.fullpath)
 	return fi, nil
 }
 
+// NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath
+_stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
+	cstr := strings.clone_to_cstring(name, context.temp_allocator)
+	fd := unix.sys_open(cstr, _O_RDONLY)
+	if fd < 0 {
+		return {}, _get_platform_error(fd)
+	}
+	defer unix.sys_close(fd)
+	return _fstat(Handle(fd), allocator)
+}
+
+_lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
+	cstr := strings.clone_to_cstring(name, context.temp_allocator)
+	fd := unix.sys_open(cstr, _O_RDONLY | _O_PATH | _O_NOFOLLOW)
+	if fd < 0 {
+		return {}, _get_platform_error(fd)
+	}
+	defer unix.sys_close(fd)
+	return _fstat(Handle(fd), allocator)
+}
+
 _same_file :: proc(fi1, fi2: File_Info) -> bool {
 	return fi1.fullpath == fi2.fullpath
 }