func (b *Bucket) DeleteFileVersion(fileName, fileID string) (*FileStatus, error) {
	request := &fileVersionRequest{
		Name: fileName,
		ID:   fileID,
	}
	response := &FileStatus{}
	if err := b.b2.apiRequest("b2_delete_file_version", request, response); err != nil {
		return nil, err
	}
	return response, nil
}
DeleteFileVersion deletes one version of a file from B2.

If the version you delete is the latest version, and there are older
versions, then the most recent older version will become the current
version, and be the one that you'll get when downloading by name. See the
File Versions page for more details.
package backblaze
import (
	"bytes"
	"crypto/sha1"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"github.com/pquerna/ffjson/ffjson"
)
func (b *Bucket) ListFileNames(startFileName string, maxFileCount int) (*ListFilesResponse, error) {
	request := &listFilesRequest{
		BucketID:      b.ID,
		StartFileName: startFileName,
		MaxFileCount:  maxFileCount,
	}
	response := &ListFilesResponse{}
	if err := b.b2.apiRequest("b2_list_file_names", request, response); err != nil {
		return nil, err
	}
	return response, nil
}
func (b *Bucket) UploadFile(name string, meta map[string]string, file io.Reader) (*File, error) {
	hash := sha1.New()
	var reader io.Reader
	var contentLength int64
	if r, ok := file.(io.ReadSeeker); ok {
		written, err := io.Copy(hash, r)
		if err != nil {
			return nil, err
		}
		r.Seek(0, 0)
		reader = r
		contentLength = written
	} else {
		buffer := &bytes.Buffer{}
		r := io.TeeReader(file, buffer)
		written, err := io.Copy(hash, r)
		if err != nil {
			return nil, err
		}
		reader = buffer
		contentLength = written
	}
	sha1Hash := hex.EncodeToString(hash.Sum(nil))
	f, err := b.UploadHashedFile(name, meta, reader, sha1Hash, contentLength)
	if b2err, ok := err.(*B2Error); ok {
		if !b2err.IsFatal() && !b.b2.NoRetry {
			f, err = b.UploadHashedFile(name, meta, reader, sha1Hash, contentLength)
		}
	}
	return f, err
}
func (b *Bucket) UploadHashedFile(name string, meta map[string]string, file io.Reader, sha1Hash string, contentLength int64) (*File, error) {
	uploadURL, auth, err := b.internalGetUploadURL()
	if err != nil {
		return nil, err
	}
	if b.b2.Debug {
		fmt.Printf("         Upload: %s/%s\n", b.Name, name)
		fmt.Printf("           SHA1: %s\n", sha1Hash)
		fmt.Printf("  ContentLength: %d\n", contentLength)
	}
	req, err := http.NewRequest("POST", uploadURL.String(), file)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Authorization", auth.AuthorizationToken)
	req.ContentLength = contentLength
	req.Header.Add("Content-Type", "b2/x-auto")
	req.Header.Add("X-Bz-File-Name", url.QueryEscape(name))
	req.Header.Add("X-Bz-Content-Sha1", sha1Hash)
	if meta != nil {
		for k, v := range meta {
			req.Header.Add("X-Bz-Info-"+url.QueryEscape(k), url.QueryEscape(v))
		}
	}
	resp, err := b.b2.httpClient.Do(req)
	if err != nil {
		auth.invalidate()
		return nil, err
	}
	result := &File{}
	if err := b.b2.parseResponse(resp, result, nil); err != nil {
		auth.invalidate()
		return nil, err
	}
	if sha1Hash != result.ContentSha1 {
		return nil, errors.New("SHA1 of uploaded file does not match local hash")
	}
	return result, nil
}
func (b *Bucket) GetFileInfo(fileID string) (*File, error) {
	request := &fileRequest{
		ID: fileID,
	}
	response := &File{}
	if err := b.b2.apiRequest("b2_get_file_info", request, response); err != nil {
		return nil, err
	}
	return response, nil
}
func (c *B2) DownloadFileByID(fileID string) (*File, io.ReadCloser, error) {
	request := &fileRequest{
		ID: fileID,
	}
	requestBody, err := ffjson.Marshal(request)
	if err != nil {
		return nil, nil, err
	}
	f, body, err := c.tryDownloadFileByID(requestBody)
	if b2err, ok := err.(*B2Error); ok {
		if !b2err.IsFatal() && !c.NoRetry {
			return c.tryDownloadFileByID(requestBody)
		}
	}
	return f, body, err
}
func (c *B2) tryDownloadFileByID(requestBody []byte) (*File, io.ReadCloser, error) {
	resp, auth, err := c.authPost("b2_download_file_by_id", bytes.NewReader(requestBody))
	if err != nil {
		return nil, nil, err
	}
	return c.downloadFile(resp, auth)
}
func (b *Bucket) FileURL(fileName string) (string, error) {
	fileURL, _, err := b.internalFileURL(fileName)
	return fileURL, err
}
func (b *Bucket) internalFileURL(fileName string) (string, *authorizationState, error) {
	b.b2.mutex.Lock()
	defer b.b2.mutex.Unlock()
	if !b.b2.auth.isValid() {
		if err := b.b2.internalAuthorizeAccount(); err != nil {
			return "", nil, err
		}
	}
	return b.b2.auth.DownloadURL + "/file/" + b.Name + "/" + fileName, b.b2.auth, nil
}
func (b *Bucket) DownloadFileByName(fileName string) (*File, io.ReadCloser, error) {
	f, body, err := b.tryDownloadFileByName(fileName)
	if b2err, ok := err.(*B2Error); ok {
		if !b2err.IsFatal() && !b.b2.NoRetry {
			return b.tryDownloadFileByName(fileName)
		}
	}
	return f, body, err
}
func (b *Bucket) tryDownloadFileByName(fileName string) (*File, io.ReadCloser, error) {
	fileURL, auth, err := b.internalFileURL(fileName)
	if err != nil {
		return nil, nil, err
	}
	req, err := http.NewRequest("GET", fileURL, nil)
	if err != nil {
		return nil, nil, err
	}
	req.Header.Add("Authorization", auth.AuthorizationToken)
	resp, err := b.b2.httpClient.Do(req)
	if err != nil {
		return nil, nil, err
	}
	return b.b2.downloadFile(resp, auth)
}
func (c *B2) downloadFile(resp *http.Response, auth *authorizationState) (*File, io.ReadCloser, error) {
	success := false
	defer func() {
		if !success {
			resp.Body.Close()
		}
	}()
	switch resp.StatusCode {
	case 200:
	case 401:
		auth.invalidate()
		return nil, nil, &B2Error{
			Code:    "UNAUTHORIZED",
			Message: "The account ID is wrong, the account does not have B2 enabled, or the application key is not valid",
			Status:  resp.StatusCode,
		}
	default:
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, nil, err
		}
		if err := c.parseError(body); err != nil {
			return nil, nil, err
		}
		return nil, nil, fmt.Errorf("Unrecognised status code: %d", resp.StatusCode)
	}
	name, err := url.QueryUnescape(resp.Header.Get("X-Bz-File-Name"))
	if err != nil {
		return nil, nil, err
	}
	file := &File{
		ID:          resp.Header.Get("X-Bz-File-Id"),
		Name:        name,
		ContentSha1: resp.Header.Get("X-Bz-Content-Sha1"),
		ContentType: resp.Header.Get("Content-Type"),
		FileInfo:    make(map[string]string),
	}
	size, err := strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64)
	if err != nil {
		return nil, nil, err
	}
	file.ContentLength = size
	for k, v := range resp.Header {
		if strings.HasPrefix(k, "X-Bz-Info-") {
			key, err := url.QueryUnescape(k[len("X-Bz-Info-"):])
			if err != nil {
				key = k[len("X-Bz-Info-"):]
				log.Printf("Unable to decode key: %q", key)
			}
			value, err := url.QueryUnescape(v[0])
			if err != nil {
				value = v[0]
				log.Printf("Unable to decode value: %q", value)
			}
			file.FileInfo[key] = value
		}
	}
	success = true  
	return file, resp.Body, nil
}
func (b *Bucket) ListFileVersions(startFileName, startFileID string, maxFileCount int) (*ListFileVersionsResponse, error) {
	request := &listFileVersionsRequest{
		BucketID:      b.ID,
		StartFileName: startFileName,
		StartFileID:   startFileID,
		MaxFileCount:  maxFileCount,
	}
	response := &ListFileVersionsResponse{}
	if err := b.b2.apiRequest("b2_list_file_versions", request, response); err != nil {
		return nil, err
	}
	return response, nil
}