Index: samba/source/configure.in =================================================================== --- samba/source/configure.in.orig +++ samba/source/configure.in @@ -3106,6 +3106,16 @@ if test x"$samba_cv_HAVE_STAT_ST_FLAGS" [Whether the stat struct has a st_flags member]) fi +AC_CACHE_CHECK([for st_flags in struct stat],samba_cv_HAVE_STAT_ST_FLAGS,[ +AC_TRY_COMPILE([#include +#include +#include ], +[struct stat st; st.st_flags = 0;], +samba_cv_HAVE_STAT_ST_FLAGS=yes,samba_cv_HAVE_STAT_ST_FLAGS=no,samba_cv_HAVE_STAT_ST_FLAGS=cross)]) +if test x"$samba_cv_HAVE_STAT_ST_FLAGS" = x"yes"; then + AC_DEFINE(HAVE_STAT_ST_FLAGS,1,[Whether the stat struct has a st_flags property]) +fi + case "$host_os" in *linux*) AC_CACHE_CHECK([for broken RedHat 7.2 system header files],samba_cv_BROKEN_REDHAT_7_SYSTEM_HEADERS,[ Index: samba/source/smbd/dosmode.c =================================================================== --- samba/source/smbd/dosmode.c.orig +++ samba/source/smbd/dosmode.c @@ -152,6 +152,15 @@ static uint32 dos_mode_from_sbuf(connect int result = 0; enum mapreadonly_options ro_opts = (enum mapreadonly_options)lp_map_readonly(SNUM(conn)); +#if defined(HAVE_STAT_ST_FLAGS) && defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE) + /* We should check the immutable bit irrespective of which MAP_READONLY + * mode we are in. + */ + if (sbuf->st_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) { + result |= aRONLY; + } + +#else if (ro_opts == MAP_READONLY_YES) { /* Original Samba method - map inverse of user "w" bit. */ if ((sbuf->st_mode & S_IWUSR) == 0) { @@ -163,18 +172,59 @@ static uint32 dos_mode_from_sbuf(connect result |= aRONLY; } } /* Else never set the readonly bit. */ +#endif + +#if defined(HAVE_STAT_ST_FLAGS) + /* The archived bit really only makes sense for regular files. Some + * systems hijack it for different purposes on directories anyway, so + * it is best avoided. + */ + if (S_ISREG(sbuf->st_mode)) { + result |= aARCH; - if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0)) +#if defined(SF_ARCHIVED) + /* aARCH means "needs to be archived", but SF_ARCHIVED + * means "was already archived", so we invert the sense + * here. + */ + if (sbuf->st_flags & SF_ARCHIVED) { + result &= ~aARCH; + } +#endif +#if defined(UF_NODUMP) + /* If a file is marked as not to be dumped (backed up), this + * is approximately the same as marking it as already + * having been backed up. The net effect is that any app + * looking at these flags will figure it doesn't need to + * be backed up. + */ + if (sbuf->st_flags & UF_NODUMP) { + result &= ~aARCH; + } +#endif + } +#else + if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0)) { result |= aARCH; + } +#endif - if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0)) + if ( MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0)) { result |= aSYSTEM; + } - if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0)) +#if defined(HAVE_STAT_ST_FLAGS) && defined(UF_HIDDEN) + if (sbuf->st_flags & UF_HIDDEN) { + result |= aHIDDEN; + } +#else + if ( MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0)) { result |= aHIDDEN; - + } +#endif + if (S_ISDIR(sbuf->st_mode)) - result = aDIR | (result & aRONLY); + result |= aDIR; result |= set_sparse_flag(sbuf); Index: samba/source/smbd/posix_acls.c =================================================================== --- samba/source/smbd/posix_acls.c.orig +++ samba/source/smbd/posix_acls.c @@ -4330,6 +4330,18 @@ BOOL can_access_file(connection_struct * } } +#if defined(HAVE_STAT_ST_FLAGS) +#if defined(UF_IMMUTABLE) && defined(SF_IMMUTABLE) + + if (access_mask & FILE_WRITE_DATA) { + if (psbuf->st_flags & (UF_IMMUTABLE | SF_IMMUTABLE)) { + return False; + } + } + +#endif +#endif + /* Check primary owner access. */ if (current_user.ut.uid == psbuf->st_uid) { switch (access_mask) {