1

I'm seriously struggling with this assignment and I can't seem to find the problem in my code.

I'm supposed to create a program that reads a raw card one block at a time with each block containing 512 bytes and write the blocks that are of a JPEG but I think you probably know this.

Basically I run this program with card.raw (usage: ./recover card.raw) but keep getting a segmentation fault with around 5000+ JPEGs being created. I've checked my code over and over to make sure I've used memory correctly but am failing to see where the problem is. Without the read and write functionality, however, the code actually succeeds in identifying the 50 individual JPEGs, so I know that my approach is roughly correct.

Any help would be greatly appreciated!

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

#define BLOCK_SIZE 512 // defining a block size of 512

typedef uint8_t BYTE;

int main(int argc, char* argv[])
{
    bool found = false; // Boolean that switches to true once the first file has been found
    char filename[8]; // Array to store my filename
    int file_count = 1; // Counter to keep track of the file number
    BYTE buffer[512] = {0}; // This is the buffer where I will place 1 block of 512 bytes at a time from the raw file and write onto the JPEG files

    if (argc != 2)
    {
        printf("Usage: ./r filename\n");
        return 1;
    }

    // Open raw file
    FILE *rawPtr = fopen(argv[1], "r");
    if (rawPtr == NULL)
    {
        fclose(rawPtr);
        printf("ERROR: CANNOT OPEN FILE.\n");
        return 2;
    }

    FILE *outptr = NULL; // Declaring output file pointer as NULL
    size_t bytesRead = fread(buffer, sizeof(BYTE), BLOCK_SIZE, rawPtr); // reading first 512 bytes and storing in buffer array AND storing number of bytes 
                                                                        // read in bytesRead

    while (bytesRead != 0) // While loop keeps looping until the last block (EOF) has been attempted to be read but bytesRead holds value of 0
    {
        // Is the block the start of a JPEG?
        if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
        {
            // Has a JPEG been found yet?
            if (found == true) // If JPEG has been found, close previous JPEG file, open new JPEG file with new name (hence file_count++) and write buffer array 
            {                  // into new file
                fclose(outptr);
                file_count++;
                sprintf(filename, "%03i.jpg", file_count);
                outptr = fopen(filename, "w");
                fwrite(buffer, sizeof(BYTE), BLOCK_SIZE, outptr);
            }
            else // If JPEG not found, must be first JPEG so open file and write buffer array into file
            {
                sprintf(filename, "%03i.jpg", file_count);
                outptr = fopen(filename, "w");
                fwrite(buffer, sizeof(BYTE), BLOCK_SIZE, outptr);
                found = true; 
            }

        }
        else // If not start of JPEG ...
        {
            if (found == true) // If start of new JPEG not detected BUT JPEG has been previously found, append buffer onto latest JPEG file
            {
                fwrite(buffer, sizeof(BYTE), BLOCK_SIZE, outptr);
            }
            else // If start of new JPEG not detected AND no file has yet been detected, do nothing as it must not be part of JPEG
            {
                printf("Searching...\n");
            }

        bytesRead = fread(buffer, sizeof(BYTE), BLOCK_SIZE, rawPtr); // Read next 512 bytes and store in buffer array. I am assuming the previous 512 bytes 
                                                                     // will be overwritten. If end of file is reached, bytesRead will be 0 and while loop will quit
        }
    }

    printf("%i JPEGs recovered\n", file_count); // Used this line to test whether the JPEGs were being identified and they indeed were (50 in total were found)
                                                // so the problem seems to have come after introducing the code to read from and write into the files

    fclose(outptr); // close last output/JPEG file
    fclose(rawPtr); // close raw input file
    return 0;
}

EDIT:

2 Answers 2

1

Having a look at your code was really helpful, I was having a hard time with this problem because I cant fully understand how fread works.

You keep reading rawPtr and sending it to buffer, and the size of it to bytesRead, but I dont understand why it wont read the same block of 512B, you are not telling the program to go to the next block of 512, I suppose it does it automatically, but can you please explain??

Thanks

2
  • Yeah you got it man! You could say it 'automatically' does it for you. But just to be more precise everytime you use the fread function to read a certain amount of bytes (or chars, ints, etc. depending on the size of data you are reading) there is a 'cursor' that moves along the file you are reading and so when you fread from that file again it will begin reading from where you left off UNLESS you fseek backwards of forwards by a certain number of bytes. If you use fseek by say 10 bytes after an initial fread of 512 bytes, you will begin reading after byte no. 502 or so. Hope that helped!
    – Ewan
    May 1, 2020 at 18:21
  • Got it, thanks man, this helped a lot May 1, 2020 at 21:19
0

Lol I found out that my last fread statement was within the last else statement, moved it outside everything got fixed #programmerlife

You must log in to answer this question.

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