Ok, I have a homework assignment to write a file in C using the POSIX API that asks for a filename to read from, a filename to write to and then copies one to the other. I have done this and it works great! I am trying to put some error checking in and I want to check to see if the file to be written to already exists and if it does, then ask if the user wishes to overwrite. The problem is that it always states that the file exists, even if it does not. The rest of the program works just fine. I have read a lot on here and found a lot of useful stuff on POSIX, but can’t find this type of problem to reference. Below is my code:
#include <fcntl.h> // POSIX: give access to open
#include <unistd.h> // POSIX: gives access to read, write, close
#include <stdio.h> // POSIX: gives access to BUFSIZ
int main() {
int source = -1;
int target;
char sourcefile[50];
char targetfile[50];
char buff[BUFSIZ];
char ow[3];
size_t size;
printf("Please enter the name of the file you wish to read: ");
scanf( "%s", sourcefile );
printf( "\n" );
printf("Please enter the name of the file you wish to write to: ");
scanf( "%s", targetfile );
printf( "\n" );
source = open( sourcefile, O_RDONLY, 0);
//Test for existence of input file
if( source == -1 )
{
perror( "Cannot find file" );
return 1;
}
target = open( targetfile, O_WRONLY, 0644 );
//Test for existence of output file
if( target == 0 )
{
perror( "File already exists" );
printf( "Do you wish to overwrite? (yes or no): " );
scanf( "%s", ow );
if( strcmp( ow, "yes" ) == 0 )
{
target = open( targetfile, O_WRONLY | O_CREAT, 0644);
}else
{
printf( "Program Terminated!\n" );
return 1;
}
}else if( target == -1 )
{
target = open( targetfile, O_WRONLY | O_CREAT, 0644);
}
while ((size = read(source, buff, BUFSIZ)) > 0)
{
write(target, buff, size);
}
close(source);
close(target);
return 0;
}
You can use
open(2)withO_EXCLto create the purported new file. This will fail if the file already exists; in that case abort fatally. Otherwise you can write the desired file contents into it.If you want to be atomic, you can write the file contents into a temporary file (using
tmpfile) and then atomically replace the created file withrename(2). That way the new file is either empty or a complete copy.An alternative (suggested by @R.) is to not bother opening the target file, copying into a temporary file, and then using
link(2)instead ofrenameto attempt to put the new file in its destination location. This will fail if the destination already exists. This may have the (arguable) benefit that if someone else creates the target file in the meantime and doesn’t use the same care that we do, then you would be a bit more gentle in that case. (But if someone else wants stampedes around your filesystem without care, there’s only so much you can do.)