feat: Add portable Timespec implementation for FileInfo

This commit is contained in:
Felicitas Pojtinger
2022-01-16 01:18:45 +01:00
parent e32d0d16c6
commit 2f8e6e8875
6 changed files with 120 additions and 41 deletions

View File

@@ -7,6 +7,7 @@ import (
"io/fs"
"os"
"sync"
"time"
"github.com/pojntfx/stfs/internal/ioext"
"github.com/pojntfx/stfs/pkg/cache"
@@ -124,17 +125,24 @@ func (f *File) syncWithoutLocking() error {
// Some OSes like i.e. Windows don't support numeric GIDs and UIDs, so use 0 instead
gid := 0
uid := 0
modTime := f.info.ModTime()
accessTime := f.info.ModTime()
changeTime := f.info.ModTime()
sys, ok := f.info.Sys().(*Stat)
if ok {
gid = int(sys.Gid)
uid = int(sys.Uid)
accessTime = time.Unix(0, sys.Atim.Nano())
changeTime = time.Unix(0, sys.Ctim.Nano())
}
f.info = NewFileInfo(
f.info.Name(),
size,
f.info.Mode(),
f.info.ModTime(),
modTime,
accessTime,
changeTime,
gid,
uid,
f.info.IsDir(),

View File

@@ -1,8 +0,0 @@
//go:build windows
package fs
type Stat struct {
Uid uint32
Gid uint32
}

View File

@@ -1,7 +0,0 @@
//go:build !windows
package fs
import "syscall"
type Stat syscall.Stat_t

View File

@@ -12,13 +12,15 @@ import (
type FileInfo struct {
os.FileInfo
name string
size int64
mode fs.FileMode
modTime time.Time
gid int
uid int
isDir bool
name string
size int64
mode fs.FileMode
modTime time.Time
accessTime time.Time
changeTime time.Time
gid int
uid int
isDir bool
log logging.StructuredLogger
}
@@ -28,6 +30,8 @@ func NewFileInfo(
size int64,
mode fs.FileMode,
modTime time.Time,
accessTime time.Time,
changeTime time.Time,
gid int,
uid int,
isDir bool,
@@ -35,13 +39,15 @@ func NewFileInfo(
log logging.StructuredLogger,
) *FileInfo {
return &FileInfo{
name: name,
size: size,
mode: mode,
modTime: modTime,
gid: gid,
uid: uid,
isDir: isDir,
name: name,
size: size,
mode: mode,
modTime: modTime,
accessTime: accessTime,
changeTime: changeTime,
gid: gid,
uid: uid,
isDir: isDir,
log: log,
}
@@ -53,13 +59,15 @@ func NewFileInfoFromTarHeader(
log logging.StructuredLogger,
) *FileInfo {
return &FileInfo{
name: hdr.FileInfo().Name(),
size: hdr.FileInfo().Size(),
mode: hdr.FileInfo().Mode(),
modTime: hdr.FileInfo().ModTime(),
gid: hdr.Gid,
uid: hdr.Uid,
isDir: hdr.FileInfo().IsDir(),
name: hdr.FileInfo().Name(),
size: hdr.FileInfo().Size(),
mode: hdr.FileInfo().Mode(),
modTime: hdr.FileInfo().ModTime(),
accessTime: hdr.AccessTime,
changeTime: hdr.ChangeTime,
gid: hdr.Gid,
uid: hdr.Uid,
isDir: hdr.FileInfo().IsDir(),
log: log,
}
@@ -110,8 +118,11 @@ func (f *FileInfo) Sys() interface{} {
"name": f.name,
})
return &Stat{
Uid: uint32(f.uid),
Gid: uint32(f.gid),
}
return NewStat(
uint32(f.uid),
uint32(f.gid),
f.modTime.UnixNano(),
f.accessTime.UnixNano(),
f.changeTime.UnixNano(),
)
}

View File

@@ -0,0 +1,52 @@
//go:build !linux
package fs
// From the Go stdlib for linux/amd64
type Timespec struct {
Sec int64
Nsec int64
}
func (ts *Timespec) Unix() (sec int64, nsec int64) {
return int64(ts.Sec), int64(ts.Nsec)
}
func (ts *Timespec) Nano() int64 {
return int64(ts.Sec)*1e9 + int64(ts.Nsec)
}
func NsecToTimespec(nsec int64) Timespec {
sec := nsec / 1e9
nsec = nsec % 1e9
if nsec < 0 {
nsec += 1e9
sec--
}
return Timespec{Sec: sec, Nsec: nsec}
}
type Stat struct {
Uid uint32
Gid uint32
Mtim Timespec
Atim Timespec
Ctim Timespec
}
func NewStat(
uid uint32,
gid uint32,
mtim int64,
atim int64,
ctim int64,
) *Stat {
return &Stat{
Uid: uid,
Gid: gid,
Mtim: NsecToTimespec(mtim),
Atim: NsecToTimespec(atim),
Ctim: NsecToTimespec(ctim),
}
}

View File

@@ -0,0 +1,23 @@
//go:build linux
package fs
import "syscall"
type Stat syscall.Stat_t
func NewStat(
uid uint32,
gid uint32,
mtim int64,
atim int64,
ctim int64,
) *Stat {
return &Stat{
Uid: uid,
Gid: gid,
Mtim: syscall.NsecToTimespec(mtim),
Atim: syscall.NsecToTimespec(atim),
Ctim: syscall.NsecToTimespec(ctim),
}
}