123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- //+private
- //+build darwin, netbsd, freebsd, openbsd
- package os2
- import "base:runtime"
- import "core:path/filepath"
- import "core:sys/posix"
- import "core:time"
- internal_stat :: proc(stat: posix.stat_t, fullpath: string) -> (fi: File_Info) {
- fi.fullpath = fullpath
- fi.name = filepath.base(fi.fullpath)
- fi.inode = u128(stat.st_ino)
- fi.size = i64(stat.st_size)
- fi.mode = int(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_GUARD()
- cname := temp_cstring(name) 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_GUARD()
- // 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 := filepath.clean(name, temp_allocator())
- 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
- if posix.lstat(temp_cstring(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
- }
|