/* Define if you have zlib */
#undef HAVE_LIBZ
+/* Define if you have libacl */
+#undef HAVE_ACL
+
/* General libs */
#undef LIBS
/* Define if you have zlib */
#undef HAVE_LIBZ
+/* Define if you have libacl */
+#undef HAVE_ACL
+
/* General libs */
#undef LIBS
have_zlib=yes
fi
+AC_CHECK_HEADER(sys/acl.h)
+AC_CHECK_LIB(acl, acl_get_file, [FDLIBS="-lacl $FDLIBS"])
+have_acl=no
+if test $ac_cv_lib_acl_acl_get_file = yes; then
+ AC_DEFINE(HAVE_ACL)
+ have_acl=yes
+fi
+
dnl Check for pthread libraries
PTHREAD_LIB=""
AC_CHECK_LIB(pthread, pthread_create, PTHREAD_LIB="-lpthread",
enable-gnome: ${support_gnome} ${gnome_version}
enable-wx-console: ${support_wx_console}
client-only: ${build_client_only}
+ ACL support: ${have_acl}
" > config.out
have_zlib=yes
fi
+if test "${ac_cv_header_sys_acl_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for sys/acl.h" >&5
+echo $ECHO_N "checking for sys/acl.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_acl_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_acl_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_acl_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking sys/acl.h usability" >&5
+echo $ECHO_N "checking sys/acl.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <sys/acl.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking sys/acl.h presence" >&5
+echo $ECHO_N "checking sys/acl.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/acl.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: sys/acl.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: sys/acl.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/acl.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/acl.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: sys/acl.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: sys/acl.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/acl.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: sys/acl.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/acl.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/acl.h: proceeding with the preprocessor's result" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to bug-autoconf@gnu.org. ##
+## ------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for sys/acl.h" >&5
+echo $ECHO_N "checking for sys/acl.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_acl_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_sys_acl_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_acl_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_acl_h" >&6
+
+fi
+
+
+echo "$as_me:$LINENO: checking for acl_get_file in -lacl" >&5
+echo $ECHO_N "checking for acl_get_file in -lacl... $ECHO_C" >&6
+if test "${ac_cv_lib_acl_acl_get_file+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lacl $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char acl_get_file ();
+int
+main ()
+{
+acl_get_file ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_acl_acl_get_file=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_acl_acl_get_file=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_acl_acl_get_file" >&5
+echo "${ECHO_T}$ac_cv_lib_acl_acl_get_file" >&6
+if test $ac_cv_lib_acl_acl_get_file = yes; then
+ FDLIBS="-lacl $FDLIBS"
+fi
+
+have_acl=no
+if test $ac_cv_lib_acl_acl_get_file = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_ACL 1
+_ACEOF
+
+ have_acl=yes
+fi
+
PTHREAD_LIB=""
echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5
echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6
enable-gnome: ${support_gnome} ${gnome_version}
enable-wx-console: ${support_wx_console}
client-only: ${build_client_only}
+ ACL support: ${have_acl}
" > config.out
#define STREAM_WIN32_GZIP_DATA 12 /* Gzipped Win32 BackupRead data */
#define STREAM_MACOS_FORK_DATA 13 /* Mac resource fork */
#define STREAM_HFSPLUS_ATTRIBUTES 14 /* Mac OS extra attributes */
+#define STREAM_UNIX_ATTRIBUTES_ACL 15 /* ACL attributes on UNIX */
/*
* File type (Bacula defined).
*/
Dmsg1(200, "catreq %s", bs->msg);
if (sscanf(bs->msg, Find_media, &Job, &index) == 2) {
- ok = find_next_volume_for_append(jcr, &mr, TRUE /*permit create new vol*/);
+ ok = find_next_volume_for_append(jcr, &mr, true /*permit create new vol*/);
/*
* Send Find Media response to Storage daemon
*/
INC_KW_PORTABLE,
INC_KW_MTIMEONLY,
INC_KW_KEEPATIME,
- INC_KW_EXCLUDE
+ INC_KW_EXCLUDE,
+ INC_KW_ACL
};
/*
{"mtimeonly", INC_KW_MTIMEONLY},
{"keepatime", INC_KW_KEEPATIME},
{"exclude", INC_KW_EXCLUDE},
+ {"aclsupport", INC_KW_ACL},
{NULL, 0}
};
{"no", INC_KW_KEEPATIME, "0"},
{"yes", INC_KW_EXCLUDE, "e"},
{"no", INC_KW_EXCLUDE, "0"},
+ {"yes", INC_KW_ACL, "A"},
+ {"no", INC_KW_ACL, "0"},
{NULL, 0, 0}
};
/*
* Automatic Volume name creation using the LabelFormat
*/
-int newVolume(JCR *jcr, MEDIA_DBR *mr)
+bool newVolume(JCR *jcr, MEDIA_DBR *mr)
{
POOL_DBR pr;
db_unlock(jcr->db);
Jmsg(jcr, M_INFO, 0, _("Created new Volume \"%s\" in catalog.\n"), mr->VolumeName);
Dmsg1(90, "Created new Volume=%s\n", mr->VolumeName);
- return 1;
+ return true;
} else {
Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
}
}
bail_out:
db_unlock(jcr->db);
- return 0;
+ return false;
}
static int create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr)
* MEDIA_DBR mr (zeroed out)
* create -- whether or not to create a new volume
*/
-int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int create)
+int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, bool create)
{
int retry = 0;
bool ok;
extern void wait_for_storage_daemon_termination(JCR *jcr);
/* next_vol.c */
-int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int create);
+int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, bool create);
bool has_volume_expired(JCR *jcr, MEDIA_DBR *mr);
void check_if_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, char **reason);
/* newvol.c */
-int newVolume(JCR *jcr, MEDIA_DBR *mr);
+bool newVolume(JCR *jcr, MEDIA_DBR *mr);
/* ua_acl.c */
bool acl_access_ok(UAContext *ua, int acl, char *item);
#include "bacula.h"
#include "filed.h"
+#ifdef HAVE_ACL
+#include <sys/acl.h>
+#include <acl/libacl.h>
+#endif
+
static int save_file(FF_PKT *ff_pkt, void *pkt);
/*
return 0;
}
}
+
+#ifdef HAVE_ACL
+ /* ACL stream */
+ if(ff_pkt->flags & FO_ACL) {
+ char *acl_text;
+ /* Read ACLs for files, dirs and links */
+ if(ff_pkt->type == FT_DIREND) {
+ /* Directory: Try for default ACL*/
+ acl_t myAcl = acl_get_file(ff_pkt->fname, ACL_TYPE_DEFAULT);
+ if(!myAcl) {
+ Dmsg1(200, "No default ACL defined for directory: %s!\n", ff_pkt->fname);
+ /* If there is no default ACL get standard ACL */
+ myAcl = acl_get_file(ff_pkt->fname, ACL_TYPE_ACCESS);
+ if(!myAcl) {
+ Emsg1(M_WARNING, 0, "Error while trying to get ACL of directory: %s!\n", ff_pkt->fname);
+ }
+ }
+ acl_text = acl_to_any_text(myAcl, NULL, ',', TEXT_ABBREVIATE);
+ /* Free memory */
+ acl_free(myAcl);
+ } else {
+ /* Files or links */
+ acl_t myAcl = acl_get_file(ff_pkt->fname, ACL_TYPE_ACCESS);
+ if(!myAcl) {
+ Emsg1(M_WARNING, 0, "Error while trying to get ACL of file: %s!\n", ff_pkt->fname);
+ acl_free(myAcl);
+ }
+ acl_text = acl_to_any_text(myAcl, NULL, ',', TEXT_ABBREVIATE);
+ acl_free(myAcl);
+ }
+
+ /* Send stream to server */
+ sd = jcr->store_bsock;
+ char *rbuf, *wbuf;
+ int rsize = jcr->buf_size;
+
+ msgsave = sd->msg;
+ rbuf = sd->msg;
+ wbuf = sd->msg;
+
+ pm_strcpy(&jcr->last_fname, ff_pkt->fname);
+
+ /*
+ * Send ACL header
+ *
+ */
+ if(!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES_ACL)) {
+ set_jcr_job_status(jcr, JS_ErrorTerminated);
+ return 0;
+ }
+
+ /* Make space at beginning of buffer for fileAddr */
+ if(ff_pkt->flags & FO_SPARSE) {
+ rbuf += SPARSE_FADDR_SIZE;
+ rsize -= SPARSE_FADDR_SIZE;
+ }
+
+ /* Send the buffer to the storage deamon */
+ if(ff_pkt->flags & FO_SPARSE) {
+ sd->msglen += SPARSE_FADDR_SIZE;
+ }
+ sd->msg = acl_text;
+ sd->msglen += strlen(acl_text);
+ if(!bnet_send(sd)) {
+ sd->msg = msgsave;
+ sd->msglen = 0;
+ bclose(&ff_pkt->bfd);
+ set_jcr_job_status(jcr, JS_ErrorTerminated);
+ Emsg1(M_WARNING, 0, "Error while trying to send ACL of %s to SD!\n", ff_pkt->fname);
+ } else {
+ jcr->JobBytes += sd->msglen;
+ sd->msg = msgsave;
+ bclose(&ff_pkt->bfd);
+ if(!bnet_sig(sd, BNET_EOD)) {
+ set_jcr_job_status(jcr, JS_ErrorTerminated);
+ } else {
+ Dmsg1(200, "ACL of file: %s successfully backed up!\n", ff_pkt->fname);
+ }
+ }
+ }
+#endif
/* Terminate any MD5 signature and send it to Storage daemon and the Director */
if (gotMD5 && ff_pkt->flags & FO_MD5) {
/* Try to connect for 1 hour at 10 second intervals */
sd = bnet_connect(jcr, 10, me->SDConnectTimeout, _("Storage daemon"),
jcr->stored_addr, NULL, stored_port, 1);
+ Dmsg0(110, "Connection OK to SD.\n");
if (sd == NULL) {
Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
jcr->stored_addr, stored_port);
#include "bacula.h"
#include "filed.h"
+#ifdef HAVE_ACL
+#include <sys/acl.h>
+#include <acl/libacl.h>
+#endif
+
/* Data received from Storage Daemon */
static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
uint64_t fileAddr = 0; /* file write address */
int non_support_data = 0;
int non_support_attr = 0;
+ int non_support_acl = 0;
int prog_name_msg = 0;
ATTR *attr;
-
+#ifdef HAVE_ACL
+ acl_t acl;
+#endif
binit(&bfd);
sd = jcr->store_bsock;
#endif
break;
+#ifdef HAVE_ACL
+ case STREAM_UNIX_ATTRIBUTES_ACL:
+ /* Recover ACL from stream and check it */
+ acl = acl_from_text(sd->msg);
+ if(acl_valid(acl) != 0) {
+ Emsg1(M_WARNING, 0, "Failure in the ACL of %s! FD is not able to restore it!\n", jcr->last_fname);
+ acl_free(acl);
+ }
+
+ /* Try to restore ACL */
+ if(attr->type == FT_DIREND) {
+ /* Directory */
+ if(acl_set_file(jcr->last_fname, ACL_TYPE_DEFAULT, acl) != 0) {
+ if(acl_set_file(jcr->last_fname, ACL_TYPE_ACCESS, acl) != 0) {
+ Emsg1(M_WARNING, 0, "Error! Can't restore ACL of directory: %s! Maybe system does not support ACLs!\n", jcr->last_fname);
+ }
+ }
+ } else {
+ /* File or Link */
+ if(acl_set_file(jcr->last_fname, ACL_TYPE_ACCESS, acl) != 0) {
+ Emsg1(M_WARNING, 0, "Error! Can't restore ACL of file: %s! Maybe system does not support ACLs!\n", jcr->last_fname);
+ }
+ }
+ acl_free(acl);
+ Dmsg1(200, "ACL of file: %s successfully restored!", jcr->last_fname);
+ break;
+#else
+ case STREAM_UNIX_ATTRIBUTES_ACL:
+ non_support_acl++;
+ break; /* unconfigured, ignore */
+#endif
+
case STREAM_MD5_SIGNATURE:
case STREAM_SHA1_SIGNATURE:
break;
Jmsg(jcr, M_ERROR, 0, _("%d non-supported data streams and %d non-supported attrib streams ignored.\n"),
non_support_data, non_support_attr);
}
+ if (non_support_acl) {
+ Jmsg(jcr, M_INFO, 0, _("%d non-supported acl streams ignored.\n"), non_support_acl);
+ }
+
}
#ifdef HAVE_LIBZ
#define FO_MTIMEONLY (1<<11) /* Use mtime rather than mtime & ctime */
#define FO_KEEPATIME (1<<12) /* Reset access time */
#define FO_EXCLUDE (1<<13) /* Exclude file */
+#define FO_ACL (1<<14) /* Backup ACLs */
struct s_included_file {
struct s_included_file *next;
case 'w':
inc->options |= FO_IF_NEWER;
break;
- case 'Z': /* gzip compression */
+ case 'A':
+ inc->options |= FO_ACL;
+ break;
+ case 'Z': /* gzip compression */
inc->options |= FO_GZIP;
inc->level = *++p - '0';
Dmsg1(200, "Compression level=%d\n", inc->level);