text: package storage
  
  // Copyright 2017 Microsoft Corporation
  //
  //  Licensed under the Apache License, Version 2.0 (the "License");
  //  you may not use this file except in compliance with the License.
  //  You may obtain a copy of the License at
  //
  //      http://www.apache.org/licenses/LICENSE-2.0
  //
  //  Unless required by applicable law or agreed to in writing, software
  //  distributed under the License is distributed on an "AS IS" BASIS,
  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  //  See the License for the specific language governing permissions and
  //  limitations under the License.
  
  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://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Create-Share
  func (s *Share) Create(options *FileRequestOptions) error {
  	extraheaders := map[string]string{}
  	if s.Properties.Quota > 0 {
  		extraheaders["x-ms-share-quota"] = strconv.Itoa(s.Properties.Quota)
  	}
  
  	params := prepareOptions(options)
  	headers, err := s.fsc.createResource(s.buildPath(), resourceShare, params, mergeMDIntoExtraHeaders(s.Metadata, extraheaders), []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://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Create-Share
  func (s *Share) CreateIfNotExists(options *FileRequestOptions) (bool, error) {
  	extraheaders := map[string]string{}
  	if s.Properties.Quota > 0 {
  		extraheaders["x-ms-share-quota"] = strconv.Itoa(s.Properties.Quota)
  	}
  
  	params := prepareOptions(options)
  	resp, err := s.fsc.createResourceNoClose(s.buildPath(), resourceShare, params, extraheaders)
  	if resp != nil {
  		defer drainRespBody(resp)
  		if resp.StatusCode == http.StatusCreated || resp.StatusCode == http.StatusConflict {
  			if resp.StatusCode == http.StatusCreated {
  				s.updateEtagAndLastModified(resp.Header)
  				return true, nil
  			}
  			return false, s.FetchAttributes(nil)
  		}
  	}
  
  	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://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Delete-Share
  func (s *Share) Delete(options *FileRequestOptions) error {
  	return s.fsc.deleteResource(s.buildPath(), resourceShare, options)
  }
  
  // DeleteIfExists operation marks this share for deletion if it exists.
  //
  // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Delete-Share
  func (s *Share) DeleteIfExists(options *FileRequestOptions) (bool, error) {
  	resp, err := s.fsc.deleteResourceNoClose(s.buildPath(), resourceShare, options)
  	if resp != nil {
  		defer drainRespBody(resp)
  		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.
  // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/get-share-properties
  func (s *Share) FetchAttributes(options *FileRequestOptions) error {
  	params := prepareOptions(options)
  	headers, err := s.fsc.getResourceHeaders(s.buildPath(), compNone, resourceShare, params, 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://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/set-share-metadata
  func (s *Share) SetMetadata(options *FileRequestOptions) error {
  	headers, err := s.fsc.setResourceHeaders(s.buildPath(), compMetadata, resourceShare, mergeMDIntoExtraHeaders(s.Metadata, nil), options)
  	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://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Set-Share-Properties
  func (s *Share) SetProperties(options *FileRequestOptions) error {
  	extraheaders := map[string]string{}
  	if s.Properties.Quota > 0 {
  		if s.Properties.Quota > 5120 {
  			return fmt.Errorf("invalid value %v for quota, valid values are [1, 5120]", s.Properties.Quota)
  		}
  		extraheaders["x-ms-share-quota"] = strconv.Itoa(s.Properties.Quota)
  	}
  
  	headers, err := s.fsc.setResourceHeaders(s.buildPath(), compProperties, resourceShare, extraheaders, options)
  	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{})
  }
  