summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorChristophe Grenier <grenier@cgsecurity.org>2007-10-29 22:38:52 +0100
committerChristophe Grenier <grenier@cgsecurity.org>2007-10-29 22:38:52 +0100
commit9928d99936105b4653d2d1b8ca74dc3ffba5c71e (patch)
tree06aa4f5e9f0055027c6fb54dd47a8414cf2fba32 /src
First version in git
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am31
-rw-r--r--src/Makefile.in753
-rw-r--r--src/adv.c1270
-rw-r--r--src/adv.h28
-rw-r--r--src/analyse.c359
-rw-r--r--src/analyse.h33
-rw-r--r--src/bfs.c90
-rw-r--r--src/bfs.h83
-rw-r--r--src/bsd.c185
-rw-r--r--src/bsd.h172
-rw-r--r--src/chgtype.c156
-rw-r--r--src/chgtype.h25
-rw-r--r--src/common.c314
-rw-r--r--src/common.h426
-rw-r--r--src/cramfs.c108
-rw-r--r--src/cramfs.h83
-rw-r--r--src/crc.c128
-rw-r--r--src/crc.h35
-rw-r--r--src/dir.c618
-rw-r--r--src/dir.h101
-rw-r--r--src/dirpart.c159
-rw-r--r--src/dirpart.h23
-rw-r--r--src/edit.c290
-rw-r--r--src/edit.h23
-rw-r--r--src/ewf.c241
-rw-r--r--src/ewf.h26
-rw-r--r--src/ext2.c176
-rw-r--r--src/ext2.h142
-rw-r--r--src/ext2_dir.c310
-rw-r--r--src/ext2_dir.h24
-rw-r--r--src/ext2_inc.h29
-rw-r--r--src/ext2p.c128
-rw-r--r--src/ext2p.h23
-rw-r--r--src/fat.c1176
-rw-r--r--src/fat.h164
-rw-r--r--src/fat_adv.c2975
-rw-r--r--src/fat_dir.c468
-rw-r--r--src/fat_dir.h24
-rw-r--r--src/fatp.c162
-rw-r--r--src/fatp.h22
-rw-r--r--src/fatx.c72
-rw-r--r--src/fatx.h33
-rw-r--r--src/file_7z.c80
-rw-r--r--src/file_a.c62
-rw-r--r--src/file_ab.c96
-rw-r--r--src/file_ace.c172
-rw-r--r--src/file_aif.c66
-rw-r--r--src/file_all.c63
-rw-r--r--src/file_asf.c69
-rw-r--r--src/file_au.c63
-rw-r--r--src/file_bkf.c63
-rw-r--r--src/file_bld.c63
-rw-r--r--src/file_bmp.c67
-rw-r--r--src/file_bz2.c62
-rw-r--r--src/file_cab.c81
-rw-r--r--src/file_cam.c63
-rw-r--r--src/file_cm.c62
-rw-r--r--src/file_crw.c86
-rw-r--r--src/file_ctg.c64
-rw-r--r--src/file_cwk.c72
-rw-r--r--src/file_dat.c62
-rw-r--r--src/file_dbf.c63
-rw-r--r--src/file_dir.c62
-rw-r--r--src/file_djv.c65
-rw-r--r--src/file_doc.c234
-rw-r--r--src/file_dpx.c92
-rw-r--r--src/file_dsc.c63
-rw-r--r--src/file_dta.c75
-rw-r--r--src/file_dump.c149
-rw-r--r--src/file_dv.c66
-rw-r--r--src/file_dwg.c71
-rw-r--r--src/file_elf.c63
-rw-r--r--src/file_evt.c98
-rw-r--r--src/file_exe.c165
-rw-r--r--src/file_ext.c65
-rw-r--r--src/file_fh10.c69
-rw-r--r--src/file_fh5.c85
-rw-r--r--src/file_flac.c64
-rw-r--r--src/file_flv.c63
-rw-r--r--src/file_fs.c63
-rw-r--r--src/file_gif.c74
-rw-r--r--src/file_gz.c71
-rw-r--r--src/file_imb.c64
-rw-r--r--src/file_indd.c90
-rw-r--r--src/file_itu.c67
-rw-r--r--src/file_jpg.c420
-rw-r--r--src/file_jpg.h24
-rw-r--r--src/file_max.c64
-rw-r--r--src/file_mdb.c90
-rw-r--r--src/file_mdf.c68
-rw-r--r--src/file_mid.c72
-rw-r--r--src/file_mkv.c66
-rw-r--r--src/file_mov.c239
-rw-r--r--src/file_mp3.c462
-rw-r--r--src/file_mpg.c85
-rw-r--r--src/file_mrw.c106
-rw-r--r--src/file_mus.c72
-rw-r--r--src/file_mysql.c73
-rw-r--r--src/file_njx.c72
-rw-r--r--src/file_ogg.c105
-rw-r--r--src/file_orf.c63
-rw-r--r--src/file_pap.c63
-rw-r--r--src/file_pcx.c77
-rw-r--r--src/file_pdf.c147
-rw-r--r--src/file_png.c104
-rw-r--r--src/file_prc.c62
-rw-r--r--src/file_ps.c103
-rw-r--r--src/file_psd.c66
-rw-r--r--src/file_pst.c105
-rw-r--r--src/file_ptb.c62
-rw-r--r--src/file_qbb.c98
-rw-r--r--src/file_qdf.c63
-rw-r--r--src/file_qxd.c77
-rw-r--r--src/file_ra.c79
-rw-r--r--src/file_raf.c66
-rw-r--r--src/file_rar.c72
-rw-r--r--src/file_raw.c75
-rw-r--r--src/file_rdc.c66
-rw-r--r--src/file_reg.c72
-rw-r--r--src/file_riff.c77
-rw-r--r--src/file_rm.c63
-rw-r--r--src/file_rns.c64
-rw-r--r--src/file_rpm.c66
-rw-r--r--src/file_sit.c63
-rw-r--r--src/file_skp.c64
-rw-r--r--src/file_spe.c267
-rw-r--r--src/file_spss.c62
-rw-r--r--src/file_stu.c63
-rw-r--r--src/file_swf.c74
-rw-r--r--src/file_tar.c67
-rw-r--r--src/file_tib.c61
-rw-r--r--src/file_tiff.c115
-rw-r--r--src/file_txt.c754
-rw-r--r--src/file_vmdk.c93
-rw-r--r--src/file_wmf.c71
-rw-r--r--src/file_x3f.c62
-rw-r--r--src/file_xcf.c67
-rw-r--r--src/file_xm.c200
-rw-r--r--src/file_zip.c591
-rw-r--r--src/filegen.c93
-rw-r--r--src/filegen.h126
-rw-r--r--src/fnctdsk.c451
-rw-r--r--src/fnctdsk.h46
-rw-r--r--src/geometry.c292
-rw-r--r--src/godmode.c1333
-rw-r--r--src/godmode.h25
-rw-r--r--src/guid_cmp.h26
-rw-r--r--src/guid_cpy.h27
-rw-r--r--src/hdaccess.c2310
-rw-r--r--src/hdaccess.h8
-rw-r--r--src/hdcache.c280
-rw-r--r--src/hdcache.h23
-rw-r--r--src/hfs.c127
-rw-r--r--src/hfs.h78
-rw-r--r--src/hfsp.c138
-rw-r--r--src/hfsp.h151
-rw-r--r--src/icon_ph.rc4
-rw-r--r--src/icon_tst.rc4
-rw-r--r--src/intrf.c2062
-rw-r--r--src/intrf.h99
-rw-r--r--src/intrface.c1507
-rw-r--r--src/intrface.h34
-rw-r--r--src/intrfn.h52
-rw-r--r--src/io_redir.c227
-rw-r--r--src/io_redir.h24
-rw-r--r--src/jfs.c119
-rw-r--r--src/jfs.h28
-rw-r--r--src/jfs_superblock.h126
-rw-r--r--src/lang.h69
-rw-r--r--src/list.c107
-rw-r--r--src/list.h336
-rw-r--r--src/log.c248
-rw-r--r--src/log.h56
-rw-r--r--src/luks.c107
-rw-r--r--src/luks.h56
-rw-r--r--src/lvm.c193
-rw-r--r--src/lvm.h123
-rw-r--r--src/md.c249
-rw-r--r--src/md.h257
-rw-r--r--src/netware.c73
-rw-r--r--src/netware.h33
-rw-r--r--src/next.c164
-rw-r--r--src/next.h3
-rw-r--r--src/ntfs.c461
-rw-r--r--src/ntfs.h71
-rw-r--r--src/ntfs_adv.c706
-rw-r--r--src/ntfs_dir.c468
-rw-r--r--src/ntfs_dir.h25
-rw-r--r--src/ntfs_fix.c228
-rw-r--r--src/ntfs_inc.h30
-rw-r--r--src/ntfs_io.c157
-rw-r--r--src/ntfs_utl.c195
-rw-r--r--src/ntfs_utl.h26
-rw-r--r--src/ntfsp.c153
-rw-r--r--src/ntfsp.h23
-rw-r--r--src/ole.h94
-rw-r--r--src/partauto.c98
-rw-r--r--src/partauto.h24
-rw-r--r--src/partgpt.c819
-rw-r--r--src/partgpt.h36
-rw-r--r--src/parti386.c1692
-rw-r--r--src/partmac.c563
-rw-r--r--src/partmac.h91
-rw-r--r--src/partnone.c365
-rw-r--r--src/partnone.h3
-rw-r--r--src/partsun.c514
-rw-r--r--src/partxbox.c427
-rw-r--r--src/partxbox.h29
-rw-r--r--src/pe.h157
-rw-r--r--src/photorec.c1298
-rw-r--r--src/photorec.h39
-rw-r--r--src/phrecn.c2171
-rw-r--r--src/phrecn.h23
-rw-r--r--src/rfs.c232
-rw-r--r--src/rfs.h109
-rw-r--r--src/rfs_dir.c530
-rw-r--r--src/rfs_dir.h24
-rw-r--r--src/savehdr.c256
-rw-r--r--src/savehdr.h35
-rw-r--r--src/sessionp.c205
-rw-r--r--src/sessionp.h24
-rw-r--r--src/sun.c124
-rw-r--r--src/sun.h79
-rw-r--r--src/swap.c123
-rw-r--r--src/swap.h46
-rw-r--r--src/sysv.c130
-rw-r--r--src/sysv.h202
-rw-r--r--src/testdisk.c369
-rw-r--r--src/testdisk.h24
-rw-r--r--src/types.h34
-rw-r--r--src/ufs.c193
-rw-r--r--src/ufs.h470
-rw-r--r--src/unicode.c57
-rw-r--r--src/unicode.h24
-rw-r--r--src/xfs.c138
-rw-r--r--src/xfs.h108
236 files changed, 48043 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..04c0064
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,31 @@
+.rc.o:
+ $(WINDRES) --include-dir $(srcdir) $< $@
+
+if USEICON
+ICON_TESTDISK=icon_tst.rc ../doc/favicon.ico
+ICON_PHOTOREC=icon_ph.rc ../doc/photorec.ico
+endif
+
+
+sbin_PROGRAMS = testdisk photorec
+#diskcp
+
+base_C = common.c crc.c ewf.c fnctdsk.c hdaccess.c hdcache.c intrf.c log.c parti386.c partgpt.c partmac.c partsun.c partnone.c partxbox.c chgtype.c io_redir.c ntfs_io.c ntfs_utl.c partauto.c unicode.c
+base_H = common.h crc.h ewf.h fnctdsk.h hdaccess.h guid_cmp.h guid_cpy.h hdcache.h intrf.h intrfn.h lang.h log.h types.h chgtype.h io_redir.h ntfs_utl.h partgpt.h partmac.h partnone.h partxbox.h partauto.h unicode.h
+
+fs_C = analyse.c bfs.c bsd.c cramfs.c fat.c fatx.c ext2.c jfs.c hfs.c hfsp.c luks.c lvm.c md.c netware.c ntfs.c rfs.c savehdr.c sun.c swap.c sysv.c ufs.c xfs.c
+fs_H = analyse.h bfs.h bsd.h cramfs.h fat.h fatx.h ext2.h jfs_superblock.h jfs.h hfs.h hfsp.h luks.h lvm.h md.h netware.h ntfs.h rfs.h savehdr.h sun.h swap.h sysv.h ufs.h xfs.h
+
+testdisk_SOURCES = testdisk.c $(base_C) $(base_H) $(fs_C) $(fs_H) testdisk.h adv.c adv.h dir.c dir.h dirpart.c dirpart.h edit.c edit.h ext2_dir.c ext2_dir.h ext2_inc.h fat_adv.c fat_dir.c fat_dir.h geometry.c godmode.c godmode.h intrface.c intrface.h ntfs_adv.c ntfs_dir.c ntfs_dir.h ntfs_fix.c ntfs_inc.h rfs_dir.c rfs_dir.h $(ICON_TESTDISK) next.c next.h
+#ntfs_udl.c ntfs_udl.h
+
+
+photorec_SOURCES = photorec.c photorec.h phrecn.c phrecn.h dir.c dir.h ext2p.c ext2p.h ext2_dir.c ext2_dir.h ext2_inc.h fat_dir.c fat_dir.h fatp.c fatp.h filegen.c filegen.h file_7z.c file_a.c file_ab.c file_ace.c file_aif.c file_all.c file_asf.c file_au.c file_bkf.c file_bld.c file_bmp.c file_bz2.c file_cab.c file_cam.c file_cm.c file_crw.c file_ctg.c file_cwk.c file_dat.c file_dbf.c file_dir.c file_djv.c file_doc.c file_dpx.c file_dsc.c file_dta.c file_dv.c file_dwg.c file_elf.c file_evt.c file_exe.c pe.h file_ext.c file_fh10.c file_fh5.c file_flac.c file_flv.c file_fs.c file_gif.c file_gz.c file_imb.c file_indd.c file_dump.c file_itu.c file_jpg.c file_jpg.h file_max.c file_mdb.c file_mdf.c file_mid.c file_mkv.c file_mov.c file_mp3.c file_mpg.c file_mrw.c file_mus.c file_mysql.c file_njx.c file_ogg.c file_orf.c file_pap.c file_pcx.c file_pdf.c file_png.c file_prc.c file_ps.c file_psd.c file_pst.c file_ptb.c file_qbb.c file_qdf.c file_qxd.c file_ra.c file_raf.c file_rar.c file_raw.c file_rdc.c file_reg.c file_riff.c file_rm.c file_rns.c file_rpm.c file_sit.c file_skp.c file_spe.c file_spss.c file_stu.c file_swf.c file_tar.c file_tib.c file_tiff.c file_txt.c file_vmdk.c file_wmf.c file_x3f.c file_xcf.c file_xm.c file_zip.c geometry.c list.c list.h ole.h ntfs_dir.c ntfs_dir.h ntfsp.c ntfsp.h ntfs_inc.h sessionp.c sessionp.h $(base_C) $(base_H) $(fs_C) $(fs_H) $(ICON_PHOTOREC)
+
+#diskcp_SOURCES = diskcp.c types.h
+
+DISTCLEANFILES = *~ core
+
+small: $(sbin_PROGRAMS) $(bin_PROGRAMS)
+ $(STRIP) -s $(sbin_PROGRAMS) $(bin_PROGRAMS)
+
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..a9b6b11
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,753 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+sbin_PROGRAMS = testdisk$(EXEEXT) photorec$(EXEEXT)
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(sbindir)"
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(sbin_PROGRAMS)
+am__photorec_SOURCES_DIST = photorec.c photorec.h phrecn.c phrecn.h \
+ dir.c dir.h ext2p.c ext2p.h ext2_dir.c ext2_dir.h ext2_inc.h \
+ fat_dir.c fat_dir.h fatp.c fatp.h filegen.c filegen.h \
+ file_7z.c file_a.c file_ab.c file_ace.c file_aif.c file_all.c \
+ file_asf.c file_au.c file_bkf.c file_bld.c file_bmp.c \
+ file_bz2.c file_cab.c file_cam.c file_cm.c file_crw.c \
+ file_ctg.c file_cwk.c file_dat.c file_dbf.c file_dir.c \
+ file_djv.c file_doc.c file_dpx.c file_dsc.c file_dta.c \
+ file_dv.c file_dwg.c file_elf.c file_evt.c file_exe.c pe.h \
+ file_ext.c file_fh10.c file_fh5.c file_flac.c file_flv.c \
+ file_fs.c file_gif.c file_gz.c file_imb.c file_indd.c \
+ file_dump.c file_itu.c file_jpg.c file_jpg.h file_max.c \
+ file_mdb.c file_mdf.c file_mid.c file_mkv.c file_mov.c \
+ file_mp3.c file_mpg.c file_mrw.c file_mus.c file_mysql.c \
+ file_njx.c file_ogg.c file_orf.c file_pap.c file_pcx.c \
+ file_pdf.c file_png.c file_prc.c file_ps.c file_psd.c \
+ file_pst.c file_ptb.c file_qbb.c file_qdf.c file_qxd.c \
+ file_ra.c file_raf.c file_rar.c file_raw.c file_rdc.c \
+ file_reg.c file_riff.c file_rm.c file_rns.c file_rpm.c \
+ file_sit.c file_skp.c file_spe.c file_spss.c file_stu.c \
+ file_swf.c file_tar.c file_tib.c file_tiff.c file_txt.c \
+ file_vmdk.c file_wmf.c file_x3f.c file_xcf.c file_xm.c \
+ file_zip.c geometry.c list.c list.h ole.h ntfs_dir.c \
+ ntfs_dir.h ntfsp.c ntfsp.h ntfs_inc.h sessionp.c sessionp.h \
+ common.c crc.c ewf.c fnctdsk.c hdaccess.c hdcache.c intrf.c \
+ log.c parti386.c partgpt.c partmac.c partsun.c partnone.c \
+ partxbox.c chgtype.c io_redir.c ntfs_io.c ntfs_utl.c \
+ partauto.c unicode.c common.h crc.h ewf.h fnctdsk.h hdaccess.h \
+ guid_cmp.h guid_cpy.h hdcache.h intrf.h intrfn.h lang.h log.h \
+ types.h chgtype.h io_redir.h ntfs_utl.h partgpt.h partmac.h \
+ partnone.h partxbox.h partauto.h unicode.h analyse.c bfs.c \
+ bsd.c cramfs.c fat.c fatx.c ext2.c jfs.c hfs.c hfsp.c luks.c \
+ lvm.c md.c netware.c ntfs.c rfs.c savehdr.c sun.c swap.c \
+ sysv.c ufs.c xfs.c analyse.h bfs.h bsd.h cramfs.h fat.h fatx.h \
+ ext2.h jfs_superblock.h jfs.h hfs.h hfsp.h luks.h lvm.h md.h \
+ netware.h ntfs.h rfs.h savehdr.h sun.h swap.h sysv.h ufs.h \
+ xfs.h icon_ph.rc ../doc/photorec.ico
+am__objects_1 = common.$(OBJEXT) crc.$(OBJEXT) ewf.$(OBJEXT) \
+ fnctdsk.$(OBJEXT) hdaccess.$(OBJEXT) hdcache.$(OBJEXT) \
+ intrf.$(OBJEXT) log.$(OBJEXT) parti386.$(OBJEXT) \
+ partgpt.$(OBJEXT) partmac.$(OBJEXT) partsun.$(OBJEXT) \
+ partnone.$(OBJEXT) partxbox.$(OBJEXT) chgtype.$(OBJEXT) \
+ io_redir.$(OBJEXT) ntfs_io.$(OBJEXT) ntfs_utl.$(OBJEXT) \
+ partauto.$(OBJEXT) unicode.$(OBJEXT)
+am__objects_2 =
+am__objects_3 = analyse.$(OBJEXT) bfs.$(OBJEXT) bsd.$(OBJEXT) \
+ cramfs.$(OBJEXT) fat.$(OBJEXT) fatx.$(OBJEXT) ext2.$(OBJEXT) \
+ jfs.$(OBJEXT) hfs.$(OBJEXT) hfsp.$(OBJEXT) luks.$(OBJEXT) \
+ lvm.$(OBJEXT) md.$(OBJEXT) netware.$(OBJEXT) ntfs.$(OBJEXT) \
+ rfs.$(OBJEXT) savehdr.$(OBJEXT) sun.$(OBJEXT) swap.$(OBJEXT) \
+ sysv.$(OBJEXT) ufs.$(OBJEXT) xfs.$(OBJEXT)
+@USEICON_TRUE@am__objects_4 = icon_ph.$(OBJEXT)
+am_photorec_OBJECTS = photorec.$(OBJEXT) phrecn.$(OBJEXT) \
+ dir.$(OBJEXT) ext2p.$(OBJEXT) ext2_dir.$(OBJEXT) \
+ fat_dir.$(OBJEXT) fatp.$(OBJEXT) filegen.$(OBJEXT) \
+ file_7z.$(OBJEXT) file_a.$(OBJEXT) file_ab.$(OBJEXT) \
+ file_ace.$(OBJEXT) file_aif.$(OBJEXT) file_all.$(OBJEXT) \
+ file_asf.$(OBJEXT) file_au.$(OBJEXT) file_bkf.$(OBJEXT) \
+ file_bld.$(OBJEXT) file_bmp.$(OBJEXT) file_bz2.$(OBJEXT) \
+ file_cab.$(OBJEXT) file_cam.$(OBJEXT) file_cm.$(OBJEXT) \
+ file_crw.$(OBJEXT) file_ctg.$(OBJEXT) file_cwk.$(OBJEXT) \
+ file_dat.$(OBJEXT) file_dbf.$(OBJEXT) file_dir.$(OBJEXT) \
+ file_djv.$(OBJEXT) file_doc.$(OBJEXT) file_dpx.$(OBJEXT) \
+ file_dsc.$(OBJEXT) file_dta.$(OBJEXT) file_dv.$(OBJEXT) \
+ file_dwg.$(OBJEXT) file_elf.$(OBJEXT) file_evt.$(OBJEXT) \
+ file_exe.$(OBJEXT) file_ext.$(OBJEXT) file_fh10.$(OBJEXT) \
+ file_fh5.$(OBJEXT) file_flac.$(OBJEXT) file_flv.$(OBJEXT) \
+ file_fs.$(OBJEXT) file_gif.$(OBJEXT) file_gz.$(OBJEXT) \
+ file_imb.$(OBJEXT) file_indd.$(OBJEXT) file_dump.$(OBJEXT) \
+ file_itu.$(OBJEXT) file_jpg.$(OBJEXT) file_max.$(OBJEXT) \
+ file_mdb.$(OBJEXT) file_mdf.$(OBJEXT) file_mid.$(OBJEXT) \
+ file_mkv.$(OBJEXT) file_mov.$(OBJEXT) file_mp3.$(OBJEXT) \
+ file_mpg.$(OBJEXT) file_mrw.$(OBJEXT) file_mus.$(OBJEXT) \
+ file_mysql.$(OBJEXT) file_njx.$(OBJEXT) file_ogg.$(OBJEXT) \
+ file_orf.$(OBJEXT) file_pap.$(OBJEXT) file_pcx.$(OBJEXT) \
+ file_pdf.$(OBJEXT) file_png.$(OBJEXT) file_prc.$(OBJEXT) \
+ file_ps.$(OBJEXT) file_psd.$(OBJEXT) file_pst.$(OBJEXT) \
+ file_ptb.$(OBJEXT) file_qbb.$(OBJEXT) file_qdf.$(OBJEXT) \
+ file_qxd.$(OBJEXT) file_ra.$(OBJEXT) file_raf.$(OBJEXT) \
+ file_rar.$(OBJEXT) file_raw.$(OBJEXT) file_rdc.$(OBJEXT) \
+ file_reg.$(OBJEXT) file_riff.$(OBJEXT) file_rm.$(OBJEXT) \
+ file_rns.$(OBJEXT) file_rpm.$(OBJEXT) file_sit.$(OBJEXT) \
+ file_skp.$(OBJEXT) file_spe.$(OBJEXT) file_spss.$(OBJEXT) \
+ file_stu.$(OBJEXT) file_swf.$(OBJEXT) file_tar.$(OBJEXT) \
+ file_tib.$(OBJEXT) file_tiff.$(OBJEXT) file_txt.$(OBJEXT) \
+ file_vmdk.$(OBJEXT) file_wmf.$(OBJEXT) file_x3f.$(OBJEXT) \
+ file_xcf.$(OBJEXT) file_xm.$(OBJEXT) file_zip.$(OBJEXT) \
+ geometry.$(OBJEXT) list.$(OBJEXT) ntfs_dir.$(OBJEXT) \
+ ntfsp.$(OBJEXT) sessionp.$(OBJEXT) $(am__objects_1) \
+ $(am__objects_2) $(am__objects_3) $(am__objects_2) \
+ $(am__objects_4)
+photorec_OBJECTS = $(am_photorec_OBJECTS)
+photorec_DEPENDENCIES =
+am__testdisk_SOURCES_DIST = testdisk.c common.c crc.c ewf.c fnctdsk.c \
+ hdaccess.c hdcache.c intrf.c log.c parti386.c partgpt.c \
+ partmac.c partsun.c partnone.c partxbox.c chgtype.c io_redir.c \
+ ntfs_io.c ntfs_utl.c partauto.c unicode.c common.h crc.h ewf.h \
+ fnctdsk.h hdaccess.h guid_cmp.h guid_cpy.h hdcache.h intrf.h \
+ intrfn.h lang.h log.h types.h chgtype.h io_redir.h ntfs_utl.h \
+ partgpt.h partmac.h partnone.h partxbox.h partauto.h unicode.h \
+ analyse.c bfs.c bsd.c cramfs.c fat.c fatx.c ext2.c jfs.c hfs.c \
+ hfsp.c luks.c lvm.c md.c netware.c ntfs.c rfs.c savehdr.c \
+ sun.c swap.c sysv.c ufs.c xfs.c analyse.h bfs.h bsd.h cramfs.h \
+ fat.h fatx.h ext2.h jfs_superblock.h jfs.h hfs.h hfsp.h luks.h \
+ lvm.h md.h netware.h ntfs.h rfs.h savehdr.h sun.h swap.h \
+ sysv.h ufs.h xfs.h testdisk.h adv.c adv.h dir.c dir.h \
+ dirpart.c dirpart.h edit.c edit.h ext2_dir.c ext2_dir.h \
+ ext2_inc.h fat_adv.c fat_dir.c fat_dir.h geometry.c godmode.c \
+ godmode.h intrface.c intrface.h ntfs_adv.c ntfs_dir.c \
+ ntfs_dir.h ntfs_fix.c ntfs_inc.h rfs_dir.c rfs_dir.h \
+ icon_tst.rc ../doc/favicon.ico next.c next.h
+@USEICON_TRUE@am__objects_5 = icon_tst.$(OBJEXT)
+am_testdisk_OBJECTS = testdisk.$(OBJEXT) $(am__objects_1) \
+ $(am__objects_2) $(am__objects_3) $(am__objects_2) \
+ adv.$(OBJEXT) dir.$(OBJEXT) dirpart.$(OBJEXT) edit.$(OBJEXT) \
+ ext2_dir.$(OBJEXT) fat_adv.$(OBJEXT) fat_dir.$(OBJEXT) \
+ geometry.$(OBJEXT) godmode.$(OBJEXT) intrface.$(OBJEXT) \
+ ntfs_adv.$(OBJEXT) ntfs_dir.$(OBJEXT) ntfs_fix.$(OBJEXT) \
+ rfs_dir.$(OBJEXT) $(am__objects_5) next.$(OBJEXT)
+testdisk_OBJECTS = $(am_testdisk_OBJECTS)
+testdisk_DEPENDENCIES =
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(photorec_SOURCES) $(testdisk_SOURCES)
+DIST_SOURCES = $(am__photorec_SOURCES_DIST) \
+ $(am__testdisk_SOURCES_DIST)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TESTDISKDATE = @TESTDISKDATE@
+USEICON_FALSE = @USEICON_FALSE@
+USEICON_TRUE = @USEICON_TRUE@
+VERSION = @VERSION@
+WINDRES = @WINDRES@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_pt_WINDRES = @ac_pt_WINDRES@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+photorec_LDADD = @photorec_LDADD@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+testdisk_LDADD = @testdisk_LDADD@
+@USEICON_TRUE@ICON_TESTDISK = icon_tst.rc ../doc/favicon.ico
+@USEICON_TRUE@ICON_PHOTOREC = icon_ph.rc ../doc/photorec.ico
+#diskcp
+base_C = common.c crc.c ewf.c fnctdsk.c hdaccess.c hdcache.c intrf.c log.c parti386.c partgpt.c partmac.c partsun.c partnone.c partxbox.c chgtype.c io_redir.c ntfs_io.c ntfs_utl.c partauto.c unicode.c
+base_H = common.h crc.h ewf.h fnctdsk.h hdaccess.h guid_cmp.h guid_cpy.h hdcache.h intrf.h intrfn.h lang.h log.h types.h chgtype.h io_redir.h ntfs_utl.h partgpt.h partmac.h partnone.h partxbox.h partauto.h unicode.h
+fs_C = analyse.c bfs.c bsd.c cramfs.c fat.c fatx.c ext2.c jfs.c hfs.c hfsp.c luks.c lvm.c md.c netware.c ntfs.c rfs.c savehdr.c sun.c swap.c sysv.c ufs.c xfs.c
+fs_H = analyse.h bfs.h bsd.h cramfs.h fat.h fatx.h ext2.h jfs_superblock.h jfs.h hfs.h hfsp.h luks.h lvm.h md.h netware.h ntfs.h rfs.h savehdr.h sun.h swap.h sysv.h ufs.h xfs.h
+testdisk_SOURCES = testdisk.c $(base_C) $(base_H) $(fs_C) $(fs_H) testdisk.h adv.c adv.h dir.c dir.h dirpart.c dirpart.h edit.c edit.h ext2_dir.c ext2_dir.h ext2_inc.h fat_adv.c fat_dir.c fat_dir.h geometry.c godmode.c godmode.h intrface.c intrface.h ntfs_adv.c ntfs_dir.c ntfs_dir.h ntfs_fix.c ntfs_inc.h rfs_dir.c rfs_dir.h $(ICON_TESTDISK) next.c next.h
+#ntfs_udl.c ntfs_udl.h
+photorec_SOURCES = photorec.c photorec.h phrecn.c phrecn.h dir.c dir.h \
+ ext2p.c ext2p.h ext2_dir.c ext2_dir.h ext2_inc.h fat_dir.c \
+ fat_dir.h fatp.c fatp.h filegen.c filegen.h file_7z.c file_a.c \
+ file_ab.c file_ace.c file_aif.c file_all.c file_asf.c \
+ file_au.c file_bkf.c file_bld.c file_bmp.c file_bz2.c \
+ file_cab.c file_cam.c file_cm.c file_crw.c file_ctg.c \
+ file_cwk.c file_dat.c file_dbf.c file_dir.c file_djv.c \
+ file_doc.c file_dpx.c file_dsc.c file_dta.c file_dv.c \
+ file_dwg.c file_elf.c file_evt.c file_exe.c pe.h file_ext.c \
+ file_fh10.c file_fh5.c file_flac.c file_flv.c file_fs.c \
+ file_gif.c file_gz.c file_imb.c file_indd.c file_dump.c \
+ file_itu.c file_jpg.c file_jpg.h file_max.c file_mdb.c \
+ file_mdf.c file_mid.c file_mkv.c file_mov.c file_mp3.c \
+ file_mpg.c file_mrw.c file_mus.c file_mysql.c file_njx.c \
+ file_ogg.c file_orf.c file_pap.c file_pcx.c file_pdf.c \
+ file_png.c file_prc.c file_ps.c file_psd.c file_pst.c \
+ file_ptb.c file_qbb.c file_qdf.c file_qxd.c file_ra.c \
+ file_raf.c file_rar.c file_raw.c file_rdc.c file_reg.c \
+ file_riff.c file_rm.c file_rns.c file_rpm.c file_sit.c \
+ file_skp.c file_spe.c file_spss.c file_stu.c file_swf.c \
+ file_tar.c file_tib.c file_tiff.c file_txt.c file_vmdk.c \
+ file_wmf.c file_x3f.c file_xcf.c file_xm.c file_zip.c \
+ geometry.c list.c list.h ole.h ntfs_dir.c ntfs_dir.h ntfsp.c \
+ ntfsp.h ntfs_inc.h sessionp.c sessionp.h $(base_C) $(base_H) \
+ $(fs_C) $(fs_H) $(ICON_PHOTOREC)
+
+#diskcp_SOURCES = diskcp.c types.h
+DISTCLEANFILES = *~ core
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj .rc
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnits src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(sbindir)" || $(mkdir_p) "$(DESTDIR)$(sbindir)"
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(sbindir)/$$f"; \
+ done
+
+clean-sbinPROGRAMS:
+ -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+
+installcheck-sbinPROGRAMS: $(sbin_PROGRAMS)
+ bad=0; pid=$$$$; list="$(sbin_PROGRAMS)"; for p in $$list; do \
+ case ' $(AM_INSTALLCHECK_STD_OPTIONS_EXEMPT) ' in \
+ *" $$p "* | *" $(srcdir)/$$p "*) continue;; \
+ esac; \
+ f=`echo "$$p" | \
+ sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ for opt in --help --version; do \
+ if "$(DESTDIR)$(sbindir)/$$f" $$opt >c$${pid}_.out \
+ 2>c$${pid}_.err </dev/null \
+ && test -n "`cat c$${pid}_.out`" \
+ && test -z "`cat c$${pid}_.err`"; then :; \
+ else echo "$$f does not support $$opt" 1>&2; bad=1; fi; \
+ done; \
+ done; rm -f c$${pid}_.???; exit $$bad
+photorec$(EXEEXT): $(photorec_OBJECTS) $(photorec_DEPENDENCIES)
+ @rm -f photorec$(EXEEXT)
+ $(LINK) $(photorec_LDFLAGS) $(photorec_OBJECTS) $(photorec_LDADD) $(LIBS)
+testdisk$(EXEEXT): $(testdisk_OBJECTS) $(testdisk_DEPENDENCIES)
+ @rm -f testdisk$(EXEEXT)
+ $(LINK) $(testdisk_LDFLAGS) $(testdisk_OBJECTS) $(testdisk_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/analyse.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bfs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bsd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chgtype.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cramfs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirpart.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ewf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext2_dir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext2p.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fat_adv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fat_dir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fatp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fatx.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_7z.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_a.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_ab.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_ace.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_aif.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_all.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_asf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_au.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_bkf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_bld.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_bmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_bz2.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_cab.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_cam.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_cm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_crw.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_ctg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_cwk.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_dat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_dbf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_dir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_djv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_doc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_dpx.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_dsc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_dta.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_dump.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_dv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_dwg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_elf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_evt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_exe.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_ext.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_fh10.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_fh5.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_flac.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_flv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_fs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_gif.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_gz.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_imb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_indd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_itu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_jpg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_max.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_mdb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_mdf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_mid.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_mkv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_mov.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_mp3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_mpg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_mrw.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_mus.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_mysql.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_njx.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_ogg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_orf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_pap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_pcx.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_pdf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_png.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_prc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_ps.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_psd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_pst.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_ptb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_qbb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_qdf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_qxd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_ra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_raf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_rar.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_raw.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_rdc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_reg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_riff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_rm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_rns.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_rpm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_sit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_skp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_spe.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_spss.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_stu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_swf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_tar.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_tib.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_txt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_vmdk.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_wmf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_x3f.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_xcf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_xm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_zip.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filegen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fnctdsk.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/geometry.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/godmode.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdaccess.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdcache.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hfs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hfsp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/intrf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/intrface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io_redir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jfs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/luks.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lvm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netware.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/next.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntfs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntfs_adv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntfs_dir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntfs_fix.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntfs_io.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntfs_utl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntfsp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partauto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partgpt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parti386.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partmac.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partnone.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partsun.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/partxbox.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/photorec.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/phrecn.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rfs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rfs_dir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/savehdr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sessionp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sun.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/swap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sysv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testdisk.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ufs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unicode.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfs.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(sbindir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-sbinPROGRAMS
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am: installcheck-sbinPROGRAMS
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-sbinPROGRAMS ctags distclean distclean-compile \
+ distclean-generic distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-exec install-exec-am install-info \
+ install-info-am install-man install-sbinPROGRAMS install-strip \
+ installcheck installcheck-am installcheck-sbinPROGRAMS \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \
+ ps ps-am tags uninstall uninstall-am uninstall-info-am \
+ uninstall-sbinPROGRAMS
+
+.rc.o:
+ $(WINDRES) --include-dir $(srcdir) $< $@
+
+small: $(sbin_PROGRAMS) $(bin_PROGRAMS)
+ $(STRIP) -s $(sbin_PROGRAMS) $(bin_PROGRAMS)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/adv.c b/src/adv.c
new file mode 100644
index 0000000..a9770f9
--- /dev/null
+++ b/src/adv.c
@@ -0,0 +1,1270 @@
+/*
+
+ File: adv.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdarg.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <ctype.h>
+#include "types.h"
+#include "common.h"
+#include "lang.h"
+#include "intrf.h"
+#include "intrfn.h"
+#include "fnctdsk.h"
+#include "chgtype.h"
+#include "testdisk.h"
+#include "dirpart.h"
+#include "fat.h"
+#include "ntfs.h"
+#include "hfs.h"
+#include "hfsp.h"
+#include "adv.h"
+#include "analyse.h"
+#include "intrface.h"
+#include "io_redir.h"
+#include "log.h"
+#include "guid_cmp.h"
+
+#define INTER_ADV_X 0
+#define INTER_ADV_Y 23
+#define INTER_ADV 15
+
+static int is_hfs(const partition_t *partition);
+static int is_hfsp(const partition_t *partition);
+static int is_linux(const partition_t *partition);
+static int is_part_hfs(const partition_t *partition);
+static int is_part_hfsp(const partition_t *partition);
+
+static int is_hfs(const partition_t *partition)
+{
+ return (is_part_hfs(partition) || partition->upart_type==UP_HFS);
+}
+
+static int is_hfsp(const partition_t *partition)
+{
+ return (is_part_hfsp(partition) || partition->upart_type==UP_HFSP || partition->upart_type==UP_HFSX);
+}
+
+static int is_linux(const partition_t *partition)
+{
+ if(is_part_linux(partition))
+ return 1;
+ switch(partition->upart_type)
+ {
+ case UP_CRAMFS:
+ case UP_EXT2:
+ case UP_EXT3:
+ case UP_JFS:
+ case UP_RFS:
+ case UP_RFS2:
+ case UP_RFS3:
+ case UP_RFS4:
+ case UP_XFS:
+ case UP_XFS2:
+ case UP_XFS3:
+ case UP_XFS4:
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int is_part_hfs(const partition_t *partition)
+{
+ switch(partition->part_type_i386)
+ {
+ case P_HFS:
+ return 1;
+ }
+ switch(partition->part_type_mac)
+ {
+ case PMAC_HFS:
+ return 1;
+ }
+ if(guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_MAC_HFS)==0)
+ return 1;
+ return 0;
+}
+
+static int is_part_hfsp(const partition_t *partition)
+{
+ switch(partition->part_type_i386)
+ {
+ case P_HFSP:
+ return 1;
+ }
+ switch(partition->part_type_mac)
+ {
+ case PMAC_HFS:
+ return 1;
+ }
+ if(guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_MAC_HFS)==0)
+ return 1;
+ return 0;
+}
+
+int is_part_linux(const partition_t *partition)
+{
+ switch(partition->part_type_i386)
+ {
+ case P_LINUX:
+ return 1;
+ }
+ switch(partition->part_type_sun)
+ {
+ case PSUN_LINUX:
+ return 1;
+ }
+ switch(partition->part_type_mac)
+ {
+ case PMAC_LINUX:
+ return 1;
+ }
+ if(guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_LINUX_DATA)==0)
+ return 1;
+ return 0;
+}
+
+void interface_adv(disk_t *disk_car, const int verbose,const int dump_ind, const unsigned int expert, char**current_cmd)
+{
+ int quit;
+ int offset=0;
+ int current_element_num=0;
+ int rewrite=1;
+ const char *options;
+ list_part_t *element;
+ list_part_t *list_part;
+ list_part_t *current_element;
+ log_info("\nInterface Advanced\n");
+ list_part=disk_car->arch->read_part(disk_car,verbose,0);
+ current_element=list_part;
+ for(element=list_part;element!=NULL;element=element->next)
+ {
+ log_partition(disk_car,element->part);
+ }
+ do
+ {
+ static struct MenuItem menuAdv[]=
+ {
+ {'t',"Type","Change type, this setting will not be saved on disk"},
+ {'b',"Boot","Boot sector recovery"},
+ {'s',"Superblock",NULL},
+// {'a',"Add", "Add temporary partition (Expert only)"},
+ {'q',"Quit","Return to main menu"},
+ {0,NULL,NULL}
+ };
+ int menu=0;
+ int i;
+ int command;
+#ifdef HAVE_NCURSES
+ if(rewrite!=0)
+ {
+ aff_copy(stdscr);
+ wmove(stdscr,4,0);
+ wdoprintf(stdscr,"%s",disk_car->description(disk_car));
+ if(list_part!=NULL)
+ mvwaddstr(stdscr,6,0,msg_PART_HEADER_LONG);
+ rewrite=0;
+ }
+ for(i=0,element=list_part;(element!=NULL) && (i<offset);element=element->next,i++);
+ for(i=offset;(element!=NULL) && ((i-offset)<INTER_ADV);element=element->next,i++)
+ {
+ wmove(stdscr,5+2+i-offset,0);
+ wclrtoeol(stdscr); /* before addstr for BSD compatibility */
+ if(element==current_element)
+ {
+ wattrset(stdscr, A_REVERSE);
+ aff_part(stdscr,AFF_PART_ORDER,disk_car,element->part);
+ wattroff(stdscr, A_REVERSE);
+ } else
+ {
+ aff_part(stdscr,AFF_PART_ORDER,disk_car,element->part);
+ }
+ }
+#endif
+ menu=0;
+ if(current_element==NULL)
+ {
+ options="q";
+#ifdef HAVE_NCURSES
+ wmove(stdscr,5+2,0);
+ wattrset(stdscr, A_REVERSE);
+ wdoprintf(stdscr,"No partition available.");
+ wattroff(stdscr, A_REVERSE);
+#endif
+ }
+ else
+ {
+ if(is_part_fat(current_element->part) ||
+ is_part_ntfs(current_element->part))
+ {
+ options="tbq";
+ menu=1;
+ }
+ else if(is_part_linux(current_element->part))
+ {
+ options="tsq";
+ menuAdv[2].desc="Locate EXT2/EXT3 backup superblock";
+ menu=1;
+ }
+ else if(is_part_hfs(current_element->part) || is_part_hfsp(current_element->part))
+ {
+ options="tsq";
+ menuAdv[2].desc="Locate HFS/HFS+ backup superblock";
+ menu=1;
+ }
+ else if(is_fat(current_element->part) ||
+ is_ntfs(current_element->part))
+ {
+ options="tbq";
+ menu=1;
+ }
+ else if(is_linux(current_element->part))
+ {
+ options="tsq";
+ menuAdv[2].desc="Locate EXT2/EXT3 backup superblock";
+ menu=1;
+ }
+ else if(is_hfs(current_element->part) || is_hfsp(current_element->part))
+ {
+ options="tsq";
+ menuAdv[2].desc="Locate HFS/HFS+ backup superblock";
+ menu=1;
+ }
+ else
+ options="tq";
+ }
+ quit=0;
+ if(*current_cmd!=NULL)
+ {
+ int keep_asking;
+ command='q';
+ do
+ {
+ keep_asking=0;
+ while(*current_cmd[0]==',')
+ (*current_cmd)++;
+ if(strncmp(*current_cmd,"type",4)==0)
+ {
+ (*current_cmd)+=4;
+ command='t';
+ }
+ else if(strncmp(*current_cmd,"boot",4)==0)
+ {
+ (*current_cmd)+=4;
+ command='b';
+ }
+ else if(strncmp(*current_cmd,"superblock",10)==0)
+ {
+ (*current_cmd)+=10;
+ command='s';
+ }
+ else
+ {
+ unsigned int order;
+ order= atoi(*current_cmd);
+ while(*current_cmd[0]!=',' && *current_cmd[0]!='\0')
+ (*current_cmd)++;
+ for(element=list_part;element!=NULL && element->part->order!=order;element=element->next);
+ if(element!=NULL)
+ {
+ current_element=element;
+ keep_asking=1;
+ }
+ }
+ } while(keep_asking>0);
+ }
+ else
+ {
+#ifdef HAVE_NCURSES
+ command = wmenuSelect(stdscr,INTER_ADV_Y, INTER_ADV_X, menuAdv, 8, options,
+ MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, menu);
+#else
+ command = 'q';
+#endif
+ }
+ switch(command)
+ {
+#ifdef HAVE_NCURSES
+ case KEY_UP:
+ if(current_element!=NULL)
+ {
+ if(current_element->prev!=NULL)
+ {
+ current_element=current_element->prev;
+ current_element_num--;
+ }
+ if(current_element_num<offset)
+ offset--;
+ }
+ break;
+ case KEY_DOWN:
+ if(current_element!=NULL)
+ {
+ if(current_element->next!=NULL)
+ {
+ current_element=current_element->next;
+ current_element_num++;
+ }
+ if(current_element_num>=offset+INTER_ADV)
+ offset++;
+ }
+ break;
+#endif
+ case 'q':
+ case 'Q':
+ quit=1;
+ break;
+ case 'a':
+ case 'A':
+ {
+ list_part=disk_car->arch->add_partition(disk_car,list_part, verbose, current_cmd);
+ current_element=list_part;
+ rewrite=1;
+ }
+ break;
+ case 'b':
+ case 'B':
+ if(current_element!=NULL)
+ {
+ partition_t *partition=current_element->part;
+ if(is_part_fat32(partition))
+ {
+ fat32_boot_sector(disk_car, partition, verbose, dump_ind, expert,current_cmd);
+ rewrite=1;
+ }
+ else if(is_part_fat12(partition) || is_part_fat16(partition))
+ {
+ fat1x_boot_sector(disk_car, partition, verbose, dump_ind,expert,current_cmd);
+ rewrite=1;
+ }
+ else if(is_part_ntfs(partition))
+ {
+ ntfs_boot_sector(disk_car, partition, verbose, dump_ind, expert, current_cmd);
+ rewrite=1;
+ }
+ else if(partition->upart_type==UP_FAT32)
+ {
+ fat32_boot_sector(disk_car, partition, verbose, dump_ind, expert,current_cmd);
+ rewrite=1;
+ }
+ else if(partition->upart_type==UP_FAT12 || partition->upart_type==UP_FAT16)
+ {
+ fat1x_boot_sector(disk_car, partition, verbose, dump_ind,expert,current_cmd);
+ rewrite=1;
+ }
+ else if(partition->upart_type==UP_NTFS)
+ {
+ ntfs_boot_sector(disk_car, partition, verbose, dump_ind, expert, current_cmd);
+ rewrite=1;
+ }
+ }
+ break;
+ case 's':
+ case 'S':
+ if(current_element!=NULL)
+ {
+ if(is_linux(current_element->part))
+ {
+ list_part_t *list_sb=search_superblock(disk_car,current_element->part,verbose,dump_ind,1);
+ interface_superblock(disk_car,list_sb,current_cmd);
+ part_free_list(list_sb);
+ }
+ if(is_hfs(current_element->part) || is_hfsp(current_element->part))
+ {
+ HFS_HFSP_boot_sector(disk_car, current_element->part, verbose, dump_ind, expert, current_cmd);
+ }
+ rewrite=1;
+ }
+ break;
+ case 't':
+ case 'T':
+ if(current_element!=NULL)
+ {
+ change_part_type(disk_car,current_element->part, current_cmd);
+ rewrite=1;
+ }
+ break;
+ }
+ } while(quit==0);
+ part_free_list(list_part);
+}
+
+#ifdef HAVE_NCURSES
+static void dump_fat1x_ncurses(disk_t *disk_car, partition_t *partition, const unsigned char *buffer_bs)
+{
+ WINDOW *window=newwin(0,0,0,0); /* full screen */
+ keypad(window, TRUE); /* Need it to get arrow key */
+ aff_copy(window);
+ wmove(window,4,0);
+ wdoprintf(window,"%s",disk_car->description(disk_car));
+ wmove(window,5,0);
+ aff_part(window,AFF_PART_ORDER,disk_car,partition);
+ mvwaddstr(window,6,0, "Boot sector");
+ dump(window,buffer_bs,FAT1x_BOOT_SECTOR_SIZE);
+ delwin(window);
+ (void) clearok(stdscr, TRUE);
+#ifdef HAVE_TOUCHWIN
+ touchwin(stdscr);
+#endif
+}
+#endif
+
+static void dump_fat1x(disk_t *disk_car, partition_t *partition, const unsigned char *buffer_bs)
+{
+ log_info("Boot sector\n");
+ dump_log(buffer_bs, FAT1x_BOOT_SECTOR_SIZE);
+#ifdef HAVE_NCURSES
+ dump_fat1x_ncurses(disk_car, partition, buffer_bs);
+#endif
+}
+
+int fat1x_boot_sector(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind, const unsigned int expert, char **current_cmd)
+{
+ unsigned char *buffer_bs;
+ const char *options="DR";
+ int rescan=1;
+ struct MenuItem menu_fat1x[]=
+ {
+ { 'P', "Previous",""},
+ { 'N', "Next","" },
+ { 'Q', "Quit","Return to Advanced menu"},
+ { 'L', "List", "List directories and files" },
+ { 'R', "Rebuild BS","Rebuild boot sector"},
+ { 'D', "Dump","Dump boot sector and backup boot sector"},
+ { 'C', "Repair FAT","Very Dangerous! Expert only"},
+ { 'I', "Init Root","Init root directory: Very Dangerous! Expert only"},
+ { 0, NULL, NULL }
+ };
+ buffer_bs=(unsigned char*)MALLOC(FAT1x_BOOT_SECTOR_SIZE);
+ while(1)
+ {
+ int command;
+ aff_buffer(BUFFER_RESET,"Q");
+ if(rescan==1)
+ {
+#ifdef HAVE_NCURSES
+ aff_copy(stdscr);
+ wmove(stdscr,4,0);
+ wdoprintf(stdscr,"%s",disk_car->description(disk_car));
+ mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG);
+ wmove(stdscr,6,0);
+ aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
+#endif
+ log_info("\nfat1x_boot_sector\n");
+ log_partition(disk_car,partition);
+ aff_buffer(BUFFER_ADD,"Boot sector\n");
+ if(disk_car->read(disk_car,FAT1x_BOOT_SECTOR_SIZE, buffer_bs, partition->part_offset)!=0)
+ {
+ aff_buffer(BUFFER_ADD,"fat1x_boot_sector: Can't read boot sector.\n");
+ memset(buffer_bs,0,FAT1x_BOOT_SECTOR_SIZE);
+ }
+ if(test_FAT(disk_car,(const struct fat_boot_sector *)buffer_bs,partition,verbose,0)==0)
+ {
+ aff_buffer(BUFFER_ADD,"OK\n");
+ if(expert==0)
+ options="DRCL";
+ else
+ options="DRCIL";
+ }
+ else
+ {
+ aff_buffer(BUFFER_ADD,"Bad\n");
+ options="DRC";
+ }
+ aff_buffer(BUFFER_ADD,"\n");
+ aff_buffer(BUFFER_ADD,"A valid FAT Boot sector must be present in order to access\n");
+ aff_buffer(BUFFER_ADD,"any data; even if the partition is not bootable.\n");
+ rescan=0;
+ }
+ screen_buffer_to_log();
+ if(*current_cmd!=NULL)
+ {
+ command=0;
+ while(*current_cmd[0]==',')
+ (*current_cmd)++;
+ if(strncmp(*current_cmd,"rebuildbs",9)==0)
+ {
+ (*current_cmd)+=9;
+ command='R';
+ }
+ else if(strncmp(*current_cmd,"dump",4)==0)
+ {
+ (*current_cmd)+=4;
+ command='D';
+ }
+ else if(strncmp(*current_cmd,"list",4)==0)
+ {
+ (*current_cmd)+=4;
+ if(strchr(options,'L')!=NULL)
+ command='L';
+ }
+ else if(strncmp(*current_cmd,"repairfat",8)==0)
+ {
+ (*current_cmd)+=8;
+ if(strchr(options,'C')!=NULL)
+ command='C';
+ }
+ else if(strncmp(*current_cmd,"initroot",8)==0)
+ {
+ (*current_cmd)+=8;
+ if(strchr(options,'I')!=NULL)
+ command='I';
+ }
+ }
+ else
+ {
+ log_flush();
+#ifdef HAVE_NCURSES
+ command=screen_buffer_display(stdscr,options,menu_fat1x);
+#else
+ command=0;
+#endif
+ }
+ switch(command)
+ {
+ case 0:
+ free(buffer_bs);
+ return 0;
+ case 'R': /* R : rebuild boot sector */
+ rebuild_FAT_BS(disk_car,partition,verbose,dump_ind,1,expert,current_cmd);
+ rescan=1;
+ break;
+ case 'D':
+ dump_fat1x(disk_car, partition, buffer_bs);
+ break;
+ case 'C':
+ repair_FAT_table(disk_car,partition,verbose);
+ break;
+ case 'I':
+ FAT_init_rootdir(disk_car,partition,verbose);
+ break;
+ case 'L':
+ dir_partition(disk_car, partition, 0,current_cmd);
+ break;
+ }
+ }
+}
+
+#ifdef HAVE_NCURSES
+static void dump_fat32_ncurses(disk_t *disk_car, const partition_t *partition, const unsigned char *buffer_bs, const unsigned char *buffer_backup_bs)
+{
+ WINDOW *window=newwin(0,0,0,0); /* full screen */
+ keypad(window, TRUE); /* Need it to get arrow key */
+ aff_copy(window);
+ wmove(window,4,0);
+ wdoprintf(window,"%s",disk_car->description(disk_car));
+ wmove(window,5,0);
+ aff_part(window,AFF_PART_ORDER,disk_car,partition);
+ mvwaddstr(window,6,0, "Boot sector Backup boot sector");
+ dump2(window, buffer_bs, buffer_backup_bs, 3*disk_car->sector_size);
+ delwin(window);
+ (void) clearok(stdscr, TRUE);
+#ifdef HAVE_TOUCHWIN
+ touchwin(stdscr);
+#endif
+}
+#endif
+
+static void dump_fat32(disk_t *disk_car, const partition_t *partition, const unsigned char *buffer_bs, const unsigned char *buffer_backup_bs)
+{
+ log_info("Boot sector Backup boot sector\n");
+ dump2_log(buffer_bs, buffer_backup_bs, 3*disk_car->sector_size);
+ log_fat2_info((const struct fat_boot_sector*)buffer_bs,(const struct fat_boot_sector*)buffer_backup_bs,UP_FAT32,disk_car->sector_size);
+#ifdef HAVE_NCURSES
+ dump_fat32_ncurses(disk_car, partition, buffer_bs, buffer_backup_bs);
+#endif
+}
+
+int fat32_boot_sector(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind, const unsigned int expert, char **current_cmd)
+{
+ unsigned char *buffer_bs;
+ unsigned char *buffer_backup_bs;
+ const char *options="DRC";
+ int rescan=1;
+ struct MenuItem menu_fat32[]=
+ {
+ { 'P', "Previous",""},
+ { 'N', "Next","" },
+ { 'Q', "Quit","Return to Advanced menu"},
+ { 'L', "List", "List directories and files" },
+ { 'O', "Org. BS","Copy boot sector over backup sector"},
+ { 'B', "Backup BS","Copy backup boot sector over boot sector"},
+ { 'R', "Rebuild BS","Rebuild boot sector"},
+ { 'D', "Dump","Dump boot sector and backup boot sector"},
+ { 'C', "Repair FAT","Very Dangerous! Expert only"},
+ { 0, NULL, NULL }
+ };
+ buffer_bs=(unsigned char*)MALLOC(3*disk_car->sector_size);
+ buffer_backup_bs=(unsigned char*)MALLOC(3*disk_car->sector_size);
+ while(1)
+ {
+ int command;
+ aff_buffer(BUFFER_RESET,"Q");
+ if(rescan==1)
+ {
+ int opt_over=0;
+ int opt_B=0;
+ int opt_O=0;
+ options="DRC";
+#ifdef HAVE_NCURSES
+ aff_copy(stdscr);
+ wmove(stdscr,4,0);
+ wdoprintf(stdscr,"%s",disk_car->description(disk_car));
+ mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG);
+ wmove(stdscr,6,0);
+ aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
+#endif
+ log_info("\nfat32_boot_sector\n");
+ log_partition(disk_car,partition);
+ aff_buffer(BUFFER_ADD,"Boot sector\n");
+ if(disk_car->read(disk_car,3*disk_car->sector_size, buffer_bs, partition->part_offset)!=0)
+ {
+ aff_buffer(BUFFER_ADD,"fat32_boot_sector: Can't read boot sector.\n");
+ memset(buffer_bs,0,3*disk_car->sector_size);
+ }
+ if(test_FAT(disk_car,(struct fat_boot_sector *)buffer_bs,partition,verbose,0)==0)
+ {
+ aff_buffer(BUFFER_ADD,"OK\n");
+ if(partition->upart_type==UP_FAT32)
+ {
+ opt_O=1;
+ opt_over=1;
+ }
+ else
+ {
+ aff_buffer(BUFFER_ADD,"Warning: valid FAT bootsector but not a FAT32 one!");
+ }
+ }
+ else
+ {
+ aff_buffer(BUFFER_ADD,"Bad\n");
+ }
+ aff_buffer(BUFFER_ADD,"\nBackup boot sector\n");
+ if(disk_car->read(disk_car,3*disk_car->sector_size, buffer_backup_bs, partition->part_offset+6*disk_car->sector_size)!=0)
+ {
+ aff_buffer(BUFFER_ADD,"fat32_boot_sector: Can't read backup boot sector.\n");
+ memset(buffer_backup_bs,0,3*disk_car->sector_size);
+ }
+ if(test_FAT(disk_car,(struct fat_boot_sector *)buffer_backup_bs,partition,verbose,0)==0)
+ {
+ aff_buffer(BUFFER_ADD,"OK\n");
+ if(partition->upart_type==UP_FAT32)
+ {
+ opt_B=1;
+ opt_over=1;
+ }
+ else
+ {
+ aff_buffer(BUFFER_ADD,"Warning: valid FAT backup bootsector but not a FAT32 one!");
+ }
+ }
+ else
+ {
+ aff_buffer(BUFFER_ADD,"Bad\n");
+ }
+ aff_buffer(BUFFER_ADD,"\n");
+ if((memcmp(buffer_bs,buffer_backup_bs,0x3E8)==0)&&(memcmp(buffer_bs+0x3F0,buffer_backup_bs+0x3F0,0x600-0x3F0))==0)
+ {
+ aff_buffer(BUFFER_ADD,"Sectors are identical.\n");
+ opt_over=0;
+ }
+ else
+ {
+ if(memcmp(buffer_bs,buffer_backup_bs,0x200)!=0)
+ aff_buffer(BUFFER_ADD,"First sectors (Boot code and partition information) are not identical.\n");
+ if((memcmp(buffer_bs+disk_car->sector_size, buffer_backup_bs+disk_car->sector_size,0x1E8)!=0)||
+ (memcmp(buffer_bs+disk_car->sector_size+0x1F0, buffer_backup_bs+disk_car->sector_size+0x1F0,0x200-0x1F0)!=0))
+ aff_buffer(BUFFER_ADD,"Second sectors (cluster information) are not identical.\n");
+ if(memcmp(buffer_bs+2*disk_car->sector_size, buffer_backup_bs+2*disk_car->sector_size,0x200)!=0)
+ aff_buffer(BUFFER_ADD,"Third sectors (Second part of boot code) are not identical.\n");
+ }
+ aff_buffer(BUFFER_ADD,"\n");
+ aff_buffer(BUFFER_ADD,"A valid FAT Boot sector must be present in order to access\n");
+ aff_buffer(BUFFER_ADD,"any data; even if the partition is not bootable.\n");
+ if(opt_over!=0)
+ {
+ if(opt_B!=0 && opt_O!=0)
+ options="DOBRL";
+ else if(opt_B!=0)
+ options="DBRL";
+ else if(opt_O!=0)
+ options="DORL";
+ }
+ else
+ {
+ if(opt_B!=0)
+ options="DRCL";
+ else
+ options="DR";
+ }
+ rescan=0;
+ }
+ screen_buffer_to_log();
+ if(*current_cmd!=NULL)
+ {
+ command=0;
+ while(*current_cmd[0]==',')
+ (*current_cmd)++;
+ if(strncmp(*current_cmd,"rebuildbs",9)==0)
+ {
+ (*current_cmd)+=9;
+ command='R';
+ }
+ else if(strncmp(*current_cmd,"dump",4)==0)
+ {
+ (*current_cmd)+=4;
+ command='D';
+ }
+ else if(strncmp(*current_cmd,"list",4)==0)
+ {
+ (*current_cmd)+=4;
+ if(strchr(options,'L')!=NULL)
+ command='L';
+ }
+ else if(strncmp(*current_cmd,"repairfat",8)==0)
+ {
+ (*current_cmd)+=8;
+ if(strchr(options,'C')!=NULL)
+ command='C';
+ }
+ else if(strncmp(*current_cmd,"originalfat",11)==0)
+ {
+ (*current_cmd)+=11;
+ if(strchr(options,'O')!=NULL)
+ command='O';
+ }
+ else if(strncmp(*current_cmd,"backupfat",9)==0)
+ {
+ (*current_cmd)+=9;
+ if(strchr(options,'B')!=NULL)
+ command='B';
+ }
+ }
+ else
+ {
+ log_flush();
+#ifdef HAVE_NCURSES
+ command=screen_buffer_display(stdscr,options,menu_fat32);
+#else
+ command=0;
+#endif
+ }
+ switch(command)
+ {
+ case 0:
+ free(buffer_bs);
+ free(buffer_backup_bs);
+ return 0;
+ case 'O': /* O : copy original boot sector over backup boot */
+ if(ask_confirmation("Copy original FAT32 boot sector over backup boot, confirm ? (Y/N)")!=0)
+ {
+ log_info("copy original boot sector over backup boot\n");
+ if(disk_car->write(disk_car,3*disk_car->sector_size, buffer_bs, partition->part_offset+6*disk_car->sector_size)!=0)
+ {
+ display_message("Write error: Can't overwrite FAT32 backup boot sector\n");
+ }
+ rescan=1;
+ }
+ break;
+ case 'B': /* B : copy backup boot sector over boot sector */
+ if(ask_confirmation("Copy backup FAT32 boot sector over boot sector, confirm ? (Y/N)")!=0)
+ {
+ log_info("copy backup boot sector over boot sector\n");
+ if(disk_car->write(disk_car,3*disk_car->sector_size, buffer_backup_bs, partition->part_offset)!=0)
+ {
+ display_message("Write error: Can't overwrite FAT32 boot sector\n");
+ }
+ rescan=1;
+ }
+ break;
+ case 'C':
+ repair_FAT_table(disk_car,partition,verbose);
+ break;
+ case 'D':
+ dump_fat32(disk_car, partition, buffer_bs, buffer_backup_bs);
+ break;
+ case 'L':
+ if(strchr(options,'O')==NULL && strchr(options,'B')!=NULL)
+ {
+ io_redir_add_redir(disk_car,partition->part_offset,3*disk_car->sector_size,0,buffer_backup_bs);
+ dir_partition(disk_car, partition, 0,current_cmd);
+ io_redir_del_redir(disk_car,partition->part_offset);
+ }
+ else
+ dir_partition(disk_car, partition, 0,current_cmd);
+ break;
+ case 'R': /* R : rebuild boot sector */
+ rebuild_FAT_BS(disk_car,partition,verbose,dump_ind,1,expert,current_cmd);
+ rescan=1;
+ break;
+ }
+ }
+}
+
+#ifdef HAVE_NCURSES
+static void dump_NTFS_ncurses(disk_t *disk_car, const partition_t *partition, const unsigned char *buffer_bs, const unsigned char *buffer_backup_bs)
+{
+ WINDOW *window=newwin(0,0,0,0); /* full screen */
+ keypad(window, TRUE); /* Need it to get arrow key */
+ aff_copy(window);
+ wmove(window,4,0);
+ wdoprintf(window,"%s",disk_car->description(disk_car));
+ wmove(window,5,0);
+ aff_part(window,AFF_PART_ORDER,disk_car,partition);
+ mvwaddstr(window,6,0, "Boot sector Backup boot sector");
+ dump2(window, buffer_bs, buffer_backup_bs, NTFS_BOOT_SECTOR_SIZE);
+ delwin(window);
+ (void) clearok(stdscr, TRUE);
+#ifdef HAVE_TOUCHWIN
+ touchwin(stdscr);
+#endif
+}
+#endif
+
+static void dump_NTFS(disk_t *disk_car, const partition_t *partition, const unsigned char *buffer_bs, const unsigned char *buffer_backup_bs)
+{
+ log_info("Boot sector Backup boot sector\n");
+ dump2_log(buffer_bs, buffer_backup_bs, NTFS_BOOT_SECTOR_SIZE);
+#ifdef HAVE_NCURSES
+ dump_NTFS_ncurses(disk_car, partition, buffer_bs, buffer_backup_bs);
+#endif
+}
+
+int ntfs_boot_sector(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind, const unsigned int expert, char **current_cmd)
+{
+ unsigned char *buffer_bs;
+ unsigned char *buffer_backup_bs;
+ const char *options="";
+ int rescan=1;
+ struct MenuItem menu_ntfs[]=
+ {
+ { 'P', "Previous",""},
+ { 'N', "Next","" },
+ { 'Q', "Quit","Return to Advanced menu"},
+ { 'L', "List", "List directories and files" },
+ { 'O', "Org. BS","Copy boot sector over backup sector"},
+ { 'B', "Backup BS","Copy backup boot sector over boot sector"},
+ { 'R', "Rebuild BS","Rebuild boot sector"},
+ { 'M', "Repair MFT","Check MFT"},
+ { 'D', "Dump","Dump boot sector and backup boot sector"},
+#if 0
+ { 'U', "Undelete","Recover deleted files"},
+#endif
+ { 0, NULL, NULL }
+ };
+ buffer_bs=(unsigned char*)MALLOC(NTFS_BOOT_SECTOR_SIZE);
+ buffer_backup_bs=(unsigned char*)MALLOC(NTFS_BOOT_SECTOR_SIZE);
+
+ while(1)
+ {
+ int command;
+ aff_buffer(BUFFER_RESET,"Q");
+ if(rescan==1)
+ {
+ int identical_sectors=0;
+ int opt_B=0;
+ int opt_O=0;
+#ifdef HAVE_NCURSES
+ aff_copy(stdscr);
+ wmove(stdscr,4,0);
+ wdoprintf(stdscr,"%s",disk_car->description(disk_car));
+ mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG);
+ wmove(stdscr,6,0);
+ aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
+#endif
+ log_info("\nntfs_boot_sector\n");
+ log_partition(disk_car,partition);
+ aff_buffer(BUFFER_ADD,"Boot sector\n");
+ if(disk_car->read(disk_car,NTFS_BOOT_SECTOR_SIZE, buffer_bs, partition->part_offset)!=0)
+ {
+ aff_buffer(BUFFER_ADD,"ntfs_boot_sector: Can't read boot sector.\n");
+ memset(buffer_bs,0,NTFS_BOOT_SECTOR_SIZE);
+ }
+ if(test_NTFS(disk_car,(struct ntfs_boot_sector*)buffer_bs,partition,verbose,0)==0)
+ {
+ aff_buffer(BUFFER_ADD,"Status: OK\n");
+ opt_O=1;
+ }
+ else
+ {
+ aff_buffer(BUFFER_ADD,"Status: Bad\n");
+ }
+ aff_buffer(BUFFER_ADD,"\nBackup boot sector\n");
+ if(disk_car->read(disk_car,NTFS_BOOT_SECTOR_SIZE, buffer_backup_bs, partition->part_offset+partition->part_size-disk_car->sector_size)!=0)
+ {
+ aff_buffer(BUFFER_ADD,"ntfs_boot_sector: Can't read backup boot sector.\n");
+ memset(buffer_backup_bs,0,NTFS_BOOT_SECTOR_SIZE);
+ }
+ if(test_NTFS(disk_car,(struct ntfs_boot_sector*)buffer_backup_bs,partition,verbose,0)==0)
+ {
+ aff_buffer(BUFFER_ADD,"Status: OK\n");
+ opt_B=1;
+ }
+ else
+ {
+ aff_buffer(BUFFER_ADD,"Status: Bad\n");
+ }
+ aff_buffer(BUFFER_ADD,"\n");
+ if(memcmp(buffer_bs,buffer_backup_bs,NTFS_BOOT_SECTOR_SIZE)==0)
+ {
+ log_ntfs_info((const struct ntfs_boot_sector *)buffer_bs);
+ aff_buffer(BUFFER_ADD,"Sectors are identical.\n");
+ identical_sectors=1;
+ }
+ else
+ {
+ log_ntfs2_info((const struct ntfs_boot_sector *)buffer_bs, (const struct ntfs_boot_sector *)buffer_backup_bs);
+ aff_buffer(BUFFER_ADD,"Sectors are not identical.\n");
+ identical_sectors=0;
+ }
+ aff_buffer(BUFFER_ADD,"\n");
+ aff_buffer(BUFFER_ADD,"A valid NTFS Boot sector must be present in order to access\n");
+ aff_buffer(BUFFER_ADD,"any data; even if the partition is not bootable.\n");
+ if(opt_B!=0 && opt_O!=0)
+ {
+// options="DRMLU";
+ if(identical_sectors==0)
+ options="DOBRL";
+ else
+ options="DRML";
+ }
+ else if(opt_B!=0)
+ options="DBRL";
+ else if(opt_O!=0)
+ options="DORL";
+ else
+ options="DR";
+ rescan=0;
+ }
+ screen_buffer_to_log();
+ if(*current_cmd!=NULL)
+ {
+ command=0;
+ while(*current_cmd[0]==',')
+ (*current_cmd)++;
+ if(strncmp(*current_cmd,"rebuildbs",9)==0)
+ {
+ (*current_cmd)+=9;
+ command='R';
+ }
+ else if(strncmp(*current_cmd,"dump",4)==0)
+ {
+ (*current_cmd)+=4;
+ command='D';
+ }
+ else if(strncmp(*current_cmd,"list",4)==0)
+ {
+ (*current_cmd)+=4;
+ command='L';
+ }
+ else if(strncmp(*current_cmd,"originalntfs",11)==0)
+ {
+ (*current_cmd)+=11;
+ if(strchr(options,'O')!=NULL)
+ command='O';
+ }
+ else if(strncmp(*current_cmd,"backupntfs",9)==0)
+ {
+ (*current_cmd)+=9;
+ if(strchr(options,'B')!=NULL)
+ command='B';
+ }
+ else if(strncmp(*current_cmd,"repairmft",9)==0)
+ {
+ (*current_cmd)+=9;
+ if(strchr(options,'M')!=NULL)
+ command='M';
+ }
+ }
+ else
+ {
+ log_flush();
+#ifdef HAVE_NCURSES
+ command=screen_buffer_display(stdscr,options,menu_ntfs);
+#else
+ command=0;
+#endif
+ }
+ switch(command)
+ {
+ case 0:
+ free(buffer_bs);
+ free(buffer_backup_bs);
+ return 0;
+ case 'O': /* O : copy original boot sector over backup boot */
+ if(ask_confirmation("Copy original NTFS boot sector over backup boot, confirm ? (Y/N)")!=0)
+ {
+ log_info("copy original boot sector over backup boot\n");
+ if(disk_car->write(disk_car,NTFS_BOOT_SECTOR_SIZE, buffer_bs, partition->part_offset+partition->part_size-disk_car->sector_size)!=0)
+ {
+ display_message("Write error: Can't overwrite NTFS backup boot sector\n");
+ }
+ rescan=1;
+ }
+ break;
+ case 'B': /* B : copy backup boot sector over boot sector */
+ if(ask_confirmation("Copy backup NTFS boot sector over boot sector, confirm ? (Y/N)")!=0)
+ {
+ log_info("copy backup boot sector over boot sector\n");
+ if(disk_car->write(disk_car,NTFS_BOOT_SECTOR_SIZE, buffer_backup_bs, partition->part_offset)!=0)
+ {
+ display_message("Write error: Can't overwrite NTFS boot sector\n");
+ }
+ rescan=1;
+ }
+ break;
+ case 'L':
+ if(strchr(options,'O')==NULL && strchr(options,'B')!=NULL)
+ {
+ io_redir_add_redir(disk_car,partition->part_offset,NTFS_BOOT_SECTOR_SIZE,0,buffer_backup_bs);
+ dir_partition(disk_car, partition, 0,current_cmd);
+ io_redir_del_redir(disk_car,partition->part_offset);
+ }
+ else
+ dir_partition(disk_car, partition, 0,current_cmd);
+ break;
+ case 'M':
+ repair_MFT(disk_car, partition, verbose, current_cmd);
+ break;
+ case 'R': /* R : rebuild boot sector */
+ rebuild_NTFS_BS(disk_car,partition,verbose,dump_ind,1,expert,current_cmd);
+ rescan=1;
+ break;
+ case 'D':
+ dump_NTFS(disk_car, partition, buffer_bs, buffer_backup_bs);
+ break;
+#if 0
+#ifdef HAVE_LIBNTFS
+ case 'U':
+ ntfs_undelete_part(disk_car, partition, verbose);
+ break;
+#endif
+#endif
+ }
+ }
+}
+
+#ifdef HAVE_NCURSES
+static void hfs_dump_ncurses(disk_t *disk_car, const partition_t *partition, const unsigned char *buffer_bs, const unsigned char *buffer_backup_bs)
+{
+ WINDOW *window=newwin(0,0,0,0); /* full screen */
+ keypad(window, TRUE); /* Need it to get arrow key */
+ aff_copy(window);
+ wmove(window,4,0);
+ wdoprintf(window,"%s",disk_car->description(disk_car));
+ wmove(window,5,0);
+ aff_part(window,AFF_PART_ORDER,disk_car,partition);
+ mvwaddstr(window,6,0, "Superblock Backup superblock");
+ dump2(window, buffer_bs, buffer_backup_bs, HFSP_BOOT_SECTOR_SIZE);
+ delwin(window);
+ (void) clearok(stdscr, TRUE);
+#ifdef HAVE_TOUCHWIN
+ touchwin(stdscr);
+#endif
+}
+#endif
+
+static void hfs_dump(disk_t *disk_car, const partition_t *partition, const unsigned char *buffer_bs, const unsigned char *buffer_backup_bs)
+{
+ log_info("Superblock Backup superblock\n");
+ dump2_log(buffer_bs, buffer_backup_bs, HFSP_BOOT_SECTOR_SIZE);
+#ifdef HAVE_NCURSES
+ hfs_dump_ncurses(disk_car, partition, buffer_bs, buffer_backup_bs);
+#endif
+}
+
+int HFS_HFSP_boot_sector(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind, const unsigned int expert, char **current_cmd)
+{
+ unsigned char *buffer_bs;
+ unsigned char *buffer_backup_bs;
+ const char *options="";
+ int rescan=1;
+ struct MenuItem menu_hfsp[]=
+ {
+ { 'P', "Previous",""},
+ { 'N', "Next","" },
+ { 'Q', "Quit","Return to Advanced menu"},
+ { 'O', "Org. BS","Copy superblock over backup sector"},
+ { 'B', "Backup BS","Copy backup superblock over superblock"},
+ { 'D', "Dump","Dump superblock and backup superblock"},
+ { 0, NULL, NULL }
+ };
+ buffer_bs=(unsigned char*)MALLOC(HFSP_BOOT_SECTOR_SIZE);
+ buffer_backup_bs=(unsigned char*)MALLOC(HFSP_BOOT_SECTOR_SIZE);
+
+ while(1)
+ {
+ int command;
+ aff_buffer(BUFFER_RESET,"Q");
+ if(rescan==1)
+ {
+ int opt_over=0;
+ int opt_B=0;
+ int opt_O=0;
+ options="D";
+#ifdef HAVE_NCURSES
+ aff_copy(stdscr);
+ wmove(stdscr,4,0);
+ wdoprintf(stdscr,"%s",disk_car->description(disk_car));
+ mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG);
+ wmove(stdscr,6,0);
+ aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
+#endif
+ log_info("\nHFS_HFSP_boot_sector\n");
+ log_partition(disk_car,partition);
+ aff_buffer(BUFFER_ADD,"Superblock\n");
+ if(disk_car->read(disk_car,HFSP_BOOT_SECTOR_SIZE, buffer_bs, partition->part_offset+0x400)!=0)
+ {
+ aff_buffer(BUFFER_ADD,"Bad: can't read HFS/HFS+ superblock.\n");
+ memset(buffer_bs,0,HFSP_BOOT_SECTOR_SIZE);
+ }
+ else if(test_HFSP(disk_car,(const struct hfsp_vh*)buffer_bs,partition,verbose,0)==0)
+ {
+ aff_buffer(BUFFER_ADD,"HFS+ OK\n");
+ opt_O=1;
+ opt_over=1;
+ }
+ else if(test_HFS(disk_car,(const hfs_mdb_t*)buffer_bs,partition,verbose,0)==0)
+ {
+ aff_buffer(BUFFER_ADD,"HFS Ok\n");
+ opt_O=1;
+ opt_over=1;
+ }
+ else
+ aff_buffer(BUFFER_ADD,"Bad\n");
+ aff_buffer(BUFFER_ADD,"\nBackup superblock\n");
+ if(disk_car->read(disk_car,HFSP_BOOT_SECTOR_SIZE, buffer_backup_bs, partition->part_offset+partition->part_size-0x400)!=0)
+ {
+ aff_buffer(BUFFER_ADD,"Bad: can't read HFS/HFS+ backup superblock.\n");
+ memset(buffer_backup_bs,0,HFSP_BOOT_SECTOR_SIZE);
+ }
+ else if(test_HFSP(disk_car,(const struct hfsp_vh*)buffer_backup_bs,partition,verbose,0)==0)
+ {
+ aff_buffer(BUFFER_ADD,"HFS+ OK\n");
+ opt_B=1;
+ opt_over=1;
+ }
+ else if(test_HFS(disk_car,(const hfs_mdb_t*)buffer_backup_bs,partition,verbose,0)==0)
+ {
+ aff_buffer(BUFFER_ADD,"HFS Ok\n");
+ opt_B=1;
+ opt_over=1;
+ }
+ else
+ aff_buffer(BUFFER_ADD,"Bad\n");
+ aff_buffer(BUFFER_ADD,"\n");
+ if(memcmp(buffer_bs,buffer_backup_bs,HFSP_BOOT_SECTOR_SIZE)==0)
+ {
+ aff_buffer(BUFFER_ADD,"Sectors are identical.\n");
+ opt_over=0;
+ }
+ else
+ {
+ aff_buffer(BUFFER_ADD,"Sectors are not identical.\n");
+ }
+ if(opt_over!=0)
+ {
+ if(opt_B!=0 && opt_O!=0)
+ options="DOB";
+ else if(opt_B!=0)
+ options="DB";
+ else if(opt_O!=0)
+ options="DO";
+ }
+ rescan=0;
+ }
+ screen_buffer_to_log();
+ if(*current_cmd!=NULL)
+ {
+ command=0;
+ while(*current_cmd[0]==',')
+ (*current_cmd)++;
+ if(strncmp(*current_cmd,"dump",4)==0)
+ {
+ (*current_cmd)+=4;
+ command='D';
+ }
+ else if(strncmp(*current_cmd,"originalhfsp",11)==0)
+ {
+ (*current_cmd)+=11;
+ if(strchr(options,'O')!=NULL)
+ command='O';
+ }
+ else if(strncmp(*current_cmd,"backuphfsp",9)==0)
+ {
+ (*current_cmd)+=9;
+ if(strchr(options,'B')!=NULL)
+ command='B';
+ }
+ }
+ else
+ {
+ log_flush();
+#ifdef HAVE_NCURSES
+ command=screen_buffer_display(stdscr,options,menu_hfsp);
+#else
+ command=0;
+#endif
+ }
+ switch(command)
+ {
+ case 0:
+ free(buffer_bs);
+ free(buffer_backup_bs);
+ return 0;
+ case 'O': /* O : copy original superblock over backup boot */
+ if(ask_confirmation("Copy original HFS/HFS+ superblock over backup boot, confirm ? (Y/N)")!=0)
+ {
+ log_info("copy original superblock over backup boot\n");
+ if(disk_car->write(disk_car,HFSP_BOOT_SECTOR_SIZE, buffer_bs, partition->part_offset+partition->part_size-0x400)!=0)
+ {
+ display_message("Write error: Can't overwrite HFS/HFS+ backup superblock\n");
+ }
+ rescan=1;
+ }
+ break;
+ case 'B': /* B : copy backup superblock over main superblock */
+ if(ask_confirmation("Copy backup HFS/HFS+ superblock over main superblock, confirm ? (Y/N)")!=0)
+ {
+ log_info("copy backup superblock over main superblock\n");
+ if(disk_car->write(disk_car,HFSP_BOOT_SECTOR_SIZE, buffer_backup_bs, partition->part_offset+0x400)!=0)
+ {
+ display_message("Write error: Can't overwrite HFS/HFS+ main superblock\n");
+ }
+ rescan=1;
+ }
+ break;
+ case 'D':
+ hfs_dump(disk_car, partition, buffer_bs, buffer_backup_bs);
+ break;
+ }
+ }
+}
diff --git a/src/adv.h b/src/adv.h
new file mode 100644
index 0000000..6dcce33
--- /dev/null
+++ b/src/adv.h
@@ -0,0 +1,28 @@
+/*
+
+ File: intrface.h
+
+ Copyright (C) 1998-2004,2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+void interface_adv(disk_t *disk_car, const int verbose,const int dump_ind, const unsigned int expert, char**current_cmd);
+int fat1x_boot_sector(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind, const unsigned int expert, char **current_cmd);
+int fat32_boot_sector(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind, const unsigned int expert, char **current_cmd);
+int ntfs_boot_sector(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind, const unsigned int expert, char **current_cmd);
+int is_part_linux(const partition_t *partition);
+int HFS_HFSP_boot_sector(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind, const unsigned int expert, char **current_cmd);
+
diff --git a/src/analyse.c b/src/analyse.c
new file mode 100644
index 0000000..bd4c4b0
--- /dev/null
+++ b/src/analyse.c
@@ -0,0 +1,359 @@
+/*
+
+ File: analyse.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+//#include <assert.h>
+#include "types.h"
+#include "common.h"
+#include "fnctdsk.h"
+#include "analyse.h"
+#include "intrf.h"
+#include "intrfn.h"
+#include "savehdr.h"
+#include "lang.h"
+#include "bfs.h"
+#include "bsd.h"
+#include "cramfs.h"
+#include "ext2.h"
+#include "fat.h"
+#include "fatx.h"
+#include "hfs.h"
+#include "hfsp.h"
+#include "jfs_superblock.h"
+#include "jfs.h"
+#include "luks.h"
+#include "lvm.h"
+#include "md.h"
+#include "netware.h"
+#include "ntfs.h"
+#include "rfs.h"
+#include "sun.h"
+#include "swap.h"
+#include "sysv.h"
+#include "ufs.h"
+#include "xfs.h"
+#include "log.h"
+
+int search_NTFS_backup(unsigned char *buffer, disk_t *disk_car,partition_t *partition, const int verbose, const int dump_ind)
+{
+// assert(sizeof(struct ntfs_boot_sector)<=DEFAULT_SECTOR_SIZE);
+ if(disk_car->read(disk_car,DEFAULT_SECTOR_SIZE, buffer, partition->part_offset)!=0)
+ return -1;
+ /* NTFS recovery using backup sector */
+ if(recover_NTFS(disk_car,(const struct ntfs_boot_sector*)buffer,partition,verbose,dump_ind,1)==0)
+ return 1;
+ return 0;
+}
+
+int search_HFS_backup(unsigned char *buffer, disk_t *disk_car,partition_t *partition, const int verbose, const int dump_ind)
+{
+// assert(sizeof(hfs_mdb_t)<=0x400);
+// assert(sizeof(struct hfsp_vh)==0x200);
+ if(disk_car->read(disk_car,0x400, buffer, partition->part_offset)!=0)
+ return -1;
+ /* HFS recovery using backup sector */
+ if(recover_HFS(disk_car,(const hfs_mdb_t*)buffer,partition,verbose,dump_ind,1)==0)
+ {
+ strncpy(partition->info,"HFS found using backup sector!",sizeof(partition->info));
+ return 1;
+ }
+ if(recover_HFSP(disk_car,(const struct hfsp_vh*)buffer,partition,verbose,dump_ind,1)==0)
+ {
+ strncpy(partition->info,"HFS+ found using backup sector!",sizeof(partition->info));
+ return 1;
+ }
+ return 0;
+}
+
+int search_FAT_backup(unsigned char *buffer, disk_t *disk_car,partition_t *partition, const int verbose, const int dump_ind)
+{
+// assert(sizeof(struct fat_boot_sector)==DEFAULT_SECTOR_SIZE);
+ if(disk_car->read(disk_car,DEFAULT_SECTOR_SIZE, buffer, partition->part_offset)!=0)
+ return -1;
+ /* FAT32 recovery using backup sector */
+ if(recover_FAT(disk_car,(const struct fat_boot_sector*)buffer,partition,verbose,dump_ind,1)==0)
+ {
+ strncpy(partition->info,"FAT found using backup sector!",sizeof(partition->info));
+ return 1;
+ }
+ return 0;
+}
+
+int search_type_0(unsigned char *buffer,disk_t *disk_car,partition_t *partition, const int verbose, const int dump_ind)
+{
+// assert(sizeof(union swap_header)<=8*DEFAULT_SECTOR_SIZE);
+// assert(sizeof(pv_disk_t)<=8*DEFAULT_SECTOR_SIZE);
+// assert(sizeof(struct fat_boot_sector)<=8*DEFAULT_SECTOR_SIZE);
+// assert(sizeof(struct ntfs_boot_sector)<=8*DEFAULT_SECTOR_SIZE);
+// assert(sizeof(struct disk_netware)<=8*DEFAULT_SECTOR_SIZE);
+// assert(sizeof(struct xfs_sb)<=8*DEFAULT_SECTOR_SIZE);
+// assert(sizeof(struct disk_fatx)<=8*DEFAULT_SECTOR_SIZE);
+ if(verbose>2)
+ {
+ log_trace("search_type_0 lba=%lu\n",(long unsigned)(partition->part_offset/disk_car->sector_size));
+ }
+ if(disk_car->read(disk_car,8*DEFAULT_SECTOR_SIZE, buffer, partition->part_offset)!=0)
+ return -1;
+ if(recover_Linux_SWAP(disk_car,(const union swap_header *)buffer,partition,verbose,dump_ind)==0) return 1;
+ if(recover_LVM(disk_car,(const pv_disk_t*)buffer,partition,verbose,dump_ind)==0) return 1;
+ if(recover_FAT(disk_car,(const struct fat_boot_sector*)buffer,partition,verbose,dump_ind,0)==0) return 1;
+ if(recover_HPFS(disk_car,(const struct fat_boot_sector*)buffer,partition,verbose,dump_ind)==0) return 1;
+ if(recover_OS2MB(disk_car,(const struct fat_boot_sector*)buffer,partition,verbose,dump_ind)==0) return 1;
+ if(recover_NTFS(disk_car,(const struct ntfs_boot_sector*)buffer,partition,verbose,dump_ind,0)==0) return 1;
+ if(recover_netware(disk_car,(const struct disk_netware *)buffer,partition)==0) return 1;
+ if(recover_xfs(disk_car,(const struct xfs_sb*)buffer,partition,verbose,dump_ind)==0) return 1;
+ if(recover_FATX(disk_car,(const struct disk_fatx*)buffer,partition,verbose,dump_ind)==0) return 1;
+ if(recover_LUKS(disk_car,(const struct luks_phdr*)buffer,partition,verbose,dump_ind)==0) return 1;
+ { /* MD 1.1 */
+ const struct mdp_superblock_1 *sb1=(const struct mdp_superblock_1 *)buffer;
+ if(le32(sb1->major_version)==1 &&
+ recover_MD(disk_car,(const struct mdp_superblock_s*)buffer,partition,verbose,dump_ind)==0)
+ {
+ partition->part_offset-=le64(sb1->super_offset)*512;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int search_type_1(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind)
+{
+// assert(sizeof(struct disklabel)<=2*0x200);
+// assert(sizeof(struct disk_super_block)<=0x200);
+// assert(sizeof(struct cramfs_super)<=2*0x200);
+// assert(sizeof(struct sysv4_super_block)<=2*0x200);
+// assert(sizeof(sun_partition_i386)<=2*0x200);
+ if(verbose>2)
+ {
+ log_trace("search_type_1 lba=%lu\n",(long unsigned)(partition->part_offset/disk_car->sector_size));
+ }
+ if(disk_car->read(disk_car,8*DEFAULT_SECTOR_SIZE, buffer, partition->part_offset)!=0)
+ return -1;
+ if(recover_BSD(disk_car,(const struct disklabel *)(buffer+0x200),partition,verbose,dump_ind)==0) return 1;
+ if(recover_BeFS(disk_car,(const struct disk_super_block *)(buffer+0x200),partition,verbose,dump_ind)==0) return 1;
+ if(recover_cramfs(disk_car,(const struct cramfs_super*)(buffer+0x200),partition,verbose,dump_ind)==0) return 1;
+ if(recover_sysv(disk_car,(const struct sysv4_super_block*)(buffer+0x200),partition,verbose,dump_ind)==0) return 1;
+ if(recover_LVM2(disk_car,(const unsigned char*)(buffer+0x200),partition,verbose,dump_ind)==0) return 1;
+ if(recover_sun_i386(disk_car,(const sun_partition_i386*)(buffer+0x200),partition,verbose,dump_ind)==0) return 1;
+ return 0;
+}
+
+int search_type_2(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind)
+{
+// assert(sizeof(struct ext2_super_block)<=1024);
+// assert(sizeof(hfs_mdb_t)<=1024);
+// assert(sizeof(struct hfsp_vh)<=1024);
+ if(verbose>2)
+ {
+ log_trace("search_type_2 lba=%lu\n",(long unsigned)(partition->part_offset/disk_car->sector_size));
+ }
+ if(disk_car->read(disk_car,1024, (buffer+0x400), partition->part_offset+1024)!=0)
+ return -1;
+ if(recover_EXT2(disk_car,(const struct ext2_super_block*)(buffer+0x400),partition,verbose,dump_ind)==0) return 1;
+ if(recover_HFS(disk_car,(const hfs_mdb_t*)(buffer+0x400),partition,verbose,dump_ind,0)==0) return 1;
+ if(recover_HFSP(disk_car,(const struct hfsp_vh*)(buffer+0x400),partition,verbose,dump_ind,0)==0) return 1;
+ return 0;
+}
+
+int search_type_8(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind)
+{
+ if(verbose>2)
+ {
+ log_trace("search_type_8 lba=%lu\n",(long unsigned)(partition->part_offset/disk_car->sector_size));
+ }
+ if(disk_car->read(disk_car,4096, buffer, partition->part_offset+4096)!=0)
+ return -1;
+ { /* MD 1.2 */
+ const struct mdp_superblock_1 *sb1=(const struct mdp_superblock_1 *)buffer;
+ if(le32(sb1->major_version)==1 &&
+ recover_MD(disk_car,(const struct mdp_superblock_s*)buffer,partition,verbose,dump_ind)==0)
+ {
+ partition->part_offset-=(uint64_t)le64(sb1->super_offset)*512-4096;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int search_type_16(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind)
+{
+// assert(sizeof(struct ufs_super_block)<=3*DEFAULT_SECTOR_SIZE);
+ if(verbose>2)
+ {
+ log_trace("search_type_16 lba=%lu\n",(long unsigned)(partition->part_offset/disk_car->sector_size));
+ }
+ if(disk_car->read(disk_car,3*DEFAULT_SECTOR_SIZE, buffer, partition->part_offset+16*512)!=0) /* 8k offset */
+ return -1;
+ /* Test UFS */
+ if(recover_ufs(disk_car,(const struct ufs_super_block*)buffer,partition,verbose,dump_ind)==0) return 1;
+ return 0;
+}
+
+int search_type_64(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind)
+{
+// assert(sizeof(struct jfs_superblock)<=2*DEFAULT_SECTOR_SIZE);
+ if(verbose>2)
+ {
+ log_trace("search_type_64 lba=%lu\n",(long unsigned)(partition->part_offset/disk_car->sector_size));
+ }
+ /* Test JFS */
+#if 0
+ if(disk_car->read(disk_car,2*DEFAULT_SECTOR_SIZE, buffer, partition->part_offset+64*512)!=0) /* 32k offset */
+ return -1;
+ if(recover_JFS(disk_car,(const struct jfs_superblock*)buffer,partition,verbose,dump_ind)==0) return 1;
+#else
+ if(disk_car->read(disk_car,3*DEFAULT_SECTOR_SIZE, buffer, partition->part_offset+63*512)!=0) /* 32k offset */
+ return -1;
+ if(recover_JFS(disk_car,(const struct jfs_superblock*)(buffer+0x200),partition,verbose,dump_ind)==0) return 1;
+#endif
+ return 0;
+}
+
+int search_type_128(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind)
+{
+ /* Reiserfs4 need to read the master superblock and the format40 superblock => 4096 */
+// assert(sizeof(struct reiserfs_super_block)<=9*DEFAULT_SECTOR_SIZE);
+// assert(4096+sizeof(struct format40_super)<=9*DEFAULT_SECTOR_SIZE);
+// assert(sizeof(struct ufs_super_block)<=9*DEFAULT_SECTOR_SIZE);
+ if(verbose>2)
+ {
+ log_trace("search_type_128 lba=%lu\n",(long unsigned)(partition->part_offset/disk_car->sector_size));
+ }
+#if 0
+ /* Test ReiserFS */
+ if(disk_car->read(disk_car,9*DEFAULT_SECTOR_SIZE, buffer, partition->part_offset+128*512)!=0) /* 64k offset */
+ return -1;
+ if(recover_rfs(disk_car,(const struct reiserfs_super_block*)buffer,partition,verbose,dump_ind)==0) return 1;
+ /* Test UFS2 */
+ if(recover_ufs(disk_car,(const struct ufs_super_block*)buffer,partition,verbose,dump_ind)==0) return 1;
+#else
+ /* Test ReiserFS */
+ if(disk_car->read(disk_car,11*DEFAULT_SECTOR_SIZE, buffer, partition->part_offset+126*512)!=0) /* 64k offset */
+ return -1;
+ if(recover_rfs(disk_car,(const struct reiserfs_super_block*)(buffer+0x400),partition,verbose,dump_ind)==0) return 1;
+ /* Test UFS2 */
+ if(recover_ufs(disk_car,(const struct ufs_super_block*)(buffer+0x400),partition,verbose,dump_ind)==0) return 1;
+#endif
+ return 0;
+}
+
+list_part_t *search_superblock(disk_t *disk_car, const partition_t *partition, const int verbose, const int dump_ind, const int interface)
+{
+ unsigned char *buffer=MALLOC(2*0x200);
+ uint64_t hd_offset;
+ int nbr_sb=0;
+ list_part_t *list_part=NULL;
+ int ind_stop=0;
+ unsigned long int old_percent=0;
+ struct ext2_super_block *sb=(struct ext2_super_block *)buffer;
+ partition_t *new_partition=partition_new(disk_car->arch);
+ log_trace("search_superblock\n");
+#ifdef HAVE_NCURSES
+ if(interface>0)
+ {
+ aff_copy(stdscr);
+ wmove(stdscr,4,0);
+ wdoprintf(stdscr,"%s",disk_car->description(disk_car));
+ mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG);
+ wmove(stdscr,6,0);
+ aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
+ wmove(stdscr,22,0);
+ wattrset(stdscr, A_REVERSE);
+ waddstr(stdscr," Stop ");
+ wattroff(stdscr, A_REVERSE);
+ }
+#endif
+ for(hd_offset=0;hd_offset<partition->part_size && nbr_sb<10 && ind_stop==0;hd_offset+=DEFAULT_SECTOR_SIZE)
+ {
+#ifdef HAVE_NCURSES
+ unsigned long int percent;
+ percent=hd_offset*100/partition->part_size;
+ if(interface>0 && percent!=old_percent)
+ {
+ wmove(stdscr,9,0);
+ wclrtoeol(stdscr);
+ wdoprintf(stdscr,"Search EXT2/EXT3 superblock %10lu/%lu %lu%%", (long unsigned)(hd_offset/disk_car->sector_size),
+ (long unsigned)(partition->part_size/disk_car->sector_size),percent);
+ wrefresh(stdscr);
+ ind_stop|=check_enter_key_or_s(stdscr);
+ old_percent=percent;
+ }
+#endif
+ /* EXT2/EXT3 */
+ if( hd_offset==(EXT2_MIN_BLOCK_SIZE<<0) ||
+ hd_offset==(EXT2_MIN_BLOCK_SIZE<<1) ||
+ hd_offset==(EXT2_MIN_BLOCK_SIZE<<2) ||
+ hd_offset==(1*(EXT2_MIN_BLOCK_SIZE<<0)*8*(EXT2_MIN_BLOCK_SIZE<<0)+2*512) ||
+ hd_offset==(1*(EXT2_MIN_BLOCK_SIZE<<1)*8*(EXT2_MIN_BLOCK_SIZE<<1)) ||
+ hd_offset==(1*(EXT2_MIN_BLOCK_SIZE<<2)*8*(EXT2_MIN_BLOCK_SIZE<<2)) ||
+ hd_offset%(3*(EXT2_MIN_BLOCK_SIZE<<0)*8*(EXT2_MIN_BLOCK_SIZE<<0)+2*512)==0 ||
+ hd_offset%(5*(EXT2_MIN_BLOCK_SIZE<<0)*8*(EXT2_MIN_BLOCK_SIZE<<0)+2*512)==0 ||
+ hd_offset%(7*(EXT2_MIN_BLOCK_SIZE<<0)*8*(EXT2_MIN_BLOCK_SIZE<<0)+2*512)==0 ||
+ hd_offset%(3*(EXT2_MIN_BLOCK_SIZE<<1)*8*(EXT2_MIN_BLOCK_SIZE<<1))==0 ||
+ hd_offset%(5*(EXT2_MIN_BLOCK_SIZE<<1)*8*(EXT2_MIN_BLOCK_SIZE<<1))==0 ||
+ hd_offset%(7*(EXT2_MIN_BLOCK_SIZE<<1)*8*(EXT2_MIN_BLOCK_SIZE<<1))==0 ||
+ hd_offset%(3*(EXT2_MIN_BLOCK_SIZE<<2)*8*(EXT2_MIN_BLOCK_SIZE<<2))==0 ||
+ hd_offset%(5*(EXT2_MIN_BLOCK_SIZE<<2)*8*(EXT2_MIN_BLOCK_SIZE<<2))==0 ||
+ hd_offset%(7*(EXT2_MIN_BLOCK_SIZE<<2)*8*(EXT2_MIN_BLOCK_SIZE<<2))==0)
+ {
+ if(disk_car->read(disk_car,1024, buffer, partition->part_offset+hd_offset)==0)
+ {
+ if(le16(sb->s_magic)==EXT2_SUPER_MAGIC)
+ {
+ dup_partition_t(new_partition,partition);
+ new_partition->part_offset+=hd_offset;
+ if(recover_EXT2(disk_car,sb,new_partition,verbose,dump_ind)==0)
+ {
+ int insert_error=0;
+ if(hd_offset<=(EXT2_MIN_BLOCK_SIZE<<2))
+ new_partition->part_offset-=hd_offset;
+ log_info("Ext2 superblock found at sector %llu (block=%llu, blocksize=%u)\n",
+ (long long unsigned) hd_offset/DEFAULT_SECTOR_SIZE,
+ (long long unsigned) hd_offset>>(EXT2_MIN_BLOCK_LOG_SIZE+le32(sb->s_log_block_size)),
+ EXT2_MIN_BLOCK_SIZE<<le32(sb->s_log_block_size));
+#ifdef HAVE_NCURSES
+ wmove(stdscr,10+nbr_sb,0);
+ wdoprintf(stdscr,"Ext2 superblock found at sector %llu (block=%llu, blocksize=%u) \n",
+ (long long unsigned) hd_offset/DEFAULT_SECTOR_SIZE,
+ (long long unsigned) hd_offset>>(EXT2_MIN_BLOCK_LOG_SIZE+le32(sb->s_log_block_size)),
+ EXT2_MIN_BLOCK_SIZE<<le32(sb->s_log_block_size));
+#endif
+ list_part=insert_new_partition(list_part, new_partition, 1, &insert_error);
+ new_partition=partition_new(disk_car->arch);
+ nbr_sb++;
+ }
+ }
+ }
+ }
+ }
+ free(new_partition);
+ free(buffer);
+ return list_part;
+}
+
diff --git a/src/analyse.h b/src/analyse.h
new file mode 100644
index 0000000..3ed5e6e
--- /dev/null
+++ b/src/analyse.h
@@ -0,0 +1,33 @@
+/*
+
+ file: analyse.h
+
+ Copyright (C) 1998-2004 Christophe GRENIER <grenier@cgsecurity.org>
+
+ this software is free software; you can redistribute it and/or modify
+ it under the terms of the gnu general public license as published by
+ the free software foundation; either version 2 of the license, or
+ (at your option) any later version.
+
+ this program is distributed in the hope that it will be useful,
+ but without any warranty; without even the implied warranty of
+ merchantability or fitness for a particular purpose. see the
+ gnu general public license for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+int search_type_0(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind);
+int search_type_1(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind);
+int search_type_2(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind);
+int search_type_8(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind);
+int search_type_16(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind);
+int search_type_64(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind);
+int search_type_128(unsigned char *buffer, disk_t *disk_car,partition_t *partition,const int verbose, const int dump_ind);
+int search_FAT_backup(unsigned char *buffer, disk_t *disk_car,partition_t *partition, const int verbose, const int dump_ind);
+int search_HFS_backup(unsigned char *buffer, disk_t *disk_car,partition_t *partition, const int verbose, const int dump_ind);
+int search_NTFS_backup(unsigned char *buffer, disk_t *disk_car,partition_t *partition, const int verbose, const int dump_ind);
+list_part_t *search_superblock(disk_t *disk_car, const partition_t *partition, const int verbose, const int dump_ind, const int interface);
diff --git a/src/bfs.c b/src/bfs.c
new file mode 100644
index 0000000..4a5de95
--- /dev/null
+++ b/src/bfs.c
@@ -0,0 +1,90 @@
+/*
+
+ File: bfs.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "types.h"
+#include "common.h"
+#include "bfs.h"
+#include "fnctdsk.h"
+#include "log.h"
+
+static int set_BeFS_info(disk_t *disk_car, const struct disk_super_block *beos_block,partition_t *partition,const int verbose, const int dump_ind);
+static int test_BeFS(disk_t *disk_car, const struct disk_super_block*beos_block,partition_t *partition,const int verbose, const int dump_ind);
+
+int check_BeFS(disk_t *disk_car,partition_t *partition,const int verbose)
+{
+ unsigned char *buffer;
+ buffer=(unsigned char*)MALLOC(BFS_SUPERBLOCK_SIZE);
+ if(disk_car->read(disk_car,BFS_SUPERBLOCK_SIZE, buffer, partition->part_offset+0x200)!=0)
+ {
+ free(buffer);
+ return 1;
+ }
+ if(test_BeFS(disk_car,(struct disk_super_block*)buffer,partition,verbose,0)!=0)
+ {
+ free(buffer);
+ return 1;
+ }
+ set_BeFS_info(disk_car,(struct disk_super_block*)buffer,partition,verbose,0);
+ free(buffer);
+ return 0;
+}
+
+int recover_BeFS(disk_t *disk_car, const struct disk_super_block *beos_block,partition_t *partition,const int verbose, const int dump_ind)
+{
+ if(test_BeFS(disk_car,beos_block,partition,verbose,dump_ind)!=0)
+ return 1;
+ set_BeFS_info(disk_car,beos_block,partition,verbose,0);
+ partition->part_size=le64(beos_block->num_blocks) * (1<<le32(beos_block->block_shift));
+ partition->part_type_i386=(unsigned char)P_BEOS;
+ return 0;
+}
+
+static int test_BeFS(disk_t *disk_car, const struct disk_super_block*beos_block,partition_t *partition,const int verbose, const int dump_ind)
+{
+ if(beos_block->magic1==le32(SUPER_BLOCK_MAGIC1) &&
+ beos_block->magic2==(signed)le32(SUPER_BLOCK_MAGIC2) &&
+ beos_block->magic3==le32(SUPER_BLOCK_MAGIC3))
+ {
+ partition->upart_type=UP_BEOS;
+ if(dump_ind!=0)
+ {
+ log_info("\nBeFS magic value at %u/%u/%u\n", offset2cylinder(disk_car,partition->part_offset),offset2head(disk_car,partition->part_offset),offset2sector(disk_car,partition->part_offset));
+ dump_log(beos_block,DEFAULT_SECTOR_SIZE);
+ }
+ return 0;
+ }
+ return 1;
+}
+
+static int set_BeFS_info(disk_t *disk_car, const struct disk_super_block *beos_block,partition_t *partition,const int verbose, const int dump_ind)
+{
+ partition->info[0]='\0';
+ set_part_name(partition,beos_block->name,B_OS_NAME_LENGTH);
+ return 0;
+}
diff --git a/src/bfs.h b/src/bfs.h
new file mode 100644
index 0000000..8eb2f3f
--- /dev/null
+++ b/src/bfs.h
@@ -0,0 +1,83 @@
+/*
+
+ File: bfs.h
+
+ Copyright (C) 1998-2006 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+/* real size is 164 */
+#define BFS_SUPERBLOCK_SIZE 512
+
+typedef struct block_run
+{
+ int32_t allocation_group;
+ uint16_t start;
+ uint16_t len; /* in blocks */
+} block_run;
+
+typedef block_run inode_addr;
+
+
+#define B_OS_NAME_LENGTH 32
+
+typedef struct disk_super_block /* super block as it is on disk */
+{
+ char name[B_OS_NAME_LENGTH];
+ int32_t magic1; /* 0x20 */
+ int32_t fs_byte_order; /* 0x24 */
+
+ uint32_t block_size; /* 0x28 in bytes */
+ uint32_t block_shift; /* 0x2C block_size == (1 << block_shift) */
+
+ int64_t num_blocks; /* 0x30 */
+ int64_t used_blocks; /* 0x38 */
+
+ int32_t inode_size; /* 0x40 # of bytes per inode */
+
+ int32_t magic2; /* 0x44 */
+ int32_t blocks_per_ag; /* 0x48 in blocks */
+ int32_t ag_shift; /* 0x4C # of bits to shift to get ag num */
+ int32_t num_ags; /* 0x50 # of allocation groups */
+ int32_t flags; /* 0x54 if it's clean, etc */
+ block_run log_blocks; /* 0x58 a block_run of the log blocks */
+ int64_t log_start; /* 0x60 block # of the beginning */
+ int64_t log_end; /* 0x68 block # of the end of the log */
+
+ int32_t magic3; /* 0x70 */
+ inode_addr root_dir; /* 0x74 */
+ inode_addr indices; /* 0x7C */
+
+ int32_t pad[8]; /* 0x84 extra stuff for the future */
+ /* 0xA4-0xFF */
+} disk_super_block;
+
+
+/*the flags field can have these values */
+#define BFS_CLEAN 0x434c454e /* 'CLEN', for flags field */
+#define BFS_DIRTY 0x44495254 /* 'DIRT', for flags field */
+
+/* these are the magic numbers for the 3 magic fields */
+#define SUPER_BLOCK_MAGIC1 0x42465331 /* BFS1 */
+#define SUPER_BLOCK_MAGIC2 0xdd121031
+#define SUPER_BLOCK_MAGIC3 0x15b6830e
+
+/* this is stored in the fs_byte_order field... it's kind of dumb */
+#define BFS_BIG_ENDIAN 0x42494745 /* BIGE */
+/* int test_beos(struct disk_super_block *,partition_t); */
+int check_BeFS(disk_t *disk_car,partition_t *partition,const int verbose);
+int recover_BeFS(disk_t *disk_car, const struct disk_super_block *beos_block,partition_t *partition,const int verbose, const int dump_ind);
diff --git a/src/bsd.c b/src/bsd.c
new file mode 100644
index 0000000..bd8759a
--- /dev/null
+++ b/src/bsd.c
@@ -0,0 +1,185 @@
+/*
+
+ File: bsd.c
+
+ Copyright (C) 1998-2006 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "types.h"
+#include "common.h"
+#include "bsd.h"
+#include "intrf.h"
+#include "fnctdsk.h"
+#include "log.h"
+
+int check_BSD(disk_t *disk_car,partition_t *partition,const int verbose, const unsigned int max_partitions)
+{
+ unsigned char *buffer;
+ buffer=(unsigned char*)MALLOC(BSD_DISKLABEL_SIZE);
+ if(disk_car->read(disk_car,BSD_DISKLABEL_SIZE, buffer, partition->part_offset+0x200))
+ {
+ free(buffer);
+ return 1;
+ }
+ if(test_BSD(disk_car,(const struct disklabel*)buffer,partition,verbose,0,max_partitions))
+ {
+ free(buffer);
+ return 1;
+ }
+ set_part_name(partition,((const struct disklabel*)buffer)->d_packname,16);
+ if(check_volume_name(partition->fsname,16))
+ partition->fsname[0]='\0';
+ free(buffer);
+ return 0;
+}
+
+int test_BSD(disk_t *disk_car, const struct disklabel*bsd_header,partition_t *partition,const int verbose, const int dump_ind, const unsigned int max_partitions)
+{
+ if((le32(bsd_header->d_magic) == DISKMAGIC)&&
+ (le32(bsd_header->d_magic2)==DISKMAGIC))
+ {
+ unsigned int i;
+ const uint16_t* cp;
+ uint16_t crc;
+ if(verbose)
+ log_info("\nBSD offset %lu, nbr_part %u, CHS=(%u,%u,%u) ",
+ (long unsigned)(partition->part_offset/disk_car->sector_size),
+ (unsigned int)le16(bsd_header->d_npartitions),
+ (unsigned int)le32(bsd_header->d_ncylinders),
+ (unsigned int)le32(bsd_header->d_ntracks),
+ (unsigned int)le32(bsd_header->d_nsectors));
+ if(le16(bsd_header->d_npartitions) > max_partitions)
+ return 1;
+ crc=0;
+ for(cp=(const uint16_t*)bsd_header;
+ cp<(const uint16_t*)&bsd_header->d_partitions[le16(bsd_header->d_npartitions)];cp++)
+ crc^=*cp;
+ if(crc==0)
+ {
+ if(verbose>0)
+ {
+ log_info("CRC Ok\n");
+ }
+ }
+ else
+ log_error("Bad CRC! CRC must be xor'd by %04X\n",crc);
+ for(i=0;i<le16(bsd_header->d_npartitions);i++)
+ {
+ if(bsd_header->d_partitions[i].p_fstype>0)
+ {
+ if(verbose>0)
+ {
+ /* UFS UFS2 SWAP */
+ log_info("BSD %c: ", 'a'+i);
+ switch(bsd_header->d_partitions[i].p_fstype)
+ {
+ case TST_FS_SWAP:
+ log_info("swap");
+ break;
+ case TST_FS_BSDFFS:
+ log_info("4.2BSD fast filesystem");
+ break;
+ case TST_FS_BSDLFS:
+ log_info("4.4BSD log-structured filesystem");
+ break;
+ default:
+ log_info("type %02X", bsd_header->d_partitions[i].p_fstype);
+ break;
+ }
+ log_info(", offset %9u, size %9u ",
+ (unsigned int)le32(bsd_header->d_partitions[i].p_offset),
+ (unsigned int)le32(bsd_header->d_partitions[i].p_size));
+ log_CHS_from_LBA(disk_car,le32(bsd_header->d_partitions[i].p_offset));
+ log_info(" -> ");
+ log_CHS_from_LBA(disk_car,le32(bsd_header->d_partitions[i].p_offset)+le32(bsd_header->d_partitions[i].p_size)-1);
+ log_info("\n");
+ }
+ }
+ }
+ if(crc)
+ return 1;
+ if(max_partitions==BSD_MAXPARTITIONS)
+ partition->upart_type=UP_FREEBSD;
+ else
+ partition->upart_type=UP_OPENBSD;
+ if(dump_ind!=0)
+ {
+ dump_log(bsd_header,DEFAULT_SECTOR_SIZE);
+ }
+ return 0;
+ }
+ return 1;
+}
+
+int recover_BSD(disk_t *disk_car, const struct disklabel*bsd_header,partition_t *partition,const int verbose, const int dump_ind)
+{
+ int i;
+ int i_max_p_offset=-1;
+ if(test_BSD(disk_car,bsd_header,partition,verbose,dump_ind,BSD_MAXPARTITIONS)==0)
+ {
+ for(i=0;i<BSD_MAXPARTITIONS;i++)
+ {
+ if(bsd_header->d_partitions[i].p_fstype>0)
+ {
+ if(i_max_p_offset==-1 || le32(bsd_header->d_partitions[i].p_offset)>le32(bsd_header->d_partitions[i_max_p_offset].p_offset))
+ i_max_p_offset=i;
+ }
+ }
+ if(i_max_p_offset>=0)
+ partition->part_size=(uint64_t)(le32(bsd_header->d_partitions[i_max_p_offset].p_size) +
+ le32(bsd_header->d_partitions[i_max_p_offset].p_offset) - 1) * disk_car->sector_size - partition->part_offset;
+ else
+ partition->part_size=0;
+ partition->part_type_i386=P_FREEBSD;
+ set_part_name(partition,bsd_header->d_packname,16);
+ if(check_volume_name(partition->fsname,16))
+ partition->fsname[0]='\0';
+ partition->info[0]='\0';
+ return 0;
+ }
+ if(test_BSD(disk_car,bsd_header,partition,verbose,dump_ind,OPENBSD_MAXPARTITIONS)==0)
+ {
+ for(i=0;i<OPENBSD_MAXPARTITIONS;i++)
+ {
+ if(bsd_header->d_partitions[i].p_fstype>0)
+ {
+ if(i_max_p_offset==-1 || le32(bsd_header->d_partitions[i].p_offset)>le32(bsd_header->d_partitions[i_max_p_offset].p_offset))
+ i_max_p_offset=i;
+ }
+ }
+ if(i_max_p_offset>=0)
+ partition->part_size=(uint64_t)(le32(bsd_header->d_partitions[i_max_p_offset].p_size) +
+ le32(bsd_header->d_partitions[i_max_p_offset].p_offset) - 1) * disk_car->sector_size - partition->part_offset;
+ else
+ partition->part_size=0;
+ partition->part_type_i386=P_OPENBSD;
+ set_part_name(partition,bsd_header->d_packname,16);
+ if(check_volume_name(partition->fsname,16))
+ partition->fsname[0]='\0';
+ partition->info[0]='\0';
+ return 0;
+ }
+ return 1;
+}
diff --git a/src/bsd.h b/src/bsd.h
new file mode 100644
index 0000000..51f8e60
--- /dev/null
+++ b/src/bsd.h
@@ -0,0 +1,172 @@
+/*
+
+ File: bsd.h
+
+ Copyright (C) 1998-2004,2006 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+/* Come mainly from sys/disklabel.h and disktab.h */
+
+#ifndef _BSD_H
+#define _BSD_H
+/* BSD_DISKLABEL_SIZE is 276 */
+#define BSD_DISKLABEL_SIZE 512
+#define STANDALONE
+
+#define BBSIZE 8192 /* size of boot area, with label */
+
+#ifdef __i386__
+#define LABELSECTOR 1 /* sector containing label */
+#define LABELOFFSET 0 /* offset of label in sector */
+#endif
+
+#ifndef LABELSECTOR
+#define LABELSECTOR 0 /* sector containing label */
+#endif
+
+#ifndef LABELOFFSET
+#define LABELOFFSET 64 /* offset of label in sector */
+#endif
+
+#define DISKMAGIC ((uint32_t)0x82564557) /* The disk magic number */
+
+#define LABEL_PART 2 /* partition containing label */
+#define RAW_PART 2 /* partition containing whole disk */
+#define SWAP_PART 1 /* partition normally containing swap */
+
+struct disklabel {
+ uint32_t d_magic; /* the magic number */
+ uint16_t d_type; /* drive type */
+ uint16_t d_subtype; /* controller/d_type specific */
+ char d_typename[16]; /* type name, e.g. "eagle" */
+
+ /*
+ * d_packname contains the pack identifier and is returned when
+ * the disklabel is read off the disk or in-core copy.
+ * d_boot0 and d_boot1 are the (optional) names of the
+ * primary (block 0) and secondary (block 1-15) bootstraps
+ * as found in /usr/mdec. These are returned when using
+ * getdiskbyname(3) to retrieve the values from /etc/disktab.
+ */
+#if defined(KERNEL) || defined(STANDALONE)
+ char d_packname[16]; /* pack identifier */
+#else
+ union {
+ char un_d_packname[16]; /* pack identifier */
+ struct {
+ char *un_d_boot0; /* primary bootstrap name */
+ char *un_d_boot1; /* secondary bootstrap name */
+ } un_b;
+ } d_un;
+#define d_packname d_un.un_d_packname
+#define d_boot0 d_un.un_b.un_d_boot0
+#define d_boot1 d_un.un_b.un_d_boot1
+#endif /* ! KERNEL or STANDALONE */
+
+ /* disk geometry: */
+ uint32_t d_secsize; /* # of bytes per sector */
+ uint32_t d_nsectors; /* # of data sectors per track */
+ uint32_t d_ntracks; /* # of tracks per cylinder */
+ uint32_t d_ncylinders; /* # of data cylinders per unit */
+ uint32_t d_secpercyl; /* # of data sectors per cylinder */
+ uint32_t d_secperunit; /* # of data sectors per unit */
+
+ /*
+ * Spares (bad sector replacements) below are not counted in
+ * d_nsectors or d_secpercyl. Spare sectors are assumed to
+ * be physical sectors which occupy space at the end of each
+ * track and/or cylinder.
+ */
+ uint16_t d_sparespertrack; /* # of spare sectors per track */
+ uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
+ /*
+ * Alternate cylinders include maintenance, replacement, configuration
+ * description areas, etc.
+ */
+ uint32_t d_acylinders; /* # of alt. cylinders per unit */
+
+ /* hardware characteristics: */
+ /*
+ * d_interleave, d_trackskew and d_cylskew describe perturbations
+ * in the media format used to compensate for a slow controller.
+ * Interleave is physical sector interleave, set up by the
+ * formatter or controller when formatting. When interleaving is
+ * in use, logically adjacent sectors are not physically
+ * contiguous, but instead are separated by some number of
+ * sectors. It is specified as the ratio of physical sectors
+ * traversed per logical sector. Thus an interleave of 1:1
+ * implies contiguous layout, while 2:1 implies that logical
+ * sector 0 is separated by one sector from logical sector 1.
+ * d_trackskew is the offset of sector 0 on track N relative to
+ * sector 0 on track N-1 on the same cylinder. Finally, d_cylskew
+ * is the offset of sector 0 on cylinder N relative to sector 0
+ * on cylinder N-1.
+ */
+ uint16_t d_rpm; /* rotational speed */
+ uint16_t d_interleave; /* hardware sector interleave */
+ uint16_t d_trackskew; /* sector 0 skew, per track */
+ uint16_t d_cylskew; /* sector 0 skew, per cylinder */
+ uint32_t d_headswitch; /* head switch time, usec */
+ uint32_t d_trkseek; /* track-to-track seek, usec */
+ uint32_t d_flags; /* generic flags */
+#define NDDATA 5
+ uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
+#define NSPARE 5
+ uint32_t d_spare[NSPARE]; /* reserved for future use */
+ uint32_t d_magic2; /* the magic number (again) */
+ uint16_t d_checksum; /* xor of data incl. partitions */
+
+ /* filesystem and partition information: */
+ uint16_t d_npartitions; /* number of partitions in following */
+ uint32_t d_bbsize; /* size of boot area at sn0, bytes */
+ uint32_t d_sbsize; /* max size of fs superblock, bytes */
+ struct partition { /* the partition table */
+ uint32_t p_size; /* number of sectors in partition */
+ uint32_t p_offset; /* starting sector */
+ uint32_t p_fsize; /* filesystem basic fragment size */
+ uint8_t p_fstype; /* filesystem type, see below */
+ uint8_t p_frag; /* filesystem fragments per block */
+ union {
+ uint16_t cpg; /* UFS: FS cylinders per group */
+ uint16_t sgs; /* LFS: FS segment shift */
+ } __partition_u1;
+#define p_cpg __partition_u1.cpg
+#define p_sgs __partition_u1.sgs
+ } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
+};
+#define TST_FS_UNUSED 0 /* unused */
+#define TST_FS_SWAP 1 /* swap */
+#define TST_FS_V6 2 /* Sixth Edition */
+#define TST_FS_V7 3 /* Seventh Edition */
+#define TST_FS_SYSV 4 /* System V */
+#define TST_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
+#define TST_FS_V8 6 /* Eighth Edition, 4K blocks */
+#define TST_FS_BSDFFS 7 /* 4.2BSD fast filesystem */
+#define TST_FS_MSDOS 8 /* MSDOS filesystem */
+#define TST_FS_BSDLFS 9 /* 4.4BSD log-structured filesystem */
+#define TST_FS_OTHER 10 /* in use, but unknown/unsupported */
+#define TST_FS_HPFS 11 /* OS/2 high-performance filesystem */
+#define TST_FS_ISO9660 12 /* ISO 9660, normally CD-ROM */
+#define TST_FS_BOOT 13 /* partition contains bootstrap */
+#define TST_FS_VINUM 14 /* Vinum drive */
+#define TST_FS_RAID 15 /* RAIDFrame drive */
+#define TST_FS_JFS2 21 /* IBM JFS2 */
+int check_BSD(disk_t *disk_car,partition_t *partition,const int verbose,const unsigned int max_partitions);
+int test_BSD(disk_t *disk_car, const struct disklabel*bsd_header,partition_t *partition,const int verbose, const int dump_ind, const unsigned int max_partitions);
+int recover_BSD(disk_t *disk_car, const struct disklabel*bsd_header,partition_t *partition,const int verbose, const int dump_ind);
+
+#endif
diff --git a/src/chgtype.c b/src/chgtype.c
new file mode 100644
index 0000000..f8bba22
--- /dev/null
+++ b/src/chgtype.c
@@ -0,0 +1,156 @@
+/*
+
+ File: chgtype.c
+
+ Copyright (C) 1998-2005 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "lang.h"
+#include "intrf.h"
+#include "intrfn.h"
+#include "fnctdsk.h"
+#include "chgtype.h"
+#include "log.h"
+#include "guid_cmp.h"
+
+extern const arch_fnct_t arch_gpt;
+extern const arch_fnct_t arch_none;
+
+struct part_name_struct
+{
+ unsigned int index;
+ const char *name;
+};
+
+static void change_part_type_cli(const disk_t *disk_car,partition_t *partition, char **current_cmd)
+{
+ while(*current_cmd[0]==',')
+ (*current_cmd)++;
+ {
+ int tmp_val= strtol(*current_cmd, NULL, 16);
+ while(*current_cmd[0]!=',' && *current_cmd[0]!='\0')
+ (*current_cmd)++;
+ partition->arch->set_part_type(partition,tmp_val);
+ }
+}
+
+#ifdef HAVE_NCURSES
+static void change_part_type_ncurses(const disk_t *disk_car,partition_t *partition)
+{
+ partition_t *new_partition;
+ char response[100];
+ int size=0;
+ int i;
+ unsigned int last[3], done = 0, next = 0;
+ struct part_name_struct part_name[0x100];
+ struct MenuItem menuType[]=
+ {
+ { 'P', "Previous",""},
+ { 'N', "Next","" },
+ { 'Q', "Proceed","Go set the partition type"},
+ { 0, NULL, NULL }
+ };
+ /* Create an index of all partition type except Intel extended */
+ new_partition=partition_new(NULL);
+ dup_partition_t(new_partition,partition);
+ for(i=0;i<=0xFF;i++)
+ {
+ if(partition->arch->set_part_type(new_partition,i)==0)
+ {
+ part_name[size].name=new_partition->arch->get_partition_typename(new_partition);
+ if(part_name[size].name!=NULL)
+ part_name[size++].index=i;
+ }
+ }
+ free(new_partition);
+
+ /* Display the list of partition type in 3 columns */
+ aff_buffer(BUFFER_RESET,"Q");
+ aff_buffer(BUFFER_ADD,"List of partition type\n");
+ for (i = 2; i >= 0; i--)
+ last[2 - i] = done += (size + i - done) / (i + 1);
+ i = done = 0;
+ while (done < last[0])
+ {
+ aff_buffer(BUFFER_ADD, "%02x %-20s%c", part_name[next].index, part_name[next].name,(i==2 ? '\n' : ' '));
+ next = last[i++] + done;
+ if (i > 2 || next >= last[i]) {
+ i = 0;
+ next = ++done;
+ }
+ }
+
+ /* Ask for the new partition type*/
+ aff_copy(stdscr);
+ wmove(stdscr,4,0);
+ aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
+ screen_buffer_display(stdscr,"",menuType);
+ wmove(stdscr,23,0);
+ wdoprintf(stdscr,"New partition type [current %02x] ? ",partition->arch->get_part_type(partition));
+ if (get_string(response, sizeof(response), NULL) > 0) {
+ int tmp_val = strtol(response, NULL, 16);
+ partition->arch->set_part_type(partition,tmp_val);
+ }
+}
+#endif
+
+void change_part_type(const disk_t *disk_car,partition_t *partition, char **current_cmd)
+{
+ const arch_fnct_t *arch=partition->arch;
+ if(partition->arch==NULL)
+ {
+ log_error("change_part_type arch==NULL\n");
+ return;
+ }
+ if(partition->arch==&arch_gpt)
+ partition->arch=&arch_none;
+ if(partition->arch->set_part_type==NULL)
+ {
+ log_error("change_part_type set_part_type==NULL\n");
+ partition->arch=arch;
+ return;
+ }
+ if(*current_cmd!=NULL)
+ change_part_type_cli(disk_car, partition, current_cmd);
+ else
+ {
+#ifdef HAVE_NCURSES
+ change_part_type_ncurses(disk_car, partition);
+#endif
+ }
+ if(arch==&arch_gpt)
+ {
+ partition->arch=arch;
+ /* TODO: use upart_type to set part_type_gpt */
+ if(guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_UNUSED)==0)
+ partition->part_type_gpt=GPT_ENT_TYPE_MS_BASIC_DATA;
+ }
+ log_info("Change partition type:\n");
+ log_partition(disk_car,partition);
+}
diff --git a/src/chgtype.h b/src/chgtype.h
new file mode 100644
index 0000000..85cf2bd
--- /dev/null
+++ b/src/chgtype.h
@@ -0,0 +1,25 @@
+/*
+
+ File: chgtype.h
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+void change_geometry(disk_t *disk_car, char **current_cmd);
+void change_part_type(const disk_t *disk_car,partition_t *partition, char **current_cmd);
+
diff --git a/src/common.c b/src/common.c
new file mode 100644
index 0000000..8024cf7
--- /dev/null
+++ b/src/common.c
@@ -0,0 +1,314 @@
+/*
+
+ File: common.c
+
+ Copyright (C) 1998-2006 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdarg.h>
+#include "types.h"
+#include "common.h"
+#include "lang.h"
+#include <ctype.h> /* tolower */
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include "intrf.h"
+#include "log.h"
+
+static unsigned int up2power_aux(const unsigned int number);
+
+void *MALLOC(size_t size)
+{
+ void *res;
+ if(size<=0)
+ {
+ log_critical("Try to allocate 0 byte of memory\n");
+ exit(EXIT_FAILURE);
+ }
+#if defined(HAVE_POSIX_MEMALIGN)
+ if(size>=512)
+ {
+ /* Warning, memory leak checker must be posix_memalign aware, otherwise *
+ * reports may look strange. Aligned memory is required if the buffer is *
+ * used for read/write operation with a file opened with O_DIRECT */
+ if(posix_memalign(&res,4096,size)==0)
+ {
+ memset(res,0,size);
+ return res;
+ }
+ }
+#endif
+ if((res=malloc(size))==NULL)
+ {
+ log_critical("\nCan't allocate %lu bytes of memory.\n", (long unsigned)size);
+ exit(EXIT_FAILURE);
+ }
+ memset(res,0,size);
+ return res;
+}
+
+#ifndef HAVE_SNPRINTF
+int snprintf(char *str, size_t size, const char *format, ...)
+{
+ int res;
+ va_list ap;
+ va_start(ap,format);
+ res=vsnprintf(str, size, format, ap);
+ va_end(ap);
+ return res;
+}
+#endif
+
+#ifndef HAVE_VSNPRINTF
+int vsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+ return vsprintf(str,format,ap);
+}
+#endif
+
+#ifndef HAVE_STRNCASECMP
+/** Case-insensitive, size-constrained, lexical comparison.
+ *
+ * Compares a specified maximum number of characters of two strings for
+ * lexical equivalence in a case-insensitive manner.
+ *
+ * @param[in] s1 - The first string to be compared.
+ * @param[in] s2 - The second string to be compared.
+ * @param[in] len - The maximum number of characters to compare.
+ *
+ * @return Zero if at least @p len characters of @p s1 are the same as
+ * the corresponding characters in @p s2 within the ASCII printable
+ * range; a value less than zero if @p s1 is lexically less than
+ * @p s2; or a value greater than zero if @p s1 is lexically greater
+ * than @p s2.
+ *
+ * @internal
+ */
+int strncasecmp(const char * s1, const char * s2, size_t len)
+{
+ while (*s1 && (*s1 == *s2 || tolower(*s1) == tolower(*s2)))
+ {
+ len--;
+ if (len == 0)
+ return 0;
+ s1++;
+ s2++;
+ }
+ return (int)*(const unsigned char *)s1 - (int)*(const unsigned char *)s2;
+}
+#endif
+
+unsigned int up2power(const unsigned int number)
+{
+ /* log_trace("up2power(%u)=>%u\n",number, (1<<up2power_aux(number-1))); */
+ if(number==0)
+ return 1;
+ return (1<<up2power_aux(number-1));
+}
+
+static unsigned int up2power_aux(const unsigned int number)
+{
+ if(number==0)
+ return 0;
+ else
+ return(1+up2power_aux(number/2));
+}
+
+int check_volume_name(const char *name,const unsigned int max_size)
+{
+ unsigned int i;
+ for(i=0;name[i]!='\0' && i<max_size;i++)
+ {
+ if((name[i]>=0x6 && name[i]<=0x1f)||
+ (name[i]>=0x3A && name[i]<=0x3f))
+ return 1;
+ switch(name[i])
+ {
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x22:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+/* case 0x2E: Pas sur */
+ case 0x2F:
+ case 0x5B:
+ case 0x5C:
+ case 0x5D:
+ case 0x7C:
+/* case 'a' ... 'z': */
+ return 1;
+ }
+ }
+ return 0; /* Ok */
+}
+
+void set_part_name(partition_t *partition,const char *src,const int max_size)
+{
+ int i;
+ for(i=0;(i<max_size) && (src[i]!=(char)0);i++)
+ partition->fsname[i]=src[i];
+ partition->fsname[i--]='\0';
+}
+
+static inline unsigned char convert_char(unsigned char car)
+{
+#ifdef DJGPP
+ switch(car)
+ {
+ case ' ':
+ case '+':
+ case ',':
+ case '.':
+ case '=':
+ case '[':
+ case ']':
+ return '_';
+ }
+ /* 'a' */
+ if(car>=224 && car<=230)
+ return 'a';
+ /* 'c' */
+ if(car==231)
+ return 'c';
+ /* 'e' */
+ if(car>=232 && car<=235)
+ return 'e';
+ /* 'i' */
+ if(car>=236 && car<=239)
+ return 'n';
+ /* n */
+ if(car==241)
+ return 'n';
+ /* 'o' */
+ if((car>=242 && car<=246) || car==248)
+ return 'o';
+ /* 'u' */
+ if(car>=249 && car<=252)
+ return 'u';
+ /* 'y' */
+ if(car>=253)
+ return 'y';
+#endif
+ return car;
+}
+
+void filename_convert(char *dst, const char*src, const unsigned int n)
+{
+ unsigned int i;
+ for(i=0;i<n-1 && src[i]!='\0';i++)
+ dst[i]=convert_char(src[i]);
+ dst[i]='\0';
+#if defined(DJGPP) || defined(__CYGWIN__) || defined(__MINGW32__)
+ while(i>0 && (dst[i]==' '||dst[i]=='.'))
+ dst[i--]='\0';
+#endif
+}
+
+static inline unsigned char filter_char(unsigned char car)
+{
+ /* Chars allowed under msdos, a-z is stored as upercase by the OS itself */
+ if((car>='A' && car<='Z') || (car>='a' && car<='z')|| (car>='0' && car<='9'))
+ return car;
+ switch(car)
+ {
+ case '$':
+ case '%':
+ case '\'':
+ case '`':
+ case '-':
+ case '@':
+ case '{':
+ case '}':
+ case '~':
+ case '!':
+ case '#':
+ case '(':
+ case ')':
+ case '&':
+ case '_':
+ case '^':
+ case ' ':
+ case '+':
+ case ',':
+ case '.':
+ case '=':
+ case '[':
+ case ']':
+ return car;
+ }
+ if(car>=224)
+ return car;
+ return '_';
+}
+
+void filename_cpy(char *dst, const char*src, const unsigned int n)
+{
+ unsigned int i;
+ for(i=0;i<n-1 && src[i]!='\0';i++)
+ dst[i]=filter_char(src[i]);
+ dst[i]='\0';
+}
+
+void create_dir(const char *dir_name, const unsigned int is_dir_name)
+{
+ /* create all sub-directories */
+ char *pos;
+ char *path=strdup(dir_name);
+ if(path==NULL)
+ return;
+ pos=path+1;
+ do
+ {
+ strcpy(path,dir_name);
+ pos=strchr(pos+1,'/');
+ if(pos!=NULL)
+ *pos='\0';
+ if(pos!=NULL || is_dir_name!=0)
+ {
+#ifdef __CYGWIN__
+ if(memcmp(&path[1],":/cygdrive",10)!=0)
+#endif
+#ifdef HAVE_MKDIR
+#ifdef __MINGW32__
+ mkdir(path);
+#else
+ mkdir(path, 0775);
+#endif
+#else
+#error You need a mkdir function!
+#endif
+ }
+ } while(pos!=NULL);
+ free(path);
+}
diff --git a/src/common.h b/src/common.h
new file mode 100644
index 0000000..05969c0
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,426 @@
+/*
+
+ File: common.h
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifndef _COMMON_H
+#define _COMMON_H
+typedef struct efi_guid_s efi_guid_t;
+struct efi_guid_s
+{
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq_hi_and_reserved;
+ uint8_t clock_seq_low;
+ uint8_t node[6];
+} __attribute__ ((__packed__));
+
+#define DEFAULT_SECTOR_SIZE 0x200
+
+#define MAX_CYLINDERS 65535
+#define MAX_HEADS 255
+#define MAX_SECTORS 63
+
+#define DISKNAME_MAX 64
+#define DISKDESCRIPTION_MAX 128
+#define TAB_PART 0x1BE
+/* PARTITION TYPE */
+#define P_NO_OS 0x00
+#define P_12FAT 0x01
+#define P_16FAT 0x04
+#define P_EXTENDED 0x05
+#define P_16FATBD 0x06
+#define P_NTFS 0x07
+#define P_HPFS 0x07
+#define P_OS2MB 0x0A
+#define P_32FAT 0x0B
+#define P_32FAT_LBA 0x0C
+#define P_16FATBD_LBA 0x0E
+#define P_EXTENDX 0x0F
+#define P_12FATH 0x11
+#define P_16FATH 0x14
+#define P_16FATBDH 0x16
+#define P_NTFSH 0x17
+#define P_32FATH 0x1B
+#define P_32FAT_LBAH 0x1C
+#define P_16FATBD_LBAH 0x1E
+#define P_SYSV 0x63
+#define P_NETWARE 0x65
+#define P_OLDLINUX 0x81
+#define P_LINSWAP 0x82
+#define P_LINUX 0x83
+#define P_LINUXEXTENDX 0x85
+#define P_LVM 0x8E
+#define P_FREEBSD 0xA5
+#define P_OPENBSD 0xA6
+#define P_NETBSD 0xA9
+#define P_HFS 0xAF
+#define P_HFSP 0xAF
+#define P_SUN 0xBF
+#define P_BEOS 0xEB
+#define P_RAID 0xFD
+#define P_UNK 255
+#define NO_ORDER 255
+/* Partition SUN */
+#define PSUN_BOOT 1
+#define PSUN_ROOT 2
+#define PSUN_SWAP 3
+#define PSUN_USR 4
+#define PSUN_WHOLE_DISK 5
+#define PSUN_STAND 6
+#define PSUN_VAR 7
+#define PSUN_HOME 8
+#define PSUN_ALT 9
+#define PSUN_CACHEFS 10
+#define PSUN_LINSWAP P_LINSWAP
+#define PSUN_LINUX P_LINUX
+#define PSUN_LVM P_LVM
+#define PSUN_RAID P_RAID
+#define PSUN_UNK 255
+
+#define PMAC_DRIVER43 1
+#define PMAC_DRIVERATA 2
+#define PMAC_DRIVERIO 3
+#define PMAC_FREE 4
+#define PMAC_FWDRIVER 5
+#define PMAC_SWAP 0x82
+#define PMAC_LINUX 0x83
+#define PMAC_HFS 0xAF
+#define PMAC_MAP 6
+#define PMAC_PATCHES 7
+#define PMAC_UNK 8
+#define PMAC_NewWorld 9
+#define PMAC_DRIVER 10
+#define PMAC_MFS 11
+#define PMAC_PRODOS 12
+#define PMAC_FAT32 13
+
+#define PXBOX_UNK 0
+#define PXBOX_FATX 1
+
+#define GPT_ENT_TYPE_UNUSED \
+ ((efi_guid_t){le32(0x00000000),le16(0x0000),le16(0x0000),0x00,0x00,{0x00,0x00,0x00,0x00,0x00,0x00}})
+#define GPT_ENT_TYPE_EFI \
+ ((efi_guid_t){le32(0xc12a7328),le16(0xf81f),le16(0x11d2),0xba,0x4b,{0x00,0xa0,0xc9,0x3e,0xc9,0x3b}})
+#define GPT_ENT_TYPE_MBR \
+ ((efi_guid_t){le32(0x024dee41),le16(0x33e7),le16(0x11d3),0x9d,0x69,{0x00,0x08,0xc7,0x81,0xf3,0x9f}})
+#define GPT_ENT_TYPE_FREEBSD \
+ ((efi_guid_t){le32(0x516e7cb4),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}})
+#define GPT_ENT_TYPE_FREEBSD_SWAP \
+ ((efi_guid_t){le32(0x516e7cb5),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}})
+#define GPT_ENT_TYPE_FREEBSD_UFS \
+ ((efi_guid_t){le32(0x516e7cb6),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}})
+/*
+ * The following is unused but documented here to avoid reuse.
+ *
+ * GPT_ENT_TYPE_FREEBSD_UFS2 \
+ * ((efi_guid_t){le32(0x516e7cb7),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}})
+ */
+
+#define GPT_ENT_TYPE_FREEBSD_VINUM \
+ ((efi_guid_t){le32(0x516e7cb8),le16(0x6ecf),le16(0x11d6),0x8f,0xf8,{0x00,0x02,0x2d,0x09,0x71,0x2b}})
+
+
+#define GPT_ENT_TYPE_MS_RESERVED \
+ ((efi_guid_t){le32(0xe3c9e316),le16(0x0b5c),le16(0x4db8),0x81,0x7d,{0xf9,0x2d,0xf0,0x02,0x15,0xae}})
+#define GPT_ENT_TYPE_MS_BASIC_DATA \
+ ((efi_guid_t){le32(0xebd0a0a2),le16(0xb9e5),le16(0x4433),0x87,0xc0,{0x68,0xb6,0xb7,0x26,0x99,0xc7}})
+#define GPT_ENT_TYPE_MS_LDM_METADATA \
+ ((efi_guid_t){le32(0x5808c8aa),le16(0x7e8f),le16(0x42e0),0x85,0xd2,{0xe1,0xe9,0x04,0x34,0xcf,0xb3}})
+#define GPT_ENT_TYPE_MS_LDM_DATA \
+ ((efi_guid_t){le32(0xaf9b60a0),le16(0x1431),le16(0x4f62),0xbc,0x68,{0x33,0x11,0x71,0x4a,0x69,0xad}})
+
+#define GPT_ENT_TYPE_LINUX_DATA GPT_ENT_TYPE_MS_BASIC_DATA
+#define GPT_ENT_TYPE_LINUX_RAID \
+ ((efi_guid_t){le32(0xa19d880f),le16(0x05fc),le16(0x4d3b),0xa0,0x06,{0x74,0x3f,0x0f,0x84,0x91,0x1e}})
+#define GPT_ENT_TYPE_LINUX_SWAP \
+ ((efi_guid_t){le32(0x0657fd6d),le16(0xa4ab),le16(0x43c4),0x84,0xe5,{0x09,0x33,0xc8,0x4b,0x4f,0x4f}})
+#define GPT_ENT_TYPE_LINUX_LVM \
+ ((efi_guid_t){le32(0xe6d6d379),le16(0xf507),le16(0x44c2),0xa2,0x3c,{0x23,0x8f,0x2a,0x3d,0xf9,0x28}})
+#define GPT_ENT_TYPE_LINUX_RESERVED \
+ ((efi_guid_t){le32(0x8da63339),le16(0x0007),le16(0x60c0),0xc4,0x36,{0x08,0x3a,0xc8,0x23,0x09,0x08}})
+
+
+#define GPT_ENT_TYPE_HPUX_DATA \
+ ((efi_guid_t){le32(0x75894c1e),le16(0x3aeb),le16(0x11d3),0xb7,0xc1,{0x7b,0x03,0xa0,0x00,0x00,0x00}})
+#define GPT_ENT_TYPE_HPUX_SERVICE \
+ ((efi_guid_t){le32(0xe2a1e728),le16(0x32e3),le16(0x11d6),0xa6,0x82,{0x7b,0x03,0xa0,0x00,0x00,0x00}})
+
+#define GPT_ENT_TYPE_MAC_HFS \
+ ((efi_guid_t){le32(0x48465300),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}})
+#define GPT_ENT_TYPE_MAC_UFS \
+ ((efi_guid_t){le32(0x55465300),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}})
+#define GPT_ENT_TYPE_MAC_RAID \
+ ((efi_guid_t){le32(0x52414944),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}})
+#define GPT_ENT_TYPE_MAC_RAID_OFFLINE \
+ ((efi_guid_t){le32(0x52414944),le16(0x5f4f),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}})
+#define GPT_ENT_TYPE_MAC_BOOT \
+ ((efi_guid_t){le32(0x426f6f74),le16(0x0000),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}})
+#define GPT_ENT_TYPE_MAC_LABEL \
+ ((efi_guid_t){le32(0x4c616265),le16(0x6c00),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}})
+#define GPT_ENT_TYPE_MAC_TV_RECOVERY \
+ ((efi_guid_t){le32(0x5265636f),le16(0x7665),le16(0x11aa),0xaa,0x11,{0x00,0x30,0x65,0x43,0xec,0xac}})
+
+#define GPT_ENT_TYPE_SOLARIS_BOOT \
+ ((efi_guid_t){le32(0x6a82cb45),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+#define GPT_ENT_TYPE_SOLARIS_ROOT \
+ ((efi_guid_t){le32(0x6a85cf4d),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+#define GPT_ENT_TYPE_SOLARIS_SWAP \
+ ((efi_guid_t){le32(0x6a87c46f),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+#define GPT_ENT_TYPE_SOLARIS_BACKUP \
+ ((efi_guid_t){le32(0x6a8b642b),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+#define GPT_ENT_TYPE_SOLARIS_USR \
+ ((efi_guid_t){le32(0x6a898cc3),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+#define GPT_ENT_TYPE_SOLARIS_VAR \
+ ((efi_guid_t){le32(0x6a8ef2e9),le16(0x1dd2),le16(0x11b2),0x99,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+#define GPT_ENT_TYPE_SOLARIS_HOME \
+ ((efi_guid_t){le32(0x6a90ba39),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+#define GPT_ENT_TYPE_SOLARIS_EFI_ALTSCTR \
+ ((efi_guid_t){le32(0x6a9283a5),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+#define GPT_ENT_TYPE_SOLARIS_RESERVED1 \
+ ((efi_guid_t){le32(0x6a945a3b),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+#define GPT_ENT_TYPE_SOLARIS_RESERVED2 \
+ ((efi_guid_t){le32(0x6a9630d1),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+#define GPT_ENT_TYPE_SOLARIS_RESERVED3 \
+ ((efi_guid_t){le32(0x6a980767),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+#define GPT_ENT_TYPE_SOLARIS_RESERVED4 \
+ ((efi_guid_t){le32(0x6a96237f),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+#define GPT_ENT_TYPE_SOLARIS_RESERVED5 \
+ ((efi_guid_t){le32(0x6a8d2ac7),le16(0x1dd2),le16(0x11b2),0x96,0xa6,{0x08,0x00,0x20,0x73,0x66,0x31}})
+
+#define TESTDISK_O_RDONLY 00
+#define TESTDISK_O_RDWR 02
+#define TESTDISK_O_DIRECT 040000
+#define TESTDISK_O_READAHEAD_8K 04
+#define TESTDISK_O_READAHEAD_32K 010
+#define TESTDISK_O_ALL 020
+
+enum upart_type { UP_UNK, UP_BEOS, UP_CRAMFS, UP_EXT2, UP_EXT3, UP_EXTENDED, UP_FAT12, UP_FAT16, UP_FAT32, UP_FATX, UP_FREEBSD, UP_HFS, UP_HFSP, UP_HFSX, UP_HPFS, UP_JFS, UP_LINSWAP, UP_LINSWAP2, UP_LUKS, UP_LVM, UP_LVM2, UP_MD, UP_MD1, UP_NETWARE, UP_NTFS, UP_OPENBSD, UP_OS2MB, UP_RFS, UP_RFS2, UP_RFS3, UP_RFS4, UP_SUN, UP_SYSV4, UP_UFS, UP_UFS2, UP_XFS, UP_XFS2, UP_XFS3, UP_XFS4};
+typedef enum upart_type upart_type_t;
+enum status_type { STATUS_DELETED, STATUS_PRIM, STATUS_PRIM_BOOT, STATUS_LOG, STATUS_EXT, STATUS_EXT_IN_EXT};
+typedef enum status_type status_type_t;
+enum errcode_type {BAD_NOERR, BAD_SS, BAD_ES, BAD_SH, BAD_EH, BAD_EBS, BAD_RS, BAD_SC, BAD_EC, BAD_SCOUNT};
+typedef enum errcode_type errcode_type_t;
+enum aff_part_type {AFF_PART_NONL, AFF_PART_ORDER, AFF_PART_SHORT};
+typedef enum aff_part_type aff_part_type_t;
+
+typedef struct param_disk_struct disk_t;
+typedef struct partition_struct partition_t;
+typedef struct CHS_struct CHS_t;
+
+struct CHS_struct
+{
+ unsigned int cylinder;
+ unsigned int head;
+ unsigned int sector;
+};
+
+typedef struct list_part_struct list_part_t;
+struct list_part_struct
+{
+ partition_t *part;
+ list_part_t *prev;
+ list_part_t *next;
+ int to_be_removed;
+};
+
+typedef struct list_disk_struct list_disk_t;
+struct list_disk_struct
+{
+ disk_t *disk;
+ list_disk_t *prev;
+ list_disk_t *next;
+};
+
+struct systypes {
+ const unsigned int part_type;
+ const char *name;
+};
+
+struct arch_fnct_struct
+{
+ const char *part_name;
+ const char *part_name_option;
+ const char *msg_part_type;
+ list_part_t *(*read_part)(disk_t *disk_car, const int verbose,const int saveheader);
+ int (*write_part)(disk_t *disk_car, const list_part_t *list_part, const int ro, const int verbose, const int align);
+ list_part_t *(*init_part_order)(const disk_t *disk_car, list_part_t *list_part);
+ /* geometry must be initialized to 0,0,0 in get_geometry_from_mbr()*/
+ int (*get_geometry_from_mbr)(const unsigned char *buffer, const int verbose, CHS_t *geometry);
+ int (*check_part)(disk_t *disk_car,const int verbose,partition_t *partition, const int saveheader);
+ int (*write_MBR_code)(disk_t *disk_car);
+ list_part_t *(*add_partition)(disk_t *disk_car,list_part_t *list_part, const int verbose, char **current_cmd);
+ void (*set_prev_status)(const disk_t *disk_car, partition_t *partition);
+ void (*set_next_status)(const disk_t *disk_car, partition_t *partition);
+ int (*test_structure)(list_part_t *list_part);
+ unsigned int (*get_part_type)(const partition_t *partition);
+ int (*set_part_type)(partition_t *partition, unsigned int part_type);
+ void (*init_structure)(const disk_t *disk_car,list_part_t *list_part, const int verbose);
+ int (*erase_list_part)(disk_t *disk_car);
+ const char *(*get_partition_typename)(const partition_t *partition);
+ int (*is_part_known)(const partition_t *partition);
+};
+
+typedef struct arch_fnct_struct arch_fnct_t;
+
+struct param_disk_struct
+{
+ uint64_t disk_size;
+ CHS_t CHS; /* logical CHS */
+ int halt_on_errors;
+ int write_used;
+ int autodetect;
+ int access_mode;
+ unsigned int sector_size;
+ char *device;
+ char description_txt[DISKDESCRIPTION_MAX];
+ char description_short_txt[DISKDESCRIPTION_MAX];
+ const char *(*description)(disk_t *disk_car);
+ const char *(*description_short)(disk_t *disk_car);
+ int (*read)(disk_t *disk_car,const unsigned int nbr_sector, void *nom_buffer, const uint64_t offset);
+ int (*write)(disk_t *disk_car,const unsigned int nbr_sector, const void *nom_buffer, const uint64_t offset);
+ int (*clean)(disk_t *disk_car);
+ const arch_fnct_t *arch;
+ void *data;
+ uint64_t disk_real_size;
+};
+
+struct partition_struct
+{
+ uint64_t part_offset;
+ uint64_t part_size;
+ unsigned long int boot_sector;
+ unsigned long int blocksize;
+ unsigned int part_type_i386;
+ unsigned int part_type_sun;
+ unsigned int part_type_mac;
+ unsigned int part_type_xbox;
+ efi_guid_t part_type_gpt;
+ efi_guid_t part_uuid;
+ upart_type_t upart_type;
+ status_type_t status;
+ unsigned int order;
+ errcode_type_t errcode;
+ char fsname[80];
+ char partname[80];
+ char info[80];
+ const arch_fnct_t *arch;
+};
+
+typedef struct my_data_struct my_data_t;
+struct my_data_struct
+{
+ disk_t *disk_car;
+ const partition_t *partition;
+ uint64_t offset;
+};
+
+void dup_partition_t(partition_t *dest, const partition_t *src);
+int read_line(void);
+char read_char(const char *);
+void *MALLOC(size_t size);
+char read_key(void);
+char test_key(void);
+unsigned int up2power(const unsigned int number);
+void my_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
+int check_volume_name(const char *name,const unsigned int max_size);
+void set_part_name(partition_t *partition,const char *src,const int max_size);
+int rebuild_FAT_BS(disk_t *disk_car,partition_t *partition, const int verbose, const int dump_ind,const int interface, const unsigned int expert, char**current_cmd);
+#ifndef BSD_MAXPARTITIONS
+#define BSD_MAXPARTITIONS 8
+#endif
+#ifndef OPENBSD_MAXPARTITIONS
+#define OPENBSD_MAXPARTITIONS 16
+#endif
+
+#ifdef TESTDISK_LSB
+#define le16(x) (x) /* x as little endian */
+#define be16(x) ((((x)&0xff00)>>8) | \
+ (((x)&0x00ff)<<8))
+#define le24(x) (x)
+#define le32(x) (x)
+#define be32(x) ((((x)&0xff000000L)>>24) | \
+ (((x)&0x00ff0000L)>>8) | \
+ (((x)&0x0000ff00L)<<8) | \
+ (((x)&0x000000ffL)<<24))
+#define le64(x) (x)
+#define be64(x) ((((x)&0xff00000000000000LL)>>56) | \
+ (((x)&0x00ff000000000000LL)>>40) | \
+ (((x)&0x0000ff0000000000LL)>>24) | \
+ (((x)&0x000000ff00000000LL)>>8) | \
+ (((x)&0x00000000ff000000LL)<<8) | \
+ (((x)&0x0000000000ff0000LL)<<24) | \
+ (((x)&0x000000000000ff00LL)<<40) | \
+ (((x)&0x00000000000000ffLL)<<56))
+#else /* bigendian */
+#define le16(x) ((((x)&0xff00)>>8) | \
+ (((x)&0x00ff)<<8))
+#define be16(x) (x)
+#define be24(x) (x)
+#define le24(x) ((((x) & 0x000000ffUL) << 16) | \
+ ((x) & 0x0000ff00UL) | \
+ (((x) & 0x00ff0000UL) >> 16))
+#define le32(x) ((((x)&0xff000000L)>>24) | \
+ (((x)&0x00ff0000L)>>8) | \
+ (((x)&0x0000ff00L)<<8) | \
+ (((x)&0x000000ffL)<<24))
+#define be32(x) (x)
+#define le64(x) ((((x)&0xff00000000000000LL)>>56) | \
+ (((x)&0x00ff000000000000LL)>>40) | \
+ (((x)&0x0000ff0000000000LL)>>24) | \
+ (((x)&0x000000ff00000000LL)>>8) | \
+ (((x)&0x00000000ff000000LL)<<8) | \
+ (((x)&0x0000000000ff0000LL)<<24) | \
+ (((x)&0x000000000000ff00LL)<<40) | \
+ (((x)&0x00000000000000ffLL)<<56))
+#define be64(x) (x)
+#endif
+#ifndef HAVE_SNPRINTF
+int snprintf(char *str, size_t size, const char *format, ...);
+#endif
+#ifndef HAVE_VSNPRINTF
+#include <stdarg.h>
+int vsnprintf(char *str, size_t size, const char *format, va_list ap);
+#endif
+#ifndef HAVE_STRNCASECMP
+int strncasecmp(const char * s1, const char * s2, size_t len);
+#endif
+void create_dir(const char *dir_name, const unsigned int is_dir_name);
+void filename_convert(char *dst, const char*src, const unsigned int n);
+void filename_cpy(char *dst, const char*src, const unsigned int n);
+
+#ifdef DJGPP
+ #define TESTDISK_OS "Dos version"
+#elif defined(TARGET_BSD)
+ #define TESTDISK_OS "BSD version"
+#elif defined(TARGET_LINUX)
+ #define TESTDISK_OS "Linux version"
+#elif defined(TARGET_SOLARIS)
+ #define TESTDISK_OS "Solaris version"
+#elif defined(__CYGWIN__) || defined(__MINGW32__)
+ #define TESTDISK_OS "Windows version"
+#elif defined(__APPLE__)
+ #define TESTDISK_OS "Apple version"
+#elif defined(__OS2__)
+ #define TESTDISK_OS "OS2 version"
+#else
+ #define TESTDISK_OS "Undefined OS"
+#endif
+#endif
diff --git a/src/cramfs.c b/src/cramfs.c
new file mode 100644
index 0000000..3d486ba
--- /dev/null
+++ b/src/cramfs.c
@@ -0,0 +1,108 @@
+/*
+
+ File: cramfs.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "cramfs.h"
+#include "fnctdsk.h"
+#include "log.h"
+
+static int set_cramfs_info(const disk_t *disk_car, const struct cramfs_super *sb,partition_t *partition, const int verbose, const int dump_ind);
+static int test_cramfs(const disk_t *disk_car, const struct cramfs_super *sb,partition_t *partition,const int verbose, const int dump_ind);
+
+int check_cramfs(disk_t *disk_car,partition_t *partition,const int verbose)
+{
+ unsigned char *buffer=(unsigned char*)MALLOC(CRAMFS_SUPERBLOCK_SIZE);
+ if(disk_car->read(disk_car,CRAMFS_SUPERBLOCK_SIZE, buffer, partition->part_offset+0x200)!=0)
+ {
+ free(buffer);
+ return 1;
+ }
+ if(test_cramfs(disk_car,(struct cramfs_super*)buffer,partition,verbose,0)==0)
+ {
+ set_cramfs_info(disk_car,(struct cramfs_super*)buffer,partition,verbose,0);
+ free(buffer);
+ return 0;
+ }
+ free(buffer);
+ return 1;
+}
+
+static int test_cramfs(const disk_t *disk_car, const struct cramfs_super *sb,partition_t *partition,const int verbose, const int dump_ind)
+{
+ if (sb->magic==le32(CRAMFS_MAGIC))
+ {
+ partition->upart_type = UP_CRAMFS;
+ }
+ else
+ return 1;
+ if(verbose>0)
+ log_info("\ncramfs Marker at %u/%u/%u\n", offset2cylinder(disk_car,partition->part_offset),offset2head(disk_car,partition->part_offset),offset2sector(disk_car,partition->part_offset));
+ return 0;
+}
+
+int recover_cramfs(disk_t *disk_car, const struct cramfs_super *sb,partition_t *partition,const int verbose, const int dump_ind)
+{
+ if(test_cramfs(disk_car,sb,partition,verbose,dump_ind)!=0)
+ return 1;
+ if(verbose>0 || dump_ind!=0)
+ {
+ log_trace("\nrecover_cramfs\n");
+ if(dump_ind!=0)
+ {
+ dump_log(sb,DEFAULT_SECTOR_SIZE);
+ }
+ }
+ partition->part_size = sb->size;
+ partition->part_type_i386 = P_LINUX;
+ partition->part_type_mac= PMAC_LINUX;
+ partition->part_type_sun= PSUN_LINUX;
+ partition->part_type_gpt= GPT_ENT_TYPE_LINUX_DATA;
+ set_cramfs_info(disk_car,sb,partition,verbose,dump_ind);
+ return 0;
+}
+
+static int set_cramfs_info(const disk_t *disk_car,const struct cramfs_super *sb,partition_t *partition, const int verbose, const int dump_ind)
+{
+ set_part_name(partition,sb->name,16);
+ switch(partition->upart_type)
+ {
+ case UP_CRAMFS:
+ strncpy(partition->info,"cramfs",sizeof(partition->info));
+ break;
+ default:
+ partition->info[0]='\0';
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/cramfs.h b/src/cramfs.h
new file mode 100644
index 0000000..39a5326
--- /dev/null
+++ b/src/cramfs.h
@@ -0,0 +1,83 @@
+/*
+
+ File: cramfs.h
+
+ Copyright (C) 2004-2006 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+/* real size is 76 */
+#define CRAMFS_SUPERBLOCK_SIZE 512
+#define CRAMFS_MAGIC 0x28cd3d45 /* some random number */
+#define CRAMFS_SIGNATURE "Compressed ROMFS"
+
+struct cramfs_info {
+ uint32_t crc;
+ uint32_t edition;
+ uint32_t blocks;
+ uint32_t files;
+};
+
+/*
+ * Width of various bitfields in struct cramfs_inode.
+ * Primarily used to generate warnings in mkcramfs.
+ */
+#define CRAMFS_MODE_WIDTH 16
+#define CRAMFS_UID_WIDTH 16
+#define CRAMFS_SIZE_WIDTH 24
+#define CRAMFS_GID_WIDTH 8
+#define CRAMFS_NAMELEN_WIDTH 6
+#define CRAMFS_OFFSET_WIDTH 26
+
+/*
+ * Since inode.namelen is a unsigned 6-bit number, the maximum cramfs
+ * path length is 63 << 2 = 252.
+ */
+#define CRAMFS_MAXPATHLEN (((1 << CRAMFS_NAMELEN_WIDTH) - 1) << 2)
+
+/*
+ * Reasonably terse representation of the inode data.
+ */
+struct cramfs_inode {
+ uint32_t mode:CRAMFS_MODE_WIDTH, uid:CRAMFS_UID_WIDTH;
+ /* SIZE for device files is i_rdev */
+ uint32_t size:CRAMFS_SIZE_WIDTH, gid:CRAMFS_GID_WIDTH;
+ /* NAMELEN is the length of the file name, divided by 4 and
+ rounded up. (cramfs doesn't support hard links.) */
+ /* OFFSET: For symlinks and non-empty regular files, this
+ contains the offset (divided by 4) of the file data in
+ compressed form (starting with an array of block pointers;
+ see README). For non-empty directories it is the offset
+ (divided by 4) of the inode of the first file in that
+ directory. For anything else, offset is zero. */
+ uint32_t namelen:CRAMFS_NAMELEN_WIDTH, offset:CRAMFS_OFFSET_WIDTH;
+};
+
+
+struct cramfs_super {
+ uint32_t magic; /* 0x28cd3d45 - random number */
+ uint32_t size; /* length in bytes */
+ uint32_t flags; /* feature flags */
+ uint32_t future; /* reserved for future use */
+ uint8_t signature[16]; /* "Compressed ROMFS" */
+ struct cramfs_info fsid; /* unique filesystem info */
+ uint8_t name[16]; /* user-defined name */
+ struct cramfs_inode root; /* root inode data */
+};
+
+
+int check_cramfs(disk_t *disk_car,partition_t *partition,const int verbose);
+int recover_cramfs(disk_t *disk_car, const struct cramfs_super *sb,partition_t *partition,const int verbose, const int dump_ind);
diff --git a/src/crc.c b/src/crc.c
new file mode 100644
index 0000000..c005103
--- /dev/null
+++ b/src/crc.c
@@ -0,0 +1,128 @@
+/*
+
+ File: crc.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+ Copyright (C) 1986 Gary S. Brown for the crc32 table.
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "crc.h"
+
+/* crc32_tab=make_crc32_table(0xEDB88320); */
+static const uint32_t crc32_tab[] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+
+unsigned int get_crc32(const void*buf, const unsigned int len, const uint32_t seed)
+{
+ unsigned int i;
+ register uint32_t crc32val;
+ const unsigned char *s=buf;
+ crc32val = seed;
+ for (i = 0; i < len; i ++)
+ {
+ crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
+ }
+ return crc32val;
+}
+
+#if 0
+uint32_t* make_crc32_table(uint32_t poly)
+{
+ unsigned i,j;
+ uint32_t *crctable = MALLOC(256*sizeof(uint32_t));
+ for (i=0;i<256;i++)
+ {
+ uint32_t r=i;
+ for (j=8;j>0;j--)
+ r=((r&1)?(r>>1)^poly:(r>>1));
+ crctable[i] = r;
+ }
+ return crctable;
+}
+
+unsigned int get_crc32_gen(const void *buf, const unsigned int len, const uint32_t seed, const uint32_t *crctab)
+{
+ unsigned int i;
+ register uint32_t crc32val;
+ const unsigned char *s=buf;
+ crc32val = seed;
+ for (i = 0; i < len; i ++)
+ {
+ crc32val = crctab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
+ }
+ return crc32val;
+}
+#endif
diff --git a/src/crc.h b/src/crc.h
new file mode 100644
index 0000000..700f896
--- /dev/null
+++ b/src/crc.h
@@ -0,0 +1,35 @@
+/*
+
+ File: crc.h
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "types.h"
+#include "common.h"
+
+#if 0
+uint32_t* make_crc32_table(uint32_t poly);
+unsigned int get_crc32_gen(const unsigned char *s, const unsigned int len, const uint32_t seed, const uint32_t *crctab);
+#endif
+unsigned int get_crc32(const void *s, const unsigned int len, const uint32_t seed);
+
diff --git a/src/dir.c b/src/dir.c
new file mode 100644
index 0000000..166f78c
--- /dev/null
+++ b/src/dir.c
@@ -0,0 +1,618 @@
+/*
+
+ File: dir.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include "types.h"
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#endif
+#include "common.h"
+#include "fat.h"
+#include "lang.h"
+#include "fnctdsk.h"
+#include "testdisk.h"
+#include "intrf.h"
+#ifdef HAVE_NCURSES
+#include "intrfn.h"
+#else
+#include <stdio.h>
+#endif
+#include "dir.h"
+#include "ext2_dir.h"
+#include "fat_dir.h"
+#include "ntfs_dir.h"
+#include "rfs_dir.h"
+#include "log.h"
+
+const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+static int dir_partition_aux(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int inode, const int first_time, char **current_cmd);
+static int copy_dir(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_data_t *dir);
+static char ftypelet (unsigned int bits);
+#ifdef HAVE_NCURSES
+static long int dir_aff_ncurses(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_data_t*dir_list, const unsigned long int inode, const int first_time);
+#endif
+
+static char ftypelet (unsigned int bits)
+{
+#ifdef LINUX_S_ISBLK
+ if (LINUX_S_ISBLK (bits))
+ return 'b';
+#endif
+ if (LINUX_S_ISCHR (bits))
+ return 'c';
+ if (LINUX_S_ISDIR (bits))
+ return 'd';
+ if (LINUX_S_ISREG (bits))
+ return '-';
+#ifdef LINUX_S_ISFIFO
+ if (LINUX_S_ISFIFO (bits))
+ return 'p';
+#endif
+#ifdef LINUX_S_ISLNK
+ if (LINUX_S_ISLNK (bits))
+ return 'l';
+#endif
+#ifdef LINUX_S_ISSOCK
+ if (LINUX_S_ISSOCK (bits))
+ return 's';
+#endif
+#ifdef LINUX_S_ISMPC
+ if (LINUX_S_ISMPC (bits))
+ return 'm';
+#endif
+#ifdef LINUX_S_ISNWK
+ if (LINUX_S_ISNWK (bits))
+ return 'n';
+#endif
+#ifdef LINUX_S_ISDOOR
+ if (LINUX_S_ISDOOR (bits))
+ return 'D';
+#endif
+#ifdef LINUX_S_ISCTG
+ if (LINUX_S_ISCTG (bits))
+ return 'C';
+#endif
+#ifdef LINUX_S_ISOFD
+ if (LINUX_S_ISOFD (bits))
+ /* off line, with data */
+ return 'M';
+#endif
+#ifdef LINUX_S_ISOFL
+ /* off line, with no data */
+ if (LINUX_S_ISOFL (bits))
+ return 'M';
+#endif
+ return '?';
+}
+
+void mode_string (const unsigned int mode, char *str)
+{
+ str[0] = ftypelet(mode);
+ str[1] = mode & LINUX_S_IRUSR ? 'r' : '-';
+ str[2] = mode & LINUX_S_IWUSR ? 'w' : '-';
+ str[3] = mode & LINUX_S_IXUSR ? 'x' : '-';
+ str[4] = mode & LINUX_S_IRGRP ? 'r' : '-';
+ str[5] = mode & LINUX_S_IWGRP ? 'w' : '-';
+ str[6] = mode & LINUX_S_IXGRP ? 'x' : '-';
+ str[7] = mode & LINUX_S_IROTH ? 'r' : '-';
+ str[8] = mode & LINUX_S_IWOTH ? 'w' : '-';
+ str[9] = mode & LINUX_S_IXOTH ? 'x' : '-';
+ str[10]='\0';
+#ifdef LINUX_S_ISUID
+ if (mode & LINUX_S_ISUID)
+ {
+ if (str[3] != 'x')
+ /* Set-uid, but not executable by owner. */
+ str[3] = 'S';
+ else
+ str[3] = 's';
+ }
+#endif
+#ifdef LINUX_S_ISGID
+ if (mode & LINUX_S_ISGID)
+ {
+ if (str[6] != 'x')
+ /* Set-gid, but not executable by group. */
+ str[6] = 'S';
+ else
+ str[6] = 's';
+ }
+#endif
+#ifdef LINUX_S_ISVTX
+ if (mode & LINUX_S_ISVTX)
+ {
+ if (str[9] != 'x')
+ /* Sticky, but not executable by others. */
+ str[9] = 'T';
+ else
+ str[9] = 't';
+ }
+#endif
+}
+
+int dir_aff_log(const disk_t *disk_car, const partition_t *partition, const dir_data_t *dir_data, const file_data_t*dir_list)
+{
+ int test_date=0;
+ const file_data_t *current_file;
+ log_partition(disk_car,partition);
+ if(dir_data!=NULL)
+ {
+ log_info("Directory %s\n",dir_data->current_directory);
+ }
+ for(current_file=dir_list;current_file!=NULL;current_file=current_file->next)
+ {
+ struct tm *tm_p;
+ char datestr[80];
+ char str[11];
+ if(current_file->filestat.st_mtime)
+ {
+ tm_p = localtime(&current_file->filestat.st_mtime);
+
+ snprintf(datestr, sizeof(datestr),"%2d-%s-%4d %02d:%02d",
+ tm_p->tm_mday, monstr[tm_p->tm_mon],
+ 1900 + tm_p->tm_year, tm_p->tm_hour,
+ tm_p->tm_min);
+ /* FIXME: a check using current_file->name will be better */
+ if(1900+tm_p->tm_year>=2000 && 1900+tm_p->tm_year<=2010)
+ {
+ test_date=1;
+ }
+ } else {
+ strncpy(datestr, " ",sizeof(datestr));
+ }
+ mode_string(current_file->filestat.st_mode,str);
+ log_info("%7lu ",(unsigned long int)current_file->filestat.st_ino);
+ log_info("%s %5u %5u ",
+ str, (unsigned int)current_file->filestat.st_uid, (unsigned int)current_file->filestat.st_gid);
+ log_info("%7llu", (long long unsigned int)current_file->filestat.st_size);
+ log_info(" %s %s\n", datestr, current_file->name);
+ }
+ return test_date;
+}
+
+#ifdef HAVE_NCURSES
+static long int dir_aff_ncurses(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_data_t*dir_list, const unsigned long int inode, const int first_time)
+{
+ /* Return value
+ * -1: quit
+ * 1: back
+ * other: new inode
+ * */
+ int quit=0;
+ int offset=0;
+ int pos_num=0;
+ const file_data_t *current_file;
+ const file_data_t *pos=dir_list;
+ WINDOW *window=(WINDOW*)dir_data->display;
+ aff_copy(window);
+ wmove(window,4,0);
+ aff_part(window,AFF_PART_ORDER,disk_car,partition);
+ mvwaddstr(window,5,0,"Use ");
+ if(first_time==0)
+ {
+ if(has_colors())
+ wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
+ waddstr(window, "Left");
+ if(has_colors())
+ wbkgdset(window,' ' | COLOR_PAIR(0));
+ waddstr(window," arrow to go back, ");
+ }
+ if(has_colors())
+ wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
+ waddstr(window,"Right");
+ if(has_colors())
+ wbkgdset(window,' ' | COLOR_PAIR(0));
+ waddstr(window," arrow to change directory, ");
+ if(dir_data->copy_file!=NULL)
+ {
+ if(has_colors())
+ wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
+ waddstr(window,"c");
+ if(has_colors())
+ wbkgdset(window,' ' | COLOR_PAIR(0));
+ waddstr(window," to copy, ");
+ }
+ if(has_colors())
+ wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(0));
+ waddstr(window,"q");
+ if(has_colors())
+ wbkgdset(window,' ' | COLOR_PAIR(0));
+ waddstr(window," to quit");
+ wmove(window,6,0);
+ wdoprintf(window,"Directory %s\n",dir_data->current_directory);
+ do
+ {
+ int i;
+ int car;
+ for(i=0,current_file=dir_list;(current_file!=NULL) && (i<offset);current_file=current_file->next,i++);
+ for(i=offset;(current_file!=NULL) &&((i-offset)<INTER_DIR);i++,current_file=current_file->next)
+ {
+ struct tm *tm_p;
+ char str[11];
+ char datestr[80];
+ wmove(window, 8+i-offset, 0);
+ wclrtoeol(window); /* before addstr for BSD compatibility */
+ if(current_file==pos)
+ wattrset(window, A_REVERSE);
+ if(current_file->filestat.st_mtime!=0)
+ {
+ tm_p = localtime(&current_file->filestat.st_mtime);
+ snprintf(datestr, sizeof(datestr),"%2d-%s-%4d %02d:%02d",
+ tm_p->tm_mday, monstr[tm_p->tm_mon],
+ 1900 + tm_p->tm_year, tm_p->tm_hour,
+ tm_p->tm_min);
+ /* May have to use %d instead of %e */
+ } else {
+ strncpy(datestr, " ",sizeof(datestr));
+ }
+ mode_string(current_file->filestat.st_mode,str);
+ wdoprintf(window, "%s %5u %5u ",
+ str, (unsigned int)current_file->filestat.st_uid, (unsigned int)current_file->filestat.st_gid);
+ wdoprintf(window, "%7llu", (long long unsigned int)current_file->filestat.st_size);
+ /* screen may overlap due to long filename */
+ wdoprintf(window, " %s %s", datestr, current_file->name);
+ if(current_file==pos)
+ wattroff(window, A_REVERSE);
+ }
+ wmove(window, 8-1, 51);
+ wclrtoeol(window);
+ if(offset>0)
+ wdoprintf(window, "Previous");
+ /* Clear the last line, useful if overlapping */
+ wmove(window,8+i-offset,0);
+ wclrtoeol(window);
+ wmove(window, 8+INTER_DIR, 51);
+ wclrtoeol(window);
+ if(current_file!=NULL)
+ wdoprintf(window, "Next");
+ if(dir_list==NULL)
+ {
+ wmove(window,8,0);
+ wdoprintf(window,"No file found, filesystem seems damaged.");
+ }
+ wrefresh(window);
+ /* Using gnome terminal under FC3, TERM=xterm, the screen is not always correct */
+ wredrawln(window,0,getmaxy(window)); /* redrawwin def is boggus in pdcur24 */
+ car=wgetch(window);
+ wmove(window,7,0);
+ wclrtoeol(window);
+ switch(car)
+ {
+ case key_ESC:
+ case 'q':
+ case 'M':
+ quit=1;
+ break;
+ case '-':
+ case KEY_LEFT:
+ if(first_time==0)
+ return 1;
+ break;
+ }
+ if(dir_list!=NULL)
+ {
+ switch(car)
+ {
+ case KEY_UP:
+ if(pos->prev!=NULL)
+ {
+ pos=pos->prev;
+ pos_num--;
+ }
+ if(pos_num<offset)
+ offset--;
+ break;
+ case KEY_DOWN:
+ if(pos->next!=NULL)
+ {
+ pos=pos->next;
+ pos_num++;
+ }
+ if(pos_num>=offset+INTER_DIR)
+ offset++;
+ break;
+ case 'p':
+ case 'P':
+ case '+':
+ case ' ':
+ case KEY_RIGHT:
+ case '\r':
+ case '\n':
+
+ case KEY_ENTER:
+#ifdef PADENTER
+ case PADENTER:
+#endif
+ if((pos!=NULL) && (LINUX_S_ISDIR(pos->filestat.st_mode)!=0))
+ {
+ unsigned long int new_inode=pos->filestat.st_ino;
+ if((new_inode!=inode) &&(strcmp(pos->name,".")!=0))
+ {
+ if(strcmp(pos->name,"..")==0)
+ return 1;
+ if(strlen(dir_data->current_directory)+1+strlen(pos->name)+1<=sizeof(dir_data->current_directory))
+ {
+ if(strcmp(dir_data->current_directory,"/"))
+ strcat(dir_data->current_directory,"/");
+ strcat(dir_data->current_directory,pos->name);
+ return (long int)new_inode;
+ }
+ }
+ }
+ break;
+ case KEY_PPAGE:
+ for(i=0;(i<INTER_DIR-1)&&(pos->prev!=NULL);i++)
+ {
+ pos=pos->prev;
+ pos_num--;
+ if(pos_num<offset)
+ offset--;
+ }
+ break;
+ case KEY_NPAGE:
+ for(i=0;(i<INTER_DIR-1)&&(pos->next!=NULL);i++)
+ {
+ pos=pos->next;
+ pos_num++;
+ if(pos_num>=offset+INTER_DIR)
+ offset++;
+ }
+ break;
+ case 'c':
+ if(dir_data->copy_file!=NULL)
+ {
+ unsigned int current_directory_namelength=strlen(dir_data->current_directory);
+ if(strcmp(pos->name,"..")!=0 &&
+ current_directory_namelength+1+strlen(pos->name)<sizeof(dir_data->current_directory)-1)
+ {
+ if(strcmp(dir_data->current_directory,"/"))
+ strcat(dir_data->current_directory,"/");
+ if(strcmp(pos->name,".")!=0)
+ strcat(dir_data->current_directory,pos->name);
+ if(dir_data->local_dir==NULL)
+ {
+ char *res;
+ if(LINUX_S_ISDIR(pos->filestat.st_mode)!=0)
+ res=ask_location("Are you sure you want to copy %s and any files below to the directory %s ? [Y/N]",dir_data->current_directory);
+ else
+ res=ask_location("Are you sure you want to copy %s to the directory %s ? [Y/N]",dir_data->current_directory);
+ // free(dir_data->local_dir);
+ dir_data->local_dir=res;
+ }
+ if(dir_data->local_dir!=NULL)
+ {
+ int res=-1;
+ wmove(window,7,0);
+ wclrtoeol(window);
+ if(has_colors())
+ wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(1));
+ wdoprintf(window,"Copying, please wait...");
+ if(has_colors())
+ wbkgdset(window,' ' | COLOR_PAIR(0));
+ wrefresh(window);
+ if(LINUX_S_ISDIR(pos->filestat.st_mode)!=0)
+ {
+ res=copy_dir(disk_car, partition, dir_data, pos);
+ }
+ else if(LINUX_S_ISREG(pos->filestat.st_mode)!=0)
+ {
+ res=dir_data->copy_file(disk_car, partition, dir_data, pos);
+ }
+ wmove(window,7,0);
+ wclrtoeol(window);
+ if(res < -1)
+ {
+ if(has_colors())
+ wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(1));
+ wdoprintf(window,"Copy failed!");
+ }
+ else
+ {
+ if(has_colors())
+ wbkgdset(window,' ' | A_BOLD | COLOR_PAIR(2));
+ if(res < 0)
+ wdoprintf(window,"Copy done! (Failed to copy some files)");
+ else
+ wdoprintf(window,"Copy done!");
+ }
+ if(has_colors())
+ wbkgdset(window,' ' | COLOR_PAIR(0));
+ }
+ dir_data->current_directory[current_directory_namelength]='\0';
+ }
+ }
+ break;
+ }
+ }
+ } while(quit==0);
+ return -1;
+}
+#endif
+
+void delete_list_file(file_data_t *file_list)
+{
+ file_data_t *current_file=file_list;
+ while(current_file!=NULL)
+ {
+ file_data_t *next=current_file->next;
+ free(current_file);
+ current_file=next;
+ }
+}
+
+int dir_partition_aff(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int inode, char **current_cmd)
+{
+ if(dir_data==NULL)
+ return -1;
+ return dir_partition_aux(disk_car,partition,dir_data,inode,1,current_cmd);
+}
+
+static int dir_partition_aux(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int inode, const int first_time, char**current_cmd)
+{
+ file_data_t *dir_list;
+ long int new_inode=-1;
+ if(dir_data->verbose>0)
+ log_info("\ndir_partition inode=%ld\n",inode);
+ dir_list=dir_data->get_dir(disk_car,partition,dir_data,inode);
+ dir_aff_log(disk_car, partition, dir_data, dir_list);
+ do
+ {
+ unsigned int current_directory_namelength=strlen(dir_data->current_directory);
+ if(*current_cmd==NULL)
+ {
+#ifdef HAVE_NCURSES
+ new_inode=dir_aff_ncurses(disk_car,partition,dir_data,dir_list,inode,first_time);
+#endif
+ }
+ if(new_inode==0 || new_inode>1)
+ {
+ if(dir_partition_aux(disk_car, partition, dir_data, (unsigned long int)new_inode,0,current_cmd)<0)
+ { /* quit */
+ delete_list_file(dir_list);
+ return -1;
+ }
+ /* back */
+ dir_data->current_directory[current_directory_namelength]='\0';
+ }
+ } while(new_inode==0 || new_inode>1);
+ delete_list_file(dir_list);
+ return new_inode;
+}
+
+/*
+Returns
+-2: no file copied
+-1: failed to copy some files
+0: all files has been copied
+*/
+static int copy_dir(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_data_t *dir)
+{
+ file_data_t *dir_list;
+ unsigned int current_directory_namelength=strlen(dir_data->current_directory);
+ file_data_t *current_file;
+ char *dir_name;
+ int copy_bad=0;
+ int copy_ok=0;
+ if(dir_data->get_dir==NULL || dir_data->copy_file==NULL)
+ return -2;
+ {
+ int l1=strlen(dir_data->local_dir);
+ int l2=strlen(dir_data->current_directory);
+ dir_name=MALLOC(l1+l2+1);
+ memcpy(dir_name,dir_data->local_dir,l1);
+ filename_convert(dir_name+l1,dir_data->current_directory,l2+1);
+ }
+ create_dir(dir_name,1);
+ dir_list=dir_data->get_dir(disk_car, partition,dir_data, (const unsigned long int)dir->filestat.st_ino);
+ for(current_file=dir_list;current_file!=NULL;current_file=current_file->next)
+ {
+ if(strlen(dir_data->current_directory)+1+strlen(current_file->name)<sizeof(dir_data->current_directory)-1)
+ {
+ if(strcmp(dir_data->current_directory,"/"))
+ strcat(dir_data->current_directory,"/");
+ strcat(dir_data->current_directory,current_file->name);
+ if(LINUX_S_ISDIR(current_file->filestat.st_mode)!=0)
+ {
+ int tmp=0;
+ if(current_file->filestat.st_ino != dir->filestat.st_ino &&
+ strcmp(current_file->name,"..")!=0 && strcmp(current_file->name,".")!=0)
+ tmp=copy_dir(disk_car, partition, dir_data, current_file);
+ if(tmp>=-1)
+ copy_ok=1;
+ if(tmp<0)
+ copy_bad=1;
+ }
+ else if(LINUX_S_ISREG(current_file->filestat.st_mode)!=0)
+ {
+// log_trace("copy_file %s\n",dir_data->current_directory);
+ int tmp;
+ tmp=dir_data->copy_file(disk_car, partition, dir_data, current_file);
+ if(tmp==0)
+ copy_ok=1;
+ else
+ copy_bad=1;
+ }
+ dir_data->current_directory[current_directory_namelength]='\0';
+ }
+ }
+ delete_list_file(dir_list);
+ set_date(dir_name, dir->filestat.st_atime, dir->filestat.st_mtime);
+ free(dir_name);
+ return (copy_bad>0?(copy_ok>0?-1:-2):0);
+}
+
+FILE *create_file(const char *filename)
+{
+ FILE *f_out;
+ f_out=fopen(filename,"wb");
+ if(!f_out)
+ {
+ create_dir(filename,0);
+ f_out=fopen(filename,"wb");
+ }
+ return f_out;
+}
+
+/**
+ * set_date - Set the file's date and time
+ * @pathname: Path and name of the file to alter
+ * @actime: Date and time to set
+ * @modtime: Date and time to set
+ *
+ * Give a file a particular date and time.
+ *
+ * Return: 1 Success, set the file's date and time
+ * 0 Error, failed to change the file's date and time
+ */
+int set_date(const char *pathname, time_t actime, time_t modtime)
+{
+#ifdef HAVE_UTIME
+ struct utimbuf ut;
+ if (!pathname)
+ return 0;
+ ut.actime = actime;
+ ut.modtime = modtime;
+ if (utime(pathname, &ut)) {
+ log_error("ERROR: Couldn't set the file's date and time for %s\n", pathname);
+ return 0;
+ }
+ return 1;
+#else
+ return 0;
+#endif
+}
diff --git a/src/dir.h b/src/dir.h
new file mode 100644
index 0000000..ef3584d
--- /dev/null
+++ b/src/dir.h
@@ -0,0 +1,101 @@
+/*
+
+ File: dir.h
+
+ Copyright (C) 2004-2006 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifndef _DIR_H
+#define _DIR_H
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#define INTER_DIR 16
+#define DIR_NAME_LEN 255
+typedef struct dir_data dir_data_t;
+typedef struct file_data file_data_t;
+struct dir_data
+{
+ void *display;
+ char current_directory[DIR_NAME_LEN];
+ unsigned long int current_inode;
+ int verbose;
+ file_data_t *(*get_dir)(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int first_inode);
+ int (*copy_file)(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const file_data_t *file);
+ void (*close)(dir_data_t *dir_data);
+ char *local_dir;
+ void *private_dir_data;
+};
+
+struct file_data
+{
+ file_data_t *prev;
+ file_data_t *next;
+ char name[DIR_NAME_LEN];
+ struct stat filestat;
+};
+
+int dir_aff_log(const disk_t *disk_car, const partition_t *partition, const dir_data_t *dir_data, const file_data_t*dir_list);
+void delete_list_file(file_data_t *file_list);
+int dir_partition_aff(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int inode, char **current_cmd);
+void mode_string (const unsigned int mode, char *str);
+FILE *create_file(const char *filename);
+int set_date(const char *pathname, time_t actime, time_t modtime);
+
+#define LINUX_S_IFMT 00170000
+#define LINUX_S_IFSOCK 0140000
+#define LINUX_S_IFLNK 0120000
+#define LINUX_S_IFREG 0100000
+#define LINUX_S_IFBLK 0060000
+#define LINUX_S_IFDIR 0040000
+#define LINUX_S_IFCHR 0020000
+#define LINUX_S_IFIFO 0010000
+#define LINUX_S_ISUID 0004000
+#define LINUX_S_ISGID 0002000
+#define LINUX_S_ISVTX 0001000
+
+
+#define LINUX_S_IRWXU 00700
+#define LINUX_S_IRUSR 00400
+#define LINUX_S_IWUSR 00200
+#define LINUX_S_IXUSR 00100
+
+#define LINUX_S_IRWXG 00070
+#define LINUX_S_IRGRP 00040
+#define LINUX_S_IWGRP 00020
+#define LINUX_S_IXGRP 00010
+
+#define LINUX_S_IRWXO 00007
+#define LINUX_S_IROTH 00004
+#define LINUX_S_IWOTH 00002
+#define LINUX_S_IXOTH 00001
+
+#define LINUX_S_IRWXUGO (LINUX_S_IRWXU|LINUX_S_IRWXG|LINUX_S_IRWXO)
+#define LINUX_S_IALLUGO (LINUX_S_ISUID|LINUX_S_ISGID|LINUX_S_ISVTX|LINUX_S_IRWXUGO)
+#define LINUX_S_IRUGO (LINUX_S_IRUSR|LINUX_S_IRGRP|LINUX_S_IROTH)
+#define LINUX_S_IWUGO (LINUX_S_IWUSR|LINUX_S_IWGRP|LINUX_S_IWOTH)
+#define LINUX_S_IXUGO (LINUX_S_IXUSR|LINUX_S_IXGRP|LINUX_S_IXOTH)
+
+#define LINUX_S_ISLNK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFLNK)
+#define LINUX_S_ISREG(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFREG)
+#define LINUX_S_ISDIR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFDIR)
+#define LINUX_S_ISCHR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFCHR)
+#define LINUX_S_ISBLK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFBLK)
+#define LINUX_S_ISFIFO(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFIFO)
+#define LINUX_S_ISSOCK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK)
+
+#endif
diff --git a/src/dirpart.c b/src/dirpart.c
new file mode 100644
index 0000000..6ddbe31
--- /dev/null
+++ b/src/dirpart.c
@@ -0,0 +1,159 @@
+/*
+
+ File: dirpart.c
+
+ Copyright (C) 1998-2006 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "fat.h"
+#include "lang.h"
+#include "fnctdsk.h"
+#include "testdisk.h"
+#include "intrf.h"
+#ifdef HAVE_NCURSES
+#include "intrfn.h"
+#else
+#include <stdio.h>
+#endif
+#include "dir.h"
+#include "ext2_dir.h"
+#include "fat_dir.h"
+#include "ntfs_dir.h"
+#include "rfs_dir.h"
+#include "dirpart.h"
+#include "ntfs.h"
+#include "adv.h"
+#include "log.h"
+
+int dir_partition(disk_t *disk_car, const partition_t *partition, const int verbose, char **current_cmd)
+{
+ dir_data_t dir_data;
+#ifdef HAVE_NCURSES
+ WINDOW *window;
+#endif
+ int res=-3;
+ if(is_part_fat(partition))
+ res=dir_partition_fat_init(disk_car,partition,&dir_data,verbose);
+ else if(is_part_ntfs(partition))
+ res=dir_partition_ntfs_init(disk_car,partition,&dir_data,verbose);
+ else if(is_part_linux(partition))
+ {
+ res=dir_partition_ext2_init(disk_car,partition,&dir_data,verbose);
+ if(res!=0)
+ res=dir_partition_reiser_init(disk_car,partition,&dir_data,verbose);
+ }
+ if(res!=0)
+ {
+ switch(partition->upart_type)
+ {
+ case UP_FAT12:
+ case UP_FAT16:
+ case UP_FAT32:
+ res=dir_partition_fat_init(disk_car,partition,&dir_data,verbose);
+ break;
+ case UP_EXT3:
+ case UP_EXT2:
+ res=dir_partition_ext2_init(disk_car,partition,&dir_data,verbose);
+ break;
+ case UP_RFS:
+ case UP_RFS2:
+ case UP_RFS3:
+ res=dir_partition_reiser_init(disk_car,partition,&dir_data,verbose);
+ break;
+ case UP_NTFS:
+ res=dir_partition_ntfs_init(disk_car,partition,&dir_data,verbose);
+ break;
+ default:
+ return res;
+ }
+ }
+#ifdef HAVE_NCURSES
+ window=newwin(0,0,0,0); /* full screen */
+ dir_data.display=window;
+ aff_copy(window);
+#else
+ dir_data.display=NULL;
+#endif
+ log_info("\n");
+ switch(res)
+ {
+ case -2:
+ aff_buffer(BUFFER_RESET,"Q");
+#ifdef HAVE_NCURSES
+ aff_copy(window);
+ wmove(window,4,0);
+ aff_part(window,AFF_PART_ORDER,disk_car,partition);
+#endif
+ log_partition(disk_car,partition);
+ aff_buffer(BUFFER_ADD,"Support for this filesystem hasn't been enable during compilation.\n");
+ screen_buffer_to_log();
+ if(*current_cmd==NULL)
+ {
+#ifdef HAVE_NCURSES
+ screen_buffer_display(window,"",NULL);
+#endif
+ }
+ break;
+ case -1:
+ aff_buffer(BUFFER_RESET,"Q");
+#ifdef HAVE_NCURSES
+ aff_copy(window);
+ wmove(window,4,0);
+ aff_part(window,AFF_PART_ORDER,disk_car,partition);
+#endif
+ log_partition(disk_car,partition);
+ aff_buffer(BUFFER_ADD,"Can't open filesystem. Filesystem seems damaged.\n");
+ screen_buffer_to_log();
+ if(*current_cmd==NULL)
+ {
+#ifdef HAVE_NCURSES
+ screen_buffer_display(window,"",NULL);
+#endif
+ }
+ break;
+ default:
+ dir_partition_aff(disk_car,partition,&dir_data,dir_data.current_inode,current_cmd);
+ dir_data.close(&dir_data);
+ break;
+ }
+#ifdef HAVE_NCURSES
+ delwin(window);
+ (void) clearok(stdscr, TRUE);
+#ifdef HAVE_TOUCHWIN
+ touchwin(stdscr);
+#endif
+#endif
+ return res;
+}
diff --git a/src/dirpart.h b/src/dirpart.h
new file mode 100644
index 0000000..0a77ce1
--- /dev/null
+++ b/src/dirpart.h
@@ -0,0 +1,23 @@
+/*
+
+ File: dirpart.h
+
+ Copyright (C) 2006 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+int dir_partition(disk_t *disk_car, const partition_t *partition, const int verbose, char **current_cmd);
+
diff --git a/src/edit.c b/src/edit.c
new file mode 100644
index 0000000..ea4c547
--- /dev/null
+++ b/src/edit.c
@@ -0,0 +1,290 @@
+/*
+
+ File: edit.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <ctype.h>
+#include "types.h"
+#include "common.h"
+#include "lang.h"
+#include "intrf.h"
+#ifdef HAVE_NCURSES
+#include "intrfn.h"
+#else
+#include <stdio.h>
+#endif
+#include "fnctdsk.h"
+#include "edit.h"
+#include "log.h"
+
+#ifdef HAVE_NCURSES
+static void interface_editor_position(const disk_t *disk_car, uint64_t *lba);
+static int dump_editor(const unsigned char *nom_dump,const unsigned int lng, const int menu_pos);
+static void interface_editor_ncurses(disk_t *disk_car);
+
+static void interface_editor_ncurses(disk_t *disk_car)
+{
+ int done = 0;
+ uint64_t hd_offset=0;
+ unsigned char *buffer=MALLOC(disk_car->sector_size);
+ log_info("%s\n",disk_car->description(disk_car));
+ while (done==0)
+ {
+ static struct MenuItem menuEditor[]=
+ {
+ { 'C', "Change position", "" },
+ { 'D', "Dump", "Dump sector" },
+ { 'Q', "Quit",""},
+ { 0, NULL, NULL }
+ };
+ switch ( wmenuSelect(stdscr,INTER_DUMP_Y, INTER_DUMP_X, menuEditor, 8, "CDQ", MENU_HORIZ | MENU_BUTTON, 0))
+ {
+ case 'c':
+ case 'C':
+ interface_editor_position(disk_car,&hd_offset);
+ break;
+ case 'd':
+ case 'D':
+ {
+ int menu_pos=KEY_DOWN;
+ while(done==0)
+ {
+ wmove(stdscr,4,0);
+ wclrtoeol(stdscr);
+ wdoprintf(stdscr,"%lu ", (unsigned long)(hd_offset/disk_car->sector_size));
+ aff_LBA2CHS(disk_car,hd_offset/disk_car->sector_size);
+ if(disk_car->read(disk_car,disk_car->sector_size, buffer, hd_offset))
+ {
+ wdoprintf(stdscr,msg_PART_RD_ERR);
+ }
+ {
+ menu_pos=dump_editor(buffer,disk_car->sector_size,menu_pos);
+ switch(menu_pos)
+ {
+ case KEY_UP:
+ if(hd_offset>0)
+ hd_offset-=disk_car->sector_size;
+ else
+ menu_pos=KEY_DOWN;
+ break;
+ case KEY_DOWN:
+ if(hd_offset<disk_car->disk_size)
+ hd_offset+=disk_car->sector_size;
+ else
+ menu_pos=KEY_UP;
+ break;
+ default:
+ done = 1;
+ break;
+ }
+ }
+ }
+ done = 0;
+ }
+ break;
+ case key_ESC:
+ case 'q':
+ case 'Q':
+ done = 1;
+ break;
+ }
+ }
+ free(buffer);
+}
+
+static void interface_editor_position(const disk_t *disk_car,uint64_t *lba)
+{
+ CHS_t position;
+ int done = 0;
+ char def[LINE_LENGTH];
+ char response[LINE_LENGTH];
+ unsigned int tmp_val;
+ int command;
+ position.cylinder=offset2cylinder(disk_car,*lba);
+ position.head=offset2head(disk_car,*lba);
+ position.sector=offset2sector(disk_car,*lba);
+ while (done==0) {
+ static struct MenuItem menuGeometry[]=
+ {
+ { 'c', "Cylinders", "Change cylinder" },
+ { 'h', "Heads", "Change head" },
+ { 's', "Sectors", "Change sector" },
+ { 'd', "Done", "Done with changing" },
+ { 0, NULL, NULL }
+ };
+ wmove(stdscr,INTER_GEOM_Y, INTER_GEOM_X);
+ wclrtoeol(stdscr);
+ wrefresh(stdscr);
+ command=wmenuSimple(stdscr,menuGeometry, 3);
+ switch (command) {
+ case 'c':
+ case 'C':
+ sprintf(def, "%u", position.cylinder);
+ mvwaddstr(stdscr,INTER_GEOM_Y, INTER_GEOM_X, "Enter the number of cylinders: ");
+ if (get_string(response, LINE_LENGTH, def) > 0) {
+ tmp_val = atoi(response);
+ if (tmp_val <= disk_car->CHS.cylinder) {
+ position.cylinder = tmp_val;
+ } else
+ wdoprintf(stdscr,"Illegal cylinders value");
+ }
+ break;
+ case 'h':
+ case 'H':
+ sprintf(def, "%u", position.head);
+ mvwaddstr(stdscr,INTER_GEOM_Y, INTER_GEOM_X, "Enter the number of heads: ");
+ if (get_string(response, LINE_LENGTH, def) > 0) {
+ tmp_val = atoi(response);
+ if (tmp_val <= disk_car->CHS.head) {
+ position.head = tmp_val;
+ } else
+ wdoprintf(stdscr,"Illegal heads value");
+ }
+ break;
+ case 's':
+ case 'S':
+ sprintf(def, "%u", position.sector);
+ mvwaddstr(stdscr,INTER_GEOM_Y, INTER_GEOM_X, "Enter the number of sectors per track: ");
+ if (get_string(response, LINE_LENGTH, def) > 0) {
+ tmp_val = atoi(response);
+ if (tmp_val > 0 && tmp_val <= disk_car->CHS.sector ) {
+ position.sector = tmp_val;
+ } else
+ wdoprintf(stdscr,"Illegal sectors value");
+ }
+ break;
+ case key_ESC:
+ case 'd':
+ case 'D':
+ done = 1;
+ break;
+ }
+ }
+ *lba=CHS2offset(disk_car,&position);
+}
+
+static int dump_editor(const unsigned char *nom_dump,const unsigned int lng, const int menu_pos)
+{
+ unsigned int i,j;
+ unsigned int pos;
+ unsigned char car;
+ int done=0;
+ unsigned int menu;
+ struct MenuItem menuDump[]=
+ {
+ { 'P', "Previous",""},
+ { 'N', "Next","" },
+ { 'Q',"Quit","Quit dump section"},
+ { 0, NULL, NULL }
+ };
+ /* write dump to log file*/
+ dump_log(nom_dump, lng);
+ /* ncurses interface */
+ pos=(menu_pos==KEY_DOWN?0:lng/0x10-DUMP_MAX_LINES);
+ menu=(menu_pos==KEY_DOWN?1:0);
+ mvwaddstr(stdscr,DUMP_Y,DUMP_X,msg_DUMP_HEXA);
+ do
+ {
+ for (i=pos; (i<lng/0x10)&&((i-pos)<DUMP_MAX_LINES); i++)
+ {
+ wmove(stdscr,DUMP_Y+i-pos,DUMP_X);
+ wclrtoeol(stdscr);
+ wdoprintf(stdscr,"%04X ",i*0x10);
+ for(j=0; j< 0x10;j++)
+ {
+ car=*(nom_dump+i*0x10+j);
+ wdoprintf(stdscr,"%02x", car);
+ if(j%4==(4-1))
+ wdoprintf(stdscr," ");
+ }
+ wdoprintf(stdscr," ");
+ for(j=0; j< 0x10;j++)
+ {
+ car=*(nom_dump+i*0x10+j);
+ if ((car<32)||(car >= 127))
+ wdoprintf(stdscr,".");
+ else
+ wdoprintf(stdscr,"%c", car);
+ }
+ }
+ switch (wmenuSelect(stdscr,INTER_DUMP_Y, INTER_DUMP_X, menuDump, 8, "PNQ", MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, menu))
+ {
+ case 'p':
+ case 'P':
+ case KEY_UP:
+ menu=0;
+ if(pos>0)
+ pos--;
+ else
+ done=KEY_UP;
+ break;
+ case 'n':
+ case 'N':
+ case KEY_DOWN:
+ menu=1;
+ if(pos<lng/0x10-DUMP_MAX_LINES)
+ pos++;
+ else
+ done = KEY_DOWN;
+ break;
+ case KEY_PPAGE:
+ menu=0;
+ if(pos==0)
+ done=KEY_UP;
+ if(pos>DUMP_MAX_LINES-1)
+ pos-=DUMP_MAX_LINES-1;
+ else
+ pos=0;
+ break;
+ case KEY_NPAGE:
+ menu=1;
+ if(pos==lng/0x10-DUMP_MAX_LINES)
+ done=KEY_DOWN;
+ if(pos<lng/0x10-DUMP_MAX_LINES-(DUMP_MAX_LINES-1))
+ pos+=DUMP_MAX_LINES-1;
+ else
+ pos=lng/0x10-DUMP_MAX_LINES;
+ break;
+ case key_ESC:
+ case 'q':
+ case 'Q':
+ done = 'Q';
+ break;
+ }
+ } while(done==0);
+ return done;
+}
+#endif
+
+void interface_editor(disk_t *disk_car)
+{
+#ifdef HAVE_NCURSES
+ interface_editor_ncurses(disk_car);
+#endif
+}
diff --git a/src/edit.h b/src/edit.h
new file mode 100644
index 0000000..dd5fb91
--- /dev/null
+++ b/src/edit.h
@@ -0,0 +1,23 @@
+/*
+
+ File: edit.h
+
+ Copyright (C) 1998-2004 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+void interface_editor(disk_t *disk_car);
+
diff --git a/src/ewf.c b/src/ewf.c
new file mode 100644
index 0000000..4152f73
--- /dev/null
+++ b/src/ewf.c
@@ -0,0 +1,241 @@
+/*
+
+ File: ewf.c
+
+ Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#if defined(HAVE_LIBEWF_H) && defined(HAVE_LIBEWF)
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* lseek, read, write, close */
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h> /* open */
+#endif
+#include <stdio.h>
+#include <errno.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* free */
+#endif
+#ifdef HAVE_GLOB_H
+#include <glob.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "ewf.h"
+#include "fnctdsk.h"
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#include <libewf.h>
+#include "log.h"
+
+static const char *fewf_description(disk_t *disk_car);
+static const char *fewf_description_short(disk_t *disk_car);
+static int fewf_clean(disk_t *disk_car);
+static int fewf_read(disk_t *disk_car, const unsigned int count, void *nom_buffer, const uint64_t offset);
+static int fewf_write(disk_t *disk_car, const unsigned int count, const void *nom_buffer, const uint64_t offset);
+static int fewf_nowrite(disk_t *disk_car, const unsigned int count, const void *nom_buffer, const uint64_t offset);
+
+
+struct info_fewf_struct
+{
+ LIBEWF_HANDLE *handle;
+ uint64_t offset;
+ char file_name[DISKNAME_MAX];
+ int mode;
+ void *buffer;
+ unsigned int buffer_size;
+};
+
+disk_t *fewf_init(const char *device, const int verbose, const arch_fnct_t *arch, const int mode)
+{
+ unsigned int num_files=0;
+ char **filenames= NULL;
+ disk_t *disk_car=NULL;
+ struct info_fewf_struct *data;
+#ifdef HAVE_GLOB_H
+ glob_t globbuf;
+#endif
+ data=MALLOC(sizeof(*data));
+ data->offset=0;
+ strncpy(data->file_name,device,sizeof(data->file_name));
+ data->file_name[sizeof(data->file_name)-1]='\0';
+ data->buffer=NULL;
+ data->buffer_size=0;
+ data->mode=mode;
+ data->handle=NULL;
+// data->handle=libewf_open(filenames, 1, ((mode&O_RDWR)==O_RDWR?LIBEWF_OPEN_WRITE:LIBEWF_OPEN_READ));
+#ifdef HAVE_GLOB_H
+ {
+ globbuf.gl_offs = 0;
+ glob(data->file_name, GLOB_DOOFFS, NULL, &globbuf);
+ if(globbuf.gl_pathc>0)
+ {
+ filenames=MALLOC(globbuf.gl_pathc * sizeof(*filenames));
+ for (num_files=0; num_files<globbuf.gl_pathc; num_files++) {
+ filenames[num_files]=globbuf.gl_pathv[num_files];
+ }
+ }
+ }
+#else
+ filenames=MALLOC(1*sizeof(*filenames));
+ filenames[num_files] = data->file_name;
+ num_files++;
+#endif /*HAVE_GLOB_H*/
+ if(filenames!=NULL)
+ data->handle=libewf_open(filenames, num_files, LIBEWF_OPEN_READ);
+ if(data->handle==NULL)
+ {
+#ifdef HAVE_GLOB_H
+ globfree(&globbuf);
+#endif
+ free(filenames);
+ free(data);
+ return NULL;
+ }
+ if( libewf_parse_header_values( data->handle, LIBEWF_DATE_FORMAT_DAYMONTH) != 1 )
+ {
+ fprintf( stderr, "Unable to parse header values.\n" );
+ }
+ disk_car=(disk_t *)MALLOC(sizeof(*disk_car));
+ disk_car->arch=arch;
+ disk_car->sector_size=libewf_get_bytes_per_sector(data->handle);
+// printf("libewf_get_bytes_per_sector %u\n",disk_car->sector_size);
+ if(disk_car->sector_size==0)
+ disk_car->sector_size=DEFAULT_SECTOR_SIZE;
+ disk_car->disk_size=libewf_get_media_size(data->handle);
+ disk_car->disk_real_size=disk_car->disk_size;
+// printf("libewf_get_media_size %llu\n",(long long unsigned) (disk_car->sector_size/disk_car->sector_size));
+ disk_car->CHS.head=255-1;
+ disk_car->CHS.sector=63;
+ disk_car->CHS.cylinder=(disk_car->disk_size/(disk_car->CHS.head+1))/disk_car->CHS.sector/disk_car->sector_size-1;
+ disk_car->device=strdup(device);
+ disk_car->write_used=0;
+ disk_car->description_txt[0]='\0';
+ disk_car->description=fewf_description;
+ disk_car->description_short=fewf_description_short;
+ disk_car->read=fewf_read;
+ disk_car->write=((mode&O_RDWR)==O_RDWR?fewf_write:fewf_nowrite);
+ disk_car->clean=fewf_clean;
+ disk_car->data=data;
+#ifdef HAVE_GLOB_H
+ globfree(&globbuf);
+#endif
+ free(filenames);
+ return disk_car;
+}
+
+static const char *fewf_description(disk_t *disk_car)
+{
+ const struct info_fewf_struct *data=(const struct info_fewf_struct *)disk_car->data;
+ char buffer_disk_size[100];
+ snprintf(disk_car->description_txt, sizeof(disk_car->description_txt),"Image %s - %s - CHS %u %u %u%s",
+ data->file_name, size_to_unit(disk_car->disk_size,buffer_disk_size),
+ disk_car->CHS.cylinder+1, disk_car->CHS.head+1, disk_car->CHS.sector,((data->mode&O_RDWR)==O_RDWR?"":" (RO)"));
+ return disk_car->description_txt;
+}
+
+static const char *fewf_description_short(disk_t *disk_car)
+{
+ const struct info_fewf_struct *data=(const struct info_fewf_struct *)disk_car->data;
+ char buffer_disk_size[100];
+ snprintf(disk_car->description_short_txt, sizeof(disk_car->description_txt),"Image %s - %s%s",
+ data->file_name, size_to_unit(disk_car->disk_size,buffer_disk_size),
+ ((data->mode&O_RDWR)==O_RDWR?"":" (RO)"));
+ return disk_car->description_short_txt;
+}
+
+static int fewf_clean(disk_t *disk_car)
+{
+ if(disk_car->data!=NULL)
+ {
+ struct info_fewf_struct *data=(struct info_fewf_struct *)disk_car->data;
+ libewf_close(data->handle);
+ if(data->buffer!=NULL)
+ {
+ free(data->buffer);
+ data->buffer=NULL;
+ }
+ free(disk_car->data);
+ disk_car->data=NULL;
+ }
+ return 0;
+}
+
+static int fewf_read(disk_t *disk_car,const unsigned int count, void *nom_buffer, const uint64_t offset)
+{
+ struct info_fewf_struct *data=(struct info_fewf_struct *)disk_car->data;
+ int64_t taille;
+ taille=libewf_read_random(data->handle, nom_buffer, count, offset);
+ if(taille!=count)
+ {
+ log_error("fewf_read(xxx,%u,buffer,%lu(%u/%u/%u)) read err: ",
+ (unsigned)(count/disk_car->sector_size), (long unsigned)(offset/disk_car->sector_size),
+ offset2cylinder(disk_car,offset), offset2head(disk_car,offset), offset2sector(disk_car,offset));
+ if(taille<0)
+ log_error("%s\n", strerror(errno));
+ else if(taille==0)
+ log_error("read after end of file\n");
+ else
+ log_error("Partial read\n");
+ if(taille<=0)
+ return -1;
+ }
+ return 0;
+}
+
+static int fewf_write(disk_t *disk_car,const unsigned int count, const void *nom_buffer, const uint64_t offset)
+{
+ struct info_fewf_struct *data=(struct info_fewf_struct *)disk_car->data;
+ return -1;
+}
+
+static int fewf_nowrite(disk_t *disk_car,const unsigned int count, const void *nom_buffer, const uint64_t offset)
+{
+ struct info_fewf_struct *data=(struct info_fewf_struct *)disk_car->data;
+ log_error("fewf_nowrite(xx,%u,buffer,%lu(%u/%u/%u)) write refused\n",
+ (unsigned)(count/disk_car->sector_size), (long unsigned)(offset/disk_car->sector_size),
+ offset2cylinder(disk_car,offset), offset2head(disk_car,offset), offset2sector(disk_car,offset));
+ return -1;
+}
+
+const char*td_ewf_version(void)
+{
+#ifdef LIBEWF_VERSION
+ return LIBEWF_VERSION;
+#else
+ return "available";
+#endif
+}
+#else
+#include "ewf.h"
+const char*td_ewf_version(void)
+{
+ return "none";
+}
+#endif
diff --git a/src/ewf.h b/src/ewf.h
new file mode 100644
index 0000000..d6ffb3e
--- /dev/null
+++ b/src/ewf.h
@@ -0,0 +1,26 @@
+/*
+
+ File: ewf.h
+
+ Copyright (C) 2006 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#if defined(HAVE_LIBEWF_H) && defined(HAVE_LIBEWF)
+disk_t *fewf_init(const char *device, const int verbose, const arch_fnct_t *arch, const int testdisk_mode);
+#endif
+const char*td_ewf_version(void);
+
diff --git a/src/ext2.c b/src/ext2.c
new file mode 100644
index 0000000..b1ce912
--- /dev/null
+++ b/src/ext2.c
@@ -0,0 +1,176 @@
+/*
+
+ File: ext2.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "ext2.h"
+#include "fnctdsk.h"
+#include "log.h"
+#include "guid_cpy.h"
+
+static int test_EXT2(disk_t *disk_car, const struct ext2_super_block *sb,partition_t *partition,const int verbose, const int dump_ind);
+static int set_EXT2_info(disk_t *disk_car, const struct ext2_super_block *sb,partition_t *partition,const int verbose, const int dump_ind);
+
+int check_EXT2(disk_t *disk_car,partition_t *partition,const int verbose)
+{
+ unsigned char *buffer=(unsigned char*)MALLOC(EXT2_SUPERBLOCK_SIZE);
+ if(disk_car->read(disk_car,EXT2_SUPERBLOCK_SIZE, buffer, partition->part_offset+0x400)!=0)
+ {
+ free(buffer);
+ return 1;
+ }
+ if(test_EXT2(disk_car,(struct ext2_super_block*)buffer,partition,verbose,0)!=0)
+ {
+ free(buffer);
+ return 1;
+ }
+ set_EXT2_info(disk_car,(struct ext2_super_block*)buffer,partition,verbose,0);
+ free(buffer);
+ return 0;
+}
+
+static int set_EXT2_info(disk_t *disk_car, const struct ext2_super_block *sb,partition_t *partition,const int verbose, const int dump_ind)
+{
+ set_part_name(partition,sb->s_volume_name,16);
+ /* sb->s_last_mounted seems to be unemployed in kernel 2.2.16 */
+ if(EXT2_HAS_COMPAT_FEATURE(sb,EXT3_FEATURE_COMPAT_HAS_JOURNAL)!=0)
+ strncpy(partition->info,"EXT3",sizeof(partition->info));
+ else
+ strncpy(partition->info,"EXT2",sizeof(partition->info));
+ if(EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_LARGE_FILE)!=0)
+ strcat(partition->info," Large file");
+ if(EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)!=0)
+ strcat(partition->info," Sparse superblock");
+ if(EXT2_HAS_INCOMPAT_FEATURE(sb,EXT3_FEATURE_INCOMPAT_RECOVER)!=0)
+ strcat(partition->info," Recover");
+ if(EXT2_HAS_INCOMPAT_FEATURE(sb,EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)!=0)
+ strcat(partition->info," Journal dev");
+ if(le16(sb->s_block_group_nr)!=0)
+ {
+ strcat(partition->info," Backup superblock");
+ if(verbose>0)
+ {
+ log_warning("\nblock_group_nr %u\n",le16(sb->s_block_group_nr));
+ }
+ }
+ /* last mounted => date */
+ return 0;
+}
+
+/*
+Primary superblock is at 1024 (SUPERBLOCK_OFFSET)
+Group 0 begin at s_first_data_block
+*/
+int recover_EXT2(disk_t *disk_car, const struct ext2_super_block *sb,partition_t *partition,const int verbose, const int dump_ind)
+{
+ if(test_EXT2(disk_car,sb,partition,verbose,dump_ind)!=0)
+ return 1;
+ if(partition==NULL)
+ return 0;
+ set_EXT2_info(disk_car,sb,partition,verbose,dump_ind);
+ partition->part_type_i386=P_LINUX;
+ partition->part_type_mac=PMAC_LINUX;
+ partition->part_type_sun=PSUN_LINUX;
+ partition->part_type_gpt=GPT_ENT_TYPE_LINUX_DATA;
+ partition->part_size=(uint64_t)le32(sb->s_blocks_count)*(EXT2_MIN_BLOCK_SIZE<<le32(sb->s_log_block_size));
+ partition->blocksize=EXT2_MIN_BLOCK_SIZE<<le32(sb->s_log_block_size);
+ guid_cpy(&partition->part_uuid, (const efi_guid_t *)&sb->s_uuid);
+ if(verbose>0)
+ {
+ log_info("\n");
+ }
+ if(le16(sb->s_block_group_nr)>0)
+ {
+ unsigned long int boot_sector=(le32(sb->s_first_data_block)+le16(sb->s_block_group_nr)*le32(sb->s_blocks_per_group));
+ if(partition->part_offset<(uint64_t)boot_sector*((EXT2_MIN_BLOCK_SIZE/disk_car->sector_size)<<le32(sb->s_log_block_size))*disk_car->sector_size)
+ {
+ log_error("recover_EXT2: part_offset problem\n");
+ return 1;
+ }
+ partition->boot_sector=boot_sector;
+ partition->part_offset-=(uint64_t)boot_sector*((EXT2_MIN_BLOCK_SIZE/disk_car->sector_size)<<le32(sb->s_log_block_size))*disk_car->sector_size;
+ log_warning("recover_EXT2: \"e2fsck -b %lu -B %lu device\" may be needed\n",
+ partition->boot_sector, partition->blocksize);
+ }
+ else
+ {
+ partition->boot_sector=0;
+ }
+ if(verbose>0)
+ {
+ log_info("recover_EXT2: s_block_group_nr=%u/%u, s_mnt_count=%u/%u, s_blocks_per_group=%u\n",
+ le16(sb->s_block_group_nr), (unsigned int)(le32(sb->s_blocks_count)/le32(sb->s_blocks_per_group)), le16(sb->s_mnt_count),le16(sb->s_max_mnt_count),(unsigned int)le32(sb->s_blocks_per_group));
+ log_info("recover_EXT2: boot_sector=%lu, s_blocksize=%lu\n",partition->boot_sector,partition->blocksize);
+ log_info("recover_EXT2: s_blocks_count %u\n",(unsigned int)le32(sb->s_blocks_count));
+ log_info("recover_EXT2: part_size %lu\n",(long unsigned)(partition->part_size/disk_car->sector_size));
+ }
+ return 0;
+}
+
+static int test_EXT2(disk_t *disk_car, const struct ext2_super_block *sb,partition_t *partition,const int verbose, const int dump_ind)
+{
+ /* There is a little offset ... */
+ if(le16(sb->s_magic)!=EXT2_SUPER_MAGIC)
+ return 1;
+ if(dump_ind!=0)
+ {
+ if(partition!=NULL && disk_car!=NULL)
+ log_info("\nEXT2/EXT3 magic value at %u/%u/%u\n",
+ offset2cylinder(disk_car,partition->part_offset),
+ offset2head(disk_car,partition->part_offset),
+ offset2sector(disk_car,partition->part_offset));
+ /* There is a little offset ... */
+ dump_log(sb,DEFAULT_SECTOR_SIZE);
+ }
+ if (le32(sb->s_free_blocks_count) >= le32(sb->s_blocks_count)) return 2;
+ if (le32(sb->s_free_inodes_count) >= le32(sb->s_inodes_count)) return 3;
+ if (le16(sb->s_errors)!=0 &&
+ (le16(sb->s_errors) != EXT2_ERRORS_CONTINUE) &&
+ (le16(sb->s_errors) != EXT2_ERRORS_RO) &&
+ (le16(sb->s_errors) != EXT2_ERRORS_PANIC))
+ return 5;
+ if ((le16(sb->s_state) & ~(EXT2_VALID_FS | EXT2_ERROR_FS))!=0)
+ return 5;
+ if (le32(sb->s_blocks_count) == 0) /* reject empty filesystem */
+ return 6;
+ if(le32(sb->s_log_block_size)>2) /* block size max = 4096, can be 8192 on alpha */
+ return 7;
+ if(partition==NULL)
+ return 0;
+ if(partition->part_size!=0 &&
+ partition->part_size<(uint64_t)le32(sb->s_blocks_count)*(EXT2_MIN_BLOCK_SIZE<<le32(sb->s_log_block_size)))
+ return 8;
+ if(EXT2_HAS_COMPAT_FEATURE(sb,EXT3_FEATURE_COMPAT_HAS_JOURNAL)!=0)
+ partition->upart_type=UP_EXT3;
+ else
+ partition->upart_type=UP_EXT2;
+ return 0;
+}
diff --git a/src/ext2.h b/src/ext2.h
new file mode 100644
index 0000000..5b67a0a
--- /dev/null
+++ b/src/ext2.h
@@ -0,0 +1,142 @@
+/*
+
+ File: ext2.h
+
+ Copyright (C) 1998-2004,2006 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#define EXT2_SUPERBLOCK_SIZE 1024
+
+#define EXT2_SB(sb) (sb)
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_SUPER_MAGIC 0xEF53
+#define EXT2_MIN_BLOCK_SIZE 1024
+#define EXT2_MAX_BLOCK_SIZE 4096
+#define EXT2_MIN_BLOCK_LOG_SIZE 10
+
+#define EXT2_MIN_BLOCK (EXT2_MIN_BLOCK_SIZE/DEFAULT_SECTOR_SIZE)
+
+/*
+ * File system states
+ */
+#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
+#define EXT2_ERROR_FS 0x0002 /* Errors detected */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
+#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
+#define EXT2_ERRORS_PANIC 3 /* Panic */
+#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
+
+/*
+ * Feature set definitions
+ */
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
+ ( le32(EXT2_SB(sb)->s_feature_compat) & (mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
+ ( le32(EXT2_SB(sb)->s_feature_ro_compat) & (mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( le32(EXT2_SB(sb)->s_feature_incompat) & (mask) )
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
+#define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010
+#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
+#define EXT2_FEATURE_COMPAT_ANY 0xffffffff
+
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+#define EXT2_FEATURE_RO_COMPAT_ANY 0xffffffff
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
+#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+ uint32_t s_inodes_count; /* Inodes count */
+ uint32_t s_blocks_count; /* Blocks count */
+ uint32_t s_r_blocks_count; /* Reserved blocks count */
+ uint32_t s_free_blocks_count; /* Free blocks count */
+ uint32_t s_free_inodes_count; /* Free inodes count */
+ uint32_t s_first_data_block; /* First Data Block */
+ uint32_t s_log_block_size; /* Block size */
+ int32_t s_log_frag_size; /* Fragment size */
+ uint32_t s_blocks_per_group; /* # Blocks per group */
+ uint32_t s_frags_per_group; /* # Fragments per group */
+ uint32_t s_inodes_per_group; /* # Inodes per group */
+ uint32_t s_mtime; /* Mount time */
+ uint32_t s_wtime; /* Write time */
+ uint16_t s_mnt_count; /* Mount count */
+ int16_t s_max_mnt_count; /* Maximal mount count */
+ uint16_t s_magic; /* Magic signature */
+ uint16_t s_state; /* File system state */
+ uint16_t s_errors; /* Behaviour when detecting errors */
+ uint16_t s_minor_rev_level; /* minor revision level */
+ uint32_t s_lastcheck; /* time of last check */
+ uint32_t s_checkinterval; /* max. time between checks */
+ uint32_t s_creator_os; /* OS */
+ uint32_t s_rev_level; /* Revision level */
+ uint16_t s_def_resuid; /* Default uid for reserved blocks */
+ uint16_t s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ uint32_t s_first_ino; /* First non-reserved inode */
+ uint16_t s_inode_size; /* size of inode structure */
+ uint16_t s_block_group_nr; /* block group # of this superblock */
+ uint32_t s_feature_compat; /* compatible feature set */
+ uint32_t s_feature_incompat; /* incompatible feature set */
+ uint32_t s_feature_ro_compat; /* readonly-compatible feature set */
+ uint8_t s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ uint32_t s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT2_COMPAT_PREALLOC flag is on.
+ */
+ uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ uint8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ uint16_t s_padding1;
+ uint32_t s_reserved[204]; /* Padding to the end of the block */
+};
+int check_EXT2(disk_t *disk_car,partition_t *partition,const int verbose);
+int recover_EXT2(disk_t *disk_car, const struct ext2_super_block *sb,partition_t *partition,const int verbose, const int dump_ind);
diff --git a/src/ext2_dir.c b/src/ext2_dir.c
new file mode 100644
index 0000000..cef98f3
--- /dev/null
+++ b/src/ext2_dir.c
@@ -0,0 +1,310 @@
+/*
+
+ File: ext2_dir.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include "ext2fs/ext2_fs.h"
+#endif
+#ifdef HAVE_EXT2FS_EXT2FS_H
+#include "ext2fs/ext2fs.h"
+#endif
+
+#include "types.h"
+#include "common.h"
+#include "intrf.h"
+#include "dir.h"
+#include "ext2_dir.h"
+#include "ext2_inc.h"
+#include "log.h"
+
+#if defined(HAVE_LIBEXT2FS)
+#define DIRENT_DELETED_FILE 4
+/*
+ * list directory
+ */
+
+#define LONG_OPT 0x0001
+
+/*
+ * I/O Manager routine prototypes
+ */
+static errcode_t my_open(const char *dev, int flags, io_channel *channel);
+static errcode_t my_close(io_channel channel);
+static errcode_t my_set_blksize(io_channel channel, int blksize);
+static errcode_t my_read_blk(io_channel channel, unsigned long block, int count, void *buf);
+static errcode_t my_write_blk(io_channel channel, unsigned long block, int count, const void *buf);
+static errcode_t my_flush(io_channel channel);
+
+static io_channel alloc_io_channel(disk_t *disk_car,my_data_t *my_data);
+static void dir_partition_ext2_close(dir_data_t *dir_data);
+
+static struct struct_io_manager my_struct_manager = {
+ magic: EXT2_ET_MAGIC_IO_MANAGER,
+ name: "TestDisk I/O Manager",
+ open: my_open,
+ close: my_close,
+ set_blksize: my_set_blksize,
+ read_blk: my_read_blk,
+ write_blk: my_write_blk,
+ flush: my_flush,
+ write_byte: NULL,
+#ifdef HAVE_STRUCT_STRUCT_IO_MANAGER_SET_OPTION
+ set_option: NULL
+#endif
+};
+static file_data_t *ext2_dir(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int cluster);
+
+io_channel *shared_ioch=NULL;
+io_manager my_io_manager = &my_struct_manager;
+/*
+ * Macro taken from unix_io.c
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+ if ((struct)->magic != (code)) return (code)
+
+/*
+ * Allocate libext2fs structures associated with I/O manager
+ */
+static io_channel alloc_io_channel(disk_t *disk_car,my_data_t *my_data)
+{
+ io_channel ioch;
+#ifdef DEBUG
+ log_trace("alloc_io_channel start\n");
+#endif
+ ioch = (io_channel)MALLOC(sizeof(struct struct_io_channel));
+ if (ioch==NULL)
+ return NULL;
+ memset(ioch, 0, sizeof(struct struct_io_channel));
+ ioch->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+ ioch->manager = my_io_manager;
+ ioch->name = (char *)MALLOC(strlen(my_data->partition->fsname)+1);
+ if (ioch->name==NULL) {
+ free(ioch);
+ return NULL;
+ }
+ memcpy(ioch->name, my_data->partition->fsname,strlen(my_data->partition->fsname)+1);
+ ioch->private_data = my_data;
+ ioch->block_size = 1024; /* The smallest ext2fs block size */
+ ioch->read_error = 0;
+ ioch->write_error = 0;
+#ifdef DEBUG
+ log_trace("alloc_io_channel end\n");
+#endif
+ return ioch;
+}
+
+static errcode_t my_open(const char *dev, int flags, io_channel *channel)
+{
+ *channel = *shared_ioch;
+#ifdef DEBUG
+ log_trace("my_open %s done\n",dev);
+#endif
+ return 0;
+}
+
+static errcode_t my_close(io_channel channel)
+{
+ free(channel->private_data);
+ free(channel->name);
+ free(channel);
+#ifdef DEBUG
+ log_trace("my_close done\n");
+#endif
+ return 0;
+}
+
+static errcode_t my_set_blksize(io_channel channel, int blksize)
+{
+ channel->block_size = blksize;
+#ifdef DEBUG
+ log_trace("my_set_blksize done\n");
+#endif
+ return 0;
+}
+
+static errcode_t my_read_blk(io_channel channel, unsigned long block, int count, void *buf)
+{
+ size_t size;
+ my_data_t *my_data=(my_data_t*)channel->private_data;
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+
+ size = (count < 0) ? -count : count * channel->block_size;
+#ifdef DEBUG
+ log_trace("my_read_blk start size=%lu, offset=%lu name=%s\n",
+ (long unsigned)size, (unsigned long)(block*channel->block_size), my_data->partition->fsname);
+#endif
+ if(my_data->disk_car->read(my_data->disk_car,size,buf,my_data->partition->part_offset+(uint64_t)block*channel->block_size)!=0)
+ return 1;
+#ifdef DEBUG
+ log_trace("my_read_blk done\n");
+#endif
+ return 0;
+}
+
+static errcode_t my_write_blk(io_channel channel, unsigned long block, int count, const void *buf)
+{
+ my_data_t *my_data=(my_data_t*)channel;
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+/* if(my_data->disk_car->write(my_data->disk_car,count*channel->block_size,buf,my_data->partition->part_offset+(uint64_t)block*channel->block_size))!=0) */
+ return 1;
+/* return 0; */
+}
+
+static errcode_t my_flush(io_channel channel)
+{
+ return 0;
+}
+
+static int list_dir_proc2(ext2_ino_t dir,
+ int entry,
+ struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *private)
+{
+ struct ext2_inode inode;
+ ext2_ino_t ino;
+ unsigned int thislen;
+ struct ext2_dir_struct *ls = (struct ext2_dir_struct *) private;
+ file_data_t *new_file=MALLOC(sizeof(*new_file));
+ new_file->prev=ls->current_file;
+ new_file->next=NULL;
+
+ thislen = ((dirent->name_len & 0xFF) < EXT2_NAME_LEN) ?
+ (dirent->name_len & 0xFF) : EXT2_NAME_LEN;
+ if(thislen>DIR_NAME_LEN)
+ thislen=DIR_NAME_LEN;
+ memcpy(new_file->name, dirent->name, thislen);
+ new_file->name[thislen] = '\0';
+ ino = dirent->inode;
+ if (ino) {
+ errcode_t retval;
+// log_trace("ext2fs_read_inode(ino=%u)\n",ino);
+ if ((retval=ext2fs_read_inode(ls->current_fs,ino, &inode))!=0)
+ {
+ log_error("ext2fs_read_inode(ino=%u) failed with error %ld.\n",(unsigned)ino, (long)retval);
+ memset(&inode, 0, sizeof(struct ext2_inode));
+ }
+ } else {
+ memset(&inode, 0, sizeof(struct ext2_inode));
+ }
+ new_file->filestat.st_dev=0;
+ new_file->filestat.st_ino=ino;
+ new_file->filestat.st_mode=inode.i_mode;
+ new_file->filestat.st_nlink=inode.i_links_count;
+ new_file->filestat.st_uid=inode.i_uid;
+ new_file->filestat.st_gid=inode.i_gid;
+ new_file->filestat.st_rdev=0;
+ new_file->filestat.st_size=LINUX_S_ISDIR(inode.i_mode)?inode.i_size:
+ inode.i_size| ((uint64_t)inode.i_size_high << 32);
+ new_file->filestat.st_blksize=blocksize;
+#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
+ new_file->filestat.st_blocks=inode.i_blocks;
+#endif
+ new_file->filestat.st_atime=inode.i_atime;
+ new_file->filestat.st_mtime=inode.i_mtime;
+ new_file->filestat.st_ctime=inode.i_ctime;
+ if(ls->current_file!=NULL)
+ ls->current_file->next=new_file;
+ else
+ ls->dir_list=new_file;
+ ls->current_file=new_file;
+ return 0;
+}
+
+static file_data_t *ext2_dir(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int cluster)
+{
+ errcode_t retval;
+ struct ext2_dir_struct *ls=(struct ext2_dir_struct*)dir_data->private_dir_data;
+ ls->dir_list=NULL;
+ ls->current_file=NULL;
+ if((retval=ext2fs_dir_iterate2(ls->current_fs, cluster, ls->flags, 0, list_dir_proc2, ls))!=0)
+ {
+ log_error("ext2fs_dir_iterate failed with error %ld.\n",(long)retval);
+ }
+ return ls->dir_list;
+}
+
+static void dir_partition_ext2_close(dir_data_t *dir_data)
+{
+ struct ext2_dir_struct *ls=(struct ext2_dir_struct *)dir_data->private_dir_data;
+ ext2fs_close (ls->current_fs);
+ /* ext2fs_close call the close function that freed my_data */
+ free(ls);
+}
+#endif
+
+int dir_partition_ext2_init(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const int verbose)
+{
+#if defined(HAVE_LIBEXT2FS)
+ struct ext2_dir_struct *ls=(struct ext2_dir_struct *)MALLOC(sizeof(*ls));
+ io_channel ioch;
+ my_data_t *my_data;
+ ls->dir_list=NULL;
+ ls->current_file=NULL;
+ /* ls->flags = DIRENT_FLAG_INCLUDE_EMPTY; */
+ ls->flags = 0;
+ my_data=MALLOC(sizeof(*my_data));
+ my_data->partition=partition;
+ my_data->disk_car=disk_car;
+ ioch=alloc_io_channel(disk_car,my_data);
+ shared_ioch=&ioch;
+ if(ext2fs_open ("/dev/testdisk", 0, partition->boot_sector, partition->blocksize, my_io_manager, &ls->current_fs)!=0)
+ {
+ free(ls);
+ return -1;
+ }
+ strncpy(dir_data->current_directory,"/",sizeof(dir_data->current_directory));
+ dir_data->current_inode=EXT2_ROOT_INO;
+ dir_data->verbose=verbose;
+ dir_data->get_dir=ext2_dir;
+ dir_data->copy_file=NULL;
+ dir_data->close=&dir_partition_ext2_close;
+ dir_data->local_dir=NULL;
+ dir_data->private_dir_data=ls;
+ return 0;
+#else
+ return -2;
+#endif
+}
+
+const char*td_ext2fs_version(void)
+{
+ const char *ext2fs_version="none";
+#if defined(HAVE_LIBEXT2FS)
+ ext2fs_get_library_version(&ext2fs_version,NULL);
+#endif
+ return ext2fs_version;
+}
diff --git a/src/ext2_dir.h b/src/ext2_dir.h
new file mode 100644
index 0000000..bfe8c2c
--- /dev/null
+++ b/src/ext2_dir.h
@@ -0,0 +1,24 @@
+/*
+
+ File: ext2_dir.h
+
+ Copyright (C) 1998-2006 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+int dir_partition_ext2_init(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const int verbose);
+const char*td_ext2fs_version(void);
+
diff --git a/src/ext2_inc.h b/src/ext2_inc.h
new file mode 100644
index 0000000..b4e34f8
--- /dev/null
+++ b/src/ext2_inc.h
@@ -0,0 +1,29 @@
+/*
+
+ File: ext2_inc.h
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#if defined(HAVE_LIBEXT2FS)
+struct ext2_dir_struct {
+ file_data_t *dir_list;
+ file_data_t *current_file;
+ ext2_filsys current_fs;
+ int flags;
+};
+#endif
diff --git a/src/ext2p.c b/src/ext2p.c
new file mode 100644
index 0000000..3f728c8
--- /dev/null
+++ b/src/ext2p.c
@@ -0,0 +1,128 @@
+/*
+
+ File: ext2p.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "list.h"
+#include "filegen.h"
+#include "intrf.h"
+#include "intrfn.h"
+#include "dir.h"
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include "ext2fs/ext2_fs.h"
+#endif
+#ifdef HAVE_EXT2FS_EXT2FS_H
+#include "ext2fs/ext2fs.h"
+#endif
+#ifdef HAVE_LIBEXT2FS
+#include "ext2p.h"
+#endif
+//#include "ext2.h"
+#include "ext2_inc.h"
+#include "ext2_dir.h"
+#include "log.h"
+
+#ifdef HAVE_LIBEXT2FS
+unsigned int ext2_remove_used_space(disk_t *disk_car,const partition_t *partition, alloc_data_t *list_search_space)
+{
+ dir_data_t dir_data;
+ switch(dir_partition_ext2_init(disk_car,partition,&dir_data,0))
+ {
+ case -2:
+ case -1:
+ aff_buffer(BUFFER_RESET,"Q");
+ {
+#ifdef HAVE_NCURSES
+ WINDOW *window;
+ window=newwin(0,0,0,0); /* full screen */
+ aff_copy(window);
+ wmove(window,4,0);
+ aff_part(window,AFF_PART_ORDER,disk_car,partition);
+#endif
+ log_partition(disk_car,partition);
+ aff_buffer(BUFFER_ADD,"Can't open filesystem. Filesystem seems damaged.\n");
+ screen_buffer_to_log();
+#ifdef HAVE_NCURSES
+ screen_buffer_display(window,"",NULL);
+ delwin(window);
+ (void) clearok(stdscr, TRUE);
+#ifdef HAVE_TOUCHWIN
+ touchwin(stdscr);
+#endif
+#endif
+ }
+ return 0;
+ }
+ {
+ const unsigned int sizeof_buffer=512;
+ struct ext2_dir_struct *ls=(struct ext2_dir_struct *)dir_data.private_dir_data;
+ unsigned char *buffer;
+ uint64_t start_free=0;
+ uint64_t end_free=0;
+ unsigned long int block;
+ const unsigned int blocksize=ls->current_fs->blocksize;
+ ext2fs_block_bitmap bitmap;
+ if(ext2fs_read_block_bitmap(ls->current_fs))
+ {
+ log_error("ext2fs_read_block_bitmap failed\n");
+ return 0;
+ }
+ bitmap=ls->current_fs->block_map;
+ if(bitmap==NULL)
+ return 0;
+ log_trace("ext2_remove_used_space %llu-%llu\n",
+ (long long unsigned)bitmap->start,
+ (long long unsigned)bitmap->end);
+ buffer=(unsigned char *)MALLOC(sizeof_buffer);
+ for(block=bitmap->start;block<=bitmap->end;block++)
+ {
+ if(ext2fs_test_bit(block - bitmap->start, bitmap->bitmap)!=0)
+ {
+ /* Not free */
+ if(end_free+1==partition->part_offset+(uint64_t)block*blocksize)
+ end_free+=blocksize;
+ else
+ {
+ if(start_free != end_free)
+ del_search_space(list_search_space, start_free, end_free);
+ start_free=partition->part_offset+(uint64_t)block*blocksize;
+ end_free=start_free+(uint64_t)blocksize-1;
+ }
+ }
+ }
+ free(buffer);
+ if(start_free != end_free)
+ del_search_space(list_search_space, start_free, end_free);
+ dir_data.close(&dir_data);
+ return blocksize;
+ }
+}
+#endif
diff --git a/src/ext2p.h b/src/ext2p.h
new file mode 100644
index 0000000..818393a
--- /dev/null
+++ b/src/ext2p.h
@@ -0,0 +1,23 @@
+/*
+
+ File: ext2p.h
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+unsigned int ext2_remove_used_space(disk_t *disk_car,const partition_t *partition, alloc_data_t *list_search_space);
+
diff --git a/src/fat.c b/src/fat.c
new file mode 100644
index 0000000..7eb7f2a
--- /dev/null
+++ b/src/fat.c
@@ -0,0 +1,1176 @@
+/*
+
+ File: fat.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "fat.h"
+#include "lang.h"
+#include "fnctdsk.h"
+#include "testdisk.h"
+#include "intrf.h"
+#ifdef HAVE_NCURSES
+#include "intrfn.h"
+#else
+#include <stdio.h>
+#endif
+#include "log.h"
+/* #include "guid_cmp.h" */
+
+static int set_FAT_info(disk_t *disk_car, const struct fat_boot_sector *fat_header, partition_t *partition,const int verbose);
+static void fat_set_part_name(partition_t *partition,const unsigned char *src,const int max_size);
+static int log_fat_info(const struct fat_boot_sector*fh1, const upart_type_t upart_type, const unsigned int sector_size);
+
+static void fat_set_part_name(partition_t *partition,const unsigned char *src,const int max_size)
+{
+ int i;
+ for(i=0;(i<max_size) && (src[i]!=(char)0);i++)
+ partition->fsname[i]=src[i];
+ partition->fsname[i--]='\0';
+ for(;(i>=0) && (src[i]==' ');i--);
+ partition->fsname[i+1]='\0';
+}
+
+static int log_fat_info(const struct fat_boot_sector*fh1, const upart_type_t upart_type, const unsigned int sector_size)
+{
+ log_info("sector_size %u\n", fat_sector_size(fh1));
+ log_info("cluster_size %u\n", fh1->cluster_size);
+ log_info("reserved %u\n", le16(fh1->reserved));
+ log_info("fats %u\n", fh1->fats);
+ log_info("dir_entries %u\n", get_dir_entries(fh1));
+ log_info("sectors %u\n", sectors(fh1));
+ log_info("media %02X\n", fh1->media);
+ log_info("fat_length %u\n", le16(fh1->fat_length));
+ log_info("secs_track %u\n", le16(fh1->secs_track));
+ log_info("heads %u\n", le16(fh1->heads));
+ log_info("hidden %u\n", (unsigned int)le32(fh1->hidden));
+ log_info("total_sect %u\n", (unsigned int)le32(fh1->total_sect));
+ if(upart_type==UP_FAT32)
+ {
+ log_info("fat32_length %u\n", (unsigned int)le32(fh1->fat32_length));
+ log_info("flags %04X\n", le16(fh1->flags));
+ log_info("version %u.%u\n", fh1->version[0], fh1->version[1]);
+ log_info("root_cluster %u\n", (unsigned int)le32(fh1->root_cluster));
+ log_info("info_sector %u\n", le16(fh1->info_sector));
+ log_info("backup_boot %u\n", le16(fh1->backup_boot));
+ if(fat32_get_free_count((const unsigned char*)fh1,sector_size)==0xFFFFFFFF)
+ log_info("free_count uninitialised\n");
+ else
+ log_info("free_count %lu\n",fat32_get_free_count((const unsigned char*)fh1,sector_size));
+ if(fat32_get_next_free((const unsigned char*)fh1,sector_size)==0xFFFFFFFF)
+ log_info("next_free uninitialised\n");
+ else
+ log_info("next_free %lu\n",fat32_get_next_free((const unsigned char*)fh1,sector_size));
+ }
+ return 0;
+}
+
+#ifdef HAVE_NCURSES
+static int dump_fat_info_ncurses(const struct fat_boot_sector*fh1, const upart_type_t upart_type, const unsigned int sector_size)
+{
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ wdoprintf(stdscr,"FAT : 12\n");
+ break;
+ case UP_FAT16:
+ wdoprintf(stdscr,"FAT : 16\n");
+ break;
+ case UP_FAT32:
+ wdoprintf(stdscr,"FAT : 32\n");
+ break;
+ default:
+ wdoprintf(stdscr,"Not a FAT\n");
+ return 0;
+ }
+ wdoprintf(stdscr,"cluster_size %u\n", fh1->cluster_size);
+ wdoprintf(stdscr,"reserved %u\n", le16(fh1->reserved));
+ if(sectors(fh1)!=0)
+ wdoprintf(stdscr,"sectors %u\n", sectors(fh1));
+ if(le32(fh1->total_sect)!=0)
+ wdoprintf(stdscr,"total_sect %u\n", (unsigned int)le32(fh1->total_sect));
+ if(upart_type==UP_FAT32)
+ {
+ wdoprintf(stdscr,"fat32_length %u\n", (unsigned int)le32(fh1->fat32_length));
+ wdoprintf(stdscr,"root_cluster %u\n", (unsigned int)le32(fh1->root_cluster));
+ wdoprintf(stdscr,"flags %04X\n", le16(fh1->flags));
+ wdoprintf(stdscr,"version %u.%u\n", fh1->version[0], fh1->version[1]);
+ wdoprintf(stdscr,"root_cluster %u\n", (unsigned int)le32(fh1->root_cluster));
+ wdoprintf(stdscr,"info_sector %u\n", le16(fh1->info_sector));
+ wdoprintf(stdscr,"backup_boot %u\n", le16(fh1->backup_boot));
+ if(fat32_get_free_count((const unsigned char*)fh1,sector_size)==0xFFFFFFFF)
+ wdoprintf(stdscr,"free_count uninitialised\n");
+ else
+ wdoprintf(stdscr,"free_count %lu\n",fat32_get_free_count((const unsigned char*)fh1,sector_size));
+ if(fat32_get_next_free((const unsigned char*)fh1,sector_size)==0xFFFFFFFF)
+ wdoprintf(stdscr,"next_free uninitialised\n");
+ else
+ wdoprintf(stdscr,"next_free %lu\n",fat32_get_next_free((const unsigned char*)fh1,sector_size));
+ } else {
+ wdoprintf(stdscr,"fat_length %u\n", le16(fh1->fat_length));
+ wdoprintf(stdscr,"dir_entries %u\n", get_dir_entries(fh1));
+ }
+ return 0;
+}
+#endif
+
+int dump_fat_info(const struct fat_boot_sector*fh1, const upart_type_t upart_type, const unsigned int sector_size)
+{
+#ifdef HAVE_NCURSES
+ return dump_fat_info_ncurses(fh1, upart_type, sector_size);
+#else
+ return 0;
+#endif
+}
+
+#ifdef HAVE_NCURSES
+static int dump_2fat_info_ncurses(const struct fat_boot_sector*fh1, const struct fat_boot_sector*fh2, const upart_type_t upart_type, const unsigned int sector_size)
+{
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ wdoprintf(stdscr,"FAT : 12\n");
+ break;
+ case UP_FAT16:
+ wdoprintf(stdscr,"FAT : 16\n");
+ break;
+ case UP_FAT32:
+ wdoprintf(stdscr,"FAT : 32\n");
+ break;
+ default:
+ wdoprintf(stdscr,"Not a FAT\n");
+ return 1;
+ }
+ wdoprintf(stdscr,"cluster_size %u %u\n", fh1->cluster_size, fh2->cluster_size);
+ wdoprintf(stdscr,"reserved %u %u\n", le16(fh1->reserved),le16(fh2->reserved));
+ if(sectors(fh1)!=0 || sectors(fh2)!=0)
+ wdoprintf(stdscr,"sectors %u %u\n", sectors(fh1), sectors(fh2));
+ if(le32(fh1->total_sect)!=0 || le32(fh2->total_sect)!=0)
+ wdoprintf(stdscr,"total_sect %u %u\n", (unsigned int)le32(fh1->total_sect), (unsigned int)le32(fh2->total_sect));
+ if(upart_type==UP_FAT32)
+ {
+ wdoprintf(stdscr,"fat32_length %u %u\n", (unsigned int)le32(fh1->fat32_length), (unsigned int)le32(fh2->fat32_length));
+ wdoprintf(stdscr,"root_cluster %u %u\n", (unsigned int)le32(fh1->root_cluster), (unsigned int)le32(fh2->root_cluster));
+ wdoprintf(stdscr,"free_count ");
+ if(fat32_get_free_count((const unsigned char*)fh1,sector_size)==0xFFFFFFFF)
+ wdoprintf(stdscr,"uninitialised ");
+ else
+ wdoprintf(stdscr,"%lu ",fat32_get_free_count((const unsigned char*)fh1,sector_size));
+ if(fat32_get_free_count((const unsigned char*)fh2,sector_size)==0xFFFFFFFF)
+ wdoprintf(stdscr,"uninitialised\n");
+ else
+ wdoprintf(stdscr,"%lu\n",fat32_get_free_count((const unsigned char*)fh2,sector_size));
+ wdoprintf(stdscr,"next_free ");
+ if(fat32_get_next_free((const unsigned char*)fh1,sector_size)==0xFFFFFFFF)
+ wdoprintf(stdscr,"uninitialised ");
+ else
+ wdoprintf(stdscr,"%lu ",fat32_get_next_free((const unsigned char*)fh1,sector_size));
+ if(fat32_get_next_free((const unsigned char*)fh2,sector_size)==0xFFFFFFFF)
+ wdoprintf(stdscr,"uninitialised\n");
+ else
+ wdoprintf(stdscr,"%lu\n",fat32_get_next_free((const unsigned char*)fh2,sector_size));
+ } else {
+ wdoprintf(stdscr,"fat_length %u %u\n", le16(fh1->fat_length), le16(fh2->fat_length));
+ wdoprintf(stdscr,"dir_entries %u %u\n", get_dir_entries(fh1), get_dir_entries(fh2));
+ }
+ return 0;
+}
+#endif
+
+int dump_2fat_info(const struct fat_boot_sector*fh1, const struct fat_boot_sector*fh2, const upart_type_t upart_type, const unsigned int sector_size)
+{
+#ifdef HAVE_NCURSES
+ return dump_2fat_info_ncurses(fh1, fh2, upart_type, sector_size);
+#else
+ return 0;
+#endif
+}
+
+int log_fat2_info(const struct fat_boot_sector*fh1, const struct fat_boot_sector*fh2, const upart_type_t upart_type, const unsigned int sector_size)
+{
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ log_info("\nFAT12\n");
+ break;
+ case UP_FAT16:
+ log_info("\nFAT16\n");
+ break;
+ case UP_FAT32:
+ log_info("\nFAT32\n");
+ break;
+ default:
+ return 1;
+ }
+ log_info("sector_size %u %u\n", fat_sector_size(fh1),fat_sector_size(fh2));
+ log_info("cluster_size %u %u\n", fh1->cluster_size,fh2->cluster_size);
+ log_info("reserved %u %u\n", le16(fh1->reserved),le16(fh2->reserved));
+ log_info("fats %u %u\n", fh1->fats,fh2->fats);
+ log_info("dir_entries %u %u\n", get_dir_entries(fh1),get_dir_entries(fh2));
+ log_info("sectors %u %u\n", sectors(fh1),sectors(fh2));
+ log_info("media %02X %02X\n", fh1->media,fh2->media);
+ log_info("fat_length %u %u\n", le16(fh1->fat_length),le16(fh2->fat_length));
+ log_info("secs_track %u %u\n", le16(fh1->secs_track),le16(fh2->secs_track));
+ log_info("heads %u %u\n", le16(fh1->heads),le16(fh2->heads));
+ log_info("hidden %u %u\n", (unsigned int)le32(fh1->hidden),(unsigned int)le32(fh2->hidden));
+ log_info("total_sect %u %u\n", (unsigned int)le32(fh1->total_sect),(unsigned int)le32(fh2->total_sect));
+ if(upart_type==UP_FAT32)
+ {
+ log_info("fat32_length %u %u\n", (unsigned int)le32(fh1->fat32_length),(unsigned int)le32(fh2->fat32_length));
+ log_info("flags %04X %04X\n", le16(fh1->flags),le16(fh2->flags));
+ log_info("version %u.%u %u.%u\n", fh1->version[0], fh1->version[1],fh2->version[0], fh2->version[1]);
+ log_info("root_cluster %u %u\n", (unsigned int)le32(fh1->root_cluster),(unsigned int)le32(fh2->root_cluster));
+ log_info("info_sector %u %u\n", le16(fh1->info_sector),le16(fh2->info_sector));
+ log_info("backup_boot %u %u\n", le16(fh1->backup_boot),le16(fh2->backup_boot));
+ log_info("free_count ");
+ if(fat32_get_free_count((const unsigned char*)fh1,sector_size)==0xFFFFFFFF)
+ log_info("uninitialised ");
+ else
+ log_info("%lu ",fat32_get_free_count((const unsigned char*)fh1,sector_size));
+ if(fat32_get_free_count((const unsigned char*)fh2,sector_size)==0xFFFFFFFF)
+ log_info("uninitialised");
+ else
+ log_info("%lu",fat32_get_free_count((const unsigned char*)fh2,sector_size));
+ log_info("\nnext_free ");
+ if(fat32_get_next_free((const unsigned char*)fh1,sector_size)==0xFFFFFFFF)
+ log_info("uninitialised ");
+ else
+ log_info("%lu ",fat32_get_next_free((const unsigned char*)fh1,sector_size));
+ if(fat32_get_next_free((const unsigned char*)fh2,sector_size)==0xFFFFFFFF)
+ log_info("uninitialised\n");
+ else
+ log_info("%lu\n",fat32_get_next_free((const unsigned char*)fh2,sector_size));
+ }
+ return 0;
+}
+
+int check_FAT(disk_t *disk_car,partition_t *partition,const int verbose)
+{
+ unsigned char *buffer;
+ buffer=MALLOC(3*disk_car->sector_size);
+ if(disk_car->read(disk_car,3*disk_car->sector_size, buffer, partition->part_offset)!=0)
+ {
+ aff_buffer(BUFFER_ADD,"check_FAT: can't read FAT boot sector\n");
+ log_error("check_FAT: can't read FAT boot sector\n");
+ free(buffer);
+ return 1;
+ }
+ if(test_FAT(disk_car,(const struct fat_boot_sector *)buffer,partition,verbose,0)!=0)
+ {
+ if(verbose>0)
+ {
+ log_error("\n\ntest_FAT()\n");
+ log_partition(disk_car,partition);
+ log_fat_info((const struct fat_boot_sector*)buffer, partition->upart_type,disk_car->sector_size);
+ }
+ free(buffer);
+ return 1;
+ }
+ set_FAT_info(disk_car,(const struct fat_boot_sector *)buffer,partition,verbose);
+ /* aff_buffer(BUFFER_ADD,"Ok\n"); */
+ free(buffer);
+ return 0;
+}
+
+static int set_FAT_info(disk_t *disk_car, const struct fat_boot_sector *fat_header, partition_t *partition,const int verbose)
+{
+ const char*buffer=(const char*)fat_header;
+ partition->fsname[0]='\0';
+ switch(partition->upart_type)
+ {
+ case UP_FAT12:
+ snprintf(partition->info,sizeof(partition->info),"FAT12");
+ if(buffer[38]==0x29) /* BS_BootSig */
+ {
+ fat_set_part_name(partition,((const unsigned char*)fat_header)+FAT1X_PART_NAME,11);
+ if(check_volume_name(partition->fsname,11))
+ partition->fsname[0]='\0';
+ }
+ break;
+ case UP_FAT16:
+ snprintf(partition->info,sizeof(partition->info),"FAT16");
+ if(buffer[38]==0x29) /* BS_BootSig */
+ {
+ fat_set_part_name(partition,((const unsigned char*)fat_header)+FAT1X_PART_NAME,11);
+ if(check_volume_name(partition->fsname,11))
+ partition->fsname[0]='\0';
+ }
+ break;
+ case UP_FAT32:
+ snprintf(partition->info,sizeof(partition->info),"FAT32");
+ fat32_set_part_name(disk_car,partition,fat_header);
+ break;
+ default:
+ log_critical("set_FAT_info unknown upart_type\n");
+ return 1;
+ }
+ return 0;
+}
+
+unsigned int get_next_cluster(disk_t *disk_car,const partition_t *partition, const upart_type_t upart_type,const int offset, const unsigned int cluster)
+{
+ /* Offset can be offset to FAT1 or to FAT2 */
+ /* log_trace("get_next_cluster(upart_type=%u,offset=%u,cluster=%u\n",upart_type,offset,cluster); */
+ unsigned char *buffer;
+ unsigned int next_cluster;
+ unsigned long int offset_s,offset_o;
+ const unsigned int buffer_size=(upart_type==UP_FAT12?2*disk_car->sector_size:disk_car->sector_size);
+ buffer=(unsigned char*)MALLOC(buffer_size);
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ {
+ offset_s=(cluster+cluster/2)/disk_car->sector_size;
+ offset_o=(cluster+cluster/2)%disk_car->sector_size;
+ if(disk_car->read(disk_car,2*disk_car->sector_size, buffer, partition->part_offset+(uint64_t)(offset+offset_s)*disk_car->sector_size)!=0)
+ {
+ log_error("get_next_cluster read error\n"); return 0;
+ }
+ if((cluster&1)!=0)
+ next_cluster=le16((*((uint16_t*)&buffer[offset_o])))>>4;
+ else
+ next_cluster=le16(*((uint16_t*)&buffer[offset_o]))&0x0FFF;
+ free(buffer);
+ return next_cluster;
+ }
+ case UP_FAT16:
+ {
+ const uint16_t *p16=(const uint16_t*)buffer;
+ offset_s=cluster/(disk_car->sector_size/2);
+ offset_o=cluster%(disk_car->sector_size/2);
+ if(disk_car->read(disk_car,disk_car->sector_size, buffer, partition->part_offset+(uint64_t)(offset+offset_s)*disk_car->sector_size)!=0)
+ {
+ log_error("get_next_cluster read error\n"); return 0;
+ }
+ next_cluster=le16(p16[offset_o]);
+ free(buffer);
+ return next_cluster;
+ }
+ case UP_FAT32:
+ {
+ const uint32_t *p32=(const uint32_t*)buffer;
+ offset_s=cluster/(disk_car->sector_size/4);
+ offset_o=cluster%(disk_car->sector_size/4);
+ if(disk_car->read(disk_car,disk_car->sector_size, buffer, partition->part_offset+(uint64_t)(offset+offset_s)*disk_car->sector_size)!=0)
+ {
+ log_error("get_next_cluster read error\n"); return 0;
+ }
+ /* FAT32 used 28 bits, the 4 high bits are reserved
+ * 0x00000000: free cluster
+ * 0x0FFFFFF7: bad cluster
+ * 0x0FFFFFF8+: EOC End of cluster
+ * */
+ next_cluster=le32(p32[offset_o])&0xFFFFFFF;
+ free(buffer);
+ return next_cluster;
+ }
+ default:
+ log_critical("fat.c get_next_cluster unknown fat type\n");
+ free(buffer);
+ return 0;
+ }
+}
+
+int set_next_cluster(disk_t *disk_car,const partition_t *partition, const upart_type_t upart_type,const int offset, const unsigned int cluster, const unsigned int next_cluster)
+{
+ unsigned char *buffer;
+ unsigned long int offset_s,offset_o;
+ const unsigned int buffer_size=(upart_type==UP_FAT12?2*disk_car->sector_size:disk_car->sector_size);
+ buffer=(unsigned char*)MALLOC(buffer_size);
+ /* Offset can be offset to FAT1 or to FAT2 */
+ /* log_trace("set_next_cluster(upart_type=%u,offset=%u,cluster=%u,next_cluster=%u)\n",upart_type,offset,cluster,next_cluster); */
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ offset_s=(cluster+cluster/2)/disk_car->sector_size;
+ offset_o=(cluster+cluster/2)%disk_car->sector_size;
+ break;
+ case UP_FAT16:
+ offset_s=cluster/(disk_car->sector_size/2);
+ offset_o=cluster%(disk_car->sector_size/2);
+ break;
+ case UP_FAT32:
+ offset_s=cluster/(disk_car->sector_size/4);
+ offset_o=cluster%(disk_car->sector_size/4);
+ break;
+ default:
+ log_critical("fat.c set_next_cluster unknown fat type\n");
+ free(buffer);
+ return 1;
+ }
+ if(disk_car->read(disk_car,buffer_size, buffer, partition->part_offset+(uint64_t)(offset+offset_s)*disk_car->sector_size)!=0)
+ {
+ log_error("set_next_cluster read error\n");
+ free(buffer);
+ return 1;
+ }
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ if((cluster&1)!=0)
+ (*((uint16_t*)&buffer[offset_o]))=le16((next_cluster<<4) | (le16(*((uint16_t*)&buffer[offset_o]))&0xF));
+ else
+ (*((uint16_t*)&buffer[offset_o]))=le16((next_cluster) | (le16(*((uint16_t*)&buffer[offset_o]))&0xF000));
+ break;
+ case UP_FAT16:
+ {
+ uint16_t *p16=(uint16_t*)buffer;
+ p16[offset_o]=le16(next_cluster);
+ }
+ break;
+ case UP_FAT32:
+ {
+ uint32_t *p32=(uint32_t*)buffer;
+ /* FAT32 used 28 bits, the 4 high bits are reserved
+ * 0x00000000: free cluster
+ * 0x0FFFFFF7: bad cluster
+ * 0x0FFFFFF8+: EOC End of cluster
+ * */
+ p32[offset_o]=le32(next_cluster);
+ }
+ break;
+ default: /* Avoid compiler warning */
+ break;
+ }
+ if(disk_car->write(disk_car,buffer_size, &buffer, partition->part_offset+(uint64_t)(offset+offset_s)*disk_car->sector_size)!=0)
+ {
+ display_message("Write error: set_next_cluster write error\n");
+ free(buffer);
+ return 1;
+ }
+ free(buffer);
+ return 0;
+}
+
+unsigned int fat32_get_prev_cluster(disk_t *disk_car,const partition_t *partition, const unsigned int fat_offset, const unsigned int cluster, const unsigned int no_of_cluster)
+{
+ const uint32_t *p32;
+ uint64_t hd_offset=partition->part_offset+(uint64_t)fat_offset*disk_car->sector_size;
+ unsigned int prev_cluster;
+ unsigned char *buffer=MALLOC(disk_car->sector_size);
+ p32=(const uint32_t*)buffer;
+
+ for(prev_cluster=2;prev_cluster<=no_of_cluster+1;prev_cluster++)
+ {
+ unsigned int offset_s,offset_o;
+ offset_s=prev_cluster/(disk_car->sector_size/4);
+ offset_o=prev_cluster%(disk_car->sector_size/4);
+ if((offset_o==0)||(prev_cluster==2))
+ {
+ if(disk_car->read(disk_car,disk_car->sector_size, &buffer, hd_offset)!=0)
+ {
+ log_error("fat32_get_prev_cluster error\n"); return 0;
+ }
+ hd_offset+=disk_car->sector_size;
+ }
+ if((le32(p32[offset_o]) & 0xFFFFFFF) ==cluster)
+ {
+ free(buffer);
+ return prev_cluster;
+ }
+ }
+ free(buffer);
+ return 0;
+}
+
+/*
+static unsigned int get_prev_cluster(disk_t *disk_car,const partition_t *partition, const upart_type_t upart_type,const int offset, const unsigned int cluster, const unsigned int no_of_cluster)
+{
+ unsigned int prev_cluster;
+ for(prev_cluster=2;prev_cluster<=no_of_cluster+1;prev_cluster++)
+ {
+ if(get_next_cluster(disk_car,partition,upart_type,offset, prev_cluster)==cluster)
+ return prev_cluster;
+ }
+ return 0;
+}
+*/
+
+int test_FAT(disk_t *disk_car,const struct fat_boot_sector *fat_header, partition_t *partition,const int verbose, const int dump_ind)
+{
+ upart_type_t upart_type=UP_UNK;
+ unsigned long int start_fat1,start_fat2,start_rootdir,start_data,no_of_cluster,fat_length,fat_length_calc,part_size,end_data;
+ const char *buffer=(const char*)fat_header;
+ if(!(le16(fat_header->marker)==0xAA55
+ && (fat_header->ignored[0]==0xeb || fat_header->ignored[0]==0xe9)
+ && (fat_header->fats==1 || fat_header->fats==2)))
+ return 1; /* Obviously not a FAT */
+ if(verbose>1)
+ {
+ log_trace("test_FAT\n");
+ log_partition(disk_car,partition);
+ }
+#ifdef HAVE_NCURSES
+ if(dump_ind!=0)
+ dump_ncurses(fat_header,DEFAULT_SECTOR_SIZE);
+#endif
+ if(!((fat_header->ignored[0]==0xeb && fat_header->ignored[2]==0x90)||fat_header->ignored[0]==0xe9))
+ {
+ aff_buffer(BUFFER_ADD,msg_CHKFAT_BAD_JUMP);
+ log_error(msg_CHKFAT_BAD_JUMP);
+ return 1;
+ }
+ if(fat_sector_size(fat_header)!=disk_car->sector_size)
+ {
+ aff_buffer(BUFFER_ADD,"check_FAT: Incorrect number of bytes per sector %u (FAT) != %u (HD)\n",fat_sector_size(fat_header),disk_car->sector_size);
+ log_error("check_FAT: Incorrect number of bytes per sector %u (FAT) != %u (HD)\n",fat_sector_size(fat_header),disk_car->sector_size);
+ return 1;
+ }
+ switch(fat_header->cluster_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ break;
+ default:
+ aff_buffer(BUFFER_ADD,msg_CHKFAT_SECT_CLUSTER);
+ log_error(msg_CHKFAT_SECT_CLUSTER);
+ return 1;
+ }
+ switch(fat_header->fats)
+ {
+ case 1:
+ aff_buffer(BUFFER_ADD,"check_FAT: Unusual, only one FAT\n");
+ log_warning("check_FAT: Unusual, only one FAT\n");
+ break;
+ case 2:
+ break;
+ default:
+ aff_buffer(BUFFER_ADD,"check_FAT: Bad number %u of FAT\n", fat_header->fats);
+ log_error("check_FAT: Bad number %u of FAT\n", fat_header->fats);
+ return 1;
+ }
+ if(fat_header->media!=0xF0 && fat_header->media<0xF8)
+ { /* Legal values are 0xF0, 0xF8-0xFF */
+ aff_buffer(BUFFER_ADD,"check_FAT: Bad media descriptor (0x%2x!=0xf8)\n",fat_header->media);
+ log_error("check_FAT: Bad media descriptor (0x%2x!=0xf8)\n",fat_header->media);
+ return 1;
+ }
+ if(fat_header->media!=0xF8)
+ { /* the only value I have ever seen is 0xF8 */
+ aff_buffer(BUFFER_ADD,"check_FAT: Unusual media descriptor (0x%2x!=0xf8)\n",fat_header->media);
+ log_warning("check_FAT: Unusual media descriptor (0x%2x!=0xf8)\n",fat_header->media);
+ }
+ fat_length=le16(fat_header->fat_length)>0?le16(fat_header->fat_length):le32(fat_header->fat32_length);
+ part_size=(sectors(fat_header)>0?sectors(fat_header):le32(fat_header->total_sect));
+ start_fat1=le16(fat_header->reserved);
+ start_fat2=start_fat1+(fat_header->fats>1?fat_length:0);
+ start_data=start_fat1+fat_header->fats*fat_length+(get_dir_entries(fat_header)*32+disk_car->sector_size-1)/disk_car->sector_size;
+ no_of_cluster=(part_size-start_data)/fat_header->cluster_size;
+ end_data=start_data+no_of_cluster*fat_header->cluster_size-1;
+ if(verbose>1)
+ {
+ log_info("number of cluster = %lu\n",no_of_cluster);
+ }
+ if(no_of_cluster<4085)
+ {
+ upart_type=UP_FAT12;
+ if(verbose>0)
+ {
+ log_info("FAT12 at %u/%u/%u\n",
+ offset2cylinder(disk_car,partition->part_offset),
+ offset2head(disk_car,partition->part_offset),
+ offset2sector(disk_car,partition->part_offset));
+ }
+ if(sectors(fat_header)==0)
+ {
+ aff_buffer(BUFFER_ADD,msg_CHKFAT_SIZE);
+ log_error(msg_CHKFAT_SIZE);
+ }
+ if(le16(fat_header->reserved)!=1)
+ {
+ aff_buffer(BUFFER_ADD,"check_FAT: Unusual number of reserved sectors %u (FAT), should be 1.\n",le16(fat_header->reserved));
+ log_warning("check_FAT: Unusual number of reserved sectors %u (FAT), should be 1.\n",le16(fat_header->reserved));
+ }
+ if((get_dir_entries(fat_header)==0)||(get_dir_entries(fat_header)%16!=0))
+ {
+ aff_buffer(BUFFER_ADD,msg_CHKFAT_ENTRY);
+ log_error(msg_CHKFAT_ENTRY);
+ return 1;
+ }
+ if((le16(fat_header->fat_length)>256)||(le16(fat_header->fat_length)==0))
+ {
+ aff_buffer(BUFFER_ADD,msg_CHKFAT_SECTPFAT);
+ log_error(msg_CHKFAT_SECTPFAT);
+ return 1;
+ }
+ start_rootdir=start_fat2+fat_length;
+ fat_length_calc=((no_of_cluster+2+disk_car->sector_size*2/3-1)*3/2/disk_car->sector_size);
+ partition->upart_type=UP_FAT12;
+ if(memcmp(buffer+FAT_NAME1,"FAT12 ",8)!=0) /* 2 Mo max */
+ {
+ aff_buffer(BUFFER_ADD,"Should be marked as FAT12\n");
+ log_warning("Should be marked as FAT12\n");
+ }
+ }
+ else if(no_of_cluster<65525)
+ {
+ upart_type=UP_FAT16;
+ if(verbose>0)
+ {
+ log_info("FAT16 at %u/%u/%u\n",
+ offset2cylinder(disk_car,partition->part_offset),
+ offset2head(disk_car,partition->part_offset),
+ offset2sector(disk_car,partition->part_offset));
+ }
+ if(le16(fat_header->reserved)!=1)
+ {
+ aff_buffer(BUFFER_ADD,"check_FAT: Unusual number of reserved sectors %u (FAT), should be 1.\n",le16(fat_header->reserved));
+ log_warning("check_FAT: Unusual number of reserved sectors %u (FAT), should be 1.\n",le16(fat_header->reserved));
+ }
+ if(le16(fat_header->fat_length)==0)
+ {
+ aff_buffer(BUFFER_ADD,msg_CHKFAT_SECTPFAT);
+ log_error(msg_CHKFAT_SECTPFAT);
+ return 1;
+ }
+ if((get_dir_entries(fat_header)==0)||(get_dir_entries(fat_header)%16!=0))
+ {
+ aff_buffer(BUFFER_ADD,msg_CHKFAT_ENTRY);
+ log_error(msg_CHKFAT_ENTRY);
+ return 1;
+ }
+ start_rootdir=start_fat2+fat_length;
+ fat_length_calc=((no_of_cluster+2+disk_car->sector_size/2-1)*2/disk_car->sector_size);
+ partition->upart_type=UP_FAT16;
+ if(memcmp(buffer+FAT_NAME1,"FAT16 ",8)!=0)
+ {
+ aff_buffer(BUFFER_ADD,"Should be marked as FAT16\n");
+ log_warning("Should be marked as FAT16\n");
+ }
+ }
+ else
+ {
+ upart_type=UP_FAT32;
+ if(verbose>0)
+ {
+ log_info("FAT32 at %u/%u/%u\n",
+ offset2cylinder(disk_car,partition->part_offset),
+ offset2head(disk_car,partition->part_offset),
+ offset2sector(disk_car,partition->part_offset));
+ }
+ if(sectors(fat_header)!=0)
+ {
+ aff_buffer(BUFFER_ADD,msg_CHKFAT_SIZE);
+ log_error(msg_CHKFAT_SIZE);
+ return 1;
+ }
+ if(get_dir_entries(fat_header)!=0)
+ {
+ aff_buffer(BUFFER_ADD,msg_CHKFAT_ENTRY);
+ log_error(msg_CHKFAT_ENTRY);
+ return 1;
+ }
+ if((fat_header->version[0]!=0) || (fat_header->version[1]!=0))
+ {
+ aff_buffer(BUFFER_ADD,msg_CHKFAT_BADFAT32VERSION);
+ log_error(msg_CHKFAT_BADFAT32VERSION);
+ }
+ if((le32(fat_header->root_cluster)<2) ||(le32(fat_header->root_cluster)>=2+no_of_cluster))
+ {
+ aff_buffer(BUFFER_ADD,"Bad root_cluster\n");
+ log_error("Bad root_cluster\n");
+ return 1;
+ }
+ start_rootdir=start_data+(le32(fat_header->root_cluster)-2)*fat_header->cluster_size;
+ fat_length_calc=((no_of_cluster+2+disk_car->sector_size/4-1)*4/disk_car->sector_size);
+ partition->upart_type=UP_FAT32;
+ if(memcmp(buffer+FAT_NAME2,"FAT32 ",8)!=0)
+ {
+ aff_buffer(BUFFER_ADD,"Should be marked as FAT32\n");
+ log_warning("Should be marked as FAT32\n");
+ }
+ }
+ if(partition->part_size>0)
+ {
+ if(part_size > partition->part_size/disk_car->sector_size)
+ {
+ aff_buffer(BUFFER_ADD,msg_CHKFAT_SIZE);
+ log_error("test_FAT size boot_sector %lu > partition %lu\n",
+ (long unsigned)part_size,
+ (long unsigned)(partition->part_size/disk_car->sector_size));
+ return 1;
+ }
+ else
+ {
+ if(verbose>0 && part_size!=partition->part_size)
+ log_warning("test_FAT size boot_sector %lu, partition %lu\n",
+ (long unsigned)part_size,
+ (long unsigned)(partition->part_size/disk_car->sector_size));
+ }
+ }
+ if(verbose>0)
+ {
+ log_info("FAT1 : %lu-%lu\n",start_fat1,start_fat1+fat_length-1);
+ log_info("FAT2 : %lu-%lu\n",start_fat2,start_fat2+fat_length-1);
+ log_info("start_rootdir : %lu",start_rootdir);
+ if(partition->upart_type==UP_FAT32)
+ log_info(" root cluster : %u",(unsigned int)le32(fat_header->root_cluster));
+ log_info("\nData : %lu-%lu\n",start_data,end_data);
+ log_info("sectors : %lu\n",part_size);
+ log_info("cluster_size : %u\n",fat_header->cluster_size);
+ log_info("no_of_cluster : %lu (2 - %lu)\n", no_of_cluster,no_of_cluster+1);
+ log_info("fat_length %lu calculated %lu\n",fat_length,fat_length_calc);
+ }
+ if(fat_length<fat_length_calc)
+ {
+ aff_buffer(BUFFER_ADD,msg_CHKFAT_SECTPFAT);
+ return 1;
+ }
+ if(fat_header->fats>1)
+ comp_FAT(disk_car,partition,fat_length,le16(fat_header->reserved));
+ if(le16(fat_header->heads)!=disk_car->CHS.head+1)
+ {
+ aff_buffer(BUFFER_ADD,"Warning: Incorrect number of heads/cylinder %u (FAT) != %u (HD)\n",le16(fat_header->heads),disk_car->CHS.head+1);
+ log_warning("heads/cylinder %u (FAT) != %u (HD)\n",le16(fat_header->heads),disk_car->CHS.head+1);
+ }
+ if(le16(fat_header->secs_track)!=disk_car->CHS.sector)
+ {
+ aff_buffer(BUFFER_ADD,"Warning: Incorrect number of sectors per track %u (FAT) != %u (HD)\n",le16(fat_header->secs_track),disk_car->CHS.sector);
+ log_warning("sect/track %u (FAT) != %u (HD)\n",le16(fat_header->secs_track),disk_car->CHS.sector);
+ }
+ return 0;
+}
+
+int comp_FAT(disk_t *disk_car,const partition_t *partition,const unsigned long int fat_size,const unsigned long int sect_res)
+{
+ /*
+ return 0 if FATs match
+ */
+ unsigned int reste;
+ uint64_t hd_offset, hd_offset2;
+ unsigned char *buffer, *buffer2;
+ buffer=(unsigned char *)MALLOC(NBR_SECT*disk_car->sector_size);
+ buffer2=(unsigned char *)MALLOC(NBR_SECT*disk_car->sector_size);
+ hd_offset=partition->part_offset+(uint64_t)sect_res*disk_car->sector_size;
+ hd_offset2=hd_offset+(uint64_t)fat_size*disk_car->sector_size;
+ reste=(fat_size>1000?1000:fat_size); /* Quick check ! */
+ while(reste>0)
+ {
+ const unsigned int read_size=reste>NBR_SECT?NBR_SECT:reste;
+ reste-=read_size;
+ if(disk_car->read(disk_car,read_size*disk_car->sector_size, buffer, hd_offset))
+ {
+ log_error("comp_FAT: can't read FAT1\n");
+ return 1;
+ }
+ if(disk_car->read(disk_car,read_size*disk_car->sector_size, buffer2, hd_offset2))
+ {
+ log_error("comp_FAT: can't read FAT2\n");
+ return 1;
+ }
+ if(memcmp(buffer,buffer2,disk_car->sector_size*read_size)!=0)
+ {
+ log_error("FAT differs, FAT sectors=%lu-%lu/%lu\n",
+ (unsigned long) ((hd_offset-partition->part_offset)/disk_car->sector_size-sect_res),
+ (unsigned long) ((hd_offset-partition->part_offset)/disk_car->sector_size-sect_res+read_size),
+ fat_size);
+ free(buffer2);
+ free(buffer);
+ return 1;
+ }
+ hd_offset+=read_size*disk_car->sector_size;
+ hd_offset2+=read_size*disk_car->sector_size;
+ }
+ free(buffer2);
+ free(buffer);
+ return 0;
+}
+
+unsigned int fat_sector_size(const struct fat_boot_sector *fat_header)
+{ return (fat_header->sector_size[1]<<8)+fat_header->sector_size[0]; }
+
+unsigned int get_dir_entries(const struct fat_boot_sector *fat_header)
+{ return (fat_header->dir_entries[1]<<8)+fat_header->dir_entries[0]; }
+
+unsigned int sectors(const struct fat_boot_sector *fat_header)
+{ return (fat_header->sectors[1]<<8)+fat_header->sectors[0]; }
+
+unsigned long int fat32_get_free_count(const unsigned char *boot_fat32, const unsigned int sector_size)
+{
+ return (boot_fat32[sector_size+0x1E8+3]<<24)+(boot_fat32[sector_size+0x1E8+2]<<16)+(boot_fat32[sector_size+0x1E8+1]<<8)+boot_fat32[sector_size+0x1E8];
+}
+
+unsigned long int fat32_get_next_free(const unsigned char *boot_fat32, const unsigned int sector_size)
+{
+ return (boot_fat32[sector_size+0x1EC+3]<<24)+(boot_fat32[sector_size+0x1EC+2]<<16)+(boot_fat32[sector_size+0x1EC+1]<<8)+boot_fat32[sector_size+0x1EC];
+}
+
+int recover_FAT(disk_t *disk_car, const struct fat_boot_sector*fat_header, partition_t *partition, const int verbose, const int dump_ind, const int backup)
+{
+ if(test_FAT(disk_car, fat_header, partition, verbose, dump_ind))
+ return 1;
+ partition->part_size=(uint64_t)(sectors(fat_header)>0?sectors(fat_header):le32(fat_header->total_sect)) *
+ fat_sector_size(fat_header);
+ /* test_FAT has set partition->upart_type */
+ switch(partition->upart_type)
+ {
+ case UP_FAT12:
+ if(verbose||dump_ind)
+ {
+ log_info("\nFAT12 at %u/%u/%u\n",
+ offset2cylinder(disk_car,partition->part_offset),
+ offset2head(disk_car,partition->part_offset),
+ offset2sector(disk_car,partition->part_offset));
+ }
+ partition->part_type_i386=P_12FAT;
+ partition->part_type_gpt=GPT_ENT_TYPE_MS_BASIC_DATA;
+ break;
+ case UP_FAT16:
+ if(verbose||dump_ind)
+ {
+ log_info("\nFAT16 at %u/%u/%u\n",
+ offset2cylinder(disk_car,partition->part_offset),
+ offset2head(disk_car,partition->part_offset),
+ offset2sector(disk_car,partition->part_offset));
+ }
+ if(sectors(fat_header)!=0)
+ partition->part_type_i386=P_16FAT;
+ else if(offset2cylinder(disk_car,partition->part_offset+partition->part_size-1)<=1024)
+ partition->part_type_i386=P_16FATBD;
+ else
+ partition->part_type_i386=P_16FATBD_LBA;
+ partition->part_type_gpt=GPT_ENT_TYPE_MS_BASIC_DATA;
+ break;
+ case UP_FAT32:
+ if(verbose||dump_ind)
+ {
+ log_info("\nFAT32 at %u/%u/%u\n",
+ offset2cylinder(disk_car,partition->part_offset),
+ offset2head(disk_car,partition->part_offset),
+ offset2sector(disk_car,partition->part_offset));
+ }
+ if(offset2cylinder(disk_car,partition->part_offset+partition->part_size-1)<=1024)
+ partition->part_type_i386=P_32FAT;
+ else
+ partition->part_type_i386=P_32FAT_LBA;
+ partition->part_type_mac=PMAC_FAT32;
+ partition->part_type_gpt=GPT_ENT_TYPE_MS_BASIC_DATA;
+ if(backup)
+ {
+ partition->boot_sector=6;
+ partition->part_offset-=6*512; /* backup sector */
+ }
+ break;
+ default:
+ log_critical("recover_FAT unknown FAT type\n");
+ return 1;
+ }
+ set_FAT_info(disk_car,fat_header,partition,verbose);
+ return 0;
+}
+
+int fat32_set_part_name(disk_t *disk_car, partition_t *partition, const struct fat_boot_sector*fat_header)
+{
+ partition->fsname[0]='\0';
+ if((fat_header->cluster_size>0)&&(fat_header->cluster_size<=128))
+ {
+ unsigned char *buffer=(unsigned char*)MALLOC(fat_header->cluster_size*disk_car->sector_size);
+ if(disk_car->read(disk_car,fat_header->cluster_size*disk_car->sector_size, buffer, partition->part_offset+(uint64_t)(le16(fat_header->reserved)+fat_header->fats*le32(fat_header->fat32_length)+(le32(fat_header->root_cluster)-2)*fat_header->cluster_size)*disk_car->sector_size))
+ {
+ log_error("fat32_set_part_name() cannot read FAT32 root cluster.\n");
+ }
+ else
+ {
+ int i;
+ int stop=0;
+ for(i=0;(i<16*fat_header->cluster_size)&&(stop==0);i++)
+ { /* Test attribut volume name and check if the volume name is erased or not */
+ if(((buffer[i*0x20+0xB] & ATTR_EXT) !=ATTR_EXT) && ((buffer[i*0x20+0xB] & ATTR_VOLUME) !=0) && (buffer[i*0x20]!=0xE5))
+ {
+ /* dump_ncurses(&buffer[i*0x20],0x20); */
+ fat_set_part_name(partition,&buffer[i*0x20],11);
+ if(check_volume_name(partition->fsname,11))
+ partition->fsname[0]='\0';
+ }
+ if(buffer[i*0x20]==0)
+ {
+ stop=1;
+ }
+ }
+ }
+ free(buffer);
+ }
+ if(partition->fsname[0]=='\0')
+ {
+ log_info("set_FAT_info: name from BS used\n");
+ fat_set_part_name(partition,((const unsigned char*)fat_header)+FAT32_PART_NAME,11);
+ if(check_volume_name(partition->fsname,11))
+ partition->fsname[0]='\0';
+ }
+ return 0;
+}
+
+int check_HPFS(disk_t *disk_car,partition_t *partition,const int verbose)
+{
+ unsigned char buffer[512];
+ if(disk_car->read(disk_car,disk_car->sector_size, &buffer, partition->part_offset)!=0)
+ {
+ aff_buffer(BUFFER_ADD,"check_HPFS: Read error\n");
+ log_error("check_HPFS: Read error\n");
+ return 1;
+ }
+ if(test_HPFS(disk_car,(const struct fat_boot_sector *)buffer,partition,verbose,0)!=0)
+ {
+ if(verbose>0)
+ {
+ log_info("\n\ntest_HPFS()\n");
+ log_partition(disk_car,partition);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int test_HPFS(disk_t *disk_car,const struct fat_boot_sector *fat_header, partition_t *partition,const int verbose, const int dump_ind)
+{
+ const char*buffer=(const char*)fat_header;
+ if(le16(fat_header->marker)==0xAA55)
+ {
+ if(memcmp(buffer+OS2_NAME,"IBM",3)==0)
+ { /* D'apres une analyse de OS2 sur systeme FAT...
+ FAT_NAME1=FAT
+ */
+ if(verbose||dump_ind)
+ {
+ log_info("\nHPFS maybe at %u/%u/%u\n",
+ offset2cylinder(disk_car,partition->part_offset),
+ offset2head(disk_car,partition->part_offset),
+ offset2sector(disk_car,partition->part_offset));
+ }
+#ifdef HAVE_NCURSES
+ if(dump_ind)
+ dump_ncurses(buffer,DEFAULT_SECTOR_SIZE);
+#endif
+ partition->part_size=(uint64_t)(sectors(fat_header)>0?sectors(fat_header):le32(fat_header->total_sect)) *
+ fat_sector_size(fat_header);
+ partition->upart_type=UP_HPFS;
+ return 0;
+ }
+ } /* fin marqueur de fin :)) */
+ return 1;
+}
+
+int recover_HPFS(disk_t *disk_car,const struct fat_boot_sector*fat_header, partition_t *partition, const int verbose, const int dump_ind)
+{
+ if(test_HPFS(disk_car,fat_header,partition,verbose,0)!=0)
+ return 1;
+ partition->part_type_i386=P_HPFS;
+ partition->part_type_gpt=GPT_ENT_TYPE_MAC_HFS;
+ partition->fsname[0]='\0';
+ partition->info[0]='\0';
+ return 0;
+}
+
+int check_OS2MB(disk_t *disk_car,partition_t *partition,const int verbose)
+{
+ unsigned char buffer[0x200];
+ if(disk_car->read(disk_car,disk_car->sector_size, &buffer, partition->part_offset)!=0)
+ {
+ aff_buffer(BUFFER_ADD,"check_OS2MB: Read error\n");
+ log_error("check_OS2MB: Read error\n");
+ return 1;
+ }
+ if(test_OS2MB(disk_car,(const struct fat_boot_sector *)buffer,partition,verbose,0)!=0)
+ {
+ if(verbose>0)
+ {
+ log_info("\n\ntest_OS2MB()\n");
+ log_partition(disk_car,partition);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int recover_OS2MB(disk_t *disk_car, const struct fat_boot_sector*fat_header, partition_t *partition, const int verbose, const int dump_ind)
+{
+ if(test_OS2MB(disk_car, fat_header, partition, verbose, dump_ind))
+ return 1;
+ partition->part_size=(uint64_t)(disk_car->CHS.head+1) * disk_car->CHS.sector*disk_car->sector_size; /* 1 cylinder */
+ partition->part_type_i386=P_OS2MB;
+ partition->fsname[0]='\0';
+ partition->info[0]='\0';
+ return 0;
+}
+
+int test_OS2MB(disk_t *disk_car,const struct fat_boot_sector *fat_header, partition_t *partition,const int verbose, const int dump_ind)
+{
+ const char*buffer=(const char*)fat_header;
+ if(le16(fat_header->marker)==0xAA55 && memcmp(buffer+FAT_NAME1,"FAT ",8)==0)
+ {
+ if(verbose||dump_ind)
+ {
+ log_info("\nMarker (0xAA55) at %u/%u/%u\n", offset2cylinder(disk_car,partition->part_offset),offset2head(disk_car,partition->part_offset),offset2sector(disk_car,partition->part_offset));
+ }
+#ifdef HAVE_NCURSES
+ if(dump_ind)
+ dump_ncurses(buffer,DEFAULT_SECTOR_SIZE);
+#endif
+ partition->upart_type=UP_OS2MB;
+ return 0;
+ }
+ return 1;
+}
+
+int is_fat(const partition_t *partition)
+{
+ return (is_fat12(partition)||is_fat16(partition)||is_fat32(partition));
+}
+
+int is_part_fat(const partition_t *partition)
+{
+ return (is_part_fat12(partition)||is_part_fat16(partition)||is_part_fat32(partition));
+}
+
+int is_part_fat12(const partition_t *partition)
+{
+ switch(partition->part_type_i386)
+ {
+ case P_12FAT:
+ case P_12FATH:
+ return 1;
+ default:
+ break;
+ }
+ /*
+ if(guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_MS_BASIC_DATA)==0)
+ return 1;
+ */
+ return 0;
+}
+
+int is_fat12(const partition_t *partition)
+{
+ return (is_part_fat12(partition) || partition->upart_type==UP_FAT12);
+}
+
+int is_part_fat16(const partition_t *partition)
+{
+ switch(partition->part_type_i386)
+ {
+ case P_16FAT:
+ case P_16FATH:
+ case P_16FATBD_LBA:
+ case P_16FATBD:
+ case P_16FATBDH:
+ case P_16FATBD_LBAH:
+ return 1;
+ default:
+ break;
+ }
+ /*
+ if(guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_MS_BASIC_DATA)==0)
+ return 1;
+ */
+ return 0;
+}
+
+int is_fat16(const partition_t *partition)
+{
+ return (is_part_fat16(partition) || partition->upart_type==UP_FAT16);
+}
+
+int is_part_fat32(const partition_t *partition)
+{
+ switch(partition->part_type_i386)
+ {
+ case P_32FAT:
+ case P_32FAT_LBA:
+ case P_32FATH:
+ case P_32FAT_LBAH:
+ return 1;
+ default:
+ break;
+ }
+ if(partition->part_type_mac==PMAC_FAT32)
+ return 1;
+ /*
+ if(guid_cmp(partition->part_type_gpt,GPT_ENT_TYPE_MS_BASIC_DATA)==0)
+ return 1;
+ */
+ return 0;
+}
+
+int is_fat32(const partition_t *partition)
+{
+ return (is_part_fat32(partition) || partition->upart_type==UP_FAT32);
+}
+
+int fat32_free_info(disk_t *disk_car,const partition_t *partition, const unsigned int fat_offset, const unsigned int no_of_cluster, unsigned int *next_free, unsigned int*free_count)
+{
+ unsigned char *buffer;
+ const uint32_t *p32;
+ unsigned int prev_cluster;
+ uint64_t hd_offset=partition->part_offset+(uint64_t)fat_offset*disk_car->sector_size;
+ buffer=(unsigned char *)MALLOC(disk_car->sector_size);
+ p32=(const uint32_t*)buffer;
+ *next_free=0;
+ *free_count=0;
+ for(prev_cluster=2;prev_cluster<=no_of_cluster+1;prev_cluster++)
+ {
+ unsigned long int cluster;
+ unsigned int offset_s,offset_o;
+ offset_s=prev_cluster/(disk_car->sector_size/4);
+ offset_o=prev_cluster%(disk_car->sector_size/4);
+ if((offset_o==0)||(prev_cluster==2))
+ {
+ if(disk_car->read(disk_car,disk_car->sector_size, buffer, hd_offset)!=0)
+ {
+ log_error("fat32_free_info read error\n");
+ *next_free=0xFFFFFFFF;
+ *free_count=0xFFFFFFFF;
+ return 1;
+ }
+ hd_offset+=disk_car->sector_size;
+ }
+ cluster=le32(p32[offset_o]) & 0xFFFFFFF;
+ if(cluster==0)
+ {
+ (*free_count)++;
+ if(*next_free==0)
+ *next_free=prev_cluster;
+ }
+ }
+ log_info("next_free %u, free_count %u\n",*next_free,*free_count);
+ free(buffer);
+ return 0;
+}
+
diff --git a/src/fat.h b/src/fat.h
new file mode 100644
index 0000000..2ac42e0
--- /dev/null
+++ b/src/fat.h
@@ -0,0 +1,164 @@
+/*
+
+ File: fat.h
+
+ Copyright (C) 1998-2004,2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifndef _FAT_H
+#define _FAT_H
+#define FAT1X_PART_NAME 0x2B
+#define FAT32_PART_NAME 0x47
+#define FAT_NAME1 0x36
+#define FAT_NAME2 0x52 /* FAT32 only */
+#define NTFS_NAME 0x03
+#define OS2_NAME 0x03
+
+#define NBR_SECT 8
+
+/*
+ * FAT partition boot sector information, taken from the Linux
+ * kernel sources.
+ */
+
+struct fat_boot_sector {
+ uint8_t ignored[3]; /* 0x00 Boot strap short or near jump */
+ int8_t system_id[8]; /* 0x03 Name - can be used to special case
+ partition manager volumes */
+ uint8_t sector_size[2]; /* 0x0B bytes per logical sector */
+ uint8_t cluster_size; /* 0x0D sectors/cluster */
+ uint16_t reserved; /* 0x0E reserved sectors */
+ uint8_t fats; /* 0x10 number of FATs */
+ uint8_t dir_entries[2]; /* 0x11 root directory entries */
+ uint8_t sectors[2]; /* 0x13 number of sectors */
+ uint8_t media; /* 0x15 media code (unused) */
+ uint16_t fat_length; /* 0x16 sectors/FAT */
+ uint16_t secs_track; /* 0x18 sectors per track */
+ uint16_t heads; /* 0x1A number of heads */
+ uint32_t hidden; /* 0x1C hidden sectors (unused) */
+ uint32_t total_sect; /* 0x20 number of sectors (if sectors == 0) */
+
+ /* The following fields are only used by FAT32 */
+ uint32_t fat32_length; /* 0x24=36 sectors/FAT */
+ uint16_t flags; /* 0x28 bit 8: fat mirroring, low 4: active fat */
+ uint8_t version[2]; /* 0x2A major, minor filesystem version */
+ uint32_t root_cluster; /* 0x2C first cluster in root directory */
+ uint16_t info_sector; /* 0x30 filesystem info sector */
+ uint16_t backup_boot; /* 0x32 backup boot sector */
+ uint8_t BPB_Reserved[12]; /* 0x34 Unused */
+ uint8_t BS_DrvNum; /* 0x40 */
+ uint8_t BS_Reserved1; /* 0x41 */
+ uint8_t BS_BootSig; /* 0x42 */
+ uint8_t BS_VolID[4]; /* 0x43 */
+ uint8_t BS_VolLab[11]; /* 0x47 */
+ uint8_t BS_FilSysType[8]; /* 0x52=82*/
+
+ /* */
+ uint8_t nothing[420]; /* 0x5A */
+ uint16_t marker;
+} __attribute__ ((__packed__));
+
+struct msdos_dir_entry {
+ int8_t name[8],ext[3]; /* name and extension */
+ uint8_t attr; /* attribute bits */
+ uint8_t lcase; /* Case for base and extension */
+ uint8_t ctime_ms; /* Creation time, milliseconds */
+ uint16_t ctime; /* Creation time */
+ uint16_t cdate; /* Creation date */
+ uint16_t adate; /* Last access date */
+ uint16_t starthi; /* High 16 bits of cluster in FAT32 */
+ uint16_t time; /* time, date and first cluster */
+ uint16_t date;
+ uint16_t start;
+ uint32_t size; /* file size (in bytes) */
+};
+
+/* Up to 13 characters of the name */
+struct msdos_dir_slot {
+ uint8_t id; /* 00 sequence number for slot */
+ uint8_t name0_4[10]; /* 01 first 5 characters in name */
+ uint8_t attr; /* 0B attribute byte */
+ uint8_t reserved; /* 0C always 0 */
+ uint8_t alias_checksum; /* 0D checksum for 8.3 alias */
+ uint8_t name5_10[12]; /* 0E 6 more characters in name */
+ uint16_t start; /* starting cluster number, 0 in long slots */
+ uint8_t name11_12[4]; /* last 2 characters in name */
+};
+
+
+int comp_FAT(disk_t *disk_car,const partition_t *partition, const unsigned long int fat_size, const unsigned long int sect_res);
+int log_fat2_info(const struct fat_boot_sector*fh1, const struct fat_boot_sector*fh2, const upart_type_t upart_type, const unsigned int sector_size);
+
+unsigned int get_next_cluster(disk_t *disk_car,const partition_t *partition, const upart_type_t upart_type,const int offset, const unsigned int cluster);
+int set_next_cluster(disk_t *disk_car,const partition_t *partition, const upart_type_t upart_type,const int offset, const unsigned int cluster, const unsigned int next_cluster);
+
+int is_fat(const partition_t *partition);
+int is_fat12(const partition_t *partition);
+int is_fat16(const partition_t *partition);
+int is_fat32(const partition_t *partition);
+int is_part_fat(const partition_t *partition);
+int is_part_fat12(const partition_t *partition);
+int is_part_fat16(const partition_t *partition);
+int is_part_fat32(const partition_t *partition);
+unsigned int get_dir_entries(const struct fat_boot_sector *fat_header);
+int dump_fat_info(const struct fat_boot_sector*fh1, const upart_type_t upart_type, const unsigned int sector_size);
+int dump_2fat_info(const struct fat_boot_sector*fh1, const struct fat_boot_sector*fh2, const upart_type_t upart_type, const unsigned int sector_size);
+int fat32_set_part_name(disk_t *disk_car, partition_t *partition, const struct fat_boot_sector*fat_header);
+unsigned int fat_sector_size(const struct fat_boot_sector *fat_header);
+unsigned int sectors(const struct fat_boot_sector *fat_header);
+unsigned int fat32_get_prev_cluster(disk_t *disk_car,const partition_t *partition, const unsigned int fat_offset, const unsigned int cluster, const unsigned int no_of_cluster);
+int fat32_free_info(disk_t *disk_car,const partition_t *partition, const unsigned int fat_offset, const unsigned int no_of_cluster, unsigned int *next_free, unsigned int*free_count);
+unsigned long int fat32_get_free_count(const unsigned char *boot_fat32, const unsigned int sector_size);
+unsigned long int fat32_get_next_free(const unsigned char *boot_fat32, const unsigned int sector_size);
+int repair_FAT_table(disk_t *disk_car, partition_t *partition, const int verbose);
+int FAT_init_rootdir(disk_t *disk_car, partition_t *partition, const int verbose);
+
+#define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */
+#define IS_FREE(n) (!*(n) || *(const unsigned char *) (n) == DELETED_FLAG)
+#define ATTR_RO 1 /* read-only */
+#define ATTR_HIDDEN 2 /* hidden */
+#define ATTR_SYS 4 /* system */
+#define ATTR_VOLUME 8 /* volume label */
+#define ATTR_DIR 16 /* directory */
+#define ATTR_ARCH 32 /* archived */
+
+#define ATTR_NONE 0 /* no attribute bits */
+#define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN)
+ /* attribute bits that are copied "as is" */
+#define ATTR_EXT (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME)
+#define ATTR_EXT_MASK (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME | ATTR_DIR | ATTR_ARCH)
+ /* bits that are used by the Windows 95/Windows NT extended FAT */
+#define FAT12_BAD 0x0FF7
+#define FAT12_EOC 0x0FF8
+#define FAT16_BAD 0xFFF7
+#define FAT16_EOC 0xFFF8
+#define FAT32_BAD 0x0FFFFFF7
+#define FAT32_EOC 0x0FFFFFF8
+#endif
+#define FAT1x_BOOT_SECTOR_SIZE 0x200
+
+int recover_FAT(disk_t *disk_car,const struct fat_boot_sector*fat_header, partition_t *partition, const int verbose, const int dump_ind, const int backup);
+int check_FAT(disk_t *disk_car,partition_t *partition, const int verbose);
+int test_FAT(disk_t *disk_car,const struct fat_boot_sector *fat_header, partition_t *partition,const int verbose, const int dump_ind);
+int recover_HPFS(disk_t *disk_car, const struct fat_boot_sector*fat_header, partition_t *partition, const int verbose, const int dump_ind);
+int check_HPFS(disk_t *disk_car,partition_t *partition, const int verbose);
+int test_HPFS(disk_t *disk_car,const struct fat_boot_sector *fat_header, partition_t *partition,const int verbose, const int dump_ind);
+int recover_OS2MB(disk_t *disk_car, const struct fat_boot_sector*fat_header, partition_t *partition, const int verbose, const int dump_ind);
+int check_OS2MB(disk_t *disk_car,partition_t *partition, const int verbose);
+int test_OS2MB(disk_t *disk_car,const struct fat_boot_sector *fat_header, partition_t *partition,const int verbose, const int dump_ind);
+
diff --git a/src/fat_adv.c b/src/fat_adv.c
new file mode 100644
index 0000000..be122d4
--- /dev/null
+++ b/src/fat_adv.c
@@ -0,0 +1,2975 @@
+/*
+
+ File: fat_adv.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "fat.h"
+#include "lang.h"
+#include "fnctdsk.h"
+#include "testdisk.h"
+#include "intrf.h"
+#ifdef HAVE_NCURSES
+#include "intrfn.h"
+#else
+#include <stdio.h>
+#endif
+#include "dir.h"
+#include "dirpart.h"
+#include "fat_dir.h"
+#include "io_redir.h"
+#include "log.h"
+
+#define INTER_FAT_ASK_X 0
+#define INTER_FAT_ASK_Y 23
+static const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+typedef struct sector_cluster_struct sector_cluster_t;
+typedef struct info_offset_struct info_offset_t;
+typedef struct cluster_offset_struct cluster_offset_t;
+
+struct sector_cluster_struct
+{
+ unsigned int sector;
+ unsigned int cluster;
+};
+
+struct info_offset_struct
+{
+ unsigned long int offset;
+ unsigned int nbr;
+ unsigned int fat_type;
+};
+
+struct cluster_offset_struct
+{
+ unsigned int cluster_size;
+ unsigned long int offset;
+ unsigned int nbr;
+ unsigned int first_sol;
+};
+static upart_type_t fat_find_info(disk_t *disk_car,unsigned int*reserved, unsigned int*fat_length, const partition_t *partition,const uint64_t max_offset,const int p_fat12,const int p_fat16,const int p_fat32,const int verbose,const int dump_ind,const int interface, const unsigned int expert, unsigned int *fats);
+static int fat_find_type(disk_t *disk_car,const partition_t *partition,const uint64_t max_offset,const int p_fat12,const int p_fat16,const int p_fat32,const int verbose,const int dump_ind,const int interface,unsigned int *nbr_offset,info_offset_t *info_offset, const unsigned int max_nbr_offset);
+
+static unsigned int fat_find_fat_start(const unsigned char *buffer,const int p_fat12, const int p_fat16, const int p_fat32,unsigned long int*fat_offset, const unsigned int sector_size);
+
+static upart_type_t no_of_cluster2part_type(const unsigned long int no_of_cluster);
+static void create_fat_boot_sector(disk_t *disk_car, partition_t *partition, const unsigned int reserved, const int verbose, const unsigned int dir_entries, const unsigned long int root_cluster, const unsigned int cluster_size, const unsigned int fat_length,const int interface, const upart_type_t upart_type, const unsigned int fats, char **current_cmd);
+static unsigned int fat32_find_root_cluster(disk_t *disk_car,const partition_t *partition,const unsigned int cluster_size, const unsigned long int no_of_cluster, const unsigned int reserved, const unsigned int fat_length, const int interface, const int verbose, const unsigned int expert, const unsigned int first_free_cluster, const unsigned int fats);
+static int write_FAT_boot_code_aux(unsigned char *buffer);
+static int find_cluster_size(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind,const int interface, unsigned int *cluster_size, unsigned long int *offset);
+static int find_dir_entries(disk_t *disk_car,const partition_t *partition, const unsigned int offset,const int verbose);
+static int find_cluster_size_aux(const sector_cluster_t *sector_cluster, const unsigned int nbr_sector_cluster,unsigned int *cluster_size, unsigned long int *offset, const int verbose, const unsigned long int part_size_in_sectors);
+static int analyse_dir_entries(disk_t *disk_car,const partition_t *partition, const unsigned int offset, const int verbose);
+static int analyse_dir_entries2(disk_t *disk_car,const partition_t *partition, const unsigned int reserved, const unsigned int fat_length,const int verbose, unsigned int root_size_max,const upart_type_t upart_type, const unsigned int fats);
+static int calcul_cluster_size(const upart_type_t upart_type, const unsigned long int data_size, const unsigned int fat_length, const unsigned int sector_size);
+static int check_entree(const unsigned char *entree);
+static int fat32_create_rootdir(disk_t *disk_car,const partition_t *partition, const unsigned int reserved, const unsigned int fat_length, const unsigned int root_cluster, const unsigned int cluster_size, const int verbose, file_data_t *rootdir_list, const unsigned int fats);
+
+static void fat_date_unix2dos(int unix_date,unsigned short *mstime, unsigned short *msdate);
+static upart_type_t select_fat_info(const info_offset_t *info_offset, const unsigned int nbr_offset,unsigned int*reserved, unsigned int*fat_length, const unsigned long int max_sector_offset, unsigned int *fats);
+static unsigned long int get_subdirectory(disk_t *disk_car,const uint64_t hd_offset, const unsigned long int i);
+
+/*
+ * 0 entree is free
+ * 1 entree is used
+ * 2 not an entry
+ * */
+static int check_entree(const unsigned char *entree)
+{
+ int i;
+ if((entree[0xB]&ATTR_EXT_MASK)==ATTR_EXT)
+ return 1;
+/* log_trace("check_entree %02x\n",*(entree+0)); */
+ if(entree[0]==0)
+ {
+ for(i=0;i<0x20;i++)
+ if(*(entree+i)!='\0')
+ return 2;
+ return 0;
+ }
+ if(entree[0]==0x20)
+ return 2;
+ if(entree[0]==0xE5)
+ return 1;
+ for(i=0;i<8+3;i++)
+ {
+ if((*(entree+i)>=0x06 && *(entree+i)<=0x1f)||
+ (*(entree+i)>=0x3a && *(entree+i)<=0x3f)||
+ (*(entree+i)>='a' && *(entree+i)<='z'))
+ return 2;
+ switch(*(entree+i))
+ {
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x22:
+ case 0x2A:
+ case 0x2B:
+ case 0x2C:
+ case 0x2E:
+ case 0x2F:
+ case 0x5B:
+ case 0x5C:
+ case 0x5D:
+ case 0x7C:
+/*log_trace("check_entree bad %c (%02x)\n",*(entree+i),*(entree+i)); */
+ return 2;
+ default:
+/*log_trace("check_entree good %c (%02x)\n",*(entree+i),*(entree+i)); */
+ break;
+ }
+ }
+ return 1;
+}
+
+/* */
+
+
+static unsigned long int get_subdirectory(disk_t *disk_car,const uint64_t hd_offset,const unsigned long int i)
+{
+ unsigned char buffer[DEFAULT_SECTOR_SIZE];
+ if(disk_car->read(disk_car,sizeof(buffer), &buffer, hd_offset)!=0)
+ {
+ log_error("fat_dir, get_subdirectory(), can't read directory\n");
+ return 1;
+ }
+/* dump_ncurses(buffer,DEFAULT_SECTOR_SIZE); */
+ /* 12345678123*/
+ if(memcmp(&buffer[0],". ",8+3)!=0)
+ return 1;
+ if((unsigned)((buffer[0x15]<<24)|(buffer[0x14]<<16)|(buffer[0x1B]<<8)|buffer[0x1A])!=i)
+ return 1;
+ /* 12345678123*/
+ if(memcmp(&buffer[0x20],".. ",8+3)!=0)
+ return 1;
+ return (buffer[0x35]<<24)+(buffer[0x34]<<16)+(buffer[0x3B]<<8)+buffer[0x3A];
+}
+
+#ifdef HAVE_NCURSES
+static int ask_root_directory(disk_t *disk_car, const partition_t *partition, const file_data_t*dir_list, const unsigned long int cluster)
+{
+ /* Return value
+ * -1: quit
+ * 1: back
+ * other: new cluster
+ * */
+ int car='A';
+ int quit=0;
+ int offset=0;
+ int pos_num=0;
+ const file_data_t *current_file;
+ const file_data_t *pos=dir_list;
+ WINDOW *window;
+ window=newwin(0,0,0,0); /* full screen */
+ aff_copy(window);
+ wmove(window,4,0);
+ aff_part(window,AFF_PART_ORDER,disk_car,partition);
+ wmove(window,6,0);
+ wdoprintf(window,"Answer Y(es), N(o) or A(bort interactive mode). N or A if not sure.");
+ curs_set(1);
+ do
+ {
+ int i;
+ for(i=0,current_file=dir_list;(current_file!=NULL) && (i<offset);current_file=current_file->next,i++);
+ for(i=offset;(current_file!=NULL) &&((i-offset)<INTER_DIR);i++,current_file=current_file->next)
+ {
+ struct tm *tm_p;
+ char str[11];
+ char datestr[80];
+ wmove(window,8+i-offset,0);
+ wclrtoeol(window); /* before addstr for BSD compatibility */
+ if(current_file==pos)
+ wattrset(window, A_REVERSE);
+ if(current_file->filestat.st_mtime!=0)
+ {
+ tm_p = localtime(&current_file->filestat.st_mtime);
+ snprintf(datestr, sizeof(datestr),"%2d-%s-%4d %02d:%02d",
+ tm_p->tm_mday, monstr[tm_p->tm_mon],
+ 1900 + tm_p->tm_year, tm_p->tm_hour,
+ tm_p->tm_min);
+ } else {
+ strncpy(datestr, " ",sizeof(datestr));
+ }
+ mode_string(current_file->filestat.st_mode,str);
+ wdoprintf(window, "%s %5u %5u ",
+ str, (unsigned int)current_file->filestat.st_uid, (unsigned int)current_file->filestat.st_gid);
+ wdoprintf(window, "%7llu", (long long unsigned int)current_file->filestat.st_size);
+ /* FIXME: screen overlaps due to long filename */
+ wdoprintf(window, " %s %s\n", datestr, current_file->name);
+ if(current_file==pos)
+ wattroff(window, A_REVERSE);
+ }
+ /* Clear the last line, useful if overlapping */
+ wmove(window,8+i-offset,0);
+ wclrtoeol(window); /* before addstr for BSD compatibility */
+ /* print the cluster in the loop, so */
+ /* the visible cursor will be at the end */
+ wmove(window,5,0);
+ wdoprintf(window,"Cluster %lu, Directory / found ? ", cluster);
+ wrefresh(window);
+ car=wgetch(window);
+ switch(car)
+ {
+ case 'a':
+ case 'A':
+ case 'y':
+ case 'Y':
+ case 'n':
+ case 'N':
+ quit=1;
+ break;
+ }
+ if(dir_list!=NULL)
+ {
+ switch(car)
+ {
+ case KEY_UP:
+ if(pos->prev!=NULL)
+ {
+ pos=pos->prev;
+ pos_num--;
+ }
+ if(pos_num<offset)
+ offset--;
+ break;
+ case KEY_DOWN:
+ if(pos->next!=NULL)
+ {
+ pos=pos->next;
+ pos_num++;
+ }
+ if(pos_num>=offset+INTER_DIR)
+ offset++;
+ break;
+ case KEY_PPAGE:
+ for(i=0;(i<INTER_DIR-1)&&(pos->prev!=NULL);i++)
+ {
+ pos=pos->prev;
+ pos_num--;
+ if(pos_num<offset)
+ offset--;
+ }
+ break;
+ case KEY_NPAGE:
+ for(i=0;(i<INTER_DIR-1)&&(pos->next!=NULL);i++)
+ {
+ pos=pos->next;
+ pos_num++;
+ if(pos_num>=offset+INTER_DIR)
+ offset++;
+ }
+ break;
+ }
+ }
+ } while(quit==0);
+ curs_set(0);
+ wdoprintf(window,"%c\n",car);
+ delwin(window);
+ (void) clearok(stdscr, TRUE);
+#ifdef HAVE_TOUCHWIN
+ touchwin(stdscr);
+#endif
+ return toupper(car);
+}
+#endif
+
+static unsigned int fat32_find_root_cluster(disk_t *disk_car,const partition_t *partition,const unsigned int cluster_size, const unsigned long int no_of_cluster,const unsigned int reserved, const unsigned int fat_length, const int interface, const int verbose, const unsigned int expert, const unsigned int first_free_cluster, const unsigned int fats)
+{
+ unsigned long int root_cluster=0;
+ const unsigned int start_data=reserved+fats*fat_length;
+ if(verbose>0)
+ log_trace("fat32_find_root_cluster(cluster_size=%u,no_of_cluster=%lu,reserved=%u,fat_length=%u,expert=%u,first_free_cluster=%u)\n",cluster_size,no_of_cluster,reserved,fat_length,expert,first_free_cluster);
+ if(cluster_size==0)
+ return 0;
+ {
+ file_data_t *rootdir_list=NULL;
+ file_data_t *current_file=NULL;
+ unsigned int dir_nbr=0;
+ int interactive=1;
+ unsigned char *buffer;
+ int ind_stop=0;
+ buffer=MALLOC(cluster_size*disk_car->sector_size);
+#ifdef HAVE_NCURSES
+ if(interface)
+ {
+ wmove(stdscr,22,0);
+ wattrset(stdscr, A_REVERSE);
+ waddstr(stdscr," Stop ");
+ wattroff(stdscr, A_REVERSE);
+ }
+#endif
+ for(root_cluster=2;(root_cluster<2+no_of_cluster)&&(ind_stop==0);root_cluster++)
+ {
+ unsigned long int percent=root_cluster*100/(2+no_of_cluster);
+#ifdef HAVE_NCURSES
+ if(interface>0 && (root_cluster&0xfff)==0)
+ {
+ wmove(stdscr,9,0);
+ wclrtoeol(stdscr);
+ wdoprintf(stdscr,"Search root cluster %10lu/%lu %lu%%",root_cluster,2+no_of_cluster,percent);
+ wrefresh(stdscr);
+ ind_stop|=check_enter_key_or_s(stdscr);
+ }
+#endif
+ if(disk_car->read(disk_car,cluster_size*disk_car->sector_size, buffer, partition->part_offset+(uint64_t)(start_data+(root_cluster-2)*cluster_size)*disk_car->sector_size)==0)
+ {
+ if(verbose>1)
+ {
+ log_verbose("fat32_find_root_cluster test cluster=%lu\n",root_cluster);
+ /*
+ dump_ncurses(buffer,cluster_size*disk_car->sector_size);
+ */
+ }
+ if((memcmp(&buffer[0],". ",8+3)==0) &&
+ (buffer[0xB]!=ATTR_EXT && (buffer[0xB]&ATTR_DIR)!=0))
+ { /* Directory found */
+ unsigned long int cluster=(buffer[1*0x20+0x15]<<24)+(buffer[1*0x20+0x14]<<16)+
+ (buffer[1*0x20+0x1B]<<8)+buffer[1*0x20+0x1A];
+ if((memcmp(&buffer[0x20],".. ",8+3)==0) &&
+ (buffer[1*0x20+0xB]!=ATTR_EXT && (buffer[1*0x20+0xB]&ATTR_DIR)!=0) && (cluster==0)
+ && (buffer[0x40]!=0)) /* First-level directory */
+ {
+ file_data_t *dir_list;
+ log_info("First-level directory found at cluster %lu\n",root_cluster);
+ /* dump_ncurses(buffer,cluster_size*disk_car->sector_size); */
+ dir_list=dir_fat_aux(buffer,cluster_size*disk_car->sector_size,cluster_size);
+ if(verbose>0)
+ {
+ dir_aff_log(disk_car, partition, NULL, dir_list);
+ }
+ {
+ file_data_t *new_file=MALLOC(sizeof(*new_file));
+ memcpy(new_file,dir_list,sizeof(*new_file));
+ new_file->prev=current_file;
+ new_file->next=NULL;
+ if(current_file!=NULL)
+ current_file->next=new_file;
+ else
+ rootdir_list=new_file;
+ current_file=new_file;
+ snprintf(new_file->name,sizeof(new_file->name),"DIR%05u",++dir_nbr);
+ }
+ delete_list_file(dir_list);
+ }
+ }
+ else if( memcmp(&buffer[0*0x20],&buffer[1*0x20],0x20)!=0)
+ { /* Potential root directory */
+ unsigned int i,found=1;
+ int etat=0,nb_subdir=0,nb_subdir_ok=0;
+ for(i=0;found && (i<cluster_size*disk_car->sector_size/0x20);i++)
+ {
+ int res=check_entree(&buffer[i*0x20]);
+ if(verbose>2)
+ log_verbose("fat32_find_root_cluster root_cluster=%lu i=%u etat=%d res=%d\n",root_cluster,i,etat,res);
+ switch(res)
+ {
+ case 0:
+ if(etat==0)
+ etat=1;
+ break;
+ case 1:
+ if(etat==1)
+ {
+ etat=2;
+ found=0;
+ }
+ break;
+ case 2:
+ found=0;
+ break;
+ }
+ if((buffer[i*0x20]!=DELETED_FLAG) && (buffer[i*0x20+0xB]!= ATTR_EXT && (buffer[i*0x20+0xB]&ATTR_DIR)!=0)) /* Test directory */
+ {
+ nb_subdir++;
+ }
+ }
+ for(i=0;found && (i<16*cluster_size);i++)
+ {
+ if((buffer[i*0x20]!=DELETED_FLAG) && (buffer[i*0x20+0xB]!= ATTR_EXT && (buffer[i*0x20+0xB]&ATTR_DIR)!=0)) /* Test directory */
+ {
+ unsigned long int cluster=(buffer[i*0x20+0x15]<<24)+(buffer[i*0x20+0x14]<<16)+
+ (buffer[i*0x20+0x1B]<<8)+buffer[i*0x20+0x1A];
+ /* log_debug("cluster %ld\n",cluster); */
+ if((cluster>2+no_of_cluster)||(get_subdirectory(disk_car,partition->part_offset+(uint64_t)(start_data+(cluster-2)*cluster_size)*disk_car->sector_size,cluster)!=0))
+ {
+ /* if(verbose) */
+ /* log_debug("failed with %s\n",&buffer[i*0x20]); */
+ }
+ else
+ nb_subdir_ok++;
+ }
+ }
+ if(found)
+ {
+ if((nb_subdir_ok>nb_subdir*0.90)&&(nb_subdir>=3))
+ {
+ unsigned long int new_root_cluster=root_cluster;
+ unsigned long int tmp=root_cluster;
+ int back=0; /* To avoid an endless loop... */
+ /* Il faut ajouter un parcours arriere de la FAT
+ * car on localise le dernier cluster du root_cluster */
+ if(verbose>0)
+ log_verbose("cluster %lu, etat=%d, found=%d,nb_subdir=%d,nb_subdir_ok=%d\n",root_cluster,etat,found,nb_subdir,nb_subdir_ok);
+ do
+ {
+ new_root_cluster=tmp;
+ tmp=fat32_get_prev_cluster(disk_car,partition,reserved,new_root_cluster,no_of_cluster);
+ if(verbose>0)
+ log_verbose("prev cluster(%lu)=>%lu\n",new_root_cluster,tmp);
+ if(tmp)
+ {
+ /* Check cluster number */
+ if((tmp<2) || (tmp>=2+no_of_cluster))
+ {
+ log_error("bad cluster number\n");
+ free(buffer);
+ return new_root_cluster;
+ }
+ /* Read the cluster */
+ if(disk_car->read(disk_car,cluster_size*disk_car->sector_size, buffer, partition->part_offset+(uint64_t)(start_data+(tmp-2)*cluster_size)*disk_car->sector_size)!=0)
+ {
+ log_critical("cluster can't be read\n");
+ free(buffer);
+ return new_root_cluster;
+ }
+ /* Check if this cluster is a directory structure. FAT can be damaged */
+ for(i=0;i<16*cluster_size;i++)
+ {
+ if(check_entree(&buffer[i*0x20])!=1)
+ {
+ log_error("cluster data is not a directory structure\n");
+ free(buffer);
+ return new_root_cluster;
+ }
+ }
+ }
+ } while(tmp && (++back<10));
+ free(buffer);
+ return new_root_cluster;
+ }
+ else
+ {
+ if(verbose>1)
+ {
+ log_verbose("cluster %lu, etat=%d, found=%d,nb_subdir=%d,nb_subdir_ok=%d\n",
+ root_cluster,etat,found,nb_subdir,nb_subdir_ok);
+ }
+ }
+ {
+ file_data_t *dir_list;
+ dir_list=dir_fat_aux(buffer,cluster_size*disk_car->sector_size,cluster_size);
+ if(dir_list!=NULL && (dir_list->next==NULL || dir_list->filestat.st_ino!=dir_list->next->filestat.st_ino))
+ {
+ int test_date=1;
+ if(verbose>0)
+ {
+ log_verbose("Potential root_cluster %lu\n",root_cluster);
+ test_date=dir_aff_log(disk_car, partition, NULL, dir_list);
+ }
+#ifdef HAVE_NCURSES
+ if(interface>0 && interactive>0 && test_date>0)
+ {
+ switch(ask_root_directory(disk_car,partition,dir_list,root_cluster))
+ {
+ case c_YES:
+ delete_list_file(dir_list);
+ free(buffer);
+ return root_cluster;
+ case 'A':
+ interactive=0;
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+ }
+ delete_list_file(dir_list);
+ }
+ }
+ }
+
+ }
+ }
+ if(ind_stop!=0)
+ log_info("Search root cluster stopped: %10lu (2..%lu)\n",root_cluster,no_of_cluster+1);
+ else
+ log_error("Search root cluster failed\n");
+ root_cluster=0;
+ if(rootdir_list==NULL)
+ {
+ log_warning("No first-level directory found.\n");
+ }
+ else
+ {
+ dir_aff_log(disk_car, partition, NULL, rootdir_list);
+ /* && (ind_stop==0) */
+ if(interface && (expert>0))
+ {
+ if(ask_confirmation("Create a new root cluster with %u first-level directories (Expert only) (Y/N)",dir_nbr)!=0 && ask_confirmation("Write root cluster, confirm ? (Y/N)")!=0)
+ {
+ root_cluster=first_free_cluster;
+ fat32_create_rootdir(disk_car, partition, reserved, fat_length, root_cluster, cluster_size, verbose, rootdir_list, fats);
+ }
+ }
+ delete_list_file(rootdir_list);
+ }
+ free(buffer);
+ }
+ return root_cluster;
+}
+
+static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+ /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
+
+static void fat_date_unix2dos(int unix_date,unsigned short *mstime, unsigned short *msdate)
+{
+ int day,year,nl_day,month;
+
+/* unix_date -= sys_tz.tz_minuteswest*60; */
+
+ /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
+ if (unix_date < 315532800)
+ unix_date = 315532800;
+
+ *mstime = le16((unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
+ (((unix_date/3600) % 24) << 11));
+ day = unix_date/86400-3652;
+ year = day/365;
+ if ((year+3)/4+365*year > day) year--;
+ day -= (year+3)/4+365*year;
+ if (day == 59 && !(year & 3)) {
+ nl_day = day;
+ month = 2;
+ }
+ else {
+ nl_day = (year & 3) || day <= 59 ? day : day-1;
+ for (month = 0; month < 12; month++)
+ if (day_n[month] > nl_day) break;
+ }
+ *msdate = le16(nl_day-day_n[month-1]+1+(month << 5)+(year << 9));
+}
+
+static int file2entry(struct msdos_dir_entry *de, const file_data_t *current_file)
+{
+ unsigned int i,j;
+ /* Name */
+ for(i=0;(i<8)&&(current_file->name[i]!='.')&&(current_file->name[i]!='\0');i++)
+ {
+ de->name[i]=current_file->name[i];
+ }
+ for(j=i;j<8;j++)
+ {
+ de->name[j]=' ';
+ }
+ /* Extension */
+ for(;(current_file->name[i]!='.')&&(current_file->name[i]!='\0');i++);
+ for(j=0;(j<3)&&(current_file->name[i]!='\0');j++)
+ {
+ de->ext[j]=current_file->name[i];
+ }
+ for(;j<3;j++)
+ {
+ de->ext[j]=' ';
+ }
+ de->attr=(LINUX_S_ISDIR(current_file->filestat.st_mode)!=0?ATTR_DIR:ATTR_NONE);
+ fat_date_unix2dos(current_file->filestat.st_mtime,&de->time,&de->date);
+ de->start=le16(current_file->filestat.st_ino);
+ de->starthi=le16(current_file->filestat.st_ino>>16);
+ de->size=le32(current_file->filestat.st_size);
+ return 0;
+}
+
+static int fat32_create_rootdir(disk_t *disk_car,const partition_t *partition, const unsigned int reserved, const unsigned int fat_length, const unsigned int root_cluster, const unsigned int cluster_size, const int verbose, file_data_t *rootdir_list, const unsigned int fats)
+{
+ const unsigned int start_data=reserved+fats*fat_length;
+ unsigned int current_entry=0;
+ unsigned int cluster;
+ unsigned char *buffer;
+ file_data_t *current_file;
+ if(verbose>0)
+ {
+ log_trace("fat32_create_rootdir(reserved=%u,fat_length=%u,root_cluster=%u,cluster_size=%u)\n",reserved,fat_length,root_cluster,cluster_size);
+ }
+ cluster=root_cluster;
+ buffer=MALLOC(disk_car->sector_size*cluster_size);
+ memset(buffer,0,disk_car->sector_size*cluster_size);
+ for(current_file=rootdir_list;current_file!=NULL;current_file=current_file->next)
+ {
+ file2entry((struct msdos_dir_entry*)buffer+current_entry,current_file);
+ if(++current_entry==(disk_car->sector_size*cluster_size/sizeof(struct msdos_dir_entry)))
+ {
+ unsigned int next_cluster;
+ if(disk_car->write(disk_car,disk_car->sector_size*cluster_size, buffer, partition->part_offset+(uint64_t)(start_data+(cluster-2)*cluster_size)*disk_car->sector_size)!=0)
+ {
+ display_message("Write error: Can't create FAT32 root cluster.\n");
+ }
+ current_entry=0;
+ memset(buffer,0,disk_car->sector_size*cluster_size);
+ /* FIXME need to write fat32_get_next_free_cluster */
+ next_cluster=cluster++;
+ set_next_cluster(disk_car,partition,UP_FAT32,reserved,cluster,next_cluster);
+ set_next_cluster(disk_car,partition,UP_FAT32,reserved+fat_length,cluster,next_cluster);
+ cluster=next_cluster;
+ }
+ }
+ if(disk_car->write(disk_car,disk_car->sector_size*cluster_size, buffer, partition->part_offset+(uint64_t)(start_data+(cluster-2)*cluster_size)*disk_car->sector_size)!=0)
+ {
+ display_message("Write error: Can't create FAT32 root cluster.\n");
+ }
+ set_next_cluster(disk_car,partition,UP_FAT32,reserved,cluster,FAT32_EOC);
+ set_next_cluster(disk_car,partition,UP_FAT32,reserved+fat_length,cluster,FAT32_EOC);
+#ifdef DEBUG
+ {
+ file_data_t *dir_list;
+ dir_list=dir_fat_aux(buffer,disk_car->sector_size*cluster_size,cluster_size);
+ dir_aff_log(disk_car, partition, NULL, dir_list);
+ delete_list_file(dir_list);
+ }
+#endif
+ free(buffer);
+ return 0;
+}
+
+static int find_dir_entries(disk_t *disk_car,const partition_t *partition, const unsigned int offset,const int verbose)
+{
+ unsigned int i;
+ int dir_entry_found=0;
+ uint64_t hd_offset;
+ unsigned char *buffer=(unsigned char *)MALLOC(disk_car->sector_size);
+ hd_offset=partition->part_offset+(uint64_t)offset*disk_car->sector_size;
+ for(i=0; i<200 && i<offset; i++)
+ {
+ if(disk_car->read(disk_car,disk_car->sector_size, buffer, hd_offset)!=0)
+ {
+ log_error("dir_entries: read error, dir_entries>=%u (%u sectors)\n",i*(disk_car->sector_size/32),i);
+ }
+ else
+ {
+ unsigned int j;
+ /* A directory entry is 32 bytes long *
+ * Entries has allocated by whole sector */
+ for(j=disk_car->sector_size/32-1;j>0;j--)
+ {
+ if(verbose>1)
+ {
+ log_verbose("find_dir_entries sector=%u entree=%d dir_entry_found=%d\n",offset-i,j,dir_entry_found);
+ }
+ if(dir_entry_found==0)
+ { /* Should be between the last directory entries and the first cluster */
+ switch(check_entree(&buffer[j*32]))
+ {
+ case 0: /* Empty entry */
+ break;
+ case 1: /* Non empty entry */
+ dir_entry_found=1;
+ break;
+ case 2: /* Failed */
+ free(buffer);
+ return 0;
+ }
+ }
+ else
+ {
+ if(check_entree(&buffer[j*32])!=1)
+ { /* Must be in the FAT table */
+ free(buffer);
+ return (i-1)*(disk_car->sector_size/32);
+ }
+ }
+ }
+ }
+ hd_offset-=disk_car->sector_size;
+ }
+ free(buffer);
+ return 0;
+}
+
+static int analyse_dir_entries(disk_t *disk_car,const partition_t *partition, const unsigned int offset,const int verbose)
+{
+ unsigned int i,j;
+ int etat=0;
+ unsigned int sector_etat1=0;
+ uint64_t hd_offset;
+ unsigned char *buffer=MALLOC(disk_car->sector_size);
+ hd_offset=partition->part_offset+(uint64_t)offset*disk_car->sector_size;
+ for(i=0;i<200;i++)
+ {
+ if(disk_car->read(disk_car,disk_car->sector_size, buffer, hd_offset)!=0)
+ {
+ log_error("dir_entries: read error, dir_entries>=%u (%u sectors)\n",i*(disk_car->sector_size/32),i);
+ }
+ else
+ {
+ for(j=0;j<(disk_car->sector_size/32);j++)
+ {
+ if(check_entree(&buffer[j*0x20])==0)
+ { /* Empty entry */
+ if(etat==0)
+ {
+ if(i==0 && j==0)
+ { /* The first entry must not be empty, otherwise there is no file */
+ free(buffer);
+ return 0;
+ }
+ etat=1;
+ sector_etat1=i;
+ if(verbose>0)
+ log_verbose("dir_entries 0->1 %d\n",i*(disk_car->sector_size/32)+j);
+ }
+ }
+ else
+ { /* Not an entry or non empty entry */
+ if(etat==1)
+ {
+ free(buffer);
+ if(i==sector_etat1)
+ { /* In the same sector, empty entry must not be followed by non-empty entry */
+ return 0;
+ }
+ /* Data found */
+ if(verbose>0)
+ log_verbose("dir_entries 1->2 %d\n",i*(disk_car->sector_size/32)+j);
+ return i*(disk_car->sector_size/32);
+ }
+ }
+ }
+ }
+ hd_offset+=disk_car->sector_size;
+ }
+ free(buffer);
+ return 0;
+}
+
+static int analyse_dir_entries2(disk_t *disk_car,const partition_t *partition, const unsigned int reserved, const unsigned int fat_length,const int verbose, unsigned int root_size_max,const upart_type_t upart_type, const unsigned int fats)
+{
+ file_data_t *current_file;
+ file_data_t *dir_list=NULL;
+ unsigned int nbr_sector;
+ unsigned char *buffer_dir;
+ if(root_size_max==0)
+ {
+ root_size_max=4096;
+ }
+ nbr_sector=(root_size_max+(disk_car->sector_size/32)-1)/(disk_car->sector_size/32);
+ buffer_dir=(unsigned char *)MALLOC(disk_car->sector_size*nbr_sector);
+ if(disk_car->read(disk_car, nbr_sector*disk_car->sector_size, buffer_dir, partition->part_offset+(uint64_t)(reserved+fats*fat_length)*disk_car->sector_size)!=0)
+ {
+ log_error("FAT 1x can't read root directory\n");
+ free(buffer_dir);
+ return 0;
+ }
+ {
+ unsigned long int start_data=reserved+fats*fat_length+(root_size_max+(disk_car->sector_size/32)-1)/(disk_car->sector_size/32);
+ unsigned int cluster_size=calcul_cluster_size(upart_type,partition->part_size/disk_car->sector_size-start_data,fat_length,disk_car->sector_size);
+ dir_list=dir_fat_aux(buffer_dir,disk_car->sector_size*nbr_sector,cluster_size);
+ }
+ if(verbose>1)
+ {
+ dir_aff_log(disk_car, partition, NULL, dir_list);
+ }
+ for(current_file=dir_list;(current_file!=NULL)&&(LINUX_S_ISDIR(current_file->filestat.st_mode)==0);current_file=current_file->next);
+ if(current_file!=NULL)
+ {
+ unsigned long int new_inode=current_file->filestat.st_ino;
+ unsigned int dir_entries;
+ if(verbose>1)
+ {
+ log_verbose("Directory %s used inode=%lu\n",current_file->name,new_inode);
+ }
+ for(dir_entries=(disk_car->sector_size/32);dir_entries<=root_size_max;dir_entries+=(disk_car->sector_size/32))
+ {
+ unsigned long int start_data=reserved+fats*fat_length+(dir_entries+(disk_car->sector_size/32)-1)/(disk_car->sector_size/32);
+ unsigned int cluster_size=calcul_cluster_size(upart_type,partition->part_size/disk_car->sector_size-start_data,fat_length,disk_car->sector_size);
+ if(verbose>1)
+ {
+ log_verbose("dir_entries %u, cluster_size %u\n",dir_entries,cluster_size);
+ }
+ if(disk_car->read(disk_car, disk_car->sector_size, buffer_dir, partition->part_offset+(uint64_t)(start_data+(new_inode-2)*cluster_size)*disk_car->sector_size)==0)
+ {
+ if((memcmp(&buffer_dir[0],". ",8+3)==0)&&(memcmp(&buffer_dir[0x20],".. ",8+3)==0))
+ {
+ unsigned long int cluster=(buffer_dir[0*0x20+0x15]<<24)+(buffer_dir[0*0x20+0x14]<<16)+
+ (buffer_dir[0*0x20+0x1B]<<8)+buffer_dir[0*0x20+0x1A];
+ unsigned long int cluster_prev=(buffer_dir[1*0x20+0x15]<<24)+(buffer_dir[1*0x20+0x14]<<16)+
+ (buffer_dir[1*0x20+0x1B]<<8)+buffer_dir[1*0x20+0x1A];
+ if(verbose>1)
+ {
+ log_verbose("Cluster %lu, directory .. found link to %lu\n",cluster,cluster_prev);
+ }
+ if(cluster_prev==0 && cluster==new_inode)
+ {
+ free(buffer_dir);
+ delete_list_file(dir_list);
+ return ((dir_entries+(disk_car->sector_size/32)-1)/(disk_car->sector_size/32))*(disk_car->sector_size/32);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ log_warning("No directory found\n");
+ }
+ free(buffer_dir);
+ delete_list_file(dir_list);
+ return root_size_max;
+}
+
+#ifdef HAVE_NCURSES
+static void fat32_dump_ncurses(disk_t *disk_car, const partition_t *partition, const upart_type_t upart_type, const unsigned char *orgboot, const unsigned char *newboot)
+{
+ WINDOW *window=newwin(0,0,0,0); /* full screen */
+ keypad(window, TRUE); /* Need it to get arrow key */
+ aff_copy(window);
+ wmove(window,4,0);
+ wdoprintf(window,"%s",disk_car->description(disk_car));
+ wmove(window,5,0);
+ aff_part(window,AFF_PART_ORDER,disk_car,partition);
+ mvwaddstr(window,6,0, " Rebuild Boot sector Boot sector");
+ dump2(window, newboot,orgboot, (unsigned int)(upart_type==UP_FAT32?3*disk_car->sector_size:DEFAULT_SECTOR_SIZE));
+ delwin(window);
+ (void) clearok(stdscr, TRUE);
+#ifdef HAVE_TOUCHWIN
+ touchwin(stdscr);
+#endif
+}
+#endif
+
+static void fat32_dump(disk_t *disk_car, const partition_t *partition, const upart_type_t upart_type, const unsigned char *orgboot, const unsigned char *newboot)
+{
+ log_info(" Rebuild Boot sector Boot sector\n");
+ dump2_log(newboot,orgboot, (unsigned int)(upart_type==UP_FAT32?3*disk_car->sector_size:DEFAULT_SECTOR_SIZE));
+#ifdef HAVE_NCURSES
+ fat32_dump_ncurses(disk_car, partition, upart_type, orgboot, newboot);
+#endif
+}
+
+static void menu_write_fat_boot_sector(disk_t *disk_car, partition_t *partition, const int verbose, const upart_type_t upart_type, const unsigned char *orgboot, const unsigned char*newboot, const int error, char **current_cmd)
+{
+ const struct fat_boot_sector *org_fat_header=(const struct fat_boot_sector *)orgboot;
+ const struct fat_boot_sector *fat_header=(const struct fat_boot_sector *)newboot;
+ struct MenuItem menuSaveBoot[]=
+ {
+ { 'D', "Dump", "Dump sector" },
+ { 'L', "List", "List directories and files" },
+ { 'W', "Write","Write boot"},
+ { 'Q',"Quit","Quit this section"},
+ { 0, NULL, NULL }
+ };
+ const char *options="DLQ";
+ int do_write=0;
+ int do_exit=0;
+ int no_confirm=0;
+ do
+ {
+ int command;
+ do_exit=0;
+#ifdef HAVE_NCURSES
+ aff_copy(stdscr);
+ wmove(stdscr,4,0);
+ wdoprintf(stdscr,"%s",disk_car->description(disk_car));
+ mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG);
+ wmove(stdscr,6,0);
+ aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
+ wmove(stdscr,8,0);
+#endif
+ if(memcmp(newboot,orgboot,DEFAULT_SECTOR_SIZE)) /* Only compare the first sector */
+ {
+ dump_2fat_info(fat_header, org_fat_header, upart_type,disk_car->sector_size);
+#ifdef HAVE_NCURSES
+ wdoprintf(stdscr,"Extrapolated boot sector and current boot sector are different.\n");
+ if(error)
+ wdoprintf(stdscr,"Warning: Extrapolated boot sector have incorrect values.\n");
+#endif
+ if(error)
+ log_error("Warning: Extrapolated boot sector have incorrect values.\n");
+ options="DLWQ";
+ }
+ else
+ {
+ dump_fat_info(fat_header, upart_type,disk_car->sector_size);
+#ifdef HAVE_NCURSES
+ wdoprintf(stdscr,"Extrapolated boot sector and current boot sector are identical.\n");
+#endif
+ }
+ if(*current_cmd!=NULL)
+ {
+ command='Q';
+ while(*current_cmd[0]==',')
+ (*current_cmd)++;
+ if(strncmp(*current_cmd,"list",4)==0)
+ {
+ (*current_cmd)+=4;
+ command='L';
+ }
+ else if(strncmp(*current_cmd,"dump",4)==0)
+ {
+ (*current_cmd)+=4;
+ command='D';
+ }
+ else if(strncmp(*current_cmd,"noconfirm",9)==0)
+ {
+ command=0; /* do nothing */
+ no_confirm=1;
+ (*current_cmd)+=9;
+ }
+ else if(strncmp(*current_cmd,"write",5)==0)
+ {
+ command='W';
+ (*current_cmd)+=5;
+ }
+ }
+ else
+ {
+#ifdef HAVE_NCURSES
+ command=wmenuSelect(stdscr,INTER_DUMP_Y, INTER_DUMP_X, menuSaveBoot,8,options,MENU_HORIZ|MENU_BUTTON, 1);
+#else
+ command=0;
+#endif
+ }
+ switch(command)
+ {
+ case 'w':
+ case 'W':
+ if(strchr(options,'W')!=NULL)
+ do_write=1;
+ break;
+ case 'd':
+ case 'D':
+ if(strchr(options,'D')!=NULL)
+ fat32_dump(disk_car, partition, upart_type, orgboot, newboot);
+ break;
+ case 'l':
+ case 'L':
+ {
+ /* TODO: use redirector and dir_partition_fat */
+ //dir_partition_fat_aux(stdscr,disk_car, partition, verbose, fat_header,upart_type,current_cmd);
+ const upart_type_t old_upart_type=upart_type;
+ partition->upart_type=upart_type;
+ io_redir_add_redir(disk_car,partition->part_offset,3*disk_car->sector_size,0,newboot);
+ dir_partition(disk_car, partition, verbose, current_cmd);
+ io_redir_del_redir(disk_car,partition->part_offset);
+ partition->upart_type=old_upart_type;
+ }
+ break;
+ case 'q':
+ case 'Q':
+ do_exit=1;
+ break;
+ }
+ } while(do_write==0 && do_exit==0);
+ if(do_write!=0 && (no_confirm!=0 || ask_confirmation("Write FAT boot sector, confirm ? (Y/N)")!=0))
+ {
+ int err=0;
+ log_info("Write new boot!\n");
+ /* Write boot sector and backup boot sector */
+ if(upart_type==UP_FAT32)
+ {
+ if(disk_car->write(disk_car,3*disk_car->sector_size, newboot, partition->part_offset)!=0 ||
+ disk_car->write(disk_car,3*disk_car->sector_size, newboot, partition->part_offset+(uint64_t)le16(fat_header->backup_boot)*disk_car->sector_size)!=0)
+ err=1;
+ }
+ else
+ {
+ if(disk_car->write(disk_car,DEFAULT_SECTOR_SIZE, newboot, partition->part_offset)!=0)
+ err=1;
+ }
+ if(err==1)
+ {
+ display_message("Write error: Can't write new FAT boot sector\n");
+ }
+ /* Note that TestDisk doesn't repair the filesystem itself, use another utility for that */
+ }
+ else
+ log_info("Don't write new boot!\n");
+}
+
+static void create_fat_boot_sector(disk_t *disk_car, partition_t *partition, const unsigned int reserved, const int verbose, const unsigned int dir_entries, const unsigned long int root_cluster, const unsigned int cluster_size, const unsigned int fat_length,const int interface, const upart_type_t upart_type, const unsigned int fats, char **current_cmd)
+{
+ unsigned char *orgboot;
+ unsigned char *newboot;
+ struct fat_boot_sector *org_fat_header;
+ struct fat_boot_sector *fat_header;
+ int error=0;
+ unsigned long int part_size=0;
+ orgboot=MALLOC(3*disk_car->sector_size);
+ newboot=MALLOC(3*disk_car->sector_size);
+ org_fat_header=(struct fat_boot_sector *)orgboot;
+ fat_header=(struct fat_boot_sector *)newboot;
+ if(disk_car->read(disk_car,3*disk_car->sector_size, orgboot, partition->part_offset)!=0)
+ {
+ log_error("create_fat_boot_sector: Can't read old boot sector\n");
+ memset(orgboot,0,3*disk_car->sector_size);
+ }
+ memcpy(newboot,orgboot,3*disk_car->sector_size);
+ if((le16(fat_header->marker)!=0xAA55)||
+ !((fat_header->ignored[0]==0xeb && fat_header->ignored[2]==0x90)||fat_header->ignored[0]==0xe9))
+ {
+ write_FAT_boot_code_aux(newboot);
+ }
+ fat_header->sector_size[0]=disk_car->sector_size & 0xFF;
+ fat_header->sector_size[1]=disk_car->sector_size >>8;
+ fat_header->fats=fats;
+ fat_header->media=0xF8;
+ fat_header->secs_track=le16(disk_car->CHS.sector);
+ fat_header->heads=le16(disk_car->CHS.head+1);
+ fat_header->marker=le16(0xAA55);
+ if(!((fat_header->ignored[0]==0xeb&&fat_header->ignored[2]==0x90)||fat_header->ignored[0]==0xe9))
+ {
+ fat_header->ignored[0]=0xeb;
+ fat_header->ignored[2]=0x90;
+ }
+
+ /* I have seen a FAT32 partition that Win98 2nd edition was unable to read
+ * because this name was missing! */
+ if(memcmp(fat_header->system_id,"MSDOS5.0",8) &&
+ memcmp(fat_header->system_id,"MSWIN4.0",8) &&
+ memcmp(fat_header->system_id,"MSWIN4.1",8))
+ memcpy(fat_header->system_id,"MSWIN4.1",8);
+ /* FIXME, need to know where the extended or logical partition start */
+ if(partition->status==STATUS_LOG)
+ fat_header->hidden=le32(disk_car->CHS.sector);
+ else
+ fat_header->hidden=le32((partition->part_offset/disk_car->sector_size));
+ fat_header->cluster_size=cluster_size;
+ fat_header->reserved=le16(reserved);
+ /* The filesystem size can be smaller than the partition size */
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ part_size=le16(fat_header->reserved)+fats*fat_length+dir_entries*32/disk_car->sector_size+cluster_size*(fat_length*disk_car->sector_size*2/3-2);
+ break;
+ case UP_FAT16:
+ part_size=le16(fat_header->reserved)+fats*fat_length+dir_entries*32/disk_car->sector_size+cluster_size*(fat_length*(disk_car->sector_size/2)-2);
+ break;
+ case UP_FAT32:
+ part_size=le16(fat_header->reserved)+fats*fat_length+cluster_size*(fat_length*(disk_car->sector_size/4)-2);
+ break;
+ default:
+ log_critical("create_fat_boot_sector: severe error\n");
+ exit(1);
+ }
+ if(part_size>partition->part_size/disk_car->sector_size)
+ part_size=partition->part_size/disk_car->sector_size;
+ if(part_size>0xFFFF)
+ {
+ fat_header->sectors[0]=0;
+ fat_header->sectors[1]=0;
+ fat_header->total_sect=le32(part_size);
+ }
+ else
+ {
+ fat_header->sectors[1]=part_size>>8;
+ fat_header->sectors[0]=part_size;
+ fat_header->total_sect=le32(0);
+ }
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ if((fat_length==0) || (dir_entries==0))
+ error=1;
+ if((newboot[36]<0x80)||(newboot[36]>0x88))
+ newboot[36]=0x80; /* BS_DrvNum=0x80 */
+ newboot[37]=0; /* BS_Reserved1=0 */
+ newboot[38]=0x29; /* Boot sig=0x29 */
+ if(memcmp(newboot+FAT_NAME2,"FAT32",5)==0)
+ memcpy(newboot+FAT_NAME2, " ",8);
+ memcpy(newboot+FAT_NAME1,"FAT12 ",8);
+ fat_header->fat_length=le16(fat_length);
+ fat_header->dir_entries[1]=dir_entries>>8;
+ fat_header->dir_entries[0]=dir_entries;
+ if(check_volume_name((const char*)&newboot[FAT1X_PART_NAME],11))
+ newboot[FAT1X_PART_NAME]='\0';
+ break;
+ case UP_FAT16:
+ if((fat_length==0) || (dir_entries==0))
+ error=1;
+ if((newboot[36]<0x80)||(newboot[36]>0x88))
+ newboot[36]=0x80; /* BS_DrvNum */
+ newboot[37]=0; /* BS_Reserved1=0 */
+ newboot[38]=0x29; /* Boot sig=0x29 */
+ if(memcmp(newboot+FAT_NAME2,"FAT32",5)==0)
+ memcpy(newboot+FAT_NAME2, " ",8);
+ memcpy(newboot+FAT_NAME1,"FAT16 ",8);
+ fat_header->fat_length=le16(fat_length);
+ fat_header->dir_entries[1]=dir_entries>>8;
+ fat_header->dir_entries[0]=dir_entries;
+ if(check_volume_name((const char*)&newboot[FAT1X_PART_NAME],11))
+ newboot[FAT1X_PART_NAME]='\0';
+ break;
+ case UP_FAT32:
+ if((fat_length==0) || (root_cluster==0))
+ error=1;
+ fat_header->fat_length=le16(0);
+ fat_header->dir_entries[0]=0;
+ fat_header->dir_entries[1]=0;
+ fat_header->fat32_length=le32(fat_length);
+ /*
+ Bits 0-3 -- Zero-based number of active FAT. Only valid if mirroring
+ is disabled.
+ Bits 4-6 -- Reserved.
+ Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
+ -- 1 means only one FAT is active; it is the one referenced
+ in bits 0-3.
+ Bits 8-15 -- Reserved.
+ */
+ fat_header->flags=le16(0);
+ fat_header->version[0]=0;
+ fat_header->version[1]=0;
+ fat_header->root_cluster=le32(root_cluster);
+ /* Sector number of FSINFO structure in the reserved area of the FAT32 volume. */
+ fat_header->info_sector=le16(1);
+ fat_header->backup_boot=le16(6);
+ memset(&fat_header->BPB_Reserved,0,sizeof(fat_header->BPB_Reserved));
+ if((fat_header->BS_DrvNum<0x80)||(fat_header->BS_DrvNum>0x87))
+ fat_header->BS_DrvNum=0x80;
+ fat_header->BS_Reserved1=0;
+ fat_header->BS_BootSig=0x29;
+ if((memcmp(newboot+FAT_NAME1,"FAT12",5)==0) ||(memcmp(newboot+FAT_NAME1,"FAT16",5)==0))
+ memcpy(newboot+FAT_NAME1," ",8);
+ memcpy(fat_header->BS_FilSysType, "FAT32 ",8);
+ newboot[0x1FC]=0x00; /* part of the signature */
+ newboot[0x1FD]=0x00;
+ memset(&newboot[disk_car->sector_size],0,2*disk_car->sector_size);
+ newboot[disk_car->sector_size]='R'; /* Signature RRaA */
+ newboot[disk_car->sector_size+1]='R';
+ newboot[disk_car->sector_size+2]='a';
+ newboot[disk_car->sector_size+3]='A';
+ newboot[disk_car->sector_size+0x1E4]='r'; /* Signature rrAa */
+ newboot[disk_car->sector_size+0x1E5]='r';
+ newboot[disk_car->sector_size+0x1E6]='A';
+ newboot[disk_car->sector_size+0x1E7]='a';
+ /* Don't set the number of free cluster or the next free cluster */
+ newboot[disk_car->sector_size+0x1E8]=0xFF; /* 488: Free clusters on disk */
+ newboot[disk_car->sector_size+0x1E9]=0xFF;
+ newboot[disk_car->sector_size+0x1EA]=0xFF;
+ newboot[disk_car->sector_size+0x1EB]=0xFF;
+ newboot[disk_car->sector_size+0x1EC]=0xFF; /* 492: Next available clusters */
+ newboot[disk_car->sector_size+0x1ED]=0xFF;
+ newboot[disk_car->sector_size+0x1EE]=0xFF;
+ newboot[disk_car->sector_size+0x1EF]=0xFF;
+ newboot[disk_car->sector_size+0x1FC]=0x00; /* End of Sector signature */
+ newboot[disk_car->sector_size+0x1FD]=0x00;
+ newboot[disk_car->sector_size+0x1FE]=0x55;
+ newboot[disk_car->sector_size+0x1FF]=0xAA;
+ newboot[2*disk_car->sector_size+0x1FC]=0x00; /* End of Sector signature */
+ newboot[2*disk_car->sector_size+0x1FD]=0x00;
+ newboot[2*disk_car->sector_size+0x1FE]=0x55;
+ newboot[2*disk_car->sector_size+0x1FF]=0xAA;
+ if(check_volume_name((const char*)&newboot[FAT32_PART_NAME],11))
+ newboot[FAT32_PART_NAME]='\0';
+ break;
+ default:
+ log_critical("create_fat_boot_sector: severe error\n");
+ exit(1);
+ }
+ if(memcmp(newboot,orgboot,1*DEFAULT_SECTOR_SIZE)) /* Only compare the first sector */
+ {
+ log_warning(" New / Current boot sector");
+ log_fat2_info(fat_header,org_fat_header,upart_type,disk_car->sector_size);
+ log_warning("Extrapolated boot sector and current boot sector are different.\n");
+ }
+ else
+ {
+ log_info("Extrapolated boot sector and current boot sector are identical.\n");
+ }
+ if(interface)
+ menu_write_fat_boot_sector(disk_car, partition, verbose, upart_type, orgboot, newboot, error, current_cmd);
+ free(orgboot);
+ free(newboot);
+}
+
+static int calcul_cluster_size(const upart_type_t upart_type, const unsigned long int data_size, const unsigned int fat_length, const unsigned int sector_size)
+{
+ /* log_info("calcul_cluster_size data_size=%lu, fat_length=%u, sector_size=%u\n",data_size,fat_length,sector_size); */
+ if(fat_length==0)
+ return 0;
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ return up2power(data_size/(fat_length*sector_size*2/3-1));
+ case UP_FAT16:
+ return up2power(data_size/(fat_length*sector_size/2-1));
+ case UP_FAT32:
+ return up2power(data_size/(fat_length*sector_size/4-1));
+ default:
+ log_critical("calcul_cluster_size: severe error\n");
+ return 0;
+ }
+}
+
+static unsigned int fat_find_fat_start(const unsigned char *buffer,const int p_fat12, const int p_fat16, const int p_fat32,unsigned long int*fat_offset, const unsigned int sector_size)
+{
+ /* TODO: handle limited size of info_offset */
+ info_offset_t *info_offset;
+ unsigned int nbr_offset=0;
+ int have_fat_signature=0;
+ info_offset=MALLOC(sector_size*sizeof(info_offset_t));
+ if(p_fat12!=0)
+ {
+ unsigned int i;
+ unsigned int low;
+ unsigned int high;
+ i=0;
+ high=0;
+ low=0;
+ while(high<(sector_size-1))
+ {
+ unsigned long int cluster=0;
+ if(low==0)
+ cluster=((buffer[high+1] & 0x0F) <<8) | buffer[high];
+ else
+ cluster=(buffer[high+1] <<4) | ((buffer[high]&0xF0)>>4);
+ if((cluster!=0) && ((cluster&0x0ff8)!=(unsigned)0x0ff8) && (((cluster-i-1)*3)%(2*sector_size)==0))
+ {
+ unsigned int j;
+ for(j=0;(j<nbr_offset) &&
+ (info_offset[j].offset!=(cluster-i-1)*3/(2*sector_size) || info_offset[j].fat_type!=12);j++);
+ if(j<nbr_offset)
+ info_offset[j].nbr++;
+ else
+ {
+ info_offset[nbr_offset].offset=(cluster-i-1)*3/(2*sector_size);
+ info_offset[nbr_offset].nbr=1;
+ info_offset[nbr_offset].fat_type=12;
+ nbr_offset++;
+ }
+ }
+ if(low==0)
+ low=1;
+ else
+ {
+ high++;
+ low=0;
+ }
+ high++;
+ i++;
+ }
+ i=1;
+ high=1;
+ low=0;
+ while(high<(sector_size-1))
+ {
+ unsigned long int cluster=0;
+ if(low==0)
+ cluster=((buffer[high+1] & 0x0F) <<8) | buffer[high];
+ else
+ cluster=(buffer[high+1] <<4) | ((buffer[high]&0xF0)>>4);
+ if((cluster!=0) && ((cluster&0x0ff8)!=(unsigned)0x0ff8) && (((cluster-i-1)*3+1)%(2*sector_size)==0))
+ {
+ unsigned int j;
+ for(j=0;(j<nbr_offset) &&
+ (info_offset[j].offset!=((cluster-i-1)*3+1)/(2*sector_size) || info_offset[j].fat_type!=12);j++);
+ if(j<nbr_offset)
+ info_offset[j].nbr++;
+ else
+ {
+ info_offset[nbr_offset].offset=((cluster-i-1)*3+1)/(2*sector_size);
+ info_offset[nbr_offset].nbr=1;
+ info_offset[nbr_offset].fat_type=12;
+ nbr_offset++;
+ }
+ }
+ if(low==0)
+ low=1;
+ else
+ {
+ high++;
+ low=0;
+ }
+ high++;
+ i++;
+ }
+ i=1;
+ high=0;
+ low=1;
+ while(high<(sector_size-1))
+ {
+ unsigned long int cluster=0;
+ if(low==0)
+ cluster=((buffer[high+1] & 0x0F) <<8) | buffer[high];
+ else
+ cluster=(buffer[high+1] <<4) | ((buffer[high]&0xF0)>>4);
+ if((cluster!=0) && ((cluster&0x0ff8)!=(unsigned)0x0ff8) && (((cluster-i-1)*3+2)%(2*sector_size)==0))
+ {
+ unsigned int j;
+ for(j=0;(j<nbr_offset) &&
+ (info_offset[j].offset!=((cluster-i-1)*3+2)/(2*sector_size) || info_offset[j].fat_type!=12);j++);
+ if(j<nbr_offset)
+ info_offset[j].nbr++;
+ else
+ {
+ info_offset[nbr_offset].offset=((cluster-i-1)*3+2)/(2*sector_size);
+ info_offset[nbr_offset].nbr=1;
+ info_offset[nbr_offset].fat_type=12;
+ nbr_offset++;
+ }
+ }
+ if(low==0)
+ low=1;
+ else
+ {
+ high++;
+ low=0;
+ }
+ high++;
+ i++;
+ }
+ if((buffer[0]==0xF0 || buffer[0]>=0xF8) && buffer[1]==0xFF)
+ {
+ unsigned int j;
+ for(j=0;(j<nbr_offset) &&
+ (info_offset[j].offset!=0 || info_offset[j].fat_type!=12);j++);
+ if(j<nbr_offset)
+ info_offset[j].nbr++;
+ else
+ {
+ info_offset[nbr_offset].offset=0;
+ info_offset[nbr_offset].nbr=1;
+ info_offset[nbr_offset].fat_type=12;
+ nbr_offset++;
+ }
+ have_fat_signature=1;
+ }
+ }
+ if(p_fat16!=0)
+ {
+ unsigned int i,j;
+ const uint16_t *p16=(const uint16_t*)buffer;
+ unsigned int err=0;
+ for(i=0; (i<sector_size/2)&&(err==0); i++)
+ {
+ unsigned long int cluster=le16(p16[i]);
+ if(cluster==1)
+ {
+ err=1;
+ }
+ if((cluster!=0) && ((cluster&0x0fff8)!=(unsigned)0x0fff8))
+ {
+ for(j=i+1; (j<sector_size/2)&&(err==0); j++)
+ {
+ if(cluster==le16(p16[j]))
+ {
+ err=1;
+ }
+ }
+ }
+ }
+ if(err==0)
+ {
+ for(i=0; i<sector_size/2; i++)
+ {
+ unsigned long int cluster=le16(p16[i]);
+ if((cluster!=0) && ((cluster&0x0fff8)!=(unsigned)0x0fff8)&&((cluster-i-1)%(sector_size/2)==0))
+ {
+ for(j=0;(j<nbr_offset) &&
+ (info_offset[j].offset!=(cluster-i-1)/(sector_size/2) || info_offset[j].fat_type!=16);j++);
+ if(j<nbr_offset)
+ info_offset[j].nbr++;
+ else
+ {
+ info_offset[nbr_offset].offset=(cluster-i-1)/(sector_size/2);
+ info_offset[nbr_offset].nbr=1;
+ info_offset[nbr_offset].fat_type=16;
+ nbr_offset++;
+ }
+ }
+ }
+ }
+ if((buffer[0]==0xF0 || buffer[0]>=0xF8) && buffer[1]==0xFF
+ && buffer[2]==0xFF && ((buffer[3] & 0xF7)==0xF7))
+ {
+ for(j=0;(j<nbr_offset)&& (info_offset[j].offset!=0 || info_offset[j].fat_type!=16);j++);
+ if(j<nbr_offset)
+ info_offset[j].nbr++;
+ else
+ {
+ info_offset[nbr_offset].offset=0;
+ info_offset[nbr_offset].nbr=1;
+ info_offset[nbr_offset].fat_type=16;
+ nbr_offset++;
+ }
+ have_fat_signature=1;
+ }
+ }
+ if(p_fat32!=0)
+ {
+ unsigned int i,j;
+ const uint32_t *p32=(const uint32_t*)buffer;
+ unsigned int err=0;
+ for(i=0; (i<sector_size/4)&&(err==0); i++)
+ {
+ unsigned long int cluster=le32(p32[i])&0x0FFFFFFF;
+ if(cluster==1)
+ {
+ err=1;
+ }
+ if((cluster!=0) && ((cluster&0x0ffffff8)!=(unsigned)0x0ffffff8))
+ {
+ for(j=i+1; (j<sector_size/4)&&(err==0); j++)
+ {
+ if(cluster==(le32(p32[j])&0x0FFFFFFF))
+ {
+ err=1;
+ }
+ }
+ }
+ }
+ if(err==0)
+ {
+ for(i=0; i<sector_size/4; i++)
+ {
+ unsigned long int cluster=le32(p32[i])&0x0FFFFFFF;
+ if((cluster!=0) && ((cluster&0x0ffffff8)!=(unsigned)0x0ffffff8)&&((cluster-i-1)%(sector_size/4)==0))
+ {
+ for(j=0;(j<nbr_offset) &&
+ ((info_offset[j].offset!=(cluster-i-1)/(sector_size/4)) || (info_offset[j].fat_type!=32));j++);
+ if(j<nbr_offset)
+ info_offset[j].nbr++;
+ else
+ {
+ info_offset[nbr_offset].offset=(cluster-i-1)/(sector_size/4);
+ info_offset[nbr_offset].nbr=1;
+ info_offset[nbr_offset].fat_type=32;
+ nbr_offset++;
+ }
+ }
+ }
+ }
+ if((buffer[0]==0xF0 || buffer[0]>=0xF8) && buffer[1]==0xFF &&
+ buffer[2]==0xFF && ((buffer[3]==0x0F) ||(buffer[3]==0xFF)) &&
+ buffer[4]==0xFF && buffer[5]==0xFF && buffer[6]==0xFF)
+ {
+ for(j=0;(j<nbr_offset)&&(info_offset[j].offset!=0 || info_offset[j].fat_type!=32);j++);
+ if(j<nbr_offset)
+ info_offset[j].nbr++;
+ else
+ {
+ info_offset[nbr_offset].offset=0;
+ info_offset[nbr_offset].nbr=1;
+ info_offset[nbr_offset].fat_type=32;
+ nbr_offset++;
+ }
+ have_fat_signature=1;
+ }
+ }
+ if(nbr_offset>0)
+ {
+ unsigned int j;
+ unsigned int best_j=0;
+ for(j=0;j<nbr_offset;j++)
+ {
+ if(info_offset[j].nbr>info_offset[best_j].nbr)
+ best_j=j;
+ }
+ if(info_offset[best_j].nbr>10 || have_fat_signature>0)
+ {
+ unsigned int res;
+ *fat_offset=info_offset[best_j].offset;
+ res=info_offset[best_j].fat_type;
+ free(info_offset);
+ return res;
+ }
+ }
+ free(info_offset);
+ return 0;
+}
+
+static int fat_find_type(disk_t *disk_car,const partition_t *partition,const uint64_t max_offset,const int p_fat12,const int p_fat16,const int p_fat32,const int verbose,const int dump_ind,const int interface,unsigned int *nbr_offset,info_offset_t *info_offset, const unsigned int max_nbr_offset)
+{
+ uint64_t offset;
+ unsigned long int old_percent=0;
+ int ind_stop=0;
+ unsigned char *buffer=MALLOC(disk_car->sector_size);
+ if(verbose>0)
+ {
+ log_trace("fat_find_type(max_offset=%lu, p_fat12=%d, p_fat16=%d, p_fat32=%d, debug=%d, dump_ind=%d)\n",
+ (long unsigned)(max_offset/disk_car->sector_size), p_fat12, p_fat16, p_fat32, verbose, dump_ind);
+ }
+#ifdef HAVE_NCURSES
+ if(interface)
+ {
+ wmove(stdscr,8,0);
+ wdoprintf(stdscr,"FAT : %s%s%s?\n",p_fat12?"12 ":"", p_fat16?"16 ":"", p_fat32?"32 ":"");
+ wmove(stdscr,22,0);
+ wattrset(stdscr, A_REVERSE);
+ waddstr(stdscr," Stop ");
+ wattroff(stdscr, A_REVERSE);
+ }
+#endif
+ for(offset=disk_car->sector_size;
+ offset<max_offset && !ind_stop;
+ offset+=disk_car->sector_size)
+ {
+#ifdef HAVE_NCURSES
+ unsigned long int percent=offset*100/max_offset;
+ if(interface && (percent!=old_percent))
+ {
+ wmove(stdscr,8,30);
+ wclrtoeol(stdscr); /* before addstr for BSD compatibility */
+ wdoprintf(stdscr,"Searching for FAT table %lu%%",percent);
+ old_percent=percent;
+ wrefresh(stdscr);
+ ind_stop|=check_enter_key_or_s(stdscr);
+ }
+#endif
+ if(disk_car->read(disk_car,disk_car->sector_size, buffer, partition->part_offset+offset)==0)
+ {
+ unsigned long int fat_offset=0;
+ unsigned int fat_type;
+ fat_type=fat_find_fat_start(buffer,p_fat12,p_fat16,p_fat32,&fat_offset,disk_car->sector_size);
+ if(fat_type!=0 && fat_offset<=(offset/disk_car->sector_size))
+ {
+ unsigned int j;
+ if(verbose>1)
+ {
+ log_info("fat_find_fat_start FAT%u at %lu:%lu\n", fat_type,
+ (long unsigned)(offset/disk_car->sector_size-fat_offset),
+ (long unsigned)(offset/disk_car->sector_size));
+ }
+ for(j=0; j<*nbr_offset && !(info_offset[j].offset==offset/disk_car->sector_size-fat_offset &&
+ info_offset[j].fat_type==fat_type); j++);
+ if(j<*nbr_offset)
+ info_offset[j].nbr++;
+ else
+ {
+ unsigned int new_info=0;
+ if(*nbr_offset<max_nbr_offset)
+ {
+ new_info=*nbr_offset;
+ (*nbr_offset)++;
+ }
+ else
+ { /* Overwrite the last information field with the lower nbr */
+ for(j=0;j<max_nbr_offset;j++)
+ {
+ if(info_offset[j].nbr <= info_offset[new_info].nbr)
+ new_info=j;
+ }
+ }
+ info_offset[new_info].offset=offset/disk_car->sector_size-fat_offset;
+ info_offset[new_info].nbr=1;
+ info_offset[new_info].fat_type=fat_type;
+ }
+ }
+ }
+ }
+#ifdef HAVE_NCURSES
+ if(interface)
+ {
+ wmove(stdscr,22,0);
+ wclrtoeol(stdscr);
+ wrefresh(stdscr);
+ }
+#endif
+ free(buffer);
+ return 0;
+}
+
+static upart_type_t fat_find_info(disk_t *disk_car,unsigned int*reserved, unsigned int*fat_length, const partition_t *partition,const uint64_t max_offset,const int p_fat12,const int p_fat16,const int p_fat32,const int verbose,const int dump_ind,const int interface, const unsigned int expert, unsigned int *fats)
+{
+ unsigned int nbr_offset=0;
+ unsigned int i;
+ info_offset_t info_offset[0x400];
+ upart_type_t upart_type=UP_UNK;
+ fat_find_type(disk_car, partition,max_offset,p_fat12,p_fat16,p_fat32,verbose,dump_ind,interface,&nbr_offset,&info_offset[0], 0x400);
+ /*
+ info_offset[0].fat_type=32;
+ info_offset[0].offset=32;
+ info_offset[0].nbr=1;
+ info_offset[1].fat_type=32;
+ info_offset[1].offset=40;
+ info_offset[1].nbr=921;
+ info_offset[2].fat_type=32;
+ info_offset[2].offset=565;
+ info_offset[2].nbr=1;
+ info_offset[3].fat_type=32;
+ info_offset[3].offset=3064;
+ info_offset[3].nbr=921;
+ info_offset[4].fat_type=32;
+ info_offset[4].offset=3589;
+ info_offset[4].nbr=1;
+ info_offset[5].fat_type=32;
+ info_offset[5].offset=35190;
+ info_offset[5].nbr=1;
+ nbr_offset=6;
+ */
+ for(i=0;i<nbr_offset;i++)
+ {
+ log_info("FAT%u at %lu(%u/%u/%u), nbr=%u\n",info_offset[i].fat_type,info_offset[i].offset,
+ offset2cylinder(disk_car,partition->part_offset+(uint64_t)info_offset[i].offset*disk_car->sector_size),
+ offset2head(disk_car,partition->part_offset+(uint64_t)info_offset[i].offset*disk_car->sector_size),
+ offset2sector(disk_car,partition->part_offset+(uint64_t)info_offset[i].offset*disk_car->sector_size),
+ info_offset[i].nbr);
+#ifdef HAVE_NCURSES
+ if(dump_ind>0 && interface>0)
+ {
+ unsigned char *buffer=MALLOC(disk_car->sector_size);
+ if(disk_car->read(disk_car,disk_car->sector_size, &buffer, partition->part_offset+(uint64_t)info_offset[i].offset*disk_car->sector_size)==0)
+ {
+ dump_ncurses(buffer,disk_car->sector_size);
+ }
+ free(buffer);
+ }
+#endif
+ }
+ if(nbr_offset==0)
+ {
+ *fat_length=0;
+ }
+ else
+ {
+ unsigned int offset_for_max_nbr=0;
+ unsigned int fat_found=0;
+ unsigned int first_fat=0;
+ unsigned int second_fat=0;
+ for(i=0; i<nbr_offset; i++)
+ {
+ /* select the good type in the 3 first possibilities */
+ if(i<3 || info_offset[i].offset<=33)
+ {
+ if(info_offset[i].nbr>info_offset[offset_for_max_nbr].nbr)
+ offset_for_max_nbr=i;
+ }
+ }
+ switch(info_offset[offset_for_max_nbr].fat_type)
+ {
+ case 12: upart_type=UP_FAT12; break;
+ case 16: upart_type=UP_FAT16; break;
+ case 32: upart_type=UP_FAT32; break;
+ }
+ for(i=0;i<nbr_offset;i++)
+ {
+ if(info_offset[i].fat_type==info_offset[offset_for_max_nbr].fat_type)
+ {
+ if(fat_found==0 && info_offset[i].nbr>=(info_offset[offset_for_max_nbr].nbr+2-1)/2)
+ {
+ first_fat=i;
+ fat_found++;
+ }
+ else if(fat_found==1 && info_offset[i].nbr>=(info_offset[first_fat].nbr+2-1)/2)
+ {
+ second_fat=i;
+ fat_found++;
+ }
+ }
+ }
+ if(fat_found==1)
+ {
+ for(i=first_fat+1;i<nbr_offset;i++)
+ {
+ if(info_offset[i].fat_type==info_offset[offset_for_max_nbr].fat_type)
+ {
+ if(fat_found==1)
+ {
+ second_fat=i;
+ fat_found++;
+ }
+ }
+ }
+ }
+ if(fat_found==1)
+ {
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ case UP_FAT16:
+ *reserved=1;
+ if(info_offset[first_fat].offset>*reserved)
+ *fat_length=info_offset[first_fat].offset-*reserved;
+ else
+ *fat_length=0;
+ break;
+ case UP_FAT32:
+ if(info_offset[first_fat].offset==32 || info_offset[first_fat].offset==33)
+ *reserved=info_offset[first_fat].offset;
+ *fat_length=0;
+ break;
+ default:
+ log_critical("fat_find_info: severe error\n");
+ return UP_UNK;
+ }
+ }
+ else
+ {
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ case UP_FAT16:
+ *reserved=info_offset[first_fat].offset; /* Should be 1 */
+ *fat_length=info_offset[second_fat].offset-*reserved;
+ break;
+ case UP_FAT32:
+ *reserved=info_offset[first_fat].offset;
+ *fat_length=info_offset[second_fat].offset-*reserved;
+ if(*reserved==32 || *reserved==33 || comp_FAT(disk_car,partition,*fat_length,*reserved)==0)
+ {
+ } else {
+ *reserved=0;
+ *fat_length=0;
+ }
+ break;
+ default:
+ log_critical("fat_find_info: severe error\n");
+ return UP_UNK;
+ }
+ }
+ if(verbose>0)
+ {
+ log_info("first_fat %lu, second_fat %lu\n",info_offset[first_fat].offset, info_offset[second_fat].offset);
+ }
+ }
+ if(expert>0 && interface>0)
+ {
+#ifdef HAVE_NCURSES
+ return select_fat_info(info_offset,nbr_offset,reserved,fat_length,max_offset/disk_car->sector_size,fats);
+#endif
+ }
+ return upart_type;
+}
+
+#ifdef HAVE_NCURSES
+static upart_type_t select_fat_info(const info_offset_t *info_offset, const unsigned int nbr_offset,unsigned int*reserved, unsigned int*fat_length, const unsigned long int max_sector_offset, unsigned int *fats)
+{
+ unsigned int i;
+ int reserved_can_be_one=0;
+ unsigned long int fat2_location=*reserved+*fat_length;
+ struct MenuItem menuSelectFAT[]=
+ {
+ { 'P', "Previous",""},
+ { 'N', "Next","" },
+ { 'Q', "Proceed","Set FAT table location"},
+ { 0, NULL, NULL }
+ };
+ aff_buffer(BUFFER_RESET,"Q");
+ aff_buffer(BUFFER_ADD,"Potential FAT location\n");
+ aff_buffer(BUFFER_ADD,"FAT - sector - score\n");
+ for(i=0;i<nbr_offset;i++)
+ {
+ if(nbr_offset<30 || info_offset[i].nbr>1)
+ aff_buffer(BUFFER_ADD," %02d %8lu %u\n",info_offset[i].fat_type,info_offset[i].offset,info_offset[i].nbr);
+ if(info_offset[i].fat_type<32)
+ {
+ reserved_can_be_one=1;
+ }
+ }
+ aff_copy(stdscr);
+ wmove(stdscr,4,0);
+ screen_buffer_to_log();
+ log_flush();
+ screen_buffer_display(stdscr,"",menuSelectFAT);
+ wmove(stdscr,INTER_FAT_ASK_Y, INTER_FAT_ASK_X);
+ *reserved=ask_number(*reserved,0,max_sector_offset,"FAT1 location (Number of reserved sector) ");
+ if(*reserved>0)
+ {
+ wmove(stdscr,INTER_FAT_ASK_Y, INTER_FAT_ASK_X);
+ fat2_location=ask_number(fat2_location,0,max_sector_offset,"FAT2 location ");
+ if(fat2_location>*reserved)
+ {
+ *fat_length=fat2_location-*reserved;
+ wmove(stdscr,INTER_FAT_ASK_Y, INTER_FAT_ASK_X);
+ *fats=ask_number(*fats,1,2,"Number of FATS (Usually 2) ");
+ }
+ else
+ {
+ *fat_length=0;
+ }
+ }
+ else
+ {
+ *fat_length=0;
+ }
+ for(i=0;i<nbr_offset;i++)
+ {
+ if(info_offset[i].offset==fat2_location)
+ {
+ switch(info_offset[i].fat_type)
+ {
+ case 12: return UP_FAT12;
+ case 16: return UP_FAT16;
+ case 32: return UP_FAT32;
+ }
+ }
+ }
+ for(i=0;i<nbr_offset;i++)
+ {
+ if(info_offset[i].offset==*reserved)
+ {
+ switch(info_offset[i].fat_type)
+ {
+ case 12: return UP_FAT12;
+ case 16: return UP_FAT16;
+ case 32: return UP_FAT32;
+ }
+ }
+ }
+ *reserved=0;
+ *fat_length=0;
+ return 0;
+}
+#endif
+
+/* Using a couple of inodes of "." directory entries, get the cluster size and where the first cluster begins.
+ * */
+static int find_cluster_size(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind,const int interface, unsigned int *cluster_size, unsigned long int *offset_org)
+{
+ unsigned int nbr_subdir=0;
+ sector_cluster_t sector_cluster[10];
+ {
+ uint64_t offset;
+ uint64_t skip_offset;
+ int ind_stop=0;
+ unsigned char *buffer=MALLOC(disk_car->sector_size);
+#ifdef HAVE_NCURSES
+ if(interface)
+ {
+ wmove(stdscr,22,0);
+ wattrset(stdscr, A_REVERSE);
+ waddstr(stdscr," Stop ");
+ wattroff(stdscr, A_REVERSE);
+ }
+#endif
+ /* 2 fats, maximum cluster size=128 */
+ skip_offset=(uint64_t)((partition->part_size-32*disk_car->sector_size)/disk_car->sector_size/128*1.5/disk_car->sector_size*2)*disk_car->sector_size;
+ if(verbose>0)
+ {
+ log_verbose("find_cluster_size skip_sectors=%lu (skip_offset=%lu)\n",
+ (unsigned long)(skip_offset/disk_car->sector_size),
+ (unsigned long)skip_offset);
+ }
+ for(offset=skip_offset;(offset<partition->part_size)&&!ind_stop&&(nbr_subdir<10);offset+=disk_car->sector_size)
+ {
+#ifdef HAVE_NCURSES
+ if(interface>0 && ((offset&(1024*disk_car->sector_size-1))==0))
+ {
+ wmove(stdscr,9,0);
+ wclrtoeol(stdscr);
+ wdoprintf(stdscr,"Search subdirectory %10lu/%lu %u",(unsigned long)(offset/disk_car->sector_size),(unsigned long)(partition->part_size/disk_car->sector_size),nbr_subdir);
+ wrefresh(stdscr);
+ ind_stop|=check_enter_key_or_s(stdscr);
+ }
+#endif
+ if(disk_car->read(disk_car,disk_car->sector_size, buffer, partition->part_offset+offset)==0)
+ {
+ if(memcmp(&buffer[0],". ",8+3)==0 && memcmp(&buffer[0x20],".. ",8+3)==0)
+ {
+ unsigned long int cluster=(buffer[0*0x20+0x15]<<24) + (buffer[0*0x20+0x14]<<16) +
+ (buffer[0*0x20+0x1B]<<8) + buffer[0*0x20+0x1A];
+ log_info("sector %lu, cluster %lu\n",
+ (unsigned long)(offset/disk_car->sector_size), cluster);
+ sector_cluster[nbr_subdir].cluster=cluster;
+ sector_cluster[nbr_subdir].sector=offset/disk_car->sector_size;
+ nbr_subdir++;
+#ifdef HAVE_NCURSES
+ if(dump_ind>0)
+ dump_ncurses(buffer,disk_car->sector_size);
+#endif
+ }
+ }
+ }
+ free(buffer);
+ }
+ return find_cluster_size_aux(sector_cluster,nbr_subdir,cluster_size,offset_org,verbose,partition->part_size/disk_car->sector_size);
+}
+
+static int find_cluster_size_aux(const sector_cluster_t *sector_cluster, const unsigned int nbr_sector_cluster,unsigned int *cluster_size, unsigned long int *offset, const int verbose, const unsigned long int part_size_in_sectors)
+{
+ cluster_offset_t *cluster_offset;
+ unsigned int i,j;
+ unsigned int nbr_sol=0;
+ if(nbr_sector_cluster<2)
+ return 0;
+ cluster_offset=MALLOC(nbr_sector_cluster*nbr_sector_cluster*sizeof(cluster_offset_t));
+ log_info("find_cluster_size_aux\n");
+ for(i=0;i<nbr_sector_cluster-1;i++)
+ {
+ for(j=i+1;j<nbr_sector_cluster;j++)
+ {
+ if(sector_cluster[j].cluster>sector_cluster[i].cluster)
+ {
+ unsigned int cluster_size_tmp=(sector_cluster[j].sector-sector_cluster[i].sector)/(sector_cluster[j].cluster-sector_cluster[i].cluster);
+ switch(cluster_size_tmp)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ if(sector_cluster[i].sector>(sector_cluster[i].cluster-2)*(*cluster_size))
+ {
+ unsigned int sol_cur;
+ unsigned int found=0;
+ unsigned int offset_tmp=sector_cluster[i].sector-(sector_cluster[i].cluster-2)*cluster_size_tmp;
+ for(sol_cur=0;(sol_cur<nbr_sol)&&!found;sol_cur++)
+ {
+ if(cluster_offset[sol_cur].cluster_size==cluster_size_tmp &&
+ cluster_offset[sol_cur].offset==offset_tmp)
+ {
+ if(cluster_offset[sol_cur].first_sol==i)
+ {
+ cluster_offset[sol_cur].nbr++;
+ }
+ /* log_debug("cluster_size=%u offset=%lu nbr=%u\n",cluster_offset[sol_cur].cluster_size,cluster_offset[sol_cur].offset,cluster_offset[sol_cur].nbr); */
+ found=1;
+ }
+ }
+ if(!found)
+ {
+ cluster_offset[nbr_sol].cluster_size=cluster_size_tmp;
+ cluster_offset[nbr_sol].offset=offset_tmp;
+ cluster_offset[nbr_sol].nbr=1;
+ cluster_offset[nbr_sol].first_sol=i;
+ nbr_sol++;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ /* Show results */
+ {
+ unsigned int nbr_max=0;
+ for(i=0;i<nbr_sol;i++)
+ {
+ if(verbose>0)
+ {
+ log_verbose("cluster_size=%u offset=%lu nbr=%u ",cluster_offset[i].cluster_size,cluster_offset[i].offset,cluster_offset[i].nbr);
+ switch(no_of_cluster2part_type((part_size_in_sectors-cluster_offset[i].offset)/cluster_offset[i].cluster_size))
+ {
+ case UP_FAT12:
+ log_info("FAT : 12\n");
+ break;
+ case UP_FAT16:
+ log_info("FAT : 16\n");
+ break;
+ case UP_FAT32:
+ log_info("FAT : 32\n");
+ break;
+ default: /* No compiler warning */
+ break;
+ }
+ }
+ if(cluster_offset[i].nbr>nbr_max)
+ {
+ nbr_max=cluster_offset[i].nbr;
+ *cluster_size=cluster_offset[i].cluster_size;
+ *offset=cluster_offset[i].offset;
+ }
+ }
+ free(cluster_offset);
+ if(nbr_max==0)
+ return 0;
+ log_info("Selected: cluster_size=%u offset=%lu nbr=%u\n",*cluster_size, *offset,nbr_max);
+ return 1;
+ }
+}
+
+static upart_type_t no_of_cluster2part_type(const unsigned long int no_of_cluster)
+{
+ if(no_of_cluster<65525)
+ {
+ if(no_of_cluster<4085)
+ return UP_FAT12;
+ else
+ return UP_FAT16;
+ }
+ return UP_FAT32;
+}
+
+int rebuild_FAT_BS(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind,const int interface,const unsigned int expert, char**current_cmd)
+{
+ unsigned long int data_size;
+ unsigned long int max_offset;
+ unsigned int fat_length=0;
+ unsigned int cluster_size_min=disk_car->sector_size;
+ unsigned int cluster_size=0;
+ unsigned int reserved=0;
+ unsigned int dir_entries=0;
+ unsigned int fats=2;
+ int p_fat12,p_fat16,p_fat32;
+ upart_type_t upart_type;
+ /*
+ * Using partition size, check if partition can be FAT12, FAT16 or FAT32
+ * */
+ if(partition->part_size>(uint64_t)(2*1024+1)*1024*1024)
+ {
+ p_fat32=1;
+ p_fat16=0;
+ p_fat12=0;
+ }
+ else
+ /* 1<<12 clusters * 8 secteurs/clusters= 32768 secteurs
+ fat_length=((1<<12+1)*1.5/DEFAULT_SECTOR_SIZE)+1=13; */
+ if(partition->part_size>=(uint64_t)(1+2*13+32768+63)*512)
+ {
+ p_fat32=1;
+ p_fat16=1;
+ p_fat12=0;
+ }
+ else
+ {
+ p_fat32=0;
+ p_fat16=1;
+ p_fat12=1;
+ }
+#ifdef TESTING
+ p_fat32=1; p_fat16=1; p_fat12=1;
+#endif
+ if(verbose)
+ {
+ log_info("\n");
+ log_partition(disk_car,partition);
+ log_info("rebuild_FAT_BS p_fat12 %d, p_fat16 %d, p_fat32 %d\n", p_fat12,p_fat16,p_fat32);
+ }
+ {
+ /* Set fat_length_max */
+ unsigned long int fat_length_max;
+ if(p_fat32)
+ { /* Cluster 512 bytes */
+ fat_length_max=partition->part_size/cluster_size_min*4;
+ }
+ else
+ if(p_fat16)
+ {
+ while(partition->part_size/cluster_size_min > (1<<16))
+ cluster_size_min*=2;
+ fat_length_max=partition->part_size/cluster_size_min*2;
+ }
+ else
+ {
+ while(partition->part_size/cluster_size_min > (1<<12))
+ cluster_size_min*=2;
+ fat_length_max=partition->part_size/cluster_size_min*1.5;
+ }
+ fat_length_max=fat_length_max/disk_car->sector_size*disk_car->sector_size;
+ if(verbose>1)
+ {
+ log_verbose("cluster_size_min %u sectors\n",cluster_size_min/disk_car->sector_size);
+ log_verbose("fat_length_max %ld sectors\n", fat_length_max/disk_car->sector_size);
+ }
+ max_offset=fat_length_max+64*disk_car->sector_size;
+ }
+ /*
+ if(verbose>1)
+ log_debug("search_fat16(partition,max_offset=%d,p_fat12=%d,p_fat16=%d,p_fat32=%d,debug=%d,dump_ind=%d)\n",max_offset,p_fat12,p_fat16,p_fat32,verbose,dump_ind);
+ */
+#ifdef HAVE_NCURSES
+ if(interface)
+ {
+ aff_copy(stdscr);
+ wmove(stdscr,4,0);
+ wdoprintf(stdscr,"%s",disk_car->description(disk_car));
+ mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG);
+ wmove(stdscr,6,0);
+ aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
+ wrefresh(stdscr);
+ }
+#endif
+ upart_type=fat_find_info(disk_car,&reserved, &fat_length, partition,max_offset,p_fat12,p_fat16,p_fat32,verbose,dump_ind,interface,expert,&fats);
+#ifdef HAVE_NCURSES
+ if(interface)
+ {
+ aff_copy(stdscr);
+ wmove(stdscr,4,0);
+ wdoprintf(stdscr,"%s",disk_car->description(disk_car));
+ mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG);
+ wmove(stdscr,6,0);
+ aff_part(stdscr,AFF_PART_ORDER,disk_car,partition);
+ wmove(stdscr,8,0);
+ wclrtoeol(stdscr);
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ waddstr(stdscr,"FAT : 12");
+ break;
+ case UP_FAT16:
+ waddstr(stdscr,"FAT : 16");
+ break;
+ case UP_FAT32:
+ waddstr(stdscr,"FAT : 32");
+ break;
+ default:
+ waddstr(stdscr,"No FAT found");
+ break;
+ }
+ }
+#endif
+ if(verbose>0)
+ {
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ log_info("FAT : 12");
+ break;
+ case UP_FAT16:
+ log_info("FAT : 16");
+ break;
+ case UP_FAT32:
+ log_info("FAT : 32");
+ break;
+ default:
+ log_info("No FAT found");
+ break;
+ }
+ log_info(", reserved=%u, fat_length=%u\n",reserved,fat_length);
+ }
+ if((upart_type!=UP_FAT12 && upart_type!=UP_FAT16 && upart_type!=UP_FAT32)||
+ (fat_length==0)||(reserved==0))
+ {
+ unsigned long int start_data=0;
+ if(find_cluster_size(disk_car, partition, verbose, dump_ind, interface,&cluster_size,&start_data)==0)
+ {
+ display_message("Can't find cluster size\n");
+ return 0;
+ }
+ if((cluster_size<=0) || (partition->part_size/disk_car->sector_size<=start_data))
+ {
+ display_message("Can't find cluster size\n");
+ return 0;
+ }
+ upart_type=no_of_cluster2part_type((partition->part_size/disk_car->sector_size-start_data)/cluster_size);
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ log_info("FAT : 12\n");
+ break;
+ case UP_FAT16:
+ log_info("FAT : 16\n");
+ break;
+ case UP_FAT32:
+ log_info("FAT : 32\n");
+ break;
+ default: /* No compiler warning */
+ break;
+ }
+ switch(upart_type)
+ {
+ case UP_FAT12:
+ case UP_FAT16:
+ reserved=1; /* must be 1 */
+ dir_entries=find_dir_entries(disk_car,partition,start_data-1,verbose);
+ switch(dir_entries)
+ {
+ case 0:
+ log_warning("dir_entries not found, should be 512\n");
+ dir_entries=512;
+ break;
+ case 512:
+ if(verbose)
+ log_info("dir_entries: %u\n", dir_entries);
+ break;
+ default:
+ log_warning("dir_entries: %u (unusual value)\n", dir_entries);
+ break;
+ }
+ fat_length=(start_data-reserved-((dir_entries-1)/16+1))/fats;
+ break;
+ case UP_FAT32:
+ reserved=32;
+ if((start_data&1)!=0)
+ reserved+=1;
+ fat_length=(start_data-reserved)/fats;
+ break;
+ default: /* No compiler warning */
+ break;
+ }
+ if(verbose>0)
+ log_info("fat_length %u\n",fat_length);
+ }
+#ifdef HAVE_NCURSES
+ if(interface)
+ {
+ if(fat_length==0)
+ waddstr(stdscr," Can't find FAT length\n");
+ wrefresh(stdscr);
+ }
+#endif
+ if(upart_type && (fat_length>1))
+ {
+ /* Initialized by fat32_free_info */
+ unsigned int free_cluster_count=0;
+ unsigned int first_free_cluster=0;
+ /* Initialized by fat32_find_root_cluster */
+ unsigned long int root_cluster=0;
+ unsigned long int start_data=reserved+fats*fat_length;
+ /* FAT1x: Find size of root directory */
+ if((upart_type==UP_FAT12) || (upart_type==UP_FAT16))
+ {
+ int old_dir_entries=dir_entries;
+ dir_entries=analyse_dir_entries(disk_car,partition,start_data,verbose);
+ log_info("dir_entries %u\n",dir_entries);
+ dir_entries=analyse_dir_entries2(disk_car,partition,reserved,fat_length,verbose,dir_entries,upart_type,fats);
+ log_info("dir_entries %u\n",dir_entries);
+ if(dir_entries==0)
+ {
+ if(old_dir_entries>0)
+ fat_length=0;
+ /*
+ else
+ {
+ dir_entries=512;
+ log_debug("analyse_dir_entries: use default dir_entries %u\n",dir_entries);
+ }
+ */
+ }
+ start_data+=(dir_entries+(disk_car->sector_size/32)-1)/(disk_car->sector_size/32);
+ }
+ if(partition->part_size/disk_car->sector_size<=start_data)
+ {
+ log_error("Error part_size=%lu <= start_data=%lu\n",
+ (unsigned long)(partition->part_size/disk_car->sector_size), start_data);
+ return 0;
+ }
+ data_size=partition->part_size/disk_car->sector_size-start_data;
+ /* Get Cluster Size */
+ {
+ int old_cluster_size=cluster_size;
+ cluster_size=calcul_cluster_size(upart_type,data_size,fat_length,disk_car->sector_size);
+ if(verbose>0)
+ log_info("cluster_size %u\n",cluster_size);
+ if((cluster_size<=0)||(cluster_size>128))
+ {
+ if(old_cluster_size>0)
+ {
+ cluster_size=old_cluster_size;
+ log_info("Assumes previous cluster size was good\n");
+ }
+ else
+ {
+ cluster_size=0;
+ }
+ }
+ if(expert>0)
+ {
+#ifdef HAVE_NCURSES
+ wmove(stdscr, INTER_FAT_ASK_Y, INTER_FAT_ASK_X);
+ cluster_size=ask_number(cluster_size,0,128,"cluster size ");
+#endif
+ switch(cluster_size)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ break;
+ default:
+ cluster_size=0;
+ break;
+ }
+ }
+ if(cluster_size==0)
+ {
+ display_message("Can't get cluster size\n");
+ return 0;
+ }
+ }
+ if(upart_type==UP_FAT32)
+ {
+ /* Use first fat */
+ fat32_free_info(disk_car,partition,reserved,data_size/cluster_size,&first_free_cluster,&free_cluster_count);
+ /* FAT32 : Find root cluster */
+ root_cluster=fat32_find_root_cluster(disk_car,partition,cluster_size,data_size/cluster_size,reserved,fat_length,interface,verbose,expert,first_free_cluster,fats);
+ if(expert>0)
+ {
+#ifdef HAVE_NCURSES
+ wmove(stdscr, INTER_FAT_ASK_Y, INTER_FAT_ASK_X);
+ root_cluster=ask_number(root_cluster,2,data_size/cluster_size+1,"root cluster ");
+#endif
+ if(verbose>1)
+ {
+ log_verbose("root_cluster=%lu (new)\n",root_cluster);
+ }
+ }
+ }
+#ifdef HAVE_NCURSES
+ if(interface)
+ {
+ wmove(stdscr,9,0);
+ wclrtoeol(stdscr);
+ wrefresh(stdscr);
+ }
+#endif
+ create_fat_boot_sector(disk_car,partition, reserved, verbose,dir_entries,root_cluster,cluster_size,fat_length,interface,upart_type,fats,current_cmd);
+ if(verbose)
+ {
+ log_info("\n");
+ log_partition(disk_car,partition);
+ }
+ }
+ return 0;
+}
+
+int FAT_init_rootdir(disk_t *disk_car, partition_t *partition, const int verbose)
+{
+ unsigned long int start_rootdir,start_data,fat_length,sector;
+ unsigned int error=0;
+ struct fat_boot_sector *fat_header;
+ unsigned char *buffer;
+ if(partition->upart_type!=UP_FAT12 && partition->upart_type!=UP_FAT16)
+ return 1;
+ if(check_FAT(disk_car,partition,verbose)!=0)
+ {
+ display_message("Boot sector not valid, can't check FAT.\n");
+ return 1;
+ }
+ buffer=(unsigned char *)MALLOC(disk_car->sector_size);
+ fat_header=(struct fat_boot_sector *)buffer;
+ if(disk_car->read(disk_car,disk_car->sector_size, buffer, partition->part_offset)!=0)
+ {
+ display_message("FAT_init_rootdir: Can't read boot sector\n");
+ free(buffer);
+ return 1;
+ }
+ fat_length=le16(fat_header->fat_length)>0?le16(fat_header->fat_length):le32(fat_header->fat32_length);
+ start_rootdir=le16(fat_header->reserved)+ fat_header->fats*fat_length;
+ start_data=start_rootdir+(get_dir_entries(fat_header)*32+disk_car->sector_size-1)/disk_car->sector_size;
+ for(sector=start_rootdir;error==0 && sector<start_data;sector++)
+ {
+ if(disk_car->read(disk_car,disk_car->sector_size, buffer, partition->part_offset+(uint64_t)sector*disk_car->sector_size)!=0)
+ {
+ log_error("FAT_init_rootdir: read error at sector %lu\n", sector);
+ }
+ else
+ {
+ unsigned int i;
+ for(i=0;error==0 && (i<disk_car->sector_size/0x20);i++)
+ {
+ if(check_entree(&buffer[i*0x20])==2)
+ {
+ error=1;
+ }
+ }
+ }
+ }
+ if(error==0)
+ {
+ display_message("TestDisk doesn't seem needed to reset the root directory.\n");
+ free(buffer);
+ return 0;
+ }
+ if(ask_confirmation("Initialize FAT root directory, confirm ? (Y/N)")!=0)
+ {
+ int err=0;
+ log_info("Initialize FAT root directory\n");
+ memset(buffer,0,disk_car->sector_size);
+ for(sector=start_rootdir;sector<start_data;sector++)
+ {
+ if(disk_car->write(disk_car,disk_car->sector_size, buffer,
+ partition->part_offset+(uint64_t)sector*disk_car->sector_size)!=0)
+ {
+ err=1;
+ }
+ }
+ if(err>0)
+ {
+ display_message("FAT_init_rootdir: write failed.\n");
+ free(buffer);
+ return 1;
+ }
+ }
+ free(buffer);
+ return 0;
+}
+
+enum fat_status_type { FAT_UNREADABLE=0, FAT_CORRUPTED=1, FAT_OK=2 };
+enum fat_ask_repair { FAT_REPAIR_ASK=0, FAT_REPAIR_YES=1, FAT_REPAIR_NO=2 };
+
+int repair_FAT_table(disk_t *disk_car, partition_t *partition, const int verbose)
+{
+ if(check_FAT(disk_car,partition,verbose)!=0)
+ {
+ display_message("Boot sector not valid, can't check FAT.\n");
+ return 1;
+ }
+ {
+ unsigned long int start_fat1,no_of_cluster,fat_length;
+ unsigned int fats;
+ unsigned int fat32_root_cluster=0;
+ int fat_damaged=0;
+#ifdef HAVE_NCURSES
+ WINDOW *window=newwin(0,0,0,0); /* full screen */
+ aff_copy(window);
+#endif
+ {
+ struct fat_boot_sector *fat_header;
+ unsigned long int part_size,start_data;
+ unsigned char *buffer;
+ buffer=MALLOC(disk_car->sector_size);
+ fat_header=(struct fat_boot_sector *)buffer;
+ if(disk_car->read(disk_car,disk_car->sector_size, buffer, partition->part_offset)!=0)
+ {
+ display_message("repair_FAT_table: Can't read boot sector\n");
+ return 1;
+ }
+ fat_length=le16(fat_header->fat_length)>0?le16(fat_header->fat_length):le32(fat_header->fat32_length);
+ part_size=(sectors(fat_header)>0?sectors(fat_header):le32(fat_header->total_sect));
+ start_fat1=le16(fat_header->reserved);
+ fats=fat_header->fats;
+ start_data=start_fat1+fats*fat_length+(get_dir_entries(fat_header)*32+disk_car->sector_size-1)/disk_car->sector_size;
+ no_of_cluster=(part_size-start_data)/fat_header->cluster_size;
+ fat32_root_cluster=le32(fat_header->root_cluster);
+ log_info("repair_FAT_table cluster=2..%lu\n",no_of_cluster+1);
+ free(buffer);
+ }
+ if(fats==0 || fats>2)
+ return 1;
+ {
+ const unsigned int buffer_size=(partition->upart_type==UP_FAT12?2*disk_car->sector_size:disk_car->sector_size);
+ unsigned int fat_status[2];
+ unsigned int allow_write[2];
+ unsigned int fat_history[2][3];
+ unsigned int old_offset_s=1234;
+ unsigned int fat_mismatch=0;
+ unsigned int fat_nbr;
+ unsigned long int cluster;
+ unsigned long int old_percent=0;
+ unsigned char *buffer_fat[2];
+ unsigned int rw_size=buffer_size;
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ buffer_fat[fat_nbr]=MALLOC(fats*buffer_size);
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ {
+ fat_history[fat_nbr][FAT_UNREADABLE]=0;
+ fat_history[fat_nbr][FAT_CORRUPTED]=0;
+ fat_history[fat_nbr][FAT_OK]=0;
+ allow_write[fat_nbr]=FAT_REPAIR_ASK;
+ fat_status[fat_nbr]=FAT_OK;
+ }
+ for(cluster=2;cluster<=no_of_cluster+1;cluster++)
+ {
+ unsigned long int next_cluster;
+ unsigned int offset_s,offset_o;
+ if(partition->upart_type==UP_FAT32)
+ {
+ offset_s=cluster/(disk_car->sector_size/4);
+ offset_o=cluster%(disk_car->sector_size/4);
+ }
+ else if(partition->upart_type==UP_FAT16)
+ {
+ offset_s=cluster/(disk_car->sector_size/2);
+ offset_o=cluster%(disk_car->sector_size/2);
+ }
+ else
+ {
+ offset_s=(cluster+cluster/2)/disk_car->sector_size;
+ offset_o=(cluster+cluster/2)%disk_car->sector_size;
+ if(offset_s==fat_length-1)
+ rw_size=disk_car->sector_size;
+ }
+ if(offset_s!=old_offset_s)
+ {
+#ifdef HAVE_NCURSES
+ unsigned long int percent=cluster*100/(no_of_cluster+1);
+ if(percent!=old_percent)
+ {
+ wmove(window,4,0);
+ wdoprintf(window,"Checking FAT %lu%%",percent);
+ wrefresh(window);
+ old_percent=percent;
+ }
+#endif
+ /* Write if necessary */
+ {
+ unsigned int nbr_fat_unreadable=0;
+ unsigned int nbr_fat_corrupted=0;
+ unsigned int nbr_fat_ok=0;
+ unsigned int good_fat_nbr=0;
+ /* Some stats about FAT table */
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ {
+ switch(fat_status[fat_nbr])
+ {
+ case FAT_UNREADABLE:
+ nbr_fat_unreadable++;
+ fat_history[fat_nbr][FAT_UNREADABLE]++;
+ break;
+ case FAT_CORRUPTED:
+ nbr_fat_corrupted++;
+ fat_history[fat_nbr][FAT_CORRUPTED]++;
+ break;
+ case FAT_OK:
+ nbr_fat_ok++;
+ good_fat_nbr=fat_nbr;
+ fat_history[fat_nbr][FAT_OK]++;
+ break;
+ }
+ }
+ if(fat_mismatch!=0)
+ {
+ if(nbr_fat_ok>1)
+ {
+ good_fat_nbr=0;
+ for(fat_nbr=1;fat_nbr<fats;fat_nbr++)
+ {
+ if(fat_history[fat_nbr][FAT_OK]>fat_history[good_fat_nbr][FAT_OK])
+ {
+ good_fat_nbr=fat_nbr;
+ }
+ else if(fat_history[fat_nbr][FAT_OK] == fat_history[good_fat_nbr][FAT_OK])
+ {
+ unsigned long int fat_offset=0;
+ if(fat_find_fat_start(buffer_fat[fat_nbr], (partition->upart_type==UP_FAT12),
+ (partition->upart_type==UP_FAT16), (partition->upart_type==UP_FAT32),
+ &fat_offset,disk_car->sector_size)!=0)
+ good_fat_nbr=fat_nbr;
+ }
+ }
+ }
+ }
+ if(verbose>1 || nbr_fat_ok!=fats || fat_mismatch>0)
+ {
+ log_verbose("nbr_fat_unreadable %u, nbr_fat_corrupted %u, nbr_fat_ok %u, good_fat_nbr %u, fat_mismatch %u\n",
+ nbr_fat_unreadable, nbr_fat_corrupted, nbr_fat_ok, good_fat_nbr, fat_mismatch);
+ }
+ /* Write FAT if necessary */
+ if(fat_mismatch!=0)
+ {
+ fat_damaged=1;
+ if(nbr_fat_ok>=1)
+ {
+ /* Use the good/best FAT to repair the bad one */
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ {
+ if(fat_nbr!=good_fat_nbr)
+ {
+ if(verbose>2)
+ {
+ dump_log(buffer_fat[fat_nbr], rw_size);
+ }
+ if(allow_write[fat_nbr]==FAT_REPAIR_ASK)
+ {
+ if(ask_confirmation("Use FAT%u to repair FAT%u table, confirm ? (Y/N)",good_fat_nbr+1,fat_nbr+1)!=0)
+ {
+ allow_write[fat_nbr]=FAT_REPAIR_YES;
+ }
+ else
+ {
+ allow_write[fat_nbr]=FAT_REPAIR_NO;
+ log_info("repair_FAT_table: doesn't correct FAT%u (sector %lu) using FAT%u\n",fat_nbr+1,
+ start_fat1+fat_length*fat_nbr+old_offset_s, good_fat_nbr+1);
+ }
+ }
+ if(allow_write[fat_nbr]==FAT_REPAIR_YES)
+ {
+ log_info("repair_FAT_table: correcting FAT%u (sector %lu) using FAT%u\n",fat_nbr+1,
+ start_fat1+fat_length*fat_nbr+old_offset_s, good_fat_nbr+1);
+ if(disk_car->write(disk_car, rw_size, buffer_fat[good_fat_nbr],
+ partition->part_offset+(uint64_t)(start_fat1+fat_length*fat_nbr+old_offset_s)*disk_car->sector_size)!=0)
+ {
+ display_message("repair_FAT_table: write failed.\n");
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ {
+ if(allow_write[fat_nbr]==FAT_REPAIR_ASK)
+ {
+ if(ask_confirmation("Remove invalid cluster from FAT%u table, confirm ? (Y/N)",fat_nbr+1)!=0)
+ {
+ allow_write[fat_nbr]=FAT_REPAIR_YES;
+ }
+ else
+ {
+ allow_write[fat_nbr]=FAT_REPAIR_NO;
+ log_info("repair_FAT_table: doesn't correct FAT%u (sector %lu)\n",fat_nbr+1,
+ start_fat1+fat_length*fat_nbr+old_offset_s);
+ }
+ }
+ if(allow_write[fat_nbr]==FAT_REPAIR_YES)
+ {
+ log_info("repair_FAT_table: correcting FAT%u (sector %lu)\n",fat_nbr+1,
+ start_fat1+fat_length*fat_nbr+old_offset_s);
+ if(disk_car->write(disk_car, rw_size, buffer_fat[fat_nbr],
+ partition->part_offset+(uint64_t)(start_fat1+fat_length*fat_nbr+old_offset_s)*disk_car->sector_size)!=0)
+ {
+ display_message("repair_FAT_table: write failed.\n");
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* only one fat or fat match */
+ if(nbr_fat_ok==0)
+ { /* fat_corrupted */
+ fat_damaged=1;
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ {
+ if(verbose>2)
+ {
+ dump_log(buffer_fat[fat_nbr], rw_size);
+ }
+ if(allow_write[fat_nbr]==FAT_REPAIR_ASK)
+ {
+ if(ask_confirmation("Remove invalid cluster from FAT%u table, confirm ? (Y/N)",fat_nbr+1)!=0)
+ {
+ allow_write[fat_nbr]=FAT_REPAIR_YES;
+ log_info("repair_FAT_table: correcting FAT%u (sector %lu)\n",fat_nbr+1,
+ start_fat1+fat_length*fat_nbr+old_offset_s);
+ }
+ else
+ {
+ allow_write[fat_nbr]=FAT_REPAIR_NO;
+ log_info("repair_FAT_table: doesn't correct FAT%u (sector %lu)\n",fat_nbr+1,
+ start_fat1+fat_length*fat_nbr+old_offset_s);
+ }
+ }
+ if(allow_write[fat_nbr]==FAT_REPAIR_YES)
+ {
+ if(disk_car->write(disk_car, rw_size, buffer_fat[fat_nbr],
+ partition->part_offset+(uint64_t)(start_fat1+fat_length*fat_nbr+old_offset_s)*disk_car->sector_size)!=0)
+ {
+ display_message("repair_FAT_table: write failed.\n");
+ }
+ }
+ }
+ }
+ }
+ }
+ /* Read FAT */
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ {
+ fat_status[fat_nbr]=FAT_OK;
+ if(verbose>1)
+ {
+ log_info("repair_FAT_table: read sector %lu (FAT%u)\n",(start_fat1+fat_length*fat_nbr+offset_s),fat_nbr+1);
+ }
+ if(disk_car->read(disk_car, rw_size,
+ buffer_fat[fat_nbr], partition->part_offset+(uint64_t)(start_fat1+fat_length*fat_nbr+offset_s)*disk_car->sector_size)!=0)
+ {
+ log_error("repair_FAT_table: read error sector %lu\n",(start_fat1+fat_length*fat_nbr+offset_s));
+ memset(buffer_fat[fat_nbr],0, rw_size);
+ fat_status[fat_nbr]=FAT_UNREADABLE;
+ }
+ if(verbose>1)
+ {
+ dump_log(buffer_fat[fat_nbr], rw_size);
+ }
+ }
+ /* Compare FAT */
+ fat_mismatch=0;
+ for(fat_nbr=1;fat_nbr<fats && fat_mismatch==0;fat_nbr++)
+ {
+ if(memcmp(buffer_fat[0], buffer_fat[fat_nbr], rw_size)!=0)
+ fat_mismatch=1;
+ }
+ }
+ /* Repair FAT if necessary */
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ {
+ if(partition->upart_type==UP_FAT32)
+ {
+ uint32_t *p32=(uint32_t*)buffer_fat[fat_nbr];
+ next_cluster=(le32(p32[offset_o]) & 0xFFFFFFF);
+ if((next_cluster<0x0FFFFFF7 && (next_cluster==1 || next_cluster>no_of_cluster+1)) ||
+ (cluster==fat32_root_cluster && next_cluster==0))
+ {
+#ifdef DEBUG
+ log_trace("FAT%u cluster %lu(%lx)->%lu(%lx)\n",fat_nbr+1,cluster,cluster,next_cluster,next_cluster);
+#endif
+ p32[offset_o]=le32(FAT32_EOC);
+ fat_status[fat_nbr]=FAT_CORRUPTED;
+ }
+ }
+ else if(partition->upart_type==UP_FAT16)
+ {
+ uint16_t *p16=(uint16_t*)buffer_fat[fat_nbr];
+ next_cluster=le16(p16[offset_o]);
+ if(next_cluster<0xFFF7 && (next_cluster==1 || next_cluster>no_of_cluster+1))
+ {
+ p16[offset_o]=le16(FAT16_EOC);
+ fat_status[fat_nbr]=FAT_CORRUPTED;
+ }
+ }
+ else
+ {
+ if((cluster&1)!=0)
+ next_cluster=le16((*((uint16_t*)&buffer_fat[fat_nbr][offset_o])))>>4;
+ else
+ next_cluster=le16(*((uint16_t*)&buffer_fat[fat_nbr][offset_o]))&0x0FFF;
+ if(next_cluster<0x0FF7 && (next_cluster==1 || next_cluster>no_of_cluster+1))
+ {
+ if((cluster&1)!=0)
+ *((uint16_t*)&buffer_fat[fat_nbr][offset_o])=le16((FAT12_EOC<<4)|(le16((*((uint16_t*)&buffer_fat[fat_nbr][offset_o])))&0x0F));
+ else
+ *((uint16_t*)&buffer_fat[fat_nbr][offset_o])=le16(FAT12_EOC |(le16((*((uint16_t*)&buffer_fat[fat_nbr][offset_o])))&0xF000));
+ fat_status[fat_nbr]=FAT_CORRUPTED;
+ }
+ }
+ }
+ old_offset_s=offset_s;
+ }
+ /* Write if necessary the last cluster */
+ {
+ unsigned int nbr_fat_unreadable=0;
+ unsigned int nbr_fat_corrupted=0;
+ unsigned int nbr_fat_ok=0;
+ unsigned int good_fat_nbr=0;
+ /* Some stats about FAT table */
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ {
+ switch(fat_status[fat_nbr])
+ {
+ case FAT_UNREADABLE:
+ nbr_fat_unreadable++;
+ fat_history[fat_nbr][FAT_UNREADABLE]++;
+ break;
+ case FAT_CORRUPTED:
+ nbr_fat_corrupted++;
+ fat_history[fat_nbr][FAT_CORRUPTED]++;
+ break;
+ case FAT_OK:
+ nbr_fat_ok++;
+ good_fat_nbr=fat_nbr;
+ fat_history[fat_nbr][FAT_OK]++;
+ break;
+ }
+ }
+ if(fat_mismatch!=0)
+ {
+ if(nbr_fat_ok>1)
+ {
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ {
+ if(fat_nbr!=good_fat_nbr)
+ {
+ if(fat_history[fat_nbr][FAT_OK]>fat_history[good_fat_nbr][FAT_OK])
+ {
+ good_fat_nbr=fat_nbr;
+ }
+ else if(fat_history[fat_nbr][FAT_OK] == fat_history[good_fat_nbr][FAT_OK])
+ {
+ unsigned long int fat_offset=0;
+ if(fat_find_fat_start(buffer_fat[fat_nbr], (partition->upart_type==UP_FAT12),
+ (partition->upart_type==UP_FAT16), (partition->upart_type==UP_FAT32),
+ &fat_offset,disk_car->sector_size)!=0)
+ good_fat_nbr=fat_nbr;
+ }
+ }
+ }
+ }
+ }
+ if(verbose>1 || nbr_fat_ok!=fats || fat_mismatch>0)
+ {
+ log_info("nbr_fat_unreadable %u, nbr_fat_corrupted %u, nbr_fat_ok %u, good_fat_nbr %u, fat_mismatch %u\n",
+ nbr_fat_unreadable, nbr_fat_corrupted, nbr_fat_ok, good_fat_nbr, fat_mismatch);
+ }
+ /* Write FAT if necessary */
+ if(fat_mismatch!=0)
+ {
+ fat_damaged=1;
+ if(nbr_fat_ok>=1)
+ {
+ /* Use the good/best FAT to repair the bad one */
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ {
+ if(fat_nbr!=good_fat_nbr)
+ {
+ if(verbose>2)
+ {
+ dump_log(buffer_fat[fat_nbr], rw_size);
+ }
+ if(allow_write[fat_nbr]==FAT_REPAIR_ASK)
+ {
+ if(ask_confirmation("Use FAT%u to repair FAT%u table, confirm ? (Y/N)",good_fat_nbr+1,fat_nbr+1)!=0)
+ {
+ allow_write[fat_nbr]=FAT_REPAIR_YES;
+ log_info("repair_FAT_table: correcting FAT%u (sector %lu) using FAT%u\n",fat_nbr+1,
+ start_fat1+fat_length*fat_nbr+old_offset_s, good_fat_nbr+1);
+ }
+ else
+ {
+ allow_write[fat_nbr]=FAT_REPAIR_NO;
+ log_info("repair_FAT_table: doesn't correct FAT%u (sector %lu) using FAT%u\n",fat_nbr+1,
+ start_fat1+fat_length*fat_nbr+old_offset_s, good_fat_nbr+1);
+ }
+ }
+ if(allow_write[fat_nbr]==FAT_REPAIR_YES)
+ {
+ if(disk_car->write(disk_car, rw_size, buffer_fat[good_fat_nbr],
+ partition->part_offset+(uint64_t)(start_fat1+fat_length*fat_nbr+old_offset_s)*disk_car->sector_size)!=0)
+ {
+ display_message("repair_FAT_table: write failed.\n");
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ {
+ if(allow_write[fat_nbr]==FAT_REPAIR_ASK)
+ {
+ if(ask_confirmation("Remove invalid cluster from FAT%u table, confirm ? (Y/N)",fat_nbr+1)!=0)
+ {
+ allow_write[fat_nbr]=FAT_REPAIR_YES;
+ log_info("repair_FAT_table: correcting FAT%u (sector %lu)\n",fat_nbr+1,
+ start_fat1+fat_length*fat_nbr+old_offset_s);
+ }
+ else
+ {
+ allow_write[fat_nbr]=FAT_REPAIR_NO;
+ log_info("repair_FAT_table: doesn't correct FAT%u (sector %lu)\n",fat_nbr+1,
+ start_fat1+fat_length*fat_nbr+old_offset_s);
+ }
+ }
+ if(allow_write[fat_nbr]==FAT_REPAIR_YES)
+ {
+ if(disk_car->write(disk_car, rw_size, &buffer_fat[fat_nbr],
+ partition->part_offset+(uint64_t)(start_fat1+fat_length*fat_nbr+old_offset_s)*disk_car->sector_size)!=0)
+ {
+ display_message("repair_FAT_table: write failed.\n");
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* only one fat or fat match */
+ if(nbr_fat_ok==0)
+ { /* fat_corrupted */
+ fat_damaged=1;
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ {
+ if(verbose>2)
+ {
+ dump_log(buffer_fat[fat_nbr], rw_size);
+ }
+ if(allow_write[fat_nbr]==FAT_REPAIR_ASK)
+ {
+ if(ask_confirmation("Remove invalid cluster from FAT%u table, confirm ? (Y/N)",fat_nbr+1)!=0)
+ {
+ allow_write[fat_nbr]=FAT_REPAIR_YES;
+ log_info("repair_FAT_table: correcting FAT%u (sector %lu)\n",fat_nbr+1,
+ start_fat1+fat_length*fat_nbr+old_offset_s);
+ }
+ else
+ {
+ allow_write[fat_nbr]=FAT_REPAIR_NO;
+ log_info("repair_FAT_table: doesn't correct FAT%u (sector %lu)\n",fat_nbr+1,
+ start_fat1+fat_length*fat_nbr+old_offset_s);
+ }
+ }
+ if(allow_write[fat_nbr]==FAT_REPAIR_YES)
+ {
+ if(disk_car->write(disk_car, rw_size, buffer_fat[fat_nbr],
+ partition->part_offset+(uint64_t)(start_fat1+fat_length*fat_nbr+old_offset_s)*disk_car->sector_size)!=0)
+ {
+ display_message("repair_FAT_table: write failed.\n");
+ }
+ }
+ }
+ }
+ }
+ }
+ for(fat_nbr=0;fat_nbr<fats;fat_nbr++)
+ free(buffer_fat[fat_nbr]);
+ }
+ if(fat_damaged==0)
+ {
+ display_message("FATs seems Ok, nothing to do.\n");
+ }
+#ifdef HAVE_NCURSES
+ delwin(window);
+ (void) clearok(stdscr, TRUE);
+#ifdef HAVE_TOUCHWIN
+ touchwin(stdscr);
+#endif
+#endif
+ }
+ return 0;
+}
+
+static int write_FAT_boot_code_aux(unsigned char *buffer)
+{
+ const unsigned char boot_code[DEFAULT_SECTOR_SIZE]= {
+ 0xeb, 0x3c, 0x90, 0x6d, 0x6b, 0x64, 0x6f, 0x73, 0x66, 0x73, 0x00, 0x00, 0x02, 0x08, 0x01, 0x00,
+ 0x02, 0x00, 0x02, 0x00, 0x00, 0xf8, 0xcc, 0x00, 0x3f, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x5a, 0x5f, 0x06, 0x00, 0x00, 0x00, 0x29, 0xf8, 0x3f, 0x7c, 0x3e, 'T', 'E', 'S', 'T', 'D',
+ 'I', 'S', 'K', 0x20, 0x20, 0x20, 0x46, 0x41, 0x54, 0x31, 0x36, 0x20, 0x20, 0x20, 0x0e, 0x1f,
+ 0xbe, 0x5b, 0x7c, 0xac, 0x22, 0xc0, 0x74, 0x0b, 0x56, 0xb4, 0x0e, 0xbb, 0x07, 0x00, 0xcd, 0x10,
+ 0x5e, 0xeb, 0xf0, 0x32, 0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe, 'T', 'h', 'i', 's', ' ',
+ 'i', 's', ' ', 'n', 'o', 't', ' ', 'a', ' ', 'b', 'o', 'o', 't', 'a', 'b', 'l',
+ 'e', ' ', 'd', 'i', 's', 'k', '.', ' ', ' ', 'P', 'l', 'e', 'a', 's', 'e', ' ',
+ 'i', 'n', 's', 'e', 'r', 't', ' ', 'a', ' ', 'b', 'o', 'o', 't', 'a', 'b', 'l',
+ 'e', ' ', 'f', 'l', 'o', 'p', 'p', 'y', ' ', 'a', 'n', 'd', 0x0d, 0x0a, 'p', 'r',
+ 'e', 's', 's', ' ', 'a', 'n', 'y', ' ', 'k', 'e', 'y', ' ', 't', 'o', ' ', 't',
+ 'r', 'y', ' ', 'a', 'g', 'a', 'i', 'n', ' ', '.', '.', '.', ' ', 0x0d, 0x0a, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
+ };
+ memcpy(buffer,&boot_code,DEFAULT_SECTOR_SIZE);
+ return 0;
+}
diff --git a/src/fat_dir.c b/src/fat_dir.c
new file mode 100644
index 0000000..fa7eeb9
--- /dev/null
+++ b/src/fat_dir.c
@@ -0,0 +1,468 @@
+/*
+
+ File: dir_fat.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <ctype.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "fat.h"
+#include "lang.h"
+#include "fnctdsk.h"
+#include "testdisk.h"
+#include "intrf.h"
+#include "dir.h"
+#include "fat_dir.h"
+#include "log.h"
+
+#define MSDOS_MKMODE(a,m) ((m & (a & ATTR_RO ? LINUX_S_IRUGO|LINUX_S_IXUGO : LINUX_S_IRWXUGO)) | (a & ATTR_DIR ? LINUX_S_IFDIR : LINUX_S_IFREG))
+struct fat_dir_struct
+{
+ struct fat_boot_sector*boot_sector;
+};
+
+
+static int date_dos2unix(const unsigned short f_time,const unsigned short f_date);
+static file_data_t *fat1x_rootdir(disk_t *disk_car, const partition_t *partition, const int verbose, const struct fat_boot_sector*fat_header);
+static file_data_t *fat12_dir(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int first_cluster);
+static file_data_t *fat16_dir(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int first_cluster);
+static file_data_t *fat32_dir(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int first_cluster);
+static inline void fat16_towchar(wchar_t *dst, const uint8_t *src, size_t len);
+static void dir_partition_fat_close(dir_data_t *dir_data);
+
+static int32_t secwest;
+
+static inline void fat16_towchar(wchar_t *dst, const uint8_t *src, size_t len)
+{
+ while (len--) {
+ *dst++ = src[0] | (src[1] << 8);
+ src += 2;
+ }
+}
+
+file_data_t *dir_fat_aux(const unsigned char*buffer, const unsigned int size, const unsigned int cluster_size)
+{
+ const struct msdos_dir_entry *de=(const struct msdos_dir_entry*)buffer;
+ wchar_t unicode[1000];
+ unsigned char long_slots;
+ file_data_t *dir_list=NULL;
+ file_data_t *current_file=NULL;
+GetNew:
+ long_slots = 0;
+ unicode[0]=0;
+ if (de->name[0] == (int8_t) DELETED_FLAG)
+ goto RecEnd;
+ if (de->attr == ATTR_EXT) {
+ unsigned int i;
+ const struct msdos_dir_slot *ds;
+ unsigned char id;
+ unsigned char slot;
+ unsigned char slots;
+ unsigned char sum;
+ unsigned char alias_checksum;
+ParseLong:
+ slots = 0;
+ ds = (const struct msdos_dir_slot *) de;
+ id = ds->id;
+ if ((id & 0x40)==0)
+ goto RecEnd;
+ slots = id & ~0x40;
+ if (slots > 20 || slots==0) /* ceil(256 * 2 / 26) */
+ goto RecEnd;
+ long_slots = slots;
+ alias_checksum = ds->alias_checksum;
+
+ slot = slots;
+ while (1) {
+ int offset;
+
+ slot--;
+ offset = slot * 13;
+ fat16_towchar(unicode + offset, ds->name0_4, 5);
+ fat16_towchar(unicode + offset + 5, ds->name5_10, 6);
+ fat16_towchar(unicode + offset + 11, ds->name11_12, 2);
+
+ if ((ds->id & 0x40)!=0) {
+ unicode[offset + 13] = 0;
+ }
+ de++;
+ if((const void*)de>=(const void*)(buffer+size))
+ goto EODir;
+ if (slot == 0)
+ break;
+ ds = (const struct msdos_dir_slot *) de;
+ if (ds->attr != ATTR_EXT)
+ goto RecEnd; /* XXX */
+ if ((ds->id & ~0x40) != slot)
+ goto ParseLong;
+ if (ds->alias_checksum != alias_checksum)
+ goto ParseLong;
+ }
+ if (de->name[0] == (int8_t) DELETED_FLAG)
+ goto RecEnd;
+ if (de->attr == ATTR_EXT)
+ goto ParseLong;
+ if (IS_FREE(de->name) || ((de->attr & ATTR_VOLUME)!=0))
+ goto RecEnd;
+ for (sum = 0, i = 0; i < 8; i++)
+ sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
+ for (i = 0; i < 3; i++)
+ sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->ext[i];
+ if (sum != alias_checksum)
+ long_slots = 0;
+ }
+RecEnd:
+ if((unicode[0]==0) &&(de->attr != ATTR_EXT))
+ { /* short name 8.3 */
+ int i;
+ int j=0;
+ for(i=0;(i<8)&&(de->name[i]!=' ');i++)
+ unicode[j++]=de->name[i];
+ if(de->ext[0]!=' ')
+ {
+ unicode[j++]='.';
+ for(i=0;(i<3)&&(de->ext[i]!=' ');i++)
+ unicode[j++]=de->ext[i];
+ }
+ unicode[j]=0;
+ }
+ if (((de->attr != ATTR_EXT)||(long_slots!=0)) && ((int8_t) unicode[0] != (int8_t) DELETED_FLAG) && !(de->attr & ATTR_VOLUME))
+ {
+ if(unicode[0]!=0)
+ {
+ unsigned int i;
+ file_data_t *new_file=MALLOC(sizeof(*new_file));
+ for(i=0;(unicode[i]!=0)&&(i<sizeof(new_file->name)-1);i++)
+ new_file->name[i]=(char) unicode[i];
+ new_file->name[i]=0;
+ new_file->filestat.st_dev=0;
+ new_file->filestat.st_ino=(le16(de->starthi)<<16)|le16(de->start);
+ new_file->filestat.st_mode = MSDOS_MKMODE(de->attr,(LINUX_S_IRWXUGO & ~(LINUX_S_IWGRP|LINUX_S_IWOTH)));
+ new_file->filestat.st_nlink=0;
+ new_file->filestat.st_uid=0;
+ new_file->filestat.st_gid=0;
+ new_file->filestat.st_rdev=0;
+ new_file->filestat.st_size=le32(de->size);
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+ new_file->filestat.st_blksize=cluster_size;
+#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
+ if(new_file->filestat.st_blksize!=0)
+ {
+ new_file->filestat.st_blocks=(new_file->filestat.st_size+new_file->filestat.st_blksize-1)/new_file->filestat.st_blksize;
+ }
+#endif
+#endif
+ new_file->filestat.st_atime=new_file->filestat.st_ctime=new_file->filestat.st_mtime=date_dos2unix(le16(de->time),le16(de->date));
+ new_file->prev=current_file;
+ new_file->next=NULL;
+ /* log_debug("fat: new file %s de=%p size=%u\n",new_file->name,de,le32(de->size)); */
+ if(current_file!=NULL)
+ current_file->next=new_file;
+ else
+ dir_list=new_file;
+ current_file=new_file;
+ }
+ else
+ {
+ return dir_list;
+ }
+ }
+ de++;
+ if((const void *)de<(const void *)(buffer+size-1))
+ goto GetNew;
+EODir:
+ return dir_list;
+}
+
+static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+ /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
+
+/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
+
+static int date_dos2unix(const unsigned short f_time, const unsigned short f_date)
+{
+ int month,year,secs;
+
+ /* first subtract and mask after that... Otherwise, if
+ f_date == 0, bad things happen */
+ month = ((f_date >> 5) - 1) & 15;
+ year = f_date >> 9;
+ secs = (f_time & 31)*2+60*((f_time >> 5) & 63)+(f_time >> 11)*3600+86400*
+ ((f_date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
+ month < 2 ? 1 : 0)+3653);
+ /* days since 1.1.70 plus 80's leap day */
+ return secs+secwest;
+}
+
+static file_data_t *fat12_dir(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int first_cluster)
+{
+ const struct fat_dir_struct *ls=(const struct fat_dir_struct*)dir_data->private_dir_data;
+ const struct fat_boot_sector*fat_header=ls->boot_sector;
+ if(fat_header->cluster_size<1)
+ {
+ log_error("FAT12: Can't list files, bad cluster size\n");
+ return NULL;
+ }
+ if(fat_sector_size(fat_header)==0)
+ {
+ log_error("FAT12: Can't list files, bad sector size\n");
+ return NULL;
+ }
+ if(first_cluster==0)
+ return fat1x_rootdir(disk_car,partition,dir_data->verbose,fat_header);
+ {
+ file_data_t *dir_list;
+ unsigned int cluster_size=fat_header->cluster_size;
+ unsigned char *buffer_dir=MALLOC(fat_sector_size(fat_header)*cluster_size*10);
+ unsigned int cluster;
+ unsigned int nbr_cluster;
+ int stop=0;
+ memset(buffer_dir,0,fat_sector_size(fat_header)*cluster_size*10);
+ for(cluster=first_cluster, nbr_cluster=0;
+ ((cluster&0x0ff8)!=(unsigned)FAT12_EOC) && (cluster>=2) && (nbr_cluster<10) && (stop==0);
+ cluster=get_next_cluster(disk_car,partition, UP_FAT12,le16(fat_header->reserved), cluster), nbr_cluster++)
+ {
+ uint64_t start=partition->part_offset+(uint64_t)(le16(fat_header->reserved)+fat_header->fats*le16(fat_header->fat_length)+(get_dir_entries(fat_header)*32+fat_sector_size(fat_header)-1)/fat_sector_size(fat_header)+(cluster-2)*cluster_size)*fat_sector_size(fat_header);
+ if(dir_data->verbose>0)
+ {
+ log_info("FAT12: cluster=%u(0x%x), pos=%lu\n",cluster,cluster,(long unsigned)(start/fat_sector_size(fat_header)));
+ }
+ if(disk_car->read(disk_car, cluster_size*fat_sector_size(fat_header), buffer_dir+(uint64_t)fat_sector_size(fat_header)*cluster_size*nbr_cluster, start))
+ {
+ log_error("FAT12: Can't read directory cluster\n");
+ stop=1;
+ }
+ }
+ dir_list=dir_fat_aux(buffer_dir,fat_sector_size(fat_header)*cluster_size*nbr_cluster,cluster_size);
+ free(buffer_dir);
+ return dir_list;
+ }
+}
+
+static file_data_t *fat16_dir(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int first_cluster)
+{
+ const struct fat_dir_struct *ls=(const struct fat_dir_struct*)dir_data->private_dir_data;
+ const struct fat_boot_sector*fat_header=ls->boot_sector;
+ if(fat_header->cluster_size<1)
+ {
+ log_error("FAT16: Can't list files, bad cluster size.\n");
+ return NULL;
+ }
+ if(fat_sector_size(fat_header)==0)
+ {
+ log_error("FAT16: Can't list files, bad sector size\n");
+ return NULL;
+ }
+ if(first_cluster==0)
+ return fat1x_rootdir(disk_car,partition,dir_data->verbose,fat_header);
+ {
+ file_data_t *dir_list=NULL;
+ unsigned int cluster_size=fat_header->cluster_size;
+ unsigned char *buffer_dir=MALLOC(disk_car->sector_size*cluster_size*10);
+ unsigned int cluster;
+ unsigned int nbr_cluster;
+ int stop=0;
+ memset(buffer_dir,0,disk_car->sector_size*cluster_size*10);
+ /* Need to correct the test */
+ for(cluster=first_cluster, nbr_cluster=0;
+ ((cluster&0xfff8)!=(unsigned)FAT16_EOC) && (cluster>=2) && (nbr_cluster<10)&&(stop==0);
+ cluster=get_next_cluster(disk_car,partition, UP_FAT16,le16(fat_header->reserved), cluster), nbr_cluster++)
+ {
+ uint64_t start=partition->part_offset+(uint64_t)(le16(fat_header->reserved)+fat_header->fats*le16(fat_header->fat_length)+(get_dir_entries(fat_header)*32+disk_car->sector_size-1)/disk_car->sector_size+(cluster-2)*cluster_size)*disk_car->sector_size;
+ if(dir_data->verbose>0)
+ {
+ log_info("FAT16 cluster=%u(0x%x), pos=%lu\n",cluster,cluster,(long unsigned)(start/disk_car->sector_size));
+ }
+ if(disk_car->read(disk_car, cluster_size*disk_car->sector_size, buffer_dir+(uint64_t)disk_car->sector_size*cluster_size*nbr_cluster, start))
+ {
+ log_error("FAT16: Can't read directory cluster\n");
+ stop=1;
+ }
+ }
+ dir_list=dir_fat_aux(buffer_dir,disk_car->sector_size*cluster_size*nbr_cluster,cluster_size);
+ free(buffer_dir);
+ return dir_list;
+ }
+}
+
+static file_data_t *fat32_dir(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const unsigned long int first_cluster)
+{
+ const struct fat_dir_struct *ls=(const struct fat_dir_struct*)dir_data->private_dir_data;
+ const struct fat_boot_sector*fat_header=ls->boot_sector;
+ if(fat_header->cluster_size==0)
+ {
+ log_error("FAT32: Can't list files, bad cluster size.\n");
+ return NULL;
+ }
+ if(le32(fat_header->root_cluster)==0)
+ {
+ log_error("FAT32: Can't list files, bad root cluster.\n");
+ return NULL;
+ }
+ if(fat_sector_size(fat_header)==0)
+ {
+ log_error("FAT32: Can't list files, bad sector size.\n");
+ return NULL;
+ }
+ {
+ file_data_t *dir_list;
+ unsigned int cluster_size=fat_header->cluster_size;
+ unsigned char *buffer_dir=MALLOC(fat_sector_size(fat_header)*cluster_size*10);
+ unsigned int cluster;
+ unsigned int nbr_cluster;
+ int stop=0;
+ memset(buffer_dir,0,fat_sector_size(fat_header)*cluster_size*10);
+ /* Need to correct the test */
+ for(cluster=(first_cluster==0?le32(fat_header->root_cluster):first_cluster), nbr_cluster=0;
+ ((cluster&0xffffff8)!=(unsigned)FAT32_EOC) && (cluster>=2) && (nbr_cluster<10) && (stop==0);
+ cluster=get_next_cluster(disk_car,partition, UP_FAT32,le16(fat_header->reserved), cluster), nbr_cluster++)
+ {
+ uint64_t start=partition->part_offset+(uint64_t)(le16(fat_header->reserved)+fat_header->fats*le32(fat_header->fat32_length)+(cluster-2)*cluster_size)*fat_sector_size(fat_header);
+ if(dir_data->verbose>0)
+ {
+ log_verbose("FAT32 cluster=%u(0x%x), pos=%lu\n",cluster,cluster,(long unsigned)(start/fat_sector_size(fat_header)));
+ }
+ if(disk_car->read(disk_car, cluster_size*fat_sector_size(fat_header), buffer_dir+(uint64_t)fat_sector_size(fat_header)*cluster_size*nbr_cluster, start))
+ {
+ log_error("FAT32: Can't read directory cluster\n");
+ stop=1;
+ }
+ // log_debug("read cluster %u\n",cluster);
+ }
+ // log_debug("nbr_cluster=%u\n",nbr_cluster);
+ dir_list=dir_fat_aux(buffer_dir,fat_sector_size(fat_header)*cluster_size*nbr_cluster,cluster_size);
+ free(buffer_dir);
+ return dir_list;
+ }
+}
+
+
+static file_data_t *fat1x_rootdir(disk_t *disk_car, const partition_t *partition, const int verbose, const struct fat_boot_sector*fat_header)
+{
+ unsigned int root_size=(get_dir_entries(fat_header)*32+disk_car->sector_size-1)/disk_car->sector_size*disk_car->sector_size;
+ if(verbose>1)
+ {
+ log_trace("fat1x_rootdir root_size=%u sectors\n",root_size/disk_car->sector_size);
+ }
+ {
+ file_data_t *res=NULL;
+ uint64_t start;
+ unsigned char *buffer_dir;
+ buffer_dir=(unsigned char*)MALLOC(root_size);
+ start=partition->part_offset+(uint64_t)((le16(fat_header->reserved)+fat_header->fats*le16(fat_header->fat_length))*disk_car->sector_size);
+ if(disk_car->read(disk_car, root_size, buffer_dir, start))
+ {
+ log_error("FAT 1x: Can't read root directory\n");
+ free(buffer_dir);
+ return NULL;
+ }
+ res=dir_fat_aux(buffer_dir,root_size,fat_header->cluster_size);
+ free(buffer_dir);
+ return res;
+ }
+}
+
+
+static void set_secwest(void)
+{
+ struct tm *tmptr;
+ time_t t;
+
+ t = time(NULL);
+ tmptr = localtime(&t);
+#ifdef HAVE_STRUCT_TM_TM_GMTOFF
+ secwest = -1 * tmptr->tm_gmtoff;
+#elif defined (DJGPP)
+ secwest = 0;
+#else
+#if defined (__CYGWIN__)
+ secwest = _timezone;
+#else
+ secwest = timezone;
+#endif
+ /* account for daylight savings */
+ if (tmptr->tm_isdst)
+ secwest -= 3600;
+#endif
+}
+
+int dir_partition_fat_init(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const int verbose)
+{
+ static unsigned char *buffer;
+ static struct fat_dir_struct *ls;
+ buffer=(unsigned char*)MALLOC(0x200);
+ if(disk_car->read(disk_car,0x200, buffer, partition->part_offset+(uint64_t)partition->boot_sector*disk_car->sector_size))
+ {
+ free(buffer);
+ return -1;
+ }
+ set_secwest();
+ ls=(struct fat_dir_struct *)MALLOC(sizeof(*ls));
+ ls->boot_sector=(struct fat_boot_sector*)buffer;
+ strncpy(dir_data->current_directory,"/",sizeof(dir_data->current_directory));
+ dir_data->current_inode=0;
+ dir_data->verbose=verbose;
+ dir_data->copy_file=NULL;
+ dir_data->close=dir_partition_fat_close;
+ dir_data->local_dir=NULL;
+ dir_data->private_dir_data=ls;
+ switch(partition->upart_type)
+ {
+ case UP_FAT12:
+ dir_data->get_dir=fat12_dir;
+ break;
+ case UP_FAT16:
+ dir_data->get_dir=fat16_dir;
+ break;
+ case UP_FAT32:
+ dir_data->get_dir=fat32_dir;
+ break;
+ default:
+ log_critical("Not a valid FAT type (upart_type=%u)\n",partition->upart_type);
+ free(ls->boot_sector);
+ free(ls);
+ dir_data->private_dir_data=NULL;
+ return -1;
+ }
+ return 0;
+}
+
+static void dir_partition_fat_close(dir_data_t *dir_data)
+{
+ struct fat_dir_struct *ls=(struct fat_dir_struct*)dir_data->private_dir_data;
+ free(ls->boot_sector);
+ free(ls);
+}
diff --git a/src/fat_dir.h b/src/fat_dir.h
new file mode 100644
index 0000000..a303457
--- /dev/null
+++ b/src/fat_dir.h
@@ -0,0 +1,24 @@
+/*
+
+ File: fat_dir.h
+
+ Copyright (C) 2004-2006 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+file_data_t *dir_fat_aux(const unsigned char*buffer, const unsigned int size, const unsigned int cluster_size);
+int dir_partition_fat_init(disk_t *disk_car, const partition_t *partition, dir_data_t *dir_data, const int verbose);
+
diff --git a/src/fatp.c b/src/fatp.c
new file mode 100644
index 0000000..f1cc6ca
--- /dev/null
+++ b/src/fatp.c
@@ -0,0 +1,162 @@
+/*
+
+ File: fatp.c
+
+ Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "list.h"
+#include "filegen.h"
+#include "fatp.h"
+#include "fat.h"
+#include "log.h"
+
+static void fat16_remove_used_space(disk_t *disk_car,const partition_t *partition, alloc_data_t *list_search_space, const unsigned int fat_offset, const unsigned int no_of_cluster, const unsigned int start_data, const unsigned int cluster_size, const unsigned int sector_size);
+static void fat32_remove_used_space(disk_t *disk_car,const partition_t *partition, alloc_data_t *list_search_space, const unsigned int fat_offset, const unsigned int no_of_cluster, const unsigned int start_data, const unsigned int cluster_size, const unsigned int sector_size);
+
+static void fat16_remove_used_space(disk_t *disk_car,const partition_t *partition, alloc_data_t *list_search_space, const unsigned int fat_offset, const unsigned int no_of_cluster, const unsigned int start_data, const unsigned int cluster_size, const unsigned int sector_size)
+{
+ unsigned char *buffer;
+ const uint16_t *p16;
+ unsigned int prev_cluster;
+ uint64_t hd_offset=partition->part_offset+(uint64_t)fat_offset*sector_size;
+ uint64_t start_free=0;
+ uint64_t end_free=0;
+ log_trace("fat16_remove_used_space\n");
+ buffer=(unsigned char *)MALLOC(sector_size);
+ p16=(const uint16_t*)buffer;
+ del_search_space(list_search_space, partition->part_offset,
+ partition->part_offset+(uint64_t)(start_data*sector_size));
+ for(prev_cluster=2;prev_cluster<=no_of_cluster+1;prev_cluster++)
+ {
+ unsigned int offset_s,offset_o;
+ offset_s=prev_cluster/(sector_size/2);
+ offset_o=prev_cluster%(sector_size/2);
+ if((offset_o==0)||(prev_cluster==2))
+ {
+ if(disk_car->read(disk_car, sector_size, buffer, hd_offset)!=0)
+ {
+ /* Consider these FAT sectors points to free clusters */
+ }
+ hd_offset+=sector_size;
+ }
+ if(le16(p16[offset_o])!=0)
+ {
+ /* Not free */
+ if(end_free+1==partition->part_offset+(uint64_t)(start_data+(prev_cluster-2)*cluster_size)*sector_size)
+ end_free+=cluster_size*sector_size;
+ else
+ {
+ if(start_free != end_free)
+ del_search_space(list_search_space, start_free, end_free);
+ start_free=partition->part_offset+(uint64_t)(start_data+(prev_cluster-2)*cluster_size)*sector_size;
+ end_free=start_free+(uint64_t)cluster_size*sector_size-1;
+ }
+ }
+ }
+ free(buffer);
+ if(start_free != end_free)
+ del_search_space(list_search_space, start_free, end_free);
+}
+
+static void fat32_remove_used_space(disk_t *disk_car,const partition_t *partition, alloc_data_t *list_search_space, const unsigned int fat_offset, const unsigned int no_of_cluster, const unsigned int start_data, const unsigned int cluster_size, const unsigned int sector_size)
+{
+ unsigned char *buffer;
+ uint32_t *p32;
+ unsigned int prev_cluster;
+ uint64_t hd_offset=partition->part_offset+(uint64_t)fat_offset*sector_size;
+ uint64_t start_free=0;
+ uint64_t end_free=0;
+ log_trace("fat32_remove_used_space\n");
+ buffer=(unsigned char *)MALLOC(sector_size);
+ p32=(uint32_t*)buffer;
+ for(prev_cluster=2;prev_cluster<=no_of_cluster+1;prev_cluster++)
+ {
+ unsigned long int cluster;
+ unsigned int offset_s,offset_o;
+ offset_s=prev_cluster/(sector_size/4);
+ offset_o=prev_cluster%(sector_size/4);
+ if((offset_o==0)||(prev_cluster==2))
+ {
+ if(disk_car->read(disk_car,sector_size, buffer, hd_offset)!=0)
+ {
+ /* Consider these FAT sectors points to free clusters */
+ }
+ hd_offset+=sector_size;
+ }
+ cluster=le32(p32[offset_o]) & 0xFFFFFFF;
+ if(cluster!=0)
+ {
+ /* Not free */
+ if(end_free+1==partition->part_offset+(uint64_t)(start_data+(prev_cluster-2)*cluster_size)*sector_size)
+ end_free+=cluster_size*sector_size;
+ else
+ {
+ if(start_free != end_free)
+ del_search_space(list_search_space, start_free, end_free);
+ start_free=partition->part_offset+(uint64_t)(start_data+(prev_cluster-2)*cluster_size)*sector_size;
+ end_free=partition->part_offset+(uint64_t)(start_data+(prev_cluster-2+1)*cluster_size)*sector_size-1;
+ }
+ }
+ }
+ free(buffer);
+ if(start_free != end_free)
+ del_search_space(list_search_space, start_free, end_free);
+}
+
+unsigned int fat_remove_used_space(disk_t *disk_car, const partition_t *partition, alloc_data_t *list_search_space)
+{
+ unsigned long int fat_length;
+ unsigned long int start_fat1;
+ unsigned long int part_size;
+ unsigned int no_of_cluster;
+ unsigned int start_data;
+ unsigned char *buffer;
+ unsigned int res;
+ unsigned int sector_size;
+ const struct fat_boot_sector *fat_header;
+ buffer=MALLOC(3*disk_car->sector_size);
+ fat_header=(const struct fat_boot_sector *)buffer;
+ if(disk_car->read(disk_car,3*disk_car->sector_size, buffer, partition->part_offset)!=0)
+ {
+ free(buffer);
+ return 0;
+ }
+ sector_size=fat_sector_size(fat_header);
+ fat_length=le16(fat_header->fat_length)>0?le16(fat_header->fat_length):le32(fat_header->fat32_length);
+ part_size=(sectors(fat_header)>0?sectors(fat_header):le32(fat_header->total_sect));
+ start_fat1=le16(fat_header->reserved);
+ start_data=start_fat1+fat_header->fats*fat_length+(get_dir_entries(fat_header)*32+sector_size-1)/sector_size;
+ no_of_cluster=(part_size-start_data)/fat_header->cluster_size;
+ if(partition->upart_type==UP_FAT16)
+ fat16_remove_used_space(disk_car,partition, list_search_space, start_fat1, no_of_cluster, start_data, fat_header->cluster_size,sector_size);
+ else if(partition->upart_type==UP_FAT32)
+ fat32_remove_used_space(disk_car,partition, list_search_space, start_fat1, no_of_cluster, start_data, fat_header->cluster_size,sector_size);
+ res=fat_header->cluster_size * sector_size;
+ free(buffer);
+ return res;
+}
diff --git a/src/fatp.h b/src/fatp.h
new file mode 100644
index 0000000..06e6eac
--- /dev/null
+++ b/src/fatp.h
@@ -0,0 +1,22 @@
+/*
+
+ File: fatp.h
+
+ Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+unsigned int fat_remove_used_space(disk_t *disk_car,const partition_t *partition, alloc_data_t *list_search_space);
diff --git a/src/fatx.c b/src/fatx.c
new file mode 100644
index 0000000..02f9750
--- /dev/null
+++ b/src/fatx.c
@@ -0,0 +1,72 @@
+/*
+
+ File: fatx.c
+
+ Copyright (C) 2005-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "fatx.h"
+static void set_FATX_info(disk_t *disk_car, const struct disk_fatx *fatx_block,partition_t *partition);
+static int test_fatx(disk_t *disk_car, const struct disk_fatx *fatx_block,partition_t *partition,const int verbose, const int dump_ind);
+
+static int test_fatx(disk_t *disk_car, const struct disk_fatx *fatx_block,partition_t *partition,const int verbose, const int dump_ind)
+{
+ if(memcmp(fatx_block->magic,"FATX",4)==0)
+ {
+ partition->upart_type=UP_FATX;
+ return 0;
+ }
+ return 1;
+}
+
+int check_FATX(disk_t *disk_car,partition_t *partition,const int verbose)
+{
+ unsigned char buffer[8*DEFAULT_SECTOR_SIZE];
+ if(disk_car->read(disk_car,sizeof(buffer), &buffer, partition->part_offset)!=0)
+ { return 1; }
+ if(test_fatx(disk_car,(const struct disk_fatx *)&buffer,partition,verbose,0)!=0)
+ return 1;
+ set_FATX_info(disk_car,(const struct disk_fatx *)&buffer,partition);
+ return 0;
+}
+
+int recover_FATX(disk_t *disk_car, const struct disk_fatx *fatx_block,partition_t *partition, const int verbose, const int dump_ind)
+{
+ if(test_fatx(disk_car,fatx_block,partition,0,0)!=0)
+ return 1;
+ set_FATX_info(disk_car,fatx_block,partition);
+ partition->part_type_xbox=PXBOX_FATX;
+ /* FIXME: Locate the partition but cannot get the part_size unfortunatly */
+ partition->part_size=(uint64_t)le32(fatx_block->cluster_size_in_sector)*512;
+ return 0;
+}
+
+static void set_FATX_info(disk_t *disk_car, const struct disk_fatx *fatx_block,partition_t *partition)
+{
+ partition->fsname[0]='\0';
+ strncpy(partition->info,"FATX",sizeof(partition->info));
+}
+
diff --git a/src/fatx.h b/src/fatx.h
new file mode 100644
index 0000000..e4b1a5b
--- /dev/null
+++ b/src/fatx.h
@@ -0,0 +1,33 @@
+/*
+
+ File: fatx.h
+
+ Copyright (C) 2005 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+struct disk_fatx
+{
+ char magic[4];
+ uint32_t volume_id;
+ uint32_t cluster_size_in_sector;
+ uint16_t fats;
+ uint32_t unknown;
+} __attribute__ ((__packed__));
+
+int check_FATX(disk_t *disk_car,partition_t *partition,const int verbose);
+int recover_FATX(disk_t *disk_car, const struct disk_fatx *fatx_block, partition_t *partition, const int verbose, const int dump_ind);
diff --git a/src/file_7z.c b/src/file_7z.c
new file mode 100644
index 0000000..02c0aef
--- /dev/null
+++ b/src/file_7z.c
@@ -0,0 +1,80 @@
+/*
+
+ File: file_7z.c
+
+ Copyright (C) 2005-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+#include "common.h"
+
+static void register_header_check_7z(file_stat_t *file_stat);
+static int header_check_7z(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_7z= {
+ .extension="7z",
+ .description="7zip archive file",
+ .min_header_distance=0,
+ .max_filesize=1024*1024,
+ .recover=1,
+ .header_check=&header_check_7z,
+ .register_header_check=&register_header_check_7z
+};
+
+static const unsigned char header_7z[6] = {'7','z', 0xbc, 0xaf, 0x27, 0x1c};
+struct header_7z {
+ unsigned char signature[6];
+ uint8_t majorversion;
+ uint8_t minorversion;
+ uint32_t crcFromArchive;
+ uint64_t nextHeaderOffset;
+ uint64_t nextHeaderSize;
+ uint64_t nextHeaderCRC;
+} __attribute__ ((__packed__));
+
+static void register_header_check_7z(file_stat_t *file_stat)
+{
+ register_header_check(0, header_7z, sizeof(header_7z), &header_check_7z, file_stat);
+}
+
+static int header_check_7z(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ const struct header_7z *buffer_7z=(const struct header_7z *)buffer;
+ if(memcmp(buffer,header_7z,sizeof(header_7z))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_7z.extension;
+ file_recovery_new->min_filesize=31;
+ /* Signature size 12 + Start header size 20 */
+ file_recovery_new->calculated_file_size=(uint64_t)le64(buffer_7z->nextHeaderOffset)+
+ le64(buffer_7z->nextHeaderSize) + 12 + 20;
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/src/file_a.c b/src/file_a.c
new file mode 100644
index 0000000..cb85847
--- /dev/null
+++ b/src/file_a.c
@@ -0,0 +1,62 @@
+/*
+
+ File: file_a.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_a(file_stat_t *file_stat);
+static int header_check_a(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_a= {
+ .extension="a",
+ .description="Unix Archive/Debian package",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_a,
+ .register_header_check=&register_header_check_a
+};
+
+static const unsigned char a_header[8] = { '!','<','a','r','c','h','>','\n'};
+
+static void register_header_check_a(file_stat_t *file_stat)
+{
+ register_header_check(0, a_header,sizeof(a_header), &header_check_a, file_stat);
+}
+
+static int header_check_a(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,a_header,sizeof(a_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_a.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_ab.c b/src/file_ab.c
new file mode 100644
index 0000000..1788f50
--- /dev/null
+++ b/src/file_ab.c
@@ -0,0 +1,96 @@
+/*
+
+ File: file_addressbook.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+#include "log.h"
+
+static void register_header_check_ab(file_stat_t *file_stat);
+static int header_check_addressbook(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+static int data_check_addressbook(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
+
+const file_hint_t file_hint_addressbook= {
+ .extension="ab",
+ .description="MAC Address Book",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_addressbook,
+ .register_header_check=&register_header_check_ab
+};
+
+static const unsigned char ab_header[2]={ 'L', 'J' };
+
+static void register_header_check_ab(file_stat_t *file_stat)
+{
+ register_header_check(0, ab_header,sizeof(ab_header), &header_check_addressbook, file_stat);
+}
+
+static int header_check_addressbook(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(buffer[0]=='L' && buffer[1]=='J' && (buffer[2]==0x1a || buffer[2]==0x0a) && buffer[3]==0x00)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->calculated_file_size=(buffer[4]<<24)+(buffer[5]<<16)+(buffer[6]<<8)+buffer[7];
+ file_recovery_new->data_check=&data_check_addressbook;
+ file_recovery_new->file_check=&file_check_size;
+ file_recovery_new->extension=file_hint_addressbook.extension;
+ return 1;
+ }
+ return 0;
+}
+
+static int data_check_addressbook(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
+{
+ while(file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2)
+ {
+ unsigned int i=file_recovery->calculated_file_size - file_recovery->file_size + buffer_size/2;
+#ifdef DEBUG_AB
+ log_debug("data_check_addressbook i=0x%x buffer_size=0x%x calculated_file_size=%lu file_size=%lu\n",
+ i, buffer_size,
+ (long unsigned)file_recovery->calculated_file_size,
+ (long unsigned)file_recovery->file_size);
+ dump_log(buffer+i,8);
+#endif
+ if(buffer[i+0]=='L' && buffer[i+1]=='J' && buffer[i+3]==0x00)
+ {
+ unsigned int length=(buffer[i+4]<<24)+(buffer[i+5]<<16)+(buffer[i+6]<<8)+buffer[i+7];
+ if(length<8)
+ {
+ return 2;
+ }
+ file_recovery->calculated_file_size+=length;
+ }
+ else
+ {
+ return 2;
+ }
+ }
+ return 1;
+}
diff --git a/src/file_ace.c b/src/file_ace.c
new file mode 100644
index 0000000..f62ce9d
--- /dev/null
+++ b/src/file_ace.c
@@ -0,0 +1,172 @@
+/*
+
+ File: file_ace.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+#include "common.h"
+#include "log.h"
+#include "crc.h"
+
+/* #define DEBUG_ACE */
+
+static void register_header_check_ace(file_stat_t *file_stat);
+static int header_check_ace(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_ace= {
+ .extension="ace",
+ .description="ACE archive",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_ace,
+ .register_header_check=&register_header_check_ace
+};
+
+static const unsigned char ace_header[7] = { '*','*','A','C','E','*','*'};
+
+static void register_header_check_ace(file_stat_t *file_stat)
+{
+ register_header_check(7, ace_header,sizeof(ace_header), &header_check_ace, file_stat);
+}
+
+struct header_ace {
+ uint16_t crc16; /** Lower 16bits of CRC32 over block up from HEAD_TYPE */
+ uint16_t size; /** Size of the block from HEAD_TYPE
+ up to the beginning of the ADDSIZE block */
+ uint8_t type; /** indicates type of block */
+ uint16_t flags; /** flags related to the block and its content
+ for all blocks these flags are valid.
+ bit 0 indicates if field add size is preset */
+ uint32_t addsize; /** an optional field which represents the size of
+ an additional block without specified structure */
+} __attribute__ ((__packed__));
+typedef struct header_ace ace_header_t;
+
+static void file_check_ace(file_recovery_t *file_recovery)
+{
+ fseek(file_recovery->handle, 0, SEEK_SET);
+
+ file_recovery->file_size = 0;
+ file_recovery->offset_error=0;
+#ifdef DEBUG_ACE
+ log_trace("file_check_ace\n");
+#endif
+ while (!feof(file_recovery->handle))
+ {
+ ace_header_t h;
+ if(fread(&h, sizeof(h), 1, file_recovery->handle)!=1)
+ {
+ return ;
+ }
+ fseek(file_recovery->handle, -sizeof(h)+4, SEEK_CUR);
+
+#ifdef DEBUG_ACE
+ log_trace("file_ace: Block header at 0x%08lx: CRC16=0x%04X size=%u type=%u"
+ " flags=0x%04X addsize=%u\n",
+ (long unsigned) file_recovery->file_size,
+ le16(h.crc16), le16(h.size), h.type, le16(h.flags),
+ (le16(h.flags)&1) ? le32(h.addsize):0);
+#endif
+ /* Type 0=Archive header, 1=File block, 2=Recovery Record, 5 new_recovery ? */
+ if (h.type!=0 && h.type!=1 && h.type!=2 && h.type!=5)
+ {
+#ifdef DEBUG_ACE
+ log_trace("file_ace: Invalid block type %u\n", h.type);
+#endif
+ return ;
+ }
+
+ /* Minimal size is type+flags */
+ if (le16(h.size) < 1+2)
+ {
+#ifdef DEBUG_ACE
+ log_trace("file_ace: Invalid block size %u\n", le16(h.size));
+#endif
+ return ;
+ }
+
+ {
+ /* Header hardly ever bigger than a filename */
+#define BUF_SIZE 256
+ unsigned char buffer[BUF_SIZE];
+ int len=le16(h.size);
+ uint32_t crc32=0xFFFFFFFF;
+
+ while (len>0)
+ {
+ int count = ((len>BUF_SIZE) ? BUF_SIZE : len);
+ int bytes = fread(buffer, 1, count, file_recovery->handle);
+
+ if (bytes != count)
+ {
+#ifdef DEBUG_ACE
+ log_trace("file_ace: truncated file\n");
+#endif
+ return ;
+ }
+ crc32=get_crc32(buffer, count, crc32);
+ len -= count;
+ }
+ if (le16(h.crc16) != (crc32&0xFFFF))
+ {
+#ifdef DEBUG_ACE
+ log_trace("file_ace: bad CRC32: %04X vs %04X\n", le16(h.crc16), crc32);
+#endif
+ return ;
+ }
+ }
+ /* Add its header size */
+ file_recovery->file_size += 2 + 2 + le16(h.size); /* +2: CRC16, +2: size */
+ /* If addsize flag, add complementary size */
+ if (le16(h.flags)&1)
+ {
+ file_recovery->file_size += le32(h.addsize);
+ fseek(file_recovery->handle, file_recovery->file_size, SEEK_SET);
+ }
+ }
+}
+
+static int header_check_ace(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(&buffer[7],ace_header,sizeof(ace_header))==0 && buffer[4]==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_ace.extension;
+ file_recovery_new->min_filesize=
+ 2 + /* CRC16 */
+ 2 + /* Head size */
+ 1 + /* Head type */
+ 2 + /* Flags */
+ 7 + /* Signature */
+ 16; /* Minimal size for marker header */
+ file_recovery_new->file_check=&file_check_ace;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_aif.c b/src/file_aif.c
new file mode 100644
index 0000000..9127ea3
--- /dev/null
+++ b/src/file_aif.c
@@ -0,0 +1,66 @@
+/*
+
+ File: file_aif.c
+
+ Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_aif(file_stat_t *file_stat);
+static int header_check_aif(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_aif= {
+ .extension="aif",
+ .description="Audio Interchange File Format",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_aif,
+ .register_header_check=&register_header_check_aif
+};
+
+static const unsigned char aif_header[4]= {'F','O','R','M'};
+
+static void register_header_check_aif(file_stat_t *file_stat)
+{
+ register_header_check(0, aif_header,sizeof(aif_header), &header_check_aif, file_stat);
+}
+
+static int header_check_aif(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,aif_header,sizeof(aif_header))==0 &&
+ buffer[8]=='A' && buffer[9]=='I' && buffer[10]=='F' && (buffer[11]=='F' || buffer[11]=='C'))
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_aif.extension;
+ file_recovery_new->calculated_file_size=((uint64_t)buffer[7]+(((uint64_t)buffer[6])<<8)+(((uint64_t)buffer[5])<<16)+(((uint64_t)buffer[4])<<24))+8;
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_all.c b/src/file_all.c
new file mode 100644
index 0000000..271fcf5
--- /dev/null
+++ b/src/file_all.c
@@ -0,0 +1,63 @@
+/*
+
+ File: file_all.c
+
+ Copyright (C) 1998-2005,2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_all(file_stat_t *file_stat);
+static int header_check_all(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_all= {
+ .extension="all",
+ .description="Cubase Song file: .all",
+ .min_header_distance=0,
+ .max_filesize=50*1024*1024,
+ .recover=1,
+ .header_check=&header_check_all,
+ .register_header_check=&register_header_check_all
+};
+
+const unsigned char all_header[8]= { 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x06, 0x04};
+
+static void register_header_check_all(file_stat_t *file_stat)
+{
+ register_header_check(0, all_header,sizeof(all_header), &header_check_all, file_stat);
+}
+
+static int header_check_all(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,all_header,8)==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->min_filesize=122;
+ file_recovery_new->extension=file_hint_all.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_asf.c b/src/file_asf.c
new file mode 100644
index 0000000..f826d11
--- /dev/null
+++ b/src/file_asf.c
@@ -0,0 +1,69 @@
+/*
+
+ File: file_asf.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+#include "log.h"
+
+static void register_header_check_asf(file_stat_t *file_stat);
+static int header_check_asf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_asf= {
+ .extension="asf",
+ .description="ASF, WMA, WMV: Advanced Streaming Format used for Audio/Video",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_asf,
+ .register_header_check=&register_header_check_asf
+};
+
+const unsigned char asf_header[4]= { 0x30,0x26,0xB2,0x75};
+
+static void register_header_check_asf(file_stat_t *file_stat)
+{
+ register_header_check(0, asf_header,sizeof(asf_header), &header_check_asf, file_stat);
+}
+
+static int header_check_asf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,asf_header,sizeof(asf_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_asf.extension;
+ /*
+ file_recovery_new->calculated_file_size=(uint64_t)buffer[70]+(((uint64_t)buffer[71])<<8)+(((uint64_t)buffer[72])<<16)+(((uint64_t)buffer[73])<<24);
+ log_info("asf calculated_file_size %llu\n", (long long unsigned)file_recovery_new->calculated_file_size);
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ */
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_au.c b/src/file_au.c
new file mode 100644
index 0000000..0c647f1
--- /dev/null
+++ b/src/file_au.c
@@ -0,0 +1,63 @@
+/*
+
+ File: file_au.c
+
+ Copyright (C) 1998-2005,2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_au(file_stat_t *file_stat);
+static int header_check_au(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_au= {
+ .extension="au",
+ .description="Sun/NeXT audio data",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_au,
+ .register_header_check=&register_header_check_au
+};
+
+static const unsigned char au_header[4]= {'.','s','n','d'};
+
+static void register_header_check_au(file_stat_t *file_stat)
+{
+ register_header_check(0, au_header,sizeof(au_header), &header_check_au, file_stat);
+}
+
+static int header_check_au(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,au_header,sizeof(au_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->min_filesize=111;
+ file_recovery_new->extension=file_hint_au.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_bkf.c b/src/file_bkf.c
new file mode 100644
index 0000000..ec90e18
--- /dev/null
+++ b/src/file_bkf.c
@@ -0,0 +1,63 @@
+/*
+
+ File: file_bkf.c
+
+ Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_bkf(file_stat_t *file_stat);
+static int header_check_bkf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_bkf= {
+ .extension="bkf",
+ .description="MS Backup file",
+ .min_header_distance=0,
+ .max_filesize=-1,
+ .recover=1,
+ .header_check=&header_check_bkf,
+ .register_header_check=&register_header_check_bkf
+};
+
+static const unsigned char bkf_header[4]= { 'T','A','P','E'};
+
+static void register_header_check_bkf(file_stat_t *file_stat)
+{
+ register_header_check(0, bkf_header,sizeof(bkf_header), &header_check_bkf, file_stat);
+}
+
+static int header_check_bkf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,bkf_header,sizeof(bkf_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->min_filesize=4;
+ file_recovery_new->extension=file_hint_bkf.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_bld.c b/src/file_bld.c
new file mode 100644
index 0000000..a57588e
--- /dev/null
+++ b/src/file_bld.c
@@ -0,0 +1,63 @@
+/*
+
+ File: file_bld.c
+
+ Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_blend(file_stat_t *file_stat);
+static int header_check_blend(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_blend= {
+ .extension="blend",
+ .description="blender",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_blend,
+ .register_header_check=&register_header_check_blend
+};
+
+static const unsigned char blend_header[7] = { 'B', 'L', 'E', 'N', 'D', 'E', 'R'};
+
+static void register_header_check_blend(file_stat_t *file_stat)
+{
+ register_header_check(0, blend_header,sizeof(blend_header), &header_check_blend, file_stat);
+}
+
+static int header_check_blend(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,blend_header,sizeof(blend_header))==0 && (buffer[7]=='_' || buffer[7]=='-'))
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_blend.extension;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/src/file_bmp.c b/src/file_bmp.c
new file mode 100644
index 0000000..620ea8c
--- /dev/null
+++ b/src/file_bmp.c
@@ -0,0 +1,67 @@
+/*
+
+ File: file_bmp.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_bmp(file_stat_t *file_stat);
+static int header_check_bmp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_bmp= {
+ .extension="bmp",
+ .description="BMP bitmap image",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_bmp,
+ .register_header_check=&register_header_check_bmp
+};
+
+static const unsigned char bmp_header[2]= {'B','M'};
+
+static void register_header_check_bmp(file_stat_t *file_stat)
+{
+ register_header_check(0, bmp_header,sizeof(bmp_header), &header_check_bmp, file_stat);
+}
+
+static int header_check_bmp(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(buffer[0]=='B' && buffer[1]=='M' &&
+ buffer[6]==0x00 && buffer[7]==0x00 && buffer[8]==0x00 && buffer[9]==0x00)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_bmp.extension;
+ file_recovery_new->min_filesize=65;
+ file_recovery_new->calculated_file_size=(uint64_t)buffer[2]+(((uint64_t)buffer[3])<<8)+(((uint64_t)buffer[4])<<16)+(((uint64_t)buffer[5])<<24);
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_bz2.c b/src/file_bz2.c
new file mode 100644
index 0000000..7525bd1
--- /dev/null
+++ b/src/file_bz2.c
@@ -0,0 +1,62 @@
+/*
+
+ File: file_bz2.c
+
+ Copyright (C) 1998-2005,2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_bz2(file_stat_t *file_stat);
+static int header_check_bz2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_bz2= {
+ .extension="bz2",
+ .description="bzip2 compressed data",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_bz2,
+ .register_header_check=&register_header_check_bz2
+};
+
+static const unsigned char bz2_header[3]= {'B','Z','h'};
+
+static void register_header_check_bz2(file_stat_t *file_stat)
+{
+ register_header_check(0, bz2_header,sizeof(bz2_header), &header_check_bz2, file_stat);
+}
+
+static int header_check_bz2(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(buffer[0]=='B' && buffer[1]=='Z' && buffer[2]=='h' && buffer[3]>='0' && buffer[4]=='1' && buffer[5]=='A' && buffer[6]=='Y' && buffer[7]=='&' && buffer[8]=='S' && buffer[9]=='Y')
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_bz2.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_cab.c b/src/file_cab.c
new file mode 100644
index 0000000..fee419d
--- /dev/null
+++ b/src/file_cab.c
@@ -0,0 +1,81 @@
+/*
+
+ File: file_cab.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "common.h"
+#include "filegen.h"
+
+static void register_header_check_cab(file_stat_t *file_stat);
+static int header_check_cab(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_cab= {
+ .extension="cab",
+ .description="Microsoft Cabinet archive",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_cab,
+ .register_header_check=&register_header_check_cab
+};
+
+static const unsigned char cab_header[4] = { 'M','S','C','F'};
+struct cab_header {
+ uint32_t magic;
+ uint32_t hdr_checksum;
+ uint32_t filesize;
+ uint32_t fld_checksum;
+ uint32_t off_file;
+ uint32_t files_checksum;
+ uint16_t cab_version;
+ uint16_t nb_folder;
+ uint16_t nb_files;
+ uint16_t flags;
+ uint16_t setid;
+ uint16_t number;
+} __attribute__ ((__packed__));
+
+static void register_header_check_cab(file_stat_t *file_stat)
+{
+ register_header_check(0, cab_header,sizeof(cab_header), &header_check_cab, file_stat);
+}
+
+static int header_check_cab(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ const struct cab_header *cab_hdr=(const struct cab_header*)buffer;
+ if(memcmp(buffer,cab_header,sizeof(cab_header))==0 && le16(cab_hdr->cab_version)==0x0103)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_cab.extension;
+ file_recovery_new->calculated_file_size=(uint64_t)le32(cab_hdr->filesize);
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_cam.c b/src/file_cam.c
new file mode 100644
index 0000000..0953c5d
--- /dev/null
+++ b/src/file_cam.c
@@ -0,0 +1,63 @@
+/*
+
+ File: file_cam.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_cam(file_stat_t *file_stat);
+static int header_check_cam(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_cam= {
+ .extension="cam",
+ .description="Casio QV Digital Camera Image",
+ .min_header_distance=0,
+ .max_filesize=10*1024*1024,
+ .recover=1,
+ .header_check=&header_check_cam,
+ .register_header_check=&register_header_check_cam
+};
+
+static const unsigned char cam_header[4]= {0x07, 0x20, 'M', 'M'};
+
+static void register_header_check_cam(file_stat_t *file_stat)
+{
+ register_header_check(0, cam_header,sizeof(cam_header), &header_check_cam, file_stat);
+}
+
+static int header_check_cam(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,cam_header,sizeof(cam_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_cam.extension;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/src/file_cm.c b/src/file_cm.c
new file mode 100644
index 0000000..5f24cb3
--- /dev/null
+++ b/src/file_cm.c
@@ -0,0 +1,62 @@
+/*
+
+ File: file_cm.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_cm(file_stat_t *file_stat);
+static int header_check_cm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_cm= {
+ .extension="comicdoc",
+ .description="Comic Life",
+ .min_header_distance=0x0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_cm,
+ .register_header_check=&register_header_check_cm
+};
+
+static const unsigned char cm_header[8] = { 'f','L','m','C','0','0','0','1'};
+
+static void register_header_check_cm(file_stat_t *file_stat)
+{
+ register_header_check(0x0, cm_header,sizeof(cm_header), &header_check_cm, file_stat);
+}
+
+static int header_check_cm(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(&buffer[0x0],cm_header,sizeof(cm_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_cm.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_crw.c b/src/file_crw.c
new file mode 100644
index 0000000..6de8f9a
--- /dev/null
+++ b/src/file_crw.c
@@ -0,0 +1,86 @@
+/*
+
+ File: file_crw.c
+
+ Copyright (C) 1998-2005,2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+#include "log.h"
+
+static void register_header_check_crw(file_stat_t *file_stat);
+static int header_check_crw(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+static int data_check_crw(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
+
+const file_hint_t file_hint_crw= {
+ .extension="crw",
+ .description="Canon Raw picture",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_crw,
+ .register_header_check=&register_header_check_crw
+};
+
+static const unsigned char crw_header_be[2]= {'I','I'};
+static const unsigned char crw_header_le[2]= {'M','M'};
+
+static void register_header_check_crw(file_stat_t *file_stat)
+{
+ register_header_check(0, crw_header_be, sizeof(crw_header_be), &header_check_crw, file_stat);
+ register_header_check(0, crw_header_le, sizeof(crw_header_le), &header_check_crw, file_stat);
+}
+
+static int header_check_crw(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(((buffer[0]==0x49 && buffer[1]==0x49)||(buffer[0]==0x4D && buffer[1]==0x4D))
+ && memcmp(buffer+6,"HEAPCCDR",8)==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_crw.extension;
+ file_recovery_new->data_check=&data_check_crw;
+ file_recovery_new->file_check=&file_check_size;
+ return 1;
+ }
+ return 0;
+}
+
+static int data_check_crw(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
+{
+ unsigned int i;
+ for(i=(buffer_size/2)-13;i+13<buffer_size;i++)
+ {
+ if(buffer[i]==0x0A && buffer[i+1]==0x30 && buffer[i+2]==0xFE && buffer[i+3]==0x17 && buffer[i+13]==0)
+ {
+ file_recovery->calculated_file_size=file_recovery->file_size+i+14-(buffer_size/2);
+ log_debug("EOF CRW found\n");
+ return 2;
+ }
+ }
+ file_recovery->calculated_file_size=file_recovery->file_size+(buffer_size/2);
+ return 1;
+}
+
diff --git a/src/file_ctg.c b/src/file_ctg.c
new file mode 100644
index 0000000..8dc8489
--- /dev/null
+++ b/src/file_ctg.c
@@ -0,0 +1,64 @@
+/*
+
+ File: file_ctg.c
+
+ Copyright (C) 1998-2005,2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_ctg(file_stat_t *file_stat);
+static int header_check_ctg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_ctg= {
+ .extension="ctg",
+ .description="Canon catalog",
+ .min_header_distance=0,
+ .max_filesize=4634,
+ .recover=0,
+ .header_check=&header_check_ctg,
+ .register_header_check=&register_header_check_ctg
+};
+
+static const unsigned char ctg_header[7]= {':','\\','D','C','I','M','\\'};
+
+static void register_header_check_ctg(file_stat_t *file_stat)
+{
+ register_header_check(1, ctg_header,sizeof(ctg_header), &header_check_ctg, file_stat);
+}
+
+static int header_check_ctg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer+1, ctg_header,sizeof(ctg_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_ctg.extension;
+ return 1;
+ }
+ return 0;
+}
+
+
diff --git a/src/file_cwk.c b/src/file_cwk.c
new file mode 100644
index 0000000..43691e9
--- /dev/null
+++ b/src/file_cwk.c
@@ -0,0 +1,72 @@
+/*
+
+ File: file_cwk.c
+
+ Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_cwk(file_stat_t *file_stat);
+static int header_check_cwk(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+static void file_check_cwk(file_recovery_t *file_recovery);
+
+const file_hint_t file_hint_cwk= {
+ .extension="cwk",
+ .description="AppleWorks",
+ .min_header_distance=0,
+ .max_filesize=200*1024*1024,
+ .recover=1,
+ .header_check=&header_check_cwk,
+ .register_header_check=&register_header_check_cwk
+};
+
+static const unsigned char cwk_header[4]= {'B','O','B','O'};
+
+static void register_header_check_cwk(file_stat_t *file_stat)
+{
+ register_header_check(4, cwk_header,sizeof(cwk_header), &header_check_cwk, file_stat);
+}
+
+static int header_check_cwk(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer+4, cwk_header, sizeof(cwk_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_cwk.extension;
+ file_recovery_new->file_check=&file_check_cwk;
+ return 1;
+ }
+ return 0;
+}
+
+static void file_check_cwk(file_recovery_t *file_recovery)
+{
+ const unsigned char cwk_footer[4]= {0xf0, 0xf1, 0xf2, 0xf3};
+ file_search_footer(file_recovery, cwk_footer,sizeof(cwk_footer));
+ if(file_recovery->file_size>0)
+ file_recovery->file_size+=4;
+}
diff --git a/src/file_dat.c b/src/file_dat.c
new file mode 100644
index 0000000..6654186
--- /dev/null
+++ b/src/file_dat.c
@@ -0,0 +1,62 @@
+/*
+
+ File: file_dat.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_dat(file_stat_t *file_stat);
+static int header_check_dat(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_dat= {
+ .extension="dat",
+ .description="Glavna Knjiga account data",
+ .min_header_distance=0,
+ .max_filesize=2*1024*1024,
+ .recover=1,
+ .header_check=&header_check_dat,
+ .register_header_check=&register_header_check_dat
+};
+
+static const unsigned char dat_header[8]= {0x30, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static void register_header_check_dat(file_stat_t *file_stat)
+{
+ register_header_check(0, dat_header,sizeof(dat_header), &header_check_dat, file_stat);
+}
+
+static int header_check_dat(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,dat_header,sizeof(dat_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_dat.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_dbf.c b/src/file_dbf.c
new file mode 100644
index 0000000..25eaa77
--- /dev/null
+++ b/src/file_dbf.c
@@ -0,0 +1,63 @@
+/*
+
+ File: file_dbf.c
+
+ Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_dbf(file_stat_t *file_stat);
+static int header_check_dbf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_dbf= {
+ .extension="dbf",
+ .description="DBase 3, prone to false positive",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_dbf,
+ .register_header_check=&register_header_check_dbf
+};
+
+static const unsigned char dbf_header[1]= {0x3};
+
+static void register_header_check_dbf(file_stat_t *file_stat)
+{
+ register_header_check(0, dbf_header,sizeof(dbf_header), &header_check_dbf, file_stat);
+}
+
+static int header_check_dbf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ /* 0x03 YY MM DD */
+ if(buffer[0]==0x3 && (buffer[1]>80 || buffer[1]<20) && (buffer[2]>=1 && buffer[2]<=12) && (buffer[3]>=1 && buffer[3]<=31))
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_dbf.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_dir.c b/src/file_dir.c
new file mode 100644
index 0000000..2c56440
--- /dev/null
+++ b/src/file_dir.c
@@ -0,0 +1,62 @@
+/*
+
+ File: file_dir.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_dir(file_stat_t *file_stat);
+static int header_check_dir(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_dir= {
+ .extension="",
+ .description="FAT subdirectory",
+ .min_header_distance=0,
+ .max_filesize=1,
+ .recover=0,
+ .header_check=&header_check_dir,
+ .register_header_check=&register_header_check_dir
+};
+
+static const unsigned char *dir_header=". ";
+
+static void register_header_check_dir(file_stat_t *file_stat)
+{
+ register_header_check(0, dir_header,8+3, &header_check_dir, file_stat);
+}
+
+static int header_check_dir(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,dir_header,8+3)==0 && memcmp(&buffer[0x20],".. ",8+3)==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_dir.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_djv.c b/src/file_djv.c
new file mode 100644
index 0000000..f1a650c
--- /dev/null
+++ b/src/file_djv.c
@@ -0,0 +1,65 @@
+/*
+
+ File: file_djv.c
+
+ Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_djv(file_stat_t *file_stat);
+static int header_check_djv(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_djv= {
+ .extension="djv",
+ .description="DjVu",
+ .min_header_distance=0,
+ .max_filesize=200*1024*1024,
+ .recover=1,
+ .header_check=&header_check_djv,
+ .register_header_check=&register_header_check_djv
+};
+
+static const unsigned char djv_header[8]= { 'A','T','&','T','F','O','R','M'};
+
+static void register_header_check_djv(file_stat_t *file_stat)
+{
+ register_header_check(0, djv_header,sizeof(djv_header), &header_check_djv, file_stat);
+}
+
+static int header_check_djv(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,djv_header,sizeof(djv_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_djv.extension;
+ file_recovery_new->calculated_file_size=((uint64_t)buffer[8]<<24)+((uint64_t)buffer[8+1]<<16)+((uint64_t)buffer[8+2]<<8)+(uint64_t)buffer[8+3]+12;
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_doc.c b/src/file_doc.c
new file mode 100644
index 0000000..a43cde1
--- /dev/null
+++ b/src/file_doc.c
@@ -0,0 +1,234 @@
+/*
+
+ File: file_doc.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "common.h"
+#include "filegen.h"
+#include "ole.h"
+#include "log.h"
+
+static void register_header_check_doc(file_stat_t *file_stat);
+static void file_check_doc(file_recovery_t *file_recovery);
+static int header_check_doc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+static const unsigned char * find_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size);
+static uint64_t test_OLE(FILE *file);
+
+const file_hint_t file_hint_doc= {
+ .extension="doc",
+ .description="Microsoft Office Document (doc/xls/ppt/vis/...), 3ds Max, MetaStock",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_doc,
+ .register_header_check=&register_header_check_doc
+};
+
+static const unsigned char doc_header[]= { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1};
+
+static void register_header_check_doc(file_stat_t *file_stat)
+{
+ register_header_check(0, doc_header,sizeof(doc_header), &header_check_doc, file_stat);
+}
+
+static const unsigned char * find_in_mem(const unsigned char *haystack, const unsigned int haystack_size, const unsigned char *needle, const unsigned int needle_size)
+{
+ unsigned int i;
+ for(i=0;i<haystack_size-needle_size;i++)
+ if(memcmp(&haystack[i],needle,needle_size)==0)
+ return &haystack[i];
+ return NULL;
+}
+
+static void file_check_doc(file_recovery_t *file_recovery)
+{
+ uint64_t doc_file_size=test_OLE(file_recovery->handle);
+ file_recovery->file_size=(doc_file_size>0?((doc_file_size<=(file_recovery->file_size))?doc_file_size:0):0);
+#ifdef DEBUG_OLE
+ log_trace("size found : %llu\n",(long long unsigned)doc_file_size);
+ log_trace("==> size : %llu\n",(long long unsigned)file_recovery->file_size);
+#endif
+}
+
+static int header_check_doc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,doc_header,sizeof(doc_header))==0)
+ {
+ const struct OLE_HDR *header=(const struct OLE_HDR *)buffer;
+ if(le16(header->reserved)!=0 || le32(header->reserved1)!=0 || le32(header->reserved2)!=0)
+ return 0;
+ if(le16(header->uMiniSectorShift)!=6 || le16(header->uSectorShift)!=9)
+ return 0;
+ if(le32(header->num_FAT_blocks)==0 ||
+ le32(header->num_extra_FAT_blocks)>50 ||
+ le32(header->num_FAT_blocks)>109+le32(header->num_extra_FAT_blocks)*((1<<le16(header->uSectorShift))-1))
+ return 0;
+ /* TODO read the Root Directory */
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->file_check=&file_check_doc;
+ if(find_in_mem(buffer,buffer_size,"S\0c\0e\0n\0e\0",10)!=NULL)
+ {
+ file_recovery_new->extension="max";
+ }
+ else if(find_in_mem(buffer,buffer_size,"WordDocument",12)!=NULL)
+ {
+ file_recovery_new->extension="doc";
+ }
+ else if(find_in_mem(buffer,buffer_size,"StarDraw",8)!=NULL)
+ {
+ file_recovery_new->extension="sda";
+ }
+ else if(find_in_mem(buffer,buffer_size,"StarCalc",8)!=NULL)
+ {
+ file_recovery_new->extension="sdc";
+ }
+ else if(find_in_mem(buffer,buffer_size,"StarImpress",11)!=NULL)
+ {
+ file_recovery_new->extension="sdd";
+ }
+ else if(find_in_mem(buffer,buffer_size,"W\0k\0s\0S\0S\0W\0o\0r\0k\0B\0o\0o\0k\0",26)!=NULL)
+ {
+ file_recovery_new->extension="xlr";
+ }
+ else if(find_in_mem(buffer,buffer_size,"Worksheet",9)!=NULL ||
+ find_in_mem(buffer,buffer_size,"Book",4)!=NULL ||
+ find_in_mem(buffer,buffer_size,"Workbook",8)!=NULL ||
+ find_in_mem(buffer,buffer_size,"W\0o\0r\0k\0b\0o\0o\0k\0",16)!=NULL ||
+ find_in_mem(buffer,buffer_size,"Calc",4)!=NULL)
+ {
+ file_recovery_new->extension="xls";
+ }
+ else if(find_in_mem(buffer,buffer_size,"Power",5)!=NULL ||
+ find_in_mem(buffer,buffer_size,"P\0o\0w\0e\0r\0",10)!=NULL)
+ {
+ file_recovery_new->extension="ppt";
+ }
+ else if(find_in_mem(buffer,buffer_size,"AccessObjSiteData",17)!=NULL)
+ {
+ file_recovery_new->extension="mdb";
+ }
+ else if(find_in_mem(buffer,buffer_size,"Visio",5)!=NULL)
+ {
+ file_recovery_new->extension="vis";
+ }
+ else if(find_in_mem(buffer,buffer_size,"Sfx",3)!=NULL)
+ {
+ file_recovery_new->extension="sdw";
+ }
+ else if(find_in_mem(buffer,buffer_size,"CPicPage",8)!=NULL)
+ { /* Flash */
+ file_recovery_new->extension="fla";
+ }
+ else if(find_in_mem(buffer,buffer_size,"Microsoft Publisher",19)!=NULL)
+ {
+ file_recovery_new->extension="pub";
+ }
+ else if(find_in_mem(buffer,buffer_size,"C\0O\0N\0T\0E\0N\0T\0S\0",16)!=NULL)
+ {
+ file_recovery_new->extension="wps";
+ }
+ else if(find_in_mem(buffer,buffer_size,"MetaStock",9)!=NULL)
+ {
+ file_recovery_new->extension="mws";
+ }
+ else
+ file_recovery_new->extension=file_hint_doc.extension;
+ return 1;
+ }
+ return 0;
+}
+
+static uint64_t test_OLE(FILE *IN)
+{
+ unsigned char buffer_header[512];
+ uint64_t totalsize;
+ uint32_t *dif;
+ uint32_t *fat;
+ unsigned int freesect_count=0;
+ struct OLE_HDR *header=(struct OLE_HDR*)&buffer_header;
+ if(!IN)
+ return 0;
+ fseek(IN,0,SEEK_SET);
+ fread(&buffer_header,sizeof(buffer_header),1,IN); /*reads first sector including OLE header */
+ /*
+ log_trace("num_FAT_blocks %u\n",le32(header->num_FAT_blocks));
+ log_trace("num_extra_FAT_blocks %u\n",le32(header->num_extra_FAT_blocks));
+ */
+ /* Sanity check */
+ if(le32(header->num_FAT_blocks)==0 ||
+ le32(header->num_extra_FAT_blocks)>50 ||
+ le32(header->num_FAT_blocks)>109+le32(header->num_extra_FAT_blocks)*((1<<le16(header->uSectorShift))-1))
+ return 0;
+ dif=(uint32_t*)MALLOC(109*4+(le32(header->num_extra_FAT_blocks)<<le16(header->uSectorShift)));
+ memcpy(dif,(header+1),109*4);
+ if(le32(header->num_extra_FAT_blocks)>0)
+ { /* Load DIF*/
+ uint32_t *dif_pos=dif+109;
+ unsigned long int i;
+ unsigned long int block=le32(header->FAT_next_block);
+ for(i=0;i<le32(header->num_extra_FAT_blocks) && block!=0xFFFFFFFF && block!=0xFFFFFFFE;i++)
+ {
+// log_trace("pointeur:0x%x\n",block);
+ if(fseek(IN,512+(block<<le16(header->uSectorShift)),SEEK_SET)<0)
+ {
+ free(dif);
+ return 0;
+ }
+ fread(dif_pos, (i<le32(header->num_extra_FAT_blocks)?128:(le32(header->num_FAT_blocks)-109)%127),4,IN);
+ dif_pos+=(((1<<le16(header->uSectorShift))/4)-1);
+ block=le32(dif[109+i*(((1<<le16(header->uSectorShift))/4)-1)+127]);
+ }
+ }
+ fat=(uint32_t*)MALLOC(le32(header->num_FAT_blocks)<<le16(header->uSectorShift));
+ { /* Load FAT */
+ unsigned long int j;
+ for(j=0;j<le32(header->num_FAT_blocks);j++)
+ {
+ if(fseek(IN,512+(le32(dif[j])<<le16(header->uSectorShift)),SEEK_SET)<0)
+ {
+ free(dif);
+ free(fat);
+ return 0;
+ }
+ fread(fat+((j<<le16(header->uSectorShift))/4),(1<<le16(header->uSectorShift)),1,IN);
+ }
+ }
+ { /* Search how many entries are not used at the end of the FAT */
+ unsigned long int i;
+ for(i=(le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4-1;
+ i>((le32(header->num_FAT_blocks)-1)<<le16(header->uSectorShift))/4 && le32(fat[i])==0xFFFFFFFF; i--)
+ freesect_count++;
+ }
+ totalsize=512+((le32(header->num_FAT_blocks)*128-freesect_count)<<le16(header->uSectorShift));
+ free(dif);
+ free(fat);
+ return totalsize;
+}
diff --git a/src/file_dpx.c b/src/file_dpx.c
new file mode 100644
index 0000000..9a1e12b
--- /dev/null
+++ b/src/file_dpx.c
@@ -0,0 +1,92 @@
+/*
+
+ File: file_dpx.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+#include "common.h"
+
+static void register_header_check_dpx(file_stat_t *file_stat);
+static int header_check_dpx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_dpx= {
+ .extension="dpx",
+ .description="Cineon image file/SMTPE DPX",
+ .min_header_distance=0,
+ .max_filesize=10*1024*1024,
+ .recover=1,
+ .header_check=&header_check_dpx,
+ .register_header_check=&register_header_check_dpx
+};
+
+static const unsigned char sdpx_header[4]= {'S', 'D', 'P', 'X'};
+static const unsigned char xpds_header[4]= {'X', 'P', 'D', 'S'};
+static const unsigned char ver10[8]= {'V', '1', '.', '0', 0x00, 0x00, 0x00, 0x00};
+
+/* Header information from http://www.cineon.com/ff_draft.php */
+struct header_dpx
+{
+ uint32_t magic_num; /* magic number 0x53445058 (SDPX) or 0x58504453 (XPDS) */
+ uint32_t offset; /* offset to image data in bytes */
+ char vers[8]; /* which header format version is being used (v1.0)*/
+ uint32_t file_size; /* file size in bytes */
+ uint32_t ditto_key; /* read time short cut - 0 = same, 1 = new */
+ uint32_t gen_hdr_size; /* generic header length in bytes */
+ uint32_t ind_hdr_size; /* industry header length in bytes */
+ uint32_t user_data_size; /* user-defined data length in bytes */
+ char file_name[100]; /* image file name */
+ char create_time[24]; /* file creation date "yyyy:mm:dd:hh:mm:ss:LTZ" */
+ char creator[100]; /* file creator's name */
+ char project[200]; /* project name */
+ char copyright[200]; /* right to use or copyright info */
+ uint32_t key; /* encryption ( FFFFFFFF = unencrypted ) */
+ char Reserved[104]; /* reserved field TBD (need to pad) */
+} __attribute__ ((__packed__));
+
+static void register_header_check_dpx(file_stat_t *file_stat)
+{
+ register_header_check(0, sdpx_header,sizeof(sdpx_header), &header_check_dpx, file_stat);
+ register_header_check(0, xpds_header,sizeof(xpds_header), &header_check_dpx, file_stat);
+}
+
+static int header_check_dpx(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ const struct header_dpx *dpx=(const struct header_dpx *)buffer;
+ if((memcmp(buffer,sdpx_header,sizeof(sdpx_header))==0 ||
+ memcmp(buffer,xpds_header,sizeof(xpds_header))==0) &&
+ memcmp(dpx->vers, ver10, sizeof(ver10))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_dpx.extension;
+ file_recovery_new->calculated_file_size=be32(dpx->file_size);
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_dsc.c b/src/file_dsc.c
new file mode 100644
index 0000000..d7c9634
--- /dev/null
+++ b/src/file_dsc.c
@@ -0,0 +1,63 @@
+/*
+
+ File: file_dsc.c
+
+ Copyright (C) 1998-2005,2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_dsc(file_stat_t *file_stat);
+static int header_check_dsc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_dsc= {
+ .extension="dsc",
+ .description="Nikon dsc",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=0,
+ .header_check=&header_check_dsc,
+ .register_header_check=&register_header_check_dsc
+};
+
+static const unsigned char dsc_header[3]= { 'M','L','T'};
+
+static void register_header_check_dsc(file_stat_t *file_stat)
+{
+ register_header_check(588, dsc_header,sizeof(dsc_header), &header_check_dsc, file_stat);
+}
+
+static int header_check_dsc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(buffer_size<1024)
+ return 0;
+ if(memcmp(&buffer[588],dsc_header,sizeof(dsc_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_dsc.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_dta.c b/src/file_dta.c
new file mode 100644
index 0000000..c3b18e7
--- /dev/null
+++ b/src/file_dta.c
@@ -0,0 +1,75 @@
+/*
+
+ File: file_dta.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_dta(file_stat_t *file_stat);
+static int header_check_dta(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_dta= {
+ .extension="dta",
+ .description="SPSS",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_dta,
+ .register_header_check=&register_header_check_dta
+};
+
+static const unsigned char dta_header_71le[3]= {0x71, 0x02, 0x01};
+static const unsigned char dta_header_72le[3]= {0x72, 0x02, 0x01};
+
+static void register_header_check_dta(file_stat_t *file_stat)
+{
+ register_header_check(0, dta_header_71le,sizeof(dta_header_71le), &header_check_dta, file_stat);
+ register_header_check(0, dta_header_72le,sizeof(dta_header_72le), &header_check_dta, file_stat);
+}
+
+static int header_check_dta(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ /*
+ ds_format 1 byte 0x71 or 0x72
+ byteorder 1 byte 0x01 -> HILO, 0x02 -> LOHI
+ filetype 1 byte 0x01
+ unused 1 byte ?
+ nvar (number of vars) 2 int encoded per byteorder
+ nobs (number of obs) 4 int encoded per byteorder
+ data_label 81 char dataset label, \0 terminated
+ time_stamp 18 char date/time saved, \0 terminated
+ */
+ if(memcmp(buffer,dta_header_71le,sizeof(dta_header_71le))==0 ||
+ memcmp(buffer,dta_header_72le,sizeof(dta_header_72le))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_dta.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_dump.c b/src/file_dump.c
new file mode 100644
index 0000000..66b607d
--- /dev/null
+++ b/src/file_dump.c
@@ -0,0 +1,149 @@
+/*
+
+ File: file_dump.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the tedumps of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "common.h"
+#include "filegen.h"
+#define TS_TAPE 1 /* dump tape header */
+
+static void register_header_check_dump(file_stat_t *file_stat);
+static int header_check_dump(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_dump= {
+ .extension="dump",
+ .description="Dump/Restore archive",
+ .min_header_distance=0,
+ .max_filesize=(((uint64_t)1<<33)-1),
+ .recover=1,
+ .header_check=&header_check_dump,
+ .register_header_check=&register_header_check_dump
+};
+
+/*
+ * TP_BSIZE is the size of file blocks on the dump tapes.
+ * Note that TP_BSIZE must be a multiple of DEV_BSIZE.
+ *
+ * NTREC is the number of TP_BSIZE blocks that are written
+ * in each tape record. HIGHDENSITYTREC is the number of
+ * TP_BSIZE blocks that are written in each tape record on
+ * 6250 BPI or higher density tapes.
+ *
+ * TP_NINDIR is the number of indirect pointers in a TS_INODE
+ * or TS_ADDR record. Note that it must be a power of two.
+ */
+#define TP_BSIZE 1024
+#define NTREC 10
+#define HIGHDENSITYTREC 32
+#define TP_NINDIR (TP_BSIZE/2)
+#define LBLSIZE 16
+#define NAMELEN 64
+
+struct dump_struct
+{
+ int32_t c_type; /* record type (see below) */
+ int32_t c_old_date; /* date of this dump */
+ int32_t c_old_ddate; /* date of previous dump */
+ int32_t c_volume; /* dump volume number */
+ int32_t c_old_tapea; /* logical block of this record */
+ uint32_t c_inumber; /* number of inode */
+ int32_t c_magic; /* magic number (see above) */
+ int32_t c_checksum; /* record checksum */
+ /*
+ * Start old dinode structure, expanded for binary
+ * compatibility with UFS1.
+ */
+ uint16_t c_mode; /* file mode */
+ int16_t c_spare1[3]; /* old nlink, ids */
+ uint64_t c_size; /* file byte count */
+ int32_t c_old_atime; /* old last access time, seconds */
+ int32_t c_atimensec; /* last access time, nanoseconds */
+ int32_t c_old_mtime; /* old last modified time, secs */
+ int32_t c_mtimensec; /* last modified time, nanosecs */
+ int32_t c_spare2[2]; /* old ctime */
+ int32_t c_rdev; /* for devices, device number */
+ int32_t c_birthtimensec; /* creation time, nanosecs */
+ int64_t c_birthtime; /* creation time, seconds */
+ int64_t c_atime; /* last access time, seconds */
+ int64_t c_mtime; /* last modified time, seconds */
+ int32_t c_spare4[7]; /* old block pointers */
+ uint32_t c_file_flags; /* status flags (chflags) */
+ int32_t c_spare5[2]; /* old blocks, generation number */
+ uint32_t c_uid; /* file owner */
+ uint32_t c_gid; /* file group */
+ int32_t c_spare6[2]; /* previously unused spares */
+ /*
+ * End old dinode structure.
+ */
+ int32_t c_count; /* number of valid c_addr entries */
+ char c_addr[TP_NINDIR]; /* 1 => data; 0 => hole in inode */
+ char c_label[LBLSIZE]; /* dump label */
+ int32_t c_level; /* level of this dump */
+ char c_filesys[NAMELEN]; /* name of dumpped file system */
+ char c_dev[NAMELEN]; /* name of dumpped device */
+ char c_host[NAMELEN]; /* name of dumpped host */
+ int32_t c_flags; /* additional information */
+ int32_t c_old_firstrec; /* first record on volume */
+ int64_t c_date; /* date of this dump */
+ int64_t c_ddate; /* date of previous dump */
+ int64_t c_tapea; /* logical block of this record */
+ int64_t c_firstrec; /* first record on volume */
+ int32_t c_spare[24]; /* reserved for future uses */
+};
+/*
+ * special record types
+ */
+#define TS_TAPE 1 /* dump tape header */
+#define TS_INODE 2 /* beginning of file record */
+#define TS_ADDR 4 /* continuation of file record */
+#define TS_BITS 3 /* map of inodes on tape */
+#define TS_CLRI 6 /* map of inodes deleted since last dump */
+#define TS_END 5 /* end of volume marker */
+
+static const unsigned char dump_header_le_old_fs[4] = { 0x6b, 0xea, 0x00, 0x00};
+static const unsigned char dump_header_le_new_fs[4] = { 0x6c, 0xea, 0x00, 0x00};
+
+static void register_header_check_dump(file_stat_t *file_stat)
+{
+ register_header_check(0x18, dump_header_le_old_fs,sizeof(dump_header_le_old_fs), &header_check_dump, file_stat);
+ register_header_check(0x18, dump_header_le_new_fs,sizeof(dump_header_le_new_fs), &header_check_dump, file_stat);
+}
+
+static int header_check_dump(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ const struct dump_struct *dump=(const struct dump_struct*)buffer;
+ if((memcmp(buffer+0x18,dump_header_le_old_fs,sizeof(dump_header_le_old_fs))==0 ||
+ memcmp(buffer+0x18,dump_header_le_new_fs,sizeof(dump_header_le_new_fs))==0) &&
+ le32(dump->c_type)==TS_TAPE)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_dump.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_dv.c b/src/file_dv.c
new file mode 100644
index 0000000..d69e4b3
--- /dev/null
+++ b/src/file_dv.c
@@ -0,0 +1,66 @@
+/*
+
+ File: file_dv.c
+
+ Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_dv(file_stat_t *file_stat);
+static int header_check_dv(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_dv= {
+ .extension="dv",
+ .description="DIF Digital Video",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_dv,
+ .register_header_check=&register_header_check_dv
+};
+static const unsigned char dv_header[3]= {0x1f, 0x07, 0x00};
+
+static void register_header_check_dv(file_stat_t *file_stat)
+{
+ register_header_check(0, dv_header,sizeof(dv_header), &header_check_dv, file_stat);
+}
+
+static int header_check_dv(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(file_recovery!=NULL && file_recovery->file_stat!=NULL && file_recovery->file_stat->file_hint==&file_hint_dv)
+ return 0;
+ /* The header may be only 3 bytes */
+ if(buffer[0]==0x1f && buffer[1]==0x07 && buffer[2]==0x00 && buffer[5]==0x78 && buffer[6]==0x78 && buffer[7]==0x78)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_dv.extension;
+ return 1;
+ }
+ return 0;
+}
+
+
diff --git a/src/file_dwg.c b/src/file_dwg.c
new file mode 100644
index 0000000..e4769ac
--- /dev/null
+++ b/src/file_dwg.c
@@ -0,0 +1,71 @@
+/*
+
+ File: file_dwg.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_dwg(file_stat_t *file_stat);
+static int header_check_dwg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_dwg= {
+ .extension="dwg",
+ .description="AutoCAD",
+ .min_header_distance=0,
+ .max_filesize=10*1024*1024,
+ .recover=1,
+ .header_check=&header_check_dwg,
+ .register_header_check=&register_header_check_dwg
+};
+
+static const unsigned char dwg_header_12[11]= {'A', 'C', '1', '0', '1', '2', 0x00, 0x00, 0x00, 0x00, 0x00};
+static const unsigned char dwg_header_13[11]= {'A', 'C', '1', '0', '1', '3', 0x00, 0x00, 0x00, 0x00, 0x00};
+static const unsigned char dwg_header_14[11]= {'A', 'C', '1', '0', '1', '4', 0x00, 0x00, 0x00, 0x00, 0x00};
+static const unsigned char dwg_header_15[11]= {'A', 'C', '1', '0', '1', '5', 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static void register_header_check_dwg(file_stat_t *file_stat)
+{
+ register_header_check(0, dwg_header_12,sizeof(dwg_header_12), &header_check_dwg, file_stat);
+ register_header_check(0, dwg_header_13,sizeof(dwg_header_13), &header_check_dwg, file_stat);
+ register_header_check(0, dwg_header_14,sizeof(dwg_header_14), &header_check_dwg, file_stat);
+ register_header_check(0, dwg_header_15,sizeof(dwg_header_15), &header_check_dwg, file_stat);
+}
+
+static int header_check_dwg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,dwg_header_12,sizeof(dwg_header_12))==0 ||
+ memcmp(buffer,dwg_header_13,sizeof(dwg_header_13))==0 ||
+ memcmp(buffer,dwg_header_14,sizeof(dwg_header_14))==0 ||
+ memcmp(buffer,dwg_header_15,sizeof(dwg_header_15))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_dwg.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_elf.c b/src/file_elf.c
new file mode 100644
index 0000000..36ba814
--- /dev/null
+++ b/src/file_elf.c
@@ -0,0 +1,63 @@
+/*
+
+ File: file_elf.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "common.h"
+#include "filegen.h"
+
+static void register_header_check_elf(file_stat_t *file_stat);
+static int header_check_elf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_elf= {
+ .extension="elf",
+ .description="Executable and Linking Format",
+ .min_header_distance=0,
+ .max_filesize=10*1024*1024,
+ .recover=1,
+ .header_check=&header_check_elf,
+ .register_header_check=&register_header_check_elf
+};
+
+static const unsigned char elf_header[4] = { 0x7f, 'E','L','F'};
+
+static void register_header_check_elf(file_stat_t *file_stat)
+{
+ register_header_check(0, elf_header,sizeof(elf_header), &header_check_elf, file_stat);
+}
+
+static int header_check_elf(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,elf_header,sizeof(elf_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_elf.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_evt.c b/src/file_evt.c
new file mode 100644
index 0000000..4d5fd3f
--- /dev/null
+++ b/src/file_evt.c
@@ -0,0 +1,98 @@
+/*
+
+ File: file_evt.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "common.h"
+#include "filegen.h"
+#include "log.h"
+
+static void register_header_check_evt(file_stat_t *file_stat);
+static int header_check_evt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+static int data_check_evt(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery);
+
+const file_hint_t file_hint_evt= {
+ .extension="evt",
+ .description="Windows Event Log",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_evt,
+ .register_header_check=&register_header_check_evt
+};
+
+static const unsigned char evt_header[8]= {0x30, 0x00, 0x00, 0x00, 'L', 'f', 'L', 'e'};
+
+static void register_header_check_evt(file_stat_t *file_stat)
+{
+ register_header_check(0, evt_header,sizeof(evt_header), &header_check_evt, file_stat);
+}
+
+static int header_check_evt(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,evt_header,sizeof(evt_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->calculated_file_size=buffer[0] + (buffer[1]<<8) + (buffer[2]<<16) + (buffer[3]<<24);
+ file_recovery_new->data_check=&data_check_evt;
+ file_recovery_new->file_check=&file_check_size;
+ file_recovery_new->extension=file_hint_evt.extension;
+ return 1;
+ }
+ return 0;
+}
+
+static int data_check_evt(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
+{
+ while(file_recovery->calculated_file_size + 8 < file_recovery->file_size + buffer_size/2)
+ {
+ unsigned int i=file_recovery->calculated_file_size - file_recovery->file_size + buffer_size/2;
+ if((buffer[i+4]=='L' && buffer[i+5]=='f' && buffer[i+6]=='L' && buffer[i+7]=='e') ||
+ (buffer[i+4]==0x11 && buffer[i+5]==0x11 && buffer[i+6]==0x11 && buffer[i+7]==0x11) ||
+ (buffer[i+4]==0x22 && buffer[i+5]==0x22 && buffer[i+6]==0x22 && buffer[i+7]==0x22) ||
+ (buffer[i+4]==0x33 && buffer[i+5]==0x33 && buffer[i+6]==0x33 && buffer[i+7]==0x33) ||
+ (buffer[i+4]==0x44 && buffer[i+5]==0x44 && buffer[i+6]==0x44 && buffer[i+7]==0x44))
+ {
+ unsigned int length=(buffer[i+0] + (buffer[i+1]<<8) + (buffer[i+2]<<16) + (buffer[i+3]<<24));
+ if(length<8)
+ {
+ return 2;
+ }
+ file_recovery->calculated_file_size+=length;
+ }
+ else
+ {
+ return 2;
+ }
+ }
+ /*
+ log_trace("data_check_evt record_offset=0x%x\n\n",record_offset);
+ */
+ return 1;
+}
+
diff --git a/src/file_exe.c b/src/file_exe.c
new file mode 100644
index 0000000..548cce6
--- /dev/null
+++ b/src/file_exe.c
@@ -0,0 +1,165 @@
+/*
+
+ File: file_exe.c
+
+ Copyright (C) 1998-2005,2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "common.h"
+#include "filegen.h"
+#include "pe.h"
+#include "log.h"
+
+static void register_header_check_exe(file_stat_t *file_stat);
+static int header_check_exe(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_exe= {
+ .extension="exe",
+ .description="MS Windows executable",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_exe,
+ .register_header_check=&register_header_check_exe
+};
+
+static const unsigned char exe_header[] = {'M','Z'};
+
+static void register_header_check_exe(file_stat_t *file_stat)
+{
+ register_header_check(0, exe_header,sizeof(exe_header), &header_check_exe, file_stat);
+}
+
+static int header_check_exe(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,exe_header,sizeof(exe_header))==0)
+ {
+ const struct pe_image_file_hdr *pe_hdr;
+ uint32_t e_lfanew=buffer[0x3c]+ (buffer[0x3c+1]<<8) +
+ (buffer[0x3c+2]<<16) + (buffer[0x3c+3]<<24); /* address of new exe header */
+ if(e_lfanew==0 || e_lfanew>buffer_size-sizeof(struct pe_image_file_hdr))
+ {
+#ifdef DEBUG_EXE
+ log_debug("EXE rejected, not PE (e_lfanew)\n");
+#endif
+ return 0;
+ }
+ pe_hdr=(const struct pe_image_file_hdr *)(buffer+e_lfanew);
+ if(le32(pe_hdr->Magic) != IMAGE_NT_SIGNATURE)
+ {
+#ifdef DEBUG_EXE
+ log_debug("EXE rejected, not PE (missing signature)\n");
+#endif
+ return 0;
+ }
+ if(le16(pe_hdr->Characteristics) & 0x2000)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension="dll";
+ }
+ else if(le16(pe_hdr->Characteristics) & 0x01)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_exe.extension;
+ }
+ else
+ {
+#ifdef DEBUG_EXE
+ log_debug("EXE rejected, bad characteristics\n");
+#endif
+ return 0;
+ }
+#ifdef DEBUG_EXE
+ {
+ const struct pe_image_optional_hdr32 *pe_image_optional32=(const struct pe_image_optional_hdr32 *)
+ (((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr)));
+ if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR_MAGIC)
+ {
+ log_debug("SizeOfCode %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfCode));
+ log_debug("SizeOfImage %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfImage));
+ }
+ else if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+ {
+ const struct pe_image_optional_hdr64 *pe_image_optional64=(const struct pe_image_optional_hdr64 *)
+ (((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr)));
+ }
+ log_debug("PE image opt 0x%lx-0x%lx\n", (long unsigned)sizeof(struct pe_image_file_hdr),
+ (long unsigned)(sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader) - 1));
+ }
+#endif
+ {
+ unsigned int i;
+ uint64_t sum=0;
+ const struct pe_image_section_hdr *pe_image_section=(const struct pe_image_section_hdr*)
+ ((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader));
+ for(i=0;i<le16(pe_hdr->NumberOfSections) && (const unsigned char*)pe_image_section < buffer+buffer_size;i++,pe_image_section++)
+ {
+ if(le32(pe_image_section->SizeOfRawData)>0)
+ {
+#ifdef DEBUG_EXE
+ log_debug("%s 0x%lx-0x%lx\n", pe_image_section->Name,
+ (unsigned long)le32(pe_image_section->PointerToRawData),
+ (unsigned long)le32(pe_image_section->PointerToRawData)+le32(pe_image_section->SizeOfRawData)-1);
+#endif
+ if(le32(pe_image_section->SizeOfRawData)%32==0)
+ {
+ if(sum < le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData))
+ sum=le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData);
+ }
+ }
+ if(le16(pe_image_section->NumberOfRelocations)>0)
+ {
+#ifdef DEBUG_EXE
+ log_debug("relocations 0x%lx-0x%lx\n",
+ (unsigned long)le32(pe_image_section->PointerToRelocations),
+ (unsigned long)le32(pe_image_section->PointerToRelocations)+1*le16(pe_image_section->NumberOfRelocations)-1);
+#endif
+ if(sum < le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations))
+ sum = le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations);
+ }
+ }
+ if(le32(pe_hdr->NumberOfSymbols)>0)
+ {
+#ifdef DEBUG_EXE
+ log_debug("Symboles 0x%lx-0x%lx\n", (long unsigned)le32(pe_hdr->PointerToSymbolTable),
+ (long unsigned)(le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols))-1);
+#endif
+ if(le32(pe_hdr->NumberOfSymbols)<0x10000)
+ {
+ if(sum < le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols))
+ sum = le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols);
+ }
+ }
+ /* It's not perfect, EXE overlay are not recovered */
+ file_recovery_new->calculated_file_size=sum;
+ }
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/src/file_ext.c b/src/file_ext.c
new file mode 100644
index 0000000..6b5fbb9
--- /dev/null
+++ b/src/file_ext.c
@@ -0,0 +1,65 @@
+/*
+
+ File: file_ext2_sb.c
+
+ Copyright (C) 1998-2005,2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "common.h"
+#include "ext2.h"
+#include "filegen.h"
+
+static void register_header_check_ext2_sb(file_stat_t *file_stat);
+static int header_check_ext2_sb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_ext2_sb= {
+ .extension="",
+ .description="EXT2/EXT3 Superblock",
+ .min_header_distance=0,
+ .max_filesize=1,
+ .recover=0,
+ .header_check=&header_check_ext2_sb,
+ .register_header_check=&register_header_check_ext2_sb
+};
+
+static const unsigned char ext2_sb_header[2]= {0x53, 0xEF};
+
+static void register_header_check_ext2_sb(file_stat_t *file_stat)
+{
+ register_header_check(0x38, ext2_sb_header,sizeof(ext2_sb_header), &header_check_ext2_sb, file_stat);
+}
+
+static int header_check_ext2_sb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(recover_EXT2(NULL,(const struct ext2_super_block *)buffer,NULL,0,0)==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_ext2_sb.extension;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/src/file_fh10.c b/src/file_fh10.c
new file mode 100644
index 0000000..abdc47c
--- /dev/null
+++ b/src/file_fh10.c
@@ -0,0 +1,69 @@
+/*
+
+ File: file_fh10.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+ Copyright (C) 2007 Peter Turczak <pnospamt@netconsequence.de>
+
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_fh10(file_stat_t *file_stat);
+static int header_check_fh10(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_fh10= {
+ .extension="fh10",
+ .description="Macromedia Freehand 10",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_fh10,
+ .register_header_check=&register_header_check_fh10
+};
+
+static const unsigned char fh10_header[] = {
+ 0x1c, 0x01 ,0x00, 0x00, 0x02, 0x00, 0x04, 0x1c, 0x01 , 0x14, 0x00, 0x02, 0x00, 0x14, 0x1c, 0x01,
+ 0x16, 0x00 ,0x02, 0x00, 0x08, 0x1c, 0x01, 0x1e, 0x00 , 0xa , 0x46, 0x72, 0x65, 0x65, 0x48, 0x61,
+ 0x6e, 0x64, 0x31, 0x30
+};
+
+static void register_header_check_fh10(file_stat_t *file_stat)
+{
+ register_header_check(0, fh10_header,sizeof(fh10_header), &header_check_fh10, file_stat);
+}
+
+static int header_check_fh10(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,fh10_header,sizeof(fh10_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->min_filesize=4096;
+ file_recovery_new->extension=file_hint_fh10.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_fh5.c b/src/file_fh5.c
new file mode 100644
index 0000000..cee9a37
--- /dev/null
+++ b/src/file_fh5.c
@@ -0,0 +1,85 @@
+/*
+
+ File: file_fh5.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+ Copyright (C) 2007 Peter Turczak <pspamt@netconsequence.de>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "common.h"
+#include "filegen.h"
+
+struct fh5_header_s
+{
+ unsigned char id[8];
+ uint32_t datalen; /* Big Endian size w/o headers */
+} __attribute__ ((__packed__));
+typedef struct fh5_header_s fh5_header_t;
+
+static void register_header_check_fh5(file_stat_t *file_stat);
+static int header_check_fh5(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+static void file_check_fh5(file_recovery_t *file_recovery);
+
+const file_hint_t file_hint_fh5= {
+ .extension="fh5",
+ .description="Macromedia Freehand 5",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_fh5,
+ .register_header_check=&register_header_check_fh5
+};
+
+static const unsigned char fh5_header[8] = { 0x41, 0x47, 0x44, 0x31, 0xbe, 0xb8, 0xbb, 0xce };
+
+static void register_header_check_fh5(file_stat_t *file_stat)
+{
+ register_header_check(0, fh5_header,sizeof(fh5_header), &header_check_fh5, file_stat);
+}
+
+static int header_check_fh5(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ const fh5_header_t *fh5_buffer=(const fh5_header_t *) buffer;
+ if(memcmp(fh5_buffer->id,fh5_header,sizeof(fh5_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->min_filesize=4096,
+ file_recovery_new->calculated_file_size=be32(fh5_buffer->datalen);
+ file_recovery_new->extension=file_hint_fh5.extension;
+ file_recovery_new->file_check=file_check_fh5;
+// log_debug("header_check_fh5: Guessed length : %u\n", fh5_file_size);
+ return 1;
+ }
+ return 0;
+}
+
+static void file_check_fh5(file_recovery_t *file_recovery)
+{
+ if(file_recovery->file_size < file_recovery->calculated_file_size)
+ file_recovery->file_size=0;
+ else if(file_recovery->file_size> file_recovery->calculated_file_size+4096)
+ file_recovery->file_size=file_recovery->calculated_file_size+4096;
+}
diff --git a/src/file_flac.c b/src/file_flac.c
new file mode 100644
index 0000000..f43690c
--- /dev/null
+++ b/src/file_flac.c
@@ -0,0 +1,64 @@
+/*
+
+ File: file_flac.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+#include "common.h"
+
+static void register_header_check_flac(file_stat_t *file_stat);
+static int header_check_flac(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_flac= {
+ .extension="flac",
+ .description="FLAC audio",
+ .min_header_distance=0,
+ .max_filesize=100*1024*1024,
+ .recover=1,
+ .header_check=&header_check_flac,
+ .register_header_check=&register_header_check_flac
+};
+
+static const unsigned char flac_header[4]= {'f', 'L', 'a', 'C'};
+
+static void register_header_check_flac(file_stat_t *file_stat)
+{
+ register_header_check(0, flac_header,sizeof(flac_header), &header_check_flac, file_stat);
+}
+
+static int header_check_flac(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer, flac_header, sizeof(flac_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_flac.extension;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/src/file_flv.c b/src/file_flv.c
new file mode 100644
index 0000000..ae73b23
--- /dev/null
+++ b/src/file_flv.c
@@ -0,0 +1,63 @@
+/*
+
+ File: file_flv.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+#include "common.h"
+
+static void register_header_check_flv(file_stat_t *file_stat);
+static int header_check_flv(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_flv= {
+ .extension="flv",
+ .description="Macromedia",
+ .min_header_distance=0,
+ .max_filesize=200*1024*1024,
+ .recover=1,
+ .header_check=&header_check_flv,
+ .register_header_check=&register_header_check_flv
+};
+
+static const unsigned char flv_header[4]= {'F', 'L', 'V', 0x01};
+
+static void register_header_check_flv(file_stat_t *file_stat)
+{
+ register_header_check(0, flv_header,sizeof(flv_header), &header_check_flv, file_stat);
+}
+
+static int header_check_flv(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer, flv_header, sizeof(flv_header))==0 && (buffer[4]==1 || buffer[4]==5))
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_flv.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_fs.c b/src/file_fs.c
new file mode 100644
index 0000000..6e83b4e
--- /dev/null
+++ b/src/file_fs.c
@@ -0,0 +1,63 @@
+/*
+
+ File: file_fs.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "common.h"
+#include "filegen.h"
+
+static void register_header_check_fs(file_stat_t *file_stat);
+static int header_check_fs(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_fs= {
+ .extension="fs",
+ .description="Zope",
+ .min_header_distance=0,
+ .max_filesize=200*1024*1024,
+ .recover=1,
+ .header_check=&header_check_fs,
+ .register_header_check=&register_header_check_fs
+};
+
+static const unsigned char fs_header[4]={ 'F', 'S','2','1' };
+
+static void register_header_check_fs(file_stat_t *file_stat)
+{
+ register_header_check(0, fs_header,sizeof(fs_header), &header_check_fs, file_stat);
+}
+
+static int header_check_fs(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(buffer[0]=='F' && buffer[1]=='S' && buffer[2]=='2' && buffer[3]=='1')
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_fs.extension;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_gif.c b/src/file_gif.c
new file mode 100644
index 0000000..de130ff
--- /dev/null
+++ b/src/file_gif.c
@@ -0,0 +1,74 @@
+/*
+
+ File: file_gif.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_gif(file_stat_t *file_stat);
+static int header_check_gif(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+static void file_check_gif(file_recovery_t *file_recovery);
+
+const file_hint_t file_hint_gif= {
+ .extension="gif",
+ .description="Graphic Interchange Format",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_gif,
+ .register_header_check=&register_header_check_gif
+};
+
+static const unsigned char gif_header[6]= { 'G','I','F','8','7','a'};
+static const unsigned char gif_header2[6]= { 'G','I','F','8','9','a'};
+
+static void register_header_check_gif(file_stat_t *file_stat)
+{
+ register_header_check(0, gif_header,sizeof(gif_header), &header_check_gif, file_stat);
+ register_header_check(0, gif_header2,sizeof(gif_header2), &header_check_gif, file_stat);
+}
+
+static int header_check_gif(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer,gif_header,sizeof(gif_header))==0
+ || memcmp(buffer,gif_header2,sizeof(gif_header2))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_gif.extension;
+ file_recovery_new->file_check=&file_check_gif;
+ file_recovery_new->min_filesize=42;
+ return 1;
+ }
+ return 0;
+}
+
+static void file_check_gif(file_recovery_t *file_recovery)
+{
+ const unsigned char gif_footer[2]= {0x00, 0x3b};
+ file_search_footer(file_recovery, gif_footer,sizeof(gif_footer));
+}
diff --git a/src/file_gz.c b/src/file_gz.c
new file mode 100644
index 0000000..0dd64a2
--- /dev/null
+++ b/src/file_gz.c
@@ -0,0 +1,71 @@
+/*
+
+ File: file_gz.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_gz(file_stat_t *file_stat);
+static int header_check_gz(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_gz= {
+ .extension="gz",
+ .description="gzip compressed data",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_gz,
+ .register_header_check=&register_header_check_gz
+};
+
+static const unsigned char gz_header[3]= {0x1F, 0x8B, 0x08};
+
+static void register_header_check_gz(file_stat_t *file_stat)
+{
+ register_header_check(0, gz_header,sizeof(gz_header), &header_check_gz, file_stat);
+}
+
+static int header_check_gz(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ /* gzip file format:
+ * a 10-byte header, containing a magic number, a version number and a timestamp
+ * optional extra headers, such as the original file name,
+ * a body, containing a deflate-compressed payload
+ * a CRC-32 checksum
+ * the length (32 bits) of the original uncompressed data
+ */
+ /* gzip, deflate */
+ if(buffer[0]==0x1F && buffer[1]==0x8B && buffer[2]==0x08 && (buffer[3]&0xe0)==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_gz.extension;
+ file_recovery_new->min_filesize=22;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_imb.c b/src/file_imb.c
new file mode 100644
index 0000000..587d63c
--- /dev/null
+++ b/src/file_imb.c
@@ -0,0 +1,64 @@
+/*
+
+ File: file_imb.c
+
+ Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+
+static void register_header_check_imb(file_stat_t *file_stat);
+static int header_check_imb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_imb= {
+ .extension="imb",
+ .description="Incredimail",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_imb,
+ .register_header_check=&register_header_check_imb
+};
+
+static const unsigned char imb_header[15]= { 0x00, 0x00, 0x00, 'I','n','c','r','e','d','i','m','a','i','l',' '};
+
+static void register_header_check_imb(file_stat_t *file_stat)
+{
+ register_header_check(0, imb_header,sizeof(imb_header), &header_check_imb, file_stat);
+}
+
+static int header_check_imb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(memcmp(buffer+1,imb_header,sizeof(imb_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_imb.extension;
+ file_recovery_new->min_filesize=16;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_indd.c b/src/file_indd.c
new file mode 100644
index 0000000..56b3bbf
--- /dev/null
+++ b/src/file_indd.c
@@ -0,0 +1,90 @@
+/*
+
+ File: file_indd.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+ Copyright (C) 2007 Peter Turczak <pnospamt@netconsequence.de>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "common.h"
+#include "filegen.h"
+#include "log.h"
+
+struct indd_header_s {
+ unsigned char id[24];
+ unsigned char unknown[256];
+ uint32_t blocks; /* Little Endian block count, one block is 4096 byte, note that headblocks need to be added in order to have the actual file length */
+ char headblocks;
+} __attribute__ ((__packed__));
+typedef struct indd_header_s indd_header_t;
+
+
+static void register_header_check_indd(file_stat_t *file_stat);
+static int header_check_indd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+static void file_check_indd(file_recovery_t *file_recovery);
+
+file_hint_t file_hint_indd= {
+ .extension="indd",
+ .description="InDesign File",
+ .min_header_distance=8192,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_indd,
+ .register_header_check=&register_header_check_indd
+};
+
+static const unsigned char indd_header[24]={
+ 0x06, 0x06, 0xed, 0xf5, 0xd8, 0x1d, 0x46, 0xe5,
+ 0xbd, 0x31, 0xef, 0xe7, 0xfe, 0x74, 0xb7, 0x1d,
+ 0x44, 0x4f, 0x43, 0x55, 0x4d, 0x45, 0x4e, 0x54 };
+
+static void register_header_check_indd(file_stat_t *file_stat)
+{
+ register_header_check(0, indd_header,sizeof(indd_header), &header_check_indd, file_stat);
+}
+
+static int header_check_indd(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ const indd_header_t *hdr = (const indd_header_t *)buffer;
+ if (memcmp(hdr->id,indd_header,sizeof(indd_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_indd.extension;
+ file_recovery_new->calculated_file_size=(uint64_t)(1+le32(hdr->blocks))*4096;
+ file_recovery_new->file_check=&file_check_indd;
+// log_debug("header_check_indd: Guessed length: %lu.\n", indd_file_size);
+ return 1;
+ }
+ return 0;
+}
+
+static void file_check_indd(file_recovery_t *file_recovery)
+{
+ if(file_recovery->file_size<file_recovery->calculated_file_size)
+ file_recovery->file_size=0;
+ else if(file_recovery->file_size>file_recovery->calculated_file_size+10*4096)
+ file_recovery->file_size=file_recovery->calculated_file_size+10*4096;
+}
diff --git a/src/file_itu.c b/src/file_itu.c
new file mode 100644
index 0000000..43fbda8
--- /dev/null
+++ b/src/file_itu.c
@@ -0,0 +1,67 @@
+/*
+
+ File: file_itu.c
+
+ Copyright (C) 2006-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#include "filegen.h"
+
+static void register_header_check_itunes(file_stat_t *file_stat);
+static int header_check_itunes(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+
+const file_hint_t file_hint_itunes= {
+ .extension="itu",
+ .description="iTunes",
+ .min_header_distance=0,
+ .max_filesize=PHOTOREC_MAX_FILE_SIZE,
+ .recover=1,
+ .header_check=&header_check_itunes,
+ .register_header_check=&register_header_check_itunes
+};
+static const unsigned char itunes_header[8]= {'m', 'h', 'b', 'd', 0x68, 0x00, 0x00, 0x00};
+
+static void register_header_check_itunes(file_stat_t *file_stat)
+{
+ register_header_check(0, itunes_header,sizeof(itunes_header), &header_check_itunes, file_stat);
+}
+
+static int header_check_itunes(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ /* mhbd */
+ if(memcmp(buffer, itunes_header, sizeof(itunes_header))==0)
+ {
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_itunes.extension;
+ file_recovery_new->min_filesize=0x68;
+ file_recovery_new->calculated_file_size=(uint64_t)buffer[8] +
+ (((uint64_t)buffer[9])<<8) + (((uint64_t)buffer[10])<<16) + (((uint64_t)buffer[11])<<24);
+ file_recovery_new->data_check=&data_check_size;
+ file_recovery_new->file_check=&file_check_size;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/file_jpg.c b/src/file_jpg.c
new file mode 100644
index 0000000..a00a62a
--- /dev/null
+++ b/src/file_jpg.c
@@ -0,0 +1,420 @@
+/*
+
+ File: file_jpg.c
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <stdio.h>
+#include "types.h"
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+#ifdef HAVE_JPEGLIB_H
+#include <jpeglib.h>
+#endif
+#include "filegen.h"
+#include "common.h"
+#include "log.h"
+
+extern const file_hint_t file_hint_indd;
+
+static void register_header_check_jpg(file_stat_t *file_stat);
+static int header_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
+static void file_check_jpg(file_recovery_t *file_recovery);
+
+const file_hint_t file_hint_jpg= {
+ .extension="jpg",
+ .description="JPG picture",
+ .min_header_distance=0,
+ .max_filesize=50*1024*1024,
+ .recover=1,
+ .header_check=&header_check_jpg,
+ .register_header_check=&register_header_check_jpg
+};
+
+static const unsigned char jpg_header_app0[4]= { 0xff,0xd8,0xff,0xe0};
+static const unsigned char jpg_header_app1[4]= { 0xff,0xd8,0xff,0xe1};
+static const unsigned char jpg_footer[2]= { 0xff,0xd9};
+
+static void register_header_check_jpg(file_stat_t *file_stat)
+{
+ register_header_check(0, jpg_header_app0,sizeof(jpg_header_app0), &header_check_jpg, file_stat);
+ register_header_check(0, jpg_header_app1,sizeof(jpg_header_app1), &header_check_jpg, file_stat);
+}
+
+static int header_check_jpg(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
+{
+ if(file_recovery!=NULL && file_recovery->file_stat!=NULL &&
+ file_recovery->file_stat->file_hint==&file_hint_indd)
+ return 0;
+ if(memcmp(buffer,jpg_header_app0,sizeof(jpg_header_app0))==0 ||
+ memcmp(buffer,jpg_header_app1,sizeof(jpg_header_app1))==0)
+ {
+ unsigned int i=2;
+ reset_file_recovery(file_recovery_new);
+ file_recovery_new->extension=file_hint_jpg.extension;
+ file_recovery_new->data_check=NULL;
+ file_recovery_new->file_check=&file_check_jpg;
+ do
+ {
+ if(buffer[i]==0xff && buffer[i+1]==0xe0)
+ { /* APP0 */
+ i+=2+(buffer[i+2]<<8)+buffer[i+3];
+ }
+ else if(buffer[i]==0xff && buffer[i+1]==0xe1)
+ { /* APP1 Exif information */
+ i+=2+(buffer[i+2]<<8)+buffer[i+3];
+ }
+ else
+ {
+ file_recovery_new->min_filesize=288;
+ return 1;
+ }
+ } while(i<6*512 && i<buffer_size);
+ file_recovery_new->min_filesize=i;
+ return 1;
+ }
+ return 0;
+}
+
+#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H)
+struct my_error_mgr {
+ struct jpeg_error_mgr pub; /* "public" fields, must be the first field */
+
+ jmp_buf setjmp_buffer; /* for return to caller */
+};
+
+static void my_output_message (j_common_ptr cinfo);
+static void my_error_exit (j_common_ptr cinfo);
+static void my_emit_message (j_common_ptr cinfo, int msg_level);
+
+static void my_output_message (j_common_ptr cinfo)
+{
+ struct my_error_mgr *myerr = (struct my_error_mgr *) cinfo->err;
+#ifdef DEBUG
+ {
+ char buffermsg[JMSG_LENGTH_MAX];
+ /* Create the message */
+ (*cinfo->err->format_message) (cinfo, buffermsg);
+ log_error("test_jpeg error %s\n",buffermsg);
+ }
+#endif
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+static void my_error_exit (j_common_ptr cinfo)
+{
+ struct my_error_mgr *myerr = (struct my_error_mgr *) cinfo->err;
+ (*cinfo->err->output_message) (cinfo);
+ /* Return control to the setjmp point */
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+static void my_emit_message (j_common_ptr cinfo, int msg_level)
+{
+ struct my_error_mgr *myerr = (struct my_error_mgr *) cinfo->err;
+ struct jpeg_error_mgr *err = &myerr->pub;
+
+ if (msg_level < 0) {
+ /* It's a warning message. Since corrupt files may generate many warnings,
+ * the policy implemented here is to show only the first warning,
+ * unless trace_level >= 3.
+ */
+ if (err->num_warnings == 0 || err->trace_level >= 3)
+ (*err->output_message) (cinfo);
+ /* Always count warnings in num_warnings. */
+ err->num_warnings++;
+ /* Return control to the setjmp point */
+ longjmp(myerr->setjmp_buffer, 1);
+ } else {
+ /* It's a trace message. Show it if trace_level >= msg_level. */
+ if (err->trace_level >= msg_level)
+ (*err->output_message) (cinfo);
+ }
+}
+
+typedef struct {
+ struct jpeg_source_mgr pub; /* public fields */
+
+ FILE * infile; /* source stream */
+ JOCTET * buffer; /* start of buffer */
+ boolean start_of_file; /* have we gotten any data yet? */
+ unsigned long int file_size;
+} my_source_mgr;
+
+#define JPG_INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
+
+/*
+ * Initialize source --- called by jpeg_read_header
+ * before any data is actually read.
+ */
+
+static void jpg_init_source (j_decompress_ptr cinfo)
+{
+ my_source_mgr * src = (my_source_mgr *) cinfo->src;
+
+ /* We reset the empty-input-file flag for each image,
+ * but we don't clear the input buffer.
+ * This is correct behavior for reading a series of images from one source.
+ */
+ src->start_of_file = TRUE;
+ src->file_size = 0;
+}
+
+
+/*
+ * Fill the input buffer --- called whenever buffer is emptied.
+ *
+ * In typical applications, this should read fresh data into the buffer
+ * (ignoring the current state of next_input_byte & bytes_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been reloaded. It is not necessary to
+ * fill the buffer entirely, only to obtain at least one more byte.
+ *
+ * There is no such thing as an EOF return. If the end of the file has been
+ * reached, the routine has a choice of ERREXIT() or inserting fake data into
+ * the buffer. In most cases, generating a warning message and inserting a
+ * fake EOI marker is the best course of action --- this will allow the
+ * decompressor to output however much of the image is there. However,
+ * the resulting error message is misleading if the real problem is an empty
+ * input file, so we handle that case specially.
+ *
+ * In applications that need to be able to suspend compression due to input
+ * not being available yet, a FALSE return indicates that no more data can be
+ * obtained right now, but more may be forthcoming later. In this situation,
+ * the decompressor will return to its caller (with an indication of the
+ * number of scanlines it has read, if any). The application should resume
+ * decompression after it has loaded more data into the input buffer. Note
+ * that there are substantial restrictions on the use of suspension --- see
+ * the documentation.
+ *
+ * When suspending, the decompressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point must be rescanned after resumption, so move it to
+ * the front of the buffer rather than discarding it.
+ */
+
+static boolean jpg_fill_input_buffer (j_decompress_ptr cinfo)
+{
+ my_source_mgr * src = (my_source_mgr *) cinfo->src;
+ size_t nbytes;
+ nbytes = fread(src->buffer, 1, JPG_INPUT_BUF_SIZE, src->infile);
+ if (nbytes <= 0) {
+ if (src->start_of_file) /* Treat empty input file as fatal error */
+ {
+ // (cinfo)->err->msg_code = JERR_INPUT_EMPTY;
+ (*(cinfo)->err->error_exit) ((j_common_ptr)cinfo);;
+ }
+ // cinfo->err->msg_code = JWRN_JPEG_EOF;
+ (*(cinfo)->err->emit_message) ((j_common_ptr)cinfo, -1);
+ /* Insert a fake EOI marker */
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ nbytes = 2;
+ }
+ src->pub.next_input_byte = src->buffer;
+ src->pub.bytes_in_buffer = nbytes;
+ src->start_of_file = FALSE;
+ src->file_size += nbytes;
+ return TRUE;
+}
+
+
+/*
+ * Skip data --- used to skip over a potentially large amount of
+ * uninteresting data (such as an APPn marker).
+ *
+ * Writers of suspendable-input applications must note that skip_input_data
+ * is not granted the right to give a suspension return. If the skip extends
+ * beyond the data currently in the buffer, the buffer can be marked empty so
+ * that the next read will cause a fill_input_buffer call that can suspend.
+ * Arranging for additional bytes to be discarded before reloading the input
+ * buffer is the application writer's problem.
+ */
+
+static void jpg_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ my_source_mgr * src = (my_source_mgr *) cinfo->src;
+
+ /* Just a dumb implementation for now. Could use fseek() except
+ * it doesn't work on pipes. Not clear that being smart is worth
+ * any trouble anyway --- large skips are infrequent.
+ */
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->pub.bytes_in_buffer) {
+ num_bytes -= (long) src->pub.bytes_in_buffer;
+ (void) jpg_fill_input_buffer(cinfo);
+ /* note we assume that fill_input_buffer will never return FALSE,
+ * so suspension need not be handled.
+ */
+ }
+ src->pub.next_input_byte += (size_t) num_bytes;
+ src->pub.bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+/*
+ * An additional method that can be provided by data source modules is the
+ * resync_to_restart method for error recovery in the presence of RST markers.
+ * For the moment, this source module just uses the default resync method
+ * provided by the JPEG library. That method assumes that no backtracking
+ * is possible.
+ */
+
+
+/*
+ * Terminate source --- called by jpeg_finish_decompress
+ * after all data has been read. Often a no-op.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+static void jpg_term_source (j_decompress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+
+/*
+ * Prepare for input from a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing decompression.
+ */
+
+static void jpeg_testdisk_src (j_decompress_ptr cinfo, FILE * infile)
+{
+ my_source_mgr * src;
+
+ /* The source object and input buffer are made permanent so that a series
+ * of JPEG images can be read from the same file by calling jpeg_testdisk_src
+ * only before the first one. (If we discarded the buffer at the end of
+ * one image, we'd likely lose the start of the next one.)
+ * This makes it unsafe to use this manager and a different source
+ * manager serially with the same JPEG object. Caveat programmer.
+ */
+ if (cinfo->src == NULL) { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ sizeof(my_source_mgr));
+ src = (my_source_mgr *) cinfo->src;
+ src->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ JPG_INPUT_BUF_SIZE * sizeof(JOCTET));
+ }
+
+ src = (my_source_mgr *) cinfo->src;
+ src->pub.init_source = jpg_init_source;
+ src->pub.fill_input_buffer = jpg_fill_input_buffer;
+ src->pub.skip_input_data = jpg_skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->pub.term_source = jpg_term_source;
+ src->infile = infile;
+ src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+ src->pub.next_input_byte = NULL; /* until buffer loaded */
+}
+#endif
+
+static void file_check_jpg(file_recovery_t *file_recovery)
+{
+ FILE* infile=file_recovery->handle;
+ uint64_t jpeg_size;
+#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H)
+ static struct my_error_mgr jerr;
+ static struct jpeg_decompress_struct cinfo;
+#endif
+ file_recovery->file_size=0;
+ file_recovery->offset_error=0;
+#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H)
+ {
+ JSAMPARRAY buffer; /* Output row buffer */
+ int row_stride; /* physical row width in output buffer */
+ fseek(infile,0,SEEK_SET);
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.output_message = my_output_message;
+ jerr.pub.error_exit = my_error_exit;
+ jerr.pub.emit_message= my_emit_message;
+ // jerr.pub.emit_message = my_emit_message;
+ /* Establish the setjmp return context for my_error_exit to use. */
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object and return.
+ */
+ /* Not accurate */
+ // jpeg_size=ftell(infile);
+ my_source_mgr * src;
+ src = (my_source_mgr *) cinfo.src;
+ jpeg_size=src->file_size - src->pub.bytes_in_buffer;
+ // log_error("JPG error at offset %llu\n", (long long unsigned)jpeg_size);
+ jpeg_destroy_decompress(&cinfo);
+ if(jpeg_size>0)
+ file_recovery->offset_error=jpeg_size;
+ return;
+ }
+ jpeg_create_decompress(&cinfo);
+ cinfo.two_pass_quantize = FALSE;
+ cinfo.dither_mode = JDITHER_NONE;
+ cinfo.desired_number_of_colors = 0;
+ cinfo.dct_method = JDCT_FASTEST;
+ cinfo.do_fancy_upsampling = FALSE;
+ cinfo.raw_data_out = TRUE;
+
+ jpeg_testdisk_src(&cinfo, infile);
+ (void) jpeg_read_header(&cinfo, TRUE);
+ (void) jpeg_start_decompress(&cinfo);
+ row_stride = cinfo.output_width * cinfo.output_components;
+ buffer = (*cinfo.mem->alloc_sarray)
+ ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
+ while (cinfo.output_scanline < cinfo.output_height) {
+ (void) jpeg_read_scanlines(&cinfo, buffer, 1);
+ }
+ (void) jpeg_finish_decompress(&cinfo);
+ {
+ my_source_mgr * src;
+ src = (my_source_mgr *) cinfo.src;
+ jpeg_size=src->file_size - src->pub.bytes_in_buffer;
+ }
+ jpeg_destroy_decompress(&cinfo);
+ }
+#else
+ /* Not accurate */
+ jpeg_size=ftell(infile);
+#endif
+// log_error("JPG size: %llu\n", (long long unsigned)jpeg_size);
+ if(jpeg_size<=0)
+ return;
+#if defined(HAVE_LIBJPEG) && defined(HAVE_JPEGLIB_H)
+ if(jerr.pub.num_warnings>0)
+ {
+ file_recovery->offset_error=jpeg_size;
+ return;
+ }
+#endif
+ file_recovery->file_size=jpeg_size;
+ file_search_footer(file_recovery, jpg_footer,sizeof(jpg_footer));
+}
diff --git a/src/file_jpg.h b/src/file_jpg.h
new file mode 100644
index 0000000..b221f9d
--- /dev/null
+++ b/src/file_jpg.h
@@ -0,0 +1,24 @@
+/*
+
+ File: file_jpg.h
+
+ Copyright (C) 1998-2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+int64_t test_jpeg(FILE *infile);
+
diff --git a/src/file_max.c b/src/file_max.c
new file mode 100644
index 0000000..4784df9
--- /dev/null
+++ b/src/file_max.c
@@ -0,0 +1,64 @@
+/*
+
+ File: file_max.c
+
+ Copyright (C) 2007 Christophe GRENIER <grenier@cgsecurity.org>
+
+ This software is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STRING_H