1
1
Fork 0
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:
Pete Batard 2019-04-15 17:04:39 +01:00
parent ddda1561ae
commit ccf0f1bf3c
No known key found for this signature in database
GPG key ID: 38E0CF5E69EDD671
20 changed files with 2338 additions and 210 deletions

View file

@ -56,6 +56,7 @@
<ClCompile Include="..\src\ext2fs\dir_iterate.c" /> <ClCompile Include="..\src\ext2fs\dir_iterate.c" />
<ClCompile Include="..\src\ext2fs\extent.c" /> <ClCompile Include="..\src\ext2fs\extent.c" />
<ClCompile Include="..\src\ext2fs\ext_attr.c" /> <ClCompile Include="..\src\ext2fs\ext_attr.c" />
<ClCompile Include="..\src\ext2fs\fallocate.c" />
<ClCompile Include="..\src\ext2fs\fileio.c" /> <ClCompile Include="..\src\ext2fs\fileio.c" />
<ClCompile Include="..\src\ext2fs\freefs.c" /> <ClCompile Include="..\src\ext2fs\freefs.c" />
<ClCompile Include="..\src\ext2fs\gen_bitmap.c" /> <ClCompile Include="..\src\ext2fs\gen_bitmap.c" />
@ -71,8 +72,8 @@
<ClCompile Include="..\src\ext2fs\i_block.c" /> <ClCompile Include="..\src\ext2fs\i_block.c" />
<ClCompile Include="..\src\ext2fs\link.c" /> <ClCompile Include="..\src\ext2fs\link.c" />
<ClCompile Include="..\src\ext2fs\lookup.c" /> <ClCompile Include="..\src\ext2fs\lookup.c" />
<ClCompile Include="..\src\ext2fs\missing.c" />
<ClCompile Include="..\src\ext2fs\mkdir.c" /> <ClCompile Include="..\src\ext2fs\mkdir.c" />
<ClCompile Include="..\src\ext2fs\mkjournal.c" />
<ClCompile Include="..\src\ext2fs\mmp.c" /> <ClCompile Include="..\src\ext2fs\mmp.c" />
<ClCompile Include="..\src\ext2fs\newdir.c" /> <ClCompile Include="..\src\ext2fs\newdir.c" />
<ClCompile Include="..\src\ext2fs\nt_io.c" /> <ClCompile Include="..\src\ext2fs\nt_io.c" />
@ -103,6 +104,9 @@
<ClInclude Include="..\src\ext2fs\ext3_extents.h" /> <ClInclude Include="..\src\ext2fs\ext3_extents.h" />
<ClInclude Include="..\src\ext2fs\ext4_acl.h" /> <ClInclude Include="..\src\ext2fs\ext4_acl.h" />
<ClInclude Include="..\src\ext2fs\hashmap.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" /> <ClInclude Include="..\src\ext2fs\rbtree.h" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">

View file

@ -27,9 +27,6 @@
<ClCompile Include="..\src\ext2fs\bitmaps.c"> <ClCompile Include="..\src\ext2fs\bitmaps.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\src\ext2fs\missing.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\ext2fs\closefs.c"> <ClCompile Include="..\src\ext2fs\closefs.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -153,6 +150,12 @@
<ClCompile Include="..\src\ext2fs\sha512.c"> <ClCompile Include="..\src\ext2fs\sha512.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </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>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\src\ext2fs\ext2_fs.h"> <ClInclude Include="..\src\ext2fs\ext2_fs.h">
@ -212,5 +215,14 @@
<ClInclude Include="..\src\ext2fs\hashmap.h"> <ClInclude Include="..\src\ext2fs\hashmap.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </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> </ItemGroup>
</Project> </Project>

View file

@ -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) * 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; BOOL success = FALSE;
char physical_name[32]; char partition_name[32];
CheckDriveIndex(DriveIndex); CheckDriveIndex(DriveIndex);
static_sprintf(physical_name, "\\??\\PHYSICALDRIVE%lu", DriveIndex);
static_sprintf(partition_name, "\\Device\\Harddisk%lu\\Partition%lu", DriveIndex, PartitionNumber);
success = TRUE; success = TRUE;
out: out:
return (success) ? safe_strdup(physical_name) : NULL; return (success) ? safe_strdup(partition_name) : NULL;
} }
/* /*

View file

@ -258,7 +258,7 @@ extern RUFUS_DRIVE_INFO SelectedDrive;
BOOL SetAutoMount(BOOL enable); BOOL SetAutoMount(BOOL enable);
BOOL GetAutoMount(BOOL* enabled); BOOL GetAutoMount(BOOL* enabled);
char* GetPhysicalName(DWORD DriveIndex); char* GetPhysicalName(DWORD DriveIndex);
char* GetNtPhysicalName(DWORD DriveIndex); char* GetPartitionName(DWORD DriveIndex, DWORD PartitionNumber);
BOOL DeletePartitions(DWORD DriveIndex); BOOL DeletePartitions(DWORD DriveIndex);
HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare); HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare);
char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent); char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent);

View file

@ -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 \ 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 \ 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 \ crc32c.c csum.c dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fallocate.c fileio.c \
gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c inline.c \ freefs.c gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c \
inline_data.c inode.c io_manager.c link.c lookup.c missing.c mkdir.c mmp.c newdir.c nt_io.c \ inline.c inline_data.c inode.c io_manager.c link.c lookup.c mkdir.c mkjournal.c mmp.c newdir.c \
punch.c rbtree.c read_bb.c rw_bitmaps.c sha512.c symlink.c valid_blk.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 libext2fs_a_CFLAGS = $(AM_CFLAGS) -DEXT2_FLAT_INCLUDES=0 -DHAVE_CONFIG_H -I. -I.. -Wno-undef -Wno-strict-aliasing -Wno-shadow

View file

@ -107,8 +107,8 @@ am_libext2fs_a_OBJECTS = libext2fs_a-alloc.$(OBJEXT) \
libext2fs_a-dirblock.$(OBJEXT) \ libext2fs_a-dirblock.$(OBJEXT) \
libext2fs_a-dir_iterate.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \ libext2fs_a-dir_iterate.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \
libext2fs_a-ext_attr.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \ libext2fs_a-ext_attr.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \
libext2fs_a-fileio.$(OBJEXT) libext2fs_a-freefs.$(OBJEXT) \ libext2fs_a-fallocate.$(OBJEXT) libext2fs_a-fileio.$(OBJEXT) \
libext2fs_a-gen_bitmap.$(OBJEXT) \ libext2fs_a-freefs.$(OBJEXT) libext2fs_a-gen_bitmap.$(OBJEXT) \
libext2fs_a-gen_bitmap64.$(OBJEXT) \ libext2fs_a-gen_bitmap64.$(OBJEXT) \
libext2fs_a-get_num_dirs.$(OBJEXT) \ libext2fs_a-get_num_dirs.$(OBJEXT) \
libext2fs_a-hashmap.$(OBJEXT) libext2fs_a-i_block.$(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-initialize.$(OBJEXT) libext2fs_a-inline.$(OBJEXT) \
libext2fs_a-inline_data.$(OBJEXT) libext2fs_a-inode.$(OBJEXT) \ libext2fs_a-inline_data.$(OBJEXT) libext2fs_a-inode.$(OBJEXT) \
libext2fs_a-io_manager.$(OBJEXT) libext2fs_a-link.$(OBJEXT) \ libext2fs_a-io_manager.$(OBJEXT) libext2fs_a-link.$(OBJEXT) \
libext2fs_a-lookup.$(OBJEXT) libext2fs_a-missing.$(OBJEXT) \ libext2fs_a-lookup.$(OBJEXT) libext2fs_a-mkdir.$(OBJEXT) \
libext2fs_a-mkdir.$(OBJEXT) libext2fs_a-mmp.$(OBJEXT) \ libext2fs_a-mkjournal.$(OBJEXT) libext2fs_a-mmp.$(OBJEXT) \
libext2fs_a-newdir.$(OBJEXT) libext2fs_a-nt_io.$(OBJEXT) \ libext2fs_a-newdir.$(OBJEXT) libext2fs_a-nt_io.$(OBJEXT) \
libext2fs_a-punch.$(OBJEXT) libext2fs_a-rbtree.$(OBJEXT) \ libext2fs_a-punch.$(OBJEXT) libext2fs_a-rbtree.$(OBJEXT) \
libext2fs_a-read_bb.$(OBJEXT) libext2fs_a-rw_bitmaps.$(OBJEXT) \ libext2fs_a-read_bb.$(OBJEXT) libext2fs_a-rw_bitmaps.$(OBJEXT) \
@ -272,10 +272,10 @@ top_srcdir = @top_srcdir@
noinst_LIBRARIES = libext2fs.a noinst_LIBRARIES = libext2fs.a
libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c \ 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 \ 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 \ crc32c.c csum.c dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fallocate.c fileio.c \
gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c inline.c \ freefs.c gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c \
inline_data.c inode.c io_manager.c link.c lookup.c missing.c mkdir.c mmp.c newdir.c nt_io.c \ inline.c inline_data.c inode.c io_manager.c link.c lookup.c mkdir.c mkjournal.c mmp.c newdir.c \
punch.c rbtree.c read_bb.c rw_bitmaps.c sha512.c symlink.c valid_blk.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 libext2fs_a_CFLAGS = $(AM_CFLAGS) -DEXT2_FLAT_INCLUDES=0 -DHAVE_CONFIG_H -I. -I.. -Wno-undef -Wno-strict-aliasing -Wno-shadow
all: all-am all: all-am
@ -459,6 +459,12 @@ libext2fs_a-ext_attr.o: ext_attr.c
libext2fs_a-ext_attr.obj: 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` $(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 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 $(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 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` $(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 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 $(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 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` $(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 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 $(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

View file

@ -177,6 +177,9 @@
/* Define if you have the 'wint_t' type. */ /* Define if you have the 'wint_t' type. */
#define HAVE_WINT_T 1 #define HAVE_WINT_T 1
/* Define if you have 'winsock.h'. */
#define HAVE_WINSOCK_H 1
/* Define to 1 if O_NOATIME works. */ /* Define to 1 if O_NOATIME works. */
#define HAVE_WORKING_O_NOATIME 0 #define HAVE_WORKING_O_NOATIME 0

View file

@ -785,9 +785,11 @@ struct ext2_super_block {
*/ */
#define EXT2_OS_LINUX 0 #define EXT2_OS_LINUX 0
#define EXT2_OS_HURD 1 #define EXT2_OS_HURD 1
#define EXT2_OS_WINDOWS 2 #define EXT2_OBSO_OS_MASIX 2
#define EXT2_OS_FREEBSD 3 #define EXT2_OS_FREEBSD 3
#define EXT2_OS_LITES 4 #define EXT2_OS_LITES 4
#define EXT2_OS_WINDOWS 5
#define EXT2_OS_MACOS 6
/* /*
* Revision levels * Revision levels

857
src/ext2fs/fallocate.c Normal file
View 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
View 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
View 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
View 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

View file

@ -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
View 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

View file

@ -316,23 +316,17 @@ static VOID _GetDeviceSize(IN HANDLE h, OUT unsigned __int64 *FsSize)
IOCTL_DISK_GET_PARTITION_INFO_EX, IOCTL_DISK_GET_PARTITION_INFO_EX,
&pi, sizeof(pi), &pi, sizeof(pi)); &pi, sizeof(pi), &pi, sizeof(pi));
if (NT_SUCCESS(Status)) { if (NT_SUCCESS(Status)) {
uprintf("Size retrieved with: IOCTL_DISK_GET_PARTITION_INFO_EX");
*FsSize = pi.PartitionLength.QuadPart; *FsSize = pi.PartitionLength.QuadPart;
} else if (Status == STATUS_INVALID_DEVICE_REQUEST) { } else if (Status == STATUS_INVALID_DEVICE_REQUEST) {
// No partitions: Try a drive geometry 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)); RtlZeroMemory(&gi, sizeof(gi));
Status = pfNtDeviceIoControlFile(h, NULL, NULL, NULL, &IoStatusBlock, Status = pfNtDeviceIoControlFile(h, NULL, NULL, NULL, &IoStatusBlock,
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
&gi, sizeof(gi), &gi, sizeof(gi)); &gi, sizeof(gi), &gi, sizeof(gi));
if (NT_SUCCESS(Status)) { if (NT_SUCCESS(Status))
uprintf("Size retrieved with: IOCTL_DISK_GET_DRIVE_GEOMETRY_EX");
*FsSize = gi.DiskSize.QuadPart; *FsSize = gi.DiskSize.QuadPart;
} else {
uprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: [%x] %s", Status, NtStatusError(Status));
}
} else if (Status == STATUS_INVALID_PARAMETER) { } else if (Status == STATUS_INVALID_PARAMETER) {
// Possibly a straight image file // Possibly a straight image file
if (GetFileSizeEx(h, &li)) if (GetFileSizeEx(h, &li))
@ -445,6 +439,12 @@ errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags)
return 0; 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 // Returns the number of blocks in a partition
// Note: Do *NOT* be tempted to cache the device size according to the NT path as // 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. // 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; 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) static errcode_t nt_write_blk(io_channel channel, unsigned long block, int count, const void *buf)
{ {
ULONG write_size; ULONG write_size;

View file

@ -49,7 +49,6 @@
#include "format.h" #include "format.h"
#include "badblocks.h" #include "badblocks.h"
#include "bled/bled.h" #include "bled/bled.h"
#include "ext2fs/ext2fs.h"
#include "../res/grub/grub_version.h" #include "../res/grub/grub_version.h"
/* /*
@ -665,51 +664,110 @@ out:
return r; return r;
} }
extern io_manager nt_io_manager(void); BOOL FormatExt2Fs(const char* label)
BOOL FormatExt2Fs(void)
{ {
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; int i, count;
struct ext2_super_block features = { 0 }; struct ext2_super_block features = { 0 };
io_manager manager = nt_io_manager(); io_manager manager = nt_io_manager();
blk_t journal_size;
blk64_t size = 0, cur; blk64_t size = 0, cur;
ext2_filsys ext2fs; ext2_filsys ext2fs = NULL;
errcode_t r; 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; HANDLE h;
DWORD dwSize; DWORD dwSize;
const uint8_t buf[1024] = { 0 }; path = strdup("\\??\\C:\\tmp\\disk.img");
memset(zb, 0xFF, sizeof(zb)); // Set to nonzero so we can detect init issues
// Create a 32 MB zeroed file to test
h = CreateFileU(path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); h = CreateFileU(path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
for (i = 0; i < 32 * 1024; i++) { 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()); uprintf("Write error: %s", WindowsErrorString());
break; break;
} }
} }
CloseHandle(h); 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 PrintInfoDebug(0, MSG_222, "ext3");
r = ext2fs_get_device_size2(path, EXT2_BLOCK_SIZE(&features), &size);
uprintf("ext2fs_get_device_size: %d", r); // Figure out the volume size and block size
// TODO: ERROR HANDLING r = ext2fs_get_device_size2(path, KB, &size);
// Set the number of blocks and reserved blocks 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_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_rev_level = 1;
features.s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; features.s_inode_size = ext2fs_default[i].inode_size;
// TODO: This needs to be computed according to volume size features.s_inodes_count = ((ext2fs_blocks_count(&features) >> ext2fs_default[i].inode_ratio) > UINT32_MAX) ?
features.s_inodes_count = 8192; 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); r = ext2fs_initialize(path, EXT2_FLAG_EXCLUSIVE | EXT2_FLAG_64BITS, &features, manager, &ext2fs);
uprintf("ext2fs_initialize: %d", r); if (r != 0) {
// TODO: ERROR HANDLING uprintf("Could not initialize ext2fs features: %d", r);
goto out;
}
// TODO: Erase superblock data // Zero 16 blocks of data from the start of our volume
// Now that the superblock has been initialized, set it up 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); CoCreateGuid((GUID*)ext2fs->super->s_uuid);
ext2fs_init_csum_seed(ext2fs); ext2fs_init_csum_seed(ext2fs);
ext2fs->super->s_def_hash_version = EXT2_HASH_HALF_MD4; 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_max_mnt_count = -1;
ext2fs->super->s_creator_os = EXT2_OS_WINDOWS; ext2fs->super->s_creator_os = EXT2_OS_WINDOWS;
ext2fs->super->s_errors = EXT2_ERRORS_CONTINUE; ext2fs->super->s_errors = EXT2_ERRORS_CONTINUE;
static_strcpy(ext2fs->super->s_volume_name, label);
// 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);
r = ext2fs_allocate_tables(ext2fs); r = ext2fs_allocate_tables(ext2fs);
uprintf("ext2fs_allocate_tables: %d", r); if (r != 0) {
// TODO: ERROR HANDLING uprintf("Could not allocate ext2fs tables: %d", r);
goto out;
}
r = ext2fs_convert_subcluster_bitmap(ext2fs, &ext2fs->block_map); r = ext2fs_convert_subcluster_bitmap(ext2fs, &ext2fs->block_map);
uprintf("ext2fs_convert_subcluster_bitmap: %d", r); if (r != 0) {
// TODO: ERROR HANDLING uprintf("Could set ext2fs cluster bitmap: %d", r);
goto out;
}
// Wipe inode table // Wipe inode table
for (i = 0; i < (int)ext2fs->group_desc_count; i++) { for (i = 0; i < (int)ext2fs->group_desc_count; i++) {
cur = ext2fs_inode_table_loc(ext2fs, i); cur = ext2fs_inode_table_loc(ext2fs, i);
count = ext2fs_div_ceil((ext2fs->super->s_inodes_per_group - ext2fs_bg_itable_unused(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); r = ext2fs_zero_blocks2(ext2fs, cur, count, &cur, &count);
if (r != 0) { if (r != 0) {
uprintf("Could not zero inode at %llu (%d blocks): %d\n", cur, count, r); uprintf("Could not zero ext2fs inode at %llu (%d blocks): %d\n", cur, count, r);
// TODO: ERROR HANDLING goto out;
break;
} }
} }
// Create root dir // Create root and lost+found dirs
r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0); r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
uprintf("ext2fs_mkdir(root): %d", r); if (r != 0) {
// TODO: ERROR HANDLING uprintf("Failed to create ext2fs root dir: %d", r);
goto out;
// Create 'lost+found' }
ext2fs->umask = 077; ext2fs->umask = 077;
r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, 0, "lost+found"); r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, 0, "lost+found");
uprintf("ext2fs_mkdir(lost+found): %d", r); if (r != 0) {
// TODO: ERROR HANDLING 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++) 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); ext2fs_mark_ib_dirty(ext2fs);
r = ext2fs_mark_inode_bitmap2(ext2fs->inode_map, EXT2_BAD_INO); r = ext2fs_mark_inode_bitmap2(ext2fs->inode_map, EXT2_BAD_INO);
uprintf("ext2fs_mark_inode_bitmap2: %d", r); if (r != 0) {
// TODO: ERROR HANDLING uprintf("Could not set ext2fs inode bitmaps: %d", r);
ext2fs_inode_alloc_stats2(ext2fs, EXT2_BAD_INO, 1, 0); goto out;
}
ext2fs_inode_alloc_stats(ext2fs, EXT2_BAD_INO, 1);
r = ext2fs_update_bb_inode(ext2fs, NULL); r = ext2fs_update_bb_inode(ext2fs, NULL);
uprintf("ext2fs_update_bb_inode: %d", r); if (r != 0) {
// TODO: ERROR HANDLING uprintf("Could not set ext2fs inode stats: %d", r);
goto out;
}
r = ext2fs_close_free(&ext2fs); // Create the journal
uprintf("ext2fs_close_free: %d", r); journal_size = ext2fs_default_journal_size(ext2fs_blocks_count(ext2fs->super));
// TODO: ERROR HANDLING 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 // If FAT32 is requested and we have a large drive (>32 GB) use
// large FAT32 format, else use MS's FormatEx. // 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); ret = use_large_fat32?FormatFAT32(DriveIndex):FormatDrive(DriveIndex);
if (!ret) { if (!ret) {
// Error will be set by FormatDrive() in FormatStatus // Error will be set by FormatDrive() in FormatStatus

View file

@ -20,6 +20,8 @@
#include <windows.h> #include <windows.h>
#include <winioctl.h> // for MEDIA_TYPE #include <winioctl.h> // for MEDIA_TYPE
#include "ext2fs/ext2fs.h"
#pragma once #pragma once
/* Callback command types (some errorcode were filled from HPUSBFW V2.2.3 and their /* 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); \ #define die(msg, err) do { uprintf(msg); \
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|err; \ FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|err; \
goto out; } while(0) 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);

View file

@ -1864,7 +1864,7 @@ out:
/* /*
* Main dialog callback * 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 INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{ {
static DWORD DeviceNum = 0; static DWORD DeviceNum = 0;
@ -1897,7 +1897,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
case WM_COMMAND: case WM_COMMAND:
#ifdef RUFUS_TEST #ifdef RUFUS_TEST
if (LOWORD(wParam) == IDC_TEST) { if (LOWORD(wParam) == IDC_TEST) {
FormatExt2Fs(); FormatExt2Fs("casper-rw");
break; break;
} }
#endif #endif

View file

@ -82,6 +82,7 @@
#define CHECK_DRIVE_TIMEOUT 2000 #define CHECK_DRIVE_TIMEOUT 2000
#define MARQUEE_TIMER_REFRESH 10 // Time between progress bar marquee refreshes, in ms #define MARQUEE_TIMER_REFRESH 10 // Time between progress bar marquee refreshes, in ms
#define FS_DEFAULT FS_FAT32 #define FS_DEFAULT FS_FAT32
#define CASPER_PARTITION_DEFAULT 2
#define SINGLE_CLUSTERSIZE_DEFAULT 0x00000100 #define SINGLE_CLUSTERSIZE_DEFAULT 0x00000100
#define BADLOCKS_PATTERN_TYPES 3 #define BADLOCKS_PATTERN_TYPES 3
#define BADBLOCK_PATTERN_COUNT 4 #define BADBLOCK_PATTERN_COUNT 4

View file

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 232, 326 IDD_DIALOG DIALOGEX 12, 12, 232, 326
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 3.6.1522" CAPTION "Rufus 3.6.1523"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0 FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@ -394,8 +394,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,6,1522,0 FILEVERSION 3,6,1523,0
PRODUCTVERSION 3,6,1522,0 PRODUCTVERSION 3,6,1523,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -413,13 +413,13 @@ BEGIN
VALUE "Comments", "https://akeo.ie" VALUE "Comments", "https://akeo.ie"
VALUE "CompanyName", "Akeo Consulting" VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus" VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "3.6.1522" VALUE "FileVersion", "3.6.1523"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2019 Pete Batard (GPL v3)" VALUE "LegalCopyright", "© 2011-2019 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html" VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus-3.6.exe" VALUE "OriginalFilename", "rufus-3.6.exe"
VALUE "ProductName", "Rufus" VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "3.6.1522" VALUE "ProductVersion", "3.6.1523"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"