I'm writing a function that perform some authentications actions. I have a file with all the user_id:password:flag couples structured like this:
Users.txt
user_123:a1b2:0 user_124:a2b1:1 user_125:a2b2:2
This is the code:
int main(){
/*...*/
/*user_id, password retrieving*/
USRPSW* p = malloc(sizeof(USRPSW));
if(p == NULL){
fprintf(stderr, "Dynamic alloc error\n");
exit(EXIT_FAILURE);
}
memset((void*)p, 0, sizeof(USRPSW));
if(usr_psw_read(acc_sock_ds, p->user_id, USR_SIZE) <= 0){
printf("Failed read: connection with %s aborted.\n",
inet_ntoa(client_addr.sin_addr));
close(acc_sock_ds);
continue;
}
if(usr_psw_read(acc_sock_ds, p->password, PSW_SIZE) <= 0){
printf("Failed read: connection with %s aborted.\n",
inet_ntoa(client_addr.sin_addr));
close(acc_sock_ds);
continue;
}
/*Authentication through user_id, password*/
FILE *fd;
fd = fopen(USERSFILE, "r");
if(fd == NULL){
fprintf(stderr, "Users file opening error\n");
exit(EXIT_FAILURE);
}
char *usr_psw_line = malloc(USR_SIZE+PSW_SIZE+3+1);
if(usr_psw_line == NULL){
fprintf(stderr, "Dynamic alloc error\n");
exit(EXIT_FAILURE);
}
while(1){
memset((void*)usr_psw_line, 0, sizeof(USR_SIZE+PSW_SIZE+3+1));
fgets(usr_psw_line, USR_SIZE+PSW_SIZE+3+1, fd);
printf("%s\n", usr_psw_line);
fseek(fd, 1, SEEK_CUR);
/*EOF management*/
/*usr_id - password matching checking */
}
/*...*/
}
How can I manage the EOF reaching? I saw that when EOF is reached fgets doesn't edits anymore the usr_psw_line but neither returns a NULL pointer. If EOF is reached it mean that no match are found in the users file and the loop breaks.
Can someone give me some tips or suggests?
fgets() return a null pointer when it reaches end-of-file or an error condition.
(EOF is a macro that specifies the value returned by certain other functions in similar conditions; it's not just an abbreviation for the phrase "end of file".)
You're ignoring the result returned by fgets(). Don't do that.
Note that just checking feof(fd) won't do what you want. feof() returns a true result if you've reached the end of the file. If you encounter an error instead, feof() still returns false, and you've got yourself an infinite loop if you're using feof() to decide when you're done. And it doesn't return true until after you've failed to read input.
Most C input functions return some special value to indicate that there's nothing more to read. For fgets() it's NULL, for fgetc() it's EOF, and so forth. If you like, you can call feof() and/or ferror() afterwards to determine why there's nothing more to read.
You might want to try something like this in your loop:
while(1)
{
memset((void*)usr_psw_line, 0, sizeof(USR_SIZE+PSW_SIZE+3+1));
if( !fgets(usr_psw_line, USR_SIZE+PSW_SIZE+3+1, fd)
|| ferror( fd ) || feof( fd ) )
{
break;
}
printf("%s\n", usr_psw_line);
fseek(fd, 1, SEEK_CUR);
/*EOF management*/
/*usr_id - password matching checking */
}
With the extra code, the loop will terminate if fgets returns NULL (no more data to read) or if you're read the EOF mark or had any error on the file. I'm sure it is overkill, but those tests have always worked for me.
Related
I figured out why the following loop was giving me bad input, re Why is “while ( !feof (file) )” always wrong?
do {
if (fread(buf, 1, siz, stdin) != siz) {
if (feof(stdin))
fputs("bad input\n", stderr);
else /* implying ferror(stdin) */
perror("fread() failed");
return EXIT_FAILURE;
}
use(buf);
} while (!feof(stdin));
Is it inevitable to write some auxiliary function/weird call for properly(?) checking EOF along the lines of ungetc(getchar(), stdin) or is there a better way?
I'd do something like
size_t nread;
while ((nread = fread(buf, 1, siz, stdin)) == siz) {
use(buf);
}
if (feof(stdin)) {
if (nread == 0) {
/* Normal EOF; do nothing. I would not actually
write this branch. :-) */
} else {
/* Short read. */
fputs("bad data\n", stderr); }
}
} else {
perror("fread");
}
There is no need to use ungetc to check for end-of-file. Instead, you can rewrite your loop to the following:
while ( fread(buf, 1, siz, stdin) == siz )
{
use(buf);
}
//verify that the loop was terminated due to end-of-file and not due
//to stream error
if ( ferror(stdin) )
{
perror( "fread() failed" );
return EXIT_FAILURE;
}
//No stream error occurred, so the loop must have been terminated due
//to end-of-file. Therefore, everything is ok and we can continue
//running the program normally.
Depending on the situation, you may want to additionally check whether a partial read occurred, and also treat that as an error. See the other answer on how you can do that.
I've a rather curious question, not very practical at all really. The error (reading a binary file in r mode) is in plain sight but I'm confused by something else.
Here's the code-
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdint.h>
#define BUFFER_LEN 512
typedef uint8_t BYTE;
int main()
{
FILE* memcard = fopen("card.raw", "r");
BYTE buffer[BUFFER_LEN];
int count = 0;
while (fread(buffer, sizeof(*buffer), BUFFER_LEN, memcard) != 0)
{
printf("count: %d\n", count++);
}
fclose(memcard);
return 0;
}
Now, card.raw is a binary file, so this reading will go wrong due to being read in r mode instead of rb. But what I'm curious about is that, that loop executes exactly 3 times, in the final execution, it doesn't even read 512 bytes.
Now if I change that loop to
while (fread(buffer, sizeof(*buffer), BUFFER_LEN, memcard) != 0)
{
printf("ftell: %ld\n", ftell(memcard));
}
It no longer stops at 3 executions. In fact, it keeps going until (presumabely) the end of file. The fread count is still messed up. Many of the reads do not return 512 as elements read. But that is most probably due to the file being opened in r mode and all the encoding errors it's being accompanied with .
ftell shouldn't affect the file itself, then why does including ftell in the loop make it execute more times?
I decided to change the loop a bit more to extract more info-
while ((count = fread(buffer, sizeof(*buffer), BUFFER_LEN, memcard)) != 0)
{
printf("fread bytes read: %d\n", count);
printf("ftell: %ld\n", ftell(memcard));
}
This loops just as many times as it would, provided ftell is included in the loop and the first few results look like-
Now if I just remove that ftell line completely, it gives me-
Only 3 executions, yet nothing changed.
What's the explanation behind this behaviour?
Note: I know the counts returned by both fread and ftell are probably wrong due to the read mode, that's not my concern though. I'm only curious - why the difference, between including ftell and not including it.
Also, in case it helps, The card.raw file is actually just the cs50 pset4 "memory card". You can get it by wget https://cdn.cs50.net/2019/fall/psets/4/recover/recover.zip and storing the output file in a .zip
Edit: I should mention this was on windows and using clang tools for VS2019. The command line options (checked from VS2019 project properties) looked like-
/permissive- /GS /W3 "Debug\" "Debug\" /Zi /Od "Debug\vc142.pdb" /fp:precise /D "_CRT_SECURE_NO_WARNINGS" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /WX- /Gd /MDd /Fa"Debug\" /EHsc /nologo /Fo"Debug\" /Fp"Debug\Test.pch" /diagnostics:column
Edit: Also, I did check for ferror inside the loop, with and without ftell, got no errors from it at all. In fact, feof returns 1 after the loop, in both cases.
Edit: I also tried adding a memcard == NULL check right after the fopen, same behaviour.
Edit: To address the answer by #orlp. I did, infact, check for errors. I should definitely have posted it though.
while ((count = fread(buffer, sizeof(*buffer), BUFFER_LEN, memcard)) != 0)
{
if ((err = ferror(memcard)))
{
fprintf(stderr, "Error code: %d", err);
perror("Error: ");
return 1;
}
printf("fread bytes read: %d\n", count);
printf("ftell: %ld\n", ftell(memcard));
}
if ((err = ferror(memcard)))
{
fprintf(stderr, "Error code: %d", err);
perror("Error: ");
return 1;
}
Neither of the 2 if statements are ever triggered.
Edit: I thought we got the answer already, it was ftell resetting the EOF. But I changed the loop to-
while ((count = fread(buffer, sizeof(*buffer), BUFFER_LEN, memcard)) != 0)
{
if ((err = ferror(memcard)))
{
fclose(memcard);
fprintf(stderr, "Error code: %d", err);
perror("Error: ");
return 1;
}
if (feof(memcard))
{
printf("reached before\n");
}
printf("fread bytes read: %d\n", count);
ftell(memcard);
if (feof(memcard))
{
printf("reached after\n");
}
}
this triggers both the first if(feof) and the second if(feof)
As expected though, if I change the ftell to fseek(memcard, 0, SEEK_CUR), the EOF is reset and the reached after is never printed.
As some commentors pointed out, it ran into an EOF, and ftell actually got rid of that EOF. Why? To find the answer, we have to look inside glibc's source code. We can find the source for ftell::
long int
_IO_ftell (FILE *fp)
{
off64_t pos;
CHECK_FILE (fp, -1L);
_IO_acquire_lock (fp);
pos = _IO_seekoff_unlocked (fp, 0, _IO_seek_cur, 0);
if (_IO_in_backup (fp) && pos != _IO_pos_BAD)
{
if (_IO_vtable_offset (fp) != 0 || fp->_mode <= 0)
pos -= fp->_IO_save_end - fp->_IO_save_base;
}
_IO_release_lock (fp);
if (pos == _IO_pos_BAD)
{
if (errno == 0)
__set_errno (EIO);
return -1L;
}
if ((off64_t) (long int) pos != pos)
{
__set_errno (EOVERFLOW);
return -1L;
}
return pos;
}
libc_hidden_def (_IO_ftell)
weak_alias (_IO_ftell, ftell)
This is the important line:
pos = _IO_seekoff_unlocked (fp, 0, _IO_seek_cur, 0);
Let's find the source for _IO_seekoff_unlocked:
off64_t
_IO_seekoff_unlocked (FILE *fp, off64_t offset, int dir, int mode)
{
if (dir != _IO_seek_cur && dir != _IO_seek_set && dir != _IO_seek_end)
{
__set_errno (EINVAL);
return EOF;
}
/* If we have a backup buffer, get rid of it, since the __seekoff
callback may not know to do the right thing about it.
This may be over-kill, but it'll do for now. TODO */
if (mode != 0 && ((_IO_fwide (fp, 0) < 0 && _IO_have_backup (fp))
|| (_IO_fwide (fp, 0) > 0 && _IO_have_wbackup (fp))))
{
if (dir == _IO_seek_cur && _IO_in_backup (fp))
{
if (_IO_vtable_offset (fp) != 0 || fp->_mode <= 0)
offset -= fp->_IO_read_end - fp->_IO_read_ptr;
else
abort ();
}
if (_IO_fwide (fp, 0) < 0)
_IO_free_backup_area (fp);
else
_IO_free_wbackup_area (fp);
}
return _IO_SEEKOFF (fp, offset, dir, mode);
}
Basically, it just does some checks then calls _IO_SEEKOFF, so let's find its source:
/* The 'seekoff' hook moves the stream position to a new position
relative to the start of the file (if DIR==0), the current position
(MODE==1), or the end of the file (MODE==2).
It matches the streambuf::seekoff virtual function.
It is also used for the ANSI fseek function. */
typedef off64_t (*_IO_seekoff_t) (FILE *FP, off64_t OFF, int DIR,
int MODE);
#define _IO_SEEKOFF(FP, OFF, DIR, MODE) JUMP3 (__seekoff, FP, OFF, DIR, MODE)
So basically, ftell ends up calling a function which is the equivalent of fseek(fp, 0, SEEK_CUR). And in the fseek standards we see: "A successful call to the fseek() function clears the end-of-file indicator for the stream." That's why ftell changes the behavior of the program.
fread() has
The fread function returns the number of elements successfully read, which may be less than nmemb if a read error or end-of-file is encountered.
When count < BUFFER_LEN, OP reported feof() was true - as expected.
What is unexpected is that a following fread() returns non-zero.
IMO, a non-compliant library.
(OP reports new info, so this answer now incomplete.)
It appears ftell(), incorrectly IMO, reset the end-of-file indicator for the stream, allowing additional reads to occur.
I'm writing a function that perform some authentications actions. I have a file with all the user_id:password:flag couples structured like this:
Users.txt
user_123:a1b2:0 user_124:a2b1:1 user_125:a2b2:2
This is the code:
int main(){
/*...*/
/*user_id, password retrieving*/
USRPSW* p = malloc(sizeof(USRPSW));
if(p == NULL){
fprintf(stderr, "Dynamic alloc error\n");
exit(EXIT_FAILURE);
}
memset((void*)p, 0, sizeof(USRPSW));
if(usr_psw_read(acc_sock_ds, p->user_id, USR_SIZE) <= 0){
printf("Failed read: connection with %s aborted.\n",
inet_ntoa(client_addr.sin_addr));
close(acc_sock_ds);
continue;
}
if(usr_psw_read(acc_sock_ds, p->password, PSW_SIZE) <= 0){
printf("Failed read: connection with %s aborted.\n",
inet_ntoa(client_addr.sin_addr));
close(acc_sock_ds);
continue;
}
/*Authentication through user_id, password*/
FILE *fd;
fd = fopen(USERSFILE, "r");
if(fd == NULL){
fprintf(stderr, "Users file opening error\n");
exit(EXIT_FAILURE);
}
char *usr_psw_line = malloc(USR_SIZE+PSW_SIZE+3+1);
if(usr_psw_line == NULL){
fprintf(stderr, "Dynamic alloc error\n");
exit(EXIT_FAILURE);
}
while(1){
memset((void*)usr_psw_line, 0, sizeof(USR_SIZE+PSW_SIZE+3+1));
fgets(usr_psw_line, USR_SIZE+PSW_SIZE+3+1, fd);
printf("%s\n", usr_psw_line);
fseek(fd, 1, SEEK_CUR);
/*EOF management*/
/*usr_id - password matching checking */
}
/*...*/
}
How can I manage the EOF reaching? I saw that when EOF is reached fgets doesn't edits anymore the usr_psw_line but neither returns a NULL pointer. If EOF is reached it mean that no match are found in the users file and the loop breaks.
Can someone give me some tips or suggests?
fgets() return a null pointer when it reaches end-of-file or an error condition.
(EOF is a macro that specifies the value returned by certain other functions in similar conditions; it's not just an abbreviation for the phrase "end of file".)
You're ignoring the result returned by fgets(). Don't do that.
Note that just checking feof(fd) won't do what you want. feof() returns a true result if you've reached the end of the file. If you encounter an error instead, feof() still returns false, and you've got yourself an infinite loop if you're using feof() to decide when you're done. And it doesn't return true until after you've failed to read input.
Most C input functions return some special value to indicate that there's nothing more to read. For fgets() it's NULL, for fgetc() it's EOF, and so forth. If you like, you can call feof() and/or ferror() afterwards to determine why there's nothing more to read.
You might want to try something like this in your loop:
while(1)
{
memset((void*)usr_psw_line, 0, sizeof(USR_SIZE+PSW_SIZE+3+1));
if( !fgets(usr_psw_line, USR_SIZE+PSW_SIZE+3+1, fd)
|| ferror( fd ) || feof( fd ) )
{
break;
}
printf("%s\n", usr_psw_line);
fseek(fd, 1, SEEK_CUR);
/*EOF management*/
/*usr_id - password matching checking */
}
With the extra code, the loop will terminate if fgets returns NULL (no more data to read) or if you're read the EOF mark or had any error on the file. I'm sure it is overkill, but those tests have always worked for me.
I need to read from stdin and fill a buffer of _SC_PAGESIZE (from sysconf()) until stdin is at EOF. This program is supposed to be a wc clone, so I would be expecting something like the contents of a regular file to be passed in. If the buffer isn't big enough for stdin, then I have to keep filling it, process it for information, then clear it and continue to fill the buffer again from the file offset in stdin. I'm just having a problem with tracking the EOF of stdin, and I'm getting an infinite loop. Here's what I have:
int pSize = sysconf(_SC_PAGESIZE);
char *buf = calloc(pSize, sizeof(char));
assert(buf);
if (argc < 2) {
int fd;
while (!feof(stdin)) {
fd = read(0, buf, pSize);
if (fd == -1)
err_sys("Error reading from file\n");
lseek(0, pSize, SEEK_CUR);
if (fd == -1)
err_sys("Error reading from file\n");
processBuffer(buf);
buf = calloc(pSize, sizeof(char));
}
close(fd);
}
I'm assuming the problem has to do with the test condition (while (!feof(stdin)), so I guess what I need is a correct test condition to exit the loop.
Why are you using a low-level read instead of opening a FILE *stream and using fgets (or POSIX getline)? Further, you leak memory every time you call:
buf = calloc(pSize, sizeof(char));
in your loop because you overwrite the address contained in buf losing the reference to the previous block of memory making it impossible to free.
Instead, allocate your buffer once, then continually fill the buffer passing the filled buffer to processBuffer. You can even use a ternary operator to determine whether to open a file or just read from stdin, e.g.
int pSize = sysconf(_SC_PAGESIZE);
char *buf = calloc(pSize, sizeof(char));
assert(buf);
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) {
perror ("fopen failed");
return 1;
}
while (fgets (buf, pSize, fp))
processBuffer(buf); /* do not call calloc again -- memory leak */
if (fp != stdin) fclose (fp); /* close file if not stdin */
(note: since fgets will read a line-at-a-time, you can simply count the number of iterations to obtain your line count -- provided your lines are not longer than _SC_PAGESIZE)
If you want to use exact pSize chunks, then you can use fread instead of fgets. The only effect would be to reduce the number of calls to processBuffer marginally, but it is completely up to you. The only thing that you would need to do is change the while (...) line to:
while (fread (buf, (size_t)pSize, 1, fp) == 1)
processBuffer(buf); /* do not call calloc again -- memory leak */
if (ferror(fp)) /* you can test ferror to insure loop exited on EOF */
perror ("fread ended in error");
(note: like read, fread does not insure a nul-terminated string in buf, so insure that processBuffer does not pass buf to a function expecting a string, or iterate over buf expecting to find a nul-terminating character at the end.)
Look things over and let me know if you have further questions.
You can write the loop like
int n;
do {
n = read(0, buf, pSize);
// process it
} while(n > 0);
Remember EOF is just one exit condition that may not occur before any other error condition occurs. True check for validity to run the loop is a healthy return code from read. Also, note that condition while(n > 0) is enough or not depends on where you are reading from. In case of stdin it may be enough. But for example for sockets the condition can be written like while(n > 0 || errno == EAGAIN)
I'm trying to print out the contents of a file, however the program will pause at the read() function and won't continue until I hit the enter key. Once the enter key is pressed, nothing is printed to the terminal. The rest of the program is not shown, but here is the method that is causing the issue.
{
char buff[1024];
ssize_t bytesRead = 0;
int readFile, error;
if((readFile = open(file,O_RDONLY)<0))
{
printf("can't open %s\n",file);
error = errno;
return -1;
}
do{
memset(buff,0,1024);
if((bytesRead=read(readFile,buff,1024))==-1)
{
printf("error reading file");
error = errno;
printf("%d",error);
}
else
printf("%s",buff);
}while(bytesRead==1024);
printf("\n");
close(readFile);
return 1;
}
Alternatively, if I change the read() function to pread(file,buff,1024,0) it throws an illegal seek 29 error.
Hitting the enter key should not effect the read call unless you are reading from stdin (standard input). In that case, the input you provided - whitespace - may be printed out in the printf("%s", buff); call. If you could include some steps on how you found out that this is the method causing the issue or how you found out that it pauses at the read line (and if you are reading from /dev/stdin), it may be easier to help.
Consequently, the same printf call may never return, if the bytes read do not contain a null and the bytesRead count is 1024 - the string in buff would not be null terminated. You can fix this by either doing buff[1023] = '\0'; or by setting a length limit in the printf call like printf("%.1024s", buff);
do{
memset(buff,0,1024);
if((bytesRead=read(readFile,buff,1024))==-1)
{
printf("error reading file");
error = errno;
printf("%d",error);
}
else
printf("%s",buff);
}while(bytesRead==1024);
Your loop isn't correct. It assumes that read() fills the buffer; it fails if the file isn't a multiple of 1024 bytes; it corrupts errno before printing it; and it does unnecessary memset() operations. Honey it's a mess. It should look like this:
while ((bytesRead=read(readFile, buff, sizeof buff)) > 0)
{
printf("%.*s", bytesRead, buff);
}
if (bytesRead < 0)
{
error = errno;
perror("error reading file");
printf("errno=%d\n",error);
}