#define _GNU_SOURCE
#include <sys/stat.h>
#include <sys/acl.h>
#include <acl/libacl.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include "util.h"
#include "acl.h"
^L
static bool
user_has_execute_bit (int fd)
{
struct stat st;
fstat(fd, &st);
return (st.st_mode & S_IXUSR);
}
static void
add_acl_bit_ifhave (acl_t *acl,
acl_perm_t which,
acl_perm_t only_ifhave)
{
int entid;
acl_entry_t aclent;
acl_permset_t aclperms;
for (entid = ACL_FIRST_ENTRY;
acl_get_entry(*acl, entid, &aclent) == 1;
entid = ACL_NEXT_ENTRY)
{
acl_get_permset(aclent, &aclperms);
if (acl_get_perm(aclperms, only_ifhave) == 1)
acl_add_perm(aclperms, which);
}
}
static void
clear_acl_bits (acl_t *acl,
acl_perm_t which)
{
int entid;
acl_entry_t aclent;
acl_permset_t aclperms;
for (entid = ACL_FIRST_ENTRY;
acl_get_entry(*acl, entid, &aclent) == 1;
entid = ACL_NEXT_ENTRY)
{
acl_get_permset(aclent, &aclperms);
acl_delete_perm(aclperms, which);
}
}
acl_t
xacl_get_fd (int fd)
{
acl_t acl;
if ((acl = acl_get_fd(fd)) == NULL) {
struct stat st;
fstat(fd, &st);
fprintf(stderr, "%s: acl_get_fd: fd %d, inode %lu: %s:\n",
progname, fd, st.st_ino, strerror(errno));
exit(EXIT_FAILURE);
}
return acl;
}
void
xacl_set_fd (int fd,
acl_t acl)
{
if (acl_set_fd(fd, acl) == -1) {
struct stat st;
fstat(fd, &st);
}
}
void
set_repoacl_from_parent (char *filename,
int parentfd)
{
char *repofile, *atticfile;
int repofilefd, atticfd;
acl_t acl;
bool inattic = false;
asprintf(&repofile, "%s,v", filename);
if ((repofilefd = open(repofile, O_RDONLY)) == -1) {
if (errno == ENOENT) {
asprintf(&atticfile, "Attic/%s", repofile);
repofilefd = xopen(atticfile, O_RDONLY);
free(atticfile);
atticfd = xopen("Attic", O_RDONLY);
inattic = true;
} else {
fprintf(stderr,
"%s: set_repoacl_from_parent: open: %s: %s\n",
progname, repofile, strerror(errno));
exit(EXIT_FAILURE);
}
}
acl = xacl_get_fd(parentfd);
if (inattic) {
xacl_set_fd(atticfd, acl);
close(atticfd);
}
clear_acl_bits(&acl, ACL_WRITE);
if (user_has_execute_bit(repofilefd))
add_acl_bit_ifhave(&acl, ACL_EXECUTE, ACL_READ);
else
clear_acl_bits(&acl, ACL_EXECUTE);
xacl_set_fd(repofilefd, acl);
close(repofilefd);
free(repofile);
}