*
* For a list of compiler flags, see the list preceding the big #if below.
*/
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
if (acl) {
if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
len = pm_strcpy(jcr->acl_text, acl_text);
+ acl_free(acl);
acl_free(acl_text);
return len;
}
+ acl_free(acl);
+#ifndef HAVE_OSF1_OS /* BACL_ENOTSUP not defined for OSF1 */
+ } else if (errno == BACL_ENOTSUP) {
+ /* Not supported, just pretend there is nothing to see */
+ return pm_strcpy(jcr->acl_text, "");
+#endif
}
/***** Do we really want to silently ignore errors from acl_get_file
and acl_to_text? *****/
char *acl_text;
if ((n = getacl(jcr->last_fname, 0, acls)) <= 0) {
+ if (errno == BACL_ENOTSUP) {
+ return pm_strcpy(jcr->acl_text, "");
+ }
return -1;
}
if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
char *acl_text;
n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
- if (n <= 0) {
+ if (n < MIN_ACL_ENTRIES) {
return -1;
+ } else if (n == MIN_ACL_ENTRIES) {
+ /* The ACLs simply reflect the (already known) standard permissions */
+ return pm_strcpy(jcr->acl_text, "");
}
if ((acls = (aclent_t *)malloc(n * sizeof(aclent_t))) == NULL) {
return -1;
}
if (acl(jcr->last_fname, GETACL, n, acls) == n) {
if ((acl_text = acltotext(acls, n)) != NULL) {
- pm_strcpy(jcr->acl_text, acl_text);
+ len = pm_strcpy(jcr->acl_text, acl_text);
free(acl_text);
free(acls);
return len;
int aclls(char *fname)
{
struct stat st;
+ int len;
if (lstat(fname, &st) != 0) {
Dmsg0(200, "acl: source does not exist\n");
jcr.last_fname = fname;
- if (bacl_get(&jcr, BACL_TYPE_ACCESS) < 0) {
+ len = bacl_get(&jcr, BACL_TYPE_ACCESS);
+ if (len < 0) {
Dmsg1(200, "acl: could not read ACLs for %s\n", jcr.last_fname);
return EXIT_FAILURE;
+ } else if (len == 0) {
+ printf("#file: %s [standard permissions - or unsupported]\n\n", jcr.last_fname);
+ } else {
+ printf("#file: %s\n%s\n", jcr.last_fname, jcr.acl_text);
}
- printf("#file: %s\n%s\n", jcr.last_fname, jcr.acl_text);
if (S_ISDIR(st.st_mode) && (BACL_CAP & BACL_CAP_DEFAULTS_DIR)) {
- if (bacl_get(&jcr, BACL_TYPE_DEFAULT) < 0) {
+ len = bacl_get(&jcr, BACL_TYPE_DEFAULT);
+ if (len < 0) {
Dmsg1(200, "acl: could not read default ACLs for %s\n", jcr.last_fname);
return EXIT_FAILURE;
+ } else if (len == 0) {
+ printf("#file: %s [default, none - or unsupported]\n\n", jcr.last_fname);
+ } else {
+ printf("#file: %s [default]\n%s\n", jcr.last_fname, jcr.acl_text);
}
- printf("#file: %s [default]\n%s\n", jcr.last_fname, jcr.acl_text);
}
return 0;
#ifndef _BACULA_ACL_
#define _BACULA_ACL_
-/* If you want shorter ACL strings when possible, uncomment this */
-#define BACL_WANT_SHORT_ACLS
+/* For shorter ACL strings when possible, define BACL_WANT_SHORT_ACLS */
+/* #define BACL_WANT_SHORT_ACLS */
-/* If you want numeric user/group ids when possible, uncomment this */
+/* For numeric user/group ids when possible, define BACL_WANT_NUMERIC_IDS */
/* #define BACL_WANT_NUMERIC_IDS */
/* We support the following types of ACLs */
#define BACL_CAP_DEFAULTS 0x001 /* Has default ACLs for directories */
#define BACL_CAP_DEFAULTS_DIR 0x002 /* Default ACLs must be read separately */
-/* Set capabilities for various OS */
-#if defined(HAVE_SUN_OS)
-#define BACL_CAP BACL_CAP_DEFAULTS
-#elif defined(HAVE_FREEBSD_OS) \
- || defined(HAVE_IRIX_OS) \
- || defined(HAVE_OSF1_OS) \
- || defined(HAVE_LINUX_OS)
+/* Set BACL_CAP (always) and BACL_ENOTSUP (when used) for various OS */
+#if defined(HAVE_FREEBSD_OS)
#define BACL_CAP (BACL_CAP_DEFAULTS|BACL_CAP_DEFAULTS_DIR)
-#else
+#define BACL_ENOTSUP EOPNOTSUPP
+#elif defined(HAVE_HPUX_OS)
#define BACL_CAP BACL_CAP_NONE
+#define BACL_ENOTSUP EOPNOTSUPP
+#elif defined(HAVE_IRIX_OS)
+#define BACL_CAP (BACL_CAP_DEFAULTS|BACL_CAP_DEFAULTS_DIR)
+#define BACL_ENOTSUP ENOSYS
+#elif defined(HAVE_LINUX_OS)
+#define BACL_CAP (BACL_CAP_DEFAULTS|BACL_CAP_DEFAULTS_DIR)
+#define BACL_ENOTSUP ENOTSUP
+#elif defined(HAVE_OSF1_OS)
+#define BACL_CAP (BACL_CAP_DEFAULTS|BACL_CAP_DEFAULTS_DIR)
+/* #define BACL_ENOTSUP ENOTSUP */ /* Don't know */
+#define BACL_CAP (BACL_CAP_DEFAULTS|BACL_CAP_DEFAULTS_DIR)
+#elif defined(HAVE_SUN_OS)
+#define BACL_CAP BACL_CAP_DEFAULTS
+#else
+#define BACL_CAP BACL_CAP_NONE /* nothing special */
#endif
#endif
}
#ifdef HAVE_DARWIN_OS
- /* Open resource fork if necessary and save content */
+ /* Regular files can have resource forks and Finder Info */
if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
ff_pkt->flags & FO_HFSPLUS)) {
if (ff_pkt->hfsinfo.rsrclength > 0) {
#endif
#ifdef HAVE_ACL
- /* Read access ACLs for files, dirs and links */
- if (!read_and_send_acl(jcr, BACL_TYPE_ACCESS, STREAM_UNIX_ATTRIBUTES_ACCESS_ACL)) {
- return 0;
- }
- /* Directories can have default ACLs too */
- if (ff_pkt->type == FT_DIREND && (BACL_CAP & BACL_CAP_DEFAULTS_DIR)) {
- if (!read_and_send_acl(jcr, BACL_TYPE_DEFAULT, STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL)) {
+ if (ff_pkt->flags & FO_ACL) {
+ /* Read access ACLs for files, dirs and links */
+ if (!read_and_send_acl(jcr, BACL_TYPE_ACCESS, STREAM_UNIX_ATTRIBUTES_ACCESS_ACL)) {
return 0;
}
+ /* Directories can have default ACLs too */
+ if (ff_pkt->type == FT_DIREND && (BACL_CAP & BACL_CAP_DEFAULTS_DIR)) {
+ if (!read_and_send_acl(jcr, BACL_TYPE_DEFAULT, STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL)) {
+ return 0;
+ }
+ }
}
#endif
/* List of all hard linked files found */
struct f_link *linklist; /* hard linked files */
- /* Darwin specific things. So as not to clutter every bclose()
- * with an #ifdef, we always include rsrc_bfd */
+ /* Darwin specific things.
+ * To avoid clutter, we always include rsrc_bfd and volhas_attrlist */
BFILE rsrc_bfd; /* fd for resource forks */
+ bool volhas_attrlist; /* Volume supports getattrlist() */
#ifdef HAVE_DARWIN_OS
struct HFSPLUS_INFO hfsinfo; /* Finder Info and resource fork size */
#endif
return accept;
}
+/*
+ * This function determines whether we can use getattrlist()
+ * It's odd, but we have to use the function to determine that...
+ * Also, the man pages talk about things as if they were implemented.
+ *
+ * On Mac OS X, this succesfully differentiates between HFS+ and UFS
+ * volumes, which makes me trust it is OK for others, too.
+ */
+static bool volume_has_attrlist(const char *fname)
+{
+#ifdef HAVE_DARWIN_OS
+ struct statfs st;
+ struct volinfo_struct {
+ unsigned long length; /* Mandatory field */
+ vol_capabilities_attr_t info; /* Volume capabilities */
+ } vol;
+ struct attrlist attrList;
+
+ memset(&attrList, 0, sizeof(attrList));
+ attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
+ attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES;
+ if (statfs(fname, &st) == 0) {
+ /* We need to check on the mount point */
+ if (getattrlist(st.f_mntonname, &attrList, &vol, sizeof(vol), FSOPT_NOFOLLOW) == 0
+ && (vol.info.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)
+ && (vol.info.valid[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)) {
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
/*
* Find a single file.
* handle_file is the callback for handling the file.
/*
* We check for allowed fstypes at top_level and fstype change (below).
*/
- if (top_level && !accept_fstype(ff_pkt, NULL)) {
- ff_pkt->type = FT_INVALIDFS;
- if (ff_pkt->flags & FO_KEEPATIME) {
- utime(fname, &restore_times);
+ if (top_level) {
+ if (!accept_fstype(ff_pkt, NULL)) {
+ ff_pkt->type = FT_INVALIDFS;
+ if (ff_pkt->flags & FO_KEEPATIME) {
+ utime(fname, &restore_times);
+ }
+ Jmsg1(jcr, M_ERROR, 0, _("Top level directory \"%s\" has an unlisted fstype\n"), fname);
+ return 1; /* Just ignore this error - or the whole backup is cancelled */
}
- Jmsg1(jcr, M_ERROR, 0, _("Top level directory \"%s\" has an unlisted fstype\n"), fname);
- return 1; /* Just ignore this error - or the whole backup is cancelled */
+ ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
}
/*
}
#ifdef HAVE_DARWIN_OS
- if (S_ISREG(ff_pkt->statp.st_mode) && ff_pkt->flags & FO_HFSPLUS) {
+ if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->volhas_attrlist
+ && S_ISREG(ff_pkt->statp.st_mode)) {
/* TODO: initialise attrList once elsewhere? */
struct attrlist attrList;
memset(&attrList, 0, sizeof(attrList));
attrList.commonattr = ATTR_CMN_FNDRINFO;
attrList.fileattr = ATTR_FILE_RSRCLENGTH;
if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo,
- sizeof(ff_pkt->hfsinfo), 0) != 0) {
+ sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
ff_pkt->type = FT_NOSTAT;
ff_pkt->ff_errno = errno;
return handle_file(ff_pkt, pkt);
int status;
dev_t our_device = ff_pkt->statp.st_dev;
bool recurse = true;
+ bool volhas_attrlist = ff_pkt->volhas_attrlist; /* Remember this if we recurse */
/*
* If we are using Win32 (non-portable) backup API, don't check
} else if (!accept_fstype(ff_pkt, NULL)) {
ff_pkt->type = FT_INVALIDFS;
recurse = false;
+ } else {
+ ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
}
}
+ /* If not recursing, just backup dir and return */
if (!recurse) {
rtn_stat = handle_file(ff_pkt, pkt);
if (ff_pkt->linked) {
if (ff_pkt->flags & FO_KEEPATIME) {
utime(fname, &restore_times);
}
+ ff_pkt->volhas_attrlist = volhas_attrlist; /* Restore value in case it changed. */
return rtn_stat;
} /* end check for directory */