diff --git a/tsk/img/raw.c b/tsk/img/raw.c index 861e1ff8db7334336c306e60e40aab344fb1b2d0..daf19babeb0bc585a65f564ddbcc37bb304dec6a 100755 --- a/tsk/img/raw.c +++ b/tsk/img/raw.c @@ -39,6 +39,17 @@ #define S_IFDIR __S_IFDIR #endif +/** + * \internal + * Test if the image is a Windows device + * @param The path to test + * + * Return 1 if the path represents a Windows device, 0 otherwise + */ +static int +is_windows_device_path(const TSK_TCHAR * image_name) { + return (TSTRNCMP(image_name, _TSK_T("\\\\.\\"), 4) == 0); +} /** * \internal @@ -133,7 +144,7 @@ raw_read_segment(IMG_RAW_INFO * raw_info, int idx, char *buf, // If the offset to seek to isn't sector-aligned and this is a device, we need to start at the previous sector boundary and // read some extra data. if ((offset_to_read % raw_info->img_info.sector_size != 0) - && (TSTRNCMP(raw_info->img_info.images[idx], _TSK_T("\\\\.\\"), 4) == 0)) { + && is_windows_device_path(raw_info->img_info.images[idx])) { offset_to_read = (offset_to_read / raw_info->img_info.sector_size) * raw_info->img_info.sector_size; len_to_read += raw_info->img_info.sector_size; // this length will already be a multiple of sector size sector_aligned_buf = (char *)tsk_malloc(len_to_read); @@ -630,6 +641,119 @@ get_size(const TSK_TCHAR * a_file, uint8_t a_is_winobj) return size; } +#ifdef TSK_WIN32 +/** +* \internal +* Test seeking to the given offset and then reading a sector. +* @param file_handle The open file handle to the image +* @param offset The offset to seek to (in bytes) +* @param len The length to read (in bytes). Should be a multiple of the sector size. +* @param buf An allocated buffer large enough to hold len bytes +* +* @return 1 if the seek/read is successful, 0 if not +*/ +static int +test_sector_read(HANDLE file_handle, TSK_OFF_T offset, DWORD len, char * buf) { + LARGE_INTEGER li; + li.QuadPart = offset; + + // Seek to the given offset + li.LowPart = SetFilePointer(file_handle, li.LowPart, + &li.HighPart, FILE_BEGIN); + if ((li.LowPart == INVALID_SET_FILE_POINTER) && + (GetLastError() != NO_ERROR)) { + return 0; + } + + // Read a byte at the given offset + DWORD nread; + if (FALSE == ReadFile(file_handle, buf, len, &nread, NULL)) { + return 0; + } + if (nread != len) { + return 0; + } + + // Success + return 1; +} + +/** + * Attempts to calculate the actual sector size needed for reading the image. + * If successful, the calculated sector size will be stored in raw_info. If it + * fails the sector_size field will not be updated. + * @param raw_info The incomplete IMG_RAW_INFO object. The sector_size field may be updated by this method. + * @param image_name Image file name + * @param image_size Image size +*/ +static void +set_device_sector_size(IMG_RAW_INFO * raw_info, const TSK_TCHAR * image_name, TSK_OFF_T image_size) { + unsigned int min_sector_size = 512; + unsigned int max_sector_size = 4096; + + HANDLE file_handle = CreateFile(image_name, FILE_READ_DATA, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, + NULL); + if (file_handle == INVALID_HANDLE_VALUE) { + if (tsk_verbose) { + tsk_fprintf(stderr, + "find_sector_size: failed to open image \"%" PRIttocTSK "\"\n", image_name); + } + return; + } + + // First test whether we need to align on sector boundaries + char* buf = malloc(max_sector_size); + int needs_sector_alignment = 0; + if (image_size > raw_info->img_info.sector_size) { + if (test_sector_read(file_handle, 1, raw_info->img_info.sector_size, buf)) { + needs_sector_alignment = 0; + } + else { + needs_sector_alignment = 1; + } + } + + // If reading a sector starting at offset 1 failed, the assumption is that we have a device + // that requires reads to be sector-aligned. + if (needs_sector_alignment) { + // Start at the minimum (512) and double up to max_sector_size (4096) + unsigned int sector_size = min_sector_size; + + while (sector_size <= max_sector_size) { + // If we don't have enough data to do the test just stop + if (image_size < sector_size * 2) { + break; + } + + if (test_sector_read(file_handle, sector_size, sector_size, buf)) { + // Found a valid sector size + if (tsk_verbose) { + tsk_fprintf(stderr, + "find_sector_size: using sector size %d\n", sector_size); + } + raw_info->img_info.sector_size = sector_size; + + if (file_handle != 0) { + CloseHandle(file_handle); + } + free(buf); + return; + } + sector_size *= 2; + } + if (tsk_verbose) { + tsk_fprintf(stderr, + "find_sector_size: failed to determine correct sector size. Reverting to default %d\n", raw_info->img_info.sector_size); + } + free(buf); + } + + if (file_handle != 0) { + CloseHandle(file_handle); + } +} +#endif /** * \internal @@ -661,9 +785,6 @@ raw_open(int a_num_img, const TSK_TCHAR * const a_images[], img_info->close = raw_close; img_info->imgstat = raw_imgstat; - img_info->sector_size = 512; - if (a_ssize) - img_info->sector_size = a_ssize; raw_info->is_winobj = 0; #if defined(TSK_WIN32) || defined(__CYGWIN__) @@ -683,6 +804,20 @@ raw_open(int a_num_img, const TSK_TCHAR * const a_images[], return NULL; } + /* Set the sector size */ + img_info->sector_size = 512; + if (a_ssize) { + img_info->sector_size = a_ssize; + } +#ifdef TSK_WIN32 + else if (is_windows_device_path(a_images[0])) { + /* On Windows, figure out the actual sector size if one was not given and this is a device. + * This is to prevent problems reading later. */ + set_device_sector_size(raw_info, a_images[0], first_seg_size); + } +#endif + + /* see if there are more of them... */ if ((a_num_img == 1) && (raw_info->is_winobj == 0)) { if ((raw_info->img_info.images =