mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-12 14:23:33 +00:00
141 lines
3.4 KiB
Odin
141 lines
3.4 KiB
Odin
#+private
|
|
#+build darwin, netbsd, freebsd, openbsd
|
|
package os
|
|
|
|
import "base:runtime"
|
|
|
|
import "core:sys/posix"
|
|
import "core:time"
|
|
|
|
internal_stat :: proc(stat: posix.stat_t, fullpath: string) -> (fi: File_Info) {
|
|
fi.fullpath = fullpath
|
|
_, fi.name = split_path(fi.fullpath)
|
|
|
|
fi.inode = u128(stat.st_ino)
|
|
fi.size = i64(stat.st_size)
|
|
|
|
fi.mode = transmute(Permissions)u32(transmute(posix._mode_t)(stat.st_mode - posix.S_IFMT))
|
|
|
|
fi.type = .Undetermined
|
|
switch {
|
|
case posix.S_ISBLK(stat.st_mode):
|
|
fi.type = .Block_Device
|
|
case posix.S_ISCHR(stat.st_mode):
|
|
fi.type = .Character_Device
|
|
case posix.S_ISDIR(stat.st_mode):
|
|
fi.type = .Directory
|
|
case posix.S_ISFIFO(stat.st_mode):
|
|
fi.type = .Named_Pipe
|
|
case posix.S_ISLNK(stat.st_mode):
|
|
fi.type = .Symlink
|
|
case posix.S_ISREG(stat.st_mode):
|
|
fi.type = .Regular
|
|
case posix.S_ISSOCK(stat.st_mode):
|
|
fi.type = .Socket
|
|
}
|
|
|
|
fi.creation_time = timespec_time(stat.st_birthtimespec)
|
|
fi.modification_time = timespec_time(stat.st_mtim)
|
|
fi.access_time = timespec_time(stat.st_atim)
|
|
|
|
timespec_time :: proc(t: posix.timespec) -> time.Time {
|
|
return time.Time{_nsec = i64(t.tv_sec) * 1e9 + i64(t.tv_nsec)}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
_fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
|
|
if f == nil || f.impl == nil {
|
|
err = .Invalid_File
|
|
return
|
|
}
|
|
|
|
impl := (^File_Impl)(f.impl)
|
|
|
|
stat: posix.stat_t
|
|
if posix.fstat(impl.fd, &stat) != .OK {
|
|
err = _get_platform_error()
|
|
return
|
|
}
|
|
|
|
fullpath := clone_string(impl.name, allocator) or_return
|
|
return internal_stat(stat, fullpath), nil
|
|
}
|
|
|
|
_stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
|
|
if name == "" {
|
|
err = .Invalid_Path
|
|
return
|
|
}
|
|
|
|
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
|
cname := clone_to_cstring(name, temp_allocator) or_return
|
|
|
|
fd := posix.open(cname, {})
|
|
if fd == -1 {
|
|
err = _get_platform_error()
|
|
return
|
|
}
|
|
defer posix.close(fd)
|
|
|
|
fullpath := _posix_absolute_path(fd, name, allocator) or_return
|
|
|
|
stat: posix.stat_t
|
|
if posix.stat(fullpath, &stat) != .OK {
|
|
err = _get_platform_error()
|
|
return
|
|
}
|
|
|
|
return internal_stat(stat, string(fullpath)), nil
|
|
}
|
|
|
|
_lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
|
|
if name == "" {
|
|
err = .Invalid_Path
|
|
return
|
|
}
|
|
|
|
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
|
|
assert(len(fullpath) > 0)
|
|
switch {
|
|
case fullpath[0] == '/':
|
|
// nothing.
|
|
case fullpath == ".":
|
|
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,
|
|
"/",
|
|
fullpath,
|
|
}, temp_allocator) or_return
|
|
}
|
|
|
|
stat: posix.stat_t
|
|
c_fullpath := clone_to_cstring(fullpath, temp_allocator) or_return
|
|
if posix.lstat(c_fullpath, &stat) != .OK {
|
|
err = _get_platform_error()
|
|
return
|
|
}
|
|
|
|
fullpath = clone_string(fullpath, allocator) or_return
|
|
return internal_stat(stat, fullpath), nil
|
|
}
|
|
|
|
_same_file :: proc(fi1, fi2: File_Info) -> bool {
|
|
return fi1.fullpath == fi2.fullpath
|
|
}
|
|
|
|
_is_reserved_name :: proc(path: string) -> bool {
|
|
return false
|
|
} |