diff --git a/solver/llbsolver/file/backend.go b/solver/llbsolver/file/backend.go index 988307f2a..18b5134dc 100644 --- a/solver/llbsolver/file/backend.go +++ b/solver/llbsolver/file/backend.go @@ -27,10 +27,17 @@ func timestampToTime(ts int64) *time.Time { return &tm } -func mkdir(d string, action pb.FileActionMkDir, user *copy.User, idmap *idtools.IdentityMapping) error { +func mkdir(d string, action pb.FileActionMkDir, user *copy.User, idmap *idtools.IdentityMapping) (err error) { + defer func() { + var osErr *os.PathError + if errors.As(err, &osErr) { + osErr.Path = strings.TrimPrefix(osErr.Path, d) + } + }() + p, err := fs.RootPath(d, action.Path) if err != nil { - return err + return errors.WithStack(err) } ch, err := mapUserToChowner(user, idmap) @@ -47,23 +54,31 @@ func mkdir(d string, action pb.FileActionMkDir, user *copy.User, idmap *idtools. if errors.Is(err, os.ErrExist) { return nil } - return err + return errors.WithStack(err) } if err := copy.Chown(p, nil, ch); err != nil { - return err + return errors.WithStack(err) } if err := copy.Utimes(p, timestampToTime(action.Timestamp)); err != nil { - return err + return errors.WithStack(err) } } return nil } -func mkfile(d string, action pb.FileActionMkFile, user *copy.User, idmap *idtools.IdentityMapping) error { +func mkfile(d string, action pb.FileActionMkFile, user *copy.User, idmap *idtools.IdentityMapping) (err error) { + defer func() { + var osErr *os.PathError + if errors.As(err, &osErr) { + // remove system root from error path if present + osErr.Path = strings.TrimPrefix(osErr.Path, d) + } + }() + p, err := fs.RootPath(d, filepath.Join("/", action.Path)) if err != nil { - return err + return errors.WithStack(err) } ch, err := mapUserToChowner(user, idmap) @@ -72,21 +87,29 @@ func mkfile(d string, action pb.FileActionMkFile, user *copy.User, idmap *idtool } if err := os.WriteFile(p, action.Data, os.FileMode(action.Mode)&0777); err != nil { - return err + return errors.WithStack(err) } if err := copy.Chown(p, nil, ch); err != nil { - return err + return errors.WithStack(err) } if err := copy.Utimes(p, timestampToTime(action.Timestamp)); err != nil { - return err + return errors.WithStack(err) } return nil } -func rm(d string, action pb.FileActionRm) error { +func rm(d string, action pb.FileActionRm) (err error) { + defer func() { + var osErr *os.PathError + if errors.As(err, &osErr) { + // remove system root from error path if present + osErr.Path = strings.TrimPrefix(osErr.Path, d) + } + }() + if action.AllowWildcard { src, err := cleanPath(action.Path) if err != nil { @@ -94,7 +117,7 @@ func rm(d string, action pb.FileActionRm) error { } m, err := copy.ResolveWildcards(d, src, false) if err != nil { - return err + return errors.WithStack(err) } for _, s := range m { @@ -117,7 +140,7 @@ func rmPath(root, src string, allowNotFound bool) error { } dir, err := fs.RootPath(root, filepath.Join("/", dir)) if err != nil { - return err + return errors.WithStack(err) } p := filepath.Join(dir, base) @@ -125,14 +148,14 @@ func rmPath(root, src string, allowNotFound bool) error { _, err := os.Stat(p) if errors.Is(err, os.ErrNotExist) { - return err + return errors.WithStack(err) } } - return os.RemoveAll(p) + return errors.WithStack(os.RemoveAll(p)) } -func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u *copy.User, idmap *idtools.IdentityMapping) error { +func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u *copy.User, idmap *idtools.IdentityMapping) (err error) { srcPath, err := cleanPath(action.Src) if err != nil { return errors.Wrap(err, "cleaning source path") @@ -144,7 +167,7 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u * if !action.CreateDestPath { p, err := fs.RootPath(dest, filepath.Join("/", action.Dest)) if err != nil { - return err + return errors.WithStack(err) } if _, err := os.Lstat(filepath.Dir(p)); err != nil { return errors.Wrapf(err, "failed to stat %s", action.Dest) @@ -177,6 +200,15 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u * copy.WithXAttrErrorHandler(xattrErrorHandler), } + defer func() { + var osErr *os.PathError + if errors.As(err, &osErr) { + // remove system root from error path if present + osErr.Path = strings.TrimPrefix(osErr.Path, src) + osErr.Path = strings.TrimPrefix(osErr.Path, dest) + } + }() + var m []string if !action.AllowWildcard { m = []string{srcPath} @@ -184,7 +216,7 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u * var err error m, err = copy.ResolveWildcards(src, srcPath, action.FollowSymlink) if err != nil { - return err + return errors.WithStack(err) } if len(m) == 0 { @@ -198,13 +230,13 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u * for _, s := range m { if action.AttemptUnpackDockerCompatibility { if ok, err := unpack(src, s, dest, destPath, ch, timestampToTime(action.Timestamp), idmap); err != nil { - return err + return errors.WithStack(err) } else if ok { continue } } if err := copy.Copy(ctx, src, s, dest, destPath, opt...); err != nil { - return err + return errors.WithStack(err) } } diff --git a/solver/llbsolver/file/backend_test.go b/solver/llbsolver/file/backend_test.go index b13df1ef7..41bda56d9 100644 --- a/solver/llbsolver/file/backend_test.go +++ b/solver/llbsolver/file/backend_test.go @@ -5,6 +5,7 @@ import ( "path/filepath" "testing" + "github.com/pkg/errors" "github.com/stretchr/testify/require" ) @@ -12,7 +13,7 @@ func TestRmPathNonExistentFileAllowNotFoundFalse(t *testing.T) { root := t.TempDir() err := rmPath(root, "doesnt_exist", false) require.Error(t, err) - require.True(t, os.IsNotExist(err)) + require.True(t, errors.Is(err, os.ErrNotExist)) } func TestRmPathNonExistentFileAllowNotFoundTrue(t *testing.T) { diff --git a/solver/llbsolver/file/backend_unix.go b/solver/llbsolver/file/backend_unix.go index d01290f30..8f3c94b4c 100644 --- a/solver/llbsolver/file/backend_unix.go +++ b/solver/llbsolver/file/backend_unix.go @@ -5,6 +5,7 @@ package file import ( "github.com/docker/docker/pkg/idtools" + "github.com/pkg/errors" copy "github.com/tonistiigi/fsutil/copy" ) @@ -23,7 +24,7 @@ func mapUserToChowner(user *copy.User, idmap *idtools.IdentityMapping) (copy.Cho GID: old.GID, }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } return ©.User{UID: identity.UID, GID: identity.GID}, nil } @@ -38,7 +39,7 @@ func mapUserToChowner(user *copy.User, idmap *idtools.IdentityMapping) (copy.Cho GID: user.GID, }) if err != nil { - return nil, err + return nil, errors.WithStack(err) } u.UID = identity.UID u.GID = identity.GID diff --git a/solver/llbsolver/ops/file.go b/solver/llbsolver/ops/file.go index 8023d70b4..aeee3307b 100644 --- a/solver/llbsolver/ops/file.go +++ b/solver/llbsolver/ops/file.go @@ -169,7 +169,7 @@ func (f *fileOp) Exec(ctx context.Context, g session.Group, inputs []solver.Resu backend, err := file.NewFileOpBackend(getReadUserFn(f.w)) if err != nil { - return nil, err + return nil, errors.WithStack(err) } fs := NewFileOpSolver(f.w, backend, f.refManager) @@ -474,7 +474,7 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp if inp.ref != nil { m, err := s.r.Prepare(ctx, inp.ref, false, g) if err != nil { - return err + return errors.WithStack(err) } inpMount = m return nil @@ -493,7 +493,7 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp if inp.ref != nil { m, err := s.r.Prepare(ctx, inp.ref, true, g) if err != nil { - return err + return errors.WithStack(err) } inpMountSecondary = m toRelease = append(toRelease, m) @@ -521,7 +521,7 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp if inp.ref != nil { mm, err := s.r.Prepare(ctx, inp.ref, true, g) if err != nil { - return nil, err + return nil, errors.WithStack(err) } toRelease = append(toRelease, mm) m = mm @@ -572,7 +572,7 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp if inpMount == nil { m, err := s.r.Prepare(ctx, nil, false, g) if err != nil { - return input{}, err + return input{}, errors.WithStack(err) } inpMount = m }