support-stflags-stat-field-rdonly   [plain text]


Index: samba/source/configure.in
===================================================================
--- samba/source/configure.in.orig
+++ samba/source/configure.in
@@ -3087,6 +3087,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 <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>],
+[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,16 +172,57 @@ 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);
 
Index: samba/source/smbd/posix_acls.c
===================================================================
--- samba/source/smbd/posix_acls.c.orig
+++ samba/source/smbd/posix_acls.c
@@ -4301,6 +4301,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) {