Skip to content

Commit

Permalink
Merge pull request #83 from fako1024/main
Browse files Browse the repository at this point in the history
Support PreserveTimes for symlinks on Unix
  • Loading branch information
otiai10 authored Aug 13, 2022
2 parents dca72eb + 55416e9 commit 73c56ae
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 2 deletions.
8 changes: 7 additions & 1 deletion copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,13 @@ func dcopy(srcdir, destdir string, info os.FileInfo, opt Options) (err error) {
func onsymlink(src, dest string, opt Options) error {
switch opt.OnSymlink(src) {
case Shallow:
return lcopy(src, dest)
if err := lcopy(src, dest); err != nil {
return err
}
if opt.PreserveTimes {
return preserveLtimes(src, dest)
}
return nil
case Deep:
orig, err := os.Readlink(src)
if err != nil {
Expand Down
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module github.com/otiai10/copy

go 1.14

require github.com/otiai10/mint v1.3.3
require (
github.com/otiai10/mint v1.3.3
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
github.com/otiai10/mint v1.3.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI=
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
20 changes: 20 additions & 0 deletions preserve_ltimes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//go:build !windows && !plan9 && !js
// +build !windows,!plan9,!js

package copy

import (
"golang.org/x/sys/unix"
)

func preserveLtimes(src, dest string) error {
info := new(unix.Stat_t)
if err := unix.Lstat(src, info); err != nil {
return err
}

return unix.Lutimes(dest, []unix.Timeval{
unix.NsecToTimeval(info.Atim.Nano()),
unix.NsecToTimeval(info.Mtim.Nano()),
})
}
35 changes: 35 additions & 0 deletions preserve_ltimes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//go:build !windows && !plan9 && !js
// +build !windows,!plan9,!js

package copy

import (
"os"
"testing"

. "github.com/otiai10/mint"
"golang.org/x/sys/unix"
)

func TestOptions_PreserveLTimes(t *testing.T) {
err := Copy("test/data/case15", "test/data.copy/case15")
Expect(t, err).ToBe(nil)
opt := Options{PreserveTimes: true}
err = Copy("test/data/case15", "test/data.copy/case15-preserveltimes", opt)
Expect(t, err).ToBe(nil)

orig, err := os.Lstat("test/data/case15/symlink")
Expect(t, err).ToBe(nil)
plain, err := os.Lstat("test/data.copy/case15/symlink")
Expect(t, err).ToBe(nil)
preserved, err := os.Lstat("test/data.copy/case15-preserveltimes/symlink")
Expect(t, err).ToBe(nil)
Expect(t, plain.ModTime().Unix()).Not().ToBe(orig.ModTime().Unix())
Expect(t, preserved.ModTime().Unix()).ToBe(orig.ModTime().Unix())
}

func TestOptions_PreserveLTimesErrorReturn(t *testing.T) {
err := preserveLtimes("doesnotexist_original.txt", "doesnotexist_copy.txt")
Expect(t, err).ToBe(unix.ENOENT)
Expect(t, os.IsNotExist(err)).ToBe(true)
}
8 changes: 8 additions & 0 deletions preserve_ltimes_x.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//go:build windows || js || plan9
// +build windows js plan9

package copy

func preserveLtimes(src, dest string) error {
return nil // Unsupported
}
28 changes: 28 additions & 0 deletions preserve_ltimes_x_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//go:build windows || js || plan9
// +build windows js plan9

package copy

import (
"os"
"testing"

. "github.com/otiai10/mint"
)

func TestOptions_PreserveLTimes(t *testing.T) {
err := Copy("test/data/case15", "test/data.copy/case15")
Expect(t, err).ToBe(nil)
opt := Options{PreserveTimes: true}
err = Copy("test/data/case15", "test/data.copy/case15-preserveltimes", opt)
Expect(t, err).ToBe(nil)

orig, err := os.Lstat("test/data/case15/symlink")
Expect(t, err).ToBe(nil)
plain, err := os.Lstat("test/data.copy/case15/symlink")
Expect(t, err).ToBe(nil)
preserved, err := os.Lstat("test/data.copy/case15-preserveltimes/symlink")
Expect(t, err).ToBe(nil)
Expect(t, plain.ModTime().Unix()).Not().ToBe(orig.ModTime().Unix())
Expect(t, preserved.ModTime().Unix()).Not().ToBe(orig.ModTime().Unix())
}
5 changes: 5 additions & 0 deletions test/data/case15/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
File with specific atime and mtime.

These two properties should be preserved if we provide the PreserveTimes options to copy.Copy.

The properties should be preserverd also for the directories and the links.
1 change: 1 addition & 0 deletions test/data/case15/symlink

0 comments on commit 73c56ae

Please sign in to comment.