1 package storage
2
3
4
5
6 import (
7 "encoding/xml"
8 "fmt"
9 "net/http"
10 "net/url"
11 "strconv"
12 )
13
14
15 type FileServiceClient struct {
16 client Client
17 auth authentication
18 }
19
20
21
22
23
24 type ListSharesParameters struct {
25 Prefix string
26 Marker string
27 Include string
28 MaxResults uint
29 Timeout uint
30 }
31
32
33
34
35
36 type ShareListResponse struct {
37 XMLName xml.Name `xml:"EnumerationResults"`
38 Xmlns string `xml:"xmlns,attr"`
39 Prefix string `xml:"Prefix"`
40 Marker string `xml:"Marker"`
41 NextMarker string `xml:"NextMarker"`
42 MaxResults int64 `xml:"MaxResults"`
43 Shares []Share `xml:"Shares>Share"`
44 }
45
46 type compType string
47
48 const (
49 compNone compType = ""
50 compList compType = "list"
51 compMetadata compType = "metadata"
52 compProperties compType = "properties"
53 compRangeList compType = "rangelist"
54 )
55
56 func (ct compType) String() string {
57 return string(ct)
58 }
59
60 type resourceType string
61
62 const (
63 resourceDirectory resourceType = "directory"
64 resourceFile resourceType = ""
65 resourceShare resourceType = "share"
66 )
67
68 func (rt resourceType) String() string {
69 return string(rt)
70 }
71
72 func (p ListSharesParameters) getParameters() url.Values {
73 out := url.Values{}
74
75 if p.Prefix != "" {
76 out.Set("prefix", p.Prefix)
77 }
78 if p.Marker != "" {
79 out.Set("marker", p.Marker)
80 }
81 if p.Include != "" {
82 out.Set("include", p.Include)
83 }
84 if p.MaxResults != 0 {
85 out.Set("maxresults", strconv.FormatUint(uint64(p.MaxResults), 10))
86 }
87 if p.Timeout != 0 {
88 out.Set("timeout", strconv.FormatUint(uint64(p.Timeout), 10))
89 }
90
91 return out
92 }
93
94 func (p ListDirsAndFilesParameters) getParameters() url.Values {
95 out := url.Values{}
96
97 if p.Prefix != "" {
98 out.Set("prefix", p.Prefix)
99 }
100 if p.Marker != "" {
101 out.Set("marker", p.Marker)
102 }
103 if p.MaxResults != 0 {
104 out.Set("maxresults", strconv.FormatUint(uint64(p.MaxResults), 10))
105 }
106 out = addTimeout(out, p.Timeout)
107
108 return out
109 }
110
111
112 func getURLInitValues(comp compType, res resourceType) url.Values {
113 values := url.Values{}
114 if comp != compNone {
115 values.Set("comp", comp.String())
116 }
117 if res != resourceFile {
118 values.Set("restype", res.String())
119 }
120 return values
121 }
122
123
124 func (f *FileServiceClient) GetShareReference(name string) *Share {
125 return &Share{
126 fsc: f,
127 Name: name,
128 Properties: ShareProperties{
129 Quota: -1,
130 },
131 }
132 }
133
134
135
136
137
138 func (f FileServiceClient) ListShares(params ListSharesParameters) (*ShareListResponse, error) {
139 q := mergeParams(params.getParameters(), url.Values{"comp": {"list"}})
140
141 var out ShareListResponse
142 resp, err := f.listContent("", q, nil)
143 if err != nil {
144 return nil, err
145 }
146 defer resp.Body.Close()
147 err = xmlUnmarshal(resp.Body, &out)
148
149
150 for i := range out.Shares {
151 out.Shares[i].fsc = &f
152 }
153 return &out, err
154 }
155
156
157
158
159 func (f *FileServiceClient) GetServiceProperties() (*ServiceProperties, error) {
160 return f.client.getServiceProperties(fileServiceName, f.auth)
161 }
162
163
164
165
166 func (f *FileServiceClient) SetServiceProperties(props ServiceProperties) error {
167 return f.client.setServiceProperties(props, fileServiceName, f.auth)
168 }
169
170
171 func (f FileServiceClient) listContent(path string, params url.Values, extraHeaders map[string]string) (*http.Response, error) {
172 if err := f.checkForStorageEmulator(); err != nil {
173 return nil, err
174 }
175
176 uri := f.client.getEndpoint(fileServiceName, path, params)
177 extraHeaders = f.client.protectUserAgent(extraHeaders)
178 headers := mergeHeaders(f.client.getStandardHeaders(), extraHeaders)
179
180 resp, err := f.client.exec(http.MethodGet, uri, headers, nil, f.auth)
181 if err != nil {
182 return nil, err
183 }
184
185 if err = checkRespCode(resp, []int{http.StatusOK}); err != nil {
186 drainRespBody(resp)
187 return nil, err
188 }
189
190 return resp, nil
191 }
192
193
194 func (f FileServiceClient) resourceExists(path string, res resourceType) (bool, http.Header, error) {
195 if err := f.checkForStorageEmulator(); err != nil {
196 return false, nil, err
197 }
198
199 uri := f.client.getEndpoint(fileServiceName, path, getURLInitValues(compNone, res))
200 headers := f.client.getStandardHeaders()
201
202 resp, err := f.client.exec(http.MethodHead, uri, headers, nil, f.auth)
203 if resp != nil {
204 defer drainRespBody(resp)
205 if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNotFound {
206 return resp.StatusCode == http.StatusOK, resp.Header, nil
207 }
208 }
209 return false, nil, err
210 }
211
212
213 func (f FileServiceClient) createResource(path string, res resourceType, urlParams url.Values, extraHeaders map[string]string, expectedResponseCodes []int) (http.Header, error) {
214 resp, err := f.createResourceNoClose(path, res, urlParams, extraHeaders)
215 if err != nil {
216 return nil, err
217 }
218 defer drainRespBody(resp)
219 return resp.Header, checkRespCode(resp, expectedResponseCodes)
220 }
221
222
223 func (f FileServiceClient) createResourceNoClose(path string, res resourceType, urlParams url.Values, extraHeaders map[string]string) (*http.Response, error) {
224 if err := f.checkForStorageEmulator(); err != nil {
225 return nil, err
226 }
227
228 values := getURLInitValues(compNone, res)
229 combinedParams := mergeParams(values, urlParams)
230 uri := f.client.getEndpoint(fileServiceName, path, combinedParams)
231 extraHeaders = f.client.protectUserAgent(extraHeaders)
232 headers := mergeHeaders(f.client.getStandardHeaders(), extraHeaders)
233
234 return f.client.exec(http.MethodPut, uri, headers, nil, f.auth)
235 }
236
237
238 func (f FileServiceClient) getResourceHeaders(path string, comp compType, res resourceType, params url.Values, verb string) (http.Header, error) {
239 resp, err := f.getResourceNoClose(path, comp, res, params, verb, nil)
240 if err != nil {
241 return nil, err
242 }
243 defer drainRespBody(resp)
244
245 if err = checkRespCode(resp, []int{http.StatusOK}); err != nil {
246 return nil, err
247 }
248
249 return resp.Header, nil
250 }
251
252
253 func (f FileServiceClient) getResourceNoClose(path string, comp compType, res resourceType, params url.Values, verb string, extraHeaders map[string]string) (*http.Response, error) {
254 if err := f.checkForStorageEmulator(); err != nil {
255 return nil, err
256 }
257
258 params = mergeParams(params, getURLInitValues(comp, res))
259 uri := f.client.getEndpoint(fileServiceName, path, params)
260 headers := mergeHeaders(f.client.getStandardHeaders(), extraHeaders)
261
262 return f.client.exec(verb, uri, headers, nil, f.auth)
263 }
264
265
266 func (f FileServiceClient) deleteResource(path string, res resourceType, options *FileRequestOptions) error {
267 resp, err := f.deleteResourceNoClose(path, res, options)
268 if err != nil {
269 return err
270 }
271 defer drainRespBody(resp)
272 return checkRespCode(resp, []int{http.StatusAccepted})
273 }
274
275
276 func (f FileServiceClient) deleteResourceNoClose(path string, res resourceType, options *FileRequestOptions) (*http.Response, error) {
277 if err := f.checkForStorageEmulator(); err != nil {
278 return nil, err
279 }
280
281 values := mergeParams(getURLInitValues(compNone, res), prepareOptions(options))
282 uri := f.client.getEndpoint(fileServiceName, path, values)
283 return f.client.exec(http.MethodDelete, uri, f.client.getStandardHeaders(), nil, f.auth)
284 }
285
286
287 func mergeMDIntoExtraHeaders(metadata, extraHeaders map[string]string) map[string]string {
288 if metadata == nil && extraHeaders == nil {
289 return nil
290 }
291 if extraHeaders == nil {
292 extraHeaders = make(map[string]string)
293 }
294 for k, v := range metadata {
295 extraHeaders[userDefinedMetadataHeaderPrefix+k] = v
296 }
297 return extraHeaders
298 }
299
300
301 func (f FileServiceClient) setResourceHeaders(path string, comp compType, res resourceType, extraHeaders map[string]string, options *FileRequestOptions) (http.Header, error) {
302 if err := f.checkForStorageEmulator(); err != nil {
303 return nil, err
304 }
305
306 params := mergeParams(getURLInitValues(comp, res), prepareOptions(options))
307 uri := f.client.getEndpoint(fileServiceName, path, params)
308 extraHeaders = f.client.protectUserAgent(extraHeaders)
309 headers := mergeHeaders(f.client.getStandardHeaders(), extraHeaders)
310
311 resp, err := f.client.exec(http.MethodPut, uri, headers, nil, f.auth)
312 if err != nil {
313 return nil, err
314 }
315 defer drainRespBody(resp)
316
317 return resp.Header, checkRespCode(resp, []int{http.StatusOK})
318 }
319
320
321
322 func (f FileServiceClient) checkForStorageEmulator() error {
323 if f.client.accountName == StorageEmulatorAccountName {
324 return fmt.Errorf("Error: File service is not currently supported by Azure Storage Emulator")
325 }
326 return nil
327 }
328
View as plain text