0

All of the first 49 images get recovered fine except the last one. I have went through the code a lot, but still can't find the problem.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define true 1
#define false 0

int EndFinder(FILE *file);

int main(int argc, char *argv[])
{
    // checks if there are two CLAs
    if (argc != 2)
    {
        printf("Usage: ./recover IMAGE\n");
        return 1;
    }

    // opens the forensic image
    FILE *raw = fopen(argv[1], "r");
    if (raw == NULL)
    {
        printf("Error: Can't find or open the file.\n");
        return 1;
    }

    // counts the recovered images from 0
    int picCount = -1;

    // array of 50 file pointers for recovered images or outputs
    FILE *rcvrd[51];
    uint8_t buffer[512];

    // iterates through the whole file
    while (1)
    {
        // reads a 512 B block
        fread(buffer, 512, 1, raw);

        // breaks the loop if it's the end of file
        if (feof(raw))
            break;

        // moves to the next block if it doesn't find a signature in the current one ...
        if (buffer[0] != 0xff || buffer[1] != 0xd8 || buffer[2] != 0xff || buffer[3] < 0xe0 || buffer[3] > 0xef)
        {
            continue;
        } // ... else if it finds the signature, it writes the recovered image into a new file and adds to picCount
        else
        {
            picCount++;

            // prompts the EndFinder for the block length of the current image
            int blockLength = EndFinder(raw);

            // creates a string in accordance with the specification for the name of the recovered image
            char name[8];
            if (picCount < 10)
                sprintf(name, "00%d.jpg", picCount);
            else
                sprintf(name, "0%d.jpg", picCount);

            // creates a file to store the image or output in
            rcvrd[picCount] = fopen(name, "w");

            // writes the first block into the output
            fwrite(buffer, 512, 1, rcvrd[picCount]);

            // if there is more than one block reads them into a buffer and writes them into the output
            for (int i = 1; i < blockLength; i++)
            {
                fread(buffer, 512, 1, raw);
                fwrite(buffer, 512, 1, rcvrd[picCount]);
            }
        }
    }
}

// finds the block length of a recovered image
int EndFinder(FILE *file)
{

    // var for the block length of the image
    int length = 1;

    // buffer for block that are goona be checked for signatures
    uint8_t buffy[512];

    // count the block length
    while (1)
    {
        // if it's end of file, go back the amount you came by and return the block length of the last image
        if (feof(file))
        {
            fseek(file, (long)-512 * length, SEEK_END);
            return length;
        }

        // read the block into buffy
        fread(buffy, 512, 1, file);

        // increase the length if not found the signature in this block
        if (buffy[0] != 0xff || buffy[1] != 0xd8 || buffy[2] != 0xff || buffy[3] < 0xe0 || buffy[3] > 0xef)
        {
            length++;
        } // if found the signature, go back the amount you came by and return the length
        else
        {
            fseek(file, (long)-512 * length, SEEK_CUR);
            return length;
        }
    }
}

1 Answer 1

0

I spent some time testing the code. It's clear that the code is not handling the EOF condition correctly. For some reason that I can't quite grasp, it's only counting 1/2 of the data blocks in the file.

Having said that, I'd like to provide some programming tips.

This code, except for the last file, appears to be working correctly, but it's overly complicated. There's an old adage in programming - "KISS - Keep It Simple, Stupid!" I end up telling myself that at some point on every project.

In this case, the biggest problem is the overall plan of reading the file to find the end of the current image, and then reading it again to process the image. Disk I/O is one of the most resource intensive and resource-expensive processes on a computer. With old style hard drives, each read takes 1000 times more time than a memory read or more. Thankfully, with solid state drives, that's been cut way down to nearly the same as a memory read. Nevertheless, double reads of the same info should always be a red flag.

It would be a lot more efficient to read data from the file only once. It's far more efficient to read in a block, determine if it has a signature or not, and process it accordingly. You'd cut the processing time roughly in half with this program. That may not seem like much here, but imagine if this were a production program running millions of times a day.

Having said all that, it would be a good exercise to figure out why this program isn't handling the last file correctly.

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .