static int src_fd=-1,dst_fd=-1;
static const char *src_name,*dst_name;
-static ext2_loff_t src_len; /* in blocks! */
-static blk_t src_lenblk; /* ==src_len, just a different type */
+static ext2_loff_t src_len,dst_len; /* in blocks! */
+static blk_t src_lenblk,dst_lenblk; /* ==src_len,==dst_len, just a different type */
static ext2_loff_t stat_lastread,stat_todo,stat_bads,stat_largest,stat_todo_hunks;
exit(EXIT_FAILURE);
}
if (len!=(gotssize=write(dst_fd,buf,len))) {
+ /* see README/"Linux kernel flaw" */
+ /* no "start==src_len-1" checking here, we may write larger blocks! */
+ if (gotssize==((src_len&~1)-start)*BLOCK
+ /* -1 instead of 0 is given when no bytes were written */
+ || (gotssize==-1 && start==src_len-1 && end==src_len))
+ return; /* suppress error message */
+
fprintf(stderr,"write(\"%s\",@%llu-@%llu=%llu=%lluB)=%lld: %m\n",dst_name,
(unsigned long long)start,
(unsigned long long)end,
}
}
+static void range_zero(ext2_loff_t start,ext2_loff_t end)
+{
+static const unsigned char buf_zero[BUF_ZERO_BLOCKS*BLOCK];
+
+ g_return_if_fail(start<end);
+
+ while (start<end) {
+ ext2_loff_t mid=((end-start)>BUF_ZERO_BLOCKS ? start+BUF_ZERO_BLOCKS : end);
+ g_assert(mid>=start);
+ g_assert(mid<=end);
+
+ write_dst(start,mid,buf_zero);
+
+ start=mid;
+ }
+}
+
static void process(ext2_loff_t start,ext2_loff_t end)
{
unsigned char block_buf[BLOCK];
ext2_loff_t bads;
ext2_loff_t gotext2_loff;
+ssize_t gotssize;
g_return_if_fail(start<end);
g_return_if_fail(end<=src_len);
exit(EXIT_FAILURE);
}
stat_todo--; /* for the forthcoming read() */
- if (!simulate_bads && sizeof(block_buf)==read(src_fd,block_buf,sizeof(block_buf))) {
+ if (!simulate_bads && (sizeof(block_buf)==(gotssize=read(src_fd,block_buf,sizeof(block_buf)))
+ /* see README/"Linux kernel flaw" */
+ || (start==src_len-1 && gotssize==((src_len&~1)-start)*BLOCK))
+ ) {
/* success read */
- write_dst(start,start+1,block_buf);
+ if (gotssize==sizeof(block_buf))
+ write_dst(start,start+1,block_buf);
+ else {
+ /* handle README/"Linux kernel flaw" */
+ fprintf(stderr,"WARNING: Ignored disk-last sector read failure; see README/\"Linux kernel flaw\"\n");
+ range_zero(start,start+1);
+ }
start++;
if (start>=end) /* finished */
return;
}
}
-static void range_zero(ext2_loff_t start,ext2_loff_t end)
-{
-static const unsigned char buf_zero[BUF_ZERO_BLOCKS*BLOCK];
-
- g_return_if_fail(start<end);
-
- while (start<end) {
- ext2_loff_t mid=((end-start)>BUF_ZERO_BLOCKS ? start+BUF_ZERO_BLOCKS : end);
- g_assert(mid>=start);
- g_assert(mid<=end);
-
- write_dst(start,mid,buf_zero);
-
- start=mid;
- }
-}
-
static void finish(void)
{
struct range *todo_linear=tree_linearize(todo_tree),*todol;
fprintf(stderr,"\"%s\" length %llu <=0\n",src_name,(unsigned long long)src_len);
exit(EXIT_FAILURE);
}
+ if (dst_fd!=-1) {
+ if (ext2fs_get_device_size(dst_name,BLOCK,&dst_lenblk)) {
+ fprintf(stderr,"ext2fs_get_device_size(\"%s\",%d,...): %m\n",dst_name,BLOCK);
+ exit(EXIT_FAILURE);
+ }
+ dst_len=dst_lenblk;
+ if (dst_len<=0) {
+ fprintf(stderr,"\"%s\" length %llu <=0\n",dst_name,(unsigned long long)dst_len);
+ exit(EXIT_FAILURE);
+ }
+ if (dst_len<src_len) {
+ fprintf(stderr,"WARNING: Ignoring exceeding trailing data of \"%s\" from %llu up to its end %llu!\n",
+ src_name,(unsigned long long)dst_len,(unsigned long long)src_len);
+ src_len=dst_len;
+ src_lenblk=dst_lenblk;
+ }
+ }
node_memchunk=g_mem_chunk_new("node_memchunk",sizeof(struct range)/*atom_size*/,
0x1000 /*are_size: 64KB*/,G_ALLOC_AND_FREE);