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