Text and Binary modes

The Issue

On a UNIX system, when an application reads from a file it gets exactly what's in the file on disk and the converse is true for writing. The situation is different in the DOS/Windows world where a file can be opened in one of two modes, binary or text. In the binary mode the system behaves exactly as in UNIX. However on writing in text mode, a NL (\n, ^J) is transformed into the sequence CR (\r, ^M) NL.

This can wreak havoc with the seek/fseek calls since the number of bytes actually in the file may differ from that seen by the application.

The mode can be specified explicitly as explained in the Programming section below. In an ideal DOS/Windows world, all programs using lines as records (such as bash, make, sed ...) would open files (and change the mode of their standard input and output) as text. All other programs (such as cat, cmp, tr ...) would use binary mode. In practice with Cygwin, programs that deal explicitly with object files specify binary mode (this is the case of od, which is helpful to diagnose CR problems). Most other programs (such as sed, cmp, tr) use the default mode.

The default Cygwin behavior

The Cygwin system gives us some flexibility in deciding how files are to be opened when the mode is not specified explicitly. The rules are evolving, this section gives the design goals.

  1. If the filename is specified as a POSIX path and it appears to reside on a file system that is mounted (i.e. if its pathname starts with a directory displayed by mount), then the default is specified by the mount flag. If the file is a symbolic link, the mode of the target file system applies.

  2. If the file is specified via a MS-DOS pathname (i.e., it contains a backslash or a colon), the default is binary.

  3. Pipes, sockets and non-file devices are opened in binary mode. For pipes opened through the pipe() system call you can use the setmode() function (see the section called “Programming” to switch to textmode. For pipes opened through popen(), you can simply specify text or binary mode just like in calls to fopen().

  4. Sockets and other non-file devices are always opened in binary mode.

  5. When redirecting, the Cygwin shells uses rules (a-d). Non-Cygwin shells always pipe and redirect with binary mode. With non-Cygwin shells the commands cat filename | program and program < filename are not equivalent when filename is on a text-mounted partition.

    The programs u2d and d2u can be used to add or remove CR's from a file. u2d add's CR's before a NL. d2u removes CR's. Use the --help option to these commands for more information.

Binary or text?

UNIX programs that have been written for maximum portability will know the difference between text and binary files and act appropriately under Cygwin. Most programs included in the official Cygwin distributions should work well in the default mode.

Binmode is the best choice usually since it's faster and easier to handle, unless you want to exchange files with native Win32 applications. It makes most sense to keep the Cygwin distribution and your Cygwin home directory in binmode and generate text files in binmode (with UNIX LF lineendings). Most Windows applications can handle binmode files just fine. A notable exception is the mini-editor Notepad, which handles UNIX lineendings incorrectly and only produces output files with DOS CRLF lineendings.

You can convert files between CRLF and LF lineendings by using certain tools in the Cygwin distribution like dos2unix and unix2dos from the dos2unix package. You can also specify a directory in the mount table to be mounted in textmode so you can use that directory for exchange purposes.

As application programmer you can decide on a file by file base, or you can specify default open modes depending on the purpose for which the application open files. See the next section for a description of your choices.

Programming

In the open() function call, binary mode can be specified with the flag O_BINARY and text mode with O_TEXT. These symbols are defined in fcntl.h.

The mkstemp() and mkstemps() calls force binary mode. Use mkostemp() or mkostemps() with the same flags as open() for more control on temporary files.

In the fopen() and popen() function calls, binary mode can be specified by adding a b to the mode string. Text mode is specified by adding a t to the mode string.

The mode of a file can be changed by the call setmode(fd,mode) where fd is a file descriptor (an integer) and mode is O_BINARY or O_TEXT. The function returns O_BINARY or O_TEXT depending on the mode before the call, and EOF on error.

There's also a convenient way to set the default open modes used in an application by just linking against various object files provided by Cygwin. For instance, if you want to make sure that all files are always opened in binary mode by an application, regardless of the mode of the underlying mount point, just add the file /lib/binmode.o to the link stage of the application in your project, like this:

  $ gcc my_tiny_app.c /lib/binmode.o -o my_tiny_app

Even simpler:

  $ gcc my_tiny_app.c -lbinmode -o my_tiny_app

This adds code which sets the default open mode for all files opened by my_tiny_app to binary for reading and writing.

Cygwin provides the following libraries and object files to set the default open mode just by linking an application against them:

  • /lib/libautomode.a      -  Open files for reading in textmode,
    /lib/automode.o            open files for writing in binary mode
    
  • /lib/libbinmode.a       -  Open files for reading and writing in binary mode
    /lib/binmode.o
    
  • /lib/libtextmode.a      -  Open files for reading and writing in textmode
    /lib/textmode.o
    
  • /lib/libtextreadmode.a  -  Open files for reading in textmode,
    /lib/textreadmode.o        keep default behaviour for writing.