Files
virtual-kubelet/vendor/github.com/vmware/vic/lib/archive/unpack_windows.go
2018-06-21 12:09:42 -07:00

128 lines
3.8 KiB
Go

// Copyright 2016-2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build windows
package archive
import (
"archive/tar"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/vmware/vic/pkg/trace"
)
const (
// fileWriteFlags is a collection of flags configuring our writes for general tar behavior
//
// O_CREATE = Create file if it does not exist
// O_TRUNC = truncate file to 0 length if it does exist(overwrite the file)
// O_WRONLY = We use this since we do not intend to read, we only need to write.
fileWriteFlags = os.O_CREATE | os.O_TRUNC | os.O_WRONLY
)
// combined with any rebase from the path spec
//
// the pathSpec will include the following elements
// - include : any tar entry that has a path below(after stripping) the include path will be written
// - strip : The strip string will indicate the
// - exlude : marks paths that are to be excluded from the write operation
// - rebase : marks the the write path that will be tacked onto the "root". e.g /tmp/unpack + /my/target/path = /tmp/unpack/my/target/path
func Unpack(op trace.Operation, tarStream io.Reader, filter *FilterSpec, root string, _ string) error {
op.Debugf("unpacking archive to root: %s, filter: %+v", root, filter)
// Online datasource is sending a tar reader instead of an io reader.
// Type check here to see if we actually need to create a tar reader.
var tr *tar.Reader
if trCheck, ok := tarStream.(*tar.Reader); ok {
tr = trCheck
} else {
tr = tar.NewReader(tarStream)
}
fi, err := os.Stat(root)
if err != nil {
// the target unpack path does not exist. We should not get here.
op.Errorf("tar unpack target does not exist: %s", root)
return err
}
if !fi.IsDir() {
err := fmt.Errorf("unpack root target is not a directory: %s", root)
op.Error(err)
return err
}
op.Debugf("using FilterSpec : (%#v)", *filter)
// process the tarball onto the filesystem
for {
header, err := tr.Next()
if err == io.EOF {
// This indicates the end of the archive
break
}
if err != nil {
op.Errorf("Error reading tar header: %s", err)
return err
}
op.Debugf("processing tar header: asset(%s), size(%d)", header.Name, header.Size)
// skip excluded elements unless explicitly included
if filter.Excludes(op, header.Name) {
continue
}
// fix up path
stripped := strings.TrimPrefix(header.Name, filter.StripPath)
rebased := filepath.Join(filter.RebasePath, stripped)
absPath := filepath.Join(root, rebased)
switch header.Typeflag {
case tar.TypeDir:
err = os.MkdirAll(absPath, header.FileInfo().Mode())
if err != nil {
op.Errorf("Failed to create directory%s: %s", absPath, err)
return err
}
case tar.TypeSymlink:
err := os.Symlink(header.Linkname, absPath)
if err != nil {
op.Errorf("Failed to create symlink %s->%s: %s", absPath, header.Linkname, err)
return err
}
case tar.TypeReg:
f, err := os.OpenFile(absPath, fileWriteFlags, header.FileInfo().Mode())
if err != nil {
op.Errorf("Failed to open file %s: %s", absPath, err)
return err
}
_, err = io.Copy(f, tr)
// TODO: add ctx.Done cancellation
f.Close()
if err != nil {
return err
}
default:
// TODO: add support for special file types - otherwise we will do absurd things such as read infinitely from /dev/random
}
op.Debugf("Finished writing to: %s", absPath)
}
return nil
}