Sigh, spam filter impounded this. (Gotta move off gmail...) On 4/12/22 04:42, Geoff Clare via austin-group-l at The Open Group wrote: > Rob Landley wrote, on 11 Apr 2022: >> >> A bunch of protocols (git, http, mbox, etc) start with lines of data >> followed by >> a block of data, so it's natural to want to call getline() and then handle >> the >> data block. But getline() takes a FILE * and things like zlib and sendfile() >> take an integer file descriptor. >> >> Posix lets me get the file descriptor out of a FILE * with fileno(), but the >> point of FILE * is to readahead and buffer. How do I get the buffered data >> out >> without reading more from the file descriptor? >> >> I can't find a portable way to do this? > > I tried this sequence of calls on a few systems, and it worked in the > way you would expect: > > fgets(buf, sizeof buf, fp); > int fd = dup(fileno(fp)); > close(fileno(fp)); > while ((ret = fread(buf, 1, sizeof buf, fp)) > 0) { ... } > read(fd, buf, sizeof buf); > > It relies on fread() not detecting EBADF until it tries to read more > data from the underlying fd.
Hmmm. That's an interesting approach. > It has some caveats: > > 1. It needs a file descriptor to be available. Understood, but acceptable. > 2. The close() will remove any fcntl() locks that the calling process > holds for the file. Fine. > 3. In a multi-threaded process it has the usual problem around fd > inheritance, but that's addressed in Issue 8 with the addition > of dup3(). Threads break everything anyway, but you could dup2(/dev/null) if you cared about them. > Also, for the standard to require it to work, I think we would need to > tweak the EBADF error for fgetc() (which fread() references) to say: > > The file descriptor underlying stream is not a valid file > descriptor open for reading and there is no buffered data > available to be returned. > > (adding the "and ..." part). Sounds reasonable. I'll give this a try. Thanks, Rob