Exemple #1
0
static void
aff_close(TSK_IMG_INFO * img_info)
{
    IMG_AFF_INFO *aff_info = (IMG_AFF_INFO *) img_info;
    af_close(aff_info->af_file);
    tsk_img_free(aff_info);
}
Exemple #2
0
static void
ewf_image_close(TSK_IMG_INFO * img_info)
{
    int i;
    IMG_EWF_INFO *ewf_info = (IMG_EWF_INFO *) img_info;

#if defined ( HAVE_LIBEWF_V2_API)
    libewf_handle_close(ewf_info->handle, NULL);
    libewf_handle_free(&(ewf_info->handle), NULL);

#else
    libewf_close(ewf_info->handle);
#endif

    // this stuff crashes if we used glob. v2 of the API has a free method.
    // not clear from the docs what we should do in v1...
    // @@@ Probably a memory leak in v1 unless libewf_close deals with it
    if (ewf_info->used_ewf_glob == 0) {
        for (i = 0; i < ewf_info->num_imgs; i++) {
            free(ewf_info->images[i]);
        }
        free(ewf_info->images);
    }
    else {
        libewf_error_t *error;
        libewf_glob_free( ewf_info->images, ewf_info->num_imgs, &error);
    }

    tsk_deinit_lock(&(ewf_info->read_lock));
    tsk_img_free(img_info);
}
Exemple #3
0
/** 
 * \internal
 * Free the memory and close the file  handles for the disk image
 *
 * @param img_info Disk image to close
 */
static void
raw_close(TSK_IMG_INFO * img_info)
{
    IMG_RAW_INFO *raw_info = (IMG_RAW_INFO *) img_info;
    int i;
    for (i = 0; i < SPLIT_CACHE; i++) {
        if (raw_info->cache[i].fd != 0)
#ifdef TSK_WIN32
            CloseHandle(raw_info->cache[i].fd);
#else
            close(raw_info->cache[i].fd);
#endif
    }
    for (i = 0; i < raw_info->num_img; i++) {
        if (raw_info->images[i])
            free(raw_info->images[i]);
    }
    if (raw_info->max_off)
        free(raw_info->max_off);
    if (raw_info->images)
        free(raw_info->images);
    if (raw_info->cptr)
        free(raw_info->cptr);

    tsk_img_free(raw_info);
}
static void
raw_close(TSK_IMG_INFO * img_info)
{
    IMG_RAW_INFO *raw_info = (IMG_RAW_INFO *) img_info;
#ifdef TSK_WIN32
    CloseHandle(raw_info->fd);
#else
    close(raw_info->fd);
#endif
    tsk_img_free(raw_info);
}
Exemple #5
0
TSK_IMG_INFO *
aff_open(const TSK_TCHAR * const images[], unsigned int a_ssize)
{
    IMG_AFF_INFO *aff_info;
    TSK_IMG_INFO *img_info;
    int type;
    char *image;

#ifdef TSK_WIN32
    // convert wchar_t* image path to char* to conform to
    // the AFFLIB API
    UTF16 *utf16 = (UTF16 *)images[0];
    size_t ilen = wcslen(utf16);
    size_t olen = ilen*4 + 1;
    UTF8 *utf8 = (UTF8 *) tsk_malloc(olen);

    image = (char *) utf8;
    if ( image == NULL )
        return NULL;
    TSKConversionResult retval =
    tsk_UTF16toUTF8_lclorder( (const UTF16 **) &utf16,
        &utf16[ilen], &utf8,
        &utf8[olen], TSKlenientConversion );
    *utf8 = '\0';
    if (retval != TSKconversionOK) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_UNICODE);
        tsk_error_set_errstr("aff_open file: %" PRIttocTSK
            ": Error converting path to UTF-8 %d\n",
            images[0], retval);
        free(image);
        return NULL;
    }
    utf8 = (UTF8 *) image;
    while ( *utf8 ) {
        if ( *utf8 > 127 ) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_UNICODE);
            tsk_error_set_errstr("aff_open file: %" PRIttocTSK
                ": Non-Latin paths are not supported for AFF images\n",
                images[0]);
            free(image);
            return NULL;
        }
        utf8++;
    }
#else
    image = (char *) tsk_malloc( strlen(images[0])+1 );
    if ( image == NULL )
        return NULL;
    strncpy(image, images[0], strlen(images[0])+1 );
#endif

    if ((aff_info =
            (IMG_AFF_INFO *) tsk_img_malloc(sizeof(IMG_AFF_INFO))) ==
        NULL) {
        free(image);
        return NULL;
    }

    img_info = (TSK_IMG_INFO *) aff_info;
    img_info->read = aff_read;
    img_info->close = aff_close;
    img_info->imgstat = aff_imgstat;

    img_info->sector_size = 512;
    if (a_ssize)
        img_info->sector_size = a_ssize;

    type = af_identify_file_type(image, 1);
    if ((type == AF_IDENTIFY_ERR) || (type == AF_IDENTIFY_NOEXIST)) {
        if (tsk_verbose) {
            tsk_fprintf(stderr,
                "aff_open: Error determining type of file: %" PRIttocTSK
                "\n", images[0]);
            perror("aff_open");
        }
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);
        tsk_error_set_errstr("aff_open file: %" PRIttocTSK
            ": Error checking type", images[0]);
        tsk_img_free(aff_info);
        free(image);
        return NULL;
    }
    else if (type == AF_IDENTIFY_AFF) {
        img_info->itype = TSK_IMG_TYPE_AFF_AFF;
    }
    else if (type == AF_IDENTIFY_AFD) {
        img_info->itype = TSK_IMG_TYPE_AFF_AFD;
    }
    else if (type == AF_IDENTIFY_AFM) {
        img_info->itype = TSK_IMG_TYPE_AFF_AFM;
    }
    else {
        img_info->itype = TSK_IMG_TYPE_AFF_ANY;
    }

    aff_info->af_file = af_open(image, O_RDONLY | O_BINARY, 0);
    if (!aff_info->af_file) {
        // @@@ Need to check here if the open failed because of an incorrect password. 
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);
        tsk_error_set_errstr("aff_open file: %" PRIttocTSK
            ": Error opening - %s", images[0], strerror(errno));
        tsk_img_free(aff_info);
        if (tsk_verbose) {
            tsk_fprintf(stderr, "Error opening AFF/AFD/AFM file\n");
            perror("aff_open");
        }
        free(image);
        return NULL;
    }
    // verify that a password was given and we can read encrypted data. 
    if (af_cannot_decrypt(aff_info->af_file)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_PASSWD);
        tsk_error_set_errstr("aff_open file: %" PRIttocTSK, images[0]);
        tsk_img_free(aff_info);
        if (tsk_verbose) {
            tsk_fprintf(stderr,
                "Error opening AFF/AFD/AFM file (incorrect password)\n");
        }
        free(image);
        return NULL;
    }

    aff_info->type = type;

    img_info->size = af_imagesize(aff_info->af_file);

    af_seek(aff_info->af_file, 0, SEEK_SET);
    aff_info->seek_pos = 0;
    free(image);
    return img_info;
}
Exemple #6
0
TSK_IMG_INFO *
ewf_open(int a_num_img,
    const TSK_TCHAR * const a_images[], unsigned int a_ssize)
{
#if defined( HAVE_LIBEWF_V2_API )
    char error_string[TSK_EWF_ERROR_STRING_SIZE];

    libewf_error_t *ewf_error = NULL;
    int result = 0;
#elif !defined( LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5 )
    uint8_t md5_hash[16];
#endif

    IMG_EWF_INFO *ewf_info = NULL;
    TSK_IMG_INFO *img_info = NULL;

#if !defined( HAVE_LIBEWF_V2_API)
    if (tsk_verbose)
        libewf_set_notify_values(stderr, 1);
#endif

    if ((ewf_info =
            (IMG_EWF_INFO *) tsk_img_malloc(sizeof(IMG_EWF_INFO))) ==
        NULL) {
        return NULL;
    }
    img_info = (TSK_IMG_INFO *) ewf_info;

    // See if they specified only the first of the set...
    ewf_info->used_ewf_glob = 0;
    if (a_num_img == 1) {
#if defined( HAVE_LIBEWF_V2_API)
#ifdef TSK_WIN32
        if (libewf_glob_wide(a_images[0], TSTRLEN(a_images[0]),
                LIBEWF_FORMAT_UNKNOWN, &ewf_info->images,
                &ewf_info->num_imgs, &ewf_error) == -1) {
#else
        if (libewf_glob(a_images[0], TSTRLEN(a_images[0]),
                LIBEWF_FORMAT_UNKNOWN, &ewf_info->images,
                &ewf_info->num_imgs, &ewf_error) == -1) {
#endif
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_IMG_MAGIC);

            getError(ewf_error, error_string);
            tsk_error_set_errstr("ewf_open: Not an E01 glob name (%s)",
                error_string);
            libewf_error_free(&ewf_error);
            tsk_img_free(ewf_info);
            return NULL;
        }

#else                           //use v1

#ifdef TSK_WIN32
        ewf_info->num_imgs =
            libewf_glob_wide(a_images[0], TSTRLEN(a_images[0]),
            LIBEWF_FORMAT_UNKNOWN, &ewf_info->images);
#else
        ewf_info->num_imgs =
            libewf_glob(a_images[0], TSTRLEN(a_images[0]),
            LIBEWF_FORMAT_UNKNOWN, &ewf_info->images);
#endif
        if (ewf_info->num_imgs <= 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_IMG_MAGIC);
            tsk_error_set_errstr("ewf_open: Not an E01 glob name");

            tsk_img_free(ewf_info);
            return NULL;
        }
#endif                          // end v1

        ewf_info->used_ewf_glob = 1;
        if (tsk_verbose)
            tsk_fprintf(stderr,
                "ewf_open: found %d segment files via libewf_glob\n",
                ewf_info->num_imgs);
    }
    else {
        int i;
        ewf_info->num_imgs = a_num_img;
        if ((ewf_info->images =
                (TSK_TCHAR **) tsk_malloc(a_num_img *
                    sizeof(TSK_TCHAR *))) == NULL) {
            tsk_img_free(ewf_info);
            return NULL;
        }
        for (i = 0; i < a_num_img; i++) {
            if ((ewf_info->images[i] =
                    (TSK_TCHAR *) tsk_malloc((TSTRLEN(a_images[i]) +
                            1) * sizeof(TSK_TCHAR))) == NULL) {
                tsk_img_free(ewf_info);
                return NULL;
            }
            TSTRNCPY(ewf_info->images[i], a_images[i],
                TSTRLEN(a_images[i]) + 1);
        }
    }


#if defined( HAVE_LIBEWF_V2_API )

    // Check the file signature before we call the library open
#if defined( TSK_WIN32 )
    if (libewf_check_file_signature_wide(a_images[0], &ewf_error) != 1)
#else
    if (libewf_check_file_signature(a_images[0], &ewf_error) != 1)
#endif
    {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_MAGIC);

        getError(ewf_error, error_string);
        tsk_error_set_errstr("ewf_open: Not an EWF file (%s)",
            error_string);
        libewf_error_free(&ewf_error);

        tsk_img_free(ewf_info);

        if (tsk_verbose != 0) {
            tsk_fprintf(stderr, "Not an EWF file\n");
        }
        return (NULL);
    }

    if (libewf_handle_initialize(&(ewf_info->handle), &ewf_error) != 1) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);

        getError(ewf_error, error_string);
        tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
            ": Error initializing handle (%s)", a_images[0], error_string);
        libewf_error_free(&ewf_error);

        tsk_img_free(ewf_info);

        if (tsk_verbose != 0) {
            tsk_fprintf(stderr, "Unable to create EWF handle\n");
        }
        return (NULL);
    }
#if defined( TSK_WIN32 )
    if (libewf_handle_open_wide(ewf_info->handle,
            (wchar_t * const *) ewf_info->images,
            ewf_info->num_imgs, LIBEWF_OPEN_READ, &ewf_error) != 1)
#else
    if (libewf_handle_open(ewf_info->handle,
            (char *const *) ewf_info->images,
            ewf_info->num_imgs, LIBEWF_OPEN_READ, &ewf_error) != 1)
#endif
    {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);

        getError(ewf_error, error_string);
        tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
            ": Error opening (%s)", a_images[0], error_string);
        libewf_error_free(&ewf_error);

        tsk_img_free(ewf_info);

        if (tsk_verbose != 0) {
            tsk_fprintf(stderr, "Error opening EWF file\n");
        }
        return (NULL);
    }
    if (libewf_handle_get_media_size(ewf_info->handle,
            (size64_t *) & (img_info->size), &ewf_error) != 1) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);

        getError(ewf_error, error_string);
        tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
            ": Error getting size of image (%s)", a_images[0],
            error_string);
        libewf_error_free(&ewf_error);

        tsk_img_free(ewf_info);

        if (tsk_verbose != 0) {
            tsk_fprintf(stderr, "Error getting size of EWF file\n");
        }
        return (NULL);
    }
    result = libewf_handle_get_utf8_hash_value_md5(ewf_info->handle,
        (uint8_t *) ewf_info->md5hash, 33, &ewf_error);

    if (result == -1) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);

        getError(ewf_error, error_string);
        tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
            ": Error getting MD5 of image (%s)", a_images[0],
            error_string);
        libewf_error_free(&ewf_error);

        tsk_img_free(ewf_info);

        if (tsk_verbose != 0) {
            tsk_fprintf(stderr, "Error getting size of EWF file\n");
        }
        return (NULL);
    }
    ewf_info->md5hash_isset = result;

#else                           // V1 API

    // Check the file signature before we call the library open
#if defined( TSK_WIN32 )
    if (libewf_check_file_signature_wide(a_images[0]) != 1)
#else
    if (libewf_check_file_signature(a_images[0]) != 1)
#endif
    {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_MAGIC);
        tsk_error_set_errstr("ewf_open: Not an EWF file");
        tsk_img_free(ewf_info);
        if (tsk_verbose)
            tsk_fprintf(stderr, "Not an EWF file\n");

        return NULL;
    }

#if defined( TSK_WIN32 )
    ewf_info->handle = libewf_open_wide(
        (wchar_t * const *) ewf_info->images, ewf_info->num_imgs,
        LIBEWF_OPEN_READ);
#else
    ewf_info->handle = libewf_open(
        (char *const *) ewf_info->images, ewf_info->num_imgs,
        LIBEWF_OPEN_READ);
#endif
    if (ewf_info->handle == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);
        tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
            ": Error opening", ewf_info->images[0]);
        tsk_img_free(ewf_info);

        if (tsk_verbose != 0) {
            tsk_fprintf(stderr, "Error opening EWF file\n");
        }
        return (NULL);
    }
#if defined( LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5 )
    // 2007 version
    img_info->size = libewf_get_media_size(ewf_info->handle);

    ewf_info->md5hash_isset = libewf_get_stored_md5_hash(ewf_info->handle,
        ewf_info->md5hash, LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5);
#else
    // libewf-20080322 version
    if (libewf_get_media_size(ewf_info->handle,
            (size64_t *) & (img_info->size)) != 1) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_IMG_OPEN);
        tsk_error_set_errstr("ewf_open file: %" PRIttocTSK
            ": Error getting size of image", ewf_info->images[0]);
        tsk_img_free(ewf_info);
        if (tsk_verbose) {
            tsk_fprintf(stderr, "Error getting size of EWF file\n");
        }
        return (NULL);
    }
    if (libewf_get_md5_hash(ewf_info->handle, md5_hash, 16) == 1) {
        int md5_string_iterator = 0;
        int md5_hash_iterator = 0;

        for (md5_hash_iterator = 0;
            md5_hash_iterator < 16; md5_hash_iterator++) {
            int digit = md5_hash[md5_hash_iterator] / 16;

            if (digit <= 9) {
                ewf_info->md5hash[md5_string_iterator++] =
                    '0' + (char) digit;
            }
            else {
                ewf_info->md5hash[md5_string_iterator++] =
                    'a' + (char) (digit - 10);
            }
            digit = md5_hash[md5_hash_iterator] % 16;

            if (digit <= 9) {
                ewf_info->md5hash[md5_string_iterator++] =
                    '0' + (char) digit;
            }
            else {
                ewf_info->md5hash[md5_string_iterator++] =
                    'a' + (char) (digit - 10);
            }
        }
        ewf_info->md5hash_isset = 1;
    }
#endif                          /* defined( LIBEWF_STRING_DIGEST_HASH_LENGTH_MD5 ) */
#endif                          /* defined( HAVE_LIBEWF_V2_API ) */
    if (a_ssize != 0) {
        img_info->sector_size = a_ssize;
    }
    else {
        img_info->sector_size = 512;
    }
    img_info->itype = TSK_IMG_TYPE_EWF_EWF;
    img_info->read = &ewf_image_read;
    img_info->close = &ewf_image_close;
    img_info->imgstat = &ewf_image_imgstat;

    // initialize the read lock
    tsk_init_lock(&(ewf_info->read_lock));

    return (img_info);
}
Exemple #7
0
/** 
 * \internal
 * Open the set of disk images as a set of split raw images
 *
 * @param a_num_img Number of images in set
 * @param a_images List of disk image paths (in sorted order)
 * @param a_ssize Size of device sector in bytes (or 0 for default)
 *
 * @return NULL on error
 */
TSK_IMG_INFO *
raw_open(int a_num_img, const TSK_TCHAR * const a_images[],
    unsigned int a_ssize)
{
    IMG_RAW_INFO *raw_info;
    TSK_IMG_INFO *img_info;
    int i;
    TSK_OFF_T first_seg_size;

    if ((raw_info =
            (IMG_RAW_INFO *) tsk_img_malloc(sizeof(IMG_RAW_INFO))) == NULL)
        return NULL;

    img_info = (TSK_IMG_INFO *) raw_info;

    img_info->itype = TSK_IMG_TYPE_RAW;
    img_info->read = raw_read;
    img_info->close = raw_close;
    img_info->imgstat = raw_imgstat;

    img_info->sector_size = 512;
    if (a_ssize)
        img_info->sector_size = a_ssize;
    raw_info->is_winobj = 0;

#if defined(TSK_WIN32) || defined(__CYGWIN__)
    /* determine if this is the path to a Windows device object */
    if ((a_images[0][0] == _TSK_T('\\'))
        && (a_images[0][1] == _TSK_T('\\'))
        && ((a_images[0][2] == _TSK_T('.')) || (a_images[0][2] == _TSK_T('?')))
        && (a_images[0][3] == _TSK_T('\\'))) {
        raw_info->is_winobj = 1;
    }
#endif

    /* Check that the first image file exists and is not a directory */
    first_seg_size = get_size(a_images[0], raw_info->is_winobj);
    if (first_seg_size < -1) {
        tsk_img_free(raw_info);
        return NULL;
    }

    /* see if there are more of them... */
    if ((a_num_img == 1) && (raw_info->is_winobj == 0)) {
        if ((raw_info->images =
                tsk_img_findFiles(a_images[0],
                    &raw_info->num_img)) == NULL) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_IMG_STAT);
            tsk_error_set_errstr
                ("raw_open: could not find segment files starting at \"%"
                PRIttocTSK "\"", a_images[0]);
            tsk_img_free(raw_info);
            return NULL;
        }
    }
    else {
        raw_info->num_img = a_num_img;
        raw_info->images =
            (TSK_TCHAR **) tsk_malloc(sizeof(TSK_TCHAR *) * a_num_img);
        if (raw_info->images == NULL) {
            tsk_img_free(raw_info);
            return NULL;
        }

        for (i = 0; i < raw_info->num_img; i++) {
            size_t len = TSTRLEN(a_images[i]);
            raw_info->images[i] =
                (TSK_TCHAR *) tsk_malloc(sizeof(TSK_TCHAR) * (len + 1));
            if (raw_info->images[i] == NULL) {
                int j;
                for (j = 0; j < i; j++) {
                    free(raw_info->images[j]);
                }
                free(raw_info->images);
                tsk_img_free(raw_info);
                return NULL;
            }
            TSTRNCPY(raw_info->images[i], a_images[i], len + 1);
        }
    }

    /* sanity check: when we have multiple segments, the size of
     * each must be known */
    if ((raw_info->num_img > 1) && (first_seg_size < 0)) {
        if (tsk_verbose) {
            tsk_fprintf(stderr,
                "raw_open: file size is unknown in a segmented raw image\n");
        }

        for (i = 0; i < raw_info->num_img; i++) {
            free(raw_info->images[i]);
        }
        free(raw_info->images);
        tsk_img_free(raw_info);
        return NULL;
    }

    /* initialize the split cache */
    raw_info->cptr = (int *) tsk_malloc(raw_info->num_img * sizeof(int));
    if (raw_info->cptr == NULL) {
        for (i = 0; i < raw_info->num_img; i++) {
            free(raw_info->images[i]);
        }
        free(raw_info->images);
        tsk_img_free(raw_info);
        return NULL;
    }
    memset((void *) &raw_info->cache, 0,
        SPLIT_CACHE * sizeof(IMG_SPLIT_CACHE));
    raw_info->next_slot = 0;

    /* initialize the offset table and re-use the first segment
     * size gathered above */
    raw_info->max_off =
        (TSK_OFF_T *) tsk_malloc(raw_info->num_img * sizeof(TSK_OFF_T));
    if (raw_info->max_off == NULL) {
        free(raw_info->cptr);
        for (i = 0; i < raw_info->num_img; i++) {
            free(raw_info->images[i]);
        }
        free(raw_info->images);
        tsk_img_free(raw_info);
        return NULL;
    }
    img_info->size = first_seg_size;
    raw_info->max_off[0] = img_info->size;
    raw_info->cptr[0] = -1;
    if (tsk_verbose) {
        tsk_fprintf(stderr,
            "raw_open: segment: 0  size: %" PRIuOFF "  max offset: %"
            PRIuOFF "  path: %" PRIttocTSK "\n", first_seg_size,
            raw_info->max_off[0], raw_info->images[0]);
    }

    /* get size info for each file - we do not open each one because that
     * could cause us to run out of file decsriptors when we only need a few.
     * The descriptors are opened as needed */
    for (i = 1; i < raw_info->num_img; i++) {
        TSK_OFF_T size;
        raw_info->cptr[i] = -1;
        size = get_size(raw_info->images[i], raw_info->is_winobj);
        if (size < 0) {
            if (size == -1) {
                if (tsk_verbose) {
                    tsk_fprintf(stderr,
                        "raw_open: file size is unknown in a segmented raw image\n");
                }
            }
            free(raw_info->cptr);
            for (i = 0; i < raw_info->num_img; i++) {
                free(raw_info->images[i]);
            }
            free(raw_info->images);
            tsk_img_free(raw_info);
            return NULL;
        }

        /* add the size of this image to the total and save the current max */
        img_info->size += size;
        raw_info->max_off[i] = img_info->size;

        if (tsk_verbose) {
            tsk_fprintf(stderr,
                "raw_open: segment: %d  size: %" PRIuOFF "  max offset: %"
                PRIuOFF "  path: %" PRIttocTSK "\n", i, size,
                raw_info->max_off[i], raw_info->images[i]);
        }
    }

    return img_info;
}