Язык Си: восстановить фотографии с карты памяти


Представьте, что вы удалили фотографии с карты памяти, а потом захотели их восстановить. Оказывается, что в некоторых случаях это возможно сделать, ведь когда мы удаляем фото кнопкой «delete», то что происходит на самом деле больше похоже не на удаление, а на забывание. Связи между байтами пропадают, но сама информация все еще находится в памяти, пока не будет перезаписана новыми  фотографиями. Проходя курс CS50 (Harvard) — в конце четвертой недели нам выпало задание recover.c, в котором нам дается исходный файл карты памяти card.raw и нужно написать программу, которая восстановит все фотографии.

Цифровые камеры зачастую хранят фотографии друг за другом в соответствии с файловой системой FAT, где вся информация разделяется на блоки одинакового размера по 512 байт. И каждая фотография записывается при помощи этих блоков. Учитывая, что фотографии могут незначительно отличаться по размеру друг от друга, но при этом записываться одинаковым количеством блоков, позволяет написать код, который последовательно пройдет по каждому блоку памяти карты и скопирует эти данные в новые файлы. «Лишние» байты называются «незанятым пространством», и в нем может сохраниться что-то даже из древних фотографий.

Код программы (Штукенция)

#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;
}

Код программы (Игроглаз):

#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;
}

 


Запись опубликована в рубрике С (Си). Добавьте в закладки постоянную ссылку.

Добавить комментарий

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