From: Kern Sibbald Date: Tue, 1 Feb 2005 10:01:30 +0000 (+0000) Subject: Merge Preben's patch for ACLs and for Mac OS X resource forks. X-Git-Tag: Release-1.38.0~656 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=4e105f45d5cced47cd25a20cc647d8d5ea15144f;p=bacula%2Fbacula Merge Preben's patch for ACLs and for Mac OS X resource forks. - Some doc updates. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1808 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/filed/acl.c b/bacula/src/filed/acl.c index e9e093f286..d16f5795b7 100644 --- a/bacula/src/filed/acl.c +++ b/bacula/src/filed/acl.c @@ -51,6 +51,7 @@ * * For a list of compiler flags, see the list preceding the big #if below. */ +#include #include #include #include @@ -175,9 +176,16 @@ int bacl_get(JCR *jcr, int acltype) 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? *****/ @@ -234,6 +242,9 @@ int bacl_get(JCR *jcr, int acltype) 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) { @@ -274,15 +285,18 @@ int bacl_get(JCR *jcr, int acltype) 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; @@ -436,6 +450,7 @@ int aclcp(char *src, char *dst) int aclls(char *fname) { struct stat st; + int len; if (lstat(fname, &st) != 0) { Dmsg0(200, "acl: source does not exist\n"); @@ -448,18 +463,26 @@ int aclls(char *fname) 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; diff --git a/bacula/src/filed/acl.h b/bacula/src/filed/acl.h index 44b46c0c0a..2d5676f24d 100644 --- a/bacula/src/filed/acl.h +++ b/bacula/src/filed/acl.h @@ -5,10 +5,10 @@ #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 */ @@ -20,16 +20,27 @@ #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 diff --git a/bacula/src/filed/backup.c b/bacula/src/filed/backup.c index 1508cf8687..de5de2e02e 100644 --- a/bacula/src/filed/backup.c +++ b/bacula/src/filed/backup.c @@ -341,7 +341,7 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) } #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) { @@ -379,15 +379,17 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) #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 diff --git a/bacula/src/findlib/find.h b/bacula/src/findlib/find.h index cf35bd589a..24107519be 100755 --- a/bacula/src/findlib/find.h +++ b/bacula/src/findlib/find.h @@ -202,9 +202,10 @@ struct FF_PKT { /* 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 diff --git a/bacula/src/findlib/find_one.c b/bacula/src/findlib/find_one.c index d3516d37fe..90709c47ee 100755 --- a/bacula/src/findlib/find_one.c +++ b/bacula/src/findlib/find_one.c @@ -88,6 +88,39 @@ static int accept_fstype(FF_PKT *ff, void *dummy) { 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. @@ -124,13 +157,16 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), /* * 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); } /* @@ -151,7 +187,8 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), } #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)); @@ -159,7 +196,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), 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); @@ -276,6 +313,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), 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 @@ -370,8 +408,11 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), } 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) { @@ -466,6 +507,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), 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 */