Fix bug #7892 - open_file_fchmod() leaves a stale lock.
[samba.git] / source3 / smbd / dosmode.c
index 555718bd83a02f2760365e3c83984003fc25326e..2092712fbdecb9fd718931c614aa69b1432f7b9d 100644 (file)
 
 #include "includes.h"
 
+extern enum protocol_types Protocol;
+
+static uint32_t filter_mode_by_protocol(uint32_t mode)
+{
+       if (Protocol <= PROTOCOL_LANMAN2) {
+               DEBUG(10,("filter_mode_by_protocol: "
+                       "filtering result 0x%x to 0x%x\n",
+                       (unsigned int)mode,
+                       (unsigned int)(mode & 0x3f) ));
+               mode &= 0x3f;
+       }
+       return mode;
+}
+
 static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
 {
 #if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
@@ -287,7 +301,7 @@ static bool set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_
                 * are not violating security in doing the setxattr.
                 */
 
-               if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, path, sbuf,
+               if (!NT_STATUS_IS_OK(open_file_fchmod(conn, path, sbuf,
                                                      &fsp)))
                        return ret;
                become_root();
@@ -295,7 +309,7 @@ static bool set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_
                        ret = True;
                }
                unbecome_root();
-               close_file_fchmod(NULL, fsp);
+               close_file(NULL, fsp, NORMAL_CLOSE);
                return ret;
        }
        DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path));
@@ -325,8 +339,10 @@ uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT
                } else {
                        p = path;
                }
-               
-               if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
+
+               /* Only . and .. are not hidden. */
+               if (p[0] == '.' && !((p[1] == '\0') ||
+                               (p[1] == '.' && p[2] == '\0'))) {
                        result |= aHIDDEN;
                }
        }
@@ -339,6 +355,12 @@ uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT
                result |= aHIDDEN;
        }
 
+       if (result == 0) {
+               result = FILE_ATTRIBUTE_NORMAL;
+       }
+
+       result = filter_mode_by_protocol(result);
+
        DEBUG(8,("dos_mode_msdfs returning "));
 
        if (result & aHIDDEN) DEBUG(8, ("h"));
@@ -484,8 +506,10 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
                } else {
                        p = path;
                }
-               
-               if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
+
+               /* Only . and .. are not hidden. */
+               if (p[0] == '.' && !((p[1] == '\0') ||
+                               (p[1] == '.' && p[2] == '\0'))) {
                        result |= aHIDDEN;
                }
        }
@@ -514,6 +538,12 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
                result |= aHIDDEN;
        }
 
+       if (result == 0) {
+               result = FILE_ATTRIBUTE_NORMAL;
+       }
+
+       result = filter_mode_by_protocol(result);
+
        DEBUG(8,("dos_mode returning "));
 
        if (result & aHIDDEN) DEBUG(8, ("h"));
@@ -675,18 +705,15 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
                 * We need to open the file with write access whilst
                 * still in our current user context. This ensures we
                 * are not violating security in doing the fchmod.
-                * This file open does *not* break any oplocks we are
-                * holding. We need to review this.... may need to
-                * break batch oplocks open by others. JRA.
                 */
                files_struct *fsp;
-               if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, st,
+               if (!NT_STATUS_IS_OK(open_file_fchmod(conn, fname, st,
                                                      &fsp)))
                        return -1;
                become_root();
                ret = SMB_VFS_FCHMOD(fsp, unixmode);
                unbecome_root();
-               close_file_fchmod(NULL, fsp);
+               close_file(NULL, fsp, NORMAL_CLOSE);
                if (!newfile) {
                        notify_fname(conn, NOTIFY_ACTION_MODIFIED,
                                FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);