file permissions and copying files

All, I have complained before about the System.Directory file permissions API, and how it relates to copyFile. Let me give an example of where the existing copyFile API is too limited. Perhaps this will help us think about what an improved API might be. The example of course is build system component of Cabal. It turns out that we actually need *three* different kinds of copyFile. The only difference in each case is the treatment of file permissions / attributes. To achieve the worst case consider a source tree that is completely read only and a user umask that makes new files not world readable. The cases are: 1. Copying files within the build tree, eg as a dummy pre-processor. In this case it should behave like "cat src > dest" and not like cp. That is, it is essential that we create the new files with default permissions and not copy the source permissions. Otherwise we would end up making read-only files which would cause problems later (especially on windows). 2. Copying source files into a temp directory to prepare a source tarball. In this case we really do want to copy file permissions. In particular we want to copy executable permissions on files like ./configure. In this case it does not matter if we also copy read-only permissions because we will only delete these files, not try to overwrite them. Also, the tarball creation code will only copy executable permissions. 3. Installing files. In this case it is essential that we specify exact permissions and ignore the umask of the installing user or the permissions of the source files. The source files could be read-only and that would mess things up on windows as we would not be able to re-install over the read-only files. We also do not want to copy permissions generally because if the umask of the user that built the files was such that they're not globally readable then installing globally (eg via sudo) will install files only readable by root. Instead we have to specify that the files are read/write by their owner and readable by everyone else (and executable for binaries). If we were to generalise from these examples we'd have some copyFile function that took an extra function to generate the permissions from a combination of the source and default permissions (or it could ignore both and use specific ones). Note that in the case where I had to set specific permissions I didn't really need full control over unix permission bits, I just wanted a couple properties. I needed executable or not, readable/writable by the file owner and readable/writable by others. Is that sufficiently abstract to map onto both Windows and Unix file permissions? The thing that works least well between unix and windows file permissions is group ownership and permissions but can these be ignored in most portable situations? So at the moment we have: data Permissions = Permissions { readable :: Bool, writable :: Bool, executable :: Bool, searchable :: Bool } The main problem with this is that it is not abstract so it looses information when we do: getPermissions src >>= setPermissions dst However suppose it was an abstract type such that this worked and had the same query functions as above. Then for setting permissions we'd also have setReadable, etc :: Permissions -> Permissions. However as I mentioned above for Cabal we'd need to distinguish setting readable/writable for the file owner vs for all other users. So how about this: data Permissions -- abstract getPermissions :: FilePath -> IO Permissions setPermissions :: FilePath -> Permissions -> IO () -- | only tells us effective permissions for the current process readable :: Permissions -> Bool writable :: Permissions -> Bool executable :: Permissions -> Bool searchable :: Permissions -> Bool setUserReadable, setOtherReadable :: Bool -> Permissions -> Permissions setUserWritable, setOtherWritable :: Bool -> Permissions -> Permissions setExecutable :: Bool -> Permissions -> Permissions setSearchable :: Bool -> Permissions -> Permissions So for Unix the mapping is: setUserReadable True/False chmod u+r / u-r setUserWritable True/False chmod u+w / u-w setOtherReadable True/False chmod go+r / go-r setOtherWritable True/False chmod go+w / go-w setExecutable True/False chmod +x / -x (for files) setSearchable True/False chmod +x / -x (for dirs) So I'm aligning group with other and not distinguishing executable/searchable for user vs others. Note also that what is set by set* is not necessarily the same as what we get back from the query functions because those take all permissions into account including group permissions and other ACLs that we cannot manipulate via this API. Comments? Duncan

On Fri, 20 Feb 2009, Duncan Coutts wrote:
I have complained before about the System.Directory file permissions API, and how it relates to copyFile.
Let me give an example of where the existing copyFile API is too limited. Perhaps this will help us think about what an improved API might be.
...
So for Unix the mapping is:
setUserReadable True/False chmod u+r / u-r setUserWritable True/False chmod u+w / u-w
setOtherReadable True/False chmod go+r / go-r setOtherWritable True/False chmod go+w / go-w
It's not hard to predict that 'Other' will be too coarse for some applications, although I haven't an example. However, maybe we should have a new package which provides common functions for Unix and Windows as needed by Cabal. I expect that the 3 cases of permission transfer that you described for Cabal will also occur in other applications. From this package a general API for System.Directory may evolve.

On Mon, 2009-02-23 at 00:46 +0100, Henning Thielemann wrote:
On Fri, 20 Feb 2009, Duncan Coutts wrote:
I have complained before about the System.Directory file permissions API, and how it relates to copyFile.
Let me give an example of where the existing copyFile API is too limited. Perhaps this will help us think about what an improved API might be.
...
So for Unix the mapping is:
setUserReadable True/False chmod u+r / u-r setUserWritable True/False chmod u+w / u-w
setOtherReadable True/False chmod go+r / go-r setOtherWritable True/False chmod go+w / go-w
It's not hard to predict that 'Other' will be too coarse for some applications, although I haven't an example. However, maybe we should have a new package which provides common functions for Unix and Windows as needed by Cabal. I expect that the 3 cases of permission transfer that you described for Cabal will also occur in other applications. From this package a general API for System.Directory may evolve.
Certainly 'Other' is too coarse in general, but I fear there is not much that is more fine grained that is also portable and useful. Is there a useful abstraction that covers Windows ACLs (and legacy file attributes) and POSIX ACLs and classic Unix permission bits? There might be but I'm not hopeful. POSIX ACLs subsume the Unix permission bits but the Windows ACL model is rather different. My guess is that something around the granularity of owner/other is what we can get in a portable API and more detailed things just have to be platform-specific. We need both. Duncan
participants (2)
-
Duncan Coutts
-
Henning Thielemann