xref: /freebsd/sys/fs/ext2fs/ext2_extattr.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 		name_len = entry->e_name_len;
585 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
586 		    entry->e_name, &name_len);
587 		if (!attr_name) {
588 			brelse(bp);
589 			return (ENOTSUP);
590 		}
591 
592 		if (strlen(name) == name_len &&
593 		    0 == strncmp(attr_name, name, name_len)) {
594 			memset(header, 0, sizeof(struct ext2fs_extattr_dinode_header));
595 
596 			return (bwrite(bp));
597 		}
598 	}
599 
600 	for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
601 	    entry = EXT2_EXTATTR_NEXT(entry)) {
602 		if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
603 		    attrnamespace)
604 			continue;
605 
606 		name_len = entry->e_name_len;
607 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
608 		    entry->e_name, &name_len);
609 		if (!attr_name) {
610 			brelse(bp);
611 			return (ENOTSUP);
612 		}
613 
614 		if (strlen(name) == name_len &&
615 		    0 == strncmp(attr_name, name, name_len)) {
616 			ext2_extattr_delete_entry((char *)EXT2_IFIRST(header),
617 			    EXT2_IFIRST(header), entry,
618 			    (char *)dinode + EXT2_INODE_SIZE(fs));
619 
620 			return (bwrite(bp));
621 		}
622 	}
623 
624 	brelse(bp);
625 
626 	return (ENOATTR);
627 }
628 
629 static int
630 ext2_extattr_block_clone(struct inode *ip, struct buf **bpp)
631 {
632 	struct m_ext2fs *fs;
633 	struct buf *sbp;
634 	struct buf *cbp;
635 	struct ext2fs_extattr_header *header;
636 	uint64_t facl;
637 
638 	fs = ip->i_e2fs;
639 	sbp = *bpp;
640 
641 	header = EXT2_HDR(sbp);
642 	if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
643 	    le32toh(header->h_refcount) == 1)
644 		return (EINVAL);
645 
646 	facl = ext2_alloc_meta(ip);
647 	if (!facl)
648 		return (ENOSPC);
649 
650 	cbp = getblk(ip->i_devvp, fsbtodb(fs, facl), fs->e2fs_bsize, 0, 0, 0);
651 	if (!cbp) {
652 		ext2_blkfree(ip, facl, fs->e2fs_bsize);
653 		return (EIO);
654 	}
655 
656 	memcpy(cbp->b_data, sbp->b_data, fs->e2fs_bsize);
657 	header->h_refcount = htole32(le32toh(header->h_refcount) - 1);
658 	bwrite(sbp);
659 
660 	ip->i_facl = facl;
661 	ext2_update(ip->i_vnode, 1);
662 
663 	header = EXT2_HDR(cbp);
664 	header->h_refcount = htole32(1);
665 
666 	*bpp = cbp;
667 
668 	return (0);
669 }
670 
671 int
672 ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name)
673 {
674 	struct m_ext2fs *fs;
675 	struct buf *bp;
676 	struct ext2fs_extattr_header *header;
677 	struct ext2fs_extattr_entry *entry;
678 	const char *attr_name;
679 	int name_len;
680 	int error;
681 
682 	fs = ip->i_e2fs;
683 
684 	error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
685 	    fs->e2fs_bsize, NOCRED, &bp);
686 	if (error) {
687 		return (error);
688 	}
689 
690 	/* Check attributes magic value */
691 	header = EXT2_HDR(bp);
692 	if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
693 	    le32toh(header->h_blocks) != 1) {
694 		brelse(bp);
695 		return (EINVAL);
696 	}
697 
698 	error = ext2_extattr_block_check(ip, bp);
699 	if (error) {
700 		brelse(bp);
701 		return (error);
702 	}
703 
704 	if (le32toh(header->h_refcount) > 1) {
705 		error = ext2_extattr_block_clone(ip, &bp);
706 		if (error) {
707 			brelse(bp);
708 			return (error);
709 		}
710 	}
711 
712 	/* If I am last entry, clean me and free the block */
713 	entry = EXT2_FIRST_ENTRY(bp);
714 	if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry)) &&
715 	    (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
716 	    attrnamespace)) {
717 		name_len = entry->e_name_len;
718 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
719 		    entry->e_name, &name_len);
720 		if (!attr_name) {
721 			brelse(bp);
722 			return (ENOTSUP);
723 		}
724 
725 		if (strlen(name) == name_len &&
726 		    0 == strncmp(attr_name, name, name_len)) {
727 			ip->i_blocks -= btodb(fs->e2fs_bsize);
728 			ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
729 			ip->i_facl = 0;
730 			error = ext2_update(ip->i_vnode, 1);
731 
732 			brelse(bp);
733 			return (error);
734 		}
735 	}
736 
737 	for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
738 	    entry = EXT2_EXTATTR_NEXT(entry)) {
739 		if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
740 		    attrnamespace)
741 			continue;
742 
743 		name_len = entry->e_name_len;
744 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
745 		    entry->e_name, &name_len);
746 		if (!attr_name) {
747 			brelse(bp);
748 			return (ENOTSUP);
749 		}
750 
751 		if (strlen(name) == name_len &&
752 		    0 == strncmp(attr_name, name, name_len)) {
753 			ext2_extattr_delete_entry(bp->b_data,
754 			    EXT2_FIRST_ENTRY(bp), entry,
755 			    bp->b_data + bp->b_bufsize);
756 
757 			return (bwrite(bp));
758 		}
759 	}
760 
761 	brelse(bp);
762 
763 	return (ENOATTR);
764 }
765 
766 static struct ext2fs_extattr_entry *
767 allocate_entry(const char *name, int attrnamespace, uint16_t offs,
768     uint32_t size, uint32_t hash)
769 {
770 	const char *attr_name;
771 	int name_len;
772 	struct ext2fs_extattr_entry *entry;
773 
774 	attr_name = ext2_extattr_name_to_linux(attrnamespace, name);
775 	name_len = strlen(attr_name);
776 
777 	entry = malloc(sizeof(struct ext2fs_extattr_entry) + name_len,
778 	    M_TEMP, M_WAITOK);
779 
780 	entry->e_name_len = name_len;
781 	entry->e_name_index = ext2_extattr_attrnamespace_to_linux(attrnamespace, name);
782 	entry->e_value_offs = htole16(offs);
783 	entry->e_value_block = 0;
784 	entry->e_value_size = htole32(size);
785 	entry->e_hash = htole32(hash);
786 	memcpy(entry->e_name, name, name_len);
787 
788 	return (entry);
789 }
790 
791 static void
792 free_entry(struct ext2fs_extattr_entry *entry)
793 {
794 
795 	free(entry, M_TEMP);
796 }
797 
798 static int
799 ext2_extattr_get_size(struct ext2fs_extattr_entry *first_entry,
800     struct ext2fs_extattr_entry *exist_entry, int header_size,
801     int name_len, int new_size)
802 {
803 	struct ext2fs_extattr_entry *entry;
804 	int size;
805 
806 	size = header_size;
807 	size += sizeof(uint32_t);
808 
809 	if (NULL == exist_entry) {
810 		size += EXT2_EXTATTR_LEN(name_len);
811 		size += EXT2_EXTATTR_SIZE(new_size);
812 	}
813 
814 	if (first_entry)
815 		for (entry = first_entry; !EXT2_IS_LAST_ENTRY(entry);
816 		    entry = EXT2_EXTATTR_NEXT(entry)) {
817 			if (entry != exist_entry)
818 				size += EXT2_EXTATTR_LEN(entry->e_name_len) +
819 				    EXT2_EXTATTR_SIZE(le32toh(entry->e_value_size));
820 			else
821 				size += EXT2_EXTATTR_LEN(entry->e_name_len) +
822 				    EXT2_EXTATTR_SIZE(new_size);
823 		}
824 
825 	return (size);
826 }
827 
828 static void
829 ext2_extattr_set_exist_entry(char *off,
830     struct ext2fs_extattr_entry *first_entry,
831     struct ext2fs_extattr_entry *entry,
832     char *end, struct uio *uio)
833 {
834 	uint16_t min_offs;
835 
836 	min_offs = ext2_extattr_delete_value(off, first_entry, entry, end);
837 
838 	entry->e_value_size = htole32(uio->uio_resid);
839 	if (le32toh(entry->e_value_size))
840 		entry->e_value_offs = htole16(min_offs -
841 		    EXT2_EXTATTR_SIZE(uio->uio_resid));
842 	else
843 		entry->e_value_offs = 0;
844 
845 	uiomove(off + le16toh(entry->e_value_offs),
846 	    le32toh(entry->e_value_size), uio);
847 }
848 
849 static struct ext2fs_extattr_entry *
850 ext2_extattr_set_new_entry(char *off, struct ext2fs_extattr_entry *first_entry,
851     const char *name, int attrnamespace, char *end, struct uio *uio)
852 {
853 	int name_len;
854 	char *pad;
855 	uint16_t min_offs;
856 	struct ext2fs_extattr_entry *entry;
857 	struct ext2fs_extattr_entry *new_entry;
858 
859 	/* Find pad's */
860 	min_offs = end - off;
861 	entry = first_entry;
862 	while (!EXT2_IS_LAST_ENTRY(entry)) {
863 		if (min_offs > le16toh(entry->e_value_offs) &&
864 		    le16toh(entry->e_value_offs) > 0)
865 			min_offs = le16toh(entry->e_value_offs);
866 
867 		entry = EXT2_EXTATTR_NEXT(entry);
868 	}
869 
870 	pad = (char*)entry + sizeof(uint32_t);
871 
872 	/* Find entry insert position */
873 	name_len = strlen(name);
874 	entry = first_entry;
875 	while (!EXT2_IS_LAST_ENTRY(entry)) {
876 		if (!(attrnamespace - entry->e_name_index) &&
877 		    !(name_len - entry->e_name_len))
878 			if (memcmp(name, entry->e_name, name_len) <= 0)
879 				break;
880 
881 		entry = EXT2_EXTATTR_NEXT(entry);
882 	}
883 
884 	/* Create new entry and insert it */
885 	new_entry = allocate_entry(name, attrnamespace, 0, uio->uio_resid, 0);
886 	memmove((char *)entry + EXT2_EXTATTR_LEN(new_entry->e_name_len), entry,
887 	    pad - (char*)entry);
888 
889 	memcpy(entry, new_entry, EXT2_EXTATTR_LEN(new_entry->e_name_len));
890 	free_entry(new_entry);
891 
892 	new_entry = entry;
893 	if (le32toh(new_entry->e_value_size) > 0)
894 		new_entry->e_value_offs = htole16(min_offs -
895 		    EXT2_EXTATTR_SIZE(le32toh(new_entry->e_value_size)));
896 
897 	uiomove(off + le16toh(new_entry->e_value_offs),
898 	    le32toh(new_entry->e_value_size), uio);
899 
900 	return (new_entry);
901 }
902 
903 int
904 ext2_extattr_inode_set(struct inode *ip, int attrnamespace,
905     const char *name, struct uio *uio)
906 {
907 	struct m_ext2fs *fs;
908 	struct buf *bp;
909 	struct ext2fs_extattr_dinode_header *header;
910 	struct ext2fs_extattr_entry *entry;
911 	const char *attr_name;
912 	int name_len;
913 	size_t size = 0, max_size;
914 	int error;
915 
916 	fs = ip->i_e2fs;
917 
918 	if ((error = bread(ip->i_devvp,
919 	    fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
920 	    (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
921 		brelse(bp);
922 		return (error);
923 	}
924 
925 	struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
926 	    ((char *)bp->b_data +
927 	    EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
928 
929 	/* Check attributes magic value */
930 	header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
931 	    E2FS_REV0_INODE_SIZE + le16toh(dinode->e2di_extra_isize));
932 
933 	if (le32toh(header->h_magic) != EXTATTR_MAGIC) {
934 		brelse(bp);
935 		return (ENOSPC);
936 	}
937 
938 	error = ext2_extattr_check(EXT2_IFIRST(header), (char *)dinode +
939 	    EXT2_INODE_SIZE(fs));
940 	if (error) {
941 		brelse(bp);
942 		return (error);
943 	}
944 
945 	/* Find if entry exist */
946 	for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
947 	    entry = EXT2_EXTATTR_NEXT(entry)) {
948 		if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
949 		    attrnamespace)
950 			continue;
951 
952 		name_len = entry->e_name_len;
953 		attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
954 		    entry->e_name, &name_len);
955 		if (!attr_name) {
956 			brelse(bp);
957 			return (ENOTSUP);
958 		}
959 
960 		if (strlen(name) == name_len &&
961 		    0 == strncmp(attr_name, name, name_len))
962 			break;
963 	}
964 
965 	max_size = EXT2_INODE_SIZE(fs) - E2FS_REV0_INODE_SIZE -
966 	    le16toh(dinode->e2di_extra_isize);
967 
968 	if (!EXT2_IS_LAST_ENTRY(entry)) {
969 		size = ext2_extattr_get_size(EXT2_IFIRST(header), entry,
970 		    sizeof(struct ext2fs_extattr_dinode_header),
971 		    entry->e_name_len, uio->uio_resid);
972 		if (size > max_size) {
973 			brelse(bp);
974 			return (ENOSPC);
975 		}
976 
977 		ext2_extattr_set_exist_entry((char *)EXT2_IFIRST(header),
978 		    EXT2_IFIRST(header), entry, (char *)header + max_size, uio);
979 	} else {
980 		/* Ensure that the same entry does not exist in the block */
981 		if (ip->i_facl) {
982 			error = ext2_extattr_block_get(ip, attrnamespace, name,
983 			    NULL, &size);
984 			if (error != ENOATTR || size > 0) {
985 				brelse(bp);
986 				if (size > 0)
987 					error = ENOSPC;
988 
989 				return (error);
990 			}
991 		}
992 
993 		size = ext2_extattr_get_size(EXT2_IFIRST(header), NULL,
994 		    sizeof(struct ext2fs_extattr_dinode_header),
995 		    entry->e_name_len, uio->uio_resid);
996 		if (size > max_size) {
997 			brelse(bp);
998 			return (ENOSPC);
999 		}
1000 
1001 		ext2_extattr_set_new_entry((char *)EXT2_IFIRST(header),
1002 		    EXT2_IFIRST(header), name, attrnamespace,
1003 		    (char *)header + max_size, uio);
1004 	}
1005 
1006 	return (bwrite(bp));
1007 }
1008 
1009 static void
1010 ext2_extattr_hash_entry(struct ext2fs_extattr_header *header,
1011     struct ext2fs_extattr_entry *entry)
1012 {
1013 	uint32_t hash = 0;
1014 	char *name = entry->e_name;
1015 	int n;
1016 
1017 	for (n=0; n < entry->e_name_len; n++) {
1018 		hash = (hash << EXT2_EXTATTR_NAME_HASH_SHIFT) ^
1019 		    (hash >> (8*sizeof(hash) - EXT2_EXTATTR_NAME_HASH_SHIFT)) ^
1020 		    (*name++);
1021 	}
1022 
1023 	if (entry->e_value_block == 0 && entry->e_value_size != 0) {
1024 		uint32_t *value = (uint32_t *)((char *)header +
1025 		    le16toh(entry->e_value_offs));
1026 		for (n = (le32toh(entry->e_value_size) +
1027 		    EXT2_EXTATTR_ROUND) >> EXT2_EXTATTR_PAD_BITS; n; n--) {
1028 			hash = (hash << EXT2_EXTATTR_VALUE_HASH_SHIFT) ^
1029 			    (hash >> (8*sizeof(hash) - EXT2_EXTATTR_VALUE_HASH_SHIFT)) ^
1030 			    le32toh(*value++);
1031 		}
1032 	}
1033 
1034 	entry->e_hash = htole32(hash);
1035 }
1036 
1037 static void
1038 ext2_extattr_rehash(struct ext2fs_extattr_header *header,
1039     struct ext2fs_extattr_entry *entry)
1040 {
1041 	struct ext2fs_extattr_entry *here;
1042 	uint32_t hash = 0;
1043 
1044 	ext2_extattr_hash_entry(header, entry);
1045 
1046 	here = EXT2_ENTRY(header+1);
1047 	while (!EXT2_IS_LAST_ENTRY(here)) {
1048 		if (here->e_hash == 0) {
1049 			/* Block is not shared if an entry's hash value == 0 */
1050 			hash = 0;
1051 			break;
1052 		}
1053 
1054 		hash = (hash << EXT2_EXTATTR_BLOCK_HASH_SHIFT) ^
1055 		    (hash >> (8*sizeof(hash) - EXT2_EXTATTR_BLOCK_HASH_SHIFT)) ^
1056 		    le32toh(here->e_hash);
1057 
1058 		here = EXT2_EXTATTR_NEXT(here);
1059 	}
1060 
1061 	header->h_hash = htole32(hash);
1062 }
1063 
1064 int
1065 ext2_extattr_block_set(struct inode *ip, int attrnamespace,
1066     const char *name, struct uio *uio)
1067 {
1068 	struct m_ext2fs *fs;
1069 	struct buf *bp;
1070 	struct ext2fs_extattr_header *header;
1071 	struct ext2fs_extattr_entry *entry;
1072 	const char *attr_name;
1073 	int name_len;
1074 	size_t size;
1075 	int error;
1076 
1077 	fs = ip->i_e2fs;
1078 
1079 	if (ip->i_facl) {
1080 		error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
1081 		    fs->e2fs_bsize, NOCRED, &bp);
1082 		if (error) {
1083 			return (error);
1084 		}
1085 
1086 		/* Check attributes magic value */
1087 		header = EXT2_HDR(bp);
1088 		if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
1089 		    le32toh(header->h_blocks) != 1) {
1090 			brelse(bp);
1091 			return (EINVAL);
1092 		}
1093 
1094 		error = ext2_extattr_block_check(ip, bp);
1095 		if (error) {
1096 			brelse(bp);
1097 			return (error);
1098 		}
1099 
1100 		if (le32toh(header->h_refcount) > 1) {
1101 			error = ext2_extattr_block_clone(ip, &bp);
1102 			if (error) {
1103 				brelse(bp);
1104 				return (error);
1105 			}
1106 
1107 			header = EXT2_HDR(bp);
1108 		}
1109 
1110 		/* Find if entry exist */
1111 		for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
1112 		    entry = EXT2_EXTATTR_NEXT(entry)) {
1113 			if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
1114 			    attrnamespace)
1115 				continue;
1116 
1117 			name_len = entry->e_name_len;
1118 			attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
1119 			    entry->e_name, &name_len);
1120 			if (!attr_name) {
1121 				brelse(bp);
1122 				return (ENOTSUP);
1123 			}
1124 
1125 			if (strlen(name) == name_len &&
1126 			    0 == strncmp(attr_name, name, name_len))
1127 				break;
1128 		}
1129 
1130 		if (!EXT2_IS_LAST_ENTRY(entry)) {
1131 			size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), entry,
1132 			    sizeof(struct ext2fs_extattr_header),
1133 			    entry->e_name_len, uio->uio_resid);
1134 			if (size > bp->b_bufsize) {
1135 				brelse(bp);
1136 				return (ENOSPC);
1137 			}
1138 
1139 			ext2_extattr_set_exist_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
1140 			    entry, bp->b_data + bp->b_bufsize, uio);
1141 		} else {
1142 			size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), NULL,
1143 			    sizeof(struct ext2fs_extattr_header),
1144 			    strlen(name), uio->uio_resid);
1145 			if (size > bp->b_bufsize) {
1146 				brelse(bp);
1147 				return (ENOSPC);
1148 			}
1149 
1150 			entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
1151 			    name, attrnamespace, bp->b_data + bp->b_bufsize, uio);
1152 
1153 			/* Clean the same entry in the inode */
1154 			error = ext2_extattr_inode_delete(ip, attrnamespace, name);
1155 			if (error && error != ENOATTR) {
1156 				brelse(bp);
1157 				return (error);
1158 			}
1159 		}
1160 
1161 		ext2_extattr_rehash(header, entry);
1162 		ext2_extattr_blk_csum_set(ip, bp);
1163 
1164 		return (bwrite(bp));
1165 	}
1166 
1167 	size = ext2_extattr_get_size(NULL, NULL,
1168 	    sizeof(struct ext2fs_extattr_header),
1169 	    strlen(ext2_extattr_name_to_linux(attrnamespace, name)), uio->uio_resid);
1170 	if (size > fs->e2fs_bsize)
1171 		return (ENOSPC);
1172 
1173 	/* Allocate block, fill EA header and insert entry */
1174 	ip->i_facl = ext2_alloc_meta(ip);
1175 	if (0 == ip->i_facl)
1176 		return (ENOSPC);
1177 
1178 	ip->i_blocks += btodb(fs->e2fs_bsize);
1179 	ext2_update(ip->i_vnode, 1);
1180 
1181 	bp = getblk(ip->i_devvp, fsbtodb(fs, ip->i_facl), fs->e2fs_bsize, 0, 0, 0);
1182 	if (!bp) {
1183 		ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
1184 		ip->i_blocks -= btodb(fs->e2fs_bsize);
1185 		ip->i_facl = 0;
1186 		ext2_update(ip->i_vnode, 1);
1187 		return (EIO);
1188 	}
1189 
1190 	header = EXT2_HDR(bp);
1191 	header->h_magic = htole32(EXTATTR_MAGIC);
1192 	header->h_refcount = htole32(1);
1193 	header->h_blocks = htole32(1);
1194 	header->h_hash = 0;
1195 	memset(header->h_reserved, 0, sizeof(header->h_reserved));
1196 	memcpy(bp->b_data, header, sizeof(struct ext2fs_extattr_header));
1197 	memset(EXT2_FIRST_ENTRY(bp), 0, sizeof(uint32_t));
1198 
1199 	entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
1200 	    name, attrnamespace, bp->b_data + bp->b_bufsize, uio);
1201 
1202 	/* Clean the same entry in the inode */
1203 	error = ext2_extattr_inode_delete(ip, attrnamespace, name);
1204 	if (error && error != ENOATTR) {
1205 		brelse(bp);
1206 		return (error);
1207 	}
1208 
1209 	ext2_extattr_rehash(header, entry);
1210 	ext2_extattr_blk_csum_set(ip, bp);
1211 
1212 	return (bwrite(bp));
1213 }
1214 
1215 int ext2_extattr_free(struct inode *ip)
1216 {
1217 	struct m_ext2fs *fs;
1218 	struct buf *bp;
1219 	struct ext2fs_extattr_header *header;
1220 	int error;
1221 
1222 	fs = ip->i_e2fs;
1223 
1224 	if (!ip->i_facl)
1225 		return (0);
1226 
1227 	error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
1228 	    fs->e2fs_bsize, NOCRED, &bp);
1229 	if (error) {
1230 		return (error);
1231 	}
1232 
1233 	/* Check attributes magic value */
1234 	header = EXT2_HDR(bp);
1235 	if (le32toh(header->h_magic) != EXTATTR_MAGIC ||
1236 	    le32toh(header->h_blocks) != 1) {
1237 		brelse(bp);
1238 		return (EINVAL);
1239 	}
1240 
1241 	error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp),
1242 	    bp->b_data + bp->b_bufsize);
1243 	if (error) {
1244 		brelse(bp);
1245 		return (error);
1246 	}
1247 
1248 	if (le32toh(header->h_refcount) > 1) {
1249 		header->h_refcount = htole32(le32toh(header->h_refcount) - 1);
1250 		bwrite(bp);
1251 	} else {
1252 		ext2_blkfree(ip, ip->i_facl, ip->i_e2fs->e2fs_bsize);
1253 		brelse(bp);
1254 	}
1255 
1256 	ip->i_blocks -= btodb(ip->i_e2fs->e2fs_bsize);
1257 	ip->i_facl = 0;
1258 	ext2_update(ip->i_vnode, 1);
1259 
1260 	return (0);
1261 }
1262