C language: recover photos from memory card


Imagine that you deleted photos from your memory card and then wanted to restore them. It turns out that in some cases it is possible to do this, because when we delete a photo with the “delete” button, what actually happens is more like not deleting, but forgetting. The links between the bytes are lost, but the information itself is still in memory until it is overwritten with new photographs. Passing the CS50 course (Harvard) – at the end of the fourth week, we got the recover.c task, in which we are given the source file of the memory card card.raw and need to write a program that will restore all the photos.

Digital cameras often store photographs one after another in accordance with the FAT file system, where all information is divided into blocks of the same size of 512 bytes. And each photo is recorded using these blocks. Considering that photos can differ slightly in size from each other, but at the same time be recorded in the same number of blocks, it allows you to write code that sequentially goes through each block of the card’s memory and copies this data into new files. The “extra” bytes are called “unallocated space”, and even ancient photographs can be stored in it.

Code of programme (Shtukensia)

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

int main(int argc, char *argv[])
{
    // Check command-line arguments (should take 1 command-line argument)
    if (argc != 2)
    {
        printf("Usage: ./recover YOUR_IMAGE.raw\n");
        return 1;
    }

    // Open memory card and check if it can be openned for reading
    FILE *image_raw = fopen(argv[1], "r");
    if (image_raw == NULL)
    {
        printf("The forensic image cannot be opened for reading\n");
        return 1;
    }

    typedef uint8_t BYTE; // 1 byte = 8 bit unsigned int
    int BLOCK_SIZE = 512; // Size of each block of JPG files
    BYTE buffer[BLOCK_SIZE]; // Initialized the buffer for temporary data from file

    int amount_jpg = 0; // How many JPG files have been written
    int jpg_found = 0; // If JPG found = 1
    char filename[8]; // store xxx.JPG names + /0

    FILE *img = NULL; // New files for JPGs


    // Repeat until reach the end of the file
    while (fread(buffer, BLOCK_SIZE, 1, image_raw)) // Read 512 Bytes to a Buffer for data from memory card
    {

        // if starts the new JPG
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {

            // if it was NOT the first JPG
            if (amount_jpg > 0)
            {
                fclose(img); // Close previously written file
            }

            // if it was first JPG
            sprintf(filename, "%03i.jpg", amount_jpg); // Store name for new JPG in buffer
            img = fopen(filename, "w"); // open new JPG file from 001.JPG
            fwrite(buffer, BLOCK_SIZE, 1, img); // write header block to JPG
            amount_jpg += 1;
            jpg_found = 1;

        }

        // if it's not the beginning of JPG
        else
        {
            // if already found JPG
            if (jpg_found == 1)
            {
                fwrite(buffer, BLOCK_SIZE, 1, img); // write from 001.JPG and put data there
            }

        }
    }

    // programm reached the end of the file -> close files
    fclose(img);
    fclose(image_raw);
    return 0;
}

Programme (igroglaz):

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

int main(int argc, char *argv[])
{
    typedef uint8_t BYTE;
    BYTE *buffer = (BYTE *)malloc(512);
    FILE *new_file = NULL; // we have to make it there to solve scope problem
    int img_num = 0;
    char *file_num = (char *)malloc(8); // "###.jpg" is 7+1 bytes (additional 1 is for \0)

    if (argc != 2)
    {
        printf("Usage: ./recover <file>\n");
        return 1;
    }

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

    if (file == NULL)
    {
        printf("File can't be opened\n");
        return 1;
    }

    // use fread() to write chunk of 512 bytes to a buffer
    while (fread(buffer, 1, 512, file) == 512) // fread() return number of bytes it has read
    {
        // check first 4 bytes for a jpg signature
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && // start of new jpg
            ((buffer[3] & 0xf0) == 0xe0)) // for buffer[3] first four bits must be 1110
        {
            if (img_num == 0) // 1st image
            {
                // put chunk to a new file, from 000.jpg up to 999.jpg
                sprintf(file_num, "%03i.jpg", img_num++);
                new_file = fopen(file_num, "wb");
                fwrite(buffer, 1, 512, new_file);
            }
            else // we already have file, so close it and open new one
            {
                fclose(new_file);
                sprintf(file_num, "%03i.jpg", img_num++);
                new_file = fopen(file_num, "wb");
                fwrite(buffer, 1, 512, new_file);
            }
        }
        // if chunk is not start of a new file - continue writing it to existent one
        else if (img_num > 0) // new_file must be defined
        {
            fwrite(buffer, 1, 512, new_file);
        }
    }

    free(buffer);
    free(file_num);
    fclose(new_file);
    fclose(file);

    return 0;
}

 


This entry was posted in C language (en). Bookmark the permalink.

Leave a Reply

🇬🇧 Attention! Comments with URLs/email are not allowed.
🇷🇺 Комментарии со ссылками/email удаляются автоматически.