michael orlitzky

Fix busted ACLs faster with libadacl

the problem

Using POSIX ACLs sucks because a lot of common tools mess with the permission bits, and ACLs change the meaning of your ancient, totally standard permission bits. I've hacked together various fixes for this in the past, and you can read these for some dumb history:

Six years of suck. The following packages are all still broken, in the sense that they fuck with the permission bits after creating files, and thus break your default ACLs:

The approach we've been using is to call the standalone apply-default-acl program on each new file, but launching a new process for every file is stupid and slow.

the fix

The magic behind apply-default-acl is now available in libadacl, the shared library that powers (and is shipped as part of) apply-default-acl. When you install apply-default-acl, the library is installed too. It has exactly one function in its public API:

#define ACL_ERROR -1
#define ACL_FAILURE 0
#define ACL_SUCCESS 1

int apply_default_acl(const char* path,
                      bool no_exec_mask,
                      bool recursive);

The three arguments are,

path (string)
The path to the file that should inherit its parent's default ACL.
no_exec_mask (bool)
Set this to true if you'd like normal files to inherit the execute permissions of their parent directories (you probably don't).
recursive (bool)
Do you want to operate recursively if path is a directory?

The function returns one of the constants,

If the parent's ACL was successfully inherited to path.
If an “expected” failure occurred, like if we ignored a symbolic link.
If an unexpected library error occurred.

When recursive is true, the most bad result from all of the paths is returned.

how to use it

  1. Download and install apply-default-acl normally, with ./configure, make, and make install.
  2. Add #include <libadacl.h> to the top of your C program.
  3. Add -ladacl to your linker flags.
  4. Call apply_default_acl() on the paths that you want to fix.
  5. Ensure that your system knows where to look for the shared library. For example, if you installed into /usr/local, then you will have to do some other shit to tell your linker to look there. I don't know, google it.

Lucky for you I have three examples prepared: new patches for coreutils, tar and p7zip.

fixing coreutils, tar, and p7zip all over again

With a recent version (0.3.1 or newer) of apply-default-acl installed, you should be able to build patched versions of these tools. If you need libadacl in your own programs, read the patches to see what they do.


user $ wget -q http://ftp.gnu.org/gnu/coreutils/coreutils-8.29.tar.xz

user $ tar -xf coreutils-8.29.tar.xz

user $ rm coreutils-8.29.tar.xz

user $ cd coreutils-8.29/

user $ wget -q http://michael.orlitzky.com/code/releases/coreutils-8.29_libadacl-0.3.1.patch

user $ patch -p1 < coreutils-8.29_libadacl-0.3.1.patch

patching file Makefile.in

patching file src/copy.c

user $ rm coreutils-8.29_libadacl-0.3.1.patch

user $ ./configure && make


user $ wget -q http://ftp.gnu.org/gnu/tar/tar-1.30.tar.xz

user $ tar -xf tar-1.30.tar.xz

user $ rm tar-1.30.tar.xz

user $ cd tar-1.30

user $ wget -q http://michael.orlitzky.com/code/releases/tar-1.30_libadacl-0.3.1.patch

user $ patch -p1 < tar-1.30_libadacl-0.3.1.patch

patching file src/Makefile.in

patching file src/common.h

patching file src/extract.c

patching file src/warning.c

user $ rm tar-1.30_libadacl-0.3.1.patch

user $ ./configure && make


user $ wget -q https://downloads.sourceforge.net/project/p7zip/p7zip/16.02/p7zip_16.02_src_all.tar.bz2

user $ tar -xf p7zip_16.02_src_all.tar.bz2

user $ rm p7zip_16.02_src_all.tar.bz2

user $ cd p7zip_16.02

user $ wget -q http://michael.orlitzky.com/code/releases/p7zip-16.02_libadacl-0.3.1.patch

user $ patch -p1 < p7zip-16.02_libadacl-0.3.1.patch

patching file CPP/Windows/FileDir.cpp

patching file makefile.linux_amd64_asm

patching file makefile.linux_x86_asm_gcc_4.X

patching file makefile.machine

user $ rm p7zip-16.02_libadacl-0.3.1.patch

user $ make