func (b *Bucket) HideFile(fileName string) (*FileStatus, error) {
	request := &hideFileRequest{
		BucketID: b.ID,
		FileName: fileName,
	}
	response := &FileStatus{}
	if err := b.b2.apiRequest("b2_hide_file", request, response); err != nil {
		return nil, err
	}
	return response, nil
}
HideFile hides a file so that downloading by name will not find the file,
but previous versions of the file are still stored. See File Versions about
what it means to hide a file.
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
}
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
}