summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorTim Prouty <tprouty@samba.org>2008-11-05 13:40:03 -0800
committerTim Prouty <tprouty@samba.org>2008-11-12 09:48:50 -0800
commitd38bffd4126062b92384f0930196059441a2d765 (patch)
tree4723e7edd92eaf95c5096afb1ff45ab29359ccbe /source3
parent7f36d3b55051150b9d4fa75af424898f48c48771 (diff)
downloadsamba-d38bffd4126062b92384f0930196059441a2d765.tar.gz
samba-d38bffd4126062b92384f0930196059441a2d765.tar.bz2
samba-d38bffd4126062b92384f0930196059441a2d765.zip
s3: Add support for storing dos attributes as st_flags in the stat struct.
Some filesystems have support for storing dos attributes directly in the inode's st_flags and accessing them through the stat struct. This patch: - Adds a configure check to see if the special flags are available. - Implements getting and setting dos attributes in the stat struct and inode, respectively. This will not change the existing functionality of any system that doesn't have the special flags available.
Diffstat (limited to 'source3')
-rw-r--r--source3/configure.in19
-rw-r--r--source3/smbd/dosmode.c160
2 files changed, 166 insertions, 13 deletions
diff --git a/source3/configure.in b/source3/configure.in
index 5e3eac55e2..24341e0bec 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -1433,6 +1433,25 @@ if test x"$samba_cv_stat_st_birthtime" = x"yes" ; then
AC_DEFINE(HAVE_STAT_ST_BIRTHTIME, 1, [whether struct stat contains st_birthtime])
fi
+AC_CACHE_CHECK([whether there is DOS flags support in the stat struct], samba_cv_stat_dos_flags,
+ [
+ AC_TRY_COMPILE(
+ [#include <sys/stat.h>],
+ [
+ int a = UF_DOS_ARCHIVE;
+ int h = UF_DOS_HIDDEN;
+ int r = UF_DOS_RO;
+ int s = UF_DOS_SYSTEM;
+ int i = UF_DOS_NOINDEX;
+ int f = UF_DOS_FLAGS;
+ ],
+ samba_cv_stat_dos_flags=yes, samba_cv_stat_dos_flags=no)
+ ])
+
+if test x"$samba_cv_stat_dos_flags" = x"yes" ; then
+ AC_DEFINE(HAVE_STAT_DOS_FLAGS, 1, [whether there is DOS flags support in the stat struct])
+fi
+
#####################################
# needed for SRV lookups
AC_CHECK_LIB(resolv, dn_expand)
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index 784b36d9bd..954cd5a4d2 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -30,6 +30,17 @@ static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
return 0;
}
+static int set_link_read_only_flag(const SMB_STRUCT_STAT *const sbuf)
+{
+#ifdef S_ISLNK
+#if LINKS_READ_ONLY
+ if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
+ return aRONLY;
+#endif
+#endif
+ return 0;
+}
+
/****************************************************************************
Change a dos mode to a unix mode.
Base permission for files:
@@ -159,13 +170,7 @@ static uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_
result = aDIR | (result & aRONLY);
result |= set_sparse_flag(sbuf);
-
-#ifdef S_ISLNK
-#if LINKS_READ_ONLY
- if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
- result |= aRONLY;
-#endif
-#endif
+ result |= set_link_read_only_flag(sbuf);
DEBUG(8,("dos_mode_from_sbuf returning "));
@@ -343,6 +348,113 @@ uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT
return(result);
}
+#ifdef HAVE_STAT_DOS_FLAGS
+/****************************************************************************
+ Convert dos attributes (FILE_ATTRIBUTE_*) to dos stat flags (UF_*)
+****************************************************************************/
+
+static int dos_attributes_to_stat_dos_flags(uint32_t dosmode)
+{
+ uint32_t dos_stat_flags = 0;
+
+ if (dosmode & aARCH)
+ dos_stat_flags |= UF_DOS_ARCHIVE;
+ if (dosmode & aHIDDEN)
+ dos_stat_flags |= UF_DOS_HIDDEN;
+ if (dosmode & aRONLY)
+ dos_stat_flags |= UF_DOS_RO;
+ if (dosmode & aSYSTEM)
+ dos_stat_flags |= UF_DOS_SYSTEM;
+ if (dosmode & FILE_ATTRIBUTE_NONINDEXED)
+ dos_stat_flags |= UF_DOS_NOINDEX;
+
+ return dos_stat_flags;
+}
+
+/****************************************************************************
+ Gets DOS attributes, accessed via st_flags in the stat struct.
+****************************************************************************/
+
+static bool get_stat_dos_flags(connection_struct *conn,
+ const char *fname,
+ const SMB_STRUCT_STAT *sbuf,
+ uint32_t *dosmode)
+{
+ SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
+ SMB_ASSERT(dosmode);
+
+ if (!lp_store_dos_attributes(SNUM(conn))) {
+ return false;
+ }
+
+ DEBUG(5, ("Getting stat dos attributes for %s.\n", fname));
+
+ if (sbuf->st_flags & UF_DOS_ARCHIVE)
+ *dosmode |= aARCH;
+ if (sbuf->st_flags & UF_DOS_HIDDEN)
+ *dosmode |= aHIDDEN;
+ if (sbuf->st_flags & UF_DOS_RO)
+ *dosmode |= aRONLY;
+ if (sbuf->st_flags & UF_DOS_SYSTEM)
+ *dosmode |= aSYSTEM;
+ if (sbuf->st_flags & UF_DOS_NOINDEX)
+ *dosmode |= FILE_ATTRIBUTE_NONINDEXED;
+ if (S_ISDIR(sbuf->st_mode))
+ *dosmode |= aDIR;
+
+ *dosmode |= set_sparse_flag(sbuf);
+ *dosmode |= set_link_read_only_flag(sbuf);
+
+ return true;
+}
+
+/****************************************************************************
+ Sets DOS attributes, stored in st_flags of the inode.
+****************************************************************************/
+
+static bool set_stat_dos_flags(connection_struct *conn,
+ const char *fname,
+ SMB_STRUCT_STAT *sbuf,
+ uint32_t dosmode,
+ bool *attributes_changed)
+{
+ uint32_t new_flags = 0;
+ int error = 0;
+
+ SMB_ASSERT(sbuf && VALID_STAT(*sbuf));
+ SMB_ASSERT(attributes_changed);
+
+ *attributes_changed = false;
+
+ if (!lp_store_dos_attributes(SNUM(conn))) {
+ return false;
+ }
+
+ DEBUG(5, ("Setting stat dos attributes for %s.\n", fname));
+
+ new_flags = (sbuf->st_flags & ~UF_DOS_FLAGS) |
+ dos_attributes_to_stat_dos_flags(dosmode);
+
+ /* Return early if no flags changed. */
+ if (new_flags == sbuf->st_flags)
+ return true;
+
+ DEBUG(5, ("Setting stat dos attributes=0x%x, prev=0x%x\n", new_flags,
+ sbuf->st_flags));
+
+ /* Set new flags with chflags. */
+ error = SMB_VFS_CHFLAGS(conn, fname, new_flags);
+ if (error) {
+ DEBUG(0, ("Failed setting new stat dos attributes (0x%x) on "
+ "file %s! errno=%d\n", new_flags, fname, errno));
+ return false;
+ }
+
+ *attributes_changed = true;
+ return true;
+}
+#endif /* HAVE_STAT_DOS_FLAGS */
+
/****************************************************************************
Change a unix mode to a dos mode.
****************************************************************************/
@@ -350,7 +462,7 @@ uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT
uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
{
uint32 result = 0;
- bool offline;
+ bool offline, used_stat_dos_flags = false;
DEBUG(8,("dos_mode: %s\n", path));
@@ -373,11 +485,16 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
}
}
- /* Get the DOS attributes from an EA by preference. */
- if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
- result |= set_sparse_flag(sbuf);
- } else {
- result |= dos_mode_from_sbuf(conn, path, sbuf);
+#ifdef HAVE_STAT_DOS_FLAGS
+ used_stat_dos_flags = get_stat_dos_flags(conn, path, sbuf, &result);
+#endif
+ if (!used_stat_dos_flags) {
+ /* Get the DOS attributes from an EA by preference. */
+ if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
+ result |= set_sparse_flag(sbuf);
+ } else {
+ result |= dos_mode_from_sbuf(conn, path, sbuf);
+ }
}
@@ -468,6 +585,23 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
return(0);
}
+#ifdef HAVE_STAT_DOS_FLAGS
+ {
+ bool attributes_changed;
+
+ if (set_stat_dos_flags(conn, fname, st, dosmode,
+ &attributes_changed))
+ {
+ if (!newfile && attributes_changed) {
+ notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
+ }
+ st->st_mode = unixmode;
+ return 0;
+ }
+ }
+#endif
+
/* Store the DOS attributes in an EA by preference. */
if (set_ea_dos_attribute(conn, fname, st, dosmode)) {
if (!newfile) {