mirror of
https://github.com/sheumann/hush.git
synced 2024-12-25 18:33:06 +00:00
import ext2fs lib to prep for new e2fsprogs
This commit is contained in:
parent
b32011943a
commit
1fd98e039d
173
e2fsprogs/ext2fs/alloc.c
Normal file
173
e2fsprogs/ext2fs/alloc.c
Normal 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;
|
||||
}
|
||||
|
57
e2fsprogs/ext2fs/alloc_sb.c
Normal file
57
e2fsprogs/ext2fs/alloc_sb.c
Normal 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;
|
||||
}
|
52
e2fsprogs/ext2fs/alloc_stats.c
Normal file
52
e2fsprogs/ext2fs/alloc_stats.c
Normal 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);
|
||||
}
|
117
e2fsprogs/ext2fs/alloc_tables.c
Normal file
117
e2fsprogs/ext2fs/alloc_tables.c
Normal 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;
|
||||
}
|
||||
|
327
e2fsprogs/ext2fs/badblocks.c
Normal file
327
e2fsprogs/ext2fs/badblocks.c
Normal 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;
|
||||
}
|
63
e2fsprogs/ext2fs/bb_compat.c
Normal file
63
e2fsprogs/ext2fs/bb_compat.c
Normal 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
267
e2fsprogs/ext2fs/bb_inode.c
Normal 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
212
e2fsprogs/ext2fs/bitmaps.c
Normal 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
91
e2fsprogs/ext2fs/bitops.c
Normal 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
617
e2fsprogs/ext2fs/bitops.h
Normal 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
437
e2fsprogs/ext2fs/block.c
Normal 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
270
e2fsprogs/ext2fs/bmap.c
Normal 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
160
e2fsprogs/ext2fs/bmove.c
Normal 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
86
e2fsprogs/ext2fs/brel.h
Normal 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
197
e2fsprogs/ext2fs/brel_ma.c
Normal 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;
|
||||
}
|
68
e2fsprogs/ext2fs/check_desc.c
Normal file
68
e2fsprogs/ext2fs/check_desc.c
Normal 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
381
e2fsprogs/ext2fs/closefs.c
Normal 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;
|
||||
}
|
||||
|
72
e2fsprogs/ext2fs/cmp_bitmaps.c
Normal file
72
e2fsprogs/ext2fs/cmp_bitmaps.c
Normal 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
260
e2fsprogs/ext2fs/dblist.c
Normal 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;
|
||||
}
|
75
e2fsprogs/ext2fs/dblist_dir.c
Normal file
75
e2fsprogs/ext2fs/dblist_dir.c
Normal 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);
|
||||
}
|
219
e2fsprogs/ext2fs/dir_iterate.c
Normal file
219
e2fsprogs/ext2fs/dir_iterate.c
Normal 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
130
e2fsprogs/ext2fs/dirblock.c
Normal 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
233
e2fsprogs/ext2fs/dirhash.c
Normal 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
456
e2fsprogs/ext2fs/dosio.c
Normal 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
153
e2fsprogs/ext2fs/dosio.h
Normal 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
96
e2fsprogs/ext2fs/dupfs.c
Normal 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;
|
||||
|
||||
}
|
||||
|
51
e2fsprogs/ext2fs/e2image.h
Normal file
51
e2fsprogs/ext2fs/e2image.h
Normal 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];
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
126
e2fsprogs/ext2fs/expanddir.c
Normal file
126
e2fsprogs/ext2fs/expanddir.c
Normal 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
117
e2fsprogs/ext2fs/ext2_err.h
Normal 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
|
69
e2fsprogs/ext2fs/ext2_ext_attr.h
Normal file
69
e2fsprogs/ext2fs/ext2_ext_attr.h
Normal 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
644
e2fsprogs/ext2fs/ext2_fs.h
Normal 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
108
e2fsprogs/ext2fs/ext2_io.h
Normal 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 */
|
||||
|
1
e2fsprogs/ext2fs/ext2_types.h
Normal file
1
e2fsprogs/ext2fs/ext2_types.h
Normal file
@ -0,0 +1 @@
|
||||
#include <linux/types.h>
|
1137
e2fsprogs/ext2fs/ext2fs.h
Normal file
1137
e2fsprogs/ext2fs/ext2fs.h
Normal file
File diff suppressed because it is too large
Load Diff
88
e2fsprogs/ext2fs/ext2fsP.h
Normal file
88
e2fsprogs/ext2fs/ext2fsP.h
Normal 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
105
e2fsprogs/ext2fs/ext_attr.c
Normal 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
378
e2fsprogs/ext2fs/fileio.c
Normal 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
208
e2fsprogs/ext2fs/finddev.c
Normal 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
82
e2fsprogs/ext2fs/flushb.c
Normal 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
147
e2fsprogs/ext2fs/freefs.c
Normal 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);
|
||||
}
|
||||
|
48
e2fsprogs/ext2fs/gen_bitmap.c
Normal file
48
e2fsprogs/ext2fs/gen_bitmap.c
Normal 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);
|
||||
}
|
157
e2fsprogs/ext2fs/get_pathname.c
Normal file
157
e2fsprogs/ext2fs/get_pathname.c
Normal 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;
|
||||
|
||||
}
|
57
e2fsprogs/ext2fs/getsectsize.c
Normal file
57
e2fsprogs/ext2fs/getsectsize.c
Normal 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
290
e2fsprogs/ext2fs/getsize.c
Normal 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
483
e2fsprogs/ext2fs/icount.c
Normal 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
387
e2fsprogs/ext2fs/imager.c
Normal 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);
|
||||
}
|
66
e2fsprogs/ext2fs/ind_block.c
Normal file
66
e2fsprogs/ext2fs/ind_block.c
Normal 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);
|
||||
}
|
||||
|
||||
|
387
e2fsprogs/ext2fs/initialize.c
Normal file
387
e2fsprogs/ext2fs/initialize.c
Normal 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
32
e2fsprogs/ext2fs/inline.c
Normal 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
794
e2fsprogs/ext2fs/inode.c
Normal 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
270
e2fsprogs/ext2fs/inode_io.c
Normal 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);
|
||||
}
|
||||
|
69
e2fsprogs/ext2fs/io_manager.c
Normal file
69
e2fsprogs/ext2fs/io_manager.c
Normal 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
114
e2fsprogs/ext2fs/irel.h
Normal 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
372
e2fsprogs/ext2fs/irel_ma.c
Normal 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;
|
||||
}
|
358
e2fsprogs/ext2fs/ismounted.c
Normal file
358
e2fsprogs/ext2fs/ismounted.c
Normal 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 */
|
67
e2fsprogs/ext2fs/jfs_compat.h
Normal file
67
e2fsprogs/ext2fs/jfs_compat.h
Normal 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 */
|
64
e2fsprogs/ext2fs/jfs_dat.h
Normal file
64
e2fsprogs/ext2fs/jfs_dat.h
Normal 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;
|
||||
|
8
e2fsprogs/ext2fs/jfs_user.h
Normal file
8
e2fsprogs/ext2fs/jfs_user.h
Normal 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 */
|
910
e2fsprogs/ext2fs/kernel-jbd.h
Normal file
910
e2fsprogs/ext2fs/kernel-jbd.h
Normal 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 */
|
112
e2fsprogs/ext2fs/kernel-list.h
Normal file
112
e2fsprogs/ext2fs/kernel-list.h
Normal 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
134
e2fsprogs/ext2fs/link.c
Normal 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
135
e2fsprogs/ext2fs/llseek.c
Normal 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
69
e2fsprogs/ext2fs/lookup.c
Normal 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
142
e2fsprogs/ext2fs/mkdir.c
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
|
425
e2fsprogs/ext2fs/mkjournal.c
Normal file
425
e2fsprogs/ext2fs/mkjournal.c
Normal 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
205
e2fsprogs/ext2fs/namei.c
Normal 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
27
e2fsprogs/ext2fs/native.c
Normal 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
72
e2fsprogs/ext2fs/newdir.c
Normal 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
326
e2fsprogs/ext2fs/openfs.c
Normal 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;
|
||||
}
|
97
e2fsprogs/ext2fs/read_bb.c
Normal file
97
e2fsprogs/ext2fs/read_bb.c
Normal 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;
|
||||
}
|
||||
|
||||
|
97
e2fsprogs/ext2fs/read_bb_file.c
Normal file
97
e2fsprogs/ext2fs/read_bb_file.c
Normal 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
220
e2fsprogs/ext2fs/res_gdt.c
Normal 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;
|
||||
}
|
||||
|
106
e2fsprogs/ext2fs/rs_bitmap.c
Normal file
106
e2fsprogs/ext2fs/rs_bitmap.c
Normal 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;
|
||||
}
|
||||
|
300
e2fsprogs/ext2fs/rw_bitmaps.c
Normal file
300
e2fsprogs/ext2fs/rw_bitmaps.c
Normal 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
78
e2fsprogs/ext2fs/sparse.c
Normal 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
237
e2fsprogs/ext2fs/swapfs.c
Normal 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
382
e2fsprogs/ext2fs/test_io.c
Normal 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
707
e2fsprogs/ext2fs/unix_io.c
Normal 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
99
e2fsprogs/ext2fs/unlink.c
Normal 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;
|
||||
}
|
||||
|
56
e2fsprogs/ext2fs/valid_blk.c
Normal file
56
e2fsprogs/ext2fs/valid_blk.c
Normal 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;
|
||||
}
|
52
e2fsprogs/ext2fs/version.c
Normal file
52
e2fsprogs/ext2fs/version.c
Normal 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);
|
||||
}
|
34
e2fsprogs/ext2fs/write_bb_file.c
Normal file
34
e2fsprogs/ext2fs/write_bb_file.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user