2 * Copyright (c) 2017, Fedor Uporov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/vnode.h>
37 #include <sys/endian.h>
39 #include <sys/extattr.h>
41 #include <fs/ext2fs/fs.h>
42 #include <fs/ext2fs/ext2fs.h>
43 #include <fs/ext2fs/inode.h>
44 #include <fs/ext2fs/ext2_dinode.h>
45 #include <fs/ext2fs/ext2_mount.h>
46 #include <fs/ext2fs/ext2_extattr.h>
47 #include <fs/ext2fs/ext2_extern.h>
50 ext2_extattr_attrnamespace_to_bsd(int attrnamespace)
53 switch (attrnamespace) {
54 case EXT4_XATTR_INDEX_SYSTEM:
55 return (EXTATTR_NAMESPACE_SYSTEM);
57 case EXT4_XATTR_INDEX_USER:
58 return (EXTATTR_NAMESPACE_USER);
60 case EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT:
61 return (POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE);
63 case EXT4_XATTR_INDEX_POSIX_ACL_ACCESS:
64 return (POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE);
67 return (EXTATTR_NAMESPACE_EMPTY);
71 ext2_extattr_name_to_bsd(int attrnamespace, const char *name, int* name_len)
74 if (attrnamespace == EXT4_XATTR_INDEX_SYSTEM)
76 else if (attrnamespace == EXT4_XATTR_INDEX_USER)
78 else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT) {
79 *name_len = strlen(POSIX1E_ACL_DEFAULT_EXTATTR_NAME);
80 return (POSIX1E_ACL_DEFAULT_EXTATTR_NAME);
81 } else if (attrnamespace == EXT4_XATTR_INDEX_POSIX_ACL_ACCESS) {
82 *name_len = strlen(POSIX1E_ACL_ACCESS_EXTATTR_NAME);
83 return (POSIX1E_ACL_ACCESS_EXTATTR_NAME);
87 * XXX: Not all linux namespaces are mapped to bsd for now,
88 * return NULL, which will be converted to ENOTSUP on upper layer.
91 printf("can not convert ext2fs name to bsd: namespace=%d\n", attrnamespace);
98 ext2_extattr_attrnamespace_to_linux(int attrnamespace, const char *name)
101 if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE &&
102 !strcmp(name, POSIX1E_ACL_DEFAULT_EXTATTR_NAME))
103 return (EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT);
105 if (attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE &&
106 !strcmp(name, POSIX1E_ACL_ACCESS_EXTATTR_NAME))
107 return (EXT4_XATTR_INDEX_POSIX_ACL_ACCESS);
109 switch (attrnamespace) {
110 case EXTATTR_NAMESPACE_SYSTEM:
111 return (EXT4_XATTR_INDEX_SYSTEM);
113 case EXTATTR_NAMESPACE_USER:
114 return (EXT4_XATTR_INDEX_USER);
118 * In this case namespace conversion should be unique,
119 * so this point is unreachable.
125 ext2_extattr_name_to_linux(int attrnamespace, const char *name)
128 if (attrnamespace == POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE ||
129 attrnamespace == POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE)
136 ext2_extattr_valid_attrname(int attrnamespace, const char *attrname)
138 if (attrnamespace == EXTATTR_NAMESPACE_EMPTY)
141 if (strlen(attrname) == 0)
144 if (strlen(attrname) + 1 > EXT2_EXTATTR_NAMELEN_MAX)
145 return (ENAMETOOLONG);
151 ext2_extattr_check(struct ext2fs_extattr_entry *entry, char *end)
153 struct ext2fs_extattr_entry *next;
155 while (!EXT2_IS_LAST_ENTRY(entry)) {
156 next = EXT2_EXTATTR_NEXT(entry);
157 if ((char *)next >= end)
167 ext2_extattr_inode_list(struct inode *ip, int attrnamespace,
168 struct uio *uio, size_t *size)
172 struct ext2fs_extattr_dinode_header *header;
173 struct ext2fs_extattr_entry *entry;
174 const char *attr_name;
180 if ((error = bread(ip->i_devvp,
181 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
182 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
187 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
188 ((char *)bp->b_data +
189 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
191 /* Check attributes magic value */
192 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
193 E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize);
195 if (header->h_magic != EXTATTR_MAGIC) {
200 error = ext2_extattr_check(EXT2_IFIRST(header),
201 (char *)dinode + EXT2_INODE_SIZE(fs));
207 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
208 entry = EXT2_EXTATTR_NEXT(entry)) {
209 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
213 name_len = entry->e_name_len;
214 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
215 entry->e_name, &name_len);
222 *size += name_len + 1;
224 char *name = malloc(name_len + 1, M_TEMP, M_WAITOK);
226 memcpy(&name[1], attr_name, name_len);
227 error = uiomove(name, name_len + 1, uio);
240 ext2_extattr_block_list(struct inode *ip, int attrnamespace,
241 struct uio *uio, size_t *size)
245 struct ext2fs_extattr_header *header;
246 struct ext2fs_extattr_entry *entry;
247 const char *attr_name;
253 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
254 fs->e2fs_bsize, NOCRED, &bp);
260 /* Check attributes magic value */
261 header = EXT2_HDR(bp);
262 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
267 error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), bp->b_data + bp->b_bufsize);
273 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
274 entry = EXT2_EXTATTR_NEXT(entry)) {
275 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
279 name_len = entry->e_name_len;
280 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
281 entry->e_name, &name_len);
288 *size += name_len + 1;
290 char *name = malloc(name_len + 1, M_TEMP, M_WAITOK);
292 memcpy(&name[1], attr_name, name_len);
293 error = uiomove(name, name_len + 1, uio);
306 ext2_extattr_inode_get(struct inode *ip, int attrnamespace,
307 const char *name, struct uio *uio, size_t *size)
311 struct ext2fs_extattr_dinode_header *header;
312 struct ext2fs_extattr_entry *entry;
313 const char *attr_name;
319 if ((error = bread(ip->i_devvp,
320 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
321 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
326 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
327 ((char *)bp->b_data +
328 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
330 /* Check attributes magic value */
331 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
332 E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize);
334 if (header->h_magic != EXTATTR_MAGIC) {
339 error = ext2_extattr_check(EXT2_IFIRST(header),
340 (char *)dinode + EXT2_INODE_SIZE(fs));
346 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
347 entry = EXT2_EXTATTR_NEXT(entry)) {
348 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
352 name_len = entry->e_name_len;
353 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
354 entry->e_name, &name_len);
360 if (strlen(name) == name_len &&
361 0 == strncmp(attr_name, name, name_len)) {
363 *size += entry->e_value_size;
365 error = uiomove(((char *)EXT2_IFIRST(header)) +
366 entry->e_value_offs, entry->e_value_size, uio);
380 ext2_extattr_block_get(struct inode *ip, int attrnamespace,
381 const char *name, struct uio *uio, size_t *size)
385 struct ext2fs_extattr_header *header;
386 struct ext2fs_extattr_entry *entry;
387 const char *attr_name;
393 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
394 fs->e2fs_bsize, NOCRED, &bp);
400 /* Check attributes magic value */
401 header = EXT2_HDR(bp);
402 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
407 error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), bp->b_data + bp->b_bufsize);
413 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
414 entry = EXT2_EXTATTR_NEXT(entry)) {
415 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
419 name_len = entry->e_name_len;
420 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
421 entry->e_name, &name_len);
427 if (strlen(name) == name_len &&
428 0 == strncmp(attr_name, name, name_len)) {
430 *size += entry->e_value_size;
432 error = uiomove(bp->b_data + entry->e_value_offs,
433 entry->e_value_size, uio);
447 ext2_extattr_delete_value(char *off,
448 struct ext2fs_extattr_entry *first_entry,
449 struct ext2fs_extattr_entry *entry, char *end)
452 struct ext2fs_extattr_entry *next;
454 min_offs = end - off;
456 while (!EXT2_IS_LAST_ENTRY(next)) {
457 if (min_offs > next->e_value_offs && next->e_value_offs > 0)
458 min_offs = next->e_value_offs;
460 next = EXT2_EXTATTR_NEXT(next);
463 if (entry->e_value_size == 0)
466 memmove(off + min_offs + EXT2_EXTATTR_SIZE(entry->e_value_size),
467 off + min_offs, entry->e_value_offs - min_offs);
469 /* Adjust all value offsets */
471 while (!EXT2_IS_LAST_ENTRY(next))
473 if (next->e_value_offs > 0 &&
474 next->e_value_offs < entry->e_value_offs)
475 next->e_value_offs +=
476 EXT2_EXTATTR_SIZE(entry->e_value_size);
478 next = EXT2_EXTATTR_NEXT(next);
481 min_offs += EXT2_EXTATTR_SIZE(entry->e_value_size);
487 ext2_extattr_delete_entry(char *off,
488 struct ext2fs_extattr_entry *first_entry,
489 struct ext2fs_extattr_entry *entry, char *end)
492 struct ext2fs_extattr_entry *next;
494 /* Clean entry value */
495 ext2_extattr_delete_value(off, first_entry, entry, end);
497 /* Clean the entry */
499 while (!EXT2_IS_LAST_ENTRY(next))
500 next = EXT2_EXTATTR_NEXT(next);
502 pad = (char*)next + sizeof(uint32_t);
504 memmove(entry, (char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len),
505 pad - ((char *)entry + EXT2_EXTATTR_LEN(entry->e_name_len)));
509 ext2_extattr_inode_delete(struct inode *ip, int attrnamespace, const char *name)
513 struct ext2fs_extattr_dinode_header *header;
514 struct ext2fs_extattr_entry *entry;
515 const char *attr_name;
521 if ((error = bread(ip->i_devvp,
522 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
523 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
528 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
529 ((char *)bp->b_data +
530 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
532 /* Check attributes magic value */
533 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
534 E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize);
536 if (header->h_magic != EXTATTR_MAGIC) {
541 error = ext2_extattr_check(EXT2_IFIRST(header),
542 (char *)dinode + EXT2_INODE_SIZE(fs));
548 /* If I am last entry, just make magic zero */
549 entry = EXT2_IFIRST(header);
550 if ((EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry))) &&
551 (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
554 name_len = entry->e_name_len;
555 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
556 entry->e_name, &name_len);
562 if (strlen(name) == name_len &&
563 0 == strncmp(attr_name, name, name_len)) {
564 memset(header, 0, sizeof(struct ext2fs_extattr_dinode_header));
570 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
571 entry = EXT2_EXTATTR_NEXT(entry)) {
572 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
576 name_len = entry->e_name_len;
577 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
578 entry->e_name, &name_len);
584 if (strlen(name) == name_len &&
585 0 == strncmp(attr_name, name, name_len)) {
586 ext2_extattr_delete_entry((char *)EXT2_IFIRST(header),
587 EXT2_IFIRST(header), entry,
588 (char *)dinode + EXT2_INODE_SIZE(fs));
600 ext2_extattr_block_clone(struct inode *ip, struct buf **bpp)
605 struct ext2fs_extattr_header *header;
611 header = EXT2_HDR(sbp);
612 if (header->h_magic != EXTATTR_MAGIC || header->h_refcount == 1)
615 facl = ext2_allocfacl(ip);
619 cbp = getblk(ip->i_devvp, fsbtodb(fs, facl), fs->e2fs_bsize, 0, 0, 0);
621 ext2_blkfree(ip, facl, fs->e2fs_bsize);
625 memcpy(cbp->b_data, sbp->b_data, fs->e2fs_bsize);
626 header->h_refcount--;
630 ext2_update(ip->i_vnode, 1);
632 header = EXT2_HDR(cbp);
633 header->h_refcount = 1;
641 ext2_extattr_block_delete(struct inode *ip, int attrnamespace, const char *name)
645 struct ext2fs_extattr_header *header;
646 struct ext2fs_extattr_entry *entry;
647 const char *attr_name;
653 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
654 fs->e2fs_bsize, NOCRED, &bp);
660 /* Check attributes magic value */
661 header = EXT2_HDR(bp);
662 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
667 error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), bp->b_data + bp->b_bufsize);
673 if (header->h_refcount > 1) {
674 error = ext2_extattr_block_clone(ip, &bp);
681 /* If I am last entry, clean me and free the block */
682 entry = EXT2_FIRST_ENTRY(bp);
683 if (EXT2_IS_LAST_ENTRY(EXT2_EXTATTR_NEXT(entry)) &&
684 (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) ==
687 name_len = entry->e_name_len;
688 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
689 entry->e_name, &name_len);
695 if (strlen(name) == name_len &&
696 0 == strncmp(attr_name, name, name_len)) {
697 ip->i_blocks -= btodb(fs->e2fs_bsize);
698 ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
700 error = ext2_update(ip->i_vnode, 1);
707 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
708 entry = EXT2_EXTATTR_NEXT(entry)) {
709 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
713 name_len = entry->e_name_len;
714 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
715 entry->e_name, &name_len);
721 if (strlen(name) == name_len &&
722 0 == strncmp(attr_name, name, name_len)) {
723 ext2_extattr_delete_entry(bp->b_data,
724 EXT2_FIRST_ENTRY(bp), entry,
725 bp->b_data + bp->b_bufsize);
736 static struct ext2fs_extattr_entry *
737 allocate_entry(const char *name, int attrnamespace, uint16_t offs,
738 uint32_t size, uint32_t hash)
740 const char *attr_name;
742 struct ext2fs_extattr_entry *entry;
744 attr_name = ext2_extattr_name_to_linux(attrnamespace, name);
745 name_len = strlen(attr_name);
747 entry = malloc(sizeof(struct ext2fs_extattr_entry) + name_len,
750 entry->e_name_len = name_len;
751 entry->e_name_index = ext2_extattr_attrnamespace_to_linux(attrnamespace, name);
752 entry->e_value_offs = offs;
753 entry->e_value_block = 0;
754 entry->e_value_size = size;
755 entry->e_hash = hash;
756 memcpy(entry->e_name, name, name_len);
762 free_entry(struct ext2fs_extattr_entry *entry)
769 ext2_extattr_get_size(struct ext2fs_extattr_entry *first_entry,
770 struct ext2fs_extattr_entry *exist_entry, int header_size,
771 int name_len, int new_size)
773 struct ext2fs_extattr_entry *entry;
777 size += sizeof(uint32_t);
779 if (NULL == exist_entry) {
780 size += EXT2_EXTATTR_LEN(name_len);
781 size += EXT2_EXTATTR_SIZE(new_size);
785 for (entry = first_entry; !EXT2_IS_LAST_ENTRY(entry);
786 entry = EXT2_EXTATTR_NEXT(entry)) {
787 if (entry != exist_entry)
788 size += EXT2_EXTATTR_LEN(entry->e_name_len) +
789 EXT2_EXTATTR_SIZE(entry->e_value_size);
791 size += EXT2_EXTATTR_LEN(entry->e_name_len) +
792 EXT2_EXTATTR_SIZE(new_size);
799 ext2_extattr_set_exist_entry(char *off,
800 struct ext2fs_extattr_entry *first_entry,
801 struct ext2fs_extattr_entry *entry,
802 char *end, struct uio *uio)
806 min_offs = ext2_extattr_delete_value(off, first_entry, entry, end);
808 entry->e_value_size = uio->uio_resid;
809 if (entry->e_value_size)
810 entry->e_value_offs = min_offs -
811 EXT2_EXTATTR_SIZE(uio->uio_resid);
813 entry->e_value_offs = 0;
815 uiomove(off + entry->e_value_offs, entry->e_value_size, uio);
818 static struct ext2fs_extattr_entry *
819 ext2_extattr_set_new_entry(char *off, struct ext2fs_extattr_entry *first_entry,
820 const char *name, int attrnamespace, char *end, struct uio *uio)
825 struct ext2fs_extattr_entry *entry;
826 struct ext2fs_extattr_entry *new_entry;
829 min_offs = end - off;
831 while (!EXT2_IS_LAST_ENTRY(entry)) {
832 if (min_offs > entry->e_value_offs && entry->e_value_offs > 0)
833 min_offs = entry->e_value_offs;
835 entry = EXT2_EXTATTR_NEXT(entry);
838 pad = (char*)entry + sizeof(uint32_t);
840 /* Find entry insert position */
841 name_len = strlen(name);
843 while (!EXT2_IS_LAST_ENTRY(entry)) {
844 if (!(attrnamespace - entry->e_name_index) &&
845 !(name_len - entry->e_name_len))
846 if (memcmp(name, entry->e_name, name_len) <= 0)
849 entry = EXT2_EXTATTR_NEXT(entry);
852 /* Create new entry and insert it */
853 new_entry = allocate_entry(name, attrnamespace, 0, uio->uio_resid, 0);
854 memmove((char *)entry + EXT2_EXTATTR_LEN(new_entry->e_name_len), entry,
857 memcpy(entry, new_entry, EXT2_EXTATTR_LEN(new_entry->e_name_len));
858 free_entry(new_entry);
861 if (new_entry->e_value_size > 0)
862 new_entry->e_value_offs = min_offs -
863 EXT2_EXTATTR_SIZE(new_entry->e_value_size);
865 uiomove(off + new_entry->e_value_offs, new_entry->e_value_size, uio);
871 ext2_extattr_inode_set(struct inode *ip, int attrnamespace,
872 const char *name, struct uio *uio)
876 struct ext2fs_extattr_dinode_header *header;
877 struct ext2fs_extattr_entry *entry;
878 const char *attr_name;
880 size_t size = 0, max_size;
885 if ((error = bread(ip->i_devvp,
886 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
887 (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
892 struct ext2fs_dinode *dinode = (struct ext2fs_dinode *)
893 ((char *)bp->b_data +
894 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number));
896 /* Check attributes magic value */
897 header = (struct ext2fs_extattr_dinode_header *)((char *)dinode +
898 E2FS_REV0_INODE_SIZE + dinode->e2di_extra_isize);
900 if (header->h_magic != EXTATTR_MAGIC) {
905 error = ext2_extattr_check(EXT2_IFIRST(header), (char *)dinode +
906 EXT2_INODE_SIZE(fs));
912 /* Find if entry exist */
913 for (entry = EXT2_IFIRST(header); !EXT2_IS_LAST_ENTRY(entry);
914 entry = EXT2_EXTATTR_NEXT(entry)) {
915 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
919 name_len = entry->e_name_len;
920 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
921 entry->e_name, &name_len);
927 if (strlen(name) == name_len &&
928 0 == strncmp(attr_name, name, name_len))
932 max_size = EXT2_INODE_SIZE(fs) - E2FS_REV0_INODE_SIZE -
933 dinode->e2di_extra_isize;
935 if (!EXT2_IS_LAST_ENTRY(entry)) {
936 size = ext2_extattr_get_size(EXT2_IFIRST(header), entry,
937 sizeof(struct ext2fs_extattr_dinode_header),
938 entry->e_name_len, uio->uio_resid);
939 if (size > max_size) {
944 ext2_extattr_set_exist_entry((char *)EXT2_IFIRST(header),
945 EXT2_IFIRST(header), entry, (char *)header + max_size, uio);
947 /* Ensure that the same entry does not exist in the block */
949 error = ext2_extattr_block_get(ip, attrnamespace, name,
951 if (error != ENOATTR || size > 0) {
960 size = ext2_extattr_get_size(EXT2_IFIRST(header), NULL,
961 sizeof(struct ext2fs_extattr_dinode_header),
962 entry->e_name_len, uio->uio_resid);
963 if (size > max_size) {
968 ext2_extattr_set_new_entry((char *)EXT2_IFIRST(header),
969 EXT2_IFIRST(header), name, attrnamespace,
970 (char *)header + max_size, uio);
977 ext2_extattr_hash_entry(struct ext2fs_extattr_header *header,
978 struct ext2fs_extattr_entry *entry)
981 char *name = entry->e_name;
984 for (n=0; n < entry->e_name_len; n++) {
985 hash = (hash << EXT2_EXTATTR_NAME_HASH_SHIFT) ^
986 (hash >> (8*sizeof(hash) - EXT2_EXTATTR_NAME_HASH_SHIFT)) ^
990 if (entry->e_value_block == 0 && entry->e_value_size != 0) {
991 uint32_t *value = (uint32_t *)((char *)header + entry->e_value_offs);
992 for (n = (entry->e_value_size +
993 EXT2_EXTATTR_ROUND) >> EXT2_EXTATTR_PAD_BITS; n; n--) {
994 hash = (hash << EXT2_EXTATTR_VALUE_HASH_SHIFT) ^
995 (hash >> (8*sizeof(hash) - EXT2_EXTATTR_VALUE_HASH_SHIFT)) ^
1000 entry->e_hash = hash;
1004 ext2_extattr_rehash(struct ext2fs_extattr_header *header,
1005 struct ext2fs_extattr_entry *entry)
1007 struct ext2fs_extattr_entry *here;
1010 ext2_extattr_hash_entry(header, entry);
1012 here = EXT2_ENTRY(header+1);
1013 while (!EXT2_IS_LAST_ENTRY(here)) {
1014 if (!here->e_hash) {
1015 /* Block is not shared if an entry's hash value == 0 */
1020 hash = (hash << EXT2_EXTATTR_BLOCK_HASH_SHIFT) ^
1021 (hash >> (8*sizeof(hash) - EXT2_EXTATTR_BLOCK_HASH_SHIFT)) ^
1024 here = EXT2_EXTATTR_NEXT(here);
1027 header->h_hash = hash;
1031 ext2_extattr_block_set(struct inode *ip, int attrnamespace,
1032 const char *name, struct uio *uio)
1034 struct m_ext2fs *fs;
1036 struct ext2fs_extattr_header *header;
1037 struct ext2fs_extattr_entry *entry;
1038 const char *attr_name;
1046 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
1047 fs->e2fs_bsize, NOCRED, &bp);
1053 /* Check attributes magic value */
1054 header = EXT2_HDR(bp);
1055 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
1060 error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp),
1061 bp->b_data + bp->b_bufsize);
1067 if (header->h_refcount > 1) {
1068 error = ext2_extattr_block_clone(ip, &bp);
1074 header = EXT2_HDR(bp);
1077 /* Find if entry exist */
1078 for (entry = EXT2_FIRST_ENTRY(bp); !EXT2_IS_LAST_ENTRY(entry);
1079 entry = EXT2_EXTATTR_NEXT(entry)) {
1080 if (ext2_extattr_attrnamespace_to_bsd(entry->e_name_index) !=
1084 name_len = entry->e_name_len;
1085 attr_name = ext2_extattr_name_to_bsd(entry->e_name_index,
1086 entry->e_name, &name_len);
1092 if (strlen(name) == name_len &&
1093 0 == strncmp(attr_name, name, name_len))
1097 if (!EXT2_IS_LAST_ENTRY(entry)) {
1098 size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), entry,
1099 sizeof(struct ext2fs_extattr_header),
1100 entry->e_name_len, uio->uio_resid);
1101 if (size > bp->b_bufsize) {
1106 ext2_extattr_set_exist_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
1107 entry, bp->b_data + bp->b_bufsize, uio);
1109 size = ext2_extattr_get_size(EXT2_FIRST_ENTRY(bp), NULL,
1110 sizeof(struct ext2fs_extattr_header),
1111 strlen(name), uio->uio_resid);
1112 if (size > bp->b_bufsize) {
1117 entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
1118 name, attrnamespace, bp->b_data + bp->b_bufsize, uio);
1120 /* Clean the same entry in the inode */
1121 error = ext2_extattr_inode_delete(ip, attrnamespace, name);
1122 if (error && error != ENOATTR) {
1128 ext2_extattr_rehash(header, entry);
1130 return (bwrite(bp));
1133 size = ext2_extattr_get_size(NULL, NULL,
1134 sizeof(struct ext2fs_extattr_header),
1135 strlen(ext2_extattr_name_to_linux(attrnamespace, name)), uio->uio_resid);
1136 if (size > fs->e2fs_bsize)
1139 /* Allocate block, fill EA header and insert entry */
1140 ip->i_facl = ext2_allocfacl(ip);
1141 if (0 == ip->i_facl)
1144 ip->i_blocks += btodb(fs->e2fs_bsize);
1145 ext2_update(ip->i_vnode, 1);
1147 bp = getblk(ip->i_devvp, fsbtodb(fs, ip->i_facl), fs->e2fs_bsize, 0, 0, 0);
1149 ext2_blkfree(ip, ip->i_facl, fs->e2fs_bsize);
1150 ip->i_blocks -= btodb(fs->e2fs_bsize);
1152 ext2_update(ip->i_vnode, 1);
1156 header = EXT2_HDR(bp);
1157 header->h_magic = EXTATTR_MAGIC;
1158 header->h_refcount = 1;
1159 header->h_blocks = 1;
1161 memset(header->h_reserved, 0, sizeof(header->h_reserved));
1162 memcpy(bp->b_data, header, sizeof(struct ext2fs_extattr_header));
1163 memset(EXT2_FIRST_ENTRY(bp), 0, sizeof(uint32_t));
1165 entry = ext2_extattr_set_new_entry(bp->b_data, EXT2_FIRST_ENTRY(bp),
1166 name, attrnamespace, bp->b_data + bp->b_bufsize, uio);
1168 /* Clean the same entry in the inode */
1169 error = ext2_extattr_inode_delete(ip, attrnamespace, name);
1170 if (error && error != ENOATTR) {
1175 ext2_extattr_rehash(header, entry);
1177 return (bwrite(bp));
1180 int ext2_extattr_free(struct inode *ip)
1182 struct m_ext2fs *fs;
1184 struct ext2fs_extattr_header *header;
1192 error = bread(ip->i_devvp, fsbtodb(fs, ip->i_facl),
1193 fs->e2fs_bsize, NOCRED, &bp);
1199 /* Check attributes magic value */
1200 header = EXT2_HDR(bp);
1201 if (header->h_magic != EXTATTR_MAGIC || header->h_blocks != 1) {
1206 error = ext2_extattr_check(EXT2_FIRST_ENTRY(bp), bp->b_data + bp->b_bufsize);
1212 if (header->h_refcount > 1) {
1213 header->h_refcount--;
1216 ext2_blkfree(ip, ip->i_facl, ip->i_e2fs->e2fs_bsize);
1220 ip->i_blocks -= btodb(ip->i_e2fs->e2fs_bsize);
1222 ext2_update(ip->i_vnode, 1);