xref: /haiku/src/add-ons/kernel/file_systems/ntfs/libntfs/xattrs.c (revision 83b1a68c52ba3e0e8796282759f694b7fdddf06d)
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