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\dir_iterate.c" /> | ||||||
|     <ClCompile Include="..\src\ext2fs\extent.c" /> |     <ClCompile Include="..\src\ext2fs\extent.c" /> | ||||||
|     <ClCompile Include="..\src\ext2fs\ext_attr.c" /> |     <ClCompile Include="..\src\ext2fs\ext_attr.c" /> | ||||||
|  |     <ClCompile Include="..\src\ext2fs\fallocate.c" /> | ||||||
|     <ClCompile Include="..\src\ext2fs\fileio.c" /> |     <ClCompile Include="..\src\ext2fs\fileio.c" /> | ||||||
|     <ClCompile Include="..\src\ext2fs\freefs.c" /> |     <ClCompile Include="..\src\ext2fs\freefs.c" /> | ||||||
|     <ClCompile Include="..\src\ext2fs\gen_bitmap.c" /> |     <ClCompile Include="..\src\ext2fs\gen_bitmap.c" /> | ||||||
|  | @ -71,8 +72,8 @@ | ||||||
|     <ClCompile Include="..\src\ext2fs\i_block.c" /> |     <ClCompile Include="..\src\ext2fs\i_block.c" /> | ||||||
|     <ClCompile Include="..\src\ext2fs\link.c" /> |     <ClCompile Include="..\src\ext2fs\link.c" /> | ||||||
|     <ClCompile Include="..\src\ext2fs\lookup.c" /> |     <ClCompile Include="..\src\ext2fs\lookup.c" /> | ||||||
|     <ClCompile Include="..\src\ext2fs\missing.c" /> |  | ||||||
|     <ClCompile Include="..\src\ext2fs\mkdir.c" /> |     <ClCompile Include="..\src\ext2fs\mkdir.c" /> | ||||||
|  |     <ClCompile Include="..\src\ext2fs\mkjournal.c" /> | ||||||
|     <ClCompile Include="..\src\ext2fs\mmp.c" /> |     <ClCompile Include="..\src\ext2fs\mmp.c" /> | ||||||
|     <ClCompile Include="..\src\ext2fs\newdir.c" /> |     <ClCompile Include="..\src\ext2fs\newdir.c" /> | ||||||
|     <ClCompile Include="..\src\ext2fs\nt_io.c" /> |     <ClCompile Include="..\src\ext2fs\nt_io.c" /> | ||||||
|  | @ -103,6 +104,9 @@ | ||||||
|     <ClInclude Include="..\src\ext2fs\ext3_extents.h" /> |     <ClInclude Include="..\src\ext2fs\ext3_extents.h" /> | ||||||
|     <ClInclude Include="..\src\ext2fs\ext4_acl.h" /> |     <ClInclude Include="..\src\ext2fs\ext4_acl.h" /> | ||||||
|     <ClInclude Include="..\src\ext2fs\hashmap.h" /> |     <ClInclude Include="..\src\ext2fs\hashmap.h" /> | ||||||
|  |     <ClInclude Include="..\src\ext2fs\jfs_compat.h" /> | ||||||
|  |     <ClInclude Include="..\src\ext2fs\kernel-jbd.h" /> | ||||||
|  |     <ClInclude Include="..\src\ext2fs\kernel-list.h" /> | ||||||
|     <ClInclude Include="..\src\ext2fs\rbtree.h" /> |     <ClInclude Include="..\src\ext2fs\rbtree.h" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <PropertyGroup Label="Globals"> |   <PropertyGroup Label="Globals"> | ||||||
|  |  | ||||||
|  | @ -27,9 +27,6 @@ | ||||||
|     <ClCompile Include="..\src\ext2fs\bitmaps.c"> |     <ClCompile Include="..\src\ext2fs\bitmaps.c"> | ||||||
|       <Filter>Source Files</Filter> |       <Filter>Source Files</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|     <ClCompile Include="..\src\ext2fs\missing.c"> |  | ||||||
|       <Filter>Source Files</Filter> |  | ||||||
|     </ClCompile> |  | ||||||
|     <ClCompile Include="..\src\ext2fs\closefs.c"> |     <ClCompile Include="..\src\ext2fs\closefs.c"> | ||||||
|       <Filter>Source Files</Filter> |       <Filter>Source Files</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  | @ -153,6 +150,12 @@ | ||||||
|     <ClCompile Include="..\src\ext2fs\sha512.c"> |     <ClCompile Include="..\src\ext2fs\sha512.c"> | ||||||
|       <Filter>Source Files</Filter> |       <Filter>Source Files</Filter> | ||||||
|     </ClCompile> |     </ClCompile> | ||||||
|  |     <ClCompile Include="..\src\ext2fs\mkjournal.c"> | ||||||
|  |       <Filter>Source Files</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |     <ClCompile Include="..\src\ext2fs\fallocate.c"> | ||||||
|  |       <Filter>Source Files</Filter> | ||||||
|  |     </ClCompile> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <ClInclude Include="..\src\ext2fs\ext2_fs.h"> |     <ClInclude Include="..\src\ext2fs\ext2_fs.h"> | ||||||
|  | @ -212,5 +215,14 @@ | ||||||
|     <ClInclude Include="..\src\ext2fs\hashmap.h"> |     <ClInclude Include="..\src\ext2fs\hashmap.h"> | ||||||
|       <Filter>Header Files</Filter> |       <Filter>Header Files</Filter> | ||||||
|     </ClInclude> |     </ClInclude> | ||||||
|  |     <ClInclude Include="..\src\ext2fs\kernel-list.h"> | ||||||
|  |       <Filter>Header Files</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="..\src\ext2fs\kernel-jbd.h"> | ||||||
|  |       <Filter>Header Files</Filter> | ||||||
|  |     </ClInclude> | ||||||
|  |     <ClInclude Include="..\src\ext2fs\jfs_compat.h"> | ||||||
|  |       <Filter>Header Files</Filter> | ||||||
|  |     </ClInclude> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| </Project> | </Project> | ||||||
							
								
								
									
										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) |  * The string is allocated and must be freed (to ensure concurrent access) | ||||||
|  */ |  */ | ||||||
| char* GetNtPhysicalName(DWORD DriveIndex) | char* GetPartitionName(DWORD DriveIndex, DWORD PartitionNumber) | ||||||
| { | { | ||||||
| 	BOOL success = FALSE; | 	BOOL success = FALSE; | ||||||
| 	char physical_name[32]; | 	char partition_name[32]; | ||||||
| 
 | 
 | ||||||
| 	CheckDriveIndex(DriveIndex); | 	CheckDriveIndex(DriveIndex); | ||||||
| 	static_sprintf(physical_name, "\\??\\PHYSICALDRIVE%lu", DriveIndex); | 	 | ||||||
|  | 	static_sprintf(partition_name, "\\Device\\Harddisk%lu\\Partition%lu", DriveIndex, PartitionNumber); | ||||||
| 	success = TRUE; | 	success = TRUE; | ||||||
| out: | out: | ||||||
| 	return (success) ? safe_strdup(physical_name) : NULL; | 	return (success) ? safe_strdup(partition_name) : NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  |  | ||||||
|  | @ -258,7 +258,7 @@ extern RUFUS_DRIVE_INFO SelectedDrive; | ||||||
| BOOL SetAutoMount(BOOL enable); | BOOL SetAutoMount(BOOL enable); | ||||||
| BOOL GetAutoMount(BOOL* enabled); | BOOL GetAutoMount(BOOL* enabled); | ||||||
| char* GetPhysicalName(DWORD DriveIndex); | char* GetPhysicalName(DWORD DriveIndex); | ||||||
| char* GetNtPhysicalName(DWORD DriveIndex); | char* GetPartitionName(DWORD DriveIndex, DWORD PartitionNumber); | ||||||
| BOOL DeletePartitions(DWORD DriveIndex); | BOOL DeletePartitions(DWORD DriveIndex); | ||||||
| HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare); | HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare); | ||||||
| char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent); | char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent); | ||||||
|  |  | ||||||
|  | @ -2,9 +2,9 @@ noinst_LIBRARIES = libext2fs.a | ||||||
| 
 | 
 | ||||||
| libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c       \ | libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c       \ | ||||||
| 	bitmaps.c bitops.c blkmap64_ba.c blkmap64_rb.c blknum.c block.c bmap.c closefs.c crc16.c         \ | 	bitmaps.c bitops.c blkmap64_ba.c blkmap64_rb.c blknum.c block.c bmap.c closefs.c crc16.c         \ | ||||||
| 	crc32c.c csum.c dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fileio.c freefs.c          \ | 	crc32c.c csum.c dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fallocate.c fileio.c       \ | ||||||
| 	gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c inline.c \ | 	freefs.c gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c \ | ||||||
| 	inline_data.c inode.c io_manager.c link.c lookup.c missing.c mkdir.c mmp.c newdir.c nt_io.c      \ | 	inline.c inline_data.c inode.c io_manager.c link.c lookup.c mkdir.c mkjournal.c mmp.c newdir.c   \ | ||||||
| 	punch.c rbtree.c read_bb.c rw_bitmaps.c sha512.c symlink.c valid_blk.c | 	nt_io.c punch.c rbtree.c read_bb.c rw_bitmaps.c sha512.c symlink.c valid_blk.c | ||||||
| 
 | 
 | ||||||
| libext2fs_a_CFLAGS = $(AM_CFLAGS) -DEXT2_FLAT_INCLUDES=0 -DHAVE_CONFIG_H -I. -I.. -Wno-undef -Wno-strict-aliasing -Wno-shadow | libext2fs_a_CFLAGS = $(AM_CFLAGS) -DEXT2_FLAT_INCLUDES=0 -DHAVE_CONFIG_H -I. -I.. -Wno-undef -Wno-strict-aliasing -Wno-shadow | ||||||
|  |  | ||||||
|  | @ -107,8 +107,8 @@ am_libext2fs_a_OBJECTS = libext2fs_a-alloc.$(OBJEXT) \ | ||||||
| 	libext2fs_a-dirblock.$(OBJEXT) \
 | 	libext2fs_a-dirblock.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-dir_iterate.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \
 | 	libext2fs_a-dir_iterate.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-ext_attr.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \
 | 	libext2fs_a-ext_attr.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-fileio.$(OBJEXT) libext2fs_a-freefs.$(OBJEXT) \
 | 	libext2fs_a-fallocate.$(OBJEXT) libext2fs_a-fileio.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-gen_bitmap.$(OBJEXT) \
 | 	libext2fs_a-freefs.$(OBJEXT) libext2fs_a-gen_bitmap.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-gen_bitmap64.$(OBJEXT) \
 | 	libext2fs_a-gen_bitmap64.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-get_num_dirs.$(OBJEXT) \
 | 	libext2fs_a-get_num_dirs.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-hashmap.$(OBJEXT) libext2fs_a-i_block.$(OBJEXT) \
 | 	libext2fs_a-hashmap.$(OBJEXT) libext2fs_a-i_block.$(OBJEXT) \
 | ||||||
|  | @ -116,8 +116,8 @@ am_libext2fs_a_OBJECTS = libext2fs_a-alloc.$(OBJEXT) \ | ||||||
| 	libext2fs_a-initialize.$(OBJEXT) libext2fs_a-inline.$(OBJEXT) \
 | 	libext2fs_a-initialize.$(OBJEXT) libext2fs_a-inline.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-inline_data.$(OBJEXT) libext2fs_a-inode.$(OBJEXT) \
 | 	libext2fs_a-inline_data.$(OBJEXT) libext2fs_a-inode.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-io_manager.$(OBJEXT) libext2fs_a-link.$(OBJEXT) \
 | 	libext2fs_a-io_manager.$(OBJEXT) libext2fs_a-link.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-lookup.$(OBJEXT) libext2fs_a-missing.$(OBJEXT) \
 | 	libext2fs_a-lookup.$(OBJEXT) libext2fs_a-mkdir.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-mkdir.$(OBJEXT) libext2fs_a-mmp.$(OBJEXT) \
 | 	libext2fs_a-mkjournal.$(OBJEXT) libext2fs_a-mmp.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-newdir.$(OBJEXT) libext2fs_a-nt_io.$(OBJEXT) \
 | 	libext2fs_a-newdir.$(OBJEXT) libext2fs_a-nt_io.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-punch.$(OBJEXT) libext2fs_a-rbtree.$(OBJEXT) \
 | 	libext2fs_a-punch.$(OBJEXT) libext2fs_a-rbtree.$(OBJEXT) \
 | ||||||
| 	libext2fs_a-read_bb.$(OBJEXT) libext2fs_a-rw_bitmaps.$(OBJEXT) \
 | 	libext2fs_a-read_bb.$(OBJEXT) libext2fs_a-rw_bitmaps.$(OBJEXT) \
 | ||||||
|  | @ -272,10 +272,10 @@ top_srcdir = @top_srcdir@ | ||||||
| noinst_LIBRARIES = libext2fs.a | noinst_LIBRARIES = libext2fs.a | ||||||
| libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c       \
 | libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c       \
 | ||||||
| 	bitmaps.c bitops.c blkmap64_ba.c blkmap64_rb.c blknum.c block.c bmap.c closefs.c crc16.c         \
 | 	bitmaps.c bitops.c blkmap64_ba.c blkmap64_rb.c blknum.c block.c bmap.c closefs.c crc16.c         \
 | ||||||
| 	crc32c.c csum.c dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fileio.c freefs.c          \
 | 	crc32c.c csum.c dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fallocate.c fileio.c       \
 | ||||||
| 	gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c inline.c \
 | 	freefs.c gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c \
 | ||||||
| 	inline_data.c inode.c io_manager.c link.c lookup.c missing.c mkdir.c mmp.c newdir.c nt_io.c      \
 | 	inline.c inline_data.c inode.c io_manager.c link.c lookup.c mkdir.c mkjournal.c mmp.c newdir.c   \
 | ||||||
| 	punch.c rbtree.c read_bb.c rw_bitmaps.c sha512.c symlink.c valid_blk.c | 	nt_io.c punch.c rbtree.c read_bb.c rw_bitmaps.c sha512.c symlink.c valid_blk.c | ||||||
| 
 | 
 | ||||||
| libext2fs_a_CFLAGS = $(AM_CFLAGS) -DEXT2_FLAT_INCLUDES=0 -DHAVE_CONFIG_H -I. -I.. -Wno-undef -Wno-strict-aliasing -Wno-shadow | libext2fs_a_CFLAGS = $(AM_CFLAGS) -DEXT2_FLAT_INCLUDES=0 -DHAVE_CONFIG_H -I. -I.. -Wno-undef -Wno-strict-aliasing -Wno-shadow | ||||||
| all: all-am | all: all-am | ||||||
|  | @ -459,6 +459,12 @@ libext2fs_a-ext_attr.o: ext_attr.c | ||||||
| libext2fs_a-ext_attr.obj: ext_attr.c | libext2fs_a-ext_attr.obj: ext_attr.c | ||||||
| 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-ext_attr.obj `if test -f 'ext_attr.c'; then $(CYGPATH_W) 'ext_attr.c'; else $(CYGPATH_W) '$(srcdir)/ext_attr.c'; fi` | 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-ext_attr.obj `if test -f 'ext_attr.c'; then $(CYGPATH_W) 'ext_attr.c'; else $(CYGPATH_W) '$(srcdir)/ext_attr.c'; fi` | ||||||
| 
 | 
 | ||||||
|  | libext2fs_a-fallocate.o: fallocate.c | ||||||
|  | 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-fallocate.o `test -f 'fallocate.c' || echo '$(srcdir)/'`fallocate.c | ||||||
|  | 
 | ||||||
|  | libext2fs_a-fallocate.obj: fallocate.c | ||||||
|  | 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-fallocate.obj `if test -f 'fallocate.c'; then $(CYGPATH_W) 'fallocate.c'; else $(CYGPATH_W) '$(srcdir)/fallocate.c'; fi` | ||||||
|  | 
 | ||||||
| libext2fs_a-fileio.o: fileio.c | libext2fs_a-fileio.o: fileio.c | ||||||
| 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-fileio.o `test -f 'fileio.c' || echo '$(srcdir)/'`fileio.c | 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-fileio.o `test -f 'fileio.c' || echo '$(srcdir)/'`fileio.c | ||||||
| 
 | 
 | ||||||
|  | @ -549,18 +555,18 @@ libext2fs_a-lookup.o: lookup.c | ||||||
| libext2fs_a-lookup.obj: lookup.c | libext2fs_a-lookup.obj: lookup.c | ||||||
| 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-lookup.obj `if test -f 'lookup.c'; then $(CYGPATH_W) 'lookup.c'; else $(CYGPATH_W) '$(srcdir)/lookup.c'; fi` | 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-lookup.obj `if test -f 'lookup.c'; then $(CYGPATH_W) 'lookup.c'; else $(CYGPATH_W) '$(srcdir)/lookup.c'; fi` | ||||||
| 
 | 
 | ||||||
| libext2fs_a-missing.o: missing.c |  | ||||||
| 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-missing.o `test -f 'missing.c' || echo '$(srcdir)/'`missing.c |  | ||||||
| 
 |  | ||||||
| libext2fs_a-missing.obj: missing.c |  | ||||||
| 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-missing.obj `if test -f 'missing.c'; then $(CYGPATH_W) 'missing.c'; else $(CYGPATH_W) '$(srcdir)/missing.c'; fi` |  | ||||||
| 
 |  | ||||||
| libext2fs_a-mkdir.o: mkdir.c | libext2fs_a-mkdir.o: mkdir.c | ||||||
| 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mkdir.o `test -f 'mkdir.c' || echo '$(srcdir)/'`mkdir.c | 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mkdir.o `test -f 'mkdir.c' || echo '$(srcdir)/'`mkdir.c | ||||||
| 
 | 
 | ||||||
| libext2fs_a-mkdir.obj: mkdir.c | libext2fs_a-mkdir.obj: mkdir.c | ||||||
| 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mkdir.obj `if test -f 'mkdir.c'; then $(CYGPATH_W) 'mkdir.c'; else $(CYGPATH_W) '$(srcdir)/mkdir.c'; fi` | 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mkdir.obj `if test -f 'mkdir.c'; then $(CYGPATH_W) 'mkdir.c'; else $(CYGPATH_W) '$(srcdir)/mkdir.c'; fi` | ||||||
| 
 | 
 | ||||||
|  | libext2fs_a-mkjournal.o: mkjournal.c | ||||||
|  | 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mkjournal.o `test -f 'mkjournal.c' || echo '$(srcdir)/'`mkjournal.c | ||||||
|  | 
 | ||||||
|  | libext2fs_a-mkjournal.obj: mkjournal.c | ||||||
|  | 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mkjournal.obj `if test -f 'mkjournal.c'; then $(CYGPATH_W) 'mkjournal.c'; else $(CYGPATH_W) '$(srcdir)/mkjournal.c'; fi` | ||||||
|  | 
 | ||||||
| libext2fs_a-mmp.o: mmp.c | libext2fs_a-mmp.o: mmp.c | ||||||
| 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mmp.o `test -f 'mmp.c' || echo '$(srcdir)/'`mmp.c | 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mmp.o `test -f 'mmp.c' || echo '$(srcdir)/'`mmp.c | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -177,6 +177,9 @@ | ||||||
| /* Define if you have the 'wint_t' type. */ | /* Define if you have the 'wint_t' type. */ | ||||||
| #define HAVE_WINT_T 1 | #define HAVE_WINT_T 1 | ||||||
| 
 | 
 | ||||||
|  | /* Define if you have 'winsock.h'. */ | ||||||
|  | #define HAVE_WINSOCK_H 1 | ||||||
|  | 
 | ||||||
| /* Define to 1 if O_NOATIME works. */ | /* Define to 1 if O_NOATIME works. */ | ||||||
| #define HAVE_WORKING_O_NOATIME 0 | #define HAVE_WORKING_O_NOATIME 0 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -785,9 +785,11 @@ struct ext2_super_block { | ||||||
|  */ |  */ | ||||||
| #define EXT2_OS_LINUX		0 | #define EXT2_OS_LINUX		0 | ||||||
| #define EXT2_OS_HURD		1 | #define EXT2_OS_HURD		1 | ||||||
| #define EXT2_OS_WINDOWS		2 | #define EXT2_OBSO_OS_MASIX	2 | ||||||
| #define EXT2_OS_FREEBSD		3 | #define EXT2_OS_FREEBSD		3 | ||||||
| #define EXT2_OS_LITES		4 | #define EXT2_OS_LITES		4 | ||||||
|  | #define EXT2_OS_WINDOWS		5 | ||||||
|  | #define EXT2_OS_MACOS		6 | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Revision levels |  * Revision levels | ||||||
|  |  | ||||||
							
								
								
									
										857
									
								
								src/ext2fs/fallocate.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										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, | 					 IOCTL_DISK_GET_PARTITION_INFO_EX, | ||||||
| 					 &pi, sizeof(pi), &pi, sizeof(pi)); | 					 &pi, sizeof(pi), &pi, sizeof(pi)); | ||||||
| 	if (NT_SUCCESS(Status)) { | 	if (NT_SUCCESS(Status)) { | ||||||
| 		uprintf("Size retrieved with: IOCTL_DISK_GET_PARTITION_INFO_EX"); |  | ||||||
| 		*FsSize = pi.PartitionLength.QuadPart; | 		*FsSize = pi.PartitionLength.QuadPart; | ||||||
| 	} else if (Status == STATUS_INVALID_DEVICE_REQUEST) { | 	} else if (Status == STATUS_INVALID_DEVICE_REQUEST) { | ||||||
| 		// No partitions: Try a drive geometry request
 | 		// No partitions: Try a drive geometry request
 | ||||||
| 		uprintf("IOCTL_DISK_GET_PARTITION_INFO_EX failed, trying with IOCTL_DISK_GET_DRIVE_GEOMETRY_EX"); |  | ||||||
| 		RtlZeroMemory(&gi, sizeof(gi)); | 		RtlZeroMemory(&gi, sizeof(gi)); | ||||||
| 
 | 
 | ||||||
| 		Status = pfNtDeviceIoControlFile(h, NULL, NULL, NULL, &IoStatusBlock, | 		Status = pfNtDeviceIoControlFile(h, NULL, NULL, NULL, &IoStatusBlock, | ||||||
| 						 IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, | 						 IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, | ||||||
| 						 &gi, sizeof(gi), &gi, sizeof(gi)); | 						 &gi, sizeof(gi), &gi, sizeof(gi)); | ||||||
| 
 | 
 | ||||||
| 		if (NT_SUCCESS(Status)) { | 		if (NT_SUCCESS(Status)) | ||||||
| 			uprintf("Size retrieved with: IOCTL_DISK_GET_DRIVE_GEOMETRY_EX"); |  | ||||||
| 			*FsSize = gi.DiskSize.QuadPart; | 			*FsSize = gi.DiskSize.QuadPart; | ||||||
| 		} else { |  | ||||||
| 			uprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: [%x] %s", Status, NtStatusError(Status)); |  | ||||||
| 		} |  | ||||||
| 	} else if (Status == STATUS_INVALID_PARAMETER) { | 	} else if (Status == STATUS_INVALID_PARAMETER) { | ||||||
| 		// Possibly a straight image file
 | 		// Possibly a straight image file
 | ||||||
| 		if (GetFileSizeEx(h, &li)) | 		if (GetFileSizeEx(h, &li)) | ||||||
|  | @ -445,6 +439,12 @@ errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Not implemented
 | ||||||
|  | errcode_t ext2fs_check_mount_point(const char *file, int *mount_flags, char *mtpt, int mtlen) | ||||||
|  | { | ||||||
|  | 	return EXT2_ET_OP_NOT_SUPPORTED; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Returns the number of blocks in a partition
 | // Returns the number of blocks in a partition
 | ||||||
| // Note: Do *NOT* be tempted to cache the device size according to the NT path as
 | // Note: Do *NOT* be tempted to cache the device size according to the NT path as
 | ||||||
| // different removable devices (e.g. UFD) may be remounted under the same path.
 | // different removable devices (e.g. UFD) may be remounted under the same path.
 | ||||||
|  | @ -648,7 +648,6 @@ static errcode_t nt_read_blk(io_channel channel, unsigned long block, int count, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TODO: Add an nt_write_blk64()
 |  | ||||||
| static errcode_t nt_write_blk(io_channel channel, unsigned long block, int count, const void *buf) | static errcode_t nt_write_blk(io_channel channel, unsigned long block, int count, const void *buf) | ||||||
| { | { | ||||||
| 	ULONG write_size; | 	ULONG write_size; | ||||||
|  |  | ||||||
							
								
								
									
										196
									
								
								src/format.c
									
										
									
									
									
								
							
							
						
						
									
										196
									
								
								src/format.c
									
										
									
									
									
								
							|  | @ -49,7 +49,6 @@ | ||||||
| #include "format.h" | #include "format.h" | ||||||
| #include "badblocks.h" | #include "badblocks.h" | ||||||
| #include "bled/bled.h" | #include "bled/bled.h" | ||||||
| #include "ext2fs/ext2fs.h" |  | ||||||
| #include "../res/grub/grub_version.h" | #include "../res/grub/grub_version.h" | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -665,51 +664,110 @@ out: | ||||||
| 	return r; | 	return r; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| extern io_manager nt_io_manager(void); | BOOL FormatExt2Fs(const char* label) | ||||||
| BOOL FormatExt2Fs(void) |  | ||||||
| { | { | ||||||
| 	const char* path = "\\??\\C:\\tmp\\disk.img"; | 	// Mostly taken from mke2fs.conf
 | ||||||
|  | 	const float reserve_ratio = 0.05f; | ||||||
|  | 	const ext2fs_default_t ext2fs_default[5] = { | ||||||
|  | 		{ 3*MB, 1024, 128, 3},		// "floppy"
 | ||||||
|  | 		{ 512*MB, 1024, 128, 2},	// "small"
 | ||||||
|  | 		{ 4*GB, 4096, 256, 2},		// "default"
 | ||||||
|  | 		{ 16*GB, 4096, 256, 3},		// "big"
 | ||||||
|  | 		{ 1024*TB, 4096, 256, 4}	// "huge"
 | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	BOOL ret = FALSE; | ||||||
|  | 	char* path = NULL; | ||||||
| 	int i, count; | 	int i, count; | ||||||
| 	struct ext2_super_block features = { 0 }; | 	struct ext2_super_block features = { 0 }; | ||||||
| 	io_manager manager = nt_io_manager(); | 	io_manager manager = nt_io_manager(); | ||||||
|  | 	blk_t journal_size; | ||||||
| 	blk64_t size = 0, cur; | 	blk64_t size = 0, cur; | ||||||
| 	ext2_filsys ext2fs; | 	ext2_filsys ext2fs = NULL; | ||||||
| 	errcode_t r; | 	errcode_t r; | ||||||
|  | 	uint8_t* buf = NULL; | ||||||
|  | 
 | ||||||
|  | #if defined(RUFUS_TEST) | ||||||
|  | 	// Create a 32 MB disk image file to test
 | ||||||
|  | 	uint8_t zb[1024]; | ||||||
| 	HANDLE h; | 	HANDLE h; | ||||||
| 	DWORD dwSize; | 	DWORD dwSize; | ||||||
| 	const uint8_t buf[1024] = { 0 }; | 	path = strdup("\\??\\C:\\tmp\\disk.img"); | ||||||
| 
 | 	memset(zb, 0xFF, sizeof(zb));	// Set to nonzero so we can detect init issues
 | ||||||
| 	// Create a 32 MB zeroed file to test
 |  | ||||||
| 	h = CreateFileU(path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | 	h = CreateFileU(path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | ||||||
| 	for (i = 0; i < 32 * 1024; i++) { | 	for (i = 0; i < 32 * 1024; i++) { | ||||||
| 		if (!WriteFile(h, buf, sizeof(buf), &dwSize, NULL) || (dwSize != sizeof(buf))) { | 		if (!WriteFile(h, zb, sizeof(zb), &dwSize, NULL) || (dwSize != sizeof(zb))) { | ||||||
| 			uprintf("Write error: %s", WindowsErrorString()); | 			uprintf("Write error: %s", WindowsErrorString()); | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	CloseHandle(h); | 	CloseHandle(h); | ||||||
|  | #else | ||||||
|  | 	path = GetPartitionName((DWORD)ComboBox_GetItemData(hDeviceList, ComboBox_GetCurSel(hDeviceList)), CASPER_PARTITION_DEFAULT); | ||||||
|  | #endif | ||||||
|  | 	if (path == NULL) | ||||||
|  | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	// TODO: We could probably remove that call and get our size from a different means
 | 	PrintInfoDebug(0, MSG_222, "ext3"); | ||||||
| 	r = ext2fs_get_device_size2(path, EXT2_BLOCK_SIZE(&features), &size); | 
 | ||||||
| 	uprintf("ext2fs_get_device_size: %d", r); | 	// Figure out the volume size and block size
 | ||||||
| 	// TODO: ERROR HANDLING
 | 	r = ext2fs_get_device_size2(path, KB, &size); | ||||||
| 	// Set the number of blocks and reserved blocks
 | 	if ((r != 0) || (size == 0)) { | ||||||
|  | 		uprintf("Could not read device size: %d", r); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 	size *= KB; | ||||||
|  | 	for (i = 0; i < ARRAYSIZE(ext2fs_default); i++) { | ||||||
|  | 		if (size < ext2fs_default[i].max_size) | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 	assert(i < ARRAYSIZE(ext2fs_default)); | ||||||
|  | 	size /= ext2fs_default[i].block_size; | ||||||
|  | 	for (features.s_log_block_size = 0; EXT2_BLOCK_SIZE_BITS(&features) <= EXT2_MAX_BLOCK_LOG_SIZE; features.s_log_block_size++) { | ||||||
|  | 		if (EXT2_BLOCK_SIZE(&features) == ext2fs_default[i].block_size) | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 	assert(EXT2_BLOCK_SIZE_BITS(&features) <= EXT2_MAX_BLOCK_LOG_SIZE); | ||||||
|  | 
 | ||||||
|  | 	// Set the blocks, reserved blocks and inodes
 | ||||||
| 	ext2fs_blocks_count_set(&features, size); | 	ext2fs_blocks_count_set(&features, size); | ||||||
| 	ext2fs_r_blocks_count_set(&features, (blk64_t)(0.05f * ext2fs_blocks_count(&features))); | 	ext2fs_r_blocks_count_set(&features, (blk64_t)(reserve_ratio * size)); | ||||||
| 	features.s_rev_level = 1; | 	features.s_rev_level = 1; | ||||||
| 	features.s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; | 	features.s_inode_size = ext2fs_default[i].inode_size; | ||||||
| 	// TODO: This needs to be computed according to volume size
 | 	features.s_inodes_count = ((ext2fs_blocks_count(&features) >> ext2fs_default[i].inode_ratio) > UINT32_MAX) ? | ||||||
| 	features.s_inodes_count = 8192; | 		UINT32_MAX : (uint32_t)(ext2fs_blocks_count(&features) >> ext2fs_default[i].inode_ratio); | ||||||
|  | 	uprintf("%d inodes, %lld blocks (block size = %d)", features.s_inodes_count, size, EXT2_BLOCK_SIZE(&features)); | ||||||
|  | 	uprintf("%lld blocks (%0.1f%%) reserved for the super user", ext2fs_r_blocks_count(&features), reserve_ratio * 100.0f); | ||||||
| 
 | 
 | ||||||
| 	// TODO: Set a volume label
 | 	// Set features for ext3
 | ||||||
|  | 	ext2fs_set_feature_journal(&features); | ||||||
|  | 	ext2fs_set_feature_xattr(&features); | ||||||
|  | 	ext2fs_set_feature_resize_inode(&features); | ||||||
|  | 	ext2fs_set_feature_dir_index(&features); | ||||||
|  | 	ext2fs_set_feature_filetype(&features); | ||||||
|  | 	ext2fs_set_feature_sparse_super(&features); | ||||||
|  | 	ext2fs_set_feature_large_file(&features); | ||||||
|  | 	features.s_backup_bgs[0] = 1; | ||||||
|  | 	features.s_default_mount_opts = EXT2_DEFM_XATTR_USER | EXT2_DEFM_ACL; | ||||||
| 
 | 
 | ||||||
| 	// Initialize the superblock
 | 	// Now that we have set our base features, initialize a virtual superblock
 | ||||||
| 	r = ext2fs_initialize(path, EXT2_FLAG_EXCLUSIVE | EXT2_FLAG_64BITS, &features, manager, &ext2fs); | 	r = ext2fs_initialize(path, EXT2_FLAG_EXCLUSIVE | EXT2_FLAG_64BITS, &features, manager, &ext2fs); | ||||||
| 	uprintf("ext2fs_initialize: %d", r); | 	if (r != 0) { | ||||||
| 	// TODO: ERROR HANDLING
 | 		uprintf("Could not initialize ext2fs features: %d", r); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	// TODO: Erase superblock data
 | 	// Zero 16 blocks of data from the start of our volume
 | ||||||
| 	// Now that the superblock has been initialized, set it up
 | 	buf = calloc(16, ext2fs->io->block_size); | ||||||
|  | 	assert(buf != NULL); | ||||||
|  | 	r = io_channel_write_blk64(ext2fs->io, 0, 16, buf); | ||||||
|  | 	safe_free(buf); | ||||||
|  | 	if (r != 0) { | ||||||
|  | 		uprintf("Could not zero ext2fs superblock area: %d", r); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Finish setting up the file system
 | ||||||
| 	CoCreateGuid((GUID*)ext2fs->super->s_uuid); | 	CoCreateGuid((GUID*)ext2fs->super->s_uuid); | ||||||
| 	ext2fs_init_csum_seed(ext2fs); | 	ext2fs_init_csum_seed(ext2fs); | ||||||
| 	ext2fs->super->s_def_hash_version = EXT2_HASH_HALF_MD4; | 	ext2fs->super->s_def_hash_version = EXT2_HASH_HALF_MD4; | ||||||
|  | @ -717,70 +775,79 @@ BOOL FormatExt2Fs(void) | ||||||
| 	ext2fs->super->s_max_mnt_count = -1; | 	ext2fs->super->s_max_mnt_count = -1; | ||||||
| 	ext2fs->super->s_creator_os = EXT2_OS_WINDOWS; | 	ext2fs->super->s_creator_os = EXT2_OS_WINDOWS; | ||||||
| 	ext2fs->super->s_errors = EXT2_ERRORS_CONTINUE; | 	ext2fs->super->s_errors = EXT2_ERRORS_CONTINUE; | ||||||
| 
 | 	static_strcpy(ext2fs->super->s_volume_name, label); | ||||||
| 	// TODO: ext2 + journaling = ext3, so the way to set ext3 is to add features:
 |  | ||||||
| 	// ext_attr, resize_inode, dir_index, filetype, sparse_super, has_journal, needs_recovery
 |  | ||||||
| 	ext2fs_set_feature_xattr(&features); |  | ||||||
| 	// ext2fs_set_feature_resize_inode(&sb);
 |  | ||||||
| 	// ext2fs_set_feature_dir_index(&sb);
 |  | ||||||
| 	ext2fs_set_feature_filetype(&features); |  | ||||||
| 	// ext2fs_set_feature_sparse_super(&sb);
 |  | ||||||
| 	// ext2fs_set_feature_journal(&sb);
 |  | ||||||
| 	// ext2fs_set_feature_journal_needs_recovery(&sb);
 |  | ||||||
| 
 |  | ||||||
| 	// Optional we may want to add:
 |  | ||||||
| 	// ext2fs_set_feature_64bit(&sb);
 |  | ||||||
| 	// NB: the following is not needed as it is set by the OS automatically when creating a > 2GB file
 |  | ||||||
| 	// ext2fs_set_feature_large_file(&sb);
 |  | ||||||
| 
 | 
 | ||||||
| 	r = ext2fs_allocate_tables(ext2fs); | 	r = ext2fs_allocate_tables(ext2fs); | ||||||
| 	uprintf("ext2fs_allocate_tables: %d", r); | 	if (r != 0) { | ||||||
| 	// TODO: ERROR HANDLING
 | 		uprintf("Could not allocate ext2fs tables: %d", r); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
| 	r = ext2fs_convert_subcluster_bitmap(ext2fs, &ext2fs->block_map); | 	r = ext2fs_convert_subcluster_bitmap(ext2fs, &ext2fs->block_map); | ||||||
| 	uprintf("ext2fs_convert_subcluster_bitmap: %d", r); | 	if (r != 0) { | ||||||
| 	// TODO: ERROR HANDLING
 | 		uprintf("Could set ext2fs cluster bitmap: %d", r); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	// Wipe inode table
 | 	// Wipe inode table
 | ||||||
| 	for (i = 0; i < (int)ext2fs->group_desc_count; i++) { | 	for (i = 0; i < (int)ext2fs->group_desc_count; i++) { | ||||||
| 		cur = ext2fs_inode_table_loc(ext2fs, i); | 		cur = ext2fs_inode_table_loc(ext2fs, i); | ||||||
| 		count = ext2fs_div_ceil((ext2fs->super->s_inodes_per_group - ext2fs_bg_itable_unused(ext2fs, i)) | 		count = ext2fs_div_ceil((ext2fs->super->s_inodes_per_group - ext2fs_bg_itable_unused(ext2fs, i)) | ||||||
| 			* EXT2_GOOD_OLD_INODE_SIZE, EXT2_GOOD_OLD_INODE_SIZE); | 			* EXT2_BLOCK_SIZE(ext2fs->super), EXT2_BLOCK_SIZE(ext2fs->super)); | ||||||
| 		r = ext2fs_zero_blocks2(ext2fs, cur, count, &cur, &count); | 		r = ext2fs_zero_blocks2(ext2fs, cur, count, &cur, &count); | ||||||
| 		if (r != 0) { | 		if (r != 0) { | ||||||
| 			uprintf("Could not zero inode at %llu (%d blocks): %d\n", cur, count, r); | 			uprintf("Could not zero ext2fs inode at %llu (%d blocks): %d\n", cur, count, r); | ||||||
| 			// TODO: ERROR HANDLING
 | 			goto out; | ||||||
| 			break; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Create root dir
 | 	// Create root and lost+found dirs
 | ||||||
| 	r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0); | 	r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0); | ||||||
| 	uprintf("ext2fs_mkdir(root): %d", r); | 	if (r != 0) { | ||||||
| 	// TODO: ERROR HANDLING
 | 		uprintf("Failed to create ext2fs root dir: %d", r); | ||||||
| 
 | 		goto out; | ||||||
| 	// Create 'lost+found'
 | 	} | ||||||
| 	ext2fs->umask = 077; | 	ext2fs->umask = 077; | ||||||
| 	r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, 0, "lost+found"); | 	r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, 0, "lost+found"); | ||||||
| 	uprintf("ext2fs_mkdir(lost+found): %d", r); | 	if (r != 0) { | ||||||
| 	// TODO: ERROR HANDLING
 | 		uprintf("Failed to create ext2fs 'lost+found' dir: %d", r); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// Create bitmaps
 | ||||||
| 	for (i = EXT2_ROOT_INO + 1; i < (int)EXT2_FIRST_INODE(ext2fs->super); i++) | 	for (i = EXT2_ROOT_INO + 1; i < (int)EXT2_FIRST_INODE(ext2fs->super); i++) | ||||||
| 		ext2fs_inode_alloc_stats2(ext2fs, i, +1, 0); | 		ext2fs_inode_alloc_stats(ext2fs, i, 1); | ||||||
| 	ext2fs_mark_ib_dirty(ext2fs); | 	ext2fs_mark_ib_dirty(ext2fs); | ||||||
| 
 | 
 | ||||||
| 	r = ext2fs_mark_inode_bitmap2(ext2fs->inode_map, EXT2_BAD_INO); | 	r = ext2fs_mark_inode_bitmap2(ext2fs->inode_map, EXT2_BAD_INO); | ||||||
| 	uprintf("ext2fs_mark_inode_bitmap2: %d", r); | 	if (r != 0) { | ||||||
| 	// TODO: ERROR HANDLING
 | 		uprintf("Could not set ext2fs inode bitmaps: %d", r); | ||||||
| 	ext2fs_inode_alloc_stats2(ext2fs, EXT2_BAD_INO, 1, 0); | 		goto out; | ||||||
|  | 	} | ||||||
|  | 	ext2fs_inode_alloc_stats(ext2fs, EXT2_BAD_INO, 1); | ||||||
| 	r = ext2fs_update_bb_inode(ext2fs, NULL); | 	r = ext2fs_update_bb_inode(ext2fs, NULL); | ||||||
| 	uprintf("ext2fs_update_bb_inode: %d", r); | 	if (r != 0) { | ||||||
| 	// TODO: ERROR HANDLING
 | 		uprintf("Could not set ext2fs inode stats: %d", r); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	r = ext2fs_close_free(&ext2fs); | 	// Create the journal
 | ||||||
| 	uprintf("ext2fs_close_free: %d", r); | 	journal_size = ext2fs_default_journal_size(ext2fs_blocks_count(ext2fs->super)); | ||||||
| 	// TODO: ERROR HANDLING
 | 	uprintf("Creating journal (%d blocks)", journal_size); | ||||||
|  | 	r = ext2fs_add_journal_inode(ext2fs, journal_size, EXT2_MKJOURNAL_NO_MNT_CHECK | EXT2_MKJOURNAL_LAZYINIT); | ||||||
| 
 | 
 | ||||||
| 	return TRUE; | 	// Finally we can call close() to get the file system gets created
 | ||||||
|  | 	r = ext2fs_close(ext2fs); | ||||||
|  | 	if (r != 0) { | ||||||
|  | 		uprintf("Could not create ext3 volume: %d", r); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 	ret = TRUE; | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 	ext2fs_free(ext2fs); | ||||||
|  | 	free(buf); | ||||||
|  | 	free(path); | ||||||
|  | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -2123,6 +2190,7 @@ DWORD WINAPI FormatThread(void* param) | ||||||
| 
 | 
 | ||||||
| 	// If FAT32 is requested and we have a large drive (>32 GB) use
 | 	// If FAT32 is requested and we have a large drive (>32 GB) use
 | ||||||
| 	// large FAT32 format, else use MS's FormatEx.
 | 	// large FAT32 format, else use MS's FormatEx.
 | ||||||
|  | 	// TODO: We'll want a single call for ext2/ext3/ext4, large FAT32 and everything (after we switch to VDS?)
 | ||||||
| 	ret = use_large_fat32?FormatFAT32(DriveIndex):FormatDrive(DriveIndex); | 	ret = use_large_fat32?FormatFAT32(DriveIndex):FormatDrive(DriveIndex); | ||||||
| 	if (!ret) { | 	if (!ret) { | ||||||
| 		// Error will be set by FormatDrive() in FormatStatus
 | 		// Error will be set by FormatDrive() in FormatStatus
 | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								src/format.h
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								src/format.h
									
										
									
									
									
								
							|  | @ -20,6 +20,8 @@ | ||||||
| #include <windows.h> | #include <windows.h> | ||||||
| #include <winioctl.h>				// for MEDIA_TYPE | #include <winioctl.h>				// for MEDIA_TYPE | ||||||
| 
 | 
 | ||||||
|  | #include "ext2fs/ext2fs.h" | ||||||
|  | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| /* Callback command types (some errorcode were filled from HPUSBFW V2.2.3 and their
 | /* Callback command types (some errorcode were filled from HPUSBFW V2.2.3 and their
 | ||||||
|  | @ -154,3 +156,13 @@ typedef struct { | ||||||
| #define die(msg, err) do { uprintf(msg); \ | #define die(msg, err) do { uprintf(msg); \ | ||||||
| 	FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|err; \ | 	FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|err; \ | ||||||
| 	goto out; } while(0) | 	goto out; } while(0) | ||||||
|  | 
 | ||||||
|  | // For ext2/ext3/ext4 formatting
 | ||||||
|  | typedef struct { | ||||||
|  | 	uint64_t max_size; | ||||||
|  | 	uint32_t block_size; | ||||||
|  | 	uint32_t inode_size; | ||||||
|  | 	uint32_t inode_ratio;	// inode to data ration (bitshift)
 | ||||||
|  | } ext2fs_default_t; | ||||||
|  | 
 | ||||||
|  | extern io_manager nt_io_manager(void); | ||||||
|  |  | ||||||
|  | @ -1864,7 +1864,7 @@ out: | ||||||
| /*
 | /*
 | ||||||
|  * Main dialog callback |  * Main dialog callback | ||||||
|  */ |  */ | ||||||
| extern BOOL FormatExt2Fs(void); | extern BOOL FormatExt2Fs(const char* label); | ||||||
| static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) | static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) | ||||||
| { | { | ||||||
| 	static DWORD DeviceNum = 0; | 	static DWORD DeviceNum = 0; | ||||||
|  | @ -1897,7 +1897,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA | ||||||
| 	case WM_COMMAND: | 	case WM_COMMAND: | ||||||
| #ifdef RUFUS_TEST | #ifdef RUFUS_TEST | ||||||
| 		if (LOWORD(wParam) == IDC_TEST) { | 		if (LOWORD(wParam) == IDC_TEST) { | ||||||
| 			FormatExt2Fs(); | 			FormatExt2Fs("casper-rw"); | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -82,6 +82,7 @@ | ||||||
| #define CHECK_DRIVE_TIMEOUT         2000 | #define CHECK_DRIVE_TIMEOUT         2000 | ||||||
| #define MARQUEE_TIMER_REFRESH       10			// Time between progress bar marquee refreshes, in ms
 | #define MARQUEE_TIMER_REFRESH       10			// Time between progress bar marquee refreshes, in ms
 | ||||||
| #define FS_DEFAULT                  FS_FAT32 | #define FS_DEFAULT                  FS_FAT32 | ||||||
|  | #define CASPER_PARTITION_DEFAULT    2 | ||||||
| #define SINGLE_CLUSTERSIZE_DEFAULT  0x00000100 | #define SINGLE_CLUSTERSIZE_DEFAULT  0x00000100 | ||||||
| #define BADLOCKS_PATTERN_TYPES      3 | #define BADLOCKS_PATTERN_TYPES      3 | ||||||
| #define BADBLOCK_PATTERN_COUNT      4 | #define BADBLOCK_PATTERN_COUNT      4 | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								src/rufus.rc
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								src/rufus.rc
									
										
									
									
									
								
							|  | @ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL | ||||||
| IDD_DIALOG DIALOGEX 12, 12, 232, 326 | IDD_DIALOG DIALOGEX 12, 12, 232, 326 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||||
| EXSTYLE WS_EX_ACCEPTFILES | EXSTYLE WS_EX_ACCEPTFILES | ||||||
| CAPTION "Rufus 3.6.1522" | CAPTION "Rufus 3.6.1523" | ||||||
| FONT 9, "Segoe UI Symbol", 400, 0, 0x0 | FONT 9, "Segoe UI Symbol", 400, 0, 0x0 | ||||||
| BEGIN | BEGIN | ||||||
|     LTEXT           "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP |     LTEXT           "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP | ||||||
|  | @ -394,8 +394,8 @@ END | ||||||
| // | // | ||||||
| 
 | 
 | ||||||
| VS_VERSION_INFO VERSIONINFO | VS_VERSION_INFO VERSIONINFO | ||||||
|  FILEVERSION 3,6,1522,0 |  FILEVERSION 3,6,1523,0 | ||||||
|  PRODUCTVERSION 3,6,1522,0 |  PRODUCTVERSION 3,6,1523,0 | ||||||
|  FILEFLAGSMASK 0x3fL |  FILEFLAGSMASK 0x3fL | ||||||
| #ifdef _DEBUG | #ifdef _DEBUG | ||||||
|  FILEFLAGS 0x1L |  FILEFLAGS 0x1L | ||||||
|  | @ -413,13 +413,13 @@ BEGIN | ||||||
|             VALUE "Comments", "https://akeo.ie" |             VALUE "Comments", "https://akeo.ie" | ||||||
|             VALUE "CompanyName", "Akeo Consulting" |             VALUE "CompanyName", "Akeo Consulting" | ||||||
|             VALUE "FileDescription", "Rufus" |             VALUE "FileDescription", "Rufus" | ||||||
|             VALUE "FileVersion", "3.6.1522" |             VALUE "FileVersion", "3.6.1523" | ||||||
|             VALUE "InternalName", "Rufus" |             VALUE "InternalName", "Rufus" | ||||||
|             VALUE "LegalCopyright", "© 2011-2019 Pete Batard (GPL v3)" |             VALUE "LegalCopyright", "© 2011-2019 Pete Batard (GPL v3)" | ||||||
|             VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html" |             VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html" | ||||||
|             VALUE "OriginalFilename", "rufus-3.6.exe" |             VALUE "OriginalFilename", "rufus-3.6.exe" | ||||||
|             VALUE "ProductName", "Rufus" |             VALUE "ProductName", "Rufus" | ||||||
|             VALUE "ProductVersion", "3.6.1522" |             VALUE "ProductVersion", "3.6.1523" | ||||||
|         END |         END | ||||||
|     END |     END | ||||||
|     BLOCK "VarFileInfo" |     BLOCK "VarFileInfo" | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue