Error handling in file opening - c

[Question 1]
When I open a file into a function, generally I do something like this:
int read_file (char *filename)
{
FILE *fin;
if ( !(fin = fopen(filename, "r")) )
return 1;
/* ... */
return fclose(fin);
}
int main ()
{
char filename[100];
if ( read_file(filename) )
{
perror(filename);
exit(1);
}
return 0;
}
Generally 0 return value is for errors (right?) then I can change the previous code into:
int read_file (char *filename)
{
FILE *fin;
if ( !(fin = fopen(filename, "r")) )
return 0;
/* ... */
return !fclose(fin);
}
int main ()
{
char filename[100];
if ( !read_file(filename) )
{
perror(filename);
exit(1);
}
return 0;
}
But I think that the first code is more clean.
Another option is only change return 1; into return -1; (in the first code that I wrote).
What's the best version?
[Question 2]
If I must handle more errors, is it correct a code like this?
int read_file (char *filename, int **vet)
{
FILE *fin;
if ( !(fin = fopen(filename, "r")) )
{
perror(filename);
return 1;
}
* vet = malloc (10 * sizeof(int));
if ( *vet == NULL )
{
perror("Memory allocation error.\n");
return 1;
}
/* ... */
return fclose(fin);
}
int main ()
{
char filename[100];
int *vet;
if ( read_file(filename, &vet) )
exit(1);
return 0;
}

Re Q1:
a) Most POSIX functions actually return -1 (or <0) for errors, not 0. Look at (for instance) open(), close(), read(), write() and so forth. The exception is the POSIX calls that return pointers, e.g. fopen(), which returns a FILE *. These return NULL on error.
b) I code my code to work like POSIX functions, which is similar the innards of many linux programs. I would call this 'the UNIX C standard'. However, many C++ programs and Java programs use true for success and false for failure. When these programmers move to C, they use 1 for success, and 0 for failure. This isn't wrong, but does cause confusion (well, causes me confusion). The worst result is when both standards are used in the same program. Picking a standard and sticking to it is more important than which standard you choose.
c) My own choice (in relation to Q1), would be to return -1 on error (i.e. as per your 'another choice' line).
Re Q2: mostly right, yes.
a) If your program is successful, better to exit(0) than return 0 I believe.
b) Quite where you perror is up to you. Perhaps you want to print the error in main().
c) Using perror immediately followed by exit(1) (or perhaps a different exit code depending on the error) is reasonable normal if you have no clean up to do or clean up within atexit.
d) If you are returning the result of fclose() on error, then the return if fopen fails should be -1 (or EOF) not 1 as if fclose() fails it returns EOF (otherwise known as -1).
e) Nit: your main function should have parameters (e.g. int main(char **argv, int argc))

in respect of negative numbers for errors - cppcheck gives warnings for that. Choosing a standard within a program suite is a good idea - programmers have enough internal logic to deal with without duplicating ... So after trying to fix a few FOSS programs I am likely to go with cppcheck recommendations then at least I can have something check my adopted standard.

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.

getting undefined behavior in counting characters of text file program?

I wrote a c program meant to count the characters in a certain file.
int main(void) {
FILE *fp;
fp = fopen("txt.txt", "r");
char text;
int count;
while (fscanf(fp, "%c", &text) != EOF) {
count++;
}
printf("%d", count);
return 0;
}
I want to add a char array into it but for some reason it changes the value of my int type (count).
for example, if I run this program I get an output of 3549. Now, lets say I declare "char potato[5000]" alongside my other char type. For some reason I get a completely different output of 159062601. Why is this and how do I prevent that?
The following proposed code:
initializes variables before using them (your compiler should have told you about this problem.
properly checks and handles I/O errors for fopen() and for fscanf()
properly closes the open file before exiting. I.E. it cleans up after itself
properly terminates printed text, so it is immediately passed to the terminal
and now, the proposed code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
fp = fopen("txt.txt", "r");
if( ! fp )
{
perror( "fopen failed" );
exit( EXIT_FAILURE );
}
char text;
int count = 0;
while ( fscanf( fp, "%c", &text ) == 1 )
{
count++;
}
fclose( fp );
printf( "%d\n", count );
return 0;
}
You have several problems in your code. i will list them below:
In c programming we declare variables in the scope begin. and initialize them if we need so. you have a mixture of declerations and code.
count variable non initialized!! you have entered the while loop with garbage value in count. UB (Undefined behavior) - in each run you will get different values.
you didnt check the return value of fopen !! you must check if the operating system succed in opening the file you have requested to manipulate.
regarding asking a question in stackoverflow, your code is not complete and you didnt post all of it.
Now lets try to learn new topics regarding working with IO streams.
return value of function fscanf
The value EOF is returned if the end of input is reached before
either the first successful conversion or a matching failure occurs.
EOF is also returned if a read error occurs, in which case the
error indicator for the stream (see ferror(3)) is set, and errno
is set indicate the error.
This is how check if errors ocured while working with the file we are reading:
int ferror(FILE *stream);
The function ferror() tests the error indicator for the stream pointed
to by stream, returning nonzero if it is set. The error indicator can
only be reset by the clearerr() function.
And in this function bellow we get a human readble error, not just an errnor number!
explain_ferror
const char *explain_ferror(FILE *fp);
The explain_ferror function is used to obtain an explanation of an
error returned by the ferror(3) system call. The least the message
will contain is the value of strerror(errno), but usually it will do
much better, and indicate the underlying cause in more detail.
The errno global variable will be used to obtain the error value to be
decoded.
#include <stdlib.h>
#include <stdio.h>
#include <libexplain/ferror.h> /* for the non standard const char* explain_ferror(FILE* fp); */
int main(void)
{
FILE *fp;
char text;
int count = 0;
fp = fopen("txt.txt", "r");
if(fp == NULL)
{
perror("fopen failed"); /*write to standard error*/
exit(EXIT_FAILURE);
}
while (fscanf(fp, "%c", &text) != EOF)
{
++count;
}
if (ferror(fp)) /* nonzero return if error occured */
{
fprintf(stderr, "%s\n", explain_ferror(fp));
exit(EXIT_FAILURE);
}
printf("%d", count);
return 0;
}
Since the const char *explain_ferror(FILE *fp); is not GNU standard function, i am posting a GNU standard functions in the code snippet below:
char *strerror(int errnum);
strerror is standard library c function which returns a pointer to a string that describes the error code passed in the argument errnum. Be aware that this function is not Thread safe. for thread safe function use The strerror_r().
Return Value
The strerror(), function return the appropriate error description string, or an "Unknown error nnn" message if the error number is unknown.
Since POSIX.1-2001 and POSIX.1-2008 requires that a successful call to strerror() shall leave errno unchanged, and note that, since no function return value is reserved to indicate an error, if we wishe to check for errors we should initialize errno to zero before the call (by calling void clearerr(FILE *stream);, and then check errno after the call.
#include <string.h>
#include <errno.h>
#include <stdio.h>
...
clearerr(fp); /* clear previous seted errno */
while (fscanf(fp, "%c", &text) != EOF)
{
++count;
}
if (ferror(fp)) /* nonzero return if error occured */
{
fprintf(stderr, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}
...
Finally:
man pages (or man7) or typing man <enter_string_here> in terminal on linux shall clear all the q.marks.
for further reading go to:
explain_ferror
ferror
fscanf

How to use goto across multiple functions

I am trying to exit a program without using exit(). I have come up with a very convoluted and dirty solution (I am a Beginner).
I would like to use if statements and if it is true, then I would like to use goto to go the main function and then return 3; and end the program.
Here is a bit of code:
FILE *filepointer;
char * line = NULL;
size_t len = 0;
size_t read;
int linecount = 0;
filepointer = fopen(filename, "r");
if (filepointer == NULL)
{
printf("[ERR] Could not read file %s.\n",filename );
goto FILE_ERROR;
}
...
int main(){
...
FILE_ERROR: return 3;
}
This however does not work as I cannot get jump between functions because I get undeclared Label as an error. Is there any way I can exclude exit() from my program and still end it returning a certain value. If there is a better solution, please let me know
The only good answer to this question is: don't do it. gotos used in this way make your code very hard to reason about.
Refactor your code so that you have a clear structure and hierarchy of calls. Use return values to propagate success/failure throughout the call stack.
goto can't be used to jump across different functions; it can only be used within the same function. To jump between functions, you can look at setjmp() and longjmp() functions.
Having said, since you claim to be a beginner, I am not convinced you really need to use either of the above. You can simply modify your function to return an "error" value. And in main(), check its value and return from main() with the error value.
By design, a goto cannot jump from one function to another. It can only be used to jump within a given function.
There are ways to jump between functions, but doing so is not only very poor design but also dangerous as it is very easy to put your program in an invalid state.
The proper way to handle this is to have your function return a specific value (or set of values) to indicate an error. Then the calling function would check for one of those error values and act accordingly.
For example:
int readFile(char *filename)
{
FILE *filepointer;
char * line = NULL;
size_t len = 0;
size_t read;
int linecount = 0;
filepointer = fopen(filename, "r");
if (filepointer == NULL)
{
// add strerror(error) to the error message to know why fopen failed
printf("[ERR] Could not read file %s: %s.\n",filename, strerror(errno) );
// error completion
return 0;
}
...
// successful completion
return 1;
}
int main(){
...
if (readFile("myfile") == 0) {
return 3;
}
...
}
If you wanted to use a go-to , and insisted on doing that, you could I guess try to expand your 1st function so it includes / encapsulates the 2nd function, and get rid of the 2nd function conpletely, so your able to do go tos and subroutines within this much larger function.
Is that an option you could try ? (If you were dead cert on using Goto's, ) ?
I would give that a go.

wrap ungetc() without puts() gets() and streams in general

I'm porting net-snmp to an embedded platform that only has limited access to the filesystem and I stumbled upon a big problem. There's a part of the core code that uses the ungetc() function, which I don't have. There are of course 2 solutions:
A) write my own ungetc() using what I have
B) modify net-snmp code in order to achieve the same result without ungetc()
Solution (B) will be eventually discussed in the net-snmp coders mailing list since requires deep understanding of the library's internals, so let's please focus on feasibility of (A)
What I have on my embedded system is:
fopen()
fclose()
fcreate()
fwrite()
fread()
fdelete()
fclear()
fcopy()
ffindfirst()
ffindnext()
frename()
fgetsize()
ftell()
fseek()
fgetc()
fgets()
The main difference is that my file functions work with INT32* file handles instead of FILE* types. I don't have the FILE* type.
What the ungetc() function does is to basically "put back the char in the stream" , either the char that it just read or another one.
In the first case the solution is easy, I rewind the pointer with fseek() one position backwards.
But in the second case I have a problem. I would be modifying the stream and not the file, except I don't have streams! I'm reading the file directly.
With ungetc() you can do something like
FILE *fp = fopen("file.txt", "r");
int c = getc (fp);
if( c == 'a' ) ungetc ('b', fp);
If "file.txt" contains "abcdefghi", a subsequent read with gets() will read "bbcdefghi" and not "abcdefghi" because the content IN THE STREAM has been changed, but not the file!
How can I replicate this behavior if I don't have "streams" ? My getc() and gets() read from an INT32* file handle and I don't have a puts() or putc() equivalent.
I can only write with fwrite() but that alters the content on the NV memory.
Thank you for your insight
Here is how I solved it. I created a more complex struct for the file handle that contains not only the handle itself but also the file name, the file size and a buffer that holds the whole content of the file. It should only load the part of the file that I need but mine is an embedded application and I know I won't be opening big files so I didn't bother.
Then once you have the "stream" it's trivial to pop chars in and out.
typedef struct _myfile {
_FS_HANDLE handle; /* file descriptor */
CHAR* fname; /* file name */
UINT32 fsize; /* file size */
CHAR* buffer; /* file buffer */
} *my_FILE;
int my_ungetc(int c, my_FILE stream)
{
if (stream)
{
UINT32 pointer = _fs_tell(stream->handle);
if (pointer > 0)
{
_fs_seek(stream->handle,pointer - 1);
stream->buffer[pointer - 1] = c;
return c;
}
}
else
{
printf("ERROR! stream is NULL!\r\n");
}
return EOF;
}
void *my_fopen(const char *filename, const char *mode)
{
my_FILE fp = _mem_alloc(sizeof(struct _myfile));
fp->fname = strdup(filename);
if (mode == "r")
{
fp->handle = _fs_open((CHAR*)filename, OPEN_READ);
if (fp->handle) fp->fsize = _get_size_with_handle(fp->handle);
if (fp->fsize)
{
fp->buffer = _mem_alloc(fp->fsize);
if (fp->buffer)
{
if (_fs_read(fp->handle,fp->buffer,fp->fsize))
{
_fs_seek(fp->handle,0);
}
else
{
printf("ERROR: unable to read %d bytes from %s\r\n",fp->fsize,filename);
}
}
else
{
printf("ERROR in my_fopen(\"%s\",\"r\"): could not alloc %d bytes for buffer\r\n",filename,fp->fsize);
}
}
else
{
fp->buffer = NULL;
printf("File \"%s\" is empty\r\n");
}
return fp;
}
else if (mode == "w")
{
fp->handle = _fs_open((CHAR*)filename, OPEN_WRITE);
if (fp->handle) fp->fsize = _get_size_with_handle(fp->handle);
fp->buffer = NULL;
return fp;
}
else
{
printf("File open mode %s not supported\r\n",mode);
return NULL;
}
}

C: writing the following code into functions

Dear respected programmers. Please could you help me (again) on how to put the following code into functions for my program.
I have read on-line and understand how functions work but when I do it myself it all goes pear shaped/wrong(I am such a noob).
Please could you help with how to for example to write the code below into functions.(like opening the input file).
My initial code looks like:
main (int argc, char **argv)
{
int bytes_read, bytes_written;
struct stat inode;
int input_fd, output_fd;
char buffer[64];
int eof = 0;
int i;
/* Check the command line arguments */
if (argc != 3)
{
printf("syntax is: %s \n", <fromfile> <tofile>\n", argv[0]);
exit (1);
}
/* Check the input file exists and is a file */
if ((stat(argv[1], &inode) == -1) || (!S_ISREG(inode.st_mode)))
{
printf("%s is not a file\n", argv[1]);
exit(2);
}
/* Check that the output file doesnt exist */
if (stat(argv[2], &inode) != -1)
{
printf("Warning: The file %s already exists. Not going to overwrite\n", argv[2]);
exit(2);
}
/* Open the input file for reading */
input_fd = open(argv[1], O_RDONLY, 0);
if (input_fd == -1)
{
printf("%s cannot be opened\n", argv[1]);
exit(3);
}
output_fd = open(argv[2], O_CREAT | O_WRONLY | O_EXCL , S_IRUSR|S_IWUSR);
if (output_fd == -1)
{
printf("%s cannot be opened\n", argv[2]);
exit(3);
}
/* Begin processing the input file here */
while (!eof)
{
bytes_read = read(input_fd, buffer, sizeof(buffer));
if (bytes_read == -1)
{
printf("%s cannot be read\n", argv[1]);
exit(4);
}
if (bytes_read > > 0)
{
bytes_written = write(output_fd, buffer, bytes_read);
if (bytes_written == -1)
{
printf("There was an error writing to the file %s\n",argv[2]);
exit(4);
}
if (bytes_written != bytes_read)
{
printf("Devistating failure! Bytes have either magically appeared and been written or dissapeard and been skipped. Data is inconsistant!\n");
exit(101);
}
}
else
{
eof = 1;
}
}
close(input_fd);
close(output_fd);
}
My attempt at opening an output file:
void outputFile(int argc, char **argv)
{
/* Check that the output file doesnt exist */
if (stat(argv[argc-1], &inode) != -1)
{
printf("Warning: The file %s already exists. Not going to overwrite\n", argv[argc-1]);
return -1;
}
/*Opening ouput files*/
file_desc_out = open(argv[i],O_CREAT | O_WRONLY | O_EXCL , S_IRUSR|S_IWUSR);
if(file_desc_out == -1)
{
printf("Error: %s cannot be opened. \n",argv[i]); //insted of argv[2] have pointer i.
return -1;
}
}
Any help on how I would now reference to this in my program is appreciated thank you.
I tried:
ouputfile (but I cant figure out what goes here and why either).
Maybe the most useful function for you is:
#include <stdio.h>
#include <stdarg.h>
extern void error_exit(int rc, const char *format, ...); /* In a header */
void error_exit(int rc, const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(rc);
}
You can then write:
if (stat(argv[2], &inode) != -1)
error_exit(2, "Warning: The file %s exists. Not going to overwrite\n",
argv[2]);
Which has the merit of brevity.
You write functions to do sub-tasks. Deciding where to break up your code into functions is tricky - as much art as science. Your code is not so big that it is completely awful to leave it as it is - one function (though the error handling can be simplified as above).
If you want to practice writing functions, consider splitting it up:
open_input_file()
open_output_file()
checked_read()
checked_write()
checked_close()
These functions would allow your main code to be written as:
int main(int argc, char **argv)
{
int bytes_read;
int input_fd, output_fd;
char buffer[64];
if (argc != 3)
error_exit(1, "Usage: %s <fromfile> <tofile>\n", argv[0]);
input_fd = open_input_file(argv[1]);
output_fd = open_output_file(argv[2]);
while ((bytes_read = checked_read(input_fd, buffer, sizeof(buffer)) > 0)
check_write(output_fd, buffer, bytes_read);
checked_close(input_fd);
checked_close(output_fd);
return 0;
}
Because you've tucked the error handling out of sight, it is now much easier to see the structure of the program. If you don't have enough functions yet, you can bury the loop into a function void file_copy(int fd_in, int fd_out). That removes more clutter from main() and leaves you with very simple code.
Given an initial attempt at a function to open the output file:
void outputFile(int argc, char **argv)
{
/* Check that the output file doesnt exist */
if (stat(argv[argc-1], &inode) != -1)
{
printf("Warning: The file %s already exists. Not going to overwrite\n", argv[argc-1]);
return -1;
}
/*Opening ouput files*/
file_desc_out = open(argv[i],O_CREAT | O_WRONLY | O_EXCL , S_IRUSR|S_IWUSR);
if(file_desc_out == -1)
{
printf("Error: %s cannot be opened. \n",argv[i]); //insted of argv[2] have pointer i.
return -1;
}
}
Critique:
You have to define the variables used by the function in the function (you will want to avoid global variables as much as possible, and there is no call for any global variable in this code).
You have to define the return type. You are opening a file - how is the file descriptor going to be returned to the calling code? So, the return type should be int.
You pass only the information needed to the function - a simple form of 'information hiding'. In this case, you only need to pass the name of the file; the information about file modes and the like is implicit in the name of the function.
In general, you have to decide how to handle errors. Unless you have directives otherwise from your homework setter, it is reasonable to exit on error with an appropriate message. If you return an error indicator, then the calling code has to test for it, and decide what to do about the error.
Errors and warnings should be written to stderr, not to stdout. The main program output (if any) goes to stdout.
Your code is confused about whether argv[i] or argv[argc-1] is the name of the output file. In a sense, this criticism is irrelevant once you pass just the filename to the function. However, consistency is a major virtue in programming, and using the same expression to identify the same thing is usually a good idea.
Consistency of layout is also important. Don't use both if( and if ( in your programs; use the canonical if ( notation as used by the language's founding fathers, K&R.
Similarly, be consistent with no spaces before commas, a space after a comma, and be consistent with spaces around operators such as '|'. Consistency makes your code easier to read, and you'll be reading your code a lot more often than you write it (at least, once you've finished your course, you will do more reading than writing).
You cannot have return -1; inside a function that returns no value.
When you a splitting up code into functions, you need to copy/move the paragraphs of code that you are extracting, leaving behind a call to the new function. You also need to copy the relevant local variables from the calling function into the new function - possibly eliminating the variables in the calling function if they are no longer used there. You do compile with most warnings enabled, don't you? You want to know about unused variables etc.
When you create the new function, one of the most important parts is working out what the correct signature of the function is. Does it return a value? If so, which value, and what is its type? If not, how does it handle errors? In this case, you probably want the function to bail out (terminate the program) if it runs into an error. In bigger systems, you might need to consistently return an error indicator (0 implies success, negative implies failure, different negatives indicating different errors). When you work with function that return an error indicator, it is almost always crucial that you check the error indicators in the calling code. For big programs, big swathes of the code can be all about error handling. Similarly, you need to work out which values are passed into the function.
I'm omitting advice about things such as 'be const correct' as overkill for your stage in learning to program in C.
you seem to actually understand how to make a function. making a function really isnt that hard. first, you need to kind of understand that a function has a type. in otherwords, argc has type int and argv has type char *, your function (currently) has type void. void means it has no value, which means when you return, you return nothing.
however, if you look at your code, you do return -1. it looks like you want to return an interger. so you should change the top from void outputfile(...) to int outputfile(...).
next, your function must return. it wont compile if there is a circumstance where it won't return (besides infinite loops). so at the very bottom, if no errors happen, it will reach the end. since you're no longer using "void" as the return type, you must return something before the end of the function. so i suggest putting a return 1; to show that everything went great
There's several things.
The function return type isn't what you want. You either want to return a file descriptor or an error code. IIRC, the file descriptor is a nonnegative int, so you can use a return type of int rather than void. You also need to return something on either path, either -1 or file_desc_out.
You probably don't want to pass in the command-line arguments as a whole, but rather something like argv[argc - 1]. In that case, the argument should be something like char * filename rather than the argc/argv it has now. (Note that the argv[i] you've got in the last printf is almost certainly wrong.)
This means it would be called something like
int file_desc_out = outputFile(argv[argc - 1]);
You need to have all variables declared in the function, specifically inode and file_desc_out.
Finally, put an extra level of indentation on the code inside the { and } of the function itself.

Resources