import ext2fs lib to prep for new e2fsprogs

This commit is contained in:
Mike Frysinger 2005-05-09 22:10:42 +00:00
parent b32011943a
commit 1fd98e039d
82 changed files with 17575 additions and 0 deletions

173
e2fsprogs/ext2fs/alloc.c Normal file
View File

@ -0,0 +1,173 @@
/*
* alloc.c --- allocate new inodes, blocks for ext2fs
*
* Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <time.h>
#include <string.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
/*
* Right now, just search forward from the parent directory's block
* group to find the next free inode.
*
* Should have a special policy for directories.
*/
errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
int mode EXT2FS_ATTR((unused)),
ext2fs_inode_bitmap map, ext2_ino_t *ret)
{
ext2_ino_t dir_group = 0;
ext2_ino_t i;
ext2_ino_t start_inode;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (!map)
map = fs->inode_map;
if (!map)
return EXT2_ET_NO_INODE_BITMAP;
if (dir > 0)
dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super);
start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->super)) + 1;
if (start_inode < EXT2_FIRST_INODE(fs->super))
start_inode = EXT2_FIRST_INODE(fs->super);
i = start_inode;
do {
if (!ext2fs_fast_test_inode_bitmap(map, i))
break;
i++;
if (i > fs->super->s_inodes_count)
i = EXT2_FIRST_INODE(fs->super);
} while (i != start_inode);
if (ext2fs_test_inode_bitmap(map, i))
return EXT2_ET_INODE_ALLOC_FAIL;
*ret = i;
return 0;
}
/*
* Stupid algorithm --- we now just search forward starting from the
* goal. Should put in a smarter one someday....
*/
errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
ext2fs_block_bitmap map, blk_t *ret)
{
blk_t i;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (!map)
map = fs->block_map;
if (!map)
return EXT2_ET_NO_BLOCK_BITMAP;
if (!goal || (goal >= fs->super->s_blocks_count))
goal = fs->super->s_first_data_block;
i = goal;
do {
if (!ext2fs_fast_test_block_bitmap(map, i)) {
*ret = i;
return 0;
}
i++;
if (i >= fs->super->s_blocks_count)
i = fs->super->s_first_data_block;
} while (i != goal);
return EXT2_ET_BLOCK_ALLOC_FAIL;
}
/*
* This function zeros out the allocated block, and updates all of the
* appropriate filesystem records.
*/
errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
char *block_buf, blk_t *ret)
{
errcode_t retval;
blk_t block;
char *buf = 0;
if (!block_buf) {
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
return retval;
block_buf = buf;
}
memset(block_buf, 0, fs->blocksize);
if (!fs->block_map) {
retval = ext2fs_read_block_bitmap(fs);
if (retval)
goto fail;
}
retval = ext2fs_new_block(fs, goal, 0, &block);
if (retval)
goto fail;
retval = io_channel_write_blk(fs->io, block, 1, block_buf);
if (retval)
goto fail;
ext2fs_block_alloc_stats(fs, block, +1);
*ret = block;
return 0;
fail:
if (buf)
ext2fs_free_mem(&buf);
return retval;
}
errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish,
int num, ext2fs_block_bitmap map, blk_t *ret)
{
blk_t b = start;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (!map)
map = fs->block_map;
if (!map)
return EXT2_ET_NO_BLOCK_BITMAP;
if (!b)
b = fs->super->s_first_data_block;
if (!finish)
finish = start;
if (!num)
num = 1;
do {
if (b+num-1 > fs->super->s_blocks_count)
b = fs->super->s_first_data_block;
if (ext2fs_fast_test_block_bitmap_range(map, b, num)) {
*ret = b;
return 0;
}
b++;
} while (b != finish);
return EXT2_ET_BLOCK_ALLOC_FAIL;
}

View File

@ -0,0 +1,57 @@
/*
* alloc_sb.c --- Allocate the superblock and block group descriptors for a
* newly initialized filesystem. Used by mke2fs when initializing a filesystem
*
* Copyright (C) 1994, 1995, 1996, 2003 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
int ext2fs_reserve_super_and_bgd(ext2_filsys fs,
dgrp_t group,
ext2fs_block_bitmap bmap)
{
blk_t super_blk, old_desc_blk, new_desc_blk;
int j, old_desc_blocks, num_blocks;
num_blocks = ext2fs_super_and_bgd_loc(fs, group, &super_blk,
&old_desc_blk, &new_desc_blk, 0);
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
old_desc_blocks = fs->super->s_first_meta_bg;
else
old_desc_blocks =
fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
if (super_blk || (group == 0))
ext2fs_mark_block_bitmap(bmap, super_blk);
if (old_desc_blk) {
for (j=0; j < old_desc_blocks; j++)
ext2fs_mark_block_bitmap(bmap, old_desc_blk + j);
}
if (new_desc_blk)
ext2fs_mark_block_bitmap(bmap, new_desc_blk);
return num_blocks;
}

View File

@ -0,0 +1,52 @@
/*
* alloc_stats.c --- Update allocation statistics for ext2fs
*
* Copyright (C) 2001 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*
*/
#include <stdio.h>
#include "ext2_fs.h"
#include "ext2fs.h"
void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
int inuse, int isdir)
{
int group = ext2fs_group_of_ino(fs, ino);
if (inuse > 0)
ext2fs_mark_inode_bitmap(fs->inode_map, ino);
else
ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
fs->group_desc[group].bg_free_inodes_count -= inuse;
if (isdir)
fs->group_desc[group].bg_used_dirs_count += inuse;
fs->super->s_free_inodes_count -= inuse;
ext2fs_mark_super_dirty(fs);
ext2fs_mark_ib_dirty(fs);
}
void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse)
{
ext2fs_inode_alloc_stats2(fs, ino, inuse, 0);
}
void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse)
{
int group = ext2fs_group_of_blk(fs, blk);
if (inuse > 0)
ext2fs_mark_block_bitmap(fs->block_map, blk);
else
ext2fs_unmark_block_bitmap(fs->block_map, blk);
fs->group_desc[group].bg_free_blocks_count -= inuse;
fs->super->s_free_blocks_count -= inuse;
ext2fs_mark_super_dirty(fs);
ext2fs_mark_bb_dirty(fs);
}

View File

@ -0,0 +1,117 @@
/*
* alloc_tables.c --- Allocate tables for a newly initialized
* filesystem. Used by mke2fs when initializing a filesystem
*
* Copyright (C) 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
ext2fs_block_bitmap bmap)
{
errcode_t retval;
blk_t group_blk, start_blk, last_blk, new_blk, blk;
int j;
group_blk = fs->super->s_first_data_block +
(group * fs->super->s_blocks_per_group);
last_blk = group_blk + fs->super->s_blocks_per_group;
if (last_blk >= fs->super->s_blocks_count)
last_blk = fs->super->s_blocks_count - 1;
if (!bmap)
bmap = fs->block_map;
/*
* Allocate the block and inode bitmaps, if necessary
*/
if (fs->stride) {
start_blk = group_blk + fs->inode_blocks_per_group;
start_blk += ((fs->stride * group) %
(last_blk - start_blk));
if (start_blk > last_blk)
start_blk = group_blk;
} else
start_blk = group_blk;
if (!fs->group_desc[group].bg_block_bitmap) {
retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
1, bmap, &new_blk);
if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
retval = ext2fs_get_free_blocks(fs, group_blk,
last_blk, 1, bmap, &new_blk);
if (retval)
return retval;
ext2fs_mark_block_bitmap(bmap, new_blk);
fs->group_desc[group].bg_block_bitmap = new_blk;
}
if (!fs->group_desc[group].bg_inode_bitmap) {
retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
1, bmap, &new_blk);
if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
retval = ext2fs_get_free_blocks(fs, group_blk,
last_blk, 1, bmap, &new_blk);
if (retval)
return retval;
ext2fs_mark_block_bitmap(bmap, new_blk);
fs->group_desc[group].bg_inode_bitmap = new_blk;
}
/*
* Allocate the inode table
*/
if (!fs->group_desc[group].bg_inode_table) {
retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
fs->inode_blocks_per_group,
bmap, &new_blk);
if (retval)
return retval;
for (j=0, blk = new_blk;
j < fs->inode_blocks_per_group;
j++, blk++)
ext2fs_mark_block_bitmap(bmap, blk);
fs->group_desc[group].bg_inode_table = new_blk;
}
return 0;
}
errcode_t ext2fs_allocate_tables(ext2_filsys fs)
{
errcode_t retval;
dgrp_t i;
for (i = 0; i < fs->group_desc_count; i++) {
retval = ext2fs_allocate_group_table(fs, i, fs->block_map);
if (retval)
return retval;
}
return 0;
}

View File

@ -0,0 +1,327 @@
/*
* badblocks.c --- routines to manipulate the bad block structure
*
* Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fsP.h"
/*
* Helper function for making a badblocks list
*/
static errcode_t make_u32_list(int size, int num, __u32 *list,
ext2_u32_list *ret)
{
ext2_u32_list bb;
errcode_t retval;
retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list), &bb);
if (retval)
return retval;
memset(bb, 0, sizeof(struct ext2_struct_u32_list));
bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
bb->size = size ? size : 10;
bb->num = num;
retval = ext2fs_get_mem(bb->size * sizeof(blk_t), &bb->list);
if (!bb->list) {
ext2fs_free_mem(&bb);
return retval;
}
if (list)
memcpy(bb->list, list, bb->size * sizeof(blk_t));
else
memset(bb->list, 0, bb->size * sizeof(blk_t));
*ret = bb;
return 0;
}
/*
* This procedure creates an empty u32 list.
*/
errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size)
{
return make_u32_list(size, 0, 0, ret);
}
/*
* This procedure creates an empty badblocks list.
*/
errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
{
return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret);
}
/*
* This procedure copies a badblocks list
*/
errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest)
{
errcode_t retval;
retval = make_u32_list(src->size, src->num, src->list, dest);
if (retval)
return retval;
(*dest)->badblocks_flags = src->badblocks_flags;
return 0;
}
errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
ext2_badblocks_list *dest)
{
return ext2fs_u32_copy((ext2_u32_list) src,
(ext2_u32_list *) dest);
}
/*
* This procedure frees a badblocks list.
*
* (note: moved to closefs.c)
*/
/*
* This procedure adds a block to a badblocks list.
*/
errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk)
{
errcode_t retval;
int i, j;
unsigned long old_size;
EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
if (bb->num >= bb->size) {
old_size = bb->size * sizeof(__u32);
bb->size += 100;
retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32),
&bb->list);
if (retval) {
bb->size -= 100;
return retval;
}
}
/*
* Add special case code for appending to the end of the list
*/
i = bb->num-1;
if ((bb->num != 0) && (bb->list[i] == blk))
return 0;
if ((bb->num == 0) || (bb->list[i] < blk)) {
bb->list[bb->num++] = blk;
return 0;
}
j = bb->num;
for (i=0; i < bb->num; i++) {
if (bb->list[i] == blk)
return 0;
if (bb->list[i] > blk) {
j = i;
break;
}
}
for (i=bb->num; i > j; i--)
bb->list[i] = bb->list[i-1];
bb->list[j] = blk;
bb->num++;
return 0;
}
errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
{
return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk);
}
/*
* This procedure finds a particular block is on a badblocks
* list.
*/
int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk)
{
int low, high, mid;
if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
return -1;
if (bb->num == 0)
return -1;
low = 0;
high = bb->num-1;
if (blk == bb->list[low])
return low;
if (blk == bb->list[high])
return high;
while (low < high) {
mid = (low+high)/2;
if (mid == low || mid == high)
break;
if (blk == bb->list[mid])
return mid;
if (blk < bb->list[mid])
high = mid;
else
low = mid;
}
return -1;
}
/*
* This procedure tests to see if a particular block is on a badblocks
* list.
*/
int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk)
{
if (ext2fs_u32_list_find(bb, blk) < 0)
return 0;
else
return 1;
}
int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
{
return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk);
}
/*
* Remove a block from the badblock list
*/
int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk)
{
int remloc, i;
if (bb->num == 0)
return -1;
remloc = ext2fs_u32_list_find(bb, blk);
if (remloc < 0)
return -1;
for (i = remloc ; i < bb->num-1; i++)
bb->list[i] = bb->list[i+1];
bb->num--;
return 0;
}
void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk)
{
ext2fs_u32_list_del(bb, blk);
}
errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
ext2_u32_iterate *ret)
{
ext2_u32_iterate iter;
errcode_t retval;
EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate), &iter);
if (retval)
return retval;
iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
iter->bb = bb;
iter->ptr = 0;
*ret = iter;
return 0;
}
errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
ext2_badblocks_iterate *ret)
{
return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb,
(ext2_u32_iterate *) ret);
}
int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk)
{
ext2_u32_list bb;
if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
return 0;
bb = iter->bb;
if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
return 0;
if (iter->ptr < bb->num) {
*blk = bb->list[iter->ptr++];
return 1;
}
*blk = 0;
return 0;
}
int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
{
return ext2fs_u32_list_iterate((ext2_u32_iterate) iter,
(__u32 *) blk);
}
void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter)
{
if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
return;
iter->bb = 0;
ext2fs_free_mem(&iter);
}
void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
{
ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter);
}
int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2)
{
EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
if (bb1->num != bb2->num)
return 0;
if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0)
return 0;
return 1;
}
int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
{
return ext2fs_u32_list_equal((ext2_u32_list) bb1,
(ext2_u32_list) bb2);
}
int ext2fs_u32_list_count(ext2_u32_list bb)
{
return bb->num;
}

View File

@ -0,0 +1,63 @@
/*
* bb_compat.c --- compatibility badblocks routines
*
* Copyright (C) 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fsP.h"
errcode_t badblocks_list_create(badblocks_list *ret, int size)
{
return ext2fs_badblocks_list_create(ret, size);
}
void badblocks_list_free(badblocks_list bb)
{
ext2fs_badblocks_list_free(bb);
}
errcode_t badblocks_list_add(badblocks_list bb, blk_t blk)
{
return ext2fs_badblocks_list_add(bb, blk);
}
int badblocks_list_test(badblocks_list bb, blk_t blk)
{
return ext2fs_badblocks_list_test(bb, blk);
}
errcode_t badblocks_list_iterate_begin(badblocks_list bb,
badblocks_iterate *ret)
{
return ext2fs_badblocks_list_iterate_begin(bb, ret);
}
int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk)
{
return ext2fs_badblocks_list_iterate(iter, blk);
}
void badblocks_list_iterate_end(badblocks_iterate iter)
{
ext2fs_badblocks_list_iterate_end(iter);
}

267
e2fsprogs/ext2fs/bb_inode.c Normal file
View File

@ -0,0 +1,267 @@
/*
* bb_inode.c --- routines to update the bad block inode.
*
* WARNING: This routine modifies a lot of state in the filesystem; if
* this routine returns an error, the bad block inode may be in an
* inconsistent state.
*
* Copyright (C) 1994, 1995 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
struct set_badblock_record {
ext2_badblocks_iterate bb_iter;
int bad_block_count;
blk_t *ind_blocks;
int max_ind_blocks;
int ind_blocks_size;
int ind_blocks_ptr;
char *block_buf;
errcode_t err;
};
static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
e2_blkcnt_t blockcnt,
blk_t ref_block, int ref_offset,
void *priv_data);
static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
e2_blkcnt_t blockcnt,
blk_t ref_block, int ref_offset,
void *priv_data);
/*
* Given a bad blocks bitmap, update the bad blocks inode to reflect
* the map.
*/
errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
{
errcode_t retval;
struct set_badblock_record rec;
struct ext2_inode inode;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (!fs->block_map)
return EXT2_ET_NO_BLOCK_BITMAP;
rec.bad_block_count = 0;
rec.ind_blocks_size = rec.ind_blocks_ptr = 0;
rec.max_ind_blocks = 10;
retval = ext2fs_get_mem(rec.max_ind_blocks * sizeof(blk_t),
&rec.ind_blocks);
if (retval)
return retval;
memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t));
retval = ext2fs_get_mem(fs->blocksize, &rec.block_buf);
if (retval)
goto cleanup;
memset(rec.block_buf, 0, fs->blocksize);
rec.err = 0;
/*
* First clear the old bad blocks (while saving the indirect blocks)
*/
retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
BLOCK_FLAG_DEPTH_TRAVERSE, 0,
clear_bad_block_proc, &rec);
if (retval)
goto cleanup;
if (rec.err) {
retval = rec.err;
goto cleanup;
}
/*
* Now set the bad blocks!
*
* First, mark the bad blocks as used. This prevents a bad
* block from being used as an indirecto block for the bad
* block inode (!).
*/
if (bb_list) {
retval = ext2fs_badblocks_list_iterate_begin(bb_list,
&rec.bb_iter);
if (retval)
goto cleanup;
retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
BLOCK_FLAG_APPEND, 0,
set_bad_block_proc, &rec);
ext2fs_badblocks_list_iterate_end(rec.bb_iter);
if (retval)
goto cleanup;
if (rec.err) {
retval = rec.err;
goto cleanup;
}
}
/*
* Update the bad block inode's mod time and block count
* field.
*/
retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
if (retval)
goto cleanup;
inode.i_atime = inode.i_mtime = time(0);
if (!inode.i_ctime)
inode.i_ctime = time(0);
inode.i_blocks = rec.bad_block_count * (fs->blocksize / 512);
inode.i_size = rec.bad_block_count * fs->blocksize;
retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode);
if (retval)
goto cleanup;
cleanup:
ext2fs_free_mem(&rec.ind_blocks);
ext2fs_free_mem(&rec.block_buf);
return retval;
}
/*
* Helper function for update_bb_inode()
*
* Clear the bad blocks in the bad block inode, while saving the
* indirect blocks.
*/
#ifdef __TURBOC__
#pragma argsused
#endif
static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
e2_blkcnt_t blockcnt,
blk_t ref_block EXT2FS_ATTR((unused)),
int ref_offset EXT2FS_ATTR((unused)),
void *priv_data)
{
struct set_badblock_record *rec = (struct set_badblock_record *)
priv_data;
errcode_t retval;
unsigned long old_size;
if (!*block_nr)
return 0;
/*
* If the block number is outrageous, clear it and ignore it.
*/
if (*block_nr >= fs->super->s_blocks_count ||
*block_nr < fs->super->s_first_data_block) {
*block_nr = 0;
return BLOCK_CHANGED;
}
if (blockcnt < 0) {
if (rec->ind_blocks_size >= rec->max_ind_blocks) {
old_size = rec->max_ind_blocks * sizeof(blk_t);
rec->max_ind_blocks += 10;
retval = ext2fs_resize_mem(old_size,
rec->max_ind_blocks * sizeof(blk_t),
&rec->ind_blocks);
if (retval) {
rec->max_ind_blocks -= 10;
rec->err = retval;
return BLOCK_ABORT;
}
}
rec->ind_blocks[rec->ind_blocks_size++] = *block_nr;
}
/*
* Mark the block as unused, and update accounting information
*/
ext2fs_block_alloc_stats(fs, *block_nr, -1);
*block_nr = 0;
return BLOCK_CHANGED;
}
/*
* Helper function for update_bb_inode()
*
* Set the block list in the bad block inode, using the supplied bitmap.
*/
#ifdef __TURBOC__
#pragma argsused
#endif
static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
e2_blkcnt_t blockcnt,
blk_t ref_block EXT2FS_ATTR((unused)),
int ref_offset EXT2FS_ATTR((unused)),
void *priv_data)
{
struct set_badblock_record *rec = (struct set_badblock_record *)
priv_data;
errcode_t retval;
blk_t blk;
if (blockcnt >= 0) {
/*
* Get the next bad block.
*/
if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk))
return BLOCK_ABORT;
rec->bad_block_count++;
} else {
/*
* An indirect block; fetch a block from the
* previously used indirect block list. The block
* most be not marked as used; if so, get another one.
* If we run out of reserved indirect blocks, allocate
* a new one.
*/
retry:
if (rec->ind_blocks_ptr < rec->ind_blocks_size) {
blk = rec->ind_blocks[rec->ind_blocks_ptr++];
if (ext2fs_test_block_bitmap(fs->block_map, blk))
goto retry;
} else {
retval = ext2fs_new_block(fs, 0, 0, &blk);
if (retval) {
rec->err = retval;
return BLOCK_ABORT;
}
}
retval = io_channel_write_blk(fs->io, blk, 1, rec->block_buf);
if (retval) {
rec->err = retval;
return BLOCK_ABORT;
}
}
/*
* Update block counts
*/
ext2fs_block_alloc_stats(fs, blk, +1);
*block_nr = blk;
return BLOCK_CHANGED;
}

212
e2fsprogs/ext2fs/bitmaps.c Normal file
View File

@ -0,0 +1,212 @@
/*
* bitmaps.c --- routines to read, write, and manipulate the inode and
* block bitmaps.
*
* Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
static errcode_t make_bitmap(__u32 start, __u32 end, __u32 real_end,
const char *descr, char *init_map,
ext2fs_generic_bitmap *ret)
{
ext2fs_generic_bitmap bitmap;
errcode_t retval;
size_t size;
retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap),
&bitmap);
if (retval)
return retval;
bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
bitmap->fs = NULL;
bitmap->start = start;
bitmap->end = end;
bitmap->real_end = real_end;
bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
if (descr) {
retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
if (retval) {
ext2fs_free_mem(&bitmap);
return retval;
}
strcpy(bitmap->description, descr);
} else
bitmap->description = 0;
size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
retval = ext2fs_get_mem(size, &bitmap->bitmap);
if (retval) {
ext2fs_free_mem(&bitmap->description);
ext2fs_free_mem(&bitmap);
return retval;
}
if (init_map)
memcpy(bitmap->bitmap, init_map, size);
else
memset(bitmap->bitmap, 0, size);
*ret = bitmap;
return 0;
}
errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
__u32 end,
__u32 real_end,
const char *descr,
ext2fs_generic_bitmap *ret)
{
return make_bitmap(start, end, real_end, descr, 0, ret);
}
errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
ext2fs_generic_bitmap *dest)
{
errcode_t retval;
ext2fs_generic_bitmap new_map;
retval = make_bitmap(src->start, src->end, src->real_end,
src->description, src->bitmap, &new_map);
if (retval)
return retval;
new_map->magic = src->magic;
new_map->fs = src->fs;
new_map->base_error_code = src->base_error_code;
*dest = new_map;
return 0;
}
void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map)
{
__u32 i, j;
for (i=map->end+1, j = i - map->start; i <= map->real_end; i++, j++)
ext2fs_set_bit(j, map->bitmap);
return;
}
errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
const char *descr,
ext2fs_inode_bitmap *ret)
{
ext2fs_inode_bitmap bitmap;
errcode_t retval;
__u32 start, end, real_end;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
fs->write_bitmaps = ext2fs_write_bitmaps;
start = 1;
end = fs->super->s_inodes_count;
real_end = (EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count);
retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
descr, &bitmap);
if (retval)
return retval;
bitmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
bitmap->fs = fs;
bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
*ret = bitmap;
return 0;
}
errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
const char *descr,
ext2fs_block_bitmap *ret)
{
ext2fs_block_bitmap bitmap;
errcode_t retval;
__u32 start, end, real_end;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
fs->write_bitmaps = ext2fs_write_bitmaps;
start = fs->super->s_first_data_block;
end = fs->super->s_blocks_count-1;
real_end = (EXT2_BLOCKS_PER_GROUP(fs->super)
* fs->group_desc_count)-1 + start;
retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
descr, &bitmap);
if (retval)
return retval;
bitmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
bitmap->fs = fs;
bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
*ret = bitmap;
return 0;
}
errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
ext2_ino_t end, ext2_ino_t *oend)
{
EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP);
if (end > bitmap->real_end)
return EXT2_ET_FUDGE_INODE_BITMAP_END;
if (oend)
*oend = bitmap->end;
bitmap->end = end;
return 0;
}
errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
blk_t end, blk_t *oend)
{
EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
if (end > bitmap->real_end)
return EXT2_ET_FUDGE_BLOCK_BITMAP_END;
if (oend)
*oend = bitmap->end;
bitmap->end = end;
return 0;
}
void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap)
{
if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
return;
memset(bitmap->bitmap, 0,
(size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
}
void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap)
{
if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
return;
memset(bitmap->bitmap, 0,
(size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
}

91
e2fsprogs/ext2fs/bitops.c Normal file
View File

@ -0,0 +1,91 @@
/*
* bitops.c --- Bitmap frobbing code. See bitops.h for the inlined
* routines.
*
* Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
#ifndef _EXT2_HAVE_ASM_BITOPS_
/*
* For the benefit of those who are trying to port Linux to another
* architecture, here are some C-language equivalents. You should
* recode these in the native assmebly language, if at all possible.
*
* C language equivalents written by Theodore Ts'o, 9/26/92.
* Modified by Pete A. Zaitcev 7/14/95 to be portable to big endian
* systems, as well as non-32 bit systems.
*/
int ext2fs_set_bit(int nr,void * addr)
{
int mask, retval;
unsigned char *ADDR = (unsigned char *) addr;
ADDR += nr >> 3;
mask = 1 << (nr & 0x07);
retval = mask & *ADDR;
*ADDR |= mask;
return retval;
}
int ext2fs_clear_bit(int nr, void * addr)
{
int mask, retval;
unsigned char *ADDR = (unsigned char *) addr;
ADDR += nr >> 3;
mask = 1 << (nr & 0x07);
retval = mask & *ADDR;
*ADDR &= ~mask;
return retval;
}
int ext2fs_test_bit(int nr, const void * addr)
{
int mask;
const unsigned char *ADDR = (const unsigned char *) addr;
ADDR += nr >> 3;
mask = 1 << (nr & 0x07);
return (mask & *ADDR);
}
#endif /* !_EXT2_HAVE_ASM_BITOPS_ */
void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
const char *description)
{
#ifndef OMIT_COM_ERR
if (description)
com_err(0, errcode, "#%lu for %s", arg, description);
else
com_err(0, errcode, "#%lu", arg);
#endif
}
void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
int code, unsigned long arg)
{
#ifndef OMIT_COM_ERR
if (bitmap->description)
com_err(0, bitmap->base_error_code+code,
"#%lu for %s", arg, bitmap->description);
else
com_err(0, bitmap->base_error_code + code, "#%lu", arg);
#endif
}

617
e2fsprogs/ext2fs/bitops.h Normal file
View File

@ -0,0 +1,617 @@
/*
* bitops.h --- Bitmap frobbing code. The byte swapping routines are
* also included here.
*
* Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*
* i386 bitops operations taken from <asm/bitops.h>, Copyright 1992,
* Linus Torvalds.
*/
extern int ext2fs_set_bit(int nr,void * addr);
extern int ext2fs_clear_bit(int nr, void * addr);
extern int ext2fs_test_bit(int nr, const void * addr);
extern __u16 ext2fs_swab16(__u16 val);
extern __u32 ext2fs_swab32(__u32 val);
#ifdef WORDS_BIGENDIAN
#define ext2fs_cpu_to_le32(x) ext2fs_swab32((x))
#define ext2fs_le32_to_cpu(x) ext2fs_swab32((x))
#define ext2fs_cpu_to_le16(x) ext2fs_swab16((x))
#define ext2fs_le16_to_cpu(x) ext2fs_swab16((x))
#define ext2fs_cpu_to_be32(x) ((__u32)(x))
#define ext2fs_be32_to_cpu(x) ((__u32)(x))
#define ext2fs_cpu_to_be16(x) ((__u16)(x))
#define ext2fs_be16_to_cpu(x) ((__u16)(x))
#else
#define ext2fs_cpu_to_le32(x) ((__u32)(x))
#define ext2fs_le32_to_cpu(x) ((__u32)(x))
#define ext2fs_cpu_to_le16(x) ((__u16)(x))
#define ext2fs_le16_to_cpu(x) ((__u16)(x))
#define ext2fs_cpu_to_be32(x) ext2fs_swab32((x))
#define ext2fs_be32_to_cpu(x) ext2fs_swab32((x))
#define ext2fs_cpu_to_be16(x) ext2fs_swab16((x))
#define ext2fs_be16_to_cpu(x) ext2fs_swab16((x))
#endif
/*
* EXT2FS bitmap manipulation routines.
*/
/* Support for sending warning messages from the inline subroutines */
extern const char *ext2fs_block_string;
extern const char *ext2fs_inode_string;
extern const char *ext2fs_mark_string;
extern const char *ext2fs_unmark_string;
extern const char *ext2fs_test_string;
extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
const char *description);
extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
int code, unsigned long arg);
extern int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
extern int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
blk_t block);
extern int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
extern int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
extern int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
ext2_ino_t inode);
extern int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
extern void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
blk_t block);
extern void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
blk_t block);
extern int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
blk_t block);
extern void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
ext2_ino_t inode);
extern void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
ext2_ino_t inode);
extern int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
ext2_ino_t inode);
extern blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap);
extern ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap);
extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap);
extern ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap);
extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num);
extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num);
extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num);
extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num);
extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num);
extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num);
extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map);
/* These two routines moved to gen_bitmap.c */
extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
__u32 bitno);
extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
blk_t bitno);
/*
* The inline routines themselves...
*
* If NO_INLINE_FUNCS is defined, then we won't try to do inline
* functions at all; they will be included as normal functions in
* inline.c
*/
#ifdef NO_INLINE_FUNCS
#if (defined(__GNUC__) && (defined(__i386__) || defined(__i486__) || \
defined(__i586__) || defined(__mc68000__) || \
defined(__sparc__)))
/* This prevents bitops.c from trying to include the C */
/* function version of these functions */
#define _EXT2_HAVE_ASM_BITOPS_
#endif
#endif /* NO_INLINE_FUNCS */
#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
#ifdef INCLUDE_INLINE_FUNCS
#define _INLINE_ extern
#else
#ifdef __GNUC__
#define _INLINE_ extern __inline__
#else /* For Watcom C */
#define _INLINE_ extern inline
#endif
#endif
#if ((defined __GNUC__) && !defined(_EXT2_USE_C_VERSIONS_) && \
(defined(__i386__) || defined(__i486__) || defined(__i586__)))
#define _EXT2_HAVE_ASM_BITOPS_
#define _EXT2_HAVE_ASM_SWAB_
#define _EXT2_HAVE_ASM_FINDBIT_
/*
* These are done by inline assembly for speed reasons.....
*
* All bitoperations return 0 if the bit was cleared before the
* operation and != 0 if it was not. Bit 0 is the LSB of addr; bit 32
* is the LSB of (addr+1).
*/
/*
* Some hacks to defeat gcc over-optimizations..
*/
struct __dummy_h { unsigned long a[100]; };
#define EXT2FS_ADDR (*(struct __dummy_h *) addr)
#define EXT2FS_CONST_ADDR (*(const struct __dummy_h *) addr)
_INLINE_ int ext2fs_set_bit(int nr, void * addr)
{
int oldbit;
__asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit),"=m" (EXT2FS_ADDR)
:"r" (nr));
return oldbit;
}
_INLINE_ int ext2fs_clear_bit(int nr, void * addr)
{
int oldbit;
__asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit),"=m" (EXT2FS_ADDR)
:"r" (nr));
return oldbit;
}
_INLINE_ int ext2fs_test_bit(int nr, const void * addr)
{
int oldbit;
__asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit)
:"m" (EXT2FS_CONST_ADDR),"r" (nr));
return oldbit;
}
#if 0
_INLINE_ int ext2fs_find_first_bit_set(void * addr, unsigned size)
{
int d0, d1, d2;
int res;
if (!size)
return 0;
/* This looks at memory. Mark it volatile to tell gcc not to move it around */
__asm__ __volatile__(
"cld\n\t"
"xorl %%eax,%%eax\n\t"
"xorl %%edx,%%edx\n\t"
"repe; scasl\n\t"
"je 1f\n\t"
"movl -4(%%edi),%%eax\n\t"
"subl $4,%%edi\n\t"
"bsfl %%eax,%%edx\n"
"1:\tsubl %%esi,%%edi\n\t"
"shll $3,%%edi\n\t"
"addl %%edi,%%edx"
:"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
:"1" ((size + 31) >> 5), "2" (addr), "S" (addr));
return res;
}
_INLINE_ int ext2fs_find_next_bit_set (void * addr, int size, int offset)
{
unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
int set = 0, bit = offset & 31, res;
if (bit) {
/*
* Look for zero in first byte
*/
__asm__("bsfl %1,%0\n\t"
"jne 1f\n\t"
"movl $32, %0\n"
"1:"
: "=r" (set)
: "r" (*p >> bit));
if (set < (32 - bit))
return set + offset;
set = 32 - bit;
p++;
}
/*
* No bit found yet, search remaining full bytes for a bit
*/
res = ext2fs_find_first_bit_set(p, size - 32 * (p - (unsigned long *) addr));
return (offset + set + res);
}
#endif
#ifdef EXT2FS_ENABLE_SWAPFS
_INLINE_ __u32 ext2fs_swab32(__u32 val)
{
#ifdef EXT2FS_REQUIRE_486
__asm__("bswap %0" : "=r" (val) : "0" (val));
#else
__asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */
"rorl $16,%0\n\t" /* swap words */
"xchgb %b0,%h0" /* swap higher bytes */
:"=q" (val)
: "0" (val));
#endif
return val;
}
_INLINE_ __u16 ext2fs_swab16(__u16 val)
{
__asm__("xchgb %b0,%h0" /* swap bytes */ \
: "=q" (val) \
: "0" (val)); \
return val;
}
#endif
#undef EXT2FS_ADDR
#endif /* i386 */
#ifdef __mc68000__
#define _EXT2_HAVE_ASM_BITOPS_
_INLINE_ int ext2fs_set_bit(int nr,void * addr)
{
char retval;
__asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0"
: "=d" (retval) : "d" (nr^7), "a" (addr));
return retval;
}
_INLINE_ int ext2fs_clear_bit(int nr, void * addr)
{
char retval;
__asm__ __volatile__ ("bfclr %2@{%1:#1}; sne %0"
: "=d" (retval) : "d" (nr^7), "a" (addr));
return retval;
}
_INLINE_ int ext2fs_test_bit(int nr, const void * addr)
{
char retval;
__asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0"
: "=d" (retval) : "d" (nr^7), "a" (addr));
return retval;
}
#endif /* __mc68000__ */
#if !defined(_EXT2_HAVE_ASM_SWAB_) && defined(EXT2FS_ENABLE_SWAPFS)
_INLINE_ __u16 ext2fs_swab16(__u16 val)
{
return (val >> 8) | (val << 8);
}
_INLINE_ __u32 ext2fs_swab32(__u32 val)
{
return ((val>>24) | ((val>>8)&0xFF00) |
((val<<8)&0xFF0000) | (val<<24));
}
#endif /* !_EXT2_HAVE_ASM_SWAB */
#if !defined(_EXT2_HAVE_ASM_FINDBIT_)
_INLINE_ int ext2fs_find_first_bit_set(void * addr, unsigned size)
{
char *cp = (unsigned char *) addr;
int res = 0, d0;
if (!size)
return 0;
while ((size > res) && (*cp == 0)) {
cp++;
res += 8;
}
d0 = ffs(*cp);
if (d0 == 0)
return size;
return res + d0 - 1;
}
_INLINE_ int ext2fs_find_next_bit_set (void * addr, int size, int offset)
{
unsigned char * p;
int set = 0, bit = offset & 7, res = 0, d0;
res = offset >> 3;
p = ((unsigned char *) addr) + res;
if (bit) {
set = ffs(*p & ~((1 << bit) - 1));
if (set)
return (offset & ~7) + set - 1;
p++;
res += 8;
}
while ((size > res) && (*p == 0)) {
p++;
res += 8;
}
d0 = ffs(*p);
if (d0 == 0)
return size;
return (res + d0 - 1);
}
#endif
_INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
blk_t bitno);
_INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
blk_t bitno)
{
if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
return 0;
}
return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
}
_INLINE_ int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap,
blk_t block)
{
return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap)
bitmap,
block);
}
_INLINE_ int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
blk_t block)
{
return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
block);
}
_INLINE_ int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap,
blk_t block)
{
return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap,
block);
}
_INLINE_ int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
ext2_ino_t inode)
{
return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
inode);
}
_INLINE_ int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
ext2_ino_t inode)
{
return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap,
inode);
}
_INLINE_ int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
ext2_ino_t inode)
{
return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap,
inode);
}
_INLINE_ void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
blk_t block)
{
#ifdef EXT2FS_DEBUG_FAST_OPS
if ((block < bitmap->start) || (block > bitmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
bitmap->description);
return;
}
#endif
ext2fs_set_bit(block - bitmap->start, bitmap->bitmap);
}
_INLINE_ void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
blk_t block)
{
#ifdef EXT2FS_DEBUG_FAST_OPS
if ((block < bitmap->start) || (block > bitmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK,
block, bitmap->description);
return;
}
#endif
ext2fs_clear_bit(block - bitmap->start, bitmap->bitmap);
}
_INLINE_ int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
blk_t block)
{
#ifdef EXT2FS_DEBUG_FAST_OPS
if ((block < bitmap->start) || (block > bitmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
block, bitmap->description);
return 0;
}
#endif
return ext2fs_test_bit(block - bitmap->start, bitmap->bitmap);
}
_INLINE_ void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
ext2_ino_t inode)
{
#ifdef EXT2FS_DEBUG_FAST_OPS
if ((inode < bitmap->start) || (inode > bitmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_MARK,
inode, bitmap->description);
return;
}
#endif
ext2fs_set_bit(inode - bitmap->start, bitmap->bitmap);
}
_INLINE_ void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
ext2_ino_t inode)
{
#ifdef EXT2FS_DEBUG_FAST_OPS
if ((inode < bitmap->start) || (inode > bitmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_UNMARK,
inode, bitmap->description);
return;
}
#endif
ext2fs_clear_bit(inode - bitmap->start, bitmap->bitmap);
}
_INLINE_ int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
ext2_ino_t inode)
{
#ifdef EXT2FS_DEBUG_FAST_OPS
if ((inode < bitmap->start) || (inode > bitmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST,
inode, bitmap->description);
return 0;
}
#endif
return ext2fs_test_bit(inode - bitmap->start, bitmap->bitmap);
}
_INLINE_ blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap)
{
return bitmap->start;
}
_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap)
{
return bitmap->start;
}
_INLINE_ blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap)
{
return bitmap->end;
}
_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap)
{
return bitmap->end;
}
_INLINE_ int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num)
{
int i;
if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
block, bitmap->description);
return 0;
}
for (i=0; i < num; i++) {
if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
return 0;
}
return 1;
}
_INLINE_ int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num)
{
int i;
#ifdef EXT2FS_DEBUG_FAST_OPS
if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
block, bitmap->description);
return 0;
}
#endif
for (i=0; i < num; i++) {
if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
return 0;
}
return 1;
}
_INLINE_ void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num)
{
int i;
if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
bitmap->description);
return;
}
for (i=0; i < num; i++)
ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
}
_INLINE_ void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num)
{
int i;
#ifdef EXT2FS_DEBUG_FAST_OPS
if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
bitmap->description);
return;
}
#endif
for (i=0; i < num; i++)
ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
}
_INLINE_ void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num)
{
int i;
if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
bitmap->description);
return;
}
for (i=0; i < num; i++)
ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
}
_INLINE_ void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num)
{
int i;
#ifdef EXT2FS_DEBUG_FAST_OPS
if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
bitmap->description);
return;
}
#endif
for (i=0; i < num; i++)
ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
}
#undef _INLINE_
#endif

437
e2fsprogs/ext2fs/block.c Normal file
View File

@ -0,0 +1,437 @@
/*
* block.c --- iterate over all blocks in an inode
*
* Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
struct block_context {
ext2_filsys fs;
int (*func)(ext2_filsys fs,
blk_t *blocknr,
e2_blkcnt_t bcount,
blk_t ref_blk,
int ref_offset,
void *priv_data);
e2_blkcnt_t bcount;
int bsize;
int flags;
errcode_t errcode;
char *ind_buf;
char *dind_buf;
char *tind_buf;
void *priv_data;
};
static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
int ref_offset, struct block_context *ctx)
{
int ret = 0, changed = 0;
int i, flags, limit, offset;
blk_t *block_nr;
limit = ctx->fs->blocksize >> 2;
if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
!(ctx->flags & BLOCK_FLAG_DATA_ONLY))
ret = (*ctx->func)(ctx->fs, ind_block,
BLOCK_COUNT_IND, ref_block,
ref_offset, ctx->priv_data);
if (!*ind_block || (ret & BLOCK_ABORT)) {
ctx->bcount += limit;
return ret;
}
if (*ind_block >= ctx->fs->super->s_blocks_count ||
*ind_block < ctx->fs->super->s_first_data_block) {
ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
ret |= BLOCK_ERROR;
return ret;
}
ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
ctx->ind_buf);
if (ctx->errcode) {
ret |= BLOCK_ERROR;
return ret;
}
block_nr = (blk_t *) ctx->ind_buf;
offset = 0;
if (ctx->flags & BLOCK_FLAG_APPEND) {
for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
*ind_block, offset,
ctx->priv_data);
changed |= flags;
if (flags & BLOCK_ABORT) {
ret |= BLOCK_ABORT;
break;
}
offset += sizeof(blk_t);
}
} else {
for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
if (*block_nr == 0)
continue;
flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
*ind_block, offset,
ctx->priv_data);
changed |= flags;
if (flags & BLOCK_ABORT) {
ret |= BLOCK_ABORT;
break;
}
offset += sizeof(blk_t);
}
}
if (changed & BLOCK_CHANGED) {
ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
ctx->ind_buf);
if (ctx->errcode)
ret |= BLOCK_ERROR | BLOCK_ABORT;
}
if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
!(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
!(ret & BLOCK_ABORT))
ret |= (*ctx->func)(ctx->fs, ind_block,
BLOCK_COUNT_IND, ref_block,
ref_offset, ctx->priv_data);
return ret;
}
static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
int ref_offset, struct block_context *ctx)
{
int ret = 0, changed = 0;
int i, flags, limit, offset;
blk_t *block_nr;
limit = ctx->fs->blocksize >> 2;
if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
BLOCK_FLAG_DATA_ONLY)))
ret = (*ctx->func)(ctx->fs, dind_block,
BLOCK_COUNT_DIND, ref_block,
ref_offset, ctx->priv_data);
if (!*dind_block || (ret & BLOCK_ABORT)) {
ctx->bcount += limit*limit;
return ret;
}
if (*dind_block >= ctx->fs->super->s_blocks_count ||
*dind_block < ctx->fs->super->s_first_data_block) {
ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
ret |= BLOCK_ERROR;
return ret;
}
ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
ctx->dind_buf);
if (ctx->errcode) {
ret |= BLOCK_ERROR;
return ret;
}
block_nr = (blk_t *) ctx->dind_buf;
offset = 0;
if (ctx->flags & BLOCK_FLAG_APPEND) {
for (i = 0; i < limit; i++, block_nr++) {
flags = block_iterate_ind(block_nr,
*dind_block, offset,
ctx);
changed |= flags;
if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
break;
}
offset += sizeof(blk_t);
}
} else {
for (i = 0; i < limit; i++, block_nr++) {
if (*block_nr == 0) {
ctx->bcount += limit;
continue;
}
flags = block_iterate_ind(block_nr,
*dind_block, offset,
ctx);
changed |= flags;
if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
break;
}
offset += sizeof(blk_t);
}
}
if (changed & BLOCK_CHANGED) {
ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
ctx->dind_buf);
if (ctx->errcode)
ret |= BLOCK_ERROR | BLOCK_ABORT;
}
if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
!(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
!(ret & BLOCK_ABORT))
ret |= (*ctx->func)(ctx->fs, dind_block,
BLOCK_COUNT_DIND, ref_block,
ref_offset, ctx->priv_data);
return ret;
}
static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
int ref_offset, struct block_context *ctx)
{
int ret = 0, changed = 0;
int i, flags, limit, offset;
blk_t *block_nr;
limit = ctx->fs->blocksize >> 2;
if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
BLOCK_FLAG_DATA_ONLY)))
ret = (*ctx->func)(ctx->fs, tind_block,
BLOCK_COUNT_TIND, ref_block,
ref_offset, ctx->priv_data);
if (!*tind_block || (ret & BLOCK_ABORT)) {
ctx->bcount += limit*limit*limit;
return ret;
}
if (*tind_block >= ctx->fs->super->s_blocks_count ||
*tind_block < ctx->fs->super->s_first_data_block) {
ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
ret |= BLOCK_ERROR;
return ret;
}
ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
ctx->tind_buf);
if (ctx->errcode) {
ret |= BLOCK_ERROR;
return ret;
}
block_nr = (blk_t *) ctx->tind_buf;
offset = 0;
if (ctx->flags & BLOCK_FLAG_APPEND) {
for (i = 0; i < limit; i++, block_nr++) {
flags = block_iterate_dind(block_nr,
*tind_block,
offset, ctx);
changed |= flags;
if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
break;
}
offset += sizeof(blk_t);
}
} else {
for (i = 0; i < limit; i++, block_nr++) {
if (*block_nr == 0) {
ctx->bcount += limit*limit;
continue;
}
flags = block_iterate_dind(block_nr,
*tind_block,
offset, ctx);
changed |= flags;
if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
break;
}
offset += sizeof(blk_t);
}
}
if (changed & BLOCK_CHANGED) {
ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
ctx->tind_buf);
if (ctx->errcode)
ret |= BLOCK_ERROR | BLOCK_ABORT;
}
if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
!(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
!(ret & BLOCK_ABORT))
ret |= (*ctx->func)(ctx->fs, tind_block,
BLOCK_COUNT_TIND, ref_block,
ref_offset, ctx->priv_data);
return ret;
}
errcode_t ext2fs_block_iterate2(ext2_filsys fs,
ext2_ino_t ino,
int flags,
char *block_buf,
int (*func)(ext2_filsys fs,
blk_t *blocknr,
e2_blkcnt_t blockcnt,
blk_t ref_blk,
int ref_offset,
void *priv_data),
void *priv_data)
{
int i;
int got_inode = 0;
int ret = 0;
blk_t blocks[EXT2_N_BLOCKS]; /* directory data blocks */
struct ext2_inode inode;
errcode_t retval;
struct block_context ctx;
int limit;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
/*
* Check to see if we need to limit large files
*/
if (flags & BLOCK_FLAG_NO_LARGE) {
ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
if (ctx.errcode)
return ctx.errcode;
got_inode = 1;
if (!LINUX_S_ISDIR(inode.i_mode) &&
(inode.i_size_high != 0))
return EXT2_ET_FILE_TOO_BIG;
}
retval = ext2fs_get_blocks(fs, ino, blocks);
if (retval)
return retval;
limit = fs->blocksize >> 2;
ctx.fs = fs;
ctx.func = func;
ctx.priv_data = priv_data;
ctx.flags = flags;
ctx.bcount = 0;
if (block_buf) {
ctx.ind_buf = block_buf;
} else {
retval = ext2fs_get_mem(fs->blocksize * 3, &ctx.ind_buf);
if (retval)
return retval;
}
ctx.dind_buf = ctx.ind_buf + fs->blocksize;
ctx.tind_buf = ctx.dind_buf + fs->blocksize;
/*
* Iterate over the HURD translator block (if present)
*/
if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
!(flags & BLOCK_FLAG_DATA_ONLY)) {
ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
if (ctx.errcode)
goto abort_exit;
got_inode = 1;
if (inode.osd1.hurd1.h_i_translator) {
ret |= (*ctx.func)(fs,
&inode.osd1.hurd1.h_i_translator,
BLOCK_COUNT_TRANSLATOR,
0, 0, priv_data);
if (ret & BLOCK_ABORT)
goto abort_exit;
}
}
/*
* Iterate over normal data blocks
*/
for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
ret |= (*ctx.func)(fs, &blocks[i],
ctx.bcount, 0, i, priv_data);
if (ret & BLOCK_ABORT)
goto abort_exit;
}
}
if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
0, EXT2_IND_BLOCK, &ctx);
if (ret & BLOCK_ABORT)
goto abort_exit;
} else
ctx.bcount += limit;
if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
0, EXT2_DIND_BLOCK, &ctx);
if (ret & BLOCK_ABORT)
goto abort_exit;
} else
ctx.bcount += limit * limit;
if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
0, EXT2_TIND_BLOCK, &ctx);
if (ret & BLOCK_ABORT)
goto abort_exit;
}
abort_exit:
if (ret & BLOCK_CHANGED) {
if (!got_inode) {
retval = ext2fs_read_inode(fs, ino, &inode);
if (retval)
return retval;
}
for (i=0; i < EXT2_N_BLOCKS; i++)
inode.i_block[i] = blocks[i];
retval = ext2fs_write_inode(fs, ino, &inode);
if (retval)
return retval;
}
if (!block_buf)
ext2fs_free_mem(&ctx.ind_buf);
return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
}
/*
* Emulate the old ext2fs_block_iterate function!
*/
struct xlate {
int (*func)(ext2_filsys fs,
blk_t *blocknr,
int bcount,
void *priv_data);
void *real_private;
};
#ifdef __TURBOC__
#pragma argsused
#endif
static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
blk_t ref_block EXT2FS_ATTR((unused)),
int ref_offset EXT2FS_ATTR((unused)),
void *priv_data)
{
struct xlate *xl = (struct xlate *) priv_data;
return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
}
errcode_t ext2fs_block_iterate(ext2_filsys fs,
ext2_ino_t ino,
int flags,
char *block_buf,
int (*func)(ext2_filsys fs,
blk_t *blocknr,
int blockcnt,
void *priv_data),
void *priv_data)
{
struct xlate xl;
xl.real_private = priv_data;
xl.func = func;
return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
block_buf, xlate_func, &xl);
}

270
e2fsprogs/ext2fs/bmap.c Normal file
View File

@ -0,0 +1,270 @@
/*
* bmap.c --- logical to physical block mapping
*
* Copyright (C) 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
#define _BMAP_INLINE_ __inline__
#else
#define _BMAP_INLINE_
#endif
extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
char *block_buf, int bmap_flags,
blk_t block, blk_t *phys_blk);
#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
static _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags,
blk_t ind, char *block_buf,
int *blocks_alloc,
blk_t nr, blk_t *ret_blk)
{
errcode_t retval;
blk_t b;
if (!ind) {
if (flags & BMAP_SET)
return EXT2_ET_SET_BMAP_NO_IND;
*ret_blk = 0;
return 0;
}
retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
if (retval)
return retval;
if (flags & BMAP_SET) {
b = *ret_blk;
#ifdef EXT2FS_ENABLE_SWAPFS
if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
b = ext2fs_swab32(b);
#endif
((blk_t *) block_buf)[nr] = b;
return io_channel_write_blk(fs->io, ind, 1, block_buf);
}
b = ((blk_t *) block_buf)[nr];
#ifdef EXT2FS_ENABLE_SWAPFS
if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
b = ext2fs_swab32(b);
#endif
if (!b && (flags & BMAP_ALLOC)) {
b = nr ? ((blk_t *) block_buf)[nr-1] : 0;
retval = ext2fs_alloc_block(fs, b,
block_buf + fs->blocksize, &b);
if (retval)
return retval;
#ifdef EXT2FS_ENABLE_SWAPFS
if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
else
#endif
((blk_t *) block_buf)[nr] = b;
retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
if (retval)
return retval;
(*blocks_alloc)++;
}
*ret_blk = b;
return 0;
}
static _BMAP_INLINE_ errcode_t block_dind_bmap(ext2_filsys fs, int flags,
blk_t dind, char *block_buf,
int *blocks_alloc,
blk_t nr, blk_t *ret_blk)
{
blk_t b;
errcode_t retval;
blk_t addr_per_block;
addr_per_block = (blk_t) fs->blocksize >> 2;
retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf,
blocks_alloc, nr / addr_per_block, &b);
if (retval)
return retval;
retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
nr % addr_per_block, ret_blk);
return retval;
}
static _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags,
blk_t tind, char *block_buf,
int *blocks_alloc,
blk_t nr, blk_t *ret_blk)
{
blk_t b;
errcode_t retval;
blk_t addr_per_block;
addr_per_block = (blk_t) fs->blocksize >> 2;
retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf,
blocks_alloc, nr / addr_per_block, &b);
if (retval)
return retval;
retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
nr % addr_per_block, ret_blk);
return retval;
}
errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
char *block_buf, int bmap_flags, blk_t block,
blk_t *phys_blk)
{
struct ext2_inode inode_buf;
blk_t addr_per_block;
blk_t b;
char *buf = 0;
errcode_t retval = 0;
int blocks_alloc = 0, inode_dirty = 0;
if (!(bmap_flags & BMAP_SET))
*phys_blk = 0;
/* Read inode structure if necessary */
if (!inode) {
retval = ext2fs_read_inode(fs, ino, &inode_buf);
if (retval)
return retval;
inode = &inode_buf;
}
addr_per_block = (blk_t) fs->blocksize >> 2;
if (!block_buf) {
retval = ext2fs_get_mem(fs->blocksize * 2, &buf);
if (retval)
return retval;
block_buf = buf;
}
if (block < EXT2_NDIR_BLOCKS) {
if (bmap_flags & BMAP_SET) {
b = *phys_blk;
#ifdef EXT2FS_ENABLE_SWAPFS
if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
b = ext2fs_swab32(b);
#endif
inode_bmap(inode, block) = b;
inode_dirty++;
goto done;
}
*phys_blk = inode_bmap(inode, block);
b = block ? inode_bmap(inode, block-1) : 0;
if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
retval = ext2fs_alloc_block(fs, b, block_buf, &b);
if (retval)
goto done;
inode_bmap(inode, block) = b;
blocks_alloc++;
*phys_blk = b;
}
goto done;
}
/* Indirect block */
block -= EXT2_NDIR_BLOCKS;
if (block < addr_per_block) {
b = inode_bmap(inode, EXT2_IND_BLOCK);
if (!b) {
if (!(bmap_flags & BMAP_ALLOC)) {
if (bmap_flags & BMAP_SET)
retval = EXT2_ET_SET_BMAP_NO_IND;
goto done;
}
b = inode_bmap(inode, EXT2_IND_BLOCK-1);
retval = ext2fs_alloc_block(fs, b, block_buf, &b);
if (retval)
goto done;
inode_bmap(inode, EXT2_IND_BLOCK) = b;
blocks_alloc++;
}
retval = block_ind_bmap(fs, bmap_flags, b, block_buf,
&blocks_alloc, block, phys_blk);
goto done;
}
/* Doubly indirect block */
block -= addr_per_block;
if (block < addr_per_block * addr_per_block) {
b = inode_bmap(inode, EXT2_DIND_BLOCK);
if (!b) {
if (!(bmap_flags & BMAP_ALLOC)) {
if (bmap_flags & BMAP_SET)
retval = EXT2_ET_SET_BMAP_NO_IND;
goto done;
}
b = inode_bmap(inode, EXT2_IND_BLOCK);
retval = ext2fs_alloc_block(fs, b, block_buf, &b);
if (retval)
goto done;
inode_bmap(inode, EXT2_DIND_BLOCK) = b;
blocks_alloc++;
}
retval = block_dind_bmap(fs, bmap_flags, b, block_buf,
&blocks_alloc, block, phys_blk);
goto done;
}
/* Triply indirect block */
block -= addr_per_block * addr_per_block;
b = inode_bmap(inode, EXT2_TIND_BLOCK);
if (!b) {
if (!(bmap_flags & BMAP_ALLOC)) {
if (bmap_flags & BMAP_SET)
retval = EXT2_ET_SET_BMAP_NO_IND;
goto done;
}
b = inode_bmap(inode, EXT2_DIND_BLOCK);
retval = ext2fs_alloc_block(fs, b, block_buf, &b);
if (retval)
goto done;
inode_bmap(inode, EXT2_TIND_BLOCK) = b;
blocks_alloc++;
}
retval = block_tind_bmap(fs, bmap_flags, b, block_buf,
&blocks_alloc, block, phys_blk);
done:
if (buf)
ext2fs_free_mem(&buf);
if ((retval == 0) && (blocks_alloc || inode_dirty)) {
inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
retval = ext2fs_write_inode(fs, ino, inode);
}
return retval;
}

160
e2fsprogs/ext2fs/bmove.c Normal file
View File

@ -0,0 +1,160 @@
/*
* bmove.c --- Move blocks around to make way for a particular
* filesystem structure.
*
* Copyright (C) 1997 Theodore Ts'o. This file may be redistributed
* under the terms of the GNU Public License.
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include "ext2_fs.h"
#include "ext2fsP.h"
struct process_block_struct {
ext2_ino_t ino;
struct ext2_inode * inode;
ext2fs_block_bitmap reserve;
ext2fs_block_bitmap alloc_map;
errcode_t error;
char *buf;
int add_dir;
int flags;
};
static int process_block(ext2_filsys fs, blk_t *block_nr,
e2_blkcnt_t blockcnt, blk_t ref_block,
int ref_offset, void *priv_data)
{
struct process_block_struct *pb;
errcode_t retval;
int ret;
blk_t block, orig;
pb = (struct process_block_struct *) priv_data;
block = orig = *block_nr;
ret = 0;
/*
* Let's see if this is one which we need to relocate
*/
if (ext2fs_test_block_bitmap(pb->reserve, block)) {
do {
if (++block >= fs->super->s_blocks_count)
block = fs->super->s_first_data_block;
if (block == orig) {
pb->error = EXT2_ET_BLOCK_ALLOC_FAIL;
return BLOCK_ABORT;
}
} while (ext2fs_test_block_bitmap(pb->reserve, block) ||
ext2fs_test_block_bitmap(pb->alloc_map, block));
retval = io_channel_read_blk(fs->io, orig, 1, pb->buf);
if (retval) {
pb->error = retval;
return BLOCK_ABORT;
}
retval = io_channel_write_blk(fs->io, block, 1, pb->buf);
if (retval) {
pb->error = retval;
return BLOCK_ABORT;
}
*block_nr = block;
ext2fs_mark_block_bitmap(pb->alloc_map, block);
ret = BLOCK_CHANGED;
if (pb->flags & EXT2_BMOVE_DEBUG)
printf("ino=%ld, blockcnt=%lld, %d->%d\n", pb->ino,
blockcnt, orig, block);
}
if (pb->add_dir) {
retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
block, (int) blockcnt);
if (retval) {
pb->error = retval;
ret |= BLOCK_ABORT;
}
}
return ret;
}
errcode_t ext2fs_move_blocks(ext2_filsys fs,
ext2fs_block_bitmap reserve,
ext2fs_block_bitmap alloc_map,
int flags)
{
ext2_ino_t ino;
struct ext2_inode inode;
errcode_t retval;
struct process_block_struct pb;
ext2_inode_scan scan;
char *block_buf;
retval = ext2fs_open_inode_scan(fs, 0, &scan);
if (retval)
return retval;
pb.reserve = reserve;
pb.error = 0;
pb.alloc_map = alloc_map ? alloc_map : fs->block_map;
pb.flags = flags;
retval = ext2fs_get_mem(fs->blocksize * 4, &block_buf);
if (retval)
return retval;
pb.buf = block_buf + fs->blocksize * 3;
/*
* If GET_DBLIST is set in the flags field, then we should
* gather directory block information while we're doing the
* block move.
*/
if (flags & EXT2_BMOVE_GET_DBLIST) {
if (fs->dblist) {
ext2fs_free_dblist(fs->dblist);
fs->dblist = NULL;
}
retval = ext2fs_init_dblist(fs, 0);
if (retval)
return retval;
}
retval = ext2fs_get_next_inode(scan, &ino, &inode);
if (retval)
return retval;
while (ino) {
if ((inode.i_links_count == 0) ||
!ext2fs_inode_has_valid_blocks(&inode))
goto next;
pb.ino = ino;
pb.inode = &inode;
pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) &&
flags & EXT2_BMOVE_GET_DBLIST);
retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
process_block, &pb);
if (retval)
return retval;
if (pb.error)
return pb.error;
next:
retval = ext2fs_get_next_inode(scan, &ino, &inode);
if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
goto next;
}
return 0;
}

86
e2fsprogs/ext2fs/brel.h Normal file
View File

@ -0,0 +1,86 @@
/*
* brel.h
*
* Copyright (C) 1996, 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
struct ext2_block_relocate_entry {
blk_t new;
__s16 offset;
__u16 flags;
union {
blk_t block_ref;
ext2_ino_t inode_ref;
} owner;
};
#define RELOCATE_TYPE_REF 0x0007
#define RELOCATE_BLOCK_REF 0x0001
#define RELOCATE_INODE_REF 0x0002
typedef struct ext2_block_relocation_table *ext2_brel;
struct ext2_block_relocation_table {
__u32 magic;
char *name;
blk_t current;
void *priv_data;
/*
* Add a block relocation entry.
*/
errcode_t (*put)(ext2_brel brel, blk_t old,
struct ext2_block_relocate_entry *ent);
/*
* Get a block relocation entry.
*/
errcode_t (*get)(ext2_brel brel, blk_t old,
struct ext2_block_relocate_entry *ent);
/*
* Initialize for iterating over the block relocation entries.
*/
errcode_t (*start_iter)(ext2_brel brel);
/*
* The iterator function for the inode relocation entries.
* Returns an inode number of 0 when out of entries.
*/
errcode_t (*next)(ext2_brel brel, blk_t *old,
struct ext2_block_relocate_entry *ent);
/*
* Move the inode relocation table from one block number to
* another.
*/
errcode_t (*move)(ext2_brel brel, blk_t old, blk_t new);
/*
* Remove a block relocation entry.
*/
errcode_t (*delete)(ext2_brel brel, blk_t old);
/*
* Free the block relocation table.
*/
errcode_t (*free)(ext2_brel brel);
};
errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
ext2_brel *brel);
#define ext2fs_brel_put(brel, old, ent) ((brel)->put((brel), old, ent))
#define ext2fs_brel_get(brel, old, ent) ((brel)->get((brel), old, ent))
#define ext2fs_brel_start_iter(brel) ((brel)->start_iter((brel)))
#define ext2fs_brel_next(brel, old, ent) ((brel)->next((brel), old, ent))
#define ext2fs_brel_move(brel, old, new) ((brel)->move((brel), old, new))
#define ext2fs_brel_delete(brel, old) ((brel)->delete((brel), old))
#define ext2fs_brel_free(brel) ((brel)->free((brel)))

197
e2fsprogs/ext2fs/brel_ma.c Normal file
View File

@ -0,0 +1,197 @@
/*
* brel_ma.c
*
* Copyright (C) 1996, 1997 Theodore Ts'o.
*
* TODO: rewrite to not use a direct array!!! (Fortunately this
* module isn't really used yet.)
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
#include "brel.h"
static errcode_t bma_put(ext2_brel brel, blk_t old,
struct ext2_block_relocate_entry *ent);
static errcode_t bma_get(ext2_brel brel, blk_t old,
struct ext2_block_relocate_entry *ent);
static errcode_t bma_start_iter(ext2_brel brel);
static errcode_t bma_next(ext2_brel brel, blk_t *old,
struct ext2_block_relocate_entry *ent);
static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new);
static errcode_t bma_delete(ext2_brel brel, blk_t old);
static errcode_t bma_free(ext2_brel brel);
struct brel_ma {
__u32 magic;
blk_t max_block;
struct ext2_block_relocate_entry *entries;
};
errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
ext2_brel *new_brel)
{
ext2_brel brel = 0;
errcode_t retval;
struct brel_ma *ma = 0;
size_t size;
*new_brel = 0;
/*
* Allocate memory structures
*/
retval = ext2fs_get_mem(sizeof(struct ext2_block_relocation_table),
&brel);
if (retval)
goto errout;
memset(brel, 0, sizeof(struct ext2_block_relocation_table));
retval = ext2fs_get_mem(strlen(name)+1, &brel->name);
if (retval)
goto errout;
strcpy(brel->name, name);
retval = ext2fs_get_mem(sizeof(struct brel_ma), &ma);
if (retval)
goto errout;
memset(ma, 0, sizeof(struct brel_ma));
brel->priv_data = ma;
size = (size_t) (sizeof(struct ext2_block_relocate_entry) *
(max_block+1));
retval = ext2fs_get_mem(size, &ma->entries);
if (retval)
goto errout;
memset(ma->entries, 0, size);
ma->max_block = max_block;
/*
* Fill in the brel data structure
*/
brel->put = bma_put;
brel->get = bma_get;
brel->start_iter = bma_start_iter;
brel->next = bma_next;
brel->move = bma_move;
brel->delete = bma_delete;
brel->free = bma_free;
*new_brel = brel;
return 0;
errout:
bma_free(brel);
return retval;
}
static errcode_t bma_put(ext2_brel brel, blk_t old,
struct ext2_block_relocate_entry *ent)
{
struct brel_ma *ma;
ma = brel->priv_data;
if (old > ma->max_block)
return EXT2_ET_INVALID_ARGUMENT;
ma->entries[(unsigned)old] = *ent;
return 0;
}
static errcode_t bma_get(ext2_brel brel, blk_t old,
struct ext2_block_relocate_entry *ent)
{
struct brel_ma *ma;
ma = brel->priv_data;
if (old > ma->max_block)
return EXT2_ET_INVALID_ARGUMENT;
if (ma->entries[(unsigned)old].new == 0)
return ENOENT;
*ent = ma->entries[old];
return 0;
}
static errcode_t bma_start_iter(ext2_brel brel)
{
brel->current = 0;
return 0;
}
static errcode_t bma_next(ext2_brel brel, blk_t *old,
struct ext2_block_relocate_entry *ent)
{
struct brel_ma *ma;
ma = brel->priv_data;
while (++brel->current < ma->max_block) {
if (ma->entries[(unsigned)brel->current].new == 0)
continue;
*old = brel->current;
*ent = ma->entries[(unsigned)brel->current];
return 0;
}
*old = 0;
return 0;
}
static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new)
{
struct brel_ma *ma;
ma = brel->priv_data;
if ((old > ma->max_block) || (new > ma->max_block))
return EXT2_ET_INVALID_ARGUMENT;
if (ma->entries[(unsigned)old].new == 0)
return ENOENT;
ma->entries[(unsigned)new] = ma->entries[old];
ma->entries[(unsigned)old].new = 0;
return 0;
}
static errcode_t bma_delete(ext2_brel brel, blk_t old)
{
struct brel_ma *ma;
ma = brel->priv_data;
if (old > ma->max_block)
return EXT2_ET_INVALID_ARGUMENT;
if (ma->entries[(unsigned)old].new == 0)
return ENOENT;
ma->entries[(unsigned)old].new = 0;
return 0;
}
static errcode_t bma_free(ext2_brel brel)
{
struct brel_ma *ma;
if (!brel)
return 0;
ma = brel->priv_data;
if (ma) {
if (ma->entries)
ext2fs_free_mem(&ma->entries);
ext2fs_free_mem(&ma);
}
if (brel->name)
ext2fs_free_mem(&brel->name);
ext2fs_free_mem(&brel);
return 0;
}

View File

@ -0,0 +1,68 @@
/*
* check_desc.c --- Check the group descriptors of an ext2 filesystem
*
* Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
/*
* This routine sanity checks the group descriptors
*/
errcode_t ext2fs_check_desc(ext2_filsys fs)
{
dgrp_t i;
blk_t block = fs->super->s_first_data_block;
blk_t next;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
for (i = 0; i < fs->group_desc_count; i++) {
next = block + fs->super->s_blocks_per_group;
/*
* Check to make sure block bitmap for group is
* located within the group.
*/
if (fs->group_desc[i].bg_block_bitmap < block ||
fs->group_desc[i].bg_block_bitmap >= next)
return EXT2_ET_GDESC_BAD_BLOCK_MAP;
/*
* Check to make sure inode bitmap for group is
* located within the group
*/
if (fs->group_desc[i].bg_inode_bitmap < block ||
fs->group_desc[i].bg_inode_bitmap >= next)
return EXT2_ET_GDESC_BAD_INODE_MAP;
/*
* Check to make sure inode table for group is located
* within the group
*/
if (fs->group_desc[i].bg_inode_table < block ||
((fs->group_desc[i].bg_inode_table +
fs->inode_blocks_per_group) >= next))
return EXT2_ET_GDESC_BAD_INODE_TABLE;
block = next;
}
return 0;
}

381
e2fsprogs/ext2fs/closefs.c Normal file
View File

@ -0,0 +1,381 @@
/*
* closefs.c --- close an ext2 filesystem
*
* Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <time.h>
#include <string.h>
#include "ext2_fs.h"
#include "ext2fsP.h"
static int test_root(int a, int b)
{
if (a == 0)
return 1;
while (1) {
if (a == 1)
return 1;
if (a % b)
return 0;
a = a / b;
}
}
int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
{
if (!(fs->super->s_feature_ro_compat &
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
return 1;
if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
test_root(group_block, 7))
return 1;
return 0;
}
int ext2fs_super_and_bgd_loc(ext2_filsys fs,
dgrp_t group,
blk_t *ret_super_blk,
blk_t *ret_old_desc_blk,
blk_t *ret_new_desc_blk,
int *ret_meta_bg)
{
blk_t group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0;
unsigned int meta_bg, meta_bg_size;
int numblocks, has_super;
int old_desc_blocks;
group_block = fs->super->s_first_data_block +
(group * fs->super->s_blocks_per_group);
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
old_desc_blocks = fs->super->s_first_meta_bg;
else
old_desc_blocks =
fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
if (group == fs->group_desc_count-1) {
numblocks = (fs->super->s_blocks_count -
fs->super->s_first_data_block) %
fs->super->s_blocks_per_group;
if (!numblocks)
numblocks = fs->super->s_blocks_per_group;
} else
numblocks = fs->super->s_blocks_per_group;
has_super = ext2fs_bg_has_super(fs, group);
if (has_super) {
super_blk = group_block;
numblocks--;
}
meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
meta_bg = group / meta_bg_size;
if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
(meta_bg < fs->super->s_first_meta_bg)) {
if (has_super) {
old_desc_blk = group_block + 1;
numblocks -= old_desc_blocks;
}
} else {
if (((group % meta_bg_size) == 0) ||
((group % meta_bg_size) == 1) ||
((group % meta_bg_size) == (meta_bg_size-1))) {
if (has_super)
has_super = 1;
new_desc_blk = group_block + has_super;
numblocks--;
}
}
numblocks -= 2 + fs->inode_blocks_per_group;
if (ret_super_blk)
*ret_super_blk = super_blk;
if (ret_old_desc_blk)
*ret_old_desc_blk = old_desc_blk;
if (ret_new_desc_blk)
*ret_new_desc_blk = new_desc_blk;
if (ret_meta_bg)
*ret_meta_bg = meta_bg;
return (numblocks);
}
/*
* This function forces out the primary superblock. We need to only
* write out those fields which we have changed, since if the
* filesystem is mounted, it may have changed some of the other
* fields.
*
* It takes as input a superblock which has already been byte swapped
* (if necessary).
*
*/
static errcode_t write_primary_superblock(ext2_filsys fs,
struct ext2_super_block *super)
{
__u16 *old_super, *new_super;
int check_idx, write_idx, size;
errcode_t retval;
if (!fs->io->manager->write_byte || !fs->orig_super) {
io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE,
super);
io_channel_set_blksize(fs->io, fs->blocksize);
return retval;
}
old_super = (__u16 *) fs->orig_super;
new_super = (__u16 *) super;
for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) {
if (old_super[check_idx] == new_super[check_idx])
continue;
write_idx = check_idx;
for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++)
if (old_super[check_idx] == new_super[check_idx])
break;
size = 2 * (check_idx - write_idx);
#if 0
printf("Writing %d bytes starting at %d\n",
size, write_idx*2);
#endif
retval = io_channel_write_byte(fs->io,
SUPERBLOCK_OFFSET + (2 * write_idx), size,
new_super + write_idx);
if (retval)
return retval;
}
memcpy(fs->orig_super, super, SUPERBLOCK_SIZE);
return 0;
}
/*
* Updates the revision to EXT2_DYNAMIC_REV
*/
void ext2fs_update_dynamic_rev(ext2_filsys fs)
{
struct ext2_super_block *sb = fs->super;
if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
return;
sb->s_rev_level = EXT2_DYNAMIC_REV;
sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
/* s_uuid is handled by e2fsck already */
/* other fields should be left alone */
}
static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group,
blk_t group_block,
struct ext2_super_block *super_shadow)
{
dgrp_t sgrp = group;
if (sgrp > ((1 << 16) - 1))
sgrp = (1 << 16) - 1;
#ifdef EXT2FS_ENABLE_SWAPFS
if (fs->flags & EXT2_FLAG_SWAP_BYTES)
super_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
else
#endif
fs->super->s_block_group_nr = sgrp;
return io_channel_write_blk(fs->io, group_block, -SUPERBLOCK_SIZE,
super_shadow);
}
errcode_t ext2fs_flush(ext2_filsys fs)
{
dgrp_t i,j;
blk_t group_block;
errcode_t retval;
unsigned long fs_state;
struct ext2_super_block *super_shadow = 0;
struct ext2_group_desc *group_shadow = 0;
struct ext2_group_desc *s, *t;
char *group_ptr;
int old_desc_blocks;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
fs_state = fs->super->s_state;
fs->super->s_wtime = time(NULL);
fs->super->s_block_group_nr = 0;
#ifdef EXT2FS_ENABLE_SWAPFS
if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
retval = EXT2_ET_NO_MEMORY;
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow);
if (retval)
goto errout;
retval = ext2fs_get_mem((size_t)(fs->blocksize *
fs->desc_blocks),
&group_shadow);
if (retval)
goto errout;
memset(group_shadow, 0, (size_t) fs->blocksize *
fs->desc_blocks);
/* swap the group descriptors */
for (j=0, s=fs->group_desc, t=group_shadow;
j < fs->group_desc_count; j++, t++, s++) {
*t = *s;
ext2fs_swap_group_desc(t);
}
} else {
super_shadow = fs->super;
group_shadow = fs->group_desc;
}
#else
super_shadow = fs->super;
group_shadow = fs->group_desc;
#endif
/*
* If this is an external journal device, don't write out the
* block group descriptors or any of the backup superblocks
*/
if (fs->super->s_feature_incompat &
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
goto write_primary_superblock_only;
/*
* Set the state of the FS to be non-valid. (The state has
* already been backed up earlier, and will be restored after
* we write out the backup superblocks.)
*/
fs->super->s_state &= ~EXT2_VALID_FS;
#ifdef EXT2FS_ENABLE_SWAPFS
if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
*super_shadow = *fs->super;
ext2fs_swap_super(super_shadow);
}
#endif
/*
* Write out the master group descriptors, and the backup
* superblocks and group descriptors.
*/
group_block = fs->super->s_first_data_block;
group_ptr = (char *) group_shadow;
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
old_desc_blocks = fs->super->s_first_meta_bg;
else
old_desc_blocks = fs->desc_blocks;
for (i = 0; i < fs->group_desc_count; i++) {
blk_t super_blk, old_desc_blk, new_desc_blk;
int meta_bg;
ext2fs_super_and_bgd_loc(fs, i, &super_blk, &old_desc_blk,
&new_desc_blk, &meta_bg);
if (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) &&i && super_blk) {
retval = write_backup_super(fs, i, super_blk,
super_shadow);
if (retval)
goto errout;
}
if (fs->flags & EXT2_FLAG_SUPER_ONLY)
continue;
if ((old_desc_blk) &&
(!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) || (i == 0))) {
retval = io_channel_write_blk(fs->io,
old_desc_blk, old_desc_blocks, group_ptr);
if (retval)
goto errout;
}
if (new_desc_blk) {
retval = io_channel_write_blk(fs->io, new_desc_blk,
1, group_ptr + (meta_bg*fs->blocksize));
if (retval)
goto errout;
}
}
fs->super->s_block_group_nr = 0;
fs->super->s_state = fs_state;
#ifdef EXT2FS_ENABLE_SWAPFS
if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
*super_shadow = *fs->super;
ext2fs_swap_super(super_shadow);
}
#endif
/*
* If the write_bitmaps() function is present, call it to
* flush the bitmaps. This is done this way so that a simple
* program that doesn't mess with the bitmaps doesn't need to
* drag in the bitmaps.c code.
*/
if (fs->write_bitmaps) {
retval = fs->write_bitmaps(fs);
if (retval)
goto errout;
}
write_primary_superblock_only:
/*
* Write out master superblock. This has to be done
* separately, since it is located at a fixed location
* (SUPERBLOCK_OFFSET). We flush all other pending changes
* out to disk first, just to avoid a race condition with an
* insy-tinsy window....
*/
retval = io_channel_flush(fs->io);
retval = write_primary_superblock(fs, super_shadow);
if (retval)
goto errout;
fs->flags &= ~EXT2_FLAG_DIRTY;
retval = io_channel_flush(fs->io);
errout:
fs->super->s_state = fs_state;
if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
if (super_shadow)
ext2fs_free_mem(&super_shadow);
if (group_shadow)
ext2fs_free_mem(&group_shadow);
}
return retval;
}
errcode_t ext2fs_close(ext2_filsys fs)
{
errcode_t retval;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (fs->flags & EXT2_FLAG_DIRTY) {
retval = ext2fs_flush(fs);
if (retval)
return retval;
}
if (fs->write_bitmaps) {
retval = fs->write_bitmaps(fs);
if (retval)
return retval;
}
ext2fs_free(fs);
return 0;
}

View File

@ -0,0 +1,72 @@
/*
* cmp_bitmaps.c --- routines to compare inode and block bitmaps.
*
* Copyright (C) 1995 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
ext2fs_block_bitmap bm2)
{
blk_t i;
EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_BLOCK_BITMAP);
EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_BLOCK_BITMAP);
if ((bm1->start != bm2->start) ||
(bm1->end != bm2->end) ||
(memcmp(bm1->bitmap, bm2->bitmap,
(size_t) (bm1->end - bm1->start)/8)))
return EXT2_ET_NEQ_BLOCK_BITMAP;
for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
if (ext2fs_fast_test_block_bitmap(bm1, i) !=
ext2fs_fast_test_block_bitmap(bm2, i))
return EXT2_ET_NEQ_BLOCK_BITMAP;
return 0;
}
errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
ext2fs_inode_bitmap bm2)
{
ext2_ino_t i;
EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_INODE_BITMAP);
EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_INODE_BITMAP);
if ((bm1->start != bm2->start) ||
(bm1->end != bm2->end) ||
(memcmp(bm1->bitmap, bm2->bitmap,
(size_t) (bm1->end - bm1->start)/8)))
return EXT2_ET_NEQ_INODE_BITMAP;
for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
if (ext2fs_fast_test_inode_bitmap(bm1, i) !=
ext2fs_fast_test_inode_bitmap(bm2, i))
return EXT2_ET_NEQ_INODE_BITMAP;
return 0;
}

260
e2fsprogs/ext2fs/dblist.c Normal file
View File

@ -0,0 +1,260 @@
/*
* dblist.c -- directory block list functions
*
* Copyright 1997 by Theodore Ts'o
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <time.h>
#include "ext2_fs.h"
#include "ext2fsP.h"
static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b);
/*
* Returns the number of directories in the filesystem as reported by
* the group descriptors. Of course, the group descriptors could be
* wrong!
*/
errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
{
dgrp_t i;
ext2_ino_t num_dirs, max_dirs;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
num_dirs = 0;
max_dirs = fs->super->s_inodes_per_group;
for (i = 0; i < fs->group_desc_count; i++) {
if (fs->group_desc[i].bg_used_dirs_count > max_dirs)
num_dirs += max_dirs / 8;
else
num_dirs += fs->group_desc[i].bg_used_dirs_count;
}
if (num_dirs > fs->super->s_inodes_count)
num_dirs = fs->super->s_inodes_count;
*ret_num_dirs = num_dirs;
return 0;
}
/*
* helper function for making a new directory block list (for
* initialize and copy).
*/
static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size, ext2_ino_t count,
struct ext2_db_entry *list,
ext2_dblist *ret_dblist)
{
ext2_dblist dblist;
errcode_t retval;
size_t len;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if ((ret_dblist == 0) && fs->dblist &&
(fs->dblist->magic == EXT2_ET_MAGIC_DBLIST))
return 0;
retval = ext2fs_get_mem(sizeof(struct ext2_struct_dblist), &dblist);
if (retval)
return retval;
memset(dblist, 0, sizeof(struct ext2_struct_dblist));
dblist->magic = EXT2_ET_MAGIC_DBLIST;
dblist->fs = fs;
if (size)
dblist->size = size;
else {
retval = ext2fs_get_num_dirs(fs, &dblist->size);
if (retval)
goto cleanup;
dblist->size = (dblist->size * 2) + 12;
}
len = (size_t) sizeof(struct ext2_db_entry) * dblist->size;
dblist->count = count;
retval = ext2fs_get_mem(len, &dblist->list);
if (retval)
goto cleanup;
if (list)
memcpy(dblist->list, list, len);
else
memset(dblist->list, 0, len);
if (ret_dblist)
*ret_dblist = dblist;
else
fs->dblist = dblist;
return 0;
cleanup:
if (dblist)
ext2fs_free_mem(&dblist);
return retval;
}
/*
* Initialize a directory block list
*/
errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist)
{
ext2_dblist dblist;
errcode_t retval;
retval = make_dblist(fs, 0, 0, 0, &dblist);
if (retval)
return retval;
dblist->sorted = 1;
if (ret_dblist)
*ret_dblist = dblist;
else
fs->dblist = dblist;
return 0;
}
/*
* Copy a directory block list
*/
errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest)
{
ext2_dblist dblist;
errcode_t retval;
retval = make_dblist(src->fs, src->size, src->count, src->list,
&dblist);
if (retval)
return retval;
dblist->sorted = src->sorted;
*dest = dblist;
return 0;
}
/*
* Close a directory block list
*
* (moved to closefs.c)
*/
/*
* Add a directory block to the directory block list
*/
errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
int blockcnt)
{
struct ext2_db_entry *new_entry;
errcode_t retval;
unsigned long old_size;
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
if (dblist->count >= dblist->size) {
old_size = dblist->size * sizeof(struct ext2_db_entry);
dblist->size += 100;
retval = ext2fs_resize_mem(old_size, (size_t) dblist->size *
sizeof(struct ext2_db_entry),
&dblist->list);
if (retval) {
dblist->size -= 100;
return retval;
}
}
new_entry = dblist->list + ( (int) dblist->count++);
new_entry->blk = blk;
new_entry->ino = ino;
new_entry->blockcnt = blockcnt;
dblist->sorted = 0;
return 0;
}
/*
* Change the directory block to the directory block list
*/
errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
int blockcnt)
{
dgrp_t i;
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
for (i=0; i < dblist->count; i++) {
if ((dblist->list[i].ino != ino) ||
(dblist->list[i].blockcnt != blockcnt))
continue;
dblist->list[i].blk = blk;
dblist->sorted = 0;
return 0;
}
return EXT2_ET_DB_NOT_FOUND;
}
void ext2fs_dblist_sort(ext2_dblist dblist,
EXT2_QSORT_TYPE (*sortfunc)(const void *,
const void *))
{
if (!sortfunc)
sortfunc = dir_block_cmp;
qsort(dblist->list, (size_t) dblist->count,
sizeof(struct ext2_db_entry), sortfunc);
dblist->sorted = 1;
}
/*
* This function iterates over the directory block list
*/
errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
int (*func)(ext2_filsys fs,
struct ext2_db_entry *db_info,
void *priv_data),
void *priv_data)
{
ext2_ino_t i;
int ret;
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
if (!dblist->sorted)
ext2fs_dblist_sort(dblist, 0);
for (i=0; i < dblist->count; i++) {
ret = (*func)(dblist->fs, &dblist->list[(int)i], priv_data);
if (ret & DBLIST_ABORT)
return 0;
}
return 0;
}
static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b)
{
const struct ext2_db_entry *db_a =
(const struct ext2_db_entry *) a;
const struct ext2_db_entry *db_b =
(const struct ext2_db_entry *) b;
if (db_a->blk != db_b->blk)
return (int) (db_a->blk - db_b->blk);
if (db_a->ino != db_b->ino)
return (int) (db_a->ino - db_b->ino);
return (int) (db_a->blockcnt - db_b->blockcnt);
}
int ext2fs_dblist_count(ext2_dblist dblist)
{
return (int) dblist->count;
}

View File

@ -0,0 +1,75 @@
/*
* dblist_dir.c --- iterate by directory entry
*
* Copyright 1997 by Theodore Ts'o
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <time.h>
#include "ext2_fs.h"
#include "ext2fsP.h"
static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info,
void *priv_data);
errcode_t ext2fs_dblist_dir_iterate(ext2_dblist dblist,
int flags,
char *block_buf,
int (*func)(ext2_ino_t dir,
int entry,
struct ext2_dir_entry *dirent,
int offset,
int blocksize,
char *buf,
void *priv_data),
void *priv_data)
{
errcode_t retval;
struct dir_context ctx;
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
ctx.dir = 0;
ctx.flags = flags;
if (block_buf)
ctx.buf = block_buf;
else {
retval = ext2fs_get_mem(dblist->fs->blocksize, &ctx.buf);
if (retval)
return retval;
}
ctx.func = func;
ctx.priv_data = priv_data;
ctx.errcode = 0;
retval = ext2fs_dblist_iterate(dblist, db_dir_proc, &ctx);
if (!block_buf)
ext2fs_free_mem(&ctx.buf);
if (retval)
return retval;
return ctx.errcode;
}
static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info,
void *priv_data)
{
struct dir_context *ctx;
ctx = (struct dir_context *) priv_data;
ctx->dir = db_info->ino;
return ext2fs_process_dir_block(fs, &db_info->blk,
db_info->blockcnt, 0, 0, priv_data);
}

View File

@ -0,0 +1,219 @@
/*
* dir_iterate.c --- ext2fs directory iteration operations
*
* Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include "ext2_fs.h"
#include "ext2fsP.h"
/*
* This function checks to see whether or not a potential deleted
* directory entry looks valid. What we do is check the deleted entry
* and each successive entry to make sure that they all look valid and
* that the last deleted entry ends at the beginning of the next
* undeleted entry. Returns 1 if the deleted entry looks valid, zero
* if not valid.
*/
static int ext2fs_validate_entry(char *buf, int offset, int final_offset)
{
struct ext2_dir_entry *dirent;
while (offset < final_offset) {
dirent = (struct ext2_dir_entry *)(buf + offset);
offset += dirent->rec_len;
if ((dirent->rec_len < 8) ||
((dirent->rec_len % 4) != 0) ||
(((dirent->name_len & 0xFF)+8) > dirent->rec_len))
return 0;
}
return (offset == final_offset);
}
errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
ext2_ino_t dir,
int flags,
char *block_buf,
int (*func)(ext2_ino_t dir,
int entry,
struct ext2_dir_entry *dirent,
int offset,
int blocksize,
char *buf,
void *priv_data),
void *priv_data)
{
struct dir_context ctx;
errcode_t retval;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
retval = ext2fs_check_directory(fs, dir);
if (retval)
return retval;
ctx.dir = dir;
ctx.flags = flags;
if (block_buf)
ctx.buf = block_buf;
else {
retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
if (retval)
return retval;
}
ctx.func = func;
ctx.priv_data = priv_data;
ctx.errcode = 0;
retval = ext2fs_block_iterate2(fs, dir, 0, 0,
ext2fs_process_dir_block, &ctx);
if (!block_buf)
ext2fs_free_mem(&ctx.buf);
if (retval)
return retval;
return ctx.errcode;
}
struct xlate {
int (*func)(struct ext2_dir_entry *dirent,
int offset,
int blocksize,
char *buf,
void *priv_data);
void *real_private;
};
static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
int entry EXT2FS_ATTR((unused)),
struct ext2_dir_entry *dirent, int offset,
int blocksize, char *buf, void *priv_data)
{
struct xlate *xl = (struct xlate *) priv_data;
return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
}
extern errcode_t ext2fs_dir_iterate(ext2_filsys fs,
ext2_ino_t dir,
int flags,
char *block_buf,
int (*func)(struct ext2_dir_entry *dirent,
int offset,
int blocksize,
char *buf,
void *priv_data),
void *priv_data)
{
struct xlate xl;
xl.real_private = priv_data;
xl.func = func;
return ext2fs_dir_iterate2(fs, dir, flags, block_buf,
xlate_func, &xl);
}
/*
* Helper function which is private to this module. Used by
* ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate()
*/
int ext2fs_process_dir_block(ext2_filsys fs,
blk_t *blocknr,
e2_blkcnt_t blockcnt,
blk_t ref_block EXT2FS_ATTR((unused)),
int ref_offset EXT2FS_ATTR((unused)),
void *priv_data)
{
struct dir_context *ctx = (struct dir_context *) priv_data;
unsigned int offset = 0;
unsigned int next_real_entry = 0;
int ret = 0;
int changed = 0;
int do_abort = 0;
int entry, size;
struct ext2_dir_entry *dirent;
if (blockcnt < 0)
return 0;
entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
ctx->errcode = ext2fs_read_dir_block(fs, *blocknr, ctx->buf);
if (ctx->errcode)
return BLOCK_ABORT;
while (offset < fs->blocksize) {
dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
if (((offset + dirent->rec_len) > fs->blocksize) ||
(dirent->rec_len < 8) ||
((dirent->rec_len % 4) != 0) ||
(((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
ctx->errcode = EXT2_ET_DIR_CORRUPTED;
return BLOCK_ABORT;
}
if (!dirent->inode &&
!(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
goto next;
ret = (ctx->func)(ctx->dir,
(next_real_entry > offset) ?
DIRENT_DELETED_FILE : entry,
dirent, offset,
fs->blocksize, ctx->buf,
ctx->priv_data);
if (entry < DIRENT_OTHER_FILE)
entry++;
if (ret & DIRENT_CHANGED)
changed++;
if (ret & DIRENT_ABORT) {
do_abort++;
break;
}
next:
if (next_real_entry == offset)
next_real_entry += dirent->rec_len;
if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
size = ((dirent->name_len & 0xFF) + 11) & ~3;
if (dirent->rec_len != size) {
unsigned int final_offset;
final_offset = offset + dirent->rec_len;
offset += size;
while (offset < final_offset &&
!ext2fs_validate_entry(ctx->buf,
offset,
final_offset))
offset += 4;
continue;
}
}
offset += dirent->rec_len;
}
if (changed) {
ctx->errcode = ext2fs_write_dir_block(fs, *blocknr, ctx->buf);
if (ctx->errcode)
return BLOCK_ABORT;
}
if (do_abort)
return BLOCK_ABORT;
return 0;
}

130
e2fsprogs/ext2fs/dirblock.c Normal file
View File

@ -0,0 +1,130 @@
/*
* dirblock.c --- directory block routines.
*
* Copyright (C) 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <time.h>
#include "ext2_fs.h"
#include "ext2fs.h"
errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
void *buf, int flags EXT2FS_ATTR((unused)))
{
errcode_t retval;
char *p, *end;
struct ext2_dir_entry *dirent;
unsigned int name_len, rec_len, do_swap;
retval = io_channel_read_blk(fs->io, block, 1, buf);
if (retval)
return retval;
#ifdef EXT2FS_ENABLE_SWAPFS
do_swap = (fs->flags & (EXT2_FLAG_SWAP_BYTES|
EXT2_FLAG_SWAP_BYTES_READ)) != 0;
#endif
p = (char *) buf;
end = (char *) buf + fs->blocksize;
while (p < end-8) {
dirent = (struct ext2_dir_entry *) p;
#ifdef EXT2FS_ENABLE_SWAPFS
if (do_swap) {
dirent->inode = ext2fs_swab32(dirent->inode);
dirent->rec_len = ext2fs_swab16(dirent->rec_len);
dirent->name_len = ext2fs_swab16(dirent->name_len);
}
#endif
name_len = dirent->name_len;
#ifdef WORDS_BIGENDIAN
if (flags & EXT2_DIRBLOCK_V2_STRUCT)
dirent->name_len = ext2fs_swab16(dirent->name_len);
#endif
rec_len = dirent->rec_len;
if ((rec_len < 8) || (rec_len % 4)) {
rec_len = 8;
retval = EXT2_ET_DIR_CORRUPTED;
}
if (((name_len & 0xFF) + 8) > dirent->rec_len)
retval = EXT2_ET_DIR_CORRUPTED;
p += rec_len;
}
return retval;
}
errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
void *buf)
{
return ext2fs_read_dir_block2(fs, block, buf, 0);
}
errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
void *inbuf, int flags EXT2FS_ATTR((unused)))
{
#ifdef EXT2FS_ENABLE_SWAPFS
int do_swap = 0;
errcode_t retval;
char *p, *end;
char *buf = 0;
struct ext2_dir_entry *dirent;
if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
do_swap = 1;
#ifndef WORDS_BIGENDIAN
if (!do_swap)
return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
#endif
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
return retval;
memcpy(buf, inbuf, fs->blocksize);
p = buf;
end = buf + fs->blocksize;
while (p < end) {
dirent = (struct ext2_dir_entry *) p;
if ((dirent->rec_len < 8) ||
(dirent->rec_len % 4)) {
ext2fs_free_mem(&buf);
return (EXT2_ET_DIR_CORRUPTED);
}
p += dirent->rec_len;
if (do_swap) {
dirent->inode = ext2fs_swab32(dirent->inode);
dirent->rec_len = ext2fs_swab16(dirent->rec_len);
dirent->name_len = ext2fs_swab16(dirent->name_len);
}
#ifdef WORDS_BIGENDIAN
if (flags & EXT2_DIRBLOCK_V2_STRUCT)
dirent->name_len = ext2fs_swab16(dirent->name_len);
#endif
}
retval = io_channel_write_blk(fs->io, block, 1, buf);
ext2fs_free_mem(&buf);
return retval;
#else
return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
#endif
}
errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
void *inbuf)
{
return ext2fs_write_dir_block2(fs, block, inbuf, 0);
}

233
e2fsprogs/ext2fs/dirhash.c Normal file
View File

@ -0,0 +1,233 @@
/*
* dirhash.c -- Calculate the hash of a directory entry
*
* Copyright (c) 2001 Daniel Phillips
*
* Copyright (c) 2002 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#include "ext2_fs.h"
#include "ext2fs.h"
/*
* Keyed 32-bit hash function using TEA in a Davis-Meyer function
* H0 = Key
* Hi = E Mi(Hi-1) + Hi-1
*
* (see Applied Cryptography, 2nd edition, p448).
*
* Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
*
* This code is made available under the terms of the GPL
*/
#define DELTA 0x9E3779B9
static void TEA_transform(__u32 buf[4], __u32 const in[])
{
__u32 sum = 0;
__u32 b0 = buf[0], b1 = buf[1];
__u32 a = in[0], b = in[1], c = in[2], d = in[3];
int n = 16;
do {
sum += DELTA;
b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
} while(--n);
buf[0] += b0;
buf[1] += b1;
}
/* F, G and H are basic MD4 functions: selection, majority, parity */
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
/*
* The generic round function. The application is so specific that
* we don't bother protecting all the arguments with parens, as is generally
* good macro practice, in favor of extra legibility.
* Rotation is separate from addition to prevent recomputation
*/
#define ROUND(f, a, b, c, d, x, s) \
(a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
#define K1 0
#define K2 013240474631UL
#define K3 015666365641UL
/*
* Basic cut-down MD4 transform. Returns only 32 bits of result.
*/
static void halfMD4Transform (__u32 buf[4], __u32 const in[])
{
__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
/* Round 1 */
ROUND(F, a, b, c, d, in[0] + K1, 3);
ROUND(F, d, a, b, c, in[1] + K1, 7);
ROUND(F, c, d, a, b, in[2] + K1, 11);
ROUND(F, b, c, d, a, in[3] + K1, 19);
ROUND(F, a, b, c, d, in[4] + K1, 3);
ROUND(F, d, a, b, c, in[5] + K1, 7);
ROUND(F, c, d, a, b, in[6] + K1, 11);
ROUND(F, b, c, d, a, in[7] + K1, 19);
/* Round 2 */
ROUND(G, a, b, c, d, in[1] + K2, 3);
ROUND(G, d, a, b, c, in[3] + K2, 5);
ROUND(G, c, d, a, b, in[5] + K2, 9);
ROUND(G, b, c, d, a, in[7] + K2, 13);
ROUND(G, a, b, c, d, in[0] + K2, 3);
ROUND(G, d, a, b, c, in[2] + K2, 5);
ROUND(G, c, d, a, b, in[4] + K2, 9);
ROUND(G, b, c, d, a, in[6] + K2, 13);
/* Round 3 */
ROUND(H, a, b, c, d, in[3] + K3, 3);
ROUND(H, d, a, b, c, in[7] + K3, 9);
ROUND(H, c, d, a, b, in[2] + K3, 11);
ROUND(H, b, c, d, a, in[6] + K3, 15);
ROUND(H, a, b, c, d, in[1] + K3, 3);
ROUND(H, d, a, b, c, in[5] + K3, 9);
ROUND(H, c, d, a, b, in[0] + K3, 11);
ROUND(H, b, c, d, a, in[4] + K3, 15);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
#undef ROUND
#undef F
#undef G
#undef H
#undef K1
#undef K2
#undef K3
/* The old legacy hash */
static ext2_dirhash_t dx_hack_hash (const char *name, int len)
{
__u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
while (len--) {
__u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
if (hash & 0x80000000) hash -= 0x7fffffff;
hash1 = hash0;
hash0 = hash;
}
return (hash0 << 1);
}
static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
{
__u32 pad, val;
int i;
pad = (__u32)len | ((__u32)len << 8);
pad |= pad << 16;
val = pad;
if (len > num*4)
len = num * 4;
for (i=0; i < len; i++) {
if ((i % 4) == 0)
val = pad;
val = msg[i] + (val << 8);
if ((i % 4) == 3) {
*buf++ = val;
val = pad;
num--;
}
}
if (--num >= 0)
*buf++ = val;
while (--num >= 0)
*buf++ = pad;
}
/*
* Returns the hash of a filename. If len is 0 and name is NULL, then
* this function can be used to test whether or not a hash version is
* supported.
*
* The seed is an 4 longword (32 bits) "secret" which can be used to
* uniquify a hash. If the seed is all zero's, then some default seed
* may be used.
*
* A particular hash version specifies whether or not the seed is
* represented, and whether or not the returned hash is 32 bits or 64
* bits. 32 bit hashes will return 0 for the minor hash.
*/
errcode_t ext2fs_dirhash(int version, const char *name, int len,
const __u32 *seed,
ext2_dirhash_t *ret_hash,
ext2_dirhash_t *ret_minor_hash)
{
__u32 hash;
__u32 minor_hash = 0;
const char *p;
int i;
__u32 in[8], buf[4];
/* Initialize the default seed for the hash checksum functions */
buf[0] = 0x67452301;
buf[1] = 0xefcdab89;
buf[2] = 0x98badcfe;
buf[3] = 0x10325476;
/* Check to see if the seed is all zero's */
if (seed) {
for (i=0; i < 4; i++) {
if (seed[i])
break;
}
if (i < 4)
memcpy(buf, seed, sizeof(buf));
}
switch (version) {
case EXT2_HASH_LEGACY:
hash = dx_hack_hash(name, len);
break;
case EXT2_HASH_HALF_MD4:
p = name;
while (len > 0) {
str2hashbuf(p, len, in, 8);
halfMD4Transform(buf, in);
len -= 32;
p += 32;
}
minor_hash = buf[2];
hash = buf[1];
break;
case EXT2_HASH_TEA:
p = name;
while (len > 0) {
str2hashbuf(p, len, in, 4);
TEA_transform(buf, in);
len -= 16;
p += 16;
}
hash = buf[0];
minor_hash = buf[1];
break;
default:
*ret_hash = 0;
return EXT2_ET_DIRHASH_UNSUPP;
}
*ret_hash = hash & ~1;
if (ret_minor_hash)
*ret_minor_hash = minor_hash;
return 0;
}

456
e2fsprogs/ext2fs/dosio.c Normal file
View File

@ -0,0 +1,456 @@
/*
* dosio.c -- Disk I/O module for the ext2fs/DOS library.
*
* Copyright (c) 1997 by Theodore Ts'o.
*
* Copyright (c) 1997 Mark Habersack
* This file may be distributed under the terms of the GNU Public License.
*
*/
#include <stdio.h>
#include <bios.h>
#include <string.h>
#include <ctype.h>
#include <io.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include <ext2fs/ext2_types.h>
#include "utils.h"
#include "dosio.h"
#include "et/com_err.h"
#include "ext2_err.h"
#include "ext2fs/io.h"
/*
* Some helper macros
*/
#define LINUX_EXT2FS 0x83
#define LINUX_SWAP 0x82
#define WRITE_ERR(_msg_) write(2, _msg_, strlen(_msg_))
#define WRITE_ERR_S(_msg_) write(2, _msg_, sizeof(_msg_))
/*
* Exported variables
*/
unsigned long _dio_error;
unsigned long _dio_hw_error;
/*
* Array of all opened partitions
*/
static PARTITION **partitions = NULL;
static unsigned short npart = 0; /* Number of mapped partitions */
static PARTITION *active = NULL;
/*
* I/O Manager routine prototypes
*/
static errcode_t dos_open(const char *dev, int flags, io_channel *channel);
static errcode_t dos_close(io_channel channel);
static errcode_t dos_set_blksize(io_channel channel, int blksize);
static errcode_t dos_read_blk(io_channel channel, unsigned long block,
int count, void *buf);
static errcode_t dos_write_blk(io_channel channel, unsigned long block,
int count, const void *buf);
static errcode_t dos_flush(io_channel channel);
static struct struct_io_manager struct_dos_manager = {
EXT2_ET_MAGIC_IO_MANAGER,
"DOS I/O Manager",
dos_open,
dos_close,
dos_set_blksize,
dos_read_blk,
dos_write_blk,
dos_flush
};
io_manager dos_io_manager = &struct_dos_manager;
/*
* Macro taken from unix_io.c
*/
/*
* For checking structure magic numbers...
*/
#define EXT2_CHECK_MAGIC(struct, code) \
if ((struct)->magic != (code)) return (code)
/*
* Calculates a CHS address of a sector from its LBA
* offset for the given partition.
*/
static void lba2chs(unsigned long lba_addr, CHS *chs, PARTITION *part)
{
unsigned long abss;
chs->offset = lba_addr & 0x000001FF;
abss = (lba_addr >> 9) + part->start;
chs->cyl = abss / (part->sects * part->heads);
chs->head = (abss / part->sects) % part->heads;
chs->sector = (abss % part->sects) + 1;
}
#ifdef __TURBOC__
#pragma argsused
#endif
/*
* Scans the passed partition table looking for *pno partition
* that has LINUX_EXT2FS type.
*
* TODO:
* For partition numbers >5 Linux uses DOS extended partitions -
* dive into them an return an appropriate entry. Also dive into
* extended partitions when scanning for a first Linux/ext2fs.
*/
static PTABLE_ENTRY *scan_partition_table(PTABLE_ENTRY *pentry,
unsigned short phys,
unsigned char *pno)
{
unsigned i;
if(*pno != 0xFF && *pno >= 5)
return NULL; /* We don't support extended partitions for now */
if(*pno != 0xFF)
{
if(pentry[*pno].type == LINUX_EXT2FS)
return &pentry[*pno];
else
{
if(!pentry[*pno].type)
*pno = 0xFE;
else if(pentry[*pno].type == LINUX_SWAP)
*pno = 0xFD;
return NULL;
}
}
for(i = 0; i < 4; i++)
if(pentry[i].type == LINUX_EXT2FS)
{
*pno = i;
return &pentry[i];
}
return NULL;
}
/*
* Allocate libext2fs structures associated with I/O manager
*/
static io_channel alloc_io_channel(PARTITION *part)
{
io_channel ioch;
ioch = (io_channel)malloc(sizeof(struct struct_io_channel));
if (!ioch)
return NULL;
memset(ioch, 0, sizeof(struct struct_io_channel));
ioch->magic = EXT2_ET_MAGIC_IO_CHANNEL;
ioch->manager = dos_io_manager;
ioch->name = (char *)malloc(strlen(part->dev)+1);
if (!ioch->name) {
free(ioch);
return NULL;
}
strcpy(ioch->name, part->dev);
ioch->private_data = part;
ioch->block_size = 1024; /* The smallest ext2fs block size */
ioch->read_error = 0;
ioch->write_error = 0;
return ioch;
}
#ifdef __TURBOC__
#pragma argsused
#endif
/*
* Open the 'name' partition, initialize all information structures
* we need to keep and create libext2fs I/O manager.
*/
static errcode_t dos_open(const char *dev, int flags, io_channel *channel)
{
unsigned char *tmp, sec[512];
PARTITION *part;
PTABLE_ENTRY *pent;
PARTITION **newparts;
if(!dev)
{
_dio_error = ERR_BADDEV;
return EXT2_ET_BAD_DEVICE_NAME;
}
/*
* First check whether the dev name is OK
*/
tmp = (unsigned char*)strrchr(dev, '/');
if(!tmp)
{
_dio_error = ERR_BADDEV;
return EXT2_ET_BAD_DEVICE_NAME;
}
*tmp = 0;
if(strcmp(dev, "/dev"))
{
_dio_error = ERR_BADDEV;
return EXT2_ET_BAD_DEVICE_NAME;
}
*tmp++ = '/';
/*
* Check whether the partition data is already in cache
*/
part = (PARTITION*)malloc(sizeof(PARTITION));
if (!part)
return ENOMEM;
{
int i = 0;
for(;i < npart; i++)
if(!strcmp(partitions[i]->dev, dev))
{
/* Found it! Make it the active one */
active = partitions[i];
*channel = alloc_io_channel(active);
if (!*channel)
return ENOMEM;
return 0;
}
}
/*
* Drive number & optionally partn number
*/
switch(tmp[0])
{
case 'h':
case 's':
part->phys = 0x80;
part->phys += toupper(tmp[2]) - 'A';
/*
* Do we have the partition number?
*/
if(tmp[3])
part->pno = isdigit((int)tmp[3]) ? tmp[3] - '0' - 1: 0;
else
part->pno = 0xFF;
break;
case 'f':
if(tmp[2])
part->phys = isdigit((int)tmp[2]) ? tmp[2] - '0' : 0;
else
part->phys = 0x00; /* We'll assume /dev/fd0 */
break;
default:
_dio_error = ERR_BADDEV;
return ENODEV;
}
if(part->phys < 0x80)
{
/* We don't support floppies for now */
_dio_error = ERR_NOTSUPP;
return EINVAL;
}
part->dev = strdup(dev);
/*
* Get drive's geometry
*/
_dio_hw_error = biosdisk(DISK_GET_GEOMETRY,
part->phys,
0, /* head */
0, /* cylinder */
1, /* sector */
1, /* just one sector */
sec);
if(!HW_OK())
{
_dio_error = ERR_HARDWARE;
if (part)
free(part);
return EFAULT;
}
/*
* Calculate the geometry
*/
part->cyls = (unsigned short)(((sec[0] >> 6) << 8) + sec[1] + 1);
part->heads = sec[3] + 1;
part->sects = sec[0] & 0x3F;
/*
* Now that we know all we need, let's look for the partition
*/
_dio_hw_error = biosdisk(DISK_READ, part->phys, 0, 0, 1, 1, sec);
if(!HW_OK())
{
_dio_error = ERR_HARDWARE;
if (part)
free(part);
return EFAULT;
}
pent = (PTABLE_ENTRY*)&sec[0x1BE];
pent = scan_partition_table(pent, part->phys, &part->pno);
if(!pent)
{
_dio_error = part->pno == 0xFE ? ERR_EMPTYPART :
part->pno == 0xFD ? ERR_LINUXSWAP : ERR_NOTEXT2FS;
if (part)
free(part);
return ENODEV;
}
/*
* Calculate the remaining figures
*/
{
unsigned long fsec, fhead, fcyl;
fsec = (unsigned long)(pent->start_sec & 0x3F);
fhead = (unsigned long)pent->start_head;
fcyl = ((pent->start_sec >> 6) << 8) + pent->start_cyl;
part->start = fsec + fhead * part->sects + fcyl *
(part->heads * part->sects) - 1;
part->len = pent->size;
}
/*
* Add the partition to the table
*/
newparts = (PARTITION**)realloc(partitions, sizeof(PARTITION) * npart);
if (!newparts) {
free(part);
return ENOMEM;
}
partitions = newparts;
partitions[npart++] = active = part;
/*
* Now alloc all libe2fs structures
*/
*channel = alloc_io_channel(active);
if (!*channel)
return ENOMEM;
return 0;
}
static errcode_t dos_close(io_channel channel)
{
if (channel->name)
free(channel->name);
if (channel)
free(channel);
return 0;
}
static errcode_t dos_set_blksize(io_channel channel, int blksize)
{
channel->block_size = blksize;
return 0;
}
static errcode_t dos_read_blk(io_channel channel, unsigned long block,
int count, void *buf)
{
PARTITION *part;
size_t size;
ext2_loff_t loc;
CHS chs;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
part = (PARTITION*)channel->private_data;
size = (size_t)((count < 0) ? -count : count * channel->block_size);
loc = (ext2_loff_t) block * channel->block_size;
lba2chs(loc, &chs, part);
/*
* Potential bug here:
* If DJGPP is used then reads of >18 sectors will fail!
* Have to rewrite biosdisk.
*/
_dio_hw_error = biosdisk(DISK_READ,
part->phys,
chs.head,
chs.cyl,
chs.sector,
size < 512 ? 1 : size/512,
buf);
if(!HW_OK())
{
_dio_error = ERR_HARDWARE;
return EFAULT;
}
return 0;
}
static errcode_t dos_write_blk(io_channel channel, unsigned long block,
int count, const void *buf)
{
PARTITION *part;
size_t size;
ext2_loff_t loc;
CHS chs;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
part = (PARTITION*)channel->private_data;
if(count == 1)
size = (size_t)channel->block_size;
else
{
if (count < 0)
size = (size_t)-count;
else
size = (size_t)(count * channel->block_size);
}
loc = (ext2_loff_t)block * channel->block_size;
lba2chs(loc, &chs, part);
_dio_hw_error = biosdisk(DISK_WRITE,
part->phys,
chs.head,
chs.cyl,
chs.sector,
size < 512 ? 1 : size/512,
(void*)buf);
if(!HW_OK())
{
_dio_error = ERR_HARDWARE;
return EFAULT;
}
return 0;
}
#ifdef __TURBOC__
#pragma argsused
#endif
static errcode_t dos_flush(io_channel channel)
{
/*
* No buffers, no flush...
*/
return 0;
}

153
e2fsprogs/ext2fs/dosio.h Normal file
View File

@ -0,0 +1,153 @@
/*
* v1.0
*
* Disk I/O include file for the ext2fs/DOS library.
*
* Copyright (c) 1997 Mark Habersack
* This file may be distributed under the terms of the GNU Public License.
*
*/
#ifndef __diskio_h
#define __diskio_h
#ifdef __TURBOC__
#ifndef __LARGE__
# error "ext2fs/DOS library requires LARGE model!"
#endif
#endif
#ifdef __TURBOC__
#include "msdos.h"
#endif
/*
* A helper structure used in LBA => CHS conversion
*/
typedef struct
{
unsigned short cyl; /* Cylinder (or track) */
unsigned short head;
unsigned short sector;
unsigned short offset; /* Offset of byte within the sector */
} CHS;
/*
* All partition data we need is here
*/
typedef struct
{
char *dev; /* _Linux_ device name (like "/dev/hda1") */
unsigned char phys; /* Physical DOS drive number */
unsigned long start; /* LBA address of partition start */
unsigned long len; /* length of partition in sectors */
unsigned char pno; /* Partition number (read from *dev) */
/* This partition's drive geometry */
unsigned short cyls;
unsigned short heads;
unsigned short sects;
} PARTITION;
/*
* PC partition table entry format
*/
#ifdef __DJGPP__
#pragma pack(1)
#endif
typedef struct
{
unsigned char active;
unsigned char start_head;
unsigned char start_sec;
unsigned char start_cyl;
unsigned char type;
unsigned char end_head;
unsigned char end_sec;
unsigned char end_cyl;
unsigned long first_sec_rel;
unsigned long size;
} PTABLE_ENTRY;
#ifdef __DJGPP__
#pragma pack()
#endif
/*
* INT 0x13 operation codes
*/
#define DISK_READ 0x02
#define DISK_WRITE 0x03
#define DISK_GET_GEOMETRY 0x08
#define DISK_READY 0x10
/*
* Errors to put in _dio_error
*/
#define ERR_BADDEV 0x00000001L
#define ERR_HARDWARE 0x00000002L
#define ERR_NOTSUPP 0x00000003L
#define ERR_NOTEXT2FS 0x00000004L
#define ERR_EMPTYPART 0x00000005L
#define ERR_LINUXSWAP 0x00000006L
/*
* Functions in diskio.c
*/
/*
* Variable contains last module's error
*/
extern unsigned long _dio_error;
/*
* This one contains last hardware error (if _dio_error == ERR_HARDWARE)
*/
extern unsigned long _dio_hw_error;
/*
* Macros to check for disk hardware errors
*/
#define HW_OK() ((unsigned char)_dio_hw_error == 0x00)
#define HW_BAD_CMD() ((unsigned char)_dio_hw_error == 0x01)
#define HW_NO_ADDR_MARK() ((unsigned char)_dio_hw_error == 0x02)
#define HW_WRITE_PROT() ((unsigned char)_dio_hw_error == 0x03)
#define HW_NO_SECTOR() ((unsigned char)_dio_hw_error == 0x04)
#define HW_RESET_FAIL() ((unsigned char)_dio_hw_error == 0x05)
#define HW_DISK_CHANGED() ((unsigned char)_dio_hw_error == 0x06)
#define HW_DRIVE_FAIL() ((unsigned char)_dio_hw_error == 0x07)
#define HW_DMA_OVERRUN() ((unsigned char)_dio_hw_error == 0x08)
#define HW_DMA_BOUNDARY() ((unsigned char)_dio_hw_error == 0x09)
#define HW_BAD_SECTOR() ((unsigned char)_dio_hw_error == 0x0A)
#define HW_BAD_TRACK() ((unsigned char)_dio_hw_error == 0x0B)
#define HW_UNSUPP_TRACK() ((unsigned char)_dio_hw_error == 0x0C)
#define HW_BAD_CRC_ECC() ((unsigned char)_dio_hw_error == 0x10)
#define HW_CRC_ECC_CORR() ((unsigned char)_dio_hw_error == 0x11)
#define HW_CONTR_FAIL() ((unsigned char)_dio_hw_error == 0x20)
#define HW_SEEK_FAIL() ((unsigned char)_dio_hw_error == 0x40)
#define HW_ATTACH_FAIL() ((unsigned char)_dio_hw_error == 0x80)
#define HW_DRIVE_NREADY() ((unsigned char)_dio_hw_error == 0xAA)
#define HW_UNDEF_ERROR() ((unsigned char)_dio_hw_error == 0xBB)
#define HW_WRITE_FAULT() ((unsigned char)_dio_hw_error == 0xCC)
#define HW_STATUS_ERROR() ((unsigned char)_dio_hw_error == 0xE0)
#define HW_SENSE_FAIL() ((unsigned char)_dio_hw_error == 0xFF)
/*
* Open the specified partition.
* String 'dev' must have a format:
*
* /dev/{sd|hd|fd}[X]
*
* where,
*
* only one of the option in curly braces can be used and X is an optional
* partition number for the given device. If X is not specified, function
* scans the drive's partition table in search for the first Linux ext2fs
* partition (signature 0x83). Along the way it dives into every extended
* partition encountered.
* Scan ends if either (a) there are no more used partition entries, or
* (b) there is no Xth partition.
*
* Routine returns 0 on success and !=0 otherwise.
*/
int open_partition(char *dev);
#endif /* __diskio_h */

96
e2fsprogs/ext2fs/dupfs.c Normal file
View File

@ -0,0 +1,96 @@
/*
* dupfs.c --- duplicate a ext2 filesystem handle
*
* Copyright (C) 1997, 1998, 2001, 2003, 2005 by Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <time.h>
#include <string.h>
#include "ext2_fs.h"
#include "ext2fsP.h"
errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest)
{
ext2_filsys fs;
errcode_t retval;
EXT2_CHECK_MAGIC(src, EXT2_ET_MAGIC_EXT2FS_FILSYS);
retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
if (retval)
return retval;
*fs = *src;
fs->device_name = 0;
fs->super = 0;
fs->orig_super = 0;
fs->group_desc = 0;
fs->inode_map = 0;
fs->block_map = 0;
fs->badblocks = 0;
fs->dblist = 0;
io_channel_bumpcount(fs->io);
if (fs->icache)
fs->icache->refcount++;
retval = ext2fs_get_mem(strlen(src->device_name)+1, &fs->device_name);
if (retval)
goto errout;
strcpy(fs->device_name, src->device_name);
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
if (retval)
goto errout;
memcpy(fs->super, src->super, SUPERBLOCK_SIZE);
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
if (retval)
goto errout;
memcpy(fs->orig_super, src->orig_super, SUPERBLOCK_SIZE);
retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
&fs->group_desc);
if (retval)
goto errout;
memcpy(fs->group_desc, src->group_desc,
(size_t) fs->desc_blocks * fs->blocksize);
if (src->inode_map) {
retval = ext2fs_copy_bitmap(src->inode_map, &fs->inode_map);
if (retval)
goto errout;
}
if (src->block_map) {
retval = ext2fs_copy_bitmap(src->block_map, &fs->block_map);
if (retval)
goto errout;
}
if (src->badblocks) {
retval = ext2fs_badblocks_copy(src->badblocks, &fs->badblocks);
if (retval)
goto errout;
}
if (src->dblist) {
retval = ext2fs_copy_dblist(src->dblist, &fs->dblist);
if (retval)
goto errout;
}
*dest = fs;
return 0;
errout:
ext2fs_free(fs);
return retval;
}

View File

@ -0,0 +1,51 @@
/*
* e2image.h --- header file describing the ext2 image format
*
* Copyright (C) 2000 Theodore Ts'o.
*
* Note: this uses the POSIX IO interfaces, unlike most of the other
* functions in this library. So sue me.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
struct ext2_image_hdr {
__u32 magic_number; /* This must be EXT2_ET_MAGIC_E2IMAGE */
char magic_descriptor[16]; /* "Ext2 Image 1.0", w/ null padding */
char fs_hostname[64];/* Hostname of machine of image */
char fs_netaddr[32]; /* Network address */
__u32 fs_netaddr_type;/* 0 = IPV4, 1 = IPV6, etc. */
__u32 fs_device; /* Device number of image */
char fs_device_name[64]; /* Device name */
char fs_uuid[16]; /* UUID of filesystem */
__u32 fs_blocksize; /* Block size of the filesystem */
__u32 fs_reserved[8];
__u32 image_device; /* Device number of image file */
__u32 image_inode; /* Inode number of image file */
__u32 image_time; /* Time of image creation */
__u32 image_reserved[8];
__u32 offset_super; /* Byte offset of the sb and descriptors */
__u32 offset_inode; /* Byte offset of the inode table */
__u32 offset_inodemap; /* Byte offset of the inode bitmaps */
__u32 offset_blockmap; /* Byte offset of the inode bitmaps */
__u32 offset_reserved[8];
};

View File

@ -0,0 +1,126 @@
/*
* expand.c --- expand an ext2fs directory
*
* Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
struct expand_dir_struct {
int done;
int newblocks;
errcode_t err;
};
static int expand_dir_proc(ext2_filsys fs,
blk_t *blocknr,
e2_blkcnt_t blockcnt,
blk_t ref_block EXT2FS_ATTR((unused)),
int ref_offset EXT2FS_ATTR((unused)),
void *priv_data)
{
struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
blk_t new_blk;
static blk_t last_blk = 0;
char *block;
errcode_t retval;
if (*blocknr) {
last_blk = *blocknr;
return 0;
}
retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
if (retval) {
es->err = retval;
return BLOCK_ABORT;
}
if (blockcnt > 0) {
retval = ext2fs_new_dir_block(fs, 0, 0, &block);
if (retval) {
es->err = retval;
return BLOCK_ABORT;
}
es->done = 1;
retval = ext2fs_write_dir_block(fs, new_blk, block);
} else {
retval = ext2fs_get_mem(fs->blocksize, &block);
if (retval) {
es->err = retval;
return BLOCK_ABORT;
}
memset(block, 0, fs->blocksize);
retval = io_channel_write_blk(fs->io, new_blk, 1, block);
}
if (retval) {
es->err = retval;
return BLOCK_ABORT;
}
ext2fs_free_mem(&block);
*blocknr = new_blk;
ext2fs_block_alloc_stats(fs, new_blk, +1);
es->newblocks++;
if (es->done)
return (BLOCK_CHANGED | BLOCK_ABORT);
else
return BLOCK_CHANGED;
}
errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
{
errcode_t retval;
struct expand_dir_struct es;
struct ext2_inode inode;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (!(fs->flags & EXT2_FLAG_RW))
return EXT2_ET_RO_FILSYS;
if (!fs->block_map)
return EXT2_ET_NO_BLOCK_BITMAP;
retval = ext2fs_check_directory(fs, dir);
if (retval)
return retval;
es.done = 0;
es.err = 0;
es.newblocks = 0;
retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
0, expand_dir_proc, &es);
if (es.err)
return es.err;
if (!es.done)
return EXT2_ET_EXPAND_DIR_ERR;
/*
* Update the size and block count fields in the inode.
*/
retval = ext2fs_read_inode(fs, dir, &inode);
if (retval)
return retval;
inode.i_size += fs->blocksize;
inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
retval = ext2fs_write_inode(fs, dir, &inode);
if (retval)
return retval;
return 0;
}

117
e2fsprogs/ext2fs/ext2_err.h Normal file
View File

@ -0,0 +1,117 @@
/*
* ext2_err.h:
* This file is automatically generated; please do not edit it.
*/
#include <et/com_err.h>
#define EXT2_ET_BASE (2133571328L)
#define EXT2_ET_MAGIC_EXT2FS_FILSYS (2133571329L)
#define EXT2_ET_MAGIC_BADBLOCKS_LIST (2133571330L)
#define EXT2_ET_MAGIC_BADBLOCKS_ITERATE (2133571331L)
#define EXT2_ET_MAGIC_INODE_SCAN (2133571332L)
#define EXT2_ET_MAGIC_IO_CHANNEL (2133571333L)
#define EXT2_ET_MAGIC_UNIX_IO_CHANNEL (2133571334L)
#define EXT2_ET_MAGIC_IO_MANAGER (2133571335L)
#define EXT2_ET_MAGIC_BLOCK_BITMAP (2133571336L)
#define EXT2_ET_MAGIC_INODE_BITMAP (2133571337L)
#define EXT2_ET_MAGIC_GENERIC_BITMAP (2133571338L)
#define EXT2_ET_MAGIC_TEST_IO_CHANNEL (2133571339L)
#define EXT2_ET_MAGIC_DBLIST (2133571340L)
#define EXT2_ET_MAGIC_ICOUNT (2133571341L)
#define EXT2_ET_MAGIC_PQ_IO_CHANNEL (2133571342L)
#define EXT2_ET_MAGIC_EXT2_FILE (2133571343L)
#define EXT2_ET_MAGIC_E2IMAGE (2133571344L)
#define EXT2_ET_MAGIC_INODE_IO_CHANNEL (2133571345L)
#define EXT2_ET_MAGIC_RESERVED_9 (2133571346L)
#define EXT2_ET_BAD_MAGIC (2133571347L)
#define EXT2_ET_REV_TOO_HIGH (2133571348L)
#define EXT2_ET_RO_FILSYS (2133571349L)
#define EXT2_ET_GDESC_READ (2133571350L)
#define EXT2_ET_GDESC_WRITE (2133571351L)
#define EXT2_ET_GDESC_BAD_BLOCK_MAP (2133571352L)
#define EXT2_ET_GDESC_BAD_INODE_MAP (2133571353L)
#define EXT2_ET_GDESC_BAD_INODE_TABLE (2133571354L)
#define EXT2_ET_INODE_BITMAP_WRITE (2133571355L)
#define EXT2_ET_INODE_BITMAP_READ (2133571356L)
#define EXT2_ET_BLOCK_BITMAP_WRITE (2133571357L)
#define EXT2_ET_BLOCK_BITMAP_READ (2133571358L)
#define EXT2_ET_INODE_TABLE_WRITE (2133571359L)
#define EXT2_ET_INODE_TABLE_READ (2133571360L)
#define EXT2_ET_NEXT_INODE_READ (2133571361L)
#define EXT2_ET_UNEXPECTED_BLOCK_SIZE (2133571362L)
#define EXT2_ET_DIR_CORRUPTED (2133571363L)
#define EXT2_ET_SHORT_READ (2133571364L)
#define EXT2_ET_SHORT_WRITE (2133571365L)
#define EXT2_ET_DIR_NO_SPACE (2133571366L)
#define EXT2_ET_NO_INODE_BITMAP (2133571367L)
#define EXT2_ET_NO_BLOCK_BITMAP (2133571368L)
#define EXT2_ET_BAD_INODE_NUM (2133571369L)
#define EXT2_ET_BAD_BLOCK_NUM (2133571370L)
#define EXT2_ET_EXPAND_DIR_ERR (2133571371L)
#define EXT2_ET_TOOSMALL (2133571372L)
#define EXT2_ET_BAD_BLOCK_MARK (2133571373L)
#define EXT2_ET_BAD_BLOCK_UNMARK (2133571374L)
#define EXT2_ET_BAD_BLOCK_TEST (2133571375L)
#define EXT2_ET_BAD_INODE_MARK (2133571376L)
#define EXT2_ET_BAD_INODE_UNMARK (2133571377L)
#define EXT2_ET_BAD_INODE_TEST (2133571378L)
#define EXT2_ET_FUDGE_BLOCK_BITMAP_END (2133571379L)
#define EXT2_ET_FUDGE_INODE_BITMAP_END (2133571380L)
#define EXT2_ET_BAD_IND_BLOCK (2133571381L)
#define EXT2_ET_BAD_DIND_BLOCK (2133571382L)
#define EXT2_ET_BAD_TIND_BLOCK (2133571383L)
#define EXT2_ET_NEQ_BLOCK_BITMAP (2133571384L)
#define EXT2_ET_NEQ_INODE_BITMAP (2133571385L)
#define EXT2_ET_BAD_DEVICE_NAME (2133571386L)
#define EXT2_ET_MISSING_INODE_TABLE (2133571387L)
#define EXT2_ET_CORRUPT_SUPERBLOCK (2133571388L)
#define EXT2_ET_BAD_GENERIC_MARK (2133571389L)
#define EXT2_ET_BAD_GENERIC_UNMARK (2133571390L)
#define EXT2_ET_BAD_GENERIC_TEST (2133571391L)
#define EXT2_ET_SYMLINK_LOOP (2133571392L)
#define EXT2_ET_CALLBACK_NOTHANDLED (2133571393L)
#define EXT2_ET_BAD_BLOCK_IN_INODE_TABLE (2133571394L)
#define EXT2_ET_UNSUPP_FEATURE (2133571395L)
#define EXT2_ET_RO_UNSUPP_FEATURE (2133571396L)
#define EXT2_ET_LLSEEK_FAILED (2133571397L)
#define EXT2_ET_NO_MEMORY (2133571398L)
#define EXT2_ET_INVALID_ARGUMENT (2133571399L)
#define EXT2_ET_BLOCK_ALLOC_FAIL (2133571400L)
#define EXT2_ET_INODE_ALLOC_FAIL (2133571401L)
#define EXT2_ET_NO_DIRECTORY (2133571402L)
#define EXT2_ET_TOO_MANY_REFS (2133571403L)
#define EXT2_ET_FILE_NOT_FOUND (2133571404L)
#define EXT2_ET_FILE_RO (2133571405L)
#define EXT2_ET_DB_NOT_FOUND (2133571406L)
#define EXT2_ET_DIR_EXISTS (2133571407L)
#define EXT2_ET_UNIMPLEMENTED (2133571408L)
#define EXT2_ET_CANCEL_REQUESTED (2133571409L)
#define EXT2_ET_FILE_TOO_BIG (2133571410L)
#define EXT2_ET_JOURNAL_NOT_BLOCK (2133571411L)
#define EXT2_ET_NO_JOURNAL_SB (2133571412L)
#define EXT2_ET_JOURNAL_TOO_SMALL (2133571413L)
#define EXT2_ET_JOURNAL_UNSUPP_VERSION (2133571414L)
#define EXT2_ET_LOAD_EXT_JOURNAL (2133571415L)
#define EXT2_ET_NO_JOURNAL (2133571416L)
#define EXT2_ET_DIRHASH_UNSUPP (2133571417L)
#define EXT2_ET_BAD_EA_BLOCK_NUM (2133571418L)
#define EXT2_ET_TOO_MANY_INODES (2133571419L)
#define EXT2_ET_NOT_IMAGE_FILE (2133571420L)
#define EXT2_ET_RES_GDT_BLOCKS (2133571421L)
#define EXT2_ET_RESIZE_INODE_CORRUPT (2133571422L)
#define EXT2_ET_SET_BMAP_NO_IND (2133571423L)
#if 0
extern const struct error_table et_ext2_error_table;
extern void initialize_ext2_error_table(void);
/* For compatibility with Heimdal */
extern void initialize_ext2_error_table_r(struct et_list **list);
#define ERROR_TABLE_BASE_ext2 (2133571328L)
/* for compatibility with older versions... */
#define init_ext2_err_tbl initialize_ext2_error_table
#define ext2_err_base ERROR_TABLE_BASE_ext2
#endif

View File

@ -0,0 +1,69 @@
/*
File: linux/ext2_ext_attr.h
On-disk format of extended attributes for the ext2 filesystem.
(C) 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org>
*/
/* Magic value in attribute blocks */
#define EXT2_EXT_ATTR_MAGIC_v1 0xEA010000
#define EXT2_EXT_ATTR_MAGIC 0xEA020000
/* Maximum number of references to one attribute block */
#define EXT2_EXT_ATTR_REFCOUNT_MAX 1024
struct ext2_ext_attr_header {
__u32 h_magic; /* magic number for identification */
__u32 h_refcount; /* reference count */
__u32 h_blocks; /* number of disk blocks used */
__u32 h_hash; /* hash value of all attributes */
__u32 h_reserved[4]; /* zero right now */
};
struct ext2_ext_attr_entry {
__u8 e_name_len; /* length of name */
__u8 e_name_index; /* attribute name index */
__u16 e_value_offs; /* offset in disk block of value */
__u32 e_value_block; /* disk block attribute is stored on (n/i) */
__u32 e_value_size; /* size of attribute value */
__u32 e_hash; /* hash value of name and value */
#if 0
char e_name[0]; /* attribute name */
#endif
};
#define EXT2_EXT_ATTR_PAD_BITS 2
#define EXT2_EXT_ATTR_PAD (1<<EXT2_EXT_ATTR_PAD_BITS)
#define EXT2_EXT_ATTR_ROUND (EXT2_EXT_ATTR_PAD-1)
#define EXT2_EXT_ATTR_LEN(name_len) \
(((name_len) + EXT2_EXT_ATTR_ROUND + \
sizeof(struct ext2_ext_attr_entry)) & ~EXT2_EXT_ATTR_ROUND)
#define EXT2_EXT_ATTR_NEXT(entry) \
( (struct ext2_ext_attr_entry *)( \
(char *)(entry) + EXT2_EXT_ATTR_LEN((entry)->e_name_len)) )
#define EXT2_EXT_ATTR_SIZE(size) \
(((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
#define EXT2_EXT_IS_LAST_ENTRY(entry) (*((__u32 *)(entry)) == 0UL)
#define EXT2_EXT_ATTR_NAME(entry) \
(((char *) (entry)) + sizeof(struct ext2_ext_attr_entry))
#define EXT2_XATTR_LEN(name_len) \
(((name_len) + EXT2_EXT_ATTR_ROUND + \
sizeof(struct ext2_xattr_entry)) & ~EXT2_EXT_ATTR_ROUND)
#define EXT2_XATTR_SIZE(size) \
(((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
#ifdef __KERNEL__
# ifdef CONFIG_EXT2_FS_EXT_ATTR
extern int ext2_get_ext_attr(struct inode *, const char *, char *, size_t, int);
extern int ext2_set_ext_attr(struct inode *, const char *, char *, size_t, int);
extern void ext2_ext_attr_free_inode(struct inode *inode);
extern void ext2_ext_attr_put_super(struct super_block *sb);
extern int ext2_ext_attr_init(void);
extern void ext2_ext_attr_done(void);
# else
# define ext2_get_ext_attr NULL
# define ext2_set_ext_attr NULL
# endif
#endif /* __KERNEL__ */

644
e2fsprogs/ext2fs/ext2_fs.h Normal file
View File

@ -0,0 +1,644 @@
/*
* linux/include/linux/ext2_fs.h
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*
* from
*
* linux/include/linux/minix_fs.h
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#ifndef _LINUX_EXT2_FS_H
#define _LINUX_EXT2_FS_H
#include <ext2fs/ext2_types.h> /* Changed from linux/types.h */
/*
* The second extended filesystem constants/structures
*/
/*
* Define EXT2FS_DEBUG to produce debug messages
*/
#undef EXT2FS_DEBUG
/*
* Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
*/
#define EXT2_PREALLOCATE
#define EXT2_DEFAULT_PREALLOC_BLOCKS 8
/*
* The second extended file system version
*/
#define EXT2FS_DATE "95/08/09"
#define EXT2FS_VERSION "0.5b"
/*
* Special inode numbers
*/
#define EXT2_BAD_INO 1 /* Bad blocks inode */
#define EXT2_ROOT_INO 2 /* Root inode */
#define EXT2_ACL_IDX_INO 3 /* ACL inode */
#define EXT2_ACL_DATA_INO 4 /* ACL inode */
#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */
#define EXT2_JOURNAL_INO 8 /* Journal inode */
/* First non-reserved inode for old ext2 filesystems */
#define EXT2_GOOD_OLD_FIRST_INO 11
/*
* The second extended file system magic number
*/
#define EXT2_SUPER_MAGIC 0xEF53
#ifdef __KERNEL__
#define EXT2_SB(sb) (&((sb)->u.ext2_sb))
#else
/* Assume that user mode programs are passing in an ext2fs superblock, not
* a kernel struct super_block. This will allow us to call the feature-test
* macros from user land. */
#define EXT2_SB(sb) (sb)
#endif
/*
* Maximal count of links to a file
*/
#define EXT2_LINK_MAX 32000
/*
* Macro-instructions used to manage several block sizes
*/
#define EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */
#define EXT2_MAX_BLOCK_LOG_SIZE 16 /* 65536 */
#define EXT2_MIN_BLOCK_SIZE (1 << EXT2_MIN_BLOCK_LOG_SIZE)
#define EXT2_MAX_BLOCK_SIZE (1 << EXT2_MAX_BLOCK_LOG_SIZE)
#ifdef __KERNEL__
#define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize)
#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
#define EXT2_ADDR_PER_BLOCK_BITS(s) (EXT2_SB(s)->addr_per_block_bits)
#define EXT2_INODE_SIZE(s) (EXT2_SB(s)->s_inode_size)
#define EXT2_FIRST_INO(s) (EXT2_SB(s)->s_first_ino)
#else
#define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size)
#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino)
#endif
#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof(__u32))
/*
* Macro-instructions used to manage fragments
*/
#define EXT2_MIN_FRAG_SIZE EXT2_MIN_BLOCK_SIZE
#define EXT2_MAX_FRAG_SIZE EXT2_MAX_BLOCK_SIZE
#define EXT2_MIN_FRAG_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE
#ifdef __KERNEL__
# define EXT2_FRAG_SIZE(s) (EXT2_SB(s)->s_frag_size)
# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_SB(s)->s_frags_per_block)
#else
# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
#endif
/*
* ACL structures
*/
struct ext2_acl_header /* Header of Access Control Lists */
{
__u32 aclh_size;
__u32 aclh_file_count;
__u32 aclh_acle_count;
__u32 aclh_first_acle;
};
struct ext2_acl_entry /* Access Control List Entry */
{
__u32 acle_size;
__u16 acle_perms; /* Access permissions */
__u16 acle_type; /* Type of entry */
__u16 acle_tag; /* User or group identity */
__u16 acle_pad1;
__u32 acle_next; /* Pointer on next entry for the */
/* same inode or on next free entry */
};
/*
* Structure of a blocks group descriptor
*/
struct ext2_group_desc
{
__u32 bg_block_bitmap; /* Blocks bitmap block */
__u32 bg_inode_bitmap; /* Inodes bitmap block */
__u32 bg_inode_table; /* Inodes table block */
__u16 bg_free_blocks_count; /* Free blocks count */
__u16 bg_free_inodes_count; /* Free inodes count */
__u16 bg_used_dirs_count; /* Directories count */
__u16 bg_pad;
__u32 bg_reserved[3];
};
/*
* Data structures used by the directory indexing feature
*
* Note: all of the multibyte integer fields are little endian.
*/
/*
* Note: dx_root_info is laid out so that if it should somehow get
* overlaid by a dirent the two low bits of the hash version will be
* zero. Therefore, the hash version mod 4 should never be 0.
* Sincerely, the paranoia department.
*/
struct ext2_dx_root_info {
__u32 reserved_zero;
__u8 hash_version; /* 0 now, 1 at release */
__u8 info_length; /* 8 */
__u8 indirect_levels;
__u8 unused_flags;
};
#define EXT2_HASH_LEGACY 0
#define EXT2_HASH_HALF_MD4 1
#define EXT2_HASH_TEA 2
#define EXT2_HASH_FLAG_INCOMPAT 0x1
struct ext2_dx_entry {
__u32 hash;
__u32 block;
};
struct ext2_dx_countlimit {
__u16 limit;
__u16 count;
};
/*
* Macro-instructions used to manage group descriptors
*/
#define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group)
#define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group)
#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
/* limits imposed by 16-bit value gd_free_{blocks,inode}_count */
#define EXT2_MAX_BLOCKS_PER_GROUP(s) ((1 << 16) - 8)
#define EXT2_MAX_INODES_PER_GROUP(s) ((1 << 16) - EXT2_INODES_PER_BLOCK(s))
#ifdef __KERNEL__
#define EXT2_DESC_PER_BLOCK(s) (EXT2_SB(s)->s_desc_per_block)
#define EXT2_DESC_PER_BLOCK_BITS(s) (EXT2_SB(s)->s_desc_per_block_bits)
#else
#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
#endif
/*
* Constants relative to the data blocks
*/
#define EXT2_NDIR_BLOCKS 12
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
/*
* Inode flags
*/
#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
#define EXT2_UNRM_FL 0x00000002 /* Undelete */
#define EXT2_COMPR_FL 0x00000004 /* Compress file */
#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
/* Reserved for compression usage... */
#define EXT2_DIRTY_FL 0x00000100
#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
#define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */
#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
/* End compression flags --- maybe not all used */
#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */
#define EXT2_IMAGIC_FL 0x00002000
#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */
#define EXT2_DIRSYNC_FL 0x00010000 /* Synchronous directory modifications */
#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
#define EXT3_EXTENTS_FL 0x00080000 /* Inode uses extents */
#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
#define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
#define EXT2_FL_USER_MODIFIABLE 0x000080FF /* User modifiable flags */
/*
* ioctl commands
*/
#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
/*
* Structure of an inode on the disk
*/
struct ext2_inode {
__u16 i_mode; /* File mode */
__u16 i_uid; /* Low 16 bits of Owner Uid */
__u32 i_size; /* Size in bytes */
__u32 i_atime; /* Access time */
__u32 i_ctime; /* Creation time */
__u32 i_mtime; /* Modification time */
__u32 i_dtime; /* Deletion Time */
__u16 i_gid; /* Low 16 bits of Group Id */
__u16 i_links_count; /* Links count */
__u32 i_blocks; /* Blocks count */
__u32 i_flags; /* File flags */
union {
struct {
__u32 l_i_reserved1;
} linux1;
struct {
__u32 h_i_translator;
} hurd1;
struct {
__u32 m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
__u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
__u32 i_generation; /* File version (for NFS) */
__u32 i_file_acl; /* File ACL */
__u32 i_dir_acl; /* Directory ACL */
__u32 i_faddr; /* Fragment address */
union {
struct {
__u8 l_i_frag; /* Fragment number */
__u8 l_i_fsize; /* Fragment size */
__u16 i_pad1;
__u16 l_i_uid_high; /* these 2 fields */
__u16 l_i_gid_high; /* were reserved2[0] */
__u32 l_i_reserved2;
} linux2;
struct {
__u8 h_i_frag; /* Fragment number */
__u8 h_i_fsize; /* Fragment size */
__u16 h_i_mode_high;
__u16 h_i_uid_high;
__u16 h_i_gid_high;
__u32 h_i_author;
} hurd2;
struct {
__u8 m_i_frag; /* Fragment number */
__u8 m_i_fsize; /* Fragment size */
__u16 m_pad1;
__u32 m_i_reserved2[2];
} masix2;
} osd2; /* OS dependent 2 */
};
/*
* Permanent part of an large inode on the disk
*/
struct ext2_inode_large {
__u16 i_mode; /* File mode */
__u16 i_uid; /* Low 16 bits of Owner Uid */
__u32 i_size; /* Size in bytes */
__u32 i_atime; /* Access time */
__u32 i_ctime; /* Creation time */
__u32 i_mtime; /* Modification time */
__u32 i_dtime; /* Deletion Time */
__u16 i_gid; /* Low 16 bits of Group Id */
__u16 i_links_count; /* Links count */
__u32 i_blocks; /* Blocks count */
__u32 i_flags; /* File flags */
union {
struct {
__u32 l_i_reserved1;
} linux1;
struct {
__u32 h_i_translator;
} hurd1;
struct {
__u32 m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
__u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
__u32 i_generation; /* File version (for NFS) */
__u32 i_file_acl; /* File ACL */
__u32 i_dir_acl; /* Directory ACL */
__u32 i_faddr; /* Fragment address */
union {
struct {
__u8 l_i_frag; /* Fragment number */
__u8 l_i_fsize; /* Fragment size */
__u16 i_pad1;
__u16 l_i_uid_high; /* these 2 fields */
__u16 l_i_gid_high; /* were reserved2[0] */
__u32 l_i_reserved2;
} linux2;
struct {
__u8 h_i_frag; /* Fragment number */
__u8 h_i_fsize; /* Fragment size */
__u16 h_i_mode_high;
__u16 h_i_uid_high;
__u16 h_i_gid_high;
__u32 h_i_author;
} hurd2;
struct {
__u8 m_i_frag; /* Fragment number */
__u8 m_i_fsize; /* Fragment size */
__u16 m_pad1;
__u32 m_i_reserved2[2];
} masix2;
} osd2; /* OS dependent 2 */
__u16 i_extra_isize;
__u16 i_pad1;
};
#define i_size_high i_dir_acl
#if defined(__KERNEL__) || defined(__linux__)
#define i_reserved1 osd1.linux1.l_i_reserved1
#define i_frag osd2.linux2.l_i_frag
#define i_fsize osd2.linux2.l_i_fsize
#define i_uid_low i_uid
#define i_gid_low i_gid
#define i_uid_high osd2.linux2.l_i_uid_high
#define i_gid_high osd2.linux2.l_i_gid_high
#define i_reserved2 osd2.linux2.l_i_reserved2
#else
#if defined(__GNU__)
#define i_translator osd1.hurd1.h_i_translator
#define i_frag osd2.hurd2.h_i_frag;
#define i_fsize osd2.hurd2.h_i_fsize;
#define i_uid_high osd2.hurd2.h_i_uid_high
#define i_gid_high osd2.hurd2.h_i_gid_high
#define i_author osd2.hurd2.h_i_author
#else
#if defined(__masix__)
#define i_reserved1 osd1.masix1.m_i_reserved1
#define i_frag osd2.masix2.m_i_frag
#define i_fsize osd2.masix2.m_i_fsize
#define i_reserved2 osd2.masix2.m_i_reserved2
#endif /* __masix__ */
#endif /* __GNU__ */
#endif /* defined(__KERNEL__) || defined(__linux__) */
/*
* File system states
*/
#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
#define EXT2_ERROR_FS 0x0002 /* Errors detected */
/*
* Mount flags
*/
#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \
EXT2_MOUNT_##opt)
/*
* Maximal mount counts between two filesystem checks
*/
#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
/*
* Behaviour when detecting errors
*/
#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
#define EXT2_ERRORS_PANIC 3 /* Panic */
#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
/*
* Structure of the super block
*/
struct ext2_super_block {
__u32 s_inodes_count; /* Inodes count */
__u32 s_blocks_count; /* Blocks count */
__u32 s_r_blocks_count; /* Reserved blocks count */
__u32 s_free_blocks_count; /* Free blocks count */
__u32 s_free_inodes_count; /* Free inodes count */
__u32 s_first_data_block; /* First Data Block */
__u32 s_log_block_size; /* Block size */
__s32 s_log_frag_size; /* Fragment size */
__u32 s_blocks_per_group; /* # Blocks per group */
__u32 s_frags_per_group; /* # Fragments per group */
__u32 s_inodes_per_group; /* # Inodes per group */
__u32 s_mtime; /* Mount time */
__u32 s_wtime; /* Write time */
__u16 s_mnt_count; /* Mount count */
__s16 s_max_mnt_count; /* Maximal mount count */
__u16 s_magic; /* Magic signature */
__u16 s_state; /* File system state */
__u16 s_errors; /* Behaviour when detecting errors */
__u16 s_minor_rev_level; /* minor revision level */
__u32 s_lastcheck; /* time of last check */
__u32 s_checkinterval; /* max. time between checks */
__u32 s_creator_os; /* OS */
__u32 s_rev_level; /* Revision level */
__u16 s_def_resuid; /* Default uid for reserved blocks */
__u16 s_def_resgid; /* Default gid for reserved blocks */
/*
* These fields are for EXT2_DYNAMIC_REV superblocks only.
*
* Note: the difference between the compatible feature set and
* the incompatible feature set is that if there is a bit set
* in the incompatible feature set that the kernel doesn't
* know about, it should refuse to mount the filesystem.
*
* e2fsck's requirements are more strict; if it doesn't know
* about a feature in either the compatible or incompatible
* feature set, it must abort and not try to meddle with
* things it doesn't understand...
*/
__u32 s_first_ino; /* First non-reserved inode */
__u16 s_inode_size; /* size of inode structure */
__u16 s_block_group_nr; /* block group # of this superblock */
__u32 s_feature_compat; /* compatible feature set */
__u32 s_feature_incompat; /* incompatible feature set */
__u32 s_feature_ro_compat; /* readonly-compatible feature set */
__u8 s_uuid[16]; /* 128-bit uuid for volume */
char s_volume_name[16]; /* volume name */
char s_last_mounted[64]; /* directory where last mounted */
__u32 s_algorithm_usage_bitmap; /* For compression */
/*
* Performance hints. Directory preallocation should only
* happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
*/
__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
__u16 s_reserved_gdt_blocks; /* Per group table for online growth */
/*
* Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
*/
__u8 s_journal_uuid[16]; /* uuid of journal superblock */
__u32 s_journal_inum; /* inode number of journal file */
__u32 s_journal_dev; /* device number of journal file */
__u32 s_last_orphan; /* start of list of inodes to delete */
__u32 s_hash_seed[4]; /* HTREE hash seed */
__u8 s_def_hash_version; /* Default hash version to use */
__u8 s_jnl_backup_type; /* Default type of journal backup */
__u16 s_reserved_word_pad;
__u32 s_default_mount_opts;
__u32 s_first_meta_bg; /* First metablock group */
__u32 s_mkfs_time; /* When the filesystem was created */
__u32 s_jnl_blocks[17]; /* Backup of the journal inode */
__u32 s_reserved[172]; /* Padding to the end of the block */
};
/*
* Codes for operating systems
*/
#define EXT2_OS_LINUX 0
#define EXT2_OS_HURD 1
#define EXT2_OS_MASIX 2
#define EXT2_OS_FREEBSD 3
#define EXT2_OS_LITES 4
/*
* Revision levels
*/
#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
#define EXT2_GOOD_OLD_INODE_SIZE 128
/*
* Journal inode backup types
*/
#define EXT3_JNL_BACKUP_BLOCKS 1
/*
* Feature set definitions
*/
#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
( EXT2_SB(sb)->s_feature_compat & (mask) )
#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
( EXT2_SB(sb)->s_feature_incompat & (mask) )
#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 not used */
#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
#define EXT2_FEATURE_COMPAT_SUPP 0
#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE)
#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
/*
* Default values for user and/or group using reserved blocks
*/
#define EXT2_DEF_RESUID 0
#define EXT2_DEF_RESGID 0
/*
* Default mount options
*/
#define EXT2_DEFM_DEBUG 0x0001
#define EXT2_DEFM_BSDGROUPS 0x0002
#define EXT2_DEFM_XATTR_USER 0x0004
#define EXT2_DEFM_ACL 0x0008
#define EXT2_DEFM_UID16 0x0010
#define EXT3_DEFM_JMODE 0x0060
#define EXT3_DEFM_JMODE_DATA 0x0020
#define EXT3_DEFM_JMODE_ORDERED 0x0040
#define EXT3_DEFM_JMODE_WBACK 0x0060
/*
* Structure of a directory entry
*/
#define EXT2_NAME_LEN 255
struct ext2_dir_entry {
__u32 inode; /* Inode number */
__u16 rec_len; /* Directory entry length */
__u16 name_len; /* Name length */
char name[EXT2_NAME_LEN]; /* File name */
};
/*
* The new version of the directory entry. Since EXT2 structures are
* stored in intel byte order, and the name_len field could never be
* bigger than 255 chars, it's safe to reclaim the extra byte for the
* file_type field.
*/
struct ext2_dir_entry_2 {
__u32 inode; /* Inode number */
__u16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[EXT2_NAME_LEN]; /* File name */
};
/*
* Ext2 directory file types. Only the low 3 bits are used. The
* other bits are reserved for now.
*/
#define EXT2_FT_UNKNOWN 0
#define EXT2_FT_REG_FILE 1
#define EXT2_FT_DIR 2
#define EXT2_FT_CHRDEV 3
#define EXT2_FT_BLKDEV 4
#define EXT2_FT_FIFO 5
#define EXT2_FT_SOCK 6
#define EXT2_FT_SYMLINK 7
#define EXT2_FT_MAX 8
/*
* EXT2_DIR_PAD defines the directory entries boundaries
*
* NOTE: It must be a multiple of 4
*/
#define EXT2_DIR_PAD 4
#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
~EXT2_DIR_ROUND)
#endif /* _LINUX_EXT2_FS_H */

108
e2fsprogs/ext2fs/ext2_io.h Normal file
View File

@ -0,0 +1,108 @@
/*
* io.h --- the I/O manager abstraction
*
* Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#ifndef _EXT2FS_EXT2_IO_H
#define _EXT2FS_EXT2_IO_H
/*
* ext2_loff_t is defined here since unix_io.c needs it.
*/
#if defined(__GNUC__) || defined(HAS_LONG_LONG)
typedef long long ext2_loff_t;
#else
typedef long ext2_loff_t;
#endif
/* llseek.c */
ext2_loff_t ext2fs_llseek (int, ext2_loff_t, int);
typedef struct struct_io_manager *io_manager;
typedef struct struct_io_channel *io_channel;
#define CHANNEL_FLAGS_WRITETHROUGH 0x01
struct struct_io_channel {
errcode_t magic;
io_manager manager;
char *name;
int block_size;
errcode_t (*read_error)(io_channel channel,
unsigned long block,
int count,
void *data,
size_t size,
int actual_bytes_read,
errcode_t error);
errcode_t (*write_error)(io_channel channel,
unsigned long block,
int count,
const void *data,
size_t size,
int actual_bytes_written,
errcode_t error);
int refcount;
int flags;
int reserved[14];
void *private_data;
void *app_data;
};
struct struct_io_manager {
errcode_t magic;
const char *name;
errcode_t (*open)(const char *name, int flags, io_channel *channel);
errcode_t (*close)(io_channel channel);
errcode_t (*set_blksize)(io_channel channel, int blksize);
errcode_t (*read_blk)(io_channel channel, unsigned long block,
int count, void *data);
errcode_t (*write_blk)(io_channel channel, unsigned long block,
int count, const void *data);
errcode_t (*flush)(io_channel channel);
errcode_t (*write_byte)(io_channel channel, unsigned long offset,
int count, const void *data);
errcode_t (*set_option)(io_channel channel, const char *option,
const char *arg);
int reserved[14];
};
#define IO_FLAG_RW 1
/*
* Convenience functions....
*/
#define io_channel_close(c) ((c)->manager->close((c)))
#define io_channel_set_blksize(c,s) ((c)->manager->set_blksize((c),s))
#define io_channel_read_blk(c,b,n,d) ((c)->manager->read_blk((c),b,n,d))
#define io_channel_write_blk(c,b,n,d) ((c)->manager->write_blk((c),b,n,d))
#define io_channel_flush(c) ((c)->manager->flush((c)))
#define io_channel_bumpcount(c) ((c)->refcount++)
/* io_manager.c */
extern errcode_t io_channel_set_options(io_channel channel,
const char *options);
extern errcode_t io_channel_write_byte(io_channel channel,
unsigned long offset,
int count, const void *data);
/* unix_io.c */
extern io_manager unix_io_manager;
/* test_io.c */
extern io_manager test_io_manager, test_io_backing_manager;
extern void (*test_io_cb_read_blk)
(unsigned long block, int count, errcode_t err);
extern void (*test_io_cb_write_blk)
(unsigned long block, int count, errcode_t err);
extern void (*test_io_cb_set_blksize)
(int blksize, errcode_t err);
#endif /* _EXT2FS_EXT2_IO_H */

View File

@ -0,0 +1 @@
#include <linux/types.h>

1137
e2fsprogs/ext2fs/ext2fs.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,88 @@
/*
* ext2fsP.h --- private header file for ext2 library
*
* Copyright (C) 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include "ext2fs.h"
/*
* Badblocks list
*/
struct ext2_struct_u32_list {
int magic;
int num;
int size;
__u32 *list;
int badblocks_flags;
};
struct ext2_struct_u32_iterate {
int magic;
ext2_u32_list bb;
int ptr;
};
/*
* Directory block iterator definition
*/
struct ext2_struct_dblist {
int magic;
ext2_filsys fs;
ext2_ino_t size;
ext2_ino_t count;
int sorted;
struct ext2_db_entry * list;
};
/*
* For directory iterators
*/
struct dir_context {
ext2_ino_t dir;
int flags;
char *buf;
int (*func)(ext2_ino_t dir,
int entry,
struct ext2_dir_entry *dirent,
int offset,
int blocksize,
char *buf,
void *priv_data);
void *priv_data;
errcode_t errcode;
};
/*
* Inode cache structure
*/
struct ext2_inode_cache {
void * buffer;
blk_t buffer_blk;
int cache_last;
int cache_size;
int refcount;
struct ext2_inode_cache_ent *cache;
};
struct ext2_inode_cache_ent {
ext2_ino_t ino;
struct ext2_inode inode;
};
/* Function prototypes */
extern int ext2fs_process_dir_block(ext2_filsys fs,
blk_t *blocknr,
e2_blkcnt_t blockcnt,
blk_t ref_block,
int ref_offset,
void *priv_data);

105
e2fsprogs/ext2fs/ext_attr.c Normal file
View File

@ -0,0 +1,105 @@
/*
* ext_attr.c --- extended attribute blocks
*
* Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
*
* Copyright (C) 2002 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <time.h>
#include "ext2_fs.h"
#include "ext2_ext_attr.h"
#include "ext2fs.h"
errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
{
errcode_t retval;
retval = io_channel_read_blk(fs->io, block, 1, buf);
if (retval)
return retval;
#ifdef EXT2FS_ENABLE_SWAPFS
if ((fs->flags & (EXT2_FLAG_SWAP_BYTES|
EXT2_FLAG_SWAP_BYTES_READ)) != 0)
ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
#endif
return 0;
}
errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
{
errcode_t retval;
char *write_buf;
char *buf = NULL;
#ifdef EXT2FS_ENABLE_SWAPFS
if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
return retval;
write_buf = buf;
ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
} else
#endif
write_buf = (char *) inbuf;
retval = io_channel_write_blk(fs->io, block, 1, write_buf);
if (buf)
ext2fs_free_mem(&buf);
if (!retval)
ext2fs_mark_changed(fs);
return retval;
}
/*
* This function adjusts the reference count of the EA block.
*/
errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
char *block_buf, int adjust,
__u32 *newcount)
{
errcode_t retval;
struct ext2_ext_attr_header *header;
char *buf = 0;
if ((blk >= fs->super->s_blocks_count) ||
(blk < fs->super->s_first_data_block))
return EXT2_ET_BAD_EA_BLOCK_NUM;
if (!block_buf) {
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
return retval;
block_buf = buf;
}
retval = ext2fs_read_ext_attr(fs, blk, block_buf);
if (retval)
goto errout;
header = (struct ext2_ext_attr_header *) block_buf;
header->h_refcount += adjust;
if (newcount)
*newcount = header->h_refcount;
retval = ext2fs_write_ext_attr(fs, blk, block_buf);
if (retval)
goto errout;
errout:
if (buf)
ext2fs_free_mem(&buf);
return retval;
}

378
e2fsprogs/ext2fs/fileio.c Normal file
View File

@ -0,0 +1,378 @@
/*
* fileio.c --- Simple file I/O routines
*
* Copyright (C) 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
struct ext2_file {
errcode_t magic;
ext2_filsys fs;
ext2_ino_t ino;
struct ext2_inode inode;
int flags;
__u64 pos;
blk_t blockno;
blk_t physblock;
char *buf;
};
#define BMAP_BUFFER (file->buf + fs->blocksize)
errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
int flags, ext2_file_t *ret)
{
ext2_file_t file;
errcode_t retval;
/*
* Don't let caller create or open a file for writing if the
* filesystem is read-only.
*/
if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) &&
!(fs->flags & EXT2_FLAG_RW))
return EXT2_ET_RO_FILSYS;
retval = ext2fs_get_mem(sizeof(struct ext2_file), &file);
if (retval)
return retval;
memset(file, 0, sizeof(struct ext2_file));
file->magic = EXT2_ET_MAGIC_EXT2_FILE;
file->fs = fs;
file->ino = ino;
file->flags = flags & EXT2_FILE_MASK;
if (inode) {
memcpy(&file->inode, inode, sizeof(struct ext2_inode));
} else {
retval = ext2fs_read_inode(fs, ino, &file->inode);
if (retval)
goto fail;
}
retval = ext2fs_get_mem(fs->blocksize * 3, &file->buf);
if (retval)
goto fail;
*ret = file;
return 0;
fail:
if (file->buf)
ext2fs_free_mem(&file->buf);
ext2fs_free_mem(&file);
return retval;
}
errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
int flags, ext2_file_t *ret)
{
return ext2fs_file_open2(fs, ino, NULL, flags, ret);
}
/*
* This function returns the filesystem handle of a file from the structure
*/
ext2_filsys ext2fs_file_get_fs(ext2_file_t file)
{
if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
return 0;
return file->fs;
}
/*
* This function flushes the dirty block buffer out to disk if
* necessary.
*/
errcode_t ext2fs_file_flush(ext2_file_t file)
{
errcode_t retval;
ext2_filsys fs;
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
fs = file->fs;
if (!(file->flags & EXT2_FILE_BUF_VALID) ||
!(file->flags & EXT2_FILE_BUF_DIRTY))
return 0;
/*
* OK, the physical block hasn't been allocated yet.
* Allocate it.
*/
if (!file->physblock) {
retval = ext2fs_bmap(fs, file->ino, &file->inode,
BMAP_BUFFER, file->ino ? BMAP_ALLOC : 0,
file->blockno, &file->physblock);
if (retval)
return retval;
}
retval = io_channel_write_blk(fs->io, file->physblock,
1, file->buf);
if (retval)
return retval;
file->flags &= ~EXT2_FILE_BUF_DIRTY;
return retval;
}
/*
* This function synchronizes the file's block buffer and the current
* file position, possibly invalidating block buffer if necessary
*/
static errcode_t sync_buffer_position(ext2_file_t file)
{
blk_t b;
errcode_t retval;
b = file->pos / file->fs->blocksize;
if (b != file->blockno) {
retval = ext2fs_file_flush(file);
if (retval)
return retval;
file->flags &= ~EXT2_FILE_BUF_VALID;
}
file->blockno = b;
return 0;
}
/*
* This function loads the file's block buffer with valid data from
* the disk as necessary.
*
* If dontfill is true, then skip initializing the buffer since we're
* going to be replacing its entire contents anyway. If set, then the
* function basically only sets file->physblock and EXT2_FILE_BUF_VALID
*/
#define DONTFILL 1
static errcode_t load_buffer(ext2_file_t file, int dontfill)
{
ext2_filsys fs = file->fs;
errcode_t retval;
if (!(file->flags & EXT2_FILE_BUF_VALID)) {
retval = ext2fs_bmap(fs, file->ino, &file->inode,
BMAP_BUFFER, 0, file->blockno,
&file->physblock);
if (retval)
return retval;
if (!dontfill) {
if (file->physblock) {
retval = io_channel_read_blk(fs->io,
file->physblock,
1, file->buf);
if (retval)
return retval;
} else
memset(file->buf, 0, fs->blocksize);
}
file->flags |= EXT2_FILE_BUF_VALID;
}
return 0;
}
errcode_t ext2fs_file_close(ext2_file_t file)
{
errcode_t retval;
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
retval = ext2fs_file_flush(file);
if (file->buf)
ext2fs_free_mem(&file->buf);
ext2fs_free_mem(&file);
return retval;
}
errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
unsigned int wanted, unsigned int *got)
{
ext2_filsys fs;
errcode_t retval = 0;
unsigned int start, c, count = 0;
__u64 left;
char *ptr = (char *) buf;
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
fs = file->fs;
while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) {
retval = sync_buffer_position(file);
if (retval)
goto fail;
retval = load_buffer(file, 0);
if (retval)
goto fail;
start = file->pos % fs->blocksize;
c = fs->blocksize - start;
if (c > wanted)
c = wanted;
left = EXT2_I_SIZE(&file->inode) - file->pos ;
if (c > left)
c = left;
memcpy(ptr, file->buf+start, c);
file->pos += c;
ptr += c;
count += c;
wanted -= c;
}
fail:
if (got)
*got = count;
return retval;
}
errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
unsigned int nbytes, unsigned int *written)
{
ext2_filsys fs;
errcode_t retval = 0;
unsigned int start, c, count = 0;
const char *ptr = (const char *) buf;
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
fs = file->fs;
if (!(file->flags & EXT2_FILE_WRITE))
return EXT2_ET_FILE_RO;
while (nbytes > 0) {
retval = sync_buffer_position(file);
if (retval)
goto fail;
start = file->pos % fs->blocksize;
c = fs->blocksize - start;
if (c > nbytes)
c = nbytes;
/*
* We only need to do a read-modify-update cycle if
* we're doing a partial write.
*/
retval = load_buffer(file, (c == fs->blocksize));
if (retval)
goto fail;
file->flags |= EXT2_FILE_BUF_DIRTY;
memcpy(file->buf+start, ptr, c);
file->pos += c;
ptr += c;
count += c;
nbytes -= c;
}
fail:
if (written)
*written = count;
return retval;
}
errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
int whence, __u64 *ret_pos)
{
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
if (whence == EXT2_SEEK_SET)
file->pos = offset;
else if (whence == EXT2_SEEK_CUR)
file->pos += offset;
else if (whence == EXT2_SEEK_END)
file->pos = EXT2_I_SIZE(&file->inode) + offset;
else
return EXT2_ET_INVALID_ARGUMENT;
if (ret_pos)
*ret_pos = file->pos;
return 0;
}
errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
int whence, ext2_off_t *ret_pos)
{
__u64 loffset, ret_loffset;
errcode_t retval;
loffset = offset;
retval = ext2fs_file_llseek(file, loffset, whence, &ret_loffset);
if (ret_pos)
*ret_pos = (ext2_off_t) ret_loffset;
return retval;
}
/*
* This function returns the size of the file, according to the inode
*/
errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size)
{
if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
return EXT2_ET_MAGIC_EXT2_FILE;
*ret_size = EXT2_I_SIZE(&file->inode);
return 0;
}
/*
* This function returns the size of the file, according to the inode
*/
ext2_off_t ext2fs_file_get_size(ext2_file_t file)
{
__u64 size;
if (ext2fs_file_get_lsize(file, &size))
return 0;
if ((size >> 32) != 0)
return 0;
return size;
}
/*
* This function sets the size of the file, truncating it if necessary
*
* XXX still need to call truncate
*/
errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
{
errcode_t retval;
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
file->inode.i_size = size;
file->inode.i_size_high = 0;
if (file->ino) {
retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
if (retval)
return retval;
}
/*
* XXX truncate inode if necessary
*/
return 0;
}

208
e2fsprogs/ext2fs/finddev.c Normal file
View File

@ -0,0 +1,208 @@
/*
* finddev.c -- this routine attempts to find a particular device in
* /dev
*
* Copyright (C) 2000 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#include <dirent.h>
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_SYS_MKDEV_H
#include <sys/mkdev.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
struct dir_list {
char *name;
struct dir_list *next;
};
/*
* This function adds an entry to the directory list
*/
static void add_to_dirlist(const char *name, struct dir_list **list)
{
struct dir_list *dp;
dp = malloc(sizeof(struct dir_list));
if (!dp)
return;
dp->name = malloc(strlen(name)+1);
if (!dp->name) {
free(dp);
return;
}
strcpy(dp->name, name);
dp->next = *list;
*list = dp;
}
/*
* This function frees a directory list
*/
static void free_dirlist(struct dir_list **list)
{
struct dir_list *dp, *next;
for (dp = *list; dp; dp = next) {
next = dp->next;
free(dp->name);
free(dp);
}
*list = 0;
}
static int scan_dir(char *dir_name, dev_t device, struct dir_list **list,
char **ret_path)
{
DIR *dir;
struct dirent *dp;
char path[1024], *cp;
int dirlen;
struct stat st;
dirlen = strlen(dir_name);
if ((dir = opendir(dir_name)) == NULL)
return errno;
dp = readdir(dir);
while (dp) {
if (dirlen + strlen(dp->d_name) + 2 >= sizeof(path))
goto skip_to_next;
if (dp->d_name[0] == '.' &&
((dp->d_name[1] == 0) ||
((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
goto skip_to_next;
sprintf(path, "%s/%s", dir_name, dp->d_name);
if (stat(path, &st) < 0)
goto skip_to_next;
if (S_ISDIR(st.st_mode))
add_to_dirlist(path, list);
if (S_ISBLK(st.st_mode) && st.st_rdev == device) {
cp = malloc(strlen(path)+1);
if (!cp) {
closedir(dir);
return ENOMEM;
}
strcpy(cp, path);
*ret_path = cp;
goto success;
}
skip_to_next:
dp = readdir(dir);
}
success:
closedir(dir);
return 0;
}
/*
* This function finds the pathname to a block device with a given
* device number. It returns a pointer to allocated memory to the
* pathname on success, and NULL on failure.
*/
char *ext2fs_find_block_device(dev_t device)
{
struct dir_list *list = 0, *new_list = 0;
struct dir_list *current;
char *ret_path = 0;
/*
* Add the starting directories to search...
*/
add_to_dirlist("/devices", &list);
add_to_dirlist("/devfs", &list);
add_to_dirlist("/dev", &list);
while (list) {
current = list;
list = list->next;
#ifdef DEBUG
printf("Scanning directory %s\n", current->name);
#endif
scan_dir(current->name, device, &new_list, &ret_path);
free(current->name);
free(current);
if (ret_path)
break;
/*
* If we're done checking at this level, descend to
* the next level of subdirectories. (breadth-first)
*/
if (list == 0) {
list = new_list;
new_list = 0;
}
}
free_dirlist(&list);
free_dirlist(&new_list);
return ret_path;
}
#ifdef DEBUG
int main(int argc, char** argv)
{
char *devname, *tmp;
int major, minor;
dev_t device;
const char *errmsg = "Couldn't parse %s: %s\n";
if ((argc != 2) && (argc != 3)) {
fprintf(stderr, "Usage: %s device_number\n", argv[0]);
fprintf(stderr, "\t: %s major minor\n", argv[0]);
exit(1);
}
if (argc == 2) {
device = strtoul(argv[1], &tmp, 0);
if (*tmp) {
fprintf(stderr, errmsg, "device number", argv[1]);
exit(1);
}
} else {
major = strtoul(argv[1], &tmp, 0);
if (*tmp) {
fprintf(stderr, errmsg, "major number", argv[1]);
exit(1);
}
minor = strtoul(argv[2], &tmp, 0);
if (*tmp) {
fprintf(stderr, errmsg, "minor number", argv[2]);
exit(1);
}
device = makedev(major, minor);
printf("Looking for device 0x%04x (%d:%d)\n", device,
major, minor);
}
devname = ext2fs_find_block_device(device);
if (devname) {
printf("Found device! %s\n", devname);
free(devname);
} else {
printf("Couldn't find device.\n");
}
return 0;
}
#endif

82
e2fsprogs/ext2fs/flushb.c Normal file
View File

@ -0,0 +1,82 @@
/*
* flushb.c --- Hides system-dependent information for both syncing a
* device to disk and to flush any buffers from disk cache.
*
* Copyright (C) 2000 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#if HAVE_SYS_MOUNT_H
#include <sys/param.h>
#include <sys/mount.h> /* This may define BLKFLSBUF */
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
/*
* For Linux, define BLKFLSBUF and FDFLUSH if necessary, since
* not all portable header file does so for us. This really should be
* fixed in the glibc header files. (Recent glibcs appear to define
* BLKFLSBUF in sys/mount.h, but FDFLUSH still doesn't seem to be
* defined anywhere portable.) Until then....
*/
#ifdef __linux__
#ifndef BLKFLSBUF
#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
#endif
#ifndef FDFLUSH
#define FDFLUSH _IO(2,0x4b) /* flush floppy disk */
#endif
#endif
/*
* This function will sync a device/file, and optionally attempt to
* flush the buffer cache. The latter is basically only useful for
* system benchmarks and for torturing systems in burn-in tests. :)
*/
errcode_t ext2fs_sync_device(int fd, int flushb)
{
/*
* We always sync the device in case we're running on old
* kernels for which we can lose data if we don't. (There
* still is a race condition for those kernels, but this
* reduces it greatly.)
*/
if (fsync (fd) == -1)
return errno;
if (flushb) {
#ifdef BLKFLSBUF
if (ioctl (fd, BLKFLSBUF, 0) == 0)
return 0;
#else
#ifdef __GNUC__
#warning BLKFLSBUF not defined
#endif /* __GNUC__ */
#endif
#ifdef FDFLUSH
ioctl (fd, FDFLUSH, 0); /* In case this is a floppy */
#else
#ifdef __GNUC__
#warning FDFLUSH not defined
#endif /* __GNUC__ */
#endif
}
return 0;
}

147
e2fsprogs/ext2fs/freefs.c Normal file
View File

@ -0,0 +1,147 @@
/*
* freefs.c --- free an ext2 filesystem
*
* Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ext2_fs.h"
#include "ext2fsP.h"
static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
void ext2fs_free(ext2_filsys fs)
{
if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS))
return;
if (fs->image_io != fs->io) {
if (fs->image_io)
io_channel_close(fs->image_io);
}
if (fs->io) {
io_channel_close(fs->io);
}
if (fs->device_name)
ext2fs_free_mem(&fs->device_name);
if (fs->super)
ext2fs_free_mem(&fs->super);
if (fs->orig_super)
ext2fs_free_mem(&fs->orig_super);
if (fs->group_desc)
ext2fs_free_mem(&fs->group_desc);
if (fs->block_map)
ext2fs_free_block_bitmap(fs->block_map);
if (fs->inode_map)
ext2fs_free_inode_bitmap(fs->inode_map);
if (fs->badblocks)
ext2fs_badblocks_list_free(fs->badblocks);
fs->badblocks = 0;
if (fs->dblist)
ext2fs_free_dblist(fs->dblist);
if (fs->icache)
ext2fs_free_inode_cache(fs->icache);
fs->magic = 0;
ext2fs_free_mem(&fs);
}
void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap)
{
if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_GENERIC_BITMAP))
return;
bitmap->magic = 0;
if (bitmap->description) {
ext2fs_free_mem(&bitmap->description);
bitmap->description = 0;
}
if (bitmap->bitmap) {
ext2fs_free_mem(&bitmap->bitmap);
bitmap->bitmap = 0;
}
ext2fs_free_mem(&bitmap);
}
void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap)
{
if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
return;
bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
ext2fs_free_generic_bitmap(bitmap);
}
void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap)
{
if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
return;
bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
ext2fs_free_generic_bitmap(bitmap);
}
/*
* Free the inode cache structure
*/
static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
{
if (--icache->refcount)
return;
if (icache->buffer)
ext2fs_free_mem(&icache->buffer);
if (icache->cache)
ext2fs_free_mem(&icache->cache);
icache->buffer_blk = 0;
ext2fs_free_mem(&icache);
}
/*
* This procedure frees a badblocks list.
*/
void ext2fs_u32_list_free(ext2_u32_list bb)
{
if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
return;
if (bb->list)
ext2fs_free_mem(&bb->list);
bb->list = 0;
ext2fs_free_mem(&bb);
}
void ext2fs_badblocks_list_free(ext2_badblocks_list bb)
{
ext2fs_u32_list_free((ext2_u32_list) bb);
}
/*
* Free a directory block list
*/
void ext2fs_free_dblist(ext2_dblist dblist)
{
if (!dblist || (dblist->magic != EXT2_ET_MAGIC_DBLIST))
return;
if (dblist->list)
ext2fs_free_mem(&dblist->list);
dblist->list = 0;
if (dblist->fs && dblist->fs->dblist == dblist)
dblist->fs->dblist = 0;
dblist->magic = 0;
ext2fs_free_mem(&dblist);
}

View File

@ -0,0 +1,48 @@
/*
* gen_bitmap.c --- Generic bitmap routines that used to be inlined.
*
* Copyright (C) 2001 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
__u32 bitno)
{
if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno);
return 0;
}
return ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap);
}
int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
blk_t bitno)
{
if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno);
return 0;
}
return ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap);
}

View File

@ -0,0 +1,157 @@
/*
* get_pathname.c --- do directry/inode -> name translation
*
* Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*
* ext2fs_get_pathname(fs, dir, ino, name)
*
* This function translates takes two inode numbers into a
* string, placing the result in <name>. <dir> is the containing
* directory inode, and <ino> is the inode number itself. If
* <ino> is zero, then ext2fs_get_pathname will return pathname
* of the the directory <dir>.
*
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
struct get_pathname_struct {
ext2_ino_t search_ino;
ext2_ino_t parent;
char *name;
errcode_t errcode;
};
#ifdef __TURBOC__
#pragma argsused
#endif
static int get_pathname_proc(struct ext2_dir_entry *dirent,
int offset EXT2FS_ATTR((unused)),
int blocksize EXT2FS_ATTR((unused)),
char *buf EXT2FS_ATTR((unused)),
void *priv_data)
{
struct get_pathname_struct *gp;
errcode_t retval;
gp = (struct get_pathname_struct *) priv_data;
if (((dirent->name_len & 0xFF) == 2) &&
!strncmp(dirent->name, "..", 2))
gp->parent = dirent->inode;
if (dirent->inode == gp->search_ino) {
retval = ext2fs_get_mem((dirent->name_len & 0xFF) + 1,
&gp->name);
if (retval) {
gp->errcode = retval;
return DIRENT_ABORT;
}
strncpy(gp->name, dirent->name, (dirent->name_len & 0xFF));
gp->name[dirent->name_len & 0xFF] = '\0';
return DIRENT_ABORT;
}
return 0;
}
static errcode_t ext2fs_get_pathname_int(ext2_filsys fs, ext2_ino_t dir,
ext2_ino_t ino, int maxdepth,
char *buf, char **name)
{
struct get_pathname_struct gp;
char *parent_name, *ret;
errcode_t retval;
if (dir == ino) {
retval = ext2fs_get_mem(2, name);
if (retval)
return retval;
strcpy(*name, (dir == EXT2_ROOT_INO) ? "/" : ".");
return 0;
}
if (!dir || (maxdepth < 0)) {
retval = ext2fs_get_mem(4, name);
if (retval)
return retval;
strcpy(*name, "...");
return 0;
}
gp.search_ino = ino;
gp.parent = 0;
gp.name = 0;
gp.errcode = 0;
retval = ext2fs_dir_iterate(fs, dir, 0, buf, get_pathname_proc, &gp);
if (retval)
goto cleanup;
if (gp.errcode) {
retval = gp.errcode;
goto cleanup;
}
retval = ext2fs_get_pathname_int(fs, gp.parent, dir, maxdepth-1,
buf, &parent_name);
if (retval)
goto cleanup;
if (!ino) {
*name = parent_name;
return 0;
}
if (gp.name)
retval = ext2fs_get_mem(strlen(parent_name)+strlen(gp.name)+2,
&ret);
else
retval = ext2fs_get_mem(strlen(parent_name)+5, &ret);
if (retval)
goto cleanup;
ret[0] = 0;
if (parent_name[1])
strcat(ret, parent_name);
strcat(ret, "/");
if (gp.name)
strcat(ret, gp.name);
else
strcat(ret, "???");
*name = ret;
ext2fs_free_mem(&parent_name);
retval = 0;
cleanup:
if (gp.name)
ext2fs_free_mem(&gp.name);
return retval;
}
errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino,
char **name)
{
char *buf;
errcode_t retval;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
return retval;
if (dir == ino)
ino = 0;
retval = ext2fs_get_pathname_int(fs, dir, ino, 32, buf, name);
ext2fs_free_mem(&buf);
return retval;
}

View File

@ -0,0 +1,57 @@
/*
* getsectsize.c --- get the sector size of a device.
*
* Copyright (C) 1995, 1995 Theodore Ts'o.
* Copyright (C) 2003 VMware, Inc.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <fcntl.h>
#ifdef HAVE_LINUX_FD_H
#include <sys/ioctl.h>
#include <linux/fd.h>
#endif
#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
#define BLKSSZGET _IO(0x12,104)/* get block device sector size */
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
/*
* Returns the number of blocks in a partition
*/
errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize)
{
int fd;
#ifdef CONFIG_LFS
fd = open64(file, O_RDONLY);
#else
fd = open(file, O_RDONLY);
#endif
if (fd < 0)
return errno;
#ifdef BLKSSZGET
if (ioctl(fd, BLKSSZGET, sectsize) >= 0) {
close(fd);
return 0;
}
#endif
*sectsize = 0;
close(fd);
return 0;
}

290
e2fsprogs/ext2fs/getsize.c Normal file
View File

@ -0,0 +1,290 @@
/*
* getsize.c --- get the size of a partition.
*
* Copyright (C) 1995, 1995 Theodore Ts'o.
* Copyright (C) 2003 VMware, Inc.
*
* Windows version of ext2fs_get_device_size by Chris Li, VMware.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <fcntl.h>
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_LINUX_FD_H
#include <linux/fd.h>
#endif
#ifdef HAVE_SYS_DISKLABEL_H
#include <sys/disklabel.h>
#endif
#ifdef HAVE_SYS_DISK_H
#ifdef HAVE_SYS_QUEUE_H
#include <sys/queue.h> /* for LIST_HEAD */
#endif
#include <sys/disk.h>
#endif
#ifdef __linux__
#include <sys/utsname.h>
#endif
#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
#define BLKGETSIZE _IO(0x12,96) /* return device size */
#endif
#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
#endif
#ifdef APPLE_DARWIN
#define BLKGETSIZE DKIOCGETBLOCKCOUNT32
#endif /* APPLE_DARWIN */
#include "ext2_fs.h"
#include "ext2fs.h"
#if defined(__CYGWIN__) || defined (WIN32)
#include "windows.h"
#include "winioctl.h"
#if (_WIN32_WINNT >= 0x0500)
#define HAVE_GET_FILE_SIZE_EX 1
#endif
errcode_t ext2fs_get_device_size(const char *file, int blocksize,
blk_t *retblocks)
{
HANDLE dev;
PARTITION_INFORMATION pi;
DISK_GEOMETRY gi;
DWORD retbytes;
#ifdef HAVE_GET_FILE_SIZE_EX
LARGE_INTEGER filesize;
#else
DWORD filesize;
#endif /* HAVE_GET_FILE_SIZE_EX */
dev = CreateFile(file, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (dev == INVALID_HANDLE_VALUE)
return EBADF;
if (DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO,
&pi, sizeof(PARTITION_INFORMATION),
&pi, sizeof(PARTITION_INFORMATION),
&retbytes, NULL)) {
*retblocks = pi.PartitionLength.QuadPart / blocksize;
} else if (DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY,
&gi, sizeof(DISK_GEOMETRY),
&gi, sizeof(DISK_GEOMETRY),
&retbytes, NULL)) {
*retblocks = gi.BytesPerSector *
gi.SectorsPerTrack *
gi.TracksPerCylinder *
gi.Cylinders.QuadPart / blocksize;
#ifdef HAVE_GET_FILE_SIZE_EX
} else if (GetFileSizeEx(dev, &filesize)) {
*retblocks = filesize.QuadPart / blocksize;
}
#else
} else {
filesize = GetFileSize(dev, NULL);
if (INVALID_FILE_SIZE != filesize) {
*retblocks = filesize / blocksize;
}
}
#endif /* HAVE_GET_FILE_SIZE_EX */
CloseHandle(dev);
return 0;
}
#else
static int valid_offset (int fd, ext2_loff_t offset)
{
char ch;
if (ext2fs_llseek (fd, offset, 0) < 0)
return 0;
if (read (fd, &ch, 1) < 1)
return 0;
return 1;
}
/*
* Returns the number of blocks in a partition
*/
errcode_t ext2fs_get_device_size(const char *file, int blocksize,
blk_t *retblocks)
{
int fd;
int valid_blkgetsize64 = 1;
#ifdef __linux__
struct utsname ut;
#endif
unsigned long long size64;
unsigned long size;
ext2_loff_t high, low;
#ifdef FDGETPRM
struct floppy_struct this_floppy;
#endif
#ifdef HAVE_SYS_DISKLABEL_H
int part;
struct disklabel lab;
struct partition *pp;
char ch;
#endif /* HAVE_SYS_DISKLABEL_H */
#ifdef CONFIG_LFS
fd = open64(file, O_RDONLY);
#else
fd = open(file, O_RDONLY);
#endif
if (fd < 0)
return errno;
#ifdef DKIOCGETBLOCKCOUNT /* For Apple Darwin */
if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) {
if ((sizeof(*retblocks) < sizeof(unsigned long long))
&& ((size64 / (blocksize / 512)) > 0xFFFFFFFF))
return EFBIG;
close(fd);
*retblocks = size64 / (blocksize / 512);
return 0;
}
#endif
#ifdef BLKGETSIZE64
#ifdef __linux__
if ((uname(&ut) == 0) &&
((ut.release[0] == '2') && (ut.release[1] == '.') &&
(ut.release[2] < '6') && (ut.release[3] == '.')))
valid_blkgetsize64 = 0;
#endif
if (valid_blkgetsize64 &&
ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
if ((sizeof(*retblocks) < sizeof(unsigned long long))
&& ((size64 / blocksize) > 0xFFFFFFFF))
return EFBIG;
close(fd);
*retblocks = size64 / blocksize;
return 0;
}
#endif
#ifdef BLKGETSIZE
if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
close(fd);
*retblocks = size / (blocksize / 512);
return 0;
}
#endif
#ifdef FDGETPRM
if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
close(fd);
*retblocks = this_floppy.size / (blocksize / 512);
return 0;
}
#endif
#ifdef HAVE_SYS_DISKLABEL_H
#if defined(DIOCGMEDIASIZE)
{
off_t ms;
u_int bs;
if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) {
*retblocks = ms / blocksize;
return 0;
}
}
#elif defined(DIOCGDINFO)
/* old disklabel interface */
part = strlen(file) - 1;
if (part >= 0) {
ch = file[part];
if (isdigit(ch))
part = 0;
else if (ch >= 'a' && ch <= 'h')
part = ch - 'a';
else
part = -1;
}
if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
pp = &lab.d_partitions[part];
if (pp->p_size) {
close(fd);
*retblocks = pp->p_size / (blocksize / 512);
return 0;
}
}
#endif /* defined(DIOCG*) */
#endif /* HAVE_SYS_DISKLABEL_H */
/*
* OK, we couldn't figure it out by using a specialized ioctl,
* which is generally the best way. So do binary search to
* find the size of the partition.
*/
low = 0;
for (high = 1024; valid_offset (fd, high); high *= 2)
low = high;
while (low < high - 1)
{
const ext2_loff_t mid = (low + high) / 2;
if (valid_offset (fd, mid))
low = mid;
else
high = mid;
}
valid_offset (fd, 0);
close(fd);
size64 = low + 1;
if ((sizeof(*retblocks) < sizeof(unsigned long long))
&& ((size64 / blocksize) > 0xFFFFFFFF))
return EFBIG;
*retblocks = size64 / blocksize;
return 0;
}
#endif /* WIN32 */
#ifdef DEBUG
int main(int argc, char **argv)
{
blk_t blocks;
int retval;
if (argc < 2) {
fprintf(stderr, "Usage: %s device\n", argv[0]);
exit(1);
}
retval = ext2fs_get_device_size(argv[1], 1024, &blocks);
if (retval) {
com_err(argv[0], retval,
"while calling ext2fs_get_device_size");
exit(1);
}
printf("Device %s has %d 1k blocks.\n", argv[1], blocks);
exit(0);
}
#endif

483
e2fsprogs/ext2fs/icount.c Normal file
View File

@ -0,0 +1,483 @@
/*
* icount.c --- an efficient inode count abstraction
*
* Copyright (C) 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <stdio.h>
#include "ext2_fs.h"
#include "ext2fs.h"
/*
* The data storage strategy used by icount relies on the observation
* that most inode counts are either zero (for non-allocated inodes),
* one (for most files), and only a few that are two or more
* (directories and files that are linked to more than one directory).
*
* Also, e2fsck tends to load the icount data sequentially.
*
* So, we use an inode bitmap to indicate which inodes have a count of
* one, and then use a sorted list to store the counts for inodes
* which are greater than one.
*
* We also use an optional bitmap to indicate which inodes are already
* in the sorted list, to speed up the use of this abstraction by
* e2fsck's pass 2. Pass 2 increments inode counts as it finds them,
* so this extra bitmap avoids searching the sorted list to see if a
* particular inode is on the sorted list already.
*/
struct ext2_icount_el {
ext2_ino_t ino;
__u16 count;
};
struct ext2_icount {
errcode_t magic;
ext2fs_inode_bitmap single;
ext2fs_inode_bitmap multiple;
ext2_ino_t count;
ext2_ino_t size;
ext2_ino_t num_inodes;
ext2_ino_t cursor;
struct ext2_icount_el *list;
};
void ext2fs_free_icount(ext2_icount_t icount)
{
if (!icount)
return;
icount->magic = 0;
if (icount->list)
ext2fs_free_mem(&icount->list);
if (icount->single)
ext2fs_free_inode_bitmap(icount->single);
if (icount->multiple)
ext2fs_free_inode_bitmap(icount->multiple);
ext2fs_free_mem(&icount);
}
errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size,
ext2_icount_t hint, ext2_icount_t *ret)
{
ext2_icount_t icount;
errcode_t retval;
size_t bytes;
ext2_ino_t i;
if (hint) {
EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT);
if (hint->size > size)
size = (size_t) hint->size;
}
retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount);
if (retval)
return retval;
memset(icount, 0, sizeof(struct ext2_icount));
retval = ext2fs_allocate_inode_bitmap(fs, 0,
&icount->single);
if (retval)
goto errout;
if (flags & EXT2_ICOUNT_OPT_INCREMENT) {
retval = ext2fs_allocate_inode_bitmap(fs, 0,
&icount->multiple);
if (retval)
goto errout;
} else
icount->multiple = 0;
if (size) {
icount->size = size;
} else {
/*
* Figure out how many special case inode counts we will
* have. We know we will need one for each directory;
* we also need to reserve some extra room for file links
*/
retval = ext2fs_get_num_dirs(fs, &icount->size);
if (retval)
goto errout;
icount->size += fs->super->s_inodes_count / 50;
}
bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el));
#if 0
printf("Icount allocated %d entries, %d bytes.\n",
icount->size, bytes);
#endif
retval = ext2fs_get_mem(bytes, &icount->list);
if (retval)
goto errout;
memset(icount->list, 0, bytes);
icount->magic = EXT2_ET_MAGIC_ICOUNT;
icount->count = 0;
icount->cursor = 0;
icount->num_inodes = fs->super->s_inodes_count;
/*
* Populate the sorted list with those entries which were
* found in the hint icount (since those are ones which will
* likely need to be in the sorted list this time around).
*/
if (hint) {
for (i=0; i < hint->count; i++)
icount->list[i].ino = hint->list[i].ino;
icount->count = hint->count;
}
*ret = icount;
return 0;
errout:
ext2fs_free_icount(icount);
return(retval);
}
errcode_t ext2fs_create_icount(ext2_filsys fs, int flags,
unsigned int size,
ext2_icount_t *ret)
{
return ext2fs_create_icount2(fs, flags, size, 0, ret);
}
/*
* insert_icount_el() --- Insert a new entry into the sorted list at a
* specified position.
*/
static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount,
ext2_ino_t ino, int pos)
{
struct ext2_icount_el *el;
errcode_t retval;
ext2_ino_t new_size = 0;
int num;
if (icount->count >= icount->size) {
if (icount->count) {
new_size = icount->list[(unsigned)icount->count-1].ino;
new_size = (ext2_ino_t) (icount->count *
((float) icount->num_inodes / new_size));
}
if (new_size < (icount->size + 100))
new_size = icount->size + 100;
#if 0
printf("Reallocating icount %d entries...\n", new_size);
#endif
retval = ext2fs_resize_mem((size_t) icount->size *
sizeof(struct ext2_icount_el),
(size_t) new_size *
sizeof(struct ext2_icount_el),
&icount->list);
if (retval)
return 0;
icount->size = new_size;
}
num = (int) icount->count - pos;
if (num < 0)
return 0; /* should never happen */
if (num) {
memmove(&icount->list[pos+1], &icount->list[pos],
sizeof(struct ext2_icount_el) * num);
}
icount->count++;
el = &icount->list[pos];
el->count = 0;
el->ino = ino;
return el;
}
/*
* get_icount_el() --- given an inode number, try to find icount
* information in the sorted list. If the create flag is set,
* and we can't find an entry, create one in the sorted list.
*/
static struct ext2_icount_el *get_icount_el(ext2_icount_t icount,
ext2_ino_t ino, int create)
{
float range;
int low, high, mid;
ext2_ino_t lowval, highval;
if (!icount || !icount->list)
return 0;
if (create && ((icount->count == 0) ||
(ino > icount->list[(unsigned)icount->count-1].ino))) {
return insert_icount_el(icount, ino, (unsigned) icount->count);
}
if (icount->count == 0)
return 0;
if (icount->cursor >= icount->count)
icount->cursor = 0;
if (ino == icount->list[icount->cursor].ino)
return &icount->list[icount->cursor++];
#if 0
printf("Non-cursor get_icount_el: %u\n", ino);
#endif
low = 0;
high = (int) icount->count-1;
while (low <= high) {
#if 0
mid = (low+high)/2;
#else
if (low == high)
mid = low;
else {
/* Interpolate for efficiency */
lowval = icount->list[low].ino;
highval = icount->list[high].ino;
if (ino < lowval)
range = 0;
else if (ino > highval)
range = 1;
else
range = ((float) (ino - lowval)) /
(highval - lowval);
mid = low + ((int) (range * (high-low)));
}
#endif
if (ino == icount->list[mid].ino) {
icount->cursor = mid+1;
return &icount->list[mid];
}
if (ino < icount->list[mid].ino)
high = mid-1;
else
low = mid+1;
}
/*
* If we need to create a new entry, it should be right at
* low (where high will be left at low-1).
*/
if (create)
return insert_icount_el(icount, ino, low);
return 0;
}
errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out)
{
errcode_t ret = 0;
unsigned int i;
const char *bad = "bad icount";
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
if (icount->count > icount->size) {
fprintf(out, "%s: count > size\n", bad);
return EXT2_ET_INVALID_ARGUMENT;
}
for (i=1; i < icount->count; i++) {
if (icount->list[i-1].ino >= icount->list[i].ino) {
fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n",
bad, i-1, icount->list[i-1].ino,
i, icount->list[i].ino);
ret = EXT2_ET_INVALID_ARGUMENT;
}
}
return ret;
}
errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret)
{
struct ext2_icount_el *el;
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
if (!ino || (ino > icount->num_inodes))
return EXT2_ET_INVALID_ARGUMENT;
if (ext2fs_test_inode_bitmap(icount->single, ino)) {
*ret = 1;
return 0;
}
if (icount->multiple &&
!ext2fs_test_inode_bitmap(icount->multiple, ino)) {
*ret = 0;
return 0;
}
el = get_icount_el(icount, ino, 0);
if (!el) {
*ret = 0;
return 0;
}
*ret = el->count;
return 0;
}
errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
__u16 *ret)
{
struct ext2_icount_el *el;
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
if (!ino || (ino > icount->num_inodes))
return EXT2_ET_INVALID_ARGUMENT;
if (ext2fs_test_inode_bitmap(icount->single, ino)) {
/*
* If the existing count is 1, then we know there is
* no entry in the list.
*/
el = get_icount_el(icount, ino, 1);
if (!el)
return EXT2_ET_NO_MEMORY;
ext2fs_unmark_inode_bitmap(icount->single, ino);
el->count = 2;
} else if (icount->multiple) {
/*
* The count is either zero or greater than 1; if the
* inode is set in icount->multiple, then there should
* be an entry in the list, so find it using
* get_icount_el().
*/
if (ext2fs_test_inode_bitmap(icount->multiple, ino)) {
el = get_icount_el(icount, ino, 1);
if (!el)
return EXT2_ET_NO_MEMORY;
el->count++;
} else {
/*
* The count was zero; mark the single bitmap
* and return.
*/
zero_count:
ext2fs_mark_inode_bitmap(icount->single, ino);
if (ret)
*ret = 1;
return 0;
}
} else {
/*
* The count is either zero or greater than 1; try to
* find an entry in the list to determine which.
*/
el = get_icount_el(icount, ino, 0);
if (!el) {
/* No entry means the count was zero */
goto zero_count;
}
el = get_icount_el(icount, ino, 1);
if (!el)
return EXT2_ET_NO_MEMORY;
el->count++;
}
if (icount->multiple)
ext2fs_mark_inode_bitmap(icount->multiple, ino);
if (ret)
*ret = el->count;
return 0;
}
errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
__u16 *ret)
{
struct ext2_icount_el *el;
if (!ino || (ino > icount->num_inodes))
return EXT2_ET_INVALID_ARGUMENT;
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
if (ext2fs_test_inode_bitmap(icount->single, ino)) {
ext2fs_unmark_inode_bitmap(icount->single, ino);
if (icount->multiple)
ext2fs_unmark_inode_bitmap(icount->multiple, ino);
else {
el = get_icount_el(icount, ino, 0);
if (el)
el->count = 0;
}
if (ret)
*ret = 0;
return 0;
}
if (icount->multiple &&
!ext2fs_test_inode_bitmap(icount->multiple, ino))
return EXT2_ET_INVALID_ARGUMENT;
el = get_icount_el(icount, ino, 0);
if (!el || el->count == 0)
return EXT2_ET_INVALID_ARGUMENT;
el->count--;
if (el->count == 1)
ext2fs_mark_inode_bitmap(icount->single, ino);
if ((el->count == 0) && icount->multiple)
ext2fs_unmark_inode_bitmap(icount->multiple, ino);
if (ret)
*ret = el->count;
return 0;
}
errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
__u16 count)
{
struct ext2_icount_el *el;
if (!ino || (ino > icount->num_inodes))
return EXT2_ET_INVALID_ARGUMENT;
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
if (count == 1) {
ext2fs_mark_inode_bitmap(icount->single, ino);
if (icount->multiple)
ext2fs_unmark_inode_bitmap(icount->multiple, ino);
return 0;
}
if (count == 0) {
ext2fs_unmark_inode_bitmap(icount->single, ino);
if (icount->multiple) {
/*
* If the icount->multiple bitmap is enabled,
* we can just clear both bitmaps and we're done
*/
ext2fs_unmark_inode_bitmap(icount->multiple, ino);
} else {
el = get_icount_el(icount, ino, 0);
if (el)
el->count = 0;
}
return 0;
}
/*
* Get the icount element
*/
el = get_icount_el(icount, ino, 1);
if (!el)
return EXT2_ET_NO_MEMORY;
el->count = count;
ext2fs_unmark_inode_bitmap(icount->single, ino);
if (icount->multiple)
ext2fs_mark_inode_bitmap(icount->multiple, ino);
return 0;
}
ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount)
{
if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT)
return 0;
return icount->size;
}

387
e2fsprogs/ext2fs/imager.c Normal file
View File

@ -0,0 +1,387 @@
/*
* image.c --- writes out the critical parts of the filesystem as a
* flat file.
*
* Copyright (C) 2000 Theodore Ts'o.
*
* Note: this uses the POSIX IO interfaces, unlike most of the other
* functions in this library. So sue me.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
#ifndef HAVE_TYPE_SSIZE_T
typedef int ssize_t;
#endif
/*
* This function returns 1 if the specified block is all zeros
*/
static int check_zero_block(char *buf, int blocksize)
{
char *cp = buf;
int left = blocksize;
while (left > 0) {
if (*cp++)
return 0;
left--;
}
return 1;
}
/*
* Write the inode table out as a single block.
*/
#define BUF_BLOCKS 32
errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
{
unsigned int group, left, c, d;
char *buf, *cp;
blk_t blk;
ssize_t actual;
errcode_t retval;
buf = malloc(fs->blocksize * BUF_BLOCKS);
if (!buf)
return ENOMEM;
for (group = 0; group < fs->group_desc_count; group++) {
blk = fs->group_desc[(unsigned)group].bg_inode_table;
if (!blk)
return EXT2_ET_MISSING_INODE_TABLE;
left = fs->inode_blocks_per_group;
while (left) {
c = BUF_BLOCKS;
if (c > left)
c = left;
retval = io_channel_read_blk(fs->io, blk, c, buf);
if (retval)
goto errout;
cp = buf;
while (c) {
if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
d = c;
goto skip_sparse;
}
/* Skip zero blocks */
if (check_zero_block(cp, fs->blocksize)) {
c--;
blk++;
left--;
cp += fs->blocksize;
lseek(fd, fs->blocksize, SEEK_CUR);
continue;
}
/* Find non-zero blocks */
for (d=1; d < c; d++) {
if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
break;
}
skip_sparse:
actual = write(fd, cp, fs->blocksize * d);
if (actual == -1) {
retval = errno;
goto errout;
}
if (actual != (ssize_t) (fs->blocksize * d)) {
retval = EXT2_ET_SHORT_WRITE;
goto errout;
}
blk += d;
left -= d;
cp += fs->blocksize * d;
c -= d;
}
}
}
retval = 0;
errout:
free(buf);
return retval;
}
/*
* Read in the inode table and stuff it into place
*/
errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd,
int flags EXT2FS_ATTR((unused)))
{
unsigned int group, c, left;
char *buf;
blk_t blk;
ssize_t actual;
errcode_t retval;
buf = malloc(fs->blocksize * BUF_BLOCKS);
if (!buf)
return ENOMEM;
for (group = 0; group < fs->group_desc_count; group++) {
blk = fs->group_desc[(unsigned)group].bg_inode_table;
if (!blk) {
retval = EXT2_ET_MISSING_INODE_TABLE;
goto errout;
}
left = fs->inode_blocks_per_group;
while (left) {
c = BUF_BLOCKS;
if (c > left)
c = left;
actual = read(fd, buf, fs->blocksize * c);
if (actual == -1) {
retval = errno;
goto errout;
}
if (actual != (ssize_t) (fs->blocksize * c)) {
retval = EXT2_ET_SHORT_READ;
goto errout;
}
retval = io_channel_write_blk(fs->io, blk, c, buf);
if (retval)
goto errout;
blk += c;
left -= c;
}
}
retval = ext2fs_flush_icache(fs);
errout:
free(buf);
return retval;
}
/*
* Write out superblock and group descriptors
*/
errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
int flags EXT2FS_ATTR((unused)))
{
char *buf, *cp;
ssize_t actual;
errcode_t retval;
buf = malloc(fs->blocksize);
if (!buf)
return ENOMEM;
/*
* Write out the superblock
*/
memset(buf, 0, fs->blocksize);
memcpy(buf, fs->super, SUPERBLOCK_SIZE);
actual = write(fd, buf, fs->blocksize);
if (actual == -1) {
retval = errno;
goto errout;
}
if (actual != (ssize_t) fs->blocksize) {
retval = EXT2_ET_SHORT_WRITE;
goto errout;
}
/*
* Now write out the block group descriptors
*/
cp = (char *) fs->group_desc;
actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
if (actual == -1) {
retval = errno;
goto errout;
}
if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
retval = EXT2_ET_SHORT_WRITE;
goto errout;
}
retval = 0;
errout:
free(buf);
return retval;
}
/*
* Read the superblock and group descriptors and overwrite them.
*/
errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
int flags EXT2FS_ATTR((unused)))
{
char *buf;
ssize_t actual, size;
errcode_t retval;
size = fs->blocksize * (fs->group_desc_count + 1);
buf = malloc(size);
if (!buf)
return ENOMEM;
/*
* Read it all in.
*/
actual = read(fd, buf, size);
if (actual == -1) {
retval = errno;
goto errout;
}
if (actual != size) {
retval = EXT2_ET_SHORT_READ;
goto errout;
}
/*
* Now copy in the superblock and group descriptors
*/
memcpy(fs->super, buf, SUPERBLOCK_SIZE);
memcpy(fs->group_desc, buf + fs->blocksize,
fs->blocksize * fs->group_desc_count);
retval = 0;
errout:
free(buf);
return retval;
}
/*
* Write the block/inode bitmaps.
*/
errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
{
char *ptr;
int c, size;
char zero_buf[1024];
ssize_t actual;
errcode_t retval;
if (flags & IMAGER_FLAG_INODEMAP) {
if (!fs->inode_map) {
retval = ext2fs_read_inode_bitmap(fs);
if (retval)
return retval;
}
ptr = fs->inode_map->bitmap;
size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
} else {
if (!fs->block_map) {
retval = ext2fs_read_block_bitmap(fs);
if (retval)
return retval;
}
ptr = fs->block_map->bitmap;
size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
}
size = size * fs->group_desc_count;
actual = write(fd, ptr, size);
if (actual == -1) {
retval = errno;
goto errout;
}
if (actual != size) {
retval = EXT2_ET_SHORT_WRITE;
goto errout;
}
size = size % fs->blocksize;
memset(zero_buf, 0, sizeof(zero_buf));
if (size) {
size = fs->blocksize - size;
while (size) {
c = size;
if (c > (int) sizeof(zero_buf))
c = sizeof(zero_buf);
actual = write(fd, zero_buf, c);
if (actual == -1) {
retval = errno;
goto errout;
}
if (actual != c) {
retval = EXT2_ET_SHORT_WRITE;
goto errout;
}
size -= c;
}
}
retval = 0;
errout:
return (retval);
}
/*
* Read the block/inode bitmaps.
*/
errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
{
char *ptr, *buf = 0;
int size;
ssize_t actual;
errcode_t retval;
if (flags & IMAGER_FLAG_INODEMAP) {
if (!fs->inode_map) {
retval = ext2fs_read_inode_bitmap(fs);
if (retval)
return retval;
}
ptr = fs->inode_map->bitmap;
size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
} else {
if (!fs->block_map) {
retval = ext2fs_read_block_bitmap(fs);
if (retval)
return retval;
}
ptr = fs->block_map->bitmap;
size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
}
size = size * fs->group_desc_count;
buf = malloc(size);
if (!buf)
return ENOMEM;
actual = read(fd, buf, size);
if (actual == -1) {
retval = errno;
goto errout;
}
if (actual != size) {
retval = EXT2_ET_SHORT_WRITE;
goto errout;
}
memcpy(ptr, buf, size);
retval = 0;
errout:
if (buf)
free(buf);
return (retval);
}

View File

@ -0,0 +1,66 @@
/*
* ind_block.c --- indirect block I/O routines
*
* Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
* 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf)
{
errcode_t retval;
blk_t *block_nr;
int i;
int limit = fs->blocksize >> 2;
if ((fs->flags & EXT2_FLAG_IMAGE_FILE) &&
(fs->io != fs->image_io))
memset(buf, 0, fs->blocksize);
else {
retval = io_channel_read_blk(fs->io, blk, 1, buf);
if (retval)
return retval;
}
#ifdef EXT2FS_ENABLE_SWAPFS
if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_READ)) {
block_nr = (blk_t *) buf;
for (i = 0; i < limit; i++, block_nr++)
*block_nr = ext2fs_swab32(*block_nr);
}
#endif
return 0;
}
errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf)
{
blk_t *block_nr;
int i;
int limit = fs->blocksize >> 2;
if (fs->flags & EXT2_FLAG_IMAGE_FILE)
return 0;
#ifdef EXT2FS_ENABLE_SWAPFS
if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_WRITE)) {
block_nr = (blk_t *) buf;
for (i = 0; i < limit; i++, block_nr++)
*block_nr = ext2fs_swab32(*block_nr);
}
#endif
return io_channel_write_blk(fs->io, blk, 1, buf);
}

View File

@ -0,0 +1,387 @@
/*
* initialize.c --- initialize a filesystem handle given superblock
* parameters. Used by mke2fs when initializing a filesystem.
*
* Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
#if defined(__linux__) && defined(EXT2_OS_LINUX)
#define CREATOR_OS EXT2_OS_LINUX
#else
#if defined(__GNU__) && defined(EXT2_OS_HURD)
#define CREATOR_OS EXT2_OS_HURD
#else
#if defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD)
#define CREATOR_OS EXT2_OS_FREEBSD
#else
#if defined(LITES) && defined(EXT2_OS_LITES)
#define CREATOR_OS EXT2_OS_LITES
#else
#define CREATOR_OS EXT2_OS_LINUX /* by default */
#endif /* defined(LITES) && defined(EXT2_OS_LITES) */
#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */
#endif /* defined(__GNU__) && defined(EXT2_OS_HURD) */
#endif /* defined(__linux__) && defined(EXT2_OS_LINUX) */
/*
* Note we override the kernel include file's idea of what the default
* check interval (never) should be. It's a good idea to check at
* least *occasionally*, specially since servers will never rarely get
* to reboot, since Linux is so robust these days. :-)
*
* 180 days (six months) seems like a good value.
*/
#ifdef EXT2_DFL_CHECKINTERVAL
#undef EXT2_DFL_CHECKINTERVAL
#endif
#define EXT2_DFL_CHECKINTERVAL (86400L * 180L)
/*
* Calculate the number of GDT blocks to reserve for online filesystem growth.
* The absolute maximum number of GDT blocks we can reserve is determined by
* the number of block pointers that can fit into a single block.
*/
static int calc_reserved_gdt_blocks(ext2_filsys fs)
{
struct ext2_super_block *sb = fs->super;
unsigned long bpg = sb->s_blocks_per_group;
unsigned int gdpb = fs->blocksize / sizeof(struct ext2_group_desc);
unsigned long max_blocks = 0xffffffff;
unsigned long rsv_groups;
int rsv_gdb;
/* We set it at 1024x the current filesystem size, or
* the upper block count limit (2^32), whichever is lower.
*/
if (sb->s_blocks_count < max_blocks / 1024)
max_blocks = sb->s_blocks_count * 1024;
rsv_groups = (max_blocks - sb->s_first_data_block + bpg - 1) / bpg;
rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - fs->desc_blocks;
if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb))
rsv_gdb = EXT2_ADDR_PER_BLOCK(sb);
#ifdef RES_GDT_DEBUG
printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %lu\n",
max_blocks, rsv_groups, rsv_gdb);
#endif
return rsv_gdb;
}
errcode_t ext2fs_initialize(const char *name, int flags,
struct ext2_super_block *param,
io_manager manager, ext2_filsys *ret_fs)
{
ext2_filsys fs;
errcode_t retval;
struct ext2_super_block *super;
int frags_per_block;
unsigned int rem;
unsigned int overhead = 0;
blk_t group_block;
unsigned int ipg;
dgrp_t i;
blk_t numblocks;
int rsv_gdt;
char *buf;
if (!param || !param->s_blocks_count)
return EXT2_ET_INVALID_ARGUMENT;
retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
if (retval)
return retval;
memset(fs, 0, sizeof(struct struct_ext2_filsys));
fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
fs->flags = flags | EXT2_FLAG_RW;
fs->umask = 022;
#ifdef WORDS_BIGENDIAN
fs->flags |= EXT2_FLAG_SWAP_BYTES;
#endif
retval = manager->open(name, IO_FLAG_RW, &fs->io);
if (retval)
goto cleanup;
fs->image_io = fs->io;
fs->io->app_data = fs;
retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
if (retval)
goto cleanup;
strcpy(fs->device_name, name);
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super);
if (retval)
goto cleanup;
fs->super = super;
memset(super, 0, SUPERBLOCK_SIZE);
#define set_field(field, default) (super->field = param->field ? \
param->field : (default))
super->s_magic = EXT2_SUPER_MAGIC;
super->s_state = EXT2_VALID_FS;
set_field(s_log_block_size, 0); /* default blocksize: 1024 bytes */
set_field(s_log_frag_size, 0); /* default fragsize: 1024 bytes */
set_field(s_first_data_block, super->s_log_block_size ? 0 : 1);
set_field(s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT);
set_field(s_errors, EXT2_ERRORS_DEFAULT);
set_field(s_feature_compat, 0);
set_field(s_feature_incompat, 0);
set_field(s_feature_ro_compat, 0);
set_field(s_first_meta_bg, 0);
if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
retval = EXT2_ET_UNSUPP_FEATURE;
goto cleanup;
}
if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
retval = EXT2_ET_RO_UNSUPP_FEATURE;
goto cleanup;
}
set_field(s_rev_level, EXT2_GOOD_OLD_REV);
if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
}
set_field(s_checkinterval, EXT2_DFL_CHECKINTERVAL);
super->s_mkfs_time = super->s_lastcheck = time(NULL);
super->s_creator_os = CREATOR_OS;
fs->blocksize = EXT2_BLOCK_SIZE(super);
fs->fragsize = EXT2_FRAG_SIZE(super);
frags_per_block = fs->blocksize / fs->fragsize;
/* default: (fs->blocksize*8) blocks/group, up to 2^16 (GDT limit) */
set_field(s_blocks_per_group, fs->blocksize * 8);
if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super))
super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super);
super->s_frags_per_group = super->s_blocks_per_group * frags_per_block;
super->s_blocks_count = param->s_blocks_count;
super->s_r_blocks_count = param->s_r_blocks_count;
if (super->s_r_blocks_count >= param->s_blocks_count) {
retval = EXT2_ET_INVALID_ARGUMENT;
goto cleanup;
}
/*
* If we're creating an external journal device, we don't need
* to bother with the rest.
*/
if (super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
fs->group_desc_count = 0;
ext2fs_mark_super_dirty(fs);
*ret_fs = fs;
return 0;
}
retry:
fs->group_desc_count = (super->s_blocks_count -
super->s_first_data_block +
EXT2_BLOCKS_PER_GROUP(super) - 1)
/ EXT2_BLOCKS_PER_GROUP(super);
if (fs->group_desc_count == 0) {
retval = EXT2_ET_TOOSMALL;
goto cleanup;
}
fs->desc_blocks = (fs->group_desc_count +
EXT2_DESC_PER_BLOCK(super) - 1)
/ EXT2_DESC_PER_BLOCK(super);
i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;
set_field(s_inodes_count, super->s_blocks_count / i);
/*
* Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
* that we have enough inodes for the filesystem(!)
*/
if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
super->s_inodes_count = EXT2_FIRST_INODE(super)+1;
/*
* There should be at least as many inodes as the user
* requested. Figure out how many inodes per group that
* should be. But make sure that we don't allocate more than
* one bitmap's worth of inodes each group.
*/
ipg = (super->s_inodes_count + fs->group_desc_count - 1) /
fs->group_desc_count;
if (ipg > fs->blocksize * 8) {
if (super->s_blocks_per_group >= 256) {
/* Try again with slightly different parameters */
super->s_blocks_per_group -= 8;
super->s_blocks_count = param->s_blocks_count;
super->s_frags_per_group = super->s_blocks_per_group *
frags_per_block;
goto retry;
} else
return EXT2_ET_TOO_MANY_INODES;
}
if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super))
ipg = EXT2_MAX_INODES_PER_GROUP(super);
super->s_inodes_per_group = ipg;
if (super->s_inodes_count > ipg * fs->group_desc_count)
super->s_inodes_count = ipg * fs->group_desc_count;
/*
* Make sure the number of inodes per group completely fills
* the inode table blocks in the descriptor. If not, add some
* additional inodes/group. Waste not, want not...
*/
fs->inode_blocks_per_group = (((super->s_inodes_per_group *
EXT2_INODE_SIZE(super)) +
EXT2_BLOCK_SIZE(super) - 1) /
EXT2_BLOCK_SIZE(super));
super->s_inodes_per_group = ((fs->inode_blocks_per_group *
EXT2_BLOCK_SIZE(super)) /
EXT2_INODE_SIZE(super));
/*
* Finally, make sure the number of inodes per group is a
* multiple of 8. This is needed to simplify the bitmap
* splicing code.
*/
super->s_inodes_per_group &= ~7;
fs->inode_blocks_per_group = (((super->s_inodes_per_group *
EXT2_INODE_SIZE(super)) +
EXT2_BLOCK_SIZE(super) - 1) /
EXT2_BLOCK_SIZE(super));
/*
* adjust inode count to reflect the adjusted inodes_per_group
*/
super->s_inodes_count = super->s_inodes_per_group *
fs->group_desc_count;
super->s_free_inodes_count = super->s_inodes_count;
/*
* check the number of reserved group descriptor table blocks
*/
if (super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE)
rsv_gdt = calc_reserved_gdt_blocks(fs);
else
rsv_gdt = 0;
set_field(s_reserved_gdt_blocks, rsv_gdt);
if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) {
retval = EXT2_ET_RES_GDT_BLOCKS;
goto cleanup;
}
/*
* Overhead is the number of bookkeeping blocks per group. It
* includes the superblock backup, the group descriptor
* backups, the inode bitmap, the block bitmap, and the inode
* table.
*/
overhead = (int) (2 + fs->inode_blocks_per_group);
if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks;
/* This can only happen if the user requested too many inodes */
if (overhead > super->s_blocks_per_group)
return EXT2_ET_TOO_MANY_INODES;
/*
* See if the last group is big enough to support the
* necessary data structures. If not, we need to get rid of
* it.
*/
rem = ((super->s_blocks_count - super->s_first_data_block) %
super->s_blocks_per_group);
if ((fs->group_desc_count == 1) && rem && (rem < overhead))
return EXT2_ET_TOOSMALL;
if (rem && (rem < overhead+50)) {
super->s_blocks_count -= rem;
goto retry;
}
/*
* At this point we know how big the filesystem will be. So
* we can do any and all allocations that depend on the block
* count.
*/
retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
if (retval)
goto cleanup;
sprintf(buf, "block bitmap for %s", fs->device_name);
retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
if (retval)
goto cleanup;
sprintf(buf, "inode bitmap for %s", fs->device_name);
retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
if (retval)
goto cleanup;
ext2fs_free_mem(&buf);
retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
&fs->group_desc);
if (retval)
goto cleanup;
memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize);
/*
* Reserve the superblock and group descriptors for each
* group, and fill in the correct group statistics for group.
* Note that although the block bitmap, inode bitmap, and
* inode table have not been allocated (and in fact won't be
* by this routine), they are accounted for nevertheless.
*/
group_block = super->s_first_data_block;
super->s_free_blocks_count = 0;
for (i = 0; i < fs->group_desc_count; i++) {
numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);
super->s_free_blocks_count += numblocks;
fs->group_desc[i].bg_free_blocks_count = numblocks;
fs->group_desc[i].bg_free_inodes_count =
fs->super->s_inodes_per_group;
fs->group_desc[i].bg_used_dirs_count = 0;
group_block += super->s_blocks_per_group;
}
ext2fs_mark_super_dirty(fs);
ext2fs_mark_bb_dirty(fs);
ext2fs_mark_ib_dirty(fs);
io_channel_set_blksize(fs->io, fs->blocksize);
*ret_fs = fs;
return 0;
cleanup:
ext2fs_free(fs);
return retval;
}

32
e2fsprogs/ext2fs/inline.c Normal file
View File

@ -0,0 +1,32 @@
/*
* inline.c --- Includes the inlined functions defined in the header
* files as standalone functions, in case the application program
* is compiled with inlining turned off.
*
* Copyright (C) 1993, 1994 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#define INCLUDE_INLINE_FUNCS
#include "ext2fs.h"

794
e2fsprogs/ext2fs/inode.c Normal file
View File

@ -0,0 +1,794 @@
/*
* 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.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fsP.h"
#include "e2image.h"
struct ext2_struct_inode_scan {
errcode_t magic;
ext2_filsys fs;
ext2_ino_t current_inode;
blk_t current_block;
dgrp_t current_group;
ext2_ino_t inodes_left;
blk_t blocks_left;
dgrp_t groups_left;
blk_t inode_buffer_blocks;
char * inode_buffer;
int inode_size;
char * ptr;
int bytes_left;
char *temp_buffer;
errcode_t (*done_group)(ext2_filsys fs,
ext2_inode_scan scan,
dgrp_t group,
void * priv_data);
void * done_group_data;
int bad_block_ptr;
int scan_flags;
int reserved[6];
};
/*
* This routine flushes the icache, if it exists.
*/
errcode_t ext2fs_flush_icache(ext2_filsys fs)
{
int i;
if (!fs->icache)
return 0;
for (i=0; i < fs->icache->cache_size; i++)
fs->icache->cache[i].ino = 0;
fs->icache->buffer_blk = 0;
return 0;
}
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);
if (retval)
return retval;
memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer);
if (retval) {
ext2fs_free_mem(&fs->icache);
return retval;
}
fs->icache->buffer_blk = 0;
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);
if (retval) {
ext2fs_free_mem(&fs->icache->buffer);
ext2fs_free_mem(&fs->icache);
return retval;
}
ext2fs_flush_icache(fs);
return 0;
}
errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
ext2_inode_scan *ret_scan)
{
ext2_inode_scan scan;
errcode_t retval;
errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks);
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
/*
* If fs->badblocks isn't set, then set it --- since the inode
* scanning functions require it.
*/
if (fs->badblocks == 0) {
/*
* Temporarly save fs->get_blocks and set it to zero,
* for compatibility with old e2fsck's.
*/
save_get_blocks = fs->get_blocks;
fs->get_blocks = 0;
retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
if (retval && fs->badblocks) {
ext2fs_badblocks_list_free(fs->badblocks);
fs->badblocks = 0;
}
fs->get_blocks = save_get_blocks;
}
retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), &scan);
if (retval)
return retval;
memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
scan->fs = fs;
scan->inode_size = EXT2_INODE_SIZE(fs->super);
scan->bytes_left = 0;
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->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);
scan->done_group = 0;
scan->done_group_data = 0;
scan->bad_block_ptr = 0;
if (retval) {
ext2fs_free_mem(&scan);
return retval;
}
retval = ext2fs_get_mem(scan->inode_size, &scan->temp_buffer);
if (retval) {
ext2fs_free_mem(&scan->inode_buffer);
ext2fs_free_mem(&scan);
return retval;
}
if (scan->fs->badblocks && scan->fs->badblocks->num)
scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
*ret_scan = scan;
return 0;
}
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);
scan->temp_buffer = NULL;
ext2fs_free_mem(&scan);
return;
}
void ext2fs_set_inode_callback(ext2_inode_scan scan,
errcode_t (*done_group)(ext2_filsys fs,
ext2_inode_scan scan,
dgrp_t group,
void * priv_data),
void *done_group_data)
{
if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
return;
scan->done_group = done_group;
scan->done_group_data = done_group_data;
}
int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
int clear_flags)
{
int old_flags;
if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
return 0;
old_flags = scan->scan_flags;
scan->scan_flags &= ~clear_flags;
scan->scan_flags |= set_flags;
return old_flags;
}
/*
* This function is called by ext2fs_get_next_inode when it needs to
* get ready to read in a new blockgroup.
*/
static errcode_t get_next_blockgroup(ext2_inode_scan scan)
{
scan->current_group++;
scan->groups_left--;
scan->current_block = scan->fs->
group_desc[scan->current_group].bg_inode_table;
scan->current_inode = scan->current_group *
EXT2_INODES_PER_GROUP(scan->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;
return 0;
}
errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
int group)
{
scan->current_group = group - 1;
scan->groups_left = scan->fs->group_desc_count - group;
return get_next_blockgroup(scan);
}
/*
* This function is called by get_next_blocks() to check for bad
* blocks in the inode table.
*
* This function assumes that badblocks_list->list is sorted in
* increasing order.
*/
static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
blk_t *num_blocks)
{
blk_t blk = scan->current_block;
badblocks_list bb = scan->fs->badblocks;
/*
* If the inode table is missing, then obviously there are no
* bad blocks. :-)
*/
if (blk == 0)
return 0;
/*
* If the current block is greater than the bad block listed
* in the bad block list, then advance the pointer until this
* is no longer the case. If we run out of bad blocks, then
* we don't need to do any more checking!
*/
while (blk > bb->list[scan->bad_block_ptr]) {
if (++scan->bad_block_ptr >= bb->num) {
scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
return 0;
}
}
/*
* If the current block is equal to the bad block listed in
* the bad block list, then handle that one block specially.
* (We could try to handle runs of bad blocks, but that
* only increases CPU efficiency by a small amount, at the
* expense of a huge expense of code complexity, and for an
* uncommon case at that.)
*/
if (blk == bb->list[scan->bad_block_ptr]) {
scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
*num_blocks = 1;
if (++scan->bad_block_ptr >= bb->num)
scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
return 0;
}
/*
* If there is a bad block in the range that we're about to
* read in, adjust the number of blocks to read so that we we
* don't read in the bad block. (Then the next block to read
* will be the bad block, which is handled in the above case.)
*/
if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
*num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
return 0;
}
/*
* This function is called by ext2fs_get_next_inode when it needs to
* read in more blocks from the current blockgroup's inode table.
*/
static errcode_t get_next_blocks(ext2_inode_scan scan)
{
blk_t num_blocks;
errcode_t retval;
/*
* Figure out how many blocks to read; we read at most
* inode_buffer_blocks, and perhaps less if there aren't that
* many blocks left to read.
*/
num_blocks = scan->inode_buffer_blocks;
if (num_blocks > scan->blocks_left)
num_blocks = scan->blocks_left;
/*
* If the past block "read" was a bad block, then mark the
* left-over extra bytes as also being bad.
*/
if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
if (scan->bytes_left)
scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
}
/*
* Do inode bad block processing, if necessary.
*/
if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
retval = check_for_inode_bad_blocks(scan, &num_blocks);
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,
scan->current_block,
(int) num_blocks,
scan->inode_buffer);
if (retval)
return EXT2_ET_NEXT_INODE_READ;
}
scan->ptr = scan->inode_buffer;
scan->bytes_left = num_blocks * scan->fs->blocksize;
scan->blocks_left -= num_blocks;
if (scan->current_block)
scan->current_block += num_blocks;
return 0;
}
#if 0
/*
* Returns 1 if the entire inode_buffer has a non-zero size and
* contains all zeros. (Not just deleted inodes, since that means
* that part of the inode table was used at one point; we want all
* zeros, which means that the inode table is pristine.)
*/
static inline int is_empty_scan(ext2_inode_scan scan)
{
int i;
if (scan->bytes_left == 0)
return 0;
for (i=0; i < scan->bytes_left; i++)
if (scan->ptr[i])
return 0;
return 1;
}
#endif
errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
struct ext2_inode *inode, int bufsize)
{
errcode_t retval;
int extra_bytes = 0;
EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
/*
* Do we need to start reading a new block group?
*/
if (scan->inodes_left <= 0) {
force_new_group:
if (scan->done_group) {
retval = (scan->done_group)
(scan->fs, scan, scan->current_group,
scan->done_group_data);
if (retval)
return retval;
}
if (scan->groups_left <= 0) {
*ino = 0;
return 0;
}
retval = get_next_blockgroup(scan);
if (retval)
return retval;
}
/*
* This is done outside the above if statement so that the
* check can be done for block group #0.
*/
if (scan->current_block == 0) {
if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
goto force_new_group;
} else
return EXT2_ET_MISSING_INODE_TABLE;
}
/*
* Have we run out of space in the inode buffer? If so, we
* need to read in more blocks.
*/
if (scan->bytes_left < scan->inode_size) {
memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
extra_bytes = scan->bytes_left;
retval = get_next_blocks(scan);
if (retval)
return retval;
#if 0
/*
* XXX test Need check for used inode somehow.
* (Note: this is hard.)
*/
if (is_empty_scan(scan))
goto force_new_group;
#endif
}
retval = 0;
if (extra_bytes) {
memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
scan->inode_size - extra_bytes);
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
#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,
(struct ext2_inode_large *) inode,
(struct ext2_inode_large *) scan->ptr,
0, bufsize);
else
#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)
retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
}
scan->inodes_left--;
scan->current_inode++;
*ino = scan->current_inode;
return retval;
}
errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
struct ext2_inode *inode)
{
return ext2fs_get_next_inode_full(scan, ino, inode,
sizeof(struct ext2_inode));
}
/*
* Functions to read and write a single inode.
*/
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;
char *ptr;
errcode_t retval;
int clen, i, inodes_per_block, length;
io_channel io;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
/* Check to see if user has an override function */
if (fs->read_inode) {
retval = (fs->read_inode)(fs, ino, inode);
if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
return retval;
}
/* Create inode cache if not present */
if (!fs->icache) {
retval = create_icache(fs);
if (retval)
return retval;
}
/* 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 */
for (i=0; i < fs->icache->cache_size; i++) {
if (fs->icache->cache[i].ino == ino) {
*inode = fs->icache->cache[i].inode;
return 0;
}
}
}
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;
block_nr += (ino - 1) / inodes_per_block;
offset = ((ino - 1) % inodes_per_block) *
EXT2_INODE_SIZE(fs->super);
io = fs->image_io;
} else {
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;
io = fs->io;
}
offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
length = EXT2_INODE_SIZE(fs->super);
if (bufsize < length)
length = bufsize;
ptr = (char *) inode;
while (length) {
clen = length;
if ((offset + length) > fs->blocksize)
clen = fs->blocksize - offset;
if (block_nr != fs->icache->buffer_blk) {
retval = io_channel_read_blk(io, block_nr, 1,
fs->icache->buffer);
if (retval)
return retval;
fs->icache->buffer_blk = block_nr;
}
memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset,
clen);
offset = 0;
length -= clen;
ptr += clen;
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);
#endif
/* Update the inode cache */
fs->icache->cache_last = (fs->icache->cache_last + 1) %
fs->icache->cache_size;
fs->icache->cache[fs->icache->cache_last].ino = ino;
fs->icache->cache[fs->icache->cache_last].inode = *inode;
return 0;
}
errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode * inode)
{
return ext2fs_read_inode_full(fs, ino, inode,
sizeof(struct ext2_inode));
}
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;
errcode_t retval = 0;
struct ext2_inode_large temp_inode, *w_inode;
char *ptr;
int clen, i, length;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
/* Check to see if user provided an override function */
if (fs->write_inode) {
retval = (fs->write_inode)(fs, ino, inode);
if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
return retval;
}
/* Check to see if the inode cache needs to be updated */
if (fs->icache) {
for (i=0; i < fs->icache->cache_size; i++) {
if (fs->icache->cache[i].ino == ino) {
fs->icache->cache[i].inode = *inode;
break;
}
}
} else {
retval = create_icache(fs);
if (retval)
return retval;
}
if (!(fs->flags & EXT2_FLAG_RW))
return EXT2_ET_RO_FILSYS;
if ((ino == 0) || (ino > fs->super->s_inodes_count))
return EXT2_ET_BAD_INODE_NUM;
length = bufsize;
if (length < EXT2_INODE_SIZE(fs->super))
length = EXT2_INODE_SIZE(fs->super);
if (length > (int) sizeof(struct ext2_inode_large)) {
w_inode = malloc(length);
if (!w_inode)
return ENOMEM;
} 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
#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;
offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
length = EXT2_INODE_SIZE(fs->super);
if (length > bufsize)
length = bufsize;
ptr = (char *) w_inode;
while (length) {
clen = length;
if ((offset + length) > fs->blocksize)
clen = fs->blocksize - offset;
if (fs->icache->buffer_blk != block_nr) {
retval = io_channel_read_blk(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,
ptr, clen);
retval = io_channel_write_blk(fs->io, block_nr, 1,
fs->icache->buffer);
if (retval)
goto errout;
offset = 0;
ptr += clen;
length -= clen;
block_nr++;
}
fs->flags |= EXT2_FLAG_CHANGED;
errout:
if (w_inode && w_inode != &temp_inode)
free(w_inode);
return retval;
}
errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode)
{
return ext2fs_write_inode_full(fs, ino, inode,
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.
*/
errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode)
{
struct ext2_inode *buf;
int size = EXT2_INODE_SIZE(fs->super);
struct ext2_inode_large *large_inode;
if (size == sizeof(struct ext2_inode))
return ext2fs_write_inode_full(fs, ino, inode,
sizeof(struct ext2_inode));
buf = malloc(size);
if (!buf)
return ENOMEM;
memset(buf, 0, size);
*buf = *inode;
large_inode = (struct ext2_inode_large *) buf;
large_inode->i_extra_isize = sizeof(struct ext2_inode_large) -
EXT2_GOOD_OLD_INODE_SIZE;
return ext2fs_write_inode_full(fs, ino, buf, size);
}
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)
return EXT2_ET_BAD_INODE_NUM;
if (fs->get_blocks) {
if (!(*fs->get_blocks)(fs, ino, blocks))
return 0;
}
retval = ext2fs_read_inode(fs, ino, &inode);
if (retval)
return retval;
for (i=0; i < EXT2_N_BLOCKS; i++)
blocks[i] = inode.i_block[i];
return 0;
}
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)
return EXT2_ET_BAD_INODE_NUM;
if (fs->check_directory) {
retval = (fs->check_directory)(fs, ino);
if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
return retval;
}
retval = ext2fs_read_inode(fs, ino, &inode);
if (retval)
return retval;
if (!LINUX_S_ISDIR(inode.i_mode))
return EXT2_ET_NO_DIRECTORY;
return 0;
}

270
e2fsprogs/ext2fs/inode_io.c Normal file
View File

@ -0,0 +1,270 @@
/*
* inode_io.c --- This is allows an inode in an ext2 filesystem image
* to be accessed via the I/O manager interface.
*
* Copyright (C) 2002 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <time.h>
#include "ext2_fs.h"
#include "ext2fs.h"
/*
* For checking structure magic numbers...
*/
#define EXT2_CHECK_MAGIC(struct, code) \
if ((struct)->magic != (code)) return (code)
struct inode_private_data {
int magic;
char name[32];
ext2_file_t file;
ext2_filsys fs;
ext2_ino_t ino;
struct ext2_inode inode;
int flags;
struct inode_private_data *next;
};
#define CHANNEL_HAS_INODE 0x8000
static struct inode_private_data *top_intern;
static int ino_unique = 0;
static errcode_t inode_open(const char *name, int flags, io_channel *channel);
static errcode_t inode_close(io_channel channel);
static errcode_t inode_set_blksize(io_channel channel, int blksize);
static errcode_t inode_read_blk(io_channel channel, unsigned long block,
int count, void *data);
static errcode_t inode_write_blk(io_channel channel, unsigned long block,
int count, const void *data);
static errcode_t inode_flush(io_channel channel);
static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
int size, const void *data);
static struct struct_io_manager struct_inode_manager = {
EXT2_ET_MAGIC_IO_MANAGER,
"Inode I/O Manager",
inode_open,
inode_close,
inode_set_blksize,
inode_read_blk,
inode_write_blk,
inode_flush,
inode_write_byte
};
io_manager inode_io_manager = &struct_inode_manager;
errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
char **name)
{
struct inode_private_data *data;
errcode_t retval;
if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data),
&data)))
return retval;
data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL;
sprintf(data->name, "%u:%d", ino, ino_unique++);
data->file = 0;
data->fs = fs;
data->ino = ino;
data->flags = 0;
if (inode) {
memcpy(&data->inode, inode, sizeof(struct ext2_inode));
data->flags |= CHANNEL_HAS_INODE;
}
data->next = top_intern;
top_intern = data;
*name = data->name;
return 0;
}
errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
char **name)
{
return ext2fs_inode_io_intern2(fs, ino, NULL, name);
}
static errcode_t inode_open(const char *name, int flags, io_channel *channel)
{
io_channel io = NULL;
struct inode_private_data *prev, *data = NULL;
errcode_t retval;
int open_flags;
if (name == 0)
return EXT2_ET_BAD_DEVICE_NAME;
for (data = top_intern, prev = NULL; data;
prev = data, data = data->next)
if (strcmp(name, data->name) == 0)
break;
if (!data)
return ENOENT;
if (prev)
prev->next = data->next;
else
top_intern = data->next;
retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
if (retval)
goto cleanup;
memset(io, 0, sizeof(struct struct_io_channel));
io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
io->manager = inode_io_manager;
retval = ext2fs_get_mem(strlen(name)+1, &io->name);
if (retval)
goto cleanup;
strcpy(io->name, name);
io->private_data = data;
io->block_size = 1024;
io->read_error = 0;
io->write_error = 0;
io->refcount = 1;
open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0;
retval = ext2fs_file_open2(data->fs, data->ino,
(data->flags & CHANNEL_HAS_INODE) ?
&data->inode : 0, open_flags,
&data->file);
if (retval)
goto cleanup;
*channel = io;
return 0;
cleanup:
if (data) {
ext2fs_free_mem(&data);
}
if (io)
ext2fs_free_mem(&io);
return retval;
}
static errcode_t inode_close(io_channel channel)
{
struct inode_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct inode_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
if (--channel->refcount > 0)
return 0;
retval = ext2fs_file_close(data->file);
ext2fs_free_mem(&channel->private_data);
if (channel->name)
ext2fs_free_mem(&channel->name);
ext2fs_free_mem(&channel);
return retval;
}
static errcode_t inode_set_blksize(io_channel channel, int blksize)
{
struct inode_private_data *data;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct inode_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
channel->block_size = blksize;
return 0;
}
static errcode_t inode_read_blk(io_channel channel, unsigned long block,
int count, void *buf)
{
struct inode_private_data *data;
errcode_t retval;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct inode_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
if ((retval = ext2fs_file_lseek(data->file,
block * channel->block_size,
EXT2_SEEK_SET, 0)))
return retval;
count = (count < 0) ? -count : (count * channel->block_size);
return ext2fs_file_read(data->file, buf, count, 0);
}
static errcode_t inode_write_blk(io_channel channel, unsigned long block,
int count, const void *buf)
{
struct inode_private_data *data;
errcode_t retval;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct inode_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
if ((retval = ext2fs_file_lseek(data->file,
block * channel->block_size,
EXT2_SEEK_SET, 0)))
return retval;
count = (count < 0) ? -count : (count * channel->block_size);
return ext2fs_file_write(data->file, buf, count, 0);
}
static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
int size, const void *buf)
{
struct inode_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct inode_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
if ((retval = ext2fs_file_lseek(data->file, offset,
EXT2_SEEK_SET, 0)))
return retval;
return ext2fs_file_write(data->file, buf, size, 0);
}
/*
* Flush data buffers to disk.
*/
static errcode_t inode_flush(io_channel channel)
{
struct inode_private_data *data;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct inode_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
return ext2fs_file_flush(data->file);
}

View File

@ -0,0 +1,69 @@
/*
* io_manager.c --- the I/O manager abstraction
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
errcode_t io_channel_set_options(io_channel channel, const char *opts)
{
errcode_t retval = 0;
char *next, *ptr, *options, *arg;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
if (!opts)
return 0;
if (!channel->manager->set_option)
return EXT2_ET_INVALID_ARGUMENT;
options = malloc(strlen(opts)+1);
if (!options)
return EXT2_ET_NO_MEMORY;
strcpy(options, opts);
ptr = options;
while (ptr && *ptr) {
next = strchr(ptr, '&');
if (next)
*next++ = 0;
arg = strchr(ptr, '=');
if (arg)
*arg++ = 0;
retval = (channel->manager->set_option)(channel, ptr, arg);
if (retval)
break;
ptr = next;
}
free(options);
return retval;
}
errcode_t io_channel_write_byte(io_channel channel, unsigned long offset,
int count, const void *data)
{
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
if (channel->manager->write_byte)
return channel->manager->write_byte(channel, offset,
count, data);
return EXT2_ET_UNIMPLEMENTED;
}

114
e2fsprogs/ext2fs/irel.h Normal file
View File

@ -0,0 +1,114 @@
/*
* irel.h
*
* Copyright (C) 1996, 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
struct ext2_inode_reference {
blk_t block;
__u16 offset;
};
struct ext2_inode_relocate_entry {
ext2_ino_t new;
ext2_ino_t orig;
__u16 flags;
__u16 max_refs;
};
typedef struct ext2_inode_relocation_table *ext2_irel;
struct ext2_inode_relocation_table {
__u32 magic;
char *name;
ext2_ino_t current;
void *priv_data;
/*
* Add an inode relocation entry.
*/
errcode_t (*put)(ext2_irel irel, ext2_ino_t old,
struct ext2_inode_relocate_entry *ent);
/*
* Get an inode relocation entry.
*/
errcode_t (*get)(ext2_irel irel, ext2_ino_t old,
struct ext2_inode_relocate_entry *ent);
/*
* Get an inode relocation entry by its original inode number
*/
errcode_t (*get_by_orig)(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
struct ext2_inode_relocate_entry *ent);
/*
* Initialize for iterating over the inode relocation entries.
*/
errcode_t (*start_iter)(ext2_irel irel);
/*
* The iterator function for the inode relocation entries.
* Returns an inode number of 0 when out of entries.
*/
errcode_t (*next)(ext2_irel irel, ext2_ino_t *old,
struct ext2_inode_relocate_entry *ent);
/*
* Add an inode reference (i.e., note the fact that a
* particular block/offset contains a reference to an inode)
*/
errcode_t (*add_ref)(ext2_irel irel, ext2_ino_t ino,
struct ext2_inode_reference *ref);
/*
* Initialize for iterating over the inode references for a
* particular inode.
*/
errcode_t (*start_iter_ref)(ext2_irel irel, ext2_ino_t ino);
/*
* The iterator function for the inode references for an
* inode. The references for only one inode can be interator
* over at a time, as the iterator state is stored in ext2_irel.
*/
errcode_t (*next_ref)(ext2_irel irel,
struct ext2_inode_reference *ref);
/*
* Move the inode relocation table from one inode number to
* another. Note that the inode references also must move.
*/
errcode_t (*move)(ext2_irel irel, ext2_ino_t old, ext2_ino_t new);
/*
* Remove an inode relocation entry, along with all of the
* inode references.
*/
errcode_t (*delete)(ext2_irel irel, ext2_ino_t old);
/*
* Free the inode relocation table.
*/
errcode_t (*free)(ext2_irel irel);
};
errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode,
ext2_irel *irel);
#define ext2fs_irel_put(irel, old, ent) ((irel)->put((irel), old, ent))
#define ext2fs_irel_get(irel, old, ent) ((irel)->get((irel), old, ent))
#define ext2fs_irel_get_by_orig(irel, orig, old, ent) \
((irel)->get_by_orig((irel), orig, old, ent))
#define ext2fs_irel_start_iter(irel) ((irel)->start_iter((irel)))
#define ext2fs_irel_next(irel, old, ent) ((irel)->next((irel), old, ent))
#define ext2fs_irel_add_ref(irel, ino, ref) ((irel)->add_ref((irel), ino, ref))
#define ext2fs_irel_start_iter_ref(irel, ino) ((irel)->start_iter_ref((irel), ino))
#define ext2fs_irel_next_ref(irel, ref) ((irel)->next_ref((irel), ref))
#define ext2fs_irel_move(irel, old, new) ((irel)->move((irel), old, new))
#define ext2fs_irel_delete(irel, old) ((irel)->delete((irel), old))
#define ext2fs_irel_free(irel) ((irel)->free((irel)))

372
e2fsprogs/ext2fs/irel_ma.c Normal file
View File

@ -0,0 +1,372 @@
/*
* irel_ma.c
*
* Copyright (C) 1996, 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
#include "irel.h"
static errcode_t ima_put(ext2_irel irel, ext2_ino_t old,
struct ext2_inode_relocate_entry *ent);
static errcode_t ima_get(ext2_irel irel, ext2_ino_t old,
struct ext2_inode_relocate_entry *ent);
static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
struct ext2_inode_relocate_entry *ent);
static errcode_t ima_start_iter(ext2_irel irel);
static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old,
struct ext2_inode_relocate_entry *ent);
static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino,
struct ext2_inode_reference *ref);
static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino);
static errcode_t ima_next_ref(ext2_irel irel, struct ext2_inode_reference *ref);
static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new);
static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old);
static errcode_t ima_free(ext2_irel irel);
/*
* This data structure stores the array of inode references; there is
* a structure for each inode.
*/
struct inode_reference_entry {
__u16 num;
struct ext2_inode_reference *refs;
};
struct irel_ma {
__u32 magic;
ext2_ino_t max_inode;
ext2_ino_t ref_current;
int ref_iter;
ext2_ino_t *orig_map;
struct ext2_inode_relocate_entry *entries;
struct inode_reference_entry *ref_entries;
};
errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode,
ext2_irel *new_irel)
{
ext2_irel irel = 0;
errcode_t retval;
struct irel_ma *ma = 0;
size_t size;
*new_irel = 0;
/*
* Allocate memory structures
*/
retval = ext2fs_get_mem(sizeof(struct ext2_inode_relocation_table),
&irel);
if (retval)
goto errout;
memset(irel, 0, sizeof(struct ext2_inode_relocation_table));
retval = ext2fs_get_mem(strlen(name)+1, &irel->name);
if (retval)
goto errout;
strcpy(irel->name, name);
retval = ext2fs_get_mem(sizeof(struct irel_ma), &ma);
if (retval)
goto errout;
memset(ma, 0, sizeof(struct irel_ma));
irel->priv_data = ma;
size = (size_t) (sizeof(ext2_ino_t) * (max_inode+1));
retval = ext2fs_get_mem(size, &ma->orig_map);
if (retval)
goto errout;
memset(ma->orig_map, 0, size);
size = (size_t) (sizeof(struct ext2_inode_relocate_entry) *
(max_inode+1));
retval = ext2fs_get_mem(size, &ma->entries);
if (retval)
goto errout;
memset(ma->entries, 0, size);
size = (size_t) (sizeof(struct inode_reference_entry) *
(max_inode+1));
retval = ext2fs_get_mem(size, &ma->ref_entries);
if (retval)
goto errout;
memset(ma->ref_entries, 0, size);
ma->max_inode = max_inode;
/*
* Fill in the irel data structure
*/
irel->put = ima_put;
irel->get = ima_get;
irel->get_by_orig = ima_get_by_orig;
irel->start_iter = ima_start_iter;
irel->next = ima_next;
irel->add_ref = ima_add_ref;
irel->start_iter_ref = ima_start_iter_ref;
irel->next_ref = ima_next_ref;
irel->move = ima_move;
irel->delete = ima_delete;
irel->free = ima_free;
*new_irel = irel;
return 0;
errout:
ima_free(irel);
return retval;
}
static errcode_t ima_put(ext2_irel irel, ext2_ino_t old,
struct ext2_inode_relocate_entry *ent)
{
struct inode_reference_entry *ref_ent;
struct irel_ma *ma;
errcode_t retval;
size_t size, old_size;
ma = irel->priv_data;
if (old > ma->max_inode)
return EXT2_ET_INVALID_ARGUMENT;
/*
* Force the orig field to the correct value; the application
* program shouldn't be messing with this field.
*/
if (ma->entries[(unsigned) old].new == 0)
ent->orig = old;
else
ent->orig = ma->entries[(unsigned) old].orig;
/*
* If max_refs has changed, reallocate the refs array
*/
ref_ent = ma->ref_entries + (unsigned) old;
if (ref_ent->refs && ent->max_refs !=
ma->entries[(unsigned) old].max_refs) {
size = (sizeof(struct ext2_inode_reference) * ent->max_refs);
old_size = (sizeof(struct ext2_inode_reference) *
ma->entries[(unsigned) old].max_refs);
retval = ext2fs_resize_mem(old_size, size, &ref_ent->refs);
if (retval)
return retval;
}
ma->entries[(unsigned) old] = *ent;
ma->orig_map[(unsigned) ent->orig] = old;
return 0;
}
static errcode_t ima_get(ext2_irel irel, ext2_ino_t old,
struct ext2_inode_relocate_entry *ent)
{
struct irel_ma *ma;
ma = irel->priv_data;
if (old > ma->max_inode)
return EXT2_ET_INVALID_ARGUMENT;
if (ma->entries[(unsigned) old].new == 0)
return ENOENT;
*ent = ma->entries[(unsigned) old];
return 0;
}
static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
struct ext2_inode_relocate_entry *ent)
{
struct irel_ma *ma;
ext2_ino_t ino;
ma = irel->priv_data;
if (orig > ma->max_inode)
return EXT2_ET_INVALID_ARGUMENT;
ino = ma->orig_map[(unsigned) orig];
if (ino == 0)
return ENOENT;
*old = ino;
*ent = ma->entries[(unsigned) ino];
return 0;
}
static errcode_t ima_start_iter(ext2_irel irel)
{
irel->current = 0;
return 0;
}
static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old,
struct ext2_inode_relocate_entry *ent)
{
struct irel_ma *ma;
ma = irel->priv_data;
while (++irel->current < ma->max_inode) {
if (ma->entries[(unsigned) irel->current].new == 0)
continue;
*old = irel->current;
*ent = ma->entries[(unsigned) irel->current];
return 0;
}
*old = 0;
return 0;
}
static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino,
struct ext2_inode_reference *ref)
{
struct irel_ma *ma;
size_t size;
struct inode_reference_entry *ref_ent;
struct ext2_inode_relocate_entry *ent;
errcode_t retval;
ma = irel->priv_data;
if (ino > ma->max_inode)
return EXT2_ET_INVALID_ARGUMENT;
ref_ent = ma->ref_entries + (unsigned) ino;
ent = ma->entries + (unsigned) ino;
/*
* If the inode reference array doesn't exist, create it.
*/
if (ref_ent->refs == 0) {
size = (size_t) ((sizeof(struct ext2_inode_reference) *
ent->max_refs));
retval = ext2fs_get_mem(size, &ref_ent->refs);
if (retval)
return retval;
memset(ref_ent->refs, 0, size);
ref_ent->num = 0;
}
if (ref_ent->num >= ent->max_refs)
return EXT2_ET_TOO_MANY_REFS;
ref_ent->refs[(unsigned) ref_ent->num++] = *ref;
return 0;
}
static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino)
{
struct irel_ma *ma;
ma = irel->priv_data;
if (ino > ma->max_inode)
return EXT2_ET_INVALID_ARGUMENT;
if (ma->entries[(unsigned) ino].new == 0)
return ENOENT;
ma->ref_current = ino;
ma->ref_iter = 0;
return 0;
}
static errcode_t ima_next_ref(ext2_irel irel,
struct ext2_inode_reference *ref)
{
struct irel_ma *ma;
struct inode_reference_entry *ref_ent;
ma = irel->priv_data;
ref_ent = ma->ref_entries + ma->ref_current;
if ((ref_ent->refs == NULL) ||
(ma->ref_iter >= ref_ent->num)) {
ref->block = 0;
ref->offset = 0;
return 0;
}
*ref = ref_ent->refs[ma->ref_iter++];
return 0;
}
static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new)
{
struct irel_ma *ma;
ma = irel->priv_data;
if ((old > ma->max_inode) || (new > ma->max_inode))
return EXT2_ET_INVALID_ARGUMENT;
if (ma->entries[(unsigned) old].new == 0)
return ENOENT;
ma->entries[(unsigned) new] = ma->entries[(unsigned) old];
if (ma->ref_entries[(unsigned) new].refs)
ext2fs_free_mem(&ma->ref_entries[(unsigned) new].refs);
ma->ref_entries[(unsigned) new] = ma->ref_entries[(unsigned) old];
ma->entries[(unsigned) old].new = 0;
ma->ref_entries[(unsigned) old].num = 0;
ma->ref_entries[(unsigned) old].refs = 0;
ma->orig_map[ma->entries[new].orig] = new;
return 0;
}
static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old)
{
struct irel_ma *ma;
ma = irel->priv_data;
if (old > ma->max_inode)
return EXT2_ET_INVALID_ARGUMENT;
if (ma->entries[(unsigned) old].new == 0)
return ENOENT;
ma->entries[old].new = 0;
if (ma->ref_entries[(unsigned) old].refs)
ext2fs_free_mem(&ma->ref_entries[(unsigned) old].refs);
ma->orig_map[ma->entries[(unsigned) old].orig] = 0;
ma->ref_entries[(unsigned) old].num = 0;
ma->ref_entries[(unsigned) old].refs = 0;
return 0;
}
static errcode_t ima_free(ext2_irel irel)
{
struct irel_ma *ma;
ext2_ino_t ino;
if (!irel)
return 0;
ma = irel->priv_data;
if (ma) {
if (ma->orig_map)
ext2fs_free_mem(&ma->orig_map);
if (ma->entries)
ext2fs_free_mem(&ma->entries);
if (ma->ref_entries) {
for (ino = 0; ino <= ma->max_inode; ino++) {
if (ma->ref_entries[(unsigned) ino].refs)
ext2fs_free_mem(&ma->ref_entries[(unsigned) ino].refs);
}
ext2fs_free_mem(&ma->ref_entries);
}
ext2fs_free_mem(&ma);
}
if (irel->name)
ext2fs_free_mem(&irel->name);
ext2fs_free_mem(&irel);
return 0;
}

View File

@ -0,0 +1,358 @@
/*
* ismounted.c --- Check to see if the filesystem was mounted
*
* Copyright (C) 1995,1996,1997,1998,1999,2000 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <fcntl.h>
#ifdef HAVE_LINUX_FD_H
#include <linux/fd.h>
#endif
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#ifdef HAVE_GETMNTINFO
#include <paths.h>
#include <sys/param.h>
#include <sys/mount.h>
#endif /* HAVE_GETMNTINFO */
#include <string.h>
#include <sys/stat.h>
#include "ext2_fs.h"
#include "ext2fs.h"
#ifdef HAVE_MNTENT_H
/*
* Helper function which checks a file in /etc/mtab format to see if a
* filesystem is mounted. Returns an error if the file doesn't exist
* or can't be opened.
*/
static errcode_t check_mntent_file(const char *mtab_file, const char *file,
int *mount_flags, char *mtpt, int mtlen)
{
struct mntent *mnt;
struct stat st_buf;
errcode_t retval = 0;
dev_t file_dev=0, file_rdev=0;
ino_t file_ino=0;
FILE *f;
int fd;
*mount_flags = 0;
if ((f = setmntent (mtab_file, "r")) == NULL)
return errno;
if (stat(file, &st_buf) == 0) {
if (S_ISBLK(st_buf.st_mode)) {
#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
file_rdev = st_buf.st_rdev;
#endif /* __GNU__ */
} else {
file_dev = st_buf.st_dev;
file_ino = st_buf.st_ino;
}
}
while ((mnt = getmntent (f)) != NULL) {
if (strcmp(file, mnt->mnt_fsname) == 0)
break;
if (stat(mnt->mnt_fsname, &st_buf) == 0) {
if (S_ISBLK(st_buf.st_mode)) {
#ifndef __GNU__
if (file_rdev && (file_rdev == st_buf.st_rdev))
break;
#endif /* __GNU__ */
} else {
if (file_dev && ((file_dev == st_buf.st_dev) &&
(file_ino == st_buf.st_ino)))
break;
}
}
}
if (mnt == 0) {
#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
/*
* Do an extra check to see if this is the root device. We
* can't trust /etc/mtab, and /proc/mounts will only list
* /dev/root for the root filesystem. Argh. Instead we
* check if the given device has the same major/minor number
* as the device that the root directory is on.
*/
if (file_rdev && stat("/", &st_buf) == 0) {
if (st_buf.st_dev == file_rdev) {
*mount_flags = EXT2_MF_MOUNTED;
if (mtpt)
strncpy(mtpt, "/", mtlen);
goto is_root;
}
}
#endif /* __GNU__ */
goto errout;
}
#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */
/* Validate the entry in case /etc/mtab is out of date */
/*
* We need to be paranoid, because some broken distributions
* (read: Slackware) don't initialize /etc/mtab before checking
* all of the non-root filesystems on the disk.
*/
if (stat(mnt->mnt_dir, &st_buf) < 0) {
retval = errno;
if (retval == ENOENT) {
#ifdef DEBUG
printf("Bogus entry in %s! (%s does not exist)\n",
mtab_file, mnt->mnt_dir);
#endif /* DEBUG */
retval = 0;
}
goto errout;
}
if (file_rdev && (st_buf.st_dev != file_rdev)) {
#ifdef DEBUG
printf("Bogus entry in %s! (%s not mounted on %s)\n",
mtab_file, file, mnt->mnt_dir);
#endif /* DEBUG */
goto errout;
}
#endif /* __GNU__ */
*mount_flags = EXT2_MF_MOUNTED;
#ifdef MNTOPT_RO
/* Check to see if the ro option is set */
if (hasmntopt(mnt, MNTOPT_RO))
*mount_flags |= EXT2_MF_READONLY;
#endif
if (mtpt)
strncpy(mtpt, mnt->mnt_dir, mtlen);
/*
* Check to see if we're referring to the root filesystem.
* If so, do a manual check to see if we can open /etc/mtab
* read/write, since if the root is mounted read/only, the
* contents of /etc/mtab may not be accurate.
*/
if (!strcmp(mnt->mnt_dir, "/")) {
is_root:
#define TEST_FILE "/.ismount-test-file"
*mount_flags |= EXT2_MF_ISROOT;
fd = open(TEST_FILE, O_RDWR|O_CREAT);
if (fd < 0) {
if (errno == EROFS)
*mount_flags |= EXT2_MF_READONLY;
} else
close(fd);
(void) unlink(TEST_FILE);
}
retval = 0;
errout:
endmntent (f);
return retval;
}
static errcode_t check_mntent(const char *file, int *mount_flags,
char *mtpt, int mtlen)
{
errcode_t retval;
#ifdef DEBUG
retval = check_mntent_file("/tmp/mtab", file, mount_flags,
mtpt, mtlen);
if (retval == 0)
return 0;
#endif /* DEBUG */
#ifdef __linux__
retval = check_mntent_file("/proc/mounts", file, mount_flags,
mtpt, mtlen);
if (retval == 0 && (*mount_flags != 0))
return 0;
#endif /* __linux__ */
#if defined(MOUNTED) || defined(_PATH_MOUNTED)
#ifndef MOUNTED
#define MOUNTED _PATH_MOUNTED
#endif /* MOUNTED */
retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen);
return retval;
#else
*mount_flags = 0;
return 0;
#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */
}
#else
#if defined(HAVE_GETMNTINFO)
static errcode_t check_getmntinfo(const char *file, int *mount_flags,
char *mtpt, int mtlen)
{
struct statfs *mp;
int len, n;
const char *s1;
char *s2;
n = getmntinfo(&mp, MNT_NOWAIT);
if (n == 0)
return errno;
len = sizeof(_PATH_DEV) - 1;
s1 = file;
if (strncmp(_PATH_DEV, s1, len) == 0)
s1 += len;
*mount_flags = 0;
while (--n >= 0) {
s2 = mp->f_mntfromname;
if (strncmp(_PATH_DEV, s2, len) == 0) {
s2 += len - 1;
*s2 = 'r';
}
if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) {
*mount_flags = EXT2_MF_MOUNTED;
break;
}
++mp;
}
if (mtpt)
strncpy(mtpt, mp->f_mntonname, mtlen);
return 0;
}
#endif /* HAVE_GETMNTINFO */
#endif /* HAVE_MNTENT_H */
/*
* Check to see if we're dealing with the swap device.
*/
static int is_swap_device(const char *file)
{
FILE *f;
char buf[1024], *cp;
dev_t file_dev;
struct stat st_buf;
int ret = 0;
file_dev = 0;
#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
if ((stat(file, &st_buf) == 0) &&
S_ISBLK(st_buf.st_mode))
file_dev = st_buf.st_rdev;
#endif /* __GNU__ */
if (!(f = fopen("/proc/swaps", "r")))
return 0;
/* Skip the first line */
fgets(buf, sizeof(buf), f);
while (!feof(f)) {
if (!fgets(buf, sizeof(buf), f))
break;
if ((cp = strchr(buf, ' ')) != NULL)
*cp = 0;
if ((cp = strchr(buf, '\t')) != NULL)
*cp = 0;
if (strcmp(buf, file) == 0) {
ret++;
break;
}
#ifndef __GNU__
if (file_dev && (stat(buf, &st_buf) == 0) &&
S_ISBLK(st_buf.st_mode) &&
file_dev == st_buf.st_rdev) {
ret++;
break;
}
#endif /* __GNU__ */
}
fclose(f);
return ret;
}
/*
* ext2fs_check_mount_point() returns 1 if the device is mounted, 0
* otherwise. If mtpt is non-NULL, the directory where the device is
* mounted is copied to where mtpt is pointing, up to mtlen
* characters.
*/
#ifdef __TURBOC__
#pragma argsused
#endif
errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
char *mtpt, int mtlen)
{
if (is_swap_device(device)) {
*mount_flags = EXT2_MF_MOUNTED | EXT2_MF_SWAP;
strncpy(mtpt, "<swap>", mtlen);
return 0;
}
#ifdef HAVE_MNTENT_H
return check_mntent(device, mount_flags, mtpt, mtlen);
#else
#ifdef HAVE_GETMNTINFO
return check_getmntinfo(device, mount_flags, mtpt, mtlen);
#else
#ifdef __GNUC__
#warning "Can't use getmntent or getmntinfo to check for mounted filesystems!"
#endif
*mount_flags = 0;
return 0;
#endif /* HAVE_GETMNTINFO */
#endif /* HAVE_MNTENT_H */
}
/*
* ext2fs_check_if_mounted() sets the mount_flags EXT2_MF_MOUNTED,
* EXT2_MF_READONLY, and EXT2_MF_ROOT
*
*/
errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags)
{
return ext2fs_check_mount_point(file, mount_flags, NULL, 0);
}
#ifdef DEBUG
int main(int argc, char **argv)
{
int retval, mount_flags;
char mntpt[80];
if (argc < 2) {
fprintf(stderr, "Usage: %s device\n", argv[0]);
exit(1);
}
mntpt[0] = 0;
retval = ext2fs_check_mount_point(argv[1], &mount_flags,
mntpt, sizeof(mntpt));
if (retval) {
com_err(argv[0], retval,
"while calling ext2fs_check_if_mounted");
exit(1);
}
printf("Device %s reports flags %02x\n", argv[1], mount_flags);
if (mount_flags & EXT2_MF_MOUNTED)
printf("\t%s is mounted.\n", argv[1]);
if (mount_flags & EXT2_MF_SWAP)
printf("\t%s is a swap device.\n", argv[1]);
if (mount_flags & EXT2_MF_READONLY)
printf("\t%s is read-only.\n", argv[1]);
if (mount_flags & EXT2_MF_ISROOT)
printf("\t%s is the root filesystem.\n", argv[1]);
if (mntpt[0])
printf("\t%s is mounted on %s.\n", argv[1], mntpt);
exit(0);
}
#endif /* DEBUG */

View File

@ -0,0 +1,67 @@
#ifndef _JFS_COMPAT_H
#define _JFS_COMPAT_H
#include "kernel-list.h"
#include <errno.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#define printk printf
#define KERN_ERR ""
#define KERN_DEBUG ""
#define READ 0
#define WRITE 1
#define cpu_to_be32(n) htonl(n)
#define be32_to_cpu(n) ntohl(n)
typedef unsigned int tid_t;
typedef struct journal_s journal_t;
struct buffer_head;
struct inode;
struct journal_s
{
unsigned long j_flags;
int j_errno;
struct buffer_head * j_sb_buffer;
struct journal_superblock_s *j_superblock;
int j_format_version;
unsigned long j_head;
unsigned long j_tail;
unsigned long j_free;
unsigned long j_first, j_last;
kdev_t j_dev;
kdev_t j_fs_dev;
int j_blocksize;
unsigned int j_blk_offset;
unsigned int j_maxlen;
struct inode * j_inode;
tid_t j_tail_sequence;
tid_t j_transaction_sequence;
__u8 j_uuid[16];
struct jbd_revoke_table_s *j_revoke;
};
#define J_ASSERT(assert) \
do { if (!(assert)) { \
printf ("Assertion failure in %s() at %s line %d: " \
"\"%s\"\n", \
__FUNCTION__, __FILE__, __LINE__, # assert); \
fatal_error(e2fsck_global_ctx, 0); \
} } while (0)
#define is_journal_abort(x) 0
#define BUFFER_TRACE(bh, info) do {} while (0)
/* Need this so we can compile with configure --enable-gcc-wall */
#ifdef NO_INLINE_FUNCS
#define inline
#endif
#endif /* _JFS_COMPAT_H */

View File

@ -0,0 +1,64 @@
/*
* jfs_dat.h --- stripped down header file which only contains the JFS
* on-disk data structures
*/
#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
/*
* On-disk structures
*/
/*
* Descriptor block types:
*/
#define JFS_DESCRIPTOR_BLOCK 1
#define JFS_COMMIT_BLOCK 2
#define JFS_SUPERBLOCK 3
/*
* Standard header for all descriptor blocks:
*/
typedef struct journal_header_s
{
__u32 h_magic;
__u32 h_blocktype;
__u32 h_sequence;
} journal_header_t;
/*
* The block tag: used to describe a single buffer in the journal
*/
typedef struct journal_block_tag_s
{
__u32 t_blocknr; /* The on-disk block number */
__u32 t_flags; /* See below */
} journal_block_tag_t;
/* Definitions for the journal tag flags word: */
#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */
#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */
#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */
#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */
/*
* The journal superblock
*/
typedef struct journal_superblock_s
{
journal_header_t s_header;
/* Static information describing the journal */
__u32 s_blocksize; /* journal device blocksize */
__u32 s_maxlen; /* total blocks in journal file */
__u32 s_first; /* first block of log information */
/* Dynamic information describing the current state of the log */
__u32 s_sequence; /* first commit ID expected in log */
__u32 s_start; /* blocknr of start of log */
} journal_superblock_t;

View File

@ -0,0 +1,8 @@
#ifndef _JFS_USER_H
#define _JFS_USER_H
typedef unsigned short kdev_t;
#include "kernel-jbd.h"
#endif /* _JFS_USER_H */

View File

@ -0,0 +1,910 @@
/*
* linux/include/linux/jbd.h
*
* Written by Stephen C. Tweedie <sct@redhat.com>
*
* Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
* option, any later version, incorporated herein by reference.
*
* Definitions for transaction data structures for the buffer cache
* filesystem journaling support.
*/
#ifndef _LINUX_JBD_H
#define _LINUX_JBD_H
#if defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE) || !defined(__KERNEL__)
/* Allow this file to be included directly into e2fsprogs */
#ifndef __KERNEL__
#include "jfs_compat.h"
#define JFS_DEBUG
#define jfs_debug jbd_debug
#else
#include <linux/journal-head.h>
#include <linux/stddef.h>
#include <asm/semaphore.h>
#endif
#ifndef __GNUC__
#define __FUNCTION__ ""
#endif
#define journal_oom_retry 1
#ifdef __STDC__
#ifdef __CONFIG_JBD_DEBUG__E2FS
/*
* Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
* consistency checks. By default we don't do this unless
* __CONFIG_JBD_DEBUG__E2FS is on.
*/
#define JBD_EXPENSIVE_CHECKING
extern int journal_enable_debug;
#define jbd_debug(n, f, a...) \
do { \
if ((n) <= journal_enable_debug) { \
printk (KERN_DEBUG "(%s, %d): %s: ", \
__FILE__, __LINE__, __FUNCTION__); \
printk (f, ## a); \
} \
} while (0)
#else
#ifdef __GNUC__
#define jbd_debug(f, a...) /**/
#else
#define jbd_debug(f, ...) /**/
#endif
#endif
#else
#define jbd_debug(x) /* AIX doesn't do STDC */
#endif
extern void * __jbd_kmalloc (char *where, size_t size, int flags, int retry);
#define jbd_kmalloc(size, flags) \
__jbd_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry)
#define jbd_rep_kmalloc(size, flags) \
__jbd_kmalloc(__FUNCTION__, (size), (flags), 1)
#define JFS_MIN_JOURNAL_BLOCKS 1024
#ifdef __KERNEL__
typedef struct handle_s handle_t; /* Atomic operation type */
typedef struct journal_s journal_t; /* Journal control structure */
#endif
/*
* Internal structures used by the logging mechanism:
*/
#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
/*
* On-disk structures
*/
/*
* Descriptor block types:
*/
#define JFS_DESCRIPTOR_BLOCK 1
#define JFS_COMMIT_BLOCK 2
#define JFS_SUPERBLOCK_V1 3
#define JFS_SUPERBLOCK_V2 4
#define JFS_REVOKE_BLOCK 5
/*
* Standard header for all descriptor blocks:
*/
typedef struct journal_header_s
{
__u32 h_magic;
__u32 h_blocktype;
__u32 h_sequence;
} journal_header_t;
/*
* The block tag: used to describe a single buffer in the journal
*/
typedef struct journal_block_tag_s
{
__u32 t_blocknr; /* The on-disk block number */
__u32 t_flags; /* See below */
} journal_block_tag_t;
/*
* The revoke descriptor: used on disk to describe a series of blocks to
* be revoked from the log
*/
typedef struct journal_revoke_header_s
{
journal_header_t r_header;
int r_count; /* Count of bytes used in the block */
} journal_revoke_header_t;
/* Definitions for the journal tag flags word: */
#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */
#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */
#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */
#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */
/*
* The journal superblock. All fields are in big-endian byte order.
*/
typedef struct journal_superblock_s
{
/* 0x0000 */
journal_header_t s_header;
/* 0x000C */
/* Static information describing the journal */
__u32 s_blocksize; /* journal device blocksize */
__u32 s_maxlen; /* total blocks in journal file */
__u32 s_first; /* first block of log information */
/* 0x0018 */
/* Dynamic information describing the current state of the log */
__u32 s_sequence; /* first commit ID expected in log */
__u32 s_start; /* blocknr of start of log */
/* 0x0020 */
/* Error value, as set by journal_abort(). */
__s32 s_errno;
/* 0x0024 */
/* Remaining fields are only valid in a version-2 superblock */
__u32 s_feature_compat; /* compatible feature set */
__u32 s_feature_incompat; /* incompatible feature set */
__u32 s_feature_ro_compat; /* readonly-compatible feature set */
/* 0x0030 */
__u8 s_uuid[16]; /* 128-bit uuid for journal */
/* 0x0040 */
__u32 s_nr_users; /* Nr of filesystems sharing log */
__u32 s_dynsuper; /* Blocknr of dynamic superblock copy*/
/* 0x0048 */
__u32 s_max_transaction; /* Limit of journal blocks per trans.*/
__u32 s_max_trans_data; /* Limit of data blocks per trans. */
/* 0x0050 */
__u32 s_padding[44];
/* 0x0100 */
__u8 s_users[16*48]; /* ids of all fs'es sharing the log */
/* 0x0400 */
} journal_superblock_t;
#define JFS_HAS_COMPAT_FEATURE(j,mask) \
((j)->j_format_version >= 2 && \
((j)->j_superblock->s_feature_compat & cpu_to_be32((mask))))
#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \
((j)->j_format_version >= 2 && \
((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask))))
#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \
((j)->j_format_version >= 2 && \
((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001
/* Features known to this kernel version: */
#define JFS_KNOWN_COMPAT_FEATURES 0
#define JFS_KNOWN_ROCOMPAT_FEATURES 0
#define JFS_KNOWN_INCOMPAT_FEATURES JFS_FEATURE_INCOMPAT_REVOKE
#ifdef __KERNEL__
#include <linux/fs.h>
#include <linux/sched.h>
#define JBD_ASSERTIONS
#ifdef JBD_ASSERTIONS
#define J_ASSERT(assert) \
do { \
if (!(assert)) { \
printk (KERN_EMERG \
"Assertion failure in %s() at %s:%d: \"%s\"\n", \
__FUNCTION__, __FILE__, __LINE__, # assert); \
BUG(); \
} \
} while (0)
#if defined(CONFIG_BUFFER_DEBUG)
void buffer_assertion_failure(struct buffer_head *bh);
#define J_ASSERT_BH(bh, expr) \
do { \
if (!(expr)) \
buffer_assertion_failure(bh); \
J_ASSERT(expr); \
} while (0)
#define J_ASSERT_JH(jh, expr) J_ASSERT_BH(jh2bh(jh), expr)
#else
#define J_ASSERT_BH(bh, expr) J_ASSERT(expr)
#define J_ASSERT_JH(jh, expr) J_ASSERT(expr)
#endif
#else
#define J_ASSERT(assert)
#endif /* JBD_ASSERTIONS */
enum jbd_state_bits {
BH_JWrite
= BH_PrivateStart, /* 1 if being written to log (@@@ DEBUGGING) */
BH_Freed, /* 1 if buffer has been freed (truncated) */
BH_Revoked, /* 1 if buffer has been revoked from the log */
BH_RevokeValid, /* 1 if buffer revoked flag is valid */
BH_JBDDirty, /* 1 if buffer is dirty but journaled */
};
/* Return true if the buffer is one which JBD is managing */
static inline int buffer_jbd(struct buffer_head *bh)
{
return __buffer_state(bh, JBD);
}
static inline struct buffer_head *jh2bh(struct journal_head *jh)
{
return jh->b_bh;
}
static inline struct journal_head *bh2jh(struct buffer_head *bh)
{
return bh->b_private;
}
struct jbd_revoke_table_s;
/* The handle_t type represents a single atomic update being performed
* by some process. All filesystem modifications made by the process go
* through this handle. Recursive operations (such as quota operations)
* are gathered into a single update.
*
* The buffer credits field is used to account for journaled buffers
* being modified by the running process. To ensure that there is
* enough log space for all outstanding operations, we need to limit the
* number of outstanding buffers possible at any time. When the
* operation completes, any buffer credits not used are credited back to
* the transaction, so that at all times we know how many buffers the
* outstanding updates on a transaction might possibly touch. */
struct handle_s
{
/* Which compound transaction is this update a part of? */
transaction_t * h_transaction;
/* Number of remaining buffers we are allowed to dirty: */
int h_buffer_credits;
/* Reference count on this handle */
int h_ref;
/* Field for caller's use to track errors through large fs
operations */
int h_err;
/* Flags */
unsigned int h_sync: 1; /* sync-on-close */
unsigned int h_jdata: 1; /* force data journaling */
unsigned int h_aborted: 1; /* fatal error on handle */
};
/* The transaction_t type is the guts of the journaling mechanism. It
* tracks a compound transaction through its various states:
*
* RUNNING: accepting new updates
* LOCKED: Updates still running but we don't accept new ones
* RUNDOWN: Updates are tidying up but have finished requesting
* new buffers to modify (state not used for now)
* FLUSH: All updates complete, but we are still writing to disk
* COMMIT: All data on disk, writing commit record
* FINISHED: We still have to keep the transaction for checkpointing.
*
* The transaction keeps track of all of the buffers modified by a
* running transaction, and all of the buffers committed but not yet
* flushed to home for finished transactions.
*/
struct transaction_s
{
/* Pointer to the journal for this transaction. */
journal_t * t_journal;
/* Sequence number for this transaction */
tid_t t_tid;
/* Transaction's current state */
enum {
T_RUNNING,
T_LOCKED,
T_RUNDOWN,
T_FLUSH,
T_COMMIT,
T_FINISHED
} t_state;
/* Where in the log does this transaction's commit start? */
unsigned long t_log_start;
/* Doubly-linked circular list of all inodes owned by this
transaction */ /* AKPM: unused */
struct inode * t_ilist;
/* Number of buffers on the t_buffers list */
int t_nr_buffers;
/* Doubly-linked circular list of all buffers reserved but not
yet modified by this transaction */
struct journal_head * t_reserved_list;
/* Doubly-linked circular list of all metadata buffers owned by this
transaction */
struct journal_head * t_buffers;
/*
* Doubly-linked circular list of all data buffers still to be
* flushed before this transaction can be committed.
* Protected by journal_datalist_lock.
*/
struct journal_head * t_sync_datalist;
/*
* Doubly-linked circular list of all writepage data buffers
* still to be written before this transaction can be committed.
* Protected by journal_datalist_lock.
*/
struct journal_head * t_async_datalist;
/* Doubly-linked circular list of all forget buffers (superceded
buffers which we can un-checkpoint once this transaction
commits) */
struct journal_head * t_forget;
/*
* Doubly-linked circular list of all buffers still to be
* flushed before this transaction can be checkpointed.
*/
/* Protected by journal_datalist_lock */
struct journal_head * t_checkpoint_list;
/* Doubly-linked circular list of temporary buffers currently
undergoing IO in the log */
struct journal_head * t_iobuf_list;
/* Doubly-linked circular list of metadata buffers being
shadowed by log IO. The IO buffers on the iobuf list and the
shadow buffers on this list match each other one for one at
all times. */
struct journal_head * t_shadow_list;
/* Doubly-linked circular list of control buffers being written
to the log. */
struct journal_head * t_log_list;
/* Number of outstanding updates running on this transaction */
int t_updates;
/* Number of buffers reserved for use by all handles in this
* transaction handle but not yet modified. */
int t_outstanding_credits;
/*
* Forward and backward links for the circular list of all
* transactions awaiting checkpoint.
*/
/* Protected by journal_datalist_lock */
transaction_t *t_cpnext, *t_cpprev;
/* When will the transaction expire (become due for commit), in
* jiffies ? */
unsigned long t_expires;
/* How many handles used this transaction? */
int t_handle_count;
};
/* The journal_t maintains all of the journaling state information for a
* single filesystem. It is linked to from the fs superblock structure.
*
* We use the journal_t to keep track of all outstanding transaction
* activity on the filesystem, and to manage the state of the log
* writing process. */
struct journal_s
{
/* General journaling state flags */
unsigned long j_flags;
/* Is there an outstanding uncleared error on the journal (from
* a prior abort)? */
int j_errno;
/* The superblock buffer */
struct buffer_head * j_sb_buffer;
journal_superblock_t * j_superblock;
/* Version of the superblock format */
int j_format_version;
/* Number of processes waiting to create a barrier lock */
int j_barrier_count;
/* The barrier lock itself */
struct semaphore j_barrier;
/* Transactions: The current running transaction... */
transaction_t * j_running_transaction;
/* ... the transaction we are pushing to disk ... */
transaction_t * j_committing_transaction;
/* ... and a linked circular list of all transactions waiting
* for checkpointing. */
/* Protected by journal_datalist_lock */
transaction_t * j_checkpoint_transactions;
/* Wait queue for waiting for a locked transaction to start
committing, or for a barrier lock to be released */
wait_queue_head_t j_wait_transaction_locked;
/* Wait queue for waiting for checkpointing to complete */
wait_queue_head_t j_wait_logspace;
/* Wait queue for waiting for commit to complete */
wait_queue_head_t j_wait_done_commit;
/* Wait queue to trigger checkpointing */
wait_queue_head_t j_wait_checkpoint;
/* Wait queue to trigger commit */
wait_queue_head_t j_wait_commit;
/* Wait queue to wait for updates to complete */
wait_queue_head_t j_wait_updates;
/* Semaphore for locking against concurrent checkpoints */
struct semaphore j_checkpoint_sem;
/* The main journal lock, used by lock_journal() */
struct semaphore j_sem;
/* Journal head: identifies the first unused block in the journal. */
unsigned long j_head;
/* Journal tail: identifies the oldest still-used block in the
* journal. */
unsigned long j_tail;
/* Journal free: how many free blocks are there in the journal? */
unsigned long j_free;
/* Journal start and end: the block numbers of the first usable
* block and one beyond the last usable block in the journal. */
unsigned long j_first, j_last;
/* Device, blocksize and starting block offset for the location
* where we store the journal. */
kdev_t j_dev;
int j_blocksize;
unsigned int j_blk_offset;
/* Device which holds the client fs. For internal journal this
* will be equal to j_dev. */
kdev_t j_fs_dev;
/* Total maximum capacity of the journal region on disk. */
unsigned int j_maxlen;
/* Optional inode where we store the journal. If present, all
* journal block numbers are mapped into this inode via
* bmap(). */
struct inode * j_inode;
/* Sequence number of the oldest transaction in the log */
tid_t j_tail_sequence;
/* Sequence number of the next transaction to grant */
tid_t j_transaction_sequence;
/* Sequence number of the most recently committed transaction */
tid_t j_commit_sequence;
/* Sequence number of the most recent transaction wanting commit */
tid_t j_commit_request;
/* Journal uuid: identifies the object (filesystem, LVM volume
* etc) backed by this journal. This will eventually be
* replaced by an array of uuids, allowing us to index multiple
* devices within a single journal and to perform atomic updates
* across them. */
__u8 j_uuid[16];
/* Pointer to the current commit thread for this journal */
struct task_struct * j_task;
/* Maximum number of metadata buffers to allow in a single
* compound commit transaction */
int j_max_transaction_buffers;
/* What is the maximum transaction lifetime before we begin a
* commit? */
unsigned long j_commit_interval;
/* The timer used to wakeup the commit thread: */
struct timer_list * j_commit_timer;
int j_commit_timer_active;
/* Link all journals together - system-wide */
struct list_head j_all_journals;
/* The revoke table: maintains the list of revoked blocks in the
current transaction. */
struct jbd_revoke_table_s *j_revoke;
};
/*
* Journal flag definitions
*/
#define JFS_UNMOUNT 0x001 /* Journal thread is being destroyed */
#define JFS_ABORT 0x002 /* Journaling has been aborted for errors. */
#define JFS_ACK_ERR 0x004 /* The errno in the sb has been acked */
#define JFS_FLUSHED 0x008 /* The journal superblock has been flushed */
#define JFS_LOADED 0x010 /* The journal superblock has been loaded */
/*
* Function declarations for the journaling transaction and buffer
* management
*/
/* Filing buffers */
extern void __journal_unfile_buffer(struct journal_head *);
extern void journal_unfile_buffer(struct journal_head *);
extern void __journal_refile_buffer(struct journal_head *);
extern void journal_refile_buffer(struct journal_head *);
extern void __journal_file_buffer(struct journal_head *, transaction_t *, int);
extern void __journal_free_buffer(struct journal_head *bh);
extern void journal_file_buffer(struct journal_head *, transaction_t *, int);
extern void __journal_clean_data_list(transaction_t *transaction);
/* Log buffer allocation */
extern struct journal_head * journal_get_descriptor_buffer(journal_t *);
extern unsigned long journal_next_log_block(journal_t *);
/* Commit management */
extern void journal_commit_transaction(journal_t *);
/* Checkpoint list management */
int __journal_clean_checkpoint_list(journal_t *journal);
extern void journal_remove_checkpoint(struct journal_head *);
extern void __journal_remove_checkpoint(struct journal_head *);
extern void journal_insert_checkpoint(struct journal_head *, transaction_t *);
extern void __journal_insert_checkpoint(struct journal_head *,transaction_t *);
/* Buffer IO */
extern int
journal_write_metadata_buffer(transaction_t *transaction,
struct journal_head *jh_in,
struct journal_head **jh_out,
int blocknr);
/* Transaction locking */
extern void __wait_on_journal (journal_t *);
/*
* Journal locking.
*
* We need to lock the journal during transaction state changes so that
* nobody ever tries to take a handle on the running transaction while
* we are in the middle of moving it to the commit phase.
*
* Note that the locking is completely interrupt unsafe. We never touch
* journal structures from interrupts.
*
* In 2.2, the BKL was required for lock_journal. This is no longer
* the case.
*/
static inline void lock_journal(journal_t *journal)
{
down(&journal->j_sem);
}
/* This returns zero if we acquired the semaphore */
static inline int try_lock_journal(journal_t * journal)
{
return down_trylock(&journal->j_sem);
}
static inline void unlock_journal(journal_t * journal)
{
up(&journal->j_sem);
}
static inline handle_t *journal_current_handle(void)
{
return current->journal_info;
}
/* The journaling code user interface:
*
* Create and destroy handles
* Register buffer modifications against the current transaction.
*/
extern handle_t *journal_start(journal_t *, int nblocks);
extern handle_t *journal_try_start(journal_t *, int nblocks);
extern int journal_restart (handle_t *, int nblocks);
extern int journal_extend (handle_t *, int nblocks);
extern int journal_get_write_access (handle_t *, struct buffer_head *);
extern int journal_get_create_access (handle_t *, struct buffer_head *);
extern int journal_get_undo_access (handle_t *, struct buffer_head *);
extern int journal_dirty_data (handle_t *,
struct buffer_head *, int async);
extern int journal_dirty_metadata (handle_t *, struct buffer_head *);
extern void journal_release_buffer (handle_t *, struct buffer_head *);
extern void journal_forget (handle_t *, struct buffer_head *);
extern void journal_sync_buffer (struct buffer_head *);
extern int journal_flushpage(journal_t *, struct page *, unsigned long);
extern int journal_try_to_free_buffers(journal_t *, struct page *, int);
extern int journal_stop(handle_t *);
extern int journal_flush (journal_t *);
extern void journal_lock_updates (journal_t *);
extern void journal_unlock_updates (journal_t *);
extern journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev,
int start, int len, int bsize);
extern journal_t * journal_init_inode (struct inode *);
extern int journal_update_format (journal_t *);
extern int journal_check_used_features
(journal_t *, unsigned long, unsigned long, unsigned long);
extern int journal_check_available_features
(journal_t *, unsigned long, unsigned long, unsigned long);
extern int journal_set_features
(journal_t *, unsigned long, unsigned long, unsigned long);
extern int journal_create (journal_t *);
extern int journal_load (journal_t *journal);
extern void journal_destroy (journal_t *);
extern int journal_recover (journal_t *journal);
extern int journal_wipe (journal_t *, int);
extern int journal_skip_recovery (journal_t *);
extern void journal_update_superblock (journal_t *, int);
extern void __journal_abort (journal_t *);
extern void journal_abort (journal_t *, int);
extern int journal_errno (journal_t *);
extern void journal_ack_err (journal_t *);
extern int journal_clear_err (journal_t *);
extern unsigned long journal_bmap(journal_t *journal, unsigned long blocknr);
extern int journal_force_commit(journal_t *journal);
/*
* journal_head management
*/
extern struct journal_head
*journal_add_journal_head(struct buffer_head *bh);
extern void journal_remove_journal_head(struct buffer_head *bh);
extern void __journal_remove_journal_head(struct buffer_head *bh);
extern void journal_unlock_journal_head(struct journal_head *jh);
/* Primary revoke support */
#define JOURNAL_REVOKE_DEFAULT_HASH 256
extern int journal_init_revoke(journal_t *, int);
extern void journal_destroy_revoke_caches(void);
extern int journal_init_revoke_caches(void);
extern void journal_destroy_revoke(journal_t *);
extern int journal_revoke (handle_t *,
unsigned long, struct buffer_head *);
extern int journal_cancel_revoke(handle_t *, struct journal_head *);
extern void journal_write_revoke_records(journal_t *, transaction_t *);
/* Recovery revoke support */
extern int journal_set_revoke(journal_t *, unsigned long, tid_t);
extern int journal_test_revoke(journal_t *, unsigned long, tid_t);
extern void journal_clear_revoke(journal_t *);
extern void journal_brelse_array(struct buffer_head *b[], int n);
/* The log thread user interface:
*
* Request space in the current transaction, and force transaction commit
* transitions on demand.
*/
extern int log_space_left (journal_t *); /* Called with journal locked */
extern tid_t log_start_commit (journal_t *, transaction_t *);
extern void log_wait_commit (journal_t *, tid_t);
extern int log_do_checkpoint (journal_t *, int);
extern void log_wait_for_space(journal_t *, int nblocks);
extern void __journal_drop_transaction(journal_t *, transaction_t *);
extern int cleanup_journal_tail(journal_t *);
/* Reduce journal memory usage by flushing */
extern void shrink_journal_memory(void);
/* Debugging code only: */
#define jbd_ENOSYS() \
do { \
printk (KERN_ERR "JBD unimplemented function " __FUNCTION__); \
current->state = TASK_UNINTERRUPTIBLE; \
schedule(); \
} while (1)
/*
* is_journal_abort
*
* Simple test wrapper function to test the JFS_ABORT state flag. This
* bit, when set, indicates that we have had a fatal error somewhere,
* either inside the journaling layer or indicated to us by the client
* (eg. ext3), and that we and should not commit any further
* transactions.
*/
static inline int is_journal_aborted(journal_t *journal)
{
return journal->j_flags & JFS_ABORT;
}
static inline int is_handle_aborted(handle_t *handle)
{
if (handle->h_aborted)
return 1;
return is_journal_aborted(handle->h_transaction->t_journal);
}
static inline void journal_abort_handle(handle_t *handle)
{
handle->h_aborted = 1;
}
/* Not all architectures define BUG() */
#ifndef BUG
#define BUG() do { \
printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
* ((char *) 0) = 0; \
} while (0)
#endif /* BUG */
#else
extern int journal_recover (journal_t *journal);
extern int journal_skip_recovery (journal_t *);
/* Primary revoke support */
extern int journal_init_revoke(journal_t *, int);
extern void journal_destroy_revoke_caches(void);
extern int journal_init_revoke_caches(void);
/* Recovery revoke support */
extern int journal_set_revoke(journal_t *, unsigned long, tid_t);
extern int journal_test_revoke(journal_t *, unsigned long, tid_t);
extern void journal_clear_revoke(journal_t *);
extern void journal_brelse_array(struct buffer_head *b[], int n);
extern void journal_destroy_revoke(journal_t *);
#endif /* __KERNEL__ */
/* Comparison functions for transaction IDs: perform comparisons using
* modulo arithmetic so that they work over sequence number wraps. */
static inline int tid_gt(tid_t x, tid_t y)
{
int difference = (x - y);
return (difference > 0);
}
static inline int tid_geq(tid_t x, tid_t y)
{
int difference = (x - y);
return (difference >= 0);
}
extern int journal_blocks_per_page(struct inode *inode);
/*
* Definitions which augment the buffer_head layer
*/
/* journaling buffer types */
#define BJ_None 0 /* Not journaled */
#define BJ_SyncData 1 /* Normal data: flush before commit */
#define BJ_AsyncData 2 /* writepage data: wait on it before commit */
#define BJ_Metadata 3 /* Normal journaled metadata */
#define BJ_Forget 4 /* Buffer superceded by this transaction */
#define BJ_IO 5 /* Buffer is for temporary IO use */
#define BJ_Shadow 6 /* Buffer contents being shadowed to the log */
#define BJ_LogCtl 7 /* Buffer contains log descriptors */
#define BJ_Reserved 8 /* Buffer is reserved for access by journal */
#define BJ_Types 9
extern int jbd_blocks_per_page(struct inode *inode);
#ifdef __KERNEL__
extern spinlock_t jh_splice_lock;
/*
* Once `expr1' has been found true, take jh_splice_lock
* and then reevaluate everything.
*/
#define SPLICE_LOCK(expr1, expr2) \
({ \
int ret = (expr1); \
if (ret) { \
spin_lock(&jh_splice_lock); \
ret = (expr1) && (expr2); \
spin_unlock(&jh_splice_lock); \
} \
ret; \
})
/*
* A number of buffer state predicates. They test for
* buffer_jbd() because they are used in core kernel code.
*
* These will be racy on SMP unless we're *sure* that the
* buffer won't be detached from the journalling system
* in parallel.
*/
/* Return true if the buffer is on journal list `list' */
static inline int buffer_jlist_eq(struct buffer_head *bh, int list)
{
return SPLICE_LOCK(buffer_jbd(bh), bh2jh(bh)->b_jlist == list);
}
/* Return true if this bufer is dirty wrt the journal */
static inline int buffer_jdirty(struct buffer_head *bh)
{
return buffer_jbd(bh) && __buffer_state(bh, JBDDirty);
}
/* Return true if it's a data buffer which journalling is managing */
static inline int buffer_jbd_data(struct buffer_head *bh)
{
return SPLICE_LOCK(buffer_jbd(bh),
bh2jh(bh)->b_jlist == BJ_SyncData ||
bh2jh(bh)->b_jlist == BJ_AsyncData);
}
#ifdef CONFIG_SMP
#define assert_spin_locked(lock) J_ASSERT(spin_is_locked(lock))
#else
#define assert_spin_locked(lock) do {} while(0)
#endif
#define buffer_trace_init(bh) do {} while (0)
#define print_buffer_fields(bh) do {} while (0)
#define print_buffer_trace(bh) do {} while (0)
#define BUFFER_TRACE(bh, info) do {} while (0)
#define BUFFER_TRACE2(bh, bh2, info) do {} while (0)
#define JBUFFER_TRACE(jh, info) do {} while (0)
#endif /* __KERNEL__ */
#endif /* CONFIG_JBD || CONFIG_JBD_MODULE || !__KERNEL__ */
/*
* Compatibility no-ops which allow the kernel to compile without CONFIG_JBD
* go here.
*/
#if defined(__KERNEL__) && !(defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE))
#define J_ASSERT(expr) do {} while (0)
#define J_ASSERT_BH(bh, expr) do {} while (0)
#define buffer_jbd(bh) 0
#define buffer_jlist_eq(bh, val) 0
#define journal_buffer_journal_lru(bh) 0
#endif /* defined(__KERNEL__) && !defined(CONFIG_JBD) */
#endif /* _LINUX_JBD_H */

View File

@ -0,0 +1,112 @@
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = { &name, &name }
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
#if (!defined(__GNUC__) && !defined(__WATCOMC__))
#define __inline__
#endif
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head * new,
struct list_head * prev,
struct list_head * next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/*
* Insert a new entry after the specified head..
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/*
* Insert a new entry at the tail
*/
static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head * prev,
struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
/*
* Splice in "list" into "head"
*/
static __inline__ void list_splice(struct list_head *list, struct list_head *head)
{
struct list_head *first = list->next;
if (first != list) {
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
}
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#endif

134
e2fsprogs/ext2fs/link.c Normal file
View File

@ -0,0 +1,134 @@
/*
* link.c --- create links in a ext2fs directory
*
* Copyright (C) 1993, 1994 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
struct link_struct {
const char *name;
int namelen;
ext2_ino_t inode;
int flags;
int done;
struct ext2_super_block *sb;
};
static int link_proc(struct ext2_dir_entry *dirent,
int offset,
int blocksize,
char *buf,
void *priv_data)
{
struct link_struct *ls = (struct link_struct *) priv_data;
struct ext2_dir_entry *next;
int rec_len, min_rec_len;
int ret = 0;
rec_len = EXT2_DIR_REC_LEN(ls->namelen);
/*
* See if the following directory entry (if any) is unused;
* if so, absorb it into this one.
*/
next = (struct ext2_dir_entry *) (buf + offset + dirent->rec_len);
if ((offset + dirent->rec_len < blocksize - 8) &&
(next->inode == 0) &&
(offset + dirent->rec_len + next->rec_len <= blocksize)) {
dirent->rec_len += next->rec_len;
ret = DIRENT_CHANGED;
}
/*
* If the directory entry is used, see if we can split the
* directory entry to make room for the new name. If so,
* truncate it and return.
*/
if (dirent->inode) {
min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
if (dirent->rec_len < (min_rec_len + rec_len))
return ret;
rec_len = dirent->rec_len - min_rec_len;
dirent->rec_len = min_rec_len;
next = (struct ext2_dir_entry *) (buf + offset +
dirent->rec_len);
next->inode = 0;
next->name_len = 0;
next->rec_len = rec_len;
return DIRENT_CHANGED;
}
/*
* If we get this far, then the directory entry is not used.
* See if we can fit the request entry in. If so, do it.
*/
if (dirent->rec_len < rec_len)
return ret;
dirent->inode = ls->inode;
dirent->name_len = ls->namelen;
strncpy(dirent->name, ls->name, ls->namelen);
if (ls->sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
dirent->name_len |= (ls->flags & 0x7) << 8;
ls->done++;
return DIRENT_ABORT|DIRENT_CHANGED;
}
/*
* Note: the low 3 bits of the flags field are used as the directory
* entry filetype.
*/
#ifdef __TURBOC__
#pragma argsused
#endif
errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
ext2_ino_t ino, int flags)
{
errcode_t retval;
struct link_struct ls;
struct ext2_inode inode;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (!(fs->flags & EXT2_FLAG_RW))
return EXT2_ET_RO_FILSYS;
ls.name = name;
ls.namelen = name ? strlen(name) : 0;
ls.inode = ino;
ls.flags = flags;
ls.done = 0;
ls.sb = fs->super;
retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
0, link_proc, &ls);
if (retval)
return retval;
if (!ls.done)
return EXT2_ET_DIR_NO_SPACE;
if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0)
return retval;
if (inode.i_flags & EXT2_INDEX_FL) {
inode.i_flags &= ~EXT2_INDEX_FL;
if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0)
return retval;
}
return 0;
}

135
e2fsprogs/ext2fs/llseek.c Normal file
View File

@ -0,0 +1,135 @@
/*
* llseek.c -- stub calling the llseek system call
*
* Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef __MSDOS__
#include <io.h>
#endif
#include "et/com_err.h"
#include "ext2fs/ext2_io.h"
#ifdef __linux__
#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
#define my_llseek lseek64
#else
#if defined(HAVE_LLSEEK)
#include <syscall.h>
#ifndef HAVE_LLSEEK_PROTOTYPE
extern long long llseek (int fd, long long offset, int origin);
#endif
#define my_llseek llseek
#else /* ! HAVE_LLSEEK */
#if defined(__alpha__) || defined (__ia64__)
#define llseek lseek
#else /* !__alpha__ && !__ia64__*/
#include <linux/unistd.h>
#ifndef __NR__llseek
#define __NR__llseek 140
#endif
#ifndef __i386__
static int _llseek (unsigned int, unsigned long,
unsigned long, ext2_loff_t *, unsigned int);
static _syscall5(int,_llseek,unsigned int,fd,unsigned long,offset_high,
unsigned long, offset_low,ext2_loff_t *,result,
unsigned int, origin)
#endif
static ext2_loff_t my_llseek (int fd, ext2_loff_t offset, int origin)
{
ext2_loff_t result;
int retval;
#ifndef __i386__
retval = _llseek(fd, ((unsigned long long) offset) >> 32,
#else
retval = syscall(__NR__llseek, fd, (unsigned long long) (offset >> 32),
#endif
((unsigned long long) offset) & 0xffffffff,
&result, origin);
return (retval == -1 ? (ext2_loff_t) retval : result);
}
#endif /* __alpha__ || __ia64__ */
#endif /* HAVE_LLSEEK */
#endif /* defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) */
ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin)
{
ext2_loff_t result;
static int do_compat = 0;
if ((sizeof(off_t) >= sizeof(ext2_loff_t)) ||
(offset < ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1))))
return lseek(fd, (off_t) offset, origin);
if (do_compat) {
errno = EINVAL;
return -1;
}
result = my_llseek (fd, offset, origin);
if (result == -1 && errno == ENOSYS) {
/*
* Just in case this code runs on top of an old kernel
* which does not support the llseek system call
*/
do_compat++;
errno = EINVAL;
}
return result;
}
#else /* !linux */
#ifndef EINVAL
#define EINVAL EXT2_ET_INVALID_ARGUMENT
#endif
ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin)
{
#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
return lseek64 (fd, offset, origin);
#else
if ((sizeof(off_t) < sizeof(ext2_loff_t)) &&
(offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) {
errno = EINVAL;
return -1;
}
return lseek (fd, (off_t) offset, origin);
#endif
}
#endif /* linux */

69
e2fsprogs/ext2fs/lookup.c Normal file
View File

@ -0,0 +1,69 @@
/*
* lookup.c --- ext2fs directory lookup operations
*
* Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
struct lookup_struct {
const char *name;
int len;
ext2_ino_t *inode;
int found;
};
#ifdef __TURBOC__
#pragma argsused
#endif
static int lookup_proc(struct ext2_dir_entry *dirent,
int offset EXT2FS_ATTR((unused)),
int blocksize EXT2FS_ATTR((unused)),
char *buf EXT2FS_ATTR((unused)),
void *priv_data)
{
struct lookup_struct *ls = (struct lookup_struct *) priv_data;
if (ls->len != (dirent->name_len & 0xFF))
return 0;
if (strncmp(ls->name, dirent->name, (dirent->name_len & 0xFF)))
return 0;
*ls->inode = dirent->inode;
ls->found++;
return DIRENT_ABORT;
}
errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name,
int namelen, char *buf, ext2_ino_t *inode)
{
errcode_t retval;
struct lookup_struct ls;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
ls.name = name;
ls.len = namelen;
ls.inode = inode;
ls.found = 0;
retval = ext2fs_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls);
if (retval)
return retval;
return (ls.found) ? 0 : EXT2_ET_FILE_NOT_FOUND;
}

142
e2fsprogs/ext2fs/mkdir.c Normal file
View File

@ -0,0 +1,142 @@
/*
* mkdir.c --- make a directory in the filesystem
*
* Copyright (C) 1994, 1995 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
#ifndef EXT2_FT_DIR
#define EXT2_FT_DIR 2
#endif
errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
const char *name)
{
errcode_t retval;
struct ext2_inode parent_inode, inode;
ext2_ino_t ino = inum;
ext2_ino_t scratch_ino;
blk_t blk;
char *block = 0;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
/*
* Allocate an inode, if necessary
*/
if (!ino) {
retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755,
0, &ino);
if (retval)
goto cleanup;
}
/*
* Allocate a data block for the directory
*/
retval = ext2fs_new_block(fs, 0, 0, &blk);
if (retval)
goto cleanup;
/*
* Create a scratch template for the directory
*/
retval = ext2fs_new_dir_block(fs, ino, parent, &block);
if (retval)
goto cleanup;
/*
* Get the parent's inode, if necessary
*/
if (parent != ino) {
retval = ext2fs_read_inode(fs, parent, &parent_inode);
if (retval)
goto cleanup;
} else
memset(&parent_inode, 0, sizeof(parent_inode));
/*
* Create the inode structure....
*/
memset(&inode, 0, sizeof(struct ext2_inode));
inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
inode.i_uid = inode.i_gid = 0;
inode.i_blocks = fs->blocksize / 512;
inode.i_block[0] = blk;
inode.i_links_count = 2;
inode.i_ctime = inode.i_atime = inode.i_mtime = time(NULL);
inode.i_size = fs->blocksize;
/*
* Write out the inode and inode data block
*/
retval = ext2fs_write_dir_block(fs, blk, block);
if (retval)
goto cleanup;
retval = ext2fs_write_new_inode(fs, ino, &inode);
if (retval)
goto cleanup;
/*
* Link the directory into the filesystem hierarchy
*/
if (name) {
retval = ext2fs_lookup(fs, parent, name, strlen(name), 0,
&scratch_ino);
if (!retval) {
retval = EXT2_ET_DIR_EXISTS;
name = 0;
goto cleanup;
}
if (retval != EXT2_ET_FILE_NOT_FOUND)
goto cleanup;
retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR);
if (retval)
goto cleanup;
}
/*
* Update parent inode's counts
*/
if (parent != ino) {
parent_inode.i_links_count++;
retval = ext2fs_write_inode(fs, parent, &parent_inode);
if (retval)
goto cleanup;
}
/*
* Update accounting....
*/
ext2fs_block_alloc_stats(fs, blk, +1);
ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
cleanup:
if (block)
ext2fs_free_mem(&block);
return retval;
}

View File

@ -0,0 +1,425 @@
/*
* mkjournal.c --- make a journal for a filesystem
*
* Copyright (C) 2000 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include "ext2_fs.h"
#include "e2p/e2p.h"
#include "ext2fs.h"
#include "jfs_user.h"
/*
* This function automatically sets up the journal superblock and
* returns it as an allocated block.
*/
errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
__u32 size, int flags,
char **ret_jsb)
{
errcode_t retval;
journal_superblock_t *jsb;
if (size < 1024)
return EXT2_ET_JOURNAL_TOO_SMALL;
if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
return retval;
memset (jsb, 0, fs->blocksize);
jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
if (flags & EXT2_MKJOURNAL_V1_SUPER)
jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
else
jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
jsb->s_blocksize = htonl(fs->blocksize);
jsb->s_maxlen = htonl(size);
jsb->s_nr_users = htonl(1);
jsb->s_first = htonl(1);
jsb->s_sequence = htonl(1);
memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
/*
* If we're creating an external journal device, we need to
* adjust these fields.
*/
if (fs->super->s_feature_incompat &
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
jsb->s_nr_users = 0;
if (fs->blocksize == 1024)
jsb->s_first = htonl(3);
else
jsb->s_first = htonl(2);
}
*ret_jsb = (char *) jsb;
return 0;
}
/*
* This function writes a journal using POSIX routines. It is used
* for creating external journals and creating journals on live
* filesystems.
*/
static errcode_t write_journal_file(ext2_filsys fs, char *filename,
blk_t size, int flags)
{
errcode_t retval;
char *buf = 0;
int fd, ret_size;
blk_t i;
if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
return retval;
/* Open the device or journal file */
if ((fd = open(filename, O_WRONLY)) < 0) {
retval = errno;
goto errout;
}
/* Write the superblock out */
retval = EXT2_ET_SHORT_WRITE;
ret_size = write(fd, buf, fs->blocksize);
if (ret_size < 0) {
retval = errno;
goto errout;
}
if (ret_size != (int) fs->blocksize)
goto errout;
memset(buf, 0, fs->blocksize);
for (i = 1; i < size; i++) {
ret_size = write(fd, buf, fs->blocksize);
if (ret_size < 0) {
retval = errno;
goto errout;
}
if (ret_size != (int) fs->blocksize)
goto errout;
}
close(fd);
retval = 0;
errout:
ext2fs_free_mem(&buf);
return retval;
}
/*
* Helper function for creating the journal using direct I/O routines
*/
struct mkjournal_struct {
int num_blocks;
int newblocks;
char *buf;
errcode_t err;
};
static int mkjournal_proc(ext2_filsys fs,
blk_t *blocknr,
e2_blkcnt_t blockcnt,
blk_t ref_block EXT2FS_ATTR((unused)),
int ref_offset EXT2FS_ATTR((unused)),
void *priv_data)
{
struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
blk_t new_blk;
static blk_t last_blk = 0;
errcode_t retval;
if (*blocknr) {
last_blk = *blocknr;
return 0;
}
retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
if (retval) {
es->err = retval;
return BLOCK_ABORT;
}
if (blockcnt > 0)
es->num_blocks--;
es->newblocks++;
retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
if (blockcnt == 0)
memset(es->buf, 0, fs->blocksize);
if (retval) {
es->err = retval;
return BLOCK_ABORT;
}
*blocknr = new_blk;
last_blk = new_blk;
ext2fs_block_alloc_stats(fs, new_blk, +1);
if (es->num_blocks == 0)
return (BLOCK_CHANGED | BLOCK_ABORT);
else
return BLOCK_CHANGED;
}
/*
* This function creates a journal using direct I/O routines.
*/
static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
blk_t size, int flags)
{
char *buf;
errcode_t retval;
struct ext2_inode inode;
struct mkjournal_struct es;
if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
return retval;
if ((retval = ext2fs_read_bitmaps(fs)))
return retval;
if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
return retval;
if (inode.i_blocks > 0)
return EEXIST;
es.num_blocks = size;
es.newblocks = 0;
es.buf = buf;
es.err = 0;
retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
0, mkjournal_proc, &es);
if (es.err) {
retval = es.err;
goto errout;
}
if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
goto errout;
inode.i_size += fs->blocksize * size;
inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
inode.i_mtime = inode.i_ctime = time(0);
inode.i_links_count = 1;
inode.i_mode = LINUX_S_IFREG | 0600;
if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
goto errout;
retval = 0;
memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
fs->super->s_jnl_blocks[16] = inode.i_size;
fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
ext2fs_mark_super_dirty(fs);
errout:
ext2fs_free_mem(&buf);
return retval;
}
/*
* This function adds a journal device to a filesystem
*/
errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
{
struct stat st;
errcode_t retval;
char buf[1024];
journal_superblock_t *jsb;
int start;
__u32 i, nr_users;
/* Make sure the device exists and is a block device */
if (stat(journal_dev->device_name, &st) < 0)
return errno;
if (!S_ISBLK(st.st_mode))
return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
/* Get the journal superblock */
start = 1;
if (journal_dev->blocksize == 1024)
start++;
if ((retval = io_channel_read_blk(journal_dev->io, start, -1024, buf)))
return retval;
jsb = (journal_superblock_t *) buf;
if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
(jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
return EXT2_ET_NO_JOURNAL_SB;
if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize)
return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
/* Check and see if this filesystem has already been added */
nr_users = ntohl(jsb->s_nr_users);
for (i=0; i < nr_users; i++) {
if (memcmp(fs->super->s_uuid,
&jsb->s_users[i*16], 16) == 0)
break;
}
if (i >= nr_users) {
memcpy(&jsb->s_users[nr_users*16],
fs->super->s_uuid, 16);
jsb->s_nr_users = htonl(nr_users+1);
}
/* Writeback the journal superblock */
if ((retval = io_channel_write_blk(journal_dev->io, start, -1024, buf)))
return retval;
fs->super->s_journal_inum = 0;
fs->super->s_journal_dev = st.st_rdev;
memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
sizeof(fs->super->s_journal_uuid));
fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
ext2fs_mark_super_dirty(fs);
return 0;
}
/*
* This function adds a journal inode to a filesystem, using either
* POSIX routines if the filesystem is mounted, or using direct I/O
* functions if it is not.
*/
errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
{
errcode_t retval;
ext2_ino_t journal_ino;
struct stat st;
char jfile[1024];
int fd, mount_flags, f;
if ((retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
jfile, sizeof(jfile)-10)))
return retval;
if (mount_flags & EXT2_MF_MOUNTED) {
strcat(jfile, "/.journal");
/*
* If .../.journal already exists, make sure any
* immutable or append-only flags are cleared.
*/
#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
(void) chflags (jfile, 0);
#else
#if HAVE_EXT2_IOCTLS
fd = open(jfile, O_RDONLY);
if (fd >= 0) {
f = 0;
ioctl(fd, EXT2_IOC_SETFLAGS, &f);
close(fd);
}
#endif
#endif
/* Create the journal file */
if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
return errno;
if ((retval = write_journal_file(fs, jfile, size, flags)))
goto errout;
/* Get inode number of the journal file */
if (fstat(fd, &st) < 0)
goto errout;
#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
#else
#if HAVE_EXT2_IOCTLS
f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;
retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
#endif
#endif
if (retval)
goto errout;
close(fd);
journal_ino = st.st_ino;
} else {
journal_ino = EXT2_JOURNAL_INO;
if ((retval = write_journal_inode(fs, journal_ino,
size, flags)))
return retval;
}
fs->super->s_journal_inum = journal_ino;
fs->super->s_journal_dev = 0;
memset(fs->super->s_journal_uuid, 0,
sizeof(fs->super->s_journal_uuid));
fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
ext2fs_mark_super_dirty(fs);
return 0;
errout:
close(fd);
return retval;
}
#ifdef DEBUG
main(int argc, char **argv)
{
errcode_t retval;
char *device_name;
ext2_filsys fs;
if (argc < 2) {
fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
exit(1);
}
device_name = argv[1];
retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
unix_io_manager, &fs);
if (retval) {
com_err(argv[0], retval, "while opening %s", device_name);
exit(1);
}
retval = ext2fs_add_journal_inode(fs, 1024);
if (retval) {
com_err(argv[0], retval, "while adding journal to %s",
device_name);
exit(1);
}
retval = ext2fs_flush(fs);
if (retval) {
printf("Warning, had trouble writing out superblocks.\n");
}
ext2fs_close(fs);
exit(0);
}
#endif

205
e2fsprogs/ext2fs/namei.c Normal file
View File

@ -0,0 +1,205 @@
/*
* namei.c --- ext2fs directory lookup operations
*
* Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
/* #define NAMEI_DEBUG */
#include "ext2_fs.h"
#include "ext2fs.h"
static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
const char *pathname, size_t pathlen, int follow,
int link_count, char *buf, ext2_ino_t *res_inode);
static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
ext2_ino_t inode, int link_count,
char *buf, ext2_ino_t *res_inode)
{
char *pathname;
char *buffer = 0;
errcode_t retval;
struct ext2_inode ei;
#ifdef NAMEI_DEBUG
printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n",
root, dir, inode, link_count);
#endif
retval = ext2fs_read_inode (fs, inode, &ei);
if (retval) return retval;
if (!LINUX_S_ISLNK (ei.i_mode)) {
*res_inode = inode;
return 0;
}
if (link_count++ > 5) {
return EXT2_ET_SYMLINK_LOOP;
}
if (ext2fs_inode_data_blocks(fs,&ei)) {
retval = ext2fs_get_mem(fs->blocksize, &buffer);
if (retval)
return retval;
retval = io_channel_read_blk(fs->io, ei.i_block[0], 1, buffer);
if (retval) {
ext2fs_free_mem(&buffer);
return retval;
}
pathname = buffer;
} else
pathname = (char *)&(ei.i_block[0]);
retval = open_namei(fs, root, dir, pathname, ei.i_size, 1,
link_count, buf, res_inode);
if (buffer)
ext2fs_free_mem(&buffer);
return retval;
}
/*
* This routine interprets a pathname in the context of the current
* directory and the root directory, and returns the inode of the
* containing directory, and a pointer to the filename of the file
* (pointing into the pathname) and the length of the filename.
*/
static errcode_t dir_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
const char *pathname, int pathlen,
int link_count, char *buf,
const char **name, int *namelen,
ext2_ino_t *res_inode)
{
char c;
const char *thisname;
int len;
ext2_ino_t inode;
errcode_t retval;
if ((c = *pathname) == '/') {
dir = root;
pathname++;
pathlen--;
}
while (1) {
thisname = pathname;
for (len=0; --pathlen >= 0;len++) {
c = *(pathname++);
if (c == '/')
break;
}
if (pathlen < 0)
break;
retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode);
if (retval) return retval;
retval = follow_link (fs, root, dir, inode,
link_count, buf, &dir);
if (retval) return retval;
}
*name = thisname;
*namelen = len;
*res_inode = dir;
return 0;
}
static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
const char *pathname, size_t pathlen, int follow,
int link_count, char *buf, ext2_ino_t *res_inode)
{
const char *basename;
int namelen;
ext2_ino_t dir, inode;
errcode_t retval;
#ifdef NAMEI_DEBUG
printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n",
root, base, pathlen, pathname, link_count);
#endif
retval = dir_namei(fs, root, base, pathname, pathlen,
link_count, buf, &basename, &namelen, &dir);
if (retval) return retval;
if (!namelen) { /* special case: '/usr/' etc */
*res_inode=dir;
return 0;
}
retval = ext2fs_lookup (fs, dir, basename, namelen, buf, &inode);
if (retval)
return retval;
if (follow) {
retval = follow_link(fs, root, dir, inode, link_count,
buf, &inode);
if (retval)
return retval;
}
#ifdef NAMEI_DEBUG
printf("open_namei: (link_count=%d) returns %lu\n",
link_count, inode);
#endif
*res_inode = inode;
return 0;
}
errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
const char *name, ext2_ino_t *inode)
{
char *buf;
errcode_t retval;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
return retval;
retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0,
buf, inode);
ext2fs_free_mem(&buf);
return retval;
}
errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
const char *name, ext2_ino_t *inode)
{
char *buf;
errcode_t retval;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
return retval;
retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0,
buf, inode);
ext2fs_free_mem(&buf);
return retval;
}
errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
ext2_ino_t inode, ext2_ino_t *res_inode)
{
char *buf;
errcode_t retval;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
return retval;
retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode);
ext2fs_free_mem(&buf);
return retval;
}

27
e2fsprogs/ext2fs/native.c Normal file
View File

@ -0,0 +1,27 @@
/*
* native.c --- returns the ext2_flag for a native byte order
*
* Copyright (C) 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include "ext2_fs.h"
#include "ext2fs.h"
int ext2fs_native_flag(void)
{
#ifdef WORDS_BIGENDIAN
return EXT2_FLAG_SWAP_BYTES;
#else
return 0;
#endif
}

72
e2fsprogs/ext2fs/newdir.c Normal file
View File

@ -0,0 +1,72 @@
/*
* newdir.c --- create a new directory block
*
* Copyright (C) 1994, 1995 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
#ifndef EXT2_FT_DIR
#define EXT2_FT_DIR 2
#endif
/*
* Create new directory block
*/
errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
ext2_ino_t parent_ino, char **block)
{
struct ext2_dir_entry *dir = NULL;
errcode_t retval;
char *buf;
int rec_len;
int filetype = 0;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
return retval;
memset(buf, 0, fs->blocksize);
dir = (struct ext2_dir_entry *) buf;
dir->rec_len = fs->blocksize;
if (dir_ino) {
if (fs->super->s_feature_incompat &
EXT2_FEATURE_INCOMPAT_FILETYPE)
filetype = EXT2_FT_DIR << 8;
/*
* Set up entry for '.'
*/
dir->inode = dir_ino;
dir->name_len = 1 | filetype;
dir->name[0] = '.';
rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1);
dir->rec_len = EXT2_DIR_REC_LEN(1);
/*
* Set up entry for '..'
*/
dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
dir->rec_len = rec_len;
dir->inode = parent_ino;
dir->name_len = 2 | filetype;
dir->name[0] = '.';
dir->name[1] = '.';
}
*block = buf;
return 0;
}

326
e2fsprogs/ext2fs/openfs.c Normal file
View File

@ -0,0 +1,326 @@
/*
* openfs.c --- open an ext2 filesystem
*
* Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
#include "e2image.h"
blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i)
{
int bg;
int has_super = 0;
int ret_blk;
if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
(i < fs->super->s_first_meta_bg))
return (group_block + i + 1);
bg = (fs->blocksize / sizeof (struct ext2_group_desc)) * i;
if (ext2fs_bg_has_super(fs, bg))
has_super = 1;
ret_blk = (fs->super->s_first_data_block + has_super +
(bg * fs->super->s_blocks_per_group));
/*
* If group_block is not the normal value, we're trying to use
* the backup group descriptors and superblock --- so use the
* alternate location of the second block group in the
* metablock group. Ideally we should be testing each bg
* descriptor block individually for correctness, but we don't
* have the infrastructure in place to do that.
*/
if (group_block != fs->super->s_first_data_block &&
((ret_blk + fs->super->s_blocks_per_group) <
fs->super->s_blocks_count))
ret_blk += fs->super->s_blocks_per_group;
return ret_blk;
}
errcode_t ext2fs_open(const char *name, int flags, int superblock,
unsigned int block_size, io_manager manager,
ext2_filsys *ret_fs)
{
return ext2fs_open2(name, 0, flags, superblock, block_size,
manager, ret_fs);
}
/*
* Note: if superblock is non-zero, block-size must also be non-zero.
* Superblock and block_size can be zero to use the default size.
*
* Valid flags for ext2fs_open()
*
* EXT2_FLAG_RW - Open the filesystem for read/write.
* EXT2_FLAG_FORCE - Open the filesystem even if some of the
* features aren't supported.
* EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
*/
errcode_t ext2fs_open2(const char *name, const char *io_options,
int flags, int superblock,
unsigned int block_size, io_manager manager,
ext2_filsys *ret_fs)
{
ext2_filsys fs;
errcode_t retval;
unsigned long i;
int j, groups_per_block, blocks_per_group;
blk_t group_block, blk;
char *dest, *cp;
struct ext2_group_desc *gdp;
EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
if (retval)
return retval;
memset(fs, 0, sizeof(struct struct_ext2_filsys));
fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
fs->flags = flags;
fs->umask = 022;
retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
if (retval)
goto cleanup;
strcpy(fs->device_name, name);
cp = strchr(fs->device_name, '?');
if (!io_options && cp) {
*cp++ = 0;
io_options = cp;
}
retval = manager->open(fs->device_name,
(flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0,
&fs->io);
if (retval)
goto cleanup;
if (io_options &&
(retval = io_channel_set_options(fs->io, io_options)))
goto cleanup;
fs->image_io = fs->io;
fs->io->app_data = fs;
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
if (retval)
goto cleanup;
if (flags & EXT2_FLAG_IMAGE_FILE) {
retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr),
&fs->image_header);
if (retval)
goto cleanup;
retval = io_channel_read_blk(fs->io, 0,
-(int)sizeof(struct ext2_image_hdr),
fs->image_header);
if (retval)
goto cleanup;
if (fs->image_header->magic_number != EXT2_ET_MAGIC_E2IMAGE)
return EXT2_ET_MAGIC_E2IMAGE;
superblock = 1;
block_size = fs->image_header->fs_blocksize;
}
/*
* If the user specifies a specific block # for the
* superblock, then he/she must also specify the block size!
* Otherwise, read the master superblock located at offset
* SUPERBLOCK_OFFSET from the start of the partition.
*
* Note: we only save a backup copy of the superblock if we
* are reading the superblock from the primary superblock location.
*/
if (superblock) {
if (!block_size) {
retval = EXT2_ET_INVALID_ARGUMENT;
goto cleanup;
}
io_channel_set_blksize(fs->io, block_size);
group_block = superblock;
fs->orig_super = 0;
} else {
io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
superblock = 1;
group_block = 0;
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
if (retval)
goto cleanup;
}
retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
fs->super);
if (retval)
goto cleanup;
if (fs->orig_super)
memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
#ifdef EXT2FS_ENABLE_SWAPFS
if ((fs->super->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES)) {
fs->flags |= EXT2_FLAG_SWAP_BYTES;
ext2fs_swap_super(fs->super);
}
#endif
if (fs->super->s_magic != EXT2_SUPER_MAGIC) {
retval = EXT2_ET_BAD_MAGIC;
goto cleanup;
}
if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) {
retval = EXT2_ET_REV_TOO_HIGH;
goto cleanup;
}
/*
* Check for feature set incompatibility
*/
if (!(flags & EXT2_FLAG_FORCE)) {
if (fs->super->s_feature_incompat &
~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
retval = EXT2_ET_UNSUPP_FEATURE;
goto cleanup;
}
if ((flags & EXT2_FLAG_RW) &&
(fs->super->s_feature_ro_compat &
~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
retval = EXT2_ET_RO_UNSUPP_FEATURE;
goto cleanup;
}
if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) &&
(fs->super->s_feature_incompat &
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
retval = EXT2_ET_UNSUPP_FEATURE;
goto cleanup;
}
}
fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
if (fs->blocksize == 0) {
retval = EXT2_ET_CORRUPT_SUPERBLOCK;
goto cleanup;
}
fs->fragsize = EXT2_FRAG_SIZE(fs->super);
fs->inode_blocks_per_group = ((fs->super->s_inodes_per_group *
EXT2_INODE_SIZE(fs->super) +
EXT2_BLOCK_SIZE(fs->super) - 1) /
EXT2_BLOCK_SIZE(fs->super));
if (block_size) {
if (block_size != fs->blocksize) {
retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE;
goto cleanup;
}
}
/*
* Set the blocksize to the filesystem's blocksize.
*/
io_channel_set_blksize(fs->io, fs->blocksize);
/*
* If this is an external journal device, don't try to read
* the group descriptors, because they're not there.
*/
if (fs->super->s_feature_incompat &
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
fs->group_desc_count = 0;
*ret_fs = fs;
return 0;
}
/*
* Read group descriptors
*/
blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super);
if (blocks_per_group == 0 ||
blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) ||
fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super)) {
retval = EXT2_ET_CORRUPT_SUPERBLOCK;
goto cleanup;
}
fs->group_desc_count = (fs->super->s_blocks_count -
fs->super->s_first_data_block +
blocks_per_group - 1) / blocks_per_group;
fs->desc_blocks = (fs->group_desc_count +
EXT2_DESC_PER_BLOCK(fs->super) - 1)
/ EXT2_DESC_PER_BLOCK(fs->super);
retval = ext2fs_get_mem(fs->desc_blocks * fs->blocksize,
&fs->group_desc);
if (retval)
goto cleanup;
if (!group_block)
group_block = fs->super->s_first_data_block;
dest = (char *) fs->group_desc;
groups_per_block = fs->blocksize / sizeof(struct ext2_group_desc);
for (i=0 ; i < fs->desc_blocks; i++) {
blk = ext2fs_descriptor_block_loc(fs, group_block, i);
retval = io_channel_read_blk(fs->io, blk, 1, dest);
if (retval)
goto cleanup;
#ifdef EXT2FS_ENABLE_SWAPFS
if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
gdp = (struct ext2_group_desc *) dest;
for (j=0; j < groups_per_block; j++)
ext2fs_swap_group_desc(gdp++);
}
#endif
dest += fs->blocksize;
}
*ret_fs = fs;
return 0;
cleanup:
ext2fs_free(fs);
return retval;
}
/*
* Set/get the filesystem data I/O channel.
*
* These functions are only valid if EXT2_FLAG_IMAGE_FILE is true.
*/
errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io)
{
if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
return EXT2_ET_NOT_IMAGE_FILE;
if (old_io) {
*old_io = (fs->image_io == fs->io) ? 0 : fs->io;
}
return 0;
}
errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io)
{
if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
return EXT2_ET_NOT_IMAGE_FILE;
fs->io = new_io ? new_io : fs->image_io;
return 0;
}
errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io)
{
if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
return EXT2_ET_NOT_IMAGE_FILE;
fs->io = fs->image_io = new_io;
fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW |
EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
fs->flags &= ~EXT2_FLAG_IMAGE_FILE;
return 0;
}

View File

@ -0,0 +1,97 @@
/*
* read_bb --- read the bad blocks inode
*
* Copyright (C) 1994 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
struct read_bb_record {
ext2_badblocks_list bb_list;
errcode_t err;
};
/*
* Helper function for ext2fs_read_bb_inode()
*/
#ifdef __TURBOC__
#pragma argsused
#endif
static int mark_bad_block(ext2_filsys fs, blk_t *block_nr,
e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
blk_t ref_block EXT2FS_ATTR((unused)),
int ref_offset EXT2FS_ATTR((unused)),
void *priv_data)
{
struct read_bb_record *rb = (struct read_bb_record *) priv_data;
if (blockcnt < 0)
return 0;
if ((*block_nr < fs->super->s_first_data_block) ||
(*block_nr >= fs->super->s_blocks_count))
return 0; /* Ignore illegal blocks */
rb->err = ext2fs_badblocks_list_add(rb->bb_list, *block_nr);
if (rb->err)
return BLOCK_ABORT;
return 0;
}
/*
* Reads the current bad blocks from the bad blocks inode.
*/
errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list)
{
errcode_t retval;
struct read_bb_record rb;
struct ext2_inode inode;
blk_t numblocks;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (!*bb_list) {
retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
if (retval)
return retval;
if (inode.i_blocks < 500)
numblocks = (inode.i_blocks /
(fs->blocksize / 512)) + 20;
else
numblocks = 500;
retval = ext2fs_badblocks_list_create(bb_list, numblocks);
if (retval)
return retval;
}
rb.bb_list = *bb_list;
rb.err = 0;
retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, 0, 0,
mark_bad_block, &rb);
if (retval)
return retval;
return rb.err;
}

View File

@ -0,0 +1,97 @@
/*
* read_bb_file.c --- read a list of bad blocks from a FILE *
*
* Copyright (C) 1994, 1995, 2000 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
/*
* Reads a list of bad blocks from a FILE *
*/
errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f,
ext2_badblocks_list *bb_list,
void *priv_data,
void (*invalid)(ext2_filsys fs,
blk_t blk,
char *badstr,
void *priv_data))
{
errcode_t retval;
blk_t blockno;
int count;
char buf[128];
if (fs)
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (!*bb_list) {
retval = ext2fs_badblocks_list_create(bb_list, 10);
if (retval)
return retval;
}
while (!feof (f)) {
if (fgets(buf, sizeof(buf), f) == NULL)
break;
count = sscanf(buf, "%u", &blockno);
if (count <= 0)
continue;
if (fs &&
((blockno < fs->super->s_first_data_block) ||
(blockno >= fs->super->s_blocks_count))) {
if (invalid)
(invalid)(fs, blockno, buf, priv_data);
continue;
}
retval = ext2fs_badblocks_list_add(*bb_list, blockno);
if (retval)
return retval;
}
return 0;
}
static void call_compat_invalid(ext2_filsys fs, blk_t blk,
char *badstr EXT2FS_ATTR((unused)),
void *priv_data)
{
void (*invalid)(ext2_filsys, blk_t);
invalid = (void (*)(ext2_filsys, blk_t)) priv_data;
if (invalid)
invalid(fs, blk);
}
/*
* Reads a list of bad blocks from a FILE *
*/
errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f,
ext2_badblocks_list *bb_list,
void (*invalid)(ext2_filsys fs, blk_t blk))
{
return ext2fs_read_bb_FILE2(fs, f, bb_list, (void *) invalid,
call_compat_invalid);
}

220
e2fsprogs/ext2fs/res_gdt.c Normal file
View File

@ -0,0 +1,220 @@
/*
* res_gdt.c --- reserve blocks for growing the group descriptor table
* during online resizing.
*
* Copyright (C) 2002 Andreas Dilger
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "ext2_fs.h"
#include "ext2fs.h"
/*
* Iterate through the groups which hold BACKUP superblock/GDT copies in an
* ext3 filesystem. The counters should be initialized to 1, 5, and 7 before
* calling this for the first time. In a sparse filesystem it will be the
* sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
* For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
*/
static unsigned int list_backups(ext2_filsys fs, unsigned int *three,
unsigned int *five, unsigned int *seven)
{
unsigned int *min = three;
int mult = 3;
unsigned int ret;
if (!(fs->super->s_feature_ro_compat &
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
ret = *min;
*min += 1;
return ret;
}
if (*five < *min) {
min = five;
mult = 5;
}
if (*seven < *min) {
min = seven;
mult = 7;
}
ret = *min;
*min *= mult;
return ret;
}
/*
* This code assumes that the reserved blocks have already been marked in-use
* during ext2fs_initialize(), so that they are not allocated for other
* uses before we can add them to the resize inode (which has to come
* after the creation of the inode table).
*/
errcode_t ext2fs_create_resize_inode(ext2_filsys fs)
{
errcode_t retval, retval2;
struct ext2_super_block *sb;
struct ext2_inode inode;
__u32 *dindir_buf, *gdt_buf;
int rsv_add;
unsigned long long apb, inode_size;
blk_t dindir_blk, rsv_off, gdt_off, gdt_blk;
int dindir_dirty = 0, inode_dirty = 0;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
sb = fs->super;
retval = ext2fs_get_mem(2 * fs->blocksize, (void **)&dindir_buf);
if (retval)
goto out_free;
gdt_buf = (__u32 *)((char *)dindir_buf + fs->blocksize);
retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
if (retval)
goto out_free;
/* Maximum possible file size (we donly use the dindirect blocks) */
apb = EXT2_ADDR_PER_BLOCK(sb);
rsv_add = fs->blocksize / 512;
if ((dindir_blk = inode.i_block[EXT2_DIND_BLOCK])) {
#ifdef RES_GDT_DEBUG
printf("reading GDT dindir %u\n", dindir_blk);
#endif
retval = ext2fs_read_ind_block(fs, dindir_blk, dindir_buf);
if (retval)
goto out_inode;
} else {
blk_t goal = 3 + sb->s_reserved_gdt_blocks +
fs->desc_blocks + fs->inode_blocks_per_group;
retval = ext2fs_alloc_block(fs, goal, 0, &dindir_blk);
if (retval)
goto out_free;
inode.i_mode = LINUX_S_IFREG | 0600;
inode.i_links_count = 1;
inode.i_block[EXT2_DIND_BLOCK] = dindir_blk;
inode.i_blocks = rsv_add;
memset(dindir_buf, 0, fs->blocksize);
#ifdef RES_GDT_DEBUG
printf("allocated GDT dindir %u\n", dindir_blk);
#endif
dindir_dirty = inode_dirty = 1;
inode_size = apb*apb + apb + EXT2_NDIR_BLOCKS;
inode_size *= fs->blocksize;
inode.i_size = inode_size & 0xFFFFFFFF;
inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF;
if(inode.i_size_high) {
sb->s_feature_ro_compat |=
EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
}
inode.i_ctime = time(0);
}
for (rsv_off = 0, gdt_off = fs->desc_blocks,
gdt_blk = sb->s_first_data_block + 1 + fs->desc_blocks;
rsv_off < sb->s_reserved_gdt_blocks;
rsv_off++, gdt_off++, gdt_blk++) {
unsigned int three = 1, five = 5, seven = 7;
unsigned int grp, last = 0;
int gdt_dirty = 0;
gdt_off %= apb;
if (!dindir_buf[gdt_off]) {
/* FIXME XXX XXX
blk_t new_blk;
retval = ext2fs_new_block(fs, gdt_blk, 0, &new_blk);
if (retval)
goto out_free;
if (new_blk != gdt_blk) {
// XXX free block
retval = -1; // XXX
}
*/
gdt_dirty = dindir_dirty = inode_dirty = 1;
memset(gdt_buf, 0, fs->blocksize);
dindir_buf[gdt_off] = gdt_blk;
inode.i_blocks += rsv_add;
#ifdef RES_GDT_DEBUG
printf("added primary GDT block %u at %u[%u]\n",
gdt_blk, dindir_blk, gdt_off);
#endif
} else if (dindir_buf[gdt_off] == gdt_blk) {
#ifdef RES_GDT_DEBUG
printf("reading primary GDT block %u\n", gdt_blk);
#endif
retval = ext2fs_read_ind_block(fs, gdt_blk, gdt_buf);
if (retval)
goto out_dindir;
} else {
#ifdef RES_GDT_DEBUG
printf("bad primary GDT %u != %u at %u[%u]\n",
dindir_buf[gdt_off], gdt_blk,dindir_blk,gdt_off);
#endif
retval = EXT2_ET_RESIZE_INODE_CORRUPT;
goto out_dindir;
}
while ((grp = list_backups(fs, &three, &five, &seven)) <
fs->group_desc_count) {
blk_t expect = gdt_blk + grp * sb->s_blocks_per_group;
if (!gdt_buf[last]) {
#ifdef RES_GDT_DEBUG
printf("added backup GDT %u grp %u@%u[%u]\n",
expect, grp, gdt_blk, last);
#endif
gdt_buf[last] = expect;
inode.i_blocks += rsv_add;
gdt_dirty = inode_dirty = 1;
} else if (gdt_buf[last] != expect) {
#ifdef RES_GDT_DEBUG
printf("bad backup GDT %u != %u at %u[%u]\n",
gdt_buf[last], expect, gdt_blk, last);
#endif
retval = EXT2_ET_RESIZE_INODE_CORRUPT;
goto out_dindir;
}
last++;
}
if (gdt_dirty) {
#ifdef RES_GDT_DEBUG
printf("writing primary GDT block %u\n", gdt_blk);
#endif
retval = ext2fs_write_ind_block(fs, gdt_blk, gdt_buf);
if (retval)
goto out_dindir;
}
}
out_dindir:
if (dindir_dirty) {
retval2 = ext2fs_write_ind_block(fs, dindir_blk, dindir_buf);
if (!retval)
retval = retval2;
}
out_inode:
#ifdef RES_GDT_DEBUG
printf("inode.i_blocks = %u, i_size = %u\n", inode.i_blocks,
inode.i_size);
#endif
if (inode_dirty) {
inode.i_atime = inode.i_mtime = time(0);
retval2 = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
if (!retval)
retval = retval2;
}
out_free:
ext2fs_free_mem((void **)&dindir_buf);
return retval;
}

View File

@ -0,0 +1,106 @@
/*
* rs_bitmap.c --- routine for changing the size of a bitmap
*
* Copyright (C) 1996, 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
errcode_t ext2fs_resize_generic_bitmap(__u32 new_end, __u32 new_real_end,
ext2fs_generic_bitmap bmap)
{
errcode_t retval;
size_t size, new_size;
__u32 bitno;
if (!bmap)
return EXT2_ET_INVALID_ARGUMENT;
EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_GENERIC_BITMAP);
/*
* If we're expanding the bitmap, make sure all of the new
* parts of the bitmap are zero.
*/
if (new_end > bmap->end) {
bitno = bmap->real_end;
if (bitno > new_end)
bitno = new_end;
for (; bitno > bmap->end; bitno--)
ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap);
}
if (new_real_end == bmap->real_end) {
bmap->end = new_end;
return 0;
}
size = ((bmap->real_end - bmap->start) / 8) + 1;
new_size = ((new_real_end - bmap->start) / 8) + 1;
if (size != new_size) {
retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap);
if (retval)
return retval;
}
if (new_size > size)
memset(bmap->bitmap + size, 0, new_size - size);
bmap->end = new_end;
bmap->real_end = new_real_end;
return 0;
}
errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
ext2fs_inode_bitmap bmap)
{
errcode_t retval;
if (!bmap)
return EXT2_ET_INVALID_ARGUMENT;
EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_INODE_BITMAP);
bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
bmap);
bmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
return retval;
}
errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
ext2fs_block_bitmap bmap)
{
errcode_t retval;
if (!bmap)
return EXT2_ET_INVALID_ARGUMENT;
EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
bmap);
bmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
return retval;
}

View File

@ -0,0 +1,300 @@
/*
* rw_bitmaps.c --- routines to read and write the inode and block bitmaps.
*
* Copyright (C) 1993, 1994, 1994, 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
#include "e2image.h"
#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
/*
* On the PowerPC, the big-endian variant of the ext2 filesystem
* has its bitmaps stored as 32-bit words with bit 0 as the LSB
* of each word. Thus a bitmap with only bit 0 set would be, as
* a string of bytes, 00 00 00 01 00 ...
* To cope with this, we byte-reverse each word of a bitmap if
* we have a big-endian filesystem, that is, if we are *not*
* byte-swapping other word-sized numbers.
*/
#define EXT2_BIG_ENDIAN_BITMAPS
#endif
#ifdef EXT2_BIG_ENDIAN_BITMAPS
static void ext2fs_swap_bitmap(ext2_filsys fs, char *bitmap, int nbytes)
{
__u32 *p = (__u32 *) bitmap;
int n;
for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
*p = ext2fs_swab32(*p);
}
#endif
errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
{
dgrp_t i;
size_t nbytes;
errcode_t retval;
char * inode_bitmap = fs->inode_map->bitmap;
char * bitmap_block = NULL;
blk_t blk;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (!(fs->flags & EXT2_FLAG_RW))
return EXT2_ET_RO_FILSYS;
if (!inode_bitmap)
return 0;
nbytes = (size_t) ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
retval = ext2fs_get_mem(fs->blocksize, &bitmap_block);
if (retval)
return retval;
memset(bitmap_block, 0xff, fs->blocksize);
for (i = 0; i < fs->group_desc_count; i++) {
memcpy(bitmap_block, inode_bitmap, nbytes);
blk = fs->group_desc[i].bg_inode_bitmap;
if (blk) {
#ifdef EXT2_BIG_ENDIAN_BITMAPS
if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
ext2fs_swap_bitmap(fs, bitmap_block, nbytes);
#endif
retval = io_channel_write_blk(fs->io, blk, 1,
bitmap_block);
if (retval)
return EXT2_ET_INODE_BITMAP_WRITE;
}
inode_bitmap += nbytes;
}
fs->flags &= ~EXT2_FLAG_IB_DIRTY;
ext2fs_free_mem(&bitmap_block);
return 0;
}
errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
{
dgrp_t i;
unsigned int j;
int nbytes;
unsigned int nbits;
errcode_t retval;
char * block_bitmap = fs->block_map->bitmap;
char * bitmap_block = NULL;
blk_t blk;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (!(fs->flags & EXT2_FLAG_RW))
return EXT2_ET_RO_FILSYS;
if (!block_bitmap)
return 0;
nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
retval = ext2fs_get_mem(fs->blocksize, &bitmap_block);
if (retval)
return retval;
memset(bitmap_block, 0xff, fs->blocksize);
for (i = 0; i < fs->group_desc_count; i++) {
memcpy(bitmap_block, block_bitmap, nbytes);
if (i == fs->group_desc_count - 1) {
/* Force bitmap padding for the last group */
nbits = ((fs->super->s_blocks_count
- fs->super->s_first_data_block)
% EXT2_BLOCKS_PER_GROUP(fs->super));
if (nbits)
for (j = nbits; j < fs->blocksize * 8; j++)
ext2fs_set_bit(j, bitmap_block);
}
blk = fs->group_desc[i].bg_block_bitmap;
if (blk) {
#ifdef EXT2_BIG_ENDIAN_BITMAPS
if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
ext2fs_swap_bitmap(fs, bitmap_block, nbytes);
#endif
retval = io_channel_write_blk(fs->io, blk, 1,
bitmap_block);
if (retval)
return EXT2_ET_BLOCK_BITMAP_WRITE;
}
block_bitmap += nbytes;
}
fs->flags &= ~EXT2_FLAG_BB_DIRTY;
ext2fs_free_mem(&bitmap_block);
return 0;
}
static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
{
dgrp_t i;
char *block_bitmap = 0, *inode_bitmap = 0;
char *buf;
errcode_t retval;
int block_nbytes = (int) EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
int inode_nbytes = (int) EXT2_INODES_PER_GROUP(fs->super) / 8;
blk_t blk;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
fs->write_bitmaps = ext2fs_write_bitmaps;
retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
if (retval)
return retval;
if (do_block) {
if (fs->block_map)
ext2fs_free_block_bitmap(fs->block_map);
sprintf(buf, "block bitmap for %s", fs->device_name);
retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
if (retval)
goto cleanup;
block_bitmap = fs->block_map->bitmap;
}
if (do_inode) {
if (fs->inode_map)
ext2fs_free_inode_bitmap(fs->inode_map);
sprintf(buf, "inode bitmap for %s", fs->device_name);
retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
if (retval)
goto cleanup;
inode_bitmap = fs->inode_map->bitmap;
}
ext2fs_free_mem(&buf);
if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
if (inode_bitmap) {
blk = (fs->image_header->offset_inodemap /
fs->blocksize);
retval = io_channel_read_blk(fs->image_io, blk,
-(inode_nbytes * fs->group_desc_count),
inode_bitmap);
if (retval)
goto cleanup;
}
if (block_bitmap) {
blk = (fs->image_header->offset_blockmap /
fs->blocksize);
retval = io_channel_read_blk(fs->image_io, blk,
-(block_nbytes * fs->group_desc_count),
block_bitmap);
if (retval)
goto cleanup;
}
return 0;
}
for (i = 0; i < fs->group_desc_count; i++) {
if (block_bitmap) {
blk = fs->group_desc[i].bg_block_bitmap;
if (blk) {
retval = io_channel_read_blk(fs->io, blk,
-block_nbytes, block_bitmap);
if (retval) {
retval = EXT2_ET_BLOCK_BITMAP_READ;
goto cleanup;
}
#ifdef EXT2_BIG_ENDIAN_BITMAPS
if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
ext2fs_swap_bitmap(fs, block_bitmap, block_nbytes);
#endif
} else
memset(block_bitmap, 0, block_nbytes);
block_bitmap += block_nbytes;
}
if (inode_bitmap) {
blk = fs->group_desc[i].bg_inode_bitmap;
if (blk) {
retval = io_channel_read_blk(fs->io, blk,
-inode_nbytes, inode_bitmap);
if (retval) {
retval = EXT2_ET_INODE_BITMAP_READ;
goto cleanup;
}
#ifdef EXT2_BIG_ENDIAN_BITMAPS
if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
ext2fs_swap_bitmap(fs, inode_bitmap, inode_nbytes);
#endif
} else
memset(inode_bitmap, 0, inode_nbytes);
inode_bitmap += inode_nbytes;
}
}
return 0;
cleanup:
if (do_block) {
ext2fs_free_mem(&fs->block_map);
fs->block_map = 0;
}
if (do_inode) {
ext2fs_free_mem(&fs->inode_map);
fs->inode_map = 0;
}
if (buf)
ext2fs_free_mem(&buf);
return retval;
}
errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs)
{
return read_bitmaps(fs, 1, 0);
}
errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
{
return read_bitmaps(fs, 0, 1);
}
errcode_t ext2fs_read_bitmaps(ext2_filsys fs)
{
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (fs->inode_map && fs->block_map)
return 0;
return read_bitmaps(fs, !fs->inode_map, !fs->block_map);
}
errcode_t ext2fs_write_bitmaps(ext2_filsys fs)
{
errcode_t retval;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (fs->block_map && ext2fs_test_bb_dirty(fs)) {
retval = ext2fs_write_block_bitmap(fs);
if (retval)
return retval;
}
if (fs->inode_map && ext2fs_test_ib_dirty(fs)) {
retval = ext2fs_write_inode_bitmap(fs);
if (retval)
return retval;
}
return 0;
}

78
e2fsprogs/ext2fs/sparse.c Normal file
View File

@ -0,0 +1,78 @@
/*
* sparse.c --- find the groups in an ext2 filesystem with metadata backups
*
* Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
* Copyright (C) 2002 Andreas Dilger.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include "ext2_fs.h"
#include "ext2fsP.h"
static int test_root(int a, int b)
{
if (a == 0)
return 1;
while (1) {
if (a == 1)
return 1;
if (a % b)
return 0;
a = a / b;
}
}
int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
{
if (!(fs->super->s_feature_ro_compat &
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
return 1;
if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
test_root(group_block, 7))
return 1;
return 0;
}
/*
* Iterate through the groups which hold BACKUP superblock/GDT copies in an
* ext3 filesystem. The counters should be initialized to 1, 5, and 7 before
* calling this for the first time. In a sparse filesystem it will be the
* sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
* For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
*/
unsigned int ext2fs_list_backups(ext2_filsys fs, unsigned int *three,
unsigned int *five, unsigned int *seven)
{
unsigned int *min = three;
int mult = 3;
unsigned int ret;
if (!(fs->super->s_feature_ro_compat &
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
ret = *min;
*min += 1;
return ret;
}
if (*five < *min) {
min = five;
mult = 5;
}
if (*seven < *min) {
min = seven;
mult = 7;
}
ret = *min;
*min *= mult;
return ret;
}

237
e2fsprogs/ext2fs/swapfs.c Normal file
View File

@ -0,0 +1,237 @@
/*
* swapfs.c --- swap ext2 filesystem data structures
*
* Copyright (C) 1995, 1996, 2002 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <time.h>
#include "ext2_fs.h"
#include "ext2fs.h"
#include <ext2fs/ext2_ext_attr.h>
#ifdef EXT2FS_ENABLE_SWAPFS
void ext2fs_swap_super(struct ext2_super_block * sb)
{
int i;
sb->s_inodes_count = ext2fs_swab32(sb->s_inodes_count);
sb->s_blocks_count = ext2fs_swab32(sb->s_blocks_count);
sb->s_r_blocks_count = ext2fs_swab32(sb->s_r_blocks_count);
sb->s_free_blocks_count = ext2fs_swab32(sb->s_free_blocks_count);
sb->s_free_inodes_count = ext2fs_swab32(sb->s_free_inodes_count);
sb->s_first_data_block = ext2fs_swab32(sb->s_first_data_block);
sb->s_log_block_size = ext2fs_swab32(sb->s_log_block_size);
sb->s_log_frag_size = ext2fs_swab32(sb->s_log_frag_size);
sb->s_blocks_per_group = ext2fs_swab32(sb->s_blocks_per_group);
sb->s_frags_per_group = ext2fs_swab32(sb->s_frags_per_group);
sb->s_inodes_per_group = ext2fs_swab32(sb->s_inodes_per_group);
sb->s_mtime = ext2fs_swab32(sb->s_mtime);
sb->s_wtime = ext2fs_swab32(sb->s_wtime);
sb->s_mnt_count = ext2fs_swab16(sb->s_mnt_count);
sb->s_max_mnt_count = ext2fs_swab16(sb->s_max_mnt_count);
sb->s_magic = ext2fs_swab16(sb->s_magic);
sb->s_state = ext2fs_swab16(sb->s_state);
sb->s_errors = ext2fs_swab16(sb->s_errors);
sb->s_minor_rev_level = ext2fs_swab16(sb->s_minor_rev_level);
sb->s_lastcheck = ext2fs_swab32(sb->s_lastcheck);
sb->s_checkinterval = ext2fs_swab32(sb->s_checkinterval);
sb->s_creator_os = ext2fs_swab32(sb->s_creator_os);
sb->s_rev_level = ext2fs_swab32(sb->s_rev_level);
sb->s_def_resuid = ext2fs_swab16(sb->s_def_resuid);
sb->s_def_resgid = ext2fs_swab16(sb->s_def_resgid);
sb->s_first_ino = ext2fs_swab32(sb->s_first_ino);
sb->s_inode_size = ext2fs_swab16(sb->s_inode_size);
sb->s_block_group_nr = ext2fs_swab16(sb->s_block_group_nr);
sb->s_feature_compat = ext2fs_swab32(sb->s_feature_compat);
sb->s_feature_incompat = ext2fs_swab32(sb->s_feature_incompat);
sb->s_feature_ro_compat = ext2fs_swab32(sb->s_feature_ro_compat);
sb->s_algorithm_usage_bitmap = ext2fs_swab32(sb->s_algorithm_usage_bitmap);
sb->s_reserved_gdt_blocks = ext2fs_swab16(sb->s_reserved_gdt_blocks);
sb->s_journal_inum = ext2fs_swab32(sb->s_journal_inum);
sb->s_journal_dev = ext2fs_swab32(sb->s_journal_dev);
sb->s_last_orphan = ext2fs_swab32(sb->s_last_orphan);
sb->s_default_mount_opts = ext2fs_swab32(sb->s_default_mount_opts);
sb->s_first_meta_bg = ext2fs_swab32(sb->s_first_meta_bg);
sb->s_mkfs_time = ext2fs_swab32(sb->s_mkfs_time);
for (i=0; i < 4; i++)
sb->s_hash_seed[i] = ext2fs_swab32(sb->s_hash_seed[i]);
for (i=0; i < 17; i++)
sb->s_jnl_blocks[i] = ext2fs_swab32(sb->s_jnl_blocks[i]);
}
void ext2fs_swap_group_desc(struct ext2_group_desc *gdp)
{
gdp->bg_block_bitmap = ext2fs_swab32(gdp->bg_block_bitmap);
gdp->bg_inode_bitmap = ext2fs_swab32(gdp->bg_inode_bitmap);
gdp->bg_inode_table = ext2fs_swab32(gdp->bg_inode_table);
gdp->bg_free_blocks_count = ext2fs_swab16(gdp->bg_free_blocks_count);
gdp->bg_free_inodes_count = ext2fs_swab16(gdp->bg_free_inodes_count);
gdp->bg_used_dirs_count = ext2fs_swab16(gdp->bg_used_dirs_count);
}
void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header)
{
struct ext2_ext_attr_header *from_header =
(struct ext2_ext_attr_header *)from;
struct ext2_ext_attr_header *to_header =
(struct ext2_ext_attr_header *)to;
struct ext2_ext_attr_entry *from_entry, *to_entry;
char *from_end = (char *)from_header + bufsize;
int n;
if (to_header != from_header)
memcpy(to_header, from_header, bufsize);
from_entry = (struct ext2_ext_attr_entry *)from_header;
to_entry = (struct ext2_ext_attr_entry *)to_header;
if (has_header) {
to_header->h_magic = ext2fs_swab32(from_header->h_magic);
to_header->h_blocks = ext2fs_swab32(from_header->h_blocks);
to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
for (n=0; n<4; n++)
to_header->h_reserved[n] =
ext2fs_swab32(from_header->h_reserved[n]);
from_entry = (struct ext2_ext_attr_entry *)(from_header+1);
to_entry = (struct ext2_ext_attr_entry *)(to_header+1);
}
while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
to_entry->e_value_offs =
ext2fs_swab16(from_entry->e_value_offs);
to_entry->e_value_block =
ext2fs_swab32(from_entry->e_value_block);
to_entry->e_value_size =
ext2fs_swab32(from_entry->e_value_size);
from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
to_entry = EXT2_EXT_ATTR_NEXT(to_entry);
}
}
void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
struct ext2_inode_large *f, int hostorder,
int bufsize)
{
unsigned i;
int islnk = 0;
__u32 *eaf, *eat;
if (hostorder && LINUX_S_ISLNK(f->i_mode))
islnk = 1;
t->i_mode = ext2fs_swab16(f->i_mode);
if (!hostorder && LINUX_S_ISLNK(t->i_mode))
islnk = 1;
t->i_uid = ext2fs_swab16(f->i_uid);
t->i_size = ext2fs_swab32(f->i_size);
t->i_atime = ext2fs_swab32(f->i_atime);
t->i_ctime = ext2fs_swab32(f->i_ctime);
t->i_mtime = ext2fs_swab32(f->i_mtime);
t->i_dtime = ext2fs_swab32(f->i_dtime);
t->i_gid = ext2fs_swab16(f->i_gid);
t->i_links_count = ext2fs_swab16(f->i_links_count);
t->i_blocks = ext2fs_swab32(f->i_blocks);
t->i_flags = ext2fs_swab32(f->i_flags);
t->i_file_acl = ext2fs_swab32(f->i_file_acl);
t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
if (!islnk || ext2fs_inode_data_blocks(fs, (struct ext2_inode *)t)) {
for (i = 0; i < EXT2_N_BLOCKS; i++)
t->i_block[i] = ext2fs_swab32(f->i_block[i]);
} else if (t != f) {
for (i = 0; i < EXT2_N_BLOCKS; i++)
t->i_block[i] = f->i_block[i];
}
t->i_generation = ext2fs_swab32(f->i_generation);
t->i_faddr = ext2fs_swab32(f->i_faddr);
switch (fs->super->s_creator_os) {
case EXT2_OS_LINUX:
t->osd1.linux1.l_i_reserved1 =
ext2fs_swab32(f->osd1.linux1.l_i_reserved1);
t->osd2.linux2.l_i_frag = f->osd2.linux2.l_i_frag;
t->osd2.linux2.l_i_fsize = f->osd2.linux2.l_i_fsize;
t->osd2.linux2.i_pad1 = ext2fs_swab16(f->osd2.linux2.i_pad1);
t->osd2.linux2.l_i_uid_high =
ext2fs_swab16 (f->osd2.linux2.l_i_uid_high);
t->osd2.linux2.l_i_gid_high =
ext2fs_swab16 (f->osd2.linux2.l_i_gid_high);
t->osd2.linux2.l_i_reserved2 =
ext2fs_swab32(f->osd2.linux2.l_i_reserved2);
break;
case EXT2_OS_HURD:
t->osd1.hurd1.h_i_translator =
ext2fs_swab32 (f->osd1.hurd1.h_i_translator);
t->osd2.hurd2.h_i_frag = f->osd2.hurd2.h_i_frag;
t->osd2.hurd2.h_i_fsize = f->osd2.hurd2.h_i_fsize;
t->osd2.hurd2.h_i_mode_high =
ext2fs_swab16 (f->osd2.hurd2.h_i_mode_high);
t->osd2.hurd2.h_i_uid_high =
ext2fs_swab16 (f->osd2.hurd2.h_i_uid_high);
t->osd2.hurd2.h_i_gid_high =
ext2fs_swab16 (f->osd2.hurd2.h_i_gid_high);
t->osd2.hurd2.h_i_author =
ext2fs_swab32 (f->osd2.hurd2.h_i_author);
break;
case EXT2_OS_MASIX:
t->osd1.masix1.m_i_reserved1 =
ext2fs_swab32(f->osd1.masix1.m_i_reserved1);
t->osd2.masix2.m_i_frag = f->osd2.masix2.m_i_frag;
t->osd2.masix2.m_i_fsize = f->osd2.masix2.m_i_fsize;
t->osd2.masix2.m_pad1 = ext2fs_swab16(f->osd2.masix2.m_pad1);
t->osd2.masix2.m_i_reserved2[0] =
ext2fs_swab32(f->osd2.masix2.m_i_reserved2[0]);
t->osd2.masix2.m_i_reserved2[1] =
ext2fs_swab32(f->osd2.masix2.m_i_reserved2[1]);
break;
}
if (bufsize < (int) (sizeof(struct ext2_inode) + sizeof(__u16)))
return; /* no i_extra_isize field */
t->i_extra_isize = ext2fs_swab16(f->i_extra_isize);
if (t->i_extra_isize > EXT2_INODE_SIZE(fs->super) -
sizeof(struct ext2_inode)) {
/* this is error case: i_extra_size is too large */
return;
}
i = sizeof(struct ext2_inode) + t->i_extra_isize + sizeof(__u32);
if (bufsize < (int) i)
return; /* no space for EA magic */
eaf = (__u32 *) (((char *) f) + sizeof(struct ext2_inode) +
f->i_extra_isize);
if (ext2fs_swab32(*eaf) != EXT2_EXT_ATTR_MAGIC)
return; /* it seems no magic here */
eat = (__u32 *) (((char *) t) + sizeof(struct ext2_inode) +
f->i_extra_isize);
*eat = ext2fs_swab32(*eaf);
/* convert EA(s) */
ext2fs_swap_ext_attr((char *) (eat + 1), (char *) (eaf + 1),
bufsize - sizeof(struct ext2_inode) -
t->i_extra_isize - sizeof(__u32), 0);
}
void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
struct ext2_inode *f, int hostorder)
{
ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) t,
(struct ext2_inode_large *) f, hostorder,
sizeof(struct ext2_inode));
}
#endif

382
e2fsprogs/ext2fs/test_io.c Normal file
View File

@ -0,0 +1,382 @@
/*
* test_io.c --- This is the Test I/O interface.
*
* Copyright (C) 1996 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
/*
* For checking structure magic numbers...
*/
#define EXT2_CHECK_MAGIC(struct, code) \
if ((struct)->magic != (code)) return (code)
struct test_private_data {
int magic;
io_channel real;
int flags;
FILE *outfile;
unsigned long block;
int read_abort_count, write_abort_count;
void (*read_blk)(unsigned long block, int count, errcode_t err);
void (*write_blk)(unsigned long block, int count, errcode_t err);
void (*set_blksize)(int blksize, errcode_t err);
void (*write_byte)(unsigned long block, int count, errcode_t err);
};
static errcode_t test_open(const char *name, int flags, io_channel *channel);
static errcode_t test_close(io_channel channel);
static errcode_t test_set_blksize(io_channel channel, int blksize);
static errcode_t test_read_blk(io_channel channel, unsigned long block,
int count, void *data);
static errcode_t test_write_blk(io_channel channel, unsigned long block,
int count, const void *data);
static errcode_t test_flush(io_channel channel);
static errcode_t test_write_byte(io_channel channel, unsigned long offset,
int count, const void *buf);
static errcode_t test_set_option(io_channel channel, const char *option,
const char *arg);
static struct struct_io_manager struct_test_manager = {
EXT2_ET_MAGIC_IO_MANAGER,
"Test I/O Manager",
test_open,
test_close,
test_set_blksize,
test_read_blk,
test_write_blk,
test_flush,
test_write_byte,
test_set_option
};
io_manager test_io_manager = &struct_test_manager;
/*
* These global variable can be set by the test program as
* necessary *before* calling test_open
*/
io_manager test_io_backing_manager = 0;
void (*test_io_cb_read_blk)
(unsigned long block, int count, errcode_t err) = 0;
void (*test_io_cb_write_blk)
(unsigned long block, int count, errcode_t err) = 0;
void (*test_io_cb_set_blksize)
(int blksize, errcode_t err) = 0;
void (*test_io_cb_write_byte)
(unsigned long block, int count, errcode_t err) = 0;
/*
* Test flags
*/
#define TEST_FLAG_READ 0x01
#define TEST_FLAG_WRITE 0x02
#define TEST_FLAG_SET_BLKSIZE 0x04
#define TEST_FLAG_FLUSH 0x08
#define TEST_FLAG_DUMP 0x10
#define TEST_FLAG_SET_OPTION 0x20
static void test_dump_block(io_channel channel,
struct test_private_data *data,
unsigned long block, const void *buf)
{
const unsigned char *cp;
FILE *f = data->outfile;
int i;
unsigned long cksum = 0;
for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
cksum += *cp;
}
fprintf(f, "Contents of block %lu, checksum %08lu: \n", block, cksum);
for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
if ((i % 16) == 0)
fprintf(f, "%04x: ", i);
fprintf(f, "%02x%c", *cp, ((i % 16) == 15) ? '\n' : ' ');
}
}
static void test_abort(io_channel channel, unsigned long block)
{
struct test_private_data *data;
FILE *f;
data = (struct test_private_data *) channel->private_data;
f = data->outfile;
test_flush(channel);
fprintf(f, "Aborting due to I/O to block %lu\n", block);
fflush(f);
abort();
}
static errcode_t test_open(const char *name, int flags, io_channel *channel)
{
io_channel io = NULL;
struct test_private_data *data = NULL;
errcode_t retval;
char *value;
if (name == 0)
return EXT2_ET_BAD_DEVICE_NAME;
retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
if (retval)
return retval;
memset(io, 0, sizeof(struct struct_io_channel));
io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
retval = ext2fs_get_mem(sizeof(struct test_private_data), &data);
if (retval) {
retval = EXT2_ET_NO_MEMORY;
goto cleanup;
}
io->manager = test_io_manager;
retval = ext2fs_get_mem(strlen(name)+1, &io->name);
if (retval)
goto cleanup;
strcpy(io->name, name);
io->private_data = data;
io->block_size = 1024;
io->read_error = 0;
io->write_error = 0;
io->refcount = 1;
memset(data, 0, sizeof(struct test_private_data));
data->magic = EXT2_ET_MAGIC_TEST_IO_CHANNEL;
if (test_io_backing_manager) {
retval = test_io_backing_manager->open(name, flags,
&data->real);
if (retval)
goto cleanup;
} else
data->real = 0;
data->read_blk = test_io_cb_read_blk;
data->write_blk = test_io_cb_write_blk;
data->set_blksize = test_io_cb_set_blksize;
data->write_byte = test_io_cb_write_byte;
data->outfile = NULL;
if ((value = getenv("TEST_IO_LOGFILE")) != NULL)
data->outfile = fopen(value, "w");
if (!data->outfile)
data->outfile = stderr;
data->flags = 0;
if ((value = getenv("TEST_IO_FLAGS")) != NULL)
data->flags = strtoul(value, NULL, 0);
data->block = 0;
if ((value = getenv("TEST_IO_BLOCK")) != NULL)
data->block = strtoul(value, NULL, 0);
data->read_abort_count = 0;
if ((value = getenv("TEST_IO_READ_ABORT")) != NULL)
data->read_abort_count = strtoul(value, NULL, 0);
data->write_abort_count = 0;
if ((value = getenv("TEST_IO_WRITE_ABORT")) != NULL)
data->write_abort_count = strtoul(value, NULL, 0);
*channel = io;
return 0;
cleanup:
if (io)
ext2fs_free_mem(&io);
if (data)
ext2fs_free_mem(&data);
return retval;
}
static errcode_t test_close(io_channel channel)
{
struct test_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct test_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
if (--channel->refcount > 0)
return 0;
if (data->real)
retval = io_channel_close(data->real);
if (data->outfile && data->outfile != stderr)
fclose(data->outfile);
ext2fs_free_mem(&channel->private_data);
if (channel->name)
ext2fs_free_mem(&channel->name);
ext2fs_free_mem(&channel);
return retval;
}
static errcode_t test_set_blksize(io_channel channel, int blksize)
{
struct test_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct test_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
if (data->real)
retval = io_channel_set_blksize(data->real, blksize);
if (data->set_blksize)
data->set_blksize(blksize, retval);
if (data->flags & TEST_FLAG_SET_BLKSIZE)
fprintf(data->outfile,
"Test_io: set_blksize(%d) returned %s\n",
blksize, retval ? error_message(retval) : "OK");
channel->block_size = blksize;
return retval;
}
static errcode_t test_read_blk(io_channel channel, unsigned long block,
int count, void *buf)
{
struct test_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct test_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
if (data->real)
retval = io_channel_read_blk(data->real, block, count, buf);
if (data->read_blk)
data->read_blk(block, count, retval);
if (data->flags & TEST_FLAG_READ)
fprintf(data->outfile,
"Test_io: read_blk(%lu, %d) returned %s\n",
block, count, retval ? error_message(retval) : "OK");
if (data->block && data->block == block) {
if (data->flags & TEST_FLAG_DUMP)
test_dump_block(channel, data, block, buf);
if (--data->read_abort_count == 0)
test_abort(channel, block);
}
return retval;
}
static errcode_t test_write_blk(io_channel channel, unsigned long block,
int count, const void *buf)
{
struct test_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct test_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
if (data->real)
retval = io_channel_write_blk(data->real, block, count, buf);
if (data->write_blk)
data->write_blk(block, count, retval);
if (data->flags & TEST_FLAG_WRITE)
fprintf(data->outfile,
"Test_io: write_blk(%lu, %d) returned %s\n",
block, count, retval ? error_message(retval) : "OK");
if (data->block && data->block == block) {
if (data->flags & TEST_FLAG_DUMP)
test_dump_block(channel, data, block, buf);
if (--data->write_abort_count == 0)
test_abort(channel, block);
}
return retval;
}
static errcode_t test_write_byte(io_channel channel, unsigned long offset,
int count, const void *buf)
{
struct test_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct test_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
if (data->real && data->real->manager->write_byte)
retval = io_channel_write_byte(data->real, offset, count, buf);
if (data->write_byte)
data->write_byte(offset, count, retval);
if (data->flags & TEST_FLAG_WRITE)
fprintf(data->outfile,
"Test_io: write_byte(%lu, %d) returned %s\n",
offset, count, retval ? error_message(retval) : "OK");
return retval;
}
/*
* Flush data buffers to disk.
*/
static errcode_t test_flush(io_channel channel)
{
struct test_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct test_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
if (data->real)
retval = io_channel_flush(data->real);
if (data->flags & TEST_FLAG_FLUSH)
fprintf(data->outfile, "Test_io: flush() returned %s\n",
retval ? error_message(retval) : "OK");
return retval;
}
static errcode_t test_set_option(io_channel channel, const char *option,
const char *arg)
{
struct test_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct test_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
if (data->flags & TEST_FLAG_SET_OPTION)
fprintf(data->outfile, "Test_io: set_option(%s, %s) ",
option, arg);
if (data->real && data->real->manager->set_option) {
retval = (data->real->manager->set_option)(data->real,
option, arg);
if (data->flags & TEST_FLAG_SET_OPTION)
fprintf(data->outfile, "returned %s\n",
retval ? error_message(retval) : "OK");
} else {
if (data->flags & TEST_FLAG_SET_OPTION)
fprintf(data->outfile, "not implemented\n");
}
return retval;
}

707
e2fsprogs/ext2fs/unix_io.c Normal file
View File

@ -0,0 +1,707 @@
/*
* unix_io.c --- This is the Unix (well, really POSIX) implementation
* of the I/O manager.
*
* Implements a one-block write-through cache.
*
* Includes support for Windows NT support under Cygwin.
*
* Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
* 2002 by Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#include <fcntl.h>
#include <time.h>
#ifdef __linux__
#include <sys/utsname.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
/*
* For checking structure magic numbers...
*/
#define EXT2_CHECK_MAGIC(struct, code) \
if ((struct)->magic != (code)) return (code)
struct unix_cache {
char *buf;
unsigned long block;
int access_time;
unsigned dirty:1;
unsigned in_use:1;
};
#define CACHE_SIZE 8
#define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */
#define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */
struct unix_private_data {
int magic;
int dev;
int flags;
int access_time;
ext2_loff_t offset;
struct unix_cache cache[CACHE_SIZE];
};
static errcode_t unix_open(const char *name, int flags, io_channel *channel);
static errcode_t unix_close(io_channel channel);
static errcode_t unix_set_blksize(io_channel channel, int blksize);
static errcode_t unix_read_blk(io_channel channel, unsigned long block,
int count, void *data);
static errcode_t unix_write_blk(io_channel channel, unsigned long block,
int count, const void *data);
static errcode_t unix_flush(io_channel channel);
static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
int size, const void *data);
static errcode_t unix_set_option(io_channel channel, const char *option,
const char *arg);
static void reuse_cache(io_channel channel, struct unix_private_data *data,
struct unix_cache *cache, unsigned long block);
/* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
* does not know buffered block devices - everything is raw. */
#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#define NEED_BOUNCE_BUFFER
#else
#undef NEED_BOUNCE_BUFFER
#endif
static struct struct_io_manager struct_unix_manager = {
EXT2_ET_MAGIC_IO_MANAGER,
"Unix I/O Manager",
unix_open,
unix_close,
unix_set_blksize,
unix_read_blk,
unix_write_blk,
unix_flush,
#ifdef NEED_BOUNCE_BUFFER
0,
#else
unix_write_byte,
#endif
unix_set_option
};
io_manager unix_io_manager = &struct_unix_manager;
/*
* Here are the raw I/O functions
*/
#ifndef NEED_BOUNCE_BUFFER
static errcode_t raw_read_blk(io_channel channel,
struct unix_private_data *data,
unsigned long block,
int count, void *buf)
{
errcode_t retval;
ssize_t size;
ext2_loff_t location;
int actual = 0;
size = (count < 0) ? -count : count * channel->block_size;
location = ((ext2_loff_t) block * channel->block_size) + data->offset;
if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
goto error_out;
}
actual = read(data->dev, buf, size);
if (actual != size) {
if (actual < 0)
actual = 0;
retval = EXT2_ET_SHORT_READ;
goto error_out;
}
return 0;
error_out:
memset((char *) buf+actual, 0, size-actual);
if (channel->read_error)
retval = (channel->read_error)(channel, block, count, buf,
size, actual, retval);
return retval;
}
#else /* NEED_BOUNCE_BUFFER */
/*
* Windows and FreeBSD block devices only allow sector alignment IO in offset and size
*/
static errcode_t raw_read_blk(io_channel channel,
struct unix_private_data *data,
unsigned long block,
int count, void *buf)
{
errcode_t retval;
size_t size, alignsize, fragment;
ext2_loff_t location;
int total = 0, actual;
#define BLOCKALIGN 512
char sector[BLOCKALIGN];
size = (count < 0) ? -count : count * channel->block_size;
location = ((ext2_loff_t) block * channel->block_size) + data->offset;
#ifdef DEBUG
printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",
count, size, block, channel->block_size, location);
#endif
if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
goto error_out;
}
fragment = size % BLOCKALIGN;
alignsize = size - fragment;
if (alignsize) {
actual = read(data->dev, buf, alignsize);
if (actual != alignsize)
goto short_read;
}
if (fragment) {
actual = read(data->dev, sector, BLOCKALIGN);
if (actual != BLOCKALIGN)
goto short_read;
memcpy(buf+alignsize, sector, fragment);
}
return 0;
short_read:
if (actual>0)
total += actual;
retval = EXT2_ET_SHORT_READ;
error_out:
memset((char *) buf+total, 0, size-actual);
if (channel->read_error)
retval = (channel->read_error)(channel, block, count, buf,
size, actual, retval);
return retval;
}
#endif
static errcode_t raw_write_blk(io_channel channel,
struct unix_private_data *data,
unsigned long block,
int count, const void *buf)
{
ssize_t size;
ext2_loff_t location;
int actual = 0;
errcode_t retval;
if (count == 1)
size = channel->block_size;
else {
if (count < 0)
size = -count;
else
size = count * channel->block_size;
}
location = ((ext2_loff_t) block * channel->block_size) + data->offset;
if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
goto error_out;
}
actual = write(data->dev, buf, size);
if (actual != size) {
retval = EXT2_ET_SHORT_WRITE;
goto error_out;
}
return 0;
error_out:
if (channel->write_error)
retval = (channel->write_error)(channel, block, count, buf,
size, actual, retval);
return retval;
}
/*
* Here we implement the cache functions
*/
/* Allocate the cache buffers */
static errcode_t alloc_cache(io_channel channel,
struct unix_private_data *data)
{
errcode_t retval;
struct unix_cache *cache;
int i;
data->access_time = 0;
for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
cache->block = 0;
cache->access_time = 0;
cache->dirty = 0;
cache->in_use = 0;
if ((retval = ext2fs_get_mem(channel->block_size,
&cache->buf)))
return retval;
}
return 0;
}
/* Free the cache buffers */
static void free_cache(struct unix_private_data *data)
{
struct unix_cache *cache;
int i;
data->access_time = 0;
for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
cache->block = 0;
cache->access_time = 0;
cache->dirty = 0;
cache->in_use = 0;
if (cache->buf)
ext2fs_free_mem(&cache->buf);
cache->buf = 0;
}
}
#ifndef NO_IO_CACHE
/*
* Try to find a block in the cache. If the block is not found, and
* eldest is a non-zero pointer, then fill in eldest with the cache
* entry to that should be reused.
*/
static struct unix_cache *find_cached_block(struct unix_private_data *data,
unsigned long block,
struct unix_cache **eldest)
{
struct unix_cache *cache, *unused_cache, *oldest_cache;
int i;
unused_cache = oldest_cache = 0;
for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
if (!cache->in_use) {
if (!unused_cache)
unused_cache = cache;
continue;
}
if (cache->block == block) {
cache->access_time = ++data->access_time;
return cache;
}
if (!oldest_cache ||
(cache->access_time < oldest_cache->access_time))
oldest_cache = cache;
}
if (eldest)
*eldest = (unused_cache) ? unused_cache : oldest_cache;
return 0;
}
/*
* Reuse a particular cache entry for another block.
*/
static void reuse_cache(io_channel channel, struct unix_private_data *data,
struct unix_cache *cache, unsigned long block)
{
if (cache->dirty && cache->in_use)
raw_write_blk(channel, data, cache->block, 1, cache->buf);
cache->in_use = 1;
cache->dirty = 0;
cache->block = block;
cache->access_time = ++data->access_time;
}
/*
* Flush all of the blocks in the cache
*/
static errcode_t flush_cached_blocks(io_channel channel,
struct unix_private_data *data,
int invalidate)
{
struct unix_cache *cache;
errcode_t retval, retval2;
int i;
retval2 = 0;
for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
if (!cache->in_use)
continue;
if (invalidate)
cache->in_use = 0;
if (!cache->dirty)
continue;
retval = raw_write_blk(channel, data,
cache->block, 1, cache->buf);
if (retval)
retval2 = retval;
else
cache->dirty = 0;
}
return retval2;
}
#endif /* NO_IO_CACHE */
static errcode_t unix_open(const char *name, int flags, io_channel *channel)
{
io_channel io = NULL;
struct unix_private_data *data = NULL;
errcode_t retval;
int open_flags;
struct stat st;
#ifdef __linux__
struct utsname ut;
#endif
if (name == 0)
return EXT2_ET_BAD_DEVICE_NAME;
retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
if (retval)
return retval;
memset(io, 0, sizeof(struct struct_io_channel));
io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
if (retval)
goto cleanup;
io->manager = unix_io_manager;
retval = ext2fs_get_mem(strlen(name)+1, &io->name);
if (retval)
goto cleanup;
strcpy(io->name, name);
io->private_data = data;
io->block_size = 1024;
io->read_error = 0;
io->write_error = 0;
io->refcount = 1;
memset(data, 0, sizeof(struct unix_private_data));
data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
if ((retval = alloc_cache(io, data)))
goto cleanup;
open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
#ifdef CONFIG_LFS
data->dev = open64(io->name, open_flags);
#else
data->dev = open(io->name, open_flags);
#endif
if (data->dev < 0) {
retval = errno;
goto cleanup;
}
#ifdef __linux__
#undef RLIM_INFINITY
#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
#define RLIM_INFINITY ((unsigned long)(~0UL>>1))
#else
#define RLIM_INFINITY (~0UL)
#endif
/*
* Work around a bug in 2.4.10-2.4.18 kernels where writes to
* block devices are wrongly getting hit by the filesize
* limit. This workaround isn't perfect, since it won't work
* if glibc wasn't built against 2.2 header files. (Sigh.)
*
*/
if ((flags & IO_FLAG_RW) &&
(uname(&ut) == 0) &&
((ut.release[0] == '2') && (ut.release[1] == '.') &&
(ut.release[2] == '4') && (ut.release[3] == '.') &&
(ut.release[4] == '1') && (ut.release[5] >= '0') &&
(ut.release[5] < '8')) &&
(fstat(data->dev, &st) == 0) &&
(S_ISBLK(st.st_mode))) {
struct rlimit rlim;
rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
setrlimit(RLIMIT_FSIZE, &rlim);
getrlimit(RLIMIT_FSIZE, &rlim);
if (((unsigned long) rlim.rlim_cur) <
((unsigned long) rlim.rlim_max)) {
rlim.rlim_cur = rlim.rlim_max;
setrlimit(RLIMIT_FSIZE, &rlim);
}
}
#endif
*channel = io;
return 0;
cleanup:
if (data) {
free_cache(data);
ext2fs_free_mem(&data);
}
if (io)
ext2fs_free_mem(&io);
return retval;
}
static errcode_t unix_close(io_channel channel)
{
struct unix_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct unix_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
if (--channel->refcount > 0)
return 0;
#ifndef NO_IO_CACHE
retval = flush_cached_blocks(channel, data, 0);
#endif
if (close(data->dev) < 0)
retval = errno;
free_cache(data);
ext2fs_free_mem(&channel->private_data);
if (channel->name)
ext2fs_free_mem(&channel->name);
ext2fs_free_mem(&channel);
return retval;
}
static errcode_t unix_set_blksize(io_channel channel, int blksize)
{
struct unix_private_data *data;
errcode_t retval;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct unix_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
if (channel->block_size != blksize) {
#ifndef NO_IO_CACHE
if ((retval = flush_cached_blocks(channel, data, 0)))
return retval;
#endif
channel->block_size = blksize;
free_cache(data);
if ((retval = alloc_cache(channel, data)))
return retval;
}
return 0;
}
static errcode_t unix_read_blk(io_channel channel, unsigned long block,
int count, void *buf)
{
struct unix_private_data *data;
struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
errcode_t retval;
char *cp;
int i, j;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct unix_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
#ifdef NO_IO_CACHE
return raw_read_blk(channel, data, block, count, buf);
#else
/*
* If we're doing an odd-sized read or a very large read,
* flush out the cache and then do a direct read.
*/
if (count < 0 || count > WRITE_DIRECT_SIZE) {
if ((retval = flush_cached_blocks(channel, data, 0)))
return retval;
return raw_read_blk(channel, data, block, count, buf);
}
cp = buf;
while (count > 0) {
/* If it's in the cache, use it! */
if ((cache = find_cached_block(data, block, &reuse[0]))) {
#ifdef DEBUG
printf("Using cached block %d\n", block);
#endif
memcpy(cp, cache->buf, channel->block_size);
count--;
block++;
cp += channel->block_size;
continue;
}
/*
* Find the number of uncached blocks so we can do a
* single read request
*/
for (i=1; i < count; i++)
if (find_cached_block(data, block+i, &reuse[i]))
break;
#ifdef DEBUG
printf("Reading %d blocks starting at %d\n", i, block);
#endif
if ((retval = raw_read_blk(channel, data, block, i, cp)))
return retval;
/* Save the results in the cache */
for (j=0; j < i; j++) {
count--;
cache = reuse[j];
reuse_cache(channel, data, cache, block++);
memcpy(cache->buf, cp, channel->block_size);
cp += channel->block_size;
}
}
return 0;
#endif /* NO_IO_CACHE */
}
static errcode_t unix_write_blk(io_channel channel, unsigned long block,
int count, const void *buf)
{
struct unix_private_data *data;
struct unix_cache *cache, *reuse;
errcode_t retval = 0;
const char *cp;
int writethrough;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct unix_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
#ifdef NO_IO_CACHE
return raw_write_blk(channel, data, block, count, buf);
#else
/*
* If we're doing an odd-sized write or a very large write,
* flush out the cache completely and then do a direct write.
*/
if (count < 0 || count > WRITE_DIRECT_SIZE) {
if ((retval = flush_cached_blocks(channel, data, 1)))
return retval;
return raw_write_blk(channel, data, block, count, buf);
}
/*
* For a moderate-sized multi-block write, first force a write
* if we're in write-through cache mode, and then fill the
* cache with the blocks.
*/
writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
if (writethrough)
retval = raw_write_blk(channel, data, block, count, buf);
cp = buf;
while (count > 0) {
cache = find_cached_block(data, block, &reuse);
if (!cache) {
cache = reuse;
reuse_cache(channel, data, cache, block);
}
memcpy(cache->buf, cp, channel->block_size);
cache->dirty = !writethrough;
count--;
block++;
cp += channel->block_size;
}
return retval;
#endif /* NO_IO_CACHE */
}
static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
int size, const void *buf)
{
struct unix_private_data *data;
errcode_t retval = 0;
ssize_t actual;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct unix_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
#ifndef NO_IO_CACHE
/*
* Flush out the cache completely
*/
if ((retval = flush_cached_blocks(channel, data, 1)))
return retval;
#endif
if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
return errno;
actual = write(data->dev, buf, size);
if (actual != size)
return EXT2_ET_SHORT_WRITE;
return 0;
}
/*
* Flush data buffers to disk.
*/
static errcode_t unix_flush(io_channel channel)
{
struct unix_private_data *data;
errcode_t retval = 0;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct unix_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
#ifndef NO_IO_CACHE
retval = flush_cached_blocks(channel, data, 0);
#endif
fsync(data->dev);
return retval;
}
static errcode_t unix_set_option(io_channel channel, const char *option,
const char *arg)
{
struct unix_private_data *data;
unsigned long tmp;
char *end;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
data = (struct unix_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
if (!strcmp(option, "offset")) {
if (!arg)
return EXT2_ET_INVALID_ARGUMENT;
tmp = strtoul(arg, &end, 0);
if (*end)
return EXT2_ET_INVALID_ARGUMENT;
data->offset = tmp;
return 0;
}
return EXT2_ET_INVALID_ARGUMENT;
}

99
e2fsprogs/ext2fs/unlink.c Normal file
View File

@ -0,0 +1,99 @@
/*
* unlink.c --- delete links in a ext2fs directory
*
* Copyright (C) 1993, 1994, 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ext2_fs.h"
#include "ext2fs.h"
struct link_struct {
const char *name;
int namelen;
ext2_ino_t inode;
int flags;
struct ext2_dir_entry *prev;
int done;
};
#ifdef __TURBOC__
#pragma argsused
#endif
static int unlink_proc(struct ext2_dir_entry *dirent,
int offset EXT2FS_ATTR((unused)),
int blocksize EXT2FS_ATTR((unused)),
char *buf EXT2FS_ATTR((unused)),
void *priv_data)
{
struct link_struct *ls = (struct link_struct *) priv_data;
struct ext2_dir_entry *prev;
prev = ls->prev;
ls->prev = dirent;
if (ls->name) {
if ((dirent->name_len & 0xFF) != ls->namelen)
return 0;
if (strncmp(ls->name, dirent->name, dirent->name_len & 0xFF))
return 0;
}
if (ls->inode) {
if (dirent->inode != ls->inode)
return 0;
} else {
if (!dirent->inode)
return 0;
}
if (prev)
prev->rec_len += dirent->rec_len;
else
dirent->inode = 0;
ls->done++;
return DIRENT_ABORT|DIRENT_CHANGED;
}
#ifdef __TURBOC__
#pragma argsused
#endif
errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir,
const char *name, ext2_ino_t ino,
int flags EXT2FS_ATTR((unused)))
{
errcode_t retval;
struct link_struct ls;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if (!name && !ino)
return EXT2_ET_INVALID_ARGUMENT;
if (!(fs->flags & EXT2_FLAG_RW))
return EXT2_ET_RO_FILSYS;
ls.name = name;
ls.namelen = name ? strlen(name) : 0;
ls.inode = ino;
ls.flags = 0;
ls.done = 0;
ls.prev = 0;
retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
0, unlink_proc, &ls);
if (retval)
return retval;
return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE;
}

View File

@ -0,0 +1,56 @@
/*
* valid_blk.c --- does the inode have valid blocks?
*
* Copyright 1997 by Theodore Ts'o
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*
*/
#include <stdio.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <time.h>
#include "ext2_fs.h"
#include "ext2fs.h"
/*
* This function returns 1 if the inode's block entries actually
* contain block entries.
*/
int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode)
{
/*
* Only directories, regular files, and some symbolic links
* have valid block entries.
*/
if (!LINUX_S_ISDIR(inode->i_mode) && !LINUX_S_ISREG(inode->i_mode) &&
!LINUX_S_ISLNK(inode->i_mode))
return 0;
/*
* If the symbolic link is a "fast symlink", then the symlink
* target is stored in the block entries.
*/
if (LINUX_S_ISLNK (inode->i_mode)) {
if (inode->i_file_acl == 0) {
/* With no EA block, we can rely on i_blocks */
if (inode->i_blocks == 0)
return 0;
} else {
/* With an EA block, life gets more tricky */
if (inode->i_size >= EXT2_N_BLOCKS*4)
return 1; /* definitely using i_block[] */
if (inode->i_size > 4 && inode->i_block[1] == 0)
return 1; /* definitely using i_block[] */
return 0; /* Probably a fast symlink */
}
}
return 1;
}

View File

@ -0,0 +1,52 @@
/*
* version.c --- Return the version of the ext2 library
*
* Copyright (C) 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "ext2_fs.h"
#include "ext2fs.h"
//#include "../../version.h"
static const char *lib_version = E2FSPROGS_VERSION;
static const char *lib_date = E2FSPROGS_DATE;
int ext2fs_parse_version_string(const char *ver_string)
{
const char *cp;
int version = 0;
for (cp = ver_string; *cp; cp++) {
if (*cp == '.')
continue;
if (!isdigit(*cp))
break;
version = (version * 10) + (*cp - '0');
}
return version;
}
int ext2fs_get_library_version(const char **ver_string,
const char **date_string)
{
if (ver_string)
*ver_string = lib_version;
if (date_string)
*date_string = lib_date;
return ext2fs_parse_version_string(lib_version);
}

View File

@ -0,0 +1,34 @@
/*
* write_bb_file.c --- write a list of bad blocks to a FILE *
*
* Copyright (C) 1994, 1995 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*/
#include <stdio.h>
#include "ext2_fs.h"
#include "ext2fs.h"
errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
unsigned int flags EXT2FS_ATTR((unused)),
FILE *f)
{
badblocks_iterate bb_iter;
blk_t blk;
errcode_t retval;
retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
if (retval)
return retval;
while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) {
fprintf(f, "%d\n", blk);
}
ext2fs_badblocks_list_iterate_end(bb_iter);
return 0;
}