For Programmers: Free Programming Magazines  


Home > Archive > Unix Programming > December 2004 > Opening a file for update with creation if necessary









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Opening a file for update with creation if necessary
Tom Anderson

2004-12-11, 8:56 pm

Hi all,

I'm not much of a UNIX programmer, or any of a C programmer (python's my
language - although i'll try to speak in C here), so apologies if this is
a stupid question.

I want to open a file for updating - mode r+. However, i'd like it to be
created if it doesn't exist, as with mode w. Can i do this with fopen, or
am i going to have to use open (with flags O_RDWR | O_CREAT) and fdopen?

Thanks,
tom

--
So the moon is approximately 24 toasters from Scunthorpe.

Bjørn Augestad

2004-12-11, 8:56 pm

Tom Anderson wrote:

> Hi all,
>
> I'm not much of a UNIX programmer, or any of a C programmer (python's my
> language - although i'll try to speak in C here), so apologies if this is
> a stupid question.
>
> I want to open a file for updating - mode r+. However, i'd like it to be
> created if it doesn't exist, as with mode w. Can i do this with fopen, or
> am i going to have to use open (with flags O_RDWR | O_CREAT) and fdopen?
>
> Thanks,
> tom
>


Check out fopen() with mode a+, possibly with an additional call to
fs/rewind/fsetpos to move to the start of the file if needed.

Bjørn.
Tom Anderson

2004-12-11, 8:56 pm

On Sat, 11 Dec 2004, Bjørn Augestad wrote:

> Tom Anderson wrote:
>
>
> Check out fopen() with mode a+, possibly with an additional call to
> fs/rewind/fsetpos to move to the start of the file if needed.


Won't that force all writes to go to the end of the file? The standard (or
at least a standard) seems to think so:

http://www.opengroup.org/onlinepubs.../xsh/fopen.html

Although i'm pretty sure Linux, at least, doesn't do this.

tom

--
Science runs with us, making us Gods.

Michael B Allen

2004-12-12, 3:58 am

On Sat, 11 Dec 2004 16:19:14 -0500, Tom Anderson wrote:

> I want to open a file for updating - mode r+. However, i'd like it to be
> created if it doesn't exist, as with mode w. Can i do this with fopen,
> or am i going to have to use open (with flags O_RDWR | O_CREAT) and
> fdopen?


To be honest I'm not certain that this really applies to your question
but the following function will open a file, creating it if necessary,
and return a value indicating wheather the file was created as opposed to
opened. It seems to me that you might be able to adapt it to your purpose.

Mike

int
copen(const char *pathname, int flags, mode_t mode, int *cre)
{
int fd, max = 3; /* maximum attempts to open */

if ((flags & O_CREAT) == 0) {
if ((fd = open(pathname, flags, mode)) == -1) {
return -1;
}
*cre = 0;
return fd;
}
while (max--) {
if ((fd = open(pathname, flags & ~(O_CREAT | O_EXCL))) != -1) {
*cre = 0;
return fd;
} else if (errno != ENOENT) {
return -1;
}
if ((fd = open(pathname, flags | O_EXCL, mode)) != -1) {
*cre = 1;
return fd;
} else if (errno != EEXIST) {
return -1;
}
}

errno = EACCES;
return -1;
}
Bjørn Augestad

2004-12-12, 3:58 am

Tom Anderson wrote:

> On Sat, 11 Dec 2004, Bjørn Augestad wrote:
>
>
>
>
> Won't that force all writes to go to the end of the file? The standard (or
> at least a standard) seems to think so:
>
> http://www.opengroup.org/onlinepubs.../xsh/fopen.html
>
> Although i'm pretty sure Linux, at least, doesn't do this.
>


You're right, from the man page:
Opening a file with append mode (a as the first character in the mode
argument) causes all subsequent writes to the file to be forced to the
then current end-of-file, regardless of intervening calls to fs().

My apologies for the crappy advice I gave you. I guess a double call to
fopen() is the way to go then. Something like the code below.

Bjørn


#include <stdio.h>

int main(int ac, char** av)
{
FILE *f;

if( (f = fopen("blabla", "r+")) == NULL
&& (f = fopen("blabla", "w+")) == NULL) {
perror("fopen");
exit(1);
}

while(*++av)
fprintf(f, "%s\n", *av);

fclose(f);
return 0;
}


> tom
>

Tom Anderson

2004-12-13, 4:08 pm

On Sat, 11 Dec 2004, Michael B Allen wrote:

> On Sat, 11 Dec 2004 16:19:14 -0500, Tom Anderson wrote:
>
>
> To be honest I'm not certain that this really applies to your question


I don't think it does - i'm all about the locking, baby. Still, it's a
nice function!

tom

--
isn't it about time we had some new label for people interested in technology who also have an interest in drinking binges, womanising and occasional bouts of ultra violence? -- D

Tom Anderson

2004-12-13, 4:08 pm

On Sun, 12 Dec 2004, Bjørn Augestad wrote:

> Tom Anderson wrote:
>
>
> You're right, from the man page:
>
> Opening a file with append mode (a as the first character in the mode
> argument) causes all subsequent writes to the file to be forced to the
> then current end-of-file, regardless of intervening calls to fs().


Which OS was that on? The man page on OS X (ie FreeBSD) says something
similar; the one on Linux (Debian 2.4.28) says "Open for writing. The file
is created if it does not exist. The stream is positioned at the end of
the file." - nothing about forcing writes to EOF. Those crazy Linux
hippies!

> My apologies for the crappy advice I gave you. I guess a double call to
> fopen() is the way to go then. Something like the code below.
>
> #include <stdio.h>
>
> int main(int ac, char** av)
> {
> FILE *f;
>
> if( (f = fopen("blabla", "r+")) == NULL
> && (f = fopen("blabla", "w+")) == NULL) {
> perror("fopen");
> exit(1);
> }
>
> while(*++av)
> fprintf(f, "%s\n", *av);
>
> fclose(f);
> return 0;
> }


That's more or less what i came up with, except i explicitly test for the
existence of the file first, rather than catching the error from the first
fopen. I think your way is more efficient, though.

The trouble is, there's still a risk of race conditions; i can't lock the
file until i've got it open, and opening with w+ will clobber it, so it
would be possible to get:

A: open with r+, fail
A: open with w+, succeed
B: open with some writing mode
B: lock
B: write
B: close + unlock
A: lock
A: now has a file that's supposed to be empty but isn't!

Actually, this isn't so bad - process A didn't explicitly want the file to
be empty anyway. And if it does, it just has to manually (re-)clobber the
file after it locks it.

I think the Right Way to do this is with fcntl.open, with funky flags, and
then stdio.fdopen - you only ever have to make one open call, you don't
have to test the state of the file, and there's no inappropriate
clobbering. More of a pain to write, though!

tom

--
isn't it about time we had some new label for people interested in technology who also have an interest in drinking binges, womanising and occasional bouts of ultra violence? -- D

Måns Rullgård

2004-12-13, 4:08 pm

Tom Anderson <twic@urchin.earth.li> writes:

> On Sun, 12 Dec 2004, Bjørn Augestad wrote:
>
>
> Which OS was that on? The man page on OS X (ie FreeBSD) says something
> similar; the one on Linux (Debian 2.4.28) says "Open for writing. The file
> is created if it does not exist. The stream is positioned at the end of
> the file." - nothing about forcing writes to EOF. Those crazy Linux
> hippies!


The man page on my Linux system has this paragraph:

Opening a file in append mode (a as the first character of
mode) causes all subsequent write operations to this stream to
occur at end-of-file, as if preceded by an
fs(stream,0,SEEK_END);
call.

--
Måns Rullgård
mru@inprovide.com
Tom Anderson

2004-12-13, 9:01 pm

On Mon, 13 Dec 2004, Måns Rullgård wrote:

> Tom Anderson <twic@urchin.earth.li> writes:
>
>
> The man page on my Linux system has this paragraph:
>
> Opening a file in append mode (a as the first character of
> mode) causes all subsequent write operations to this stream to
> occur at end-of-file, as if preceded by an
> fs(stream,0,SEEK_END);
> call.


Hmm. The man page for fopen on mine has nothing at all like that; perhaps
we have different versions of glibc or something. The man page for open
says:

The file is opened in append mode. Before each
write, the file pointer is positioned at the end of
the file, as if with ls.

And when i actually get of my arse and try it, i see that fopening with
mode "a" does indeed get you the 'correct' force-to-end behaviour. ISTR
reading something about Linux not doing this; that might be an old version
or something. So it goes.

tom

--
This isn't right. This isn't even wrong.

Ara.T.Howard@noaa.gov

2004-12-14, 3:57 am

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2010 codecomments.com