1 /*
2 * Catalog B-tree file thread record functions
3 *
4 * Copyright (C) 2009-2021, Joachim Metz <joachim.metz@gmail.com>
5 *
6 * Refer to AUTHORS for acknowledgements.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 #include <common.h>
23 #include <byte_stream.h>
24 #include <memory.h>
25 #include <types.h>
26
27 #include "libfshfs_debug.h"
28 #include "libfshfs_definitions.h"
29 #include "libfshfs_libcerror.h"
30 #include "libfshfs_libcnotify.h"
31 #include "libfshfs_libuna.h"
32 #include "libfshfs_thread_record.h"
33
34 #include "fshfs_catalog_file.h"
35
36 /* Creates a thread record
37 * Make sure the value thread_record is referencing, is set to NULL
38 * Returns 1 if successful or -1 on error
39 */
libfshfs_thread_record_initialize(libfshfs_thread_record_t ** thread_record,uint32_t identifier,libcerror_error_t ** error)40 int libfshfs_thread_record_initialize(
41 libfshfs_thread_record_t **thread_record,
42 uint32_t identifier,
43 libcerror_error_t **error )
44 {
45 static char *function = "libfshfs_thread_record_initialize";
46
47 if( thread_record == NULL )
48 {
49 libcerror_error_set(
50 error,
51 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
52 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
53 "%s: invalid thread record.",
54 function );
55
56 return( -1 );
57 }
58 if( *thread_record != NULL )
59 {
60 libcerror_error_set(
61 error,
62 LIBCERROR_ERROR_DOMAIN_RUNTIME,
63 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
64 "%s: invalid thread record value already set.",
65 function );
66
67 return( -1 );
68 }
69 *thread_record = memory_allocate_structure(
70 libfshfs_thread_record_t );
71
72 if( *thread_record == NULL )
73 {
74 libcerror_error_set(
75 error,
76 LIBCERROR_ERROR_DOMAIN_MEMORY,
77 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
78 "%s: unable to create thread record.",
79 function );
80
81 goto on_error;
82 }
83 if( memory_set(
84 *thread_record,
85 0,
86 sizeof( libfshfs_thread_record_t ) ) == NULL )
87 {
88 libcerror_error_set(
89 error,
90 LIBCERROR_ERROR_DOMAIN_MEMORY,
91 LIBCERROR_MEMORY_ERROR_SET_FAILED,
92 "%s: unable to clear thread record.",
93 function );
94
95 goto on_error;
96 }
97 ( *thread_record )->identifier = identifier;
98
99 return( 1 );
100
101 on_error:
102 if( *thread_record != NULL )
103 {
104 memory_free(
105 *thread_record );
106
107 *thread_record = NULL;
108 }
109 return( -1 );
110 }
111
112 /* Frees a thread record
113 * Returns 1 if successful or -1 on error
114 */
libfshfs_thread_record_free(libfshfs_thread_record_t ** thread_record,libcerror_error_t ** error)115 int libfshfs_thread_record_free(
116 libfshfs_thread_record_t **thread_record,
117 libcerror_error_t **error )
118 {
119 static char *function = "libfshfs_thread_record_free";
120
121 if( thread_record == NULL )
122 {
123 libcerror_error_set(
124 error,
125 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
126 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
127 "%s: invalid thread record.",
128 function );
129
130 return( -1 );
131 }
132 if( *thread_record != NULL )
133 {
134 if( ( *thread_record )->name != NULL )
135 {
136 memory_free(
137 ( *thread_record )->name );
138 }
139 memory_free(
140 *thread_record );
141
142 *thread_record = NULL;
143 }
144 return( 1 );
145 }
146
147 /* Reads a thread record
148 * Returns 1 if successful or -1 on error
149 */
libfshfs_thread_record_read_data(libfshfs_thread_record_t * thread_record,const uint8_t * data,size_t data_size,libcerror_error_t ** error)150 int libfshfs_thread_record_read_data(
151 libfshfs_thread_record_t *thread_record,
152 const uint8_t *data,
153 size_t data_size,
154 libcerror_error_t **error )
155 {
156 static char *function = "libfshfs_thread_record_read_data";
157 size_t header_size = 0;
158 uint16_t name_size = 0;
159 uint16_t record_type = 0;
160
161 #if defined( HAVE_DEBUG_OUTPUT )
162 uint16_t value_16bit = 0;
163 #endif
164
165 if( thread_record == NULL )
166 {
167 libcerror_error_set(
168 error,
169 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
170 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
171 "%s: invalid thread record.",
172 function );
173
174 return( -1 );
175 }
176 if( thread_record->name != NULL )
177 {
178 libcerror_error_set(
179 error,
180 LIBCERROR_ERROR_DOMAIN_RUNTIME,
181 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
182 "%s: invalid thread record - name value already set.",
183 function );
184
185 return( -1 );
186 }
187 if( data == NULL )
188 {
189 libcerror_error_set(
190 error,
191 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
192 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
193 "%s: invalid data.",
194 function );
195
196 return( -1 );
197 }
198 if( ( data_size < 2 )
199 || ( data_size > (size_t) SSIZE_MAX ) )
200 {
201 libcerror_error_set(
202 error,
203 LIBCERROR_ERROR_DOMAIN_RUNTIME,
204 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
205 "%s: invalid data size value out of bounds.",
206 function );
207
208 return( -1 );
209 }
210 byte_stream_copy_to_uint16_big_endian(
211 data,
212 record_type );
213
214 if( ( record_type == LIBFSHFS_RECORD_TYPE_HFSPLUS_DIRECTORY_THREAD_RECORD )
215 || ( record_type == LIBFSHFS_RECORD_TYPE_HFSPLUS_FILE_THREAD_RECORD ) )
216 {
217 header_size = sizeof( fshfs_catalog_thread_record_hfsplus_t );
218 }
219 else if( ( record_type == LIBFSHFS_RECORD_TYPE_HFS_DIRECTORY_THREAD_RECORD )
220 || ( record_type == LIBFSHFS_RECORD_TYPE_HFS_FILE_THREAD_RECORD ) )
221 {
222 header_size = sizeof( fshfs_catalog_thread_record_hfs_t );
223 }
224 else
225 {
226 libcerror_error_set(
227 error,
228 LIBCERROR_ERROR_DOMAIN_RUNTIME,
229 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
230 "%s: unsupported record type: 0x%04" PRIx16 "\n",
231 function,
232 record_type );
233
234 goto on_error;
235 }
236 if( data_size < header_size )
237 {
238 libcerror_error_set(
239 error,
240 LIBCERROR_ERROR_DOMAIN_RUNTIME,
241 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
242 "%s: invalid data size value out of bounds.",
243 function );
244
245 goto on_error;
246 }
247 if( ( record_type == LIBFSHFS_RECORD_TYPE_HFSPLUS_DIRECTORY_THREAD_RECORD )
248 || ( record_type == LIBFSHFS_RECORD_TYPE_HFSPLUS_FILE_THREAD_RECORD ) )
249 {
250 byte_stream_copy_to_uint16_big_endian(
251 ( (fshfs_catalog_thread_record_hfsplus_t *) data )->name_size,
252 name_size );
253 }
254 else
255 {
256 /* TODO add HFS support */
257 }
258 #if defined( HAVE_DEBUG_OUTPUT )
259 if( libcnotify_verbose != 0 )
260 {
261 libcnotify_printf(
262 "%s: thread record data:\n",
263 function );
264 libcnotify_print_data(
265 data,
266 header_size + ( name_size * 2 ),
267 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
268 }
269 #endif
270 if( ( record_type == LIBFSHFS_RECORD_TYPE_HFSPLUS_DIRECTORY_THREAD_RECORD )
271 || ( record_type == LIBFSHFS_RECORD_TYPE_HFSPLUS_FILE_THREAD_RECORD ) )
272 {
273 byte_stream_copy_to_uint32_big_endian(
274 ( (fshfs_catalog_thread_record_hfsplus_t *) data )->parent_identifier,
275 thread_record->parent_identifier );
276 }
277 else
278 {
279 byte_stream_copy_to_uint32_big_endian(
280 ( (fshfs_catalog_thread_record_hfs_t *) data )->parent_identifier,
281 thread_record->parent_identifier );
282 }
283 thread_record->name_size = name_size;
284
285 #if defined( HAVE_DEBUG_OUTPUT )
286 if( libcnotify_verbose != 0 )
287 {
288 if( ( record_type == LIBFSHFS_RECORD_TYPE_HFSPLUS_DIRECTORY_THREAD_RECORD )
289 || ( record_type == LIBFSHFS_RECORD_TYPE_HFSPLUS_FILE_THREAD_RECORD ) )
290 {
291 byte_stream_copy_to_uint16_big_endian(
292 ( (fshfs_catalog_thread_record_hfsplus_t *) data )->record_type,
293 value_16bit );
294 }
295 else
296 {
297 value_16bit = ( (fshfs_catalog_thread_record_hfs_t *) data )->record_type;
298 }
299 libcnotify_printf(
300 "%s: record type\t\t\t\t: 0x%04" PRIx16 " (%s)\n",
301 function,
302 value_16bit,
303 libfshfs_debug_print_catalog_record_type(
304 record_type ) );
305
306 if( ( record_type == LIBFSHFS_RECORD_TYPE_HFS_DIRECTORY_THREAD_RECORD )
307 || ( record_type == LIBFSHFS_RECORD_TYPE_HFS_FILE_THREAD_RECORD ) )
308 {
309 libcnotify_printf(
310 "%s: unknown1\t\t\t\t: 0x%02" PRIx8 "\n",
311 function,
312 ( (fshfs_catalog_thread_record_hfs_t *) data )->unknown1 );
313 }
314 if( ( record_type == LIBFSHFS_RECORD_TYPE_HFSPLUS_DIRECTORY_THREAD_RECORD )
315 || ( record_type == LIBFSHFS_RECORD_TYPE_HFSPLUS_FILE_THREAD_RECORD ) )
316 {
317 byte_stream_copy_to_uint16_big_endian(
318 ( (fshfs_catalog_thread_record_hfsplus_t *) data )->unknown1,
319 value_16bit );
320 libcnotify_printf(
321 "%s: unknown1\t\t\t\t: 0x%04" PRIx16 "\n",
322 function,
323 value_16bit );
324 }
325 else
326 {
327 libcnotify_printf(
328 "%s: unknown2:\n",
329 function );
330 libcnotify_print_data(
331 ( (fshfs_catalog_thread_record_hfs_t *) data )->unknown2,
332 8,
333 0 );
334 }
335 libcnotify_printf(
336 "%s: parent identifier\t\t\t: %" PRIu32 "\n",
337 function,
338 thread_record->parent_identifier );
339
340 libcnotify_printf(
341 "%s: name number of characters\t\t: %" PRIu16 " (%" PRIu32 ")\n",
342 function,
343 thread_record->name_size,
344 (uint32_t) thread_record->name_size * 2 );
345 }
346 #endif /* defined( HAVE_DEBUG_OUTPUT ) */
347
348 if( thread_record->name_size > 0 )
349 {
350 if( (uint32_t) thread_record->name_size > ( (uint32_t) UINT16_MAX / 2 ) )
351 {
352 libcerror_error_set(
353 error,
354 LIBCERROR_ERROR_DOMAIN_RUNTIME,
355 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
356 "%s: invalid thread record - name size value out of bounds.",
357 function );
358
359 goto on_error;
360 }
361 thread_record->name_size *= 2;
362
363 if( thread_record->name_size > ( data_size - header_size ) )
364 {
365 libcerror_error_set(
366 error,
367 LIBCERROR_ERROR_DOMAIN_RUNTIME,
368 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
369 "%s: invalid thread record - name size value out of bounds.",
370 function );
371
372 goto on_error;
373 }
374 thread_record->name = (uint8_t *) memory_allocate(
375 sizeof( uint8_t ) * thread_record->name_size );
376
377 if( thread_record->name == NULL )
378 {
379 libcerror_error_set(
380 error,
381 LIBCERROR_ERROR_DOMAIN_MEMORY,
382 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
383 "%s: unable to create name.",
384 function );
385
386 goto on_error;
387 }
388 if( memory_copy(
389 thread_record->name,
390 &( data[ header_size ] ),
391 thread_record->name_size ) == NULL )
392 {
393 libcerror_error_set(
394 error,
395 LIBCERROR_ERROR_DOMAIN_MEMORY,
396 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
397 "%s: unable to copy name.",
398 function );
399
400 goto on_error;
401 }
402 #if defined( HAVE_DEBUG_OUTPUT )
403 if( libcnotify_verbose != 0 )
404 {
405 if( libfshfs_debug_print_utf16_name_value(
406 function,
407 "name\t\t\t\t\t",
408 &( data[ header_size ] ),
409 (size_t) thread_record->name_size,
410 LIBUNA_ENDIAN_BIG,
411 error ) != 1 )
412 {
413 libcerror_error_set(
414 error,
415 LIBCERROR_ERROR_DOMAIN_RUNTIME,
416 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
417 "%s: unable to print UTF-16 name value.",
418 function );
419
420 goto on_error;
421 }
422 }
423 #endif /* defined( HAVE_DEBUG_OUTPUT ) */
424 }
425 #if defined( HAVE_DEBUG_OUTPUT )
426 if( libcnotify_verbose != 0 )
427 {
428 libcnotify_printf(
429 "\n" );
430 }
431 #endif
432 return( 1 );
433
434 on_error:
435 if( thread_record->name != NULL )
436 {
437 memory_free(
438 thread_record->name );
439
440 thread_record->name = NULL;
441 }
442 thread_record->name_size = 0;
443
444 return( -1 );
445 }
446
447