Skip to content

Commit

Permalink
utimes
Browse files Browse the repository at this point in the history
  • Loading branch information
CAFxX authored Jan 9, 2022
1 parent 276769b commit d6edae9
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 6 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Flags:
--perm=PERM File permissions
--uid=UID File owner user
--gid=GID File owner group
--mtime=MTIME File modification time (RFC 3339)
--atime=ATIME File access time (RFC 3339)
Args:
<filename> Name of the file to create
Expand Down
63 changes: 57 additions & 6 deletions atomicfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"path"
"strconv"
"strings"
"time"
"unsafe"

"golang.org/x/sys/unix"
)
Expand Down Expand Up @@ -83,6 +85,34 @@ func Ownership(uid, gid int) Option {
})
}

func ModificationTime(t time.Time) Option {
return optionFunc(func(c *config) error {
if c.mtime != defaultConfig().mtime {
return &werror{"multiple modification times", nil}
}
ts, err := unix.TimeToTimespec(t)
if err != nil {
return &werror{"invalid modification time", err}
}
c.mtime = ts
return nil
})
}

func AccessTime(t time.Time) Option {
return optionFunc(func(c *config) error {
if c.atime != defaultConfig().atime {
return &werror{"multiple access times", nil}
}
ts, err := unix.TimeToTimespec(t)
if err != nil {
return &werror{"invalid access time", err}
}
c.atime = ts
return nil
})
}

// TODO: owner/group, permissions, file times, lock, xattr, fadvise flags, fsync, ...

type config struct {
Expand All @@ -93,16 +123,20 @@ type config struct {
name string
value []byte
}
perm uint32
uid int
gid int
perm uint32
uid int
gid int
mtime unix.Timespec
atime unix.Timespec
}

func defaultConfig() config {
return config{
perm: ^uint32(0),
uid: -1,
gid: -1,
perm: ^uint32(0),
uid: -1,
gid: -1,
mtime: unix.Timespec{Nsec: unix.UTIME_OMIT},
atime: unix.Timespec{Nsec: unix.UTIME_OMIT},
}
}

Expand Down Expand Up @@ -173,6 +207,14 @@ func Create(filename string, options ...Option) error {
return &werror{"setting xattr", err}
}
}

if cfg.mtime != defaultConfig().mtime || cfg.atime != defaultConfig().atime {
err := futimens(int(f.Fd()), &[2]unix.Timespec{cfg.atime, cfg.mtime})
if err != nil {
return &werror{"setting access/modification time", err}
}
}

if cfg.flushData {
err := f.Sync()
if err != nil {
Expand Down Expand Up @@ -247,3 +289,12 @@ func guessContentSize(r io.Reader) int64 {
}
return 0
}

// https://github.com/golang/go/issues/49699
func futimens(fd int, times *[2]unix.Timespec) (err error) {
_, _, e1 := unix.Syscall6(unix.SYS_UTIMENSAT, uintptr(fd), 0, uintptr(unsafe.Pointer(times)), 0, 0, 0)
if e1 != 0 {
err = e1
}
return
}
17 changes: 17 additions & 0 deletions cmd/atomicfile/atomicfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"os"
"strconv"
"time"

"github.com/CAFxX/atomicfile"
"gopkg.in/alecthomas/kingpin.v2"
Expand All @@ -16,6 +17,8 @@ func main() {
perm := kingpin.Flag("perm", "File permissions").String()
uid := kingpin.Flag("uid", "File owner user").Default("-1").PlaceHolder("UID").Int()
gid := kingpin.Flag("gid", "File owner group").Default("-1").PlaceHolder("GID").Int()
mtime := kingpin.Flag("mtime", "File modification time (RFC 3339)").String()
atime := kingpin.Flag("atime", "File access time (RFC 3339)").String()
kingpin.Parse()

opts := []atomicfile.Option{
Expand All @@ -40,6 +43,20 @@ func main() {
if *uid != -1 || *gid != -1 {
opts = append(opts, atomicfile.Ownership(*uid, *gid))
}
if *mtime != "" {
t, err := time.Parse(time.RFC3339Nano, *mtime)
if err != nil {
fatal(err)
}
opts = append(opts, atomicfile.ModificationTime(t))
}
if *atime != "" {
t, err := time.Parse(time.RFC3339Nano, *atime)
if err != nil {
fatal(err)
}
opts = append(opts, atomicfile.AccessTime(t))
}

err := atomicfile.Create(*filename, opts...)
if err != nil {
Expand Down

0 comments on commit d6edae9

Please sign in to comment.