dbuenzli / bos

Basic OS interaction for OCaml
http://erratique.ch/software/bos
ISC License
63 stars 16 forks source link

OS.File.write functions fail when user has no write permission for directory #70

Open verbosemode opened 7 years ago

verbosemode commented 7 years ago

OS.File.write functions use with_oc, which creates temporary files in the directory of the target file. This however fails if the user has just permissions to write to the file, but not for the directory itself.

Maybe this could be fixed by making the directory for the temp files configurable for these functions. But in this case special caution might be required by the user to not use a world-readable directory if the files contain sensitive information.

Here are two examples where the write functions fail.

Example 1: Writing to files in /sys on GNU/Linux

utop # OS.File.write (Fpath.v "/sys/class/backlight/intel_backlight/brightness") "500";;

  • : (unit, _[> Rresult.R.msg ]) result = Result.Error (`Msg
    "create temporary file /sys/class/backlight/intel_backlight/bos-bf1c94.tmp: Permission denied")

Example 2: Writing to a file in a root-owned directory in /tmp, where the user has only write permission to this single file

$ whoami lobo $ mkdir /tmp/foo $ touch /tmo/foo/bar $ sudo chown root:root /tmp/foo $ sudo chmod 755 /tmp/foo $ ls -ld /tmp/foo drwxr-xr-x 2 root root 4096 Jul 16 15:02 /tmp/foo $ ls -ld /tmp/foo/bar -rw------- 1 lobo lobo 0 Jul 16 15:02 /tmp/foo/bar

utop # OS.File.write (Fpath.v "/tmp/foo/bar") "500";;

  • : (unit, _[> Rresult.R.msg ]) result = Result.Error (`Msg "create temporary file /tmp/foo/bos-b33494.tmp: Permission denied")
dbuenzli commented 7 years ago

Yes this is documented here.

I'm afraid there's no good solution to this problem but not use these functions and handle this yourself in these cases, using for example bos' support for temporary files and Bos.OS.File.move.

The problem is that bos wants to guarantee you atomicity which only rename(2) gives you. However many Linux setup have the default temporary directory on another file system which leads to EXDEV errors when you rename(2).

dbuenzli commented 7 years ago

Or maybe an atomic optional argument could be added which defaults to true.

verbosemode commented 7 years ago

Thank you very much for the clarification. Having an atomic argument sounds like a good solution, if it doesn't clutter the code too much. Since this is really just a corner case. Actually, example 2 was just made up and I would have only needed it for writing to /sys recently.

dbuenzli commented 5 years ago

Actually, example 2 was just made up and I would have only needed it for writing to /sys recently.

Note that I guess example1 could be solved by stating the file and avoid doing this on non-regular files. This could also solve the problem for writing to /dev/stdout and /dev/stderr.

/cc @rizo