[comp.sys.hp] fopen/fseek interaction

arons@sesame.ucdavis.edu (Tom &) (12/21/89)

In porting a program from a BSD system to hp-ux version 3.10 on a 9k/800
I discovered a difference in stdio behavior.

	fd = fopen(path, "a")

is used on the BSD system to open, creating if necessary a file.
One, and only one, number is kept in the file by using:

	fseek(fd, 0L, 0);
	fprintf(fd, "%d\n", n);

to update the file.

On the hp-ux system the fseek's are effectively no-ops, that is
the file consists of as many numbers as there are writes.  Changing
the "a" to a "r+" in the fopen works fine if the file exists, but
won't create a new file.  "a+" seems to behave the same as "a".
In all cases the fseek returns a 0, indicating success.  A workaround
is easy enough to implement, but it is annoying to have to #ifdef the
code.

I am not sure whether the difference is a bug in either the BSD or
hp-ux system, or some BSD/System V semantic difference.  Does anyone
know?  The man page explanations for fopen on both systems are
virtually identical.

Tom Arons			Internet: arons@iris.ucdavis.edu
EE/CS Department		Bitnet:   arons@ucdavis
University of California	UUCP:     {lll-crg, ucbvax}!ucdavis!iris!arons
Davis, CA 95616			Phone:    (916) 752-1750

decot@hpisod2.HP.COM (Dave Decot) (12/21/89)

> In porting a program from a BSD system to hp-ux version 3.10 on a 9k/800
> I discovered a difference in stdio behavior.
> 
> 	fd = fopen(path, "a")
> 
> is used on the BSD system to open, creating if necessary a file.
> One, and only one, number is kept in the file by using:
> 
> 	fseek(fd, 0L, 0);
> 	fprintf(fd, "%d\n", n);
> 
> to update the file.

Since this code is opening the file for append (which means all writes
should be done at the end) and seeking to the beginning, and not using
the more intuitive "w+" flag to accomplish what appears at first glance
to be the same effect, I would assume that the code is written this way
as some kind of attempt to update the file atomically without conflicting
with some other application.  It is unclear that it would succeed at
that goal even on the BSD system.

> On the hp-ux system the fseek's are effectively no-ops, that is
> the file consists of as many numbers as there are writes.

Indeed it should.  The "a" asks for "append mode".  According to
open(2) on both systems, that means every write appends to the end
of the file, regardless of the current file offset.

> Changing
> the "a" to a "r+" in the fopen works fine if the file exists, but
> won't create a new file.  "a+" seems to behave the same as "a".
> In all cases the fseek returns a 0, indicating success.  A workaround
> is easy enough to implement, but it is annoying to have to #ifdef the
> code.

Perhaps just use "w+" mode, or if this is an attempt to keep a sequence
number from being updated simultaneously by different processes, rewrite the
code to do proper file locking.

> I am not sure whether the difference is a bug in either the BSD or
> hp-ux system, or some BSD/System V semantic difference.  Does anyone
> know?  The man page explanations for fopen on both systems are
> virtually identical.

The difference is the two interpretations of the word "append" for
fopen().  See O_APPEND on open(2) for the (consistent) definitions of how
appending to files is done.  HP-UX sets the O_APPEND flag to do fopen()'s
"a" append mode, BSD does not set O_APPEND, so writes do not always
occur at the end of the file.

Dave Decot
HP

DISCLAIMER: This article is not necessarily the opinion of Hewlett-Packard
Company.  It is provided without warranty of any kind, and the effects
of its use is solely the responsibility of the user.

kah@hpfcso.HP.COM (Kathy Harris) (12/22/89)

/ hpfcso:comp.sys.hp / arons@sesame.ucdavis.edu (Tom &) / 10:48 am  Dec 20, 1989 /
>In porting a program from a BSD system to hp-ux version 3.10 on a 9k/800
>I discovered a difference in stdio behavior.

>	fd = fopen(path, "a")

>is used on the BSD system to open, creating if necessary a file.
>One, and only one, number is kept in the file by using:

>	fseek(fd, 0L, 0);
>	fprintf(fd, "%d\n", n);

>to update the file.

>On the hp-ux system the fseek's are effectively no-ops, that is
>the file consists of as many numbers as there are writes.  Changing
>the "a" to a "r+" in the fopen works fine if the file exists, but
>won't create a new file.  "a+" seems to behave the same as "a".
>In all cases the fseek returns a 0, indicating success.  A workaround
>is easy enough to implement, but it is annoying to have to #ifdef the
>code.

The HP-UX behavior is correct AT&T Sys V.2 stdio behavior.  I don't know
if BSD defines different behavior or if this is a bug in BSD.

The relevant section in the HP-UX manual is from fopen(3S):

	When a file is opened for append (i.e., when *type* is "a"
	or "a+"), it is impossible to overwirte information already
	in the file.  Fseek may be used to reposition the pointer
	to any position in the file, but when output is written to the file, 
	the current file pointer is disregarded.  All output is
	written at the end of the file and causes the file pointer
	to be respositioned at the end of the output.

The ANSI C definition for "append" modes is similar.

You have several options to set up code that should be portable:

	(a) If you always want to start with a "clean" file, use "w+"
	    to do the fopen.
	(b) If you want to retain an existing file, but create a new
	    one if necessary, then use open(2) to open the file and
	    then fdopen(3S) to set up the stream.  Open(2) gives you
	    finer control over how a file is opened.  You would
	    want to use the flags O_RDWR and O_CREAT

Kathy Harris
H.P. Colorado Language Lab
	

rer@hpfcdc.HP.COM (Rob Robason) (12/28/89)

> In porting a program from a BSD system to hp-ux version 3.10 on a 9k/800
> I discovered a difference in stdio behavior.
>       fd = fopen(path, "a")
> is used on the BSD system to open, creating if necessary a file.

Here are the open(2) flags for each mode:

MODE            BSD                             HP-UX
-----------------------------------------------------------------------------
"a"             O_CREAT | O_WRONLY*             O_CREAT | O_APPEND | O_WRONLY*
"r"             O_RDONLY*                       O_RDONLY*
"w"             O_TRUNC | O_CREAT | O_WRONLY*   O_TRUNC | O_CREAT | O_WRONLY*
--------
* if the "+" is present in mode, uses O_RDWR

The HP-UX code derives from SysV.2.  I suspect the difference results
from the earlier heritage of BSD from version 7, although I can't easily
verify that.

> On the hp-ux system the fseek's are effectively no-ops, that is the file
> consists of as many numbers as there are writes.

This is consistent with the O_APPEND flag to open(2).

> Changing the "a" to a "r+" in the fopen works fine if the file exists,
> but won't create a new file.

At least this is consistent between the two systems.

> "a+" seems to behave the same as "a".  In all cases the fseek returns a
> 0, indicating success.

The fseek _does_ succeed, but the file pointer is repositioned at the time
of the write by the OS.

> A workaround is easy enough to implement, but it is annoying to have to
> #ifdef the code.

As Kathy mentions, the "w" mode will work and it is also the same on
both systems.  Just remember that it truncates the file, so if you're
planning on reading the old number before writing a new one, you'll have
a problem.  If this is the case, you might consider splitting the create
operation from the fopen so you can share code without ifdef.  Whichever
you use, this will be necessary in porting to other SysV (and as Kathy
also mentions, POSIX) conformant systems as well.

> I am not sure whether the difference is a bug in either the BSD or hp-ux
> system, or some BSD/System V semantic difference.  Does anyone know?

From the description:

   "a"  append: open for writing at end of file, or create for writing

it sure seems like it was intended that O_APPEND was to be used.

> Tom Arons			Internet: arons@iris.ucdavis.edu

Rob Robason