2 * Copyright (c) 1999-2004
3 * Stelian Pop <stelian@popies.net>, 1999-2004
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 static const char rcsid
[] =
32 "$Id: xattr.c,v 1.1 2005/05/02 15:10:47 stelian Exp $";
36 #include <compatlfs.h>
37 #include <compaterr.h>
38 #include <sys/types.h>
44 #include <bsdcompat.h>
45 #include <protocols/dumprestore.h>
48 #include "pathnames.h"
51 * Data structures below taken from the kernel
54 /* Maximum number of references to one attribute block */
55 #define EXT2_XATTR_REFCOUNT_MAX 1024
58 #define EXT2_XATTR_INDEX_MAX 10
59 #define EXT2_XATTR_INDEX_USER 1
60 #define EXT2_XATTR_INDEX_POSIX_ACL_ACCESS 2
61 #define EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT 3
62 #define EXT2_XATTR_INDEX_TRUSTED 4
63 #define EXT2_XATTR_INDEX_LUSTRE 5
64 #define EXT2_XATTR_INDEX_SECURITY 6
66 struct ext2_xattr_header
{
67 u_int32_t h_magic
; /* magic number for identification */
68 u_int32_t h_refcount
; /* reference count */
69 u_int32_t h_blocks
; /* number of disk blocks used */
70 u_int32_t h_hash
; /* hash value of all attributes */
71 u_int32_t h_reserved
[4]; /* zero right now */
74 struct ext3_xattr_ibody_header
{
75 u_int32_t h_magic
; /* magic number for identification */
78 struct ext2_xattr_entry
{
79 u_char e_name_len
; /* length of name */
80 u_char e_name_index
; /* attribute name index */
81 u_int16_t e_value_offs
; /* offset in disk block of value */
82 u_int32_t e_value_block
; /* disk block attribute is stored on (n/i) */
83 u_int32_t e_value_size
; /* size of attribute value */
84 u_int32_t e_hash
; /* hash value of name and value */
85 char e_name
[0]; /* attribute name */
88 #define EXT2_XATTR_PAD_BITS 2
89 #define EXT2_XATTR_PAD (1<<EXT2_XATTR_PAD_BITS)
90 #define EXT2_XATTR_ROUND (EXT2_XATTR_PAD-1)
91 #define EXT2_XATTR_LEN(name_len) \
92 (((name_len) + EXT2_XATTR_ROUND + \
93 sizeof(struct ext2_xattr_entry)) & ~EXT2_XATTR_ROUND)
94 #define EXT2_XATTR_NEXT(entry) \
95 ( (struct ext2_xattr_entry *)( \
96 (char *)(entry) + EXT2_XATTR_LEN((entry)->e_name_len)) )
97 #define EXT3_XATTR_SIZE(size) \
98 (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND)
100 #define HDR(buffer) ((struct ext2_xattr_header *)(buffer))
101 #define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr))
102 #define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
104 #define BFIRST(buffer) ENTRY(HDR(buffer)+1)
105 #define IFIRST(buffer) ENTRY(((struct ext3_xattr_ibody_header *)(buffer))+1)
107 #define FIRST_ENTRY(buffer) \
108 ((HDR(buffer)->h_magic == EXT2_XATTR_MAGIC2) ? \
113 * On-block xattr value offsets start at the beginning of the block, but
114 * on-inode xattr value offsets start after the initial header
115 * (ext3_xattr_ibody_header).
117 #define VALUE_OFFSET(buffer, entry) \
118 (((HDR(buffer)->h_magic == EXT2_XATTR_MAGIC2) ? \
119 (entry)->e_value_offs + sizeof(struct ext3_xattr_ibody_header) : \
120 (entry)->e_value_offs))
123 * xattr syscalls do not exist yet in libc, get our own copy here,
124 * taken from libattr.
126 #if defined (__i386__)
127 # define HAVE_XATTR_SYSCALLS 1
128 # define __NR_lsetxattr 227
129 # define __NR_lgetxattr 230
130 # define __NR_llistxattr 233
131 #elif defined (__sparc__)
132 # define HAVE_XATTR_SYSCALLS 1
133 # define __NR_lsetxattr 170
134 # define __NR_lgetxattr 173
135 # define __NR_llistxattr 179
136 #elif defined (__ia64__)
137 # define HAVE_XATTR_SYSCALLS 1
138 # define __NR_lsetxattr 1218
139 # define __NR_lgetxattr 1221
140 # define __NR_llistxattr 1224
141 #elif defined (__powerpc__)
142 # define HAVE_XATTR_SYSCALLS 1
143 # define __NR_lsetxattr 210
144 # define __NR_lgetxattr 213
145 # define __NR_llistxattr 216
146 #elif defined (__x86_64__)
147 # define HAVE_XATTR_SYSCALLS 1
148 # define __NR_lsetxattr 189
149 # define __NR_lgetxattr 192
150 # define __NR_llistxattr 195
151 #elif defined (__s390__)
152 # define HAVE_XATTR_SYSCALLS 1
153 # define __NR_lsetxattr 225
154 # define __NR_lgetxattr 228
155 # define __NR_llistxattr 231
156 #elif defined (__arm__)
157 # define HAVE_XATTR_SYSCALLS 1
158 # define __NR_SYSCALL_BASE 0x900000
159 # define __NR_lsetxattr (__NR_SYSCALL_BASE+227)
160 # define __NR_lgetxattr (__NR_SYSCALL_BASE+230)
161 # define __NR_llistxattr (__NR_SYSCALL_BASE+233)
162 #elif defined (__mips64__)
163 # define HAVE_XATTR_SYSCALLS 1
164 # define __NR_Linux 5000
165 # define __NR_lsetxattr (__NR_Linux + 218)
166 # define __NR_lgetxattr (__NR_Linux + 221)
167 # define __NR_llistxattr (__NR_Linux + 224)
168 #elif defined (__mips__)
169 # define HAVE_XATTR_SYSCALLS 1
170 # define __NR_Linux 4000
171 # define __NR_lsetxattr (__NR_Linux + 225)
172 # define __NR_lgetxattr (__NR_Linux + 228)
173 # define __NR_llistxattr (__NR_Linux + 231)
174 #elif defined (__alpha__)
175 # define HAVE_XATTR_SYSCALLS 1
176 # define __NR_lsetxattr 383
177 # define __NR_lgetxattr 386
178 # define __NR_llistxattr 389
179 #elif defined (__mc68000__)
180 # define HAVE_XATTR_SYSCALLS 1
181 # define __NR_lsetxattr 224
182 # define __NR_lgetxattr 227
183 # define __NR_llistxattr 230
185 # warning "Extended attribute syscalls undefined for this architecture"
186 # define HAVE_XATTR_SYSCALLS 0
189 #if HAVE_XATTR_SYSCALLS
190 # define SYSCALL(args...) syscall(args)
192 # define SYSCALL(args...) ( errno = ENOSYS, -1 )
195 static int lsetxattr
__P((const char *, const char *, void *, size_t, int));
196 static ssize_t lgetxattr
__P((const char *, const char *, void *, size_t));
197 static ssize_t llistxattr
__P((const char *, char *, size_t));
198 static int xattr_cb_list
__P((char *, char *, int, void *));
199 static int xattr_cb_set
__P((char *, char *, int, void *));
200 static int xattr_cb_compare
__P((char *, char *, int, void *));
201 static int xattr_verify
__P((char *));
202 static int xattr_count
__P((char *, int *));
203 static int xattr_walk
__P((char *, int (*)(char *, char *, int, void *), void *));
206 lsetxattr(const char *path
, const char *name
, void *value
, size_t size
, int flags
)
208 return SYSCALL(__NR_lsetxattr
, path
, name
, value
, size
, flags
);
212 lgetxattr(const char *path
, const char *name
, void *value
, size_t size
)
214 return SYSCALL(__NR_lgetxattr
, path
, name
, value
, size
);
218 llistxattr(const char *path
, char *list
, size_t size
)
220 return SYSCALL(__NR_llistxattr
, path
, list
, size
);
224 * Dump code starts here :)
228 xattr_cb_list(char *name
, char *value
, int valuelen
, void *private)
230 value
[valuelen
] = '\0';
231 printf("EA: %s:%s\n", name
, value
);
237 xattr_cb_set(char *name
, char *value
, int valuelen
, void *private)
239 char *path
= (char *)private;
241 if (lsetxattr(path
, name
, value
, valuelen
, 0) < 0) {
242 warn("lsetxattr %s failed", path
);
249 xattr_cb_compare(char *name
, char *value
, int valuelen
, void *private)
251 char *path
= (char *)private;
252 char valuef
[XATTR_MAXSIZE
];
255 valuesz
= lgetxattr(path
, name
, valuef
, XATTR_MAXSIZE
);
257 warn("%s: lgetxattr failed\n", path
);
261 if (valuesz
!= valuelen
) {
262 fprintf(stderr
, "%s: EA %s value changed\n", path
, value
);
266 if (memcmp(value
, valuef
, valuelen
)) {
267 fprintf(stderr
, "%s: EA %s value changed\n", path
, value
);
275 xattr_verify(char *buffer
)
277 struct ext2_xattr_entry
*entry
;
280 end
= buffer
+ XATTR_MAXSIZE
;
283 swabst("4i", (u_char
*)buffer
);
285 if (HDR(buffer
)->h_magic
!= EXT2_XATTR_MAGIC
&&
286 HDR(buffer
)->h_magic
!= EXT2_XATTR_MAGIC2
) {
287 fprintf(stderr
, "error in EA block 1\n");
288 fprintf(stderr
, "magic = %x\n", HDR(buffer
)->h_magic
);
293 /* check the on-disk data structure */
294 entry
= FIRST_ENTRY(buffer
);
296 swabst("2b1s3i", (u_char
*)entry
);
297 while (!IS_LAST_ENTRY(entry
)) {
298 struct ext2_xattr_entry
*next
= EXT2_XATTR_NEXT(entry
);
300 if ((char *)next
>= end
) {
301 fprintf(stderr
, "error in EA block\n");
306 swabst("2b1s3i", (u_char
*)entry
);
312 xattr_count(char *buffer
, int *count
)
314 struct ext2_xattr_entry
*entry
;
317 /* list the attribute names */
318 for (entry
= FIRST_ENTRY(buffer
); !IS_LAST_ENTRY(entry
);
319 entry
= EXT2_XATTR_NEXT(entry
))
327 xattr_walk(char *buffer
, int (*xattr_cb
)(char *, char *, int, void *), void *private)
329 struct ext2_xattr_entry
*entry
;
331 /* list the attribute names */
332 for (entry
= FIRST_ENTRY(buffer
); !IS_LAST_ENTRY(entry
);
333 entry
= EXT2_XATTR_NEXT(entry
)) {
334 char name
[XATTR_MAXSIZE
], value
[XATTR_MAXSIZE
];
337 switch (entry
->e_name_index
) {
338 case EXT2_XATTR_INDEX_USER
:
339 strcpy(name
, "user.");
341 case EXT2_XATTR_INDEX_POSIX_ACL_ACCESS
:
342 case EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT
:
343 strcpy(name
, "system.");
345 case EXT2_XATTR_INDEX_TRUSTED
:
346 strcpy(name
, "trusted.");
348 case EXT2_XATTR_INDEX_LUSTRE
:
349 strcpy(name
, "lustre.");
351 case EXT2_XATTR_INDEX_SECURITY
:
352 strcpy(name
, "security.");
355 fprintf(stderr
, "Unknown EA index\n");
360 memcpy(name
+ off
, entry
->e_name
, entry
->e_name_len
);
361 name
[off
+ entry
->e_name_len
] = '\0';
364 memcpy(value
, buffer
+ VALUE_OFFSET(buffer
, entry
), entry
->e_value_size
);
366 if (xattr_cb(name
, value
, entry
->e_value_size
, private) != GOOD
)
374 xattr_compare(char *path
, char *buffer
)
377 char *names
= NULL
, *end_names
, *name
;
379 countf
= llistxattr(path
, NULL
, 0);
381 warn("%s: llistxattr failed", path
);
385 names
= malloc(countf
+ 1);
387 warn("%s: llistxattr failed", path
);
391 countf
= llistxattr(path
, names
, countf
);
393 warn("%s: llistxattr failed", path
);
398 names
[countf
] = '\0';
399 end_names
= names
+ countf
;
402 for (name
= names
; name
!= end_names
; name
= strchr(name
, '\0') + 1) {
411 if (xattr_verify(buffer
) == FAIL
)
414 if (xattr_count(buffer
, &countt
) == FAIL
)
420 if (countf
!= countt
) {
421 fprintf(stderr
, "%s: EA count changed from %d to %d\n", path
, countt
, countf
);
428 return xattr_walk(buffer
, xattr_cb_compare
, path
);
432 xattr_extract(char *path
, char *buffer
)
435 fprintf(stderr
, "xattr_extract(%s)\n", path
);
436 xattr_walk(buffer
, xattr_cb_list
, NULL
);
439 if (xattr_verify(buffer
) == FAIL
)
442 return xattr_walk(buffer
, xattr_cb_set
, path
);