Opening a file in C for reading - c

I have an issue with C programming and would like a huge help from you all.
I'm supposed to write a console application that is going to manage human resources. The code below is supposed to check if the userlist.txt file exists and if so it reads from it. The code compiles and links successfully but I get a segmentation fault when I execute it.
bool userListAvailable() {
bool userListExist = false;
struct user_details userlist[number_of_employee];
FILE *userListFile=fopen("userlist.txt", "w");
if (!(userListFile == NULL)) {
fread(userlist, sizeof (userlist), 1, userListFile);
for (int i = 0; i < sizeof (userlist); ++i) {
if (strstr(userlist[i].email, "#") != NULL) {
userListExist = true;
break;
}
}
}
fclose(userListFile);
return userListExist;
}
Any idea on what I'm doing wrong? I tried several other almost similar questions , but it was in vain.

In addition to the discussion at the top
for (int i = 0; i < sizeof(userlist); ++i) {
Is most likely wrong, as you want to read number_of_employee rather than the number of bytes in your buffer.
Most likely you'd get a segfault at userlist[i] as sizeof(userlist) is probably a larger number than number_of_employee

If you want to check if the userlist.txt file exists, You can check it using Open.
Open will return the new file descriptor, or -1 if an error occurred (in which case, errno is set appropriately). Here is the man http://man7.org/linux/man-pages/man2/open.2.html
Then if the FD (file descriptor) than open returned is different that -1, it means that the file exist and that you succesfully opened it, so you can read it using the FD.

Related

How do I check if file was written to successfully?

I have written the function, don't know it that's correct but how do I return true and false using if condition?
Function bool save_book(Book, char)**
Input Parameters: A pointer to a Book and a string representing a file name.
Return Value: Return true if the book's contents were stored to a file successfully. Otherwise false.
Note This function should create or open a file based on the file name and store each Line of the book in it.
Below is my code
bool save_book(Book *b, char* fileName){
FILE *filePointer = fopen(fileName,"w");
for (int i = 0; i < pBook->lineCount; i++)
{
fprintf(filePointer, "%s", b->lines[i]);
}
fclose(filePointer);
return true;
}
this is the struct I am using:
typedef struct _Book
{
int characterCount;
int lineCount;
int maxLineCount;
char **lines;
}Book;
You have to check every individual I/O operation.
To make it fun, they all return different things on error. fopen will return NULL. fprintf will return a negative number. fclose will return EOF.
Here it is annotated with a short list of what might go wrong at each step.
bool save_book(Book *b, char* fileName) {
// Maybe the directory doesn't exist.
// Maybe you don't have permission.
// Maybe there's a disallowed character.
// Maybe the disk is full.
// Maybe it's a network drive and there's a network error.
// Maybe the drive got unmounted.
FILE *filePointer = fopen(fileName,"w");
if( filePointer == NULL ) {
return false;
}
for (int i = 0; i < b->lineCount; i++)
{
// Maybe the disk is full.
// Maybe it's a network drive and there's a network error.
// Maybe the drive got unmounted.
if( fprintf(filePointer, "%s", b->lines[i]) < 0 ) {
// Even though the filePointer variable will be automatically freed
// the underlying file handle will not be automatically closed.
// There's a limit to how many open file handles one can have open.
// No need to check for error, we know something has already gone wrong.
fclose(filePointer);
return false;
}
}
// Maybe the disk is full.
// Maybe it's a network drive and there's a network error.
// Maybe the drive got unmounted.
if( fclose(filePointer) != 0 ) {
return false;
}
return true;
}
In reality you probably don't need to check fprintf, checking fclose should catch the same errors. But if you're writing a very large and expensive file you might want to know if you ran out of disk space sooner rather than later.
You can also optionally print the error. Each of those functions will set the global errno on failure. You can turn this into a human readable string with strerror.
if( filePointer == NULL ) {
fprintf(stderr, "Error while opening '%s' for writing: %s", fileName, strerror(errno));
return false;
}
Note that rather than checking for an exact error code, I tend to check for that which is not the success code. Rather than if( fclose(filePointer) == EOF ) I've checked for if( fclose(filePointer) != 0 ), the lack of a success code. This is a defense programming practice just in case the error is severe enough that it can't even return its correct error code (extremely unlikely in standard library code) or I didn't read the spec quite right.

Will errno == ENOENT be a sufficient check to check if file exists in C?

Using PellesC on Windows 8.1.
I know this topic has been addressed many times with many solutions. I have read solutions stating the usage of CreateFile, PathFileExists, GetFileAttributes, _access which I somewhat understand.
I have also read an important point about race conditions in the answer to the questions Quickest way to check whether or not file exists
and What's the best way to check if a file exists in C? (cross platform).
So if I open a file using fopen() in C and when it fails (for any reason) and passes NULL back; then can I further check for errno == ENOENT and be content with it and report correctly that the file does not exists.
#include <stdio.h>
#include <string.h>
#include <errno.h>
int file_exists(char filename[]) {
int err = 0; //copy of errno at specific instance
int r = 0; //1 for exists and 0 for not exists
FILE *f = NULL;
//validate
if (filename == NULL) {
puts("Error: bad filename.");
return 0;
}
printf("Checking if file %s exists...\n", filename);
//check
errno = 0;
f = fopen(filename, "r");
err = errno;
if (f == NULL) {
switch (errno) {
case ENOENT:
r = 0;
break;
default:
r = 1;
}
printf("errno = %d\n%s\n", err, strerror(err));
} else {
fclose(f);
r = 1;
}
if (r == 0) {
puts("It does not.");
} else {
puts("It does.");
}
return r;
}
fopen needs to do lots of stuff and checking before the file is opened. ENOENT implies that the file does not exist, but file not existing does not imply ENOENT.
It is possible for a file to not exist and you to get another error, such as EACCES for not being able to read the parent directory for example.
On the other hand, ENOENT from fopen does not mean that some other process couldn't have created the file even before fopen returns or before you're inspecting the errno and so on; this is the reason why C11 added the x flag for opening a file for writing in exclusive mode - failing if the file already exists.
To sum it up: if you get ENOENT, the file did not exist when you tried opening it. If you get some other error, then each other error code would belong to one of 3 these classes - that it is certain that either
the file existed, or
it cannot have existed
or it might have existed at the time
at the time of opening. It is up to you and your required logic how you'd handle these other errors. A simple way would be to refuse to continue processing, reporting the error to the user.

Writing byte arrays back to their original state on disk in C

This might seem useless to most, but I'm trying to figure out how to write a byte array back to the original file it once was, rather than executing in memory (found an overwhelming amount of information on executing in memory).
Particularly, how to do this in C on linux.
I have converted the linux program 'touch' to a byte array:
char touch[] = {
0x7F,0x45,0x4C,0x46,0x02,0x01,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x3E,0x00,
0x01,0x00,0x00,0x00,0xA0,0x38,0x00,0x00,0x00,0x00,
0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x68,0x64,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x40,0x00,0x38,0x00,0x09,0x00,0x40,0x00,
0x1E,0x00,0x1D,0x00,0x06,0x00,0x00,0x00,0x05,0x00,
etc..
so I am basically just trying to write touch to the current directory as newtouch.
With windows I found the CreateFile function. Is open() the equivalent on linux?
Any help would be great. thanks
just write your array using fwrite, opening the file as binary (no issue on Linux, but text/default mode creates corrupt binary files on Windows because of endline conversion)
#include <stdio.h>
const char touch[] = {
0x7F,0x45,0x4C,0x46,0x02,0x01,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x3E,0x00,
0x01,0x00,0x00,0x00,0xA0,0x38,0x00,0x00,0x00,0x00};
int main()
{
int rc=1;
FILE *f=fopen("xxx","wb");
if (f!=NULL)
{
size_t written = fwrite(touch,sizeof(touch),1,f);
if (written != 1)
{
fprintf(stderr,"disk write issue\n");
}
else
{
rc = 0;
}
fclose(f);
}
else
{
fprintf(stderr,"cannot create file\n");
}
return rc;
}
Here I'm able to use sizeof(touch) to get the proper size because touch is an array, not just a pointer on data.
// Open a file for writing.
// (This will replace any existing file. Use "w+" for appending)
FILE *file = fopen("filename", "wb");
int results = fputs(array, file);
if (results == EOF) {
// Failed to write do error code here.
}
fclose(file);

Creating and returning file via C function

What I'm trying to do is to write a function that creates a file, fills it with data and returns the file to main(). The question is - what is the right way to "return file". Should I pass pointer / file descriptor or just disregard all this and use filename?
EDIT: doing the right way (I hope):
int mkrandfile(const char *name, int range, int qnt)
{
FILE *afile;
int i = 0;
if (afile = fopen(name, "w+"))
{
while((i <= qnt) && fprintf(afile, "%d ", rand() % range - range/2))
i++;
fclose(afile);
if (i != qnt + 1)
return -2;
}
else
return -1;
}
You are correct that returning afile from that function is wrong. Once the file is closed, that file handle is no longer valid. Use of it by the caller would result in undefined behavior.
While it is probably not the best idea from a modularity standpoint, you could leave the file open and then return the handle. But I think one of the following might be better:
Pass in an opened file handle to the function (let the caller open and close it).
Make the caller open the file again on its own.
The first option may be more efficient when file caching by the OS (if applicable here) is considered.

Reading in .txt file with different extension in C

At the moment my program has no problem reading in a .txt file, but my program needs to read in a text file with a different file extension (.emu is the requirement). When simply changing the same file's extension to .emu, the variable 'file' is NULL and therefore the file isn't opened, can anyone help?
Had a little look around and haven't been able to find a solution so any help is much appreciated
here's the source code:
void handleArgs (const char *filename, int trace, int before, int after) {
FILE *file = fopen(filename, "r");
char *address = malloc(MAX_ADD_LENGTH * sizeof(char));
char *instruction = malloc(MAX_INS_LENGTH * sizeof(char));
long int addressDecoded;
if (file == NULL || file == 0) {
fprintf(stderr, "Error: Could not open file");
}
else {
if (ferror(file) == 0) {
while (fscanf(file, "%s %s", address, instruction) != EOF) {
if (strlen(address) == 8 && strlen(instruction) == 8) {
addressDecoded = strtol(address, NULL, 16);
printf("%ld\n", addressDecoded);
//instruction = decodeInstruction(instruction);
}
else {
fprintf(stderr, "Error: particular line is of wrong length");
}
}
}
}
fclose(file);
}
argument 'filename' when executing is simply '/foopath/test.emu'
There's nothing special to C about the file extension. Reread your code for simple errors like changing the filename in one place, but not the other. If you're passing in the filename, pass the whole name, not just the part to the left of the period.
Files are data, and have names. What comes before the dot in a name, is just as much a part of it as what comes after -- the extensions were created just as hints as to what the file contains, but they are NOT required to be strictly related to the file's contents.
The file may not exist, or your priviledges may not be enough to open it. Or maybe there's some other kind of error. How can you diagnose this?
When you use a system call and it doesn't behave the way you want to, there's a variable called errno in errno.h (#include <errno.h>) that will contain a number representing the status of the last call. There's a huge list of symbolic constants to put names to these values, you can google it up.
For example, if you try to open a file and the returned pointer is useless, you might want to check errno to see if the file existed, or if you're exceding system restrictions for opened files, etc.

Resources