Coverage Report

Created: 2025-07-23 06:40

/src/sleuthkit/tsk/img/raw.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Brian Carrier [carrier <at> sleuthkit [dot] org]
3
 * Copyright (c) 2006-2011 Brian Carrier, Basis Technology.  All rights reserved
4
 * Copyright (c) 2005 Brian Carrier.  All rights reserved
5
 *
6
 * raw
7
 *
8
 * This software is distributed under the Common Public License 1.0
9
 *
10
 */
11
12
13
/**
14
 * \file raw.c
15
 * Internal code to open and read single or split raw disk images
16
 */
17
18
#include "tsk_img_i.h"
19
#include "raw.h"
20
#include "tsk/util/file_system_utils.h"
21
22
#include <memory>
23
24
#ifdef __APPLE__
25
#include <sys/disk.h>
26
#endif
27
28
#ifdef TSK_WIN32
29
#include <winioctl.h>
30
#else
31
#include <sys/types.h>
32
#include <sys/stat.h>
33
#include <unistd.h>
34
#include <fcntl.h>
35
#endif
36
37
#ifndef S_IFMT
38
#define S_IFMT __S_IFMT
39
#endif
40
41
#ifndef S_IFDIR
42
#define S_IFDIR __S_IFDIR
43
#endif
44
45
/**
46
 * \internal
47
 * Read from one of the multiple files in a split set of disk images.
48
 *
49
 * @param split_info Disk image info to read from
50
 * @param idx Index of the disk image in the set to read from
51
 * @param buf [out] Buffer to write data to
52
 * @param len Number of bytes to read
53
 * @param rel_offset Byte offset in the disk image to read from (not the offset in the full disk image set)
54
 *
55
 * @return -1 on error or number of bytes read
56
 */
57
static ssize_t
58
raw_read_segment(IMG_RAW_INFO * raw_info, int idx, char *buf,
59
    size_t len, TSK_OFF_T rel_offset)
60
0
{
61
0
    TSK_IMG_INFO* img_info = &raw_info->img_info.img_info;
62
63
0
    IMG_SPLIT_CACHE *cimg;
64
0
    ssize_t cnt;
65
66
    /* Is the image already open? */
67
0
    if (raw_info->cptr[idx] == -1) {
68
0
        if (tsk_verbose) {
69
0
            tsk_fprintf(stderr,
70
0
                "raw_read_segment: opening file into slot %d: %" PRIttocTSK
71
0
                "\n", raw_info->next_slot, img_info->images[idx]);
72
0
        }
73
74
        /* Grab the next cache slot */
75
0
        cimg = &raw_info->cache[raw_info->next_slot];
76
77
        /* Free it if being used */
78
0
        if (cimg->fd != 0) {
79
0
            if (tsk_verbose) {
80
0
                tsk_fprintf(stderr,
81
0
                    "raw_read_segment: closing file %" PRIttocTSK "\n",
82
0
                    img_info->images[cimg->image]);
83
0
            }
84
#ifdef TSK_WIN32
85
            CloseHandle(cimg->fd);
86
#else
87
0
            close(cimg->fd);
88
0
#endif
89
0
            raw_info->cptr[cimg->image] = -1;
90
0
        }
91
92
#ifdef TSK_WIN32
93
        cimg->fd = CreateFile(img_info->images[idx], FILE_READ_DATA,
94
                              FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0,
95
                              NULL);
96
        if ( cimg->fd == INVALID_HANDLE_VALUE ) {
97
            int lastError = (int)GetLastError();
98
            cimg->fd = 0; /* so we don't close it next time */
99
            tsk_error_reset();
100
            tsk_error_set_errno(TSK_ERR_IMG_OPEN);
101
            tsk_error_set_errstr("raw_read: file \"%" PRIttocTSK
102
                                "\" - %d", img_info->images[idx], lastError);
103
            return -1;
104
        }
105
106
#else
107
0
        if ((cimg->fd =
108
0
                open(img_info->images[idx], O_RDONLY | O_BINARY)) < 0) {
109
0
            cimg->fd = 0; /* so we don't close it next time */
110
0
            tsk_error_reset();
111
0
            tsk_error_set_errno(TSK_ERR_IMG_OPEN);
112
0
            tsk_error_set_errstr("raw_read: file \"%" PRIttocTSK
113
0
                "\" - %s", img_info->images[idx], strerror(errno));
114
0
            return -1;
115
0
        }
116
0
#endif
117
0
        cimg->image = idx;
118
0
        cimg->seek_pos = 0;
119
0
        raw_info->cptr[idx] = raw_info->next_slot;
120
0
        if (++raw_info->next_slot == SPLIT_CACHE) {
121
0
            raw_info->next_slot = 0;
122
0
        }
123
0
    }
124
0
    else {
125
        /* image already open */
126
0
        cimg = &raw_info->cache[raw_info->cptr[idx]];
127
0
    }
128
129
#ifdef TSK_WIN32
130
    {
131
        // Default to the values that were passed in
132
        TSK_OFF_T offset_to_read = rel_offset;
133
        size_t len_to_read = len;
134
        char ** buf_pointer = &buf;
135
        char * sector_aligned_buf = NULL;
136
137
        // If the offset to seek to isn't sector-aligned and this is a device, we need to start at the previous sector boundary and
138
        // read some extra data.
139
        if ((offset_to_read % img_info->sector_size != 0)
140
                && is_windows_device_path(img_info->images[idx])) {
141
            offset_to_read = (offset_to_read / img_info->sector_size) * img_info->sector_size;
142
            len_to_read += img_info->sector_size; // this length will already be a multiple of sector size
143
            sector_aligned_buf = (char *)tsk_malloc(len_to_read);
144
            if (sector_aligned_buf == NULL) {
145
                tsk_error_reset();
146
                tsk_error_set_errno(TSK_ERR_IMG_READ);
147
                tsk_error_set_errstr("raw_read: error allocating memory to read file \"%" PRIttocTSK
148
                    "\" offset: %" PRIdOFF " read len: %" PRIuSIZE,
149
                    img_info->images[idx], offset_to_read, len_to_read);
150
                return -1;
151
            }
152
            buf_pointer = &sector_aligned_buf;
153
        }
154
155
        DWORD nread;
156
        if (cimg->seek_pos != offset_to_read) {
157
            LARGE_INTEGER li;
158
            li.QuadPart = offset_to_read;
159
160
            li.LowPart = SetFilePointer(cimg->fd, li.LowPart,
161
                &li.HighPart, FILE_BEGIN);
162
163
            if ((li.LowPart == INVALID_SET_FILE_POINTER) &&
164
                (GetLastError() != NO_ERROR)) {
165
                if (sector_aligned_buf != NULL) {
166
                    free(sector_aligned_buf);
167
                }
168
                int lastError = (int)GetLastError();
169
                tsk_error_reset();
170
                tsk_error_set_errno(TSK_ERR_IMG_SEEK);
171
                tsk_error_set_errstr("raw_read: file \"%" PRIttocTSK
172
                    "\" offset %" PRIdOFF " seek - %d",
173
                    img_info->images[idx], offset_to_read,
174
                    lastError);
175
                return -1;
176
            }
177
            cimg->seek_pos = offset_to_read;
178
        }
179
180
        //For physical drive when the buffer is larger than remaining data,
181
        // WinAPI ReadFile call returns -1
182
        //in this case buffer of exact length must be passed to ReadFile
183
        if ((raw_info->is_winobj) && (offset_to_read + (TSK_OFF_T)len_to_read > img_info->size ))
184
            len_to_read = (size_t)(img_info->size - offset_to_read);
185
186
        if (FALSE == ReadFile(cimg->fd, *buf_pointer, (DWORD)len_to_read, &nread, NULL)) {
187
            if (sector_aligned_buf != NULL) {
188
                free(sector_aligned_buf);
189
            }
190
            int lastError = GetLastError();
191
            tsk_error_reset();
192
            tsk_error_set_errno(TSK_ERR_IMG_READ);
193
            tsk_error_set_errstr("raw_read: file \"%" PRIttocTSK
194
                "\" offset: %" PRIdOFF " read len: %" PRIuSIZE " - %d",
195
                img_info->images[idx], offset_to_read, len_to_read,
196
                lastError);
197
            return -1;
198
        }
199
        // When the read operation reaches the end of a file,
200
        // ReadFile returns TRUE and sets nread to zero.
201
        // We need to check if we've reached the end of a file and set nread to
202
        // the number of bytes read.
203
        if (raw_info->is_winobj && nread == 0 && offset_to_read + len_to_read == (size_t) img_info->size) {
204
            nread = (DWORD)len_to_read;
205
        }
206
        cnt = (ssize_t) nread;
207
208
        if (raw_info->img_writer != NULL) {
209
            /* img_writer is not used with split images, so rel_offset is just the normal offset*/
210
            raw_info->img_writer->add(raw_info->img_writer, offset_to_read, *buf_pointer, cnt);
211
            // If WriteFile returns error in the addNewBlock, hadErrorExtending is 1
212
            if (raw_info->img_writer->inFinalizeImageWriter && raw_info->img_writer->hadErrorExtending) {
213
                if (sector_aligned_buf != NULL) {
214
                    free(sector_aligned_buf);
215
                }
216
                tsk_error_reset();
217
                tsk_error_set_errno(TSK_ERR_IMG_WRITE);
218
                tsk_error_set_errstr("raw_read: file \"%" PRIttocTSK
219
                    "\" offset: %" PRIdOFF " tsk_img_writer_add cnt: %" PRIuSIZE,
220
                    img_info->images[idx], offset_to_read, cnt
221
                    );
222
                return -1;
223
            }
224
        }
225
226
        // Update this with the actual bytes read
227
        cimg->seek_pos += cnt;
228
229
        // If we had to do the sector alignment, copy the result into the original buffer and fix
230
        // the number of bytes read
231
        if (sector_aligned_buf != NULL) {
232
            memcpy(buf, sector_aligned_buf + rel_offset % img_info->sector_size, len);
233
            cnt = cnt - rel_offset % img_info->sector_size;
234
            if (cnt < 0) {
235
                cnt = -1;
236
            }
237
            free(sector_aligned_buf);
238
        }
239
    }
240
#else
241
0
    if (cimg->seek_pos != rel_offset) {
242
0
        if (lseek(cimg->fd, rel_offset, SEEK_SET) != rel_offset) {
243
0
            tsk_error_reset();
244
0
            tsk_error_set_errno(TSK_ERR_IMG_SEEK);
245
0
            tsk_error_set_errstr("raw_read: file \"%" PRIttocTSK
246
0
                "\" offset %" PRIdOFF " seek - %s", img_info->images[idx],
247
0
                rel_offset, strerror(errno));
248
0
            return -1;
249
0
        }
250
0
        cimg->seek_pos = rel_offset;
251
0
    }
252
253
0
    cnt = read(cimg->fd, buf, len);
254
0
    if (cnt < 0) {
255
0
        tsk_error_reset();
256
0
        tsk_error_set_errno(TSK_ERR_IMG_READ);
257
0
        tsk_error_set_errstr("raw_read: file \"%" PRIttocTSK "\" offset: %"
258
0
      PRIdOFF " read len: %" PRIuSIZE " - %s", img_info->images[idx],
259
0
            rel_offset, len, strerror(errno));
260
0
        return -1;
261
0
    }
262
0
    cimg->seek_pos += cnt;
263
0
#endif
264
265
0
    return cnt;
266
0
}
267
268
269
/**
270
 * \internal
271
 * Read data from a (potentially split) raw disk image.  The offset to
272
 * start reading from is equal to the volume offset plus the read offset.
273
 *
274
 * Note: The routine -assumes- we are under a lock on &(img_info->cache_lock))
275
 *
276
 * @param img_info Disk image to read from
277
 * @param offset Byte offset in image to start reading from
278
 * @param buf [out] Buffer to write data to
279
 * @param len Number of bytes to read
280
 *
281
 * @return number of bytes read or -1 on error
282
 */
283
static ssize_t
284
raw_read(TSK_IMG_INFO * img_info, TSK_OFF_T offset, char *buf, size_t len)
285
0
{
286
0
    IMG_RAW_INFO *raw_info = (IMG_RAW_INFO *) img_info;
287
0
    int i;
288
289
0
    if (tsk_verbose) {
290
0
        tsk_fprintf(stderr,
291
0
            "raw_read: byte offset: %" PRIdOFF " len: %" PRIuSIZE "\n",
292
0
            offset, len);
293
0
    }
294
295
0
    if (offset > img_info->size) {
296
0
        tsk_error_reset();
297
0
        tsk_error_set_errno(TSK_ERR_IMG_READ_OFF);
298
0
        tsk_error_set_errstr("raw_read: offset %" PRIdOFF " too large",
299
0
            offset);
300
0
        return -1;
301
0
    }
302
303
0
    tsk_take_lock(&raw_info->read_lock);
304
0
    std::unique_ptr<tsk_lock_t, void(*)(tsk_lock_t*)> lock_guard(
305
0
      &raw_info->read_lock, tsk_release_lock
306
0
    );
307
308
    // Find the location of the offset
309
0
    for (i = 0; i < img_info->num_img; i++) {
310
311
        /* Does the data start in this image? */
312
0
        if (offset < raw_info->max_off[i]) {
313
0
            TSK_OFF_T rel_offset;
314
0
            size_t read_len;
315
0
            ssize_t cnt;
316
317
            /* Get the offset relative to this image segment */
318
0
            if (i > 0) {
319
0
                rel_offset = offset - raw_info->max_off[i - 1];
320
0
            }
321
0
            else {
322
0
                rel_offset = offset;
323
0
            }
324
325
            /* Get the length to read */
326
            // NOTE: max_off - offset can be a very large number.  Do not cast to size_t
327
0
            if (raw_info->max_off[i] - offset >= (TSK_OFF_T)len)
328
0
                read_len = len;
329
0
            else
330
0
                read_len = (size_t) (raw_info->max_off[i] - offset);
331
332
333
0
            if (tsk_verbose) {
334
0
                tsk_fprintf(stderr,
335
0
                    "raw_read: found in image %d relative offset: %"
336
0
          PRIdOFF " len: %" PRIdOFF "\n", i, rel_offset,
337
0
                    (TSK_OFF_T) read_len);
338
0
            }
339
340
0
            cnt = raw_read_segment(raw_info, i, buf, read_len, rel_offset);
341
0
            if (cnt < 0) {
342
0
                return -1;
343
0
            }
344
0
            if ((size_t) cnt != read_len) {
345
0
                return cnt;
346
0
            }
347
348
            /* read from the next image segment(s) if needed */
349
0
            if (((size_t) cnt == read_len) && (read_len != len)) {
350
351
0
                len -= read_len;
352
353
                /* go to the next image segment */
354
0
                while ((len > 0) && (i+1 < img_info->num_img)) {
355
0
                    ssize_t cnt2;
356
357
0
                    i++;
358
359
0
                    if ((raw_info->max_off[i] - raw_info->max_off[i - 1]) >= (TSK_OFF_T)len)
360
0
                        read_len = len;
361
0
                    else
362
0
                        read_len = (size_t) (raw_info->max_off[i] - raw_info->max_off[i - 1]);
363
364
0
                    if (tsk_verbose) {
365
0
                        tsk_fprintf(stderr,
366
0
                            "raw_read: additional image reads: image %d len: %"
367
0
              PRIuSIZE "\n", i, read_len);
368
0
                    }
369
370
0
                    cnt2 = raw_read_segment(raw_info, i, &buf[cnt],
371
0
                        read_len, 0);
372
0
                    if (cnt2 < 0) {
373
0
                        return -1;
374
0
                    }
375
0
                    cnt += cnt2;
376
377
0
                    if ((size_t) cnt2 != read_len) {
378
0
                        return cnt;
379
0
                    }
380
381
0
                    len -= cnt2;
382
0
                }
383
0
            }
384
0
            return cnt;
385
0
        }
386
0
    }
387
388
0
    tsk_error_reset();
389
0
    tsk_error_set_errno(TSK_ERR_IMG_READ_OFF);
390
0
    tsk_error_set_errstr("raw_read: offset %" PRIdOFF
391
0
        " not found in any segments", offset);
392
393
0
    return -1;
394
0
}
395
396
397
/**
398
 * \internal
399
 * Display information about the disk image set.
400
 *
401
 * @param img_info Disk image to analyze
402
 * @param hFile Handle to print information to
403
 */
404
static void
405
raw_imgstat(TSK_IMG_INFO * img_info, FILE * hFile)
406
0
{
407
0
    IMG_RAW_INFO *raw_info = (IMG_RAW_INFO *) img_info;
408
409
0
    tsk_fprintf(hFile, "IMAGE FILE INFORMATION\n");
410
0
    tsk_fprintf(hFile, "--------------------------------------------\n");
411
0
    tsk_fprintf(hFile, "Image Type: raw\n");
412
0
    tsk_fprintf(hFile, "\nSize in bytes: %" PRIdOFF "\n", img_info->size);
413
0
    tsk_fprintf(hFile, "Sector size:\t%d\n", img_info->sector_size);
414
415
0
    if (img_info->num_img > 1) {
416
0
        int i;
417
418
0
        tsk_fprintf(hFile,
419
0
            "\n--------------------------------------------\n");
420
0
        tsk_fprintf(hFile, "Split Information:\n");
421
422
0
        for (i = 0; i < img_info->num_img; i++) {
423
0
            tsk_fprintf(hFile,
424
0
                "%" PRIttocTSK "  (%" PRIdOFF " to %" PRIdOFF ")\n",
425
0
                img_info->images[i],
426
0
                (TSK_OFF_T) (i == 0) ? 0 : raw_info->max_off[i - 1],
427
0
                (TSK_OFF_T) (raw_info->max_off[i] - 1));
428
0
        }
429
0
    }
430
0
}
431
432
433
/**
434
 * \internal
435
 * Free the memory and close the file  handles for the disk image
436
 *
437
 * @param img_info Disk image to close
438
 */
439
static void
440
raw_close(TSK_IMG_INFO * img_info)
441
0
{
442
0
    IMG_RAW_INFO *raw_info = (IMG_RAW_INFO *) img_info;
443
0
    int i;
444
445
#ifdef TSK_WIN32
446
    if (raw_info->img_writer != NULL) {
447
        raw_info->img_writer->close(raw_info->img_writer);
448
        free(raw_info->img_writer);
449
        raw_info->img_writer = NULL;
450
    }
451
#endif
452
453
0
    for (i = 0; i < SPLIT_CACHE; i++) {
454
0
        if (raw_info->cache[i].fd != 0)
455
#ifdef TSK_WIN32
456
            CloseHandle(raw_info->cache[i].fd);
457
#else
458
0
            close(raw_info->cache[i].fd);
459
0
#endif
460
0
    }
461
462
0
    free(raw_info->max_off);
463
0
    free(raw_info->cptr);
464
465
0
    tsk_deinit_lock(&(raw_info->read_lock));
466
0
    tsk_img_free(raw_info);
467
0
}
468
469
#ifdef TSK_WIN32
470
/**
471
* \internal
472
* Test seeking to the given offset and then reading a sector.
473
* @param file_handle The open file handle to the image
474
* @param offset      The offset to seek to (in bytes)
475
* @param len         The length to read (in bytes). Should be a multiple of the sector size.
476
* @param buf         An allocated buffer large enough to hold len bytes
477
*
478
* @return 1 if the seek/read is successful, 0 if not
479
*/
480
static int
481
test_sector_read(HANDLE file_handle, TSK_OFF_T offset, DWORD len, char * buf) {
482
    LARGE_INTEGER li;
483
    li.QuadPart = offset;
484
485
    // Seek to the given offset
486
    li.LowPart = SetFilePointer(file_handle, li.LowPart,
487
        &li.HighPart, FILE_BEGIN);
488
    if ((li.LowPart == INVALID_SET_FILE_POINTER) &&
489
        (GetLastError() != NO_ERROR)) {
490
        return 0;
491
    }
492
493
    // Read a byte at the given offset
494
    DWORD nread;
495
    if (FALSE == ReadFile(file_handle, buf, len, &nread, NULL)) {
496
        return 0;
497
    }
498
    if (nread != len) {
499
        return 0;
500
    }
501
502
    // Success
503
    return 1;
504
}
505
506
/**
507
 * Attempts to calculate the actual sector size needed for reading the image.
508
 * If successful, the calculated sector size will be stored in raw_info. If it
509
 * fails the sector_size field will not be updated.
510
 * @param raw_info    The incomplete IMG_RAW_INFO object. The sector_size field may be updated by this method.
511
 * @param image_name  Image file name
512
 * @param image_size  Image size
513
*/
514
static void
515
set_device_sector_size(IMG_RAW_INFO * raw_info, const TSK_TCHAR * image_name, TSK_OFF_T image_size) {
516
    unsigned int min_sector_size = 512;
517
    unsigned int max_sector_size = 4096;
518
519
    HANDLE file_handle = CreateFile(image_name, FILE_READ_DATA,
520
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0,
521
        NULL);
522
    if (file_handle == INVALID_HANDLE_VALUE) {
523
        if (tsk_verbose) {
524
            tsk_fprintf(stderr,
525
                "find_sector_size: failed to open image \"%" PRIttocTSK "\"\n", image_name);
526
        }
527
        return;
528
    }
529
530
    TSK_IMG_INFO* img_info = &raw_info->img_info.img_info;
531
532
    // First test whether we need to align on sector boundaries
533
    char* buf = (char*) malloc(max_sector_size);
534
    int needs_sector_alignment = 0;
535
    if (image_size > img_info->sector_size) {
536
        if (test_sector_read(file_handle, 1, img_info->sector_size, buf)) {
537
            needs_sector_alignment = 0;
538
        }
539
        else {
540
            needs_sector_alignment = 1;
541
        }
542
    }
543
544
    // If reading a sector starting at offset 1 failed, the assumption is that we have a device
545
    // that requires reads to be sector-aligned.
546
    if (needs_sector_alignment) {
547
        // Start at the minimum (512) and double up to max_sector_size (4096)
548
        unsigned int sector_size = min_sector_size;
549
550
        while (sector_size <= max_sector_size) {
551
            // If we don't have enough data to do the test just stop
552
            if (image_size < sector_size * 2) {
553
                break;
554
            }
555
556
            if (test_sector_read(file_handle, sector_size, sector_size, buf)) {
557
                // Found a valid sector size
558
                if (tsk_verbose) {
559
                    tsk_fprintf(stderr,
560
                        "find_sector_size: using sector size %d\n", sector_size);
561
                }
562
                img_info->sector_size = sector_size;
563
564
                if (file_handle != 0) {
565
                    CloseHandle(file_handle);
566
                }
567
                free(buf);
568
                return;
569
            }
570
            sector_size *= 2;
571
        }
572
        if (tsk_verbose) {
573
            tsk_fprintf(stderr,
574
                "find_sector_size: failed to determine correct sector size. Reverting to default %d\n", img_info->sector_size);
575
        }
576
        free(buf);
577
    }
578
579
    if (file_handle != 0) {
580
        CloseHandle(file_handle);
581
    }
582
}
583
#endif
584
585
/**
586
 * \internal
587
 * Open the set of disk images as a set of split raw images
588
 *
589
 * @param a_num_img Number of images in set
590
 * @param a_images List of disk image paths (in sorted order)
591
 * @param a_ssize Size of device sector in bytes (or 0 for default)
592
 *
593
 * @return NULL on error
594
 */
595
TSK_IMG_INFO *
596
raw_open(int a_num_img, const TSK_TCHAR * const a_images[],
597
    unsigned int a_ssize)
598
0
{
599
0
    TSK_IMG_INFO *img_info;
600
0
    int i;
601
0
    TSK_OFF_T first_seg_size;
602
603
0
    const auto deleter = [](IMG_RAW_INFO* raw_info) {
604
0
        if (raw_info) {
605
0
            free(raw_info->cptr);
606
0
            free(raw_info->max_off);
607
0
        }
608
0
        tsk_img_free(raw_info);
609
0
    };
610
611
0
    std::unique_ptr<IMG_RAW_INFO, decltype(deleter)> raw_info{
612
0
        (IMG_RAW_INFO *) tsk_img_malloc(sizeof(IMG_RAW_INFO)),
613
0
        deleter
614
0
    };
615
0
    if (!raw_info) {
616
0
        return nullptr;
617
0
    }
618
619
0
    raw_info->cptr = nullptr;
620
0
    raw_info->max_off = nullptr;
621
0
    img_info = (TSK_IMG_INFO *) raw_info.get();
622
623
0
    img_info->itype = TSK_IMG_TYPE_RAW;
624
625
0
    raw_info->img_info.read = raw_read;
626
0
    raw_info->img_info.close = raw_close;
627
0
    raw_info->img_info.imgstat = raw_imgstat;
628
629
0
    raw_info->is_winobj = 0;
630
631
#if defined(TSK_WIN32) || defined(__CYGWIN__)
632
    /* determine if this is the path to a Windows device object */
633
    if ((a_images[0][0] == _TSK_T('\\'))
634
        && (a_images[0][1] == _TSK_T('\\'))
635
        && ((a_images[0][2] == _TSK_T('.')) || (a_images[0][2] == _TSK_T('?')))
636
        && (a_images[0][3] == _TSK_T('\\'))) {
637
        raw_info->is_winobj = 1;
638
    }
639
#endif
640
641
    /* Check that the first image file exists and is not a directory */
642
0
    first_seg_size = get_size_of_file_on_disk(a_images[0], raw_info->is_winobj);
643
0
    if (first_seg_size < -1) {
644
0
        return nullptr;
645
0
    }
646
647
    /* Set the sector size */
648
0
    img_info->sector_size = 512;
649
0
    if (a_ssize) {
650
0
        img_info->sector_size = a_ssize;
651
0
    }
652
#ifdef TSK_WIN32
653
    else if (is_windows_device_path(a_images[0])) {
654
        /* On Windows, figure out the actual sector size if one was not given and this is a device.
655
         * This is to prevent problems reading later. */
656
        set_device_sector_size(raw_info.get(), a_images[0], first_seg_size);
657
    }
658
#endif
659
660
    /* see if there are more of them... */
661
0
    if (a_num_img == 1 && raw_info->is_winobj == 0) {
662
0
        if ((img_info->images =
663
0
                tsk_img_findFiles(a_images[0],
664
0
                    &img_info->num_img)) == nullptr) {
665
0
            tsk_error_reset();
666
0
            tsk_error_set_errno(TSK_ERR_IMG_STAT);
667
0
            tsk_error_set_errstr
668
0
                ("raw_open: could not find segment files starting at \"%"
669
0
                PRIttocTSK "\"", a_images[0]);
670
0
            return nullptr;
671
0
        }
672
0
    }
673
0
    else {
674
0
        if (!tsk_img_copy_image_names(img_info, a_images, a_num_img)) {
675
0
            return nullptr;
676
0
        }
677
0
    }
678
679
    /* sanity check: when we have multiple segments, the size of
680
     * each must be known */
681
0
    if (img_info->num_img > 1 && first_seg_size < 0) {
682
0
        if (tsk_verbose) {
683
0
            tsk_fprintf(stderr,
684
0
                "raw_open: file size is unknown in a segmented raw image\n");
685
0
        }
686
0
        return nullptr;
687
0
    }
688
689
    /* initialize the split cache */
690
0
    raw_info->cptr = (int *) tsk_malloc(img_info->num_img * sizeof(int));
691
0
    if (!raw_info->cptr) {
692
0
        return nullptr;
693
0
    }
694
0
    memset((void *) &raw_info->cache, 0,
695
0
        SPLIT_CACHE * sizeof(IMG_SPLIT_CACHE));
696
0
    raw_info->next_slot = 0;
697
698
    /* initialize the offset table and re-use the first segment
699
     * size gathered above */
700
0
    raw_info->max_off =
701
0
        (TSK_OFF_T *) tsk_malloc(img_info->num_img * sizeof(TSK_OFF_T));
702
0
    if (!raw_info->max_off) {
703
0
        return nullptr;
704
0
    }
705
0
    img_info->size = first_seg_size;
706
0
    raw_info->max_off[0] = img_info->size;
707
0
    raw_info->cptr[0] = -1;
708
0
    if (tsk_verbose) {
709
0
        tsk_fprintf(stderr,
710
0
            "raw_open: segment: 0  size: %" PRIdOFF "  max offset: %"
711
0
      PRIdOFF "  path: %" PRIttocTSK "\n", first_seg_size,
712
0
            raw_info->max_off[0], img_info->images[0]);
713
0
    }
714
715
    /* get size info for each file - we do not open each one because that
716
     * could cause us to run out of file descriptors when we only need a few.
717
     * The descriptors are opened as needed */
718
0
    for (i = 1; i < img_info->num_img; i++) {
719
0
        TSK_OFF_T size;
720
0
        raw_info->cptr[i] = -1;
721
0
        size = get_size_of_file_on_disk(img_info->images[i], raw_info->is_winobj);
722
0
        if (size < 0) {
723
0
            if (size == -1) {
724
0
                if (tsk_verbose) {
725
0
                    tsk_fprintf(stderr,
726
0
                        "raw_open: file size is unknown in a segmented raw image\n");
727
0
                }
728
0
            }
729
0
            return nullptr;
730
0
        }
731
732
        /* add the size of this image to the total and save the current max */
733
0
        img_info->size += size;
734
0
        raw_info->max_off[i] = img_info->size;
735
736
0
        if (tsk_verbose) {
737
0
            tsk_fprintf(stderr,
738
0
                "raw_open: segment: %d  size: %" PRIdOFF "  max offset: %"
739
0
        PRIdOFF "  path: %" PRIttocTSK "\n", i, size,
740
0
                raw_info->max_off[i], img_info->images[i]);
741
0
        }
742
0
    }
743
744
    // initialize the read lock
745
0
    tsk_init_lock(&raw_info->read_lock);
746
747
0
    return (TSK_IMG_INFO*) raw_info.release();
748
0
}