github.com/wulonghui/docker@v1.8.0-rc2/pkg/chrootarchive/diff_unix.go (about)

     1  //+build !windows
     2  
     3  package chrootarchive
     4  
     5  import (
     6  	"bytes"
     7  	"encoding/json"
     8  	"flag"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"os"
    12  	"path/filepath"
    13  	"runtime"
    14  
    15  	"github.com/docker/docker/pkg/archive"
    16  	"github.com/docker/docker/pkg/reexec"
    17  	"github.com/docker/docker/pkg/system"
    18  )
    19  
    20  type applyLayerResponse struct {
    21  	LayerSize int64 `json:"layerSize"`
    22  }
    23  
    24  // applyLayer is the entry-point for docker-applylayer on re-exec. This is not
    25  // used on Windows as it does not support chroot, hence no point sandboxing
    26  // through chroot and rexec.
    27  func applyLayer() {
    28  
    29  	var (
    30  		tmpDir = ""
    31  		err    error
    32  	)
    33  	runtime.LockOSThread()
    34  	flag.Parse()
    35  
    36  	if err := chroot(flag.Arg(0)); err != nil {
    37  		fatal(err)
    38  	}
    39  
    40  	// We need to be able to set any perms
    41  	oldmask, err := system.Umask(0)
    42  	defer system.Umask(oldmask)
    43  	if err != nil {
    44  		fatal(err)
    45  	}
    46  
    47  	if tmpDir, err = ioutil.TempDir("/", "temp-docker-extract"); err != nil {
    48  		fatal(err)
    49  	}
    50  
    51  	os.Setenv("TMPDIR", tmpDir)
    52  	size, err := archive.UnpackLayer("/", os.Stdin)
    53  	os.RemoveAll(tmpDir)
    54  	if err != nil {
    55  		fatal(err)
    56  	}
    57  
    58  	encoder := json.NewEncoder(os.Stdout)
    59  	if err := encoder.Encode(applyLayerResponse{size}); err != nil {
    60  		fatal(fmt.Errorf("unable to encode layerSize JSON: %s", err))
    61  	}
    62  
    63  	flush(os.Stdout)
    64  	flush(os.Stdin)
    65  	os.Exit(0)
    66  }
    67  
    68  // ApplyLayer parses a diff in the standard layer format from `layer`,
    69  // and applies it to the directory `dest`. The stream `layer` can only be
    70  // uncompressed.
    71  // Returns the size in bytes of the contents of the layer.
    72  func ApplyLayer(dest string, layer archive.ArchiveReader) (size int64, err error) {
    73  	return applyLayerHandler(dest, layer, true)
    74  }
    75  
    76  // ApplyUncompressedLayer parses a diff in the standard layer format from
    77  // `layer`, and applies it to the directory `dest`. The stream `layer`
    78  // can only be uncompressed.
    79  // Returns the size in bytes of the contents of the layer.
    80  func ApplyUncompressedLayer(dest string, layer archive.ArchiveReader) (int64, error) {
    81  	return applyLayerHandler(dest, layer, false)
    82  }
    83  
    84  func applyLayerHandler(dest string, layer archive.ArchiveReader, decompress bool) (size int64, err error) {
    85  	dest = filepath.Clean(dest)
    86  	if decompress {
    87  		decompressed, err := archive.DecompressStream(layer)
    88  		if err != nil {
    89  			return 0, err
    90  		}
    91  		defer decompressed.Close()
    92  
    93  		layer = decompressed
    94  	}
    95  
    96  	cmd := reexec.Command("docker-applyLayer", dest)
    97  	cmd.Stdin = layer
    98  
    99  	outBuf, errBuf := new(bytes.Buffer), new(bytes.Buffer)
   100  	cmd.Stdout, cmd.Stderr = outBuf, errBuf
   101  
   102  	if err = cmd.Run(); err != nil {
   103  		return 0, fmt.Errorf("ApplyLayer %s stdout: %s stderr: %s", err, outBuf, errBuf)
   104  	}
   105  
   106  	// Stdout should be a valid JSON struct representing an applyLayerResponse.
   107  	response := applyLayerResponse{}
   108  	decoder := json.NewDecoder(outBuf)
   109  	if err = decoder.Decode(&response); err != nil {
   110  		return 0, fmt.Errorf("unable to decode ApplyLayer JSON response: %s", err)
   111  	}
   112  
   113  	return response.LayerSize, nil
   114  }