Coverage Report

Created: 2023-06-07 06:53

/src/libfsxfs/libfsxfs/libfsxfs_extents.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Extents functions
3
 *
4
 * Copyright (C) 2020-2023, 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 "libfsxfs_definitions.h"
27
#include "libfsxfs_extent.h"
28
#include "libfsxfs_extents.h"
29
#include "libfsxfs_libcdata.h"
30
#include "libfsxfs_libcerror.h"
31
#include "libfsxfs_libcnotify.h"
32
33
/* Retrieves the last extent
34
 * Returns 1 if successful or -1 on error
35
 */
36
int libfsxfs_extents_get_last_extent(
37
     libcdata_array_t *extents_array,
38
     libfsxfs_extent_t **last_extent,
39
     libcerror_error_t **error )
40
5.53k
{
41
5.53k
  static char *function = "libfsxfs_extents_get_last_extent";
42
5.53k
  int number_of_extents = 0;
43
44
5.53k
  if( last_extent == NULL )
45
0
  {
46
0
    libcerror_error_set(
47
0
     error,
48
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
49
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
50
0
     "%s: invalid last extent.",
51
0
     function );
52
53
0
    return( -1 );
54
0
  }
55
5.53k
  if( libcdata_array_get_number_of_entries(
56
5.53k
       extents_array,
57
5.53k
       &number_of_extents,
58
5.53k
       error ) != 1 )
59
0
  {
60
0
    libcerror_error_set(
61
0
     error,
62
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
63
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
64
0
     "%s: unable to retrieve number of extents.",
65
0
     function );
66
67
0
    return( -1 );
68
0
  }
69
5.53k
  if( number_of_extents == 0 )
70
2.12k
  {
71
2.12k
    *last_extent = NULL;
72
2.12k
  }
73
3.41k
  else if( libcdata_array_get_entry_by_index(
74
3.41k
            extents_array,
75
3.41k
            number_of_extents - 1,
76
3.41k
            (intptr_t **) last_extent,
77
3.41k
            error ) != 1 )
78
0
  {
79
0
    libcerror_error_set(
80
0
     error,
81
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
82
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
83
0
     "%s: unable to retrieve extent: %d.",
84
0
     function,
85
0
     number_of_extents - 1 );
86
87
0
    return( -1 );
88
0
  }
89
5.53k
  return( 1 );
90
5.53k
}
91
92
/* Reads the extent list data
93
 * Returns 1 if successful or -1 on error
94
 */
95
int libfsxfs_extents_read_data(
96
     libcdata_array_t *extents_array,
97
     uint32_t number_of_extents,
98
     const uint8_t *data,
99
     size_t data_size,
100
     uint8_t add_sparse_extents,
101
     libcerror_error_t **error )
102
3.81k
{
103
3.81k
  libfsxfs_extent_t *last_extent   = NULL;
104
3.81k
  libfsxfs_extent_t *sparse_extent = NULL;
105
3.81k
  libfsxfs_extent_t *extent        = NULL;
106
3.81k
  static char *function            = "libfsxfs_extents_read_data";
107
3.81k
  size_t data_offset               = 0;
108
3.81k
  uint64_t logical_block_number    = 0;
109
3.81k
  uint32_t extent_index            = 0;
110
3.81k
  int entry_index                  = 0;
111
112
3.81k
  if( data == NULL )
113
0
  {
114
0
    libcerror_error_set(
115
0
     error,
116
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
117
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
118
0
     "%s: invalid data.",
119
0
     function );
120
121
0
    return( -1 );
122
0
  }
123
3.81k
  if( ( data_size == 0 )
124
3.81k
   || ( data_size > (size_t) SSIZE_MAX ) )
125
0
  {
126
0
    libcerror_error_set(
127
0
     error,
128
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
129
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
130
0
     "%s: invalid data size value out of bounds.",
131
0
     function );
132
133
0
    return( -1 );
134
0
  }
135
3.81k
  if( (size_t) number_of_extents > ( data_size / 16 ) )
136
86
  {
137
86
    libcerror_error_set(
138
86
     error,
139
86
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
140
86
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
141
86
     "%s: invalid number of extents value out of bounds.",
142
86
     function );
143
144
86
    return( -1 );
145
86
  }
146
3.72k
  if( libfsxfs_extents_get_last_extent(
147
3.72k
       extents_array,
148
3.72k
       &last_extent,
149
3.72k
       error ) != 1 )
150
0
  {
151
0
    libcerror_error_set(
152
0
     error,
153
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
154
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
155
0
     "%s: unable to retrieve last extent.",
156
0
     function );
157
158
0
    goto on_error;
159
0
  }
160
3.72k
  if( last_extent != NULL )
161
1.80k
  {
162
#if defined( HAVE_DEBUG_OUTPUT )
163
    if( libcnotify_verbose != 0 )
164
    {
165
      libcnotify_printf(
166
       "%s: logical block number\t\t\t: %" PRIu64 "\n",
167
       function,
168
       last_extent->logical_block_number );
169
170
      libcnotify_printf(
171
       "%s: physical block number\t\t\t: %" PRIu64 "\n",
172
       function,
173
       last_extent->physical_block_number );
174
175
      libcnotify_printf(
176
       "%s: number of blocks\t\t\t: %" PRIu64 "\n",
177
       function,
178
       last_extent->number_of_blocks );
179
180
      libcnotify_printf(
181
       "\n" );
182
    }
183
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
184
185
1.80k
    logical_block_number = last_extent->logical_block_number + last_extent->number_of_blocks;
186
1.80k
  }
187
#if defined( HAVE_DEBUG_OUTPUT )
188
  if( libcnotify_verbose != 0 )
189
  {
190
    libcnotify_printf(
191
     "%s: extent list data:\n",
192
     function );
193
    libcnotify_print_data(
194
     data,
195
     (size_t) number_of_extents * 16,
196
     LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
197
  }
198
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
199
200
3.72k
  for( extent_index = 0;
201
335k
       extent_index < number_of_extents;
202
331k
       extent_index++ )
203
331k
  {
204
331k
    if( libfsxfs_extent_initialize(
205
331k
         &extent,
206
331k
         error ) != 1 )
207
0
    {
208
0
      libcerror_error_set(
209
0
       error,
210
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
211
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
212
0
       "%s: unable to create extent: %" PRIu32 ".",
213
0
       function,
214
0
       extent_index );
215
216
0
      goto on_error;
217
0
    }
218
331k
    if( libfsxfs_extent_read_data(
219
331k
         extent,
220
331k
         &( data[ data_offset ] ),
221
331k
         16,
222
331k
         error ) != 1 )
223
0
    {
224
0
      libcerror_error_set(
225
0
       error,
226
0
       LIBCERROR_ERROR_DOMAIN_IO,
227
0
       LIBCERROR_IO_ERROR_READ_FAILED,
228
0
       "%s: unable to read extent: %" PRIu32 ".",
229
0
       function,
230
0
       extent_index );
231
232
0
      goto on_error;
233
0
    }
234
331k
    data_offset += 16;
235
236
331k
    if( ( add_sparse_extents != 0 )
237
331k
     && ( extent->logical_block_number > logical_block_number ) )
238
121k
    {
239
121k
      if( libfsxfs_extent_initialize(
240
121k
           &sparse_extent,
241
121k
           error ) != 1 )
242
0
      {
243
0
        libcerror_error_set(
244
0
         error,
245
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
246
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
247
0
         "%s: unable to create sparse extent.",
248
0
         function );
249
250
0
        goto on_error;
251
0
      }
252
121k
      sparse_extent->logical_block_number = logical_block_number;
253
121k
      sparse_extent->number_of_blocks     = extent->logical_block_number - logical_block_number;
254
121k
      sparse_extent->range_flags          = LIBFSXFS_EXTENT_FLAG_IS_SPARSE;
255
256
121k
      if( libcdata_array_append_entry(
257
121k
           extents_array,
258
121k
           &entry_index,
259
121k
           (intptr_t *) sparse_extent,
260
121k
           error ) != 1 )
261
0
      {
262
0
        libcerror_error_set(
263
0
         error,
264
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
265
0
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
266
0
         "%s: unable to append sparse extent to array.",
267
0
         function );
268
269
0
        goto on_error;
270
0
      }
271
121k
      sparse_extent = NULL;
272
121k
    }
273
331k
    logical_block_number = extent->logical_block_number + extent->number_of_blocks;
274
275
331k
    if( libcdata_array_append_entry(
276
331k
         extents_array,
277
331k
         &entry_index,
278
331k
         (intptr_t *) extent,
279
331k
         error ) != 1 )
280
0
    {
281
0
      libcerror_error_set(
282
0
       error,
283
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
284
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
285
0
       "%s: unable to append extent: %" PRIu32 " to extents array.",
286
0
       function,
287
0
       extent_index );
288
289
0
      goto on_error;
290
0
    }
291
331k
    extent = NULL;
292
331k
  }
293
3.72k
  return( 1 );
294
295
0
on_error:
296
0
  if( sparse_extent != NULL )
297
0
  {
298
0
    libfsxfs_extent_free(
299
0
     &sparse_extent,
300
0
     NULL );
301
0
  }
302
0
  if( extent != NULL )
303
0
  {
304
0
    libfsxfs_extent_free(
305
0
     &extent,
306
0
     NULL );
307
0
  }
308
0
  libcdata_array_empty(
309
0
   extents_array,
310
0
   (int (*)(intptr_t **, libcerror_error_t **)) &libfsxfs_extent_free,
311
0
   NULL );
312
313
0
  return( -1 );
314
3.72k
}
315