develooper Front page | perl.perl5.porters | Postings from May 2008

Re: File::Path::mkpath() incompatiblity in perl-5.10

Thread Previous | Thread Next
David Landgren
May 30, 2008 23:55
Re: File::Path::mkpath() incompatiblity in perl-5.10
Message ID:
Jan Dubois wrote:
> On Fri, 30 May 2008, David Landgren wrote:
>> Jan Dubois wrote:
>>> On Thu, 15 May 2008, David Landgren wrote:
>>>> There are two other issues I am addressing, the fact that (stat $foo)[1]
>>>> (the inode) always returns 0 on Windows (and thus prevents UNC paths
>>>> from being removed), and asking to remove the current directory (or
>>>> ancestor), for which the code now croaks when it tries to chdir back to
>>>> the original directory at the end of the run, and it's been blown away.
>>>> The solution to the first can be solved if Win32::IdentifyFile is available.
>>> Note that all the information returned by Win32::IdentifyFile is already
>>> available inside our win32_stat() function (unless you set
>>> $^WIN32_SLOPPY_STAT to a true value).  So we could cheaply create a fake
>>> inode from it.
>> C:\temp>perl -e "$^WIN32_SLOPPY_STAT=1"
>> Bareword found where operator expected at -e line 1, near
>>          (Missing operator before IN32_SLOPPY_STAT?)
>> syntax error at -e line 1, near "$^WIN32_SLOPPY_STAT"
>> Execution of -e aborted due to compilation errors.
>> Oh hang on, I don't have AS Perl on this machine, only Strawberry.
> This is a core Perl feature; nothing ActivePerl or StrawberryPerl specific.
> You just have to write it as ${^WIN32_SLOPPY_STAT} because '^' is not a
> word character.  Note that the file index information is not available
> at the Perl level, only at the C level inside win32_stat().  I was only
> trying to say that we could fake up our own inode in there if we wanted to.
>>> The problem is that the file id can be up to 64 bits (of which only 48
>>> are used on NTFS I think, but it is up to the file system driver to
>>> implement this), and st_ino is only 16 bits in the standard "struct
>>> stat" as defined by MSVCRT.dll. A trivial way to fake an inode would be
>>> to just xor the 64 bit file id in 16 bit chunks to fold it, but of
>>> course you cannot avoid collisions this way. One advantage of this is
>>> that it could be integrated into 5.10 and 5.8 if we wanted to.
> I did some experiments with this, and surprisingly noticed that I get
> the least number of collisions if I just use the lowest 16 bits of the
> file index instead of xor-ing it together (on NTFS).  Maybe there is
> some redundancy in the file index, and the xor is therefore canceling
> out relevant information.
> But I don't think having an inode field with collisions is very useful,
> so I don't think we should bother with this approach.

I don't really care about mapping the number back to a filesystem 
entity. It just needs to be a unique, opaque cookie.

Actually, thinking a whole more about this, I'm not even sure it's 
possible to create the race condition that exists on Unix.

On Unix, with its reference count implementation, you can say rmdir 
`pwd` and it will succeed. You just can't chdir .. afterwards.

On Windows, you cannot:

C:\temp\foo>cd| perl -ne "chomp;rmdir $_ or warn qq{$_: $!}"
C:\temp\foo: Permission denied at -e line 1, <> line 1.

Furthermore, if I have one shell windows set to c:\temp\foo\bar,
and another window set to c:\temp, in the latter window I cannot rename 
c:\temp\foo to c:\temp\zyxxy, I get an Access Denied error.

So I'm beginning to think that Windows is impervious to the attack that 
can be mounted on Unix. In which case the whole point becomes moot.

>>> Another approach might be to redefine Stat_t to our own definition and
>>> use 64 bits for the inode inside Perl.  I'm not sure if this would be
>>> a problem for XS code, or for integration into 5.10.
> Haven't found time to think about this some more yet.
>>> Just for my information, how does the inode field prevent UNC paths from
>>> being removed and doesn't affect other paths?
>> Getting back to working on this again.
>> Actually, it's worse than I thought. The approach doesn't work on local
>> drives either. Consider:
>> cd \temp # or any non-root directory
>> C:\temp>perl -le "$,=' ';print +(stat '.')[0,1];print +(stat '..')[0,1]"
>> 2 0
>> 2 0
>> I would expect the inode value to change. I'm sort of surprised no-one's
>> commented on this before.
> The inode field is *always* 0 under MSWin32 AFAIK.  Documented in perlport.pod:
> |          device and inode are not meaningful. (Win32)


> That's why I was wondering how things are different for UNC paths.

Actually they're not. I thought only UNC paths showed this behaviour, 
but local paths do too. But if what I said above holds, then all this 
checking can be ignored on MSWin32 platforms. I imagine Cygwin would be 
immune as well.


stubborn tiny lights vs. clustering darkness forever ok?

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About