1997-04-26 17:21:57 +04:00
|
|
|
/*
|
|
|
|
* openfs.c --- open an ext2 filesystem
|
2008-08-28 07:07:54 +04:00
|
|
|
*
|
1997-04-29 20:17:09 +04:00
|
|
|
* Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
|
2008-08-28 07:07:54 +04:00
|
|
|
*
|
1997-04-29 20:17:09 +04:00
|
|
|
* %Begin-Header%
|
2010-05-18 05:31:56 +04:00
|
|
|
* This file may be redistributed under the terms of the GNU Library
|
|
|
|
* General Public License, version 2.
|
1997-04-29 20:17:09 +04:00
|
|
|
* %End-Header%
|
1997-04-26 17:21:57 +04:00
|
|
|
*/
|
|
|
|
|
2011-09-19 01:34:37 +04:00
|
|
|
#include "config.h"
|
1997-04-26 17:21:57 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
1997-04-26 17:58:21 +04:00
|
|
|
#if HAVE_UNISTD_H
|
1997-04-26 17:21:57 +04:00
|
|
|
#include <unistd.h>
|
1997-04-26 17:58:21 +04:00
|
|
|
#endif
|
1997-04-26 17:21:57 +04:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <time.h>
|
1997-10-20 03:00:21 +04:00
|
|
|
#if HAVE_SYS_STAT_H
|
1997-04-26 17:21:57 +04:00
|
|
|
#include <sys/stat.h>
|
1997-10-20 03:00:21 +04:00
|
|
|
#endif
|
|
|
|
#if HAVE_SYS_TYPES_H
|
1997-04-26 17:21:57 +04:00
|
|
|
#include <sys/types.h>
|
1997-10-20 03:00:21 +04:00
|
|
|
#endif
|
2011-09-24 21:48:55 +04:00
|
|
|
#ifdef HAVE_ERRNO_H
|
|
|
|
#include <errno.h>
|
|
|
|
#endif
|
1997-04-26 17:21:57 +04:00
|
|
|
|
Many files:
inode.c (ext2fs_open_inode_scan): Initialize the group variables
so that we don't need to call get_next_blockgroup() the first
time around. Saves a bit of time, and prevents us from
needing to assign -1 to current_group (which is an unsigned
value).
icount.c (insert_icount_el): Cast the estimated number of inodes
from a float to an ino_t.
alloc.c, alloc_tables.c, badlbocks.c, bb_compat.c, bb_inode.c,
bitmaps.c, bitops.c, block.c, bmap.c, bmove.c, brel_ma.c,
check_desc.c, closefs.c, cmp_bitmaps.c, dblist.c,
dblist_dir.c, dir_iterate.c, dirblock.c, dupfs.c, expanddir.c,
ext2fs.h, fileio.c, freefs.c, get_pathname.c, getsize.c,
icount.c, initialize.c, inline.c, inode.c, irel_ma.c,
ismounted.c, link.c, lookup.c, mkdir.c, namei.c, native.c,
newdir.c, openfs.c, read_bb.c, read_bb_file.c, rs_bitmap.c,
rw_bitmaps.c, swapfs.c, test_io.c, tst_badblocks.c,
tst_getsize.c, tst_iscan.c, unix_io.c, unlink.c, valid_blk.c,
version.c: If EXT2_FLAT_INCLUDES is defined, then assume all
of the ext2-specific header files are in a flat directory.
block.c, bmove.c, dirblock.c, fileio.c: Explicitly cast
all assignments from void * to be compatible with C++.
closefs.c (ext2fs_flush): Add a call to io_channel_flush() to
make sure the contents of the disk are flushed to disk.
dblist.c (ext2fs_add_dir_block): Change new to be new_entry to
avoid C++ namespace clash.
bitmaps.c (ext2fs_copy_bitmap): Change new to be new_map to
avoid C++ namespace clash.
ext2fs.h, bb_inode.c, block.c, bmove.c, brel.h, brel_ma.c,
irel.h, irel_ma.c, dblist.c, dblist_dir.c, dir_iterate.c,
ext2fsP.h, expanddir.c, get_pathname.c, inode.c, link.c,
unlink.c: Change private to be priv_data (to avoid C++
namespace clash)
1998-01-19 17:47:53 +03:00
|
|
|
#include "ext2_fs.h"
|
2002-10-20 08:38:57 +04:00
|
|
|
|
|
|
|
|
1997-04-26 17:21:57 +04:00
|
|
|
#include "ext2fs.h"
|
2001-05-03 08:02:29 +04:00
|
|
|
#include "e2image.h"
|
1997-04-26 17:21:57 +04:00
|
|
|
|
2009-06-02 00:15:40 +04:00
|
|
|
blk64_t ext2fs_descriptor_block_loc2(ext2_filsys fs, blk64_t group_block,
|
|
|
|
dgrp_t i)
|
2002-10-20 08:38:57 +04:00
|
|
|
{
|
|
|
|
int bg;
|
2014-01-11 22:58:15 +04:00
|
|
|
int has_super = 0, group_zero_adjust = 0;
|
2009-06-02 00:15:40 +04:00
|
|
|
blk64_t ret_blk;
|
2002-10-20 08:38:57 +04:00
|
|
|
|
2014-01-11 22:58:15 +04:00
|
|
|
/*
|
|
|
|
* On a bigalloc FS with 1K blocks, block 0 is reserved for non-ext4
|
|
|
|
* stuff, so adjust for that if we're being asked for group 0.
|
|
|
|
*/
|
|
|
|
if (i == 0 && fs->blocksize == 1024 && EXT2FS_CLUSTER_RATIO(fs) > 1)
|
|
|
|
group_zero_adjust = 1;
|
|
|
|
|
2002-10-20 08:38:57 +04:00
|
|
|
if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
|
|
|
|
(i < fs->super->s_first_meta_bg))
|
2014-01-11 22:58:15 +04:00
|
|
|
return group_block + i + 1 + group_zero_adjust;
|
2002-10-20 08:38:57 +04:00
|
|
|
|
2007-08-30 19:38:13 +04:00
|
|
|
bg = EXT2_DESC_PER_BLOCK(fs->super) * i;
|
2002-10-20 08:38:57 +04:00
|
|
|
if (ext2fs_bg_has_super(fs, bg))
|
|
|
|
has_super = 1;
|
2014-01-11 22:54:57 +04:00
|
|
|
ret_blk = ext2fs_group_first_block2(fs, bg);
|
2002-10-31 19:45:06 +03:00
|
|
|
/*
|
|
|
|
* 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 &&
|
2014-01-11 22:54:57 +04:00
|
|
|
((ret_blk + has_super + fs->super->s_blocks_per_group) <
|
|
|
|
ext2fs_blocks_count(fs->super))) {
|
2002-10-31 19:45:06 +03:00
|
|
|
ret_blk += fs->super->s_blocks_per_group;
|
2014-01-11 22:54:57 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're going to jump forward a block group, make sure
|
|
|
|
* that we adjust has_super to account for the next group's
|
|
|
|
* backup superblock (or lack thereof).
|
|
|
|
*/
|
|
|
|
if (ext2fs_bg_has_super(fs, bg + 1))
|
|
|
|
has_super = 1;
|
|
|
|
else
|
|
|
|
has_super = 0;
|
|
|
|
}
|
2014-01-11 22:58:15 +04:00
|
|
|
return ret_blk + has_super + group_zero_adjust;
|
2002-10-20 08:38:57 +04:00
|
|
|
}
|
|
|
|
|
2009-06-02 00:15:40 +04:00
|
|
|
blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i)
|
|
|
|
{
|
|
|
|
return ext2fs_descriptor_block_loc2(fs, group_block, i);
|
|
|
|
}
|
|
|
|
|
2004-11-30 22:07:11 +03:00
|
|
|
errcode_t ext2fs_open(const char *name, int flags, int superblock,
|
2008-08-28 07:07:54 +04:00
|
|
|
unsigned int block_size, io_manager manager,
|
2004-11-30 22:07:11 +03:00
|
|
|
ext2_filsys *ret_fs)
|
|
|
|
{
|
2008-08-28 07:07:54 +04:00
|
|
|
return ext2fs_open2(name, 0, flags, superblock, block_size,
|
2004-11-30 22:07:11 +03:00
|
|
|
manager, ret_fs);
|
|
|
|
}
|
|
|
|
|
1997-04-26 17:21:57 +04:00
|
|
|
/*
|
|
|
|
* 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.
|
1997-04-29 20:17:09 +04:00
|
|
|
*
|
|
|
|
* Valid flags for ext2fs_open()
|
2008-08-28 07:07:54 +04:00
|
|
|
*
|
1997-04-29 20:17:09 +04:00
|
|
|
* EXT2_FLAG_RW - Open the filesystem for read/write.
|
|
|
|
* EXT2_FLAG_FORCE - Open the filesystem even if some of the
|
2001-05-14 03:12:10 +04:00
|
|
|
* features aren't supported.
|
|
|
|
* EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
|
2011-09-24 21:48:55 +04:00
|
|
|
* EXT2_FLAG_SKIP_MMP - Open without multi-mount protection check.
|
2012-03-23 03:48:10 +04:00
|
|
|
* EXT2_FLAG_64BITS - Allow 64-bit bitfields (needed for large
|
|
|
|
* filesystems)
|
1997-04-26 17:21:57 +04:00
|
|
|
*/
|
2004-11-30 22:07:11 +03:00
|
|
|
errcode_t ext2fs_open2(const char *name, const char *io_options,
|
|
|
|
int flags, int superblock,
|
2008-08-28 07:07:54 +04:00
|
|
|
unsigned int block_size, io_manager manager,
|
2004-11-30 22:07:11 +03:00
|
|
|
ext2_filsys *ret_fs)
|
1997-04-26 17:21:57 +04:00
|
|
|
{
|
|
|
|
ext2_filsys fs;
|
|
|
|
errcode_t retval;
|
2009-04-23 09:30:42 +04:00
|
|
|
unsigned long i, first_meta_bg;
|
2006-11-13 07:26:46 +03:00
|
|
|
__u32 features;
|
2013-01-01 22:28:27 +04:00
|
|
|
unsigned int blocks_per_group, io_flags;
|
2010-06-13 19:00:00 +04:00
|
|
|
blk64_t group_block, blk;
|
2004-11-30 22:07:11 +03:00
|
|
|
char *dest, *cp;
|
2014-01-11 22:58:15 +04:00
|
|
|
int group_zero_adjust = 0;
|
2008-03-18 06:17:13 +03:00
|
|
|
#ifdef WORDS_BIGENDIAN
|
2013-01-01 22:28:27 +04:00
|
|
|
unsigned int groups_per_block;
|
1997-04-26 17:58:21 +04:00
|
|
|
struct ext2_group_desc *gdp;
|
2008-03-18 06:17:13 +03:00
|
|
|
int j;
|
|
|
|
#endif
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-04-26 17:34:30 +04:00
|
|
|
EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
|
1997-10-26 06:41:24 +03:00
|
|
|
|
2003-08-01 17:41:07 +04:00
|
|
|
retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
|
1997-10-26 06:41:24 +03:00
|
|
|
if (retval)
|
|
|
|
return retval;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-04-26 17:21:57 +04:00
|
|
|
memset(fs, 0, sizeof(struct struct_ext2_filsys));
|
1997-04-26 17:34:30 +04:00
|
|
|
fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
|
1997-04-26 17:21:57 +04:00
|
|
|
fs->flags = flags;
|
2007-06-19 02:26:50 +04:00
|
|
|
/* don't overwrite sb backups unless flag is explicitly cleared */
|
|
|
|
fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
|
2001-12-24 17:40:00 +03:00
|
|
|
fs->umask = 022;
|
2004-11-30 22:07:11 +03:00
|
|
|
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;
|
|
|
|
}
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2006-03-19 03:16:10 +03:00
|
|
|
io_flags = 0;
|
|
|
|
if (flags & EXT2_FLAG_RW)
|
|
|
|
io_flags |= IO_FLAG_RW;
|
|
|
|
if (flags & EXT2_FLAG_EXCLUSIVE)
|
|
|
|
io_flags |= IO_FLAG_EXCLUSIVE;
|
2010-09-24 18:02:25 +04:00
|
|
|
if (flags & EXT2_FLAG_DIRECT_IO)
|
|
|
|
io_flags |= IO_FLAG_DIRECT_IO;
|
2006-03-19 03:16:10 +03:00
|
|
|
retval = manager->open(fs->device_name, io_flags, &fs->io);
|
1997-04-26 17:21:57 +04:00
|
|
|
if (retval)
|
|
|
|
goto cleanup;
|
2008-08-28 07:07:54 +04:00
|
|
|
if (io_options &&
|
2004-11-30 22:07:11 +03:00
|
|
|
(retval = io_channel_set_options(fs->io, io_options)))
|
|
|
|
goto cleanup;
|
2004-07-29 05:11:48 +04:00
|
|
|
fs->image_io = fs->io;
|
1997-08-24 06:57:55 +04:00
|
|
|
fs->io->app_data = fs;
|
2012-05-07 22:41:49 +04:00
|
|
|
retval = io_channel_alloc_buf(fs->io, -SUPERBLOCK_SIZE, &fs->super);
|
1997-10-26 06:41:24 +03:00
|
|
|
if (retval)
|
1997-04-26 17:21:57 +04:00
|
|
|
goto cleanup;
|
2001-05-03 08:02:29 +04:00
|
|
|
if (flags & EXT2_FLAG_IMAGE_FILE) {
|
|
|
|
retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr),
|
2003-08-01 17:41:07 +04:00
|
|
|
&fs->image_header);
|
2001-05-03 08:02:29 +04:00
|
|
|
if (retval)
|
|
|
|
goto cleanup;
|
|
|
|
retval = io_channel_read_blk(fs->io, 0,
|
2006-05-22 03:26:45 +04:00
|
|
|
-(int)sizeof(struct ext2_image_hdr),
|
2001-05-03 08:02:29 +04:00
|
|
|
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;
|
|
|
|
}
|
1997-04-26 17:21:57 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
2000-10-27 00:24:43 +04:00
|
|
|
*
|
|
|
|
* Note: we only save a backup copy of the superblock if we
|
|
|
|
* are reading the superblock from the primary superblock location.
|
1997-04-26 17:21:57 +04:00
|
|
|
*/
|
|
|
|
if (superblock) {
|
|
|
|
if (!block_size) {
|
1997-10-31 09:07:47 +03:00
|
|
|
retval = EXT2_ET_INVALID_ARGUMENT;
|
1997-04-26 17:21:57 +04:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
io_channel_set_blksize(fs->io, block_size);
|
2002-10-31 19:45:06 +03:00
|
|
|
group_block = superblock;
|
2000-10-27 00:24:43 +04:00
|
|
|
fs->orig_super = 0;
|
1997-04-26 17:21:57 +04:00
|
|
|
} else {
|
|
|
|
io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
|
|
|
|
superblock = 1;
|
1997-04-26 17:34:30 +04:00
|
|
|
group_block = 0;
|
2003-08-01 17:41:07 +04:00
|
|
|
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
|
2000-10-27 00:24:43 +04:00
|
|
|
if (retval)
|
|
|
|
goto cleanup;
|
1997-04-26 17:21:57 +04:00
|
|
|
}
|
|
|
|
retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
|
|
|
|
fs->super);
|
|
|
|
if (retval)
|
|
|
|
goto cleanup;
|
2000-10-27 00:24:43 +04:00
|
|
|
if (fs->orig_super)
|
|
|
|
memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
|
1997-04-26 17:58:21 +04:00
|
|
|
|
2012-08-03 04:47:44 +04:00
|
|
|
if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) {
|
|
|
|
retval = 0;
|
|
|
|
if (!ext2fs_verify_csum_type(fs, fs->super))
|
|
|
|
retval = EXT2_ET_UNKNOWN_CSUM;
|
|
|
|
if (!ext2fs_superblock_csum_verify(fs, fs->super))
|
|
|
|
retval = EXT2_ET_SB_CSUM_INVALID;
|
|
|
|
if (retval)
|
|
|
|
goto cleanup;
|
2012-08-03 04:47:44 +04:00
|
|
|
}
|
|
|
|
|
2007-08-11 09:56:48 +04:00
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
|
|
fs->flags |= EXT2_FLAG_SWAP_BYTES;
|
|
|
|
ext2fs_swap_super(fs->super);
|
|
|
|
#else
|
|
|
|
if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
|
|
|
|
retval = EXT2_ET_UNIMPLEMENTED;
|
|
|
|
goto cleanup;
|
1997-04-26 17:58:21 +04:00
|
|
|
}
|
ChangeLog, Makefile.in, swapfs.c, unix.c:
Makefile.in: Add message.c and swapfs.c to the list of source files to
build the make depend.
swapfs.c, unix.c: Only support the -s and -S options to e2fsck if
ENABLE_SWAPFS is defined.
Many files:
ext2fs.h, bitops.h, block.c, bmap.c, closefs.c, dirblock.c, inode.c,
native.c, openfs.c, rw_bitmaps.c, swapfs.c: Only include the
byte-swapping logic if ENABLE_SWAPFS is turned on or if we're on a
big-endian machine.
initialize.c (ext2fs_initialize):Use WORDS_BIGENDIAN directly to set
EXT2_FLAG_SWAP_BYTES, instead of using ext2fs_native_flag.
native.c (ext2fs_native_flag): Use WORDS_BIGENDIAN provided by
autoconf to determine whether or not return EXT2_FLAG_SWAP_BYTES.
2001-06-11 11:00:04 +04:00
|
|
|
#endif
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-04-26 17:21:57 +04:00
|
|
|
if (fs->super->s_magic != EXT2_SUPER_MAGIC) {
|
|
|
|
retval = EXT2_ET_BAD_MAGIC;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
1997-04-26 17:34:30 +04:00
|
|
|
if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) {
|
|
|
|
retval = EXT2_ET_REV_TOO_HIGH;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2001-01-01 19:17:12 +03:00
|
|
|
|
1997-04-29 20:17:09 +04:00
|
|
|
/*
|
|
|
|
* Check for feature set incompatibility
|
|
|
|
*/
|
|
|
|
if (!(flags & EXT2_FLAG_FORCE)) {
|
2006-11-13 07:26:46 +03:00
|
|
|
features = fs->super->s_feature_incompat;
|
|
|
|
#ifdef EXT2_LIB_SOFTSUPP_INCOMPAT
|
|
|
|
if (flags & EXT2_FLAG_SOFTSUPP_FEATURES)
|
2011-09-17 00:49:16 +04:00
|
|
|
features &= ~EXT2_LIB_SOFTSUPP_INCOMPAT;
|
2006-11-13 07:26:46 +03:00
|
|
|
#endif
|
|
|
|
if (features & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
|
1997-04-29 20:17:09 +04:00
|
|
|
retval = EXT2_ET_UNSUPP_FEATURE;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2006-11-13 07:26:46 +03:00
|
|
|
|
|
|
|
features = fs->super->s_feature_ro_compat;
|
|
|
|
#ifdef EXT2_LIB_SOFTSUPP_RO_COMPAT
|
|
|
|
if (flags & EXT2_FLAG_SOFTSUPP_FEATURES)
|
2011-09-17 00:49:16 +04:00
|
|
|
features &= ~EXT2_LIB_SOFTSUPP_RO_COMPAT;
|
2006-11-13 07:26:46 +03:00
|
|
|
#endif
|
1997-04-29 20:17:09 +04:00
|
|
|
if ((flags & EXT2_FLAG_RW) &&
|
2006-11-13 07:26:46 +03:00
|
|
|
(features & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
|
1997-04-29 20:17:09 +04:00
|
|
|
retval = EXT2_ET_RO_UNSUPP_FEATURE;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2006-11-13 07:26:46 +03:00
|
|
|
|
ChangeLog, ext2_err.et.in, ext2fs.h, initialize.c, mkjournal.c, openfs.c:
initialize.c (ext2fs_initialize): Add support for initializing the
ext2 superblock for external journal devices. This basically means we
don't bother to allocate any block group descriptors.
openfs.c (ext2fs_open): Only open external journal devices if the new
flag EXT2_FLAG_JOURNAL_DEV_OK is passed to ext2fs_open. When opening
such devices, don't try to read the block group descriptors, since
they're not there.
ext2_err.et.in (EXT2_NO_JOURNAL_SB): Add new error code
mkjournal.c: Export a new function,
ext2fs_create_journal_superblock(), which allocates and returns a
buffer containing a journal superblock. This is needed by mke2fs to
create an external journal. Rewrote ext2fs_add_journal_device() so
that it no longer creates the external journal, but rather adds a
filesystem to an existing external journal. It handles all of the
UUID manipulation.
ext2fs.h: List the EXT3_FEATURE_JOURNAL_DEV as a flag supported by the
library. Define the EXT2_FLAG_JOURNAL_DEV_OK. Changed function
prototype for ext2fs_add_journal_device().
2001-01-16 09:56:14 +03:00
|
|
|
if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) &&
|
|
|
|
(fs->super->s_feature_incompat &
|
|
|
|
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
|
|
|
|
retval = EXT2_ET_UNSUPP_FEATURE;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
1997-04-29 20:17:09 +04:00
|
|
|
}
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2008-07-12 01:45:07 +04:00
|
|
|
if ((fs->super->s_log_block_size + EXT2_MIN_BLOCK_LOG_SIZE) >
|
|
|
|
EXT2_MAX_BLOCK_LOG_SIZE) {
|
1997-04-29 18:53:37 +04:00
|
|
|
retval = EXT2_ET_CORRUPT_SUPERBLOCK;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-10-12 05:20:54 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* bigalloc requires cluster-aware bitfield operations, which at the
|
|
|
|
* moment means we need EXT2_FLAG_64BITS.
|
|
|
|
*/
|
|
|
|
if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
|
|
|
|
EXT4_FEATURE_RO_COMPAT_BIGALLOC) &&
|
|
|
|
!(flags & EXT2_FLAG_64BITS)) {
|
|
|
|
retval = EXT2_ET_CANT_USE_LEGACY_BITMAPS;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-06-05 00:36:19 +04:00
|
|
|
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
|
|
|
|
EXT4_FEATURE_RO_COMPAT_BIGALLOC) &&
|
|
|
|
(fs->super->s_log_block_size != fs->super->s_log_cluster_size)) {
|
|
|
|
retval = EXT2_ET_CORRUPT_SUPERBLOCK;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-09-15 23:44:56 +04:00
|
|
|
fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
|
2007-09-08 00:40:25 +04:00
|
|
|
if (EXT2_INODE_SIZE(fs->super) < EXT2_GOOD_OLD_INODE_SIZE) {
|
|
|
|
retval = EXT2_ET_CORRUPT_SUPERBLOCK;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-31 01:40:15 +04:00
|
|
|
|
|
|
|
/* Enforce the block group descriptor size */
|
|
|
|
if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) {
|
2013-12-26 09:30:56 +04:00
|
|
|
if (fs->super->s_desc_size < EXT2_MIN_DESC_SIZE_64BIT) {
|
2012-07-31 01:40:15 +04:00
|
|
|
retval = EXT2_ET_BAD_DESC_SIZE;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (fs->super->s_desc_size &&
|
|
|
|
fs->super->s_desc_size != EXT2_MIN_DESC_SIZE) {
|
|
|
|
retval = EXT2_ET_BAD_DESC_SIZE;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-04 18:20:47 +04:00
|
|
|
fs->cluster_ratio_bits = fs->super->s_log_cluster_size -
|
|
|
|
fs->super->s_log_block_size;
|
|
|
|
if (EXT2_BLOCKS_PER_GROUP(fs->super) !=
|
|
|
|
EXT2_CLUSTERS_PER_GROUP(fs->super) << fs->cluster_ratio_bits) {
|
|
|
|
retval = EXT2_ET_CORRUPT_SUPERBLOCK;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-01-20 07:16:10 +03:00
|
|
|
fs->inode_blocks_per_group = ((EXT2_INODES_PER_GROUP(fs->super) *
|
1997-04-26 18:48:50 +04:00
|
|
|
EXT2_INODE_SIZE(fs->super) +
|
|
|
|
EXT2_BLOCK_SIZE(fs->super) - 1) /
|
|
|
|
EXT2_BLOCK_SIZE(fs->super));
|
1997-04-26 17:21:57 +04:00
|
|
|
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);
|
ChangeLog, ext2_err.et.in, ext2fs.h, initialize.c, mkjournal.c, openfs.c:
initialize.c (ext2fs_initialize): Add support for initializing the
ext2 superblock for external journal devices. This basically means we
don't bother to allocate any block group descriptors.
openfs.c (ext2fs_open): Only open external journal devices if the new
flag EXT2_FLAG_JOURNAL_DEV_OK is passed to ext2fs_open. When opening
such devices, don't try to read the block group descriptors, since
they're not there.
ext2_err.et.in (EXT2_NO_JOURNAL_SB): Add new error code
mkjournal.c: Export a new function,
ext2fs_create_journal_superblock(), which allocates and returns a
buffer containing a journal superblock. This is needed by mke2fs to
create an external journal. Rewrote ext2fs_add_journal_device() so
that it no longer creates the external journal, but rather adds a
filesystem to an existing external journal. It handles all of the
UUID manipulation.
ext2fs.h: List the EXT3_FEATURE_JOURNAL_DEV as a flag supported by the
library. Define the EXT2_FLAG_JOURNAL_DEV_OK. Changed function
prototype for ext2fs_add_journal_device().
2001-01-16 09:56:14 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2009-03-17 05:16:44 +03:00
|
|
|
if (EXT2_INODES_PER_GROUP(fs->super) == 0) {
|
|
|
|
retval = EXT2_ET_CORRUPT_SUPERBLOCK;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-31 02:44:04 +04:00
|
|
|
/* Precompute the FS UUID to seed other checksums */
|
|
|
|
ext2fs_init_csum_seed(fs);
|
2009-03-17 05:16:44 +03:00
|
|
|
|
1997-04-26 17:21:57 +04:00
|
|
|
/*
|
|
|
|
* Read group descriptors
|
|
|
|
*/
|
2002-06-10 21:05:56 +04:00
|
|
|
blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super);
|
|
|
|
if (blocks_per_group == 0 ||
|
|
|
|
blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) ||
|
2009-01-20 07:16:10 +03:00
|
|
|
fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super) ||
|
|
|
|
EXT2_DESC_PER_BLOCK(fs->super) == 0 ||
|
2009-09-08 04:46:34 +04:00
|
|
|
fs->super->s_first_data_block >= ext2fs_blocks_count(fs->super)) {
|
1999-05-30 01:48:03 +04:00
|
|
|
retval = EXT2_ET_CORRUPT_SUPERBLOCK;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-09-08 04:46:34 +04:00
|
|
|
fs->group_desc_count = ext2fs_div64_ceil(ext2fs_blocks_count(fs->super) -
|
|
|
|
fs->super->s_first_data_block,
|
|
|
|
blocks_per_group);
|
|
|
|
if (fs->group_desc_count * EXT2_INODES_PER_GROUP(fs->super) !=
|
|
|
|
fs->super->s_inodes_count) {
|
|
|
|
retval = EXT2_ET_CORRUPT_SUPERBLOCK;
|
2009-01-20 07:16:10 +03:00
|
|
|
goto cleanup;
|
2009-09-08 04:46:34 +04:00
|
|
|
}
|
2006-08-30 09:57:00 +04:00
|
|
|
fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
|
|
|
|
EXT2_DESC_PER_BLOCK(fs->super));
|
2007-11-10 03:01:06 +03:00
|
|
|
retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize,
|
2003-08-01 17:41:07 +04:00
|
|
|
&fs->group_desc);
|
1997-10-26 06:41:24 +03:00
|
|
|
if (retval)
|
1997-04-26 17:21:57 +04:00
|
|
|
goto cleanup;
|
1997-04-26 17:34:30 +04:00
|
|
|
if (!group_block)
|
2002-10-20 08:38:57 +04:00
|
|
|
group_block = fs->super->s_first_data_block;
|
2014-01-11 22:58:15 +04:00
|
|
|
/*
|
|
|
|
* On a FS with a 1K blocksize, block 0 is reserved for bootloaders
|
|
|
|
* so we must increment block numbers to any group 0 items.
|
|
|
|
*
|
|
|
|
* However, we cannot touch group_block directly because in the meta_bg
|
|
|
|
* case, the ext2fs_descriptor_block_loc2() function will interpret
|
|
|
|
* group_block != s_first_data_block to mean that we want to access the
|
|
|
|
* backup group descriptors. This is not what we want if the caller
|
|
|
|
* set superblock == 0 (i.e. auto-detect the superblock), which is
|
|
|
|
* what's going on here.
|
|
|
|
*/
|
2011-07-05 21:42:07 +04:00
|
|
|
if (group_block == 0 && fs->blocksize == 1024)
|
2014-01-11 22:58:15 +04:00
|
|
|
group_zero_adjust = 1;
|
1997-04-26 17:21:57 +04:00
|
|
|
dest = (char *) fs->group_desc;
|
2013-01-01 22:28:27 +04:00
|
|
|
#ifdef WORDS_BIGENDIAN
|
2007-08-30 19:38:13 +04:00
|
|
|
groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
|
2013-01-01 22:28:27 +04:00
|
|
|
#endif
|
2009-04-23 09:30:42 +04:00
|
|
|
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
|
|
|
|
first_meta_bg = fs->super->s_first_meta_bg;
|
|
|
|
else
|
|
|
|
first_meta_bg = fs->desc_blocks;
|
|
|
|
if (first_meta_bg) {
|
2014-01-11 22:58:15 +04:00
|
|
|
retval = io_channel_read_blk(fs->io, group_block +
|
|
|
|
group_zero_adjust + 1,
|
2009-04-23 09:30:42 +04:00
|
|
|
first_meta_bg, dest);
|
|
|
|
if (retval)
|
|
|
|
goto cleanup;
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
|
|
gdp = (struct ext2_group_desc *) dest;
|
2010-07-31 02:41:47 +04:00
|
|
|
for (j=0; j < groups_per_block*first_meta_bg; j++) {
|
|
|
|
gdp = ext2fs_group_desc(fs, fs->group_desc, j);
|
|
|
|
ext2fs_swap_group_desc2(fs, gdp);
|
|
|
|
}
|
2009-04-23 09:30:42 +04:00
|
|
|
#endif
|
|
|
|
dest += fs->blocksize*first_meta_bg;
|
|
|
|
}
|
|
|
|
for (i=first_meta_bg ; i < fs->desc_blocks; i++) {
|
2010-06-13 19:00:00 +04:00
|
|
|
blk = ext2fs_descriptor_block_loc2(fs, group_block, i);
|
2009-09-08 05:14:24 +04:00
|
|
|
retval = io_channel_read_blk64(fs->io, blk, 1, dest);
|
1997-04-26 17:21:57 +04:00
|
|
|
if (retval)
|
|
|
|
goto cleanup;
|
2007-08-11 09:56:48 +04:00
|
|
|
#ifdef WORDS_BIGENDIAN
|
2009-10-26 04:46:01 +03:00
|
|
|
for (j=0; j < groups_per_block; j++) {
|
2011-11-10 16:02:04 +04:00
|
|
|
gdp = ext2fs_group_desc(fs, fs->group_desc,
|
|
|
|
i * groups_per_block + j);
|
2009-10-26 04:46:01 +03:00
|
|
|
ext2fs_swap_group_desc2(fs, gdp);
|
|
|
|
}
|
ChangeLog, Makefile.in, swapfs.c, unix.c:
Makefile.in: Add message.c and swapfs.c to the list of source files to
build the make depend.
swapfs.c, unix.c: Only support the -s and -S options to e2fsck if
ENABLE_SWAPFS is defined.
Many files:
ext2fs.h, bitops.h, block.c, bmap.c, closefs.c, dirblock.c, inode.c,
native.c, openfs.c, rw_bitmaps.c, swapfs.c: Only include the
byte-swapping logic if ENABLE_SWAPFS is turned on or if we're on a
big-endian machine.
initialize.c (ext2fs_initialize):Use WORDS_BIGENDIAN directly to set
EXT2_FLAG_SWAP_BYTES, instead of using ext2fs_native_flag.
native.c (ext2fs_native_flag): Use WORDS_BIGENDIAN provided by
autoconf to determine whether or not return EXT2_FLAG_SWAP_BYTES.
2001-06-11 11:00:04 +04:00
|
|
|
#endif
|
1997-04-26 17:21:57 +04:00
|
|
|
dest += fs->blocksize;
|
|
|
|
}
|
|
|
|
|
2007-05-19 06:06:53 +04:00
|
|
|
fs->stride = fs->super->s_raid_stride;
|
|
|
|
|
2007-10-22 06:03:25 +04:00
|
|
|
/*
|
|
|
|
* If recovery is from backup superblock, Clear _UNININT flags &
|
|
|
|
* reset bg_itable_unused to zero
|
|
|
|
*/
|
2012-08-03 04:47:45 +04:00
|
|
|
if (superblock > 1 && ext2fs_has_group_desc_csum(fs)) {
|
2009-09-08 05:15:12 +04:00
|
|
|
dgrp_t group;
|
|
|
|
|
|
|
|
for (group = 0; group < fs->group_desc_count; group++) {
|
libext2fs: clean up ext2fs_bg_flags_ interfaces
The ext2fs_bg_flag* functions were confusing.
Currently we have this:
void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags);
void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group,__u16 bg_flags);
(_set (unused) sets exactly bg_flags; _clear clears all and ignores bg_flags)
and these, which can twiddle individual bits in bg_flags:
void ext2fs_bg_flag_set(ext2_filsys fs, dgrp_t group, __u16 bg_flag);
void ext2fs_bg_flag_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flag);
A better interface, after the patch below, is just:
ext2fs_bg_flags_zap(fs, group) /* zeros bg_flags */
ext2fs_bg_flags_set(fs, group, flags) /* adds flags to bg_flags */
ext2fs_bg_flags_clear(fs, group, flags) /* clears flags in bg_flags */
and remove the original ext2fs_bg_flags_set / ext2fs_bg_flags_clear.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2009-10-26 04:41:32 +03:00
|
|
|
ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
|
|
|
|
ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
|
Convert to use block group accessor functions
Convert direct accesses to use the following block group accessor
functions: ext2fs_block_bitmap_loc(), ext2fs_inode_bitmap_loc(),
ext2fs_inode_table_loc(), ext2fs_bg_itable_unused(),
ext2fs_block_bitmap_loc_set(), ext2fs_inode_bitmap_loc_set(),
ext2fs_inode_table_loc_set(), ext2fs_bg_free_inodes_count(),
ext2fs_ext2fs_bg_used_dirs_count(), ext2fs_bg_free_inodes_count_set(),
ext2fs_bg_free_blocks_count_set(), ext2fs_bg_used_dirs_count_set()
Signed-off-by: Valerie Aurora Henson <vaurora@redhat.com>
Signed-off-by: Nick Dokos <nicholas.dokos@hp.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2009-10-26 04:43:47 +03:00
|
|
|
ext2fs_bg_itable_unused_set(fs, group, 0);
|
2012-02-08 06:11:21 +04:00
|
|
|
/* The checksum will be reset later, but fix it here
|
|
|
|
* anyway to avoid printing a lot of spurious errors. */
|
|
|
|
ext2fs_group_desc_csum_set(fs, group);
|
2007-10-22 06:03:25 +04:00
|
|
|
}
|
libext2fs: don't mark the superblock as dirty if the fs was opened r/o
If the file system is read/only opened with a backup superblock, and
the file system has uninit_bg enabled, the super block must not be
marked as dirty; otherwise, ext2fs_close() will call ext2fs_flush(),
which will fail, since the file descriptor for the block device was
opened read/only, and then the file descriptor won't actually be
closed.
This is normally not a problem since most of the time the program will
exit shortly after calling ext2fs_close(), and many programs don't
bother checking the error return from ext2fs_close(), especially if
the file system was opened read/only.
A big exception to this is e2fsck, since it opens and close the file
systems during its startup, and to make matters worse, registers an
error handler which will noisly complain about the failed writes
caused by ext2fs_flush().
Fix this by not marking the superblock as dirty if the file system was
opened read/only. The changes to the block group descriptors to clear
the uninit bits will still happen, so that e2fsck -n will properly
scan the whole file system. However, those changes will get dropped
when the file system handle is closed.
Addresses-SourceForge-Bug: #3444351
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-02-21 05:27:58 +04:00
|
|
|
if (fs->flags & EXT2_FLAG_RW)
|
|
|
|
ext2fs_mark_super_dirty(fs);
|
2007-10-22 06:03:25 +04:00
|
|
|
}
|
|
|
|
|
2011-09-24 21:48:55 +04:00
|
|
|
if ((fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) &&
|
|
|
|
!(flags & EXT2_FLAG_SKIP_MMP) &&
|
|
|
|
(flags & (EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE))) {
|
|
|
|
retval = ext2fs_mmp_start(fs);
|
|
|
|
if (retval) {
|
|
|
|
fs->flags |= EXT2_FLAG_SKIP_MMP; /* just do cleanup */
|
|
|
|
ext2fs_mmp_stop(fs);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-09 05:47:11 +04:00
|
|
|
fs->flags &= ~EXT2_FLAG_NOFREE_ON_ERROR;
|
|
|
|
*ret_fs = fs;
|
|
|
|
|
1997-04-26 17:21:57 +04:00
|
|
|
return 0;
|
|
|
|
cleanup:
|
2014-02-21 05:54:29 +04:00
|
|
|
if (!(flags & EXT2_FLAG_NOFREE_ON_ERROR)) {
|
2008-02-27 04:45:36 +03:00
|
|
|
ext2fs_free(fs);
|
2014-02-21 05:54:29 +04:00
|
|
|
fs = NULL;
|
|
|
|
}
|
|
|
|
*ret_fs = fs;
|
1997-04-26 17:21:57 +04:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2004-07-29 05:11:48 +04:00
|
|
|
/*
|
|
|
|
* Set/get the filesystem data I/O channel.
|
2008-08-28 07:07:54 +04:00
|
|
|
*
|
2004-07-29 05:11:48 +04:00
|
|
|
* 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)
|
|
|
|
{
|
2013-12-02 23:47:08 +04:00
|
|
|
errcode_t err;
|
|
|
|
|
2004-07-29 05:11:48 +04:00
|
|
|
if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
|
|
|
|
return EXT2_ET_NOT_IMAGE_FILE;
|
2013-12-02 23:47:08 +04:00
|
|
|
err = io_channel_set_blksize(new_io, fs->blocksize);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2013-12-02 23:52:31 +04:00
|
|
|
if ((new_io == fs->image_io) || (new_io == fs->io))
|
|
|
|
return 0;
|
|
|
|
if ((fs->image_io != fs->io) &&
|
|
|
|
fs->image_io)
|
|
|
|
io_channel_close(fs->image_io);
|
|
|
|
if (fs->io)
|
|
|
|
io_channel_close(fs->io);
|
2004-07-29 05:11:48 +04:00
|
|
|
fs->io = fs->image_io = new_io;
|
2008-08-28 07:07:54 +04:00
|
|
|
fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW |
|
2004-07-29 05:11:48 +04:00
|
|
|
EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
|
|
|
|
fs->flags &= ~EXT2_FLAG_IMAGE_FILE;
|
|
|
|
return 0;
|
|
|
|
}
|