1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
/*
* Brian Carrier [carrier <at> sleuthkit [dot] org]
* Copyright (c) 2008 Brian Carrier. All Rights reserved
*
* This software is distributed under the Common Public License 1.0
*/
/**
* \file img_io.c
* Contains the basic img reading API redirection functions.
*/
#include "tsk_img_i.h"
/**
* \ingroup imglib
* Reads data from an open disk image
* @param a_img_info Disk image to read from
* @param a_off Byte offset to start reading from
* @param a_buf Buffer to read into
* @param a_len Number of bytes to read into buffer
* @returns -1 on error or number of bytes read
*/
ssize_t
tsk_img_read(TSK_IMG_INFO * a_img_info, TSK_OFF_T a_off,
char *a_buf, size_t a_len)
{
#define CACHE_AGE 1000
ssize_t retval = 0;
int i;
int cache_next = 0; // index to lowest age cache (to use next)
size_t len2;
if (a_img_info == NULL) {
tsk_error_reset();
tsk_errno = TSK_ERR_IMG_ARG;
snprintf(tsk_errstr, TSK_ERRSTR_L,
"tsk_img_read: pointer is NULL");
return -1;
}
// if they ask for more than the cache length, skip the cache
if (a_len > TSK_IMG_INFO_CACHE_LEN) {
return a_img_info->read(a_img_info, a_off, a_buf, a_len);
}
if (a_off >= a_img_info->size) {
tsk_error_reset();
tsk_errno = TSK_ERR_IMG_READ_OFF;
snprintf(tsk_errstr, TSK_ERRSTR_L, "tsk_img_read - %" PRIuOFF,
a_off);
return -1;
}
/* See if the requested length is going to be too long.
* we'll use this length when checking the cache. */
len2 = a_len;
if (a_off + len2 > a_img_info->size)
len2 = (size_t) (a_img_info->size - a_off);
// check if it is in the cache
for (i = 0; i < TSK_IMG_INFO_CACHE_NUM; i++) {
// Look into the in-use cache entries
if (a_img_info->cache_len[i] > 0) {
// the retval check makes sure we don't go back in after data was read
if ((retval == 0) && (a_img_info->cache_off[i] <= a_off) &&
(a_img_info->cache_off[i] + a_img_info->cache_len[i] >=
a_off + len2)) {
/*
if (tsk_verbose)
fprintf(stderr,
"tsk_img_read: Read found in cache %d\n", i);
*/
// We found it...
memcpy(a_buf,
&a_img_info->cache[i][a_off -
a_img_info->cache_off[i]], len2);
retval = (ssize_t) len2;
// reset its "age" since it was useful
a_img_info->cache_age[i] = CACHE_AGE;
// we don't break out of the loop so that we update all ages
}
else {
/* decrease its "age" since it was not useful.
* We don't let used ones go below 1 so that they are not
* confused with entries that have never been used. */
a_img_info->cache_age[i]--;
// see if this is the most eligible replacement
if ((a_img_info->cache_len[cache_next] > 0)
&& (a_img_info->cache_age[i] <
a_img_info->cache_age[cache_next]))
cache_next = i;
}
}
else {
cache_next = i;
}
}
// if we didn't find it, then load it into the cache_next entry
if (retval == 0) {
size_t rlen;
// round the offset down to a sector boundary
a_img_info->cache_off[cache_next] = (a_off / 512) * 512;
/*
if (tsk_verbose)
fprintf(stderr,
"tsk_img_read: Loading data into cache %d (%" PRIuOFF
")\n", cache_next, a_img_info->cache_off[cache_next]);
*/
// figure out the length to read into the cache
rlen = TSK_IMG_INFO_CACHE_LEN;
if (a_img_info->cache_off[cache_next] + rlen > a_img_info->size) {
rlen =
(size_t) (a_img_info->size -
a_img_info->cache_off[cache_next]);
}
retval =
a_img_info->read(a_img_info, a_img_info->cache_off[cache_next],
a_img_info->cache[cache_next], rlen);
// if no error, then set the variables and copy the data
if (retval != -1) {
a_img_info->cache_age[cache_next] = CACHE_AGE;
a_img_info->cache_len[cache_next] = retval;
// update the length we can actually copy (in case we did not get to read all that we wanted)
if (a_off + len2 > a_img_info->cache_off[cache_next] + retval)
len2 =
(size_t) (a_img_info->cache_off[cache_next] + retval -
a_off);
memcpy(a_buf,
&a_img_info->cache[cache_next][a_off -
a_img_info->cache_off[cache_next]], len2);
retval = (ssize_t) len2;
}
else {
a_img_info->cache_len[cache_next] = 0;
a_img_info->cache_age[cache_next] = 0;
a_img_info->cache_off[cache_next] = 0;
}
}
return retval;
}
|