2 * inode.c --- utility routines to read and write inodes
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
7 * This file may be redistributed under the terms of the GNU Public
22 #include <sys/types.h>
25 #include <linux/ext2_fs.h>
29 struct ext2_struct_inode_scan {
38 blk_t inode_buffer_blocks;
44 errcode_t (*done_group)(ext2_filsys fs,
48 void * done_group_data;
54 static errcode_t create_icache(ext2_filsys fs)
60 fs->icache = malloc(sizeof(struct ext2_inode_cache));
61 memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
62 fs->icache->buffer = malloc(fs->blocksize);
63 if (!fs->icache->buffer) {
65 return EXT2_NO_MEMORY;
67 fs->icache->buffer_blk = 0;
68 fs->icache->cache_last = -1;
69 fs->icache->cache_size = 4;
70 fs->icache->refcount = 1;
71 fs->icache->cache = malloc(sizeof(struct ext2_inode_cache_ent)
72 * fs->icache->cache_size);
73 if (!fs->icache->cache) {
74 free(fs->icache->buffer);
76 return EXT2_NO_MEMORY;
78 for (i=0; i < fs->icache->cache_size; i++)
79 fs->icache->cache[i].ino = 0;
83 errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
84 ext2_inode_scan *ret_scan)
88 errcode_t (*save_get_blocks)(ext2_filsys f, ino_t ino, blk_t *blocks);
90 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
93 * If fs->badblocks isn't set, then set it --- since the inode
94 * scanning functions require it.
96 if (fs->badblocks == 0) {
98 * Temporarly save fs->get_blocks and set it to zero,
99 * for compatibility with old e2fsck's.
101 save_get_blocks = fs->get_blocks;
103 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
104 if (retval && fs->badblocks) {
105 badblocks_list_free(fs->badblocks);
108 fs->get_blocks = save_get_blocks;
111 scan = (ext2_inode_scan) malloc(sizeof(struct ext2_struct_inode_scan));
113 return EXT2_NO_MEMORY;
114 memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
116 scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
118 scan->inode_size = EXT2_INODE_SIZE(fs->super);
119 scan->bytes_left = 0;
120 scan->current_group = -1;
121 scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
122 scan->groups_left = fs->group_desc_count;
123 scan->inode_buffer = malloc((size_t) (scan->inode_buffer_blocks *
125 scan->done_group = 0;
126 scan->done_group_data = 0;
127 scan->bad_block_ptr = 0;
128 if (!scan->inode_buffer) {
130 return EXT2_NO_MEMORY;
132 scan->temp_buffer = malloc(scan->inode_size);
133 if (!scan->temp_buffer) {
134 free(scan->inode_buffer);
136 return EXT2_NO_MEMORY;
138 if (scan->fs->badblocks && scan->fs->badblocks->num)
139 scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
144 void ext2fs_close_inode_scan(ext2_inode_scan scan)
146 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
149 free(scan->inode_buffer);
150 scan->inode_buffer = NULL;
151 free(scan->temp_buffer);
152 scan->temp_buffer = NULL;
157 void ext2fs_set_inode_callback(ext2_inode_scan scan,
158 errcode_t (*done_group)(ext2_filsys fs,
159 ext2_inode_scan scan,
162 void *done_group_data)
164 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
167 scan->done_group = done_group;
168 scan->done_group_data = done_group_data;
171 int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
176 if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
179 old_flags = scan->scan_flags;
180 scan->scan_flags &= ~clear_flags;
181 scan->scan_flags |= set_flags;
186 * This function is called by ext2fs_get_next_inode when it needs to
187 * get ready to read in a new blockgroup.
189 static errcode_t get_next_blockgroup(ext2_inode_scan scan)
191 scan->current_group++;
194 scan->current_block = scan->fs->
195 group_desc[scan->current_group].bg_inode_table;
197 scan->bytes_left = 0;
198 scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
199 scan->blocks_left = scan->fs->inode_blocks_per_group;
203 errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
206 scan->current_group = group - 1;
207 scan->groups_left = scan->fs->group_desc_count - group;
208 scan->current_inode = group * EXT2_INODES_PER_GROUP(scan->fs->super);
209 return get_next_blockgroup(scan);
213 * This function is called by get_next_blocks() to check for bad
214 * blocks in the inode table.
216 * This function assumes that badblocks_list->list is sorted in
219 static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
222 blk_t blk = scan->current_block;
223 badblocks_list bb = scan->fs->badblocks;
226 * If the inode table is missing, then obviously there are no
233 * If the current block is greater than the bad block listed
234 * in the bad block list, then advance the pointer until this
235 * is no longer the case. If we run out of bad blocks, then
236 * we don't need to do any more checking!
238 while (blk > bb->list[scan->bad_block_ptr]) {
239 if (++scan->bad_block_ptr >= bb->num) {
240 scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
246 * If the current block is equal to the bad block listed in
247 * the bad block list, then handle that one block specially.
248 * (We could try to handle runs of bad blocks, but that
249 * only increases CPU efficiency by a small amount, at the
250 * expense of a huge expense of code complexity, and for an
251 * uncommon case at that.)
253 if (blk == bb->list[scan->bad_block_ptr]) {
254 scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
256 if (++scan->bad_block_ptr >= bb->num)
257 scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
262 * If there is a bad block in the range that we're about to
263 * read in, adjust the number of blocks to read so that we we
264 * don't read in the bad block. (Then the next block to read
265 * will be the bad block, which is handled in the above case.)
267 if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
268 *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
274 * This function is called by ext2fs_get_next_inode when it needs to
275 * read in more blocks from the current blockgroup's inode table.
277 static errcode_t get_next_blocks(ext2_inode_scan scan)
283 * Figure out how many blocks to read; we read at most
284 * inode_buffer_blocks, and perhaps less if there aren't that
285 * many blocks left to read.
287 num_blocks = scan->inode_buffer_blocks;
288 if (num_blocks > scan->blocks_left)
289 num_blocks = scan->blocks_left;
292 * If the past block "read" was a bad block, then mark the
293 * left-over extra bytes as also being bad.
295 if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
296 if (scan->bytes_left)
297 scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
298 scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
302 * Do inode bad block processing, if necessary.
304 if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
305 retval = check_for_inode_bad_blocks(scan, &num_blocks);
310 if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
311 (scan->current_block == 0)) {
312 memset(scan->inode_buffer, 0,
313 (size_t) num_blocks * scan->fs->blocksize);
315 retval = io_channel_read_blk(scan->fs->io,
320 return EXT2_ET_NEXT_INODE_READ;
322 scan->ptr = scan->inode_buffer;
323 scan->bytes_left = num_blocks * scan->fs->blocksize;
325 scan->blocks_left -= num_blocks;
326 if (scan->current_block)
327 scan->current_block += num_blocks;
331 errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ino_t *ino,
332 struct ext2_inode *inode)
337 EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
340 * Do we need to start reading a new block group?
342 if (scan->inodes_left <= 0) {
344 if (scan->done_group) {
345 retval = (scan->done_group)
346 (scan->fs, scan, scan->current_group,
347 scan->done_group_data);
351 if (scan->groups_left <= 0) {
355 retval = get_next_blockgroup(scan);
358 if (scan->current_block == 0) {
359 if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
362 return EXT2_ET_MISSING_INODE_TABLE;
367 * Have we run out of space in the inode buffer? If so, we
368 * need to read in more blocks.
370 if (scan->bytes_left < scan->inode_size) {
371 memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
372 extra_bytes = scan->bytes_left;
374 retval = get_next_blocks(scan);
381 memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
382 scan->inode_size - extra_bytes);
383 scan->ptr += scan->inode_size - extra_bytes;
384 scan->bytes_left -= scan->inode_size - extra_bytes;
386 if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
387 (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
388 ext2fs_swap_inode(scan->fs, inode,
389 (struct ext2_inode *) scan->temp_buffer, 0);
391 *inode = *((struct ext2_inode *) scan->temp_buffer);
392 if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
393 retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
394 scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
396 if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
397 (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
398 ext2fs_swap_inode(scan->fs, inode,
399 (struct ext2_inode *) scan->ptr, 0);
401 *inode = *((struct ext2_inode *) scan->ptr);
402 scan->ptr += scan->inode_size;
403 scan->bytes_left -= scan->inode_size;
404 if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
405 retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
409 scan->current_inode++;
410 *ino = scan->current_inode;
415 * Functions to read and write a single inode.
417 errcode_t ext2fs_read_inode (ext2_filsys fs, ino_t ino,
418 struct ext2_inode * inode)
420 unsigned long group, block, block_nr, offset;
425 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
427 /* Check to see if user has an override function */
428 if (fs->read_inode) {
429 retval = (fs->read_inode)(fs, ino, inode);
430 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
433 /* Create inode cache if not present */
435 retval = create_icache(fs);
439 /* Check to see if it's in the inode cache */
440 for (i=0; i < fs->icache->cache_size; i++) {
441 if (fs->icache->cache[i].ino == ino) {
442 *inode = fs->icache->cache[i].inode;
446 if (ino > fs->super->s_inodes_count)
447 return EXT2_ET_BAD_INODE_NUM;
448 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
449 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
450 EXT2_INODE_SIZE(fs->super);
451 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
452 if (!fs->group_desc[(unsigned)group].bg_inode_table)
453 return EXT2_ET_MISSING_INODE_TABLE;
454 block_nr = fs->group_desc[(unsigned)group].bg_inode_table + block;
455 if (block_nr != fs->icache->buffer_blk) {
456 retval = io_channel_read_blk(fs->io, block_nr, 1,
460 fs->icache->buffer_blk = block_nr;
462 offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
463 ptr = ((char *) fs->icache->buffer) + (unsigned) offset;
465 memset(inode, 0, sizeof(struct ext2_inode));
466 length = EXT2_INODE_SIZE(fs->super);
467 if (length > sizeof(struct ext2_inode))
468 length = sizeof(struct ext2_inode);
470 if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) {
471 clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
472 memcpy((char *) inode, ptr, clen);
475 retval = io_channel_read_blk(fs->io, block_nr+1, 1,
478 fs->icache->buffer_blk = 0;
481 fs->icache->buffer_blk = block_nr+1;
483 memcpy(((char *) inode) + clen,
484 fs->icache->buffer, length);
486 memcpy((char *) inode, ptr, length);
488 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
489 (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
490 ext2fs_swap_inode(fs, inode, inode, 0);
492 /* Update the inode cache */
493 fs->icache->cache_last = (fs->icache->cache_last + 1) %
494 fs->icache->cache_size;
495 fs->icache->cache[fs->icache->cache_last].ino = ino;
496 fs->icache->cache[fs->icache->cache_last].inode = *inode;
501 errcode_t ext2fs_write_inode(ext2_filsys fs, ino_t ino,
502 struct ext2_inode * inode)
504 unsigned long group, block, block_nr, offset;
506 struct ext2_inode temp_inode;
510 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
512 /* Check to see if user provided an override function */
513 if (fs->write_inode) {
514 retval = (fs->write_inode)(fs, ino, inode);
515 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
519 /* Check to see if the inode cache needs to be updated */
521 for (i=0; i < fs->icache->cache_size; i++) {
522 if (fs->icache->cache[i].ino == ino) {
523 fs->icache->cache[i].inode = *inode;
528 retval = create_icache(fs);
533 if (!(fs->flags & EXT2_FLAG_RW))
534 return EXT2_ET_RO_FILSYS;
536 if (ino > fs->super->s_inodes_count)
537 return EXT2_ET_BAD_INODE_NUM;
539 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
540 (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
541 ext2fs_swap_inode(fs, &temp_inode, inode, 1);
543 memcpy(&temp_inode, inode, sizeof(struct ext2_inode));
545 group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
546 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
547 EXT2_INODE_SIZE(fs->super);
548 block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
549 if (!fs->group_desc[(unsigned) group].bg_inode_table)
550 return EXT2_ET_MISSING_INODE_TABLE;
551 block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
552 offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
553 ptr = (char *) fs->icache->buffer + (unsigned) offset;
555 length = EXT2_INODE_SIZE(fs->super);
557 if (length > sizeof(struct ext2_inode))
558 length = sizeof(struct ext2_inode);
560 if (fs->icache->buffer_blk != block_nr) {
561 retval = io_channel_read_blk(fs->io, block_nr, 1,
565 fs->icache->buffer_blk = block_nr;
568 if ((offset + length) > EXT2_BLOCK_SIZE(fs->super)) {
569 clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
574 memcpy(ptr, &temp_inode, clen);
575 retval = io_channel_write_blk(fs->io, block_nr, 1, fs->icache->buffer);
580 retval = io_channel_read_blk(fs->io, ++block_nr, 1,
583 fs->icache->buffer_blk = 0;
586 fs->icache->buffer_blk = block_nr;
587 memcpy(fs->icache->buffer, ((char *) &temp_inode) + clen,
590 retval = io_channel_write_blk(fs->io, block_nr, 1,
596 fs->flags |= EXT2_FLAG_CHANGED;
600 errcode_t ext2fs_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks)
602 struct ext2_inode inode;
606 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
608 if (ino > fs->super->s_inodes_count)
609 return EXT2_ET_BAD_INODE_NUM;
611 if (fs->get_blocks) {
612 if (!(*fs->get_blocks)(fs, ino, blocks))
615 retval = ext2fs_read_inode(fs, ino, &inode);
618 for (i=0; i < EXT2_N_BLOCKS; i++)
619 blocks[i] = inode.i_block[i];
623 errcode_t ext2fs_check_directory(ext2_filsys fs, ino_t ino)
625 struct ext2_inode inode;
628 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
630 if (ino > fs->super->s_inodes_count)
631 return EXT2_ET_BAD_INODE_NUM;
633 if (fs->check_directory) {
634 retval = (fs->check_directory)(fs, ino);
635 if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
638 retval = ext2fs_read_inode(fs, ino, &inode);
641 if (!LINUX_S_ISDIR(inode.i_mode))
642 return EXT2_NO_DIRECTORY;