Coverage Report

Created: 2025-10-12 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sleuthkit/tsk/fs/fs_block.c
Line
Count
Source
1
/*
2
 * The Sleuth Kit
3
 *
4
 * Brian Carrier [carrier <at> sleuthkit [dot] org]
5
 * Copyright (c) 2008-2011 Brian Carrier, Basis Technology.  All Rights reserved
6
 *
7
 * This software is distributed under the Common Public License 1.0
8
 */
9
10
/** \file fs_block.c
11
 * Contains functions to allocate, free, and read data into a TSK_FS_BLOCK structure.
12
 */
13
14
#include <errno.h>
15
#include "tsk_fs_i.h"
16
17
/**
18
 * \internal
19
 * Allocate a TSK_FS_BLOCK structure.
20
 * @param a_fs File system to create block for
21
 * @returns NULL on error
22
 */
23
TSK_FS_BLOCK *
24
tsk_fs_block_alloc(TSK_FS_INFO * a_fs)
25
0
{
26
0
    TSK_FS_BLOCK *fs_block;
27
28
0
    fs_block = (TSK_FS_BLOCK *) tsk_malloc(sizeof(TSK_FS_BLOCK));
29
0
    if (fs_block == NULL)
30
0
        return NULL;
31
32
0
    fs_block->buf = (char *) tsk_malloc(a_fs->block_size);
33
0
    if (fs_block->buf == NULL) {
34
0
        free(fs_block);
35
0
        return NULL;
36
0
    }
37
0
    fs_block->tag = TSK_FS_BLOCK_TAG;
38
0
    fs_block->addr = 0;
39
0
    fs_block->flags = 0;
40
0
    fs_block->fs_info = a_fs;
41
42
0
    return fs_block;
43
0
}
44
45
/**
46
 * \ingroup fslib
47
 * Free the memory associated with the TSK_FS_BLOCK structure.
48
 * @param a_fs_block Block to free
49
 */
50
void
51
tsk_fs_block_free(TSK_FS_BLOCK * a_fs_block)
52
0
{
53
0
    free(a_fs_block->buf);
54
0
    a_fs_block->tag = 0;
55
0
    free(a_fs_block);
56
0
}
57
58
59
60
TSK_FS_BLOCK *
61
tsk_fs_block_get(TSK_FS_INFO * a_fs, TSK_FS_BLOCK * a_fs_block,
62
    TSK_DADDR_T a_addr)
63
0
{
64
0
    return tsk_fs_block_get_flag(a_fs, a_fs_block, a_addr,
65
0
        a_fs->block_getflags(a_fs, a_addr));
66
0
}
67
68
/**
69
 * \ingroup fslib
70
 * Get the contents and flags of a specific file system block. Note that if the block contains
71
 * compressed data, then this function will return the compressed data with the RAW flag set.
72
 * The uncompressed data can be obtained only from the file-level functions.
73
 *
74
 * @param a_fs The file system to read the block from.
75
 * @param a_fs_block The structure to write the block data into or NULL to have one created.
76
 * @param a_addr The file system address to read.
77
 * @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)
78
 * @return The TSK_FS_BLOCK with the data or NULL on error.  (If a_fs_block was not NULL, this will
79
 * be the same structure).
80
 */
81
TSK_FS_BLOCK *
82
tsk_fs_block_get_flag(TSK_FS_INFO * a_fs, TSK_FS_BLOCK * a_fs_block,
83
    TSK_DADDR_T a_addr, TSK_FS_BLOCK_FLAG_ENUM a_flags)
84
0
{
85
0
    TSK_OFF_T offs;
86
0
    size_t len;
87
88
0
    if (a_fs == NULL) {
89
0
        tsk_error_reset();
90
0
        tsk_error_set_errno(TSK_ERR_FS_READ);
91
0
        tsk_error_set_errstr("tsk_fs_block_get: fs unallocated");
92
0
        return NULL;
93
0
    }
94
0
    if (a_fs_block == NULL) {
95
0
        a_fs_block = tsk_fs_block_alloc(a_fs);
96
0
    }
97
0
    else if ((a_fs_block->tag != TSK_FS_BLOCK_TAG)
98
0
        || (a_fs_block->buf == NULL)) {
99
0
        tsk_error_reset();
100
0
        tsk_error_set_errno(TSK_ERR_FS_READ);
101
0
        tsk_error_set_errstr("tsk_fs_block_get: fs_block unallocated");
102
0
        return NULL;
103
0
    }
104
105
0
    len = a_fs->block_size;
106
107
0
    if (a_addr > a_fs->last_block_act) {
108
0
        tsk_error_reset();
109
0
        tsk_error_set_errno(TSK_ERR_FS_READ);
110
0
        if (a_addr <= a_fs->last_block)
111
0
            tsk_error_set_errstr
112
0
                ("tsk_fs_block_get: Address missing in partial image: %"
113
0
                PRIuDADDR ")", a_addr);
114
0
        else
115
0
            tsk_error_set_errstr
116
0
                ("tsk_fs_block_get: Address is too large for image: %"
117
0
                PRIuDADDR ")", a_addr);
118
0
        return NULL;
119
0
    }
120
121
0
    a_fs_block->fs_info = a_fs;
122
0
    a_fs_block->addr = a_addr;
123
0
    a_fs_block->flags = a_flags;
124
0
    a_fs_block->flags |= TSK_FS_BLOCK_FLAG_RAW;
125
0
    offs = (TSK_OFF_T) a_addr *a_fs->block_size;
126
127
0
    if ((a_fs_block->flags & TSK_FS_BLOCK_FLAG_AONLY) == 0) {
128
0
        ssize_t cnt;
129
0
        cnt =
130
0
            tsk_img_read(a_fs->img_info, a_fs->offset + offs,
131
0
            a_fs_block->buf, len);
132
0
        if (cnt != (ssize_t)len) {
133
0
            return NULL;
134
0
        }
135
0
    }
136
0
    return a_fs_block;
137
0
}
138
139
140
141
/**
142
 * \internal
143
 * Set the fields of a FS_BLOCk structure.  This is internally used to set the data from a
144
 * larger buffer so that larger disk reads can occur.
145
 *
146
 * @param a_fs File system
147
 * @param a_fs_block Block to load data into
148
 * @param a_addr Address where data is from
149
 * @param a_flags Flags for data
150
 * @param a_buf Buffer to copy data from  and into a_fs_block (block_size will be copied)
151
 * @returns 1 on error, 0 on success
152
 */
153
int
154
tsk_fs_block_set(TSK_FS_INFO * a_fs, TSK_FS_BLOCK * a_fs_block,
155
    TSK_DADDR_T a_addr, TSK_FS_BLOCK_FLAG_ENUM a_flags, char *a_buf)
156
0
{
157
0
    if ((a_fs == NULL) || (a_fs->tag != TSK_FS_INFO_TAG)) {
158
0
        tsk_error_reset();
159
0
        tsk_error_set_errno(TSK_ERR_FS_READ);
160
0
        tsk_error_set_errstr("tsk_fs_block_set: fs_info unallocated");
161
0
        return 1;
162
0
    }
163
0
    if ((a_fs_block->tag != TSK_FS_BLOCK_TAG) || (a_fs_block->buf == NULL)) {
164
0
        tsk_error_reset();
165
0
        tsk_error_set_errno(TSK_ERR_FS_READ);
166
0
        tsk_error_set_errstr("tsk_fs_block_set: fs_block unallocated");
167
0
        return 1;
168
0
    }
169
0
    a_fs_block->fs_info = a_fs;
170
0
    if ((a_flags & TSK_FS_BLOCK_FLAG_AONLY) == 0)
171
0
        memcpy(a_fs_block->buf, a_buf, a_fs->block_size);
172
0
    a_fs_block->addr = a_addr;
173
0
    a_fs_block->flags = a_flags;
174
0
    return 0;
175
0
}
176
177
178
/**
179
 * \ingroup fslib
180
 *
181
 * Cycle through a range of file system blocks and call the callback function
182
 * with the contents and allocation status of each.
183
 *
184
 * @param a_fs File system to analyze
185
 * @param a_start_blk Block address to start walking from
186
 * @param a_end_blk Block address to walk to
187
 * @param a_flags Flags used during walk to determine which blocks to call callback with
188
 * @param a_action Callback function
189
 * @param a_ptr Pointer that will be passed to callback
190
 * @returns 1 on error and 0 on success
191
 */
192
uint8_t
193
tsk_fs_block_walk(TSK_FS_INFO * a_fs,
194
    TSK_DADDR_T a_start_blk, TSK_DADDR_T a_end_blk,
195
    TSK_FS_BLOCK_WALK_FLAG_ENUM a_flags, TSK_FS_BLOCK_WALK_CB a_action,
196
    void *a_ptr)
197
0
{
198
0
    if ((a_fs == NULL) || (a_fs->tag != TSK_FS_INFO_TAG)) {
199
0
        tsk_error_reset();
200
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
201
0
        tsk_error_set_errstr
202
0
            ("tsk_fs_block_walk: FS_INFO structure is not allocated");
203
0
        return 1;
204
0
    }
205
0
    return a_fs->block_walk(a_fs, a_start_blk, a_end_blk, a_flags,
206
0
        a_action, a_ptr);
207
0
}