1 /*
2  * The file system data handle functions
3  *
4  * Copyright (C) 2018-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 <memory.h>
24 #include <types.h>
25 
26 #include "libfsapfs_data_block.h"
27 #include "libfsapfs_definitions.h"
28 #include "libfsapfs_encryption_context.h"
29 #include "libfsapfs_file_extent.h"
30 #include "libfsapfs_libbfio.h"
31 #include "libfsapfs_libcdata.h"
32 #include "libfsapfs_libcerror.h"
33 #include "libfsapfs_libfcache.h"
34 #include "libfsapfs_libfdata.h"
35 #include "libfsapfs_profiler.h"
36 #include "libfsapfs_unused.h"
37 #include "libfsapfs_file_system_data_handle.h"
38 
39 /* Creates file system data handle
40  * Make sure the value file_system_data_handle is referencing, is set to NULL
41  * Returns 1 if successful or -1 on error
42  */
libfsapfs_file_system_data_handle_initialize(libfsapfs_file_system_data_handle_t ** file_system_data_handle,libfsapfs_io_handle_t * io_handle,libfsapfs_encryption_context_t * encryption_context,libcdata_array_t * file_extents,libcerror_error_t ** error)43 int libfsapfs_file_system_data_handle_initialize(
44      libfsapfs_file_system_data_handle_t **file_system_data_handle,
45      libfsapfs_io_handle_t *io_handle,
46      libfsapfs_encryption_context_t *encryption_context,
47      libcdata_array_t *file_extents,
48      libcerror_error_t **error )
49 {
50 	static char *function = "libfsapfs_file_system_data_handle_initialize";
51 
52 	if( file_system_data_handle == NULL )
53 	{
54 		libcerror_error_set(
55 		 error,
56 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
57 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
58 		 "%s: invalid file system data handle.",
59 		 function );
60 
61 		return( -1 );
62 	}
63 	if( *file_system_data_handle != NULL )
64 	{
65 		libcerror_error_set(
66 		 error,
67 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
68 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
69 		 "%s: invalid file system data handle value already set.",
70 		 function );
71 
72 		return( -1 );
73 	}
74 	if( io_handle == NULL )
75 	{
76 		libcerror_error_set(
77 		 error,
78 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
79 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
80 		 "%s: invalid IO handle.",
81 		 function );
82 
83 		return( -1 );
84 	}
85 	*file_system_data_handle = memory_allocate_structure(
86 	                            libfsapfs_file_system_data_handle_t );
87 
88 	if( *file_system_data_handle == NULL )
89 	{
90 		libcerror_error_set(
91 		 error,
92 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
93 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
94 		 "%s: unable to create file system data handle.",
95 		 function );
96 
97 		goto on_error;
98 	}
99 	if( memory_set(
100 	     *file_system_data_handle,
101 	     0,
102 	     sizeof( libfsapfs_file_system_data_handle_t ) ) == NULL )
103 	{
104 		libcerror_error_set(
105 		 error,
106 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
107 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
108 		 "%s: unable to clear file system data handle.",
109 		 function );
110 
111 		goto on_error;
112 	}
113 	( *file_system_data_handle )->io_handle          = io_handle;
114 	( *file_system_data_handle )->encryption_context = encryption_context;
115 	( *file_system_data_handle )->file_extents       = file_extents;
116 
117 	return( 1 );
118 
119 on_error:
120 	if( *file_system_data_handle != NULL )
121 	{
122 		memory_free(
123 		 *file_system_data_handle );
124 
125 		*file_system_data_handle = NULL;
126 	}
127 	return( -1 );
128 }
129 
130 /* Frees file system data handle
131  * Returns 1 if successful or -1 on error
132  */
libfsapfs_file_system_data_handle_free(libfsapfs_file_system_data_handle_t ** file_system_data_handle,libcerror_error_t ** error)133 int libfsapfs_file_system_data_handle_free(
134      libfsapfs_file_system_data_handle_t **file_system_data_handle,
135      libcerror_error_t **error )
136 {
137 	static char *function = "libfsapfs_file_system_data_handle_free";
138 
139 	if( file_system_data_handle == NULL )
140 	{
141 		libcerror_error_set(
142 		 error,
143 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
144 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
145 		 "%s: invalid file system data handle.",
146 		 function );
147 
148 		return( -1 );
149 	}
150 	if( *file_system_data_handle != NULL )
151 	{
152 		memory_free(
153 		 *file_system_data_handle );
154 
155 		*file_system_data_handle = NULL;
156 	}
157 	return( 1 );
158 }
159 
160 /* Reads a data block
161  * Callback function for a data block vector
162  * Returns 1 if successful or -1 on error
163  */
libfsapfs_file_system_data_handle_read_data_block(libfsapfs_file_system_data_handle_t * file_system_data_handle,libbfio_handle_t * file_io_handle,libfdata_vector_t * vector,libfcache_cache_t * cache,int element_index,int element_data_file_index,off64_t element_data_offset,size64_t element_data_size,uint32_t element_data_flags,uint8_t read_flags LIBFSAPFS_ATTRIBUTE_UNUSED,libcerror_error_t ** error)164 int libfsapfs_file_system_data_handle_read_data_block(
165      libfsapfs_file_system_data_handle_t *file_system_data_handle,
166      libbfio_handle_t *file_io_handle,
167      libfdata_vector_t *vector,
168      libfcache_cache_t *cache,
169      int element_index,
170      int element_data_file_index,
171      off64_t element_data_offset,
172      size64_t element_data_size,
173      uint32_t element_data_flags,
174      uint8_t read_flags LIBFSAPFS_ATTRIBUTE_UNUSED,
175      libcerror_error_t **error )
176 {
177 	libfsapfs_data_block_t *data_block   = NULL;
178 	libfsapfs_file_extent_t *file_extent = NULL;
179 	static char *function                = "libfsapfs_file_system_data_handle_read_data_block";
180 	uint64_t encryption_identifier       = 0;
181 	int64_t file_extent_offset           = 0;
182 
183 #if defined( HAVE_PROFILER )
184 	int64_t profiler_start_timestamp     = 0;
185 #endif
186 
187 	LIBFSAPFS_UNREFERENCED_PARAMETER( read_flags );
188 
189 	if( file_system_data_handle == NULL )
190 	{
191 		libcerror_error_set(
192 		 error,
193 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
194 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
195 		 "%s: invalid file system data handle.",
196 		 function );
197 
198 		return( -1 );
199 	}
200 	if( file_system_data_handle->io_handle == NULL )
201 	{
202 		libcerror_error_set(
203 		 error,
204 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
205 		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
206 		 "%s: invalid file system data handle - missing IO handle.",
207 		 function );
208 
209 		return( -1 );
210 	}
211 	if( element_data_size > (size64_t) SSIZE_MAX )
212 	{
213 		libcerror_error_set(
214 		 error,
215 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
216 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
217 		 "%s: invalid element data size value exceeds maximum.",
218 		 function );
219 
220 		return( -1 );
221 	}
222 	if( libfsapfs_data_block_initialize(
223 	     &data_block,
224 	     (size_t) element_data_size,
225 	     error ) != 1 )
226 	{
227 		libcerror_error_set(
228 		 error,
229 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
230 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
231 		 "%s: unable to create data block.",
232 		 function );
233 
234 		goto on_error;
235 	}
236 #if defined( HAVE_PROFILER )
237 	if( file_system_data_handle->io_handle->profiler != NULL )
238 	{
239 		if( libfsapfs_profiler_start_timing(
240 		     file_system_data_handle->io_handle->profiler,
241 		     &profiler_start_timestamp,
242 		     error ) != 1 )
243 		{
244 			libcerror_error_set(
245 			 error,
246 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
247 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
248 			 "%s: unable to start timing.",
249 			 function );
250 
251 			goto on_error;
252 		}
253 	}
254 #endif /* defined( HAVE_PROFILER ) */
255 
256 	if( ( element_data_flags & LIBFDATA_RANGE_FLAG_IS_SPARSE ) != 0 )
257 	{
258 		if( libfsapfs_data_block_clear_data(
259 		     data_block,
260 		     error ) != 1 )
261 		{
262 			libcerror_error_set(
263 			 error,
264 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
265 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
266 			 "%s: unable to clear data block.",
267 			 function );
268 
269 			goto on_error;
270 		}
271 	}
272 	else
273 	{
274 		encryption_identifier = element_data_offset / element_data_size;
275 
276 		if( file_system_data_handle->file_extents != NULL )
277 		{
278 			if( libcdata_array_get_entry_by_index(
279 			     file_system_data_handle->file_extents,
280 			     element_data_file_index,
281 			     (intptr_t **) &file_extent,
282 			     error ) != 1 )
283 			{
284 				libcerror_error_set(
285 				 error,
286 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
287 				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
288 				 "%s: unable to retrieve file extent: %d.",
289 				 function,
290 				 element_data_file_index );
291 
292 				goto on_error;
293 			}
294 			if( file_extent == NULL )
295 			{
296 				libcerror_error_set(
297 				 error,
298 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
299 				 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
300 				 "%s: missing file extent: %d.",
301 				 function,
302 				 element_data_file_index );
303 
304 				goto on_error;
305 			}
306 			file_extent_offset    = (int64_t) encryption_identifier - (int64_t) file_extent->physical_block_number;
307 			encryption_identifier = file_extent->encryption_identifier + file_extent_offset;
308 		}
309 		if( libfsapfs_data_block_read(
310 		     data_block,
311 		     file_system_data_handle->io_handle,
312 		     file_system_data_handle->encryption_context,
313 		     file_io_handle,
314 		     element_data_offset,
315 		     encryption_identifier,
316 		     error ) != 1 )
317 		{
318 			libcerror_error_set(
319 			 error,
320 			 LIBCERROR_ERROR_DOMAIN_IO,
321 			 LIBCERROR_IO_ERROR_READ_FAILED,
322 			 "%s: unable to read data block.",
323 			 function );
324 
325 			goto on_error;
326 		}
327 	}
328 #if defined( HAVE_PROFILER )
329 	if( file_system_data_handle->io_handle->profiler != NULL )
330 	{
331 		if( libfsapfs_profiler_stop_timing(
332 		     file_system_data_handle->io_handle->profiler,
333 		     profiler_start_timestamp,
334 		     function,
335 		     element_data_offset,
336 		     element_data_size,
337 		     error ) != 1 )
338 		{
339 			libcerror_error_set(
340 			 error,
341 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
342 			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
343 			 "%s: unable to stop timing.",
344 			 function );
345 
346 			goto on_error;
347 		}
348 	}
349 #endif /* defined( HAVE_PROFILER ) */
350 
351 	if( libfdata_vector_set_element_value_by_index(
352 	     vector,
353 	     (intptr_t *) file_io_handle,
354 	     (libfdata_cache_t *) cache,
355 	     element_index,
356 	     (intptr_t *) data_block,
357 	     (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_data_block_free,
358 	     LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
359 	     error ) != 1 )
360 	{
361 		libcerror_error_set(
362 		 error,
363 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
364 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
365 		 "%s: unable to set data block as element value.",
366 		 function );
367 
368 		goto on_error;
369 	}
370 	return( 1 );
371 
372 on_error:
373 	if( data_block != NULL )
374 	{
375 		libfsapfs_data_block_free(
376 		 &data_block,
377 		 NULL );
378 	}
379 	return( -1 );
380 }
381 
382