/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 | } |