inode.c revision a78926effb15bbabb1c0ed3e438b03be25c4d48c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * inode.c --- utility routines to read and write inodes
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * %Begin-Header%
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This file may be redistributed under the terms of the GNU Public
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * License.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * %End-Header%
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <string.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if HAVE_UNISTD_H
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <unistd.h>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if HAVE_SYS_STAT_H
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h>
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if HAVE_SYS_TYPES_H
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if EXT2_FLAT_INCLUDES
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ext2_fs.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <linux/ext2_fs.h>
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ext2fsP.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "e2image.h"
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)struct ext2_struct_inode_scan {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	errcode_t		magic;
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)	ext2_filsys		fs;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ext2_ino_t		current_inode;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	blk_t			current_block;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	dgrp_t			current_group;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ext2_ino_t		inodes_left;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	blk_t			blocks_left;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	dgrp_t			groups_left;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	blk_t			inode_buffer_blocks;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char *			inode_buffer;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int			inode_size;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char *			ptr;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int			bytes_left;
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)	char			*temp_buffer;
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)	errcode_t		(*done_group)(ext2_filsys fs,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					      ext2_inode_scan scan,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					      dgrp_t group,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					      void * priv_data);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	void *			done_group_data;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int			bad_block_ptr;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int			scan_flags;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int			reserved[6];
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This routine flushes the icache, if it exists.
607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) */
617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)errcode_t ext2fs_flush_icache(ext2_filsys fs)
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles){
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)	int	i;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!fs->icache)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return 0;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i=0; i < fs->icache->cache_size; i++)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		fs->icache->cache[i].ino = 0;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static errcode_t create_icache(ext2_filsys fs)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)	errcode_t	retval;
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (fs->icache)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return 0;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache),
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				(void **) &fs->icache);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (retval)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return retval;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)	memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	retval = ext2fs_get_mem(fs->blocksize, (void **) &fs->icache->buffer);
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)	if (retval) {
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)		ext2fs_free_mem((void **) &fs->icache);
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)		return retval;
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)	}
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)	fs->icache->buffer_blk = 0;
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)	fs->icache->cache_last = -1;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	fs->icache->cache_size = 4;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	fs->icache->refcount = 1;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache_ent)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				* fs->icache->cache_size,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				(void **) &fs->icache->cache);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (retval) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ext2fs_free_mem((void **) &fs->icache->buffer);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ext2fs_free_mem((void **) &fs->icache);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return retval;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ext2fs_flush_icache(fs);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				 ext2_inode_scan *ret_scan)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ext2_inode_scan	scan;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	errcode_t	retval;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * If fs->badblocks isn't set, then set it --- since the inode
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * scanning functions require it.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
120c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch	if (fs->badblocks == 0) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/*
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 * Temporarly save fs->get_blocks and set it to zero,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		 * for compatibility with old e2fsck's.
124c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch		 */
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		save_get_blocks = fs->get_blocks;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		fs->get_blocks = 0;
127c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch		retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (retval && fs->badblocks) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			badblocks_list_free(fs->badblocks);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			fs->badblocks = 0;
131c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch		}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		fs->get_blocks = save_get_blocks;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan),
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				(void **) &scan);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (retval)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return retval;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->fs = fs;
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	scan->inode_size = EXT2_INODE_SIZE(fs->super);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->bytes_left = 0;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->current_group = 0;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->groups_left = fs->group_desc_count - 1;
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->current_block = scan->fs->
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		group_desc[scan->current_group].bg_inode_table;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->blocks_left = scan->fs->inode_blocks_per_group;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	retval = ext2fs_get_mem((size_t) (scan->inode_buffer_blocks *
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)					  fs->blocksize),
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				(void **) &scan->inode_buffer);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->done_group = 0;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->done_group_data = 0;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->bad_block_ptr = 0;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (retval) {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ext2fs_free_mem((void **) &scan);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return retval;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	retval = ext2fs_get_mem(scan->inode_size,
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				(void **) &scan->temp_buffer);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (retval) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ext2fs_free_mem((void **) &scan->inode_buffer);
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ext2fs_free_mem((void **) &scan);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return retval;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (scan->fs->badblocks && scan->fs->badblocks->num)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	*ret_scan = scan;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ext2fs_close_inode_scan(ext2_inode_scan scan)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ext2fs_free_mem((void **) &scan->inode_buffer);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->inode_buffer = NULL;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ext2fs_free_mem((void **) &scan->temp_buffer);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->temp_buffer = NULL;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ext2fs_free_mem((void **) &scan);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ext2fs_set_inode_callback(ext2_inode_scan scan,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			       errcode_t (*done_group)(ext2_filsys fs,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						       ext2_inode_scan scan,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						       dgrp_t group,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)						       void * priv_data),
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			       void *done_group_data)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->done_group = done_group;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->done_group_data = done_group_data;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			    int clear_flags)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int	old_flags;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
207e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)		return 0;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	old_flags = scan->scan_flags;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->scan_flags &= ~clear_flags;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->scan_flags |= set_flags;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return old_flags;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This function is called by ext2fs_get_next_inode when it needs to
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * get ready to read in a new blockgroup.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static errcode_t get_next_blockgroup(ext2_inode_scan scan)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->current_group++;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->groups_left--;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->current_block = scan->fs->
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		group_desc[scan->current_group].bg_inode_table;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->current_inode = scan->current_group *
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		EXT2_INODES_PER_GROUP(scan->fs->super);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->bytes_left = 0;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->blocks_left = scan->fs->inode_blocks_per_group;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					    int	group)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->current_group = group - 1;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->groups_left = scan->fs->group_desc_count - group;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return get_next_blockgroup(scan);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This function is called by get_next_blocks() to check for bad
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * blocks in the inode table.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This function assumes that badblocks_list->list is sorted in
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * increasing order.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					    blk_t *num_blocks)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	blk_t	blk = scan->current_block;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	badblocks_list	bb = scan->fs->badblocks;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * If the inode table is missing, then obviously there are no
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * bad blocks.  :-)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (blk == 0)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return 0;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * If the current block is greater than the bad block listed
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * in the bad block list, then advance the pointer until this
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * is no longer the case.  If we run out of bad blocks, then
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * we don't need to do any more checking!
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	while (blk > bb->list[scan->bad_block_ptr]) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (++scan->bad_block_ptr >= bb->num) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return 0;
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci		}
2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	}
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	/*
2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	 * If the current block is equal to the bad block listed in
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	 * the bad block list, then handle that one block specially.
2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	 * (We could try to handle runs of bad blocks, but that
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	 * only increases CPU efficiency by a small amount, at the
2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci	 * expense of a huge expense of code complexity, and for an
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * uncommon case at that.)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (blk == bb->list[scan->bad_block_ptr]) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		*num_blocks = 1;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (++scan->bad_block_ptr >= bb->num)
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)			scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return 0;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	/*
295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch	 * If there is a bad block in the range that we're about to
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * read in, adjust the number of blocks to read so that we we
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * don't read in the bad block.  (Then the next block to read
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * will be the bad block, which is handled in the above case.)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		*num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This function is called by ext2fs_get_next_inode when it needs to
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * read in more blocks from the current blockgroup's inode table.
309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static errcode_t get_next_blocks(ext2_inode_scan scan)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	blk_t		num_blocks;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	errcode_t	retval;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * Figure out how many blocks to read; we read at most
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * inode_buffer_blocks, and perhaps less if there aren't that
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * many blocks left to read.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	num_blocks = scan->inode_buffer_blocks;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (num_blocks > scan->blocks_left)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		num_blocks = scan->blocks_left;
32303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * If the past block "read" was a bad block, then mark the
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * left-over extra bytes as also being bad.
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (scan->bytes_left)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * Do inode bad block processing, if necessary.
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		retval = check_for_inode_bad_blocks(scan, &num_blocks);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (retval)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return retval;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    (scan->current_block == 0)) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		memset(scan->inode_buffer, 0,
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		       (size_t) num_blocks * scan->fs->blocksize);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		retval = io_channel_read_blk(scan->fs->io,
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					     scan->current_block,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					     (int) num_blocks,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					     scan->inode_buffer);
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (retval)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return EXT2_ET_NEXT_INODE_READ;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->ptr = scan->inode_buffer;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->bytes_left = num_blocks * scan->fs->blocksize;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	scan->blocks_left -= num_blocks;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (scan->current_block)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		scan->current_block += num_blocks;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if 0
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Returns 1 if the entire inode_buffer has a non-zero size and
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * contains all zeros.  (Not just deleted inodes, since that means
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * that part of the inode table was used at one point; we want all
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * zeros, which means that the inode table is pristine.)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static inline int is_empty_scan(ext2_inode_scan scan)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int	i;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (scan->bytes_left == 0)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return 0;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	for (i=0; i < scan->bytes_left; i++)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (scan->ptr[i])
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return 0;
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 1;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				struct ext2_inode *inode)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	errcode_t	retval;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int		extra_bytes = 0;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * Do we need to start reading a new block group?
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (scan->inodes_left <= 0) {
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	force_new_group:
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (scan->done_group) {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			retval = (scan->done_group)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				(scan->fs, scan, scan->current_group,
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				 scan->done_group_data);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (retval)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				return retval;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (scan->groups_left <= 0) {
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			*ino = 0;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return 0;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		retval = get_next_blockgroup(scan);
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (retval)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return retval;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * This is done outside the above if statement so that the
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * check can be done for block group #0.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (scan->current_block == 0) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			goto force_new_group;
420		} else
421			return EXT2_ET_MISSING_INODE_TABLE;
422	}
423
424
425	/*
426	 * Have we run out of space in the inode buffer?  If so, we
427	 * need to read in more blocks.
428	 */
429	if (scan->bytes_left < scan->inode_size) {
430		memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
431		extra_bytes = scan->bytes_left;
432
433		retval = get_next_blocks(scan);
434		if (retval)
435			return retval;
436#if 0
437		/*
438		 * XXX test  Need check for used inode somehow.
439		 * (Note: this is hard.)
440		 */
441		if (is_empty_scan(scan))
442			goto force_new_group;
443#endif
444	}
445
446	retval = 0;
447	if (extra_bytes) {
448		memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
449		       scan->inode_size - extra_bytes);
450		scan->ptr += scan->inode_size - extra_bytes;
451		scan->bytes_left -= scan->inode_size - extra_bytes;
452
453		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
454		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
455			ext2fs_swap_inode(scan->fs, inode,
456				 (struct ext2_inode *) scan->temp_buffer, 0);
457		else
458			*inode = *((struct ext2_inode *) scan->temp_buffer);
459		if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
460			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
461		scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
462	} else {
463		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
464		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
465			ext2fs_swap_inode(scan->fs, inode,
466				 (struct ext2_inode *) scan->ptr, 0);
467		else
468			*inode = *((struct ext2_inode *) scan->ptr);
469		scan->ptr += scan->inode_size;
470		scan->bytes_left -= scan->inode_size;
471		if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
472			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
473	}
474
475	scan->inodes_left--;
476	scan->current_inode++;
477	*ino = scan->current_inode;
478	return retval;
479}
480
481/*
482 * Functions to read and write a single inode.
483 */
484errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
485			     struct ext2_inode * inode)
486{
487	unsigned long 	group, block, block_nr, offset;
488	char 		*ptr;
489	errcode_t	retval;
490	int 		clen, length, i, inodes_per_block;
491
492	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
493
494	/* Check to see if user has an override function */
495	if (fs->read_inode) {
496		retval = (fs->read_inode)(fs, ino, inode);
497		if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
498			return retval;
499	}
500	/* Create inode cache if not present */
501	if (!fs->icache) {
502		retval = create_icache(fs);
503		if (retval)
504			return retval;
505	}
506	/* Check to see if it's in the inode cache */
507	for (i=0; i < fs->icache->cache_size; i++) {
508		if (fs->icache->cache[i].ino == ino) {
509			*inode = fs->icache->cache[i].inode;
510			return 0;
511		}
512	}
513	if ((ino == 0) || (ino > fs->super->s_inodes_count))
514		return EXT2_ET_BAD_INODE_NUM;
515	if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
516		inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
517		block_nr = fs->image_header->offset_inode / fs->blocksize;
518		block_nr += (ino - 1) / inodes_per_block;
519		offset = ((ino - 1) % inodes_per_block) *
520			EXT2_INODE_SIZE(fs->super);
521	} else {
522		group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
523		offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
524			EXT2_INODE_SIZE(fs->super);
525		block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
526		if (!fs->group_desc[(unsigned)group].bg_inode_table)
527			return EXT2_ET_MISSING_INODE_TABLE;
528		block_nr = fs->group_desc[(unsigned)group].bg_inode_table +
529			block;
530	}
531	if (block_nr != fs->icache->buffer_blk) {
532		retval = io_channel_read_blk(fs->io, block_nr, 1,
533					     fs->icache->buffer);
534		if (retval)
535			return retval;
536		fs->icache->buffer_blk = block_nr;
537	}
538	offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
539	ptr = ((char *) fs->icache->buffer) + (unsigned) offset;
540
541	memset(inode, 0, sizeof(struct ext2_inode));
542	length = EXT2_INODE_SIZE(fs->super);
543	if (length > sizeof(struct ext2_inode))
544		length = sizeof(struct ext2_inode);
545
546	if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) {
547		clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
548		memcpy((char *) inode, ptr, clen);
549		length -= clen;
550
551		retval = io_channel_read_blk(fs->io, block_nr+1, 1,
552					     fs->icache->buffer);
553		if (retval) {
554			fs->icache->buffer_blk = 0;
555			return retval;
556		}
557		fs->icache->buffer_blk = block_nr+1;
558
559		memcpy(((char *) inode) + clen,
560		       fs->icache->buffer, length);
561	} else
562		memcpy((char *) inode, ptr, length);
563
564	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
565	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
566		ext2fs_swap_inode(fs, inode, inode, 0);
567
568	/* Update the inode cache */
569	fs->icache->cache_last = (fs->icache->cache_last + 1) %
570		fs->icache->cache_size;
571	fs->icache->cache[fs->icache->cache_last].ino = ino;
572	fs->icache->cache[fs->icache->cache_last].inode = *inode;
573
574	return 0;
575}
576
577errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
578			     struct ext2_inode * inode)
579{
580	unsigned long group, block, block_nr, offset;
581	errcode_t	retval;
582	struct ext2_inode temp_inode;
583	char *ptr;
584	int clen, length, i;
585
586	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
587
588	/* Check to see if user provided an override function */
589	if (fs->write_inode) {
590		retval = (fs->write_inode)(fs, ino, inode);
591		if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
592			return retval;
593	}
594
595	/* Check to see if the inode cache needs to be updated */
596	if (fs->icache) {
597		for (i=0; i < fs->icache->cache_size; i++) {
598			if (fs->icache->cache[i].ino == ino) {
599				fs->icache->cache[i].inode = *inode;
600				break;
601			}
602		}
603	} else {
604		retval = create_icache(fs);
605		if (retval)
606			return retval;
607	}
608
609	if (!(fs->flags & EXT2_FLAG_RW))
610		return EXT2_ET_RO_FILSYS;
611
612	if ((ino == 0) || (ino > fs->super->s_inodes_count))
613		return EXT2_ET_BAD_INODE_NUM;
614
615	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
616	    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
617		ext2fs_swap_inode(fs, &temp_inode, inode, 1);
618	else
619		memcpy(&temp_inode, inode, sizeof(struct ext2_inode));
620
621	group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
622	offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
623		EXT2_INODE_SIZE(fs->super);
624	block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
625	if (!fs->group_desc[(unsigned) group].bg_inode_table)
626		return EXT2_ET_MISSING_INODE_TABLE;
627	block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
628	offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
629	ptr = (char *) fs->icache->buffer + (unsigned) offset;
630
631	length = EXT2_INODE_SIZE(fs->super);
632	clen = length;
633	if (length > sizeof(struct ext2_inode))
634		length = sizeof(struct ext2_inode);
635
636	if (fs->icache->buffer_blk != block_nr) {
637		retval = io_channel_read_blk(fs->io, block_nr, 1,
638					     fs->icache->buffer);
639		if (retval)
640			return retval;
641		fs->icache->buffer_blk = block_nr;
642	}
643
644	if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) {
645		clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
646		length -= clen;
647	} else {
648		length = 0;
649	}
650	memcpy(ptr, &temp_inode, clen);
651	retval = io_channel_write_blk(fs->io, block_nr, 1, fs->icache->buffer);
652	if (retval)
653		return retval;
654
655	if (length) {
656		retval = io_channel_read_blk(fs->io, ++block_nr, 1,
657					     fs->icache->buffer);
658		if (retval) {
659			fs->icache->buffer_blk = 0;
660			return retval;
661		}
662		fs->icache->buffer_blk = block_nr;
663		memcpy(fs->icache->buffer, ((char *) &temp_inode) + clen,
664		       length);
665
666		retval = io_channel_write_blk(fs->io, block_nr, 1,
667					      fs->icache->buffer);
668		if (retval)
669			return retval;
670	}
671
672	fs->flags |= EXT2_FLAG_CHANGED;
673	return 0;
674}
675
676errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
677{
678	struct ext2_inode	inode;
679	int			i;
680	errcode_t		retval;
681
682	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
683
684	if (ino > fs->super->s_inodes_count)
685		return EXT2_ET_BAD_INODE_NUM;
686
687	if (fs->get_blocks) {
688		if (!(*fs->get_blocks)(fs, ino, blocks))
689			return 0;
690	}
691	retval = ext2fs_read_inode(fs, ino, &inode);
692	if (retval)
693		return retval;
694	for (i=0; i < EXT2_N_BLOCKS; i++)
695		blocks[i] = inode.i_block[i];
696	return 0;
697}
698
699errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
700{
701	struct	ext2_inode	inode;
702	errcode_t		retval;
703
704	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
705
706	if (ino > fs->super->s_inodes_count)
707		return EXT2_ET_BAD_INODE_NUM;
708
709	if (fs->check_directory) {
710		retval = (fs->check_directory)(fs, ino);
711		if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
712			return retval;
713	}
714	retval = ext2fs_read_inode(fs, ino, &inode);
715	if (retval)
716		return retval;
717	if (!LINUX_S_ISDIR(inode.i_mode))
718		return EXT2_ET_NO_DIRECTORY;
719	return 0;
720}
721
722