diff --git a/Makefile.in b/Makefile.in
index 1e08adf7..02e3b298 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -32,7 +32,7 @@ NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
subdir = .
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+DIST_COMMON = README $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/configure $(am__configure_deps)
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
diff --git a/TODO b/TODO
index 46609588..3642192f 100644
--- a/TODO
+++ b/TODO
@@ -6,6 +6,7 @@ o set keyboard according to locale in DOS
o allow selection of one of the existing compatible volume (keep existing MBR) / full repartitioning (overwrite MBR)
o FreeDOS integration
o Enable compression for NTFS
-o Bootable NTFS/exFAT
+o Bootable NTFS/exFAT?
+ http://sourceforge.net/projects/grub4dos/
o GPT support?
o disable indexing support on NTFS?
diff --git a/configure b/configure
index f2a60a98..81c7c2db 100644
--- a/configure
+++ b/configure
@@ -3360,7 +3360,7 @@ $as_echo "#define _GNU_SOURCE /**/" >>confdefs.h
# AC_MSG_ERROR([unsupported development environment])
#esac
-AM_CFLAGS="${AM_CFLAGS} -DWINVER=0x501 -D_WIN32_IE=0x501"
+AM_CFLAGS="${AM_CFLAGS} -D__MSVCRT_VERSION__=0x700 -DWINVER=0x501 -D_WIN32_IE=0x501"
AM_LDFLAGS="${AM_LDFLAGS} -Wl,-no-undefined"
# Debug logging
diff --git a/configure.ac b/configure.ac
index f54a00ac..6320e096 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([rufus], [1.0.1], [https://github.com/pbatard/rufus/issues], [rufus], [https://github.com/pbatard/rufus])
+AC_INIT([rufus], [1.0.2], [https://github.com/pbatard/rufus/issues], [rufus], [https://github.com/pbatard/rufus])
AM_INIT_AUTOMAKE([-Wno-portability foreign no-dist no-dependencies])
AC_CONFIG_SRCDIR([src/rufus.c])
AC_CONFIG_MACRO_DIR([m4])
@@ -31,7 +31,7 @@ AC_DEFINE([_GNU_SOURCE], [], [Use GNU extensions])
# AC_MSG_ERROR([unsupported development environment])
#esac
-AM_CFLAGS="${AM_CFLAGS} -DWINVER=0x501 -D_WIN32_IE=0x501"
+AM_CFLAGS="${AM_CFLAGS} -D__MSVCRT_VERSION__=0x700 -DWINVER=0x501 -D_WIN32_IE=0x501"
AM_LDFLAGS="${AM_LDFLAGS} -Wl,-no-undefined"
# Debug logging
diff --git a/src/.msvc/rufus_2010.vcxproj b/src/.msvc/rufus_2010.vcxproj
index 5438044c..12a1a896 100644
--- a/src/.msvc/rufus_2010.vcxproj
+++ b/src/.msvc/rufus_2010.vcxproj
@@ -146,6 +146,7 @@
+
@@ -159,6 +160,7 @@
+
diff --git a/src/.msvc/rufus_2010.vcxproj.filters b/src/.msvc/rufus_2010.vcxproj.filters
index 3d76b7ae..d6b4d3e0 100644
--- a/src/.msvc/rufus_2010.vcxproj.filters
+++ b/src/.msvc/rufus_2010.vcxproj.filters
@@ -51,6 +51,9 @@
Source Files
+
+ Source Files
+
@@ -155,6 +158,9 @@
Header Files
+
+ Header Files
+
diff --git a/src/.msvc/rufus_sources b/src/.msvc/rufus_sources
index 1932a2ef..9982e36e 100644
--- a/src/.msvc/rufus_sources
+++ b/src/.msvc/rufus_sources
@@ -23,15 +23,16 @@ TARGETLIBS=$(SDK_LIB_PATH)\kernel32.lib \
# http://jpassing.com/2008/02/01/how-to-use-manifests-with-buildexe/
SXS_APPLICATION_MANIFEST=common_controls_and_elevation.manifest
-SOURCES=rufus.c \
- format.c \
- stdio.c \
- stdlg.c \
- msdos.c \
- drive.c \
- file.c \
- br.c \
- fat12.c \
- fat16.c \
- fat32.c \
+SOURCES=rufus.c \
+ format.c \
+ stdio.c \
+ stdlg.c \
+ msdos.c \
+ badblocks.c \
+ drive.c \
+ file.c \
+ br.c \
+ fat12.c \
+ fat16.c \
+ fat32.c \
rufus.rc
diff --git a/src/Makefile.am b/src/Makefile.am
index 513eaeb8..e57b3725 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,7 +9,7 @@ pkg_v_rc_0 = @echo " RC $@";
%_rc.o: %.rc
$(pkg_v_rc)$(WINDRES) -i $< -o $@
-rufus_SOURCES = fat12.c fat16.c fat32.c br.c file.c drive.c msdos.c format.c stdio.c stdlg.c rufus.c
+rufus_SOURCES = fat12.c fat16.c fat32.c br.c file.c drive.c msdos.c badblocks.c format.c stdio.c stdlg.c rufus.c
rufus_CFLAGS = -I./inc $(ARCH_CFLAGS) $(AM_CFLAGS)
rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows
rufus_LDADD = rufus_rc.o -lsetupapi -lole32 -lgdi32
diff --git a/src/Makefile.in b/src/Makefile.in
index 83566384..a423f1e2 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -48,8 +48,9 @@ PROGRAMS = $(noinst_PROGRAMS)
am_rufus_OBJECTS = rufus-fat12.$(OBJEXT) rufus-fat16.$(OBJEXT) \
rufus-fat32.$(OBJEXT) rufus-br.$(OBJEXT) rufus-file.$(OBJEXT) \
rufus-drive.$(OBJEXT) rufus-msdos.$(OBJEXT) \
- rufus-format.$(OBJEXT) rufus-stdio.$(OBJEXT) \
- rufus-stdlg.$(OBJEXT) rufus-rufus.$(OBJEXT)
+ rufus-badblocks.$(OBJEXT) rufus-format.$(OBJEXT) \
+ rufus-stdio.$(OBJEXT) rufus-stdlg.$(OBJEXT) \
+ rufus-rufus.$(OBJEXT)
rufus_OBJECTS = $(am_rufus_OBJECTS)
rufus_DEPENDENCIES = rufus_rc.o
rufus_LINK = $(CCLD) $(rufus_CFLAGS) $(CFLAGS) $(rufus_LDFLAGS) \
@@ -167,7 +168,7 @@ top_srcdir = @top_srcdir@
pkg_v_rc = $(pkg_v_rc_$(V))
pkg_v_rc_ = $(pkg_v_rc_$(AM_DEFAULT_VERBOSITY))
pkg_v_rc_0 = @echo " RC $@";
-rufus_SOURCES = fat12.c fat16.c fat32.c br.c file.c drive.c msdos.c format.c stdio.c stdlg.c rufus.c
+rufus_SOURCES = fat12.c fat16.c fat32.c br.c file.c drive.c msdos.c badblocks.c format.c stdio.c stdlg.c rufus.c
rufus_CFLAGS = -I./inc $(ARCH_CFLAGS) $(AM_CFLAGS)
rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows
rufus_LDADD = rufus_rc.o -lsetupapi -lole32 -lgdi32
@@ -282,6 +283,14 @@ rufus-msdos.obj: msdos.c
$(AM_V_CC) @AM_BACKSLASH@
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-msdos.obj `if test -f 'msdos.c'; then $(CYGPATH_W) 'msdos.c'; else $(CYGPATH_W) '$(srcdir)/msdos.c'; fi`
+rufus-badblocks.o: badblocks.c
+ $(AM_V_CC) @AM_BACKSLASH@
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-badblocks.o `test -f 'badblocks.c' || echo '$(srcdir)/'`badblocks.c
+
+rufus-badblocks.obj: badblocks.c
+ $(AM_V_CC) @AM_BACKSLASH@
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-badblocks.obj `if test -f 'badblocks.c'; then $(CYGPATH_W) 'badblocks.c'; else $(CYGPATH_W) '$(srcdir)/badblocks.c'; fi`
+
rufus-format.o: format.c
$(AM_V_CC) @AM_BACKSLASH@
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-format.o `test -f 'format.c' || echo '$(srcdir)/'`format.c
diff --git a/src/badblocks.c b/src/badblocks.c
new file mode 100644
index 00000000..8e9e13dd
--- /dev/null
+++ b/src/badblocks.c
@@ -0,0 +1,1051 @@
+/*
+ * badblocks.c - Bad blocks checker
+ *
+ * Copyright (C) 1992, 1993, 1994 Remy Card
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * Copyright 1995, 1996, 1997, 1998, 1999 by Theodore Ts'o
+ * Copyright 1999 by David Beattie
+ * Copyright 2011 by Pete Batard
+ *
+ * This file is based on the minix file system programs fsck and mkfs
+ * written and copyrighted by Linus Torvalds
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+/*
+ * History:
+ * 93/05/26 - Creation from e2fsck
+ * 94/02/27 - Made a separate bad blocks checker
+ * 99/06/30...99/07/26 - Added non-destructive write-testing,
+ * configurable blocks-at-once parameter,
+ * loading of badblocks list to avoid testing
+ * blocks known to be bad, multiple passes to
+ * make sure that no new blocks are added to the
+ * list. (Work done by David Beattie)
+ * 11/12/04 - Windows/Rufus integration (Pete Batard)
+ */
+
+#include
+#include
+#include
+//#include
+#include
+#include
+#include
+#include
+#include
+
+#include "rufus.h"
+#include "badblocks.h"
+#include "file.h"
+
+/*
+ *From e2fsprogs/e2fsck/badblocks.c
+ */
+static errcode_t make_u32_list(int size, int num, __u32 *list,
+ ext2_u32_list *ret)
+{
+ ext2_u32_list bb;
+
+ bb = calloc(1, sizeof(struct ext2_struct_u32_list));
+ if (bb == NULL)
+ return EXT2_ET_NO_MEMORY;
+ bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
+ bb->size = size ? size : 10;
+ bb->num = num;
+ bb->list = malloc(sizeof(blk_t) * bb->size);
+ if (bb->list == NULL) {
+ free(bb);
+ bb = NULL;
+ return EXT2_ET_NO_MEMORY;
+ }
+ if (list)
+ memcpy(bb->list, list, bb->size * sizeof(blk_t));
+ else
+ memset(bb->list, 0, bb->size * sizeof(blk_t));
+ *ret = bb;
+ return 0;
+}
+
+/*
+ * This procedure creates an empty badblocks list.
+ */
+static errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
+{
+ return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret);
+}
+
+/*
+ * This procedure adds a block to a badblocks list.
+ */
+static errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk)
+{
+ int i, j;
+ unsigned long old_size;
+ __u32* old_bb_list = bb->list;
+
+ EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
+
+ if (bb->num >= bb->size) {
+ old_size = bb->size * sizeof(__u32);
+ bb->size += 100;
+ bb->list = realloc(bb->list, bb->size * sizeof(__u32));
+ if (bb->list == NULL) {
+ bb->list = old_bb_list;
+ bb->size -= 100;
+ return EXT2_ET_NO_MEMORY;
+ }
+ }
+
+ /*
+ * Add special case code for appending to the end of the list
+ */
+ i = bb->num-1;
+ if ((bb->num != 0) && (bb->list[i] == blk))
+ return 0;
+ if ((bb->num == 0) || (bb->list[i] < blk)) {
+ bb->list[bb->num++] = blk;
+ return 0;
+ }
+
+ j = bb->num;
+ for (i=0; i < bb->num; i++) {
+ if (bb->list[i] == blk)
+ return 0;
+ if (bb->list[i] > blk) {
+ j = i;
+ break;
+ }
+ }
+ for (i=bb->num; i > j; i--)
+ bb->list[i] = bb->list[i-1];
+ bb->list[j] = blk;
+ bb->num++;
+ return 0;
+}
+
+static errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
+{
+ return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk);
+}
+
+/*
+ * This procedure finds a particular block is on a badblocks
+ * list.
+ */
+static int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk)
+{
+ int low, high, mid;
+
+ if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
+ return -1;
+
+ if (bb->num == 0)
+ return -1;
+
+ low = 0;
+ high = bb->num-1;
+ if (blk == bb->list[low])
+ return low;
+ if (blk == bb->list[high])
+ return high;
+
+ while (low < high) {
+ mid = ((unsigned)low + (unsigned)high)/2;
+ if (mid == low || mid == high)
+ break;
+ if (blk == bb->list[mid])
+ return mid;
+ if (blk < bb->list[mid])
+ high = mid;
+ else
+ low = mid;
+ }
+ return -1;
+}
+
+/*
+ * This procedure tests to see if a particular block is on a badblocks
+ * list.
+ */
+static int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk)
+{
+ if (ext2fs_u32_list_find(bb, blk) < 0)
+ return 0;
+ else
+ return 1;
+}
+
+static int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
+{
+ return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk);
+}
+
+/*
+ * Remove a block from the badblock list
+ */
+int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk)
+{
+ int remloc, i;
+
+ if (bb->num == 0)
+ return -1;
+
+ remloc = ext2fs_u32_list_find(bb, blk);
+ if (remloc < 0)
+ return -1;
+
+ for (i = remloc ; i < bb->num-1; i++)
+ bb->list[i] = bb->list[i+1];
+ bb->num--;
+ return 0;
+}
+
+static void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk)
+{
+ ext2fs_u32_list_del(bb, blk);
+}
+
+static errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
+ ext2_u32_iterate *ret)
+{
+ ext2_u32_iterate iter;
+
+ EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
+
+ iter = malloc(sizeof(struct ext2_struct_u32_iterate));
+ if (iter == NULL)
+ return EXT2_ET_NO_MEMORY;
+
+ iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
+ iter->bb = bb;
+ iter->ptr = 0;
+ *ret = iter;
+ return 0;
+}
+
+static errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
+ ext2_badblocks_iterate *ret)
+{
+ return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb,
+ (ext2_u32_iterate *) ret);
+}
+
+
+static int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk)
+{
+ ext2_u32_list bb;
+
+ if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
+ return 0;
+
+ bb = iter->bb;
+
+ if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
+ return 0;
+
+ if (iter->ptr < bb->num) {
+ *blk = bb->list[iter->ptr++];
+ return 1;
+ }
+ *blk = 0;
+ return 0;
+}
+
+static int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
+{
+ return ext2fs_u32_list_iterate((ext2_u32_iterate) iter,
+ (__u32 *) blk);
+}
+
+
+static void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter)
+{
+ if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
+ return;
+
+ iter->bb = 0;
+ free(iter);
+}
+
+static void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
+{
+ ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter);
+}
+
+
+static int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2)
+{
+ EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
+ EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
+
+ if (bb1->num != bb2->num)
+ return 0;
+
+ if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0)
+ return 0;
+ return 1;
+}
+
+static int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
+{
+ return ext2fs_u32_list_equal((ext2_u32_list) bb1,
+ (ext2_u32_list) bb2);
+}
+
+static int ext2fs_u32_list_count(ext2_u32_list bb)
+{
+ return bb->num;
+}
+
+/*
+ * from e2fsprogs\misc\badblocks.c
+ */
+static int v_flag = 2; /* verbose */
+static int w_flag = 0; /* do r/w test: 0=no, 1=yes,
+ * 2=non-destructive */
+static int s_flag = 1; /* show progress of test */
+static int t_flag = 0; /* number of test patterns */
+static int t_max = 0; /* allocated test patterns */
+static unsigned int *t_patts = NULL; /* test patterns */
+// TODO: set this from parameter
+static unsigned int max_bb = 32; /* Abort test if more than this number of bad blocks has been encountered */
+static unsigned int d_flag = 0; /* delay factor between reads */
+static DWORD time_start;
+
+#define T_INC 32
+
+unsigned int sys_page_size = 4096;
+
+static blk_t currently_testing = 0;
+static blk_t num_blocks = 0;
+static blk_t num_read_errors = 0;
+static blk_t num_write_errors = 0;
+static blk_t num_corruption_errors = 0;
+static ext2_badblocks_list bb_list = NULL;
+static FILE *out;
+static blk_t next_bad = 0;
+static ext2_badblocks_iterate bb_iter = NULL;
+
+enum error_types { READ_ERROR, WRITE_ERROR, CORRUPTION_ERROR };
+
+static __inline void *allocate_buffer(size_t size) {
+ // TODO: requires -D__MSVCRT_VERSION__=0x700 for MinGW
+ // find out if older XP platforms might miss it
+ return _aligned_malloc(size, sys_page_size);
+}
+
+static __inline void free_buffer(void* p) {
+ _aligned_free(p);
+}
+
+/*
+ * This routine reports a new bad block. If the bad block has already
+ * been seen before, then it returns 0; otherwise it returns 1.
+ */
+static int bb_output (blk_t bad, enum error_types error_type)
+{
+ errcode_t errcode;
+
+ if (ext2fs_badblocks_list_test(bb_list, bad))
+ return 0;
+
+ uprintf("%lu\n", (unsigned long) bad);
+
+ errcode = ext2fs_badblocks_list_add(bb_list, bad);
+ if (errcode) {
+ uprintf("Error %d adding to in-memory bad block list", errcode);
+ exit (1);
+ }
+
+ /* kludge:
+ increment the iteration through the bb_list if
+ an element was just added before the current iteration
+ position. This should not cause next_bad to change. */
+ if (bb_iter && bad < next_bad)
+ ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
+
+ if (error_type == READ_ERROR) {
+ num_read_errors++;
+ } else if (error_type == WRITE_ERROR) {
+ num_write_errors++;
+ } else if (error_type == CORRUPTION_ERROR) {
+ num_corruption_errors++;
+ }
+ return 1;
+}
+
+static float calc_percent(unsigned long current, unsigned long total) {
+ float percent = 0.0;
+ if (total <= 0)
+ return percent;
+ if (current >= total) {
+ percent = 100.0f;
+ } else {
+ percent=(100.0f*(float)current/(float)total);
+ }
+ return percent;
+}
+
+static void print_status(void)
+{
+ static DWORD msecs = 0;
+ DWORD time_end;
+
+ // TODO: use GetTickCount64 on Vista and later
+ time_end = GetTickCount();
+ /* update status every second */
+ if (time_end - time_start >= msecs) {
+ uprintf("%6.2f%% done, %0.2f elapsed. "
+ "(%d/%d/%d errors)",
+ calc_percent((unsigned long) currently_testing,
+ (unsigned long) num_blocks),
+ (time_end - time_start)/1000.0,
+ num_read_errors,
+ num_write_errors,
+ num_corruption_errors);
+ msecs += 1000;
+ }
+}
+
+static void pattern_fill(unsigned char *buffer, unsigned int pattern,
+ size_t n)
+{
+ unsigned int i, nb;
+ unsigned char bpattern[sizeof(pattern)], *ptr;
+
+ if (pattern == (unsigned int) ~0) {
+ for (ptr = buffer; ptr < buffer + n; ptr++) {
+ (*ptr) = rand() % (1 << (8 * sizeof(char)));
+ }
+ PrintStatus("Testing with random pattern: ");
+ } else {
+ bpattern[0] = 0;
+ for (i = 0; i < sizeof(bpattern); i++) {
+ if (pattern == 0)
+ break;
+ bpattern[i] = pattern & 0xFF;
+ pattern = pattern >> 8;
+ }
+ nb = i ? (i-1) : 0;
+ for (ptr = buffer, i = nb; ptr < buffer + n; ptr++) {
+ *ptr = bpattern[i];
+ if (i == 0)
+ i = nb;
+ else
+ i--;
+ }
+ PrintStatus("Testing with pattern 0x%02X", bpattern[i]);
+ }
+}
+
+/*
+ * Perform a read of a sequence of blocks; return the number of blocks
+ * successfully sequentially read.
+ */
+static int do_read (HANDLE hDrive, unsigned char * buffer, int tryout, int block_size,
+ blk_t current_block)
+{
+ long got;
+ DWORD tv1, tv2;
+#define NANOSEC (1000000000L)
+#define MILISEC (1000L)
+
+#if 0
+ printf("do_read: block %d, try %d\n", current_block, tryout);
+#endif
+
+ if (v_flag > 1)
+ print_status();
+
+ /* Try the read */
+ if (d_flag)
+ tv1 = GetTickCount();
+ got = read_sectors(hDrive, block_size, current_block, tryout, buffer);
+ // read (dev, buffer, tryout * block_size);
+ if (d_flag)
+ tv2 = GetTickCount();
+ if (got < 0)
+ got = 0;
+ if (got & 511)
+ uprintf("Weird value (%ld) in do_read\n", got);
+ got /= block_size;
+ if (d_flag && got == tryout) {
+// TODO: either remove or update for Windows
+#ifdef HAVE_NANOSLEEP
+ struct timespec ts;
+ ts.tv_sec = tv2.tv_sec - tv1.tv_sec;
+ ts.tv_nsec = (tv2.tv_usec - tv1.tv_usec) * MILISEC;
+ if (ts.tv_nsec < 0) {
+ ts.tv_nsec += NANOSEC;
+ ts.tv_sec -= 1;
+ }
+ /* increase/decrease the sleep time based on d_flag value */
+ ts.tv_sec = ts.tv_sec * d_flag / 100;
+ ts.tv_nsec = ts.tv_nsec * d_flag / 100;
+ if (ts.tv_nsec > NANOSEC) {
+ ts.tv_sec += ts.tv_nsec / NANOSEC;
+ ts.tv_nsec %= NANOSEC;
+ }
+ if (ts.tv_sec || ts.tv_nsec)
+ nanosleep(&ts, NULL);
+#else
+#ifdef HAVE_USLEEP
+ struct timeval tv;
+ tv.tv_sec = tv2.tv_sec - tv1.tv_sec;
+ tv.tv_usec = tv2.tv_usec - tv1.tv_usec;
+ tv.tv_sec = tv.tv_sec * d_flag / 100;
+ tv.tv_usec = tv.tv_usec * d_flag / 100;
+ if (tv.tv_usec > 1000000) {
+ tv.tv_sec += tv.tv_usec / 1000000;
+ tv.tv_usec %= 1000000;
+ }
+ if (tv.tv_sec)
+ sleep(tv.tv_sec);
+ if (tv.tv_usec)
+ usleep(tv.tv_usec);
+#endif
+#endif
+ }
+ return got;
+}
+
+/*
+ * Perform a write of a sequence of blocks; return the number of blocks
+ * successfully sequentially written.
+ */
+static int do_write(HANDLE hDrive, unsigned char * buffer, int tryout, int block_size,
+ unsigned long current_block)
+{
+ long got;
+
+#if 0
+ printf("do_write: block %lu, try %d\n", current_block, tryout);
+#endif
+ if (v_flag > 1)
+ print_status();
+
+ /* Try the write */
+ got = write_sectors(hDrive, block_size, current_block, tryout, buffer);
+ if (got < 0)
+ got = 0;
+ if (got & 511)
+ uprintf("Weird value (%ld) in do_write\n", got);
+ got /= block_size;
+ return got;
+}
+
+static unsigned int test_ro (HANDLE hDrive, blk_t last_block,
+ int block_size, blk_t first_block,
+ unsigned int blocks_at_once)
+{
+ unsigned char * blkbuf;
+ int tryout;
+ int got;
+ unsigned int bb_count = 0;
+ errcode_t errcode;
+ blk_t recover_block = ~0;
+
+ errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
+ if (errcode) {
+ // TODO: set FormatStatus
+ uprintf("errcode %d while beginning bad block list iteration\n", errcode);
+ return 0;
+ }
+ do {
+ ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
+ } while (next_bad && next_bad < first_block);
+
+ if (t_flag) {
+ blkbuf = allocate_buffer((blocks_at_once + 1) * block_size);
+ } else {
+ blkbuf = allocate_buffer(blocks_at_once * block_size);
+ }
+ if (!blkbuf)
+ {
+ // TODO: err
+ uprintf("could not allocate buffers\n");
+ return 0;
+ }
+ if (t_flag) {
+ uprintf("Checking for bad blocks in read-only mode\n");
+ pattern_fill(blkbuf + blocks_at_once * block_size,
+ t_patts[0], block_size);
+ }
+ tryout = blocks_at_once;
+ currently_testing = first_block;
+ num_blocks = last_block - 1;
+ if (!t_flag && (s_flag || v_flag)) {
+ // Printstatus
+ uprintf("Checking for bad blocks (read-only test): \n");
+ }
+ while (currently_testing < last_block)
+ {
+ if (max_bb && bb_count >= max_bb) {
+ if (s_flag || v_flag) {
+ uprintf("Too many bad blocks, aborting test\n");
+ }
+ break;
+ }
+ if (next_bad) {
+ if (currently_testing == next_bad) {
+ /* fprintf (out, "%lu\n", nextbad); */
+ ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
+ currently_testing++;
+ continue;
+ }
+ else if (currently_testing + tryout > next_bad)
+ tryout = next_bad - currently_testing;
+ }
+ if (currently_testing + tryout > last_block)
+ tryout = last_block - currently_testing;
+ got = do_read(hDrive, blkbuf, tryout, block_size, currently_testing);
+ if (t_flag) {
+ /* test the comparison between all the
+ blocks successfully read */
+ int i;
+ for (i = 0; i < got; ++i)
+ if (memcmp (blkbuf+i*block_size,
+ blkbuf+blocks_at_once*block_size,
+ block_size))
+ bb_count += bb_output(currently_testing + i, CORRUPTION_ERROR);
+ }
+ if (got == 0 && tryout == 1)
+ bb_count += bb_output(currently_testing++, READ_ERROR);
+ currently_testing += got;
+ if (got != tryout) {
+ tryout = 1;
+ if (recover_block == ~0)
+ recover_block = currently_testing - got +
+ blocks_at_once;
+ continue;
+ } else if (currently_testing == recover_block) {
+ tryout = blocks_at_once;
+ recover_block = ~0;
+ }
+ }
+ num_blocks = 0;
+// alarm(0);
+// if (s_flag || v_flag)
+// fputs(_(done_string), stderr);
+
+ fflush (stderr);
+ free_buffer(blkbuf);
+
+ ext2fs_badblocks_list_iterate_end(bb_iter);
+
+ return bb_count;
+}
+
+static unsigned int test_rw(HANDLE hDrive, blk_t last_block, int block_size, blk_t first_block, unsigned int blocks_at_once)
+{
+ unsigned char *buffer, *read_buffer;
+ const unsigned int patterns[] = {0xaa}; // {0xaa, 0x55, 0xff, 0x00};
+ const unsigned int *pattern;
+ int i, tryout, got, nr_pattern, pat_idx;
+ unsigned int bb_count = 0;
+ blk_t recover_block = ~0;
+
+ buffer = allocate_buffer(2 * blocks_at_once * block_size);
+ read_buffer = buffer + blocks_at_once * block_size;
+
+ if (!buffer) {
+ uprintf("Error while allocating buffers");
+ return 0;
+ }
+
+ uprintf("Checking for bad blocks in read-write mode\n");
+ uprintf("From block %lu to %lu\n", (unsigned long) first_block, (unsigned long) last_block - 1);
+ if (t_flag) {
+ pattern = t_patts;
+ nr_pattern = t_flag;
+ } else {
+ pattern = patterns;
+ nr_pattern = ARRAYSIZE(patterns);
+ }
+ // TODO: allow cancellation
+ for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
+ pattern_fill(buffer, pattern[pat_idx], blocks_at_once * block_size);
+ num_blocks = last_block - 1;
+ currently_testing = first_block;
+// if (s_flag && v_flag <= 1)
+// alarm_intr(SIGALRM);
+ if (s_flag | v_flag)
+ uprintf("Writing\n");
+ tryout = blocks_at_once;
+ while (currently_testing < last_block) {
+ if (max_bb && bb_count >= max_bb) {
+ if (s_flag || v_flag) {
+ // TODO: this abort blows
+ uprintf("Too many bad blocks, aborting test\n");
+ }
+ break;
+ }
+ if (currently_testing + tryout > last_block)
+ tryout = last_block - currently_testing;
+ got = do_write(hDrive, buffer, tryout, block_size, currently_testing);
+ if (v_flag > 1)
+ print_status();
+
+ if (got == 0 && tryout == 1)
+ bb_count += bb_output(currently_testing++, WRITE_ERROR);
+ currently_testing += got;
+ if (got != tryout) {
+ tryout = 1;
+ if (recover_block == ~0)
+ recover_block = currently_testing -
+ got + blocks_at_once;
+ continue;
+ } else if (currently_testing == recover_block) {
+ tryout = blocks_at_once;
+ recover_block = ~0;
+ }
+ }
+
+ num_blocks = 0;
+// alarm (0);
+// if (s_flag | v_flag)
+// fputs(_(done_string), stderr);
+ if (s_flag | v_flag)
+ // TODO: status
+ uprintf("Reading and comparing\n");
+ num_blocks = last_block;
+ currently_testing = first_block;
+// if (s_flag && v_flag <= 1)
+// alarm_intr(SIGALRM);
+
+ tryout = blocks_at_once;
+ while (currently_testing < last_block) {
+ if (max_bb && bb_count >= max_bb) {
+ if (s_flag || v_flag) {
+ uprintf("Too many bad blocks, aborting test\n");
+ }
+ break;
+ }
+ if (currently_testing + tryout > last_block)
+ tryout = last_block - currently_testing;
+ got = do_read(hDrive, read_buffer, tryout, block_size,
+ currently_testing);
+ if (got == 0 && tryout == 1)
+ bb_count += bb_output(currently_testing++, READ_ERROR);
+ currently_testing += got;
+ if (got != tryout) {
+ tryout = 1;
+ if (recover_block == ~0)
+ recover_block = currently_testing -
+ got + blocks_at_once;
+ continue;
+ } else if (currently_testing == recover_block) {
+ tryout = blocks_at_once;
+ recover_block = ~0;
+ }
+ for (i=0; i < got; i++) {
+ if (memcmp(read_buffer + i * block_size,
+ buffer + i * block_size,
+ block_size))
+ bb_count += bb_output(currently_testing+i, CORRUPTION_ERROR);
+ }
+ if (v_flag > 1)
+ print_status();
+ }
+
+ num_blocks = 0;
+// alarm (0);
+// if (s_flag | v_flag)
+// fputs(_(done_string), stderr);
+ }
+ free_buffer(buffer);
+ return bb_count;
+}
+
+struct saved_blk_record {
+ blk_t block;
+ int num;
+};
+
+static unsigned int test_nd(HANDLE hDrive, blk_t last_block,
+ int block_size, blk_t first_block,
+ unsigned int blocks_at_once)
+{
+ unsigned char *blkbuf, *save_ptr, *test_ptr, *read_ptr;
+ unsigned char *test_base, *save_base, *read_base;
+ int tryout, i;
+ const unsigned int patterns[] = { ~0 };
+ const unsigned int *pattern;
+ int nr_pattern, pat_idx;
+ int got, used2, written;
+ blk_t save_currently_testing;
+ struct saved_blk_record *test_record;
+ /* This is static to prevent being clobbered by the longjmp */
+ static int num_saved;
+ jmp_buf terminate_env;
+ errcode_t errcode;
+ unsigned long buf_used;
+ static unsigned int bb_count;
+ int granularity = blocks_at_once;
+ blk_t recover_block = ~0;
+
+ bb_count = 0;
+ errcode = ext2fs_badblocks_list_iterate_begin(bb_list,&bb_iter);
+ if (errcode) {
+ uprintf("Error %d while beginning bad block list iteration", errcode);
+ exit (1);
+ }
+ do {
+ ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
+ } while (next_bad && next_bad < first_block);
+
+ blkbuf = allocate_buffer(3 * blocks_at_once * block_size);
+ test_record = malloc (blocks_at_once*sizeof(struct saved_blk_record));
+ if (!blkbuf || !test_record) {
+ uprintf("Error while allocating buffers");
+ exit (1);
+ }
+
+ save_base = blkbuf;
+ test_base = blkbuf + (blocks_at_once * block_size);
+ read_base = blkbuf + (2 * blocks_at_once * block_size);
+
+ num_saved = 0;
+
+ if (v_flag) {
+ uprintf("Checking for bad blocks in non-destructive read-write mode\n");
+ uprintf("From block %lu to %lu\n",
+ (unsigned long) first_block,
+ (unsigned long) last_block - 1);
+ }
+ if (s_flag || v_flag > 1) {
+ uprintf("Checking for bad blocks (non-destructive read-write test)\n");
+ }
+ if (setjmp(terminate_env)) {
+ /*
+ * Abnormal termination by a signal is handled here.
+ */
+// signal (SIGALRM, SIG_IGN);
+ uprintf("Interrupt caught, cleaning up\n");
+
+ save_ptr = save_base;
+ for (i=0; i < num_saved; i++) {
+ do_write(hDrive, save_ptr, test_record[i].num,
+ block_size, test_record[i].block);
+ save_ptr += test_record[i].num * block_size;
+ }
+ fflush (out);
+ exit(1);
+ }
+
+ if (t_flag) {
+ pattern = t_patts;
+ nr_pattern = t_flag;
+ } else {
+ pattern = patterns;
+ nr_pattern = sizeof(patterns) / sizeof(patterns[0]);
+ }
+ for (pat_idx = 0; pat_idx < nr_pattern; pat_idx++) {
+ pattern_fill(test_base, pattern[pat_idx],
+ blocks_at_once * block_size);
+
+ buf_used = 0;
+ bb_count = 0;
+ save_ptr = save_base;
+ test_ptr = test_base;
+ currently_testing = first_block;
+ num_blocks = last_block - 1;
+// if (s_flag && v_flag <= 1)
+// alarm_intr(SIGALRM);
+
+ while (currently_testing < last_block) {
+ if (max_bb && bb_count >= max_bb) {
+ if (s_flag || v_flag) {
+ uprintf("Too many bad blocks, aborting test\n");
+ }
+ break;
+ }
+ got = tryout = granularity - buf_used;
+ if (next_bad) {
+ if (currently_testing == next_bad) {
+ /* fprintf (out, "%lu\n", nextbad); */
+ ext2fs_badblocks_list_iterate (bb_iter, &next_bad);
+ currently_testing++;
+ goto check_for_more;
+ }
+ else if (currently_testing + tryout > next_bad)
+ tryout = next_bad - currently_testing;
+ }
+ if (currently_testing + tryout > last_block)
+ tryout = last_block - currently_testing;
+ got = do_read(hDrive, save_ptr, tryout, block_size,
+ currently_testing);
+ if (got == 0) {
+ if (recover_block == ~0)
+ recover_block = currently_testing +
+ blocks_at_once;
+ if (granularity != 1) {
+ granularity = 1;
+ continue;
+ }
+ /* First block must have been bad. */
+ bb_count += bb_output(currently_testing++, READ_ERROR);
+ goto check_for_more;
+ }
+
+ /*
+ * Note the fact that we've saved this much data
+ * *before* we overwrite it with test data
+ */
+ test_record[num_saved].block = currently_testing;
+ test_record[num_saved].num = got;
+ num_saved++;
+
+ /* Write the test data */
+ written = do_write(hDrive, test_ptr, got, block_size,
+ currently_testing);
+ if (written != got)
+ uprintf("Error %d during test data write, block %lu", errno,
+ (unsigned long) currently_testing +
+ written);
+
+ buf_used += got;
+ save_ptr += got * block_size;
+ test_ptr += got * block_size;
+ currently_testing += got;
+ if (got != tryout) {
+ tryout = 1;
+ if (recover_block == ~0)
+ recover_block = currently_testing -
+ got + blocks_at_once;
+ continue;
+ }
+
+ check_for_more:
+ /*
+ * If there's room for more blocks to be tested this
+ * around, and we're not done yet testing the disk, go
+ * back and get some more blocks.
+ */
+ if ((buf_used != granularity) &&
+ (currently_testing < last_block))
+ continue;
+
+ if (currently_testing >= recover_block) {
+ granularity = blocks_at_once;
+ recover_block = ~0;
+ }
+
+ save_currently_testing = currently_testing;
+
+ /*
+ * for each contiguous block that we read into the
+ * buffer (and wrote test data into afterwards), read
+ * it back (looping if necessary, to get past newly
+ * discovered unreadable blocks, of which there should
+ * be none, but with a hard drive which is unreliable,
+ * it has happened), and compare with the test data
+ * that was written; output to the bad block list if
+ * it doesn't match.
+ */
+ used2 = 0;
+ save_ptr = save_base;
+ test_ptr = test_base;
+ read_ptr = read_base;
+ tryout = 0;
+
+ while (1) {
+ if (tryout == 0) {
+ if (used2 >= num_saved)
+ break;
+ currently_testing = test_record[used2].block;
+ tryout = test_record[used2].num;
+ used2++;
+ }
+
+ got = do_read(hDrive, read_ptr, tryout,
+ block_size, currently_testing);
+
+ /* test the comparison between all the
+ blocks successfully read */
+ for (i = 0; i < got; ++i)
+ if (memcmp (test_ptr+i*block_size,
+ read_ptr+i*block_size, block_size))
+ bb_count += bb_output(currently_testing + i, CORRUPTION_ERROR);
+ if (got < tryout) {
+ bb_count += bb_output(currently_testing + got, READ_ERROR);
+ got++;
+ }
+
+ /* write back original data */
+ do_write(hDrive, save_ptr, got,
+ block_size, currently_testing);
+ save_ptr += got * block_size;
+
+ currently_testing += got;
+ test_ptr += got * block_size;
+ read_ptr += got * block_size;
+ tryout -= got;
+ }
+
+ /* empty the buffer so it can be reused */
+ num_saved = 0;
+ buf_used = 0;
+ save_ptr = save_base;
+ test_ptr = test_base;
+ currently_testing = save_currently_testing;
+ }
+ num_blocks = 0;
+// alarm(0);
+// if (s_flag || v_flag > 1)
+// fputs(_(done_string), stderr);
+
+ }
+ free_buffer(blkbuf);
+ free(test_record);
+
+ ext2fs_badblocks_list_iterate_end(bb_iter);
+
+ return bb_count;
+}
+
+int BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, int block_size)
+{
+ errcode_t errcode;
+ unsigned int blocks_at_once = 64;
+ unsigned int (*test_func)(HANDLE, blk_t,
+ int, blk_t,
+ unsigned int);
+ int num_passes = 0;
+ int passes_clean = 0;
+ int bb_count;
+ blk_t first_block = 0, last_block = (blk_t)disk_size/block_size;
+
+ errcode = ext2fs_badblocks_list_create(&bb_list, 0);
+ if (errcode) {
+ uprintf("Error %d while creating in-memory bad blocks list", errcode);
+ return -1;
+ }
+
+ test_func = test_rw;
+ time_start = GetTickCount();
+ do {
+ bb_count = test_func(hPhysicalDrive, last_block, block_size, first_block, blocks_at_once);
+ if (bb_count)
+ passes_clean = 0;
+ else
+ ++passes_clean;
+
+ if (v_flag)
+ uprintf("Pass completed, %u bad blocks found. (%d/%d/%d errors)\n",
+ bb_count, num_read_errors, num_write_errors, num_corruption_errors);
+
+ } while (passes_clean < num_passes);
+ free(t_patts);
+ free(bb_list->list);
+ free(bb_list);
+
+ return bb_count;
+}
diff --git a/src/badblocks.h b/src/badblocks.h
new file mode 100644
index 00000000..20e23963
--- /dev/null
+++ b/src/badblocks.h
@@ -0,0 +1,60 @@
+/*
+ * badblocks.c - Bad blocks checker
+ *
+ * Copyright (C) 1992, 1993, 1994 Remy Card
+ * Laboratoire MASI, Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * Copyright 1995, 1996, 1997, 1998, 1999 by Theodore Ts'o
+ * Copyright 1999 by David Beattie
+ * Copyright 2011 by Pete Batard
+ *
+ * This file is based on the minix file system programs fsck and mkfs
+ * written and copyrighted by Linus Torvalds
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include
+
+#ifndef __u32
+#define __u32 UINT32
+#endif
+typedef UINT32 blk_t;
+typedef struct ext2_struct_u32_list *ext2_badblocks_list;
+typedef struct ext2_struct_u32_iterate *ext2_badblocks_iterate;
+typedef struct ext2_struct_u32_list *ext2_u32_list;
+typedef struct ext2_struct_u32_iterate *ext2_u32_iterate;
+typedef long errcode_t;
+
+#define EXT2_ET_NO_MEMORY (2133571398L)
+#define EXT2_ET_MAGIC_BADBLOCKS_LIST (2133571330L)
+#define EXT2_ET_MAGIC_BADBLOCKS_ITERATE (2133571331L)
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+ if ((struct)->magic != (code)) return (code)
+
+/*
+ * Badblocks list
+ */
+struct ext2_struct_u32_list {
+ int magic;
+ int num;
+ int size;
+ __u32 *list;
+ int badblocks_flags;
+};
+
+struct ext2_struct_u32_iterate {
+ int magic;
+ ext2_u32_list bb;
+ int ptr;
+};
+
+/*
+ * Shared prototypes
+ */
+BOOL BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, int block_size);
diff --git a/src/file.c b/src/file.c
index 9b01b87a..31c2e319 100644
--- a/src/file.c
+++ b/src/file.c
@@ -22,64 +22,53 @@
#include "rufus.h"
#include "file.h"
+/* Returns the number of bytes written or -1 on error */
int write_sectors(HANDLE hDrive, size_t SectorSize,
size_t StartSector, size_t nSectors,
- const void *pBuf, size_t BufSize)
+ const void *pBuf)
{
LARGE_INTEGER ptr;
- DWORD Size;
-
- if(SectorSize * nSectors > BufSize)
- {
- uprintf("write_sectors: Buffer is too small\n");
- return 0;
- }
+ DWORD Size = 0;
ptr.QuadPart = StartSector*SectorSize;
if(!SetFilePointerEx(hDrive, ptr, NULL, FILE_BEGIN))
{
uprintf("write_sectors: Could not access sector %d - %s\n", StartSector, WindowsErrorString());
- return 0;
+ return -1;
}
- if((!WriteFile(hDrive, pBuf, (DWORD)BufSize, &Size, NULL)) || (Size != BufSize))
+ if((!WriteFile(hDrive, pBuf, (DWORD)nSectors*SectorSize, &Size, NULL)) || (Size != nSectors*SectorSize))
{
uprintf("write_sectors: Write error - %s\n", WindowsErrorString());
uprintf(" StartSector:%0X, nSectors:%0X, SectorSize:%0X\n", StartSector, nSectors, SectorSize);
- return 0;
+ return Size;
}
- return 1;
+ return Size;
}
+/* Returns the number of bytes read or -1 on error */
int read_sectors(HANDLE hDrive, size_t SectorSize,
size_t StartSector, size_t nSectors,
- void *pBuf, size_t BufSize)
+ void *pBuf)
{
LARGE_INTEGER ptr;
- DWORD Size;
-
- if(SectorSize * nSectors > BufSize)
- {
- uprintf("read_sectors: Buffer is too small\n");
- return 0;
- }
+ DWORD Size = 0;
ptr.QuadPart = StartSector*SectorSize;
if(!SetFilePointerEx(hDrive, ptr, NULL, FILE_BEGIN))
{
uprintf("read_sectors: Could not access sector %d - %s\n", StartSector, WindowsErrorString());
- return 0;
+ return -1;
}
- if((!ReadFile(hDrive, pBuf, (DWORD)BufSize, &Size, NULL)) || (Size != BufSize))
+ if((!ReadFile(hDrive, pBuf, (DWORD)nSectors*SectorSize, &Size, NULL)) || (Size != nSectors*SectorSize))
{
uprintf("read_sectors: Read error - %s\n", WindowsErrorString());
uprintf(" StartSector:%0X, nSectors:%0X, SectorSize:%0X\n", StartSector, nSectors, SectorSize);
- return 0;
}
- return 1;
+ return Size;
}
/* Use a bastardized fp that contains a Windows handle and the sector size */
@@ -101,8 +90,8 @@ int contains_data(FILE *fp, size_t Position,
return 0;
}
- if(!read_sectors(hDrive, SectorSize, StartSector,
- NumSectors, aucBuf, sizeof(aucBuf)))
+ if(read_sectors(hDrive, SectorSize, StartSector,
+ NumSectors, aucBuf) <= 0)
return 0;
if(memcmp(pData, &aucBuf[Position - StartSector*SectorSize], Len))
@@ -130,15 +119,15 @@ int write_data(FILE *fp, size_t Position,
}
/* Data to write may not be aligned on a sector boundary => read into a sector buffer first */
- if(!read_sectors(hDrive, SectorSize, StartSector,
- NumSectors, aucBuf, sizeof(aucBuf)))
+ if(read_sectors(hDrive, SectorSize, StartSector,
+ NumSectors, aucBuf) <= 0)
return 0;
if(!memcpy(&aucBuf[Position - StartSector*SectorSize], pData, Len))
return 0;
- if(!write_sectors(hDrive, SectorSize, StartSector,
- NumSectors, aucBuf, sizeof(aucBuf)))
+ if(write_sectors(hDrive, SectorSize, StartSector,
+ NumSectors, aucBuf) <= 0)
return 0;
return 1;
} /* write_data */
diff --git a/src/format.c b/src/format.c
index e8eaa769..7afdf6be 100644
--- a/src/format.c
+++ b/src/format.c
@@ -37,6 +37,7 @@
#include "fat32.h"
#include "file.h"
#include "format.h"
+#include "badblocks.h"
/*
* Globals
@@ -234,7 +235,7 @@ static BOOL WriteMBR(HANDLE hPhysicalDrive)
goto out;
}
- if (!read_sectors(hPhysicalDrive, SelectedDrive.Geometry.BytesPerSector, 0, nSecs, buf, SecSize)) {
+ if (!read_sectors(hPhysicalDrive, SelectedDrive.Geometry.BytesPerSector, 0, nSecs, buf)) {
uprintf("Could not read MBR\n");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_READ_FAULT;
goto out;
@@ -262,7 +263,7 @@ static BOOL WriteMBR(HANDLE hPhysicalDrive)
buf[0x1be] = 0x80; // Set first partition bootable
}
- if (!write_sectors(hPhysicalDrive, SelectedDrive.Geometry.BytesPerSector, 0, nSecs, buf, SecSize*nSecs)) {
+ if (!write_sectors(hPhysicalDrive, SecSize, 0, nSecs, buf)) {
uprintf("Could not write MBR\n");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
goto out;
@@ -318,7 +319,25 @@ void __cdecl FormatThread(void* param)
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
goto out;
}
- // At this stage with have both a handle and a lock to the physical drive
+ // At this stage with have both a handle and a lock to the physical drive...
+
+ if (IsChecked(IDC_BADBLOCKS)) {
+ // ... but we can't write sectors that are part of a volume, even if we have
+ // access to physical, unless we have a lock (which doesn't have to be write)
+ hLogicalVolume = GetDriveHandle(num, drive_name, FALSE, TRUE);
+ if (hLogicalVolume == INVALID_HANDLE_VALUE) {
+ uprintf("Could not lock volume for badblock checks\n");
+ FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
+ goto out;
+ }
+
+ if (BadBlocks(hPhysicalDrive, SelectedDrive.DiskSize, SelectedDrive.Geometry.BytesPerSector)) {
+ // TODO: report block failure number, etc
+ uprintf("Bad blocks check failed.\n");
+ goto out;
+ }
+ safe_unlockclose(hLogicalVolume);
+ }
if (!CreatePartition(hPhysicalDrive)) {
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE;
@@ -359,7 +378,7 @@ void __cdecl FormatThread(void* param)
}
if (IsChecked(IDC_DOS)) {
- // We must have a lock to modify the FS boot record...
+ // We must have a lock to modify the volume boot record...
hLogicalVolume = GetDriveHandle(num, drive_name, TRUE, TRUE);
if (hLogicalVolume == INVALID_HANDLE_VALUE) {
uprintf("Could not re-mount volume for partition boot record access\n");
diff --git a/src/inc/file.h b/src/inc/file.h
index 7bff2107..16f1b2c3 100644
--- a/src/inc/file.h
+++ b/src/inc/file.h
@@ -14,14 +14,14 @@ int contains_data(FILE *fp, size_t ulPosition,
int write_data(FILE *fp, size_t ulPosition,
const void *pData, size_t uiLen);
-/* Checks if a file contains a data pattern of length uiLen at position
- ulPositoin. The file pointer will change when calling this function! */
+/* Writes nSectors of size SectorSize starting at sector StartSector */
int write_sectors(void *hDrive, size_t SectorSize,
size_t StartSector, size_t nSectors,
- const void *pBuf, size_t BufSize);
+ const void *pBuf);
+/* Reads nSectors of size SectorSize starting at sector StartSector */
int read_sectors(void *hDrive, size_t SectorSize,
size_t StartSector, size_t nSectors,
- void *pBuf, size_t BufSize);
+ void *pBuf);
#endif
diff --git a/src/msdos.c b/src/msdos.c
index d75101e9..ed9e43bb 100644
--- a/src/msdos.c
+++ b/src/msdos.c
@@ -288,6 +288,7 @@ BOOL ExtractMSDOS(const char* path)
{
char dllname[MAX_PATH] = "C:\\Windows\\System32";
int i, j;
+ BOOL r = TRUE;
HMODULE hDLL;
HRSRC hDiskImage;
@@ -321,17 +322,17 @@ BOOL ExtractMSDOS(const char* path)
return FALSE;
}
- for (i=0; i
#include
-// http://git.kernel.org/?p=fs/ext2/e2fsprogs.git;a=blob;f=misc/badblocks.c
-// http://thestarman.pcministry.com/asm/mbr/MSWIN41.htm
-// http://sourceforge.net/projects/grub4dos/ (bootable NTFS?)
-
#include "msapi_utf8.h"
#include "resource.h"
#include "rufus.h"
@@ -571,6 +567,7 @@ static void EnableControls(BOOL bEnable)
} else {
EnableWindow(GetDlgItem(hMainDialog, IDC_DOS), FALSE);
}
+ EnableWindow(GetDlgItem(hMainDialog, IDC_BADBLOCKS), bEnable);
EnableWindow(GetDlgItem(hMainDialog, IDC_ABOUT), bEnable);
EnableWindow(GetDlgItem(hMainDialog, IDC_START), bEnable);
SetDlgItemTextA(hMainDialog, IDCANCEL, bEnable?"Close":"Cancel");
diff --git a/src/rufus.rc b/src/rufus.rc
index 2fc58af5..255809c5 100644
--- a/src/rufus.rc
+++ b/src/rufus.rc
@@ -27,14 +27,14 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
// Dialog
//
-IDD_DIALOG DIALOGEX 12, 12, 206, 263
+IDD_DIALOG DIALOGEX 12, 12, 206, 278
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
-CAPTION "Rufus v1.0.1.76"
+CAPTION "Rufus v1.0.2.77"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
- DEFPUSHBUTTON "Start",IDC_START,94,223,50,14
- PUSHBUTTON "Close",IDCANCEL,148,223,50,14
+ DEFPUSHBUTTON "Start",IDC_START,94,236,50,14
+ PUSHBUTTON "Close",IDCANCEL,148,236,50,14
COMBOBOX IDC_DEVICE,8,17,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "&Device",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,9,6,22,8
COMBOBOX IDC_FILESYSTEM,8,75,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
@@ -43,13 +43,15 @@ BEGIN
LTEXT "Ca&pacity",IDC_STATIC,9,35,29,8
COMBOBOX IDC_CLUSTERSIZE,8,104,190,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "&Cluster size",IDC_STATIC,9,93,105,10
- PUSHBUTTON "About...",IDC_ABOUT,8,223,50,14
- GROUPBOX "Format Options",IDC_STATIC,7,149,189,40
+ PUSHBUTTON "About...",IDC_ABOUT,8,236,50,14
+ GROUPBOX "Format Options",IDC_STATIC,7,149,189,52
EDITTEXT IDC_LABEL,7,131,190,13,ES_AUTOHSCROLL
CONTROL "&Quick Format",IDC_QUICKFORMAT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,161,58,10
CONTROL "Create an &MS-DOS startup disk",IDC_DOS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,173,115,10
LTEXT "New volume &label",IDC_STATIC,9,121,105,10
- CONTROL "",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH | WS_BORDER,7,197,189,9
+ CONTROL "",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH | WS_BORDER,7,210,189,9
+ CONTROL "Check device for bad blocks (*ALPHA*)",IDC_BADBLOCKS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,185,171,10
END
IDD_ABOUTBOX DIALOGEX 0, 0, 287, 195
@@ -63,7 +65,7 @@ BEGIN
DEFPUSHBUTTON "OK",IDOK,231,175,50,14,WS_GROUP
CONTROL "https://github.com/pbatard/rufus",IDC_ABOUT_RUFUS_URL,
"SysLink",WS_TABSTOP,46,47,114,9
- LTEXT "Version 1.0.1 (Build 76)",IDC_STATIC,46,19,78,8
+ LTEXT "Version 1.0.2 (Build 77)",IDC_STATIC,46,19,78,8
PUSHBUTTON "License...",IDC_ABOUT_LICENSE,46,175,50,14,WS_GROUP
EDITTEXT IDC_ABOUT_COPYRIGHTS,46,107,235,63,ES_MULTILINE | ES_READONLY | WS_VSCROLL
LTEXT "Report bugs or request enhancements at:",IDC_STATIC,46,66,187,8
@@ -138,7 +140,7 @@ GUIDELINES DESIGNINFO
BEGIN
IDD_DIALOG, DIALOG
BEGIN
- BOTTOMMARGIN, 249
+ BOTTOMMARGIN, 264
END
IDD_ABOUTBOX, DIALOG
@@ -162,8 +164,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,1,76
- PRODUCTVERSION 1,0,1,76
+ FILEVERSION 1,0,2,77
+ PRODUCTVERSION 1,0,2,77
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -180,13 +182,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "akeo.ie"
VALUE "FileDescription", "Rufus"
- VALUE "FileVersion", "1.0.1.76"
+ VALUE "FileVersion", "1.0.2.77"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
- VALUE "ProductVersion", "1.0.1.76"
+ VALUE "ProductVersion", "1.0.2.77"
END
END
BLOCK "VarFileInfo"