fread and ferror don't set errno - c

I'm trying to check when fread() raises an error, so I use ferror().
chunk = fread(buf, 1, 100, file);
if (ferror(file))
{
return errno;
}
But, ferror() man page (man 3 ferror, or just man ferror) says:
ERRORS
These functions should not fail and do not set the external variable errno.
So, how can I know the error type occurred when file has been read, although fread() and ferror() didn't set errno?

You can't get there from here.
fread does not set errno (as you have discovered), and as such you cannot really determine much about a specific error state; only that there is one. The exact nature of the error is generally implementation-dependent. There is no C standard-library-based portable way to gather it .
For specific system-level errors, you can slum it to system-calls, possibly suffering with the pitfalls like poor/nonexistent IO buffering along the way. There POSIX can somewhat come to your rescue. Calls like read, do set errno and have a fairly detailed set of possible outcomes. That may be an option for you if the platform you're working with is POSIX compliant and the code is really so critical to be in-the-know.
But from the C standard library, you're not going to find much beyond being told an error has happened. Generally you'll find you don't need more than that anyway.

Those functions don't use errno, so you shouldn't either.
It is worth noting that you can tell if everything went smoothly from the return value of fread(). If the return value of fread() differs from the passed nmemb parameter (100 in your case), then you either reached the end of your file or an error occured reading it (source). So test only in that case:
Just drop the use of errno alltogether:
chunk = fread(buf, 1, 100, file);
if (chunk != 100) { // If fread() returns a number different to the nmemb parameter, either error or EOF occured
if (ferror(file))
{
printf("Error occured while reading file.");
return -1; // Or what ever return value you use to indicate an error
}
}

Related

Checking the return value of fclose() [duplicate]

Is it required to check the return value of fclose? If we have successfully opened a file, what are the chances that it may fail to close?
When you fwrite to a file, it may not actually write anything, it may stay in a buffer (inside the FILE object). Calling fflush would actually write it to disk. That operation may fail, for example if you just ran out of disk space, or there is some other I/O error.
fclose flushes the buffers implicitly too, so it may fail for the same reasons.
From comp.lang.c:
The fclose() call can fail, and should
be error-checked just as assiduously
as all the other file operations.
Sounds pedantic, right? Wrong. In a
former life, my company's product
managed to destroy a customer's data
by omitting a check for failure when
closing a file. The sequence went
something like (paraphrased):
stream = fopen(tempfile, "w");
if (stream == NULL) ...
while (more_to_write)
if (fwrite(buffer, 1, buflen, stream) != buflen) ...
fclose (stream);
/* The new version has been written successfully. Delete
* the old one and rename.
*/
remove (realfile);
rename (tempfile, realfile);
Of course, what happened was that
fclose() ran out of disk space trying
to write the last couple blocks of
data, so the `tempfile' was truncated
and unusable. And since the fclose()
failure wasn't detected, the program
went right ahead and destroyed the
best extant version of the data in
favor of the damaged version. And, as
Murphy would have it, the victim in
this particular incident was the
person in charge of the customer's
department, the person with authority
to buy more of our product or replace
it with a competitor's product --
and, natch, a person who was already
unhappy with us for other reasons.
It'd be a stretch to ascribe all of
the ensuing misery to this single
omission, but it may be worth pointing
out that both the customer and my
former company have since vanished
from the corporate ecology.
CHECK THOSE FAILURE CODES!
You could (and should) report the error, but in a sense, the stream is still closed:
After the call to fclose(), any use of stream results in undefined behavior.
fclose() will flush any unwritten output (via fflush()) before returning, so the error results from the underlying write() won't be reported at fwrite() or fprintf() time, but when you do the fclose(). As a result, any error that write() or fflush() can generate can be generated by fclose().
fclose() will also call close() which can generate errors on NFS clients, where the changed file isn't actually uploaded to the remote server until close() time. If the NFS server crashed, then the close() will fail, and thus fclose() will fail as well. This might be true of other networked filesystems.
You must ALWAYS check result of fclose()
Let's say you're generating data. You have old data that you fread() from a file, and then do some processing on the data, generate more data, and then write it to a new file. You are careful to not overwrite the old file because you know that trying to create new file might fail, and you would like to keep your old data in that case (some data is better than no data). After finishing all the fwrite()s, which all succeed (because you meticulously checked the return value from fwrite()), you fclose() the file. Then, you rename() your just-written file and overwrite the old file.
If fclose() failed because of write error (disk full?), you just overwrote your last good file with something that might be junk. Oops.
So, if it is critical, you should check the return value of fclose().
In terms of code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *ifp = fopen("in.dat", "rb");
FILE *ofp = fopen("out.dat", "wb");
char buf[BUFSIZ];
size_t n;
int success = 1;
if (ifp == NULL) {
fprintf(stderr, "error opening in.dat\n");
perror("in.dat");
return EXIT_FAILURE;
}
if (ofp == NULL) {
fclose(ifp);
fprintf(stderr, "error opening out.dat\n");
perror("out.dat");
return EXIT_FAILURE;
}
while ((n = fread(buf, 1, sizeof buf, ifp)) > 0) {
size_t nw;
if ((nw = fwrite(buf, 1, n, ofp)) != n) {
fprintf(stderr, "error writing, wrote %lu bytes instead of %lu\n",
(unsigned long)n,
(unsigned long)nw);
fclose(ifp);
fclose(ofp);
return EXIT_FAILURE;
}
}
if (ferror(ifp)) {
fprintf(stderr, "ferror on ifp\n");
fclose(ofp);
fclose(ifp);
return EXIT_FAILURE;
}
#ifdef MAYLOSE_DATA
fclose(ofp);
fclose(ifp);
rename("out.dat", "in.dat"); /* Oops, may lose data */
#else
if (fclose(ofp) == EOF) {
perror("out.dat");
success = 0;
}
if (fclose(ifp) == EOF) {
perror("in.dat");
success = 0;
}
if (success) {
rename("out.dat", "in.dat"); /* Good */
}
#endif
return EXIT_SUCCESS;
}
In the above code, we have been careful about fopen(), fwrite(), and fread(), but even then, not checking fclose() may result in data loss (when compiled with MAYLOSE_DATA defined).
One reason fclose can fail is if there is any data still buffered and the implicit fflush fails. What I recommend is to always call fflush and do any error handling there.
I've seen many times fclose() returning non-zero.
And on careful examination found out that the actual problem was with the write and not fclose.
Since the stuff being written are being buffered before actual write happens and when an fclose() is called all the buffer is flushed. So any problem in writing of the buffered suff, say like disk full, appears during fclose(). As David Yell says, to write a bullet proof application you need to consider the return value of fclose().
The fclose man page cites that it may fail for any of the reasons that close or fflush may fail.
Quoting:
The close() system call will fail if:
[EBADF] fildes is not a valid, active file descriptor.
[EINTR] Its execution was interrupted by a signal.
[EIO] A previously-uncommitted write(2) encountered an
input/output error.
fflush can fail for reasons that write() would fail, basically in the event that you can't actually write to/save the file.
In a sense, closing a file never fails: errors are returned if a pending write operation failed, but the stream will be closed.
To avoid problems and ensure (as far as you can from a C program), I suggest you:
Properly handle errors returned by fwrite().
Call fflush() before closing the stream. Do remember to check for errors returned by fflush().
If, in the context of your application, you can think of something useful to do if fclose() fails, then test the return value. If you can't, don't.

In Linux fwrite command does not set errno, how to get proper errno on failure cases

From man page of fwrite in linux,
DESCRIPTION
The function fread() reads nmemb elements of data, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr.
The function fwrite() writes nmemb elements of data, each size bytes long, to the stream pointed to by stream, obtaining them from the location given by ptr.
For nonlocking counterparts, see unlocked_stdio(3).
RETURN VALUE
On success, fread() and fwrite() return the number of items read or written. This number equals the number of bytes transferred only when size is 1. If an error occurs, or the end of the file is reached,
the return value is a short item count (or zero).
fread() does not distinguish between end-of-file and error, and callers must use feof(3) and ferror(3) to determine which occurred.
Now my question is:
Suppose fwrite() system call failure occurred due to No space on the drive. How can we get the errno for it. As fwrite is not setting the errno in case of failure.
Just in case errno is:
The header file defines the integer variable errno, which
is set by system calls and some library functions in the event of an
error to indicate what went wrong.
Talking in terms of Programming language: C
fwrite() is not a direct system call, and in general all I/O done via a FILE * pointer is buffered. There is no guarantee that a call to fwrite() will actually perform a write at that time. Errors can be returned immediately, or by later calls to functions using FILE *. However, fclose() will write out any remaining buffered data, and will return an error if that write did not succeed.
In summary, you need to check for errors during every call to fwrite(), fread() and fclose(). If you want to avoid doing error checking everywhere, you can call ferror() at any time to check the error status of a FILE *.
The variable errno is set when errors occur, because the C library internally calls read() and write(), and those set errno in case of errors.
fwrite() cannot fail due to EOF, but fread() can.
For fwrite(), you discover an error if it did not write the same amount of items you told it to, so you check it like this:
size_t written = fwrite(buf, element_size, num_elements, file);
if (written != num_elements) {
//error , here errno do get set and you can inspect it/print it etc.
}
Now, a FILE* have an internal buffer, so a fwrite() call might not actually write the data to the operating system or file unless that internal buffer gets full.
This means you also either have to fflush() the FILE* and also check for errors after each fwrite() call like so:
if (fflush(file) == EOF) {
//error , here errno do get set and you can inspect it/print it etc.
}
Or you have to accept that a potential write failure can be given to you on any future fwrite() calls you perform if e.g. those calls happens to flush() the FILE* automatically.
And you'd also have to check for errors when calling fclose():
if (fclose(file) == EOF) {
//error , here errno do get set and you can inspect it/print it etc.
}
For fread() you can inspect errno if it failed. After you have handled any data an fread() call have read, you can do
if (ferror(file)) {
//error , here errno do get set and you can inspect it/print it etc.
}
As fwrite is not setting the errno in case of failure: not exactly. The only possible error for fwrite is an error that would occur during the call of the underlying write system call. In that case the errno variable will be set but the write call and as such will be available, and you will be able to directly use the strerror or perror functions to get a textual description of the error.
BTW, fwrite is not a system call but a standard library function: is does not directly call a kernel function.

File operations with error indicator set

I have to individually read characters and substrings from a stream in C while parsing them. I wish also to check for input error. The obvious way to do this is something like:
c = fgetc(f);
if(ferror(f)) {
puts(strerror(errno));
exit(1);
}
/* do something with c */
c = fgetc(f);
if(ferror(f)) {
puts(strerror(errno));
exit(1);
}
/* do something with c */
Etc. However, it would be much more practical and fast (in the non-exceptional case when there's no error) if I could do all the input operations and check for the error indicator later:
c = fgetc(f);
/* do something with c */
c = fgetc(f);
/* do something with c */
if(ferror(f)) {
puts(strerror(errno));
exit(1);
}
This would be possible if input operations like fgetc(), scanf() etc were simple passthrough no-ops when the error indicator of f is set. Say, an error occours in the first fgetc() and therefore the second fgetc() is a no-op that fails but change neither the error indicator of f nor errno.
A similiar question may be asked about output functions.
My question is: is this the behaviour of stdio functions? May I check ferror(f) after all operations and get errno then if I am sure that all those "do something with c" do not change errno?
Thanks!
No, those are not the defined semantics of errno.
Quoting this manual page:
Its value is significant only when the return value of the call indicated an error (i.e., -1 from most system calls; -1 or NULL from most library functions); a function that succeeds is allowed to change errno.
This implies that if you were to do two I/O operations where the first fails, and the second is a "no-op" (like read zero bytes) it could succeed and opt to clear errno, thus dropping the error set by the first call.
Answering my own question, it seems that the reliable way to implement what I was looking for is to write a wrapper function myfgetc(), as Michael Walz suggested, together with a global variable myerrno:
__thread int myerrno = 0;
int myfgetc(FILE *f) {
int c;
if(myerrno)
return EOF;
if((c = fgetc(f)) == EOF)
myerrno = errno;
return c;
}
The storage class __thread is added to myerrno so that every thread has its own myerrno. It can be ommited if the program is single threaded.
...is this (an error occurs in the first fgetc() and therefore the second fgetc() is a no-op that fails) the behaviour of stdio functions?
No - not a no-op.
FILE has: "an error indicator that records whether a read/write error has occurred," (C11dr § § 7.21.1 2), not that an error just occurred. It is a flag that accumulates the history of read errors.
For fgetc() and friends,
If a read error occurs, the error indicator for the stream is set and the fgetc function returns EOF. C11dr § 7.21.7.1 3.
This return of EOF due to input error differs from EOF due to end-of-file. The latter has an or "If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end-of-file indicator for the stream is set and the fgetc function returns EOF". EOF due to input error does not have an or.
I interpret this to imply that the error indicator of the stream can be true and fgetc() does not return EOF as the byte just read was not in error.
How a stream error indicator affects following input code? may be useful.
May I check ferror(f) after all operations and get errno then if I am sure that all those "do something with c" do not change errno?
errno not that useful here. C does not specify any I/O functions as certainly setting errno - that is an extension of some compilers. C expressly prohibits standard functions from clearing errno.
Yes, code can check ferror(f) to see if an error had occurred sometime in the past. Examination of errno is not needed.
To clear both error indicator and end-of-file, research clearer().

Does EOF set errno?

I always struggle with return values of system calls - they are just so inconsistent!
Normally I check if they are NULL or -1 and then call perror. However, for fgets, the man page says:
gets() and fgets() return s on success, and NULL on error or when end of file occurs while no characters have been read.
which means the return value NULL is not necessarily an error - it can also be EOF. Is errno set when the end of file is reached? Can I still call perror in this case?
If not, what is the common way to tell if the call returned an error versus EOF. I want to use perror with NULL string for errors and a custom string for EOF.
Use ferror and feof to distinguish between error and EOF. There's no general way to find out exactly what the error was, if there was an error, but you can tell that there was one.
Standard C (f)gets (and (f)getc) are not required to set errno, although a conforming library implementation can set errno to a non-zero value pretty much at will.
Posix does requires that (f)get{c,s} set errno on read errors, but that only helps you after you have determined that there was a read error (by calling ferror). It's also important to remember that library functions never set errno to 0, but may set errno to a non-zero value even if no error occurs. So you cannot test errno as a replacement for checking the error return of any library function, including fgets. And since end-of-file is not an error, errno will (probably) not be modified on EOF, so its value in that case is meaningless.
According to fputs own documentation, yes, EOF does set errno. The man pages infer it indirectly as opposed to stating it outright, which hopefully will be amended. The function fputs returns an integer that will either be positive on success or EOF on failure. So the key to error handling fputs is to setup a code block that checks the return value of fputs as it is being called. The following is a snippet of how I've been taught to handle fputs errors.
if (fputs(buffer, stdout) == EOF)
{
fprintf(stderr, "fputs returned EOF: %s\n", strerror(errno));
// .. and now do whatever cleanup you need to do.
// or be lazy and exit(-1)
}
Here I am writing the contents of buffer to standard output and checking to see if fputs returns EOF. EOF indicates an error code was set, so as long as you follow the documentation on the man pages for fputs, you should be able to create a bunch of if statements to check the various error codes errno can be set to.
(1) What is buffer? Some character array I declared elsewhere.
(2) What does fprintf do? It prints output to a passed in file descriptor, which is in this case standard error (stderr... it prints to console like stdout, but for errors).
(3) What is strerror? It is a function defined in the string.h header that prints error information for the passed in error code. It has information for every single error code that errno can be set to. The header string.h should NOT be confused with strings.h, which is a BSD linux header file that does not contain strerror(3).
Edit: Ok, I messed up. You were looking for an answer on fgets, not fputs.
To check for an error on fgets, do the following
if (fgets(buffer, BUF_SIZE, myFile) == NULL)
{
// print out error as a string to stderr
fprintf(stderr, "fgets error occurred: %s\n", strerror(errno));
// do cleanup
}
// special: you also need to check errno AFTER the if statement...
The thing is, the only way you are getting an error on this is if the stream becomes unreadable, which is either due to permissions or trying to read something that is in write mode. In the case of a network, it may be possible for something to cut off your connection in the middle of reading, in which case you need to check the error code after the fgets if statement as well. But it will set the error code if something went wrong.
At least that is if the man pages are correct. See the linux man pages for more details. Only error code that can be set is the "I can't read this thing" code, which is errno == EBADF

fclose return value check

Is it required to check the return value of fclose? If we have successfully opened a file, what are the chances that it may fail to close?
When you fwrite to a file, it may not actually write anything, it may stay in a buffer (inside the FILE object). Calling fflush would actually write it to disk. That operation may fail, for example if you just ran out of disk space, or there is some other I/O error.
fclose flushes the buffers implicitly too, so it may fail for the same reasons.
From comp.lang.c:
The fclose() call can fail, and should
be error-checked just as assiduously
as all the other file operations.
Sounds pedantic, right? Wrong. In a
former life, my company's product
managed to destroy a customer's data
by omitting a check for failure when
closing a file. The sequence went
something like (paraphrased):
stream = fopen(tempfile, "w");
if (stream == NULL) ...
while (more_to_write)
if (fwrite(buffer, 1, buflen, stream) != buflen) ...
fclose (stream);
/* The new version has been written successfully. Delete
* the old one and rename.
*/
remove (realfile);
rename (tempfile, realfile);
Of course, what happened was that
fclose() ran out of disk space trying
to write the last couple blocks of
data, so the `tempfile' was truncated
and unusable. And since the fclose()
failure wasn't detected, the program
went right ahead and destroyed the
best extant version of the data in
favor of the damaged version. And, as
Murphy would have it, the victim in
this particular incident was the
person in charge of the customer's
department, the person with authority
to buy more of our product or replace
it with a competitor's product --
and, natch, a person who was already
unhappy with us for other reasons.
It'd be a stretch to ascribe all of
the ensuing misery to this single
omission, but it may be worth pointing
out that both the customer and my
former company have since vanished
from the corporate ecology.
CHECK THOSE FAILURE CODES!
You could (and should) report the error, but in a sense, the stream is still closed:
After the call to fclose(), any use of stream results in undefined behavior.
fclose() will flush any unwritten output (via fflush()) before returning, so the error results from the underlying write() won't be reported at fwrite() or fprintf() time, but when you do the fclose(). As a result, any error that write() or fflush() can generate can be generated by fclose().
fclose() will also call close() which can generate errors on NFS clients, where the changed file isn't actually uploaded to the remote server until close() time. If the NFS server crashed, then the close() will fail, and thus fclose() will fail as well. This might be true of other networked filesystems.
You must ALWAYS check result of fclose()
Let's say you're generating data. You have old data that you fread() from a file, and then do some processing on the data, generate more data, and then write it to a new file. You are careful to not overwrite the old file because you know that trying to create new file might fail, and you would like to keep your old data in that case (some data is better than no data). After finishing all the fwrite()s, which all succeed (because you meticulously checked the return value from fwrite()), you fclose() the file. Then, you rename() your just-written file and overwrite the old file.
If fclose() failed because of write error (disk full?), you just overwrote your last good file with something that might be junk. Oops.
So, if it is critical, you should check the return value of fclose().
In terms of code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *ifp = fopen("in.dat", "rb");
FILE *ofp = fopen("out.dat", "wb");
char buf[BUFSIZ];
size_t n;
int success = 1;
if (ifp == NULL) {
fprintf(stderr, "error opening in.dat\n");
perror("in.dat");
return EXIT_FAILURE;
}
if (ofp == NULL) {
fclose(ifp);
fprintf(stderr, "error opening out.dat\n");
perror("out.dat");
return EXIT_FAILURE;
}
while ((n = fread(buf, 1, sizeof buf, ifp)) > 0) {
size_t nw;
if ((nw = fwrite(buf, 1, n, ofp)) != n) {
fprintf(stderr, "error writing, wrote %lu bytes instead of %lu\n",
(unsigned long)n,
(unsigned long)nw);
fclose(ifp);
fclose(ofp);
return EXIT_FAILURE;
}
}
if (ferror(ifp)) {
fprintf(stderr, "ferror on ifp\n");
fclose(ofp);
fclose(ifp);
return EXIT_FAILURE;
}
#ifdef MAYLOSE_DATA
fclose(ofp);
fclose(ifp);
rename("out.dat", "in.dat"); /* Oops, may lose data */
#else
if (fclose(ofp) == EOF) {
perror("out.dat");
success = 0;
}
if (fclose(ifp) == EOF) {
perror("in.dat");
success = 0;
}
if (success) {
rename("out.dat", "in.dat"); /* Good */
}
#endif
return EXIT_SUCCESS;
}
In the above code, we have been careful about fopen(), fwrite(), and fread(), but even then, not checking fclose() may result in data loss (when compiled with MAYLOSE_DATA defined).
One reason fclose can fail is if there is any data still buffered and the implicit fflush fails. What I recommend is to always call fflush and do any error handling there.
I've seen many times fclose() returning non-zero.
And on careful examination found out that the actual problem was with the write and not fclose.
Since the stuff being written are being buffered before actual write happens and when an fclose() is called all the buffer is flushed. So any problem in writing of the buffered suff, say like disk full, appears during fclose(). As David Yell says, to write a bullet proof application you need to consider the return value of fclose().
The fclose man page cites that it may fail for any of the reasons that close or fflush may fail.
Quoting:
The close() system call will fail if:
[EBADF] fildes is not a valid, active file descriptor.
[EINTR] Its execution was interrupted by a signal.
[EIO] A previously-uncommitted write(2) encountered an
input/output error.
fflush can fail for reasons that write() would fail, basically in the event that you can't actually write to/save the file.
In a sense, closing a file never fails: errors are returned if a pending write operation failed, but the stream will be closed.
To avoid problems and ensure (as far as you can from a C program), I suggest you:
Properly handle errors returned by fwrite().
Call fflush() before closing the stream. Do remember to check for errors returned by fflush().
If, in the context of your application, you can think of something useful to do if fclose() fails, then test the return value. If you can't, don't.

Resources