When working with Access Control Lists (ACL) in Linux, many administrators expect the -R
flag in setfacl
to behave like chmod -R
, applying permissions uniformly to both directories and files. However, ACLs handle recursion differently due to their more granular permission system.
The command you tried:
setfacl -Rm d:u:foo:rwX test
Specifically sets default ACLs (notice the d:
prefix), which only affect directories. This is why subtest/
received the ACL but subtest.txt
didn't.
For complete recursive ACL application, you need two separate operations:
# Apply to existing files and directories
setfacl -Rm u:foo:rwX test/
# Set default ACLs for future items
setfacl -Rm d:u:foo:rwX test/
The capital X
is crucial - it grants execute permission only if the target is a directory or already has execute permission. This prevents accidentally making scripts executable.
Always verify with:
getfacl -R test/ | less
For more control, you can use find
:
# For directories
find test/ -type d -exec setfacl -m d:u:foo:rwX {} +
# For regular files
find test/ -type f -exec setfacl -m u:foo:rw {} +
Remember that:
- Default ACLs only affect newly created items
- Existing files need explicit permission setting
- The order of operations matters when combining default and regular ACLs
Here's how I typically set up a web directory:
# Set default ACLs for future items
setfacl -Rm d:u:www-data:rwX,d:u:deploy:rwX /var/www/
# Apply to existing structure
setfacl -Rm u:www-data:rwX,u:deploy:rwX /var/www/
# Remove execute from files where not needed
find /var/www/ -type f -exec setfacl -m u:www-data:r-X,u:deploy:r-X {} +
When working with Linux filesystem permissions, many administrators encounter a specific challenge with setfacl
's recursive flag (-R
). The command appears to work partially - applying to directories but skipping files in the recursive operation. Here's the technical breakdown of what's happening:
$ tree test/
test/
├── subtest/
└── subtest.txt
The key lies in understanding the difference between regular ACL entries and default ACL entries (specified with d:
prefix). Default ACLs only propagate to:
- Newly created files/directories
- Existing directories (when using
-R
)
This explains why your command:
setfacl -Rm d:u:foo:rwX test
affected subtest/
but not subtest.txt
.
Method 1: Combined ACL Setting
For immediate effect on both existing files and directories:
setfacl -Rm u:foo:rwX test # Applies to existing files and directories
setfacl -Rm d:u:foo:rwX test # Sets default for future items
Method 2: Using find with setfacl
For more granular control:
find test/ -type d -exec setfacl -Rm d:u:foo:rwX {} + # Directories
find test/ -type f -exec setfacl -Rm u:foo:rw {} + # Files
Method 3: XCAPE Permission Flag
The capital X
in permissions is special:
setfacl -Rm u:foo:rwX test # Execute only if directory or already executable
Here's a complete setup for a web directory with mixed content:
# Set existing permissions
setfacl -Rm u:deploy:rwX /var/www/project
setfacl -Rm g:developers:r-X /var/www/project
setfacl -Rm d:u:deploy:rwX /var/www/project
setfacl -Rm d:g:developers:r-X /var/www/project
# Verify with:
getfacl /var/www/project
- Order of operations matters - set defaults after setting current permissions
- Remember that
X
differs fromx
in significant ways - Default ACLs don't automatically apply to symlinks (use
-h
flag carefully) - Consider filesystem limitations (some don't support all ACL features)