RFD: deprecate permissions-related stuff in System.Directory

System.Directory has the following: Permissions( Permissions, readable, -- :: Permissions -> Bool writable, -- :: Permissions -> Bool executable, -- :: Permissions -> Bool searchable -- :: Permissions -> Bool ) getPermissions -- :: FilePath -> IO Permissions setPermissions -- :: FilePath -> Permissions -> IO () I propose to deprecate all this, in favour of using platform-specific functionality instead. Here's why: * Most uses of `getPermissions` are wrong. If you use `getPermissions` to predict whether a future operation will fail or not, then the right thing to do is to perform the operation and catch the failure exception. The result of `getPermissions` is immediately stale, and cannot be relied on alone. * The meaning of these operations on Windows is not clear. Windows has a much more elaborate access control model than Unix. For example, permissions can be inherited. Windows' emulation of the Unix `access()` function doesn't support the execute bit, and only has partial support for the other bits. * There doesn't seem to be a good least-common-denominator for access control, so we should provide good platform-specific support instead. (one problem here is that we don't have good platform-specific support for Windows, yet). These functions are hardly ever used. I did a Google code search for setPermissions and aside from implementations of setPermissions itself and tests for it, I came up with: * copying permissions from one file to another. This is used in the implementation of `copyFile`. We can and should do this natively. * one use in Wash * some uses in old versions of Cabal, when installing files (Cabal now uses `copyFile`). There are a few more uses of `getPermissions`, but as pointed out above, these are usually flawed. In any case they can usually be replaced by openFile. This isn't a proper proposal because I haven't written any code, but if we reach agreement in principle, I'll submit a real proposal. Cheers, Simon

On Thu, 23 Aug 2007, Simon Marlow wrote:
I propose to deprecate all this, in favour of using platform-specific functionality instead. Here's why:
* Most uses of `getPermissions` are wrong. If you use `getPermissions` to predict whether a future operation will fail or not, then the right thing to do is to perform the operation and catch the failure exception.
very true
These functions are hardly ever used. I did a Google code search for setPermissions and aside from implementations of setPermissions itself and tests for it, I came up with:
I used setting of permissions for 'install' like commands. E.g., I generated some HTML and wrote it to some place where it must be accessed by the werb server.

Simon Marlow
These functions are hardly ever used.
There are a few more uses of `getPermissions`, but as pointed out above, these are usually flawed. In any case they can usually be replaced by openFile.
I have a perfectly OK use of getPermissions: in hmake, there is a routine that scans the PATH variable looking for an executable with a given name. Basically, it is a Haskell implementation of the unix 'which' command. There is no actual use of the executable, just a test to report/reject the candidate pathname. Regards, Malcolm

Malcolm Wallace wrote:
Simon Marlow
wrote some fairly convincing arguments against the universal use of get/setPermissions: These functions are hardly ever used.
There are a few more uses of `getPermissions`, but as pointed out above, these are usually flawed. In any case they can usually be replaced by openFile.
I have a perfectly OK use of getPermissions: in hmake, there is a routine that scans the PATH variable looking for an executable with a given name. Basically, it is a Haskell implementation of the unix 'which' command. There is no actual use of the executable, just a test to report/reject the candidate pathname.
You wouldn't be losing much by using doesFileExist rather than getPermissions. On Windows it turns out to be really hard if not impossible to check for execute permission - the only reliable way is to actually try to execute the file. The current getPermissions always returns True for execute permission on Windows, and the one in GHC 6.8.1 returns True if the filename ends in something like ".exe" or ".bat" (both are wrong, just wrong in different ways). Cheers, Simon

I have a perfectly OK use of getPermissions: in hmake, there is a routine that scans the PATH variable looking for an executable with a given name. Basically, it is a Haskell implementation of the unix 'which' command. There is no actual use of the executable, just a test to report/reject the candidate pathname.
You wouldn't be losing much by using doesFileExist rather than getPermissions.
But on unix, it would be totally incorrect to return a file of the right name but with the wrong permissions. This is what my Haskell `which` originally did, and it bit me hard on a couple of occasions, hence the extra check.
On Windows it turns out to be really hard if not impossible to check for execute permission - the only reliable way is to actually try to execute the file.
Mounting a FAT filesystem on unix (or indeed any filesystem via Samba) also makes all files appear to be executable. These are just broken platforms, and I don't think they should hold us hostage or dictate our preferred API. I'm not saying that the current API is perfect - it could certainly be improved. But I'm just pointing out that there are valid use-cases for what we have currently. If you have concrete suggestions for a new API, I would certainly be interested. Regards, Malcolm

On Thu, 30 Aug 2007, Malcolm Wallace wrote:
I have a perfectly OK use of getPermissions: in hmake, there is a routine that scans the PATH variable looking for an executable with a given name. Basically, it is a Haskell implementation of the unix 'which' command. There is no actual use of the executable, just a test to report/reject the candidate pathname.
You wouldn't be losing much by using doesFileExist rather than getPermissions.
But on unix, it would be totally incorrect to return a file of the right name but with the wrong permissions. This is what my Haskell `which` originally did, and it bit me hard on a couple of occasions, hence the extra check.
I remind that Simon originally suggested to separate OS dependend stuff. That is, your implementation of 'which' perfectly works on UNIX but not on Windows. However the general 'getPermission' function suggests that it would work on every OS equally.

Malcolm Wallace wrote:
I have a perfectly OK use of getPermissions: in hmake, there is a routine that scans the PATH variable looking for an executable with a given name. Basically, it is a Haskell implementation of the unix 'which' command. There is no actual use of the executable, just a test to report/reject the candidate pathname. You wouldn't be losing much by using doesFileExist rather than getPermissions.
But on unix, it would be totally incorrect to return a file of the right name but with the wrong permissions. This is what my Haskell `which` originally did, and it bit me hard on a couple of occasions, hence the extra check.
On Windows it turns out to be really hard if not impossible to check for execute permission - the only reliable way is to actually try to execute the file.
Mounting a FAT filesystem on unix (or indeed any filesystem via Samba) also makes all files appear to be executable. These are just broken platforms, and I don't think they should hold us hostage or dictate our preferred API.
Tempting as it is, I couldn't possibly label Windows as "broken" :-) Since this is supposed to be a portable API, the fact that you can't implement it on certain platforms definitely *should* be an indication that it is the wrong API.
I'm not saying that the current API is perfect - it could certainly be improved. But I'm just pointing out that there are valid use-cases for what we have currently. If you have concrete suggestions for a new API, I would certainly be interested.
One suggestion is to just get rid of this functionality - code that needs to do access-control stuff must use OS-specific APIs. This is arguably the right thing. What we have now is a "best-effort" API: it tries to do something reasonable, but may do something bogus. Some people find this distasteful, but it can be useful at times (as you and others have pointed out). I'm not really convinced one way or the other, which is why I started this RFD. Cheers, Simon

Hi
returns True for execute permission on Windows, and the one in GHC 6.8.1 returns True if the filename ends in something like ".exe" or ".bat" (both are wrong, just wrong in different ways).
The GHC one is pretty wrong, since ".com" is also a valid extension for executables. Windows increased the number of executable things in 2000 (I think), and its controlled by the environment variable %PATHEXT%. On my machine: PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH i.e. vbs, wsh etc. all are exectuable. Thanks Neil

Neil Mitchell wrote:
returns True for execute permission on Windows, and the one in GHC 6.8.1 returns True if the filename ends in something like ".exe" or ".bat" (both are wrong, just wrong in different ways).
The GHC one is pretty wrong, since ".com" is also a valid extension for executables.
Um, I said "something like ...". The code in fact is Microsoft's implementation of stat(), in the CRT. The list it uses is: /* see if file appears to be executable - check extension of name */ if (p = _tcsrchr(name, _T('.'))) { if ( !_tcsicmp(p, _T(".exe")) || !_tcsicmp(p, _T(".cmd")) || !_tcsicmp(p, _T(".bat")) || !_tcsicmp(p, _T(".com")) ) uxmode |= _S_IEXEC; } Cheers, Simon
participants (4)
-
Henning Thielemann
-
Malcolm Wallace
-
Neil Mitchell
-
Simon Marlow