michael orlitzky

Fix busted ACLs faster with libadacl

posted 2018-03-06; updated 2024-04-09

Update 2024-04-09
New 7zip-23.01 patch.
Update 2023-07-02
New coreutils-9.3 patch.
Update 2023-01-13
New coreutils-9.1 patch without the fuzz.
Update 2018-03-28
the new v0.4.0 of apply-default-acl (and libadacl) drops the --no-exec-mask flag and function parameter.

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 recursive);

The two arguments are,

path (string)
The path to the file that should inherit its parent's default ACL.
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 https://ftp.gnu.org/gnu/coreutils/coreutils-9.3.tar.xz

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

user $ rm coreutils-9.3.tar.xz

user $ cd coreutils-9.3/

user $ wget -q https://michael.orlitzky.com/code/releases/coreutils-9.3_libadacl-0.4.4.patch

user $ patch -p1 < coreutils-9.3_libadacl-0.4.4.patch

patching file Makefile.in

patching file src/copy.c

user $ rm coreutils-9.3_libadacl-0.4.4.patch

user $ ./configure && make


user $ wget -q https://ftp.gnu.org/gnu/tar/tar-1.35.tar.xz

user $ tar -xf tar-1.35.tar.xz

user $ rm tar-1.35.tar.xz

user $ cd tar-1.35

user $ wget -q https://michael.orlitzky.com/code/releases/tar-1.35_libadacl-0.4.4.patch

user $ patch -p1 < tar-1.35_libadacl-0.4.4.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.35_libadacl-0.4.4.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 https://michael.orlitzky.com/code/releases/p7zip-16.02_libadacl-0.4.0.patch

user $ patch -p1 < p7zip-16.02_libadacl-0.4.0.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.4.0.patch

user $ make


user $ mkdir 7zip-23.01

user $ cd 7zip-23.01

user $ wget -q https://downloads.sourceforge.net/sevenzip/7-Zip/23.01/7z2301-src.tar.xz

user $ tar -xf 7z2301-src.tar.xz

user $ rm 7z2301-src.tar.xz

user $ wget -q https://michael.orlitzky.com/code/releases/7zip-23.01_libadacl-0.4.4.patch

user $ patch -p1 < 7zip-23.01_libadacl-0.4.4.patch

File CPP/7zip/7zip_gcc.mak is read-only; trying to patch anyway

patching file CPP/7zip/7zip_gcc.mak

File CPP/Windows/FileDir.cpp is read-only; trying to patch anyway

patching file CPP/Windows/FileDir.cpp

user $ rm 7zip-23.01_libadacl-0.4.4.patch

user $ cd CPP/7zip/Bundles/Alone2

user $ make -f ../../cmpl_gcc.mak # or ../../cmpl_clang.mak