Ejemplo n.º 1
0
Archivo: file.c Proyecto: uw-dims/tsk4j
/*
 * Class:     edu_uw_apl_commons_tsk4j_filesys_File
 * Method:    attribute
 * Signature: (JI)J
 */
JNIEXPORT jlong JNICALL Java_edu_uw_apl_commons_tsk4j_filesys_File_attribute
(JNIEnv *env, jobject thiz, jlong nativePtr, jint indx ) {

  TSK_FS_FILE* info = (TSK_FS_FILE*)nativePtr;
  const TSK_FS_ATTR* attr = tsk_fs_file_attr_get_idx( info, indx );
  return (jlong)attr;
}
Ejemplo n.º 2
0
static TSK_WALK_RET_ENUM
count_slack_inode_act(TSK_FS_FILE * fs_file, void *ptr)
{
    BLKCALC_DATA *data = (BLKCALC_DATA *) ptr;

    if (tsk_verbose)
        tsk_fprintf(stderr,
            "count_slack_inode_act: Processing meta data: %" PRIuINUM
            "\n", fs_file->meta->addr);

    /* We will now do a file walk on the content */
    if (TSK_FS_TYPE_ISNTFS(fs_file->fs_info->ftype) == 0) {
        data->flen = fs_file->meta->size;
        if (tsk_fs_file_walk(fs_file,
                TSK_FS_FILE_WALK_FLAG_SLACK, count_slack_file_act, ptr)) {

            /* ignore any errors */
            if (tsk_verbose)
                tsk_fprintf(stderr, "Error walking file %" PRIuINUM,
                    fs_file->meta->addr);
            tsk_error_reset();
        }
    }

    /* For NTFS we go through each non-resident attribute */
    else {
        int i, cnt;

        cnt = tsk_fs_file_attr_getsize(fs_file);
        for (i = 0; i < cnt; i++) {
            const TSK_FS_ATTR *fs_attr =
                tsk_fs_file_attr_get_idx(fs_file, i);
            if (!fs_attr)
                continue;

            if (fs_attr->flags & TSK_FS_ATTR_NONRES) {
                data->flen = fs_attr->size;
                if (tsk_fs_file_walk_type(fs_file, fs_attr->type,
                        fs_attr->id, TSK_FS_FILE_WALK_FLAG_SLACK,
                        count_slack_file_act, ptr)) {
                    /* ignore any errors */
                    if (tsk_verbose)
                        tsk_fprintf(stderr,
                            "Error walking file %" PRIuINUM,
                            fs_file->meta->addr);
                    tsk_error_reset();
                }
            }
        }
    }
    return TSK_WALK_CONT;
}
Ejemplo n.º 3
0
/**
 * Method that can be used from within processFile() to look at each
 * attribute that a file may have.  This will call the processAttribute()
 * method (which you must implement) on each of the attributes in the file.
 * @param fs_file file  details
 * @param path full path of parent directory
 * @returns STOP if the file system processing should stop and not process more files or OK.
 */
TSK_RETVAL_ENUM
    TskAuto::processAttributes(TSK_FS_FILE * fs_file, const char *path)
{
    int
     count = tsk_fs_file_attr_getsize(fs_file), i;
    for (i = 0; i < count; i++) {
        TSK_RETVAL_ENUM retval =
            processAttribute(fs_file, tsk_fs_file_attr_get_idx(fs_file, i),
            path);
        if ((retval == TSK_STOP) || (m_stopAllProcessing))
            return TSK_STOP;
    }
    return TSK_OK;
}
Ejemplo n.º 4
0
/*
** find_inode
**
** Callback action for inode_walk
*/
static TSK_WALK_RET_ENUM
ifind_data_act(TSK_FS_FILE * fs_file, void *ptr)
{
    IFIND_DATA_DATA *data = (IFIND_DATA_DATA *) ptr;
    int file_flags =
        (TSK_FS_FILE_WALK_FLAG_AONLY | TSK_FS_FILE_WALK_FLAG_SLACK);
    int i, cnt;

    data->curinode = fs_file->meta->addr;

    /* Search all attributes */
    cnt = tsk_fs_file_attr_getsize(fs_file);
    for (i = 0; i < cnt; i++) {
        const TSK_FS_ATTR *fs_attr = tsk_fs_file_attr_get_idx(fs_file, i);
        if (!fs_attr)
            continue;

        data->curtype = fs_attr->type;
        data->curid = fs_attr->id;
        if (fs_attr->flags & TSK_FS_ATTR_NONRES) {
            if (tsk_fs_attr_walk(fs_attr,
                    file_flags, ifind_data_file_act, ptr)) {
                if (tsk_verbose)
                    tsk_fprintf(stderr,
                        "Error walking file %" PRIuINUM
                        " Attribute: %i", fs_file->meta->addr, i);

                /* Ignore these errors */
                tsk_error_reset();
            }

            // stop if we only want one hit
            if ((data->found) && (!(data->flags & TSK_FS_IFIND_ALL)))
                break;
        }
    }

    if ((data->found) && (!(data->flags & TSK_FS_IFIND_ALL)))
        return TSK_WALK_STOP;
    else
        return TSK_WALK_CONT;
}
Ejemplo n.º 5
0
/** \ingroup fslib
* Return a specific attribute by its ID for the file.  
* @param a_fs_file File to get data from
* @param a_id Id of attribute to load 
* @returns NULL on error
*/
const TSK_FS_ATTR *
tsk_fs_file_attr_get_id(TSK_FS_FILE * a_fs_file, uint16_t a_id)
{
    int i, size;
    if (tsk_fs_file_attr_check(a_fs_file, "tsk_fs_file_attr_get_type"))
        return NULL;

    size = tsk_fs_file_attr_getsize(a_fs_file);
    for (i = 0; i < size; i++) {
        const TSK_FS_ATTR *fs_attr =
            tsk_fs_file_attr_get_idx(a_fs_file, i);
        if (fs_attr == NULL)
            return NULL;

        if (fs_attr->id == a_id)
            return fs_attr;
    }
    tsk_error_set_errno(TSK_ERR_FS_ATTR_NOTFOUND);
    tsk_error_set_errstr
        ("tsk_fs_attr_get_id: Attribute ID %d not found", a_id);
    return NULL;
}
Ejemplo n.º 6
0
// file contains attributes, one attribute is the content.
static void 
log_file_offsets_in_filesystem(find_file_data *data, TSK_FS_FILE *file){

    int i;
    int cnt = tsk_fs_file_attr_getsize(file);
    TSK_FS_FILE_WALK_FLAG_ENUM 
        file_walk_flags = (TSK_FS_FILE_WALK_FLAG_ENUM)(
                    TSK_FS_FILE_WALK_FLAG_AONLY   // Provide callback with only addr
                    | TSK_FS_FILE_WALK_FLAG_SLACK // Include file's slack space
                    );
    
    for (i = 0; i < cnt; i++) {
        const TSK_FS_ATTR *attr = tsk_fs_file_attr_get_idx(file, i);
        if (attr && is_attr_on_disk(attr)) {
            tsk_fs_attr_walk(
                    attr,                           // file attribute to log offsets
                    file_walk_flags,                // walk options
                    log_attr_offsets_in_filesystem, // action for each attr
                    data                            // argument for action
                    );
        }
    }
}
Ejemplo n.º 7
0
/* 
 * call back action function for dent_walk
 */
static TSK_WALK_RET_ENUM
print_dent_act(TSK_FS_FILE * fs_file, const char *a_path, void *ptr)
{
    FLS_DATA *fls_data = (FLS_DATA *) ptr;

    /* only print dirs if TSK_FS_FLS_DIR is set and only print everything
     ** else if TSK_FS_FLS_FILE is set (or we aren't sure what it is)
     */
    if (((fls_data->flags & TSK_FS_FLS_DIR) &&
            ((fs_file->meta) &&
                (fs_file->meta->type == TSK_FS_META_TYPE_DIR)))
        || ((fls_data->flags & TSK_FS_FLS_FILE) && (((fs_file->meta)
                    && (fs_file->meta->type != TSK_FS_META_TYPE_DIR))
                || (!fs_file->meta)))) {


        /* Make a special case for NTFS so we can identify all of the
         * alternate data streams!
         */
        if ((TSK_FS_TYPE_ISNTFS(fs_file->fs_info->ftype))
            && (fs_file->meta)) {
            uint8_t printed = 0;
            int i, cnt;

            // cycle through the attributes
            cnt = tsk_fs_file_attr_getsize(fs_file);
            for (i = 0; i < cnt; i++) {
                const TSK_FS_ATTR *fs_attr =
                    tsk_fs_file_attr_get_idx(fs_file, i);
                if (!fs_attr)
                    continue;

                if (fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_DATA) {
                    printed = 1;

                    if (fs_file->meta->type == TSK_FS_META_TYPE_DIR) {

                        /* we don't want to print the ..:blah stream if
                         * the -a flag was not given
                         */
                        if ((fs_file->name->name[0] == '.')
                            && (fs_file->name->name[1])
                            && (fs_file->name->name[2] == '\0')
                            && ((fls_data->flags & TSK_FS_FLS_DOT) == 0)) {
                            continue;
                        }
                    }

                    printit(fs_file, a_path, fs_attr, fls_data);
                }
                else if (fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_IDXROOT) {
                    printed = 1;

                    /* If it is . or .. only print it if the flags say so,
                     * we continue with other streams though in case the 
                     * directory has a data stream 
                     */
                    if (!((TSK_FS_ISDOT(fs_file->name->name)) &&
                            ((fls_data->flags & TSK_FS_FLS_DOT) == 0)))
                        printit(fs_file, a_path, fs_attr, fls_data);
                }
                /* Print the FILE_NAME times if this is the same attribute
                 * that we collected the times from. */
                else if ((fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_FNAME) &&
                    (fs_attr->id == fs_file->meta->time2.ntfs.fn_id) &&
                    (fls_data->flags & TSK_FS_FLS_MAC)) {
                    /* If it is . or .. only print it if the flags say so,
                     * we continue with other streams though in case the 
                     * directory has a data stream 
                     */
                    if (!((TSK_FS_ISDOT(fs_file->name->name)) &&
                            ((fls_data->flags & TSK_FS_FLS_DOT) == 0)))
                        printit(fs_file, a_path, fs_attr, fls_data);
                }
            }

            /* A user reported that an allocated file had the standard
             * attributes, but no $Data.  We should print something */
            if (printed == 0) {
                printit(fs_file, a_path, NULL, fls_data);
            }

        }
        else {
            /* skip it if it is . or .. and we don't want them */
            if (!((TSK_FS_ISDOT(fs_file->name->name))
                    && ((fls_data->flags & TSK_FS_FLS_DOT) == 0)))
                printit(fs_file, a_path, NULL, fls_data);
        }
    }
    return TSK_WALK_CONT;
}
Ejemplo n.º 8
0
/* inode walk call back for tsk_fs_ifind_par to find unallocated files
 * based on parent directory
 */
static TSK_WALK_RET_ENUM
ifind_par_act(TSK_FS_FILE * fs_file, void *ptr)
{
    IFIND_PAR_DATA *data = (IFIND_PAR_DATA *) ptr;
    TSK_FS_META_NAME_LIST *fs_name_list;

    /* go through each file name attribute for this file */
    fs_name_list = fs_file->meta->name2;
    while (fs_name_list) {

        /* we found a file that has the target parent directory.
         * Make a FS_NAME structure and print it.  */
        if (fs_name_list->par_inode == data->parinode) {
            int i, cnt;
            uint8_t printed;
            TSK_FS_NAME *fs_name;

            if ((fs_name = tsk_fs_name_alloc(256, 0)) == NULL)
                return TSK_WALK_ERROR;

            /* Fill in the basics of the fs_name entry
             * so we can print in the fls formats */
            fs_name->meta_addr = fs_file->meta->addr;
            fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC;
            strncpy(fs_name->name, fs_name_list->name, fs_name->name_size);

            // now look for the $Data and $IDXROOT attributes
            fs_file->name = fs_name;
            printed = 0;

            // cycle through the attributes
            cnt = tsk_fs_file_attr_getsize(fs_file);
            for (i = 0; i < cnt; i++) {
                const TSK_FS_ATTR *fs_attr =
                    tsk_fs_file_attr_get_idx(fs_file, i);
                if (!fs_attr)
                    continue;

                if ((fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_DATA)
                    || (fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_IDXROOT)) {

                    if (data->flags & TSK_FS_IFIND_PAR_LONG) {
                        tsk_fs_name_print_long(stdout, fs_file, NULL,
                            fs_file->fs_info, fs_attr, 0, 0);
                        tsk_printf("\n");
                    }
                    else {
                        tsk_fs_name_print(stdout, fs_file, NULL,
                            fs_file->fs_info, fs_attr, 0);
                        tsk_printf("\n");
                    }
                    printed = 1;
                }
            }

            // if there were no attributes, print what we got
            if (printed == 0) {
                if (data->flags & TSK_FS_IFIND_PAR_LONG) {
                    tsk_fs_name_print_long(stdout, fs_file, NULL,
                        fs_file->fs_info, NULL, 0, 0);
                    tsk_printf("\n");
                }
                else {
                    tsk_fs_name_print(stdout, fs_file, NULL,
                        fs_file->fs_info, NULL, 0);
                    tsk_printf("\n");
                }
            }
            tsk_fs_name_free(fs_name);
            data->found = 1;
        }
        fs_name_list = fs_name_list->next;
    }

    return TSK_WALK_CONT;
}
Ejemplo n.º 9
0
/**
 * \ingroup fslib
 *
 * Find the meta data address for a given file name (UTF-8).
 * The basic idea of the function is to break the given name into its
 * subdirectories and start looking for each (starting in the root
 * directory).
 *
 * @param a_fs FS to analyze
 * @param a_path UTF-8 path of file to search for
 * @param [out] a_result Meta data address of file
 * @param [out] a_fs_name Copy of name details (or NULL if details not wanted)
 * @returns -1 on (system) error, 0 if found, and 1 if not found
 */
int8_t
tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path,
    TSK_INUM_T * a_result, TSK_FS_NAME * a_fs_name)
{
    char *cpath;
    size_t clen;
    char *cur_dir;              // The "current" directory or file we are looking for
    char *cur_attr;             // The "current" attribute of the dir we are looking for
    TSK_INUM_T next_meta;
    uint8_t is_done;
    char *strtok_last;
    *a_result = 0;

    // copy path to a buffer that we can modify
    clen = strlen(a_path) + 1;
    if ((cpath = (char *) tsk_malloc(clen)) == NULL) {
        return -1;
    }
    strncpy(cpath, a_path, clen);

    // Get the first part of the directory path.
    cur_dir = (char *) strtok_r(cpath, "/", &strtok_last);
    cur_attr = NULL;

    /* If there is no token, then only a '/' was given */
    if (cur_dir == NULL) {
        free(cpath);
        *a_result = a_fs->root_inum;

        // create the dummy entry if needed
        if (a_fs_name) {
            a_fs_name->meta_addr = a_fs->root_inum;
            // Note that we are not filling in meta_seq -- we could, we just aren't

            a_fs_name->type = TSK_FS_NAME_TYPE_DIR;
            a_fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
            if (a_fs_name->name)
                a_fs_name->name[0] = '\0';
            if (a_fs_name->shrt_name)
                a_fs_name->shrt_name[0] = '\0';
        }
        return 0;
    }

    /* If this is NTFS, separate out the attribute of the current directory */
    if (TSK_FS_TYPE_ISNTFS(a_fs->ftype)
        && ((cur_attr = strchr(cur_dir, ':')) != NULL)) {
        *(cur_attr) = '\0';
        cur_attr++;
    }

    if (tsk_verbose)
        tsk_fprintf(stderr, "Looking for %s\n", cur_dir);

    // initialize the first place to look, the root dir
    next_meta = a_fs->root_inum;

    // we loop until we know the outcome and then exit.
    // everything should return from inside the loop.
    is_done = 0;
    while (is_done == 0) {
        size_t i;
        TSK_FS_FILE *fs_file_alloc = NULL;      // set to the allocated file that is our target
        TSK_FS_FILE *fs_file_del = NULL;        // set to an unallocated file that matches our criteria

        TSK_FS_DIR *fs_dir = NULL;

        // open the next directory in the recursion
        if ((fs_dir = tsk_fs_dir_open_meta(a_fs, next_meta)) == NULL) {
            free(cpath);
            return -1;
        }

        /* Verify this is indeed a directory.  We had one reported
         * problem where a file was a disk image and opening it as
         * a directory found the directory entries inside of the file
         * and this caused problems... */
        if ( !TSK_FS_IS_DIR_META(fs_dir->fs_file->meta->type)) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_GENFS);
            tsk_error_set_errstr("Address %" PRIuINUM
                " is not for a directory\n", next_meta);
            free(cpath);
            return -1;
        }

        // cycle through each entry
        for (i = 0; i < tsk_fs_dir_getsize(fs_dir); i++) {

            TSK_FS_FILE *fs_file;
            uint8_t found_name = 0;

            if ((fs_file = tsk_fs_dir_get(fs_dir, i)) == NULL) {
                tsk_fs_dir_close(fs_dir);
                free(cpath);
                return -1;
            }

            /*
             * Check if this is the name that we are currently looking for,
             * as identified in 'cur_dir'
             */
            if ((fs_file->name->name)
                && (a_fs->name_cmp(a_fs, fs_file->name->name,
                        cur_dir) == 0)) {
                found_name = 1;
            }
            else if ((fs_file->name->shrt_name)
                && (a_fs->name_cmp(a_fs, fs_file->name->shrt_name,
                        cur_dir) == 0)) {
                found_name = 1;
            }

            /* For NTFS, we have to check the attribute name. */
            if ((found_name == 1) && (TSK_FS_TYPE_ISNTFS(a_fs->ftype))) {
                /*  ensure we have the right attribute name */
                if (cur_attr != NULL) {
                    found_name = 0;
                    if (fs_file->meta) {
                        int cnt, i;

                        // cycle through the attributes
                        cnt = tsk_fs_file_attr_getsize(fs_file);
                        for (i = 0; i < cnt; i++) {
                            const TSK_FS_ATTR *fs_attr =
                                tsk_fs_file_attr_get_idx(fs_file, i);
                            if (!fs_attr)
                                continue;

                            if ((fs_attr->name)
                                && (a_fs->name_cmp(a_fs, fs_attr->name,
                                        cur_attr) == 0)) {
                                found_name = 1;
                                break;
                            }
                        }
                    }
                }
            }

            if (found_name) {
                /* If we found our file and it is allocated, then stop. If
                 * it is unallocated, keep on going to see if we can get
                 * an allocated hit */
                if (fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC) {
                    fs_file_alloc = fs_file;
                    break;
                }
                else {
                    // if we already have an unalloc and its addr is 0, then use the new one
                    if ((fs_file_del)
                        && (fs_file_del->name->meta_addr == 0)) {
                        tsk_fs_file_close(fs_file_del);
                    }
                    fs_file_del = fs_file;
                }
            }
            // close the file if we did not save it for future analysis.
            else {
                tsk_fs_file_close(fs_file);
                fs_file = NULL;
            }
        }

        // we found a directory, go into it
        if ((fs_file_alloc) || (fs_file_del)) {

            const char *pname;
            TSK_FS_FILE *fs_file_tmp;

            // choose the alloc one first (if they both exist)
            if (fs_file_alloc)
                fs_file_tmp = fs_file_alloc;
            else
                fs_file_tmp = fs_file_del;

            pname = cur_dir;    // save a copy of the current name pointer

            // advance to the next name
            cur_dir = (char *) strtok_r(NULL, "/", &(strtok_last));
            cur_attr = NULL;

            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "Found it (%s), now looking for %s\n", pname, cur_dir);

            /* That was the last name in the path -- we found the file! */
            if (cur_dir == NULL) {
                *a_result = fs_file_tmp->name->meta_addr;

                // make a copy if one was requested
                if (a_fs_name) {
                    tsk_fs_name_copy(a_fs_name, fs_file_tmp->name);
                }

                if (fs_file_alloc)
                    tsk_fs_file_close(fs_file_alloc);
                if (fs_file_del)
                    tsk_fs_file_close(fs_file_del);

                tsk_fs_dir_close(fs_dir);
                free(cpath);
                return 0;
            }

            // update the attribute field, if needed
            if (TSK_FS_TYPE_ISNTFS(a_fs->ftype)
                && ((cur_attr = strchr(cur_dir, ':')) != NULL)) {
                *(cur_attr) = '\0';
                cur_attr++;
            }

            // update the value for the next directory to open
            next_meta = fs_file_tmp->name->meta_addr;

            if (fs_file_alloc) {
                tsk_fs_file_close(fs_file_alloc);
                fs_file_alloc = NULL;
            }
            if (fs_file_del) {
                tsk_fs_file_close(fs_file_del);
                fs_file_del = NULL;
            }
        }

        // no hit in directory
        else {
            is_done = 1;
        }

        tsk_fs_dir_close(fs_dir);
        fs_dir = NULL;
    }

    free(cpath);
    return 1;
}
Ejemplo n.º 10
0
/* Verify that all attributes can be accessed from both get_idx and get_type...
 * @param a_addr The metadata address of the file to analyze
 * @param a_len Expected number of attributes in file.
 * @returns 1 if a test failed
 */
static int
test_get_apis(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr, int a_len)
{
    TSK_FS_FILE *fs_file;
    int retval = 0;

    // open the file
    fs_file = tsk_fs_file_open_meta(a_fs, NULL, a_addr);
    if (!fs_file) {
        fprintf(stderr, "Error opening file %" PRIuINUM " via meta\n",
            a_addr);
        tsk_error_print(stderr);
        return 1;
    }

    int len = tsk_fs_file_attr_getsize(fs_file);
    if (len != a_len) {
        fprintf(stderr,
            "%" PRIuINUM
            " attribute count diff from expected (%d vs %d)\n", a_addr,
            a_len, len);
        tsk_error_print(stderr);
        return 1;
    }

    for (int i = 0; i < len; i++) {

        // get the attribute by index
        const TSK_FS_ATTR *fs_attr = tsk_fs_file_attr_get_idx(fs_file, i);
        if (!fs_attr) {
            fprintf(stderr,
                "Error getting attribute %d from %" PRIuINUM "\n", i,
                a_addr);
            tsk_error_print(stderr);
            return 1;
        }

        // verify we can also get it via type / id
        const TSK_FS_ATTR *fs_attr2 =
            tsk_fs_file_attr_get_type(fs_file, fs_attr->type, fs_attr->id,
            1);
        if (!fs_attr2) {
            fprintf(stderr,
                "Error getting attribute %d-%d from %" PRIuINUM "\n",
                fs_attr->type, fs_attr->id, a_addr);
            tsk_error_print(stderr);
            return 1;
        }

        if ((fs_attr->type != fs_attr2->type)
            || (fs_attr->id != fs_attr2->id)) {
            fprintf(stderr,
                "Attribute from get_type not expected %d-%d vs %d-%d from %"
                PRIuINUM "\n", fs_attr->type, fs_attr->id, fs_attr2->type,
                fs_attr2->id, a_addr);
            tsk_error_print(stderr);
            return 1;
        }

        if (fs_attr != fs_attr2) {
            fprintf(stderr,
                "Attribute from get_type not same addr as original %lu vs %lu from %"
                PRIuINUM "\n", (long) fs_attr, (long) fs_attr2, a_addr);
            tsk_error_print(stderr);
            return 1;
        }

        // verify we also get something via only type
        fs_attr2 = tsk_fs_file_attr_get_type(fs_file, fs_attr->type, 0, 0);
        if (!fs_attr2) {
            fprintf(stderr,
                "Error getting attribute %d (no id) from %" PRIuINUM "\n",
                fs_attr->type, a_addr);
            tsk_error_print(stderr);
            return 1;
        }

        if (fs_attr->type != fs_attr2->type) {
            fprintf(stderr,
                "Attribute from get_type (no id) not expected %d vs %d from %"
                PRIuINUM "\n", fs_attr->type, fs_attr2->type, a_addr);
            tsk_error_print(stderr);
            return 1;
        }

        // Try with a "random" ID: Note this atribute could actually exist...
        fs_attr2 =
            tsk_fs_file_attr_get_type(fs_file, fs_attr->type, 0xfd, 1);
        if (fs_attr2) {
            fprintf(stderr,
                "Got unexpected attribute %d-0xfd (random ID) from %"
                PRIuINUM "\n", fs_attr->type, a_addr);
            tsk_error_print(stderr);
            return 1;
        }
        else if (tsk_error_get_errno() != TSK_ERR_FS_ATTR_NOTFOUND) {
            fprintf(stderr,
                "Unexpected error code %x from getting %d-0xfd (random ID) from %"
                PRIuINUM "\n", (int)tsk_error_get_errno(), fs_attr->type, a_addr);
            tsk_error_print(stderr);
            return 1;
        }
        tsk_error_reset();

        // Try with a "random" type Note this atribute could actually exist...
        fs_attr2 =
            tsk_fs_file_attr_get_type(fs_file,
            (TSK_FS_ATTR_TYPE_ENUM) (fs_attr->type + 37), 0, 0);
        if (fs_attr2) {
            fprintf(stderr,
                "Got unexpected attribute %d-X (random type, no id) from %"
                PRIuINUM "\n", fs_attr->type + 37, a_addr);
            tsk_error_print(stderr);
            return 1;
        }
        else if (tsk_error_get_errno() != TSK_ERR_FS_ATTR_NOTFOUND) {
            fprintf(stderr,
                "Unexpected error code %x from getting %d-X (random type, no id) from %"
                PRIuINUM "\n", (int)tsk_error_get_errno(), fs_attr->type, a_addr);
            tsk_error_print(stderr);
            return 1;
        }
        tsk_error_reset();

    }

    tsk_fs_file_close(fs_file);

    return retval;
}