mirror of
https://github.com/samuelncui/acp.git
synced 2026-03-27 13:34:58 +00:00
feat: add sys attr copy and one to one copy
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,3 +17,4 @@
|
||||
go.sum
|
||||
output/
|
||||
test.sh
|
||||
upload_test.sh
|
||||
|
||||
@@ -3,7 +3,6 @@ package acp
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func (c *Copyer) cleanupJob(ctx context.Context, copyed <-chan *baseJob) {
|
||||
@@ -13,9 +12,10 @@ func (c *Copyer) cleanupJob(ctx context.Context, copyed <-chan *baseJob) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for _, name := range job.successTargets {
|
||||
if err := os.Chtimes(name, job.modTime, job.modTime); err != nil {
|
||||
c.reportError(job.path, name, fmt.Errorf("change info, chtimes fail, %w", err))
|
||||
if err := copyAttrs(name, job); err != nil {
|
||||
c.reportError(job.path, name, fmt.Errorf("change info, copy attrs fail, %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"flag"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
"github.com/samuelncui/acp"
|
||||
@@ -63,7 +64,47 @@ func main() {
|
||||
}()
|
||||
|
||||
opts := make([]acp.Option, 0, 8)
|
||||
opts = append(opts, acp.WildcardJob(acp.Source(sources...), acp.Target(targetPaths...)))
|
||||
|
||||
useAccurate := func() bool {
|
||||
if *noTarget {
|
||||
return false
|
||||
}
|
||||
if len(sources) > 1 {
|
||||
return false
|
||||
}
|
||||
if len(targetPaths) > 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
dst, src := targetPaths[0], sources[0]
|
||||
if strings.HasSuffix(dst, "/") {
|
||||
return false
|
||||
}
|
||||
|
||||
dstStat, err := os.Stat(dst)
|
||||
if err == nil {
|
||||
return !dstStat.IsDir()
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
logrus.Fatalf("stat dst path fail, %s", err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
srcStat, err := os.Stat(src)
|
||||
if err == nil {
|
||||
return srcStat.Mode().IsRegular()
|
||||
}
|
||||
|
||||
logrus.Fatalf("stat src path fail, %s", err)
|
||||
panic(err)
|
||||
}()
|
||||
|
||||
if useAccurate {
|
||||
opts = append(opts, acp.AccurateJob(sources[0], []string{targetPaths[0]}))
|
||||
} else {
|
||||
opts = append(opts, acp.WildcardJob(acp.Source(sources...), acp.Target(targetPaths...)))
|
||||
}
|
||||
|
||||
// if *continueReport != "" {
|
||||
// f, err := os.Open(*continueReport)
|
||||
// if err != nil {
|
||||
@@ -106,8 +147,8 @@ func main() {
|
||||
report := getter()
|
||||
r, err := os.Create(*reportPath)
|
||||
if err != nil {
|
||||
logrus.Warnf("open report fail, path= '%s', err= %w", *reportPath, err)
|
||||
logrus.Infof("report: %s", report)
|
||||
logrus.Warnf("open report fail, path= '%s', err= %s", *reportPath, err)
|
||||
logrus.Infof("report= %q", report.ToJSONString(false))
|
||||
return
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
13
copy.go
13
copy.go
@@ -139,6 +139,12 @@ func (c *Copyer) write(ctx context.Context, job *writeJob, ch chan<- *baseJob, c
|
||||
job.fail(target, fmt.Errorf("open dst file fail, %w", err))
|
||||
continue
|
||||
}
|
||||
if !job.copyer.toDevice.linear {
|
||||
if err := truncate(file, job.size); err != nil {
|
||||
job.fail(target, fmt.Errorf("truncate dst file fail, %w", err))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
ch := make(chan []byte, 4)
|
||||
chans = append(chans, ch)
|
||||
@@ -150,7 +156,7 @@ func (c *Copyer) write(ctx context.Context, job *writeJob, ch chan<- *baseJob, c
|
||||
var rerr error
|
||||
defer func() {
|
||||
if rerr == nil {
|
||||
job.succes(target)
|
||||
job.success(target)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -183,8 +189,13 @@ func (c *Copyer) write(ctx context.Context, job *writeJob, ch chan<- *baseJob, c
|
||||
}
|
||||
}
|
||||
|
||||
if err := file.Sync(); err != nil {
|
||||
rerr = fmt.Errorf("sync dst file fail, %w", err)
|
||||
return
|
||||
}
|
||||
if readErr != nil {
|
||||
rerr = readErr
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
2
index.go
2
index.go
@@ -98,6 +98,7 @@ func (c *Copyer) walk(ctx context.Context) ([]*baseJob, error) {
|
||||
size: stat.Size(),
|
||||
mode: stat.Mode(),
|
||||
modTime: stat.ModTime(),
|
||||
sys: stat.Sys(),
|
||||
|
||||
targets: targets,
|
||||
})
|
||||
@@ -154,6 +155,7 @@ func (c *Copyer) walk(ctx context.Context) ([]*baseJob, error) {
|
||||
size: stat.Size(),
|
||||
mode: stat.Mode(),
|
||||
modTime: stat.ModTime(),
|
||||
sys: stat.Sys(),
|
||||
|
||||
targets: j.dsts,
|
||||
})
|
||||
|
||||
3
job.go
3
job.go
@@ -42,6 +42,7 @@ type baseJob struct {
|
||||
size int64 // length in bytes for regular files; system-dependent for others
|
||||
mode fs.FileMode // file mode bits
|
||||
modTime time.Time // modification time
|
||||
sys any
|
||||
|
||||
lock sync.Mutex
|
||||
writeTime time.Time
|
||||
@@ -73,7 +74,7 @@ func (j *baseJob) setHash(h []byte) {
|
||||
j.copyer.submit(&EventUpdateJob{j.report()})
|
||||
}
|
||||
|
||||
func (j *baseJob) succes(path string) {
|
||||
func (j *baseJob) success(path string) {
|
||||
j.lock.Lock()
|
||||
defer j.lock.Unlock()
|
||||
|
||||
|
||||
34
syscall_darwin.go
Normal file
34
syscall_darwin.go
Normal file
@@ -0,0 +1,34 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package acp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func truncate(file *os.File, size int64) error {
|
||||
if err := file.Truncate(size); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyAttrs(name string, j *baseJob) error {
|
||||
if err := os.Chmod(name, j.mode); err != nil {
|
||||
return fmt.Errorf("chmod fail, %w", err)
|
||||
}
|
||||
if os.Geteuid() == 0 {
|
||||
if stat, ok := j.sys.(*syscall.Stat_t); ok {
|
||||
if err := os.Chown(name, int(stat.Uid), int(stat.Gid)); err != nil {
|
||||
return fmt.Errorf("chown fail, %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := os.Chtimes(name, j.modTime, j.modTime); err != nil {
|
||||
return fmt.Errorf("chtimes fail, %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
34
syscall_linux.go
Normal file
34
syscall_linux.go
Normal file
@@ -0,0 +1,34 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package acp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func truncate(file *os.File, size int64) error {
|
||||
if err := syscall.Fallocate(int(file.Fd()), 0, 0, size); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyAttrs(name string, j *baseJob) error {
|
||||
if err := os.Chmod(name, j.mode); err != nil {
|
||||
return fmt.Errorf("chmod fail, %w", err)
|
||||
}
|
||||
if os.Geteuid() == 0 {
|
||||
if stat, ok := j.sys.(*syscall.Stat_t); ok {
|
||||
if err := os.Chown(name, int(stat.Uid), int(stat.Gid)); err != nil {
|
||||
return fmt.Errorf("chown fail, %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := os.Chtimes(name, j.modTime, j.modTime); err != nil {
|
||||
return fmt.Errorf("chtimes fail, %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
23
syscall_other.go
Normal file
23
syscall_other.go
Normal file
@@ -0,0 +1,23 @@
|
||||
//go:build !linux && !darwin && !windows
|
||||
// +build !linux,!darwin,!windows
|
||||
|
||||
package acp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func truncate(_ *os.File, _ int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyAttrs(name string, j *baseJob) error {
|
||||
if err := os.Chmod(name, j.mode); err != nil {
|
||||
return fmt.Errorf("chmod fail, %w", err)
|
||||
}
|
||||
if err := os.Chtimes(name, j.modTime, j.modTime); err != nil {
|
||||
return fmt.Errorf("chtimes fail, %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
26
syscall_windows.go
Normal file
26
syscall_windows.go
Normal file
@@ -0,0 +1,26 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package acp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func truncate(file *os.File, size int64) error {
|
||||
if err := file.Truncate(size); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyAttrs(name string, j *baseJob) error {
|
||||
if err := os.Chmod(name, j.mode); err != nil {
|
||||
return fmt.Errorf("chmod fail, %w", err)
|
||||
}
|
||||
if err := os.Chtimes(name, j.modTime, j.modTime); err != nil {
|
||||
return fmt.Errorf("chtimes fail, %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user