Weird behaviour with fscanf in C program - c

I would like to know in below code snippet why fscanf is throwing -1 in the middle of the execution and due to this I am not getting desired output.
#include<stdio.h>
#include<string.h>
#include<malloc.h>
int main(){
FILE *fp=NULL;
char fname[200], cmd[200];
int i=0,j=0;
system("ls /tmp/*.msg -1rt > /tmp/xyz.txt");
fp=fopen("/tmp/xyz.txt","r+");
if(fp!=NULL){
i=fscanf(fp,"%s",fname);
while(i!=EOF){
sleep(2);
printf("Filename is:'%s'\n",fname);
sprintf(cmd, "rm -rf %s; touch /tmp/a_%d_new.msg",fname,j++);
system(cmd);
memset(fname, 0, 200);
memset(cmd,0, 200);
system("ls /tmp/*.msg -rt1 > /tmp/xyz.txt");
i=fscanf(fp,"%s",fname);// fscanf will return error after some iterations
printf("The I Value is: '%d'\n",i);
}
}
if(fp!=NULL)
fclose(fp);
return 0;
}
Reproducing steps:
Create a /tmp/xyz.txt file (no data)
> xyz.txt ( make it empty if any data there)
rm -rf *.msg
touch a.msg b.msg c.msg d.msg e.msg f.msg
Here I am expecting gracefull exit from while loop . in current scenario it is not happening due to fscanf function.

It occurred to me that I did a better job at explaining this the second time, so here is my better explanation:
FILE is a stateful device that includes an EOF flag and a buffer. If when buffering, end of file is reached then it might be queued in the buffer, and the buffer won't be updated until it's exhausted. What is essentially happening is a copy of part of the file is made in memory, and when you make external changes to that file the copy in memory becomes out of sync.
The solution is to synchronise the buffer somehow. If you change the file position, then the standard library will have no choice but to update the cached version and reset the EOF flag. You have two options:
rewind makes sense if you intend to use < the way you have, because you're overwriting the file each loop, so you'll want to read from the start of the file.
fgetpos, followed by your fscanf, followed by fsetpos only makes sense if you intended to use << instead of <, because << concatenates to the end of the file, so when fscanf fails you'll be able to pick up where you left off after you update the file.
In my first answer, I also posed a question about the design you have chosen. The gist of that is, whichever of the above choices you make, fscanf should not normally produce an EOF value unless one of your system calls fails to create files. I think you have gathered this based on a conversation we had below. Unfortunately I can't make any suggestions unless you give a more broad overview on what problem your program is supposed to solve... All I can say is, while(i!=EOF) doesn't make a whole lot of sense.
Having said that, it's unusual (kind of wasteful, possibly erroneous and insecure) for C code to be calling system... Again, I need to know what problem your program is expected to solve to make a better suggestion.

Related

Writing in the executable while running the program

I'm writing a C program and I would like to be able to store data inside the executable file.
I tried making a function to write a single byte at the end of the file but it looks like it can't open the file because it reaches the printf and then gives "segmentation fault".
void writeByte(char c){
FILE *f;
f = fopen("game","wb");
if(f == 0)
printf("\nFile not found\n");
fseek(f,-1,SEEK_END);
fwrite(&c,1,sizeof(char),f);
fclose(f);
}
The file is in the correct directory and the name is correct. When I try to read the last byte instead of writing it works without problems.
Edit: I know I should abort the program instead of trying to write anyway but my main problem is that the program can't open the file despite being in the same directory.
There are several unrelated problems in your code and the problem you're trying to solve.
First you lack proper error handling. If any function that can fail (like e.g. fopen) fails, you should act accordingly. If, for example you did
#include <error.h>
#include <errno.h>
...
f = fopen("game","wb");
if ( f == NULL ) {
error(1,errno,"File could not be opened");
}
...
You would have recieved an useful error message like
./game: File could not be opened: Text file busy
You printed a message, which is not even correct (the file not beeing able to be opened is somthing different, than not beeing found) and continued the program which resulted in a segmentation fault because you dereferenced the NULL pointer stored in f after the failure of fopen.
Second As the message tells us (at least on my linux machine), the file is busy. That means, that my operating system does not allow me to open the executable I'm running in write mode. The answers to this question lists numerous source of the explanation of this error message. There might be ways to get around this and open a running executable in write mode, but I doubt this is easy and I doubt that this would solve your problem because:...
Third Executable files are stored in a special binary format (usually ELF on Linux). They are not designed to be manually modified. I don't know what happens if you just append data to it, but you could run into serious problems if your not very careful and know what you're doing.
If you just try to store data, use another plain and fresh file. If you're hoping to append code to an executable, you really should gather some background information about ELF files (e.g. from man elf) before continuing.

Proper methods to Copy files/folders programmatically in C using POSIX functions

These terms may not be 100% accurate, but I'm using the GCC compiler and POSIX library. I have C code compiled with the SQLite amalgamation file to a single executable.
In the user interface that exchanges JSON messages with the C program, I'd like to make it possible for users to copy the SQLite database files they create through the C program, and copy a full directory/folder.
Thus far, I've been able to rename and move files and folders programmatically.
I've read many questions and answers here, at Microsoft's C runtime library, and other places but I must be missing the fundamental points. I'm using regular old C, not C++ or C#.
My question is are there POSIX functions similar to rename(), _mkdir(), rmdir(), remove(), _stat(), that allow for programmatic copying of files and folders in Windows and Linux?
If not, can one just make a new folder and/or file and fread/fwrite the bytes from the original file to the new file?
I am primarily concerned with copying SQLite database files, although I wouldn't mind knowing the answer in general also.
Is this answer an adequate method?
Is the system() function a poor method? It seems to work quite well. However, it took awhile to figure out how to stop the messages, such as "copied 2 files" from being sent to stdout and shutting down the requesting application since it's not well-formed JSON. This answer explains how and has a link to Microsoft "Using command redirection operators". A /q in xcopy may or may not be necessary also, but certainly didn't do the job alone.
Thank you very much for any direction you may be able to provide.
The question that someone suggested as an answer and placed the little submission box on this question is one that I had already linked to in my question. I don't mean to be rude but, if it had answered my question, I would not have written this one. Thank you whoever you are for taking the time to respond, I appreciate it.
I don't see how that would be a better option than using system() because with the right parameters all the sub-directories and files of a single parent folder can be copied in one statement without having to iterate through all of them manually. Is there any reason why it would not be better to use system() apart from the fact that code will need to be different for each OS?
Handling errors are a bit different because system() doesn't return an errno but an exit code; however, the errors can be redirected from stderr to a file and pulled from there, when necessary
rename(): posix
_mkdir(): not posix. You want mkdir which is. mkdir takes two arguments, the second of which should usually be 077.
rmdir(): posix
remove(): posix
_stat(): not posix, you want stat() which is.
_stat and _mkdir are called as such on the Windows C library because they're not quite compatible with the modern Unix calls. _mkdir is missing an argument, and _stat looks like a very old version of the Unix call. You'll have trouble on Windows with files larger than 2GB.
You could do:
#ifdef _WIN32
int mkdir(const char *path, int mode) { return _mkdir(path); } /* In the original C we could have #defined this but that doesn't work anymore */
#define stat _stat64
#endif
but if you do so, test it like crazy.
In the end, you're going to be copying stuff with stdio; this loop works. (beware the linked answer; it has bugs that'll bite ya.)
int copyfile(const char *src, const char *dst)
{
const int bufsz = 65536;
char *buf = malloc(bufsz);
if (!buf) return -1; /* like mkdir, rmdir, return 0 for success, -1 for failure */
FILE *hin = fopen(src, "rb");
if (!hin) { free(buf); return -1; }
FILE *hout = fopen(dst, "wb");
if (!hout) { free(buf); fclose(hin); return -1; }
size_t buflen;
while ((buflen = fread(buf, 1, bufsz)) > 0) {
if (buflen != fwrite(buf, 1, buflen)) {
fclose(hout);
fclose(hin);
free(buf);
return -1; /* IO error writing data */
}
}
free(buf);
int r = ferror(hin) ? -1 : 0; /* check if fread had indicated IO error on input */
fclose(hin);
return r | (fclose(hout) ? -1 : 0); /* final case: check if IO error flushing buffer -- don't omit this it really can happen; calling `fflush()` won't help. */
}

C/C++ BEGINNER - fgets with stdin causing unexpected 'loop' results

I'm a programming student who's only really looked at Java up until now. This semester is our first time using C and I'm having a lot of trouble wrapping my head around some of the simplest functions. I really have no idea what I'm doing. I couldn't even get Eclipse to work correctly with MinGW so I eventually gave up and reverted to Netbeans.
So basically I'm trying to use fgets to read user input for a switch-case menu, but I can't get fgets to work in even the simplest situations. To troubleshoot I tried copying a simple fgets example from online, but even that is giving me unexpected results.
When I run the code below it just runs an infinite empty loop (it does not prompt for user entry at all, it does not accept any user entry, it just 'runs' forever and the console remains blank). When I delete the fgets line and remove the other reference to the 'name' variable it works as you would expect (prints the user entry prompt and then ends).
Example code:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
char name[10];
printf("Who are you? ");
fgets(name,10,stdin);
printf("Glad to meet you, %s.\n",name);
return(0);
return (EXIT_SUCCESS);
}
Any advice would be appreciated!
Other info:
I am running - Win 8 (poor me) & Netbeans IDE 8.0 (with MinGW)
When creating my C project I select File=> New Project=> C/C++=> C/C++ Application
EDIT: When I run the program I have tried:
1) right clicking the project file => Run; and
2) clicking the big green arrow in the netbeans ribbon;
.... neither works.
This code should work, but for you to be able to input anything, you need to run in in a proper terminal.
My guess is that you're running it inside your IDE and it's set to use pipes as stdin/stdout. Instead you should start cmd.exe and run the program in there (you'll have to navigate to the correct directory first).
Or, optionally, there might be a setting in your IDE to run the program using cmd.exe or with a builtin terminal.
A final note. You should learn to use sizeof whenever a buffer size is required. I.e. change this:
fgets(name,10,stdin);
to
fgets(name, sizeof(name), stdin);
Also, please use spaces to make your code more readable. Reading code is a big part of programming.
1) You might want to flush the file, after printf("Who are you? "); with fflush(stdout);
2) You have two return statements (which is harmless).
Other than that, your code is fine.
It works perfect - but you might want using fflush(stdin); before the fgets() call.
Also remember fgets return a string with '\n' after a user input - solved simply with name[strlen(name)-1]='\0'; - which is basically putting NULL as an "end of a string" symbol, basically you remove the '\n'.
And DO NOT change 10 to sizeof(name) - it doesn't matter at all, basically it's even supposedly worse as you can't use this in functions properly (sizeof(name) won't always match the length and would be the size of the pointer).
You should try compiling with MinGW if it didn't work, it will surely work on it.
A reminder: fgets() may let you enter MILLION characters, but it will take the first 10, in this case, at least.

Writing information from files into an archive file?

I'm a relatively decent Java programmer, but completely new to C. Thus some of these functions, pointers, etc are giving me some trouble...
I'm trying to create an archive file (I'm basically re-writing the ar sys call). I can fstat the files I want, store the necessary information into a struct I've defined. But now comes my trouble. I want to write the struct to the archive file. So I was thinking I could use sprintf() to put my struct into a buffer and then just write the buffer.
sprintf(stat_buffer, "%s", file_struct);
write(fd, stat_buffer, 60);
This doesn't appear to work. I can tell the size of the archive file is increasing by the desired 60 bytes, but if I cat the file, it prints nonsense.
Also, trying to write the actual contents of the file isn't working either...
while (iosize = read(fd2, text_buffer, 512) > 0) {
write(fd, text_buffer, iosize);
if (iosize == -1) {
perror("read");
exit(1);
}
}
I'm sure this is a relatively easy fix, just curious as to what it is!
Thanks!
%s is used to print string. So sprint will stop when it will meet a \0 character.
Instead, you could directly write your structure to your file. write(fd, &file_struct, sizeof(filestruct)); but you wont be able to read it with a cat call. You still can, from another unarchiver program, read the file content and store it to a structure read(fd, &filestruct, sizeof(filestruct));
This system is not perfect anyways, because it will store the structure using your computer endianess and wont be portable. If you want to do it right, check out the ar file format specification.

Overwriting files in Windows by renaming randomly fails

I have a text file that I want to edit by rewriting it to a temp file and then overwrite the original. This code doesn't do that as it's simplified but it does include the problem I have. On Windows the EXAMPLE.TXT file will disappear after a seemly random number of runs when the rename function fails. I don't know why but so far it has worked fine on Linux. Why does this happen and how can I solve it going in an entirety different direction, such as overwriting the original file from within the program without renaming?
Furthermore, what other, better methods exist? This method has other flaws on Windows, such as the program being closed by a user just after remove is called but before rename, which would not be a problem on Linux (after getting rid of remove)?
#include <stdio.h>
#include <assert.h>
int main(int argc, char *argv[]) {
unsigned int i=0;
FILE *fileStream, *tempStream;
char fileName[] = "EXAMPLE.TXT";
char *tempName = tmpnam(NULL);
while(1) {
printf("%u\n",i++);
assert(fileStream = fopen(fileName, "r+"));
assert(tempStream = fopen(tempName, "w"));
fprintf(tempStream,"LINE\n");
fflush(tempStream); /* fclose alone is enough on linux, but windows will sometimes not fully flush when closing! */
assert(fclose(tempStream) == 0);
assert(fclose(fileStream) == 0);
assert(remove(fileName) == 0); /* windows fails if the file already exists, linux overwrites */
assert(rename(tempName,fileName) == 0);
}
}
Doing it this way is indeed likely to cause trouble. There are four possible outcomes of your code on Windows:
deletes fine, rename works, no problem
deletes fine, but another process had the file open with delete sharing. Common for malware scanners and file content indexers. Which ensures that the file actually gets deleted when the last handle on the file is closed. Problem is, the rename fails because the file still exists
doesn't delete because the file is locked, your assert fires
nothing at all happens because assert() is a no-op when you build the release version.
Good odds for the last bullet btw, it certainly explains repeatable failure. You'll need a more defensive strategy to deal with the 2nd bullet:
delete filename.bak, report error if that failed
rename fileName to filename.bak, report error if that failed
rename tempName to filename, report error and rename filename.back back if that failed
delete filename.bak, don't report error
This is such a common scenario that the winapi has a function for it, ReplaceFile(). Be sure to use the backup file option for maximum bang for the buck.
-
Sometimes antivirus software can cause such a problem by scanning a file at an inconvenient moment.
If the remove fails, try sleeping for a short time and then retrying.

Resources