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! */
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); % }
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.)
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
State Changed From-To: open->suspended Mark suspended awaiting patches.
Fixed in r285140.