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