Coverage Report

Created: 2025-07-04 07:01

/src/libfsapfs/libfsapfs/libfsapfs_file_system_data_handle.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * The file system data handle functions
3
 *
4
 * Copyright (C) 2018-2024, 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
 */
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
1.96k
{
50
1.96k
  static char *function = "libfsapfs_file_system_data_handle_initialize";
51
52
1.96k
  if( file_system_data_handle == NULL )
53
0
  {
54
0
    libcerror_error_set(
55
0
     error,
56
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
57
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
58
0
     "%s: invalid file system data handle.",
59
0
     function );
60
61
0
    return( -1 );
62
0
  }
63
1.96k
  if( *file_system_data_handle != NULL )
64
0
  {
65
0
    libcerror_error_set(
66
0
     error,
67
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
68
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
69
0
     "%s: invalid file system data handle value already set.",
70
0
     function );
71
72
0
    return( -1 );
73
0
  }
74
1.96k
  if( io_handle == NULL )
75
0
  {
76
0
    libcerror_error_set(
77
0
     error,
78
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
79
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
80
0
     "%s: invalid IO handle.",
81
0
     function );
82
83
0
    return( -1 );
84
0
  }
85
1.96k
  *file_system_data_handle = memory_allocate_structure(
86
1.96k
                              libfsapfs_file_system_data_handle_t );
87
88
1.96k
  if( *file_system_data_handle == NULL )
89
0
  {
90
0
    libcerror_error_set(
91
0
     error,
92
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
93
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
94
0
     "%s: unable to create file system data handle.",
95
0
     function );
96
97
0
    goto on_error;
98
0
  }
99
1.96k
  if( memory_set(
100
1.96k
       *file_system_data_handle,
101
1.96k
       0,
102
1.96k
       sizeof( libfsapfs_file_system_data_handle_t ) ) == NULL )
103
0
  {
104
0
    libcerror_error_set(
105
0
     error,
106
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
107
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
108
0
     "%s: unable to clear file system data handle.",
109
0
     function );
110
111
0
    goto on_error;
112
0
  }
113
1.96k
  ( *file_system_data_handle )->io_handle          = io_handle;
114
1.96k
  ( *file_system_data_handle )->encryption_context = encryption_context;
115
1.96k
  ( *file_system_data_handle )->file_extents       = file_extents;
116
117
1.96k
  return( 1 );
118
119
0
on_error:
120
0
  if( *file_system_data_handle != NULL )
121
0
  {
122
0
    memory_free(
123
0
     *file_system_data_handle );
124
125
0
    *file_system_data_handle = NULL;
126
0
  }
127
0
  return( -1 );
128
1.96k
}
129
130
/* Frees file system data handle
131
 * Returns 1 if successful or -1 on error
132
 */
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
1.96k
{
137
1.96k
  static char *function = "libfsapfs_file_system_data_handle_free";
138
139
1.96k
  if( file_system_data_handle == NULL )
140
0
  {
141
0
    libcerror_error_set(
142
0
     error,
143
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
144
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
145
0
     "%s: invalid file system data handle.",
146
0
     function );
147
148
0
    return( -1 );
149
0
  }
150
1.96k
  if( *file_system_data_handle != NULL )
151
1.96k
  {
152
1.96k
    memory_free(
153
1.96k
     *file_system_data_handle );
154
155
1.96k
    *file_system_data_handle = NULL;
156
1.96k
  }
157
1.96k
  return( 1 );
158
1.96k
}
159
160
/* Reads a data block
161
 * Callback function for a data block vector
162
 * Returns 1 if successful or -1 on error
163
 */
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
1.29k
{
177
1.29k
  libfsapfs_data_block_t *data_block   = NULL;
178
1.29k
  libfsapfs_file_extent_t *file_extent = NULL;
179
1.29k
  static char *function                = "libfsapfs_file_system_data_handle_read_data_block";
180
1.29k
  uint64_t encryption_identifier       = 0;
181
1.29k
  int64_t file_extent_offset           = 0;
182
183
#if defined( HAVE_PROFILER )
184
  int64_t profiler_start_timestamp     = 0;
185
#endif
186
187
1.29k
  LIBFSAPFS_UNREFERENCED_PARAMETER( read_flags );
188
189
1.29k
  if( file_system_data_handle == NULL )
190
0
  {
191
0
    libcerror_error_set(
192
0
     error,
193
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
194
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
195
0
     "%s: invalid file system data handle.",
196
0
     function );
197
198
0
    return( -1 );
199
0
  }
200
1.29k
  if( file_system_data_handle->io_handle == NULL )
201
0
  {
202
0
    libcerror_error_set(
203
0
     error,
204
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
205
0
     LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
206
0
     "%s: invalid file system data handle - missing IO handle.",
207
0
     function );
208
209
0
    return( -1 );
210
0
  }
211
1.29k
  if( element_data_size > (size64_t) SSIZE_MAX )
212
0
  {
213
0
    libcerror_error_set(
214
0
     error,
215
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
216
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
217
0
     "%s: invalid element data size value exceeds maximum.",
218
0
     function );
219
220
0
    return( -1 );
221
0
  }
222
1.29k
  if( libfsapfs_data_block_initialize(
223
1.29k
       &data_block,
224
1.29k
       (size_t) element_data_size,
225
1.29k
       error ) != 1 )
226
0
  {
227
0
    libcerror_error_set(
228
0
     error,
229
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
230
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
231
0
     "%s: unable to create data block.",
232
0
     function );
233
234
0
    goto on_error;
235
0
  }
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
1.29k
  if( ( element_data_flags & LIBFDATA_RANGE_FLAG_IS_SPARSE ) != 0 )
257
0
  {
258
0
    if( libfsapfs_data_block_clear_data(
259
0
         data_block,
260
0
         error ) != 1 )
261
0
    {
262
0
      libcerror_error_set(
263
0
       error,
264
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
265
0
       LIBCERROR_RUNTIME_ERROR_SET_FAILED,
266
0
       "%s: unable to clear data block.",
267
0
       function );
268
269
0
      goto on_error;
270
0
    }
271
0
  }
272
1.29k
  else
273
1.29k
  {
274
1.29k
    encryption_identifier = element_data_offset / element_data_size;
275
276
1.29k
    if( file_system_data_handle->file_extents != NULL )
277
0
    {
278
0
      if( libcdata_array_get_entry_by_index(
279
0
           file_system_data_handle->file_extents,
280
0
           element_data_file_index,
281
0
           (intptr_t **) &file_extent,
282
0
           error ) != 1 )
283
0
      {
284
0
        libcerror_error_set(
285
0
         error,
286
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
287
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
288
0
         "%s: unable to retrieve file extent: %d.",
289
0
         function,
290
0
         element_data_file_index );
291
292
0
        goto on_error;
293
0
      }
294
0
      if( file_extent == NULL )
295
0
      {
296
0
        libcerror_error_set(
297
0
         error,
298
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
299
0
         LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
300
0
         "%s: missing file extent: %d.",
301
0
         function,
302
0
         element_data_file_index );
303
304
0
        goto on_error;
305
0
      }
306
0
      file_extent_offset    = (int64_t) encryption_identifier - (int64_t) file_extent->physical_block_number;
307
0
      encryption_identifier = file_extent->encryption_identifier + file_extent_offset;
308
0
    }
309
1.29k
    if( libfsapfs_data_block_read(
310
1.29k
         data_block,
311
1.29k
         file_system_data_handle->io_handle,
312
1.29k
         file_system_data_handle->encryption_context,
313
1.29k
         file_io_handle,
314
1.29k
         element_data_offset,
315
1.29k
         encryption_identifier,
316
1.29k
         error ) != 1 )
317
9
    {
318
9
      libcerror_error_set(
319
9
       error,
320
9
       LIBCERROR_ERROR_DOMAIN_IO,
321
9
       LIBCERROR_IO_ERROR_READ_FAILED,
322
9
       "%s: unable to read data block.",
323
9
       function );
324
325
9
      goto on_error;
326
9
    }
327
1.29k
  }
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
1.28k
  if( libfdata_vector_set_element_value_by_index(
352
1.28k
       vector,
353
1.28k
       (intptr_t *) file_io_handle,
354
1.28k
       (libfdata_cache_t *) cache,
355
1.28k
       element_index,
356
1.28k
       (intptr_t *) data_block,
357
1.28k
       (int (*)(intptr_t **, libcerror_error_t **)) &libfsapfs_data_block_free,
358
1.28k
       LIBFDATA_LIST_ELEMENT_VALUE_FLAG_MANAGED,
359
1.28k
       error ) != 1 )
360
0
  {
361
0
    libcerror_error_set(
362
0
     error,
363
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
364
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
365
0
     "%s: unable to set data block as element value.",
366
0
     function );
367
368
0
    goto on_error;
369
0
  }
370
1.28k
  return( 1 );
371
372
9
on_error:
373
9
  if( data_block != NULL )
374
9
  {
375
9
    libfsapfs_data_block_free(
376
9
     &data_block,
377
9
     NULL );
378
9
  }
379
9
  return( -1 );
380
1.28k
}
381