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