Say, I want to give a user colleague read access to a directory /rather/long/path/to/the/directory, but not necessarily to its parent directories.

As explained for example here and there, I first need to make sure that colleague can traverse the path. Using setfacl :

setfacl -m u:colleague:x /rather
setfacl -m u:colleague:x /rather/long
setfacl -m u:colleague:x /rather/long/path
setfacl -m u:colleague:x /rather/long/path/to
setfacl -m u:colleague:x /rather/long/path/to/the
setfacl -m u:colleague:xr /rather/long/path/to/the/directory

This is quite tedious for a deeply nested path. Is there a more elegant way to do this?

P.S. To make it a bit harder, being a normal user I might not have the right to change the permissions for the top-level directory in the path (e.g. /home). If possible, the solution should either ignore these directories (assuming that colleague can traverse them) or, even better, check whether colleague is allowed to traverse them and give an error message, if he is not.

  • I've deleted my answer because I can't test it and prove at the moment (my linux box is somewhere far away). – Kitet Jul 12 '14 at 15:22

The simple, stupid answer:

You can shorten your sequence of commands a little by combining the first n–1 of them:

setfacl -m u:colleague:x  /rather /rather/long /rather/long/path /rather/long/path/to /rather/long/path/to/the
setfacl -m u:colleague:xr /rather/long/path/to/the/directory

An “obvious” warning:

Even if you own the target (leaf) directory, you need to have execute (traverse) access to every directory in the path.  If there’s any directory that you don’t have access to and you don’t own, you’re out of luck.  (You need to assume an identity (i.e., root or the owner of the directory) that lets you give yourself access, or persuade somebody who has the power to do so.  That’s out of the scope of this question.)

But, if there are intermediate directories that you own but don’t have access to (e.g., somebody has done chmod 0), you need to give yourself access from the top down.

The answer: (TL;DR)

I made the above point because this works from the bottom up:

while branch="$(dirname "$branch")"
     setfacl -m u:colleague:x "$branch"  ||  break
     if [ "$branch" = / ]
setfacl -m u:colleague:xr "$leaf"

Optionally, you can hide any error messages from setfacl by adding 2> /dev/null.  If you have a pathological situation where you own /rather/long and /rather/long/path/to, but not /rather/long/path (but its permissions are open), remove the || break after the setfacl, because you need to keep climbing the tree after getting the error on setfacl … /rather/long/path.  Otherwise, if you are not root, you could remove the if [ "$branch" = / ] test, because the loop will terminate when you reach a directory level where you can’t run setfacl.  (But that’s not a great idea; if you save this as a script, you will someday run it as root, and then you’ll have an infinite loop.)

It goes without saying that, if you make this a script, the directory path and the colleague’s name should be parameters.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.