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