summaryrefslogtreecommitdiff
path: root/libntfs-3g/xattrs.c (plain)
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
69struct LE_POSIX_ACE {
70 le16 tag;
71 le16 perms;
72 le32 id;
73} __attribute__((__packed__));
74
75struct 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
85static const char xattr_ntfs_3g[] = "ntfs-3g.";
86static const char nf_ns_user_prefix[] = "user.";
87static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1;
88
89static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl";
90static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib";
91static const char nf_ns_xattr_attrib_be[] = "system.ntfs_attrib_be";
92static const char nf_ns_xattr_efsinfo[] = "system.ntfs_efsinfo";
93static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data";
94static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id";
95static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name";
96static const char nf_ns_xattr_times[] = "system.ntfs_times";
97static const char nf_ns_xattr_times_be[] = "system.ntfs_times_be";
98static const char nf_ns_xattr_crtime[] = "system.ntfs_crtime";
99static const char nf_ns_xattr_crtime_be[] = "system.ntfs_crtime_be";
100static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access";
101static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default";
102
103static const char nf_ns_alt_xattr_efsinfo[] = "user.ntfs.efsinfo";
104
105struct XATTRNAME {
106 enum SYSTEMXATTRS xattr;
107 const char *name;
108} ;
109
110static 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
134static 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
157static 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
179int 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
205enum 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
242static 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
252static 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
268static 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
356static 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
409struct 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
462void 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
477int 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
600int 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
723int 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