diff --git a/kittens/ssh/config.go b/kittens/ssh/config.go index 45a6f12a5..ca07bde74 100644 --- a/kittens/ssh/config.go +++ b/kittens/ssh/config.go @@ -12,10 +12,9 @@ import ( "path" "path/filepath" "strings" - "syscall" - "time" "kitty/tools/config" + "kitty/tools/stat" "kitty/tools/utils" "kitty/tools/utils/paths" "kitty/tools/utils/shlex" @@ -242,31 +241,30 @@ func excluded(pattern, path string) bool { } func get_file_data(callback func(h *tar.Header, data []byte) error, seen map[file_unique_id]string, local_path, arcname string, exclude_patterns []string) error { - s, err := os.Lstat(local_path) + s_, err := os.Lstat(local_path) if err != nil { return err } - u, unix_stat_conv_ok := s.Sys().(*syscall.Stat_t) - if u == nil { - unix_stat_conv_ok = false - } + s := stat.Get(s_) cb := func(h *tar.Header, data []byte, arcname string) error { h.Name = arcname if h.Typeflag == tar.TypeDir { h.Name = strings.TrimRight(h.Name, "/") + "/" } h.Size = int64(len(data)) - h.Mode = int64(s.Mode().Perm()) - h.ModTime = s.ModTime() + h.Mode = int64(s.Mode.Perm()) + h.ModTime = s.Mtime h.Format = tar.FormatPAX - if unix_stat_conv_ok { - h.AccessTime = time.Unix(0, u.Atim.Nano()) - h.ChangeTime = time.Unix(0, u.Ctim.Nano()) + if s.Has_atime { + h.AccessTime = s.Atime + } + if s.Has_ctime { + h.ChangeTime = s.Ctime } return callback(h, data) } // we only copy regular files, directories and symlinks - switch s.Mode().Type() { + switch s.Mode.Type() { case fs.ModeSymlink: target, err := os.Readlink(local_path) if err != nil { @@ -323,8 +321,8 @@ func get_file_data(callback func(h *tar.Header, data []byte) error, seen map[fil } } case 0: // Regular file - if unix_stat_conv_ok { - fid := file_unique_id{dev: uint64(u.Dev), inode: uint64(u.Ino)} + if s.Has_ino && s.Has_dev { + fid := file_unique_id{dev: s.Dev, inode: s.Ino} if prev, ok := seen[fid]; ok { // Hard link return cb(&tar.Header{Typeflag: tar.TypeLink, Linkname: prev}, nil, arcname) } diff --git a/tools/stat/api.go b/tools/stat/api.go new file mode 100644 index 000000000..695bbfe43 --- /dev/null +++ b/tools/stat/api.go @@ -0,0 +1,51 @@ +package stat + +import ( + "fmt" + "io/fs" + "syscall" + "time" +) + +var _ = fmt.Print + +type StatResult struct { + Name string + Size int64 + Mode fs.FileMode + Ctime, Mtime, Atime time.Time + Has_ctime, Has_atime bool + Dev, Ino uint64 + Has_dev, Has_ino bool + Number_links uint64 + Has_number_links bool + Uid, Gid uint64 + Has_uid, Has_gid bool +} + +func (s *StatResult) setup_common(f fs.FileInfo) (u *syscall.Stat_t) { + s.Name = f.Name() + s.Size = f.Size() + s.Mode = f.Mode() + s.Mtime = f.ModTime() + ok := false + u, ok = f.Sys().(*syscall.Stat_t) + if !ok { + u = nil + } + if u != nil { + s.Has_atime = true + s.Has_ctime = true + s.Dev = uint64(u.Dev) + s.Ino = uint64(u.Ino) + s.Has_dev = true + s.Has_ino = true + s.Number_links = uint64(u.Nlink) + s.Has_number_links = true + s.Uid = uint64(u.Uid) + s.Gid = uint64(u.Gid) + s.Has_uid = true + s.Has_gid = true + } + return +} diff --git a/tools/stat/get1.go b/tools/stat/get1.go new file mode 100644 index 000000000..b2ba53941 --- /dev/null +++ b/tools/stat/get1.go @@ -0,0 +1,20 @@ +//go:build aix || linux || dragonfly || openbsd || solaris + +package stat + +import ( + "fmt" + "io/fs" + "time" +) + +var _ = fmt.Print + +func Get(f fs.FileInfo) (ans StatResult) { + u := ans.setup_common(f) + if u != nil { + ans.Ctime = time.Unix(u.Ctim.Unix()) + ans.Atime = time.Unix(u.Atim.Unix()) + } + return +} diff --git a/tools/stat/get2.go b/tools/stat/get2.go new file mode 100644 index 000000000..747ffe33d --- /dev/null +++ b/tools/stat/get2.go @@ -0,0 +1,20 @@ +//go:build darwin || freebsd || netbsd + +package stat + +import ( + "fmt" + "io/fs" + "time" +) + +var _ = fmt.Print + +func Get(f fs.FileInfo) (ans StatResult) { + u := ans.setup_common(f) + if u != nil { + ans.Ctime = time.Unix(u.Ctimespec.Unix()) + ans.Atime = time.Unix(u.Atimespec.Unix()) + } + return +}