// buildAci builds a target aci from the root directory using any uid shift // information from uidRange. func buildAci(root, manifestPath, target string, uidRange *user.UidRange) (e error) { mode := os.O_CREATE | os.O_WRONLY if flagOverwriteACI { mode |= os.O_TRUNC } else { mode |= os.O_EXCL } aciFile, err := os.OpenFile(target, mode, 0644) if err != nil { if os.IsExist(err) { return errors.New("target file exists (try --overwrite)") } else { return errwrap.Wrap(fmt.Errorf("unable to open target %s", target), err) } } gw := gzip.NewWriter(aciFile) tr := tar.NewWriter(gw) defer func() { tr.Close() gw.Close() aciFile.Close() // e is implicitly assigned by the return statement. As defer runs // after return, but before actually returning, this works. if e != nil { os.Remove(target) } }() b, err := ioutil.ReadFile(manifestPath) if err != nil { return errwrap.Wrap(errors.New("unable to read Image Manifest"), err) } var im schema.ImageManifest if err := im.UnmarshalJSON(b); err != nil { return errwrap.Wrap(errors.New("unable to load Image Manifest"), err) } iw := aci.NewImageWriter(im, tr) // Unshift uid and gid when pod was started with --private-user (user namespace) var walkerCb aci.TarHeaderWalkFunc = func(hdr *tar.Header) bool { if uidRange != nil { uid, gid, err := uidRange.UnshiftRange(uint32(hdr.Uid), uint32(hdr.Gid)) if err != nil { stderr.PrintE("error unshifting gid and uid", err) return false } hdr.Uid, hdr.Gid = int(uid), int(gid) } return true } if err := filepath.Walk(root, aci.BuildWalker(root, iw, walkerCb)); err != nil { return errwrap.Wrap(errors.New("error walking rootfs"), err) } if err = iw.Close(); err != nil { return errwrap.Wrap(fmt.Errorf("unable to close image %s", target), err) } return }