I am trying to redirect output from an exec()ed function into a buffer, so I though I would try and use open_memstream to handle the dynamic buffering
I put together this to test it out:
#include <stdio.h>
#include <unistd.h>
int main() {
char* buffer;
size_t buffer_len;
FILE* stream = open_memstream(&buffer, &buffer_len);
if(!stream) perror("Something went wrong with `open_memstream`!");
fflush(stream);
puts("Start");
if(dup2(fileno(stream), STDOUT_FILENO) == -1) perror("Something went wrong!");
puts("Internal");
fclose(stream);
FILE* f = fopen("out.txt", "w+");
fputs(buffer, f);
fclose(f);
}
But running it gives me the error bad file descriptor on dup2, which shouldn't be the case since open_memstream doesn't return NULL which it is supposed to do on error.
Is there something about the implementation of open_memstream that makes it nonviable to manipulate its underlying descriptor? Or am I just being dumb and using a function wrong?
Cheers in advance for any help given, and if this is impossible to do with open_memstream, is there a way to handle it with FILE* instead of using fds directly?
You should check return value (and subsequently errno) after every operation that can go wrong. Here, you are missing a check for fileno(stream) return value.
FILE* stream = open_memstream(&buffer, &buffer_len);
if(!stream) perror("Failed to open_memstream");
int fd = fileno(stream);
if (fd == -1) {
perror("Failed to get memstream fileno");
exit(1);
}
When you add the above, your program will fail with message
Failed to get memstream fileno: Bad file descriptor
The reason for this failure is already explained in comments on the question.
Have look at open with the O_TMPFILE parameter, or at memfd_create, which is similar to open_memstream but returns a file descriptor.
These approaches force you to forgo the convenience of having &buffer, &buffer_len. But nothing is actually lost. One can use lseek to learn the tmp file size and then mmap to access it as a memory buffer, getting all the conveniences back.
Related
Title says it all: can one use stat() after fopen() to avoid Time of Check to Time of Use (TOCTOU) race conditions?
Some details:
I am writing a C program that only reads files, but needs to error properly when asked to read a directory. As of right now, it uses open() (with O_RDWR) to generate an error and then checks errno for EISDIR, like so:
int fd = open(path, O_RDWR);
if (fd == -1) {
if (errno == EISDIR) return PATH_IS_DIR;
else return FILE_ERR;
}
The problem with the above solution is that this program only needs to read files, so by opening a file with O_RDWR, I might wrongly get a permissions error if the user has read permissions, but not write permissions.
Is it possible to do the following to avoid TOCTOU race conditions?
struct stat pstat;
FILE *f = fopen(path, "r");
if (!f) return FILE_ERR;
if (stat(path, &pstat) == -1) {
fclose(f);
return FILE_ERR;
}
if (S_ISDIR(pstat.st_mode)) {
fclose(f);
return PATH_IS_DIR;
}
If it is not possible, is there another solution to prevent TOCTOU bugs and also wrong permission errors?
No, the code presented in the question does not avoid a TOCTOU race.
Testing after use is prone to exactly the same errors as testing before use. In both cases, the name is resolved at two different times, with possibly different results. This is the cause of the race, and it can happen whichever access happens first.
The only way to avoid this is to open the file once, and use the file descriptor so obtained for any other checks you need. Modern OSes provide interfaces such as fstat() for exactly this purpose.
If you want to use C's buffered I/O, you can get the file descriptor from a FILE* using fileno() - or you can create a FILE* from a file descriptor using fdopen().
It requires a very small change to your code:
# Untested
struct stat pstat;
FILE *f = fopen(path, "r");
if (!f) return FILE_ERR;
if (fstat(fileno(f), &pstat) == -1) {
// ^^^^^^^^^^^^^^^ <-- CHANGED HERE
fclose(f);
return FILE_ERR;
}
if (S_ISDIR(pstat.st_mode)) {
fclose(f);
return PATH_IS_DIR;
}
EDIT (2018-10-25): Toby Speight's answer is better.
There is a solution: use open(), then
fstat().
An example:
struct stat pstat;
int fd = open(path, O_RDONLY);
if (fd == -1) return FILE_ERR;
if (fstat(fd, &pstat) == -1) {
close(fd);
return FILE_ERR;
}
if (S_ISDIR(pstat.st_mode)) {
close(fd);
return PATH_IS_DIR;
}
I found this while checking that I had covered all of my bases before asking this question.
The following is my code for a method that copies a file from a path to a file to a directory provided as the destination. The copy works perfectly fine, however my chmod call assigns the wrong permissions to the copied file in the destination. If the permission in the source is 644, the copied file has a permission of 170 or 120.
I have been attempting to debug this for hours and it's driving me slightly crazy so any help is greatly appreciated.
void copy_file(char* src, char* dest) {
char a;
//extract file name through a duplicate ptr
char* fname = strdup(src);
char* dname = basename(fname);
//open read and write streams
FILE* read;
FILE* write;
read = fopen(src, "r");
chdir(dest);
write = fopen(dname, "w");
//error checking
if (read == NULL) //|| (write == NULL))
{
perror("Read Error: ");
exit(0);
}
else if (write == NULL)
{
perror("Write Error: ");
exit(0);
}
//write from src to dest char by char
while (1){
a = fgetc(read);
if (a == EOF)
{
break;
}
fputc(a, write);
}
//close files
fclose(read);
fclose(write);
// this is where I attempt to assign source file permissions
//and it goes horribly wrong
struct stat src_st;
if(stat(src, &src_st)){
perror("stat: ");
}
chmod(dname, src_st.st_mode);
printf("%o\n", src_st.st_mode & 0777);
}
You fopen(src, "r"), then you chdir(dest). This means that when you later call stat(src, &src_st), there is no reason to think that stat will access the same file as fopen did, or indeed that stat will access any file at all.
If stat fails, you proceed to call chmod anyway, so you pass whatever random junk was in src_st.st_mode to chmod.
You should use fstat(fileno(read), &src_st) before calling fclose(src), instead of calling stat(src, &src_st).
The basic problem is you have to check your system calls like fopen, chdir, and stat immediately.
For example, first thing I tried was copy_file( "test.data", "test2.data" ) not realizing it expected a destination directory.
char* fname = strdup(src);
char* dname = basename(fname);
dname is now test.data, same as the source.
read = fopen(src, "r"); // succeeds
chdir(dest); // fails
write = fopen(dname, "w"); // blows away test.data, the source
You do eventually check read and write, but after the damage has been done.
Blowing away your source file is really bad. It's important that your code deals with failed system calls. If you don't, it will sail along causing confusion and destruction.
Most system calls in C return 0 for success. This is an anti-pattern where the return value is an error flag, so false is failure, and anything else indicates what kind of error (though stat doesn't use that, it uses errno).
When it fails, stat returns -1 which is true. So this is the wrong way around.
struct stat src_st;
if(stat(src, &src_st)){
perror("stat: ");
}
Instead, you have to check for non-zero.
struct stat src_st;
if(stat(src, &src_st) != 0 ){
// Note that I don't use perror, it doesn't provide enough information.
fprintf(stderr, "Could not stat %s: %s\n", src, strerror(errno));
exit(1);
}
As you can guess this gets tedious in the extreme, and you're going to forget, or do it slightly different each time. You'll want to write wrappers around those functions to do the error handling for you.
FILE *fopen_checked( const char *file, const char *mode ) {
FILE *fp = fopen(file, mode);
if( file == NULL ) {
fprintf(stderr, "Could not open '%s' for '%s': %s", file, mode, strerror(errno));
exit(1);
}
return fp;
}
It's not the best error handling, but it will at least ensure your code appropriately halts and catches fire.
A note about chdir: if you can avoid it don't use it. chdir affects the global state of the program, the current working directory, and globals add complexity to everything. It's very, very easy for a function to change directory and not change back, as yours does. Now your process is in a weird state.
For example, if one did copy_file( "somefile", "foo" ) this leaves the program in foo/. If they then did copy_file( "otherfile", "foo" ) they'd be trying to copy foo/otherfile to foo/foo/otherfile.
And, as #robmayoff pointed out, your stat fails because the process is now in a different directory. So even the function doing the chdir is confused by it.
Ensuring that your functions always chdir back to the original directory in a language like C is very difficult and greatly complicates error handling. Instead, stay in your original directory and use functions like basename to join paths together.
Finally, avoid mixing your file operations. Use filenames or use file descriptors, but try not to use both. That means if you're using fopen, use fstat and fchmod. You might have to use fileno to get a file descriptor out of the FILE pointer.
This avoids having to carry around and keep in sync two pieces of data, the file descriptor and the filename. It also avoids issues with chdir or the file being renamed or even deleted, the file descriptor will still work so long as it remains open.
This is also a problem:
char a;
...
while (1){
a = fgetc(read);
if (a == EOF)
{
break;
}
fputc(a, write);
}
fgetc() returns int, not char. Per the C Standard, 7.21.7.1 The fgetc function:
7.21.7.1 The fgetc function
Synopsis
#include <stdio.h>
int fgetc(FILE *stream);
Assuming sizeof( int ) > sizeof( char ), char values are signed, 2s-complement integers, and EOF is an int defined to be -1 (all very common values), reading a file with char a = fgetc( stream ); will fail upon reading a valid 0xFF character value. And if your implementation's default char value is unsigned char, char a = fgetc( stream ); will never produce a value that matches EOF.
I have this function
char* Readfiletobuffer(char* file, FILE* fp){
char * buffer;
int file_size;
fp = fopen(file, "r");
if (fp != NULL) {
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
buffer = (char*) malloc((file_size + 1) * sizeof(char));
fseek(fp, 0, SEEK_SET);
fread(buffer, file_size, 1, fp);
buffer[file_size] = '\0';
return buffer;
} else {
printf("error loading file");
}
fclose(fp);
}
which I call 1050 times in my program and at the 1019th time fopen() returns a NULL pointer.
It doesn't depend on the file, it's always the 1019th time so I think it's something with freeing memory but why isn't the fclose() call enough?
Does someone have an idea?
Your program can tell you with errno, the global variable where many functions assign their error code to when they fail. Combined with strerror to provide a human readable error message, you'd change your error handling to something like this.
#include <errno.h>
#include <string.h>
...
fp = fopen(file, "r");
if (fp == NULL) {
fprintf(stderr, "Could not open '%s': %s", file, strerror(errno));
exit(1);
}
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
...
Note the use of early exit to eliminate having nest the whole function in an if/else block.
Also note that you're failing to check the rest of your file operations. fseek, ftell, and fread can all fail. You need similar checks for all of them. Rather than littering your code with error handling, and probably forgetting to do it in a few places, I recommend writing little wrappers.
FILE *open_file(const char *filename, const char *mode) {
FILE *fp = fopen(filename, mode);
if( fp == NULL ) {
fprintf(
stderr, "Could not open '%s' for '%s': %s\n",
filename, mode, strerror(errno)
);
exit(1);
}
return fp;
}
Note that this isn't the best error handling, it simply exits on error. At this stage in your learning C, it's probably best to just bail out on an error. If you did something like return NULL odds are you won't have the error handling to handle a null pointer and it will just bounce around causing mysterious problems and crashes later in the code. For now it's best to halt and catch fire as close to the error as possible.
Spoiler alert: your process ran out of file handles because you're not closing your files. As #BLUEPIXY correctly points out in the comments your fclose is after you return normally and will only happen if the file fails to open.
Since you're passing in the file pointer, maybe you intend to use it later? In that case you can't hold onto that many open files and you'll have to redesign your code. If not, there's no reason to pass it in since the function is opening it.
You should have gotten a warning like this, if you had warnings turned on with -Wall.
test.c:23:1: warning: control may reach end of non-void function [-Wreturn-type]
}
If the file fails to open, nothing gets returned, and that's not ok.
Don't ignore your warnings, fix all of them. Investigating this warning would have pointed you at the problem.
Check all your file operations to make sure they succeeded.
Include strerror(errno) in your error messages so you know why it failed.
Investigate and fix all your warnings.
Please see below code.
#include < stdio.h >
#include < fcntl.h >
#include < stdlib.h >
#include < string.h >
int main(int argc,char **argv,char **envp)
{
int fd;
size_t sz;
char filebuffer[1024];
int loop;
fd=open("sample",O_RDONLY);
if(fd==-1)
{
perror("");
exit(1);
}
loop=0;
while(++loop<300)
{
lseek(fd,0,SEEK_SET);
memset(filebuffer,0,1024);
sz=read(fd,filebuffer,1024);
printf("%d.sz=%zd\t%s\n",loop,sz,filebuffer);
sleep(1);
}
close(fd);
return 0;
}
In this code, I am able to read file. But when I am changing file (reading file "sample") at the same time during reading. Then I am not able to read the changed file. I tried O_SYNC flag too. but still, it is not working, but O_DIRECT is undefined error is coming up. How can I ensure that I am able to read changes? Second thing, but I observed, if I close and open the file reading, then I am able to read changed file.
Question:
How can I read changed file without closing and opening?
I think that you're asking the following question:
I have a program which opens a file called sample and repeatedly reads the first block of that file. That works fine. However, if I edit the file sample, for example with a text editor, then my program does not see the changes, although it will if it closes and reopens the file. How can I see the changes without closing and reopening the file?
If that's your question, then the answer is:
Sorry, you cannot, because the text editor does not modify the file. It creates a new file with the old name.
In Unix, once you open a file, it will not actually get deleted, even if its name is unlinked. If another program "deletes" the file and then creates a new file with the same name, the file you have open is no longer accessible to any other program, but it is still the same file and it will not get deleted until you close it.
Most Unix text utilities, even the ones which claim to work "in-place" (such as sed -i) really do not modify files. That includes text editors. So your program doesn't see changes in the file because the file is not changing; the name has been given to a new file.
So the only way to deal with this is to close and reopen the file. When you reopen, you will be opening the new file with the old name.
The reason for not getting updated data in file could be sync time in filesystem.
I suggest fflush() after writing in to file. This makes your cache data to be written in file.
Related discussions.
Small file not committed to disk for over a minute
Is fwrite non-blocking?
This is an adaptation of your code. It forks to create two processes. The child contains your code, substantially unchanged (different error message, file name variable, and more care with printing the filebuffer which is not null terminated). The parent writes characters (the same character, over and over) to the file.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static char const filename[] = "sample";
int main(void)
{
int fd;
size_t sz;
char filebuffer[1024];
int loop;
switch (fork())
{
case -1:
fprintf(stderr, "Failed to fork\n");
break;
case 0:
sleep(1);
fd = open(filename, O_RDONLY);
if (fd == -1)
{
fprintf(stderr, "Failed to open file %s for reading\n", filename);
exit(1);
}
loop = 0;
while (++loop < 300)
{
lseek(fd, 0, SEEK_SET);
memset(filebuffer, 0, 1024);
sz = read(fd, filebuffer, 1024);
printf("%d.sz=%zd\t%.*s\n", loop, sz, (int)sz, filebuffer);
sleep(1);
}
close(fd);
break;
default:
fd = open(filename, O_WRONLY|O_CREAT, 0644);
if (fd == -1)
{
fprintf(stderr, "Failed to create file %s for writing\n", filename);
exit(1);
}
for (loop = 0; loop < 256; loop++)
{
memset(filebuffer, (loop % 64) + 33, sizeof(filebuffer));
lseek(fd, 0L, SEEK_SET);
write(fd, filebuffer, sizeof(filebuffer));
sleep(1);
}
close(fd);
break;
}
return 0;
}
Example output:
1.sz=1024 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
2.sz=1024 ################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################
3.sz=1024 ################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################################
4.sz=1024 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5.sz=1024 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
6.sz=1024 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
7.sz=1024 ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
8.sz=1024 ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
9.sz=1024 ****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
As you can see, the processes run asynchronously, so the data in the file does not always change between reads, but the process is seeing the changes.
Try running this on your computer. It should work. (Sample output from Mac OS X 10.8.5.) If it doesn't, you'll need to identify which file system type you have, but I don't think it'll be a problem.
I would like to know how the contents of a file can be cleared in C. I know it can be done using truncate, but I can't find any source clearly describing how.
The other answers explain how to use truncate correctly... but if you found yourself on a non-POSIX system that doesn't have unistd.h, then the easiest thing to do is just open the file for writing and immediately close it:
#include <stdio.h>
int main()
{
FILE *file = fopen("asdf.txt", "w");
if (!file)
{
perror("Could not open file");
}
fclose(file);
return 0;
}
Opening a file with "w" (for write mode) "empties" the file so you can start overwriting it; immediately closing it then results in a 0-length file.
The truncate() call in UNIX is simply:
truncate("/some/path/file", 0);
While you can just open and close the file, the truncate call is designed specifically for this use case:
#include <unistd.h> //for truncate
#include <stdio.h> //for perror
int main()
{
if (truncate("/home/fmark/file.txt", 0) == -1){
perror("Could not truncate")
}
return 0;
}
If you already have the file open, you can use that handle with ftruncate:
#include <stdio.h> //for fopen, perror
#include <unistd.h> //for ftruncate
int main()
{
FILE *file = fopen("asdf.txt", "r+");
if (file == NULL) {
perror("could not open file");
}
//do something with the contents of file
if (ftruncate(file, 0) == -1){
perror("Could not truncate")
}
fclose(file);
return 0;
}
truncate(2) is not a portable call. It only conforms to 4.2BSD. While it is found on most *nix type systems, I would say use a POSIX.1 compliant routines which are pretty much guaranteed on most modern environments (including Windows).
so here is a POSIX.1-2000 compliant code snippet:
int truncate_file(const char *name) {
int fd;
fd = open (name, O_TRUNC|O_WRONLY);
if ( fd >= 0 )
close(fd); /* open can return 0 as a valid descriptor */
return fd;
}
For deleting the contents of a fie obviously there is basic method of opening a file in write mode "w" and then close it without doing any changes in it.
FILE *fp = fopen (file_path, "w");
fclose(fp);
this will delete all the data in file as when you open a already existing file using "w" mode the file is deleted and a new file with the same name is opened for writing, this will result into deletion of contents of your file.
BUT there is truncate syscall in UNIX systems, which is specially for the same purpose and pretty easy to use:
truncate (filepath, 0);
if you have already opened your file so either you close your file before doing truncate or use ftruncate
ftruncate (file_path, 0);