Bug 75767 - [libc] [request] "fdclose" function in libc
Summary: [libc] [request] "fdclose" function in libc
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: 4.10-RELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-01-03 22:00 UTC by Ronald F. Guilmette
Modified: 2015-07-04 17:49 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ronald F. Guilmette 2005-01-03 22:00:51 UTC
In certain contexts, and when using certain programming styles, it is
important to be able to symmetrically "undo" the effects of various calls
to various standard library (libc) routines.

At present, due to the lack of an "fdclose" primitive in libc, it is not
easily possible to symmetrically undo the effects of a call to the "fdopen"
function.  One may call fclose on an open stdio file pointer, however the
fclose function actually has two effects, i.e.:

   1)  recycling the stdio file descriptor that was allocated by the prior
	call to fdopen() into the pool of available stdio file descriptors
	and...

   2)  calling close(2) on the underlying UNIX file descriptor.

Unfortunately, only the first of these two effects actually constitutes
a symmetric undo-ing of the actions performed by a call to fdopen.  The
second effect is an unfortunate (and undesirable) side-effect of fclose
in some instances.

Thus, it would be useful to have a new function in libc, i.e. an "fdclose"
function whose only effect would be to recycle a stdio file descriptor
into the pool of free/available stdio file descriptors *without* also
closing the underlying UNIX file descriptor.

Fix: 

Add a new "fdclose" function to libc.  This should have the same effects
as fclose, except that it should *not* close the underlying UNIX file
descriptor.
How-To-Repeat: 
	int fd;
	FILE *fp;

	fd = open ("foo", O_RDWR | O_CREAT, 0666);
	fp = fdopen (fd, "r+");
	...
	fclose (fp);
	write (fd, buf, size);  /* A problematic error occurs here! */
Comment 1 Giorgos Keramidas freebsd_committer freebsd_triage 2005-01-04 00:38:13 UTC
On 2005-01-03 13:50, "Ronald F.Guilmette" <rfg@monkeys.com> wrote:
> In certain contexts, and when using certain programming styles, it is
> important to be able to symmetrically "undo" the effects of various
> calls to various standard library (libc) routines.
>
> At present, due to the lack of an "fdclose" primitive in libc, it is
> not easily possible to symmetrically undo the effects of a call to the
> "fdopen" function.  One may call fclose on an open stdio file pointer,
> however the fclose function actually has two effects, i.e.:
>
> 1) recycling the stdio file descriptor that was allocated by the prior
>    call to fdopen() into the pool of available stdio file descriptors
>    and...
>
> 2) calling close(2) on the underlying UNIX file descriptor.
>
> Unfortunately, only the first of these two effects actually
> constitutes a symmetric undo-ing of the actions performed by a call to
> fdopen.  The second effect is an unfortunate (and undesirable)
> side-effect of fclose in some instances.
>
> Thus, it would be useful to have a new function in libc, i.e. an
> "fdclose" function whose only effect would be to recycle a stdio file
> descriptor into the pool of free/available stdio file descriptors
> *without* also closing the underlying UNIX file descriptor.

I believe there is no easy way to fdclose() a FILE object _and_ do it in
a way that would satisfy all the potential uses of such a function.
Some of the problems that an implementation would have to face are
immediate results of the buffered nature of FILE streams:

  a) Should any pending writes be flushed out before the FILE object is
     destroyed?

  b) What should the implementation do with any data that has been
     "read-ahead" and cannot be pushed back to an input stream?

I don't think there is a Right Thing(TM) for all the possible cases.
Especially if the FILE object is attached to a device node, which may or
may not support data read-ahead, pushing back of input data, rewinding
on every open(), etc.

> Add a new "fdclose" function to libc.  This should have the same
> effects as fclose, except that it should *not* close the underlying
> UNIX file descriptor.

You can probably emulate most of the behavior of fdclose() when such a
need arises with something like this:

% #include <errno.h>
% #include <stdio.h>
% #include <unistd.h>
%
% int
% fdclose(FILE *fp)
% {
%         int fd, nfd;
%         int status;
%
%         if (fp == NULL || (fd = fileno(fp)) < 0)
%                 goto out;
%         if ((nfd = dup(fd)) < 0 || (status = fclose(fp)) != 0 ||
%             dup2(nfd, fd) < 0 || close(nfd) < 0)
%                 goto syserr;
%         return (0);
%
% out:
%         errno = EINVAL;
% syserr:
%         return (-1);
% }
Comment 2 Ronald F. Guilmette 2005-01-04 04:59:48 UTC
In message <20050104003813.GF45341@gothmog.gr>, you wrote:

>I believe there is no easy way to fdclose() a FILE object _and_ do it in
>a way that would satisfy all the potential uses of such a function.

I didn't request something that would ``satisfy all of the potential uses
of such a function''.

My goals are not nearly so gradiose, and my need is a very simple one.

>Some of the problems that an implementation would have to face are
>immediate results of the buffered nature of FILE streams:
>
>  a) Should any pending writes be flushed out before the FILE object is
>     destroyed?

Please see my PR.  I asked for a function that would do everything that
fclose() does _except_ for calling close() on the underlying file.

>  b) What should the implementation do with any data that has been
>     "read-ahead" and cannot be pushed back to an input stream?

Please see my PR.  I asked for a function that would do everything that
fclose() does _except_ for calling close() on the underlying file.

>I don't think there is a Right Thing(TM) for all the possible cases.

Of course there isn't.  That's why I didn't ask for anything that would
do the ``Right Thing(TM) for all the possible cases''.

Nothing and nobody can satisfy everyone.  A hammer is no good for
unscrewing screws.  But it is an excelent tool for pounding nails.
I own one, and use it frequently for its intended purpose.  And I am
very glad to have it in my toolbox.

>Especially if the FILE object is attached to a device node, which may or
>may not support data read-ahead, pushing back of input data, rewinding
>on every open(), etc.

All of these issues also come up in the case of calling fclose().  And
the fclose() library function, whatever its specific semantics may be,
has been considered useful by many many programmers, over time, despite
the fact that it does not solve every problem for every programmer.  (It
_does_ solve _enough_ problems for _enough_ programmers to be rightfully
a part of libc.)

>> Add a new "fdclose" function to libc.  This should have the same
>> effects as fclose, except that it should *not* close the underlying
>> UNIX file descriptor.
>
>You can probably emulate most of the behavior of fdclose() when such a
>need arises with something like this:

Actually, since I sent in my PR, I did some more digging in the sources
of libc, and I found a much simpler way to get what I want, at least on
FreeBSD (however this is quite definitely _not_ portable):

    file->_close = NULL;
    fclose (file);

(I would still like to see the above functionality turned into a library
function however.)
Comment 3 Giorgos Keramidas freebsd_committer freebsd_triage 2005-01-05 11:18:26 UTC
On 2005-01-04 05:00, "Ronald F. Guilmette" <rfg@monkeys.com> wrote:
>In message <20050104003813.GF45341@gothmog.gr>, you wrote:
>> I believe there is no easy way to fdclose() a FILE object _and_ do it in
>> a way that would satisfy all the potential uses of such a function.
>
> I didn't request something that would ``satisfy all of the potential uses
> of such a function''.
>
> My goals are not nearly so gradiose, and my need is a very simple one.

>> Some of the problems that an implementation would have to face are
>> immediate results of the buffered nature of FILE streams:
>>
>>  a) Should any pending writes be flushed out before the FILE object is
>>     destroyed?
>
> Please see my PR.  I asked for a function that would do everything that
> fclose() does _except_ for calling close() on the underlying file.
> [...]
> Please see my PR.  I asked for a function that would do everything that
> fclose() does _except_ for calling close() on the underlying file.

I *did* see your PR.  I also gave it a bit of careful thought.
I'm sorry if my response sounded insulting in any way.  That was
definitely not my intention.

I'm just trying to see why the addition of an unportable function to
libc would be beneficial for other libc users too.  If there is no way
this may be useful to others too, it may as well be left as a patch a
few select users who depend on it apply on their source trees.

>>> Add a new "fdclose" function to libc.  This should have the same
>>> effects as fclose, except that it should *not* close the underlying
>>> UNIX file descriptor.

>> You can probably emulate most of the behavior of fdclose() when such a
>> need arises with something like this: [snip]
>
> Actually, since I sent in my PR, I did some more digging in the sources
> of libc, and I found a much simpler way to get what I want, at least on
> FreeBSD (however this is quite definitely _not_ portable):
>
>     file->_close = NULL;
>     fclose (file);
>
> (I would still like to see the above functionality turned into a library
> function however.)

Which would be non-standard, supported by FreeBSD only, hence unportable
to other systems.  I really don't see why adding an unportable function
to libc would make things better, but don't let my opinion stop you from
doing it if you feel it's useful.

- Giorgos
Comment 4 Mark Linimon freebsd_committer freebsd_triage 2008-03-04 02:24:47 UTC
State Changed
From-To: open->suspended

Mark suspended awaiting patches.
Comment 5 Mariusz Zaborski freebsd_committer freebsd_triage 2015-07-04 17:49:50 UTC
Fixed in r285140.