diff --git a/copy.go b/copy.go index 175d2de..0d99a03 100644 --- a/copy.go +++ b/copy.go @@ -10,7 +10,6 @@ import ( "path" "sync" "sync/atomic" - "syscall" "time" mapset "github.com/deckarep/golang-set/v2" @@ -24,9 +23,6 @@ const ( var ( sha256Pool = &sync.Pool{New: func() interface{} { return sha256.New() }} - - ErrTargetNoSpace = fmt.Errorf("acp: target have no space") - ErrTargetDropToReadonly = fmt.Errorf("acp: target droped into readonly") ) func (c *Copyer) copy(ctx context.Context, prepared <-chan *writeJob) <-chan *baseJob { @@ -126,37 +122,14 @@ func (c *Copyer) write(ctx context.Context, job *writeJob, ch chan<- *baseJob, c } if err := os.MkdirAll(path.Dir(target), os.ModePerm); err != nil { - // if no space - if errors.Is(err, syscall.ENOSPC) { - noSpaceDevices.Add(dev) - job.fail(target, fmt.Errorf("%w, mkdir dst dir fail", ErrTargetNoSpace)) - continue - } - if errors.Is(err, syscall.EROFS) { - noSpaceDevices.Add(dev) - job.fail(target, fmt.Errorf("%w, mkdir dst dir fail", ErrTargetDropToReadonly)) - continue - } - - job.fail(target, fmt.Errorf("mkdir dst dir fail, %w", err)) + job.fail(target, fmt.Errorf("mkdir dst dir fail, %w", mappingError(err))) continue } file, err := os.OpenFile(target, c.createFlag, job.mode) if err != nil { // if no space - if errors.Is(err, syscall.ENOSPC) { - noSpaceDevices.Add(dev) - job.fail(target, fmt.Errorf("%w, open dst file fail", ErrTargetNoSpace)) - continue - } - if errors.Is(err, syscall.EROFS) { - noSpaceDevices.Add(dev) - job.fail(target, fmt.Errorf("%w, open dst file fail", ErrTargetDropToReadonly)) - continue - } - - job.fail(target, fmt.Errorf("open dst file fail, %w", err)) + job.fail(target, fmt.Errorf("open dst file fail, %w", mappingError(err))) continue } @@ -182,19 +155,7 @@ func (c *Copyer) write(ctx context.Context, job *writeJob, ch chan<- *baseJob, c c.reportError(job.path, target, fmt.Errorf("delete failed file has error, %w", err)) } - // if no space - if errors.Is(rerr, syscall.ENOSPC) { - noSpaceDevices.Add(dev) - job.fail(target, fmt.Errorf("%w, write dst file fail", ErrTargetNoSpace)) - return - } - if errors.Is(rerr, syscall.EROFS) { - noSpaceDevices.Add(dev) - job.fail(target, fmt.Errorf("%w, write dst file fail", ErrTargetDropToReadonly)) - return - } - - job.fail(target, fmt.Errorf("write dst file fail, %w", rerr)) + job.fail(target, fmt.Errorf("write dst file fail, %w", mappingError(rerr))) }() defer file.Close() diff --git a/disk_usage.go b/disk_usage.go index e948ad5..091378c 100644 --- a/disk_usage.go +++ b/disk_usage.go @@ -1,8 +1,10 @@ package acp import ( + "errors" "fmt" "sync" + "syscall" "github.com/samuelncui/godf" ) @@ -11,6 +13,22 @@ const ( defaultDiskUsageFreshInterval = 1024 * 1024 * 1024 * 2 ) +var ( + ErrTargetNoSpace = fmt.Errorf("acp: target have no space") + ErrTargetDropToReadonly = fmt.Errorf("acp: target droped into readonly") + + errorMapping = []errorPair{ + {from: syscall.ENOSPC, to: ErrTargetNoSpace}, + {from: syscall.EROFS, to: ErrTargetDropToReadonly}, + {from: syscall.EIO, to: ErrTargetDropToReadonly}, + } +) + +type errorPair struct { + from error + to error +} + type diskUsageCache struct { mountPoint string freshInterval int64 @@ -49,3 +67,17 @@ func (m *diskUsageCache) check(need int64) error { return nil } + +func mappingError(err error) error { + if err == nil { + return nil + } + + for _, p := range errorMapping { + if errors.Is(err, p.from) { + return fmt.Errorf("%w: %w", p.to, err) + } + } + + return err +}