File: img_io.c

package info (click to toggle)
sleuthkit 3.2.3-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 9,624 kB
  • sloc: ansic: 104,268; sh: 9,445; cpp: 7,793; makefile: 256
file content (157 lines) | stat: -rw-r--r-- 5,149 bytes parent folder | download | duplicates (2)
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;
}