problem with O_CREAT ?

Andrew Tridgell (tridge@arvidsjaur.anu.edu.au)
Sun, 16 Jun 1996 23:38:16 +1000


There may be a problem with the handling of O_CREAT in linux.

I've always thought that O_CREAT should be ignored in a open() call if
the file exists. I don't have the posix specs handy, so please correct
me if this is wrong.

The program included below seems to show that it is not ignored in
Linux (using kernel 2.0). It should print "all OK", but instead prints
"2nd open failed : permission denied".

I had a look at linux/fs/open.c and the problem seems to be this but
of code in do_open() which assumes that O_CREAT implies opening for
writing:

if (flag & (O_TRUNC | O_CREAT))
flag |= 2;

changing it to:

if (flag & O_TRUNC)
flag |= 2;

would probably "fix" the problem, but might have some nasty side effects.

Would someone with the posix specs handy like to tell me if I've
misunderstood O_CREAT ?

When writing rsync I assumed O_CREAT was ignored when the file
exists. I was surprised to find it didn't work :-)

Cheers, Andrew

PS: I know it's unusual to open file with O_RDONLY|O_CREAT, but it is
very useful in some situations.

---------------

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

char *fname = "test.tmp";

void main()
{
int fd;

/* create a readonly file */
unlink(fname);
if ((fd=open(fname,O_RDWR|O_CREAT,0444)) == -1) {
printf("first open failed : %s\n",strerror(errno));
exit(1);
}
close(fd);

/* try and open it for reading. This should work. Under linux 2.0 it doesn't */
if ((fd=open(fname,O_RDONLY|O_CREAT,0666)) == -1) {
printf("2nd open failed : %s\n",strerror(errno));
exit(1);
}
close(fd);

/* it worked - clean up */
unlink(fname);

printf("all OK\n");
}