1 package storage
2
3
4
5
6 import (
7 "encoding/xml"
8 "net/http"
9 "net/url"
10 "sync"
11 )
12
13
14 type Directory struct {
15 fsc *FileServiceClient
16 Metadata map[string]string
17 Name string `xml:"Name"`
18 parent *Directory
19 Properties DirectoryProperties
20 share *Share
21 }
22
23
24 type DirectoryProperties struct {
25 LastModified string `xml:"Last-Modified"`
26 Etag string `xml:"Etag"`
27 }
28
29
30
31
32
33 type ListDirsAndFilesParameters struct {
34 Prefix string
35 Marker string
36 MaxResults uint
37 Timeout uint
38 }
39
40
41
42
43
44 type DirsAndFilesListResponse struct {
45 XMLName xml.Name `xml:"EnumerationResults"`
46 Xmlns string `xml:"xmlns,attr"`
47 Marker string `xml:"Marker"`
48 MaxResults int64 `xml:"MaxResults"`
49 Directories []Directory `xml:"Entries>Directory"`
50 Files []File `xml:"Entries>File"`
51 NextMarker string `xml:"NextMarker"`
52 }
53
54
55 func (d *Directory) buildPath() string {
56 path := ""
57 current := d
58 for current.Name != "" {
59 path = "/" + current.Name + path
60 current = current.parent
61 }
62 return d.share.buildPath() + path
63 }
64
65
66
67
68
69 func (d *Directory) Create(options *FileRequestOptions) error {
70
71 if d.parent == nil {
72 return nil
73 }
74
75 params := prepareOptions(options)
76 headers, err := d.fsc.createResource(d.buildPath(), resourceDirectory, params, mergeMDIntoExtraHeaders(d.Metadata, nil), []int{http.StatusCreated})
77 if err != nil {
78 return err
79 }
80
81 d.updateEtagAndLastModified(headers)
82 return nil
83 }
84
85
86
87
88
89
90 func (d *Directory) CreateIfNotExists(options *FileRequestOptions) (bool, error) {
91
92 if d.parent == nil {
93 return false, nil
94 }
95
96 params := prepareOptions(options)
97 resp, err := d.fsc.createResourceNoClose(d.buildPath(), resourceDirectory, params, nil)
98 if resp != nil {
99 defer drainRespBody(resp)
100 if resp.StatusCode == http.StatusCreated || resp.StatusCode == http.StatusConflict {
101 if resp.StatusCode == http.StatusCreated {
102 d.updateEtagAndLastModified(resp.Header)
103 return true, nil
104 }
105
106 return false, d.FetchAttributes(nil)
107 }
108 }
109
110 return false, err
111 }
112
113
114
115
116
117 func (d *Directory) Delete(options *FileRequestOptions) error {
118 return d.fsc.deleteResource(d.buildPath(), resourceDirectory, options)
119 }
120
121
122
123
124 func (d *Directory) DeleteIfExists(options *FileRequestOptions) (bool, error) {
125 resp, err := d.fsc.deleteResourceNoClose(d.buildPath(), resourceDirectory, options)
126 if resp != nil {
127 defer drainRespBody(resp)
128 if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusNotFound {
129 return resp.StatusCode == http.StatusAccepted, nil
130 }
131 }
132 return false, err
133 }
134
135
136 func (d *Directory) Exists() (bool, error) {
137 exists, headers, err := d.fsc.resourceExists(d.buildPath(), resourceDirectory)
138 if exists {
139 d.updateEtagAndLastModified(headers)
140 }
141 return exists, err
142 }
143
144
145
146 func (d *Directory) FetchAttributes(options *FileRequestOptions) error {
147 params := prepareOptions(options)
148 headers, err := d.fsc.getResourceHeaders(d.buildPath(), compNone, resourceDirectory, params, http.MethodHead)
149 if err != nil {
150 return err
151 }
152
153 d.updateEtagAndLastModified(headers)
154 d.Metadata = getMetadataFromHeaders(headers)
155
156 return nil
157 }
158
159
160 func (d *Directory) GetDirectoryReference(name string) *Directory {
161 return &Directory{
162 fsc: d.fsc,
163 Name: name,
164 parent: d,
165 share: d.share,
166 }
167 }
168
169
170 func (d *Directory) GetFileReference(name string) *File {
171 return &File{
172 fsc: d.fsc,
173 Name: name,
174 parent: d,
175 share: d.share,
176 mutex: &sync.Mutex{},
177 }
178 }
179
180
181
182
183
184 func (d *Directory) ListDirsAndFiles(params ListDirsAndFilesParameters) (*DirsAndFilesListResponse, error) {
185 q := mergeParams(params.getParameters(), getURLInitValues(compList, resourceDirectory))
186
187 resp, err := d.fsc.listContent(d.buildPath(), q, nil)
188 if err != nil {
189 return nil, err
190 }
191
192 defer resp.Body.Close()
193 var out DirsAndFilesListResponse
194 err = xmlUnmarshal(resp.Body, &out)
195 return &out, err
196 }
197
198
199
200
201
202
203
204
205
206 func (d *Directory) SetMetadata(options *FileRequestOptions) error {
207 headers, err := d.fsc.setResourceHeaders(d.buildPath(), compMetadata, resourceDirectory, mergeMDIntoExtraHeaders(d.Metadata, nil), options)
208 if err != nil {
209 return err
210 }
211
212 d.updateEtagAndLastModified(headers)
213 return nil
214 }
215
216
217 func (d *Directory) updateEtagAndLastModified(headers http.Header) {
218 d.Properties.Etag = headers.Get("Etag")
219 d.Properties.LastModified = headers.Get("Last-Modified")
220 }
221
222
223
224
225 func (d *Directory) URL() string {
226 return d.fsc.client.getEndpoint(fileServiceName, d.buildPath(), url.Values{})
227 }
228
View as plain text