xref: /freebsd/sys/fs/ext2fs/ext2_extattr.c (revision cd3acfe7)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2017, Fedor Uporov
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/types.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/vnode.h>
37 #include <sys/bio.h>
38 #include <sys/buf.h>
39 #include <sys/endian.h>
40 #include <sys/conf.h>
41 #include <sys/extattr.h>
42 #include <sys/sdt.h>
43 
44 #include <fs/ext2fs/fs.h>
45 #include <fs/ext2fs/ext2fs.h>
46 #include <fs/ext2fs/inode.h>
47 #include <fs/ext2fs/ext2_dinode.h>
48 #include <fs/ext2fs/ext2_mount.h>
49 #include <fs/ext2fs/ext2_extattr.h>
50 #include <fs/ext2fs/ext2_extern.h>
51 
52 SDT_PROVIDER_DECLARE(ext2fs);
53 /*
54  * ext2fs trace probe:
55  * arg0: verbosity. Higher numbers give more verbose messages
56  * arg1: Textual message
57  */
58 SDT_PROBE_DEFINE2(ext2fs, , trace, extattr, "int", "char*");
59 
60 static int
61 ext2_extattr_attrnamespace_to_bsd(int attrnamespace)
62 {
63 
64 	switch (attrnamespace) {
65 	case EXT4_XATTR_INDEX_SYSTEM:
66 		return (EXTATTR_NAMESPACE_SYSTEM);
67 
68 	case EXT4_XATTR_INDEX_USER:
69 		return (EXTATTR_NAMESPACE_USER);
70 
71 	case EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT:
72 		return (POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE);
73 
74 	case EXT4_XATTR_INDEX_POSIX_ACL_ACCESS:
75 		return (POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE);
76 	}
77 
78 	return (EXTATTR_NAMESPACE_EMPTY);
79 }
80 
81 static const char *
82 ext2_extattr_name_to_bsd(int attrnamespace, const char *name, int* name_len)
83 {
84 
85 	if (attrnamespace == EXT4_XATTR_INDEX_SYSTEM)
86 		return (name);
87 	else if (attrnamespace == EXT4_XATTR_INDEX_USER)
88 		return (name);
89 	else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT) {
90 		*name_len = strlen(POSIX1E_ACL_DEFAULT_EXTATTR_NAME);
91 		return (POSIX1E_ACL_DEFAULT_EXTATTR_NAME);
92 	} else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_ACCESS) {
93 		*name_len = strlen(POSIX1E_ACL_ACCESS_EXTATTR_NAME);
94 		return (POSIX1E_ACL_ACCESS_EXTATTR_NAME);
95 	}
96 
97 	/*
98 	 * XXX: Not all linux namespaces are mapped to bsd for now,
99 	 * return NULL, which will be converted to ENOTSUP on upper layer.
100 	 */
101 	SDT_PROBE2(ext2fs, , trace, extattr, 1,
102 	    "can not convert ext2fs name to bsd namespace");
103 
104 	return (NULL);
105 }
106 
107 static int
108 ext2_extattr_attrnamespace_to_linux(int attrnamespace, const char *name)
109 {
110 
111 	if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE &&
112 	    !strcmp(name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME))
113 		return (EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT);
114 
115 	if (attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE &&
116 	    !strcmp(name, POSIX1E_ACL_ACCESS_EXTATTR_NAME))
117 		return (EXT4_XATTR_INDEX_POSIX_ACL_ACCESS);
118 
119 	switch (attrnamespace) {
120 	case EXTATTR_NAMESPACE_SYSTEM:
121 		return (EXT4_XATTR_INDEX_SYSTEM);
122 
123 	case EXTATTR_NAMESPACE_USER:
124 		return (EXT4_XATTR_INDEX_USER);
125 	}
126 
127 	/*
128 	 * In this case namespace conversion should be unique,
129 	 * so this point is unreachable.
130 	 */
131 	return (-1);
132 }
133 
134 static const char *
135 ext2_extattr_name_to_linux(int attrnamespace, const char *name)
136 {
137 
138 	if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE ||
139 	    attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE)
140 		return ("");
141 	else
142 		return (name);
143 }
144 
145 int
146 ext2_extattr_valid_attrname(int attrnamespace, const char *attrname)
147 {
148 	if (attrnamespace == EXTATTR_NAMESPACE_EMPTY)
149 		return (EINVAL);
150 
151 	if (strlen(attrname) == 0)
152 		return (EINVAL);
153 
154 	if (strlen(attrname) + 1 > EXT2_EXTATTR_NAMELEN_MAX)
155 		return (ENAMETOOLONG);
156 
157 	return (0);
158 }
159 
160 static int
161 ext2_extattr_check(struct ext2fs_extattr_entry *entry, char *end)
162 {
163 	struct ext2fs_extattr_entry *next;
164 
165 	while (!EXT2_IS_LAST_ENTRY(entry)) {
166 		next = EXT2_EXTATTR_NEXT(entry);
167 		if ((char *)next >= end)
168 			return (EIO);
169 
170 		entry = next;
171 	}
172 
173 	return (0);
174 }
175 
176 static int
177 ext2_extattr_block_check(struct inode *ip, struct buf *bp)
178 {
179 	struct ext2fs_extattr_header *header;
180 	int error;
181 
182 	header = (struct ext2fs_extattr_header *)bp->b_data;
183 
184 	error = ext2_extattr_check(EXT2_IFIRST(header),
185 	    bp->b_data + bp->b_bufsize);
186 	if (error)
187 		return (error);
188 
189 	return (ext2_extattr_blk_csum_verify(ip, bp));
190 }
191 
192 int
193 ext2_extattr_inode_list(struct inode *ip, int attrnamespace,
194     struct uio *uio, size_t *size)
195 {
196 	struct m_ext2fs *fs;
197 	struct buf *bp;
198 	struct ext2fs_extattr_dinode_header *header;
199 	struct ext2fs_extattr_entry *entry;
200 	const char *attr_name;
201 	int name_len;
202 	int error;
203 
204 	fs = ip->i_e2fs;
205 
206 	if ((error = bread(ip->i_devvp,
207 	    fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
208 	    (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
209 		brelse(bp);
210 		return (error);
211 	}
212 
213 	struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
214 	    ((char *)bp->b_data +
215 	    EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
216 
217 	/* Check attributes magic value */
218 	header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
219 	    E2FS_REV0_INODE_SIZE + le16toh(dinode->e2di_extra_isize));
220 
221 	if (le32toh(header->h_magic) != EXTATTR_MAGIC) {
222 		brelse(bp);
223 		return (0);
224 	}
225 
226 	error = ext2_extattr_check(EXT2_IFIRST(header),
227 	    (char *)dinode + EXT2_INODE_SIZE(fs));
228 	if (error) {
229 		brelse(bp);
230 		return (error);
231 	}
232 
233 	for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
234 	    entry = EXT2_EXTATTR_NEXT(entry)) {
235 		if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
236 		    attrnamespace)
237 			continue;
238 
239 		name_len = entry->e_name_len;
240 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
241 		    entry->e_name, &name_len);
242 		if (!attr_name) {
243 			brelse(bp);
244 			return (ENOTSUP);
245 		}
246 
247 		if (size != NULL)
248 			*size += name_len + 1;
249 
250 		if (uio != NULL) {
251 			char *name = malloc(name_len + 1, M_TEMP, M_WAITOK);
252 			name[0] = name_len;
253 			memcpy(&name[1], attr_name, name_len);
254 			error = uiomove(name, name_len + 1, uio);
255 			free(name, M_TEMP);
256 			if (error)
257 				break;
258 		}
259 	}
260 
261 	brelse(bp);
262 
263 	return (error);
264 }
265 
266 int
267 ext2_extattr_block_list(struct inode *ip, int attrnamespace,
268     struct uio *uio, size_t *size)
269 {
270 	struct m_ext2fs *fs;
271 	struct buf *bp;
272 	struct ext2fs_extattr_header *header;
273 	struct ext2fs_extattr_entry *entry;
274 	const char *attr_name;
275 	int name_len;
276 	int error;
277 
278 	fs = ip->i_e2fs;
279 
280 	error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
281 	    fs->e2fs_bsize, NOCRED, &bp);
282 	if (error) {
283 		return (error);
284 	}
285 
286 	/* Check attributes magic value */
287 	header = EXT2_HDR(bp);
288 	if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
289 	    le32toh(header->h_blocks) != 1) {
290 		brelse(bp);
291 		return (EINVAL);
292 	}
293 
294 	error = ext2_extattr_block_check(ip, bp);
295 	if (error) {
296 		brelse(bp);
297 		return (error);
298 	}
299 
300 	for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
301 	    entry = EXT2_EXTATTR_NEXT(entry)) {
302 		if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
303 		    attrnamespace)
304 			continue;
305 
306 		name_len = entry->e_name_len;
307 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
308 		    entry->e_name, &name_len);
309 		if (!attr_name) {
310 			brelse(bp);
311 			return (ENOTSUP);
312 		}
313 
314 		if (size != NULL)
315 			*size += name_len + 1;
316 
317 		if (uio != NULL) {
318 			char *name = malloc(name_len + 1, M_TEMP, M_WAITOK);
319 			name[0] = name_len;
320 			memcpy(&name[1], attr_name, name_len);
321 			error = uiomove(name, name_len + 1, uio);
322 			free(name, M_TEMP);
323 			if (error)
324 				break;
325 		}
326 	}
327 
328 	brelse(bp);
329 
330 	return (error);
331 }
332 
333 int
334 ext2_extattr_inode_get(struct inode *ip, int attrnamespace,
335     const char *name, struct uio *uio, size_t *size)
336 {
337 	struct m_ext2fs *fs;
338 	struct buf *bp;
339 	struct ext2fs_extattr_dinode_header *header;
340 	struct ext2fs_extattr_entry *entry;
341 	const char *attr_name;
342 	int name_len;
343 	int error;
344 
345 	fs = ip->i_e2fs;
346 
347 	if ((error = bread(ip->i_devvp,
348 	    fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
349 	    (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
350 		brelse(bp);
351 		return (error);
352 	}
353 
354 	struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
355 	    ((char *)bp->b_data +
356 	    EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
357 
358 	/* Check attributes magic value */
359 	header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
360 	    E2FS_REV0_INODE_SIZE + le16toh(dinode->e2di_extra_isize));
361 
362 	if (le32toh(header->h_magic) != EXTATTR_MAGIC) {
363 		brelse(bp);
364 		return (ENOATTR);
365 	}
366 
367 	error = ext2_extattr_check(EXT2_IFIRST(header),
368 	    (char *)dinode + EXT2_INODE_SIZE(fs));
369 	if (error) {
370 		brelse(bp);
371 		return (error);
372 	}
373 
374 	for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
375 	    entry = EXT2_EXTATTR_NEXT(entry)) {
376 		if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
377 		    attrnamespace)
378 			continue;
379 
380 		name_len = entry->e_name_len;
381 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
382 		    entry->e_name, &name_len);
383 		if (!attr_name) {
384 			brelse(bp);
385 			return (ENOTSUP);
386 		}
387 
388 		if (strlen(name) == name_len &&
389 		    0 == strncmp(attr_name, name, name_len)) {
390 			if (size != NULL)
391 				*size += le32toh(entry->e_value_size);
392 
393 			if (uio != NULL)
394 				error = uiomove(((char *)EXT2_IFIRST(header)) +
395 				    le16toh(entry->e_value_offs),
396 				    le32toh(entry->e_value_size), uio);
397 
398 			brelse(bp);
399 			return (error);
400 		}
401 	 }
402 
403 	brelse(bp);
404 
405 	return (ENOATTR);
406 }
407 
408 int
409 ext2_extattr_block_get(struct inode *ip, int attrnamespace,
410     const char *name, struct uio *uio, size_t *size)
411 {
412 	struct m_ext2fs *fs;
413 	struct buf *bp;
414 	struct ext2fs_extattr_header *header;
415 	struct ext2fs_extattr_entry *entry;
416 	const char *attr_name;
417 	int name_len;
418 	int error;
419 
420 	fs = ip->i_e2fs;
421 
422 	error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
423 	    fs->e2fs_bsize, NOCRED, &bp);
424 	if (error) {
425 		return (error);
426 	}
427 
428 	/* Check attributes magic value */
429 	header = EXT2_HDR(bp);
430 	if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
431 	    le32toh(header->h_blocks) != 1) {
432 		brelse(bp);
433 		return (EINVAL);
434 	}
435 
436 	error = ext2_extattr_block_check(ip, bp);
437 	if (error) {
438 		brelse(bp);
439 		return (error);
440 	}
441 
442 	for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
443 	    entry = EXT2_EXTATTR_NEXT(entry)) {
444 		if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
445 		    attrnamespace)
446 			continue;
447 
448 		name_len = entry->e_name_len;
449 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
450 		    entry->e_name, &name_len);
451 		if (!attr_name) {
452 			brelse(bp);
453 			return (ENOTSUP);
454 		}
455 
456 		if (strlen(name) == name_len &&
457 		    0 == strncmp(attr_name, name, name_len)) {
458 			if (size != NULL)
459 				*size += le32toh(entry->e_value_size);
460 
461 			if (uio != NULL)
462 				error = uiomove(bp->b_data +
463 				    le16toh(entry->e_value_offs),
464 				    le32toh(entry->e_value_size), uio);
465 
466 			brelse(bp);
467 			return (error);
468 		}
469 	 }
470 
471 	brelse(bp);
472 
473 	return (ENOATTR);
474 }
475 
476 static uint16_t
477 ext2_extattr_delete_value(char *off,
478     struct ext2fs_extattr_entry *first_entry,
479     struct ext2fs_extattr_entry *entry, char *end)
480 {
481 	uint16_t min_offs;
482 	struct ext2fs_extattr_entry *next;
483 
484 	min_offs = end - off;
485 	next = first_entry;
486 	while (!EXT2_IS_LAST_ENTRY(next)) {
487 		if (min_offs > le16toh(next->e_value_offs) &&
488 		    le16toh(next->e_value_offs) > 0)
489 			min_offs = le16toh(next->e_value_offs);
490 
491 		next = EXT2_EXTATTR_NEXT(next);
492 	}
493 
494 	if (entry->e_value_size == 0)
495 		return (min_offs);
496 
497 	memmove(off + min_offs + EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size)),
498 	    off + min_offs, le16toh(entry->e_value_offs) - min_offs);
499 
500 	/* Adjust all value offsets */
501 	next = first_entry;
502 	while (!EXT2_IS_LAST_ENTRY(next))
503 	{
504 		if (le16toh(next->e_value_offs) > 0 &&
505 		    le16toh(next->e_value_offs) < le16toh(entry->e_value_offs))
506 			next->e_value_offs = htole16(le16toh(next->e_value_offs) +
507 			    EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size)));
508 
509 		next = EXT2_EXTATTR_NEXT(next);
510 	}
511 
512 	min_offs += EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size));
513 
514 	return (min_offs);
515 }
516 
517 static void
518 ext2_extattr_delete_entry(char *off,
519     struct ext2fs_extattr_entry *first_entry,
520     struct ext2fs_extattr_entry *entry, char *end)
521 {
522 	char *pad;
523 	struct ext2fs_extattr_entry *next;
524 
525 	/* Clean entry value */
526 	ext2_extattr_delete_value(off, first_entry, entry, end);
527 
528 	/* Clean the entry */
529 	next = first_entry;
530 	while (!EXT2_IS_LAST_ENTRY(next))
531 		next = EXT2_EXTATTR_NEXT(next);
532 
533 	pad = (char*)next + sizeof(uint32_t);
534 
535 	memmove(entry, (char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len),
536 	    pad - ((char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len)));
537 }
538 
539 int
540 ext2_extattr_inode_delete(struct inode *ip, int attrnamespace, const char *name)
541 {
542 	struct m_ext2fs *fs;
543 	struct buf *bp;
544 	struct ext2fs_extattr_dinode_header *header;
545 	struct ext2fs_extattr_entry *entry;
546 	const char *attr_name;
547 	int name_len;
548 	int error;
549 
550 	fs = ip->i_e2fs;
551 
552 	if ((error = bread(ip->i_devvp,
553 	    fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
554 	    (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
555 		brelse(bp);
556 		return (error);
557 	}
558 
559 	struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
560 	    ((char *)bp->b_data +
561 	    EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
562 
563 	/* Check attributes magic value */
564 	header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
565 	    E2FS_REV0_INODE_SIZE + le16toh(dinode->e2di_extra_isize));
566 
567 	if (le32toh(header->h_magic) != EXTATTR_MAGIC) {
568 		brelse(bp);
569 		return (ENOATTR);
570 	}
571 
572 	error = ext2_extattr_check(EXT2_IFIRST(header),
573 	    (char *)dinode + EXT2_INODE_SIZE(fs));
574 	if (error) {
575 		brelse(bp);
576 		return (error);
577 	}
578 
579 	/* If I am last entry, just make magic zero */
580 	entry = EXT2_IFIRST(header);
581 	if ((EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry))) &&
582 	    (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
583 	    attrnamespace)) {
584 
585 		name_len = entry->e_name_len;
586 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
587 		    entry->e_name, &name_len);
588 		if (!attr_name) {
589 			brelse(bp);
590 			return (ENOTSUP);
591 		}
592 
593 		if (strlen(name) == name_len &&
594 		    0 == strncmp(attr_name, name, name_len)) {
595 			memset(header, 0, sizeof(struct ext2fs_extattr_dinode_header));
596 
597 			return (bwrite(bp));
598 		}
599 	}
600 
601 	for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
602 	    entry = EXT2_EXTATTR_NEXT(entry)) {
603 		if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
604 		    attrnamespace)
605 			continue;
606 
607 		name_len = entry->e_name_len;
608 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
609 		    entry->e_name, &name_len);
610 		if (!attr_name) {
611 			brelse(bp);
612 			return (ENOTSUP);
613 		}
614 
615 		if (strlen(name) == name_len &&
616 		    0 == strncmp(attr_name, name, name_len)) {
617 			ext2_extattr_delete_entry((char *)EXT2_IFIRST(header),
618 			    EXT2_IFIRST(header), entry,
619 			    (char *)dinode + EXT2_INODE_SIZE(fs));
620 
621 			return (bwrite(bp));
622 		}
623 	}
624 
625 	brelse(bp);
626 
627 	return (ENOATTR);
628 }
629 
630 static int
631 ext2_extattr_block_clone(struct inode *ip, struct buf **bpp)
632 {
633 	struct m_ext2fs *fs;
634 	struct buf *sbp;
635 	struct buf *cbp;
636 	struct ext2fs_extattr_header *header;
637 	uint64_t facl;
638 
639 	fs = ip->i_e2fs;
640 	sbp = *bpp;
641 
642 	header = EXT2_HDR(sbp);
643 	if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
644 	    le32toh(header->h_refcount) == 1)
645 		return (EINVAL);
646 
647 	facl = ext2_alloc_meta(ip);
648 	if (!facl)
649 		return (ENOSPC);
650 
651 	cbp = getblk(ip->i_devvp, fsbtodb(fs, facl), fs->e2fs_bsize, 0, 0, 0);
652 	if (!cbp) {
653 		ext2_blkfree(ip, facl, fs->e2fs_bsize);
654 		return (EIO);
655 	}
656 
657 	memcpy(cbp->b_data, sbp->b_data, fs->e2fs_bsize);
658 	header->h_refcount = htole32(le32toh(header->h_refcount) - 1);
659 	bwrite(sbp);
660 
661 	ip->i_facl = facl;
662 	ext2_update(ip->i_vnode, 1);
663 
664 	header = EXT2_HDR(cbp);
665 	header->h_refcount = htole32(1);
666 
667 	*bpp = cbp;
668 
669 	return (0);
670 }
671 
672 int
673 ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name)
674 {
675 	struct m_ext2fs *fs;
676 	struct buf *bp;
677 	struct ext2fs_extattr_header *header;
678 	struct ext2fs_extattr_entry *entry;
679 	const char *attr_name;
680 	int name_len;
681 	int error;
682 
683 	fs = ip->i_e2fs;
684 
685 	error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
686 	    fs->e2fs_bsize, NOCRED, &bp);
687 	if (error) {
688 		return (error);
689 	}
690 
691 	/* Check attributes magic value */
692 	header = EXT2_HDR(bp);
693 	if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
694 	    le32toh(header->h_blocks) != 1) {
695 		brelse(bp);
696 		return (EINVAL);
697 	}
698 
699 	error = ext2_extattr_block_check(ip, bp);
700 	if (error) {
701 		brelse(bp);
702 		return (error);
703 	}
704 
705 	if (le32toh(header->h_refcount) > 1) {
706 		error = ext2_extattr_block_clone(ip, &bp);
707 		if (error) {
708 			brelse(bp);
709 			return (error);
710 		}
711 	}
712 
713 	/* If I am last entry, clean me and free the block */
714 	entry = EXT2_FIRST_ENTRY(bp);
715 	if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry)) &&
716 	    (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
717 	    attrnamespace)) {
718 
719 		name_len = entry->e_name_len;
720 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
721 		    entry->e_name, &name_len);
722 		if (!attr_name) {
723 			brelse(bp);
724 			return (ENOTSUP);
725 		}
726 
727 		if (strlen(name) == name_len &&
728 		    0 == strncmp(attr_name, name, name_len)) {
729 			ip->i_blocks -= btodb(fs->e2fs_bsize);
730 			ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
731 			ip->i_facl = 0;
732 			error = ext2_update(ip->i_vnode, 1);
733 
734 			brelse(bp);
735 			return (error);
736 		}
737 	}
738 
739 	for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
740 	    entry = EXT2_EXTATTR_NEXT(entry)) {
741 		if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
742 		    attrnamespace)
743 			continue;
744 
745 		name_len = entry->e_name_len;
746 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
747 		    entry->e_name, &name_len);
748 		if (!attr_name) {
749 			brelse(bp);
750 			return (ENOTSUP);
751 		}
752 
753 		if (strlen(name) == name_len &&
754 		    0 == strncmp(attr_name, name, name_len)) {
755 			ext2_extattr_delete_entry(bp->b_data,
756 			    EXT2_FIRST_ENTRY(bp), entry,
757 			    bp->b_data + bp->b_bufsize);
758 
759 			return (bwrite(bp));
760 		}
761 	}
762 
763 	brelse(bp);
764 
765 	return (ENOATTR);
766 }
767 
768 static struct ext2fs_extattr_entry *
769 allocate_entry(const char *name, int attrnamespace, uint16_t offs,
770     uint32_t size, uint32_t hash)
771 {
772 	const char *attr_name;
773 	int name_len;
774 	struct ext2fs_extattr_entry *entry;
775 
776 	attr_name = ext2_extattr_name_to_linux(attrnamespace, name);
777 	name_len = strlen(attr_name);
778 
779 	entry = malloc(sizeof(struct ext2fs_extattr_entry) + name_len,
780 	    M_TEMP, M_WAITOK);
781 
782 	entry->e_name_len = name_len;
783 	entry->e_name_index = ext2_extattr_attrnamespace_to_linux(attrnamespace, name);
784 	entry->e_value_offs = htole16(offs);
785 	entry->e_value_block = 0;
786 	entry->e_value_size = htole32(size);
787 	entry->e_hash = htole32(hash);
788 	memcpy(entry->e_name, name, name_len);
789 
790 	return (entry);
791 }
792 
793 static void
794 free_entry(struct ext2fs_extattr_entry *entry)
795 {
796 
797 	free(entry, M_TEMP);
798 }
799 
800 static int
801 ext2_extattr_get_size(struct ext2fs_extattr_entry *first_entry,
802     struct ext2fs_extattr_entry *exist_entry, int header_size,
803     int name_len, int new_size)
804 {
805 	struct ext2fs_extattr_entry *entry;
806 	int size;
807 
808 	size = header_size;
809 	size += sizeof(uint32_t);
810 
811 	if (NULL == exist_entry) {
812 		size += EXT2_EXTATTR_LEN(name_len);
813 		size += EXT2_EXTATTR_SIZE(new_size);
814 	}
815 
816 	if (first_entry)
817 		for (entry = first_entry; !EXT2_IS_LAST_ENTRY(entry);
818 		    entry = EXT2_EXTATTR_NEXT(entry)) {
819 			if (entry != exist_entry)
820 				size += EXT2_EXTATTR_LEN(entry->e_name_len) +
821 				    EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size));
822 			else
823 				size += EXT2_EXTATTR_LEN(entry->e_name_len) +
824 				    EXT2_EXTATTR_SIZE(new_size);
825 		}
826 
827 	return (size);
828 }
829 
830 static void
831 ext2_extattr_set_exist_entry(char *off,
832     struct ext2fs_extattr_entry *first_entry,
833     struct ext2fs_extattr_entry *entry,
834     char *end, struct uio *uio)
835 {
836 	uint16_t min_offs;
837 
838 	min_offs = ext2_extattr_delete_value(off, first_entry, entry, end);
839 
840 	entry->e_value_size = htole32(uio->uio_resid);
841 	if (le32toh(entry->e_value_size))
842 		entry->e_value_offs = htole16(min_offs -
843 		    EXT2_EXTATTR_SIZE(uio->uio_resid));
844 	else
845 		entry->e_value_offs = 0;
846 
847 	uiomove(off + le16toh(entry->e_value_offs),
848 	    le32toh(entry->e_value_size), uio);
849 }
850 
851 static struct ext2fs_extattr_entry *
852 ext2_extattr_set_new_entry(char *off, struct ext2fs_extattr_entry *first_entry,
853     const char *name, int attrnamespace, char *end, struct uio *uio)
854 {
855 	int name_len;
856 	char *pad;
857 	uint16_t min_offs;
858 	struct ext2fs_extattr_entry *entry;
859 	struct ext2fs_extattr_entry *new_entry;
860 
861 	/* Find pad's */
862 	min_offs = end - off;
863 	entry = first_entry;
864 	while (!EXT2_IS_LAST_ENTRY(entry)) {
865 		if (min_offs > le16toh(entry->e_value_offs) &&
866 		    le16toh(entry->e_value_offs) > 0)
867 			min_offs = le16toh(entry->e_value_offs);
868 
869 		entry = EXT2_EXTATTR_NEXT(entry);
870 	}
871 
872 	pad = (char*)entry + sizeof(uint32_t);
873 
874 	/* Find entry insert position */
875 	name_len = strlen(name);
876 	entry = first_entry;
877 	while (!EXT2_IS_LAST_ENTRY(entry)) {
878 		if (!(attrnamespace - entry->e_name_index) &&
879 		    !(name_len - entry->e_name_len))
880 			if (memcmp(name, entry->e_name, name_len) <= 0)
881 				break;
882 
883 		entry = EXT2_EXTATTR_NEXT(entry);
884 	}
885 
886 	/* Create new entry and insert it */
887 	new_entry = allocate_entry(name, attrnamespace, 0, uio->uio_resid, 0);
888 	memmove((char *)entry + EXT2_EXTATTR_LEN(new_entry->e_name_len), entry,
889 	    pad - (char*)entry);
890 
891 	memcpy(entry, new_entry, EXT2_EXTATTR_LEN(new_entry->e_name_len));
892 	free_entry(new_entry);
893 
894 	new_entry = entry;
895 	if (le32toh(new_entry->e_value_size) > 0)
896 		new_entry->e_value_offs = htole16(min_offs -
897 		    EXT2_EXTATTR_SIZE(le32toh(new_entry->e_value_size)));
898 
899 	uiomove(off + le16toh(new_entry->e_value_offs),
900 	    le32toh(new_entry->e_value_size), uio);
901 
902 	return (new_entry);
903 }
904 
905 int
906 ext2_extattr_inode_set(struct inode *ip, int attrnamespace,
907     const char *name, struct uio *uio)
908 {
909 	struct m_ext2fs *fs;
910 	struct buf *bp;
911 	struct ext2fs_extattr_dinode_header *header;
912 	struct ext2fs_extattr_entry *entry;
913 	const char *attr_name;
914 	int name_len;
915 	size_t size = 0, max_size;
916 	int error;
917 
918 	fs = ip->i_e2fs;
919 
920 	if ((error = bread(ip->i_devvp,
921 	    fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
922 	    (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
923 		brelse(bp);
924 		return (error);
925 	}
926 
927 	struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
928 	    ((char *)bp->b_data +
929 	    EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
930 
931 	/* Check attributes magic value */
932 	header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
933 	    E2FS_REV0_INODE_SIZE + le16toh(dinode->e2di_extra_isize));
934 
935 	if (le32toh(header->h_magic) != EXTATTR_MAGIC) {
936 		brelse(bp);
937 		return (ENOSPC);
938 	}
939 
940 	error = ext2_extattr_check(EXT2_IFIRST(header), (char *)dinode +
941 	    EXT2_INODE_SIZE(fs));
942 	if (error) {
943 		brelse(bp);
944 		return (error);
945 	}
946 
947 	/* Find if entry exist */
948 	for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
949 	    entry = EXT2_EXTATTR_NEXT(entry)) {
950 		if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
951 		    attrnamespace)
952 			continue;
953 
954 		name_len = entry->e_name_len;
955 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
956 		    entry->e_name, &name_len);
957 		if (!attr_name) {
958 			brelse(bp);
959 			return (ENOTSUP);
960 		}
961 
962 		if (strlen(name) == name_len &&
963 		    0 == strncmp(attr_name, name, name_len))
964 			break;
965 	}
966 
967 	max_size = EXT2_INODE_SIZE(fs) - E2FS_REV0_INODE_SIZE -
968 	    le16toh(dinode->e2di_extra_isize);
969 
970 	if (!EXT2_IS_LAST_ENTRY(entry)) {
971 		size = ext2_extattr_get_size(EXT2_IFIRST(header), entry,
972 		    sizeof(struct ext2fs_extattr_dinode_header),
973 		    entry->e_name_len, uio->uio_resid);
974 		if (size > max_size) {
975 			brelse(bp);
976 			return (ENOSPC);
977 		}
978 
979 		ext2_extattr_set_exist_entry((char *)EXT2_IFIRST(header),
980 		    EXT2_IFIRST(header), entry, (char *)header + max_size, uio);
981 	} else {
982 		/* Ensure that the same entry does not exist in the block */
983 		if (ip->i_facl) {
984 			error = ext2_extattr_block_get(ip, attrnamespace, name,
985 			    NULL, &size);
986 			if (error != ENOATTR || size > 0) {
987 				brelse(bp);
988 				if (size > 0)
989 					error = ENOSPC;
990 
991 				return (error);
992 			}
993 		}
994 
995 		size = ext2_extattr_get_size(EXT2_IFIRST(header), NULL,
996 		    sizeof(struct ext2fs_extattr_dinode_header),
997 		    entry->e_name_len, uio->uio_resid);
998 		if (size > max_size) {
999 			brelse(bp);
1000 			return (ENOSPC);
1001 		}
1002 
1003 		ext2_extattr_set_new_entry((char *)EXT2_IFIRST(header),
1004 		    EXT2_IFIRST(header), name, attrnamespace,
1005 		    (char *)header + max_size, uio);
1006 	}
1007 
1008 	return (bwrite(bp));
1009 }
1010 
1011 static void
1012 ext2_extattr_hash_entry(struct ext2fs_extattr_header *header,
1013     struct ext2fs_extattr_entry *entry)
1014 {
1015 	uint32_t hash = 0;
1016 	char *name = entry->e_name;
1017 	int n;
1018 
1019 	for (n=0; n < entry->e_name_len; n++) {
1020 		hash = (hash << EXT2_EXTATTR_NAME_HASH_SHIFT) ^
1021 		    (hash >> (8*sizeof(hash) - EXT2_EXTATTR_NAME_HASH_SHIFT)) ^
1022 		    (*name++);
1023 	}
1024 
1025 	if (entry->e_value_block == 0 && entry->e_value_size != 0) {
1026 		uint32_t *value = (uint32_t *)((char *)header +
1027 		    le16toh(entry->e_value_offs));
1028 		for (n = (le32toh(entry->e_value_size) +
1029 		    EXT2_EXTATTR_ROUND) >> EXT2_EXTATTR_PAD_BITS; n; n--) {
1030 			hash = (hash << EXT2_EXTATTR_VALUE_HASH_SHIFT) ^
1031 			    (hash >> (8*sizeof(hash) - EXT2_EXTATTR_VALUE_HASH_SHIFT)) ^
1032 			    le32toh(*value++);
1033 		}
1034 	}
1035 
1036 	entry->e_hash = htole32(hash);
1037 }
1038 
1039 static void
1040 ext2_extattr_rehash(struct ext2fs_extattr_header *header,
1041     struct ext2fs_extattr_entry *entry)
1042 {
1043 	struct ext2fs_extattr_entry *here;
1044 	uint32_t hash = 0;
1045 
1046 	ext2_extattr_hash_entry(header, entry);
1047 
1048 	here = EXT2_ENTRY(header+1);
1049 	while (!EXT2_IS_LAST_ENTRY(here)) {
1050 		if (here->e_hash == 0) {
1051 			/* Block is not shared if an entry's hash value == 0 */
1052 			hash = 0;
1053 			break;
1054 		}
1055 
1056 		hash = (hash << EXT2_EXTATTR_BLOCK_HASH_SHIFT) ^
1057 		    (hash >> (8*sizeof(hash) - EXT2_EXTATTR_BLOCK_HASH_SHIFT)) ^
1058 		    le32toh(here->e_hash);
1059 
1060 		here = EXT2_EXTATTR_NEXT(here);
1061 	}
1062 
1063 	header->h_hash = htole32(hash);
1064 }
1065 
1066 int
1067 ext2_extattr_block_set(struct inode *ip, int attrnamespace,
1068     const char *name, struct uio *uio)
1069 {
1070 	struct m_ext2fs *fs;
1071 	struct buf *bp;
1072 	struct ext2fs_extattr_header *header;
1073 	struct ext2fs_extattr_entry *entry;
1074 	const char *attr_name;
1075 	int name_len;
1076 	size_t size;
1077 	int error;
1078 
1079 	fs = ip->i_e2fs;
1080 
1081 	if (ip->i_facl) {
1082 		error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
1083 		    fs->e2fs_bsize, NOCRED, &bp);
1084 		if (error) {
1085 			return (error);
1086 		}
1087 
1088 		/* Check attributes magic value */
1089 		header = EXT2_HDR(bp);
1090 		if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
1091 		    le32toh(header->h_blocks) != 1) {
1092 			brelse(bp);
1093 			return (EINVAL);
1094 		}
1095 
1096 		error = ext2_extattr_block_check(ip, bp);
1097 		if (error) {
1098 			brelse(bp);
1099 			return (error);
1100 		}
1101 
1102 		if (le32toh(header->h_refcount) > 1) {
1103 			error = ext2_extattr_block_clone(ip, &bp);
1104 			if (error) {
1105 				brelse(bp);
1106 				return (error);
1107 			}
1108 
1109 			header = EXT2_HDR(bp);
1110 		}
1111 
1112 		/* Find if entry exist */
1113 		for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
1114 		    entry = EXT2_EXTATTR_NEXT(entry)) {
1115 			if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
1116 			    attrnamespace)
1117 				continue;
1118 
1119 			name_len = entry->e_name_len;
1120 			attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
1121 			    entry->e_name, &name_len);
1122 			if (!attr_name) {
1123 				brelse(bp);
1124 				return (ENOTSUP);
1125 			}
1126 
1127 			if (strlen(name) == name_len &&
1128 			    0 == strncmp(attr_name, name, name_len))
1129 				break;
1130 		}
1131 
1132 		if (!EXT2_IS_LAST_ENTRY(entry)) {
1133 			size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), entry,
1134 			    sizeof(struct ext2fs_extattr_header),
1135 			    entry->e_name_len, uio->uio_resid);
1136 			if (size > bp->b_bufsize) {
1137 				brelse(bp);
1138 				return (ENOSPC);
1139 			}
1140 
1141 			ext2_extattr_set_exist_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
1142 			    entry, bp->b_data + bp->b_bufsize, uio);
1143 		} else {
1144 			size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), NULL,
1145 			    sizeof(struct ext2fs_extattr_header),
1146 			    strlen(name), uio->uio_resid);
1147 			if (size > bp->b_bufsize) {
1148 				brelse(bp);
1149 				return (ENOSPC);
1150 			}
1151 
1152 			entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
1153 			    name, attrnamespace, bp->b_data + bp->b_bufsize, uio);
1154 
1155 			/* Clean the same entry in the inode */
1156 			error = ext2_extattr_inode_delete(ip, attrnamespace, name);
1157 			if (error && error != ENOATTR) {
1158 				brelse(bp);
1159 				return (error);
1160 			}
1161 		}
1162 
1163 		ext2_extattr_rehash(header, entry);
1164 		ext2_extattr_blk_csum_set(ip, bp);
1165 
1166 		return (bwrite(bp));
1167 	}
1168 
1169 	size = ext2_extattr_get_size(NULL, NULL,
1170 	    sizeof(struct ext2fs_extattr_header),
1171 	    strlen(ext2_extattr_name_to_linux(attrnamespace, name)), uio->uio_resid);
1172 	if (size > fs->e2fs_bsize)
1173 		return (ENOSPC);
1174 
1175 	/* Allocate block, fill EA header and insert entry */
1176 	ip->i_facl = ext2_alloc_meta(ip);
1177 	if (0 == ip->i_facl)
1178 		return (ENOSPC);
1179 
1180 	ip->i_blocks += btodb(fs->e2fs_bsize);
1181 	ext2_update(ip->i_vnode, 1);
1182 
1183 	bp = getblk(ip->i_devvp, fsbtodb(fs, ip->i_facl), fs->e2fs_bsize, 0, 0, 0);
1184 	if (!bp) {
1185 		ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
1186 		ip->i_blocks -= btodb(fs->e2fs_bsize);
1187 		ip->i_facl = 0;
1188 		ext2_update(ip->i_vnode, 1);
1189 		return (EIO);
1190 	}
1191 
1192 	header = EXT2_HDR(bp);
1193 	header->h_magic = htole32(EXTATTR_MAGIC);
1194 	header->h_refcount = htole32(1);
1195 	header->h_blocks = htole32(1);
1196 	header->h_hash = 0;
1197 	memset(header->h_reserved, 0, sizeof(header->h_reserved));
1198 	memcpy(bp->b_data, header, sizeof(struct ext2fs_extattr_header));
1199 	memset(EXT2_FIRST_ENTRY(bp), 0, sizeof(uint32_t));
1200 
1201 	entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
1202 	    name, attrnamespace, bp->b_data + bp->b_bufsize, uio);
1203 
1204 	/* Clean the same entry in the inode */
1205 	error = ext2_extattr_inode_delete(ip, attrnamespace, name);
1206 	if (error && error != ENOATTR) {
1207 		brelse(bp);
1208 		return (error);
1209 	}
1210 
1211 	ext2_extattr_rehash(header, entry);
1212 	ext2_extattr_blk_csum_set(ip, bp);
1213 
1214 	return (bwrite(bp));
1215 }
1216 
1217 int ext2_extattr_free(struct inode *ip)
1218 {
1219 	struct m_ext2fs *fs;
1220 	struct buf *bp;
1221 	struct ext2fs_extattr_header *header;
1222 	int error;
1223 
1224 	fs = ip->i_e2fs;
1225 
1226 	if (!ip->i_facl)
1227 		return (0);
1228 
1229 	error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
1230 	    fs->e2fs_bsize, NOCRED, &bp);
1231 	if (error) {
1232 		return (error);
1233 	}
1234 
1235 	/* Check attributes magic value */
1236 	header = EXT2_HDR(bp);
1237 	if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
1238 	    le32toh(header->h_blocks) != 1) {
1239 		brelse(bp);
1240 		return (EINVAL);
1241 	}
1242 
1243 	error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp),
1244 	    bp->b_data + bp->b_bufsize);
1245 	if (error) {
1246 		brelse(bp);
1247 		return (error);
1248 	}
1249 
1250 	if (le32toh(header->h_refcount) > 1) {
1251 		header->h_refcount = htole32(le32toh(header->h_refcount) - 1);
1252 		bwrite(bp);
1253 	} else {
1254 		ext2_blkfree(ip, ip->i_facl, ip->i_e2fs->e2fs_bsize);
1255 		brelse(bp);
1256 	}
1257 
1258 	ip->i_blocks -= btodb(ip->i_e2fs->e2fs_bsize);
1259 	ip->i_facl = 0;
1260 	ext2_update(ip->i_vnode, 1);
1261 
1262 	return (0);
1263 }
1264