0

I´ve been working on recover for the past few days and I am having some trouble getting a working solution. The code below prints out 49 jpgs instead of 50, and they are all incomplete or very blurry. Many of the jpgs only have a small line of coloured pixels at the top (the rest being grey), leading me to think that there is something wrong with the way I am appending to the files (i.e. maybe the first FAT block gets successfully turned into jpg, but not the rest of the blocks that make up that jpg).

Also, I am not quite sure how to close the last jpg. I would have to do that inside the while loop, but only at the last time it is being run, which I still don't know how to do.

I am grateful in advance for any help :)

Best,

A somewhat lost student

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

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("Usage: recover\n");
        return 1;
    }

    FILE *file = fopen(argv[1], "r");

    if (file == NULL)
    {
        printf("oh no, can't read file\n");
        return 2;
    }

    typedef uint8_t BYTE;

    //allocate 512 bytes to a buffer (512 bytes is the size of each FAT block from our file)
    BYTE *buffer = malloc(512);

    //counter for jpgs
    int counter = 000; 

    //initialise active jpg
    FILE *active_jpg = NULL;

    //do while we can find FAT blocks
    while((fread(buffer, sizeof(BYTE), 512, file)) > 0)
    {
        //checking whether it is the beginning of a jpg
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && ((buffer[3] & 0xf0) == 0xe0))
        {
            //if this is the first jpg 
            if (active_jpg == NULL)
            {
                char filename[8];

                sprintf(filename, "%03i.jpg", counter);

                //open new file called "000.jpg" and write to it
                active_jpg = fopen(filename, "w");

                fwrite(buffer, 1, 512, active_jpg);
            }

            //else if it is the beginning of a jpg, but not our first jpg
            else if (active_jpg != NULL)
            {
                //close jpg we had been working on
                fclose(active_jpg);

                //increase jpg counter by 1
                counter++;

                //make new file, name it according to counter, and write to it from buffer
                char filename[8];

                sprintf(filename, "%03i.jpg", counter);

                active_jpg = fopen(filename, "w");

                fwrite(buffer, 1, 512, active_jpg);

            }
        }

        //else if the block is NOT the start of a jpg
        else
        {
            //if there is a jpg being written
            if (active_jpg != NULL)
            {

                char filename[8];

                sprintf(filename, "%03i.jpg", counter);

                printf("%s", filename);

                //open the active jpg in "append mode" and append the buffer info to it
                FILE *append_jpg = fopen(filename, "a+");

                fwrite(buffer, 1, 512, append_jpg);
            }
        }
    }

    //close raw memory card
    fclose(file);

    //free buffer
    free(buffer); 

}
1

Let's take a careful look at the code that is supposed to process all the data blocks that follow the signature block:

    //else if the block is NOT the start of a jpg
    else
    {
        //if there is a jpg being written
        if (active_jpg != NULL)
        {

            char filename[8];

            sprintf(filename, "%03i.jpg", counter);

            printf("%s", filename);

            //open the active jpg in "append mode" and append the buffer info to it
            FILE *append_jpg = fopen(filename, "a+");

            fwrite(buffer, 1, 512, append_jpg);
        }
    }

Obviously, the printf is diagnostic, so let's ignore that.

Here's my question. Why does the code reopen the file to append to it?

The file was opened earlier and remains open. It doesn't need to be reopened again for append. The entire IF block can be rewritten using only the fwrite statement and the existing file pointer that opened the file for write.

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

3
  • Yup, that solves it, thank you so much! I thought I had to open the file twice because the first time I was opening it to write, and the second I was appending... But now I realise I can just open it in appending mode ("a") even for a newly-created file. – HumbleCauchyServant Mar 30 '20 at 22:46
  • Not really. Think about what each of those does. If you open an existing file for "a" or append, it's going to do exactly that, append to the end of an existing file or create a new one if it doesn't exist. If you open an existing file for "w" write, it will delete the existing file. Then, it will create a new file, whether it existed or not. You need to be really careful about not opening for append when you really want to create a new file. Once a file is opened for write or append, though, you can keep writing more to that file using the same pointer until you close that pointer. – Cliff B Mar 30 '20 at 22:53
  • Also, while it is possible to open the same file with multiple pointers, and for both read and write, it's a very dangerous thing and should be avoided unless you have a really, really good reason for opening a file more than once at the same time. – Cliff B Mar 30 '20 at 22:56

You must log in to answer this question.

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