X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lib%2Fext2fs%2Finode.c;h=b7805bcb13fc801d746bc8c5e4c0f6aadedd43b1;hb=bad5ce5ca531b65116edfc9c79abc65b1c6ab9ed;hp=8d528b4475936a1574fd8ff08d9a3331683cadd2;hpb=f5fa20078bfc05b554294fe9c5505375d7913e8c;p=tools%2Fe2fsprogs.git diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c index 8d528b4..b7805bc 100644 --- a/lib/ext2fs/inode.c +++ b/lib/ext2fs/inode.c @@ -1,14 +1,15 @@ /* * inode.c --- utility routines to read and write inodes - * + * * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. * * %Begin-Header% - * This file may be redistributed under the terms of the GNU Public - * License. + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. * %End-Header% */ +#include "config.h" #include #include #if HAVE_UNISTD_H @@ -17,6 +18,7 @@ #if HAVE_ERRNO_H #include #endif +#include #if HAVE_SYS_STAT_H #include #endif @@ -32,7 +34,7 @@ struct ext2_struct_inode_scan { errcode_t magic; ext2_filsys fs; ext2_ino_t current_inode; - blk_t current_block; + blk64_t current_block; dgrp_t current_group; ext2_ino_t inodes_left; blk_t blocks_left; @@ -59,7 +61,7 @@ struct ext2_struct_inode_scan { errcode_t ext2fs_flush_icache(ext2_filsys fs) { int i; - + if (!fs->icache) return 0; @@ -73,7 +75,7 @@ errcode_t ext2fs_flush_icache(ext2_filsys fs) static errcode_t create_icache(ext2_filsys fs) { errcode_t retval; - + if (fs->icache) return 0; retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), &fs->icache); @@ -90,9 +92,9 @@ static errcode_t create_icache(ext2_filsys fs) fs->icache->cache_last = -1; fs->icache->cache_size = 4; fs->icache->refcount = 1; - retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache_ent) - * fs->icache->cache_size, - &fs->icache->cache); + retval = ext2fs_get_array(fs->icache->cache_size, + sizeof(struct ext2_inode_cache_ent), + &fs->icache->cache); if (retval) { ext2fs_free_mem(&fs->icache->buffer); ext2fs_free_mem(&fs->icache); @@ -142,13 +144,24 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, scan->current_group = 0; scan->groups_left = fs->group_desc_count - 1; scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8; - scan->current_block = scan->fs-> - group_desc[scan->current_group].bg_inode_table; + scan->current_block = ext2fs_inode_table_loc(scan->fs, + scan->current_group); scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super); scan->blocks_left = scan->fs->inode_blocks_per_group; - retval = ext2fs_get_mem((size_t) (scan->inode_buffer_blocks * - fs->blocksize), - &scan->inode_buffer); + if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, + EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { + __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group); + if (scan->inodes_left > unused) + scan->inodes_left -= unused; + else + scan->inodes_left = 0; + scan->blocks_left = + (scan->inodes_left + + (fs->blocksize / scan->inode_size - 1)) * + scan->inode_size / fs->blocksize; + } + retval = io_channel_alloc_buf(fs->io, scan->inode_buffer_blocks, + &scan->inode_buffer); scan->done_group = 0; scan->done_group_data = 0; scan->bad_block_ptr = 0; @@ -164,8 +177,8 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, } if (scan->fs->badblocks && scan->fs->badblocks->num) scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS; - if (EXT2_HAS_COMPAT_FEATURE(fs->super, - EXT2_FEATURE_COMPAT_LAZY_BG)) + if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, + EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) scan->scan_flags |= EXT2_SF_DO_LAZY; *ret_scan = scan; return 0; @@ -175,7 +188,7 @@ void ext2fs_close_inode_scan(ext2_inode_scan scan) { if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) return; - + ext2fs_free_mem(&scan->inode_buffer); scan->inode_buffer = NULL; ext2fs_free_mem(&scan->temp_buffer); @@ -193,7 +206,7 @@ void ext2fs_set_inode_callback(ext2_inode_scan scan, { if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) return; - + scan->done_group = done_group; scan->done_group_data = done_group_data; } @@ -218,18 +231,32 @@ int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags, */ static errcode_t get_next_blockgroup(ext2_inode_scan scan) { + ext2_filsys fs = scan->fs; + scan->current_group++; scan->groups_left--; - - scan->current_block = scan->fs-> - group_desc[scan->current_group].bg_inode_table; + scan->current_block = ext2fs_inode_table_loc(scan->fs, + scan->current_group); scan->current_inode = scan->current_group * - EXT2_INODES_PER_GROUP(scan->fs->super); + EXT2_INODES_PER_GROUP(fs->super); scan->bytes_left = 0; - scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super); - scan->blocks_left = scan->fs->inode_blocks_per_group; + scan->inodes_left = EXT2_INODES_PER_GROUP(fs->super); + scan->blocks_left = fs->inode_blocks_per_group; + if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, + EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { + __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group); + if (scan->inodes_left > unused) + scan->inodes_left -= unused; + else + scan->inodes_left = 0; + scan->blocks_left = + (scan->inodes_left + + (fs->blocksize / scan->inode_size - 1)) * + scan->inode_size / fs->blocksize; + } + return 0; } @@ -249,9 +276,9 @@ errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan, * increasing order. */ static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan, - blk_t *num_blocks) + blk64_t *num_blocks) { - blk_t blk = scan->current_block; + blk64_t blk = scan->current_block; badblocks_list bb = scan->fs->badblocks; /* @@ -308,7 +335,7 @@ static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan, */ static errcode_t get_next_blocks(ext2_inode_scan scan) { - blk_t num_blocks; + blk64_t num_blocks; errcode_t retval; /* @@ -338,13 +365,13 @@ static errcode_t get_next_blocks(ext2_inode_scan scan) if (retval) return retval; } - + if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) || (scan->current_block == 0)) { memset(scan->inode_buffer, 0, (size_t) num_blocks * scan->fs->blocksize); } else { - retval = io_channel_read_blk(scan->fs->io, + retval = io_channel_read_blk64(scan->fs->io, scan->current_block, (int) num_blocks, scan->inode_buffer); @@ -370,7 +397,7 @@ static errcode_t get_next_blocks(ext2_inode_scan scan) static inline int is_empty_scan(ext2_inode_scan scan) { int i; - + if (scan->bytes_left == 0) return 0; @@ -386,7 +413,7 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino, { errcode_t retval; int extra_bytes = 0; - + EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN); /* @@ -410,12 +437,14 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino, return retval; } /* - * These checks are done outside the above if statement so + * These checks are done outside the above if statement so * they can be done for block group #0. */ if ((scan->scan_flags & EXT2_SF_DO_LAZY) && - (scan->fs->group_desc[scan->current_group].bg_flags & - EXT2_BG_INODE_UNINIT)) + (ext2fs_bg_flags_test(scan->fs, scan->current_group, EXT2_BG_INODE_UNINIT) + )) + goto force_new_group; + if (scan->inodes_left == 0) goto force_new_group; if (scan->current_block == 0) { if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) { @@ -423,7 +452,7 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino, } else return EXT2_ET_MISSING_INODE_TABLE; } - + /* * Have we run out of space in the inode buffer? If so, we @@ -453,30 +482,28 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino, scan->ptr += scan->inode_size - extra_bytes; scan->bytes_left -= scan->inode_size - extra_bytes; -#ifdef EXT2FS_ENABLE_SWAPFS - if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) || - (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) - ext2fs_swap_inode_full(scan->fs, - (struct ext2_inode_large *) inode, - (struct ext2_inode_large *) scan->temp_buffer, - 0, bufsize); - else +#ifdef WORDS_BIGENDIAN + memset(inode, 0, bufsize); + ext2fs_swap_inode_full(scan->fs, + (struct ext2_inode_large *) inode, + (struct ext2_inode_large *) scan->temp_buffer, + 0, bufsize); +#else + memcpy(inode, scan->temp_buffer, bufsize); #endif - *inode = *((struct ext2_inode *) scan->temp_buffer); if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES) retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE; scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES; } else { -#ifdef EXT2FS_ENABLE_SWAPFS - if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) || - (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) - ext2fs_swap_inode_full(scan->fs, +#ifdef WORDS_BIGENDIAN + memset(inode, 0, bufsize); + ext2fs_swap_inode_full(scan->fs, (struct ext2_inode_large *) inode, (struct ext2_inode_large *) scan->ptr, 0, bufsize); - else +#else + memcpy(inode, scan->ptr, bufsize); #endif - memcpy(inode, scan->ptr, bufsize); scan->ptr += scan->inode_size; scan->bytes_left -= scan->inode_size; if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) @@ -502,7 +529,8 @@ errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino, errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode * inode, int bufsize) { - unsigned long group, block, block_nr, offset; + blk64_t block_nr; + unsigned long group, block, offset; char *ptr; errcode_t retval; int clen, i, inodes_per_block, length; @@ -511,11 +539,15 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); /* Check to see if user has an override function */ - if (fs->read_inode) { + if (fs->read_inode && + ((bufsize == sizeof(struct ext2_inode)) || + (EXT2_INODE_SIZE(fs->super) == sizeof(struct ext2_inode)))) { retval = (fs->read_inode)(fs, ino, inode); if (retval != EXT2_ET_CALLBACK_NOTHANDLED) return retval; } + if ((ino == 0) || (ino > fs->super->s_inodes_count)) + return EXT2_ET_BAD_INODE_NUM; /* Create inode cache if not present */ if (!fs->icache) { retval = create_icache(fs); @@ -524,7 +556,7 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, } /* Check to see if it's in the inode cache */ if (bufsize == sizeof(struct ext2_inode)) { - /* only old good inode can be retrieve from the cache */ + /* only old good inode can be retrieved from the cache */ for (i=0; i < fs->icache->cache_size; i++) { if (fs->icache->cache[i].ino == ino) { *inode = fs->icache->cache[i].inode; @@ -532,8 +564,6 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, } } } - if ((ino == 0) || (ino > fs->super->s_inodes_count)) - return EXT2_ET_BAD_INODE_NUM; if (fs->flags & EXT2_FLAG_IMAGE_FILE) { inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super); block_nr = fs->image_header->offset_inode / fs->blocksize; @@ -543,12 +573,14 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, io = fs->image_io; } else { group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); + if (group > fs->group_desc_count) + return EXT2_ET_BAD_INODE_NUM; offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * EXT2_INODE_SIZE(fs->super); block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super); - if (!fs->group_desc[(unsigned)group].bg_inode_table) + if (!ext2fs_inode_table_loc(fs, (unsigned) group)) return EXT2_ET_MISSING_INODE_TABLE; - block_nr = fs->group_desc[(unsigned)group].bg_inode_table + + block_nr = ext2fs_inode_table_loc(fs, group) + block; io = fs->io; } @@ -565,7 +597,7 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, clen = fs->blocksize - offset; if (block_nr != fs->icache->buffer_blk) { - retval = io_channel_read_blk(io, block_nr, 1, + retval = io_channel_read_blk64(io, block_nr, 1, fs->icache->buffer); if (retval) return retval; @@ -581,12 +613,10 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, block_nr++; } -#ifdef EXT2FS_ENABLE_SWAPFS - if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || - (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)) - ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode, - (struct ext2_inode_large *) inode, - 0, length); +#ifdef WORDS_BIGENDIAN + ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode, + (struct ext2_inode_large *) inode, + 0, bufsize); #endif /* Update the inode cache */ @@ -594,7 +624,7 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, fs->icache->cache_size; fs->icache->cache[fs->icache->cache_last].ino = ino; fs->icache->cache[fs->icache->cache_last].inode = *inode; - + return 0; } @@ -608,7 +638,8 @@ errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino, errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode * inode, int bufsize) { - unsigned long group, block, block_nr, offset; + blk64_t block_nr; + unsigned long group, block, offset; errcode_t retval = 0; struct ext2_inode_large temp_inode, *w_inode; char *ptr; @@ -636,7 +667,7 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, if (retval) return retval; } - + if (!(fs->flags & EXT2_FLAG_RW)) return EXT2_ET_RO_FILSYS; @@ -649,29 +680,31 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, if (length > (int) sizeof(struct ext2_inode_large)) { w_inode = malloc(length); - if (!w_inode) - return ENOMEM; + if (!w_inode) { + retval = ENOMEM; + goto errout; + } } else w_inode = &temp_inode; memset(w_inode, 0, length); -#ifdef EXT2FS_ENABLE_SWAPFS - if ((fs->flags & EXT2_FLAG_SWAP_BYTES) || - (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) - ext2fs_swap_inode_full(fs, w_inode, - (struct ext2_inode_large *) inode, - 1, bufsize); - else +#ifdef WORDS_BIGENDIAN + ext2fs_swap_inode_full(fs, w_inode, + (struct ext2_inode_large *) inode, + 1, bufsize); +#else + memcpy(w_inode, inode, bufsize); #endif - memcpy(w_inode, inode, bufsize); - + group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * EXT2_INODE_SIZE(fs->super); block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super); - if (!fs->group_desc[(unsigned) group].bg_inode_table) - return EXT2_ET_MISSING_INODE_TABLE; - block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block; + if (!ext2fs_inode_table_loc(fs, (unsigned) group)) { + retval = EXT2_ET_MISSING_INODE_TABLE; + goto errout; + } + block_nr = ext2fs_inode_table_loc(fs, (unsigned) group) + block; offset &= (EXT2_BLOCK_SIZE(fs->super) - 1); @@ -687,18 +720,18 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, clen = fs->blocksize - offset; if (fs->icache->buffer_blk != block_nr) { - retval = io_channel_read_blk(fs->io, block_nr, 1, + retval = io_channel_read_blk64(fs->io, block_nr, 1, fs->icache->buffer); if (retval) goto errout; fs->icache->buffer_blk = block_nr; } - - memcpy((char *) fs->icache->buffer + (unsigned) offset, + + memcpy((char *) fs->icache->buffer + (unsigned) offset, ptr, clen); - retval = io_channel_write_blk(fs->io, block_nr, 1, + retval = io_channel_write_blk64(fs->io, block_nr, 1, fs->icache->buffer); if (retval) goto errout; @@ -708,7 +741,7 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, length -= clen; block_nr++; } - + fs->flags |= EXT2_FLAG_CHANGED; errout: if (w_inode && w_inode != &temp_inode) @@ -723,7 +756,7 @@ errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino, sizeof(struct ext2_inode)); } -/* +/* * This function should be called when writing a new inode. It makes * sure that extra part of large inodes is initialized properly. */ @@ -733,6 +766,15 @@ errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *buf; int size = EXT2_INODE_SIZE(fs->super); struct ext2_inode_large *large_inode; + errcode_t retval; + __u32 t = fs->now ? fs->now : time(NULL); + + if (!inode->i_ctime) + inode->i_ctime = t; + if (!inode->i_mtime) + inode->i_mtime = t; + if (!inode->i_atime) + inode->i_atime = t; if (size == sizeof(struct ext2_inode)) return ext2fs_write_inode_full(fs, ino, inode, @@ -746,19 +788,23 @@ errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino, *buf = *inode; large_inode = (struct ext2_inode_large *) buf; - large_inode->i_extra_isize = sizeof(struct ext2_inode_large) - + large_inode->i_extra_isize = sizeof(struct ext2_inode_large) - EXT2_GOOD_OLD_INODE_SIZE; + if (!large_inode->i_crtime) + large_inode->i_crtime = t; - return ext2fs_write_inode_full(fs, ino, buf, size); + retval = ext2fs_write_inode_full(fs, ino, buf, size); + free(buf); + return retval; } - + errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks) { struct ext2_inode inode; int i; errcode_t retval; - + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if (ino > fs->super->s_inodes_count) @@ -780,7 +826,7 @@ errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino) { struct ext2_inode inode; errcode_t retval; - + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if (ino > fs->super->s_inodes_count)