Hello again Philip, all.
Sorry for being so late, it has just been a few hours ago that i had
the time and space to go for that.
Steffen Nurpmeso wrote in <20191224014741.0pvgt%[email protected]>:
|Philip Guenther wrote in <[email protected]>:
||On Sat, 21 Dec 2019, Steffen Nurpmeso wrote:
||> Philip Guenther wrote in <[email protected]\
||> l>:
||>|On Sat, 21 Dec 2019, Steffen Nurpmeso wrote:
...
..[and reformatting]..
* POSIX Issue 7 overloaded fflush(3): if used on a readable stream,
*
* if the file is not already at EOF, and the file is one capable of
* seeking, the file offset of the underlying open file description
* shall be set to the file position of the stream */
#if !su_OS_OPENBSD &&\
defined _POSIX_VERSION && _POSIX_VERSION + 0 >= 200809L
# define n_real_seek(FP,OFF,WH) \
(fseek(FP, OFF, WH) != -1 && fflush(FP) != EOF)
# define really_rewind(stream) \
do{\
rewind(stream);\
fflush(stream);\
}while(0)
...
||>|Wheee: do _any_ BSDs implement that? A quick eyeball of Net, Free, and
||>|Dragonfly find they all do nothing and return either EBADF (Net, \
||>|Open) or
||>|0 (Free, Dragonfly), the latter with a citation to SUSv3.
||>
||> The test runs on FreeBSD 11.2,3-RC2/12 and also Dragonfly 5.6.1,
||> as well as SunOS 5.9..11, GNU and musl Linux. That is all i have
||> at the moment.
||
||Can you provide a more specific test case which passes on glibc and \
||either
||FreeBSD or Dragonfly but not on OpenBSD?
No, i cannot; yes i can, but that would involve looking for
_POSIX_VERSION, where FreeBSD etc. do not claim support for
200809L, and therefore the other macro is always chosen, which
explicitly lseek(2)s to get the descriptor right.
||
||The quick test program I whipped up below gives consistent results on
...
|I could maybe create a short reproducer, but not the next couple
|of days, and then i really want to shipout the release,
|_this_year_!, but maybe thereafter? This is all i know.
So i have written a little program which i duplicates the issue,
please find it attached.
I did not sit down and tried to write a patch, because the full
wording of POSIX is
If stream points to an output stream or an update stream in
which the most recent operation was not input, fflush( ) shall
cause any unwritten data for that stream to be written to the
file, and the last data modification and last file status change
timestamps of the underlying file shall be marked for update.
For a stream open for reading with an underlying file
description, if the file is not already at EOF, and the file is
one capable of seeking, the file offset of the underlying open
file description shall be set to the file position of the
stream, and any characters pushed back onto the stream by
ungetc( ) or ungetwc( ) that have not subsequently been read
from the stream shall be discarded (without further changing the
file offset).
and this would imply to me that the stream should keep track of
whether the last operation has been an input one, or not.
Other than that it still requires knowledge regarding the current
offset (may not be correct?), the ungetc buffer, etc. (Yes i have
looked around in BSD stdio for this again.)
Ciao!
--steffen
|
|Der Kragenbaer, The moon bear,
|der holt sich munter he cheerfully and one by one
|einen nach dem anderen runter wa.ks himself off
|(By Robert Gernhardt)
/* POSIX Issue 7 overloaded fflush(3): if used on a readable stream, then
*
* if the file is not already at EOF, and the file is one capable of
* seeking, the file offset of the underlying open file description shall
* be set to the file position of the stream */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define boole signed char
static void panic(int lno);
#define TEST(X) if((X) == 0) panic(__LINE__)
static boole check(FILE *fp, long size);
static boole try(long size);
static void
panic(int lno){
fprintf(stderr, "PANIC line %d\n", lno);
exit(1);
}
static boole
check(FILE *fp, long size){
long t;
off_t o;
t = ftell(fp);
o = lseek(fileno(fp), 0, SEEK_CUR);
printf("%ld\t%ld\t%ld%s\n", size, t, (long)o, (t == o ? "" : "\t*"));
return (t == o);
}
static boole
try(long size){
char buf[32];
boole error;
FILE *fp;
int fd;
long i;
for(i = 1;;){
snprintf(buf, sizeof buf, "ff-rew-desc-%ld.dat", i);
if((fd = open(buf, O_RDWR | O_CREAT | O_EXCL, 0666)) != -1){
TEST(unlink(buf) == 0);
break;
}
TEST(++i < 21);
}
TEST((fp = fdopen(fd, "w+")) != NULL);
for(i = 0; i < size; ++i)
TEST(fputc("abc123"[i % (sizeof("abc123") -1)], fp) != EOF);
TEST(fflush(fp) != EOF);
rewind(fp);
/* Could simply seek instead of reading it ? */
for(--size, i = 0; i < size; ++i)
TEST(getc(fp) != EOF);
TEST(!ferror(fp));
TEST(!feof(fp));
/* */
TEST(fflush(fp) == 0);
error = !check(fp, size);
rewind(fp);
TEST(fflush(fp) == 0);
error |= !check(fp, size);
fclose(fp);
return error;
}
int
main(void){
int errors;
errors = 0;
errors += try(171);
errors += try(5123);
errors += try(2 * 8192 + 5123);
return (errors != 0);
}