Re: fread breaks file descriptors opened in "w" mode.



On Nov 18, 2:15 pm, Lénaïc Huard <lenaic.hu...@xxxxxxxxxxx> wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello all,

For some reasons, somewhere in a program, I'd like, if possible, to quickly
parse a whole file before rewinding it and letting the full analysis start.
My problem is that the FILE* I want do parse has been fopen'ed far away
from where I am and I don't know in which MODE my FILE* has been opened.
And additionally, my FILE* may not be a regular file, but a continuous
stream (pipe), in which case it is not rewindable.

So my program basically behaves like this:

void PreParsing( FILE *my_file )
{
  /*
   * Test if my FILE * is seekable
   */
  if( fseek( my_file, 0, SEEK_SET ) == 0 ) {

    /*
     * If so, go on for the pre-parsing.
     */
    //...
    fread( buf, BUF_SIZE, 1, my_file );
    //...

    /*
     * Rewind the file.
     */
    if( fseek( my_file, 0, SEEK_SET ) != 0 ) {
      // unexpected error since my FILE * was expected to be seekable.
    }
  }

}

* On both Linux 2.6.xx and Solaris 5.10,

when the my_file is a regular file that has been fopen'ed with "w" as mode,
 - the first fseek returns 0 meaning success: my_file is seekable
 - the fread returns 0 meaning that there was nothing to read: expected
since a file opened in "w" is truncated, hence is empty, and anyhow, cannot
be read!
 - the second fseek returns 0 meaning success: my_file could be rewound..

when the my_file is a pipe that has been fopen'ed with "w" as mode,
 - the first fseek returns -1 and errno is set to 29 (Illegal seek).
That's exactly what I expected since a pipe cannot be sought.

Ok. So, on Linux 2.6.xx and Solaris 5.10, my code behaves like I expected
for both regular files and pipes.

* On AIX 5.2,

when the my_file is a pipe that has been fopen'ed with "w" as mode,
 - the first fseek returns -1 and errno is set to 29 (Illegal seek).
I'm still OK with that.

but...
when the my_file is a regular file that has been fopen'ed with "w" as mode,
 - the first fseek returns 0 meaning success: my_file is seekable
 - the fread returns 0 meaning that there was nothing to read: expected
since a file opened in "w" is truncated, hence is empty, and anyhow, cannot
be read!
 - the second fseek returns -1 and sets errno to 9 (Bad file number)
I'm a little bit surprised by this error.

In fact, after having had a deeper look on that, it appears to me that a
fread attempt on a FILE * opened in "w" mode breaks it since any subsequent
operation (fseek, fwrite and even fclose !) fails with the error 9 (Bad
file number).
So, on AIX , my function fails to restore the FILE * state at its end.

So, I have a few questions:

 - a fread on a FILE * opened in "w" will for sure return 0 item, but is it
really expected that it makes the given FILE * totally unusable even for
fclose !?! This behavior has been observed only on AIX. Linux and Solaris
works.
 - given a FILE *, is there a better way to guess in which mode it has been
opened than attempting to read or write it and look at errors ?
 - given a FILE *, is there a better way to guess if it can be sought than
attempting a fseek on it ?

PS: I Xposted my problem on both comp.lang.c and comp.unix.aix because I
have no idea whether this is an AIX specific problem or if the C norm
specifies explicitly that fread have unpredictable effects on a write-only
file descriptor. Anyhow, my goal is to find a portable solution that uses
as less platform specific stuff as possible.

Thanks for your advices.
Lénaïc ...still puzzled by AIX behavior...
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)

iEYEARECAAYFAkkjPpUACgkQjYEjJATS6Bi55ACgj+RbzOhyjDj63G+ciKo0Iy1B
FuoAn3WsnRc69XXDi2KV0Wt4aOFo0Bpf
=In7u
-----END PGP SIGNATURE-----

Partial solution - you can discover if it is a PIPE or a Special
Device
by doing a "stat" on it and checking the
mode:

Passed in as a parm: FILE *fp;

struct stat my_stat;
mode_t the_type;

fstat ( fileno(fp), &my_stat);

/* apply mask to get just file_type */
the_type = (my_stat.st_mode & _S_IFMT )

if ( the_type == _S_IFIFO ) {
printf("Its a pipe\n");
}else{
if ( the_type == _S_IFBLK ) {
printf("It is a Block Special device\n");
}else{
if ( the_type == _S_IFCHR ) {
printf("It is a Character Special device\n");
....... etc....

-tony
.



Relevant Pages

  • Re: locking and cache coherence
    ... reads and writes to a pipe are globally ordered. ... After a writeto a regular file has successfully returned: ... It should be the case even when process one and process two are on different machines, pipe P is a TCP socket, and the regular file RF resides on a third machine and is exported via NFS. ... I think this is not an omission in the SUS, as the further parts about pipe-targeted writes are very multi-process-conscious. ...
    (comp.programming.threads)
  • Re: poll(2) on a pipe fd
    ... After a writeto a regular file has successfully returned: ... I don't think that guarantee can apply to "whatever mechanism". ... He tries to use file locks to establish ... request shall append to the end of the pipe. ...
    (comp.os.linux.development.apps)
  • Re: ufsrestore not /dev/fd friendly
    ... By just poking with 'truss', I wasn't able to find anywhere ... that it attempted a seek on the filehandle or something like that, ... less than from the regular file. ... context-sensitive name for a pipe (whose other end ...
    (comp.unix.solaris)
  • Re: poll(2) on a pipe fd
    ... Do you assume that the common children of a single parent have different timers )? ... Because the timestamps only tell you the time the function call was entered or returned. ... That is, if whatever mechanism ensures that writereturns before readcommences, and the written/read object is a regular file, then visibility is guaranteed. ... There is no file offset associated with a pipe, hence each write request shall append to the end of the pipe. ...
    (comp.os.linux.development.apps)
  • Re: AIX - monitoring memory and cpu usage?
    ... TWAPI based stuff to AIX and would love to seee some examples. ... I don't have access to them now, but it basically involved opening a pipe to vmstat and then reading lines. ... proc ReadStats pipe { ...
    (comp.lang.tcl)