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
68struct LE_POSIX_ACE {
69	le16 tag;
70	le16 perms;
71	le32 id;
72} __attribute__((__packed__));
73
74struct 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
84static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl";
85static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib";
86static const char nf_ns_xattr_attrib_be[] = "system.ntfs_attrib_be";
87static const char nf_ns_xattr_efsinfo[] = "system.ntfs_efsinfo";
88static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data";
89static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id";
90static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name";
91static const char nf_ns_xattr_times[] = "system.ntfs_times";
92static const char nf_ns_xattr_times_be[] = "system.ntfs_times_be";
93static const char nf_ns_xattr_crtime[] = "system.ntfs_crtime";
94static const char nf_ns_xattr_crtime_be[] = "system.ntfs_crtime_be";
95static const char nf_ns_xattr_ea[] = "system.ntfs_ea";
96static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access";
97static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default";
98
99static const char nf_ns_alt_xattr_efsinfo[] = "user.ntfs.efsinfo";
100
101struct XATTRNAME {
102	enum SYSTEMXATTRS xattr;
103	const char *name;
104} ;
105
106static 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
131static 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
154static 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
176int 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
202enum 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
239static 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
249static 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
265static 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
353static 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
406struct 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
459void 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/*
474 *		Get an NTFS attribute into an extended attribute
475 *
476 *	Returns the non-negative size of attribute if successful,
477 *	        or negative, with errno set, when fails
478 *	Note : the size is returned even if no buffer is provided
479 *	for returning the attribute, or if it is zero-sized.
480 */
481
482int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx,
483			enum SYSTEMXATTRS attr,
484			ntfs_inode *ni, ntfs_inode *dir_ni,
485			char *value, size_t size)
486{
487	int res;
488	int i;
489#if POSIXACLS
490#if __BYTE_ORDER == __BIG_ENDIAN
491	struct POSIX_ACL *acl;
492#endif
493#endif
494
495	switch (attr) {
496	case XATTR_NTFS_ACL :
497		res = ntfs_get_ntfs_acl(scx, ni, value, size);
498		break;
499#if POSIXACLS
500#if __BYTE_ORDER == __BIG_ENDIAN
501	case XATTR_POSIX_ACC :
502		acl = (struct POSIX_ACL*)ntfs_malloc(size);
503		if (acl) {
504			res = ntfs_get_posix_acl(scx, ni,
505				nf_ns_xattr_posix_access, (char*)acl, size);
506			if (res > 0) {
507				if (cpu_to_le_acl(acl,res,
508						(struct LE_POSIX_ACL*)value))
509					res = -errno;
510			}
511			free(acl);
512		} else
513			res = -errno;
514		break;
515	case XATTR_POSIX_DEF :
516		acl = (struct POSIX_ACL*)ntfs_malloc(size);
517		if (acl) {
518			res = ntfs_get_posix_acl(scx, ni,
519				nf_ns_xattr_posix_default, (char*)acl, size);
520			if (res > 0) {
521				if (cpu_to_le_acl(acl,res,
522						(struct LE_POSIX_ACL*)value))
523					res = -errno;
524			}
525			free(acl);
526		} else
527			res = -errno;
528		break;
529#else
530	case XATTR_POSIX_ACC :
531		res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_access,
532				value, size);
533		break;
534	case XATTR_POSIX_DEF :
535		res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_default,
536				value, size);
537		break;
538#endif
539#endif
540	case XATTR_NTFS_ATTRIB :
541		res = ntfs_get_ntfs_attrib(ni, value, size);
542		break;
543	case XATTR_NTFS_ATTRIB_BE :
544		res = ntfs_get_ntfs_attrib(ni, value, size);
545		if ((res == 4) && value) {
546			if (size >= 4)
547				fix_big_endian(value,4);
548			else
549				res = -EINVAL;
550		}
551		break;
552	case XATTR_NTFS_EFSINFO :
553		if (ni->vol->efs_raw)
554			res = ntfs_get_efs_info(ni, value, size);
555		else
556			res = -EPERM;
557		break;
558	case XATTR_NTFS_REPARSE_DATA :
559		res = ntfs_get_ntfs_reparse_data(ni, value, size);
560		break;
561	case XATTR_NTFS_OBJECT_ID :
562		res = ntfs_get_ntfs_object_id(ni, value, size);
563		break;
564	case XATTR_NTFS_DOS_NAME:
565		if (dir_ni)
566			res = ntfs_get_ntfs_dos_name(ni, dir_ni, value, size);
567		else
568			res = -errno;
569		break;
570	case XATTR_NTFS_TIMES:
571		res = ntfs_inode_get_times(ni, value, size);
572		break;
573	case XATTR_NTFS_TIMES_BE:
574		res = ntfs_inode_get_times(ni, value, size);
575		if ((res > 0) && value) {
576			for (i=0; (i+1)*sizeof(u64)<=(unsigned int)res; i++)
577				fix_big_endian(&value[i*sizeof(u64)],
578						sizeof(u64));
579		}
580		break;
581	case XATTR_NTFS_CRTIME:
582		res = ntfs_inode_get_times(ni, value,
583				(size >= sizeof(u64) ? sizeof(u64) : size));
584		break;
585	case XATTR_NTFS_CRTIME_BE:
586		res = ntfs_inode_get_times(ni, value,
587				(size >= sizeof(u64) ? sizeof(u64) : size));
588		if ((res >= (int)sizeof(u64)) && value)
589			fix_big_endian(value,sizeof(u64));
590		break;
591	case XATTR_NTFS_EA :
592		res = ntfs_get_ntfs_ea(ni, value, size);
593		break;
594	default :
595		errno = EOPNOTSUPP;
596		res = -errno;
597		break;
598	}
599	return (res);
600}
601
602/*
603 *		Set an NTFS attribute from an extended attribute
604 *
605 *	Returns 0 if successful,
606 *	        non-zero, with errno set, when fails
607 */
608
609int ntfs_xattr_system_setxattr(struct SECURITY_CONTEXT *scx,
610			enum SYSTEMXATTRS attr,
611			ntfs_inode *ni, ntfs_inode *dir_ni,
612			const char *value, size_t size, int flags)
613{
614	int res;
615	int i;
616	char buf[4*sizeof(u64)];
617#if POSIXACLS
618#if __BYTE_ORDER == __BIG_ENDIAN
619	struct POSIX_ACL *acl;
620#endif
621#endif
622
623	switch (attr) {
624	case XATTR_NTFS_ACL :
625		res = ntfs_set_ntfs_acl(scx, ni, value, size, flags);
626		break;
627#if POSIXACLS
628#if __BYTE_ORDER == __BIG_ENDIAN
629	case XATTR_POSIX_ACC :
630		acl = (struct POSIX_ACL*)ntfs_malloc(size);
631		if (acl) {
632			if (!le_acl_to_cpu((const struct LE_POSIX_ACL*)value,
633					size, acl)) {
634				res = ntfs_set_posix_acl(scx ,ni ,
635					nf_ns_xattr_posix_access,
636					(char*)acl, size, flags);
637			} else
638				res = -errno;
639			free(acl);
640		} else
641			res = -errno;
642		break;
643	case XATTR_POSIX_DEF :
644		acl = (struct POSIX_ACL*)ntfs_malloc(size);
645		if (acl) {
646			if (!le_acl_to_cpu((const struct LE_POSIX_ACL*)value,
647					size, acl)) {
648				res = ntfs_set_posix_acl(scx ,ni ,
649					nf_ns_xattr_posix_default,
650					(char*)acl, size, flags);
651			} else
652				res = -errno;
653			free(acl);
654		} else
655			res = -errno;
656		break;
657#else
658	case XATTR_POSIX_ACC :
659		res = ntfs_set_posix_acl(scx ,ni , nf_ns_xattr_posix_access,
660					value, size, flags);
661		break;
662	case XATTR_POSIX_DEF :
663		res = ntfs_set_posix_acl(scx, ni, nf_ns_xattr_posix_default,
664					value, size, flags);
665		break;
666#endif
667#endif
668	case XATTR_NTFS_ATTRIB :
669		res = ntfs_set_ntfs_attrib(ni, value, size, flags);
670		break;
671	case XATTR_NTFS_ATTRIB_BE :
672		if (value && (size >= 4)) {
673			memcpy(buf,value,4);
674			fix_big_endian(buf,4);
675			res = ntfs_set_ntfs_attrib(ni, buf, 4, flags);
676		} else
677			res = ntfs_set_ntfs_attrib(ni, value, size, flags);
678		break;
679	case XATTR_NTFS_EFSINFO :
680		if (ni->vol->efs_raw)
681			res = ntfs_set_efs_info(ni, value, size, flags);
682		else {
683			errno = EPERM;
684			res = -EPERM;
685		}
686		break;
687	case XATTR_NTFS_REPARSE_DATA :
688		res = ntfs_set_ntfs_reparse_data(ni, value, size, flags);
689		break;
690	case XATTR_NTFS_OBJECT_ID :
691		res = ntfs_set_ntfs_object_id(ni, value, size, flags);
692		break;
693	case XATTR_NTFS_DOS_NAME:
694		if (dir_ni)
695		/* warning : this closes both inodes */
696			res = ntfs_set_ntfs_dos_name(ni, dir_ni, value,
697						size, flags);
698		else {
699			errno = EINVAL;
700			res = -errno;
701		}
702		break;
703	case XATTR_NTFS_TIMES:
704		res = ntfs_inode_set_times(ni, value, size, flags);
705		break;
706	case XATTR_NTFS_TIMES_BE:
707		if (value && (size > 0) && (size <= 4*sizeof(u64))) {
708			memcpy(buf,value,size);
709			for (i=0; (i+1)*sizeof(u64)<=size; i++)
710				fix_big_endian(&buf[i*sizeof(u64)],
711						sizeof(u64));
712			res = ntfs_inode_set_times(ni, buf, size, flags);
713		} else
714			res = ntfs_inode_set_times(ni, value, size, flags);
715		break;
716	case XATTR_NTFS_CRTIME:
717		res = ntfs_inode_set_times(ni, value,
718			(size >= sizeof(u64) ? sizeof(u64) : size), flags);
719		break;
720	case XATTR_NTFS_CRTIME_BE:
721		if (value && (size >= sizeof(u64))) {
722			memcpy(buf,value,sizeof(u64));
723			fix_big_endian(buf,sizeof(u64));
724			res = ntfs_inode_set_times(ni, buf, sizeof(u64), flags);
725		} else
726			res = ntfs_inode_set_times(ni, value, size, flags);
727		break;
728	case XATTR_NTFS_EA :
729		res = ntfs_set_ntfs_ea(ni, value, size, flags);
730		break;
731	default :
732		errno = EOPNOTSUPP;
733		res = -errno;
734		break;
735	}
736	return (res);
737}
738
739int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx,
740			enum SYSTEMXATTRS attr,
741			ntfs_inode *ni, ntfs_inode *dir_ni)
742{
743	int res;
744
745	res = 0;
746	switch (attr) {
747		/*
748		 * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES
749		 * is never allowed
750		 */
751	case XATTR_NTFS_ACL :
752	case XATTR_NTFS_ATTRIB :
753	case XATTR_NTFS_ATTRIB_BE :
754	case XATTR_NTFS_EFSINFO :
755	case XATTR_NTFS_TIMES :
756	case XATTR_NTFS_TIMES_BE :
757	case XATTR_NTFS_CRTIME :
758	case XATTR_NTFS_CRTIME_BE :
759		res = -EPERM;
760		break;
761#if POSIXACLS
762	case XATTR_POSIX_ACC :
763	case XATTR_POSIX_DEF :
764		if (ni) {
765			if (!ntfs_allowed_as_owner(scx, ni)
766			   || ntfs_remove_posix_acl(scx, ni,
767					(attr == XATTR_POSIX_ACC ?
768					nf_ns_xattr_posix_access :
769					nf_ns_xattr_posix_default)))
770				res = -errno;
771		} else
772			res = -errno;
773		break;
774#endif
775	case XATTR_NTFS_REPARSE_DATA :
776		if (ni) {
777			if (!ntfs_allowed_as_owner(scx, ni)
778			    || ntfs_remove_ntfs_reparse_data(ni))
779				res = -errno;
780		} else
781			res = -errno;
782		break;
783	case XATTR_NTFS_OBJECT_ID :
784		if (ni) {
785			if (!ntfs_allowed_as_owner(scx, ni)
786			    || ntfs_remove_ntfs_object_id(ni))
787				res = -errno;
788		} else
789			res = -errno;
790		break;
791	case XATTR_NTFS_DOS_NAME:
792		if (ni && dir_ni) {
793			if (ntfs_remove_ntfs_dos_name(ni,dir_ni))
794				res = -errno;
795			/* ni and dir_ni have been closed */
796		} else
797			res = -errno;
798		break;
799	case XATTR_NTFS_EA :
800		res = ntfs_remove_ntfs_ea(ni);
801		break;
802	default :
803		errno = EOPNOTSUPP;
804		res = -errno;
805		break;
806	}
807	return (res);
808}
809