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