由于代码太长了接上面的函数:
int main(int argc, char ** argv)
{
int c;
atexit(cleanup);
while( (c = getopt(argc, argv, "fdi:o:Dvhx")) != -1 )
{
switch(c)
{
case 'x': relaxed = 1; break;
case 'f': dry = 0; break;
case 'd': print_dds = 1; break;
case 'D': do_direct_io = 1; break;
case 'v': verbose++; break;
case 'i': input_filename = strdup(optarg); break;
case 'o': output_filename = strdup(optarg); break;
case 'h': help(); exit(0);
default: help(); exit(1);
} /* switch argument */
} /* while getopt() */
if(!input_filename)
{
fputs("Error: input filename not specified\n\n", stderr);
help();
exit(1);
}
if(!dry && !output_filename)
{
fputs("Error: no dry run and no output filename\n\n", stderr);
help();
exit(1);
}
/* better safe than sorry */
sync();
/* check and open snapshot */
flags = O_RDONLY;
err = stat(input_filename, &st);
if(-1 == err)
{
perror("stat(snapshot)");
exit(1);
}
/* block device; will set O_DIRECT */
if(S_ISBLK(st.st_mode) && do_direct_io)
flags |= O_DIRECT;
inputfd = open(input_filename, flags);
if(-1 == inputfd)
{
perror("open(snapshot)");
exit(1);
}
/* determine size & flush buffers */
if(S_ISBLK(st.st_mode))
{
err = ioctl(inputfd, BLKGETSIZE64, &input_length);
if(-1 == err)
{
perror("ioctl(snapshot, BLKGETSIZE64)");
exit(1);
}
err = ioctl(inputfd, BLKFLSBUF, 0);
if(-1 == err)
{
perror("ioctl(snapshot, BLKFLSBUF)");
if(!relaxed) exit(1);
else fputs("relaxed mode, will continue ...\n", stderr);
}
}
else
input_length = st.st_size;
/* now the same for the output */
if(!dry)
{
flags = O_WRONLY;
err = stat(output_filename, &st);
if(-1 == err)
{
perror("stat(output)");
exit(1);
}
/* block device; will set O_DIRECT */
if(S_ISBLK(st.st_mode) && do_direct_io)
flags |= O_DIRECT;
outputfd = open(output_filename, flags);
if(-1 == outputfd)
{
perror("open(output)");
exit(1);
}
/* determine size & flush buffers */
if(S_ISBLK(st.st_mode))
{
err = ioctl(outputfd, BLKGETSIZE64, &output_length);
if(-1 == err)
{
perror("ioctl(output, BLKGETSIZE64)");
exit(1);
}
err = ioctl(outputfd, BLKFLSBUF, 0);
if(-1 == err)
{
perror("ioctl(output, BLKFLSBUF)");
if(!relaxed) exit(1);
else fputs("relaxed mode, will continue ...\n", stderr);
}
}
else
output_length = st.st_size;
}
/* FIXME perhaps add an override option? */
if(input_length < 4096 || (!dry && output_length < (4 * 1024 * 1024)))
{
fputs("Error: suspicious file/device sizes\n", stderr);
exit(1);
}
/* the allocations; special care for O_DIRECT */
if(do_direct_io)
{
header_orig = malloc(512 + PAGE_SIZE);
if(!header_orig)
{
perror("malloc()");
exit(1);
}
header = (unsigned char *) PAGE_ALIGN((ptrdiff_t) header_orig);
if(verbose)
fprintf(stdout, "header_orig = %p (%lu), header = %p (%lu)\n", header_orig, (unsigned long) header_orig % PAGE_SIZE, header, (unsigned long) header % PAGE_SIZE);
}
else
{
header_orig = header = malloc(512);
if(!header_orig)
{
perror("malloc()");
exit(1);
}
}
/* Not sure if BLKFLSBUF waits for the flushing to finish; better safe than sorry */
fputs("Artificial sleep (1 second)\n", stdout);
sleep(1);
/* FIXME: do retries here as well? */
err = pread(inputfd, header, 512, 0);
if(-1 == err)
{
perror("read(snapshot, header)");
exit(1);
}
magic = (uint32_t *) header;
*magic = __le32_to_cpu(*magic);
if(SNAP_MAGIC != *magic)
{
fputs("Invalid header MAGIC\n", stderr);
fprintf(stderr, "%#x != %#x\n", *magic, SNAP_MAGIC);
exit(1);
}
fprintf(stdout, "Found a proper MAGIC header: %#x\n", *magic);
valid = (uint32_t *) (header+4);
*valid = __le32_to_cpu(*valid);
if(0 == *valid)
{
fputs("valid == 0\n", stderr);
exit(1);
}
fprintf(stdout, "valid = %u\n", *valid);
version = (uint32_t *) (header+8);
*version = __le32_to_cpu(*version);
if(*version != SNAPSHOT_DISK_VERSION)
{
fputs("version != 1\n", stderr);
exit(1);
}
fprintf(stdout, "version = %u\n", *version);
cs = (uint32_t *) (header+12);
*cs = __le32_to_cpu(*cs);
chunk_size = *cs;
if(chunk_size < 1 || chunk_size > 1024 || (0 != (chunk_size & (chunk_size-1))))
{
fputs("chunk size has to be >=1 and <=1024 and a power of 2\n", stderr);
exit(1);
}
fprintf(stdout, "chunk_size = %u (%u bytes)\n", chunk_size, chunk_size*512);
chunk_size *= 512;
/* the allocations; special care for O_DIRECT */
if(do_direct_io)
{
buf_orig = buf = malloc(chunk_size + PAGE_SIZE);
chunk_orig = chunk = malloc(chunk_size + PAGE_SIZE);
if(!buf_orig || !chunk_orig)
{
perror("malloc()");
exit(1);
}
buf = (unsigned char *) PAGE_ALIGN((ptrdiff_t) buf_orig);
if(verbose)
fprintf(stdout, "buf_orig = %p (%lu), buf = %p (%lu)\n", buf_orig, (unsigned long) buf_orig % PAGE_SIZE, buf, (unsigned long) buf % PAGE_SIZE);
chunk = (unsigned char *) PAGE_ALIGN((ptrdiff_t) chunk_orig);
if(verbose)
fprintf(stdout, "chunk_orig = %p (%lu), chunk = %p (%lu)\n", chunk_orig, (unsigned long) chunk_orig % PAGE_SIZE, chunk, (unsigned long) chunk % PAGE_SIZE);
}
else
{
buf_orig = buf = malloc(chunk_size);
chunk_orig = chunk = malloc(chunk_size);
if(!buf_orig || !chunk_orig)
{
perror("malloc()");
exit(1);
}
}
/*
* do the work
*/
do
{
retries=0;
do {
if(0 != retries)
fprintf(stderr, "Warning: retrying pread() on exception area %llu at %llu\n", chunk_now, chunk_now*chunk_size);
err = pread(inputfd, buf, chunk_size, chunk_now*chunk_size);
if(-1 == err)
{
if(EINTR == errno)
continue;
perror("pread(inputfd)");
exit(1);
}
else if(0 == err)
{
fputs("pread(inputfd): early EOF!\n", stderr);
exit(1);
}
else if(err != chunk_size)
{
if(retries++ < 2)
continue;
fputs("pread(inputfd): incomplete read!\n", stderr);
exit(1);
}
break;
} while(1);
/* process the exception area */
for(i=0; i < chunk_size/16; i++)
{
temp_u64 = (uint64_t *)(buf+(i*16));
de.old_chunk = __le64_to_cpu(*temp_u64);
temp_u64 = (uint64_t *)(buf+(i*16)+8);
de.new_chunk = __le64_to_cpu(*temp_u64);
if(verbose >= 2)
fprintf(stdout, "... chunk_now = %llu, i = %u, de.old_chunk = %llu, de.new_chunk = %llu, old %p, new %p\n", chunk_now, i, de.old_chunk, de.new_chunk, buf+(i*16), buf+(i*16)+8);
/* 0 as a new chunk means "we've reached the end" */
if(0 == de.new_chunk)
{
go = 0;
break;
}
else if((1 == chunk_now && 0 == i && de.new_chunk != 2) || (de.new_chunk < 2))
{
fputs("(1 == chunk_now && 0 == i && de.new_chunk != 2) || (de.new_chunk < 2), perhaps not a snapshot?\n", stderr);
exit(1);
}
total_count++;
/* the data transfer */
read_write_chunk();
} /* for i */
/* next hop */
chunk_now += chunk_size/16 + 1;
if(verbose && go)
fprintf(stdout, "Seeking into exception area in chunk %llu\n", chunk_now);
} while(go);
/* flush buffers again (no error handling this time as there's nothing to do anyway) */
if(S_ISBLK(st.st_mode)) err = ioctl(outputfd, BLKFLSBUF, 0);
/* better safe than sorry */
sync();
fprintf(stdout, "Found %llu exceptions of chunksize %u, total size %llu bytes (%llu KiB, %.3Lf MiB, %.3Lf GiB).\n", total_count, chunk_size, total_count*chunk_size, (total_count*chunk_size)/1024, ((long double)(total_count*chunk_size))/(1024*1024), ((long double)(total_count*chunk_size))/(1024*1024*1024));
close(inputfd);
if(-1 != outputfd) close(outputfd);
memset(buf, 0, chunk_size);
memset(chunk, 0, chunk_size);
/* cleanup() will do the rest */
return 0;
} /* main() */
[/code]
谢谢