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