vendor/github.com/Microsoft/opengcs/service/gcsutils/remotefs/utils.go
7a7357da
 package remotefs
 
 import (
 	"bytes"
 	"encoding/binary"
 	"encoding/json"
 	"io"
 	"io/ioutil"
 	"os"
 	"syscall"
 
 	"github.com/docker/docker/pkg/archive"
 )
 
 // ReadError is an utility function that reads a serialized error from the given reader
 // and deserializes it.
 func ReadError(in io.Reader) (*ExportedError, error) {
 	b, err := ioutil.ReadAll(in)
 	if err != nil {
 		return nil, err
 	}
 
 	// No error
 	if len(b) == 0 {
 		return nil, nil
 	}
 
 	var exportedErr ExportedError
 	if err := json.Unmarshal(b, &exportedErr); err != nil {
 		return nil, err
 	}
 
 	return &exportedErr, nil
 }
 
 // ExportedToError will convert a ExportedError to an error. It will try to match
 // the error to any existing known error like os.ErrNotExist. Otherwise, it will just
 // return an implementation of the error interface.
 func ExportedToError(ee *ExportedError) error {
 	if ee.Error() == os.ErrNotExist.Error() {
 		return os.ErrNotExist
 	} else if ee.Error() == os.ErrExist.Error() {
 		return os.ErrExist
 	} else if ee.Error() == os.ErrPermission.Error() {
 		return os.ErrPermission
 	}
 	return ee
 }
 
 // WriteError is an utility function that serializes the error
 // and writes it to the output writer.
 func WriteError(err error, out io.Writer) error {
 	if err == nil {
 		return nil
 	}
 	err = fixOSError(err)
 
 	var errno int
 	switch typedError := err.(type) {
 	case *os.PathError:
 		if se, ok := typedError.Err.(syscall.Errno); ok {
 			errno = int(se)
 		}
 	case *os.LinkError:
 		if se, ok := typedError.Err.(syscall.Errno); ok {
 			errno = int(se)
 		}
 	case *os.SyscallError:
 		if se, ok := typedError.Err.(syscall.Errno); ok {
 			errno = int(se)
 		}
 	}
 
 	exportedError := &ExportedError{
 		ErrString: err.Error(),
 		ErrNum:    errno,
 	}
 
 	b, err1 := json.Marshal(exportedError)
 	if err1 != nil {
 		return err1
 	}
 
 	_, err1 = out.Write(b)
 	if err1 != nil {
 		return err1
 	}
 	return nil
 }
 
 // fixOSError converts possible platform dependent error into the portable errors in the
 // Go os package if possible.
 func fixOSError(err error) error {
 	// The os.IsExist, os.IsNotExist, and os.IsPermissions functions are platform
 	// dependent, so sending the raw error might break those functions on a different OS.
 	// Go defines portable errors for these.
 	if os.IsExist(err) {
 		return os.ErrExist
 	} else if os.IsNotExist(err) {
 		return os.ErrNotExist
 	} else if os.IsPermission(err) {
 		return os.ErrPermission
 	}
 	return err
 }
 
 // ReadTarOptions reads from the specified reader and deserializes an archive.TarOptions struct.
 func ReadTarOptions(r io.Reader) (*archive.TarOptions, error) {
 	var size uint64
 	if err := binary.Read(r, binary.BigEndian, &size); err != nil {
 		return nil, err
 	}
 
 	rawJSON := make([]byte, size)
 	if _, err := io.ReadFull(r, rawJSON); err != nil {
 		return nil, err
 	}
 
 	var opts archive.TarOptions
 	if err := json.Unmarshal(rawJSON, &opts); err != nil {
 		return nil, err
 	}
 	return &opts, nil
 }
 
 // WriteTarOptions serializes a archive.TarOptions struct and writes it to the writer.
 func WriteTarOptions(w io.Writer, opts *archive.TarOptions) error {
 	optsBuf, err := json.Marshal(opts)
 	if err != nil {
 		return err
 	}
 
 	optsSize := uint64(len(optsBuf))
 	optsSizeBuf := &bytes.Buffer{}
 	if err := binary.Write(optsSizeBuf, binary.BigEndian, optsSize); err != nil {
 		return err
 	}
 
 	if _, err := optsSizeBuf.WriteTo(w); err != nil {
 		return err
 	}
 
 	if _, err := w.Write(optsBuf); err != nil {
 		return err
 	}
 
 	return nil
 }
 
 // ReadFileHeader reads from r and returns a deserialized FileHeader
 func ReadFileHeader(r io.Reader) (*FileHeader, error) {
 	hdr := &FileHeader{}
 	if err := binary.Read(r, binary.BigEndian, hdr); err != nil {
 		return nil, err
 	}
 	return hdr, nil
 }
 
 // WriteFileHeader serializes a FileHeader and writes it to w, along with any extra data
 func WriteFileHeader(w io.Writer, hdr *FileHeader, extraData []byte) error {
 	if err := binary.Write(w, binary.BigEndian, hdr); err != nil {
 		return err
 	}
 	if _, err := w.Write(extraData); err != nil {
 		return err
 	}
 	return nil
 }