permissions api in directory package is useless (and possibly harmful)

All, We need to think about a new better permissions api for the System.Directory module. The current api and also the implementation are at best useless and possibly harmful. I've been trying to debug various permission problems related to installing files with Cabal on Unix and Windows. Half the problems seem to stem from the permissions api and the copying of permissions in copyFile. data Permissions = Permissions { readable :: Bool, writable :: Bool, executable :: Bool, searchable :: Bool } getPermissions :: FilePath -> IO Permissions setPermissions :: FilePath -> Permissions -> IO () These are clearly designed for the unix permissions model, however they do not map onto it very usefully. get/setPermissions only get the user permissions, not the group or other. So for example if I have a file: -rw-rw-rw- 1 duncan users 0 2009-01-28 12:34 foo then setPermissions "foo" (Permissions True False False False) only removes write permissions from me, not from everyone else: -r--rw-rw- 1 duncan users 0 2009-01-28 12:34 foo which cannot be what we wanted. It's also pretty useless for installing files globally. For that we want to say that a file is readable by everyone and only writable by the owner (usually root). It might even be ok to say only readable by everyone and writable by nobody, but we cannot even do that. Combine that with copyFile copying permissions and we can easily lock people out or install world-writable files depending on the umask of the user building the software. On windows getPermissions tells us almost nothing. In particular if it says the file is readable or writable, this is no guarantee that we can read or write the file. getPermissions does not look at permissions. It only consults the old DOS read-only attribute (and the file extension to tell us if a file is executable). Similarly, on windows setPermissions also only sets the read-only attribute. The read-only attribute should really be avoided. It has rather unhelpful semantics. For example moving a file over a read-only file fails, where as if windows permissions (ACLs) are used then it works as expected (same as on POSIX). The read-only attribute is only there for compatibility with heritage software, we should really never set it. There is also an implementation of copyPermissions, it's not actually exposed in System.Directory but it is used by copyFile. It calls stat to get the permissions and chmod to set them. The implementation is the same between unix and windows, on windows it uses the stat and chmod from the msvcrt library. On Unix copyPermissions does work and is probably the right thing for copyFile to do. It's the default behaviour of /bin/cp for example. However it does mean there is no easy efficient way to make a copy of a file where the destination file gets the default permissions, given the umask of the current user. This means that copyFile is not appropriate for installing files, since the user building a package is not necessarily the same as the one installing it and their umasks can and often are different. The unix install program does not copy permissions, instead it sets them explicitly. We have no portable way of doing the same. But we can at least use the System.Posix.Files.setFileMode to do it. One nice thing about copyFile is that it replaces the destination file atomically. However if we have to set the permissions in a second step then we loose this nice property. Ideally we would create the temporary file in the destination directory (exclusively and with permissions such that no other user could write to our file), we'd copy the data over, set the new destination permissions and atomically replace the destination file. The copyPermissions function on windows is useless. It does not copy permissions. The way that msvcrt implements stat and chmod means that the only "permissions" that are copied is the old DOS read-only attribute. Perhaps copying the read-only attribute is the right thing for copyFile to do, it's what the Win32 CopyFile function does, however it's never what I want to do for installing software package files. So, can we craft a useful api for permissions? We should consider what the defaults for copyfile etc should be with respect to permissions. Where those defaults are not helpful can we think of a way to let us do what we want (eg get default or specific permissions instead of copying permissions). Or is it impossible and we just have to use system-specific functions whenever we need something non-standard. In which case we need to make those functions better, they appear to be mostly lacking for the Win32 case. In either case I'm sure the existing permissions api needs to be deprecated with big flashing warnings. Duncan Oh, and while I'm thinking about it: it's not currently possible to open new/exclusive files with specific permissions and the open temp file functions on windows do not ensure the file is writable only by the current user.

On Wed, Jan 28, 2009 at 2:13 PM, Duncan Coutts
We need to think about a new better permissions api for the System.Directory module. The current api and also the implementation are at best useless and possibly harmful.
Perhaps there's something we can learn from the rearchitecture of Java's file handling that's happening in NIO 2. They're overhauling how files, directories, file systems, links, and metadata is handled. They address things such as providing both a lowest common denominator layer and platform specific "extensions". See for example http://javanio.info/filearea/nioserver/WhatsNewNIO2.pdf starting at slide 17. Cheers, Johan

On Wed, 2009-01-28 at 14:57 +0100, Johan Tibell wrote:
On Wed, Jan 28, 2009 at 2:13 PM, Duncan Coutts
wrote: We need to think about a new better permissions api for the System.Directory module. The current api and also the implementation are at best useless and possibly harmful.
Perhaps there's something we can learn from the rearchitecture of Java's file handling that's happening in NIO 2. They're overhauling how files, directories, file systems, links, and metadata is handled. They address things such as providing both a lowest common denominator layer and platform specific "extensions".
See for example http://javanio.info/filearea/nioserver/WhatsNewNIO2.pdf starting at slide 17.
Yes, I'm sure there are some good ideas to consider there. I looked at NIO1 and it's got some fairly sensible stuff. Duncan
participants (2)
-
Duncan Coutts
-
Johan Tibell