187 lines
5.6 KiB
Go
187 lines
5.6 KiB
Go
|
package storage
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"net/http"
|
||
|
"net/url"
|
||
|
"strconv"
|
||
|
)
|
||
|
|
||
|
// Share represents an Azure file share.
|
||
|
type Share struct {
|
||
|
fsc *FileServiceClient
|
||
|
Name string `xml:"Name"`
|
||
|
Properties ShareProperties `xml:"Properties"`
|
||
|
Metadata map[string]string
|
||
|
}
|
||
|
|
||
|
// ShareProperties contains various properties of a share.
|
||
|
type ShareProperties struct {
|
||
|
LastModified string `xml:"Last-Modified"`
|
||
|
Etag string `xml:"Etag"`
|
||
|
Quota int `xml:"Quota"`
|
||
|
}
|
||
|
|
||
|
// builds the complete path for this share object.
|
||
|
func (s *Share) buildPath() string {
|
||
|
return fmt.Sprintf("/%s", s.Name)
|
||
|
}
|
||
|
|
||
|
// Create this share under the associated account.
|
||
|
// If a share with the same name already exists, the operation fails.
|
||
|
//
|
||
|
// See https://msdn.microsoft.com/en-us/library/azure/dn167008.aspx
|
||
|
func (s *Share) Create() error {
|
||
|
headers, err := s.fsc.createResource(s.buildPath(), resourceShare, nil, mergeMDIntoExtraHeaders(s.Metadata, nil), []int{http.StatusCreated})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
s.updateEtagAndLastModified(headers)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// CreateIfNotExists creates this share under the associated account if
|
||
|
// it does not exist. Returns true if the share is newly created or false if
|
||
|
// the share already exists.
|
||
|
//
|
||
|
// See https://msdn.microsoft.com/en-us/library/azure/dn167008.aspx
|
||
|
func (s *Share) CreateIfNotExists() (bool, error) {
|
||
|
resp, err := s.fsc.createResourceNoClose(s.buildPath(), resourceShare, nil, nil)
|
||
|
if resp != nil {
|
||
|
defer readAndCloseBody(resp.body)
|
||
|
if resp.statusCode == http.StatusCreated || resp.statusCode == http.StatusConflict {
|
||
|
if resp.statusCode == http.StatusCreated {
|
||
|
s.updateEtagAndLastModified(resp.headers)
|
||
|
return true, nil
|
||
|
}
|
||
|
return false, s.FetchAttributes()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false, err
|
||
|
}
|
||
|
|
||
|
// Delete marks this share for deletion. The share along with any files
|
||
|
// and directories contained within it are later deleted during garbage
|
||
|
// collection. If the share does not exist the operation fails
|
||
|
//
|
||
|
// See https://msdn.microsoft.com/en-us/library/azure/dn689090.aspx
|
||
|
func (s *Share) Delete() error {
|
||
|
return s.fsc.deleteResource(s.buildPath(), resourceShare)
|
||
|
}
|
||
|
|
||
|
// DeleteIfExists operation marks this share for deletion if it exists.
|
||
|
//
|
||
|
// See https://msdn.microsoft.com/en-us/library/azure/dn689090.aspx
|
||
|
func (s *Share) DeleteIfExists() (bool, error) {
|
||
|
resp, err := s.fsc.deleteResourceNoClose(s.buildPath(), resourceShare)
|
||
|
if resp != nil {
|
||
|
defer readAndCloseBody(resp.body)
|
||
|
if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound {
|
||
|
return resp.statusCode == http.StatusAccepted, nil
|
||
|
}
|
||
|
}
|
||
|
return false, err
|
||
|
}
|
||
|
|
||
|
// Exists returns true if this share already exists
|
||
|
// on the storage account, otherwise returns false.
|
||
|
func (s *Share) Exists() (bool, error) {
|
||
|
exists, headers, err := s.fsc.resourceExists(s.buildPath(), resourceShare)
|
||
|
if exists {
|
||
|
s.updateEtagAndLastModified(headers)
|
||
|
s.updateQuota(headers)
|
||
|
}
|
||
|
return exists, err
|
||
|
}
|
||
|
|
||
|
// FetchAttributes retrieves metadata and properties for this share.
|
||
|
func (s *Share) FetchAttributes() error {
|
||
|
headers, err := s.fsc.getResourceHeaders(s.buildPath(), compNone, resourceShare, http.MethodHead)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
s.updateEtagAndLastModified(headers)
|
||
|
s.updateQuota(headers)
|
||
|
s.Metadata = getMetadataFromHeaders(headers)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// GetRootDirectoryReference returns a Directory object at the root of this share.
|
||
|
func (s *Share) GetRootDirectoryReference() *Directory {
|
||
|
return &Directory{
|
||
|
fsc: s.fsc,
|
||
|
share: s,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ServiceClient returns the FileServiceClient associated with this share.
|
||
|
func (s *Share) ServiceClient() *FileServiceClient {
|
||
|
return s.fsc
|
||
|
}
|
||
|
|
||
|
// SetMetadata replaces the metadata for this share.
|
||
|
//
|
||
|
// Some keys may be converted to Camel-Case before sending. All keys
|
||
|
// are returned in lower case by GetShareMetadata. HTTP header names
|
||
|
// are case-insensitive so case munging should not matter to other
|
||
|
// applications either.
|
||
|
//
|
||
|
// See https://msdn.microsoft.com/en-us/library/azure/dd179414.aspx
|
||
|
func (s *Share) SetMetadata() error {
|
||
|
headers, err := s.fsc.setResourceHeaders(s.buildPath(), compMetadata, resourceShare, mergeMDIntoExtraHeaders(s.Metadata, nil))
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
s.updateEtagAndLastModified(headers)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// SetProperties sets system properties for this share.
|
||
|
//
|
||
|
// Some keys may be converted to Camel-Case before sending. All keys
|
||
|
// are returned in lower case by SetShareProperties. HTTP header names
|
||
|
// are case-insensitive so case munging should not matter to other
|
||
|
// applications either.
|
||
|
//
|
||
|
// See https://msdn.microsoft.com/en-us/library/azure/mt427368.aspx
|
||
|
func (s *Share) SetProperties() error {
|
||
|
if s.Properties.Quota < 1 || s.Properties.Quota > 5120 {
|
||
|
return fmt.Errorf("invalid value %v for quota, valid values are [1, 5120]", s.Properties.Quota)
|
||
|
}
|
||
|
|
||
|
headers, err := s.fsc.setResourceHeaders(s.buildPath(), compProperties, resourceShare, map[string]string{
|
||
|
"x-ms-share-quota": strconv.Itoa(s.Properties.Quota),
|
||
|
})
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
s.updateEtagAndLastModified(headers)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// updates Etag and last modified date
|
||
|
func (s *Share) updateEtagAndLastModified(headers http.Header) {
|
||
|
s.Properties.Etag = headers.Get("Etag")
|
||
|
s.Properties.LastModified = headers.Get("Last-Modified")
|
||
|
}
|
||
|
|
||
|
// updates quota value
|
||
|
func (s *Share) updateQuota(headers http.Header) {
|
||
|
quota, err := strconv.Atoi(headers.Get("x-ms-share-quota"))
|
||
|
if err == nil {
|
||
|
s.Properties.Quota = quota
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// URL gets the canonical URL to this share. This method does not create a publicly accessible
|
||
|
// URL if the share is private and this method does not check if the share exists.
|
||
|
func (s *Share) URL() string {
|
||
|
return s.fsc.client.getEndpoint(fileServiceName, s.buildPath(), url.Values{})
|
||
|
}
|