2 * xattrs.c : common functions to deal with system extended attributes
4 * Copyright (c) 2010 Jean-Pierre Andre
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.
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.
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
26 #ifdef HAVE_SETXATTR /* extended attributes support required */
57 #include "object_id.h"
63 #if __BYTE_ORDER == __BIG_ENDIAN
66 * Posix ACL structures
73 } __attribute__((__packed__
));
79 struct LE_POSIX_ACE ace
[0];
80 } __attribute__((__packed__
));
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;
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";
103 static const char nf_ns_alt_xattr_efsinfo
[] = "user.ntfs.efsinfo";
106 enum SYSTEMXATTRS xattr
;
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 */
128 * Make an integer big-endian
130 * Swap bytes on a small-endian computer and does nothing on a
131 * big-endian computer.
134 static void fix_big_endian(char *p
, int size
)
136 #if __BYTE_ORDER == __LITTLE_ENDIAN
151 #if __BYTE_ORDER == __BIG_ENDIAN
154 * Make a Posix ACL CPU endian
157 static int le_acl_to_cpu(const struct LE_POSIX_ACL
*le_acl
, size_t size
,
158 struct POSIX_ACL
*acl
)
163 acl
->version
= le_acl
->version
;
164 acl
->flags
= le_acl
->flags
;
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
);
176 * Make a Posix ACL little endian
179 int cpu_to_le_acl(const struct POSIX_ACL
*acl
, size_t size
,
180 struct LE_POSIX_ACL
*le_acl
)
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
);
201 * Determine whether an extended attribute is mapped to
202 * internal data (original name in system namespace, or renamed)
205 enum SYSTEMXATTRS
ntfs_xattr_system_type(const char *name
,
209 enum SYSTEMXATTRS ret
;
210 #ifdef XATTR_MAPPINGS
211 const struct XATTRMAPPING
*q
;
212 #endif /* XATTR_MAPPINGS */
214 p
= nf_ns_xattr_names
;
215 while (p
->name
&& strcmp(p
->name
,name
))
218 #ifdef XATTR_MAPPINGS
219 if (!p
->name
&& vol
&& vol
->xattr_mapping
) {
220 q
= vol
->xattr_mapping
;
221 while (q
&& strcmp(q
->name
,name
))
226 #else /* XATTR_MAPPINGS */
230 && !strcmp(nf_ns_alt_xattr_efsinfo
,name
))
231 ret
= XATTR_NTFS_EFSINFO
;
232 #endif /* XATTR_MAPPINGS */
236 #ifdef XATTR_MAPPINGS
239 * Basic read from a user mapping file on another volume
242 static int basicread(void *fileid
, char *buf
, size_t size
, off_t offs
__attribute__((unused
)))
244 return (read(*(int*)fileid
, buf
, size
));
249 * Read from a user mapping file on current NTFS partition
252 static int localread(void *fileid
, char *buf
, size_t size
, off_t offs
)
254 return (ntfs_attr_data_read((ntfs_inode
*)fileid
,
255 AT_UNNAMED
, 0, buf
, size
, offs
));
259 * Get a single mapping item from buffer
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
268 static struct XATTRMAPPING
*getmappingitem(FILEREADER reader
, void *fileid
,
269 off_t
*poffs
, char *buf
, int *psrc
, s64
*psize
)
276 enum SYSTEMXATTRS xattr
;
278 char maptext
[LINESZ
];
279 struct XATTRMAPPING
*item
;
285 while ((src
< *psize
)
286 && (buf
[src
] != '\n')) {
289 && (buf
[src
] != '\r')
290 && (buf
[src
] != '\t')
291 && (buf
[src
] != ' '))
292 maptext
[dst
++] = buf
[src
];
297 *psize
= reader(fileid
, buf
, (size_t)BUFSZ
, *poffs
);
305 } while (*psize
&& ((maptext
[0] == '#') || !gotend
));
306 item
= (struct XATTRMAPPING
*)NULL
;
308 /* decompose into system name and user name */
310 pu
= strchr(maptext
,':');
316 /* check name validity */
317 if ((strlen(pu
) < 6) || strncmp(pu
,"user.",5))
319 xattr
= ntfs_xattr_system_type(ps
,
321 if (xattr
== XATTR_UNMAPPED
)
325 item
= (struct XATTRMAPPING
*)ntfs_malloc(
326 sizeof(struct XATTRMAPPING
)
330 strcpy(item
->name
,pu
);
331 item
->next
= (struct XATTRMAPPING
*)NULL
;
334 ntfs_log_early_error("Bad xattr mapping item, aborting\n");
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
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.
356 static struct XATTRMAPPING
*ntfs_read_xattr_mapping(FILEREADER reader
,
360 struct XATTRMAPPING
*item
;
361 struct XATTRMAPPING
*current
;
362 struct XATTRMAPPING
*firstitem
;
363 struct XATTRMAPPING
*lastitem
;
369 firstitem
= (struct XATTRMAPPING
*)NULL
;
370 lastitem
= (struct XATTRMAPPING
*)NULL
;
372 size
= reader(fileid
, buf
, (size_t)BUFSZ
, (off_t
)0);
376 item
= getmappingitem(reader
, fileid
, &offs
,
379 /* check no double mapping */
381 for (current
=firstitem
; current
; current
=current
->next
)
382 if ((current
->xattr
== item
->xattr
)
383 || !strcmp(current
->name
,item
->name
))
387 ntfs_log_early_error("Conflicting xattr mapping ignored\n");
389 item
->next
= (struct XATTRMAPPING
*)NULL
;
391 lastitem
->next
= item
;
403 * Build the extended attribute mappings to user namespace
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
409 struct XATTRMAPPING
*ntfs_xattr_build_mapping(ntfs_volume
*vol
,
410 const char *xattrmap_path
)
412 struct XATTRMAPPING
*firstmapping
;
413 struct XATTRMAPPING
*mapping
;
419 firstmapping
= (struct XATTRMAPPING
*)NULL
;
422 xattrmap_path
= XATTRMAPPINGFILE
;
423 if (xattrmap_path
[0] == '/') {
424 fd
= open(xattrmap_path
,O_RDONLY
);
426 firstmapping
= ntfs_read_xattr_mapping(basicread
, (void*)&fd
);
431 ni
= ntfs_pathname_to_inode(vol
, NULL
, xattrmap_path
);
433 firstmapping
= ntfs_read_xattr_mapping(localread
, ni
);
434 ntfs_inode_close(ni
);
438 if (notfound
&& strcmp(xattrmap_path
, XATTRMAPPINGFILE
)) {
439 ntfs_log_early_error("Could not open \"%s\"\n",xattrmap_path
);
443 for (mapping
=firstmapping
; mapping
; mapping
=mapping
->next
)
444 if (mapping
->xattr
== XATTR_NTFS_EFSINFO
)
449 mapping
= (struct XATTRMAPPING
*)ntfs_malloc(
450 sizeof(struct XATTRMAPPING
)
451 + strlen(nf_ns_alt_xattr_efsinfo
));
453 mapping
->next
= firstmapping
;
454 mapping
->xattr
= XATTR_NTFS_EFSINFO
;
455 strcpy(mapping
->name
,nf_ns_alt_xattr_efsinfo
);
456 firstmapping
= mapping
;
459 return (firstmapping
);
462 void ntfs_xattr_free_mapping(struct XATTRMAPPING
*mapping
)
464 struct XATTRMAPPING
*p
, *q
;
474 #endif /* XATTR_MAPPINGS */
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
)
485 #if __BYTE_ORDER == __BIG_ENDIAN
486 struct POSIX_ACL
*acl
;
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.
497 case XATTR_NTFS_ACL
:
498 res
= ntfs_get_ntfs_acl(scx
, ni
, value
, size
);
501 #if __BYTE_ORDER == __BIG_ENDIAN
502 case XATTR_POSIX_ACC
:
503 acl
= (struct POSIX_ACL
*)ntfs_malloc(size
);
505 res
= ntfs_get_posix_acl(scx
, ni
,
506 nf_ns_xattr_posix_access
, (char*)acl
, size
);
508 if (cpu_to_le_acl(acl
,res
,
509 (struct LE_POSIX_ACL
*)value
))
516 case XATTR_POSIX_DEF
:
517 acl
= (struct POSIX_ACL
*)ntfs_malloc(size
);
519 res
= ntfs_get_posix_acl(scx
, ni
,
520 nf_ns_xattr_posix_default
, (char*)acl
, size
);
522 if (cpu_to_le_acl(acl
,res
,
523 (struct LE_POSIX_ACL
*)value
))
531 case XATTR_POSIX_ACC
:
532 res
= ntfs_get_posix_acl(scx
, ni
, nf_ns_xattr_posix_access
,
535 case XATTR_POSIX_DEF
:
536 res
= ntfs_get_posix_acl(scx
, ni
, nf_ns_xattr_posix_default
,
541 case XATTR_NTFS_ATTRIB
:
542 res
= ntfs_get_ntfs_attrib(ni
, value
, size
);
544 case XATTR_NTFS_ATTRIB_BE
:
545 res
= ntfs_get_ntfs_attrib(ni
, value
, size
);
546 if ((res
== 4) && value
) {
548 fix_big_endian(value
,4);
553 case XATTR_NTFS_EFSINFO
:
554 if (ni
->vol
->efs_raw
)
555 res
= ntfs_get_efs_info(ni
, value
, size
);
559 case XATTR_NTFS_REPARSE_DATA
:
560 res
= ntfs_get_ntfs_reparse_data(ni
, value
, size
);
562 case XATTR_NTFS_OBJECT_ID
:
563 res
= ntfs_get_ntfs_object_id(ni
, value
, size
);
565 case XATTR_NTFS_DOS_NAME
:
567 res
= ntfs_get_ntfs_dos_name(ni
, dir_ni
, value
, size
);
571 case XATTR_NTFS_TIMES
:
572 res
= ntfs_inode_get_times(ni
, value
, size
);
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
)],
582 case XATTR_NTFS_CRTIME
:
583 res
= ntfs_inode_get_times(ni
, value
,
584 (size
>= sizeof(u64
) ? sizeof(u64
) : size
));
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
));
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
)
607 char buf
[4*sizeof(u64
)];
609 #if __BYTE_ORDER == __BIG_ENDIAN
610 struct POSIX_ACL
*acl
;
615 case XATTR_NTFS_ACL
:
616 res
= ntfs_set_ntfs_acl(scx
, ni
, value
, size
, flags
);
619 #if __BYTE_ORDER == __BIG_ENDIAN
620 case XATTR_POSIX_ACC
:
621 acl
= (struct POSIX_ACL
*)ntfs_malloc(size
);
623 if (!le_acl_to_cpu((const struct LE_POSIX_ACL
*)value
,
625 res
= ntfs_set_posix_acl(scx
,ni
,
626 nf_ns_xattr_posix_access
,
627 (char*)acl
, size
, flags
);
634 case XATTR_POSIX_DEF
:
635 acl
= (struct POSIX_ACL
*)ntfs_malloc(size
);
637 if (!le_acl_to_cpu((const struct LE_POSIX_ACL
*)value
,
639 res
= ntfs_set_posix_acl(scx
,ni
,
640 nf_ns_xattr_posix_default
,
641 (char*)acl
, size
, flags
);
649 case XATTR_POSIX_ACC
:
650 res
= ntfs_set_posix_acl(scx
,ni
, nf_ns_xattr_posix_access
,
653 case XATTR_POSIX_DEF
:
654 res
= ntfs_set_posix_acl(scx
, ni
, nf_ns_xattr_posix_default
,
659 case XATTR_NTFS_ATTRIB
:
660 res
= ntfs_set_ntfs_attrib(ni
, value
, size
, flags
);
662 case XATTR_NTFS_ATTRIB_BE
:
663 if (value
&& (size
>= 4)) {
665 fix_big_endian(buf
,4);
666 res
= ntfs_set_ntfs_attrib(ni
, buf
, 4, flags
);
668 res
= ntfs_set_ntfs_attrib(ni
, value
, size
, flags
);
670 case XATTR_NTFS_EFSINFO
:
671 if (ni
->vol
->efs_raw
)
672 res
= ntfs_set_efs_info(ni
, value
, size
, flags
);
676 case XATTR_NTFS_REPARSE_DATA
:
677 res
= ntfs_set_ntfs_reparse_data(ni
, value
, size
, flags
);
679 case XATTR_NTFS_OBJECT_ID
:
680 res
= ntfs_set_ntfs_object_id(ni
, value
, size
, flags
);
682 case XATTR_NTFS_DOS_NAME
:
684 /* warning : this closes both inodes */
685 res
= ntfs_set_ntfs_dos_name(ni
, dir_ni
, value
,
690 case XATTR_NTFS_TIMES
:
691 res
= ntfs_inode_set_times(ni
, value
, size
, flags
);
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
)],
699 res
= ntfs_inode_set_times(ni
, buf
, size
, flags
);
701 res
= ntfs_inode_set_times(ni
, value
, size
, flags
);
703 case XATTR_NTFS_CRTIME
:
704 res
= ntfs_inode_set_times(ni
, value
,
705 (size
>= sizeof(u64
) ? sizeof(u64
) : size
), flags
);
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
);
713 res
= ntfs_inode_set_times(ni
, value
, size
, flags
);
723 int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT
*scx
,
724 enum SYSTEMXATTRS attr
,
725 ntfs_inode
*ni
, ntfs_inode
*dir_ni
)
732 * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES
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
:
746 case XATTR_POSIX_ACC
:
747 case XATTR_POSIX_DEF
:
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
)))
759 case XATTR_NTFS_REPARSE_DATA
:
761 if (!ntfs_allowed_as_owner(scx
, ni
)
762 || ntfs_remove_ntfs_reparse_data(ni
))
767 case XATTR_NTFS_OBJECT_ID
:
769 if (!ntfs_allowed_as_owner(scx
, ni
)
770 || ntfs_remove_ntfs_object_id(ni
))
775 case XATTR_NTFS_DOS_NAME
:
777 if (ntfs_remove_ntfs_dos_name(ni
,dir_ni
))
779 /* ni and dir_ni have been closed */
791 #endif /* HAVE_SETXATTR */