Hi !

On Windows, Rubicon complained about some of the 'chmod' tests.
When trying to understand the cause I realized that the
situation with stat/chmod in Ruby on Windows is quite complex.

Below is my investigation of this.
My  conclusion is that it would be better if Ruby just "passed on"
the different stat/chmod-semantics of Windows. Today we have three
different stat/chmod-models:

    a) UNIX-model           (used in Ruby on Unix)
    b) Ruby-Windows-model   (used in Ruby on Windows)
    c) Windows-model        (used in Windows-applications using
                             stat/chmod calls)

I propose that b) should be replaced with c).
b) is implemented in win32/win32.c" (it was introduced 2002/09/08).
Read on to see the details ...

There are two reasons stat/chmod is an issue on Windows:

  1) Windows has a limited support for the 'st_mode' attribute
     of a file. The documentation of "_chmod" in MSDN says:

         [...]
         If write permission is not given, the file is read-only. Note
         that all files are always readable; it is not possible to
         give write-only permission. Thus the modes _S_IWRITE and
        _S_IREAD | _S_IWRITE are equivalent.

     As far as I understand this, the only thing you can do with
     chmod(2) calls, is to set/clear the _S_IWRITE bit, i.e. to make
     the file readonly or read-and-writable.

     When querying this 'st_mode' field with stat(2), Windows fakes
     some of the bits to make it  look like a UNIX stat-struct.
     From the MSDN documentation of the "_stat" call and the
     'st_mode' field:

        Bit mask for file-mode information. The _S_IFDIR bit is set if
        path specifies a directory; the _S_IFREG bit is set if path
        specifies an ordinary file or a device. User read/write bits
        are set according to the file's permission mode; user execute
        bits are set according to the filename extension.

     Unix has three permission bits for each of read/write/execute,
     but via the chmod/stat interface on Windows we only have *one*
     bit for each of these. The stat function seems to return these
     single bits repeated three times, ie.:

         readonly                --->  0444
         readwrite               --->  0666
         readonly  and .exe name --->  0555
         readwrite and .exe name --->  0777

     So Windows don't distinguish between user/group/other the way
     it is done in UNIX-filesystems.


  2) On Windows, Ruby uses the stat/fstat calls (implemented in functions
     called _stat/_fstat, and corresponding to stat(2)/fstat(2) on Unix).

     *But* for some reason Ruby modifies the result of the '_stat'
     call before returning it to the caller (eg. the Ruby
     class method File.stat implemented by 'rb_file_s_stat').
     In "win32/win32.c" in the function "rb_w32_stat" you find:

            ret = stat(buf2, st);
            if (ret == 0) {
                st->st_mode &= ~(S_IWGRP | S_IWOTH);
            }

     This modifies a return value like:  0666 ---> 0644.

     But if you call the  *instance* method File#stat on an open
     filehandle you would get 0666, ie. no removal of write bits for
     group/other is done. This seems inconsistent.


As I mentioned above, I believe the best thing would be to remove
the extra code in "win32/win32.c", and let the File.stat methods
return whatever the Windows "_stat/_fstat" calls returns.

The current behaviour was introduced revision 1.66, 2002/09/08:
>
>  * win32/win32.c (rb_w32_stat): remove S_IWGRP and S_IWOTH bits
>    from st_mode.
>

I don't know *why* this change was done (I realize that there
probably was some seemingly good reason for the change).

My main argument for removing this new behaviour is that it
complicates things (having three models a described above).

And anyone really caring about the file premissions on a file in
Windows should probably use the native Windows-interfaces.

What do you think ?

/Johan Holmberg