コード例 #1
0
ファイル: fs_attr.c プロジェクト: judsonp/sleuthkit
/**
 * \internal
 * Add a set of consecutive runs to an attribute. This will add and remove FILLER entries
 * as needed and update internal variables. 
 *
 * @param a_fs File system run is from
 * @param fs_attr Attribute to add run to
 * @param a_data_run_new The set of runs to add.  
 *
 * @returns 1 on error and 0 on succes
 */
uint8_t
tsk_fs_attr_add_run(TSK_FS_INFO * a_fs, TSK_FS_ATTR * a_fs_attr,
    TSK_FS_ATTR_RUN * a_data_run_new)
{
    TSK_FS_ATTR_RUN *data_run_cur, *data_run_prev;
    TSK_DADDR_T run_len;

    tsk_error_reset();

    if (a_fs_attr == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("tsk_fs_attr_add_run: Error, a_fs_attr is NULL");
        return 1;
    }

    // we only support the case of a null run if it is the only run...
    if (a_data_run_new == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("tsk_fs_attr_add_run: Error, a_data_run_new is NULL (%"
            PRIuINUM ")", a_fs_attr->fs_file->meta->addr);
        return 1;
    }

    run_len = 0;
    data_run_cur = a_data_run_new;
    while (data_run_cur) {
        run_len += data_run_cur->len;
        data_run_cur = data_run_cur->next;
    }

    /* First thing, is to check if we can just add it to the end */
    if ((a_fs_attr->nrd.run_end)
        && (a_fs_attr->nrd.run_end->offset + a_fs_attr->nrd.run_end->len ==
            a_data_run_new->offset)) {

        a_fs_attr->nrd.run_end->next = a_data_run_new;
        // update the pointer to the end of the list
        while (a_fs_attr->nrd.run_end->next)
            a_fs_attr->nrd.run_end = a_fs_attr->nrd.run_end->next;

        /* return head of a_fs_attr list */
        return 0;
    }

    // cycle through existing runs and see if we can add this into a filler spot
    data_run_cur = a_fs_attr->nrd.run;
    data_run_prev = NULL;
    while (data_run_cur) {

        if (tsk_verbose)
            tsk_fprintf(stderr,
                "tsk_fs_attr_add: %" PRIuOFF "@%" PRIuOFF
                " (Filler: %s)\n", data_run_cur->offset, data_run_cur->len,
                (data_run_cur->flags & TSK_FS_ATTR_RUN_FLAG_FILLER) ? "Yes"
                : "No");

        /* Do we replace this filler spot? */
        if (data_run_cur->flags & TSK_FS_ATTR_RUN_FLAG_FILLER) {

            /* This should never happen because we always add 
             * the filler to start from VCN 0 */
            if (data_run_cur->offset > a_data_run_new->offset) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_FS_GENFS);
                tsk_error_set_errstr
                    ("tsk_fs_attr_add_run: could not add data_run b.c. offset (%"
                    PRIuOFF ") is larger than FILLER (%" PRIuOFF ") (%"
                    PRIuINUM ")", a_data_run_new->offset,
                    data_run_cur->offset, a_fs_attr->fs_file->meta->addr);
                dump_attr(a_fs_attr);
                return 1;
            }

            /* Check if the new run starts inside of this filler. */
            if (data_run_cur->offset + data_run_cur->len >
                a_data_run_new->offset) {
                TSK_FS_ATTR_RUN *endrun;

                /* if the new starts at the same as the filler, 
                 * replace the pointer */
                if (data_run_cur->offset == a_data_run_new->offset) {
                    if (data_run_prev)
                        data_run_prev->next = a_data_run_new;
                    else
                        a_fs_attr->nrd.run = a_data_run_new;
                }

                /* The new run does not start at the begining of
                 * the filler, so make a new start filler
                 */
                else {
                    TSK_FS_ATTR_RUN *newfill = tsk_fs_attr_run_alloc();
                    if (newfill == NULL)
                        return 1;

                    if (data_run_prev)
                        data_run_prev->next = newfill;
                    else
                        a_fs_attr->nrd.run = newfill;

                    newfill->next = a_data_run_new;
                    newfill->len =
                        a_data_run_new->offset - data_run_cur->offset;
                    newfill->offset = data_run_cur->offset;
                    newfill->flags = TSK_FS_ATTR_RUN_FLAG_FILLER;

                    data_run_cur->len -= newfill->len;
                }

                /* get to the end of the run that we are trying to add */
                endrun = a_data_run_new;
                while (endrun->next)
                    endrun = endrun->next;

                /* if the filler is the same size as the
                 * new one, replace it 
                 */
                if (run_len == data_run_cur->len) {
                    endrun->next = data_run_cur->next;

                    // update the pointer to the end of the list (if we are the end)
                    if (endrun->next == NULL)
                        a_fs_attr->nrd.run_end = endrun;

                    free(data_run_cur);
                }
                /* else adjust the last filler entry */
                else {
                    endrun->next = data_run_cur;
                    data_run_cur->len -= run_len;
                    data_run_cur->offset =
                        a_data_run_new->offset + a_data_run_new->len;
                }

                return 0;
            }
        }

        data_run_prev = data_run_cur;
        data_run_cur = data_run_cur->next;
    }


    /* 
     * There is no filler holding the location of this run, so
     * we will add it to the end of the list 
     * 
     * we got here because it did not fit in the current list or
     * because the current list is NULL
     *
     * At this point data_run_prev is the end of the existing list or
     * 0 if there is no list
     */
    /* This is an error condition.  
     * It means that we cycled through the existing runs,
     * ended at a VCN that is larger than what we are adding,
     * and never found a filler entry to insert it into... 
     */
    if ((data_run_prev)
        && (data_run_prev->offset + data_run_prev->len >
            a_data_run_new->offset)) {

        /* MAYBE this is because of a duplicate entry .. */
        if ((data_run_prev->addr == a_data_run_new->addr) &&
            (data_run_prev->len == a_data_run_new->len)) {
            // @@@ Sould be we freeing this....?  What if the caller tries to write to it?
            tsk_fs_attr_run_free(a_data_run_new);
            return 0;
        }

        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_GENFS);
        tsk_error_set_errstr
            ("fs_attr_add_run: error adding additional run (%" PRIuINUM
            "): No filler entry for %" PRIuDADDR ". Final: %" PRIuDADDR,
            a_fs_attr->fs_file->meta->addr, a_data_run_new->offset,
            data_run_prev->offset + data_run_prev->len);
        dump_attr(a_fs_attr);
        return 1;
    }

    /* we should add it right here */
    else if (((data_run_prev)
            && (data_run_prev->offset + data_run_prev->len ==
                a_data_run_new->offset))
        || (a_data_run_new->offset == 0)) {
        if (data_run_prev)
            data_run_prev->next = a_data_run_new;
        else
            a_fs_attr->nrd.run = a_data_run_new;
    }
    /* we need to make a filler before it */
    else {
        TSK_FS_ATTR_RUN *tmprun = tsk_fs_attr_run_alloc();
        if (tmprun == NULL)
            return 1;

        if (data_run_prev) {
            data_run_prev->next = tmprun;
            tmprun->offset = data_run_prev->offset + data_run_prev->len;
        }
        else {
            a_fs_attr->nrd.run = tmprun;
        }

        tmprun->len = a_data_run_new->offset - tmprun->offset;
        tmprun->flags = TSK_FS_ATTR_RUN_FLAG_FILLER;
        tmprun->next = a_data_run_new;
    }

    // update the pointer to the end of the list
    a_fs_attr->nrd.run_end = a_data_run_new;
    while (a_fs_attr->nrd.run_end->next)
        a_fs_attr->nrd.run_end = a_fs_attr->nrd.run_end->next;

    return 0;
}
コード例 #2
0
ファイル: unix_misc.c プロジェクト: eugene7646/sleuthkit
/** \internal
 * Process an array of addresses and turn them into runs
 *
 * @param fs File system to analyze
 * @param fs_attr Data attribute to add runs to
 * @param addrs Buffer of addresses to process and turn into runs
 * @param addr_len Number of addresses in buffer
 * @param length Length of file remaining
 *
 * @returns the number of bytes processed and -1 if an error occurred
 */
static TSK_OFF_T
unix_make_data_run_direct(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr,
    TSK_DADDR_T * addrs, size_t addr_len, TSK_OFF_T length)
{
    TSK_DADDR_T run_start = 0;
    TSK_DADDR_T run_len = 0;
    TSK_DADDR_T blks_processed = 0;
    size_t i;
    size_t fs_blen;             // how big is each "block" (in fragments)

    if (addr_len == 0) {
        return 0;
    }

    // block_size is a fragment size in UFS, so we need to maintain length in fragments
    if (TSK_FS_TYPE_ISFFS(fs->ftype)) {
        FFS_INFO *ffs = (FFS_INFO *) fs;
        fs_blen = ffs->ffsbsize_f;
    }
    else {
        fs_blen = 1;
    }

    run_start = addrs[0];
    run_len = fs_blen;

    /* Note that we are lazy about length.  We stop only when a run is past length,
     * we do not end exactly at length -- although that should happen anyway.  
     */
    for (i = 0; i < addr_len; i++) {

        /* Make a new run if:
         * - This is the last addresss in the buffer
         * - The next address is not part of the current run
         * -- special case for sparse since they use 0 as an address
         */
        if ((i + 1 == addr_len) ||
            ((run_start + run_len != addrs[i + 1]) && (run_start != 0)) ||
            ((run_start == 0) && (addrs[i + 1] != 0))) {

            TSK_FS_ATTR_RUN *data_run;

            // make a non-resident run
            data_run = tsk_fs_attr_run_alloc();
            if (data_run == NULL)
                return -1;

            data_run->addr = run_start;
            data_run->len = run_len;

            if (run_start == 0)
                data_run->flags = TSK_FS_ATTR_RUN_FLAG_SPARSE;

            // save the run
            tsk_fs_attr_append_run(fs, fs_attr, data_run);

            // get ready for the next run
            if (i + 1 != addr_len)
                run_start = addrs[i + 1];
            run_len = 0;

            // stop if we are past the length requested
            if (blks_processed * fs->block_size > (TSK_DADDR_T) length)
                break;
        }
        run_len += fs_blen;
        blks_processed += fs_blen;
    }

    return blks_processed * fs->block_size;
}
コード例 #3
0
ファイル: fs_attr.c プロジェクト: judsonp/sleuthkit
/**
 * \internal
 * Set the needed fields along with an initial run list for a data attribute.  To add more 
 * runs, use ...._add_run().
 *
 * @param a_fs File system the run comes from.
 * @param a_fs_attr The data attribute to initialize and add the run to
 * @param a_data_run_new The set of runs to add (can be NULL).
 * @param name Name of the attribute (can be NULL)
 * @param type Type of attribute to add run to
 * @param id Id of attribute to add run to
 * @param size Total size of the attribute (can be larger than length of initial run being added) 
 * @param init_size Number of bytes in attribute that have been initialized (less then or equal to size)
 * (note that this sets the initialized size for the attribute and it will not be updated as more runs are added).
 * @param alloc_size Allocated size of the attribute (>= size).  Identifies the slack space. 
 * (note that this sets the allocated size for the attribute and it will not be updated as more runs are added).
 * @param flags Flags about compression, sparse etc. of data
 * @param compsize Compression unit size (in case it needs to be created)
 *
 * @returns 1 on error and 0 on success
 */
uint8_t
tsk_fs_attr_set_run(TSK_FS_FILE * a_fs_file, TSK_FS_ATTR * a_fs_attr,
    TSK_FS_ATTR_RUN * a_data_run_new, const char *name,
    TSK_FS_ATTR_TYPE_ENUM type, uint16_t id, TSK_OFF_T size,
    TSK_OFF_T init_size, TSK_OFF_T alloc_size,
    TSK_FS_ATTR_FLAG_ENUM flags, uint32_t compsize)
{
    if ((a_fs_file == NULL) || (a_fs_file->meta == NULL)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("Null fs_file in tsk_fs_attr_set_run");
        return 1;
    }
    if (a_fs_attr == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("Null fs_attr in tsk_fs_attr_set_run");
        return 1;
    }

    if (alloc_size < size) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("tsk_fs_attr_set_run: alloc_size (%" PRIuOFF
            ") is less than size (%" PRIuOFF ")", alloc_size, size);
        return 1;
    }

    a_fs_attr->fs_file = a_fs_file;
    a_fs_attr->flags = (TSK_FS_ATTR_INUSE | TSK_FS_ATTR_NONRES | flags);
    a_fs_attr->type = type;
    a_fs_attr->id = id;
    a_fs_attr->size = size;
    a_fs_attr->nrd.allocsize = alloc_size;
    a_fs_attr->nrd.initsize = init_size;
    a_fs_attr->nrd.compsize = compsize;

    if (fs_attr_put_name(a_fs_attr, name)) {
        return 1;
    }

    /* Add the a_data_run_new to the attribute. */

    /* We support the ODD case where the run is NULL.  In this case, 
     * we set the attribute size info, but set everything else to NULL.
     */
    if (a_data_run_new == NULL) {
        a_fs_attr->nrd.run = NULL;
        a_fs_attr->nrd.run_end = NULL;
        return 0;
    }


    /*
     * If this is not in the begining, then we need to make a filler 
     * to account for the cluster numbers we haven't seen yet
     *
     * This commonly happens when we process an MFT entry that
     * is not a base entry and it is referenced in an $ATTR_LIST
     *
     * The $DATA attribute in the non-base have a non-zero
     * a_data_run_new->offset.  
     */
    if (a_data_run_new->offset != 0) {
        TSK_FS_ATTR_RUN *fill_run = tsk_fs_attr_run_alloc();
        fill_run->flags = TSK_FS_ATTR_RUN_FLAG_FILLER;
        fill_run->offset = 0;
        fill_run->addr = 0;
        fill_run->len = a_data_run_new->offset;
        fill_run->next = a_data_run_new;
        a_data_run_new = fill_run;
    }

    a_fs_attr->nrd.run = a_data_run_new;

    // update the pointer to the end of the list
    a_fs_attr->nrd.run_end = a_data_run_new;
    while (a_fs_attr->nrd.run_end->next) {
        a_fs_attr->nrd.run_end = a_fs_attr->nrd.run_end->next;
    }

    return 0;
}
コード例 #4
0
ファイル: unix_misc.c プロジェクト: eugene7646/sleuthkit
/** \internal
 * Read an indirect block and process the contents to make a runlist from the pointers. 
 *
 * @param fs File system to analyze
 * @param fs_attr Structure to save run data into
 * @param fs_attr_indir Structure to save addresses of indirect block pointers in
 * @param buf Buffers to read block data into (0 is block sized, 1+ are DADDR_T arrays based on FS type)
 * @param level Indirection level that this will process at (1+)
 * @param addr Address of block to read
 * @param length Length of file remaining
 *
 * @returns the number of bytes processed during call and -1 if an error occurred
 */
static TSK_OFF_T
unix_make_data_run_indirect(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr,
    TSK_FS_ATTR * fs_attr_indir, char *buf[], int level, TSK_DADDR_T addr,
    TSK_OFF_T length)
{
    char *myname = "unix_make_data_run_indirect";
    size_t addr_cnt = 0;
    TSK_DADDR_T *myaddrs = (TSK_DADDR_T *) buf[level];
    TSK_OFF_T length_remain = length;
    TSK_OFF_T retval;
    size_t fs_bufsize;
    size_t fs_blen;
    TSK_FS_ATTR_RUN *data_run;

    if (tsk_verbose)
        tsk_fprintf(stderr, "%s: level %d block %" PRIuDADDR "\n", myname,
            level, addr);

    // block_size is a fragment size in UFS, so we need to maintain length in fragments
    if (TSK_FS_TYPE_ISFFS(fs->ftype)) {
        FFS_INFO *ffs = (FFS_INFO *) fs;
        fs_blen = ffs->ffsbsize_f;
        fs_bufsize = ffs->ffsbsize_b;
    }
    else {
        fs_blen = 1;
        fs_bufsize = fs->block_size;
    }

    if (addr > fs->last_block) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
        tsk_error_set_errstr("unix: Indirect block address too large: %"
            PRIuDADDR "", addr);
        return -1;
    }

    // make a non-resident run
    data_run = tsk_fs_attr_run_alloc();
    if (data_run == NULL)
        return -1;

    data_run->addr = addr;
    data_run->len = fs_blen;

    /*
     * Read a block of disk addresses.
     */
    // sparse
    if (addr == 0) {
        memset(buf[0], 0, fs_bufsize);
        data_run->flags = TSK_FS_ATTR_RUN_FLAG_SPARSE;
    }
    else {
        ssize_t cnt;
        // read the data into the scratch buffer
        cnt = tsk_fs_read_block(fs, addr, buf[0], fs_bufsize);
        if (cnt != fs_bufsize) {
            if (cnt >= 0) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_FS_READ);
            }
            tsk_error_set_errstr2("unix_make_data_run_indir: Block %"
                PRIuDADDR, addr);
            return -1;
        }
    }

    // save the run
    tsk_fs_attr_append_run(fs, fs_attr_indir, data_run);

    // convert the raw addresses to the correct endian ordering
    if ((fs->ftype == TSK_FS_TYPE_FFS1)
        || (fs->ftype == TSK_FS_TYPE_FFS1B)
        || (TSK_FS_TYPE_ISEXT(fs->ftype))) {
        size_t n;
        uint32_t *iaddr = (uint32_t *) buf[0];
        addr_cnt = fs_bufsize / sizeof(*iaddr);
        for (n = 0; n < addr_cnt; n++) {
            myaddrs[n] = tsk_getu32(fs->endian, (uint8_t *) & iaddr[n]);
        }
    }
    else if (fs->ftype == TSK_FS_TYPE_FFS2) {
        size_t n;
        uint64_t *iaddr = (uint64_t *) buf[0];
        addr_cnt = fs_bufsize / sizeof(*iaddr);
        for (n = 0; n < addr_cnt; n++) {
            myaddrs[n] = tsk_getu64(fs->endian, (uint8_t *) & iaddr[n]);
        }
    }

    // pass the addresses to the next level
    if (level == 1) {
        retval =
            unix_make_data_run_direct(fs, fs_attr, myaddrs, addr_cnt,
            length_remain);
        if (retval != -1) {
            length_remain -= retval;
        }
    }
    else {
        size_t i;
        retval = 0;
        for (i = 0; i < addr_cnt && retval != -1; i++) {
            retval =
                unix_make_data_run_indirect(fs, fs_attr, fs_attr_indir,
                buf, level - 1, myaddrs[i], length_remain);
            if (retval == -1) {
                break;
            }
            else {
                length_remain -= retval;
            }
        }
    }

    if (retval == -1)
        return -1;
    else
        return length - length_remain;
}