blob: 5be2c06a689794a7955a504c3461d0626dbcdcd1
1 | /** |
2 | * xattrs.c : common functions to deal with system extended attributes |
3 | * |
4 | * Copyright (c) 2010 Jean-Pierre Andre |
5 | * |
6 | * This program/include file is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License as published |
8 | * by the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program/include file is distributed in the hope that it will be |
12 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program (in the main directory of the NTFS-3G |
18 | * distribution in the file COPYING); if not, write to the Free Software |
19 | * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ |
21 | |
22 | #ifdef HAVE_CONFIG_H |
23 | #include "config.h" |
24 | #endif |
25 | |
26 | #ifdef HAVE_SETXATTR /* extended attributes support required */ |
27 | |
28 | #ifdef HAVE_STDIO_H |
29 | #include <stdio.h> |
30 | #endif |
31 | #ifdef HAVE_STDLIB_H |
32 | #include <stdlib.h> |
33 | #endif |
34 | #ifdef HAVE_STRING_H |
35 | #include <string.h> |
36 | #endif |
37 | #ifdef HAVE_FCNTL_H |
38 | #include <fcntl.h> |
39 | #endif |
40 | #ifdef HAVE_UNISTD_H |
41 | #include <unistd.h> |
42 | #endif |
43 | #ifdef HAVE_ERRNO_H |
44 | #include <errno.h> |
45 | #endif |
46 | |
47 | #include "types.h" |
48 | #include "param.h" |
49 | #include "layout.h" |
50 | #include "attrib.h" |
51 | #include "index.h" |
52 | #include "dir.h" |
53 | #include "security.h" |
54 | #include "acls.h" |
55 | #include "efs.h" |
56 | #include "reparse.h" |
57 | #include "object_id.h" |
58 | #include "misc.h" |
59 | #include "logging.h" |
60 | #include "xattrs.h" |
61 | |
62 | #if POSIXACLS |
63 | #if __BYTE_ORDER == __BIG_ENDIAN |
64 | |
65 | /* |
66 | * Posix ACL structures |
67 | */ |
68 | |
69 | struct LE_POSIX_ACE { |
70 | le16 tag; |
71 | le16 perms; |
72 | le32 id; |
73 | } __attribute__((__packed__)); |
74 | |
75 | struct LE_POSIX_ACL { |
76 | u8 version; |
77 | u8 flags; |
78 | le16 filler; |
79 | struct LE_POSIX_ACE ace[0]; |
80 | } __attribute__((__packed__)); |
81 | |
82 | #endif |
83 | #endif |
84 | |
85 | static const char xattr_ntfs_3g[] = "ntfs-3g."; |
86 | static const char nf_ns_user_prefix[] = "user."; |
87 | static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1; |
88 | |
89 | static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl"; |
90 | static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib"; |
91 | static const char nf_ns_xattr_attrib_be[] = "system.ntfs_attrib_be"; |
92 | static const char nf_ns_xattr_efsinfo[] = "system.ntfs_efsinfo"; |
93 | static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data"; |
94 | static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id"; |
95 | static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name"; |
96 | static const char nf_ns_xattr_times[] = "system.ntfs_times"; |
97 | static const char nf_ns_xattr_times_be[] = "system.ntfs_times_be"; |
98 | static const char nf_ns_xattr_crtime[] = "system.ntfs_crtime"; |
99 | static const char nf_ns_xattr_crtime_be[] = "system.ntfs_crtime_be"; |
100 | static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access"; |
101 | static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default"; |
102 | |
103 | static const char nf_ns_alt_xattr_efsinfo[] = "user.ntfs.efsinfo"; |
104 | |
105 | struct XATTRNAME { |
106 | enum SYSTEMXATTRS xattr; |
107 | const char *name; |
108 | } ; |
109 | |
110 | static struct XATTRNAME nf_ns_xattr_names[] = { |
111 | { XATTR_NTFS_ACL, nf_ns_xattr_ntfs_acl }, |
112 | { XATTR_NTFS_ATTRIB, nf_ns_xattr_attrib }, |
113 | { XATTR_NTFS_ATTRIB_BE, nf_ns_xattr_attrib_be }, |
114 | { XATTR_NTFS_EFSINFO, nf_ns_xattr_efsinfo }, |
115 | { XATTR_NTFS_REPARSE_DATA, nf_ns_xattr_reparse }, |
116 | { XATTR_NTFS_OBJECT_ID, nf_ns_xattr_object_id }, |
117 | { XATTR_NTFS_DOS_NAME, nf_ns_xattr_dos_name }, |
118 | { XATTR_NTFS_TIMES, nf_ns_xattr_times }, |
119 | { XATTR_NTFS_TIMES_BE, nf_ns_xattr_times_be }, |
120 | { XATTR_NTFS_CRTIME, nf_ns_xattr_crtime }, |
121 | { XATTR_NTFS_CRTIME_BE, nf_ns_xattr_crtime_be }, |
122 | { XATTR_POSIX_ACC, nf_ns_xattr_posix_access }, |
123 | { XATTR_POSIX_DEF, nf_ns_xattr_posix_default }, |
124 | { XATTR_UNMAPPED, (char*)NULL } /* terminator */ |
125 | }; |
126 | |
127 | /* |
128 | * Make an integer big-endian |
129 | * |
130 | * Swap bytes on a small-endian computer and does nothing on a |
131 | * big-endian computer. |
132 | */ |
133 | |
134 | static void fix_big_endian(char *p, int size) |
135 | { |
136 | #if __BYTE_ORDER == __LITTLE_ENDIAN |
137 | int i,j; |
138 | int c; |
139 | |
140 | i = 0; |
141 | j = size - 1; |
142 | while (i < j) { |
143 | c = p[i]; |
144 | p[i++] = p[j]; |
145 | p[j--] = c; |
146 | } |
147 | #endif |
148 | } |
149 | |
150 | #if POSIXACLS |
151 | #if __BYTE_ORDER == __BIG_ENDIAN |
152 | |
153 | /* |
154 | * Make a Posix ACL CPU endian |
155 | */ |
156 | |
157 | static int le_acl_to_cpu(const struct LE_POSIX_ACL *le_acl, size_t size, |
158 | struct POSIX_ACL *acl) |
159 | { |
160 | int i; |
161 | int cnt; |
162 | |
163 | acl->version = le_acl->version; |
164 | acl->flags = le_acl->flags; |
165 | acl->filler = 0; |
166 | cnt = (size - sizeof(struct LE_POSIX_ACL)) / sizeof(struct LE_POSIX_ACE); |
167 | for (i=0; i<cnt; i++) { |
168 | acl->ace[i].tag = le16_to_cpu(le_acl->ace[i].tag); |
169 | acl->ace[i].perms = le16_to_cpu(le_acl->ace[i].perms); |
170 | acl->ace[i].id = le32_to_cpu(le_acl->ace[i].id); |
171 | } |
172 | return (0); |
173 | } |
174 | |
175 | /* |
176 | * Make a Posix ACL little endian |
177 | */ |
178 | |
179 | int cpu_to_le_acl(const struct POSIX_ACL *acl, size_t size, |
180 | struct LE_POSIX_ACL *le_acl) |
181 | { |
182 | int i; |
183 | int cnt; |
184 | |
185 | le_acl->version = acl->version; |
186 | le_acl->flags = acl->flags; |
187 | le_acl->filler = const_cpu_to_le16(0); |
188 | cnt = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE); |
189 | for (i=0; i<cnt; i++) { |
190 | le_acl->ace[i].tag = cpu_to_le16(acl->ace[i].tag); |
191 | le_acl->ace[i].perms = cpu_to_le16(acl->ace[i].perms); |
192 | le_acl->ace[i].id = cpu_to_le32(acl->ace[i].id); |
193 | } |
194 | return (0); |
195 | } |
196 | |
197 | #endif |
198 | #endif |
199 | |
200 | /* |
201 | * Determine whether an extended attribute is mapped to |
202 | * internal data (original name in system namespace, or renamed) |
203 | */ |
204 | |
205 | enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name, |
206 | ntfs_volume *vol) |
207 | { |
208 | struct XATTRNAME *p; |
209 | enum SYSTEMXATTRS ret; |
210 | #ifdef XATTR_MAPPINGS |
211 | const struct XATTRMAPPING *q; |
212 | #endif /* XATTR_MAPPINGS */ |
213 | |
214 | p = nf_ns_xattr_names; |
215 | while (p->name && strcmp(p->name,name)) |
216 | p++; |
217 | ret = p->xattr; |
218 | #ifdef XATTR_MAPPINGS |
219 | if (!p->name && vol && vol->xattr_mapping) { |
220 | q = vol->xattr_mapping; |
221 | while (q && strcmp(q->name,name)) |
222 | q = q->next; |
223 | if (q) |
224 | ret = q->xattr; |
225 | } |
226 | #else /* XATTR_MAPPINGS */ |
227 | if (!p->name |
228 | && vol |
229 | && vol->efs_raw |
230 | && !strcmp(nf_ns_alt_xattr_efsinfo,name)) |
231 | ret = XATTR_NTFS_EFSINFO; |
232 | #endif /* XATTR_MAPPINGS */ |
233 | return (ret); |
234 | } |
235 | |
236 | #ifdef XATTR_MAPPINGS |
237 | |
238 | /* |
239 | * Basic read from a user mapping file on another volume |
240 | */ |
241 | |
242 | static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribute__((unused))) |
243 | { |
244 | return (read(*(int*)fileid, buf, size)); |
245 | } |
246 | |
247 | |
248 | /* |
249 | * Read from a user mapping file on current NTFS partition |
250 | */ |
251 | |
252 | static int localread(void *fileid, char *buf, size_t size, off_t offs) |
253 | { |
254 | return (ntfs_attr_data_read((ntfs_inode*)fileid, |
255 | AT_UNNAMED, 0, buf, size, offs)); |
256 | } |
257 | |
258 | /* |
259 | * Get a single mapping item from buffer |
260 | * |
261 | * Always reads a full line, truncating long lines |
262 | * Refills buffer when exhausted |
263 | * Returns pointer to item, or NULL when there is no more |
264 | * Note : errors are logged, but not returned |
265 | // TODO partially share with acls.c |
266 | */ |
267 | |
268 | static struct XATTRMAPPING *getmappingitem(FILEREADER reader, void *fileid, |
269 | off_t *poffs, char *buf, int *psrc, s64 *psize) |
270 | { |
271 | int src; |
272 | int dst; |
273 | char *pe; |
274 | char *ps; |
275 | char *pu; |
276 | enum SYSTEMXATTRS xattr; |
277 | int gotend; |
278 | char maptext[LINESZ]; |
279 | struct XATTRMAPPING *item; |
280 | |
281 | src = *psrc; |
282 | dst = 0; |
283 | do { |
284 | gotend = 0; |
285 | while ((src < *psize) |
286 | && (buf[src] != '\n')) { |
287 | /* ignore spaces */ |
288 | if ((dst < LINESZ) |
289 | && (buf[src] != '\r') |
290 | && (buf[src] != '\t') |
291 | && (buf[src] != ' ')) |
292 | maptext[dst++] = buf[src]; |
293 | src++; |
294 | } |
295 | if (src >= *psize) { |
296 | *poffs += *psize; |
297 | *psize = reader(fileid, buf, (size_t)BUFSZ, *poffs); |
298 | src = 0; |
299 | } else { |
300 | gotend = 1; |
301 | src++; |
302 | maptext[dst] = '\0'; |
303 | dst = 0; |
304 | } |
305 | } while (*psize && ((maptext[0] == '#') || !gotend)); |
306 | item = (struct XATTRMAPPING*)NULL; |
307 | if (gotend) { |
308 | /* decompose into system name and user name */ |
309 | ps = maptext; |
310 | pu = strchr(maptext,':'); |
311 | if (pu) { |
312 | *pu++ = 0; |
313 | pe = strchr(pu,':'); |
314 | if (pe) |
315 | *pe = 0; |
316 | /* check name validity */ |
317 | if ((strlen(pu) < 6) || strncmp(pu,"user.",5)) |
318 | pu = (char*)NULL; |
319 | xattr = ntfs_xattr_system_type(ps, |
320 | (ntfs_volume*)NULL); |
321 | if (xattr == XATTR_UNMAPPED) |
322 | pu = (char*)NULL; |
323 | } |
324 | if (pu) { |
325 | item = (struct XATTRMAPPING*)ntfs_malloc( |
326 | sizeof(struct XATTRMAPPING) |
327 | + strlen(pu)); |
328 | if (item) { |
329 | item->xattr = xattr; |
330 | strcpy(item->name,pu); |
331 | item->next = (struct XATTRMAPPING*)NULL; |
332 | } |
333 | } else { |
334 | ntfs_log_early_error("Bad xattr mapping item, aborting\n"); |
335 | } |
336 | } |
337 | *psrc = src; |
338 | return (item); |
339 | } |
340 | |
341 | /* |
342 | * Read xattr mapping file and split into their attribute. |
343 | * Parameters are kept in a chained list. |
344 | * Returns the head of list, if any |
345 | * Errors are logged, but not returned |
346 | * |
347 | * If an absolute path is provided, the mapping file is assumed |
348 | * to be located in another mounted file system, and plain read() |
349 | * are used to get its contents. |
350 | * If a relative path is provided, the mapping file is assumed |
351 | * to be located on the current file system, and internal IO |
352 | * have to be used since we are still mounting and we have not |
353 | * entered the fuse loop yet. |
354 | */ |
355 | |
356 | static struct XATTRMAPPING *ntfs_read_xattr_mapping(FILEREADER reader, |
357 | void *fileid) |
358 | { |
359 | char buf[BUFSZ]; |
360 | struct XATTRMAPPING *item; |
361 | struct XATTRMAPPING *current; |
362 | struct XATTRMAPPING *firstitem; |
363 | struct XATTRMAPPING *lastitem; |
364 | BOOL duplicated; |
365 | int src; |
366 | off_t offs; |
367 | s64 size; |
368 | |
369 | firstitem = (struct XATTRMAPPING*)NULL; |
370 | lastitem = (struct XATTRMAPPING*)NULL; |
371 | offs = 0; |
372 | size = reader(fileid, buf, (size_t)BUFSZ, (off_t)0); |
373 | if (size > 0) { |
374 | src = 0; |
375 | do { |
376 | item = getmappingitem(reader, fileid, &offs, |
377 | buf, &src, &size); |
378 | if (item) { |
379 | /* check no double mapping */ |
380 | duplicated = FALSE; |
381 | for (current=firstitem; current; current=current->next) |
382 | if ((current->xattr == item->xattr) |
383 | || !strcmp(current->name,item->name)) |
384 | duplicated = TRUE; |
385 | if (duplicated) { |
386 | free(item); |
387 | ntfs_log_early_error("Conflicting xattr mapping ignored\n"); |
388 | } else { |
389 | item->next = (struct XATTRMAPPING*)NULL; |
390 | if (lastitem) |
391 | lastitem->next = item; |
392 | else |
393 | firstitem = item; |
394 | lastitem = item; |
395 | } |
396 | } |
397 | } while (item); |
398 | } |
399 | return (firstitem); |
400 | } |
401 | |
402 | /* |
403 | * Build the extended attribute mappings to user namespace |
404 | * |
405 | * Note : no error is returned. If we refused mounting when there |
406 | * is an error it would be too difficult to fix the offending file |
407 | */ |
408 | |
409 | struct XATTRMAPPING *ntfs_xattr_build_mapping(ntfs_volume *vol, |
410 | const char *xattrmap_path) |
411 | { |
412 | struct XATTRMAPPING *firstmapping; |
413 | struct XATTRMAPPING *mapping; |
414 | BOOL user_efs; |
415 | BOOL notfound; |
416 | ntfs_inode *ni; |
417 | int fd; |
418 | |
419 | firstmapping = (struct XATTRMAPPING*)NULL; |
420 | notfound = FALSE; |
421 | if (!xattrmap_path) |
422 | xattrmap_path = XATTRMAPPINGFILE; |
423 | if (xattrmap_path[0] == '/') { |
424 | fd = open(xattrmap_path,O_RDONLY); |
425 | if (fd > 0) { |
426 | firstmapping = ntfs_read_xattr_mapping(basicread, (void*)&fd); |
427 | close(fd); |
428 | } else |
429 | notfound = TRUE; |
430 | } else { |
431 | ni = ntfs_pathname_to_inode(vol, NULL, xattrmap_path); |
432 | if (ni) { |
433 | firstmapping = ntfs_read_xattr_mapping(localread, ni); |
434 | ntfs_inode_close(ni); |
435 | } else |
436 | notfound = TRUE; |
437 | } |
438 | if (notfound && strcmp(xattrmap_path, XATTRMAPPINGFILE)) { |
439 | ntfs_log_early_error("Could not open \"%s\"\n",xattrmap_path); |
440 | } |
441 | if (vol->efs_raw) { |
442 | user_efs = TRUE; |
443 | for (mapping=firstmapping; mapping; mapping=mapping->next) |
444 | if (mapping->xattr == XATTR_NTFS_EFSINFO) |
445 | user_efs = FALSE; |
446 | } else |
447 | user_efs = FALSE; |
448 | if (user_efs) { |
449 | mapping = (struct XATTRMAPPING*)ntfs_malloc( |
450 | sizeof(struct XATTRMAPPING) |
451 | + strlen(nf_ns_alt_xattr_efsinfo)); |
452 | if (mapping) { |
453 | mapping->next = firstmapping; |
454 | mapping->xattr = XATTR_NTFS_EFSINFO; |
455 | strcpy(mapping->name,nf_ns_alt_xattr_efsinfo); |
456 | firstmapping = mapping; |
457 | } |
458 | } |
459 | return (firstmapping); |
460 | } |
461 | |
462 | void ntfs_xattr_free_mapping(struct XATTRMAPPING *mapping) |
463 | { |
464 | struct XATTRMAPPING *p, *q; |
465 | |
466 | p = mapping; |
467 | while (p) { |
468 | q = p->next; |
469 | free(p); |
470 | p = q; |
471 | } |
472 | } |
473 | |
474 | #endif /* XATTR_MAPPINGS */ |
475 | |
476 | |
477 | int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx, |
478 | enum SYSTEMXATTRS attr, |
479 | ntfs_inode *ni, ntfs_inode *dir_ni, |
480 | char *value, size_t size) |
481 | { |
482 | int res; |
483 | int i; |
484 | #if POSIXACLS |
485 | #if __BYTE_ORDER == __BIG_ENDIAN |
486 | struct POSIX_ACL *acl; |
487 | #endif |
488 | #endif |
489 | |
490 | /* |
491 | * the returned value is the needed |
492 | * size. If it is too small, no copy |
493 | * is done, and the caller has to |
494 | * issue a new call with correct size. |
495 | */ |
496 | switch (attr) { |
497 | case XATTR_NTFS_ACL : |
498 | res = ntfs_get_ntfs_acl(scx, ni, value, size); |
499 | break; |
500 | #if POSIXACLS |
501 | #if __BYTE_ORDER == __BIG_ENDIAN |
502 | case XATTR_POSIX_ACC : |
503 | acl = (struct POSIX_ACL*)ntfs_malloc(size); |
504 | if (acl) { |
505 | res = ntfs_get_posix_acl(scx, ni, |
506 | nf_ns_xattr_posix_access, (char*)acl, size); |
507 | if (res > 0) { |
508 | if (cpu_to_le_acl(acl,res, |
509 | (struct LE_POSIX_ACL*)value)) |
510 | res = -errno; |
511 | } |
512 | free(acl); |
513 | } else |
514 | res = -errno; |
515 | break; |
516 | case XATTR_POSIX_DEF : |
517 | acl = (struct POSIX_ACL*)ntfs_malloc(size); |
518 | if (acl) { |
519 | res = ntfs_get_posix_acl(scx, ni, |
520 | nf_ns_xattr_posix_default, (char*)acl, size); |
521 | if (res > 0) { |
522 | if (cpu_to_le_acl(acl,res, |
523 | (struct LE_POSIX_ACL*)value)) |
524 | res = -errno; |
525 | } |
526 | free(acl); |
527 | } else |
528 | res = -errno; |
529 | break; |
530 | #else |
531 | case XATTR_POSIX_ACC : |
532 | res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_access, |
533 | value, size); |
534 | break; |
535 | case XATTR_POSIX_DEF : |
536 | res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_default, |
537 | value, size); |
538 | break; |
539 | #endif |
540 | #endif |
541 | case XATTR_NTFS_ATTRIB : |
542 | res = ntfs_get_ntfs_attrib(ni, value, size); |
543 | break; |
544 | case XATTR_NTFS_ATTRIB_BE : |
545 | res = ntfs_get_ntfs_attrib(ni, value, size); |
546 | if ((res == 4) && value) { |
547 | if (size >= 4) |
548 | fix_big_endian(value,4); |
549 | else |
550 | res = -EINVAL; |
551 | } |
552 | break; |
553 | case XATTR_NTFS_EFSINFO : |
554 | if (ni->vol->efs_raw) |
555 | res = ntfs_get_efs_info(ni, value, size); |
556 | else |
557 | res = -EPERM; |
558 | break; |
559 | case XATTR_NTFS_REPARSE_DATA : |
560 | res = ntfs_get_ntfs_reparse_data(ni, value, size); |
561 | break; |
562 | case XATTR_NTFS_OBJECT_ID : |
563 | res = ntfs_get_ntfs_object_id(ni, value, size); |
564 | break; |
565 | case XATTR_NTFS_DOS_NAME: |
566 | if (dir_ni) |
567 | res = ntfs_get_ntfs_dos_name(ni, dir_ni, value, size); |
568 | else |
569 | res = -errno; |
570 | break; |
571 | case XATTR_NTFS_TIMES: |
572 | res = ntfs_inode_get_times(ni, value, size); |
573 | break; |
574 | case XATTR_NTFS_TIMES_BE: |
575 | res = ntfs_inode_get_times(ni, value, size); |
576 | if ((res > 0) && value) { |
577 | for (i=0; (i+1)*sizeof(u64)<=(unsigned int)res; i++) |
578 | fix_big_endian(&value[i*sizeof(u64)], |
579 | sizeof(u64)); |
580 | } |
581 | break; |
582 | case XATTR_NTFS_CRTIME: |
583 | res = ntfs_inode_get_times(ni, value, |
584 | (size >= sizeof(u64) ? sizeof(u64) : size)); |
585 | break; |
586 | case XATTR_NTFS_CRTIME_BE: |
587 | res = ntfs_inode_get_times(ni, value, |
588 | (size >= sizeof(u64) ? sizeof(u64) : size)); |
589 | if ((res >= (int)sizeof(u64)) && value) |
590 | fix_big_endian(value,sizeof(u64)); |
591 | break; |
592 | default : |
593 | errno = EOPNOTSUPP; |
594 | res = -errno; |
595 | break; |
596 | } |
597 | return (res); |
598 | } |
599 | |
600 | int ntfs_xattr_system_setxattr(struct SECURITY_CONTEXT *scx, |
601 | enum SYSTEMXATTRS attr, |
602 | ntfs_inode *ni, ntfs_inode *dir_ni, |
603 | const char *value, size_t size, int flags) |
604 | { |
605 | int res; |
606 | int i; |
607 | char buf[4*sizeof(u64)]; |
608 | #if POSIXACLS |
609 | #if __BYTE_ORDER == __BIG_ENDIAN |
610 | struct POSIX_ACL *acl; |
611 | #endif |
612 | #endif |
613 | |
614 | switch (attr) { |
615 | case XATTR_NTFS_ACL : |
616 | res = ntfs_set_ntfs_acl(scx, ni, value, size, flags); |
617 | break; |
618 | #if POSIXACLS |
619 | #if __BYTE_ORDER == __BIG_ENDIAN |
620 | case XATTR_POSIX_ACC : |
621 | acl = (struct POSIX_ACL*)ntfs_malloc(size); |
622 | if (acl) { |
623 | if (!le_acl_to_cpu((const struct LE_POSIX_ACL*)value, |
624 | size, acl)) { |
625 | res = ntfs_set_posix_acl(scx ,ni , |
626 | nf_ns_xattr_posix_access, |
627 | (char*)acl, size, flags); |
628 | } else |
629 | res = -errno; |
630 | free(acl); |
631 | } else |
632 | res = -errno; |
633 | break; |
634 | case XATTR_POSIX_DEF : |
635 | acl = (struct POSIX_ACL*)ntfs_malloc(size); |
636 | if (acl) { |
637 | if (!le_acl_to_cpu((const struct LE_POSIX_ACL*)value, |
638 | size, acl)) { |
639 | res = ntfs_set_posix_acl(scx ,ni , |
640 | nf_ns_xattr_posix_default, |
641 | (char*)acl, size, flags); |
642 | } else |
643 | res = -errno; |
644 | free(acl); |
645 | } else |
646 | res = -errno; |
647 | break; |
648 | #else |
649 | case XATTR_POSIX_ACC : |
650 | res = ntfs_set_posix_acl(scx ,ni , nf_ns_xattr_posix_access, |
651 | value, size, flags); |
652 | break; |
653 | case XATTR_POSIX_DEF : |
654 | res = ntfs_set_posix_acl(scx, ni, nf_ns_xattr_posix_default, |
655 | value, size, flags); |
656 | break; |
657 | #endif |
658 | #endif |
659 | case XATTR_NTFS_ATTRIB : |
660 | res = ntfs_set_ntfs_attrib(ni, value, size, flags); |
661 | break; |
662 | case XATTR_NTFS_ATTRIB_BE : |
663 | if (value && (size >= 4)) { |
664 | memcpy(buf,value,4); |
665 | fix_big_endian(buf,4); |
666 | res = ntfs_set_ntfs_attrib(ni, buf, 4, flags); |
667 | } else |
668 | res = ntfs_set_ntfs_attrib(ni, value, size, flags); |
669 | break; |
670 | case XATTR_NTFS_EFSINFO : |
671 | if (ni->vol->efs_raw) |
672 | res = ntfs_set_efs_info(ni, value, size, flags); |
673 | else |
674 | res = -EPERM; |
675 | break; |
676 | case XATTR_NTFS_REPARSE_DATA : |
677 | res = ntfs_set_ntfs_reparse_data(ni, value, size, flags); |
678 | break; |
679 | case XATTR_NTFS_OBJECT_ID : |
680 | res = ntfs_set_ntfs_object_id(ni, value, size, flags); |
681 | break; |
682 | case XATTR_NTFS_DOS_NAME: |
683 | if (dir_ni) |
684 | /* warning : this closes both inodes */ |
685 | res = ntfs_set_ntfs_dos_name(ni, dir_ni, value, |
686 | size, flags); |
687 | else |
688 | res = -errno; |
689 | break; |
690 | case XATTR_NTFS_TIMES: |
691 | res = ntfs_inode_set_times(ni, value, size, flags); |
692 | break; |
693 | case XATTR_NTFS_TIMES_BE: |
694 | if (value && (size > 0) && (size <= 4*sizeof(u64))) { |
695 | memcpy(buf,value,size); |
696 | for (i=0; (i+1)*sizeof(u64)<=size; i++) |
697 | fix_big_endian(&buf[i*sizeof(u64)], |
698 | sizeof(u64)); |
699 | res = ntfs_inode_set_times(ni, buf, size, flags); |
700 | } else |
701 | res = ntfs_inode_set_times(ni, value, size, flags); |
702 | break; |
703 | case XATTR_NTFS_CRTIME: |
704 | res = ntfs_inode_set_times(ni, value, |
705 | (size >= sizeof(u64) ? sizeof(u64) : size), flags); |
706 | break; |
707 | case XATTR_NTFS_CRTIME_BE: |
708 | if (value && (size >= sizeof(u64))) { |
709 | memcpy(buf,value,sizeof(u64)); |
710 | fix_big_endian(buf,sizeof(u64)); |
711 | res = ntfs_inode_set_times(ni, buf, sizeof(u64), flags); |
712 | } else |
713 | res = ntfs_inode_set_times(ni, value, size, flags); |
714 | break; |
715 | default : |
716 | errno = EOPNOTSUPP; |
717 | res = -errno; |
718 | break; |
719 | } |
720 | return (res); |
721 | } |
722 | |
723 | int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx, |
724 | enum SYSTEMXATTRS attr, |
725 | ntfs_inode *ni, ntfs_inode *dir_ni) |
726 | { |
727 | int res; |
728 | |
729 | res = 0; |
730 | switch (attr) { |
731 | /* |
732 | * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES |
733 | * is never allowed |
734 | */ |
735 | case XATTR_NTFS_ACL : |
736 | case XATTR_NTFS_ATTRIB : |
737 | case XATTR_NTFS_ATTRIB_BE : |
738 | case XATTR_NTFS_EFSINFO : |
739 | case XATTR_NTFS_TIMES : |
740 | case XATTR_NTFS_TIMES_BE : |
741 | case XATTR_NTFS_CRTIME : |
742 | case XATTR_NTFS_CRTIME_BE : |
743 | res = -EPERM; |
744 | break; |
745 | #if POSIXACLS |
746 | case XATTR_POSIX_ACC : |
747 | case XATTR_POSIX_DEF : |
748 | if (ni) { |
749 | if (!ntfs_allowed_as_owner(scx, ni) |
750 | || ntfs_remove_posix_acl(scx, ni, |
751 | (attr == XATTR_POSIX_ACC ? |
752 | nf_ns_xattr_posix_access : |
753 | nf_ns_xattr_posix_default))) |
754 | res = -errno; |
755 | } else |
756 | res = -errno; |
757 | break; |
758 | #endif |
759 | case XATTR_NTFS_REPARSE_DATA : |
760 | if (ni) { |
761 | if (!ntfs_allowed_as_owner(scx, ni) |
762 | || ntfs_remove_ntfs_reparse_data(ni)) |
763 | res = -errno; |
764 | } else |
765 | res = -errno; |
766 | break; |
767 | case XATTR_NTFS_OBJECT_ID : |
768 | if (ni) { |
769 | if (!ntfs_allowed_as_owner(scx, ni) |
770 | || ntfs_remove_ntfs_object_id(ni)) |
771 | res = -errno; |
772 | } else |
773 | res = -errno; |
774 | break; |
775 | case XATTR_NTFS_DOS_NAME: |
776 | if (ni && dir_ni) { |
777 | if (ntfs_remove_ntfs_dos_name(ni,dir_ni)) |
778 | res = -errno; |
779 | /* ni and dir_ni have been closed */ |
780 | } else |
781 | res = -errno; |
782 | break; |
783 | default : |
784 | errno = EOPNOTSUPP; |
785 | res = -errno; |
786 | break; |
787 | } |
788 | return (res); |
789 | } |
790 | |
791 | #endif /* HAVE_SETXATTR */ |
792 |