From f4891446832bfaaadc8b7f7a0f9a6974ae961110 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Wed, 26 Nov 2008 12:58:18 +0000 Subject: [PATCH] kes Apply Marco's Extended attribute support patch. kes Update projects file git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@8084 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/autoconf/config.h.in | 19 + bacula/autoconf/config.h.in.save | 19 + bacula/autoconf/configure.in | 141 +++- bacula/projects | 164 ++-- bacula/src/baconfig.h | 90 ++- bacula/src/dird/inc_conf.c | 11 +- bacula/src/filed/Makefile.in | 2 +- bacula/src/filed/acl.c | 1244 ++++++++++++++++++++++-------- bacula/src/filed/acl.h | 40 +- bacula/src/filed/backup.c | 87 +-- bacula/src/filed/job.c | 3 + bacula/src/filed/protos.h | 8 +- bacula/src/filed/restore.c | 62 +- bacula/src/filed/status.c | 4 +- bacula/src/findlib/bfile.c | 34 + bacula/src/findlib/find.h | 1 + bacula/src/findlib/match.c | 3 + bacula/src/jcr.h | 5 +- bacula/src/lib/mem_pool.c | 50 +- bacula/src/lib/mem_pool.h | 5 +- bacula/src/stored/bscan.c | 27 +- bacula/src/tools/testfind.c | 3 + bacula/src/version.h | 6 +- bacula/technotes-2.5 | 3 + 24 files changed, 1427 insertions(+), 604 deletions(-) diff --git a/bacula/autoconf/config.h.in b/bacula/autoconf/config.h.in index d015a65f05..e0f50d210b 100644 --- a/bacula/autoconf/config.h.in +++ b/bacula/autoconf/config.h.in @@ -152,12 +152,31 @@ /* Define if you have zlib */ #undef HAVE_LIBZ +/* Defines if your system have the sys/acl.h header file */ +#undef HAVE_SYS_ACL_H + /* Define if you have libacl */ #undef HAVE_ACL /* Define if you have extended acls */ #undef HAVE_EXTENDED_ACL +/* Defines if your system have the sys/xattr.h header file */ +#undef HAVE_SYS_XATTR_H + +/* Define if you have extended attributes */ +#undef HAVE_XATTR + +/* Define when you have extended attributes functions starting with l (like lstat) */ +#undef HAVE_LLISTXATTR +#undef HAVE_LGETXATTR +#undef HAVE_LSETXATTR + +/* Define when you have extended attributes functions not starting with l (like stat) */ +#undef HAVE_LISTXATTR +#undef HAVE_GETXATTR +#undef HAVE_SETXATTR + /* General libs */ #undef LIBS diff --git a/bacula/autoconf/config.h.in.save b/bacula/autoconf/config.h.in.save index d015a65f05..e0f50d210b 100644 --- a/bacula/autoconf/config.h.in.save +++ b/bacula/autoconf/config.h.in.save @@ -152,12 +152,31 @@ /* Define if you have zlib */ #undef HAVE_LIBZ +/* Defines if your system have the sys/acl.h header file */ +#undef HAVE_SYS_ACL_H + /* Define if you have libacl */ #undef HAVE_ACL /* Define if you have extended acls */ #undef HAVE_EXTENDED_ACL +/* Defines if your system have the sys/xattr.h header file */ +#undef HAVE_SYS_XATTR_H + +/* Define if you have extended attributes */ +#undef HAVE_XATTR + +/* Define when you have extended attributes functions starting with l (like lstat) */ +#undef HAVE_LLISTXATTR +#undef HAVE_LGETXATTR +#undef HAVE_LSETXATTR + +/* Define when you have extended attributes functions not starting with l (like stat) */ +#undef HAVE_LISTXATTR +#undef HAVE_GETXATTR +#undef HAVE_SETXATTR + /* General libs */ #undef LIBS diff --git a/bacula/autoconf/configure.in b/bacula/autoconf/configure.in index de0de1d711..6e413a01f0 100644 --- a/bacula/autoconf/configure.in +++ b/bacula/autoconf/configure.in @@ -124,7 +124,7 @@ dnl -------------------------------------------------- dnl Libtool config dnl -------------------------------------------------- AC_ARG_ENABLE(libtool, - AC_HELP_STRING([--enable-libtool], [enable building using GNU libtool @<:@default=yes@:>@]), + AC_HELP_STRING([--disable-libtool], [disable building using GNU libtool @<:@default=no@:>@]), [ if test x$enableval = xno; then use_libtool=no @@ -227,7 +227,24 @@ if test x${prefix} = xNONE ; then fi if test `eval echo ${libdir}` = NONE/lib ; then - libdir=/usr/lib + # + # Some platforms have other defaults (for 64 bits libs) + # + case `uname -s` in + Linux) + case `uname -m` in + x86_64) + libdir=/usr/lib64 + ;; + *) + libdir=/usr/lib + ;; + esac + ;; + *) + libdir=/usr/lib + ;; + esac fi if test `eval echo ${includedir}` = NONE/include ; then @@ -1149,7 +1166,7 @@ AC_ARG_WITH(scriptdir, AC_SUBST(scriptdir) # ------------------------------------------ -# Where to place plugindir (script files) +# Where to place plugindir (plugin files) # ------------------------------------------ plugindir=`eval echo ${sysconfdir}` AC_ARG_WITH(plugindir, @@ -2204,43 +2221,105 @@ if test x$FDLIBS = x-lz; then fi dnl -dnl Check for ACL libraries +dnl Check for ACL support and libraries dnl +support_acl=yes +AC_ARG_ENABLE(acl, + AC_HELP_STRING([--disable-acl], [disable acl support @<:@default=auto@:>@]), + [ + if test x$enableval = xno; then + support_acl=no + fi + ] +) + have_acl=no have_extended_acl=no -AC_CHECK_HEADER(sys/acl.h) -AC_CHECK_FUNC(acl_get_file, [have_acl=yes], +if test x$support_acl = xyes; then + AC_CHECK_HEADER(sys/acl.h, [ AC_DEFINE(HAVE_SYS_ACL_H,1,[Defines if your system have the sys/acl.h header file])] , ) + AC_CHECK_FUNC(acl_get_file, + [ + have_acl=yes + ], [ + AC_CHECK_LIB(acl, acl_get_file, + [ + have_acl=yes; + FDLIBS="-lacl $FDLIBS" + ], [ + AC_CHECK_LIB(pacl, acl_get_file, + [ + have_acl=yes; + FDLIBS="-lpacl $FDLIBS" + ], [ + AC_CHECK_LIB(sec, acltotext, + [ + have_acl=yes; + FDLIBS="-lsec $FDLIBS" + + AC_CHECK_LIB(sec, acl_totext, + [ + have_extended_acl=yes + ] + ) + ] + ) + ] + ) + ] + ) + ] + ) + if test $have_acl = yes; then + AC_DEFINE(HAVE_ACL) + fi + + if test $have_extended_acl = yes; then + AC_DEFINE(HAVE_EXTENDED_ACL) + fi +fi + +dnl +dnl Check for XATTR support +dnl +support_xattr=yes +AC_ARG_ENABLE(xattr, + AC_HELP_STRING([--disable-xattr], [disable xattr support @<:@default=auto@:>@]), [ - AC_CHECK_LIB(acl, acl_get_file, - [ - have_acl=yes; - FDLIBS="-lacl $FDLIBS" - ], [ - AC_CHECK_LIB(sec, acltotext, - [ - have_acl=yes; - FDLIBS="-lsec $FDLIBS" - - AC_CHECK_LIB(sec, acl_totext, - [ - have_extended_acl=yes - ] - ) - ] - ) - ] - ) + if test x$enableval = xno; then + support_acl=no + fi ] ) -if test $have_acl = yes; then - AC_DEFINE(HAVE_ACL) -fi -if test $have_extended_acl = yes; then - AC_DEFINE(HAVE_EXTENDED_ACL) +have_xattr=no +if test x$support_xattr = xyes; then + AC_CHECK_HEADER(sys/xattr.h, [ AC_DEFINE(HAVE_SYS_XATTR_H,1,[Defines if your system have the sys/xattr.h header file])] , ) + AC_CHECK_FUNCS(llistxattr lgetxattr lsetxattr, + [ + have_xattr=yes + AC_DEFINE(HAVE_LLISTXATTR) + AC_DEFINE(HAVE_LGETXATTR) + AC_DEFINE(HAVE_LSETXATTR) + ], [ + AC_CHECK_FUNCS(listxattr getxattr setxattr, + [ + have_xattr=yes + AC_DEFINE(HAVE_LISTXATTR) + AC_DEFINE(HAVE_GETXATTR) + AC_DEFINE(HAVE_SETXATTR) + ] + ) + ] + ) + + if test $have_xattr = yes; then + AC_DEFINE(HAVE_XATTR) + fi fi +dnl dnl Check for pthread libraries +dnl PTHREAD_LIB="" AC_CHECK_LIB(pthread, pthread_create, PTHREAD_LIB="-lpthread", [ @@ -2861,6 +2940,7 @@ Configuration on `date`: Subsys directory: ${subsysdir} Man directory: ${mandir} Data directory: ${datarootdir} + Plugin directory: ${plugindir} C Compiler: ${CC} ${CCVERSION} C++ Compiler: ${CXX} ${CXXVERSION} Compiler flags: ${WCFLAGS} ${CFLAGS} @@ -2910,6 +2990,7 @@ Configuration on `date`: build-dird: ${build_dird} build-stored: ${build_stored} ACL support: ${have_acl} + XATTR support: ${have_xattr} Python support: ${support_python} ${PYTHON_LIBS} Batch insert enabled: ${support_batch_insert} diff --git a/bacula/projects b/bacula/projects index b41e63e315..7da1727b7b 100644 --- a/bacula/projects +++ b/bacula/projects @@ -1,29 +1,32 @@ Projects: Bacula Projects Roadmap - Status updated 26 August 2008 + Status updated 26 November 2008 Items Completed: - -Summary: Item 1: Accurate restoration of renamed/deleted files -Item 2: Allow FD to initiate a backup Item 3: Merge multiple backups (Synthetic Backup or Consolidation) Item 4: Implement Catalog directive for Pool resource in Director Item 5: Add an item to the restore option where you can select a Pool +Item 8: Implement Copy pools +Item 12: Add Plug-ins to the FileSet Include statements. +Item 13: Restore only file attributes (permissions, ACL, owner, group...) +Item 18: Better control over Job execution +Item 26: Store and restore extended attributes, especially selinux file contexts +Item 27: make changing "spooldata=yes|no" possible for +Item 28: Implement an option to modify the last written date for volumes + +Summary: +Item 2: Allow FD to initiate a backup Item 6: Deletion of disk Volumes when pruned Item 7: Implement Base jobs -Item 8: Implement Copy pools Item 9: Scheduling syntax that permits more flexibility and options Item 10: Message mailing based on backup types Item 11: Cause daemons to use a specific IP address to source communications -Item 12: Add Plug-ins to the FileSet Include statements. -Item 13: Restore only file attributes (permissions, ACL, owner, group...) Item 14: Add an override in Schedule for Pools based on backup types -Item 15: Implement more Python events and functions +Item 15: Implement more Python events and functions --- Abandoned for plugins Item 16: Allow inclusion/exclusion of files in a fileset by creation/mod times Item 17: Automatic promotion of backup levels based on backup size -Item 18: Better control over Job execution Item 19: Automatic disabling of devices Item 20: An option to operate on all pools with update vol parameters Item 21: Include timestamp of job launch in "stat clients" output @@ -36,7 +39,7 @@ Item 25: Archival (removal) of User Files to Tape Item 1: Accurate restoration of renamed/deleted files Date: 28 November 2005 Origin: Martin Simmons (martin at lispworks dot com) - Status: + Status: Done What: When restoring a fileset for a specified date (including "most recent"), Bacula should give you exactly the files and directories @@ -81,7 +84,7 @@ Item 2: Allow FD to initiate a backup Item 3: Merge multiple backups (Synthetic Backup or Consolidation) Origin: Marc Cousin and Eric Bollengier Date: 15 November 2005 - Status: + Status: Done What: A merged backup is a backup made without connecting to the Client. It would be a Merge of existing backups into a single backup. @@ -116,7 +119,7 @@ Item 3: Merge multiple backups (Synthetic Backup or Consolidation) Item 4: Implement Catalog directive for Pool resource in Director Origin: Alan Davis adavis@ruckus.com Date: 6 March 2007 - Status: Submitted + Status: Done, but not tested, and possibly not fully implemented. What: The current behavior is for the director to create all pools found in the configuration file in all catalogs. Add a @@ -134,7 +137,7 @@ Item 4: Implement Catalog directive for Pool resource in Director Item 5: Add an item to the restore option where you can select a Pool Origin: kshatriyak at gmail dot com Date: 1/1/2006 - Status: + Status: Done at least via command line What: In the restore option (Select the most recent backup for a client) it would be useful to add an option where you can limit @@ -219,7 +222,7 @@ Item 7: Implement Base jobs Item 8: Implement Copy pools Date: 27 November 2005 Origin: David Boyes (dboyes at sinenomine dot net) - Status: + Status: A trivial version of this is done. What: I would like Bacula to have the capability to write copies of backed-up data on multiple physical volumes selected @@ -540,7 +543,7 @@ Status: Item 15: Implement more Python events and functions Date: 28 October 2005 Origin: Kern - Status: + Status: Project abandoned in favor of plugins. What: Allow Python scripts to be called at more places within Bacula and provide additional access to Bacula @@ -852,7 +855,73 @@ Item 25: Archival (removal) of User Files to Tape storage pool gets full) data is migrated to Tape. +Item 26: Store and restore extended attributes, especially selinux file contexts + Date: 28 December 2007 + Origin: Frank Sweetser + Status: Done + What: The ability to store and restore extended attributes on + filesystems that support them, such as ext3. + Why: Security Enhanced Linux (SELinux) enabled systems make extensive + use of extended attributes. In addition to the standard user, + group, and permission, each file has an associated SELinux context + stored as an extended attribute. This context is used to define + which operations a given program is permitted to perform on that + file. Storing contexts on an SELinux system is as critical as + storing ownership and permissions. In the case of a full system + restore, the system will not even be able to boot until all + critical system files have been properly relabeled. + + Notes: Fedora ships with a version of tar that has been patched to handle + extended attributes. The patch has not been integrated upstream + yet, so could serve as a good starting point. + + http://linux.die.net/man/2/getxattr + http://linux.die.net/man/2/setxattr + http://linux.die.net/man/2/listxattr + === + http://linux.die.net/man/3/getfilecon + http://linux.die.net/man/3/setfilecon + +Item 27: make changing "spooldata=yes|no" possible for + manual/interactive jobs + Origin: Marc Schiffbauer + Date: 12 April 2007) + Status: Done + + What: Make it possible to modify the spooldata option + for a job when being run from within the console. + Currently it is possible to modify the backup level + and the spooldata setting in a Schedule resource. + It is also possible to modify the backup level when using + the "run" command in the console. + But it is currently not possible to to the same + with "spooldata=yes|no" like: + + run job=MyJob level=incremental spooldata=yes + + Why: In some situations it would be handy to be able to switch + spooldata on or off for interactive/manual jobs based on + which data the admin expects or how fast the LAN/WAN + connection currently is. + + Notes: ./. + +Item 28: Implement an option to modify the last written date for volumes +Date: 16 September 2008 +Origin: Franck (xeoslaenor at gmail dot com) +Status: Done +What: The ability to modify the last written date for a volume +Why: It's sometime necessary to jump a volume when you have a pool of volume + which recycles the oldest volume at each backup. + Sometime, it needs to cancel a set of backup (one day + backup, completely) and we want to avoid that bacula + choose the volume (which is not written at all) from + the cancelled backup (It has to jump to next volume). + in this case, we just need to update the written date + manually to avoir the "oldest volume" purge. +Notes: An option can be add to "update volume" command (like 'written date' + choice for example) ========= New Items since the last vote ================= @@ -933,32 +1002,6 @@ Item 1: Implement an interface between Bacula and Amazon's S3. locally and syncing them to S3, and manually fetching them again when they're needed. This is very cumbersome. -Item: Store and restore extended attributes, especially selinux file contexts - Date: 28 December 2007 - Origin: Frank Sweetser - What: The ability to store and restore extended attributes on - filesystems that support them, such as ext3. - - Why: Security Enhanced Linux (SELinux) enabled systems make extensive - use of extended attributes. In addition to the standard user, - group, and permission, each file has an associated SELinux context - stored as an extended attribute. This context is used to define - which operations a given program is permitted to perform on that - file. Storing contexts on an SELinux system is as critical as - storing ownership and permissions. In the case of a full system - restore, the system will not even be able to boot until all - critical system files have been properly relabeled. - - Notes: Fedora ships with a version of tar that has been patched to handle - extended attributes. The patch has not been integrated upstream - yet, so could serve as a good starting point. - - http://linux.die.net/man/2/getxattr - http://linux.die.net/man/2/setxattr - http://linux.die.net/man/2/listxattr - === - http://linux.die.net/man/3/getfilecon - http://linux.die.net/man/3/setfilecon Item 1: enable/disable compression depending on storage device (disk/tape) Origin: Ralf Gross ralf-lists@ralfgross.de @@ -1147,45 +1190,6 @@ Item X: Add EFS support on Windows encrypted-file-related callback functions. ========== Already implemented ================================ -Item n: make changing "spooldata=yes|no" possible for - manual/interactive jobs - Origin: Marc Schiffbauer - Date: 12 April 2007) - Status: - - What: Make it possible to modify the spooldata option - for a job when being run from within the console. - Currently it is possible to modify the backup level - and the spooldata setting in a Schedule resource. - It is also possible to modify the backup level when using - the "run" command in the console. - But it is currently not possible to to the same - with "spooldata=yes|no" like: - - run job=MyJob level=incremental spooldata=yes - - Why: In some situations it would be handy to be able to switch - spooldata on or off for interactive/manual jobs based on - which data the admin expects or how fast the LAN/WAN - connection currently is. - - Notes: ./. - -Item 1: Implement an option to modify the last written date for volumes -Date: 16 September 2008 -Origin: Franck (xeoslaenor at gmail dot com) -Status: Proposing -What: The ability to modify the last written date for a volume -Why: It's sometime necessary to jump a volume when you have a pool of volume - which recycles the oldest volume at each backup. - Sometime, it needs to cancel a set of backup (one day - backup, completely) and we want to avoid that bacula - choose the volume (which is not written at all) from - the cancelled backup (It has to jump to next volume). - in this case, we just need to update the written date - manually to avoir the "oldest volume" purge. -Notes: An option can be add to "update volume" command (like 'written date' - choice for example) ============= Empty Feature Request form =========== Item n: One line summary ... diff --git a/bacula/src/baconfig.h b/bacula/src/baconfig.h index ea97586501..16d6832e10 100644 --- a/bacula/src/baconfig.h +++ b/bacula/src/baconfig.h @@ -199,7 +199,7 @@ void InitWinAPIWrapper(); #define DEFAULT_NETWORK_BUFFER_SIZE (64 * 1024) /* - * Stream definitions. Once defined these must NEVER + * Stream definitions. Once defined these must NEVER * change as they go on the storage media. * Note, the following streams are passed from the SD to the DIR * so that they may be put into the catalog (actually only the @@ -218,10 +218,9 @@ void InitWinAPIWrapper(); #define STREAM_MD5_SIGNATURE 3 /* deprecated */ #define STREAM_MD5_DIGEST 3 /* MD5 digest for the file */ #define STREAM_GZIP_DATA 4 /* GZip compressed file data */ -/* Extended Unix attributes with Win32 Extended data. Deprecated. */ -#define STREAM_UNIX_ATTRIBUTES_EX 5 /* Extended Unix attr for Win32 EX */ +#define STREAM_UNIX_ATTRIBUTES_EX 5 /* Extended Unix attr for Win32 EX - Deprecated */ #define STREAM_SPARSE_DATA 6 /* Sparse data stream */ -#define STREAM_SPARSE_GZIP_DATA 7 +#define STREAM_SPARSE_GZIP_DATA 7 /* Sparse gzipped data stream */ #define STREAM_PROGRAM_NAMES 8 /* program names for program data */ #define STREAM_PROGRAM_DATA 9 /* Data needing program */ #define STREAM_SHA1_SIGNATURE 10 /* deprecated */ @@ -230,22 +229,75 @@ void InitWinAPIWrapper(); #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 */ -/*** FIXME ***/ -#define STREAM_UNIX_ACCESS_ACL 15 /* Standard ACL attributes on UNIX */ -#define STREAM_UNIX_DEFAULT_ACL 16 /* Default ACL attributes on UNIX */ -/*** FIXME ***/ -#define STREAM_SHA256_DIGEST 17 /* SHA-256 digest for the file */ -#define STREAM_SHA512_DIGEST 18 /* SHA-512 digest for the file */ -#define STREAM_SIGNED_DIGEST 19 /* Signed File Digest, ASN.1, DER Encoded */ -#define STREAM_ENCRYPTED_FILE_DATA 20 /* Encrypted, uncompressed data */ -#define STREAM_ENCRYPTED_WIN32_DATA 21 /* Encrypted, uncompressed Win32 BackupRead data */ -#define STREAM_ENCRYPTED_SESSION_DATA 22 /* Encrypted Session Data, ASN.1, DER Encoded */ -#define STREAM_ENCRYPTED_FILE_GZIP_DATA 23 /* Encrypted, compressed data */ -#define STREAM_ENCRYPTED_WIN32_GZIP_DATA 24 /* Encrypted, compressed Win32 BackupRead data */ -#define STREAM_ENCRYPTED_MACOS_FORK_DATA 25 /* Encrypted, uncompressed Mac resource fork */ -#define STREAM_PLUGIN_NAME 26 /* Plugin "file" string */ -#define STREAM_PLUGIN_DATA 27 /* Plugin specific data */ +#define STREAM_UNIX_ACCESS_ACL 15 /* Standard ACL attributes on UNIX - Deprecated */ +#define STREAM_UNIX_DEFAULT_ACL 16 /* Default ACL attributes on UNIX - Deprecated */ +#define STREAM_SHA256_DIGEST 17 /* SHA-256 digest for the file */ +#define STREAM_SHA512_DIGEST 18 /* SHA-512 digest for the file */ +#define STREAM_SIGNED_DIGEST 19 /* Signed File Digest, ASN.1, DER Encoded */ +#define STREAM_ENCRYPTED_FILE_DATA 20 /* Encrypted, uncompressed data */ +#define STREAM_ENCRYPTED_WIN32_DATA 21 /* Encrypted, uncompressed Win32 BackupRead data */ +#define STREAM_ENCRYPTED_SESSION_DATA 22 /* Encrypted Session Data, ASN.1, DER Encoded */ +#define STREAM_ENCRYPTED_FILE_GZIP_DATA 23 /* Encrypted, compressed data */ +#define STREAM_ENCRYPTED_WIN32_GZIP_DATA 24 /* Encrypted, compressed Win32 BackupRead data */ +#define STREAM_ENCRYPTED_MACOS_FORK_DATA 25 /* Encrypted, uncompressed Mac resource fork */ +#define STREAM_PLUGIN_NAME 26 /* Plugin "file" string */ +#define STREAM_PLUGIN_DATA 27 /* Plugin specific data */ +/* + * Additional Stream definitions. Once defined these must NEVER + * change as they go on the storage media. + * + * The Stream numbers from 1000-1999 are reserved for ACL and extended attribute streams. + * Each different platform has its own stream id(s), if a platform supports multiple stream types + * it should supply different handlers for each type it supports and this should be called + * from the stream dispatch function. Currently in this reserved space we allocate the + * different acl streams from 1000 on and the different extended attributes streams from + * 1999 down. So the two naming spaces grows towards each other. + */ +#define STREAM_ACL_AIX_TEXT 1000 /* AIX specific string representation from acl_get */ +#define STREAM_ACL_DARWIN_ACCESS_ACL_T 1001 /* Darwin (OSX) specific acl_t string representation + * from acl_to_text (POSIX acl) + */ +#define STREAM_ACL_FREEBSD_DEFAULT_ACL_T 1002 /* FreeBSD specific acl_t string representation + * from acl_to_text (POSIX acl) for default acls. + */ +#define STREAM_ACL_FREEBSD_ACCESS_ACL_T 1003 /* FreeBSD specific acl_t string representation + * from acl_to_text (POSIX acl) for access acls. + */ +#define STREAM_ACL_HPUX_ACL_ENTRY 1004 /* HPUX specific acl_entry string representation + * from acltostr (POSIX acl) + */ +#define STREAM_ACL_IRIX_DEFAULT_ACL_T 1005 /* IRIX specific acl_t string representation + * from acl_to_text (POSIX acl) for default acls. + */ +#define STREAM_ACL_IRIX_ACCESS_ACL_T 1006 /* IRIX specific acl_t string representation + * from acl_to_text (POSIX acl) for access acls. + */ +#define STREAM_ACL_LINUX_DEFAULT_ACL_T 1007 /* Linux specific acl_t string representation + * from acl_to_text (POSIX acl) for default acls. + */ +#define STREAM_ACL_LINUX_ACCESS_ACL_T 1008 /* Linux specific acl_t string representation + * from acl_to_text (POSIX acl) for access acls. + */ +#define STREAM_ACL_TRU64_DEFAULT_ACL_T 1009 /* Tru64 specific acl_t string representation + * from acl_to_text (POSIX acl) for default acls. + */ +#define STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T 1010 /* Tru64 specific acl_t string representation + * from acl_to_text (POSIX acl) for default acls. + */ +#define STREAM_ACL_TRU64_ACCESS_ACL_T 1011 /* Tru64 specific acl_t string representation + * from acl_to_text (POSIX acl) for access acls. + */ +#define STREAM_ACL_SOLARIS_ACLENT_T 1012 /* Solaris specific aclent_t string representation + * from acltotext or acl_totext (POSIX acl) + */ +#define STREAM_ACL_SOLARIS_ACE_T 1013 /* Solaris specific ace_t string representation from + * from acl_totext (NFSv4 or ZFS acl) + */ +#define STREAM_XATTR_DARWIN 1996 /* Darwin (OSX) specific extended attributes */ +#define STREAM_XATTR_FREEBSD 1997 /* FreeBSD specific extended attributes */ +#define STREAM_XATTR_LINUX 1998 /* Linux specific extended attributes */ +#define STREAM_XATTR_NETBSD 1999 /* NetBSD specific extended attributes */ /* * File type (Bacula defined). diff --git a/bacula/src/dird/inc_conf.c b/bacula/src/dird/inc_conf.c index c8a7dfa2a4..5df66b1ac0 100644 --- a/bacula/src/dird/inc_conf.c +++ b/bacula/src/dird/inc_conf.c @@ -128,6 +128,7 @@ static RES_ITEM options_items[] = { {"checkfilechanges",store_opts, {0}, 0, 0, 1}, {"strippath", store_opts, {0}, 0, 0, 0}, {"honornodumpflag", store_opts, {0}, 0, 0, 0}, + {"xattrsupport", store_opts, {0}, 0, 0, 0}, {NULL, NULL, {0}, 0, 0, 0} }; @@ -157,7 +158,8 @@ enum { INC_KW_ENHANCEDWILD, INC_KW_CHKCHANGES, INC_KW_STRIPPATH, - INC_KW_HONOR_NODUMP + INC_KW_HONOR_NODUMP, + INC_KW_XATTR }; /* @@ -188,8 +190,9 @@ static struct s_kw FS_option_kw[] = { {"noatime", INC_KW_NOATIME}, {"enhancedwild", INC_KW_ENHANCEDWILD}, {"checkfilechanges", INC_KW_CHKCHANGES}, - {"strippath", INC_KW_STRIPPATH}, - {"honornodumpflag", INC_KW_HONOR_NODUMP}, + {"strippath", INC_KW_STRIPPATH}, + {"honornodumpflag", INC_KW_HONOR_NODUMP}, + {"xattrsupport", INC_KW_XATTR}, {NULL, 0} }; @@ -259,6 +262,8 @@ static struct s_fs_opt FS_options[] = { {"no", INC_KW_CHKCHANGES, "0"}, {"yes", INC_KW_HONOR_NODUMP, "N"}, {"no", INC_KW_HONOR_NODUMP, "0"}, + {"yes", INC_KW_XATTR, "X"}, + {"no", INC_KW_XATTR, "0"}, {NULL, 0, 0} }; diff --git a/bacula/src/filed/Makefile.in b/bacula/src/filed/Makefile.in index 0034045635..a69df1f016 100644 --- a/bacula/src/filed/Makefile.in +++ b/bacula/src/filed/Makefile.in @@ -31,7 +31,7 @@ dummy: SVRSRCS = filed.c authenticate.c acl.c backup.c estimate.c \ fd_plugins.c accurate.c \ filed_conf.c heartbeat.c job.c pythonfd.c \ - restore.c status.c verify.c verify_vol.c + restore.c status.c verify.c verify_vol.c xattr.c SVROBJS = $(SVRSRCS:.c=.o) # these are the objects that are changed by the .configure process diff --git a/bacula/src/filed/acl.c b/bacula/src/filed/acl.c index a9a61449d1..3f2303f6df 100644 --- a/bacula/src/filed/acl.c +++ b/bacula/src/filed/acl.c @@ -71,79 +71,124 @@ */ #if !defined(HAVE_ACL) /* ACL support is required, of course */ \ || !( defined(HAVE_AIX_OS) /* man page -- may need flags */ \ - || defined(HAVE_FREEBSD_OS) /* tested -- compile without flags */ \ || defined(HAVE_DARWIN_OS) /* tested -- compile without flags */ \ + || defined(HAVE_FREEBSD_OS) /* tested -- compile without flags */ \ + || defined(HAVE_HPUX_OS) /* man page -- may need flags */ \ || defined(HAVE_IRIX_OS) /* man page -- compile without flags */ \ - || defined(HAVE_OSF1_OS) /* man page -- may need -lpacl */ \ || defined(HAVE_LINUX_OS) /* tested -- compile with -lacl */ \ - || defined(HAVE_HPUX_OS) /* man page -- may need flags */ \ + || defined(HAVE_OSF1_OS) /* man page -- may need -lpacl */ \ || defined(HAVE_SUN_OS) /* tested -- compile with -lsec */ \ ) + /* - * ***FIXME*** - * For now we abandon this test and only test for Linux: - * 1. This is backwards compatible. - * 2. If we allow any of the other now, we may have to provide conversion - * routines if we ever want to distinguish them. Or just do our best - * with what we have and give all ACL streams a new number/type. + * Entry points when compiled without support for ACLs or on an unsupported platform. */ -#endif - -#if !defined(HAVE_ACL) \ - || !( defined(HAVE_LINUX_OS) \ - || defined(HAVE_FREEBSD_OS) \ - || defined(HAVE_DARWIN_OS) \ - || defined(HAVE_IRIX_OS) \ - || defined(HAVE_OSF1_OS) \ - || defined(HAVE_SUN_OS) \ - ) - -/* bacl_get() returns the lenght of the string, or -1 on error. */ -int bacl_get(JCR *jcr, int acltype) +bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) { Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n")); - return -1; + return false; } -int bacl_set(JCR *jcr, int acltype) +bool parse_acl_stream(JCR *jcr, int stream) { Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for your machine.\n")); - return -1; + return false; +} + +#else + +/* + * Send an ACL stream to the SD. + */ +static bool send_acl_stream(JCR *jcr, int stream, int len) +{ + BSOCK *sd = jcr->store_bsock; + POOLMEM *msgsave; +#ifdef FD_NO_SEND_TEST + return true; +#endif + + /* + * Send header + */ + if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) { + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + sd->bstrerror()); + + return false; + } + + /* + * Send the buffer to the storage deamon + */ + Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_data); + msgsave = sd->msg; + sd->msg = jcr->acl_data; + sd->msglen = len + 1; + if (!sd->send()) { + sd->msg = msgsave; + sd->msglen = 0; + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + sd->bstrerror()); + + return false; + } + + jcr->JobBytes += sd->msglen; + sd->msg = msgsave; + if (!sd->signal(BNET_EOD)) { + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + sd->bstrerror()); + + return false; + } + + Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname); + + return true; } -#elif defined(HAVE_AIX_OS) +#if defined(HAVE_AIX_OS) #include -int bacl_get(JCR *jcr, int acltype) +static bool aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) { char *acl_text; int len; if ((acl_text = acl_get(jcr->last_fname)) != NULL) { - len = pm_strcpy(jcr->acl_text, acl_text); + len = pm_strcpy(jcr->acl_data, acl_text); actuallyfree(acl_text); - return len; + + return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT, len); } - return -1; + + return false; } -int bacl_set(JCR *jcr, int acltype) +static bool aix_parse_acl_stream(JCR *jcr, int stream) { - if (acl_put(jcr->last_fname, jcr->acl_text, 0) != 0) { - return -1; + if (acl_put(jcr->last_fname, jcr->acl_data, 0) != 0) { + return false; } - return 0; + + return true; } -#elif defined(HAVE_FREEBSD_OS) \ - || defined(HAVE_DARWIN_OS) \ +#elif defined(HAVE_DARWIN_OS) \ + || defined(HAVE_FREEBSD_OS) \ || defined(HAVE_IRIX_OS) \ || defined(HAVE_OSF1_OS) \ || defined(HAVE_LINUX_OS) #include + +#ifdef HAVE_SYS_ACL_H #include +#else +#error "configure failed to detect availability of sys/acl.h" +#endif /* On IRIX we can get shortened ACLs */ #if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS) @@ -165,15 +210,157 @@ int bacl_set(JCR *jcr, int acltype) #endif #endif -int bacl_get(JCR *jcr, int acltype) +/* + * Some generic functions used by multiple OSes. + */ +static acl_type_t bac_to_os_acltype(bacl_type acltype) +{ + acl_type_t ostype; + + switch (acltype) { + case BACL_TYPE_ACCESS: + ostype = ACL_TYPE_ACCESS; + break; + case BACL_TYPE_DEFAULT: + ostype = ACL_TYPE_DEFAULT; + break; + +#ifdef ACL_TYPE_DEFAULT_DIR + case BACL_TYPE_DEFAULT_DIR: + /* + * OSF1 has an additional acl type named ACL_TYPE_DEFAULT_DIR. + */ + ostype = ACL_TYPE_DEFAULT_DIR; + break; +#endif +#ifdef ACL_TYPE_EXTENDED + case BACL_TYPE_EXTENDED: + /* + * MacOSX has an additional acl type named ACL_TYPE_EXTENDED. + */ + ostype = ACL_TYPE_EXTENDED; + break; +#endif + default: + /* + * This should never happen, as the per os version function only tries acl + * types supported on a certain platform. + */ + ostype = ACL_TYPE_NONE; + break; + } + + return ostype; +} + +/* + * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.) + * There is no need to store those acls as we already store the stat bits too. + */ +#if defined(HAVE_DARWIN_OS) +static bool acl_is_trivial(acl_t acl) +{ + /* + * acl is trivial if it is empty. + */ + return (acl_entries(acl) == 0); +} +#else /* FreeBSD, IRIX, OSF1, Linux */ +static bool acl_is_trivial(acl_t acl) +{ + /* + * acl is trivial if it has only the following entries: + * "user::", + * "group::", + * "other::" + */ + acl_entry_t ace; + acl_tag_t tag; +#if defined(HAVE_FREEBSD_OS) || defined(HAVE_LINUX_OS) + int entry_available; + + entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace); + while (entry_available == 1) { + /* + * Get the tag type of this acl entry. + * If we fail to get the tagtype we call the acl non-trivial. + */ + if (acl_get_tag_type(ace, &tag) < 0) + return false; + + /* + * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell. + */ + if (tag != ACL_USER_OBJ && + tag != ACL_GROUP_OBJ && + tag != ACL_OTHER) + return false; + + entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace); + } + + return true; +#elif defined(HAVE_IRIX_OS) + int n; + + for (n = 0; n < acl->acl_cnt; n++) { + ace = &acl->acl_entry[n]; + tag = ace->ae_tag; + + /* + * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell. + */ + if (tag != ACL_USER_OBJ && + tag != ACL_GROUP_OBJ && + tag != ACL_OTHER) + return false; + } + + return true; +#elif defined(HAVE_OSF1_OS) + int count; + + ace = acl->acl_first; + count = acl->acl_num; + + while (count > 0) { + tag = ace->entry->acl_type; + + /* + * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell. + */ + if (tag != ACL_USER_OBJ && + tag != ACL_GROUP_OBJ && + tag != ACL_OTHER) + return false; + + /* + * On Tru64, perm can also contain non-standard bits such as + * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ... + */ + if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE))) + return false; + + ace = ace->next; + count--; + } + + return true; +#endif +} +#endif + +/* + * Generic wrapper around acl_get_file call. + */ +static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype) { acl_t acl; int len; acl_type_t ostype; char *acl_text; - ostype = (acltype & BACL_TYPE_DEFAULT) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS; - + ostype = bac_to_os_acltype(acltype); acl = acl_get_file(jcr->last_fname, ostype); if (acl) { #if defined(HAVE_IRIX_OS) @@ -190,59 +377,103 @@ int bacl_get(JCR *jcr, int acltype) * to acl_to_text() besides. */ if (acl->acl_cnt <= 0) { - acl_free(acl); + pm_strcpy(jcr->acl_data, ""); + acl_free(acl); return 0; } #endif + + /* + * Make sure this is not just a trivial ACL. + */ + if ((acltype == BACL_TYPE_ACCESS || + acltype == BACL_TYPE_EXTENDED) && + acl_is_trivial(acl)) { + /* + * The ACLs simply reflect the (already known) standard permissions + * So we don't send an ACL stream to the SD. + */ + pm_strcpy(jcr->acl_data, ""); + acl_free(acl); + return 0; + } + if ((acl_text = acl_to_text(acl, NULL)) != NULL) { - len = pm_strcpy(jcr->acl_text, acl_text); + len = pm_strcpy(jcr->acl_data, acl_text); acl_free(acl); acl_free(acl_text); + return len; } + berrno be; Jmsg2(jcr, M_ERROR, 0, _("acl_to_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror()); - Dmsg3(100, "acl_to_text error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, be.bstrerror()); + Dmsg2(100, "acl_to_text error file=%s ERR=%s\n", + jcr->last_fname, be.bstrerror()); + + pm_strcpy(jcr->acl_data, ""); 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, ""); + + return -1; + } + + /* + * Handle errors gracefully. + */ + switch (errno) { +#if defined(BACL_ENOTSUP) + case BACL_ENOTSUP: + /* + * Not supported, just pretend there is nothing to see + */ + pm_strcpy(jcr->acl_data, ""); + return 0; #endif + default: + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("acl_get_file error on file \"%s\": ERR=%s\n"), + jcr->last_fname, be.bstrerror()); + Dmsg2(100, "acl_get_file error file=%s ERR=%s\n", + jcr->last_fname, be.bstrerror()); + + pm_strcpy(jcr->acl_data, ""); + return -1; } - /***** Do we really want to silently ignore errors from acl_get_file - and acl_to_text? *****/ - return 0; } -int bacl_set(JCR *jcr, int acltype) +/* + * Generic wrapper around acl_set_file call. + */ +static bool generic_set_acl_on_os(JCR *jcr, bacl_type acltype) { acl_t acl; acl_type_t ostype; - ostype = (acltype & BACL_TYPE_DEFAULT) ? ACL_TYPE_DEFAULT : ACL_TYPE_ACCESS; - - /* If we get empty default ACLs, clear ACLs now */ - if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_text) == 0) { + /* + * If we get empty default ACLs, clear ACLs now + */ + ostype = bac_to_os_acltype(acltype); + if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data) == 0) { if (acl_delete_def_file(jcr->last_fname) == 0) { - return 0; + return true; } berrno be; Jmsg2(jcr, M_ERROR, 0, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror()); - return -1; + + return false; } - acl = acl_from_text(jcr->acl_text); + acl = acl_from_text(jcr->acl_data); if (acl == NULL) { berrno be; Jmsg2(jcr, M_ERROR, 0, _("acl_from_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror()); Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, be.bstrerror()); - return -1; + jcr->acl_data, jcr->last_fname, be.bstrerror()); + + return false; } /* @@ -255,100 +486,450 @@ int bacl_set(JCR *jcr, int acltype) Jmsg2(jcr, M_ERROR, 0, _("ac_valid error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror()); Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, be.bstrerror()); + jcr->acl_data, jcr->last_fname, be.bstrerror()); acl_free(acl); - return -1; + + return false; } #endif /* * Restore the ACLs, but don't complain about links which really should * not have attributes, and the file it is linked to may not yet be restored. + * This is only true for the old acl streams as in the new implementation we + * don't save acls of symlinks (which cannot have acls anyhow) */ if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) { berrno be; Jmsg2(jcr, M_ERROR, 0, _("acl_set_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror()); Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, be.bstrerror()); + jcr->acl_data, jcr->last_fname, be.bstrerror()); acl_free(acl); - return -1; + + return false; } acl_free(acl); - return 0; + + return true; +} + +/* + * OS specific functions for handling different types of acl streams. + */ +#if defined(HAVE_DARWIN_OS) +static bool darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) +{ + int len; + +#if defined(ACL_TYPE_EXTENDED) + /* + * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS) + * and acl_get_file (name, ACL_TYPE_DEFAULT) + * always return NULL / EINVAL. There is no point in making + * these two useless calls. The real ACL is retrieved through + * acl_get_file (name, ACL_TYPE_EXTENDED). + * + * Read access ACLs for files, dirs and links + */ + if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED)) < 0) + return false; +#else + /* + * Read access ACLs for files, dirs and links + */ + if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0) + return false; +#endif + + if (len > 0) { + if (!send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL_T, len)) + return false; + } + + return true; +} + +static bool darwin_parse_acl_stream(JCR *jcr, int stream) +{ + switch (stream) { + case STREAM_UNIX_ACCESS_ACL: + case STREAM_ACL_DARWIN_ACCESS_ACL_T: + return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS); + } + + return false; +} +#elif defined(HAVE_FREEBSD_OS) +static bool freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) +{ + int len; + + /* + * Read access ACLs for files, dirs and links + */ + if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0) + return false; + + if (len > 0) { + if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL_T, len)) + return false; + } + + /* + * Directories can have default ACLs too + */ + if (ff_pkt->type == FT_DIREND) { + if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0) + return false; + + if (len > 0) { + if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL_T, len)) + return false; + } + } + + return true; +} + +static bool freebsd_parse_acl_stream(JCR *jcr, int stream) +{ + switch (stream) { + case STREAM_UNIX_ACCESS_ACL: + case STREAM_ACL_FREEBSD_ACCESS_ACL_T: + return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS); + case STREAM_UNIX_DEFAULT_ACL: + case STREAM_ACL_FREEBSD_DEFAULT_ACL_T: + return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT); + } + + return false; +} +#elif defined(HAVE_IRIX_OS) +static bool irix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) +{ + int len; + + /* + * Read access ACLs for files, dirs and links + */ + if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0) + return false; + + if (len > 0) { + if (!send_acl_stream(jcr, STREAM_ACL_IRIX_ACCESS_ACL_T, len)) + return false; + } + + /* + * Directories can have default ACLs too + */ + if (ff_pkt->type == FT_DIREND) { + if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0) + return false; + + if (len > 0) { + if (!send_acl_stream(jcr, STREAM_ACL_IRIX_DEFAULT_ACL_T, len)) + return false; + } + } + + return true; +} + +static bool irix_parse_acl_stream(JCR *jcr, int stream) +{ + switch (stream) { + case STREAM_UNIX_ACCESS_ACL: + case STREAM_ACL_IRIX_ACCESS_ACL_T: + return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS); + case STREAM_UNIX_DEFAULT_ACL: + case STREAM_ACL_IRIX_DEFAULT_ACL_T: + return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT); + } + + return false; +} +#elif defined(HAVE_LINUX_OS) +static bool linux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) +{ + int len; + + /* + * Read access ACLs for files, dirs and links + */ + if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0) + return false; + + if (len > 0) { + if (!send_acl_stream(jcr, STREAM_ACL_LINUX_ACCESS_ACL_T, len)) + return false; + } + + /* + * Directories can have default ACLs too + */ + if (ff_pkt->type == FT_DIREND) { + if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0) + return false; + + if (len > 0) { + if (!send_acl_stream(jcr, STREAM_ACL_LINUX_DEFAULT_ACL_T, len)) + return false; + } + } + + return true; +} + +static bool linux_parse_acl_stream(JCR *jcr, int stream) +{ + switch (stream) { + case STREAM_UNIX_ACCESS_ACL: + case STREAM_ACL_LINUX_ACCESS_ACL_T: + return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS); + case STREAM_UNIX_DEFAULT_ACL: + case STREAM_ACL_LINUX_DEFAULT_ACL_T: + return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT); + } + + return false; +} +#elif defined(HAVE_OSF1_OS) +static bool tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) +{ + int len; + + /* + * Read access ACLs for files, dirs and links + */ + if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0) + return false; + + if (len > 0) { + if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL_T, len)) + return false; + } + + /* + * Directories can have default ACLs too + */ + if (ff_pkt->type == FT_DIREND) { + if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0) + return false; + + if (len > 0) { + if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL_T, len)) + return false; + } + + /* + * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls. + * This is an inherited acl for all subdirs. + * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM + * Section 21.5 Default ACLs + */ + if ((len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0) + return false; + + if (len > 0) { + if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T, len)) + return false; + } + } + + return true; } +static bool tru64_parse_acl_stream(JCR *jcr, int stream) +{ + switch (stream) { + case STREAM_UNIX_ACCESS_ACL: + case STREAM_ACL_TRU64_ACCESS_ACL_T: + return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS); + case STREAM_UNIX_DEFAULT_ACL: + case STREAM_ACL_TRU64_DEFAULT_ACL_T: + return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT); + case STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T: + return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR); +} +#endif + #elif defined(HAVE_HPUX_OS) +#ifdef HAVE_SYS_ACL_H #include +#else +#error "configure failed to detect availability of sys/acl.h" +#endif + #include -int bacl_get(JCR *jcr, int acltype) +/* + * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.) + * There is no need to store those acls as we already store the stat bits too. + */ +static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb) +{ + int n; + struct acl_entry ace + + for (n = 0; n < count; n++) { + ace = entries[n]; + + /* + * See if this acl just is the stat mode in acl form. + */ + if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) || + (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) || + (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP))) + return false; + } + + return true; +} + +/* + * OS specific functions for handling different types of acl streams. + */ +static bool hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) { int n, len; struct acl_entry acls[NACLENTRIES]; char *acl_text; - if ((n = getacl(jcr->last_fname, 0, acls)) <= 0) { - if (errno == BACL_ENOTSUP) { - return pm_strcpy(jcr->acl_text, ""); + if ((n = getacl(jcr->last_fname, 0, acls)) < 0) { + switch(errno) { +#if defined(BACL_ENOTSUP) + case BACL_ENOTSUP: + /* + * Not supported, just pretend there is nothing to see + */ + pm_strcpy(jcr->acl_data, ""); + return true; +#endif + default: + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("getacl error on file \"%s\": ERR=%s\n"), + jcr->last_fname, be.bstrerror()); + Dmsg2(100, "getacl error file=%s ERR=%s\n", + jcr->last_fname, be.bstrerror()); + + pm_strcpy(jcr->acl_data, ""); + return false; } - return -1; } + + if (n == 0) { + pm_strcpy(jcr->acl_data, ""); + return true; + } + if ((n = getacl(jcr->last_fname, n, acls)) > 0) { + if (acl_is_trivial(n, acls, ff_pkt->statp)) { + /* + * The ACLs simply reflect the (already known) standard permissions + * So we don't send an ACL stream to the SD. + */ + pm_strcpy(jcr->acl_data, ""); + return true; + } + if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) { - len = pm_strcpy(jcr->acl_text, acl_text); + len = pm_strcpy(jcr->acl_data, acl_text); actuallyfree(acl_text); - return len; + + return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY, len); } + berrno be; Jmsg2(jcr, M_ERROR, 0, _("acltostr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror()); Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, be.bstrerror()); - return -1; + jcr->acl_data, jcr->last_fname, be.bstrerror()); + + return false; } - return -1; + + return false; } -int bacl_set(JCR *jcr, int acltype) +static bool hpux_parse_acl_stream(JCR *jcr, int stream) { int n, stat; struct acl_entry acls[NACLENTRIES]; - n = strtoacl(jcr->acl_text, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP); + n = strtoacl(jcr->acl_data, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP); if (n <= 0) { berrno be; Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror()); Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, be.bstrerror()); - return -1; + jcr->acl_data, jcr->last_fname, be.bstrerror()); + + return false; } - if (strtoacl(jcr->acl_text, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) { + if (strtoacl(jcr->acl_data, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) { berrno be; Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror()); Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, be.bstrerror()); - return -1; + jcr->acl_data, jcr->last_fname, be.bstrerror()); + + return false; } /* * Restore the ACLs, but don't complain about links which really should * not have attributes, and the file it is linked to may not yet be restored. + * This is only true for the old acl streams as in the new implementation we + * don't save acls of symlinks (which cannot have acls anyhow) */ if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) { berrno be; Jmsg2(jcr, M_ERROR, 0, _("setacl error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror()); Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, be.bstrerror()); - return -1; + jcr->acl_data, jcr->last_fname, be.bstrerror()); + + return false; } - return 0; + + return true; } #elif defined(HAVE_SUN_OS) +#ifdef HAVE_SYS_ACL_H #include +#else +#error "configure failed to detect availability of sys/acl.h" +#endif + +#if defined(HAVE_EXTENDED_ACL) +/* + * We define some internals of the Solaris acl libs here as those + * are not exposed yet. Probably because they want us to see the + * acls as opague data. But as we need to support different platforms + * and versions of Solaris we need to expose some data to be able + * to determine the type of acl used to stuff it into the correct + * data stream. I know this is far from portable, but maybe the + * propper interface is exposed later on and we can get ride of + * this kludge. Newer versions of Solaris include sys/acl_impl.h + * which has implementation details of acls, if thats included we + * don't have to define it ourself. + */ +#if !defined(_SYS_ACL_IMPL_H) +typedef enum acl_type { + ACLENT_T = 0, + ACE_T = 1 +} acl_type_t; +#endif + +/* + * Two external references to functions in the libsec library function not in current include files. + */ +extern "C" { +int acl_type(acl_t *); +char *acl_strerror(int); +} /* * As the new libsec interface with acl_totext and acl_fromtext also handles @@ -356,22 +937,43 @@ int bacl_set(JCR *jcr, int acltype) * for acls retrieved and stored in the database with older fd versions. If the * new interface is not defined (Solaris 9 and older we fall back to the old code) */ -#if defined(HAVE_EXTENDED_ACL) -int bacl_get(JCR *jcr, int acltype) +static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) { int len, flags; acl_t *aclp; char *acl_text; + bool stream_status = false; /* * Get ACL info: don't bother allocating space if there is only a trivial ACL. */ - if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) - return -1; + if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) { + switch (errno) { +#if defined(BACL_ENOTSUP) + case BACL_ENOTSUP: + /* + * Not supported, just pretend there is nothing to see + */ + pm_strcpy(jcr->acl_data, ""); + return true; +#endif + default: + Jmsg2(jcr, M_ERROR, 0, _("acl_get error on file \"%s\": ERR=%s\n"), + jcr->last_fname, acl_strerror(errno)); + Dmsg2(100, "acl_get error file=%s ERR=%s\n", + jcr->last_fname, acl_strerror(errno)); + + return false; + } + } if (aclp == NULL) { - /* The ACLs simply reflect the (already known) standard permissions */ - return pm_strcpy(jcr->acl_text, ""); + /* + * The ACLs simply reflect the (already known) standard permissions + * So we don't send an ACL stream to the SD. + */ + pm_strcpy(jcr->acl_data, ""); + return true; } #if defined(ACL_SID_FMT) @@ -384,60 +986,117 @@ int bacl_get(JCR *jcr, int acltype) #endif /* ACL_SID_FMT */ if ((acl_text = acl_totext(aclp, flags)) != NULL) { - len = pm_strcpy(jcr->acl_text, acl_text); + len = pm_strcpy(jcr->acl_data, acl_text); actuallyfree(acl_text); - acl_free(aclp); + switch (acl_type(aclp)) { + case ACLENT_T: + stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT_T, len); + break; + case ACE_T: + stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACE_T, len); + break; + default: + break; + } - return len; + acl_free(aclp); } - acl_free(aclp); - - return -1; -} - -/* - * As the header acl.h doesn't seem to define this one we need to. - */ -extern "C" { -char *acl_strerror(int); + return stream_status; } -int bacl_set(JCR *jcr, int acltype) +static bool solaris_parse_acl_stream(JCR *jcr, int stream) { acl_t *aclp; int error; - if ((error = acl_fromtext(jcr->acl_text, &aclp)) != 0) { - Jmsg2(jcr, M_ERROR, 0, _("acl_fromtext error on file \"%s\": ERR=%s\n"), - jcr->last_fname, acl_strerror(error)); - Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, acl_strerror(error)); - return -1; - } + switch (stream) { + case STREAM_UNIX_ACCESS_ACL: + case STREAM_ACL_SOLARIS_ACLENT_T: + case STREAM_ACL_SOLARIS_ACE_T: + if ((error = acl_fromtext(jcr->acl_data, &aclp)) != 0) { + Jmsg2(jcr, M_ERROR, 0, _("acl_fromtext error on file \"%s\": ERR=%s\n"), + jcr->last_fname, acl_strerror(error)); + Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n", + jcr->acl_data, jcr->last_fname, acl_strerror(error)); + return false; + } - /* - * Restore the ACLs, but don't complain about links which really should - * not have attributes, and the file it is linked to may not yet be restored. - */ - if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) { - Jmsg2(jcr, M_ERROR, 0, _("acl_set error on file \"%s\": ERR=%s\n"), - jcr->last_fname, acl_strerror(error)); - Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, acl_strerror(error)); + /* + * Validate that the conversion gave us the correct acl type. + */ + switch (stream) { + case STREAM_ACL_SOLARIS_ACLENT_T: + if (acl_type(aclp) != ACLENT_T) { + Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"), + jcr->last_fname); + return false; + } + case STREAM_ACL_SOLARIS_ACE_T: + if (acl_type(aclp) != ACE_T) { + Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"), + jcr->last_fname); + return false; + } + default: + /* + * Stream id which doesn't describe the type of acl which is encoded. + */ + break; + } - acl_free(aclp); - return -1; - } + /* + * Restore the ACLs, but don't complain about links which really should + * not have attributes, and the file it is linked to may not yet be restored. + * This is only true for the old acl streams as in the new implementation we + * don't save acls of symlinks (which cannot have acls anyhow) + */ + if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) { + Jmsg2(jcr, M_ERROR, 0, _("acl_set error on file \"%s\": ERR=%s\n"), + jcr->last_fname, acl_strerror(error)); + Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n", + jcr->acl_data, jcr->last_fname, acl_strerror(error)); + + acl_free(aclp); + return false; + } - acl_free(aclp); - return 0; + acl_free(aclp); + return true; + default: + return false; + } /* end switch (stream) */ } #else /* HAVE_EXTENDED_ACL */ -int bacl_get(JCR *jcr, int acltype) +/* + * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.) + * There is no need to store those acls as we already store the stat bits too. + */ +static bool acl_is_trivial(int count, aclent_t *entries) +{ + int n; + aclent_t *ace; + + for (n = 0; n < count; n++) { + ace = &entries[n]; + + if (!(ace->a_type == USER_OBJ || + ace->a_type == GROUP_OBJ || + ace->a_type == OTHER_OBJ || + ace->a_type == CLASS_OBJ)) + return false; + } + + return true; +} + +/* + * OS specific functions for handling different types of acl streams. + */ +static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt); { int n, len; aclent_t *acls; @@ -445,45 +1104,55 @@ int bacl_get(JCR *jcr, int acltype) n = acl(jcr->last_fname, GETACLCNT, 0, NULL); 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; - } + return false; + + acls = (aclent_t *)malloc(n * sizeof(aclent_t)); if (acl(jcr->last_fname, GETACL, n, acls) == n) { + if (acl_is_trivial(n, acls)) { + /* + * The ACLs simply reflect the (already known) standard permissions + * So we don't send an ACL stream to the SD. + */ + free(acls); + pm_strcpy(jcr->acl_data, ""); + return true; + } + if ((acl_text = acltotext(acls, n)) != NULL) { - len = pm_strcpy(jcr->acl_text, acl_text); + len = pm_strcpy(jcr->acl_data, acl_text); actuallyfree(acl_text); free(acls); - return len; + + return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT_T, len); } + berrno be; Jmsg2(jcr, M_ERROR, 0, _("acltotext error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror()); Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, be.bstrerror()); + jcr->acl_data, jcr->last_fname, be.bstrerror()); } + free(acls); - return -1; + return false; } -int bacl_set(JCR *jcr, int acltype) +static bool solaris_parse_acl_stream(JCR *jcr, int stream) { int n; aclent_t *acls; - acls = aclfromtext(jcr->acl_text, &n); + acls = aclfromtext(jcr->acl_data, &n); if (!acls) { berrno be; Jmsg2(jcr, M_ERROR, 0, _("aclfromtext error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror()); Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, be.bstrerror()); - return -1; + jcr->acl_data, jcr->last_fname, be.bstrerror()); + + return false; } + /* * Restore the ACLs, but don't complain about links which really should * not have attributes, and the file it is linked to may not yet be restored. @@ -493,213 +1162,116 @@ int bacl_set(JCR *jcr, int acltype) Jmsg2(jcr, M_ERROR, 0, _("acl(SETACL) error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror()); Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n", - jcr->acl_text, jcr->last_fname, be.bstrerror()); + jcr->acl_data, jcr->last_fname, be.bstrerror()); actuallyfree(acls); - return -1; + + return false; } + actuallyfree(acls); - return 0; + return true; } #endif /* HAVE_EXTENDED_ACL */ #endif /* HAVE_SUN_OS */ - -#ifdef TEST_PROGRAM - /* - * Test program setup - * - * Compile and set up with eg. with eg. - * - * $ cc -DTEST_PROGRAM -DHAVE_SUN_OS -lsec -o acl acl.c - * $ ln -s acl aclcp - * - * You can then list ACLs with acl and copy them with aclcp. - * - * For a list of compiler flags, see the list preceding the big #if below. + * Entry points when compiled with support for ACLs on a supported platform. */ -#include -#include -#include -#include -#include -#include "acl.h" - -#define BACLLEN 65535 -#define pm_strcpy(d,s) (strncpy(d, s, BACLLEN - 1) == NULL ? -1 : (int)strlen(d)) -#define Dmsg0(n,s) fprintf(stderr, s) -#define Dmsg1(n,s,a1) fprintf(stderr, s, a1) -#define Dmsg2(n,s,a1,a2) fprintf(stderr, s, a1, a2) - -int aclls(char *fname); -int aclcp(char *src, char *dst); - -struct JCRstruct { - char *last_fname; - char acl_text[BACLLEN]; -}; -typedef struct JCRstruct JCR; -JCR jcr; - -int main(int argc, char **argv) -{ - char *prgname; - int status = 0; - if (argc < 1) { - Dmsg0(200, "Cannot determine my own name\n"); - return EXIT_FAILURE; - } - - prgname = last_path_separator(argv[0]); - if (prgname == NULL || *++prgname == '\0') { - prgname = argv[0]; - } - --argc; - ++argv; - - /* aclcp "copies" ACLs - set ACLs on destination equal to ACLs on source */ - if (strcmp(prgname, "aclcp") == 0) { - int verbose = 0; - if (strcmp(*argv, "-v") == 0) { - ++verbose; - --argc; - ++argv; - } - if (argc != 2) { - Dmsg2(200, "%s: wrong number of arguments\n" - "usage:\t%s [-v] source destination\n" - "\tCopies ACLs from source to destination.\n" - "\tSpecify -v to show ACLs after copy for verification.\n", - prgname, prgname); - return EXIT_FAILURE; - } - if (strcmp(argv[0], argv[1]) == 0) { - Dmsg2(200, "%s: identical source and destination.\n" - "usage:\t%s [-v] source destination\n" - "\tCopies ACLs from source to destination.\n" - "\tSpecify -v to show ACLs after copy for verification.\n", - prgname, prgname); - return EXIT_FAILURE; - } - if (verbose) { - aclls(argv[0]); - } - status = aclcp(argv[0], argv[1]); - if (verbose && status == 0) { - aclls(argv[1]); - } - return status; - } - - /* Default: just list ACLs */ - if (argc < 1) { - Dmsg2(200, "%s: missing arguments\n" - "usage:\t%s file ...\n" - "\tLists ACLs of specified files or directories.\n", - prgname, prgname); - return EXIT_FAILURE; - } - while (argc--) { - if (!aclls(*argv++)) { - status = EXIT_FAILURE; - } - } - - return status; -} - -/**** Test program *****/ -int aclcp(char *src, char *dst) +/* + * Read and send an ACL for the last encountered file. + */ +bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) { - struct stat st; - - if (lstat(dst, &st) != 0) { - Dmsg0(200, "aclcp: destination does not exist\n"); - return EXIT_FAILURE; - } - if (S_ISLNK(st.st_mode)) { - Dmsg0(200, "aclcp: cannot set ACL on symlinks\n"); - return EXIT_FAILURE; - } - if (lstat(src, &st) != 0) { - Dmsg0(200, "aclcp: source does not exist\n"); - return EXIT_FAILURE; - } - if (S_ISLNK(st.st_mode)) { - Dmsg0(200, "aclcp: will not read ACL from symlinks\n"); - return EXIT_FAILURE; - } - - jcr.last_fname = src; - if (bacl_get(&jcr, BACL_TYPE_ACCESS) < 0) { - Dmsg1(200, "aclcp: could not read ACLs for %s\n", jcr.last_fname); - return EXIT_FAILURE; - } else { - jcr.last_fname = dst; - if (bacl_set(&jcr, BACL_TYPE_ACCESS) < 0) { - Dmsg1(200, "aclcp: could not set ACLs on %s\n", jcr.last_fname); - return EXIT_FAILURE; - } - } - - if (S_ISDIR(st.st_mode) && (BACL_CAP & BACL_CAP_DEFAULTS_DIR)) { - jcr.last_fname = src; - if (bacl_get(&jcr, BACL_TYPE_DEFAULT) < 0) { - Dmsg1(200, "aclcp: could not read default ACLs for %s\n", jcr.last_fname); - return EXIT_FAILURE; - } else { - jcr.last_fname = dst; - if (bacl_set(&jcr, BACL_TYPE_DEFAULT) < 0) { - Dmsg1(200, "aclcp: could not set default ACLs on %s\n", jcr.last_fname); - return EXIT_FAILURE; - } - } - } - - return 0; + /* + * Call the appropriate function, the ifdefs make sure the proper code is compiled. + */ +#if defined(HAVE_AIX_OS) + return aix_build_acl_streams(jcr, ff_pkt); +#elif defined(HAVE_DARWIN_OS) + return darwin_build_acl_streams(jcr, ff_pkt); +#elif defined(HAVE_FREEBSD_OS) + return freebsd_build_acl_streams(jcr, ff_pkt); +#elif defined(HAVE_HPUX_OS) + return hpux_build_acl_streams(jcr, ff_pkt); +#elif defined(HAVE_IRIX_OS) + return irix_build_acl_streams(jcr, ff_pkt); +#elif defined(HAVE_LINUX_OS) + return linux_build_acl_streams(jcr, ff_pkt); +#elif defined(HAVE_OSF1_OS) + return tru64_build_acl_streams(jcr, ff_pkt); +#elif defined(HAVE_SUN_OS) + return solaris_build_acl_streams(jcr, ff_pkt); +#endif } -/**** Test program *****/ -int aclls(char *fname) +bool parse_acl_stream(JCR *jcr, int stream) { - struct stat st; - int len; - - if (lstat(fname, &st) != 0) { - Dmsg0(200, "acl: source does not exist\n"); - return EXIT_FAILURE; - } - if (S_ISLNK(st.st_mode)) { - Dmsg0(200, "acl: will not read ACL from symlinks\n"); - return EXIT_FAILURE; - } - - jcr.last_fname = fname; - - 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); - } - - if (S_ISDIR(st.st_mode) && (BACL_CAP & BACL_CAP_DEFAULTS_DIR)) { - 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); - } - } - - return 0; + /* + * Based on the stream being passed in dispatch to the right function + * for parsing and restoring a specific acl. The platform determines + * which streams are recognized and parsed and which are handled by + * the default case and ignored. The old STREAM_UNIX_ACCESS_ACL and + * STREAM_UNIX_DEFAULT_ACL is handled as a legacy stream by each function. + * As only one of the platform defines is true per compile we never end + * up with duplicate switch values. + */ + switch (stream) { +#if defined(HAVE_AIX_OS) + case STREAM_UNIX_ACCESS_ACL: + case STREAM_UNIX_DEFAULT_ACL: + case STREAM_ACL_AIX_TEXT: + return aix_parse_acl_stream(jcr, stream); +#elif defined(HAVE_DARWIN_OS) + case STREAM_UNIX_ACCESS_ACL: + case STREAM_ACL_DARWIN_ACCESS_ACL_T: + return darwin_parse_acl_stream(jcr, stream); +#elif defined(HAVE_FREEBSD_OS) + case STREAM_UNIX_ACCESS_ACL: + case STREAM_UNIX_DEFAULT_ACL: + case STREAM_ACL_FREEBSD_DEFAULT_ACL_T: + case STREAM_ACL_FREEBSD_ACCESS_ACL_T: + return freebsd_parse_acl_stream(jcr, stream); +#elif defined(HAVE_HPUX_OS) + case STREAM_UNIX_ACCESS_ACL: + case STREAM_ACL_HPUX_ACL_ENTRY: + return hpux_parse_acl_stream(jcr, stream); +#elif defined(HAVE_IRIX_OS) + case STREAM_UNIX_ACCESS_ACL: + case STREAM_UNIX_DEFAULT_ACL: + case STREAM_ACL_IRIX_DEFAULT_ACL_T: + case STREAM_ACL_IRIX_ACCESS_ACL_T: + return irix_parse_acl_stream(jcr, stream); +#elif defined(HAVE_LINUX_OS) + case STREAM_UNIX_ACCESS_ACL: + case STREAM_UNIX_DEFAULT_ACL: + case STREAM_ACL_LINUX_DEFAULT_ACL_T: + case STREAM_ACL_LINUX_ACCESS_ACL_T: + return linux_parse_acl_stream(jcr, stream); +#elif defined(HAVE_OSF1_OS) + case STREAM_UNIX_ACCESS_ACL: + case STREAM_UNIX_DEFAULT_ACL: + case STREAM_ACL_TRU64_DEFAULT_ACL_T: + case STREAM_ACL_TRU64_ACCESS_ACL_T: + case STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T: + return tru64_parse_acl_stream(jcr, stream); +#elif defined(HAVE_SUN_OS) + case STREAM_UNIX_ACCESS_ACL: + case STREAM_ACL_SOLARIS_ACLENT_T: +#if defined(HAVE_EXTENDED_ACL) + case STREAM_ACL_SOLARIS_ACE_T: +#endif + return solaris_parse_acl_stream(jcr, stream); +#endif + default: + /* + * Issue a warning and discard the message. But pretend the restore was ok. + */ + Qmsg2(jcr, M_WARNING, 0, + _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"), + jcr->last_fname, stream); + return true; + } /* end switch (stream) */ } #endif diff --git a/bacula/src/filed/acl.h b/bacula/src/filed/acl.h index f03d5c31eb..81149cf96b 100644 --- a/bacula/src/filed/acl.h +++ b/bacula/src/filed/acl.h @@ -38,39 +38,37 @@ /* 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_TYPE_NONE 0x000 -#define BACL_TYPE_ACCESS 0x001 -#define BACL_TYPE_DEFAULT 0x002 +/* + * We support the following types of ACLs + */ +typedef enum { + BACL_TYPE_NONE = 0, + BACL_TYPE_ACCESS = 1, + BACL_TYPE_DEFAULT = 2, + BACL_TYPE_DEFAULT_DIR = 3, + BACL_TYPE_EXTENDED = 4 +} bacl_type; -#define BACL_CAP_NONE 0x000 /* No special capabilities */ -#define BACL_CAP_DEFAULTS 0x001 /* Has default ACLs for directories */ -#define BACL_CAP_DEFAULTS_DIR 0x002 /* Default ACLs must be read separately */ +/* + * This value is used as ostype when we encounter a invalid acl type. + * The way the code is build this should never happen. + */ +#if !defined(ACL_TYPE_NONE) +#define ACL_TYPE_NONE 0x0 +#endif -/* 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) #define BACL_ENOTSUP EOPNOTSUPP #elif defined(HAVE_DARWIN_OS) -#define BACL_CAP BACL_CAP_NONE #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 */ +#elif defined(HAVE_SUN_OS) +#define BACL_ENOTSUP ENOSYS #endif #endif diff --git a/bacula/src/filed/backup.c b/bacula/src/filed/backup.c index 9525a0579c..c5d8d3e768 100644 --- a/bacula/src/filed/backup.c +++ b/bacula/src/filed/backup.c @@ -42,7 +42,6 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level); static int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest, DIGEST *signature_digest); bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream); -static bool read_and_send_acl(JCR *jcr, int acltype, int stream); static bool crypto_session_start(JCR *jcr); static void crypto_session_end(JCR *jcr); static bool crypto_session_send(JCR *jcr, BSOCK *sd); @@ -145,7 +144,8 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr) start_heartbeat_monitor(jcr); - jcr->acl_text = get_pool_memory(PM_MESSAGE); + jcr->acl_data = get_pool_memory(PM_MESSAGE); + jcr->xattr_data = get_pool_memory(PM_MESSAGE); /* Subroutine save_file() is called for each file */ if (!find_files(jcr, (FF_PKT *)jcr->ff, save_file, plugin_save)) { @@ -155,7 +155,8 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr) accurate_send_deleted_list(jcr); /* send deleted list to SD */ - free_pool_memory(jcr->acl_text); + free_pool_memory(jcr->acl_data); + free_pool_memory(jcr->xattr_data); stop_heartbeat_monitor(jcr); @@ -582,7 +583,7 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level) Dmsg1(300, "Saving Finder Info for \"%s\"\n", ff_pkt->fname); sd->fsend("%ld %d 0", jcr->JobFiles, STREAM_HFSPLUS_ATTRIBUTES); Dmsg1(300, "bfiled>stored:header %s\n", sd->msg); - memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32); + pm_memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32); sd->msglen = 32; if (digest) { crypto_digest_update(digest, (uint8_t *)sd->msg, sd->msglen); @@ -595,17 +596,20 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level) } #endif - 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_ACCESS_ACL)) { + /* + * Save ACLs for anything not being a symlink. + */ + if (ff_pkt->flags & FO_ACL && ff_pkt->type != FT_LNK) { + if (!build_acl_streams(jcr, ff_pkt)) + goto bail_out; + } + + /* + * Save Extended Attributes for all files. + */ + if (ff_pkt->flags & FO_XATTR) { + if (!build_xattr_streams(jcr, ff_pkt)) goto bail_out; - } - /* 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_DEFAULT_ACL)) { - goto bail_out; - } - } } /* Terminate the signing digest and send it to the Storage daemon */ @@ -1021,61 +1025,6 @@ err: return 0; } -/* - * Read and send an ACL for the last encountered file. - */ -static bool read_and_send_acl(JCR *jcr, int acltype, int stream) -{ -#ifdef HAVE_ACL - BSOCK *sd = jcr->store_bsock; - POOLMEM *msgsave; - int len; -#ifdef FD_NO_SEND_TEST - return true; -#endif - - len = bacl_get(jcr, acltype); - if (len < 0) { - Jmsg1(jcr, M_WARNING, 0, _("Error reading ACL of %s\n"), jcr->last_fname); - return true; - } - if (len == 0) { - return true; /* no ACL */ - } - - /* Send header */ - if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) { - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - sd->bstrerror()); - return false; - } - - /* Send the buffer to the storage deamon */ - Dmsg2(400, "Backing up ACL type 0x%2x <%s>\n", acltype, jcr->acl_text); - msgsave = sd->msg; - sd->msg = jcr->acl_text; - sd->msglen = len + 1; - if (!sd->send()) { - sd->msg = msgsave; - sd->msglen = 0; - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - sd->bstrerror()); - return false; - } - - jcr->JobBytes += sd->msglen; - sd->msg = msgsave; - if (!sd->signal(BNET_EOD)) { - Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), - sd->bstrerror()); - return false; - } - - Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname); -#endif - return true; -} - bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream) { BSOCK *sd = jcr->store_bsock; diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index 9256b4241f..8d0cf550e4 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -1120,6 +1120,9 @@ static void set_options(findFOPTS *fo, const char *opts) case 'N': fo->flags |= FO_HONOR_NODUMP; break; + case 'X': + fo->flags |= FO_XATTR; + break; default: Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p); break; diff --git a/bacula/src/filed/protos.h b/bacula/src/filed/protos.h index 21794509b2..8c3dcb77fe 100644 --- a/bacula/src/filed/protos.h +++ b/bacula/src/filed/protos.h @@ -47,8 +47,8 @@ void start_dir_heartbeat(JCR *jcr); void stop_dir_heartbeat(JCR *jcr); /* From acl.c */ -int bacl_get(JCR *jcr, int acltype); -int bacl_set(JCR *jcr, int acltype); +bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt); +bool parse_acl_stream(JCR *jcr, int stream); /* from accurate.c */ bool accurate_send_deleted_list(JCR *jcr); @@ -59,3 +59,7 @@ bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream); void strip_path(FF_PKT *ff_pkt); void unstrip_path(FF_PKT *ff_pkt); +/* from xattr.c */ +bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt); +bool parse_xattr_stream(JCR *jcr, int stream); + diff --git a/bacula/src/filed/restore.c b/bacula/src/filed/restore.c index 0fc635e39f..eba51ce3fa 100644 --- a/bacula/src/filed/restore.c +++ b/bacula/src/filed/restore.c @@ -62,6 +62,11 @@ const bool have_acl = false; const bool have_sha2 = false; #endif +#if defined(HAVE_XATTR) +const bool have_xattr = true; +#else +const bool have_xattr = false; +#endif /* Data received from Storage Daemon */ static char rec_header[] = "rechdr %ld %ld %ld %ld %ld"; @@ -171,6 +176,7 @@ void do_restore(JCR *jcr) int non_support_acl = 0; int non_support_progname = 0; int non_support_crypto = 0; + int non_support_xattr = 0; #ifdef HAVE_DARWIN_OS struct attrlist attrList; @@ -243,9 +249,8 @@ void do_restore(JCR *jcr) binit(&rctx.bfd); binit(&rctx.forkbfd); attr = rctx.attr = new_attr(jcr); - jcr->acl_text = get_pool_memory(PM_MESSAGE); - - + jcr->acl_data = get_pool_memory(PM_MESSAGE); + jcr->xattr_data = get_pool_memory(PM_MESSAGE); while (bget_msg(sd) >= 0 && !job_canceled(jcr)) { /* Remember previous stream type */ @@ -573,6 +578,21 @@ void do_restore(JCR *jcr) break; case STREAM_UNIX_ACCESS_ACL: + case STREAM_UNIX_DEFAULT_ACL: + case STREAM_ACL_AIX_TEXT: + case STREAM_ACL_DARWIN_ACCESS_ACL_T: + case STREAM_ACL_FREEBSD_DEFAULT_ACL_T: + case STREAM_ACL_FREEBSD_ACCESS_ACL_T: + case STREAM_ACL_HPUX_ACL_ENTRY: + case STREAM_ACL_IRIX_DEFAULT_ACL_T: + case STREAM_ACL_IRIX_ACCESS_ACL_T: + case STREAM_ACL_LINUX_DEFAULT_ACL_T: + case STREAM_ACL_LINUX_ACCESS_ACL_T: + case STREAM_ACL_TRU64_DEFAULT_ACL_T: + case STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T: + case STREAM_ACL_TRU64_ACCESS_ACL_T: + case STREAM_ACL_SOLARIS_ACLENT_T: + case STREAM_ACL_SOLARIS_ACE_T: /* * Do not restore ACLs when * a) The current file is not extracted @@ -583,28 +603,36 @@ void do_restore(JCR *jcr) break; } if (have_acl) { - pm_strcpy(jcr->acl_text, sd->msg); - Dmsg2(400, "Restoring ACL type 0x%2x <%s>\n", BACL_TYPE_ACCESS, jcr->acl_text); - if (bacl_set(jcr, BACL_TYPE_ACCESS) != 0) { - Qmsg1(jcr, M_WARNING, 0, _("Can't restore ACL of %s\n"), jcr->last_fname); + pm_memcpy(jcr->acl_data, sd->msg, sd->msglen); + jcr->acl_data_len = sd->msglen; + if (!parse_acl_stream(jcr, rctx.stream)) { + Qmsg1(jcr, M_WARNING, 0, _("Can't restore ACLs of %s\n"), jcr->last_fname); } } else { non_support_acl++; } break; - case STREAM_UNIX_DEFAULT_ACL: + case STREAM_XATTR_DARWIN: + case STREAM_XATTR_FREEBSD: + case STREAM_XATTR_LINUX: + /* + * Do not restore Extended Attributes when + * a) The current file is not extracted + * b) and it is not a directory (they are never "extracted") + * c) or the file name is empty + */ if ((!rctx.extract && jcr->last_type != FT_DIREND) || (*jcr->last_fname == 0)) { break; } - if (have_acl) { - pm_strcpy(jcr->acl_text, sd->msg); - Dmsg2(400, "Restoring ACL type 0x%2x <%s>\n", BACL_TYPE_DEFAULT, jcr->acl_text); - if (bacl_set(jcr, BACL_TYPE_DEFAULT) != 0) { - Qmsg1(jcr, M_WARNING, 0, _("Can't restore default ACL of %s\n"), jcr->last_fname); + if (have_xattr) { + pm_memcpy(jcr->xattr_data, sd->msg, sd->msglen); + jcr->xattr_data_len = sd->msglen; + if (!parse_xattr_stream(jcr, rctx.stream)) { + Qmsg1(jcr, M_WARNING, 0, _("Can't restore Extended Attributes of %s\n"), jcr->last_fname); } } else { - non_support_acl++; + non_support_xattr++; } break; @@ -703,7 +731,8 @@ ok_out: bclose(&rctx.forkbfd); bclose(&rctx.bfd); free_attr(rctx.attr); - free_pool_memory(jcr->acl_text); + free_pool_memory(jcr->xattr_data); + free_pool_memory(jcr->acl_data); Dmsg2(10, "End Do Restore. Files=%d Bytes=%s\n", jcr->JobFiles, edit_uint64(jcr->JobBytes, ec1)); if (non_support_data > 1 || non_support_attr > 1) { @@ -722,6 +751,9 @@ ok_out: if (non_support_crypto) { Jmsg(jcr, M_INFO, 0, _("%d non-supported crypto streams ignored.\n"), non_support_acl); } + if (non_support_xattr) { + Jmsg(jcr, M_INFO, 0, _("%d non-supported xattr streams ignored.\n"), non_support_xattr); + } } diff --git a/bacula/src/filed/status.c b/bacula/src/filed/status.c index 4ee3c13685..aa55a87323 100644 --- a/bacula/src/filed/status.c +++ b/bacula/src/filed/status.c @@ -340,8 +340,8 @@ static void sendit(const char *msg, int len, STATUS_PKT *sp) { if (sp->bs) { BSOCK *user = sp->bs; - user->msg = check_pool_memory_size(user->msg, len+1); - memcpy(user->msg, msg, len+1); + + pm_memcpy(user->msg, msg, len+1); user->msglen = len+1; user->send(); } else { diff --git a/bacula/src/findlib/bfile.c b/bacula/src/findlib/bfile.c index c9dba67d09..eafaf6c17f 100644 --- a/bacula/src/findlib/bfile.c +++ b/bacula/src/findlib/bfile.c @@ -143,6 +143,40 @@ const char *stream_to_ascii(int stream) return _("Encrypted Win32 GZIP data"); case STREAM_ENCRYPTED_MACOS_FORK_DATA: return _("Encrypted MacOS fork data"); + case STREAM_ACL_AIX_TEXT: + return _("AIX Specific ACL attribs"); + case STREAM_ACL_DARWIN_ACCESS_ACL_T: + return _("Darwin Specific ACL attribs"); + case STREAM_ACL_FREEBSD_DEFAULT_ACL_T: + return _("FreeBSD Specific Default ACL attribs"); + case STREAM_ACL_FREEBSD_ACCESS_ACL_T: + return _("FreeBSD Specific Access ACL attribs"); + case STREAM_ACL_HPUX_ACL_ENTRY: + return _("HPUX Specific ACL attribs"); + case STREAM_ACL_IRIX_DEFAULT_ACL_T: + return _("Irix Specific Default ACL attribs"); + case STREAM_ACL_IRIX_ACCESS_ACL_T: + return _("Irix Specific Access ACL attribs"); + case STREAM_ACL_LINUX_DEFAULT_ACL_T: + return _("Linux Specific Default ACL attribs"); + case STREAM_ACL_LINUX_ACCESS_ACL_T: + return _("Linux Specific Access ACL attribs"); + case STREAM_ACL_TRU64_DEFAULT_ACL_T: + return _("OSF1 Specific Default ACL attribs"); + case STREAM_ACL_TRU64_ACCESS_ACL_T: + return _("OSF1 Specific Access ACL attribs"); + case STREAM_ACL_SOLARIS_ACLENT_T: + return _("Solaris Specific ACL attribs"); + case STREAM_ACL_SOLARIS_ACE_T: + return _("Solaris Specific ACL attribs"); + case STREAM_XATTR_DARWIN: + return _("Darwin Specific Extended attribs"); + case STREAM_XATTR_FREEBSD: + return _("FreeBSD Specific Extended attribs"); + case STREAM_XATTR_LINUX: + return _("Linux Specific Extended attribs"); + case STREAM_XATTR_NETBSD: + return _("NetBSD Specific Extended attribs"); default: sprintf(buf, "%d", stream); return (const char *)buf; diff --git a/bacula/src/findlib/find.h b/bacula/src/findlib/find.h index 86568bda08..035102cd17 100644 --- a/bacula/src/findlib/find.h +++ b/bacula/src/findlib/find.h @@ -101,6 +101,7 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); #define FO_CHKCHANGES (1<<24) /* Check if file have been modified during backup */ #define FO_STRIPPATH (1<<25) /* Check for stripping path */ #define FO_HONOR_NODUMP (1<<26) /* honor NODUMP flag */ +#define FO_XATTR (1<<27) /* Backup Extended Attributes */ struct s_included_file { struct s_included_file *next; diff --git a/bacula/src/findlib/match.c b/bacula/src/findlib/match.c index c285ce7fce..e4e69bdea8 100644 --- a/bacula/src/findlib/match.c +++ b/bacula/src/findlib/match.c @@ -195,6 +195,9 @@ void add_fname_to_include_list(FF_PKT *ff, int prefixed, const char *fname) case 'K': inc->options |= FO_NOATIME; break; + case 'X': + inc->options |= FO_XATTR; + break; default: Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *rp); break; diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index d7dfff922f..fcda30cdb7 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -331,7 +331,10 @@ public: /* File Daemon specific part of JCR */ uint32_t num_files_examined; /* files examined this job */ POOLMEM *last_fname; /* last file saved/verified */ - POOLMEM *acl_text; /* text of ACL for backup */ + POOLMEM *acl_data; /* data with ACLs for backup/restore */ + uint32_t acl_data_len; /* length of acl data buffer */ + POOLMEM *xattr_data; /* data with Extended Attributes for backup/restore */ + uint32_t xattr_data_len; /* length of xattr_data buffer */ int32_t last_type; /* type of last file saved/verified */ int incremental; /* set if incremental for SINCE */ utime_t mtime; /* begin time for SINCE */ diff --git a/bacula/src/lib/mem_pool.c b/bacula/src/lib/mem_pool.c index d961c396c7..e36f63df6a 100644 --- a/bacula/src/lib/mem_pool.c +++ b/bacula/src/lib/mem_pool.c @@ -95,7 +95,6 @@ struct abufhead { static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - #ifdef SMARTALLOC #define HEAD_SIZE BALIGN(sizeof(struct abufhead)) @@ -154,7 +153,6 @@ POOLMEM *sm_get_memory(const char *fname, int lineno, int32_t size) return (POOLMEM *)(((char *)buf)+HEAD_SIZE); } - /* Return the size of a memory buffer */ int32_t sm_sizeof_pool_memory(const char *fname, int lineno, POOLMEM *obuf) { @@ -233,7 +231,6 @@ void sm_free_pool_memory(const char *fname, int lineno, POOLMEM *obuf) V(mutex); } - #else /* ========= NO SMARTALLOC ========================================= */ @@ -284,7 +281,6 @@ POOLMEM *get_memory(int32_t size) return (POOLMEM *)(((char *)buf)+HEAD_SIZE); } - /* Return the size of a memory buffer */ int32_t sizeof_pool_memory(POOLMEM *obuf) { @@ -295,8 +291,6 @@ int32_t sizeof_pool_memory(POOLMEM *obuf) return ((struct abufhead *)cp)->ablen; } - - /* Realloc pool memory buffer */ POOLMEM *realloc_pool_memory(POOLMEM *obuf, int32_t size) { @@ -321,7 +315,6 @@ POOLMEM *realloc_pool_memory(POOLMEM *obuf, int32_t size) return (POOLMEM *)(((char *)buf)+HEAD_SIZE); } - POOLMEM *check_pool_memory_size(POOLMEM *obuf, int32_t size) { ASSERT(obuf); @@ -361,10 +354,8 @@ void free_pool_memory(POOLMEM *obuf) Dmsg2(1800, "free_pool_memory %p pool=%d\n", buf, pool); V(mutex); } - #endif /* SMARTALLOC */ - /* * Clean up memory pool periodically * @@ -393,9 +384,6 @@ void garbage_collect_memory_pool() } } - - - /* Release all pooled memory */ void close_memory_pool() { @@ -423,7 +411,6 @@ void close_memory_pool() } #ifdef DEBUG - static const char *pool_name(int pool) { static const char *name[] = {"NoPool", "NAME ", "FNAME ", "MSG ", "EMSG "}; @@ -452,7 +439,6 @@ void print_memory_pool_stats() void print_memory_pool_stats() {} #endif /* DEBUG */ - /* * Concatenate a string (str) onto a pool memory buffer pm * Returns: length of concatenated string @@ -483,7 +469,6 @@ int pm_strcat(POOLMEM *&pm, const char *str) return pmlen + len - 1; } - int pm_strcat(POOLMEM *&pm, POOL_MEM &str) { int pmlen = strlen(pm); @@ -507,7 +492,6 @@ int pm_strcat(POOL_MEM &pm, const char *str) return pmlen + len - 1; } - /* * Copy a string (str) into a pool memory buffer pm * Returns: length of string copied @@ -545,7 +529,6 @@ int pm_strcpy(POOLMEM *&pm, POOL_MEM &str) return len - 1; } - int pm_strcpy(POOL_MEM &pm, const char *str) { int len; @@ -558,6 +541,38 @@ int pm_strcpy(POOL_MEM &pm, const char *str) return len - 1; } +/* + * Copy data into a pool memory buffer pm + * Returns: length of data copied + */ +int pm_memcpy(POOLMEM **pm, const void *data, size_t n) +{ + *pm = check_pool_memory_size(*pm, n); + memcpy(*pm, data, n); + return n; +} + +int pm_memcpy(POOLMEM *&pm, const void *data, size_t n) +{ + pm = check_pool_memory_size(pm, n); + memcpy(pm, data, n); + return n; +} + +int pm_memcpy(POOLMEM *&pm, POOL_MEM &data, size_t n) +{ + pm = check_pool_memory_size(pm, n); + memcpy(pm, data.c_str(), n); + return n; +} + +int pm_memcpy(POOL_MEM &pm, const void *data, size_t n) +{ + pm.check_size(n); + memcpy(pm.c_str(), data, n); + return n; +} + /* ============== CLASS POOL_MEM ============== */ /* Return the size of a memory buffer */ @@ -608,7 +623,6 @@ int POOL_MEM::strcat(const char *str) return pmlen + len - 1; } - int POOL_MEM::strcpy(const char *str) { int len; diff --git a/bacula/src/lib/mem_pool.h b/bacula/src/lib/mem_pool.h index cdf03d71bf..abb4daeba3 100644 --- a/bacula/src/lib/mem_pool.h +++ b/bacula/src/lib/mem_pool.h @@ -111,6 +111,9 @@ int pm_strcpy(POOLMEM **pm, const char *str); int pm_strcpy(POOLMEM *&pm, const char *str); int pm_strcpy(POOL_MEM &pm, const char *str); int pm_strcpy(POOLMEM *&pm, POOL_MEM &str); - +int pm_memcpy(POOLMEM **pm, const void *data, size_t n); +int pm_memcpy(POOLMEM *&pm, const void *data, size_t n); +int pm_memcpy(POOL_MEM &pm, const void *data, size_t n); +int pm_memcpy(POOLMEM *&pm, POOL_MEM &data, size_t n); #endif diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index a4d320c721..2dd620b683 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -791,9 +791,30 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) } break; - case STREAM_UNIX_ACCESS_ACL: /* Standard ACL attributes on UNIX */ - case STREAM_UNIX_DEFAULT_ACL: /* Default ACL attributes on UNIX */ - /* Ignore Unix attributes */ + case STREAM_UNIX_ACCESS_ACL: /* Deprecated Standard ACL attributes on UNIX */ + case STREAM_UNIX_DEFAULT_ACL: /* Deprecated Default ACL attributes on UNIX */ + case STREAM_ACL_AIX_TEXT: + case STREAM_ACL_DARWIN_ACCESS_ACL_T: + case STREAM_ACL_FREEBSD_DEFAULT_ACL_T: + case STREAM_ACL_FREEBSD_ACCESS_ACL_T: + case STREAM_ACL_HPUX_ACL_ENTRY: + case STREAM_ACL_IRIX_DEFAULT_ACL_T: + case STREAM_ACL_IRIX_ACCESS_ACL_T: + case STREAM_ACL_LINUX_DEFAULT_ACL_T: + case STREAM_ACL_LINUX_ACCESS_ACL_T: + case STREAM_ACL_TRU64_DEFAULT_ACL_T: + case STREAM_ACL_TRU64_DEFAULT_DIR_ACL_T: + case STREAM_ACL_TRU64_ACCESS_ACL_T: + case STREAM_ACL_SOLARIS_ACLENT_T: + case STREAM_ACL_SOLARIS_ACE_T: + /* Ignore Unix ACL attributes */ + break; + + case STREAM_XATTR_DARWIN: + case STREAM_XATTR_FREEBSD: + case STREAM_XATTR_LINUX: + case STREAM_XATTR_NETBSD: + /* Ignore Unix Extended attributes */ break; default: diff --git a/bacula/src/tools/testfind.c b/bacula/src/tools/testfind.c index bacabaedf3..5df537689c 100644 --- a/bacula/src/tools/testfind.c +++ b/bacula/src/tools/testfind.c @@ -632,6 +632,9 @@ static void set_options(findFOPTS *fo, const char *opts) fo->GZIP_level = *++p - '0'; Dmsg1(200, "Compression level=%d\n", fo->GZIP_level); break; + case 'X': + fo->flags |= FO_XATTR; + break; default: Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p); break; diff --git a/bacula/src/version.h b/bacula/src/version.h index 41b6ccfe37..194530f2b6 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -3,9 +3,9 @@ */ #undef VERSION -#define VERSION "2.5.20" -#define BDATE "25 November 2008" -#define LSMDATE "25Nov08" +#define VERSION "2.5.21" +#define BDATE "26 November 2008" +#define LSMDATE "26Nov08" #define PROG_COPYRIGHT "Copyright (C) %d-2008 Free Software Foundation Europe e.V.\n" #define BYEAR "2008" /* year for copyright messages in progs */ diff --git a/bacula/technotes-2.5 b/bacula/technotes-2.5 index cc9bd59347..d2f8b33064 100644 --- a/bacula/technotes-2.5 +++ b/bacula/technotes-2.5 @@ -10,6 +10,9 @@ filepattern (restore with regex in bsr) mixed priorities General: +26Nov08 +kes Apply Marco's Extended attribute support patch. +kes Update projects file 25Nov08 kes More changes to ensure that during thread switches the jcr is removed from the TSD. -- 2.39.5