1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "finfo.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <sys/stat.h>
36 #include <limits.h>
37
38 #include <cx/string.h>
39 #include <cx/list.h>
40 #include <cx/array_list.h>
41 #include <libidav/crypto.h>
42 #include <libidav/utils.h>
43
44 #ifndef _WIN32
45 #include <unistd.h>
46 #endif
47
48 #include "libxattr.h"
49
50 uint32_t parse_finfo_settings(
const char *str,
char **error) {
51 cxstring s = cx_str(str);
52
53 if(!cx_strcmp(s,
CX_STR(
"*")) || !cx_strcmp(s,
CX_STR(
"a")) || !cx_strcmp(s,
CX_STR(
"all"))) {
54 return FINFO_MTIME|
FINFO_OWNER|
FINFO_MODE|
FINFO_XATTR;
55 }
56
57 CxStrtokCtx fs = cx_strtok(s,
CX_STR(
","),
INT_MAX);
58 cxstring f;
59 uint32_t finfo =
0;
60 char *err =
NULL;
61 while(cx_strtok_next(&fs, &f)) {
62 if(!cx_strcasecmp(f,
CX_STR(
"mtime"))) {
63 finfo |=
FINFO_MTIME;
64 }
else if(!cx_strcasecmp(f,
CX_STR(
"owner"))) {
65 finfo |=
FINFO_OWNER;
66 }
else if(!cx_strcasecmp(f,
CX_STR(
"mode"))) {
67 finfo |=
FINFO_MODE;
68 }
else if(!cx_strcasecmp(f,
CX_STR(
"xattr"))) {
69 finfo |=
FINFO_XATTR;
70 }
else if(error && !err) {
71 err = cx_strdup(f).ptr;
72 continue;
73 }
74 }
75
76 return err ?
0 : finfo;
77 }
78
79 int resource_set_finfo(
const char *path, DavResource *res,
uint32_t finfo) {
80 if(!path || finfo ==
0) {
81 return 0;
82 }
83
84 struct stat s;
85 if(stat(path, &s)) {
86 fprintf(stderr,
"failed to stat: %s\n", path);
87 return 1;
88 }
89 return resource_set_finfo_s(&s, res, finfo);
90 }
91
92 int resource_set_finfo_s(
struct stat *s, DavResource *res,
uint32_t finfo) {
93 if(finfo ==
0) {
94 return 0;
95 }
96
97 DavXmlNode *content =
NULL;
98 DavXmlNode *last =
NULL;
99
100 if((finfo &
FINFO_MTIME) ==
FINFO_MTIME) {
101 char str[
32];
102 struct tm *date = gmtime(&s->st_mtime);
103 strftime(str,
32,
"%a, %d %b %Y %H:%M:%S GMT", date);
104 DavXmlNode *mtime = dav_text_element(res->session,
DAV_PROPS_NS,
"mtime", str);
105 content = mtime;
106 last = mtime;
107 }
108 #ifndef _WIN32
109 if((finfo &
FINFO_OWNER) ==
FINFO_OWNER) {
110
111 }
112 if((finfo &
FINFO_MODE) ==
FINFO_MODE) {
113 mode_t mode = s->st_mode &
07777;
114 char str[
32];
115 snprintf(str,
32,
"%o", (
int)mode);
116 DavXmlNode *xmode = dav_text_element(res->session,
DAV_PROPS_NS,
"mode", str);
117 if(last) {
118 last->next = xmode;
119 }
else {
120 content = xmode;
121 }
122 last = xmode;
123 }
124 #endif
125
126
127 dav_set_property_ns(res,
DAV_PROPS_NS,
"finfo", content);;
128
129 return 0;
130 }
131
132
133 static void* array_realloc(
void *array,
134 size_t capacity,
135 size_t elem_size,
136 struct cx_array_reallocator_s *alloc)
137 {
138 return realloc(array, capacity * elem_size);
139 }
140
141 XAttributes* xml_get_attributes(DavXmlNode *xml) {
142 XAttributes *attributes = calloc(
1,
sizeof(XAttributes));
143 size_t x_names_size =
0;
144 size_t x_names_alloc =
8;
145 size_t x_values_size =
0;
146 size_t x_values_alloc =
8;
147 attributes->names = calloc(x_names_alloc,
sizeof(
char*));
148 attributes->values = calloc(x_values_alloc,
sizeof(cxmutstr));
149
150 struct cx_array_reallocator_s re = { .realloc = array_realloc };
151
152 size_t count =
0;
153
154 char *hash =
NULL;
155
156 DavXmlNode *node = xml;
157 for(;node;node=node->next) {
158 if(node->type ==
DAV_XML_ELEMENT) {
159 if(!strcmp(node->name,
"hash")) {
160 hash = dav_xml_getstring(node->children);
161 }
else if(!strcmp(node->name,
"xattr")) {
162 char *xattr_name = dav_xml_get_attr(node,
"name");
163 if(xattr_name) {
164 char *xname = strdup(xattr_name);
165 cx_array_copy(
166 (
void**)&attributes->names,
167 &x_names_size,
168 &x_names_alloc,
169 count,
170 &xname,
171 sizeof(
void*),
172 1,
173 &re);
174
175 char *text = dav_xml_getstring(node->children);
176 if(!text) {
177 text =
"";
178 }
179
180 int len =
0;
181 char *val = util_base64decode_len(text, &len);
182
183 cxmutstr value;
184 value.ptr = val;
185 value.length = len;
186
187 cx_array_copy(
188 (
void**)&attributes->values,
189 &x_values_size,
190 &x_values_alloc,
191 count,
192 &value,
193 sizeof(cxmutstr),
194 1,
195 &re);
196
197 count++;
198 }
199 }
200 }
201 }
202
203 if(count ==
0) {
204 free(attributes->names);
205 free(attributes->values);
206 free(attributes);
207 return NULL;
208 }
209
210 attributes->hash = hash ? strdup(hash) :
NULL;
211 attributes->nattr = count;
212
213 return attributes;
214 }
215
216 XAttributes* file_get_attributes(
217 const char *path,
218 xattr_filter_func filter,
219 void *filterdata)
220 {
221 ssize_t nelm =
0;
222 char **attributes = xattr_list(path, &nelm);
223 if(nelm <=
0) {
224 return NULL;
225 }
226
227 XAttributes *xattr = malloc(
sizeof(XAttributes));
228 xattr->nattr =
0;
229 xattr->names = calloc(nelm,
sizeof(
char*));
230 xattr->values = calloc(nelm,
sizeof(cxmutstr));
231
232 DAV_SHA_CTX *sha256 = dav_hash_init();
233
234 size_t nattr =
0;
235 for(
int i=
0;i<nelm;i++) {
236 if(filter) {
237
238 if(!filter(attributes[i], filterdata)) {
239
240 continue;
241 }
242 }
243
244 ssize_t valuelen =
0;
245 char *value = xattr_get(path, attributes[i], &valuelen);
246 if(valuelen >=
0) {
247 dav_hash_update(sha256, attributes[i], strlen(attributes[i]));
248 dav_hash_update(sha256, value, valuelen);
249
250 xattr->names[nattr] = attributes[i];
251 cxmutstr v;
252 v.ptr = value;
253 v.length = valuelen;
254 xattr->values[nattr] = v;
255 nattr++;
256 }
else {
257
258 free(attributes[i]);
259 }
260 }
261
262 xattr->nattr = nattr;
263
264 unsigned char hash[
DAV_SHA256_DIGEST_LENGTH];
265 dav_hash_final(sha256, hash);
266 xattr->hash = util_hexstr(hash,
DAV_SHA256_DIGEST_LENGTH);
267
268 free(attributes);
269
270 if(nattr >
0) {
271 return xattr;
272 }
else {
273 xattributes_free(xattr);
274 return NULL;
275 }
276 }
277
278 int resource_set_xattr(DavResource *res, XAttributes *xattr) {
279 if(!xattr || xattr->nattr ==
0) {
280 return 0;
281 }
282
283 DavXmlNode *content = dav_xml_createnode_with_text(
DAV_PROPS_NS,
"hash", xattr->hash);
284 DavXmlNode *last = content;
285
286 for(
int i=
0;i<xattr->nattr;i++) {
287 DavXmlNode *attr = dav_xml_createnode(
DAV_PROPS_NS,
"xattr");
288 dav_xml_add_attr(attr,
"name", xattr->names[i]);
289 last->next = attr;
290 last = attr;
291
292 cxmutstr value = xattr->values[i];
293 if(value.length >
0) {
294 char *encval = util_base64encode(value.ptr, value.length);
295 attr->children = dav_xml_createtextnode(encval);
296 free(encval);
297 }
298 }
299
300 dav_set_property_ns(res,
DAV_PROPS_NS,
"xattributes", content);
301
302 return 0;
303 }
304
305 void xattributes_free(XAttributes *xattr) {
306 free(xattr->hash);
307 for(
int i=
0;i<xattr->nattr;i++) {
308 free(xattr->names[i]);
309 free(xattr->values[i].ptr);
310 }
311 free(xattr);
312 }
313
314 char* get_xattr_hash(DavXmlNode *finfo) {
315 DavXmlNode *node = finfo;
316 while(node) {
317 if(node->type ==
DAV_XML_ELEMENT && !strcmp(node->name,
"hash")) {
318 return dav_xml_getstring(node->children);
319 }
320 node = node->next;
321 }
322 return NULL;
323 }
324
325 void finfo_get_values(DavXmlNode *xml, FileInfo *outval) {
326 memset(outval,
0,
sizeof(FileInfo));
327 DavXmlNode *node = xml;
328 while(node) {
329 if(node->type ==
DAV_XML_ELEMENT) {
330 if(!strcmp(node->name,
"mtime")) {
331 char *mtime = dav_xml_getstring(node->children);
332 if(mtime) {
333 outval->last_modified = util_parse_lastmodified(mtime);
334 outval->date_set =
TRUE;
335 }
336 }
else if(!strcmp(node->name,
"mode")) {
337 char *mode_str = dav_xml_getstring(node->children);
338 if(mode_str) {
339 char *end;
340 errno =
0;
341 long int mode = strtol(mode_str, &end,
8);
342 if(errno ==
0) {
343 mode &=
07777;
344 outval->mode = mode;
345 outval->mode_set =
TRUE;
346 }
347 }
348 }
349 }
350 node = node->next;
351 }
352
353 }
354