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…
	
	Add table
		Add a link
		
	
		Reference in a new issue