mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[ext2fs] add journal support for ext3 formatting
* Also clean up code, handle errors and fix issues
This commit is contained in:
parent
ddda1561ae
commit
ccf0f1bf3c
20 changed files with 2338 additions and 210 deletions
|
@ -56,6 +56,7 @@
|
|||
<ClCompile Include="..\src\ext2fs\dir_iterate.c" />
|
||||
<ClCompile Include="..\src\ext2fs\extent.c" />
|
||||
<ClCompile Include="..\src\ext2fs\ext_attr.c" />
|
||||
<ClCompile Include="..\src\ext2fs\fallocate.c" />
|
||||
<ClCompile Include="..\src\ext2fs\fileio.c" />
|
||||
<ClCompile Include="..\src\ext2fs\freefs.c" />
|
||||
<ClCompile Include="..\src\ext2fs\gen_bitmap.c" />
|
||||
|
@ -71,8 +72,8 @@
|
|||
<ClCompile Include="..\src\ext2fs\i_block.c" />
|
||||
<ClCompile Include="..\src\ext2fs\link.c" />
|
||||
<ClCompile Include="..\src\ext2fs\lookup.c" />
|
||||
<ClCompile Include="..\src\ext2fs\missing.c" />
|
||||
<ClCompile Include="..\src\ext2fs\mkdir.c" />
|
||||
<ClCompile Include="..\src\ext2fs\mkjournal.c" />
|
||||
<ClCompile Include="..\src\ext2fs\mmp.c" />
|
||||
<ClCompile Include="..\src\ext2fs\newdir.c" />
|
||||
<ClCompile Include="..\src\ext2fs\nt_io.c" />
|
||||
|
@ -103,6 +104,9 @@
|
|||
<ClInclude Include="..\src\ext2fs\ext3_extents.h" />
|
||||
<ClInclude Include="..\src\ext2fs\ext4_acl.h" />
|
||||
<ClInclude Include="..\src\ext2fs\hashmap.h" />
|
||||
<ClInclude Include="..\src\ext2fs\jfs_compat.h" />
|
||||
<ClInclude Include="..\src\ext2fs\kernel-jbd.h" />
|
||||
<ClInclude Include="..\src\ext2fs\kernel-list.h" />
|
||||
<ClInclude Include="..\src\ext2fs\rbtree.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
<ClCompile Include="..\src\ext2fs\bitmaps.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\ext2fs\missing.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\ext2fs\closefs.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -153,6 +150,12 @@
|
|||
<ClCompile Include="..\src\ext2fs\sha512.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\ext2fs\mkjournal.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\ext2fs\fallocate.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\ext2fs\ext2_fs.h">
|
||||
|
@ -212,5 +215,14 @@
|
|||
<ClInclude Include="..\src\ext2fs\hashmap.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\ext2fs\kernel-list.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\ext2fs\kernel-jbd.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\ext2fs\jfs_compat.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
11
src/drive.c
11
src/drive.c
|
@ -229,19 +229,20 @@ out:
|
|||
}
|
||||
|
||||
/*
|
||||
* Return an NT path to access the physical drive, or NULL on error.
|
||||
* Return the path to access a partition on a specific disk, or NULL on error.
|
||||
* The string is allocated and must be freed (to ensure concurrent access)
|
||||
*/
|
||||
char* GetNtPhysicalName(DWORD DriveIndex)
|
||||
char* GetPartitionName(DWORD DriveIndex, DWORD PartitionNumber)
|
||||
{
|
||||
BOOL success = FALSE;
|
||||
char physical_name[32];
|
||||
char partition_name[32];
|
||||
|
||||
CheckDriveIndex(DriveIndex);
|
||||
static_sprintf(physical_name, "\\??\\PHYSICALDRIVE%lu", DriveIndex);
|
||||
|
||||
static_sprintf(partition_name, "\\Device\\Harddisk%lu\\Partition%lu", DriveIndex, PartitionNumber);
|
||||
success = TRUE;
|
||||
out:
|
||||
return (success) ? safe_strdup(physical_name) : NULL;
|
||||
return (success) ? safe_strdup(partition_name) : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -258,7 +258,7 @@ extern RUFUS_DRIVE_INFO SelectedDrive;
|
|||
BOOL SetAutoMount(BOOL enable);
|
||||
BOOL GetAutoMount(BOOL* enabled);
|
||||
char* GetPhysicalName(DWORD DriveIndex);
|
||||
char* GetNtPhysicalName(DWORD DriveIndex);
|
||||
char* GetPartitionName(DWORD DriveIndex, DWORD PartitionNumber);
|
||||
BOOL DeletePartitions(DWORD DriveIndex);
|
||||
HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare);
|
||||
char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent);
|
||||
|
|
|
@ -2,9 +2,9 @@ noinst_LIBRARIES = libext2fs.a
|
|||
|
||||
libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c \
|
||||
bitmaps.c bitops.c blkmap64_ba.c blkmap64_rb.c blknum.c block.c bmap.c closefs.c crc16.c \
|
||||
crc32c.c csum.c dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fileio.c freefs.c \
|
||||
gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c inline.c \
|
||||
inline_data.c inode.c io_manager.c link.c lookup.c missing.c mkdir.c mmp.c newdir.c nt_io.c \
|
||||
punch.c rbtree.c read_bb.c rw_bitmaps.c sha512.c symlink.c valid_blk.c
|
||||
crc32c.c csum.c dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fallocate.c fileio.c \
|
||||
freefs.c gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c \
|
||||
inline.c inline_data.c inode.c io_manager.c link.c lookup.c mkdir.c mkjournal.c mmp.c newdir.c \
|
||||
nt_io.c punch.c rbtree.c read_bb.c rw_bitmaps.c sha512.c symlink.c valid_blk.c
|
||||
|
||||
libext2fs_a_CFLAGS = $(AM_CFLAGS) -DEXT2_FLAT_INCLUDES=0 -DHAVE_CONFIG_H -I. -I.. -Wno-undef -Wno-strict-aliasing -Wno-shadow
|
||||
|
|
|
@ -107,8 +107,8 @@ am_libext2fs_a_OBJECTS = libext2fs_a-alloc.$(OBJEXT) \
|
|||
libext2fs_a-dirblock.$(OBJEXT) \
|
||||
libext2fs_a-dir_iterate.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \
|
||||
libext2fs_a-ext_attr.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \
|
||||
libext2fs_a-fileio.$(OBJEXT) libext2fs_a-freefs.$(OBJEXT) \
|
||||
libext2fs_a-gen_bitmap.$(OBJEXT) \
|
||||
libext2fs_a-fallocate.$(OBJEXT) libext2fs_a-fileio.$(OBJEXT) \
|
||||
libext2fs_a-freefs.$(OBJEXT) libext2fs_a-gen_bitmap.$(OBJEXT) \
|
||||
libext2fs_a-gen_bitmap64.$(OBJEXT) \
|
||||
libext2fs_a-get_num_dirs.$(OBJEXT) \
|
||||
libext2fs_a-hashmap.$(OBJEXT) libext2fs_a-i_block.$(OBJEXT) \
|
||||
|
@ -116,8 +116,8 @@ am_libext2fs_a_OBJECTS = libext2fs_a-alloc.$(OBJEXT) \
|
|||
libext2fs_a-initialize.$(OBJEXT) libext2fs_a-inline.$(OBJEXT) \
|
||||
libext2fs_a-inline_data.$(OBJEXT) libext2fs_a-inode.$(OBJEXT) \
|
||||
libext2fs_a-io_manager.$(OBJEXT) libext2fs_a-link.$(OBJEXT) \
|
||||
libext2fs_a-lookup.$(OBJEXT) libext2fs_a-missing.$(OBJEXT) \
|
||||
libext2fs_a-mkdir.$(OBJEXT) libext2fs_a-mmp.$(OBJEXT) \
|
||||
libext2fs_a-lookup.$(OBJEXT) libext2fs_a-mkdir.$(OBJEXT) \
|
||||
libext2fs_a-mkjournal.$(OBJEXT) libext2fs_a-mmp.$(OBJEXT) \
|
||||
libext2fs_a-newdir.$(OBJEXT) libext2fs_a-nt_io.$(OBJEXT) \
|
||||
libext2fs_a-punch.$(OBJEXT) libext2fs_a-rbtree.$(OBJEXT) \
|
||||
libext2fs_a-read_bb.$(OBJEXT) libext2fs_a-rw_bitmaps.$(OBJEXT) \
|
||||
|
@ -272,10 +272,10 @@ top_srcdir = @top_srcdir@
|
|||
noinst_LIBRARIES = libext2fs.a
|
||||
libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c \
|
||||
bitmaps.c bitops.c blkmap64_ba.c blkmap64_rb.c blknum.c block.c bmap.c closefs.c crc16.c \
|
||||
crc32c.c csum.c dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fileio.c freefs.c \
|
||||
gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c inline.c \
|
||||
inline_data.c inode.c io_manager.c link.c lookup.c missing.c mkdir.c mmp.c newdir.c nt_io.c \
|
||||
punch.c rbtree.c read_bb.c rw_bitmaps.c sha512.c symlink.c valid_blk.c
|
||||
crc32c.c csum.c dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fallocate.c fileio.c \
|
||||
freefs.c gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c \
|
||||
inline.c inline_data.c inode.c io_manager.c link.c lookup.c mkdir.c mkjournal.c mmp.c newdir.c \
|
||||
nt_io.c punch.c rbtree.c read_bb.c rw_bitmaps.c sha512.c symlink.c valid_blk.c
|
||||
|
||||
libext2fs_a_CFLAGS = $(AM_CFLAGS) -DEXT2_FLAT_INCLUDES=0 -DHAVE_CONFIG_H -I. -I.. -Wno-undef -Wno-strict-aliasing -Wno-shadow
|
||||
all: all-am
|
||||
|
@ -459,6 +459,12 @@ libext2fs_a-ext_attr.o: ext_attr.c
|
|||
libext2fs_a-ext_attr.obj: ext_attr.c
|
||||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-ext_attr.obj `if test -f 'ext_attr.c'; then $(CYGPATH_W) 'ext_attr.c'; else $(CYGPATH_W) '$(srcdir)/ext_attr.c'; fi`
|
||||
|
||||
libext2fs_a-fallocate.o: fallocate.c
|
||||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-fallocate.o `test -f 'fallocate.c' || echo '$(srcdir)/'`fallocate.c
|
||||
|
||||
libext2fs_a-fallocate.obj: fallocate.c
|
||||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-fallocate.obj `if test -f 'fallocate.c'; then $(CYGPATH_W) 'fallocate.c'; else $(CYGPATH_W) '$(srcdir)/fallocate.c'; fi`
|
||||
|
||||
libext2fs_a-fileio.o: fileio.c
|
||||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-fileio.o `test -f 'fileio.c' || echo '$(srcdir)/'`fileio.c
|
||||
|
||||
|
@ -549,18 +555,18 @@ libext2fs_a-lookup.o: lookup.c
|
|||
libext2fs_a-lookup.obj: lookup.c
|
||||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-lookup.obj `if test -f 'lookup.c'; then $(CYGPATH_W) 'lookup.c'; else $(CYGPATH_W) '$(srcdir)/lookup.c'; fi`
|
||||
|
||||
libext2fs_a-missing.o: missing.c
|
||||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-missing.o `test -f 'missing.c' || echo '$(srcdir)/'`missing.c
|
||||
|
||||
libext2fs_a-missing.obj: missing.c
|
||||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-missing.obj `if test -f 'missing.c'; then $(CYGPATH_W) 'missing.c'; else $(CYGPATH_W) '$(srcdir)/missing.c'; fi`
|
||||
|
||||
libext2fs_a-mkdir.o: mkdir.c
|
||||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mkdir.o `test -f 'mkdir.c' || echo '$(srcdir)/'`mkdir.c
|
||||
|
||||
libext2fs_a-mkdir.obj: mkdir.c
|
||||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mkdir.obj `if test -f 'mkdir.c'; then $(CYGPATH_W) 'mkdir.c'; else $(CYGPATH_W) '$(srcdir)/mkdir.c'; fi`
|
||||
|
||||
libext2fs_a-mkjournal.o: mkjournal.c
|
||||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mkjournal.o `test -f 'mkjournal.c' || echo '$(srcdir)/'`mkjournal.c
|
||||
|
||||
libext2fs_a-mkjournal.obj: mkjournal.c
|
||||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mkjournal.obj `if test -f 'mkjournal.c'; then $(CYGPATH_W) 'mkjournal.c'; else $(CYGPATH_W) '$(srcdir)/mkjournal.c'; fi`
|
||||
|
||||
libext2fs_a-mmp.o: mmp.c
|
||||
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mmp.o `test -f 'mmp.c' || echo '$(srcdir)/'`mmp.c
|
||||
|
||||
|
|
|
@ -177,6 +177,9 @@
|
|||
/* Define if you have the 'wint_t' type. */
|
||||
#define HAVE_WINT_T 1
|
||||
|
||||
/* Define if you have 'winsock.h'. */
|
||||
#define HAVE_WINSOCK_H 1
|
||||
|
||||
/* Define to 1 if O_NOATIME works. */
|
||||
#define HAVE_WORKING_O_NOATIME 0
|
||||
|
||||
|
|
|
@ -785,9 +785,11 @@ struct ext2_super_block {
|
|||
*/
|
||||
#define EXT2_OS_LINUX 0
|
||||
#define EXT2_OS_HURD 1
|
||||
#define EXT2_OS_WINDOWS 2
|
||||
#define EXT2_OBSO_OS_MASIX 2
|
||||
#define EXT2_OS_FREEBSD 3
|
||||
#define EXT2_OS_LITES 4
|
||||
#define EXT2_OS_WINDOWS 5
|
||||
#define EXT2_OS_MACOS 6
|
||||
|
||||
/*
|
||||
* Revision levels
|
||||
|
|
857
src/ext2fs/fallocate.c
Normal file
857
src/ext2fs/fallocate.c
Normal file
|
@ -0,0 +1,857 @@
|
|||
/*
|
||||
* fallocate.c -- Allocate large chunks of file.
|
||||
*
|
||||
* Copyright (C) 2014 Oracle.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#ifndef min
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0)
|
||||
#else
|
||||
# define dbg_printf(f, ...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Extent-based fallocate code.
|
||||
*
|
||||
* Find runs of unmapped logical blocks by starting at start and walking the
|
||||
* extents until we reach the end of the range we want.
|
||||
*
|
||||
* For each run of unmapped blocks, try to find the extents on either side of
|
||||
* the range. If there's a left extent that can grow by at least a cluster and
|
||||
* there are lblocks between start and the next lcluster after start, see if
|
||||
* there's an implied cluster allocation; if so, zero the blocks (if the left
|
||||
* extent is initialized) and adjust the extent. Ditto for the blocks between
|
||||
* the end of the last full lcluster and end, if there's a right extent.
|
||||
*
|
||||
* Try to attach as much as we can to the left extent, then try to attach as
|
||||
* much as we can to the right extent. For the remainder, try to allocate the
|
||||
* whole range; map in whatever we get; and repeat until we're done.
|
||||
*
|
||||
* To attach to a left extent, figure out the maximum amount we can add to the
|
||||
* extent and try to allocate that much, and append if successful. To attach
|
||||
* to a right extent, figure out the max we can add to the extent, try to
|
||||
* allocate that much, and prepend if successful.
|
||||
*
|
||||
* We need an alloc_range function that tells us how much we can allocate given
|
||||
* a maximum length and one of a suggested start, a fixed start, or a fixed end
|
||||
* point.
|
||||
*
|
||||
* Every time we modify the extent tree we also need to update the block stats.
|
||||
*
|
||||
* At the end, update i_blocks and i_size appropriately.
|
||||
*/
|
||||
|
||||
static void dbg_print_extent(const char *desc EXT2FS_ATTR((unused)),
|
||||
const struct ext2fs_extent *extent EXT2FS_ATTR((unused)))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (desc)
|
||||
printf("%s: ", desc);
|
||||
printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ",
|
||||
extent->e_lblk, extent->e_lblk + extent->e_len - 1,
|
||||
extent->e_len, extent->e_pblk);
|
||||
if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF)
|
||||
fputs("LEAF ", stdout);
|
||||
if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fputs("UNINIT ", stdout);
|
||||
if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
|
||||
fputs("2ND_VISIT ", stdout);
|
||||
if (!extent->e_flags)
|
||||
fputs("(none)", stdout);
|
||||
fputc('\n', stdout);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
static errcode_t claim_range(ext2_filsys fs, struct ext2_inode *inode,
|
||||
blk64_t blk, blk64_t len)
|
||||
{
|
||||
blk64_t clusters;
|
||||
|
||||
clusters = (len + EXT2FS_CLUSTER_RATIO(fs) - 1) /
|
||||
EXT2FS_CLUSTER_RATIO(fs);
|
||||
ext2fs_block_alloc_stats_range(fs, blk,
|
||||
clusters * EXT2FS_CLUSTER_RATIO(fs), +1);
|
||||
return ext2fs_iblk_add_blocks(fs, inode, clusters);
|
||||
}
|
||||
|
||||
static errcode_t ext_falloc_helper(ext2_filsys fs,
|
||||
int flags,
|
||||
ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
ext2_extent_handle_t handle,
|
||||
struct ext2fs_extent *left_ext,
|
||||
struct ext2fs_extent *right_ext,
|
||||
blk64_t range_start, blk64_t range_len,
|
||||
blk64_t alloc_goal)
|
||||
{
|
||||
struct ext2fs_extent newex, ex;
|
||||
int op;
|
||||
blk64_t fillable, pblk, plen, x, y;
|
||||
blk64_t eof_blk = 0, cluster_fill = 0;
|
||||
errcode_t err;
|
||||
blk_t max_extent_len, max_uninit_len, max_init_len;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("%s: ", __func__);
|
||||
if (left_ext)
|
||||
printf("left_ext=%llu--%llu, ", left_ext->e_lblk,
|
||||
left_ext->e_lblk + left_ext->e_len - 1);
|
||||
if (right_ext)
|
||||
printf("right_ext=%llu--%llu, ", right_ext->e_lblk,
|
||||
right_ext->e_lblk + right_ext->e_len - 1);
|
||||
printf("start=%llu len=%llu, goal=%llu\n", range_start, range_len,
|
||||
alloc_goal);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
/* Can't create initialized extents past EOF? */
|
||||
if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF))
|
||||
eof_blk = EXT2_I_SIZE(inode) / fs->blocksize;
|
||||
|
||||
/* The allocation goal must be as far into a cluster as range_start. */
|
||||
alloc_goal = (alloc_goal & ~EXT2FS_CLUSTER_MASK(fs)) |
|
||||
(range_start & EXT2FS_CLUSTER_MASK(fs));
|
||||
|
||||
max_uninit_len = EXT_UNINIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs);
|
||||
max_init_len = EXT_INIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs);
|
||||
|
||||
/* We must lengthen the left extent to the end of the cluster */
|
||||
if (left_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) {
|
||||
/* How many more blocks can be attached to left_ext? */
|
||||
if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fillable = max_uninit_len - left_ext->e_len;
|
||||
else
|
||||
fillable = max_init_len - left_ext->e_len;
|
||||
|
||||
if (fillable > range_len)
|
||||
fillable = range_len;
|
||||
if (fillable == 0)
|
||||
goto expand_right;
|
||||
|
||||
/*
|
||||
* If range_start isn't on a cluster boundary, try an
|
||||
* implied cluster allocation for left_ext.
|
||||
*/
|
||||
cluster_fill = EXT2FS_CLUSTER_RATIO(fs) -
|
||||
(range_start & EXT2FS_CLUSTER_MASK(fs));
|
||||
cluster_fill &= EXT2FS_CLUSTER_MASK(fs);
|
||||
if (cluster_fill == 0)
|
||||
goto expand_right;
|
||||
|
||||
if (cluster_fill > fillable)
|
||||
cluster_fill = fillable;
|
||||
|
||||
/* Don't expand an initialized left_ext beyond EOF */
|
||||
if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) {
|
||||
x = left_ext->e_lblk + left_ext->e_len - 1;
|
||||
dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n",
|
||||
__func__, x, x + cluster_fill, eof_blk);
|
||||
if (eof_blk >= x && eof_blk <= x + cluster_fill)
|
||||
cluster_fill = eof_blk - x;
|
||||
if (cluster_fill == 0)
|
||||
goto expand_right;
|
||||
}
|
||||
|
||||
err = ext2fs_extent_goto(handle, left_ext->e_lblk);
|
||||
if (err)
|
||||
goto expand_right;
|
||||
left_ext->e_len += cluster_fill;
|
||||
range_start += cluster_fill;
|
||||
range_len -= cluster_fill;
|
||||
alloc_goal += cluster_fill;
|
||||
|
||||
dbg_print_extent("ext_falloc clus left+", left_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, left_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Zero blocks */
|
||||
if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) {
|
||||
err = ext2fs_zero_blocks2(fs, left_ext->e_pblk +
|
||||
left_ext->e_len -
|
||||
cluster_fill, cluster_fill,
|
||||
NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
expand_right:
|
||||
/* We must lengthen the right extent to the beginning of the cluster */
|
||||
if (right_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) {
|
||||
/* How much can we attach to right_ext? */
|
||||
if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fillable = max_uninit_len - right_ext->e_len;
|
||||
else
|
||||
fillable = max_init_len - right_ext->e_len;
|
||||
|
||||
if (fillable > range_len)
|
||||
fillable = range_len;
|
||||
if (fillable == 0)
|
||||
goto try_merge;
|
||||
|
||||
/*
|
||||
* If range_end isn't on a cluster boundary, try an implied
|
||||
* cluster allocation for right_ext.
|
||||
*/
|
||||
cluster_fill = right_ext->e_lblk & EXT2FS_CLUSTER_MASK(fs);
|
||||
if (cluster_fill == 0)
|
||||
goto try_merge;
|
||||
|
||||
err = ext2fs_extent_goto(handle, right_ext->e_lblk);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (cluster_fill > fillable)
|
||||
cluster_fill = fillable;
|
||||
right_ext->e_lblk -= cluster_fill;
|
||||
right_ext->e_pblk -= cluster_fill;
|
||||
right_ext->e_len += cluster_fill;
|
||||
range_len -= cluster_fill;
|
||||
|
||||
dbg_print_extent("ext_falloc clus right+", right_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, right_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Zero blocks if necessary */
|
||||
if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) {
|
||||
err = ext2fs_zero_blocks2(fs, right_ext->e_pblk,
|
||||
cluster_fill, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
try_merge:
|
||||
/* Merge both extents together, perhaps? */
|
||||
if (left_ext && right_ext) {
|
||||
/* Are the two extents mergeable? */
|
||||
if ((left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) !=
|
||||
(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))
|
||||
goto try_left;
|
||||
|
||||
/* User requires init/uninit but extent is uninit/init. */
|
||||
if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
|
||||
(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ||
|
||||
((flags & EXT2_FALLOCATE_FORCE_UNINIT) &&
|
||||
!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)))
|
||||
goto try_left;
|
||||
|
||||
/*
|
||||
* Skip initialized extent unless user wants to zero blocks
|
||||
* or requires init extent.
|
||||
*/
|
||||
if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(!(flags & EXT2_FALLOCATE_ZERO_BLOCKS) ||
|
||||
!(flags & EXT2_FALLOCATE_FORCE_INIT)))
|
||||
goto try_left;
|
||||
|
||||
/* Will it even fit? */
|
||||
x = left_ext->e_len + range_len + right_ext->e_len;
|
||||
if (x > (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT ?
|
||||
max_uninit_len : max_init_len))
|
||||
goto try_left;
|
||||
|
||||
err = ext2fs_extent_goto(handle, left_ext->e_lblk);
|
||||
if (err)
|
||||
goto try_left;
|
||||
|
||||
/* Allocate blocks */
|
||||
y = left_ext->e_pblk + left_ext->e_len;
|
||||
err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL |
|
||||
EXT2_NEWRANGE_MIN_LENGTH, y,
|
||||
right_ext->e_pblk - y + 1, NULL,
|
||||
&pblk, &plen);
|
||||
if (err)
|
||||
goto try_left;
|
||||
if (pblk + plen != right_ext->e_pblk)
|
||||
goto try_left;
|
||||
err = claim_range(fs, inode, pblk, plen);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Modify extents */
|
||||
left_ext->e_len = x;
|
||||
dbg_print_extent("ext_falloc merge", left_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, left_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &newex);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_delete(handle, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
*right_ext = *left_ext;
|
||||
|
||||
/* Zero blocks */
|
||||
if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, range_start, range_len,
|
||||
NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try_left:
|
||||
/* Extend the left extent */
|
||||
if (left_ext) {
|
||||
/* How many more blocks can be attached to left_ext? */
|
||||
if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fillable = max_uninit_len - left_ext->e_len;
|
||||
else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS)
|
||||
fillable = max_init_len - left_ext->e_len;
|
||||
else
|
||||
fillable = 0;
|
||||
|
||||
/* User requires init/uninit but extent is uninit/init. */
|
||||
if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
|
||||
(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ||
|
||||
((flags & EXT2_FALLOCATE_FORCE_UNINIT) &&
|
||||
!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)))
|
||||
goto try_right;
|
||||
|
||||
if (fillable > range_len)
|
||||
fillable = range_len;
|
||||
|
||||
/* Don't expand an initialized left_ext beyond EOF */
|
||||
x = left_ext->e_lblk + left_ext->e_len - 1;
|
||||
if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) {
|
||||
dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n",
|
||||
__func__, x, x + fillable, eof_blk);
|
||||
if (eof_blk >= x && eof_blk <= x + fillable)
|
||||
fillable = eof_blk - x;
|
||||
}
|
||||
|
||||
if (fillable == 0)
|
||||
goto try_right;
|
||||
|
||||
/* Test if the right edge of the range is already mapped? */
|
||||
if (EXT2FS_CLUSTER_RATIO(fs) > 1) {
|
||||
err = ext2fs_map_cluster_block(fs, ino, inode,
|
||||
x + fillable, &pblk);
|
||||
if (err)
|
||||
goto out;
|
||||
if (pblk)
|
||||
fillable -= 1 + ((x + fillable)
|
||||
& EXT2FS_CLUSTER_MASK(fs));
|
||||
if (fillable == 0)
|
||||
goto try_right;
|
||||
}
|
||||
|
||||
/* Allocate range of blocks */
|
||||
x = left_ext->e_pblk + left_ext->e_len;
|
||||
err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL |
|
||||
EXT2_NEWRANGE_MIN_LENGTH,
|
||||
x, fillable, NULL, &pblk, &plen);
|
||||
if (err)
|
||||
goto try_right;
|
||||
err = claim_range(fs, inode, pblk, plen);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Modify left_ext */
|
||||
err = ext2fs_extent_goto(handle, left_ext->e_lblk);
|
||||
if (err)
|
||||
goto out;
|
||||
range_start += plen;
|
||||
range_len -= plen;
|
||||
left_ext->e_len += plen;
|
||||
dbg_print_extent("ext_falloc left+", left_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, left_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Zero blocks if necessary */
|
||||
if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
try_right:
|
||||
/* Extend the right extent */
|
||||
if (right_ext) {
|
||||
/* How much can we attach to right_ext? */
|
||||
if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fillable = max_uninit_len - right_ext->e_len;
|
||||
else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS)
|
||||
fillable = max_init_len - right_ext->e_len;
|
||||
else
|
||||
fillable = 0;
|
||||
|
||||
/* User requires init/uninit but extent is uninit/init. */
|
||||
if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
|
||||
(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ||
|
||||
((flags & EXT2_FALLOCATE_FORCE_UNINIT) &&
|
||||
!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)))
|
||||
goto try_anywhere;
|
||||
|
||||
if (fillable > range_len)
|
||||
fillable = range_len;
|
||||
if (fillable == 0)
|
||||
goto try_anywhere;
|
||||
|
||||
/* Test if the left edge of the range is already mapped? */
|
||||
if (EXT2FS_CLUSTER_RATIO(fs) > 1) {
|
||||
err = ext2fs_map_cluster_block(fs, ino, inode,
|
||||
right_ext->e_lblk - fillable, &pblk);
|
||||
if (err)
|
||||
goto out;
|
||||
if (pblk)
|
||||
fillable -= EXT2FS_CLUSTER_RATIO(fs) -
|
||||
((right_ext->e_lblk - fillable)
|
||||
& EXT2FS_CLUSTER_MASK(fs));
|
||||
if (fillable == 0)
|
||||
goto try_anywhere;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: It would be nice if we could handle allocating a
|
||||
* variable range from a fixed end point instead of just
|
||||
* skipping to the general allocator if the whole range is
|
||||
* unavailable.
|
||||
*/
|
||||
err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL |
|
||||
EXT2_NEWRANGE_MIN_LENGTH,
|
||||
right_ext->e_pblk - fillable,
|
||||
fillable, NULL, &pblk, &plen);
|
||||
if (err)
|
||||
goto try_anywhere;
|
||||
err = claim_range(fs, inode,
|
||||
pblk & ~EXT2FS_CLUSTER_MASK(fs),
|
||||
plen + (pblk & EXT2FS_CLUSTER_MASK(fs)));
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Modify right_ext */
|
||||
err = ext2fs_extent_goto(handle, right_ext->e_lblk);
|
||||
if (err)
|
||||
goto out;
|
||||
range_len -= plen;
|
||||
right_ext->e_lblk -= plen;
|
||||
right_ext->e_pblk -= plen;
|
||||
right_ext->e_len += plen;
|
||||
dbg_print_extent("ext_falloc right+", right_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, right_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Zero blocks if necessary */
|
||||
if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, pblk,
|
||||
plen + cluster_fill, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
try_anywhere:
|
||||
/* Try implied cluster alloc on the left and right ends */
|
||||
if (range_len > 0 && (range_start & EXT2FS_CLUSTER_MASK(fs))) {
|
||||
cluster_fill = EXT2FS_CLUSTER_RATIO(fs) -
|
||||
(range_start & EXT2FS_CLUSTER_MASK(fs));
|
||||
cluster_fill &= EXT2FS_CLUSTER_MASK(fs);
|
||||
if (cluster_fill > range_len)
|
||||
cluster_fill = range_len;
|
||||
newex.e_lblk = range_start;
|
||||
err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk,
|
||||
&pblk);
|
||||
if (err)
|
||||
goto out;
|
||||
if (pblk == 0)
|
||||
goto try_right_implied;
|
||||
newex.e_pblk = pblk;
|
||||
newex.e_len = cluster_fill;
|
||||
newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 :
|
||||
EXT2_EXTENT_FLAGS_UNINIT);
|
||||
dbg_print_extent("ext_falloc iclus left+", &newex);
|
||||
ext2fs_extent_goto(handle, newex.e_lblk);
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
|
||||
&ex);
|
||||
if (err == EXT2_ET_NO_CURRENT_NODE)
|
||||
ex.e_lblk = 0;
|
||||
else if (err)
|
||||
goto out;
|
||||
|
||||
if (ex.e_lblk > newex.e_lblk)
|
||||
op = 0; /* insert before */
|
||||
else
|
||||
op = EXT2_EXTENT_INSERT_AFTER;
|
||||
dbg_printf("%s: inserting %s lblk %llu newex=%llu\n",
|
||||
__func__, op ? "after" : "before", ex.e_lblk,
|
||||
newex.e_lblk);
|
||||
err = ext2fs_extent_insert(handle, op, &newex);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, newex.e_pblk,
|
||||
newex.e_len, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
range_start += cluster_fill;
|
||||
range_len -= cluster_fill;
|
||||
}
|
||||
|
||||
try_right_implied:
|
||||
y = range_start + range_len;
|
||||
if (range_len > 0 && (y & EXT2FS_CLUSTER_MASK(fs))) {
|
||||
cluster_fill = y & EXT2FS_CLUSTER_MASK(fs);
|
||||
if (cluster_fill > range_len)
|
||||
cluster_fill = range_len;
|
||||
newex.e_lblk = y & ~EXT2FS_CLUSTER_MASK(fs);
|
||||
err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk,
|
||||
&pblk);
|
||||
if (err)
|
||||
goto out;
|
||||
if (pblk == 0)
|
||||
goto no_implied;
|
||||
newex.e_pblk = pblk;
|
||||
newex.e_len = cluster_fill;
|
||||
newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 :
|
||||
EXT2_EXTENT_FLAGS_UNINIT);
|
||||
dbg_print_extent("ext_falloc iclus right+", &newex);
|
||||
ext2fs_extent_goto(handle, newex.e_lblk);
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
|
||||
&ex);
|
||||
if (err == EXT2_ET_NO_CURRENT_NODE)
|
||||
ex.e_lblk = 0;
|
||||
else if (err)
|
||||
goto out;
|
||||
|
||||
if (ex.e_lblk > newex.e_lblk)
|
||||
op = 0; /* insert before */
|
||||
else
|
||||
op = EXT2_EXTENT_INSERT_AFTER;
|
||||
dbg_printf("%s: inserting %s lblk %llu newex=%llu\n",
|
||||
__func__, op ? "after" : "before", ex.e_lblk,
|
||||
newex.e_lblk);
|
||||
err = ext2fs_extent_insert(handle, op, &newex);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, newex.e_pblk,
|
||||
newex.e_len, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
range_len -= cluster_fill;
|
||||
}
|
||||
|
||||
no_implied:
|
||||
if (range_len == 0)
|
||||
return 0;
|
||||
|
||||
newex.e_lblk = range_start;
|
||||
if (flags & EXT2_FALLOCATE_FORCE_INIT) {
|
||||
max_extent_len = max_init_len;
|
||||
newex.e_flags = 0;
|
||||
} else {
|
||||
max_extent_len = max_uninit_len;
|
||||
newex.e_flags = EXT2_EXTENT_FLAGS_UNINIT;
|
||||
}
|
||||
pblk = alloc_goal;
|
||||
y = range_len;
|
||||
for (x = 0; x < y;) {
|
||||
cluster_fill = newex.e_lblk & EXT2FS_CLUSTER_MASK(fs);
|
||||
fillable = min(range_len + cluster_fill, max_extent_len);
|
||||
err = ext2fs_new_range(fs, 0, pblk & ~EXT2FS_CLUSTER_MASK(fs),
|
||||
fillable,
|
||||
NULL, &pblk, &plen);
|
||||
if (err)
|
||||
goto out;
|
||||
err = claim_range(fs, inode, pblk, plen);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Create extent */
|
||||
newex.e_pblk = pblk + cluster_fill;
|
||||
newex.e_len = plen - cluster_fill;
|
||||
dbg_print_extent("ext_falloc create", &newex);
|
||||
ext2fs_extent_goto(handle, newex.e_lblk);
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
|
||||
&ex);
|
||||
if (err == EXT2_ET_NO_CURRENT_NODE)
|
||||
ex.e_lblk = 0;
|
||||
else if (err)
|
||||
goto out;
|
||||
|
||||
if (ex.e_lblk > newex.e_lblk)
|
||||
op = 0; /* insert before */
|
||||
else
|
||||
op = EXT2_EXTENT_INSERT_AFTER;
|
||||
dbg_printf("%s: inserting %s lblk %llu newex=%llu\n",
|
||||
__func__, op ? "after" : "before", ex.e_lblk,
|
||||
newex.e_lblk);
|
||||
err = ext2fs_extent_insert(handle, op, &newex);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Update variables at end of loop */
|
||||
x += plen - cluster_fill;
|
||||
range_len -= plen - cluster_fill;
|
||||
newex.e_lblk += plen - cluster_fill;
|
||||
pblk += plen - cluster_fill;
|
||||
if (pblk >= ext2fs_blocks_count(fs->super))
|
||||
pblk = fs->super->s_first_data_block;
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static errcode_t extent_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, blk64_t goal,
|
||||
blk64_t start, blk64_t len)
|
||||
{
|
||||
ext2_extent_handle_t handle;
|
||||
struct ext2fs_extent left_extent, right_extent;
|
||||
struct ext2fs_extent *left_adjacent, *right_adjacent;
|
||||
errcode_t err;
|
||||
blk64_t range_start, range_end = 0, end, next;
|
||||
blk64_t count, goal_distance;
|
||||
|
||||
end = start + len - 1;
|
||||
err = ext2fs_extent_open2(fs, ino, inode, &handle);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Find the extent closest to the start of the alloc range. We don't
|
||||
* check the return value because _goto() sets the current node to the
|
||||
* next-lowest extent if 'start' is in a hole; or the next-highest
|
||||
* extent if there aren't any lower ones; or doesn't set a current node
|
||||
* if there was a real error reading the extent tree. In that case,
|
||||
* _get() will error out.
|
||||
*/
|
||||
start_again:
|
||||
ext2fs_extent_goto(handle, start);
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &left_extent);
|
||||
if (err == EXT2_ET_NO_CURRENT_NODE) {
|
||||
blk64_t max_blocks = ext2fs_blocks_count(fs->super);
|
||||
|
||||
if (goal == ~0ULL)
|
||||
goal = ext2fs_find_inode_goal(fs, ino, inode, start);
|
||||
err = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
|
||||
goal, max_blocks - 1, &goal);
|
||||
goal += start;
|
||||
err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL,
|
||||
NULL, start, len, goal);
|
||||
goto errout;
|
||||
} else if (err)
|
||||
goto errout;
|
||||
|
||||
dbg_print_extent("ext_falloc initial", &left_extent);
|
||||
next = left_extent.e_lblk + left_extent.e_len;
|
||||
if (left_extent.e_lblk > start) {
|
||||
/* The nearest extent we found was beyond start??? */
|
||||
goal = left_extent.e_pblk - (left_extent.e_lblk - start);
|
||||
err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL,
|
||||
&left_extent, start,
|
||||
left_extent.e_lblk - start, goal);
|
||||
if (err)
|
||||
goto errout;
|
||||
|
||||
goto start_again;
|
||||
} else if (next >= start) {
|
||||
range_start = next;
|
||||
left_adjacent = &left_extent;
|
||||
} else {
|
||||
range_start = start;
|
||||
left_adjacent = NULL;
|
||||
}
|
||||
goal = left_extent.e_pblk + (range_start - left_extent.e_lblk);
|
||||
|
||||
do {
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF,
|
||||
&right_extent);
|
||||
dbg_printf("%s: ino=%d get next =%d\n", __func__, ino,
|
||||
(int)err);
|
||||
dbg_print_extent("ext_falloc next", &right_extent);
|
||||
/* Stop if we've seen this extent before */
|
||||
if (!err && right_extent.e_lblk <= left_extent.e_lblk)
|
||||
err = EXT2_ET_EXTENT_NO_NEXT;
|
||||
|
||||
if (err && err != EXT2_ET_EXTENT_NO_NEXT)
|
||||
goto errout;
|
||||
if (err == EXT2_ET_EXTENT_NO_NEXT ||
|
||||
right_extent.e_lblk > end + 1) {
|
||||
range_end = end;
|
||||
right_adjacent = NULL;
|
||||
} else {
|
||||
/* Handle right_extent.e_lblk <= end */
|
||||
range_end = right_extent.e_lblk - 1;
|
||||
right_adjacent = &right_extent;
|
||||
}
|
||||
goal_distance = range_start - next;
|
||||
if (err != EXT2_ET_EXTENT_NO_NEXT &&
|
||||
goal_distance > (range_end - right_extent.e_lblk))
|
||||
goal = right_extent.e_pblk -
|
||||
(right_extent.e_lblk - range_start);
|
||||
|
||||
dbg_printf("%s: ino=%d rstart=%llu rend=%llu\n", __func__, ino,
|
||||
range_start, range_end);
|
||||
err = 0;
|
||||
if (range_start <= range_end) {
|
||||
count = range_end - range_start + 1;
|
||||
err = ext_falloc_helper(fs, flags, ino, inode, handle,
|
||||
left_adjacent, right_adjacent,
|
||||
range_start, count, goal);
|
||||
if (err)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (range_end == end)
|
||||
break;
|
||||
|
||||
err = ext2fs_extent_goto(handle, right_extent.e_lblk);
|
||||
if (err)
|
||||
goto errout;
|
||||
next = right_extent.e_lblk + right_extent.e_len;
|
||||
left_extent = right_extent;
|
||||
left_adjacent = &left_extent;
|
||||
range_start = next;
|
||||
goal = left_extent.e_pblk + (range_start - left_extent.e_lblk);
|
||||
} while (range_end < end);
|
||||
|
||||
errout:
|
||||
ext2fs_extent_free(handle);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map physical blocks to a range of logical blocks within a file. The range
|
||||
* of logical blocks are (start, start + len). If there are already extents,
|
||||
* the mappings will try to extend the mappings; otherwise, it will try to map
|
||||
* start as if logical block 0 points to goal. If goal is ~0ULL, then the goal
|
||||
* is calculated based on the inode group.
|
||||
*
|
||||
* Flags:
|
||||
* - EXT2_FALLOCATE_ZERO_BLOCKS: Zero the blocks that are allocated.
|
||||
* - EXT2_FALLOCATE_FORCE_INIT: Create only initialized extents.
|
||||
* - EXT2_FALLOCATE_FORCE_UNINIT: Create only uninitialized extents.
|
||||
* - EXT2_FALLOCATE_INIT_BEYOND_EOF: Create extents beyond EOF.
|
||||
*
|
||||
* If neither FORCE_INIT nor FORCE_UNINIT are specified, this function will
|
||||
* try to expand any extents it finds, zeroing blocks as necessary.
|
||||
*/
|
||||
errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, blk64_t goal,
|
||||
blk64_t start, blk64_t len)
|
||||
{
|
||||
struct ext2_inode inode_buf;
|
||||
blk64_t blk, x;
|
||||
errcode_t err;
|
||||
|
||||
if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
|
||||
(flags & EXT2_FALLOCATE_FORCE_UNINIT)) ||
|
||||
(flags & ~EXT2_FALLOCATE_ALL_FLAGS))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
if (len > ext2fs_blocks_count(fs->super))
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
else if (len == 0)
|
||||
return 0;
|
||||
|
||||
/* Read inode structure if necessary */
|
||||
if (!inode) {
|
||||
err = ext2fs_read_inode(fs, ino, &inode_buf);
|
||||
if (err)
|
||||
return err;
|
||||
inode = &inode_buf;
|
||||
}
|
||||
dbg_printf("%s: ino=%d start=%llu len=%llu goal=%llu\n", __func__, ino,
|
||||
start, len, goal);
|
||||
|
||||
if (inode->i_flags & EXT4_EXTENTS_FL) {
|
||||
err = extent_fallocate(fs, flags, ino, inode, goal, start, len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* XXX: Allocate a bunch of blocks the slow way */
|
||||
for (blk = start; blk < start + len; blk++) {
|
||||
err = ext2fs_bmap2(fs, ino, inode, NULL, 0, blk, 0, &x);
|
||||
if (err)
|
||||
return err;
|
||||
if (x)
|
||||
continue;
|
||||
|
||||
err = ext2fs_bmap2(fs, ino, inode, NULL,
|
||||
BMAP_ALLOC | BMAP_UNINIT | BMAP_ZERO, blk,
|
||||
0, &x);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
out:
|
||||
if (inode == &inode_buf)
|
||||
ext2fs_write_inode(fs, ino, inode);
|
||||
return err;
|
||||
}
|
104
src/ext2fs/jfs_compat.h
Normal file
104
src/ext2fs/jfs_compat.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
|
||||
#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
|
||||
#ifdef HAVE_WINSOCK_H
|
||||
// Heck if we're gonna use WinSock just for htonl and friends
|
||||
#include <stdlib.h>
|
||||
#define htonl _byteswap_ulong
|
||||
#define ntohl _byteswap_ulong
|
||||
#define htons _byteswap_ushort
|
||||
#define ntohs _byteswap_ushort
|
||||
#else
|
||||
#include <arpa/inet.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)
|
||||
#define cpu_to_be16(n) htons(n)
|
||||
#define be16_to_cpu(n) ntohs(n)
|
||||
|
||||
typedef unsigned int tid_t;
|
||||
typedef struct journal_s journal_t;
|
||||
typedef struct kdev_s *kdev_t;
|
||||
|
||||
struct buffer_head;
|
||||
struct inode;
|
||||
|
||||
#define GFP_KERNEL 0
|
||||
#define JFS_TAG_SIZE32 JBD_TAG_SIZE32
|
||||
#define JFS_BARRIER 0
|
||||
typedef __u64 u64;
|
||||
#define JFS_CRC32_CHKSUM JBD2_CRC32_CHKSUM
|
||||
#define JFS_CRC32_CHKSUM_SIZE JBD2_CRC32_CHKSUM_SIZE
|
||||
#define put_bh(x) brelse(x)
|
||||
#define be64_to_cpu(x) ext2fs_be64_to_cpu(x)
|
||||
|
||||
static inline __u32 jbd2_chksum(journal_t *j EXT2FS_ATTR((unused)),
|
||||
__u32 crc, const void *address,
|
||||
unsigned int length)
|
||||
{
|
||||
return ext2fs_crc32c_le(crc, address, length);
|
||||
}
|
||||
#define crc32_be(x, y, z) ext2fs_crc32_be((x), (y), (z))
|
||||
#define spin_lock_init(x)
|
||||
#define spin_lock(x)
|
||||
#define spin_unlock(x)
|
||||
#define yield()
|
||||
#define SLAB_HWCACHE_ALIGN 0
|
||||
#define SLAB_TEMPORARY 0
|
||||
#define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\
|
||||
sizeof(struct __struct), __alignof__(struct __struct),\
|
||||
(__flags), NULL)
|
||||
|
||||
#define blkdev_issue_flush(kdev, a, b) sync_blockdev(kdev)
|
||||
#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
|
||||
|
||||
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 jbd2_revoke_table_s *j_revoke;
|
||||
struct jbd2_revoke_table_s *j_revoke_table[2];
|
||||
tid_t j_failed_commit;
|
||||
__u32 j_csum_seed;
|
||||
};
|
||||
|
||||
#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 */
|
461
src/ext2fs/kernel-jbd.h
Normal file
461
src/ext2fs/kernel-jbd.h
Normal file
|
@ -0,0 +1,461 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
#include "jfs_compat.h"
|
||||
#define JFS_DEBUG
|
||||
#define jfs_debug jbd_debug
|
||||
|
||||
#if !defined(__GNUC__) && !defined(_MSC_VER)
|
||||
#define __FUNCTION__ ""
|
||||
#endif
|
||||
|
||||
#define journal_oom_retry 1
|
||||
|
||||
#ifdef __STDC__
|
||||
#ifdef CONFIG_JBD_DEBUG
|
||||
/*
|
||||
* Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
|
||||
* consistency checks. By default we don't do this unless
|
||||
* CONFIG_JBD_DEBUG 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__
|
||||
#if defined(__KERNEL__) || !defined(CONFIG_JBD_DEBUG)
|
||||
#define jbd_debug(f, a...) /**/
|
||||
#else
|
||||
extern int journal_enable_debug;
|
||||
#define jbd_debug(n, f, a...) \
|
||||
do { \
|
||||
if ((n) <= journal_enable_debug) { \
|
||||
printf("(%s, %d): %s: ", \
|
||||
__FILE__, __LINE__, __func__); \
|
||||
printf(f, ## a); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif /*__KERNEL__ */
|
||||
#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
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* Checksum types.
|
||||
*/
|
||||
#define JBD2_CRC32_CHKSUM 1
|
||||
#define JBD2_MD5_CHKSUM 2
|
||||
#define JBD2_SHA1_CHKSUM 3
|
||||
#define JBD2_CRC32C_CHKSUM 4
|
||||
|
||||
#define JBD2_CRC32_CHKSUM_SIZE 4
|
||||
|
||||
#define JBD2_CHECKSUM_BYTES (32 / sizeof(__u32))
|
||||
/*
|
||||
* Commit block header for storing transactional checksums:
|
||||
*
|
||||
* NOTE: If FEATURE_COMPAT_CHECKSUM (checksum v1) is set, the h_chksum*
|
||||
* fields are used to store a checksum of the descriptor and data blocks.
|
||||
*
|
||||
* If FEATURE_INCOMPAT_CSUM_V2 (checksum v2) is set, then the h_chksum
|
||||
* field is used to store crc32c(uuid+commit_block). Each journal metadata
|
||||
* block gets its own checksum, and data block checksums are stored in
|
||||
* journal_block_tag (in the descriptor). The other h_chksum* fields are
|
||||
* not used.
|
||||
*
|
||||
* If FEATURE_INCOMPAT_CSUM_V3 is set, the descriptor block uses
|
||||
* journal_block_tag3_t to store a full 32-bit checksum. Everything else
|
||||
* is the same as v2.
|
||||
*
|
||||
* Checksum v1, v2, and v3 are mutually exclusive features.
|
||||
*/
|
||||
struct commit_header {
|
||||
__u32 h_magic;
|
||||
__u32 h_blocktype;
|
||||
__u32 h_sequence;
|
||||
unsigned char h_chksum_type;
|
||||
unsigned char h_chksum_size;
|
||||
unsigned char h_padding[2];
|
||||
__u32 h_chksum[JBD2_CHECKSUM_BYTES];
|
||||
__u64 h_commit_sec;
|
||||
__u32 h_commit_nsec;
|
||||
};
|
||||
|
||||
/*
|
||||
* The block tag: used to describe a single buffer in the journal
|
||||
*/
|
||||
typedef struct journal_block_tag3_s
|
||||
{
|
||||
__u32 t_blocknr; /* The on-disk block number */
|
||||
__u32 t_flags; /* See below */
|
||||
__u32 t_blocknr_high; /* most-significant high 32bits. */
|
||||
__u32 t_checksum; /* crc32c(uuid+seq+block) */
|
||||
} journal_block_tag3_t;
|
||||
|
||||
typedef struct journal_block_tag_s
|
||||
{
|
||||
__u32 t_blocknr; /* The on-disk block number */
|
||||
__u16 t_checksum; /* truncated crc32c(uuid+seq+block) */
|
||||
__u16 t_flags; /* See below */
|
||||
__u32 t_blocknr_high; /* most-significant high 32bits. */
|
||||
} journal_block_tag_t;
|
||||
|
||||
/* Tail of descriptor block, for checksumming */
|
||||
struct journal_block_tail {
|
||||
__be32 t_checksum;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* Tail of revoke block, for checksumming */
|
||||
struct journal_revoke_tail {
|
||||
__be32 r_checksum;
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
|
||||
|
||||
#define UUID_SIZE 16
|
||||
#define JFS_USERS_MAX 48
|
||||
#define JFS_USERS_SIZE (UUID_SIZE * JFS_USERS_MAX)
|
||||
/*
|
||||
* 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 */
|
||||
__u8 s_checksum_type; /* checksum type */
|
||||
__u8 s_padding2[3];
|
||||
__u32 s_padding[42];
|
||||
__u32 s_checksum; /* crc32c(superblock) */
|
||||
|
||||
/* 0x0100 */
|
||||
__u8 s_users[JFS_USERS_SIZE]; /* 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 & ext2fs_cpu_to_be32((mask))))
|
||||
#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \
|
||||
((j)->j_format_version >= 2 && \
|
||||
((j)->j_superblock->s_feature_ro_compat & ext2fs_cpu_to_be32((mask))))
|
||||
#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \
|
||||
((j)->j_format_version >= 2 && \
|
||||
((j)->j_superblock->s_feature_incompat & ext2fs_cpu_to_be32((mask))))
|
||||
|
||||
#define JFS_FEATURE_COMPAT_CHECKSUM 0x00000001
|
||||
|
||||
#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001
|
||||
#define JFS_FEATURE_INCOMPAT_64BIT 0x00000002
|
||||
#define JFS_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004
|
||||
#define JFS_FEATURE_INCOMPAT_CSUM_V2 0x00000008
|
||||
#define JFS_FEATURE_INCOMPAT_CSUM_V3 0x00000010
|
||||
|
||||
/* 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|\
|
||||
JFS_FEATURE_INCOMPAT_ASYNC_COMMIT|\
|
||||
JFS_FEATURE_INCOMPAT_64BIT|\
|
||||
JFS_FEATURE_INCOMPAT_CSUM_V2|\
|
||||
JFS_FEATURE_INCOMPAT_CSUM_V3)
|
||||
|
||||
#ifdef NO_INLINE_FUNCS
|
||||
extern size_t journal_tag_bytes(journal_t *journal);
|
||||
extern int journal_has_csum_v2or3(journal_t *journal);
|
||||
extern int tid_gt(tid_t x, tid_t y) EXT2FS_ATTR((unused));
|
||||
extern int tid_geq(tid_t x, tid_t y) EXT2FS_ATTR((unused));
|
||||
#endif
|
||||
|
||||
#if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
|
||||
#ifdef E2FSCK_INCLUDE_INLINE_FUNCS
|
||||
#if (__STDC_VERSION__ >= 199901L)
|
||||
#define _INLINE_ extern inline
|
||||
#else
|
||||
#define _INLINE_ inline
|
||||
#endif
|
||||
#else /* !E2FSCK_INCLUDE_INLINE FUNCS */
|
||||
#if (__STDC_VERSION__ >= 199901L)
|
||||
#define _INLINE_ inline
|
||||
#else /* not C99 */
|
||||
#ifdef __GNUC__
|
||||
#define _INLINE_ extern __inline__
|
||||
#else /* For Watcom C */
|
||||
#define _INLINE_ extern inline
|
||||
#endif /* __GNUC__ */
|
||||
#endif /* __STDC_VERSION__ >= 199901L */
|
||||
#endif /* INCLUDE_INLINE_FUNCS */
|
||||
|
||||
/* journal feature predicate functions */
|
||||
#define JFS_FEATURE_COMPAT_FUNCS(name, flagname) \
|
||||
_INLINE_ int jfs_has_feature_##name(journal_t *j); \
|
||||
_INLINE_ int jfs_has_feature_##name(journal_t *j) \
|
||||
{ \
|
||||
return ((j)->j_format_version >= 2 && \
|
||||
((j)->j_superblock->s_feature_compat & \
|
||||
ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_##flagname)) != 0); \
|
||||
} \
|
||||
_INLINE_ void jfs_set_feature_##name(journal_t *j); \
|
||||
_INLINE_ void jfs_set_feature_##name(journal_t *j) \
|
||||
{ \
|
||||
(j)->j_superblock->s_feature_compat |= \
|
||||
ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_##flagname); \
|
||||
} \
|
||||
_INLINE_ void jfs_clear_feature_##name(journal_t *j); \
|
||||
_INLINE_ void jfs_clear_feature_##name(journal_t *j) \
|
||||
{ \
|
||||
(j)->j_superblock->s_feature_compat &= \
|
||||
~ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_##flagname); \
|
||||
}
|
||||
|
||||
#define JFS_FEATURE_RO_COMPAT_FUNCS(name, flagname) \
|
||||
_INLINE_ int jfs_has_feature_##name(journal_t *j); \
|
||||
_INLINE_ int jfs_has_feature_##name(journal_t *j) \
|
||||
{ \
|
||||
return ((j)->j_format_version >= 2 && \
|
||||
((j)->j_superblock->s_feature_ro_compat & \
|
||||
ext2fs_cpu_to_be32(JFS_FEATURE_RO_COMPAT_##flagname)) != 0); \
|
||||
} \
|
||||
_INLINE_ void jfs_set_feature_##name(journal_t *j); \
|
||||
_INLINE_ void jfs_set_feature_##name(journal_t *j) \
|
||||
{ \
|
||||
(j)->j_superblock->s_feature_ro_compat |= \
|
||||
ext2fs_cpu_to_be32(JFS_FEATURE_RO_COMPAT_##flagname); \
|
||||
} \
|
||||
_INLINE_ void jfs_clear_feature_##name(journal_t *j); \
|
||||
_INLINE_ void jfs_clear_feature_##name(journal_t *j) \
|
||||
{ \
|
||||
(j)->j_superblock->s_feature_ro_compat &= \
|
||||
~ext2fs_cpu_to_be32(JFS_FEATURE_RO_COMPAT_##flagname); \
|
||||
}
|
||||
|
||||
#define JFS_FEATURE_INCOMPAT_FUNCS(name, flagname) \
|
||||
_INLINE_ int jfs_has_feature_##name(journal_t *j); \
|
||||
_INLINE_ int jfs_has_feature_##name(journal_t *j) \
|
||||
{ \
|
||||
return ((j)->j_format_version >= 2 && \
|
||||
((j)->j_superblock->s_feature_incompat & \
|
||||
ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_##flagname)) != 0); \
|
||||
} \
|
||||
_INLINE_ void jfs_set_feature_##name(journal_t *j); \
|
||||
_INLINE_ void jfs_set_feature_##name(journal_t *j) \
|
||||
{ \
|
||||
(j)->j_superblock->s_feature_incompat |= \
|
||||
ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_##flagname); \
|
||||
} \
|
||||
_INLINE_ void jfs_clear_feature_##name(journal_t *j); \
|
||||
_INLINE_ void jfs_clear_feature_##name(journal_t *j) \
|
||||
{ \
|
||||
(j)->j_superblock->s_feature_incompat &= \
|
||||
~ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_##flagname); \
|
||||
}
|
||||
|
||||
#else
|
||||
#define JFS_FEATURE_COMPAT_FUNCS(name, flagname) \
|
||||
extern int jfs_has_feature_##name(journal_t *j); \
|
||||
extern void jfs_set_feature_##name(journal_t *j); \
|
||||
extern void jfs_clear_feature_##name(journal_t *j);
|
||||
|
||||
#define JFS_FEATURE_RO_COMPAT_FUNCS(name, flagname) \
|
||||
extern int jfs_has_feature_##name(journal_t *j); \
|
||||
extern void jfs_set_feature_##name(journal_t *j); \
|
||||
extern void jfs_clear_feature_##name(journal_t *j);
|
||||
|
||||
#define JFS_FEATURE_INCOMPAT_FUNCS(name, flagname) \
|
||||
extern int jfs_has_feature_##name(journal_t *j); \
|
||||
extern void jfs_set_feature_##name(journal_t *j); \
|
||||
extern void jfs_clear_feature_##name(journal_t *j);
|
||||
|
||||
#endif /* (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) */
|
||||
|
||||
JFS_FEATURE_COMPAT_FUNCS(checksum, CHECKSUM)
|
||||
|
||||
JFS_FEATURE_INCOMPAT_FUNCS(revoke, REVOKE)
|
||||
JFS_FEATURE_INCOMPAT_FUNCS(64bit, 64BIT)
|
||||
JFS_FEATURE_INCOMPAT_FUNCS(async_commit, ASYNC_COMMIT)
|
||||
JFS_FEATURE_INCOMPAT_FUNCS(csum2, CSUM_V2)
|
||||
JFS_FEATURE_INCOMPAT_FUNCS(csum3, CSUM_V3)
|
||||
|
||||
#if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
|
||||
/*
|
||||
* helper functions to deal with 32 or 64bit block numbers.
|
||||
*/
|
||||
_INLINE_ size_t journal_tag_bytes(journal_t *journal)
|
||||
{
|
||||
size_t sz;
|
||||
|
||||
if (jfs_has_feature_csum3(journal))
|
||||
return sizeof(journal_block_tag3_t);
|
||||
|
||||
sz = sizeof(journal_block_tag_t);
|
||||
|
||||
if (jfs_has_feature_csum2(journal))
|
||||
sz += sizeof(__u16);
|
||||
|
||||
if (jfs_has_feature_64bit(journal))
|
||||
return sz;
|
||||
|
||||
return sz - sizeof(__u32);
|
||||
}
|
||||
|
||||
_INLINE_ int journal_has_csum_v2or3(journal_t *journal)
|
||||
{
|
||||
if (jfs_has_feature_csum2(journal) || jfs_has_feature_csum3(journal))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Comparison functions for transaction IDs: perform comparisons using
|
||||
* modulo arithmetic so that they work over sequence number wraps. */
|
||||
|
||||
_INLINE_ int tid_gt(tid_t x, tid_t y)
|
||||
{
|
||||
int difference = (x - y);
|
||||
return (difference > 0);
|
||||
}
|
||||
|
||||
_INLINE_ int tid_geq(tid_t x, tid_t y)
|
||||
{
|
||||
int difference = (x - y);
|
||||
return (difference >= 0);
|
||||
}
|
||||
#endif /* (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) */
|
||||
|
||||
#undef _INLINE_
|
||||
|
||||
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);
|
||||
|
||||
#endif /* _LINUX_JBD_H */
|
109
src/ext2fs/kernel-list.h
Normal file
109
src/ext2fs/kernel-list.h
Normal file
|
@ -0,0 +1,109 @@
|
|||
#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 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
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* missing.c --- stuff we need from features we don't care about (journal)
|
||||
*
|
||||
* Copyright (C) 2000 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
/*
|
||||
* Convenience function which zeros out _num_ blocks starting at
|
||||
* _blk_. In case of an error, the details of the error is returned
|
||||
* via _ret_blk_ and _ret_count_ if they are non-NULL pointers.
|
||||
* Returns 0 on success, and an error code on an error.
|
||||
*
|
||||
* As a special case, if the first argument is NULL, then it will
|
||||
* attempt to free the static zeroizing buffer. (This is to keep
|
||||
* programs that check for memory leaks happy.)
|
||||
*/
|
||||
#define MAX_STRIDE_LENGTH (4194304 / (int) fs->blocksize)
|
||||
errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num,
|
||||
blk64_t *ret_blk, int *ret_count)
|
||||
{
|
||||
int j, count;
|
||||
static void *buf;
|
||||
static int stride_length;
|
||||
errcode_t retval;
|
||||
|
||||
/* If fs is null, clean up the static buffer and return */
|
||||
if (!fs) {
|
||||
if (buf) {
|
||||
free(buf);
|
||||
buf = 0;
|
||||
stride_length = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Deal with zeroing less than 1 block */
|
||||
if (num <= 0)
|
||||
return 0;
|
||||
|
||||
/* Try a zero out command, if supported */
|
||||
retval = io_channel_zeroout(fs->io, blk, num);
|
||||
if (retval == 0)
|
||||
return 0;
|
||||
|
||||
/* Allocate the zeroizing buffer if necessary */
|
||||
if (num > stride_length && stride_length < MAX_STRIDE_LENGTH) {
|
||||
void *p;
|
||||
int new_stride = num;
|
||||
|
||||
if (new_stride > MAX_STRIDE_LENGTH)
|
||||
new_stride = MAX_STRIDE_LENGTH;
|
||||
p = realloc(buf, fs->blocksize * new_stride);
|
||||
if (!p)
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
buf = p;
|
||||
stride_length = new_stride;
|
||||
memset(buf, 0, fs->blocksize * stride_length);
|
||||
}
|
||||
/* OK, do the write loop */
|
||||
j=0;
|
||||
while (j < num) {
|
||||
if (blk % stride_length) {
|
||||
count = stride_length - (blk % stride_length);
|
||||
if (count > (num - j))
|
||||
count = num - j;
|
||||
} else {
|
||||
count = num - j;
|
||||
if (count > stride_length)
|
||||
count = stride_length;
|
||||
}
|
||||
retval = io_channel_write_blk64(fs->io, blk, count, buf);
|
||||
if (retval) {
|
||||
if (ret_count)
|
||||
*ret_count = count;
|
||||
if (ret_blk)
|
||||
*ret_blk = blk;
|
||||
return retval;
|
||||
}
|
||||
j += count; blk += count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num,
|
||||
blk_t *ret_blk, int *ret_count)
|
||||
{
|
||||
blk64_t ret_blk2;
|
||||
errcode_t retval;
|
||||
|
||||
retval = ext2fs_zero_blocks2(fs, blk, num, &ret_blk2, ret_count);
|
||||
if (retval)
|
||||
*ret_blk = (blk_t) ret_blk2;
|
||||
return retval;
|
||||
}
|
591
src/ext2fs/mkjournal.c
Normal file
591
src/ext2fs/mkjournal.c
Normal file
|
@ -0,0 +1,591 @@
|
|||
/*
|
||||
* 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 Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#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
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
#include "kernel-jbd.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 num_blocks, int flags,
|
||||
char **ret_jsb)
|
||||
{
|
||||
errcode_t retval;
|
||||
journal_superblock_t *jsb;
|
||||
|
||||
if (num_blocks < JFS_MIN_JOURNAL_BLOCKS)
|
||||
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(num_blocks);
|
||||
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 (ext2fs_has_feature_journal_dev(fs->super)) {
|
||||
jsb->s_nr_users = 0;
|
||||
jsb->s_first = htonl(ext2fs_journal_sb_start(fs->blocksize) + 1);
|
||||
}
|
||||
|
||||
*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 num_blocks, int flags)
|
||||
{
|
||||
errcode_t retval;
|
||||
char *buf = 0;
|
||||
int fd, ret_size;
|
||||
blk_t i;
|
||||
|
||||
if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags,
|
||||
&buf)))
|
||||
return retval;
|
||||
|
||||
/* Open the device or journal file */
|
||||
if ((fd = open(filename, O_WRONLY)) < 0) {
|
||||
retval = errno;
|
||||
goto errfree;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
if (flags & EXT2_MKJOURNAL_LAZYINIT)
|
||||
goto success;
|
||||
|
||||
for (i = 1; i < num_blocks; i++) {
|
||||
ret_size = write(fd, buf, fs->blocksize);
|
||||
if (ret_size < 0) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
if (ret_size != (int) fs->blocksize)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
success:
|
||||
retval = 0;
|
||||
errout:
|
||||
close(fd);
|
||||
errfree:
|
||||
ext2fs_free_mem(&buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convenience function which zeros out _num_ blocks starting at
|
||||
* _blk_. In case of an error, the details of the error is returned
|
||||
* via _ret_blk_ and _ret_count_ if they are non-NULL pointers.
|
||||
* Returns 0 on success, and an error code on an error.
|
||||
*
|
||||
* As a special case, if the first argument is NULL, then it will
|
||||
* attempt to free the static zeroizing buffer. (This is to keep
|
||||
* programs that check for memory leaks happy.)
|
||||
*/
|
||||
#define MAX_STRIDE_LENGTH (4194304 / (int) fs->blocksize)
|
||||
errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num,
|
||||
blk64_t *ret_blk, int *ret_count)
|
||||
{
|
||||
int j, count;
|
||||
static void *buf;
|
||||
static int stride_length;
|
||||
errcode_t retval;
|
||||
|
||||
/* If fs is null, clean up the static buffer and return */
|
||||
if (!fs) {
|
||||
if (buf) {
|
||||
free(buf);
|
||||
buf = 0;
|
||||
stride_length = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Deal with zeroing less than 1 block */
|
||||
if (num <= 0)
|
||||
return 0;
|
||||
|
||||
/* Try a zero out command, if supported */
|
||||
retval = io_channel_zeroout(fs->io, blk, num);
|
||||
if (retval == 0)
|
||||
return 0;
|
||||
|
||||
/* Allocate the zeroizing buffer if necessary */
|
||||
if (num > stride_length && stride_length < MAX_STRIDE_LENGTH) {
|
||||
void *p;
|
||||
int new_stride = num;
|
||||
|
||||
if (new_stride > MAX_STRIDE_LENGTH)
|
||||
new_stride = MAX_STRIDE_LENGTH;
|
||||
p = realloc(buf, fs->blocksize * new_stride);
|
||||
if (!p)
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
buf = p;
|
||||
stride_length = new_stride;
|
||||
memset(buf, 0, fs->blocksize * stride_length);
|
||||
}
|
||||
/* OK, do the write loop */
|
||||
j=0;
|
||||
while (j < num) {
|
||||
if (blk % stride_length) {
|
||||
count = stride_length - (blk % stride_length);
|
||||
if (count > (num - j))
|
||||
count = num - j;
|
||||
} else {
|
||||
count = num - j;
|
||||
if (count > stride_length)
|
||||
count = stride_length;
|
||||
}
|
||||
retval = io_channel_write_blk64(fs->io, blk, count, buf);
|
||||
if (retval) {
|
||||
if (ret_count)
|
||||
*ret_count = count;
|
||||
if (ret_blk)
|
||||
*ret_blk = blk;
|
||||
return retval;
|
||||
}
|
||||
j += count; blk += count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num,
|
||||
blk_t *ret_blk, int *ret_count)
|
||||
{
|
||||
blk64_t ret_blk2;
|
||||
errcode_t retval;
|
||||
|
||||
retval = ext2fs_zero_blocks2(fs, blk, num, &ret_blk2, ret_count);
|
||||
if (retval)
|
||||
*ret_blk = (blk_t) ret_blk2;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the initial goal block to be roughly at the middle of the
|
||||
* filesystem. Pick a group that has the largest number of free
|
||||
* blocks.
|
||||
*/
|
||||
static blk64_t get_midpoint_journal_block(ext2_filsys fs)
|
||||
{
|
||||
dgrp_t group, start, end, i, log_flex;
|
||||
|
||||
group = ext2fs_group_of_blk2(fs, (ext2fs_blocks_count(fs->super) -
|
||||
fs->super->s_first_data_block) / 2);
|
||||
log_flex = 1 << fs->super->s_log_groups_per_flex;
|
||||
if (fs->super->s_log_groups_per_flex && (group > log_flex)) {
|
||||
group = group & ~(log_flex - 1);
|
||||
while ((group < fs->group_desc_count) &&
|
||||
ext2fs_bg_free_blocks_count(fs, group) == 0)
|
||||
group++;
|
||||
if (group == fs->group_desc_count)
|
||||
group = 0;
|
||||
start = group;
|
||||
} else
|
||||
start = (group > 0) ? group-1 : group;
|
||||
end = ((group+1) < fs->group_desc_count) ? group+1 : group;
|
||||
group = start;
|
||||
for (i = start + 1; i <= end; i++)
|
||||
if (ext2fs_bg_free_blocks_count(fs, i) >
|
||||
ext2fs_bg_free_blocks_count(fs, group))
|
||||
group = i;
|
||||
return ext2fs_group_first_block2(fs, group);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 num_blocks, blk64_t goal, int flags)
|
||||
{
|
||||
char *buf;
|
||||
errcode_t retval;
|
||||
struct ext2_inode inode;
|
||||
unsigned long long inode_size;
|
||||
int falloc_flags = EXT2_FALLOCATE_FORCE_INIT;
|
||||
blk64_t zblk;
|
||||
|
||||
if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags,
|
||||
&buf)))
|
||||
return retval;
|
||||
|
||||
if ((retval = ext2fs_read_bitmaps(fs)))
|
||||
goto out2;
|
||||
|
||||
if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
|
||||
goto out2;
|
||||
|
||||
if (inode.i_blocks > 0) {
|
||||
retval = EEXIST;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
if (goal == ~0ULL)
|
||||
goal = get_midpoint_journal_block(fs);
|
||||
|
||||
if (ext2fs_has_feature_extents(fs->super))
|
||||
inode.i_flags |= EXT4_EXTENTS_FL;
|
||||
|
||||
if (!(flags & EXT2_MKJOURNAL_LAZYINIT))
|
||||
falloc_flags |= EXT2_FALLOCATE_ZERO_BLOCKS;
|
||||
|
||||
inode_size = (unsigned long long)fs->blocksize * num_blocks;
|
||||
inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0);
|
||||
inode.i_links_count = 1;
|
||||
inode.i_mode = LINUX_S_IFREG | 0600;
|
||||
retval = ext2fs_inode_size_set(fs, &inode, inode_size);
|
||||
if (retval)
|
||||
goto out2;
|
||||
|
||||
retval = ext2fs_fallocate(fs, falloc_flags, journal_ino,
|
||||
&inode, goal, 0, num_blocks);
|
||||
if (retval)
|
||||
goto out2;
|
||||
|
||||
if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode)))
|
||||
goto out2;
|
||||
|
||||
retval = ext2fs_bmap2(fs, journal_ino, &inode, NULL, 0, 0, NULL, &zblk);
|
||||
if (retval)
|
||||
goto out2;
|
||||
|
||||
retval = io_channel_write_blk64(fs->io, zblk, 1, buf);
|
||||
if (retval)
|
||||
goto out2;
|
||||
|
||||
memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
|
||||
fs->super->s_jnl_blocks[15] = inode.i_size_high;
|
||||
fs->super->s_jnl_blocks[16] = inode.i_size;
|
||||
fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
|
||||
out2:
|
||||
ext2fs_free_mem(&buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a reasonable journal file size (in blocks) given the number of blocks
|
||||
* in the filesystem. For very small filesystems, it is not reasonable to
|
||||
* have a journal that fills more than half of the filesystem.
|
||||
*
|
||||
* n.b. comments assume 4k blocks
|
||||
*/
|
||||
int ext2fs_default_journal_size(__u64 num_blocks)
|
||||
{
|
||||
if (num_blocks < 2048)
|
||||
return -1;
|
||||
if (num_blocks < 32768) /* 128 MB */
|
||||
return (1024); /* 4 MB */
|
||||
if (num_blocks < 256*1024) /* 1 GB */
|
||||
return (4096); /* 16 MB */
|
||||
if (num_blocks < 512*1024) /* 2 GB */
|
||||
return (8192); /* 32 MB */
|
||||
if (num_blocks < 4096*1024) /* 16 GB */
|
||||
return (16384); /* 64 MB */
|
||||
if (num_blocks < 8192*1024) /* 32 GB */
|
||||
return (32768); /* 128 MB */
|
||||
if (num_blocks < 16384*1024) /* 64 GB */
|
||||
return (65536); /* 256 MB */
|
||||
if (num_blocks < 32768*1024) /* 128 GB */
|
||||
return (131072); /* 512 MB */
|
||||
return 262144; /* 1 GB */
|
||||
}
|
||||
|
||||
int ext2fs_journal_sb_start(int blocksize)
|
||||
{
|
||||
if (blocksize == EXT2_MIN_BLOCK_SIZE)
|
||||
return 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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[SUPERBLOCK_SIZE];
|
||||
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 = ext2fs_journal_sb_start(journal_dev->blocksize);
|
||||
if ((retval = io_channel_read_blk64(journal_dev->io, start,
|
||||
-SUPERBLOCK_SIZE,
|
||||
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);
|
||||
if (nr_users > JFS_USERS_MAX)
|
||||
return EXT2_ET_CORRUPT_JOURNAL_SB;
|
||||
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_blk64(journal_dev->io, start,
|
||||
-SUPERBLOCK_SIZE, 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));
|
||||
memset(fs->super->s_jnl_blocks, 0, sizeof(fs->super->s_jnl_blocks));
|
||||
ext2fs_set_feature_journal(fs->super);
|
||||
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_inode2(ext2_filsys fs, blk_t num_blocks,
|
||||
blk64_t goal, int flags)
|
||||
{
|
||||
errcode_t retval;
|
||||
ext2_ino_t journal_ino;
|
||||
struct stat st;
|
||||
char jfile[1024];
|
||||
int mount_flags;
|
||||
int fd = -1;
|
||||
|
||||
if (flags & EXT2_MKJOURNAL_NO_MNT_CHECK)
|
||||
mount_flags = 0;
|
||||
else if ((retval = ext2fs_check_mount_point(fs->device_name,
|
||||
&mount_flags,
|
||||
jfile, sizeof(jfile)-10)))
|
||||
return retval;
|
||||
|
||||
if (mount_flags & EXT2_MF_MOUNTED) {
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
int f = 0;
|
||||
#endif
|
||||
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) {
|
||||
retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
|
||||
close(fd);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Create the journal file */
|
||||
if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
|
||||
return errno;
|
||||
|
||||
/* Note that we can't do lazy journal initialization for mounted
|
||||
* filesystems, since the zero writing is also allocating the
|
||||
* journal blocks. We could use fallocate, but not all kernels
|
||||
* support that, and creating a journal on a mounted ext2
|
||||
* filesystems is extremely rare these days... Ignore it. */
|
||||
flags &= ~EXT2_MKJOURNAL_LAZYINIT;
|
||||
|
||||
if ((retval = write_journal_file(fs, jfile, num_blocks, flags)))
|
||||
goto errout;
|
||||
|
||||
/* Get inode number of the journal file */
|
||||
if (fstat(fd, &st) < 0) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
|
||||
retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
|
||||
#else
|
||||
#if HAVE_EXT2_IOCTLS
|
||||
if (ioctl(fd, EXT2_IOC_GETFLAGS, &f) < 0) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
f |= EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;
|
||||
retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
|
||||
#endif
|
||||
#endif
|
||||
if (retval) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (close(fd) < 0) {
|
||||
retval = errno;
|
||||
fd = -1;
|
||||
goto errout;
|
||||
}
|
||||
journal_ino = st.st_ino;
|
||||
memset(fs->super->s_jnl_blocks, 0,
|
||||
sizeof(fs->super->s_jnl_blocks));
|
||||
} else {
|
||||
if ((mount_flags & EXT2_MF_BUSY) &&
|
||||
!(fs->flags & EXT2_FLAG_EXCLUSIVE)) {
|
||||
retval = EBUSY;
|
||||
goto errout;
|
||||
}
|
||||
journal_ino = EXT2_JOURNAL_INO;
|
||||
if ((retval = write_journal_inode(fs, journal_ino,
|
||||
num_blocks, goal, 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));
|
||||
ext2fs_set_feature_journal(fs->super);
|
||||
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
return 0;
|
||||
errout:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags)
|
||||
{
|
||||
return ext2fs_add_journal_inode2(fs, num_blocks, ~0ULL, flags);
|
||||
}
|
||||
|
||||
|
||||
#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, JFS_MIN_JOURNAL_BLOCKS, 0);
|
||||
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_free(&fs);
|
||||
exit(0);
|
||||
|
||||
}
|
||||
#endif
|
|
@ -316,23 +316,17 @@ static VOID _GetDeviceSize(IN HANDLE h, OUT unsigned __int64 *FsSize)
|
|||
IOCTL_DISK_GET_PARTITION_INFO_EX,
|
||||
&pi, sizeof(pi), &pi, sizeof(pi));
|
||||
if (NT_SUCCESS(Status)) {
|
||||
uprintf("Size retrieved with: IOCTL_DISK_GET_PARTITION_INFO_EX");
|
||||
*FsSize = pi.PartitionLength.QuadPart;
|
||||
} else if (Status == STATUS_INVALID_DEVICE_REQUEST) {
|
||||
// No partitions: Try a drive geometry request
|
||||
uprintf("IOCTL_DISK_GET_PARTITION_INFO_EX failed, trying with IOCTL_DISK_GET_DRIVE_GEOMETRY_EX");
|
||||
RtlZeroMemory(&gi, sizeof(gi));
|
||||
|
||||
Status = pfNtDeviceIoControlFile(h, NULL, NULL, NULL, &IoStatusBlock,
|
||||
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
||||
&gi, sizeof(gi), &gi, sizeof(gi));
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
uprintf("Size retrieved with: IOCTL_DISK_GET_DRIVE_GEOMETRY_EX");
|
||||
if (NT_SUCCESS(Status))
|
||||
*FsSize = gi.DiskSize.QuadPart;
|
||||
} else {
|
||||
uprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: [%x] %s", Status, NtStatusError(Status));
|
||||
}
|
||||
} else if (Status == STATUS_INVALID_PARAMETER) {
|
||||
// Possibly a straight image file
|
||||
if (GetFileSizeEx(h, &li))
|
||||
|
@ -445,6 +439,12 @@ errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
errcode_t ext2fs_check_mount_point(const char *file, int *mount_flags, char *mtpt, int mtlen)
|
||||
{
|
||||
return EXT2_ET_OP_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
// Returns the number of blocks in a partition
|
||||
// Note: Do *NOT* be tempted to cache the device size according to the NT path as
|
||||
// different removable devices (e.g. UFD) may be remounted under the same path.
|
||||
|
@ -648,7 +648,6 @@ static errcode_t nt_read_blk(io_channel channel, unsigned long block, int count,
|
|||
return 0;
|
||||
}
|
||||
|
||||
// TODO: Add an nt_write_blk64()
|
||||
static errcode_t nt_write_blk(io_channel channel, unsigned long block, int count, const void *buf)
|
||||
{
|
||||
ULONG write_size;
|
||||
|
|
196
src/format.c
196
src/format.c
|
@ -49,7 +49,6 @@
|
|||
#include "format.h"
|
||||
#include "badblocks.h"
|
||||
#include "bled/bled.h"
|
||||
#include "ext2fs/ext2fs.h"
|
||||
#include "../res/grub/grub_version.h"
|
||||
|
||||
/*
|
||||
|
@ -665,51 +664,110 @@ out:
|
|||
return r;
|
||||
}
|
||||
|
||||
extern io_manager nt_io_manager(void);
|
||||
BOOL FormatExt2Fs(void)
|
||||
BOOL FormatExt2Fs(const char* label)
|
||||
{
|
||||
const char* path = "\\??\\C:\\tmp\\disk.img";
|
||||
// Mostly taken from mke2fs.conf
|
||||
const float reserve_ratio = 0.05f;
|
||||
const ext2fs_default_t ext2fs_default[5] = {
|
||||
{ 3*MB, 1024, 128, 3}, // "floppy"
|
||||
{ 512*MB, 1024, 128, 2}, // "small"
|
||||
{ 4*GB, 4096, 256, 2}, // "default"
|
||||
{ 16*GB, 4096, 256, 3}, // "big"
|
||||
{ 1024*TB, 4096, 256, 4} // "huge"
|
||||
};
|
||||
|
||||
BOOL ret = FALSE;
|
||||
char* path = NULL;
|
||||
int i, count;
|
||||
struct ext2_super_block features = { 0 };
|
||||
io_manager manager = nt_io_manager();
|
||||
blk_t journal_size;
|
||||
blk64_t size = 0, cur;
|
||||
ext2_filsys ext2fs;
|
||||
ext2_filsys ext2fs = NULL;
|
||||
errcode_t r;
|
||||
uint8_t* buf = NULL;
|
||||
|
||||
#if defined(RUFUS_TEST)
|
||||
// Create a 32 MB disk image file to test
|
||||
uint8_t zb[1024];
|
||||
HANDLE h;
|
||||
DWORD dwSize;
|
||||
const uint8_t buf[1024] = { 0 };
|
||||
|
||||
// Create a 32 MB zeroed file to test
|
||||
path = strdup("\\??\\C:\\tmp\\disk.img");
|
||||
memset(zb, 0xFF, sizeof(zb)); // Set to nonzero so we can detect init issues
|
||||
h = CreateFileU(path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
for (i = 0; i < 32 * 1024; i++) {
|
||||
if (!WriteFile(h, buf, sizeof(buf), &dwSize, NULL) || (dwSize != sizeof(buf))) {
|
||||
if (!WriteFile(h, zb, sizeof(zb), &dwSize, NULL) || (dwSize != sizeof(zb))) {
|
||||
uprintf("Write error: %s", WindowsErrorString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
CloseHandle(h);
|
||||
#else
|
||||
path = GetPartitionName((DWORD)ComboBox_GetItemData(hDeviceList, ComboBox_GetCurSel(hDeviceList)), CASPER_PARTITION_DEFAULT);
|
||||
#endif
|
||||
if (path == NULL)
|
||||
goto out;
|
||||
|
||||
// TODO: We could probably remove that call and get our size from a different means
|
||||
r = ext2fs_get_device_size2(path, EXT2_BLOCK_SIZE(&features), &size);
|
||||
uprintf("ext2fs_get_device_size: %d", r);
|
||||
// TODO: ERROR HANDLING
|
||||
// Set the number of blocks and reserved blocks
|
||||
PrintInfoDebug(0, MSG_222, "ext3");
|
||||
|
||||
// Figure out the volume size and block size
|
||||
r = ext2fs_get_device_size2(path, KB, &size);
|
||||
if ((r != 0) || (size == 0)) {
|
||||
uprintf("Could not read device size: %d", r);
|
||||
goto out;
|
||||
}
|
||||
size *= KB;
|
||||
for (i = 0; i < ARRAYSIZE(ext2fs_default); i++) {
|
||||
if (size < ext2fs_default[i].max_size)
|
||||
break;
|
||||
}
|
||||
assert(i < ARRAYSIZE(ext2fs_default));
|
||||
size /= ext2fs_default[i].block_size;
|
||||
for (features.s_log_block_size = 0; EXT2_BLOCK_SIZE_BITS(&features) <= EXT2_MAX_BLOCK_LOG_SIZE; features.s_log_block_size++) {
|
||||
if (EXT2_BLOCK_SIZE(&features) == ext2fs_default[i].block_size)
|
||||
break;
|
||||
}
|
||||
assert(EXT2_BLOCK_SIZE_BITS(&features) <= EXT2_MAX_BLOCK_LOG_SIZE);
|
||||
|
||||
// Set the blocks, reserved blocks and inodes
|
||||
ext2fs_blocks_count_set(&features, size);
|
||||
ext2fs_r_blocks_count_set(&features, (blk64_t)(0.05f * ext2fs_blocks_count(&features)));
|
||||
ext2fs_r_blocks_count_set(&features, (blk64_t)(reserve_ratio * size));
|
||||
features.s_rev_level = 1;
|
||||
features.s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
|
||||
// TODO: This needs to be computed according to volume size
|
||||
features.s_inodes_count = 8192;
|
||||
features.s_inode_size = ext2fs_default[i].inode_size;
|
||||
features.s_inodes_count = ((ext2fs_blocks_count(&features) >> ext2fs_default[i].inode_ratio) > UINT32_MAX) ?
|
||||
UINT32_MAX : (uint32_t)(ext2fs_blocks_count(&features) >> ext2fs_default[i].inode_ratio);
|
||||
uprintf("%d inodes, %lld blocks (block size = %d)", features.s_inodes_count, size, EXT2_BLOCK_SIZE(&features));
|
||||
uprintf("%lld blocks (%0.1f%%) reserved for the super user", ext2fs_r_blocks_count(&features), reserve_ratio * 100.0f);
|
||||
|
||||
// TODO: Set a volume label
|
||||
// Set features for ext3
|
||||
ext2fs_set_feature_journal(&features);
|
||||
ext2fs_set_feature_xattr(&features);
|
||||
ext2fs_set_feature_resize_inode(&features);
|
||||
ext2fs_set_feature_dir_index(&features);
|
||||
ext2fs_set_feature_filetype(&features);
|
||||
ext2fs_set_feature_sparse_super(&features);
|
||||
ext2fs_set_feature_large_file(&features);
|
||||
features.s_backup_bgs[0] = 1;
|
||||
features.s_default_mount_opts = EXT2_DEFM_XATTR_USER | EXT2_DEFM_ACL;
|
||||
|
||||
// Initialize the superblock
|
||||
// Now that we have set our base features, initialize a virtual superblock
|
||||
r = ext2fs_initialize(path, EXT2_FLAG_EXCLUSIVE | EXT2_FLAG_64BITS, &features, manager, &ext2fs);
|
||||
uprintf("ext2fs_initialize: %d", r);
|
||||
// TODO: ERROR HANDLING
|
||||
if (r != 0) {
|
||||
uprintf("Could not initialize ext2fs features: %d", r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
// TODO: Erase superblock data
|
||||
// Now that the superblock has been initialized, set it up
|
||||
// Zero 16 blocks of data from the start of our volume
|
||||
buf = calloc(16, ext2fs->io->block_size);
|
||||
assert(buf != NULL);
|
||||
r = io_channel_write_blk64(ext2fs->io, 0, 16, buf);
|
||||
safe_free(buf);
|
||||
if (r != 0) {
|
||||
uprintf("Could not zero ext2fs superblock area: %d", r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Finish setting up the file system
|
||||
CoCreateGuid((GUID*)ext2fs->super->s_uuid);
|
||||
ext2fs_init_csum_seed(ext2fs);
|
||||
ext2fs->super->s_def_hash_version = EXT2_HASH_HALF_MD4;
|
||||
|
@ -717,70 +775,79 @@ BOOL FormatExt2Fs(void)
|
|||
ext2fs->super->s_max_mnt_count = -1;
|
||||
ext2fs->super->s_creator_os = EXT2_OS_WINDOWS;
|
||||
ext2fs->super->s_errors = EXT2_ERRORS_CONTINUE;
|
||||
|
||||
// TODO: ext2 + journaling = ext3, so the way to set ext3 is to add features:
|
||||
// ext_attr, resize_inode, dir_index, filetype, sparse_super, has_journal, needs_recovery
|
||||
ext2fs_set_feature_xattr(&features);
|
||||
// ext2fs_set_feature_resize_inode(&sb);
|
||||
// ext2fs_set_feature_dir_index(&sb);
|
||||
ext2fs_set_feature_filetype(&features);
|
||||
// ext2fs_set_feature_sparse_super(&sb);
|
||||
// ext2fs_set_feature_journal(&sb);
|
||||
// ext2fs_set_feature_journal_needs_recovery(&sb);
|
||||
|
||||
// Optional we may want to add:
|
||||
// ext2fs_set_feature_64bit(&sb);
|
||||
// NB: the following is not needed as it is set by the OS automatically when creating a > 2GB file
|
||||
// ext2fs_set_feature_large_file(&sb);
|
||||
static_strcpy(ext2fs->super->s_volume_name, label);
|
||||
|
||||
r = ext2fs_allocate_tables(ext2fs);
|
||||
uprintf("ext2fs_allocate_tables: %d", r);
|
||||
// TODO: ERROR HANDLING
|
||||
if (r != 0) {
|
||||
uprintf("Could not allocate ext2fs tables: %d", r);
|
||||
goto out;
|
||||
}
|
||||
r = ext2fs_convert_subcluster_bitmap(ext2fs, &ext2fs->block_map);
|
||||
uprintf("ext2fs_convert_subcluster_bitmap: %d", r);
|
||||
// TODO: ERROR HANDLING
|
||||
if (r != 0) {
|
||||
uprintf("Could set ext2fs cluster bitmap: %d", r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Wipe inode table
|
||||
for (i = 0; i < (int)ext2fs->group_desc_count; i++) {
|
||||
cur = ext2fs_inode_table_loc(ext2fs, i);
|
||||
count = ext2fs_div_ceil((ext2fs->super->s_inodes_per_group - ext2fs_bg_itable_unused(ext2fs, i))
|
||||
* EXT2_GOOD_OLD_INODE_SIZE, EXT2_GOOD_OLD_INODE_SIZE);
|
||||
* EXT2_BLOCK_SIZE(ext2fs->super), EXT2_BLOCK_SIZE(ext2fs->super));
|
||||
r = ext2fs_zero_blocks2(ext2fs, cur, count, &cur, &count);
|
||||
if (r != 0) {
|
||||
uprintf("Could not zero inode at %llu (%d blocks): %d\n", cur, count, r);
|
||||
// TODO: ERROR HANDLING
|
||||
break;
|
||||
uprintf("Could not zero ext2fs inode at %llu (%d blocks): %d\n", cur, count, r);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
// Create root dir
|
||||
// Create root and lost+found dirs
|
||||
r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
|
||||
uprintf("ext2fs_mkdir(root): %d", r);
|
||||
// TODO: ERROR HANDLING
|
||||
|
||||
// Create 'lost+found'
|
||||
if (r != 0) {
|
||||
uprintf("Failed to create ext2fs root dir: %d", r);
|
||||
goto out;
|
||||
}
|
||||
ext2fs->umask = 077;
|
||||
r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, 0, "lost+found");
|
||||
uprintf("ext2fs_mkdir(lost+found): %d", r);
|
||||
// TODO: ERROR HANDLING
|
||||
if (r != 0) {
|
||||
uprintf("Failed to create ext2fs 'lost+found' dir: %d", r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Create bitmaps
|
||||
for (i = EXT2_ROOT_INO + 1; i < (int)EXT2_FIRST_INODE(ext2fs->super); i++)
|
||||
ext2fs_inode_alloc_stats2(ext2fs, i, +1, 0);
|
||||
ext2fs_inode_alloc_stats(ext2fs, i, 1);
|
||||
ext2fs_mark_ib_dirty(ext2fs);
|
||||
|
||||
r = ext2fs_mark_inode_bitmap2(ext2fs->inode_map, EXT2_BAD_INO);
|
||||
uprintf("ext2fs_mark_inode_bitmap2: %d", r);
|
||||
// TODO: ERROR HANDLING
|
||||
ext2fs_inode_alloc_stats2(ext2fs, EXT2_BAD_INO, 1, 0);
|
||||
if (r != 0) {
|
||||
uprintf("Could not set ext2fs inode bitmaps: %d", r);
|
||||
goto out;
|
||||
}
|
||||
ext2fs_inode_alloc_stats(ext2fs, EXT2_BAD_INO, 1);
|
||||
r = ext2fs_update_bb_inode(ext2fs, NULL);
|
||||
uprintf("ext2fs_update_bb_inode: %d", r);
|
||||
// TODO: ERROR HANDLING
|
||||
if (r != 0) {
|
||||
uprintf("Could not set ext2fs inode stats: %d", r);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = ext2fs_close_free(&ext2fs);
|
||||
uprintf("ext2fs_close_free: %d", r);
|
||||
// TODO: ERROR HANDLING
|
||||
// Create the journal
|
||||
journal_size = ext2fs_default_journal_size(ext2fs_blocks_count(ext2fs->super));
|
||||
uprintf("Creating journal (%d blocks)", journal_size);
|
||||
r = ext2fs_add_journal_inode(ext2fs, journal_size, EXT2_MKJOURNAL_NO_MNT_CHECK | EXT2_MKJOURNAL_LAZYINIT);
|
||||
|
||||
return TRUE;
|
||||
// Finally we can call close() to get the file system gets created
|
||||
r = ext2fs_close(ext2fs);
|
||||
if (r != 0) {
|
||||
uprintf("Could not create ext3 volume: %d", r);
|
||||
goto out;
|
||||
}
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
ext2fs_free(ext2fs);
|
||||
free(buf);
|
||||
free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2123,6 +2190,7 @@ DWORD WINAPI FormatThread(void* param)
|
|||
|
||||
// If FAT32 is requested and we have a large drive (>32 GB) use
|
||||
// large FAT32 format, else use MS's FormatEx.
|
||||
// TODO: We'll want a single call for ext2/ext3/ext4, large FAT32 and everything (after we switch to VDS?)
|
||||
ret = use_large_fat32?FormatFAT32(DriveIndex):FormatDrive(DriveIndex);
|
||||
if (!ret) {
|
||||
// Error will be set by FormatDrive() in FormatStatus
|
||||
|
|
12
src/format.h
12
src/format.h
|
@ -20,6 +20,8 @@
|
|||
#include <windows.h>
|
||||
#include <winioctl.h> // for MEDIA_TYPE
|
||||
|
||||
#include "ext2fs/ext2fs.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Callback command types (some errorcode were filled from HPUSBFW V2.2.3 and their
|
||||
|
@ -154,3 +156,13 @@ typedef struct {
|
|||
#define die(msg, err) do { uprintf(msg); \
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|err; \
|
||||
goto out; } while(0)
|
||||
|
||||
// For ext2/ext3/ext4 formatting
|
||||
typedef struct {
|
||||
uint64_t max_size;
|
||||
uint32_t block_size;
|
||||
uint32_t inode_size;
|
||||
uint32_t inode_ratio; // inode to data ration (bitshift)
|
||||
} ext2fs_default_t;
|
||||
|
||||
extern io_manager nt_io_manager(void);
|
||||
|
|
|
@ -1864,7 +1864,7 @@ out:
|
|||
/*
|
||||
* Main dialog callback
|
||||
*/
|
||||
extern BOOL FormatExt2Fs(void);
|
||||
extern BOOL FormatExt2Fs(const char* label);
|
||||
static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static DWORD DeviceNum = 0;
|
||||
|
@ -1897,7 +1897,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
case WM_COMMAND:
|
||||
#ifdef RUFUS_TEST
|
||||
if (LOWORD(wParam) == IDC_TEST) {
|
||||
FormatExt2Fs();
|
||||
FormatExt2Fs("casper-rw");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
#define CHECK_DRIVE_TIMEOUT 2000
|
||||
#define MARQUEE_TIMER_REFRESH 10 // Time between progress bar marquee refreshes, in ms
|
||||
#define FS_DEFAULT FS_FAT32
|
||||
#define CASPER_PARTITION_DEFAULT 2
|
||||
#define SINGLE_CLUSTERSIZE_DEFAULT 0x00000100
|
||||
#define BADLOCKS_PATTERN_TYPES 3
|
||||
#define BADBLOCK_PATTERN_COUNT 4
|
||||
|
|
10
src/rufus.rc
10
src/rufus.rc
|
@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
|||
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
EXSTYLE WS_EX_ACCEPTFILES
|
||||
CAPTION "Rufus 3.6.1522"
|
||||
CAPTION "Rufus 3.6.1523"
|
||||
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
||||
BEGIN
|
||||
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
||||
|
@ -394,8 +394,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,6,1522,0
|
||||
PRODUCTVERSION 3,6,1522,0
|
||||
FILEVERSION 3,6,1523,0
|
||||
PRODUCTVERSION 3,6,1523,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -413,13 +413,13 @@ BEGIN
|
|||
VALUE "Comments", "https://akeo.ie"
|
||||
VALUE "CompanyName", "Akeo Consulting"
|
||||
VALUE "FileDescription", "Rufus"
|
||||
VALUE "FileVersion", "3.6.1522"
|
||||
VALUE "FileVersion", "3.6.1523"
|
||||
VALUE "InternalName", "Rufus"
|
||||
VALUE "LegalCopyright", "© 2011-2019 Pete Batard (GPL v3)"
|
||||
VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html"
|
||||
VALUE "OriginalFilename", "rufus-3.6.exe"
|
||||
VALUE "ProductName", "Rufus"
|
||||
VALUE "ProductVersion", "3.6.1522"
|
||||
VALUE "ProductVersion", "3.6.1523"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
Loading…
Reference in a new issue