stat/chmod on Windows
From:
Johan Holmberg <holmberg@...>
Date:
2003-06-18 11:33:32 UTC
List:
ruby-core #1149
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