[BUG] file Truncate is it really busted?

Richard A. O'Keefe ok at atlas.otago.ac.nz
Thu Nov 29 00:36:25 UTC 2001


woods at weird.com (Greg A. Woods) replied to my explanation of the
'f' prefixes in C file handling functions.

	Well there's also the fact that the two uses of the 'f' prefix are
	really in fundamentally different levels of the API -- or depending on
	your point of view maybe even completely different APIs.

Fundamentally different?  Some of them are in the kernel, and some of them
are in the C stdio library, but from the point of view of your average UNIX
programmer this is a distinction without a difference.  open() and fopen()
are *both* in POSIX.  A UNIX look-alike could quite legitimately place
fopen() in the kernel and open() in a library, just like it is on my Mac
at home.  (Yep, Think C layered the UNIX functions on top of the stdio
functions, and they were layered on top of the MacOS ones.)

	The stdio library functions that have an 'f' prefix operate on
	FILE structures.  The system calls that have an 'f' prefix
	operate on kernel file descriptors.
	
Yes, I know.  That's pretty much what I said.  That's the PROBLEM.

	> It would make sense to have an fftruncate() function (truncate +
	> f prefix to get file descriptor + f prefix to get FILE*), but there is none.
	
	Actually, no, it doesn't -- but the reasons why depend on one having an
	intuitive understanding of the difference in API levels between the
	stdio library and raw system calls.
	
	The functions like fclose(), fread(), et al require a FILE* because they
	operate on the internal elements of a FILE structure.
	
Non sequitur.  The getchar(), getc(), putchar, putc(), printf(), and scanf()
functions, amongst others, operate on the internal elements of a FILE
structure, but don't have a FILE * argument.  And the clearerr() and fileno()
functions, amongst others, have a FILE * argument but don't have an "f"
prefix.  (fileno() begins with "f", but it's part of the word "file", not
a prefix.)

Some stdio functions with a FILE* prefix have an f prefix.  Some don't.
A uniform rule appears to have been applied to *both* the (2) and (3s)
functions:  if you want a file handling function, and there is already
one with the name you want, stick an 'f' in front.  Anyone looking for
a deeper level of meaning is looking for consistency that just isn't there.

By the way, I once wrote my own implementation of stdio, complete except
for *scanf(), which I had no particular use for.

	If you want to use a system call on a file opened by stdio you simply
	access the file descriptor from the (opaque) FILE structure using the
	fileno() function.
	
For many things it's not that simple, but everyone who has an intuitive
understanding of the difference in API levels &c &c already knows that.

	I.e. there is no need to confuse stdio and system call naming
	conventions with ugly constructions like "fftruncate()" because it is
	already more properly done with ftruncate(fileno(FILE*)).
	
I'm sorry, but this is precisely why it WOULD make sense to have fftruncate(),
because ftruncate(fileno(fp)) just plain doesn't work.  I *think* the
following code will work, but of course it isn't portable to systems that
don't have f{un,}lockfile():

    int fftruncate(FILE *fp) {
	int r, e;

        flockfile(fp);
        fflush(fp);
        r = ftruncate(fileno(fp));
	e = errno;
	funlockfile(fp);
	errno = e;
	return r;
    }

Even this doesn't work if the last transput operation on the stream was
an input operation; fflush() only makes the file position and the stream
position agree when the last operation was not an input.  In order to
handle the input case, we'd have to seek back in the file to where the
stream is (because of the buffered input), which is doable, *AND* we
would have to mark the buffer as empty, which we can't do in a portable
way.  I could do it easily enough on any of the 32-bit UNIX systems I have
access to, but it would not be portable, and it certainly wouldn't work
with LFS 64-bit filesystems, because the vendors have taken care to hide
the 64-bit filesystem FILE* record completely.

A little learning is a dangerous thing...





More information about the Squeak-dev mailing list