Subject: Re: text/binary problem since 20020530 snapshot
From: John Marshall <[email-masked]>
To: Ton van Overbeek <[email-masked]>
Cc: [email-masked]
Date: Tue, 4 Jun 2002 16:26:28 +0200

On Mon, Jun 03, 2002 at 06:41:24PM +0200, Ton van Overbeek wrote:
> Since the 20020530 snapshot the default mode for open is binary.
> From http://www.cygwin.com/snapshots/winsup-changelog-20020529-20020530 :
>> 2002-05-29  Christopher Faylor  <[email-masked]>
>> 
>>         * fhandler.cc (binmode): Default to binmode when mode is not known.
[...]
> Questions:
> - With the behaviour since 20020503, does it make any difference at all
>   if a filesystem is text or binary mounted for reading/writing when
>   no mode is specified in the open() call ?

I've always found these binmode/textmode mounts v. LF/CR-LF files issues
confusing, so I did some tests to try to see what was going on.  Trying
to read a six byte file containing "a\r\nb\r\n" (test program attached
below), I got the following with cygwin1.dll 1.3.10 (and an empty
$CYGWIN):
			binary mount		text mount
fopen "rb"		61 0d 0a 62 0d 0a	61 0d 0a 62 0d 0a
fopen "r"		61 0d 0a 62 0d 0a	61 0a 62 0a
open O_RDONLY		61 0d 0a 62 0d 0a	61 0a 62 0a
open O_RDONLY|O_TEXT	61 0a 62 0a		61 0a 62 0a
open O_RDONLY|O_BINARY	61 0d 0a 62 0d 0a	61 0d 0a 62 0d 0a

I also did this with the 20020530 and 20020603 cygwin1.dll snapshots: in
these cases, the results, for files on both binary and text mounts, were
as listed above for a binary mount.  So in these snapshots, for *reading*
the filesystem's text/binary mode isn't making any difference.  Probably
it still makes a difference on writing (at least for O_WRONLY|O_TEXT and
"w") but I didn't test that.

> - What is the intended behaviour of a text vs binary mounted filesystem
>   in the case of question 1 ?

FWIW (very little) my naive expectation (based on ISO C's fopen()
without "b" meaning text files, and on open() being a Unix function,
hence using raw binary files by default) is

			binary mount		text mount
fopen "rb"		61 0d 0a 62 0d 0a	61 0d 0a 62 0d 0a
fopen "r"		(?1)			61 0a 62 0a
open O_RDONLY		61 0d 0a 62 0d 0a	61 0d 0a 62 0d 0a
open O_RDONLY|O_TEXT	(?2)			61 0a 62 0a
open O_RDONLY|O_BINARY	61 0d 0a 62 0d 0a	61 0d 0a 62 0d 0a

Actually it's a hard question: for the (?) cases, I could make arguments
either way.  It depends on what a "text file" is: maybe it's CR-LF
because Cygwin is trying to interoperate with Windows, or maybe it's LF
because Cygwin is trying to be a POSIX environment.  I kind of had the
impression that choosing binmode/textmode when you mounted things was
how you expressed your preference between the two goals, but even after
rereading http://cygwin.com/cygwin-ug-net/using-textbinary.html several
times, I'm still confused.

Theoretically I think ?1 and ?2 should be the same (because they're both
asking for the same thing, namely text files, either implicitly or
explicitly).  Pragmatically I can see why ?1 would want to be 61 0d 0a
62 0d 0a (compatibility with bad Unix code that thinks it doesn't need
to use "b" in fopen() calls because there's no such thing as text files)
and pragmatically I can see why ?2 would want to be 61 0a 62 0a
(convenience for overachieving O_TEXT-using open() code).  Ouch.

(In the context of what brought this up in Ton's posting: for text
mounts, two of those cases have changed between 1.3.10 and the current
snapshots.  If prc-tools was being broken by the fopen("r") change, I
think I'd have grounds for complaint.  But it appears that it's being
broken by the open(O_RDONLY) change, which I agree with, so this
particular problem in prc-tools is definitely my bug.)

Clearly my expectation is different from Chris's, at least as expressed
in the current snapshots.  The case that differs is fopen("r") on a file
located on a text mount.

There's an argument that it should be 61 0d 0a 62 0d 0a for the sake of
that bad Unix code.  (And calling it "bad Unix code" is of course unfair
-- really what it is is good POSIX code.)  There's also an argument that
it should be 61 0a 62 0a for the sake of programmers who read the ISO C
standard and believe that fopen("r") does the right thing for a text
file.  Me, I would have thought that the fact that the file is on a text
mount would mean the second argument trumps the first.

Comments?  Or am I just terminally confused?

    John
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

void dump (const char *buf, int len) {
  int i;
  for (i = 0; i < len; i++)
    printf (" %02x", buf[i]);
  printf ("\n");
  }

void with_fopen (const char *fname, const char *mode) {
  FILE *f = fopen (fname, mode);
  if (f) {
    char buf[20];
    int len = fread (buf, 1, sizeof buf, f);
    fclose (f);
    printf ("fopen (\"%s\")\t", mode);
    dump (buf, len);
    }
  else
    printf ("Can't fopen (\"%s\")\n", mode);
  }

void with_open (const char *fname, int flags, const char *flags_text) {
  int fd = open (fname, flags);
  if (fd >= 0) {
    char buf[20];
    int len = read (fd, buf, sizeof buf);
    close (fd);
    printf ("%s\t", flags_text);
    dump (buf, len);
    }
  else
    printf ("Can't open (%s)\n", flags_text);
  }

int main (int argc, char **argv) {
  const char *fname = (argc > 1)? argv[1] : "textfile.foo";
  FILE *f = fopen (fname, "wb");

  if (f) {
    fwrite ("a\x0d\x0a" "b\x0d\x0a", 1, 6, f);
    fclose (f);
    }
  else
    printf ("Can't write\n");

  with_fopen (fname, "rb");
  with_fopen (fname, "r");

  with_open (fname, O_RDONLY, "open (O_RDONLY)");
#ifdef O_TEXT
  with_open (fname, O_RDONLY | O_TEXT, "O_RDONLY|O_TEXT");
#else
  printf ("Don't have O_TEXT\n");
#endif
#ifdef O_BINARY
  with_open (fname, O_RDONLY | O_BINARY, "O_RD..|O_BINARY");
#else
  printf ("Don't have O_BINARY\n");
#endif

  return 0;
  }

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/