/* File: dimage.c Copyright (C) 2007-2009 Christophe GRENIER 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 #endif #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #include #include #include #include #if defined(__FRAMAC__) #include "__fc_builtin.h" #endif #include "types.h" #include "common.h" #include "intrf.h" #include "intrfn.h" #include "log.h" #include "dimage.h" #define READ_SIZE 256*512 /* Skip 10Mb when there is a read error */ #define SKIP_SIZE 10*1024*1024 #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif #ifndef O_BINARY #define O_BINARY 0 #endif static void disk_image_backward(int disk_dst, disk_t *disk, const uint64_t src_offset_start, const uint64_t src_offset_end, uint64_t dst_offset) { uint64_t src_offset; unsigned char *buffer=(unsigned char *)MALLOC(disk->sector_size); for(src_offset=src_offset_end-disk->sector_size; src_offset > src_offset_start; src_offset-=disk->sector_size, dst_offset-=disk->sector_size) { const ssize_t pread_res=disk->pread(disk, buffer, disk->sector_size, src_offset); if((unsigned)pread_res != disk->sector_size) { free(buffer); return; } #if defined(HAVE_PWRITE) if(pwrite(disk_dst, buffer, pread_res, src_offset)<0) { free(buffer); return; } #else if(lseek(disk_dst, src_offset, SEEK_SET)<0) { free(buffer); return; } if(write(disk_dst, buffer, pread_res) != pread_res) { free(buffer); return; } #endif } free(buffer); } int disk_image(disk_t *disk, const partition_t *partition, const char *image_dd) { int ind_stop=0; uint64_t nbr_read_error=0; uint64_t src_offset=partition->part_offset; uint64_t src_offset_old; uint64_t dst_offset=0; const uint64_t src_offset_end=partition->part_offset+partition->part_size; const uint64_t offset_inc=(src_offset_end-src_offset)/10000; uint64_t src_offset_next=src_offset; struct stat stat_buf; unsigned char *buffer=(unsigned char *)MALLOC(READ_SIZE); unsigned int readsize=READ_SIZE; int disk_dst; #ifdef HAVE_PWRITE int use_pwrite=1; #endif #ifdef HAVE_NCURSES WINDOW *window; #endif assert(disk->sector_size > 0); assert(disk->sector_size <= READ_SIZE); if((disk_dst=open(image_dd, O_CREAT|O_LARGEFILE|O_RDWR|O_BINARY, 0644)) < 0) { log_error("Can't create file %s.\n",image_dd); display_message("Can't create file!\n"); free(buffer); return -1; } #if !defined(DISABLED_FOR_FRAMAC) if(fstat(disk_dst, &stat_buf)==0) { int res=1; #ifdef HAVE_NCURSES if(stat_buf.st_size > 0) res=ask_confirmation("Append to existing file ? (Y/N)"); #endif if(res>0) { dst_offset=stat_buf.st_size; src_offset+=dst_offset; } } #endif src_offset_old=src_offset; #ifdef HAVE_NCURSES window=newwin(LINES, COLS, 0, 0); /* full screen */ aff_copy(window); wmove(window,5,0); wprintw(window,"%s\n",disk->description_short(disk)); wmove(window,6,0); aff_part(window,AFF_PART_ORDER|AFF_PART_STATUS,disk,partition); wmove(window,10,0); waddstr(window, "Disk images are mainly used "); wmove(window,11,0); waddstr(window, "- for forensic purposes"); wmove(window,12,0); waddstr(window, "- or to deal with media with bad sectors"); #ifdef WIN32 wmove(window,14,0); waddstr(window, "To use TestDisk or PhotoRec with this disk image, go in command line and run"); wmove(window,15,0); waddstr(window, " testdisk_win.exe image.dd"); wmove(window,16,0); waddstr(window, "or photorec_win.exe image.dd"); #else wmove(window,14,0); waddstr(window, "To use TestDisk or PhotoRec with this disk image, start a Terminal and run"); wmove(window,15,0); waddstr(window, " testdisk image.dd"); wmove(window,16,0); waddstr(window, "or photorec image.dd"); #endif wmove(window,22,0); wattrset(window, A_REVERSE); waddstr(window," Stop "); wattroff(window, A_REVERSE); #endif while(ind_stop==0 && src_offset < src_offset_end) { ssize_t pread_res; int update=0; if(src_offset_end-src_offset < readsize) readsize=src_offset_end-src_offset; pread_res=disk->pread(disk, buffer, readsize, src_offset); if(pread_res > 0) { #if defined(HAVE_PWRITE) if(use_pwrite>0 && pwrite(disk_dst, buffer, pread_res, dst_offset)<0) #endif { #ifdef HAVE_PWRITE use_pwrite=0; #endif if(lseek(disk_dst, dst_offset, SEEK_SET)<0) { ind_stop=2; log_critical("disk_image lseek() failed: %s\n",strerror(errno)); } else if(write(disk_dst, buffer, pread_res) != pread_res) { log_critical("disk_image write() failed: %s\n",strerror(errno)); ind_stop=2; } } if(src_offset_old + SKIP_SIZE==src_offset) { disk_image_backward(disk_dst, disk, src_offset_old, src_offset, dst_offset); } } src_offset_old=src_offset; if((unsigned)pread_res == readsize) { src_offset+=readsize; dst_offset+=readsize; readsize=READ_SIZE; } else { update=1; nbr_read_error++; readsize=disk->sector_size; src_offset+=SKIP_SIZE; dst_offset+=SKIP_SIZE; } if(src_offset>src_offset_next) { update=1; src_offset_next=src_offset+offset_inc; } if(update && ind_stop==0) { #ifdef HAVE_NCURSES unsigned int i; const float percent=(src_offset-partition->part_offset)*100.00/partition->part_size; wmove(window,7,0); wprintw(window,"%3.2f %% ", percent); for(i=0;i"); wrefresh(window); ind_stop=check_enter_key_or_s(window); #endif } } close(disk_dst); #ifdef HAVE_NCURSES delwin(window); (void) clearok(stdscr, TRUE); #ifdef HAVE_TOUCHWIN touchwin(stdscr); #endif #endif if(ind_stop==2) { display_message("No space left for the file image.\n"); free(buffer); return -2; } if(ind_stop) { if(nbr_read_error==0) display_message("Incomplete image created.\n"); else display_message("Incomplete image created: read errors have occured.\n"); free(buffer); return 0; } if(nbr_read_error==0) display_message("Image created successfully.\n"); else display_message("Image created successfully but read errors have occured.\n"); free(buffer); return 0; }