CS50 recover, when to use buffer and &buffer? - c

I am solved the pset4 recover in the CS50. Although I solved the problem, I am confuse between "buffer" & "&buffer". Please pay attention to "LINE AAAAA" & "LINE BBBBB".
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// New type to store a byte of data
typedef uint8_t BYTE;
// Number of "block size" 512
const int BLOCK_SIZE = 512;
int main(int argc, char *argv[])
{
// Check for 2 command-line arguments
if (argc != 2)
{
printf("Usage: ./recover IMAGE\n");
return 1;
}
// Open card.raw file
FILE *input = fopen(argv[1],"r");
// Check for fail to open
if (input == NULL)
{
printf("Couldn't open the file.\n");
return 1;
}
// Read the first 4 bytes
BYTE buffer[BLOCK_SIZE];
// Count image
int count_image = 0;
// Assign NULL to output_file
FILE *output = NULL;
// Declare filename
char filename[8];
// LINE AAAAA
while (fread(buffer, sizeof(BYTE), BLOCK_SIZE, input) == BLOCK_SIZE)
{
// Check first 4 bytes for JPEG file format
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
// Only for first image, generate new filename and write into it
if (count_image == 0)
{
// Generate a new file with sequence name
sprintf(filename, "%03i.jpg", count_image);
// Open new file
output = fopen(filename, "w");
// LINE BBBBB
fwrite (&buffer, sizeof(BYTE), BLOCK_SIZE, output);
// Add filename counter
count_image++;
}
// For subsequence new repeat JPG images
// Close output file, generate new file, and write into it
else if (count_image > 0)
{
// fclose current writing files
fclose (output);
// Generate a new file with sequence name
sprintf(filename, "%03i.jpg", count_image);
// Open new file
output = fopen(filename, "w");
// LINE BBBBB
fwrite (&buffer, sizeof(BYTE), BLOCK_SIZE, output);
// Add filename counter
count_image++;
}
}
// Not fulfill the 4 bytes JPG condition, keep writing to the same filename
else if (count_image > 0)
{
// LINE BBBBB
fwrite (&buffer, sizeof(BYTE), BLOCK_SIZE, output);
}
}
fclose(output);
fclose(input);
}
Question:
Why do we use "&buffer" in LINE BBBBB instead of "buffer"?
I know LINE AAAAA is using "buffer" as BYTE buffer[BLOCK_SIZE] is an pointer or array. So "buffer" mean the location of the pointer.

When buffer is used, it often converts to the address of the first element. &buffer is the address of the array.
Those 2 addresses will compare equal, yet have different types. When the type is important, use the matching one. Enable all warnings to help identify incorrect type usage.
Since fread() use void *, either will work.
Conceptually use buffer in this case to match the sizeof(BYTE) and BLOCK_SIZE.
or
fread(&buffer, sizeof buffer, 1, input) == 1)

fwrite(buffer, ...) will work fine.

Related

CS50 PSET4 RECOVER: fread() not populating buffer array

Hello and thank you for taking a look.
I'm working through CS50x and am struggling with Recover. The aim is to open a .raw file, read its contents in 512-byte blocks, check the initial four bytes for .jpg headers, and then write each JPEG data to a new file.
I have a body of code written, and the file compiles. The debugger tells me that my buffer[512] variable remains empty/zeroed. This then means the program skips if/else conditions and the program exits.
While my logic within the While loop may be flawed, I haven't been able to step far enough into the program to consider this.
I looked up my issue before posting. Some sources like to use fread(buffer, 512, 1, input), but CS50 itself uses fread(buffer, 1, 512, input). Also, when initialising the filename, I have tried both char *filename = malloc(8 * sizeof(char)); and char filename[8];. For both lines I have tried each method and am still missing something.
My code is below. Thank you in advance for your time.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
int main(int argc, char *argv[])
{
// First check the number of arguments is correct.
if (argc != 2)
{
printf("Correct Usage: ./recover.c [filename]\n");
return 1;
}
// Open the file.
FILE *inputFile = fopen(argv[1], "r");
if (inputFile == NULL)
{
printf("File not found.\n");
return 1;
}
// Create counter of number of files.
int counter = 0;
// Create filename variable
char *filename = malloc(8 * sizeof(char)); // 7 + 1 for \0
// Create a 512-size array buffer.
BYTE buffer[512];
// Initialise img file for scope access.
FILE *img = NULL;
while (fread(buffer, sizeof(BYTE), 512, inputFile))
{
// If start of new JPEG:
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
if (counter == 0) // If the FIRST JPEG
{
// Make new file:
sprintf(filename, "%03i.jpg", counter);
img = fopen(filename, "w");
fwrite(buffer, sizeof(BYTE), 512, img);
}
else // If not the first JPEG
{
fclose(img); // Close previous file.
counter++;
// Make new file:
sprintf(filename, "%03i.jpg", counter); // Update filename.
img = fopen(filename, "w");
fwrite(buffer, sizeof(BYTE), 512, img);
}
}
else if (counter > 0) // buffer is continuation of previous.
{
fwrite(buffer, sizeof(BYTE), 512, img);
}
else
{
printf("I exited with no images.\n");
return 2;
}
}
free(filename);
fclose(img);
fclose(inputFile);
return 0;
}
The program exits (returns) after the first line in the raw file is read (assuming it's not a jpeg header, which is the case with the distro raw file). else if (counter > 0) evaluates to false, so the else branch executes.
Thank you everyone for your response. The issue is now fixed!
#DinoCoderSaurus (sorry, can't upvote yet) prompted me to realise that I had assumed (wrongly) that the data in the raw file would immediately begin with a .jpeg header (in fact it looks like the data begins with a hidden message, "surprise").
The Else condition was initially put there to avoid errors but of course it was prematurely exiting the While loop. The buffer was populated correctly after a couple of loops.
I then encountered the second problem (pointed out by #Some_programmer_dude) that counter++; was in the wrong place, which meant after the first new JPEG, no others could be written.
I'll also take your comments about best practice into consideration.

CS50 Recover - How do I use sprintf? error: use of undeclared identifier 'filename'; did you mean 'rename'?

CS50 is my first coding experience and I can't get past Recover. I'm taking the online free course and I'm working by myself and these problem sets are very difficult for me. If my code and questions look novice I apologize in advance.
Some questions:
Am I using sprintf correctly? What do I need to use in place of the "filename" (see error)
Am I using the while loop correctly?
Am I even close to the right solution or should I quit coding at this point?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// check usage
if (argc != 2)
{
printf("Please enter only 1 argument\n");
return 1;
}
// open file
FILE *file = fopen(argv[1],"r");
if (file == NULL)
{
printf("Usage: ./recover usage\n");
return 1;
}
int count = 0;
// Read first 4 bytes
unsigned char buffer[4];
while(fread(buffer, 512, 1, file) == 512);
// check first 4 bytes
if (buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0)
// count this 512B block
{
if (count == 0) // if first jpeg
{
sprintf(filename, "%03i.jpg", count); // last number is ith filename
FILE *img = fopen(filename, "w"); // writing to filename
fwrite(buffer, 512, 1, filename); // write to buffer 512 bytes at a time to filename
}
else
{
fclose(filename);
count++; // add to existing count
sprintf(filename, "%03i.jpg", count); // last number is ith filename
FILE *img = fopen(filename, "w"); // writing to filename
fwrite(buffer, 512, 1, filename); // write to buffer 512 bytes at a time to filename
}
}
else
{
if (count > 1)
{
sprintf(filename, "%03i.jpg", count); // last number is ith filename
FILE *img = fopen(filename, "a"); // writing to filename
fwrite(buffer, 512, 1, filename); // write to buffer 512 bytes at a time to filename
}
}
fclose(argv[1]);
}
Here are my error codes:
~/pset4/recover/ $ make recover
clang -ggdb3 -O0 -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow recover.c -lcrypt -lcs50 -lm -o recover
recover.c:33:25: error: use of undeclared identifier 'filename'; did you mean 'rename'?
sprintf(filename, "%03i.jpg", count); // last number is ith filename
^~~~~~~~
rename
recover.c:57:12: error: incompatible pointer types passing 'char *' to parameter of type 'FILE *' (aka 'struct _IO_FILE *') [-Werror,-Wincompatible-pointer-types]
fclose(argv[1]);
^~~~~~~
/usr/include/stdio.h:199:26: note: passing argument to parameter '__stream' here
extern int fclose (FILE *__stream);
^
11 errors generated.
: recipe for target 'recover' failed
make: *** [recover] Error 1
There are a number of issues in your code. Some have 'simple' fixes, others I can only make 'intelligent guesses' at.
First, you are using a filename variable in which to write the name of your output files, but never declare that; this is a simple fix: declare a char filename[512]; variable (or whatever size, in place of 512, you feel is necessary).
Second, the fclose function takes, as its argument, a previously-opened FILE* 'handle'; this will, in your code, be either the file variable (for the input file) or the img variable (for the outputs).
Third, your code uses very 'local' definitions for the img variable, which aren't shared between the different if ... else blocks; to fix this, declare the variable in a more 'outer' scope and just use it (without re-declaring) in the various other places.
Other issues are that your while (fread(buffer, 512, 1, file) == 512); statement is reading lots of times (probably) but the following code is only executed after that read operation fails, which is almost certainly not what you need; so, you should have a { ... } block to enclose (most of) the following code in that while loop.
There are also a couple of places where I think you should be closing the output file: once inside the loop, where you 'reopen' a new output, and once after the whole big loop is finished, to close the 'dangling' open file handle.
I have added comments with the triple slash (///) in the code below, to address these points. Please feel free to ask for any further clarification and/or explanation.
int main(int argc, char* argv[])
{
// check usage
if (argc != 2) {
printf("Please enter only 1 argument\n");
return 1;
}
// open file
FILE* file = fopen(argv[1], "r");
if (file == NULL) {
printf("Usage: ./recover usage\n");
return 1;
}
int count = 0;
/// TEST first 4 bytes
unsigned char buffer[512]; /// This needs to be 512 bytes - not just the first 4 that you test!!
char filename[512]; /// Buffer in which to write filename string
FILE* img = NULL; /// This variable MUST be in the more outer scope!
while (fread(buffer, 1, 512, file) == 512) { /// count and size were round the wrong way!
// check first 4 bytes
if (buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0)
// count this 512B block
{
if (count == 0) { // if first jpeg
sprintf(filename, "%03i.jpg", count); // last number is ith filename
img = fopen(filename, "w"); /// Don't (re)declare a local "img"
fwrite(buffer, 1, 512, img); /// Use FILE* handle, not name!
}
else {
fclose(img); /// Use FILE* handle, not name!
count++; // add to existing count
sprintf(filename, "%03i.jpg", count); // last number is ith filename
img = fopen(filename, "w"); /// Don't (re)declare a local "img"
fwrite(buffer, 1, 512, img); /// Use FILE* handle, not name!
}
}
else {
if (count > 1) {
fclose(img); /// I THINK you need to close the old file first!
sprintf(filename, "%03i.jpg", count); // last number is ith filename
img = fopen(filename, "a"); // writing to filename
fwrite(buffer, 1, 512, img); // write to buffer 512 bytes at a time to filename
}
}
}
fclose(img); /// At SOME point (probably here) you should close the remaining opened output file!
fclose(file); /// Use FILE* handle, not name!
return 0;
}
Also, to be thorough, you really should be checking every result from the img - fopen(...) calls, and adding some kind of error handling if that is ever NULL (as you have done when opening the input file).
Thanks to Adrian Mole's pointers, I've completed my code as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
// check usage
if (argc != 2)
{
printf("Please enter only 1 argument\n");
return 1;
}
// open file
FILE *file = fopen(argv[1], "r");
if (file == NULL)
{
printf("Usage: ./recover usage\n");
return 1;
}
int count = 0; // create count integer
unsigned char buffer[512]; /// This needs to be 512 bytes - not just the first 4 that you test!!
char filename[512]; // Buffer in which to write filename string
FILE *img = NULL; // This variable MUST be in the more outer scope!
while (fread(buffer, 1, 512, file) == 512) // count and size were round the wrong way!
{
// check first 4 bytes
if (buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0)
// count this 512B block
{
if (count == 0) // if first jpeg
{
count++;
sprintf(filename, "%03i.jpg", count - 1); // last number is ith filename
img = fopen(filename, "w"); // Don't (re)declare a local "img"
fwrite(buffer, 1, 512, img); // using img handle
}
else
{
fclose(img); /// Use FILE* handle, not name!
count++; // add to existing count
sprintf(filename, "%03i.jpg", count - 1); // last number is ith filename
img = fopen(filename, "w"); // Don't (re)declare a local "img"
fwrite(buffer, 1, 512, img); // Using img handle
}
}
else
{
if (count > 0)
{
fwrite(buffer, 1, 512, img); // write to buffer 512 bytes at a time to filename
}
else
{
continue;
}
}
}
fclose(img); // At SOME point (probably here) you should close the remaining opened output file!
fclose(file); // Use FILE* handle, not name!
return 0;
}

C - Why does my code break when removing unused variable declaration

I am writing a program in C to recover images from a raw file for CS50 and I am having a strange problem. I have a variable int cnt that I was using for debug purposes and I got the program to work so I was removing leftover debug code. But when I remove the cnt declaration I start outputting corrupt files.
Before removing line 25 below I was outputing .jpg files that I could open and view, then I removed the line, recompiled, deleted the photos from the last run, and reran the program on the same .raw data and the new files I got were unrecognized. So I put the declaration back in, recompiled, deleted the old photos, and ran the program again and got good files. Does anyone know why removing an unused declaration is messing with my results? The offending declaration is on line 25.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: ./recover image\n");
return 1;
}
int filesFound = 0;
FILE *inFile = fopen(argv[1], "r");
FILE *outFile = NULL;
if (inFile == NULL)
{
printf("Image file could not be opened\n");
return 1;
}
uint8_t buffer[512];
int cnt = 0;
while (!feof(inFile))
{
fread(buffer, 512, 1, inFile);
// check for start of jpg file
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0)
{
// start of jpg was found
if (outFile != NULL)
{
// close the current file and then open a new file to write to
fclose(outFile);
outFile = NULL;
}
// open a file to write to
char fName[4];
sprintf(fName, "%03i.jpg", filesFound);
outFile = fopen(fName, "w");
filesFound++;
}
if (outFile != NULL){
// we have found data to write and opened a file
fwrite(buffer, 512, 1, outFile);
}
}
//Be sure to close my files
fclose(inFile);
if (outFile != NULL)
{
fclose(outFile);
}
return 0;
}
char fName[4] does not have sufficient room for the name generated by "%03i.jpg", so you are overrunning the buffer. Make it larger and use snprintf, not sprintf, and test the return value to detect errors:
int result = snprintf(fName, sizeof fName, "%03i.jpg", filesFound);
if (sizeof fName <= result)
{
fprintf(stderr, "Internal error, buffer is too small for file name.\n");
exit(EXIT_FAILURE);
}
Instead of printing an error, you could instead use the return value of snprintf, which indicates the length needed, to allocate memory for a larger buffer and then redo the snprintf with that buffer.
(Note that snprintf may return a negative result if an error occurs. Normally, this will become a large number upon conversion to size_t for the comparison, so it will trigger this error message. However, in a robust program, you might want to insert a separate test for result < 0.)

Pset4 (cs50) recover does not work properly. It compiles, but does not recover more than 2 jpegs. Is something wrong with checking for JPEG signature?

I am learning how to code and I have no experience with that at all. I've successful got to PSET4 and stuck on recover. I've read everything online about this problem and i found out that many people have similar code as I do and it works. Does not work for me whatsoever. Please have a look and give me a hint what did I do wrong and how to correct it.
Here is everything about the pset4 recover i downloaded their card.raw from here card.raw
/** recovering JPEG files from a memory card
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef uint8_t BYTE;
int main(int argc, char* argv[])
{
// ensure proper usage
if (argc != 2)
{
fprintf(stderr,
"Usage: ./recover infile (the name of a forensic image from which to recover JPEGs)\n");
return 1;
}
// open input file (forensic image)
FILE* inptr = fopen(argv[1], "r");
if (inptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
FILE* outptr = NULL;
// create a pointer array of 512 elements to store 512 bytes from the memory card
BYTE* buffer = malloc(sizeof(BYTE) * 512);
if (buffer == NULL)
{
return 3;
}
// count amount of jpeg files found
int jpeg = 0;
// string for a file name using sprintf
char filename[8] = { 0 };
// read memory card untill the end of file
while (fread(buffer, sizeof(BYTE) * 512, 1, inptr) != 0)
{
// check if jpeg is found
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff
&& (buffer[3] >= 0xe0 || buffer[3] <= 0xef))
{
if (jpeg > 0)
{
fclose(outptr);
}
sprintf(filename, "%03d.JPEG", jpeg);
outptr = fopen(filename, "w");
jpeg++;
}
if (jpeg > 0)
{
fwrite(buffer, sizeof(BYTE) * 512, 1, outptr);
}
}
// free memory
free(buffer);
// close filename
fclose(outptr);
// close input file (forensic image)
fclose(inptr);
return 0;
}
The main problem is that you invoke undefined behavior because filename is not enough big. sprintf() need be 9 and 17 bytes with your code but you only has 8. So you have a buffer overflow.
Just change:
char filename[8] = { 0 };
to
char filename[17] = { 0 };
Because, you use an int, this value is implemented defined but in many system has an int with 32 bits. So the value possible are between -2^31 and 2^31 - 1 that make a maximum of 11 chars (-2147483648). We add the number of chars in ".JPEG", 5. We have 16 but you forget the null terminate byte of a c-string. So we are 17 maximum.
Modern compiler warning you: gcc version 7.1.1 20170516 (GCC):
In function ‘main’:
warning: ‘sprintf’ writing a terminating nul past the end of the destination [-Wformat-overflow ]
sprintf(filename, "%03d.JPEG", jpeg++);
^
note: ‘sprintf’ output between 9 and 17 bytes into a destination of size 8
sprintf(filename, "%03d.JPEG", jpeg++);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Plus, your typedef is useless because a char world be always a byte in C. More than that you don't need a byte but an octet so like char, uint8_t would be always an octet in C. So you don't need typedef.
Again one thing, you allocate your buffer but it's useless because your buffer has a constant size. So just create an array is more simple.
#include <stdint.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: ./recover infile (the name of a forensic image "
"from which to recover JPEGs)\n");
return 1;
}
FILE *inptr = fopen(argv[1], "r");
if (inptr == NULL) {
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
FILE *outptr = NULL;
uint8_t buffer[512];
size_t const buffer_size = sizeof buffer / sizeof *buffer;
size_t jpeg = 0;
while (fread(buffer, sizeof *buffer, buffer_size, inptr) == buffer_size) {
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff &&
buffer[3] == 0xe0) {
if (outptr != NULL) {
fclose(outptr);
}
char filename[26];
sprintf(filename, "%03zu.JPEG", jpeg++);
outptr = fopen(filename, "w");
}
if (outptr != NULL) {
fwrite(buffer, sizeof *buffer, buffer_size, outptr);
}
}
if (outptr != NULL) {
fwrite(buffer, sizeof *buffer, buffer_size, outptr);
}
if (outptr != NULL) {
fclose(outptr);
}
fclose(inptr);
}
Note: This example is clearly not perfect, this will be better to make a true parser for jpeg file to have a better control flow. Here we suppose that all gonna be right.
how do you know that an instance of a JPEG image will always end with '\n'? Or better, how do you know that a JPEG image will be an exact multiple of 512?
You dont know.
So the posted code needs to calculate the actual value OR use some method to have the last call to fread() for any specific JPEG instance, to stop reading at the end of that image,
Then the check for the ID bytes of the next JPEG image will find the next image.
Otherwise, the start of the next image is already written to the prior output file and the check for a new image will fail.
In general this will result in the last created file containing more than one image.
This link: 'https://en.wikipedia.org/wiki/JPEG_File_Interchange_Format' is a web page that describes the format of a JPEG file.
On every digital camera that I have used, the SD card has a directory of all the files.
Suggest using that directory and the info in the linked web page to find each JPEG image and to determine when the end of that image has been encountered. (I.E. the 0xFF 0xD9)

Segmentation Fault on CS50's pset4

I'm driving myself crazy trying to figure out what is happening with me code.
I'm currently in CS50's pset4. Recover Challenge.
For those who don't know what is it about:
We're given a file called card.raw in which there are some deleted photos. Our task is to implement a program that can do a bit of forensics (idyllically) and recover the lost photos.
Hereby I attach my code:
#include <stdio.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage: ./recover file\n");
return 1;
}
//declaring pointer infile and giving the address of argv[1];
char *infile = argv[1];
//Opening file
FILE *raw_data;
raw_data = fopen(infile, "r");
//Checking for NULL error
if(raw_data == NULL)
{
fprintf(stderr, "Could not open file.\n");
return 2;
}
uint8_t buffer[512]; //Delcaring unsigned int variable type. Array of 512 bytes.
int counter = 0; //Declaring counter for counting jpegs files
FILE *outfile; //Setting pointer named outfile for printing here
char filename[8]; //declaring 'filename' variable for storing the file's name
//While we can reads blocks of memory of 512 bytes from raw_data (aka the address from the infile) into buffer:
while (fread(buffer, 512, 1, raw_data))
{
//Condition for tracking the first bytes that form a JPEG file
if(buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0)
{
if(counter == 0) //If this is the 1st file, then name the file with
//counter value with 3 digits (%03d)
{
sprintf(filename, "%03d.jpg", counter); // And 3 digits (%i3)
outfile = fopen(filename, "w"); //Open file named outfile in write mode
counter++;
}
else //If this is not the first JPG opened, firstly close the
{ // current open file, and then open a new one with the
fclose(outfile); // current counter value and 3 digits for its name
sprintf(filename, "%03d.jpg", counter);
outfile = fopen(filename, "w"); //Open file named 'outfile' in write mode
counter++;
}
}
fwrite(buffer, 1, sizeof(buffer), outfile); /* Write function that takes buffer data (aka the
pointer to the array of elements to be written,
writes 1 byte of elements of the syze buffer (512)
and it writes it to the output, aka 'outfile' */
}
fclose(outfile); //Remember to close the last file once we get out of the while-loop
}
Here's the tricky part:
I've successfully recovered all the problem images.
But, if I run the code several times, let's say for example, 5 times, I end up having a Segmentation Fault.
When I run check50, I get the following message (I will attach an image with both the segmentation fault after some successful runs and the check50 veredict). Click here to see the image
I just can't get it. I supose there might be some trouble with memory, but I just don't know what is it.
Thank you very much for your time and your help guys. StackOVerFlow is always such a nice place to seek for guidance.
EDIT
If I run echo $? once the Segmentation Fault has prompted, I get a value of 139.
Here's the terminal prompt screenshot
EDIT
Just as #Thomas Dickey has pointed out, the program was writing on a file regardless of having an open file yet or not.
I've updated and fixed a bit my code in order to keep it cleaner, and added an if condition in order to fix it.
Here's the solution:
#include <stdio.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage: ./recover file\n");
return 1;
}
//declaring pointer infile and giving the address of argv[1];
char *infile = argv[1];
//Opening file
FILE *raw_data;
raw_data = fopen(infile, "r");
//Checking for NULL error
if(raw_data == NULL)
{
fprintf(stderr, "Could not open file.\n");
return 2;
}
uint8_t buffer[512]; //Delcaring unsigned int variable type. Array of 512 bytes.
int counter = 0; //Declaring counter for counting jpegs files
FILE *outfile; //Setting pointer named outfile for printing here
char filename[8]; //declaring 'filename' variable for storing the file's name
//While we can reads blocks of memory of 512 bytes from raw_data (aka the address from the infile) into buffer:
while (fread(buffer, 512, 1, raw_data))
{
//Condition for tracking the first bytes that form a JPEG file
if(buffer[0] == 0xff &&
buffer[1] == 0xd8 &&
buffer[2] == 0xff &&
(buffer[3] & 0xf0) == 0xe0)
{
if(counter != 0)
{
fclose(outfile); //If this is not the first JPG opened, close previous file
}
sprintf(filename, "%03d.jpg", counter); //print stream to 'filename' the value of 'counter' in 3 digits
outfile = fopen(filename, "w"); //Open file named outfile in write mode
counter++; //Add 1 to counter
}
if(counter != 0) //Don't start writing on a file until the first jpeg is found
{
fwrite(buffer, sizeof(buffer), 1, outfile); /* - Write function that takes buffer data
(aka the array of elements to be written) ,
- Write a block of 512 bytes of elements
(aka the size of buffer),
- 1 block of 512 bytes at a time,
- And it writes it to the output, aka 'outfile' */
}
}
fclose(outfile); //Remember to close the last file once we get out of the while-loop
return 0;
}
The program only opens the output file if the header looks okay, but writes to the output irregardless. If you read a file that doesn't have a jpeg header, it'll break.

Resources