fread failing to read a file - c

I have a nest struct here.
typedef struct
{
struct_one one;
struct_two two;
struct_three three;
} outermost_struct;
Passing a pointer to the outer struct in the function
outermost_struct settings
readFileInStruct(settings_file, &settings)
My Function to read the bin file in struct
int readConfigIn2Struct
(
char file_name[],
outermost_struct*settings_mem_location
)
{
FILE *ptr_file;
ptr_file = fopen(file_name,"rb");
if(ptr_file == NULL)
{
return -1;
}
fread(&(*settings_mem_location),sizeof(outermost_struct),1,ptr_file);
fclose(ptr_file);
return 0;
}
Here fread fails and returns to the main function. Can anyone tell me why is my fread failing? The size of teh file is 73kb and struct has enough memory to accommodate the entire file.
Now instead of doing fread once for the entire file, I am trying to do fread for each struct.
fread(&(*settings_mem_location),sizeof(struct_one),1,ptr_file);
Here fread correctly writes into struct_one. Now I need fread to write into struct_two. How do I advance the pointer to point to struct_two?

Detailed error checking and logging is debugging for free. On top of this including additional logging mostly helps.
Below a possible version of the code you show, reflecting my statements above:
int readConfigIn2Struct (
char file_name[],
outermost_struct * settings_mem_location)
{
#ifdef DEBUG
fprintf(stderr, "%s:%d - Entering %s with file_name = '%s', outermost_struct * = %p\n",
__FILE__, __LINE__, __func__, file_name, (void*) settings_mem_location);
#endif
assert(NULL != file_name);
assert(NULL != settings_mem_location);
int result = 0; /* be optimistic. */
FILE *ptr_file = fopen(file_name, "rb");
if (ptr_file == NULL)
{
result = -1;
}
else
{
size_t bytes_to_read = sizeof * settings_mem_location;
#ifdef DEBUG
fprintf(stderr, "Bytes to read from '%s': %zu\", file_name, bytes_to_read);
#endif
size_t bytes_read = fread(settings_mem_location, 1, bytes_to_read, ptr_file);
if (bytes_read < bytes_to_read)
{
result = -1;
if (feof(ptr_file))
{
fprintf(stderr, "Unexpectedly reached EOF after %zu bytes\", bytes_read);
}
else if (ferror(ptr_file))
{
fprintf(stderr, "An error occurred after reading %zu bytes\", bytes_read);
}
}
fclose(ptr_file);
}
#ifdef DEBUG
fprintf(stderr, "%s:%d - Leaving %s with result = %d\n", __FILE__,
__LINE__, __func__, result);
#endif
return result; /* One exit point per function is preferred over several. */
}
Compile with option -DDEBUG to enable additional logging like entry and exit.
To have the calls to assert() being removed automagically compile with option -DNDEBUG.
Details about assert() are in the documentation here.

Related

Unable to read from file from argv

I am trying to read from a file, and here is my code, but as I run my code nothing shows up. Have I used the getline() function incorrectly? I can not understand my problem.
const char *READ = "r";
/**
* main - Entry point of my program
*
* Return: On success, it returns 0. On
* error it returns -1
*/
int main(int ac, char **av)
{
FILE *fpointer;
char *lineptr = NULL;
size_t *n = 0;
int line_number = 1;
if (ac != 2)
{
fprintf(stderr, "USAGE: monty file\n");
exit(EXIT_FAILURE);
}
fpointer = fopen(av[1], READ);
if (fpointer == NULL)
{
fprintf(stderr, "Error: Can't open file %s\n", av[1]);
exit(EXIT_FAILURE);
}
while (getline(&lineptr, n, fpointer) != -1)
{
printf("Line %d: %s\n", line_number, lineptr);
line_number++;
}
return (0);
}
getline(&lineptr, n, fpointer) returns -1. You did not explicitly check this and print an error message.
Checking errno it's because of EINVAL: invalid argument. Also good to check errno.
Reason is that n is NULL, while a pointer to an existing size_t is required.
BTW, indenting with 8 spaces is rather uncommon; I'd stay with 4 space. (Also, never use TAB characters.)
It's advisable to stick with extremely common argc and argv.
Nice you put {s on a further empty line; I like that style.
You'd get this:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
const char *READ = "r";
int main(int argc, char **argv)
{
FILE *fpointer;
char *lineptr = NULL;
size_t n;
int line_number = 1;
if (argc != 2)
{
fprintf(stderr, "USAGE: monty file\n");
exit(EXIT_FAILURE);
}
fpointer = fopen(argv[1], READ);
if (fpointer == NULL)
{
fprintf(stderr, "Error: Can't open file '%s'.\n", argv[1]);
exit(EXIT_FAILURE);
}
if (getline(&lineptr, &n, fpointer) == -1)
{
printf("Failed to read file '%s': %s.\n", argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
do
{
printf("Line %4d: %s\n", line_number, lineptr);
line_number++;
}
while (getline(&lineptr, &n, fpointer) != -1);
return (0);
}
Declaration of getline:
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
As an output parameter, the type of n is size_t *. It points to a space for writing by getline.
But in your code, n points to 0, which is NOT a vaild addr to write in.

Problems with C XOR executable file encryption / decryption

I'm trying to create a simple XOR crypter / decrypter in C for .exe files. I'm still pretty new in C and don't understand everything yet, especially memory stuff. So I've been following an online tutorial on how to make a simple XOR string crypter which worked fine. Now I wanted to modify it so I can en/decrypt executable files and decided to utilize the fwrite() and fread() functions. This is what I've come up with:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // execve function
#define XOR_KEY 0xAA // key
#define JOB_CRYPT 1 // alter flow depending on the job
#define JOB_DECRYPT 2
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
void xorFile (char *infile, char *outfile) {
FILE *nFile, *eFile;
long nFileSize; // store file size of the file we want to read
char *buffer; // buffer for reading
char *eBuffer; // buffer for storing encrypted data
size_t rResult;
size_t wResult;
///// READ FILE /////
nFile = fopen(infile, "rb");
if(nFile == NULL) {
fputs("Error opening file...", stderr);
exit(EXIT_FAILURE);
}
fseek(nFile, 0, SEEK_END);
nFileSize = ftell(nFile);
rewind(nFile);
buffer = (char *) malloc(sizeof(char) * nFileSize);
if(buffer == NULL) {
fputs("Error allocating memory...", stderr);
exit(EXIT_FAILURE);
}
rResult = fread(buffer, 1, nFileSize, nFile);
if(rResult != nFileSize) {
fputs("Error reading file...", stderr);
exit(EXIT_FAILURE);
}
fclose(nFile);
printf("File size is: %ld\n", nFileSize);
printf("Buffer size is (pointer): %u\n", sizeof(buffer));
printf("Reading result: %lu\n", rResult);
////// WRITE TO FILE //////
eFile = fopen(outfile, "wb");
if(eFile == NULL) {
fputs("Error creating file...", stderr);
exit(EXIT_FAILURE);
}
eBuffer = (char *) malloc(sizeof(char) * nFileSize);
if(eBuffer == NULL) {
fputs("Error allocating memory (2)...", stderr);
exit(EXIT_FAILURE);
}
// encrypt byte by byte and save to buffer
printf("Proceeding with encryption!\n");
for(int i = 0; buffer[i] != EOF; i++) {
eBuffer[i] = buffer[i] ^ XOR_KEY;
}
printf("Proceeding with fwrite()!\n");
wResult = fwrite(eBuffer, 1, nFileSize, eFile);
fclose(eFile);
printf("eBuffer size is (pointer)%u\n", sizeof(eBuffer));
printf("Writing result: %lu\n", wResult);
free(buffer); // free buffers in heap
free(eBuffer);
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
int main(int argc, char *argv[]) {
// checking if all parameters were given
if(argc < 4) {
fprintf(stderr, "Usage: %s [CRYPT | DECRYPT] [IN-FILE] [OUT-FILE]\n", argv[0]);
exit(EXIT_FAILURE);
}
int job;
// DOLOCIMO JOB
if(strcmp(argv[1], "CRYPT") == 0) {
job = JOB_CRYPT;
} else if (strcmp(argv[1], "DECRYPT") == 0) {
job = JOB_DECRYPT;
} else {
fprintf(stderr, "Please select [CRYPT | DECRYPT]!");
exit(EXIT_FAILURE);
}
// CRYPT/DECRYPT OUR FILE
xorFile(argv[2], argv[3]);
if(job == JOB_DECRYPT) {
char *args[] = {argv[3], NULL};
int errExec = execve(args[0], args, NULL);
if(errExec == -1) {
perror("Error executing file...");
exit(EXIT_FAILURE);
}
}
return 0;
}
I'm sorry for the ugly looking code but I first wanted to make it work and I'll refine it later.
Anyways, when I run it in command prompt, the encryption works fine, it generates an encrypted file, but when I run the decrpytion job, the program
crashes during the decryption process. Here's a picture of what happens so you can imagine it better.
Since I have less than 10 reputation, I'm not allowed to embedd pictures.
Here is a link to Imgur.
What's going wrong here? Am I creating a buffer overflow when I'm decrypting it?
Thank you!
Here's the problem:
for(int i = 0; buffer[i] != EOF; i++) {
eBuffer[i] = buffer[i] ^ XOR_KEY;
}
Binary files can contain bytes with any value. So the EOF value is valid and does not designate the end of the file. This means that if the file contains a byte with this value, the loop will quit early and you won't XOR all the bytes. If the file does not contain this byte, the loop will run past the end of the allocated memory which invokes undefined behavior which in this case manifests in a crash.
You know how many bytes you need to processes, so use that as your loop control:
for(int i = 0; i < nFileSize; i++) {
A few other minor corrections:
buffer = (char *) malloc(sizeof(char) * nFileSize);
if(buffer == NULL) {
fputs("Error allocating memory...", stderr);
exit(EXIT_FAILURE);
}
Don't cast the return value of malloc. Also, sizeof(char) is 1 by definition, so you can leave that out.
Also, if a system or library function fails, you should use perror to print the error message. This will print additional information regarding why the function failed.
buffer = malloc(nFileSize);
if(buffer == NULL) {
perror("Error allocating memory...");
exit(EXIT_FAILURE);
}

How to I make a temporary filename that's safe for concurrent execution?

In the following code, I need a unique filename, do some stuff with it, and let it be. It is about converting a .class file to binary, let us call it compilation.
It works perfectly when run in isolation or done 3 times at a time; however, I run into issues when I start up many multiple processes (e.g., 7) where one or more of my compilations fail.
This is the code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
static unsigned int numFiles = 0;
static unsigned long numBytes = 0;
FILE* rawf;
char* raw_file_name_end = ".raw_ujc";
char * rawfilename;
static void byte(unsigned char v){
if(numBytes) printf(", ");
printf((numBytes & 0x0F) ? "0x%02X" : "\n\t0x%02X", v);
fwrite(&v,sizeof(v),1,rawf);
numBytes++;
}
int main(int argc, char** argv){
const char* self = argv[0];
int c;
const char* classCvt = 0;
long len;
if(argc == 1){
fprintf(stderr, "USAGE: %s [-c <path_to_classCvt>] <file 1> [<file 2> [ <file 3> [...]]] > result.c\n", self);
return -1;
}
argv++;
argc--;
if(argv[0][0] == '-' && argv[0][1] == 'c' && !argv[0][2]){
classCvt = argv[1];
argv += 2;
argc -= 2;
}
printf("\nService optimized bytecode = {\n\t");
while(argc--){
char* filename = *argv;
rawfilename = malloc(sizeof(char) * (strlen(filename)-strlen(".class")) + sizeof(char) * strlen(raw_file_name_end)+1);
strncpy(rawfilename,filename,(strlen(filename)-strlen(".class")));
strcat(rawfilename,raw_file_name_end);
fprintf(stderr, "rawfilename after alloc: %s \n", rawfilename);
if(classCvt){
char* t;
filename = tempnam(NULL, NULL);
if(!filename){
fprintf(stderr, "%s: failed to create a tempfile: %d\n", self, errno);
return -10;
}
t = malloc(strlen(filename) + strlen(classCvt) + strlen(*argv) + 32);
if(!t){
fprintf(stderr, "%s: failed to alloc a small string. This is unlikely\n", self);
free(t);
return -11;
}
sprintf(t, "%s < %s > %s", classCvt, *argv, filename);
if(system(t)){
fprintf(stderr, "%s: system() fail: %d\n", self, errno);
free(t);
return -12;
}
free(t);
}
printf("filename is %s\n",filename);
FILE* f = fopen(filename, "r");
rawf = fopen(rawfilename, "wb");
if(filename != *argv){
unlink(filename);
free(filename);
}
if(!f){
fprintf(stderr, "%s: failed to open '%s': %d\n", self, *argv, errno);
fclose(f);
return -2;
}
if(!f){
fprintf(stderr, "%s: failed to open '%s': %d\n", self, *argv, errno);
fclose(f);
return -2;
}
if(fseek(f, 0, SEEK_END)){
fprintf(stderr, "%s: failed to seek(1) in '%s': %d\n", self, *argv, errno);
fclose(f);
return -3;
}
len = ftell(f);
if(len < 0){
fprintf(stderr, "%s: failed to tell in '%s': %d\n", self, *argv, errno);
fclose(f);
return -4;
}
if(fseek(f, 0, SEEK_SET)){
fprintf(stderr, "%s: failed to seek(2) in '%s': %d\n", self, *argv, errno);
fclose(f);
return -5;
}
if(len > 0x00FFFFFFUL){
fprintf(stderr, "%s: file '%s' is %lu bytes, while maximum allowable size is %lu.\n", self, *argv, len, 0x00FFFFFFUL);
fclose(f);
return -6;
}
byte(len >> 16);
byte(len >> 8);
byte(len);
while((c = fgetc(f)) != EOF){
byte(c);
}
numFiles++;
fclose(f);
fclose(rawf);
argv++;
}
byte(0);
byte(0);
byte(0);
printf("\n};\n");
fprintf(stderr, "%s: processed %u files, producing %lu (0x%lX) bytes of output\n", self, numFiles, numBytes, numBytes);
fprintf(stderr, "rawfilename at end: %s \n", rawfilename);
free(rawfilename);
return 0;
}
After looking around, people recommend using mkstemp(); however, as you can see, I actually do need the filename in several places.
I tried adjusting this but keep running into errors. How can I safely adjust this work method?
From the manpage for mkstemp
int mkstemp(char *template);
The mkstemp() function generates a unique temporary filename from template, creates and opens the file, and returns an open file descriptor for the file.
The last six characters of template must be "XXXXXX" and these are
replaced with a string that makes the filename unique. Since it will
be modified, template must not be a string constant, but should be
declared as a character array.
The file is created with permissions 0600, that is, read plus write
for owner only. The returned file descriptor provides both read and
write access to the file. The file is opened with the open(2) O_EXCL
flag, guaranteeing that the caller is the process that creates the
file.
so if you need the filename, you can find it in the template argument passed to mkstemp.

I am trying to print a txt file and it doesn't work in C homework

I'm writing code that's supposed to verify that a .txt file is a certain format.
I wrote my code as I saw in a tutorial and in the website
and for some reason my program doesn't even print my file.
Can you tell me what I'm doing wrong?
The code will do something far more complex, but I'm still trying to work on my basics.
Here's my code so far:
int main(int argc, char *argv[]) {
/* argv[0] = name of my running file
* argv[1] = the first file that i receive
*/
define MAXBUFLEN 4096
char source[MAXBUFLEN + 1];
int badReturnValue = 1;
char *error = "Error! trying to open the file ";
if (argc != 2) {
printf("please supply a file \n");
return badReturnValue;
}
char *fileName = argv[1];
FILE *fp = fopen(argv[1], "r"); /* "r" = open for reading */
if (fp != NULL) {
size_t newLen = fread(&source, sizeof(char), MAXBUFLEN, fp);
if (ferror(fp) != 0) {
printf("%s %s", error, fileName);
return badReturnValue;
}
int symbol;
while ((symbol = getc(fp)) != EOF) {
putchar(symbol);
}
printf("finish");
fclose(fp);
}
else {
printf("%s %s", error, fileName);
return badReturnValue;
}
}
I think you need a bit more explanations:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
// there might be a macro BUFLEN defined in stdio
// which size is optimized for reading in chunks.
// Test if avaiable otherwise define it
#ifndef BUFLEN
# define BUFLEN 4096
#endif
int main(int argc, char *argv[])
{
char source[BUFLEN];
char *filename;
FILE *fp;
size_t fpread, written;
char c;
int ret_fclose;
if (argc != 2) {
fprintf(stderr, "Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
// reset errno, just in case
errno = 0;
// work on copy
filename = malloc(strlen(argv[1]) + 1);
if (filename == NULL) {
fprintf(stderr, "Allocating %zu bytes failed\n", strlen(argv[1]) + 1);
exit(EXIT_FAILURE);
}
filename = strcpy(filename, argv[1]);
// try to open the file at 'filename'
fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Opening file \"%s\" filename failed\n", filename);
// errno might got set to something usable, check and print
if (errno != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
}
exit(EXIT_FAILURE);
}
// You have two options here. One is to read in chunks of MAXBUFLEN
while ((fpread = fread(&source, 1, BUFLEN, fp)) > 0) {
// Do something with the stuff we read into "source"
// we do nothing with it here, we just write to stdout
written = fwrite(&source, 1, fpread, stdout);
// you can use 'written' for error check when writing to an actual file
// but it is unlikely (but not impossible!) with stdout
// test if we wrote what we read
if ((fpread - written) != 0) {
fprintf(stderr, "We did not write what we read. Diff: %d\n",
(int) (fpread - written));
}
}
// fread() does not distinguish between EOF and error, we have to check by hand
if (feof(fp)) {
// we have read all, exit
puts("\n\n\tfinish\n");
// No, wait, we want to do it again in a different way, so: no exit
// exit(EXIT_SUCCESS);
} else {
// some error may have occured, check
if (ferror(fp)) {
fprintf(stderr, "Something bad happend while reading \"%s\"\n", filename);
if (errno != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
}
exit(EXIT_FAILURE);
}
}
// the other way is to read it byte by byte
// reset the filepointers/errors et al.
rewind(fp);
// rewind() should have reseted errno, but better be safe than sorry
errno = 0;
printf("\n\n\tread and print \"%s\" again\n\n\n\n", filename);
// read one byte and print it until end of file
while ((c = fgetc(fp)) != EOF) {
// just print. Gathering them into "source" is left as an exercise
fputc(c, stdout);
}
// clean up
errno = 0;
ret_fclose = fclose(fp);
// even fclose() might fail
if (ret_fclose == EOF) {
fprintf(stderr, "Something bad happend while closing \"%s\"\n", filename);
if (errno != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
}
exit(EXIT_FAILURE);
}
// The macros EXIT_FAILURE and EXIT_SUCCESS are set to the correct values for
// the OS to tell it if we had an eror or not.
// Using exit() is noot necessary here but there exits teh function atexit()
// that runs a given function (e.g: clean up, safe content etc.) when called
exit(EXIT_SUCCESS);
}
You read from the file twice but only print once.
If the file is to small the first reading will read all of the contents, and the second reading will not produce anything so you don't print anything.
I believe you have to reset the pointer after using fread.
Try fseek(fp, SEEK_SET, 0) to reset the pointer to the beginning of the file. Then print the file.

Linux, reading the tape device

I'm using plain C and trying to read data from stream device (single tape)
size_t res=0;
size_t total=0;
char data[512];
FILE *f = fopen("/dev/st0","r");
if(!f)
{
perror ("Error:");
printf( "Value: %d\n", errno );
return;
}
while((res=fread(data,1, sizeof data,f))>0)
{
total+=res;
}
fclose(f);
printf("read: %ld bytes\n", total);
It doesn't work this way, so I assume there should be some specific way to do it.
I didn't find something useful in google. May be source code of mt tool can help, but again it doesn't read/write to tape.
The result is
read: 0 bytes
To read the first sizeof(data) bytes (if any) from the device specified do like so:
#define _POSIX_SOURCE /* for ferror */
#include <stdio.h>
#define DEVICENAME "/dev/st0"
int main(void)
{
int result = EXIT_SUCCESS; /* Be optimistic. */
size_t total = 0;
char data[1024];
FILE * f = fopen(DEVICENAME, "r");
if (NULL == f)
{
fprintf(stderr, "Failed to open '%s'.\n", DEVICENAME);
result = EXIT_FAILURE;
}
else
{
total = fread(data, 1, sizeof(data), f);
if (ferror(f))
{
fprintf(stderr, "Error reading from '%s'.\n", DEVICENAME);
result = EXIT_FAILURE;
}
fclose(f);
}
printf("Read %zd bytes from '%s'.\n", total, DEVICENAME);
return result;
}

Resources