Coverage Report

Created: 2026-01-20 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libfsntfs/libfsntfs/libfsntfs_usn_change_journal.c
Line
Count
Source
1
/*
2
 * USN change journal functions
3
 *
4
 * Copyright (C) 2010-2025, 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 "libfsntfs_cluster_block_stream.h"
28
#include "libfsntfs_definitions.h"
29
#include "libfsntfs_file_entry.h"
30
#include "libfsntfs_libcerror.h"
31
#include "libfsntfs_libcnotify.h"
32
#include "libfsntfs_libcthreads.h"
33
#include "libfsntfs_mft_attribute.h"
34
#include "libfsntfs_types.h"
35
#include "libfsntfs_usn_change_journal.h"
36
37
/* Creates an USN change journal
38
 * Make sure the value usn_change_journal is referencing, is set to NULL
39
 * Returns 1 if successful or -1 on error
40
 */
41
int libfsntfs_usn_change_journal_initialize(
42
     libfsntfs_usn_change_journal_t **usn_change_journal,
43
     libfsntfs_io_handle_t *io_handle,
44
     libbfio_handle_t *file_io_handle,
45
     libfsntfs_directory_entry_t *directory_entry,
46
     libfsntfs_mft_attribute_t *data_attribute,
47
     libcerror_error_t **error )
48
0
{
49
0
  libfsntfs_internal_usn_change_journal_t *internal_usn_change_journal = NULL;
50
0
  static char *function                                                = "libfsntfs_usn_change_journal_initialize";
51
0
  off64_t segment_offset                                               = 0;
52
0
  int segment_file_index                                               = 0;
53
54
0
  if( usn_change_journal == NULL )
55
0
  {
56
0
    libcerror_error_set(
57
0
     error,
58
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
59
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
60
0
     "%s: invalid USN change journal.",
61
0
     function );
62
63
0
    return( -1 );
64
0
  }
65
0
  if( *usn_change_journal != NULL )
66
0
  {
67
0
    libcerror_error_set(
68
0
     error,
69
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
70
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
71
0
     "%s: invalid USN change journal value already set.",
72
0
     function );
73
74
0
    return( -1 );
75
0
  }
76
0
  if( directory_entry == NULL )
77
0
  {
78
0
    libcerror_error_set(
79
0
     error,
80
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
81
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
82
0
     "%s: invalid directory entry.",
83
0
     function );
84
85
0
    return( -1 );
86
0
  }
87
0
  if( data_attribute == NULL )
88
0
  {
89
0
    libcerror_error_set(
90
0
     error,
91
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
92
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
93
0
     "%s: invalid $J data attribute.",
94
0
     function );
95
96
0
    return( -1 );
97
0
  }
98
0
  internal_usn_change_journal = memory_allocate_structure(
99
0
                                 libfsntfs_internal_usn_change_journal_t );
100
101
0
  if( internal_usn_change_journal == NULL )
102
0
  {
103
0
    libcerror_error_set(
104
0
     error,
105
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
106
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
107
0
     "%s: unable to create USN change journal.",
108
0
     function );
109
110
0
    goto on_error;
111
0
  }
112
0
  if( memory_set(
113
0
       internal_usn_change_journal,
114
0
       0,
115
0
       sizeof( libfsntfs_internal_usn_change_journal_t ) ) == NULL )
116
0
  {
117
0
    libcerror_error_set(
118
0
     error,
119
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
120
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
121
0
     "%s: unable to clear USN change journal.",
122
0
     function );
123
124
0
    memory_free(
125
0
     internal_usn_change_journal );
126
127
0
    return( -1 );
128
0
  }
129
0
  if( libfsntfs_cluster_block_stream_initialize(
130
0
       &( internal_usn_change_journal->data_stream ),
131
0
       io_handle,
132
0
       data_attribute,
133
0
       NULL,
134
0
       0,
135
0
       error ) != 1 )
136
0
  {
137
0
    libcerror_error_set(
138
0
     error,
139
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
140
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
141
0
     "%s: unable to create $J data stream.",
142
0
     function );
143
144
0
    goto on_error;
145
0
  }
146
0
  if( libfdata_stream_get_size(
147
0
       internal_usn_change_journal->data_stream,
148
0
       &( internal_usn_change_journal->data_size ),
149
0
       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 $J data stream size.",
156
0
     function );
157
158
0
    goto on_error;
159
0
  }
160
0
  if( libfdata_stream_get_number_of_segments(
161
0
       internal_usn_change_journal->data_stream,
162
0
       &( internal_usn_change_journal->number_of_extents ),
163
0
       error ) != 1 )
164
0
  {
165
0
    libcerror_error_set(
166
0
     error,
167
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
168
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
169
0
     "%s: unable to retrieve $J data stream number of extents.",
170
0
     function );
171
172
0
    goto on_error;
173
0
  }
174
0
  if( libfdata_stream_get_segment_by_index(
175
0
       internal_usn_change_journal->data_stream,
176
0
       internal_usn_change_journal->extent_index,
177
0
       &segment_file_index,
178
0
       &segment_offset,
179
0
       &( internal_usn_change_journal->extent_size ),
180
0
       &( internal_usn_change_journal->extent_flags ),
181
0
       error ) != 1 )
182
0
  {
183
0
    libcerror_error_set(
184
0
     error,
185
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
186
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
187
0
     "%s: unable to retrieve $J data stream extent: %d.",
188
0
     function,
189
0
     internal_usn_change_journal->extent_index );
190
191
0
    goto on_error;
192
0
  }
193
/* TODO what defines the journal block size? the index entry size? */
194
0
  internal_usn_change_journal->journal_block_size = 0x1000;
195
196
0
  internal_usn_change_journal->journal_block_data = (uint8_t *) memory_allocate(
197
0
                                                                 sizeof( uint8_t ) * internal_usn_change_journal->journal_block_size );
198
199
0
  if( internal_usn_change_journal->journal_block_data == NULL )
200
0
  {
201
0
    libcerror_error_set(
202
0
     error,
203
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
204
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
205
0
     "%s: unable to create journal block data.",
206
0
     function );
207
208
0
    goto on_error;
209
0
  }
210
0
  internal_usn_change_journal->file_io_handle  = file_io_handle;
211
0
  internal_usn_change_journal->directory_entry = directory_entry;
212
213
0
  *usn_change_journal = (libfsntfs_usn_change_journal_t *) internal_usn_change_journal;
214
215
0
  return( 1 );
216
217
0
on_error:
218
0
  if( internal_usn_change_journal != NULL )
219
0
  {
220
0
    if( internal_usn_change_journal->data_stream != NULL )
221
0
    {
222
0
      libfdata_stream_free(
223
0
       &( internal_usn_change_journal->data_stream ),
224
0
       NULL );
225
0
    }
226
0
    memory_free(
227
0
     internal_usn_change_journal );
228
0
  }
229
0
  return( -1 );
230
0
}
231
232
/* Frees an USN change journal
233
 * Returns 1 if successful or -1 on error
234
 */
235
int libfsntfs_usn_change_journal_free(
236
     libfsntfs_usn_change_journal_t **usn_change_journal,
237
     libcerror_error_t **error )
238
0
{
239
0
  libfsntfs_internal_usn_change_journal_t *internal_usn_change_journal = NULL;
240
0
  static char *function                                                = "libfsntfs_usn_change_journal_free";
241
0
  int result                                                           = 1;
242
243
0
  if( usn_change_journal == NULL )
244
0
  {
245
0
    libcerror_error_set(
246
0
     error,
247
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
248
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
249
0
     "%s: invalid USN change journal.",
250
0
     function );
251
252
0
    return( -1 );
253
0
  }
254
0
  if( *usn_change_journal != NULL )
255
0
  {
256
0
    internal_usn_change_journal = (libfsntfs_internal_usn_change_journal_t *) *usn_change_journal;
257
0
    *usn_change_journal         = NULL;
258
259
    /* The file_io_handle reference is freed elsewhere
260
     */
261
0
    if( libfsntfs_directory_entry_free(
262
0
         &( internal_usn_change_journal->directory_entry ),
263
0
         error ) != 1 )
264
0
    {
265
0
      libcerror_error_set(
266
0
       error,
267
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
268
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
269
0
       "%s: unable to free directory entry.",
270
0
       function );
271
272
0
      result = -1;
273
0
    }
274
0
    if( libfdata_stream_free(
275
0
         &( internal_usn_change_journal->data_stream ),
276
0
         error ) != 1 )
277
0
    {
278
0
      libcerror_error_set(
279
0
       error,
280
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
281
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
282
0
       "%s: unable to free $J data stream.",
283
0
       function );
284
285
0
      result = -1;
286
0
    }
287
0
    memory_free(
288
0
     internal_usn_change_journal->journal_block_data );
289
290
0
    memory_free(
291
0
     internal_usn_change_journal );
292
0
  }
293
0
  return( result );
294
0
}
295
296
/* Retrieves the current offset of the default data stream (nameless $DATA attribute)
297
 * Returns the offset if successful or -1 on error
298
 */
299
int libfsntfs_usn_change_journal_get_offset(
300
     libfsntfs_usn_change_journal_t *usn_change_journal,
301
     off64_t *offset,
302
     libcerror_error_t **error )
303
0
{
304
0
  libfsntfs_internal_usn_change_journal_t *internal_usn_change_journal = NULL;
305
0
  static char *function                                                = "libfsntfs_usn_change_journal_get_offset";
306
307
0
  if( usn_change_journal == NULL )
308
0
  {
309
0
    libcerror_error_set(
310
0
     error,
311
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
312
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
313
0
     "%s: invalid USN change journal.",
314
0
     function );
315
316
0
    return( -1 );
317
0
  }
318
0
  internal_usn_change_journal = (libfsntfs_internal_usn_change_journal_t *) usn_change_journal;
319
320
0
  if( offset == NULL )
321
0
  {
322
0
    libcerror_error_set(
323
0
     error,
324
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
325
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
326
0
     "%s: invalid offset.",
327
0
     function );
328
329
0
    return( -1 );
330
0
  }
331
0
  *offset = internal_usn_change_journal->data_offset;
332
333
0
  return( 1 );
334
0
}
335
336
/* Reads an USN record from the USN change journal
337
 * Returns the number of bytes read if successful or -1 on error
338
 */
339
ssize_t libfsntfs_usn_change_journal_read_usn_record(
340
         libfsntfs_usn_change_journal_t *usn_change_journal,
341
         uint8_t *usn_record_data,
342
         size_t usn_record_data_size,
343
         libcerror_error_t **error )
344
0
{
345
0
  libfsntfs_internal_usn_change_journal_t *internal_usn_change_journal = NULL;
346
0
  static char *function                                                = "libfsntfs_usn_change_journal_read_usn_record";
347
0
  size_t read_size                                                     = 0;
348
0
  ssize_t read_count                                                   = 0;
349
0
  off64_t journal_block_offset                                         = 0;
350
0
  off64_t segment_offset                                               = 0;
351
0
  uint32_t usn_record_size                                             = 0;
352
0
  int read_journal_block                                               = 0;
353
0
  int segment_file_index                                               = 0;
354
355
0
  if( usn_change_journal == NULL )
356
0
  {
357
0
    libcerror_error_set(
358
0
     error,
359
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
360
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
361
0
     "%s: invalid USN change journal.",
362
0
     function );
363
364
0
    return( -1 );
365
0
  }
366
0
  internal_usn_change_journal = (libfsntfs_internal_usn_change_journal_t *) usn_change_journal;
367
368
0
  if( ( internal_usn_change_journal->journal_block_size < 60 )
369
0
   || ( internal_usn_change_journal->journal_block_size > MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
370
0
  {
371
0
    libcerror_error_set(
372
0
     error,
373
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
374
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
375
0
     "%s: invalid USN change journal - journal block size value out of bounds.",
376
0
     function );
377
378
0
    return( -1 );
379
0
  }
380
0
  if( usn_record_data == NULL )
381
0
  {
382
0
    libcerror_error_set(
383
0
     error,
384
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
385
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
386
0
     "%s: invalid USN record data.",
387
0
     function );
388
389
0
    return( -1 );
390
0
  }
391
0
  if( usn_record_data_size > (size_t) SSIZE_MAX )
392
0
  {
393
0
    libcerror_error_set(
394
0
     error,
395
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
396
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
397
0
     "%s: invalid USN record data size value out of bounds.",
398
0
     function );
399
400
0
    return( -1 );
401
0
  }
402
0
  if( internal_usn_change_journal->extent_index >= internal_usn_change_journal->number_of_extents )
403
0
  {
404
0
    return( 0 );
405
0
  }
406
0
  while( usn_record_size == 0 )
407
0
  {
408
0
    if( internal_usn_change_journal->data_offset == 0 )
409
0
    {
410
0
      read_journal_block = 1;
411
0
    }
412
0
    else if( internal_usn_change_journal->journal_block_offset >= ( internal_usn_change_journal->journal_block_size - 60 ) )
413
0
    {
414
      /* Get the next journal block
415
       */
416
0
      internal_usn_change_journal->extent_offset += internal_usn_change_journal->journal_block_size;
417
418
0
      read_journal_block = 1;
419
0
    }
420
0
    while( ( ( internal_usn_change_journal->extent_flags & LIBFSNTFS_EXTENT_FLAG_IS_SPARSE ) != 0 )
421
0
        || ( (size64_t) internal_usn_change_journal->extent_offset >= internal_usn_change_journal->extent_size ) )
422
0
    {
423
      /* Get the next non-sparse extent
424
       */
425
0
      internal_usn_change_journal->extent_start_offset += internal_usn_change_journal->extent_size;
426
0
      internal_usn_change_journal->extent_index        += 1;
427
428
0
      if( internal_usn_change_journal->extent_index >= internal_usn_change_journal->number_of_extents )
429
0
      {
430
0
        return( 0 );
431
0
      }
432
0
      if( libfdata_stream_get_segment_by_index(
433
0
           internal_usn_change_journal->data_stream,
434
0
           internal_usn_change_journal->extent_index,
435
0
           &segment_file_index,
436
0
           &segment_offset,
437
0
           &( internal_usn_change_journal->extent_size ),
438
0
           &( internal_usn_change_journal->extent_flags ),
439
0
           error ) != 1 )
440
0
      {
441
0
        libcerror_error_set(
442
0
         error,
443
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
444
0
         LIBCERROR_RUNTIME_ERROR_GET_FAILED,
445
0
         "%s: unable to retrieve $J data stream extent: %d.",
446
0
         function,
447
0
         internal_usn_change_journal->extent_index );
448
449
0
        return( -1 );
450
0
      }
451
0
      internal_usn_change_journal->extent_offset = 0;
452
453
#if defined( HAVE_DEBUG_OUTPUT )
454
      if( libcnotify_verbose != 0 )
455
      {
456
        libcnotify_printf(
457
         "%s: $J data stream extent: %d segment offset\t: 0x%08" PRIx64 "\n",
458
         function,
459
         internal_usn_change_journal->extent_index,
460
         segment_offset );
461
462
        libcnotify_printf(
463
         "%s: $J data stream extent: %d size\t: %" PRIu64 "\n",
464
         function,
465
         internal_usn_change_journal->extent_index,
466
         internal_usn_change_journal->extent_size );
467
468
        libcnotify_printf(
469
         "\n" );
470
      }
471
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
472
473
0
      if( ( internal_usn_change_journal->extent_flags & LIBFSNTFS_EXTENT_FLAG_IS_SPARSE ) != 0 )
474
0
      {
475
0
        internal_usn_change_journal->data_offset += internal_usn_change_journal->extent_size;
476
0
      }
477
0
      else
478
0
      {
479
0
        read_journal_block = 1;
480
0
      }
481
0
    }
482
0
    if( read_journal_block != 0 )
483
0
    {
484
0
      if( (size64_t) internal_usn_change_journal->extent_offset >= internal_usn_change_journal->extent_size )
485
0
      {
486
0
        libcerror_error_set(
487
0
         error,
488
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
489
0
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
490
0
         "%s: invalid USN change journal - extent data offset value out of bounds.",
491
0
         function );
492
493
0
        return( -1 );
494
0
      }
495
0
      if( memory_set(
496
0
           internal_usn_change_journal->journal_block_data,
497
0
           0,
498
0
           internal_usn_change_journal->journal_block_size ) == NULL )
499
0
      {
500
0
        libcerror_error_set(
501
0
         error,
502
0
         LIBCERROR_ERROR_DOMAIN_MEMORY,
503
0
         LIBCERROR_MEMORY_ERROR_SET_FAILED,
504
0
         "%s: unable to clear journal block.",
505
0
         function );
506
507
0
        return( -1 );
508
0
      }
509
0
      read_size = internal_usn_change_journal->journal_block_size;
510
511
0
      if( read_size > ( internal_usn_change_journal->extent_size - internal_usn_change_journal->extent_offset ) )
512
0
      {
513
0
        read_size = (size_t) ( internal_usn_change_journal->extent_size - internal_usn_change_journal->extent_offset );
514
0
      }
515
0
      journal_block_offset = internal_usn_change_journal->extent_start_offset + internal_usn_change_journal->extent_offset;
516
517
0
      read_count = libfdata_stream_read_buffer_at_offset(
518
0
                    internal_usn_change_journal->data_stream,
519
0
                    (intptr_t *) internal_usn_change_journal->file_io_handle,
520
0
                    internal_usn_change_journal->journal_block_data,
521
0
                    read_size,
522
0
                    journal_block_offset,
523
0
                    0,
524
0
                    error );
525
526
0
      if( read_count != (ssize_t) read_size )
527
0
      {
528
0
        libcerror_error_set(
529
0
         error,
530
0
         LIBCERROR_ERROR_DOMAIN_IO,
531
0
         LIBCERROR_IO_ERROR_READ_FAILED,
532
0
         "%s: unable to read journal block from $J data stream at offset: %" PRIi64 " (0x%08" PRIx64 ").",
533
0
         function,
534
0
         journal_block_offset,
535
0
         journal_block_offset );
536
537
0
        return( -1 );
538
0
      }
539
0
      internal_usn_change_journal->journal_block_offset = 0;
540
0
    }
541
#if defined( HAVE_DEBUG_OUTPUT )
542
    if( libcnotify_verbose != 0 )
543
    {
544
      libcnotify_printf(
545
       "%s: journal block offset\t: %" PRIzd "\n",
546
       function,
547
       internal_usn_change_journal->journal_block_offset );
548
549
      libcnotify_printf(
550
       "%s: journal block size\t: %" PRIu64 "\n",
551
       function,
552
       internal_usn_change_journal->journal_block_size );
553
554
      libcnotify_printf(
555
       "\n" );
556
    }
557
#endif
558
0
    if( internal_usn_change_journal->journal_block_offset >= ( internal_usn_change_journal->journal_block_size - 60 ) )
559
0
    {
560
0
      libcerror_error_set(
561
0
       error,
562
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
563
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
564
0
       "%s: invalid USN change journal - journal block offset value out of bounds.",
565
0
       function );
566
567
0
      return( -1 );
568
0
    }
569
#if defined( HAVE_DEBUG_OUTPUT )
570
    if( libcnotify_verbose != 0 )
571
    {
572
      libcnotify_printf(
573
       "%s: USN change journal record header data:\n",
574
       function );
575
      libcnotify_print_data(
576
       &( internal_usn_change_journal->journal_block_data[ internal_usn_change_journal->journal_block_offset ] ),
577
       60,
578
       0 );
579
    }
580
#endif
581
0
    byte_stream_copy_to_uint32_little_endian(
582
0
     &( internal_usn_change_journal->journal_block_data[ internal_usn_change_journal->journal_block_offset ] ),
583
0
     usn_record_size );
584
585
0
    if( usn_record_size == 0 )
586
0
    {
587
0
      internal_usn_change_journal->data_offset          = internal_usn_change_journal->journal_block_size - internal_usn_change_journal->journal_block_offset;
588
0
      internal_usn_change_journal->journal_block_offset = internal_usn_change_journal->journal_block_size;
589
0
    }
590
0
  }
591
0
  if( ( usn_record_size < 60 )
592
0
   || ( usn_record_size > ( internal_usn_change_journal->journal_block_size - internal_usn_change_journal->journal_block_offset ) ) )
593
0
  {
594
0
    libcerror_error_set(
595
0
     error,
596
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
597
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
598
0
     "%s: invalid USN record size value out of bounds.",
599
0
     function );
600
601
0
    return( -1 );
602
0
  }
603
0
  if( usn_record_data_size < usn_record_size )
604
0
  {
605
0
    libcerror_error_set(
606
0
     error,
607
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
608
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
609
0
     "%s: USN record data size value too small.",
610
0
     function );
611
612
0
    return( -1 );
613
0
  }
614
0
  if( memory_copy(
615
0
       usn_record_data,
616
0
       &( internal_usn_change_journal->journal_block_data[ internal_usn_change_journal->journal_block_offset ] ),
617
0
       (size_t) usn_record_size ) == NULL )
618
0
  {
619
0
    libcerror_error_set(
620
0
     error,
621
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
622
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
623
0
     "%s: unable to copy USN record data.",
624
0
     function );
625
626
0
    return( -1 );
627
0
  }
628
0
  internal_usn_change_journal->data_offset          += usn_record_size;
629
0
  internal_usn_change_journal->journal_block_offset += usn_record_size;
630
631
0
  return( (ssize_t) usn_record_size );
632
0
}
633