func (c *Connection) TreeHashFromMultipartUpload(vault, uploadID string) (string, error) {
	marker := ""
	m := MultiTreeHasher{}
	for {
		parts, err := c.ListMultipartParts(vault, uploadID, marker, 0)
		if err != nil {
			return "", err
		}
		for _, v := range parts.Parts {
			m.Add(v.SHA256TreeHash)
		}
		if parts.Marker == "" {
			break
		}
		marker = parts.Marker
	}
	return m.CreateHash(), nil
}
TreeHashFromMultipartUpload lists the underlying parts
and returns a hex-formatted treehash of the entire archive,
for use in sending along with a CompleteMultipart request.
package glacier
import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"time"
	"github.com/rdwilliamson/aws"
)
type Multipart struct {
	ArchiveDescription string
	CreationDate       time.Time
	MultipartUploadId  string
	PartSizeInBytes    int64
	VaultARN           string
}
type MultipartPart struct {
	RangeInBytes   string
	SHA256TreeHash string
}
type MultipartParts struct {
	ArchiveDescription string
	CreationDate       time.Time
	Marker             string
	MultipartUploadId  string
	PartSizeInBytes    int64
	Parts              []MultipartPart
	VaultARN           string
}
func (c *Connection) InitiateMultipart(vault string, size int64, description string) (string, error) {
	request, err := http.NewRequest("POST", c.vault(vault)+"/multipart-uploads", nil)
	if err != nil {
		return "", err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")
	request.Header.Add("x-amz-part-size", fmt.Sprint(size))
	if description != "" {
		request.Header.Add("x-amz-archive-description", description)
	}
	c.Signature.Sign(request, nil)
	response, err := c.client().Do(request)
	if err != nil {
		return "", err
	}
	defer response.Body.Close()
	if response.StatusCode != http.StatusCreated {
		return "", aws.ParseError(response)
	}
	io.Copy(ioutil.Discard, response.Body)
	return response.Header.Get("x-amz-multipart-upload-id"), nil
}
func (c *Connection) UploadMultipart(vault, uploadId string, start int64, body io.ReadSeeker) error {
	request, err := http.NewRequest("PUT", c.vault(vault)+"/multipart-uploads/"+uploadId, body)
	if err != nil {
		return err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")
	th := NewTreeHash()
	n, err := io.Copy(th, body)
	if err != nil {
		return err
	}
	th.Close()
	_, err = body.Seek(0, 0)
	if err != nil {
		return err
	}
	hash := th.Hash()
	request.Header.Add("x-amz-content-sha256", toHex(hash))
	request.Header.Add("x-amz-sha256-tree-hash", toHex(th.TreeHash()))
	request.Header.Add("Content-Range", fmt.Sprintf("bytes %d-%d/*", start, start+n-1))
	request.ContentLength = n
	c.Signature.Sign(request, aws.HashedPayload(hash))
	response, err := c.client().Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	if response.StatusCode != http.StatusNoContent {
		return aws.ParseError(response)
	}
	io.Copy(ioutil.Discard, response.Body)
	return nil
}
func (c *Connection) CompleteMultipart(vault, uploadId, treeHash string, size int64) (string, error) {
	request, err := http.NewRequest("POST", c.vault(vault)+"/multipart-uploads/"+uploadId, nil)
	if err != nil {
		return "", err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")
	request.Header.Add("x-amz-sha256-tree-hash", treeHash)
	request.Header.Add("x-amz-archive-size", fmt.Sprint(size))
	c.Signature.Sign(request, nil)
	response, err := c.client().Do(request)
	if err != nil {
		return "", err
	}
	defer response.Body.Close()
	if response.StatusCode != http.StatusCreated {
		return "", aws.ParseError(response)
	}
	io.Copy(ioutil.Discard, response.Body)
	return response.Header.Get("x-amz-archive-id"), nil
}
func (c *Connection) AbortMultipart(vault, uploadId string) error {
	request, err := http.NewRequest("DELETE", c.vault(vault)+"/multipart-uploads/"+uploadId, nil)
	if err != nil {
		return err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")
	c.Signature.Sign(request, nil)
	response, err := c.client().Do(request)
	if err != nil {
		return err
	}
	defer response.Body.Close()
	if response.StatusCode != http.StatusNoContent {
		return aws.ParseError(response)
	}
	io.Copy(ioutil.Discard, response.Body)
	return nil
}
func (c *Connection) ListMultipartParts(vault, uploadId, marker string, limit int) (*MultipartParts, error) {
	parameters := parameters{}
	if limit > 0 {
		parameters.add("limit", strconv.Itoa(limit))
	}
	if marker != "" {
		parameters.add("marker", marker)
	}
	request, err := http.NewRequest("GET", c.vault(vault)+"/multipart-uploads/"+uploadId+parameters.encode(), nil)
	if err != nil {
		return nil, err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")
	c.Signature.Sign(request, nil)
	response, err := c.client().Do(request)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	if response.StatusCode != http.StatusOK {
		return nil, aws.ParseError(response)
	}
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}
	var list struct {
		ArchiveDescription string
		CreationDate       string
		Marker             *string
		MultipartUploadId  string
		PartSizeInBytes    int64
		Parts              []MultipartPart
		VaultARN           string
	}
	err = json.Unmarshal(body, &list)
	if err != nil {
		return nil, err
	}
	var result MultipartParts
	result.ArchiveDescription = list.ArchiveDescription
	result.CreationDate, err = time.Parse(time.RFC3339, list.CreationDate)
	if err != nil {
		return nil, err
	}
	if list.Marker != nil {
		result.Marker = *list.Marker
	}
	result.MultipartUploadId = list.MultipartUploadId
	result.PartSizeInBytes = list.PartSizeInBytes
	result.Parts = list.Parts
	result.VaultARN = list.VaultARN
	return &result, nil
}
func (c *Connection) ListMultipartUploads(vault, marker string, limit int) ([]Multipart, string, error) {
	query := url.Values{}
	if limit > 0 {
		query.Add("limit", fmt.Sprint(limit))
	}
	if marker != "" {
		query.Add("marker", marker)
	}
	request, err := http.NewRequest("GET", c.vault(vault)+"/multipart-uploads"+query.Encode(), nil)
	if err != nil {
		return nil, "", err
	}
	request.Header.Add("x-amz-glacier-version", "2012-06-01")
	c.Signature.Sign(request, nil)
	response, err := c.client().Do(request)
	if err != nil {
		return nil, "", err
	}
	defer response.Body.Close()
	if response.StatusCode != http.StatusOK {
		return nil, "", aws.ParseError(response)
	}
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, "", err
	}
	var list struct {
		Marker      *string
		UploadsList []struct {
			ArchiveDescription *string
			CreationDate       string
			MultipartUploadId  string
			PartSizeInBytes    int64
			VaultARN           string
		}
	}
	err = json.Unmarshal(body, &list)
	if err != nil {
		return nil, "", err
	}
	parts := make([]Multipart, len(list.UploadsList))
	for i, v := range list.UploadsList {
		if v.ArchiveDescription != nil {
			parts[i].ArchiveDescription = *v.ArchiveDescription
		}
		parts[i].CreationDate, err = time.Parse(time.RFC3339, v.CreationDate)
		if err != nil {
			return nil, "", err
		}
		parts[i].MultipartUploadId = v.MultipartUploadId
		parts[i].PartSizeInBytes = v.PartSizeInBytes
		parts[i].VaultARN = v.VaultARN
	}
	var m string
	if list.Marker != nil {
		m = *list.Marker
	}
	return parts, m, nil
}