File: fs_block.c

package info (click to toggle)
sleuthkit 4.12.1%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 18,608 kB
  • sloc: ansic: 143,795; cpp: 52,225; java: 37,892; xml: 2,416; python: 1,076; perl: 874; makefile: 439; sh: 184
file content (207 lines) | stat: -rw-r--r-- 6,297 bytes parent folder | download | duplicates (5)
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*
 * The Sleuth Kit
 *
 * Brian Carrier [carrier <at> sleuthkit [dot] org]
 * Copyright (c) 2008-2011 Brian Carrier, Basis Technology.  All Rights reserved
 *
 * This software is distributed under the Common Public License 1.0
 */

/** \file fs_block.c
 * Contains functions to allocate, free, and read data into a TSK_FS_BLOCK structure. 
 */

#include <errno.h>
#include "tsk_fs_i.h"

/**
 * \internal
 * Allocate a TSK_FS_BLOCK structure.  
 * @param a_fs File system to create block for
 * @returns NULL on error
 */
TSK_FS_BLOCK *
tsk_fs_block_alloc(TSK_FS_INFO * a_fs)
{
    TSK_FS_BLOCK *fs_block;

    fs_block = (TSK_FS_BLOCK *) tsk_malloc(sizeof(TSK_FS_BLOCK));
    if (fs_block == NULL)
        return NULL;

    fs_block->buf = (char *) tsk_malloc(a_fs->block_size);
    if (fs_block->buf == NULL) {
        free(fs_block);
        return NULL;
    }
    fs_block->tag = TSK_FS_BLOCK_TAG;
    fs_block->addr = 0;
    fs_block->flags = 0;
    fs_block->fs_info = a_fs;

    return fs_block;
}

/**
 * \ingroup fslib
 * Free the memory associated with the TSK_FS_BLOCK structure. 
 * @param a_fs_block Block to free
 */
void
tsk_fs_block_free(TSK_FS_BLOCK * a_fs_block)
{
    free(a_fs_block->buf);
    a_fs_block->tag = 0;
    free(a_fs_block);
}



TSK_FS_BLOCK *
tsk_fs_block_get(TSK_FS_INFO * a_fs, TSK_FS_BLOCK * a_fs_block,
    TSK_DADDR_T a_addr)
{
    return tsk_fs_block_get_flag(a_fs, a_fs_block, a_addr,
        a_fs->block_getflags(a_fs, a_addr));
}

/**
 * \ingroup fslib
 * Get the contents and flags of a specific file system block. Note that if the block contains
 * compressed data, then this function will return the compressed data with the RAW flag set. 
 * The uncompressed data can be obtained only from the file-level functions.
 *
 * @param a_fs The file system to read the block from.
 * @param a_fs_block The structure to write the block data into or NULL to have one created.
 * @param a_addr The file system address to read.
 * @param a_flags Flag to assign to the returned TSK_FS_BLOCK (use if you already have it as part of a block_walk-type scenario)
 * @return The TSK_FS_BLOCK with the data or NULL on error.  (If a_fs_block was not NULL, this will
 * be the same structure). 
 */
TSK_FS_BLOCK *
tsk_fs_block_get_flag(TSK_FS_INFO * a_fs, TSK_FS_BLOCK * a_fs_block,
    TSK_DADDR_T a_addr, TSK_FS_BLOCK_FLAG_ENUM a_flags)
{
    TSK_OFF_T offs;
    size_t len;

    if (a_fs == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_READ);
        tsk_error_set_errstr("tsk_fs_block_get: fs unallocated");
        return NULL;
    }
    if (a_fs_block == NULL) {
        a_fs_block = tsk_fs_block_alloc(a_fs);
    }
    else if ((a_fs_block->tag != TSK_FS_BLOCK_TAG)
        || (a_fs_block->buf == NULL)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_READ);
        tsk_error_set_errstr("tsk_fs_block_get: fs_block unallocated");
        return NULL;
    }

    len = a_fs->block_size;

    if (a_addr > a_fs->last_block_act) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_READ);
        if (a_addr <= a_fs->last_block)
            tsk_error_set_errstr
                ("tsk_fs_block_get: Address missing in partial image: %"
                PRIuDADDR ")", a_addr);
        else
            tsk_error_set_errstr
                ("tsk_fs_block_get: Address is too large for image: %"
                PRIuDADDR ")", a_addr);
        return NULL;
    }

    a_fs_block->fs_info = a_fs;
    a_fs_block->addr = a_addr;
    a_fs_block->flags = a_flags;
    a_fs_block->flags |= TSK_FS_BLOCK_FLAG_RAW;
    offs = (TSK_OFF_T) a_addr *a_fs->block_size;

    if ((a_fs_block->flags & TSK_FS_BLOCK_FLAG_AONLY) == 0) {
        ssize_t cnt;
        cnt =
            tsk_img_read(a_fs->img_info, a_fs->offset + offs,
            a_fs_block->buf, len);
        if (cnt != (ssize_t)len) {
            return NULL;
        }
    }
    return a_fs_block;
}



/**
 * \internal
 * Set the fields of a FS_BLOCk structure.  This is internally used to set the data from a 
 * larger buffer so that larger disk reads can occur. 
 *
 * @param a_fs File system
 * @param a_fs_block Block to load data into
 * @param a_addr Address where data is from
 * @param a_flags Flags for data
 * @param a_buf Buffer to copy data from  and into a_fs_block (block_size will be copied)
 * @returns 1 on error, 0 on success
 */
int
tsk_fs_block_set(TSK_FS_INFO * a_fs, TSK_FS_BLOCK * a_fs_block,
    TSK_DADDR_T a_addr, TSK_FS_BLOCK_FLAG_ENUM a_flags, char *a_buf)
{
    if ((a_fs == NULL) || (a_fs->tag != TSK_FS_INFO_TAG)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_READ);
        tsk_error_set_errstr("tsk_fs_block_set: fs_info unallocated");
        return 1;
    }
    if ((a_fs_block->tag != TSK_FS_BLOCK_TAG) || (a_fs_block->buf == NULL)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_READ);
        tsk_error_set_errstr("tsk_fs_block_set: fs_block unallocated");
        return 1;
    }
    a_fs_block->fs_info = a_fs;
    if ((a_flags & TSK_FS_BLOCK_FLAG_AONLY) == 0)
        memcpy(a_fs_block->buf, a_buf, a_fs->block_size);
    a_fs_block->addr = a_addr;
    a_fs_block->flags = a_flags;
    return 0;
}


/** 
 * \ingroup fslib
 *
 * Cycle through a range of file system blocks and call the callback function
 * with the contents and allocation status of each. 
 *
 * @param a_fs File system to analyze
 * @param a_start_blk Block address to start walking from
 * @param a_end_blk Block address to walk to
 * @param a_flags Flags used during walk to determine which blocks to call callback with
 * @param a_action Callback function
 * @param a_ptr Pointer that will be passed to callback
 * @returns 1 on error and 0 on success
 */
uint8_t
tsk_fs_block_walk(TSK_FS_INFO * a_fs,
    TSK_DADDR_T a_start_blk, TSK_DADDR_T a_end_blk,
    TSK_FS_BLOCK_WALK_FLAG_ENUM a_flags, TSK_FS_BLOCK_WALK_CB a_action,
    void *a_ptr)
{
    if ((a_fs == NULL) || (a_fs->tag != TSK_FS_INFO_TAG)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("tsk_fs_block_walk: FS_INFO structure is not allocated");
        return 1;
    }
    return a_fs->block_walk(a_fs, a_start_blk, a_end_blk, a_flags,
        a_action, a_ptr);
}