func TestChrootApplyDotDotFile(t *testing.T) { tmpdir, err := ioutil.TempDir("", "docker-TestChrootApplyDotDotFile") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") if err := os.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if err := ioutil.WriteFile(filepath.Join(src, "..gitme"), []byte(""), 0644); err != nil { t.Fatal(err) } stream, err := archive.Tar(src, archive.Uncompressed) if err != nil { t.Fatal(err) } dest := filepath.Join(tmpdir, "dest") if err := os.MkdirAll(dest, 0700); err != nil { t.Fatal(err) } if _, err := ApplyLayer(dest, stream); err != nil { t.Fatal(err) } }
// gh#10426: Verify the fix for having a huge excludes list (like on `docker load` with large # of // local images) func TestChrootUntarWithHugeExcludesList(t *testing.T) { tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarHugeExcludes") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if err := ioutil.WriteFile(filepath.Join(src, "toto"), []byte("hello toto"), 0644); err != nil { t.Fatal(err) } stream, err := archive.Tar(src, archive.Uncompressed) if err != nil { t.Fatal(err) } dest := filepath.Join(tmpdir, "dest") if err := system.MkdirAll(dest, 0700); err != nil { t.Fatal(err) } options := &archive.TarOptions{} //65534 entries of 64-byte strings ~= 4MB of environment space which should overflow //on most systems when passed via environment or command line arguments excludes := make([]string, 65534, 65534) for i := 0; i < 65534; i++ { excludes[i] = strings.Repeat(string(i), 64) } options.ExcludePatterns = excludes if err := Untar(stream, dest, options); err != nil { t.Fatal(err) } }
func TestChrootUntarPath(t *testing.T) { tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarPath") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") if err := os.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if _, err := prepareSourceDirectory(10, src, true); err != nil { t.Fatal(err) } dest := filepath.Join(tmpdir, "dest") // Untar a directory if err := UntarPath(src, dest); err == nil { t.Fatal("Expected error on untaring a directory") } // Untar a tar file stream, err := archive.Tar(src, archive.Uncompressed) if err != nil { t.Fatal(err) } buf := new(bytes.Buffer) buf.ReadFrom(stream) tarfile := filepath.Join(tmpdir, "src.tar") if err := ioutil.WriteFile(tarfile, buf.Bytes(), 0644); err != nil { t.Fatal(err) } if err := UntarPath(tarfile, dest); err != nil { t.Fatal(err) } }
// Push pushes a plugin to the store. func (pm *Manager) Push(name string, metaHeader http.Header, authConfig *types.AuthConfig) error { p, err := pm.pluginStore.GetByName(name) if err != nil { return err } dest := filepath.Join(pm.libRoot, p.GetID()) config, err := ioutil.ReadFile(filepath.Join(dest, "config.json")) if err != nil { return err } var dummy types.Plugin err = json.Unmarshal(config, &dummy) if err != nil { return err } rootfs, err := archive.Tar(p.Rootfs, archive.Gzip) if err != nil { return err } defer rootfs.Close() _, err = distribution.Push(name, pm.registryService, metaHeader, authConfig, ioutil.NopCloser(bytes.NewReader(config)), rootfs) // XXX: Ignore returning digest for now. // Since digest needs to be written to the ProgressWriter. return err }
func (l *Local) fetch(path string) (string, error) { path, err := resolve(path) if err != nil { return "", err } id := l.IDProvider.ProvideID(path) // synchronize all downloads, we could optimize by only mutexing around each // particular rootfs path, but in practice importing local rootfses is decently fast, // and concurrently importing local rootfses is rare. l.mu.Lock() defer l.mu.Unlock() if _, err := l.Cake.Get(id); err == nil { return id.GraphID(), nil // use cache } tar, err := archive.Tar(path, archive.Uncompressed) if err != nil { return "", fmt.Errorf("repository_fetcher: fetch local rootfs: untar rootfs: %v", err) } defer tar.Close() if err := l.Cake.Register(&image.Image{ID: id.GraphID()}, tar); err != nil { return "", fmt.Errorf("repository_fetcher: fetch local rootfs: register rootfs: %v", err) } return id.GraphID(), nil }
func TestMakeSumTarContext(t *testing.T) { contextDir, err := ioutil.TempDir("", "builder-tarsum-test") if err != nil { t.Fatalf("Error with creating temporary directory: %s", err) } defer os.RemoveAll(contextDir) testFilename := filepath.Join(contextDir, filename) err = ioutil.WriteFile(testFilename, []byte(contents), 0644) if err != nil { t.Fatalf("Error when writing file (%s) contents: %s", testFilename, err) } tarStream, err := archive.Tar(contextDir, archive.Uncompressed) if err != nil { t.Fatalf("error: %s", err) } defer tarStream.Close() tarSum, err := MakeTarSumContext(tarStream) if err != nil { t.Fatalf("Error when executing MakeSumContext: %s", err) } if tarSum == nil { t.Fatalf("Tar sum context should not be nil") } }
func diff(id, parent string) (diff archive.Archive, err error) { // create pod // start or replace pod glog.Infof("Diff between %s and %s", id, parent) layerFs := "/tmp/test1" if parent == "" { archive, err := archive.Tar(layerFs, archive.Uncompressed) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() return err }), nil } parentFs := "/tmp/test2" changes, err := archive.ChangesDirs(layerFs, parentFs) if err != nil { return nil, err } archive, err := archive.ExportChanges(layerFs, changes) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() return err }), nil }
func TestChrootTarUntar(t *testing.T) { tmpdir, err := ioutil.TempDir("", "docker-TestChrootTarUntar") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") if err := os.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if err := ioutil.WriteFile(filepath.Join(src, "toto"), []byte("hello toto"), 0644); err != nil { t.Fatal(err) } if err := ioutil.WriteFile(filepath.Join(src, "lolo"), []byte("hello lolo"), 0644); err != nil { t.Fatal(err) } stream, err := archive.Tar(src, archive.Uncompressed) if err != nil { t.Fatal(err) } dest := filepath.Join(tmpdir, "src") if err := os.MkdirAll(dest, 0700); err != nil { t.Fatal(err) } if err := Untar(stream, dest, &archive.TarOptions{ExcludePatterns: []string{"lolo"}}); err != nil { t.Fatal(err) } }
func (c *devicemapper) TarStream(id, parent string) (io.ReadCloser, error) { mainPath, releaseMain, err := c.Mount(id) if err != nil { return nil, err } if parent == "" { tar, err := archive.Tar(mainPath, archive.Uncompressed) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(tar, func() error { releaseMain() return tar.Close() }), nil } parentPath, releaseParent, err := c.Mount(parent) if err != nil { releaseMain() return nil, err } tar, err := Diff(mainPath, parentPath) if err != nil { releaseParent() releaseMain() return nil, err } return ioutils.NewReadCloserWrapper(tar, func() error { releaseParent() releaseMain() return tar.Close() }), nil }
// Build the Image func (c *ImageService) Build(tag, dir string) error { // tar the file context, err := archive.Tar(dir, archive.Uncompressed) if err != nil { return err } var body io.Reader body = ioutil.NopCloser(context) // Upload the build context v := url.Values{} v.Set("t", tag) v.Set("q", "1") v.Set("rm", "1") // url path path := fmt.Sprintf("/build?%s", v.Encode()) // set content type to tar file headers := http.Header{} headers.Set("Content-Type", "application/tar") // make the request return c.stream("POST", path, body /*os.Stdout*/, nil, headers) }
func tarFromFiles(files ...FileApplier) ([]byte, error) { td, err := ioutil.TempDir("", "tar-") if err != nil { return nil, err } defer os.RemoveAll(td) for _, f := range files { if err := f.ApplyFile(td); err != nil { return nil, err } } r, err := archive.Tar(td, archive.Uncompressed) if err != nil { return nil, err } buf := bytes.NewBuffer(nil) if _, err := io.Copy(buf, r); err != nil { return nil, err } return buf.Bytes(), nil }
func executeTestCase(t *testing.T, testCase dispatchTestCase) { contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") defer cleanup() for filename, content := range testCase.files { createTestTempFile(t, contextDir, filename, content, 0777) } tarStream, err := archive.Tar(contextDir, archive.Uncompressed) if err != nil { t.Fatalf("Error when creating tar stream: %s", err) } defer func() { if err = tarStream.Close(); err != nil { t.Fatalf("Error when closing tar stream: %s", err) } }() context, err := builder.MakeTarSumContext(tarStream) if err != nil { t.Fatalf("Error when creating tar context: %s", err) } defer func() { if err = context.Close(); err != nil { t.Fatalf("Error when closing tar context: %s", err) } }() r := strings.NewReader(testCase.dockerfile) d := parser.Directive{} parser.SetEscapeToken(parser.DefaultEscapeToken, &d) n, err := parser.Parse(r, &d) if err != nil { t.Fatalf("Error when parsing Dockerfile: %s", err) } config := &container.Config{} options := &types.ImageBuildOptions{} b := &Builder{runConfig: config, options: options, Stdout: ioutil.Discard, context: context} err = b.dispatch(0, n.Children[0]) if err == nil { t.Fatalf("No error when executing test %s", testCase.name) } if !strings.Contains(err.Error(), testCase.expectedError) { t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", testCase.expectedError, err.Error()) } }
func registerImageLayer(cake *layercake.Docker, img *image.Image) { tmp, err := ioutil.TempDir("", "my-img") Expect(err).NotTo(HaveOccurred()) defer os.RemoveAll(tmp) Expect(ioutil.WriteFile(path.Join(tmp, img.ID), []byte("Hello"), 0700)).To(Succeed()) archiver, _ := archive.Tar(tmp, archive.Uncompressed) Expect(cake.Register(img, archiver)).To(Succeed()) }
// Diff produces an archive of the changes between the specified // layer and its parent layer which may be "". func (gdw *NaiveDiffDriver) Diff(id, parent string) (arch archive.Archive, err error) { startTime := time.Now() driver := gdw.ProtoDriver layerFs, err := driver.Get(id, "") if err != nil { return nil, err } defer func() { if err != nil { driver.Put(id) } }() if parent == "" { archive, err := archive.Tar(layerFs, archive.Uncompressed) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() driver.Put(id) return err }), nil } parentFs, err := driver.Get(parent, "") if err != nil { return nil, err } defer driver.Put(parent) changes, err := archive.ChangesDirs(layerFs, parentFs) if err != nil { return nil, err } archive, err := archive.ExportChanges(layerFs, changes, gdw.uidMaps, gdw.gidMaps) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() driver.Put(id) // NaiveDiffDriver compares file metadata with parent layers. Parent layers // are extracted from tar's with full second precision on modified time. // We need this hack here to make sure calls within same second receive // correct result. time.Sleep(startTime.Truncate(time.Second).Add(time.Second).Sub(time.Now())) return err }), nil }
func TestGetContextFromReaderTar(t *testing.T) { contextDir, cleanup := createTestTempDir(t, "", "builder-context-test") defer cleanup() createTestTempFile(t, contextDir, DefaultDockerfileName, dockerfileContents, 0777) tarStream, err := archive.Tar(contextDir, archive.Uncompressed) if err != nil { t.Fatalf("Error when creating tar: %s", err) } tarArchive, relDockerfile, err := GetContextFromReader(tarStream, DefaultDockerfileName) if err != nil { t.Fatalf("Error when executing GetContextFromReader: %s", err) } tarReader := tar.NewReader(tarArchive) header, err := tarReader.Next() if err != nil { t.Fatalf("Error when reading tar archive: %s", err) } if header.Name != DefaultDockerfileName { t.Fatalf("Dockerfile name should be: %s, got: %s", DefaultDockerfileName, header.Name) } buff := new(bytes.Buffer) buff.ReadFrom(tarReader) contents := buff.String() _, err = tarReader.Next() if err != io.EOF { t.Fatalf("Tar stream too long: %s", err) } if err = tarArchive.Close(); err != nil { t.Fatalf("Error when closing tar stream: %s", err) } if dockerfileContents != contents { t.Fatalf("Uncompressed tar archive does not equal: %s, got: %s", dockerfileContents, contents) } if relDockerfile != DefaultDockerfileName { t.Fatalf("Relative path not equals %s, got: %s", DefaultDockerfileName, relDockerfile) } }
//Save persits the contents of dir to the cache, task identifies the task (external) that manages the files there func (c Cache) Save(dir string, task string) { tarball, err := archive.Tar(dir, archive.Gzip) checkerr(err) cacheWriter, err := c.Store.Writer(c.path(dir, task)) checkerr(err) _, err = io.Copy(cacheWriter, tarball) checkerr(err) cacheWriter.Close() c.log.Info("Cache for", dir, "saved as", c.path(dir, task)) }
// Diff produces an archive of the changes between the specified // layer and its parent layer which may be "". func (gdw *naiveDiffDriver) Diff(id, parent string) (arch archive.Archive, err error) { driver := gdw.ProtoDriver layerFs, err := driver.Get(id, "") if err != nil { return nil, err } defer func() { if err != nil { driver.Put(id) } }() if parent == "" { archive, err := archive.Tar(layerFs, archive.Uncompressed) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() driver.Put(id) return err }), nil } parentFs, err := driver.Get(parent, "") if err != nil { return nil, err } defer driver.Put(parent) changes, err := archive.ChangesDirs(layerFs, parentFs) if err != nil { return nil, err } archive, err := archive.ExportChanges(layerFs, changes) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() driver.Put(id) return err }), nil }
// Push pushes a plugin to the store. func (pm *Manager) Push(name string, metaHeader http.Header, authConfig *types.AuthConfig) error { p, err := pm.get(name) dest := filepath.Join(pm.libRoot, p.P.ID) config, err := os.Open(filepath.Join(dest, "manifest.json")) if err != nil { return err } rootfs, err := archive.Tar(filepath.Join(dest, "rootfs"), archive.Gzip) if err != nil { return err } _, err = distribution.Push(name, pm.registryService, metaHeader, authConfig, config, rootfs) // XXX: Ignore returning digest for now. // Since digest needs to be written to the ProgressWriter. return nil }
func (c *btrfs) TarStream(id, parent string) (io.ReadCloser, error) { mainPath, _, err := c.Mount(id) if err != nil { return nil, err } if parent == "" { return archive.Tar(mainPath, archive.Uncompressed) } parentPath, _, err := c.Mount(parent) if err != nil { return nil, err } return Diff(mainPath, parentPath) }
// getContextFromReader will read the contents of the given reader as either a // Dockerfile or tar archive. Returns a tar archive used as a context and a // path to the Dockerfile inside the tar. func getContextFromReader(r io.ReadCloser, dockerfileName string) (out io.ReadCloser, relDockerfile string, err error) { buf := bufio.NewReader(r) magic, err := buf.Peek(archive.HeaderSize) if err != nil && err != io.EOF { return nil, "", fmt.Errorf("failed to peek context header from STDIN: %v", err) } if archive.IsArchive(magic) { return ioutils.NewReadCloserWrapper(buf, func() error { return r.Close() }), dockerfileName, nil } // Input should be read as a Dockerfile. tmpDir, err := ioutil.TempDir("", "docker-build-context-") if err != nil { return nil, "", fmt.Errorf("unbale to create temporary context directory: %v", err) } f, err := os.Create(filepath.Join(tmpDir, api.DefaultDockerfileName)) if err != nil { return nil, "", err } _, err = io.Copy(f, buf) if err != nil { f.Close() return nil, "", err } if err := f.Close(); err != nil { return nil, "", err } if err := r.Close(); err != nil { return nil, "", err } tar, err := archive.Tar(tmpDir, archive.Uncompressed) if err != nil { return nil, "", err } return ioutils.NewReadCloserWrapper(tar, func() error { err := tar.Close() os.RemoveAll(tmpDir) return err }), api.DefaultDockerfileName, nil }
// exportLayer generates an archive from a layer based on the given ID. func (d *Driver) exportLayer(id string, parentLayerPaths []string) (archive.Archive, error) { if hcsshim.IsTP4() { // Export in TP4 format to maintain compatibility with existing images and // because ExportLayer is somewhat broken on TP4 and can't work with the new // scheme. tempFolder, err := ioutil.TempDir("", "hcs") if err != nil { return nil, err } defer func() { if err != nil { os.RemoveAll(tempFolder) } }() if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil { return nil, err } archive, err := archive.Tar(tempFolder, archive.Uncompressed) if err != nil { return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() os.RemoveAll(tempFolder) return err }), nil } var r hcsshim.LayerReader r, err := hcsshim.NewLayerReader(d.info, id, parentLayerPaths) if err != nil { return nil, err } archive, w := io.Pipe() go func() { err := writeTarFromLayer(r, w) cerr := r.Close() if err == nil { err = cerr } w.CloseWithError(err) }() return archive, nil }
func (container *Container) Export() (archive.Archive, error) { if err := container.Mount(); err != nil { return nil, err } archive, err := archive.Tar(container.basefs, archive.Uncompressed) if err != nil { container.Unmount() return nil, err } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() container.Unmount() return err }), nil }
func TestDockerfileOutsideTheBuildContext(t *testing.T) { contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") defer cleanup() tarStream, err := archive.Tar(contextDir, archive.Uncompressed) if err != nil { t.Fatalf("Error when creating tar stream: %s", err) } defer func() { if err = tarStream.Close(); err != nil { t.Fatalf("Error when closing tar stream: %s", err) } }() context, err := builder.MakeTarSumContext(tarStream) if err != nil { t.Fatalf("Error when creating tar context: %s", err) } defer func() { if err = context.Close(); err != nil { t.Fatalf("Error when closing tar context: %s", err) } }() options := &types.ImageBuildOptions{ Dockerfile: "../../Dockerfile", } b := &Builder{options: options, context: context} err = b.readDockerfile() if err == nil { t.Fatalf("No error when executing test for Dockerfile outside the build context") } expectedError := "Forbidden path outside the build context" if !strings.Contains(err.Error(), expectedError) { t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", expectedError, err.Error()) } }
func (container *Container) export(ctx context.Context) (archive.Archive, error) { if err := container.Mount(ctx); err != nil { return nil, err } archive, err := archive.Tar(container.basefs, archive.Uncompressed) if err != nil { container.Unmount(ctx) return nil, err } arch := ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() container.Unmount(ctx) return err }) container.logEvent(ctx, "export") return arch, err }
// MakeGitContext returns a Context from gitURL that is cloned in a temporary directory. func MakeGitContext(gitURL string) (ModifiableContext, error) { root, err := utils.GitClone(gitURL) if err != nil { return nil, err } c, err := archive.Tar(root, archive.Uncompressed) if err != nil { return nil, err } defer func() { // TODO: print errors? c.Close() os.RemoveAll(root) }() return MakeTarSumContext(c) }
func TestEmptyDockerfile(t *testing.T) { contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") defer cleanup() createTestTempFile(t, contextDir, builder.DefaultDockerfileName, "", 0777) tarStream, err := archive.Tar(contextDir, archive.Uncompressed) if err != nil { t.Fatalf("Error when creating tar stream: %s", err) } defer func() { if err = tarStream.Close(); err != nil { t.Fatalf("Error when closing tar stream: %s", err) } }() context, err := builder.MakeTarSumContext(tarStream) if err != nil { t.Fatalf("Error when creating tar context: %s", err) } defer func() { if err = context.Close(); err != nil { t.Fatalf("Error when closing tar context: %s", err) } }() options := &types.ImageBuildOptions{} b := &Builder{options: options, context: context} err = b.readDockerfile() if err == nil { t.Fatalf("No error when executing test for empty Dockerfile") } if !strings.Contains(err.Error(), "The Dockerfile (Dockerfile) cannot be empty") { t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", "The Dockerfile (Dockerfile) cannot be empty", err.Error()) } }
func (d *WindowsGraphDriver) Export(id string, parentLayerPaths []string) (arch archive.Archive, err error) { layerFs, err := d.Get(id, "") if err != nil { return } defer func() { if err != nil { d.Put(id) } }() tempFolder := layerFs + "-temp" if err = os.MkdirAll(tempFolder, 0755); err != nil { logrus.Errorf("Could not create %s %s", tempFolder, err) return } defer func() { if err != nil { if err2 := os.RemoveAll(tempFolder); err2 != nil { logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) } } }() if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil { return } archive, err := archive.Tar(tempFolder, archive.Uncompressed) if err != nil { return } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() d.Put(id) if err2 := os.RemoveAll(tempFolder); err2 != nil { logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) } return err }), nil }
func readAndCheckDockerfile(t *testing.T, testName, contextDir, dockerfilePath, expectedError string) { tarStream, err := archive.Tar(contextDir, archive.Uncompressed) if err != nil { t.Fatalf("Error when creating tar stream: %s", err) } defer func() { if err = tarStream.Close(); err != nil { t.Fatalf("Error when closing tar stream: %s", err) } }() context, err := builder.MakeTarSumContext(tarStream) if err != nil { t.Fatalf("Error when creating tar context: %s", err) } defer func() { if err = context.Close(); err != nil { t.Fatalf("Error when closing tar context: %s", err) } }() options := &types.ImageBuildOptions{ Dockerfile: dockerfilePath, } b := &Builder{options: options, context: context} err = b.readDockerfile() if err == nil { t.Fatalf("No error when executing test: %s", testName) } if !strings.Contains(err.Error(), expectedError) { t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", expectedError, err.Error()) } }
func TestChrootUntarPath(t *testing.T) { // TODO Windows: Figure out why this is failing if runtime.GOOS == "windows" { t.Skip("Failing on Windows") } tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarPath") if err != nil { t.Fatal(err) } defer os.RemoveAll(tmpdir) src := filepath.Join(tmpdir, "src") if err := system.MkdirAll(src, 0700); err != nil { t.Fatal(err) } if _, err := prepareSourceDirectory(10, src, false); err != nil { t.Fatal(err) } dest := filepath.Join(tmpdir, "dest") // Untar a directory if err := UntarPath(src, dest); err == nil { t.Fatal("Expected error on untaring a directory") } // Untar a tar file stream, err := archive.Tar(src, archive.Uncompressed) if err != nil { t.Fatal(err) } buf := new(bytes.Buffer) buf.ReadFrom(stream) tarfile := filepath.Join(tmpdir, "src.tar") if err := ioutil.WriteFile(tarfile, buf.Bytes(), 0644); err != nil { t.Fatal(err) } if err := UntarPath(tarfile, dest); err != nil { t.Fatal(err) } if err := compareDirectories(src, dest); err != nil { t.Fatal(err) } }
// exportLayer generates an archive from a layer based on the given ID. func (d *Driver) exportLayer(id string, parentLayerPaths []string) (arch archive.Archive, err error) { layerFolder := d.dir(id) tempFolder := layerFolder + "-" + strconv.FormatUint(uint64(random.Rand.Uint32()), 10) if err = os.MkdirAll(tempFolder, 0755); err != nil { logrus.Errorf("Could not create %s %s", tempFolder, err) return } defer func() { if err != nil { _, folderName := filepath.Split(tempFolder) if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil { logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) } } }() if err = hcsshim.ExportLayer(d.info, id, tempFolder, parentLayerPaths); err != nil { return } archive, err := archive.Tar(tempFolder, archive.Uncompressed) if err != nil { return } return ioutils.NewReadCloserWrapper(archive, func() error { err := archive.Close() d.Put(id) _, folderName := filepath.Split(tempFolder) if err2 := hcsshim.DestroyLayer(d.info, folderName); err2 != nil { logrus.Warnf("Couldn't clean-up tempFolder: %s %s", tempFolder, err2) } return err }), nil }