inode.c revision 71669d0541f0d3db64792c60a28abddba78382e2
1/*
2 * inode.c --- utility routines to read and write inodes
3 *
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#if HAVE_SYS_STAT_H
18#include <sys/stat.h>
19#endif
20#if HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23
24#include "ext2_fs.h"
25#include "ext2fsP.h"
26#include "e2image.h"
27
28struct ext2_struct_inode_scan {
29	errcode_t		magic;
30	ext2_filsys		fs;
31	ext2_ino_t		current_inode;
32	blk_t			current_block;
33	dgrp_t			current_group;
34	ext2_ino_t		inodes_left;
35	blk_t			blocks_left;
36	dgrp_t			groups_left;
37	blk_t			inode_buffer_blocks;
38	char *			inode_buffer;
39	int			inode_size;
40	char *			ptr;
41	int			bytes_left;
42	char			*temp_buffer;
43	errcode_t		(*done_group)(ext2_filsys fs,
44					      ext2_inode_scan scan,
45					      dgrp_t group,
46					      void * priv_data);
47	void *			done_group_data;
48	int			bad_block_ptr;
49	int			scan_flags;
50	int			reserved[6];
51};
52
53/*
54 * This routine flushes the icache, if it exists.
55 */
56errcode_t ext2fs_flush_icache(ext2_filsys fs)
57{
58	int	i;
59
60	if (!fs->icache)
61		return 0;
62
63	for (i=0; i < fs->icache->cache_size; i++)
64		fs->icache->cache[i].ino = 0;
65
66	fs->icache->buffer_blk = 0;
67	return 0;
68}
69
70static errcode_t create_icache(ext2_filsys fs)
71{
72	errcode_t	retval;
73
74	if (fs->icache)
75		return 0;
76	retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), &fs->icache);
77	if (retval)
78		return retval;
79
80	memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
81	retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer);
82	if (retval) {
83		ext2fs_free_mem(&fs->icache);
84		return retval;
85	}
86	fs->icache->buffer_blk = 0;
87	fs->icache->cache_last = -1;
88	fs->icache->cache_size = 4;
89	fs->icache->refcount = 1;
90	retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache_ent)
91				* fs->icache->cache_size,
92				&fs->icache->cache);
93	if (retval) {
94		ext2fs_free_mem(&fs->icache->buffer);
95		ext2fs_free_mem(&fs->icache);
96		return retval;
97	}
98	ext2fs_flush_icache(fs);
99	return 0;
100}
101
102errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
103				 ext2_inode_scan *ret_scan)
104{
105	ext2_inode_scan	scan;
106	errcode_t	retval;
107	errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks);
108
109	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
110
111	/*
112	 * If fs->badblocks isn't set, then set it --- since the inode
113	 * scanning functions require it.
114	 */
115	if (fs->badblocks == 0) {
116		/*
117		 * Temporarly save fs->get_blocks and set it to zero,
118		 * for compatibility with old e2fsck's.
119		 */
120		save_get_blocks = fs->get_blocks;
121		fs->get_blocks = 0;
122		retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
123		if (retval && fs->badblocks) {
124			ext2fs_badblocks_list_free(fs->badblocks);
125			fs->badblocks = 0;
126		}
127		fs->get_blocks = save_get_blocks;
128	}
129
130	retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), &scan);
131	if (retval)
132		return retval;
133	memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
134
135	scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
136	scan->fs = fs;
137	scan->inode_size = EXT2_INODE_SIZE(fs->super);
138	scan->bytes_left = 0;
139	scan->current_group = 0;
140	scan->groups_left = fs->group_desc_count - 1;
141	scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
142	scan->current_block = scan->fs->
143		group_desc[scan->current_group].bg_inode_table;
144	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
145	scan->blocks_left = scan->fs->inode_blocks_per_group;
146	retval = ext2fs_get_mem((size_t) (scan->inode_buffer_blocks *
147					  fs->blocksize),
148				&scan->inode_buffer);
149	scan->done_group = 0;
150	scan->done_group_data = 0;
151	scan->bad_block_ptr = 0;
152	if (retval) {
153		ext2fs_free_mem(&scan);
154		return retval;
155	}
156	retval = ext2fs_get_mem(scan->inode_size, &scan->temp_buffer);
157	if (retval) {
158		ext2fs_free_mem(&scan->inode_buffer);
159		ext2fs_free_mem(&scan);
160		return retval;
161	}
162	if (scan->fs->badblocks && scan->fs->badblocks->num)
163		scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
164	*ret_scan = scan;
165	return 0;
166}
167
168void ext2fs_close_inode_scan(ext2_inode_scan scan)
169{
170	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
171		return;
172
173	ext2fs_free_mem(&scan->inode_buffer);
174	scan->inode_buffer = NULL;
175	ext2fs_free_mem(&scan->temp_buffer);
176	scan->temp_buffer = NULL;
177	ext2fs_free_mem(&scan);
178	return;
179}
180
181void ext2fs_set_inode_callback(ext2_inode_scan scan,
182			       errcode_t (*done_group)(ext2_filsys fs,
183						       ext2_inode_scan scan,
184						       dgrp_t group,
185						       void * priv_data),
186			       void *done_group_data)
187{
188	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
189		return;
190
191	scan->done_group = done_group;
192	scan->done_group_data = done_group_data;
193}
194
195int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
196			    int clear_flags)
197{
198	int	old_flags;
199
200	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
201		return 0;
202
203	old_flags = scan->scan_flags;
204	scan->scan_flags &= ~clear_flags;
205	scan->scan_flags |= set_flags;
206	return old_flags;
207}
208
209/*
210 * This function is called by ext2fs_get_next_inode when it needs to
211 * get ready to read in a new blockgroup.
212 */
213static errcode_t get_next_blockgroup(ext2_inode_scan scan)
214{
215	scan->current_group++;
216	scan->groups_left--;
217
218	scan->current_block = scan->fs->
219		group_desc[scan->current_group].bg_inode_table;
220
221	scan->current_inode = scan->current_group *
222		EXT2_INODES_PER_GROUP(scan->fs->super);
223
224	scan->bytes_left = 0;
225	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
226	scan->blocks_left = scan->fs->inode_blocks_per_group;
227	return 0;
228}
229
230errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
231					    int	group)
232{
233	scan->current_group = group - 1;
234	scan->groups_left = scan->fs->group_desc_count - group;
235	return get_next_blockgroup(scan);
236}
237
238/*
239 * This function is called by get_next_blocks() to check for bad
240 * blocks in the inode table.
241 *
242 * This function assumes that badblocks_list->list is sorted in
243 * increasing order.
244 */
245static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
246					    blk_t *num_blocks)
247{
248	blk_t	blk = scan->current_block;
249	badblocks_list	bb = scan->fs->badblocks;
250
251	/*
252	 * If the inode table is missing, then obviously there are no
253	 * bad blocks.  :-)
254	 */
255	if (blk == 0)
256		return 0;
257
258	/*
259	 * If the current block is greater than the bad block listed
260	 * in the bad block list, then advance the pointer until this
261	 * is no longer the case.  If we run out of bad blocks, then
262	 * we don't need to do any more checking!
263	 */
264	while (blk > bb->list[scan->bad_block_ptr]) {
265		if (++scan->bad_block_ptr >= bb->num) {
266			scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
267			return 0;
268		}
269	}
270
271	/*
272	 * If the current block is equal to the bad block listed in
273	 * the bad block list, then handle that one block specially.
274	 * (We could try to handle runs of bad blocks, but that
275	 * only increases CPU efficiency by a small amount, at the
276	 * expense of a huge expense of code complexity, and for an
277	 * uncommon case at that.)
278	 */
279	if (blk == bb->list[scan->bad_block_ptr]) {
280		scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
281		*num_blocks = 1;
282		if (++scan->bad_block_ptr >= bb->num)
283			scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
284		return 0;
285	}
286
287	/*
288	 * If there is a bad block in the range that we're about to
289	 * read in, adjust the number of blocks to read so that we we
290	 * don't read in the bad block.  (Then the next block to read
291	 * will be the bad block, which is handled in the above case.)
292	 */
293	if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
294		*num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
295
296	return 0;
297}
298
299/*
300 * This function is called by ext2fs_get_next_inode when it needs to
301 * read in more blocks from the current blockgroup's inode table.
302 */
303static errcode_t get_next_blocks(ext2_inode_scan scan)
304{
305	blk_t		num_blocks;
306	errcode_t	retval;
307
308	/*
309	 * Figure out how many blocks to read; we read at most
310	 * inode_buffer_blocks, and perhaps less if there aren't that
311	 * many blocks left to read.
312	 */
313	num_blocks = scan->inode_buffer_blocks;
314	if (num_blocks > scan->blocks_left)
315		num_blocks = scan->blocks_left;
316
317	/*
318	 * If the past block "read" was a bad block, then mark the
319	 * left-over extra bytes as also being bad.
320	 */
321	if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
322		if (scan->bytes_left)
323			scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
324		scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
325	}
326
327	/*
328	 * Do inode bad block processing, if necessary.
329	 */
330	if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
331		retval = check_for_inode_bad_blocks(scan, &num_blocks);
332		if (retval)
333			return retval;
334	}
335
336	if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
337	    (scan->current_block == 0)) {
338		memset(scan->inode_buffer, 0,
339		       (size_t) num_blocks * scan->fs->blocksize);
340	} else {
341		retval = io_channel_read_blk(scan->fs->io,
342					     scan->current_block,
343					     (int) num_blocks,
344					     scan->inode_buffer);
345		if (retval)
346			return EXT2_ET_NEXT_INODE_READ;
347	}
348	scan->ptr = scan->inode_buffer;
349	scan->bytes_left = num_blocks * scan->fs->blocksize;
350
351	scan->blocks_left -= num_blocks;
352	if (scan->current_block)
353		scan->current_block += num_blocks;
354	return 0;
355}
356
357#if 0
358/*
359 * Returns 1 if the entire inode_buffer has a non-zero size and
360 * contains all zeros.  (Not just deleted inodes, since that means
361 * that part of the inode table was used at one point; we want all
362 * zeros, which means that the inode table is pristine.)
363 */
364static inline int is_empty_scan(ext2_inode_scan scan)
365{
366	int	i;
367
368	if (scan->bytes_left == 0)
369		return 0;
370
371	for (i=0; i < scan->bytes_left; i++)
372		if (scan->ptr[i])
373			return 0;
374	return 1;
375}
376#endif
377
378errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
379				struct ext2_inode *inode)
380{
381	errcode_t	retval;
382	int		extra_bytes = 0;
383
384	EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
385
386	/*
387	 * Do we need to start reading a new block group?
388	 */
389	if (scan->inodes_left <= 0) {
390	force_new_group:
391		if (scan->done_group) {
392			retval = (scan->done_group)
393				(scan->fs, scan, scan->current_group,
394				 scan->done_group_data);
395			if (retval)
396				return retval;
397		}
398		if (scan->groups_left <= 0) {
399			*ino = 0;
400			return 0;
401		}
402		retval = get_next_blockgroup(scan);
403		if (retval)
404			return retval;
405	}
406	/*
407	 * This is done outside the above if statement so that the
408	 * check can be done for block group #0.
409	 */
410	if (scan->current_block == 0) {
411		if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
412			goto force_new_group;
413		} else
414			return EXT2_ET_MISSING_INODE_TABLE;
415	}
416
417
418	/*
419	 * Have we run out of space in the inode buffer?  If so, we
420	 * need to read in more blocks.
421	 */
422	if (scan->bytes_left < scan->inode_size) {
423		memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
424		extra_bytes = scan->bytes_left;
425
426		retval = get_next_blocks(scan);
427		if (retval)
428			return retval;
429#if 0
430		/*
431		 * XXX test  Need check for used inode somehow.
432		 * (Note: this is hard.)
433		 */
434		if (is_empty_scan(scan))
435			goto force_new_group;
436#endif
437	}
438
439	retval = 0;
440	if (extra_bytes) {
441		memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
442		       scan->inode_size - extra_bytes);
443		scan->ptr += scan->inode_size - extra_bytes;
444		scan->bytes_left -= scan->inode_size - extra_bytes;
445
446#ifdef EXT2FS_ENABLE_SWAPFS
447		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
448		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
449			ext2fs_swap_inode(scan->fs, inode,
450				 (struct ext2_inode *) scan->temp_buffer, 0);
451		else
452#endif
453			*inode = *((struct ext2_inode *) scan->temp_buffer);
454		if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
455			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
456		scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
457	} else {
458#ifdef EXT2FS_ENABLE_SWAPFS
459		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
460		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
461			ext2fs_swap_inode(scan->fs, inode,
462				 (struct ext2_inode *) scan->ptr, 0);
463		else
464#endif
465			*inode = *((struct ext2_inode *) scan->ptr);
466		scan->ptr += scan->inode_size;
467		scan->bytes_left -= scan->inode_size;
468		if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
469			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
470	}
471
472	scan->inodes_left--;
473	scan->current_inode++;
474	*ino = scan->current_inode;
475	return retval;
476}
477
478/*
479 * Functions to read and write a single inode.
480 */
481errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
482			     struct ext2_inode * inode)
483{
484	unsigned long 	group, block, block_nr, offset;
485	char 		*ptr;
486	errcode_t	retval;
487	int 		clen, i, inodes_per_block;
488	unsigned int	length;
489	io_channel	io;
490
491	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
492
493	/* Check to see if user has an override function */
494	if (fs->read_inode) {
495		retval = (fs->read_inode)(fs, ino, inode);
496		if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
497			return retval;
498	}
499	/* Create inode cache if not present */
500	if (!fs->icache) {
501		retval = create_icache(fs);
502		if (retval)
503			return retval;
504	}
505	/* Check to see if it's in the inode cache */
506	for (i=0; i < fs->icache->cache_size; i++) {
507		if (fs->icache->cache[i].ino == ino) {
508			*inode = fs->icache->cache[i].inode;
509			return 0;
510		}
511	}
512	if ((ino == 0) || (ino > fs->super->s_inodes_count))
513		return EXT2_ET_BAD_INODE_NUM;
514	if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
515		inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
516		block_nr = fs->image_header->offset_inode / fs->blocksize;
517		block_nr += (ino - 1) / inodes_per_block;
518		offset = ((ino - 1) % inodes_per_block) *
519			EXT2_INODE_SIZE(fs->super);
520		io = fs->image_io;
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		io = fs->io;
531	}
532	if (block_nr != fs->icache->buffer_blk) {
533		retval = io_channel_read_blk(io, block_nr, 1,
534					     fs->icache->buffer);
535		if (retval)
536			return retval;
537		fs->icache->buffer_blk = block_nr;
538	}
539	offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
540	ptr = ((char *) fs->icache->buffer) + (unsigned) offset;
541
542	memset(inode, 0, sizeof(struct ext2_inode));
543	length = EXT2_INODE_SIZE(fs->super);
544	if (length > sizeof(struct ext2_inode))
545		length = sizeof(struct ext2_inode);
546
547	if ((offset + length) > (unsigned) EXT2_BLOCK_SIZE(fs->super)) {
548		clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
549		memcpy((char *) inode, ptr, clen);
550		length -= clen;
551
552		retval = io_channel_read_blk(io, block_nr+1, 1,
553					     fs->icache->buffer);
554		if (retval) {
555			fs->icache->buffer_blk = 0;
556			return retval;
557		}
558		fs->icache->buffer_blk = block_nr+1;
559
560		memcpy(((char *) inode) + clen,
561		       fs->icache->buffer, length);
562	} else
563		memcpy((char *) inode, ptr, length);
564
565#ifdef EXT2FS_ENABLE_SWAPFS
566	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
567	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
568		ext2fs_swap_inode(fs, inode, inode, 0);
569#endif
570
571	/* Update the inode cache */
572	fs->icache->cache_last = (fs->icache->cache_last + 1) %
573		fs->icache->cache_size;
574	fs->icache->cache[fs->icache->cache_last].ino = ino;
575	fs->icache->cache[fs->icache->cache_last].inode = *inode;
576
577	return 0;
578}
579
580errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
581			     struct ext2_inode * inode)
582{
583	unsigned long group, block, block_nr, offset;
584	errcode_t	retval;
585	struct ext2_inode temp_inode;
586	char *ptr;
587	int clen, i;
588	unsigned int length;
589
590	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
591
592	/* Check to see if user provided an override function */
593	if (fs->write_inode) {
594		retval = (fs->write_inode)(fs, ino, inode);
595		if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
596			return retval;
597	}
598
599	/* Check to see if the inode cache needs to be updated */
600	if (fs->icache) {
601		for (i=0; i < fs->icache->cache_size; i++) {
602			if (fs->icache->cache[i].ino == ino) {
603				fs->icache->cache[i].inode = *inode;
604				break;
605			}
606		}
607	} else {
608		retval = create_icache(fs);
609		if (retval)
610			return retval;
611	}
612
613	if (!(fs->flags & EXT2_FLAG_RW))
614		return EXT2_ET_RO_FILSYS;
615
616	if ((ino == 0) || (ino > fs->super->s_inodes_count))
617		return EXT2_ET_BAD_INODE_NUM;
618
619#ifdef EXT2FS_ENABLE_SWAPFS
620	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
621	    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
622		ext2fs_swap_inode(fs, &temp_inode, inode, 1);
623	else
624#endif
625		memcpy(&temp_inode, inode, sizeof(struct ext2_inode));
626
627	group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
628	offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
629		EXT2_INODE_SIZE(fs->super);
630	block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
631	if (!fs->group_desc[(unsigned) group].bg_inode_table)
632		return EXT2_ET_MISSING_INODE_TABLE;
633	block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
634	offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
635	ptr = (char *) fs->icache->buffer + (unsigned) offset;
636
637	length = EXT2_INODE_SIZE(fs->super);
638	clen = length;
639	if (length > sizeof(struct ext2_inode))
640		length = sizeof(struct ext2_inode);
641
642	if (fs->icache->buffer_blk != block_nr) {
643		retval = io_channel_read_blk(fs->io, block_nr, 1,
644					     fs->icache->buffer);
645		if (retval)
646			return retval;
647		fs->icache->buffer_blk = block_nr;
648	}
649
650	if ((offset + length) > (unsigned) EXT2_BLOCK_SIZE(fs->super)) {
651		clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
652		length -= clen;
653	} else {
654		length = 0;
655	}
656	memcpy(ptr, &temp_inode, clen);
657	retval = io_channel_write_blk(fs->io, block_nr, 1, fs->icache->buffer);
658	if (retval)
659		return retval;
660
661	if (length) {
662		retval = io_channel_read_blk(fs->io, ++block_nr, 1,
663					     fs->icache->buffer);
664		if (retval) {
665			fs->icache->buffer_blk = 0;
666			return retval;
667		}
668		fs->icache->buffer_blk = block_nr;
669		memcpy(fs->icache->buffer, ((char *) &temp_inode) + clen,
670		       length);
671
672		retval = io_channel_write_blk(fs->io, block_nr, 1,
673					      fs->icache->buffer);
674		if (retval)
675			return retval;
676	}
677
678	fs->flags |= EXT2_FLAG_CHANGED;
679	return 0;
680}
681
682errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
683{
684	struct ext2_inode	inode;
685	int			i;
686	errcode_t		retval;
687
688	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
689
690	if (ino > fs->super->s_inodes_count)
691		return EXT2_ET_BAD_INODE_NUM;
692
693	if (fs->get_blocks) {
694		if (!(*fs->get_blocks)(fs, ino, blocks))
695			return 0;
696	}
697	retval = ext2fs_read_inode(fs, ino, &inode);
698	if (retval)
699		return retval;
700	for (i=0; i < EXT2_N_BLOCKS; i++)
701		blocks[i] = inode.i_block[i];
702	return 0;
703}
704
705errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
706{
707	struct	ext2_inode	inode;
708	errcode_t		retval;
709
710	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
711
712	if (ino > fs->super->s_inodes_count)
713		return EXT2_ET_BAD_INODE_NUM;
714
715	if (fs->check_directory) {
716		retval = (fs->check_directory)(fs, ino);
717		if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
718			return retval;
719	}
720	retval = ext2fs_read_inode(fs, ino, &inode);
721	if (retval)
722		return retval;
723	if (!LINUX_S_ISDIR(inode.i_mode))
724		return EXT2_ET_NO_DIRECTORY;
725	return 0;
726}
727
728