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