I have basic code as follows,
fd = open("test.file", O_RDONLY);
if (read(fd, &tempch, 1) < 1) {
perror("File Read Error");
exit(1);
}
printf("We could read from the file\n");
the test.file is present in file system and has been granted with 777 rights. the program throws error "file read error: success"... could anybody tell the possible reason? thanks
It is perfectly normal for read() to return a zero count, it simply means that it has encountered the end of a file. If it returns a value less than zero, it is an error.
If -1 is returned, errno should be set, which will tell you what went wrong.
Does your file contain anything? Since you mentioned UNIX like permissions, the POSIX specification for read() should be useful for you.
You might want to check the return value of open and also how many bytes are present in test.file! If the file is of 0 bytes then return value of less than 1 is as expected.
From the read manual page
On success, the number of bytes read
is returned (zero indicates end of
file), and the file position is
advanced by this number. It is not an
error if this number is smaller than
the number of bytes requested; this
may happen for example because fewer
bytes are actually available right now
(maybe because we were close to
end-of-file, or because we are reading
from a pipe, or from a terminal), or
because read() was interrupted by a
signal.
I'm not certain, but this
if (read(fd, &tempch, 1) < 1)
should almost certainly be
if (read(fd, &tempch, 1) < 0)
Related
This code works beautifully in Linux, but with MacOS it always fails to read the tree (it will read too bytes). It works with redirection from a file. It reads when a file is explicitly opened. But on a pipe, always too few bytes.
// Load the saved tree
uint16_t treeBytes = 0;
read(fileIn, &treeBytes, sizeof(treeBytes));
if (verbose) { printf("tree (%u)\n", treeBytes); }
uint8_t savedTree[treeBytes];
int readSz = read(fileIn, savedTree, treeBytes);
if (readSz != treeBytes)
{
fprintf(stderr, "%d != %u: ", readSz, treeBytes);
ERROR("Truncated tree read");
}
There are two bugs here:
You aren't checking the return from the first read() call. There are four possible returns here, three of which will break your program: -1 on error, 0 on abnormal close (typical for sockets only), 1 for a short read, and 2 (sizeof(treeBytes)) for a successful read. Don't assume.
You are collapsing those three failure cases as one in your second read(), which probably explains your reported symptom. There is nothing mandating that read() must block until it gets treeBytes from the pipe. It is allowed to return 1 byte at a time for a blocking FD, and 0 for a nonblocking FD. As Mark Sechell comented above, read in a loop until you have as many bytes as you expect or you hit an error case.
I have some legacy code that does this all over the place:
int fd; // open a file
if(fd == -1)
{
close(fd);
}
This looks very wrong to me.
Is closing an invalid file descriptor valid?
According to manual:
Upon successful completion, a value of 0 is returned. Otherwise, a
value
of -1 is returned and the global integer variable errno is set to indicate the error.
and then:
The close() system call will fail if:
[EBADF] fildes is not a valid, active file descriptor.
Then nothing harmful will happen.
It returns an error code.There is nothing wrong but it is not useful either, as there is no check made on the return value anyway.
Quoting the man page
Return Value
close() returns zero on success. On error, -1 is returned, and errno is set appropriately.
and
Errors
EBADF
fd isn't a valid open file descriptor.
note that in windows msvc, calling close with an invalid fd causes an abort() to occur by means of an assertion. the fd is checked it is greater than or equal to 0 and less than some magic number "nhandle" (which has the value of 64 on my system) not even an exception you can catch, or returning -1. it just bombs.
you'll get something like this (screenshot thanks to one of the users of my library):
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
}
}
Consider the following line of code:
while((n = read(STDIN_FILENO, buff, BUFSIZ)) > 0)
As per my understanding read/write functions are a part of non-buffered I/O. So does that mean read() function will read only one character per call from stdio? Or in other words, the value of n will be
-1 in case of error
n = 0 in case of EOF
1 otherwise
If it is not the case, when would the above read() function will return and why?
Note: I was also thinking that read() will wait until it successfully reads BUFSIZ number of characters from stdin. But what happens in a case number of characters available to read are less than BUFSIZ? Will read wait forever or until EOF arrives (Ctrl + D on unix or Ctrl + Z on windows)?
Also, lets say BUFSIZ = 100 and stdin = ACtrl+D (i.e EOF immediately following a single character). Now how many times the while loop will iterate?
The way read() behaves depends on what is being read. For regular files, if you ask for N characters, you get N characters if they are available, less than N if end of file intervenes.
If read() is reading from a terminal in canonical/cooked mode, the tty driver provides data a line at a time. So if you tell read() to get 3 characters or 300, read will hang until the tty driver has seen a newline or the terminal's defined EOF key, and then read() will return with either the number of characters in the line or the number of characters you requested, whichever is smaller.
If read() is reading from a terminal in non-canonical/raw mode, read will have access to keypresses immediately. If you ask read() to get 3 characters it might return with anywhere from 0 to 3 characters depending on input timing and how the terminal was configured.
read() will behave differently in the face of signals, returning with less than the requested number of characters, or -1 with errno set to EINTR if a signal interrupted the read before any characters arrived.
read() will behave differently if the descriptor has been configured for non-blocking I/O. read() will return -1 with errno set to EAGAIN or EWOULDBLOCK if no input was immediately available. This applies to sockets.
So as you can see, you should be ready for surprises when you call read(). You won't always get the number of characters you requested, and you might get non-fatal errors like EINTR, which means you should retry the read().
Your code reads:
while((n = read(0, buff, BUFSIZ) != 0))
This is flawed - the parentheses mean it is interpreted as:
while ((n = (read(0, buff, BUFSIZ) != 0)) != 0)
where the boolean condition is evaluated before the assignment, so n will only obtain the values 0 (the condition is not true) and 1 (the condition is true).
You should write:
while ((n = read(0, buff, BUFSIZ)) > 0)
This stops on EOF or a read error, and n lets you know which condition you encountered.
Apparently, the code above was a typo in the question.
Unbuffered I/O will read up to the number of characters you read (but not more). It may read less on account of EOF or an error. It may also read less because less is available at the time of the call. Consider a terminal; typically, that will only read up to the end of line because there isn't any more available than that. Consider a pipe; if the feeding process has generated 128 unread bytes, then if BUFSIZ is 4096, you'll only get 128 bytes from the read. A non-blocking file descriptor may return because nothing is available; a socket may return fewer bytes because there isn't more information available yet; a disk read may return fewer bytes because there are fewer than the requested number of bytes left in the file when the read is performed.
In general, though, read() won't return just one byte if you request many bytes.
As the read() manpage states:
Return Value
On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal. On error, -1 is returned, and errno is set appropriately. In this case it is left unspecified whether the file position (if any) changes.
So, each read() will read up to the number of specified bytes; but it may read less. "Non-buffered" means that if you specify read(fd, bar, 1), read will only read one byte. Buffered IO attempts to read in quanta of BUFSIZ, even if you only want one character. This may sound wasteful, but it avoids the overhead of making system calls, which makes it fast.
read attempts to get all of characters requested.
if EOF happens before all of the requested characters can be returned, it returns what it got
after it does this the next read returns -1, to let you know you the file end.
What happens when it tries to read and there is nothing there involves something called blocking. You can call open to read a file blocking or non-blocking. "blocking" means wait until there is something to return.
This is what you see in a shell waiting for input. It sits there. Until you hit return.
Non-blocking means that read will return no bytes of data if there are none. Depending on a lot of other factors which would make a completely correct answer unusable for you, read will set errno to something like EWOULDBLOCK, which lets you know why your read returned zero bytes. It is not necessarily a fatal error.
Your code could test for a minus to find EOF or errors
When we say read is unbuffered, it means no buffering takes place at the level of your process after the data is pulled off the underlying open file description, which is a potentially-shared resource. If stdin is a terminal, there are likely at least 2 additional buffers in play, however:
The terminal buffer, which can probably hold 1-4k of data off the line until.
The kernel's cooked/canonical mode buffer for line entry/editing on a terminal, which lets the user perform primitive editing (backspace, backword, erase line, etc.) on the line until it's submitted (to the buffer described above) by pressing enter.
read will pull whatever has already been submitted, up to the max read length you passed to it, but it cannot pull anything from the line editing buffer. If you want to disable this extra layer of buffering, you need to lookup how to disable cooked/canonical mode for a terminal using tcsetattr, etc.
I have got a small program that prints the contents of files using the system call - read.
unsigned char buffer[8];
size_t offset=0;
size_t bytes_read;
int i;
int fd = open(argv[1], O_RDONLY);
do{
bytes_read = read(fd, buffer, sizeof(buffer));
printf("0x%06x : ", offset);
for(i=0; i<bytes_read; ++i)
{
printf("%c ", buffer[i]);
}
printf("\n");
offset = offset + bytes_read;
}while(bytes_read == sizeof(buffer));
Now while running I give a file name that doesn't exist.
It prints some kind of data mixed with environment variables and a segmentation fault at the end.
How is this possible? What is the program printing?
Thanks,
John
It's printing rubbish because fd will invariably be set to -1 which is not a good thing to pass to read since it will, in turn do nothing other than return -1 as well. It will leave your buffer untouched meaning that it's holding whatever rubbish you had in there when you started.
You could probably put the entire do loop inside something like:
if (fd == -1) {
printf ("error here");
} else {
// do loop here
}
read is returning -1 because fd is invalid, you store that in bytes_read which is of type size_t which is unsigned, so your loop prints (size_t)-1 chars, which is a very large number, much larger than the size of buffer. So, you're printing a big chunk of your address space and then getting a segfault when you eventually reach the end and access an invalid address.
As others have mentioned (without answering your actual question), you should be checking the results of open for an error. e.g.,
int fd = open(argv[1], O_RDONLY);
if( fd < 0 ){
fprintf(stderr, "error opening %s: %s\n", argv[1], strerror(errno));
exit(1);
}
A caveat: if you do another system call, or call any routine that might do a system call (e.g., printf) before calling strerror, you must save errno and then pass the saved copy to strerror.
Another note about your program:
while(bytes_read == sizeof(buffer))
This is not a good test, because read can return less than the amount you ask for. Your loop should continue until read returns <= 0.
You should probably check that the file descriptor returned by open is valid before using it. As per these docs, you should get a non-negative response for a valid file. Reading from an invalid descriptor is likely the source of your problem.
Upon successful completion, open function shall open the file and return a non-negative integer representing the file descriptor. Otherwise, -1 shall be returned and errno set to indicate the error. So please check fd before entering the loop to perform the read.