"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "add.go" between
buildah-1.10.1.tar.gz and buildah-1.11.0.tar.gz

About: Buildah is a tool that facilitates building Open Container Initiative (OCI) container images.

add.go  (buildah-1.10.1):add.go  (buildah-1.11.0)
skipping to change at line 19 skipping to change at line 19
"path/filepath" "path/filepath"
"strings" "strings"
"syscall" "syscall"
"time" "time"
"github.com/containers/buildah/pkg/chrootuser" "github.com/containers/buildah/pkg/chrootuser"
"github.com/containers/buildah/util" "github.com/containers/buildah/util"
"github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/fileutils" "github.com/containers/storage/pkg/fileutils"
"github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/system"
"github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// AddAndCopyOptions holds options for add and copy commands. // AddAndCopyOptions holds options for add and copy commands.
type AddAndCopyOptions struct { type AddAndCopyOptions struct {
// Chown is a spec for the user who should be given ownership over the // Chown is a spec for the user who should be given ownership over the
// newly-added content, potentially overriding permissions which would // newly-added content, potentially overriding permissions which would
// otherwise match those of local files and directories being copied. // otherwise match those of local files and directories being copied.
Chown string Chown string
// All of the data being copied will pass through Hasher, if set. // All of the data being copied will pass through Hasher, if set.
// If the sources are URLs or files, their contents will be passed to // If the sources are URLs or files, their contents will be passed to
// Hasher. // Hasher.
// If the sources include directory trees, Hasher will be passed // If the sources include directory trees, Hasher will be passed
// tar-format archives of the directory trees. // tar-format archives of the directory trees.
Hasher io.Writer Hasher io.Writer
// Excludes is the contents of the .dockerignore file // Excludes is the contents of the .dockerignore file
Excludes []string Excludes []string
// The base directory for Excludes and data to copy in // ContextDir is the base directory for Excludes for content being copied
ContextDir string ContextDir string
// ID mapping options to use when contents to be copied are part of // ID mapping options to use when contents to be copied are part of
// another container, and need ownerships to be mapped from the host to // another container, and need ownerships to be mapped from the host to
// that container's values before copying them into the container. // that container's values before copying them into the container.
IDMappingOptions *IDMappingOptions IDMappingOptions *IDMappingOptions
// DryRun indicates that the content should be digested, but not actually
// copied into the container.
DryRun bool
} }
// addURL copies the contents of the source URL to the destination. This is // addURL copies the contents of the source URL to the destination. This is
// its own function so that deferred closes happen after we're done pulling // its own function so that deferred closes happen after we're done pulling
// down each item of potentially many. // down each item of potentially many.
func addURL(destination, srcurl string, owner idtools.IDPair, hasher io.Writer) func (b *Builder) addURL(destination, srcurl string, owner idtools.IDPair, hashe
error { r io.Writer, dryRun bool) error {
logrus.Debugf("saving %q to %q", srcurl, destination)
resp, err := http.Get(srcurl) resp, err := http.Get(srcurl)
if err != nil { if err != nil {
return errors.Wrapf(err, "error getting %q", srcurl) return errors.Wrapf(err, "error getting %q", srcurl)
} }
defer resp.Body.Close() defer resp.Body.Close()
f, err := os.Create(destination)
if err != nil { thisHasher := hasher
return errors.Wrapf(err, "error creating %q", destination) if thisHasher != nil && b.ContentDigester.Hash() != nil {
} thisHasher = io.MultiWriter(thisHasher, b.ContentDigester.Hash())
if err = f.Chown(owner.UID, owner.GID); err != nil { }
return errors.Wrapf(err, "error setting owner of %q to %d:%d", de if thisHasher == nil {
stination, owner.UID, owner.GID) thisHasher = b.ContentDigester.Hash()
} }
if last := resp.Header.Get("Last-Modified"); last != "" { thisWriter := thisHasher
if mtime, err2 := time.Parse(time.RFC1123, last); err2 != nil {
logrus.Debugf("error parsing Last-Modified time %q: %v", if !dryRun {
last, err2) logrus.Debugf("saving %q to %q", srcurl, destination)
} else { f, err := os.Create(destination)
defer func() { if err != nil {
if err3 := os.Chtimes(destination, time.Now(), mt return errors.Wrapf(err, "error creating %q", destination
ime); err3 != nil { )
logrus.Debugf("error setting mtime on %q
to Last-Modified time %q: %v", destination, last, err3)
}
}()
} }
defer f.Close()
if err = f.Chown(owner.UID, owner.GID); err != nil {
return errors.Wrapf(err, "error setting owner of %q to %d
:%d", destination, owner.UID, owner.GID)
}
if last := resp.Header.Get("Last-Modified"); last != "" {
if mtime, err2 := time.Parse(time.RFC1123, last); err2 !=
nil {
logrus.Debugf("error parsing Last-Modified time %
q: %v", last, err2)
} else {
defer func() {
if err3 := os.Chtimes(destination, time.N
ow(), mtime); err3 != nil {
logrus.Debugf("error setting mtim
e on %q to Last-Modified time %q: %v", destination, last, err3)
}
}()
}
}
defer func() {
if err2 := f.Chmod(0600); err2 != nil {
logrus.Debugf("error setting permissions on %q: %
v", destination, err2)
}
}()
thisWriter = io.MultiWriter(f, thisWriter)
} }
defer f.Close()
bodyReader := io.Reader(resp.Body) n, err := io.Copy(thisWriter, resp.Body)
if hasher != nil {
bodyReader = io.TeeReader(bodyReader, hasher)
}
n, err := io.Copy(f, bodyReader)
if err != nil { if err != nil {
return errors.Wrapf(err, "error reading contents for %q from %q", destination, srcurl) return errors.Wrapf(err, "error reading contents for %q from %q", destination, srcurl)
} }
if resp.ContentLength >= 0 && n != resp.ContentLength { if resp.ContentLength >= 0 && n != resp.ContentLength {
return errors.Errorf("error reading contents for %q from %q: wron g length (%d != %d)", destination, srcurl, n, resp.ContentLength) return errors.Errorf("error reading contents for %q from %q: wron g length (%d != %d)", destination, srcurl, n, resp.ContentLength)
} }
if err := f.Chmod(0600); err != nil {
return errors.Wrapf(err, "error setting permissions on %q", desti
nation)
}
return nil return nil
} }
// Add copies the contents of the specified sources into the container's root // Add copies the contents of the specified sources into the container's root
// filesystem, optionally extracting contents of local files that look like // filesystem, optionally extracting contents of local files that look like
// non-empty archives. // non-empty archives.
func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption s, source ...string) error { func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption s, source ...string) error {
excludes, err := dockerIgnoreMatcher(options.Excludes, options.ContextDir ) excludes, err := dockerIgnoreMatcher(options.Excludes, options.ContextDir )
if err != nil { if err != nil {
return err return err
skipping to change at line 122 skipping to change at line 136
if err != nil { if err != nil {
return err return err
} }
containerOwner := idtools.IDPair{UID: int(user.UID), GID: int(user.GID)} containerOwner := idtools.IDPair{UID: int(user.UID), GID: int(user.GID)}
hostUID, hostGID, err := util.GetHostIDs(b.IDMappingOptions.UIDMap, b.IDM appingOptions.GIDMap, user.UID, user.GID) hostUID, hostGID, err := util.GetHostIDs(b.IDMappingOptions.UIDMap, b.IDM appingOptions.GIDMap, user.UID, user.GID)
if err != nil { if err != nil {
return err return err
} }
hostOwner := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)} hostOwner := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)}
dest := mountPoint dest := mountPoint
if destination != "" && filepath.IsAbs(destination) { if !options.DryRun {
dir := filepath.Dir(destination) // Resolve the destination if it was specified as a relative path
if dir != "." && dir != "/" { .
if err = idtools.MkdirAllAndChownNew(filepath.Join(dest, if destination != "" && filepath.IsAbs(destination) {
dir), 0755, hostOwner); err != nil { dir := filepath.Dir(destination)
return errors.Wrapf(err, "error creating director if dir != "." && dir != "/" {
y %q", filepath.Join(dest, dir)) if err = idtools.MkdirAllAndChownNew(filepath.Joi
} n(dest, dir), 0755, hostOwner); err != nil {
} return errors.Wrapf(err, "error creating
dest = filepath.Join(dest, destination) directory %q", filepath.Join(dest, dir))
} else { }
if err = idtools.MkdirAllAndChownNew(filepath.Join(dest, b.WorkDi }
r()), 0755, hostOwner); err != nil { dest = filepath.Join(dest, destination)
return errors.Wrapf(err, "error creating directory %q", f } else {
ilepath.Join(dest, b.WorkDir())) if err = idtools.MkdirAllAndChownNew(filepath.Join(dest,
} b.WorkDir()), 0755, hostOwner); err != nil {
dest = filepath.Join(dest, b.WorkDir(), destination) return errors.Wrapf(err, "error creating director
} y %q", filepath.Join(dest, b.WorkDir()))
// If the destination was explicitly marked as a directory by ending it }
// with a '/', create it so that we can be sure that it's a directory, dest = filepath.Join(dest, b.WorkDir(), destination)
// and any files we're copying will be placed in the directory. }
if len(destination) > 0 && destination[len(destination)-1] == os.PathSepa // If the destination was explicitly marked as a directory by end
rator { ing it
if err = idtools.MkdirAllAndChownNew(dest, 0755, hostOwner); err // with a '/', create it so that we can be sure that it's a direc
!= nil { tory,
return errors.Wrapf(err, "error creating directory %q", d // and any files we're copying will be placed in the directory.
est) if len(destination) > 0 && destination[len(destination)-1] == os.
} PathSeparator {
} if err = idtools.MkdirAllAndChownNew(dest, 0755, hostOwne
// Make sure the destination's parent directory is usable. r); err != nil {
if destpfi, err2 := os.Stat(filepath.Dir(dest)); err2 == nil && !destpfi. return errors.Wrapf(err, "error creating director
IsDir() { y %q", dest)
return errors.Errorf("%q already exists, but is not a subdirector }
y)", filepath.Dir(dest)) }
// Make sure the destination's parent directory is usable.
if destpfi, err2 := os.Stat(filepath.Dir(dest)); err2 == nil && !
destpfi.IsDir() {
return errors.Errorf("%q already exists, but is not a sub
directory)", filepath.Dir(dest))
}
} }
// Now look at the destination itself. // Now look at the destination itself.
destfi, err := os.Stat(dest) destfi, err := os.Stat(dest)
if err != nil { if err != nil {
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
return errors.Wrapf(err, "couldn't determine what %q is", dest) return errors.Wrapf(err, "couldn't determine what %q is", dest)
} }
destfi = nil destfi = nil
} }
if len(source) > 1 && (destfi == nil || !destfi.IsDir()) { if len(source) > 1 && (destfi == nil || !destfi.IsDir()) {
return errors.Errorf("destination %q is not a directory", dest) return errors.Errorf("destination %q is not a directory", dest)
} }
copyFileWithTar := b.copyFileWithTar(options.IDMappingOptions, &container copyFileWithTar := b.copyFileWithTar(options.IDMappingOptions, &container
Owner, options.Hasher) Owner, options.Hasher, options.DryRun)
copyWithTar := b.copyWithTar(options.IDMappingOptions, &containerOwner, o copyWithTar := b.copyWithTar(options.IDMappingOptions, &containerOwner, o
ptions.Hasher) ptions.Hasher, options.DryRun)
untarPath := b.untarPath(nil, options.Hasher) untarPath := b.untarPath(nil, options.Hasher, options.DryRun)
err = addHelper(excludes, extract, dest, destfi, hostOwner, options, copy err = b.addHelper(excludes, extract, dest, destfi, hostOwner, options, co
FileWithTar, copyWithTar, untarPath, source...) pyFileWithTar, copyWithTar, untarPath, source...)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
// user returns the user (and group) information which the destination should be long to. // user returns the user (and group) information which the destination should be long to.
func (b *Builder) user(mountPoint string, userspec string) (specs.User, string, error) { func (b *Builder) user(mountPoint string, userspec string) (specs.User, string, error) {
if userspec == "" { if userspec == "" {
userspec = b.User() userspec = b.User()
skipping to change at line 233 skipping to change at line 250
return nil, nil return nil, nil
} }
// return a matcher object // return a matcher object
matcher, err := fileutils.NewPatternMatcher(patterns) matcher, err := fileutils.NewPatternMatcher(patterns)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "error creating file matcher using patterns %v", patterns) return nil, errors.Wrapf(err, "error creating file matcher using patterns %v", patterns)
} }
return matcher, nil return matcher, nil
} }
func addHelper(excludes *fileutils.PatternMatcher, extract bool, dest string, de func (b *Builder) addHelper(excludes *fileutils.PatternMatcher, extract bool, de
stfi os.FileInfo, hostOwner idtools.IDPair, options AddAndCopyOptions, copyFileW st string, destfi os.FileInfo, hostOwner idtools.IDPair, options AddAndCopyOptio
ithTar, copyWithTar, untarPath func(src, dest string) error, source ...string) e ns, copyFileWithTar, copyWithTar, untarPath func(src, dest string) error, source
rror { ...string) error {
for _, src := range source { for n, src := range source {
if strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "h ttps://") { if strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "h ttps://") {
b.ContentDigester.Start("")
// We assume that source is a file, and we're copying // We assume that source is a file, and we're copying
// it to the destination. If the destination is // it to the destination. If the destination is
// already a directory, create a file inside of it. // already a directory, create a file inside of it.
// Otherwise, the destination is the file to which // Otherwise, the destination is the file to which
// we'll save the contents. // we'll save the contents.
url, err := url.Parse(src) url, err := url.Parse(src)
if err != nil { if err != nil {
return errors.Wrapf(err, "error parsing URL %q", src) return errors.Wrapf(err, "error parsing URL %q", src)
} }
d := dest d := dest
if destfi != nil && destfi.IsDir() { if destfi != nil && destfi.IsDir() {
d = filepath.Join(dest, path.Base(url.Path)) d = filepath.Join(dest, path.Base(url.Path))
} }
if err = addURL(d, src, hostOwner, options.Hasher); err ! = nil { if err = b.addURL(d, src, hostOwner, options.Hasher, opti ons.DryRun); err != nil {
return err return err
} }
continue continue
} }
glob, err := filepath.Glob(src) glob, err := filepath.Glob(src)
if err != nil { if err != nil {
return errors.Wrapf(err, "invalid glob %q", src) return errors.Wrapf(err, "invalid glob %q", src)
} }
if len(glob) == 0 { if len(glob) == 0 {
skipping to change at line 273 skipping to change at line 291
for _, gsrc := range glob { for _, gsrc := range glob {
esrc, err := filepath.EvalSymlinks(gsrc) esrc, err := filepath.EvalSymlinks(gsrc)
if err != nil { if err != nil {
return errors.Wrapf(err, "error evaluating symlin ks %q", gsrc) return errors.Wrapf(err, "error evaluating symlin ks %q", gsrc)
} }
srcfi, err := os.Stat(esrc) srcfi, err := os.Stat(esrc)
if err != nil { if err != nil {
return errors.Wrapf(err, "error reading %q", esrc ) return errors.Wrapf(err, "error reading %q", esrc )
} }
if srcfi.IsDir() { if srcfi.IsDir() {
b.ContentDigester.Start("dir")
// The source is a directory, so copy the content s of // The source is a directory, so copy the content s of
// the source directory into the target directory . Try // the source directory into the target directory . Try
// to create it first, so that if there's a probl em, // to create it first, so that if there's a probl em,
// we'll discover why that won't work. // we'll discover why that won't work.
if err = idtools.MkdirAllAndChownNew(dest, 0755, if !options.DryRun {
hostOwner); err != nil { if err = idtools.MkdirAllAndChownNew(dest
return errors.Wrapf(err, "error creating , 0755, hostOwner); err != nil {
directory %q", dest) return errors.Wrapf(err, "error c
reating directory %q", dest)
}
} }
logrus.Debugf("copying %q to %q", esrc+string(os. PathSeparator)+"*", dest+string(os.PathSeparator)+"*") logrus.Debugf("copying[%d] %q to %q", n, esrc+str ing(os.PathSeparator)+"*", dest+string(os.PathSeparator)+"*")
if excludes == nil || !excludes.Exclusions() { if excludes == nil || !excludes.Exclusions() {
if err = copyWithTar(esrc, dest); err != nil { if err = copyWithTar(esrc, dest); err != nil {
return errors.Wrapf(err, "error c opying %q to %q", esrc, dest) return errors.Wrapf(err, "error c opying %q to %q", esrc, dest)
} }
continue continue
} }
err := filepath.Walk(esrc, func(path string, info os.FileInfo, err error) error { err := filepath.Walk(esrc, func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
skip, err := excludes.Matches(path) skip, err := excludes.Matches(path)
if err != nil { if err != nil {
return errors.Wrapf(err, "error c hecking if %s is an excluded path", path) return errors.Wrapf(err, "error c hecking if %s is an excluded path", path)
} }
if skip { if skip {
return nil return nil
} }
// combine the filename with the dest dir ectory // combine the source's basename with the dest directory
fpath, err := filepath.Rel(esrc, path) fpath, err := filepath.Rel(esrc, path)
if err != nil { if err != nil {
return errors.Wrapf(err, "error c onverting %s to a path relative to %s", path, esrc) return errors.Wrapf(err, "error c onverting %s to a path relative to %s", path, esrc)
} }
mtime := info.ModTime()
atime := mtime
times := []syscall.Timespec{
syscall.NsecToTimespec(atime.Unix
()),
syscall.NsecToTimespec(mtime.Unix
()),
}
if info.IsDir() {
return addHelperDirectory(esrc, p
ath, filepath.Join(dest, fpath), info, hostOwner, times)
}
if info.Mode()&os.ModeSymlink == os.ModeS
ymlink {
return addHelperSymlink(path, fil
epath.Join(dest, fpath), hostOwner, times)
}
if !info.Mode().IsRegular() {
return errors.Errorf("error copyi
ng %q to %q: source is not a regular file; file mode is %s", path, dest, info.Mo
de())
}
if err = copyFileWithTar(path, filepath.J oin(dest, fpath)); err != nil { if err = copyFileWithTar(path, filepath.J oin(dest, fpath)); err != nil {
return errors.Wrapf(err, "error c opying %q to %q", path, dest) return errors.Wrapf(err, "error c opying %q to %q", path, dest)
} }
return nil return nil
}) })
if err != nil { if err != nil {
return err return err
} }
continue continue
} }
b.ContentDigester.Start("file")
if !extract || !archive.IsArchivePath(esrc) { if !extract || !archive.IsArchivePath(esrc) {
// This source is a file, and either it's not an // This source is a file, and either it's not an
// archive, or we don't care whether or not it's an // archive, or we don't care whether or not it's an
// archive. // archive.
d := dest d := dest
if destfi != nil && destfi.IsDir() { if destfi != nil && destfi.IsDir() {
d = filepath.Join(dest, filepath.Base(gsr c)) d = filepath.Join(dest, filepath.Base(gsr c))
} }
// Copy the file, preserving attributes. // Copy the file, preserving attributes.
logrus.Debugf("copying %q to %q", esrc, d) logrus.Debugf("copying[%d] %q to %q", n, esrc, d)
if err = copyFileWithTar(esrc, d); err != nil { if err = copyFileWithTar(esrc, d); err != nil {
return errors.Wrapf(err, "error copying % q to %q", esrc, d) return errors.Wrapf(err, "error copying % q to %q", esrc, d)
} }
continue continue
} }
// We're extracting an archive into the destination direc tory. // We're extracting an archive into the destination direc tory.
logrus.Debugf("extracting contents of %q into %q", esrc, dest) logrus.Debugf("extracting contents[%d] of %q into %q", n, esrc, dest)
if err = untarPath(esrc, dest); err != nil { if err = untarPath(esrc, dest); err != nil {
return errors.Wrapf(err, "error extracting %q int o %q", esrc, dest) return errors.Wrapf(err, "error extracting %q int o %q", esrc, dest)
} }
} }
} }
return nil return nil
} }
func addHelperDirectory(esrc, path, dest string, info os.FileInfo, hostOwner idt
ools.IDPair, times []syscall.Timespec) error {
if err := idtools.MkdirAllAndChownNew(dest, info.Mode().Perm(), hostOwner
); err != nil {
// discard only EEXIST on the top directory, which would have bee
n created earlier in the caller
if !os.IsExist(err) || path != esrc {
return errors.Errorf("error creating directory %q", dest)
}
}
if err := idtools.SafeLchown(dest, hostOwner.UID, hostOwner.GID); err !=
nil {
return errors.Wrapf(err, "error setting owner of directory %q to
%d:%d", dest, hostOwner.UID, hostOwner.GID)
}
if err := system.LUtimesNano(dest, times); err != nil {
return errors.Wrapf(err, "error setting dates on directory %q", d
est)
}
return nil
}
func addHelperSymlink(src, dest string, hostOwner idtools.IDPair, times []syscal
l.Timespec) error {
linkContents, err := os.Readlink(src)
if err != nil {
return errors.Wrapf(err, "error reading contents of symbolic link
at %q", src)
}
if err = os.Symlink(linkContents, dest); err != nil {
if !os.IsExist(err) {
return errors.Wrapf(err, "error creating symbolic link to
%q at %q", linkContents, dest)
}
if err = os.RemoveAll(dest); err != nil {
return errors.Wrapf(err, "error clearing symbolic link ta
rget %q", dest)
}
if err = os.Symlink(linkContents, dest); err != nil {
return errors.Wrapf(err, "error creating symbolic link to
%q at %q (second try)", linkContents, dest)
}
}
if err = idtools.SafeLchown(dest, hostOwner.UID, hostOwner.GID); err != n
il {
return errors.Wrapf(err, "error setting owner of symbolic link %q
to %d:%d", dest, hostOwner.UID, hostOwner.GID)
}
if err = system.LUtimesNano(dest, times); err != nil {
return errors.Wrapf(err, "error setting dates on symbolic link %q
", dest)
}
logrus.Debugf("Symlink(%s, %s)", linkContents, dest)
return nil
}
 End of changes. 22 change blocks. 
112 lines changed or deleted 118 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)