audit_logging: Remove debug log header and JSON Authentication: prefix
[amitay/samba.git] / source3 / modules / vfs_syncops.c
index c098159ff66a6f024f880067b5ead29897759f0e..f94588c60ed09edfe2b8f0feb320678613ab82b6 100644 (file)
@@ -2,6 +2,7 @@
  * ensure meta data operations are performed synchronously
  *
  * Copyright (C) Andrew Tridgell     2007
+ * Copyright (C) Christian Ambach, 2010-2011
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,6 +20,8 @@
  */
 
 #include "includes.h"
+#include "system/filesys.h"
+#include "smbd/smbd.h"
 
 /*
 
 
   On those filesystems this module provides a way to perform those
   operations safely.  
- */
 
-/*
   most of the performance loss with this module is in fsync on close(). 
-  You can disable that with syncops:onclose = no
+  You can disable that with
+     syncops:onclose = no
+  that can be set either globally or per share.
+
+  On certain filesystems that only require the last data written to be
+  fsync()'ed, you can disable the metadata synchronization of this module with
+     syncops:onmeta = no
+  This option can be set either globally or per share.
+
+  you can also disable the module completely for a share with
+     syncops:disable = true
+
  */
-static bool sync_onclose;
+
+struct syncops_config_data {
+       bool onclose;
+       bool onmeta;
+       bool disable;
+};
 
 /*
   given a filename, find the parent directory
@@ -91,19 +108,6 @@ static void syncops_two_names(const char *name1, const char *name2)
        talloc_free(tmp_ctx);
 }
 
-/*
-  sync two meta data changes for 1 names
- */
-static void syncops_name(const char *name)
-{
-       char *parent;
-       parent = parent_dir(NULL, name);
-       if (parent) {
-               syncops_sync_directory(parent);
-               talloc_free(parent);
-       }
-}
-
 /*
   sync two meta data changes for 1 names
  */
@@ -125,37 +129,71 @@ static int syncops_rename(vfs_handle_struct *handle,
                          const struct smb_filename *smb_fname_src,
                          const struct smb_filename *smb_fname_dst)
 {
-       int ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
-       if (ret == 0) {
+
+       int ret;
+       struct syncops_config_data *config;
+
+       SMB_VFS_HANDLE_GET_DATA(handle, config,
+                               struct syncops_config_data,
+                               return -1);
+
+       ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
+       if (ret == 0 && config->onmeta && !config->disable) {
                syncops_two_names(smb_fname_src->base_name,
                                  smb_fname_dst->base_name);
        }
        return ret;
 }
 
-/* handle the rest with a macro */
-#define SYNCOPS_NEXT(op, fname, args) do {   \
-       int ret = SMB_VFS_NEXT_ ## op args; \
-       if (ret == 0 && fname) syncops_name(fname); \
-       return ret; \
-} while (0)
-
 #define SYNCOPS_NEXT_SMB_FNAME(op, fname, args) do {   \
-       int ret = SMB_VFS_NEXT_ ## op args; \
-       if (ret == 0 && fname) syncops_smb_fname(fname); \
+       int ret; \
+       struct syncops_config_data *config; \
+       SMB_VFS_HANDLE_GET_DATA(handle, config, \
+                               struct syncops_config_data, \
+                               return -1); \
+       ret = SMB_VFS_NEXT_ ## op args; \
+       if (ret == 0 \
+       && config->onmeta && !config->disable \
+       && fname) syncops_smb_fname(fname); \
        return ret; \
 } while (0)
 
 static int syncops_symlink(vfs_handle_struct *handle,
-                          const char *oldname, const char *newname)
+                       const char *link_contents,
+                       const struct smb_filename *new_smb_fname)
 {
-       SYNCOPS_NEXT(SYMLINK, newname, (handle, oldname, newname));
+       int ret;
+       struct syncops_config_data *config;
+
+       SMB_VFS_HANDLE_GET_DATA(handle, config,
+                               struct syncops_config_data,
+                               return -1);
+
+       ret = SMB_VFS_NEXT_SYMLINK(handle, link_contents, new_smb_fname);
+       if (ret == 0 && config->onmeta && !config->disable) {
+               syncops_two_names(link_contents,
+                                 new_smb_fname->base_name);
+       }
+       return ret;
 }
 
 static int syncops_link(vfs_handle_struct *handle,
-                        const char *oldname, const char *newname)
+                       const struct smb_filename *old_smb_fname,
+                       const struct smb_filename *new_smb_fname)
 {
-       SYNCOPS_NEXT(LINK, newname, (handle, oldname, newname));
+       int ret;
+       struct syncops_config_data *config;
+
+       SMB_VFS_HANDLE_GET_DATA(handle, config,
+                               struct syncops_config_data,
+                               return -1);
+
+       ret = SMB_VFS_NEXT_LINK(handle, old_smb_fname, new_smb_fname);
+       if (ret == 0 && config->onmeta && !config->disable) {
+               syncops_two_names(old_smb_fname->base_name,
+                                 new_smb_fname->base_name);
+       }
+       return ret;
 }
 
 static int syncops_open(vfs_handle_struct *handle,
@@ -173,25 +211,37 @@ static int syncops_unlink(vfs_handle_struct *handle,
 }
 
 static int syncops_mknod(vfs_handle_struct *handle,
-                        const char *fname, mode_t mode, SMB_DEV_T dev)
+                       const struct smb_filename *smb_fname,
+                       mode_t mode,
+                       SMB_DEV_T dev)
 {
-        SYNCOPS_NEXT(MKNOD, fname, (handle, fname, mode, dev));
+        SYNCOPS_NEXT_SMB_FNAME(MKNOD,
+                       smb_fname, (handle, smb_fname, mode, dev));
 }
 
-static int syncops_mkdir(vfs_handle_struct *handle,  const char *fname, mode_t mode)
+static int syncops_mkdir(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname,
+                       mode_t mode)
 {
-        SYNCOPS_NEXT(MKDIR, fname, (handle, fname, mode));
+        SYNCOPS_NEXT_SMB_FNAME(MKDIR, smb_fname, (handle, smb_fname, mode));
 }
 
-static int syncops_rmdir(vfs_handle_struct *handle,  const char *fname)
+static int syncops_rmdir(vfs_handle_struct *handle,
+                       const struct smb_filename *smb_fname)
 {
-        SYNCOPS_NEXT(RMDIR, fname, (handle, fname));
+        SYNCOPS_NEXT_SMB_FNAME(RMDIR, smb_fname, (handle, smb_fname));
 }
 
 /* close needs to be handled specially */
 static int syncops_close(vfs_handle_struct *handle, files_struct *fsp)
 {
-       if (fsp->can_write && sync_onclose) {
+       struct syncops_config_data *config;
+
+       SMB_VFS_HANDLE_GET_DATA(handle, config,
+                               struct syncops_config_data,
+                               return -1);
+
+       if (fsp->can_write && config->onclose) {
                /* ideally we'd only do this if we have written some
                 data, but there is no flag for that in fsp yet. */
                fsync(fsp->fh->fd);
@@ -199,20 +249,55 @@ static int syncops_close(vfs_handle_struct *handle, files_struct *fsp)
        return SMB_VFS_NEXT_CLOSE(handle, fsp);
 }
 
+static int syncops_connect(struct vfs_handle_struct *handle, const char *service,
+                          const char *user)
+{
+
+       struct syncops_config_data *config;
+       int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
+       if (ret < 0) {
+               return ret;
+       }
+
+       config = talloc_zero(handle->conn, struct syncops_config_data);
+       if (!config) {
+               SMB_VFS_NEXT_DISCONNECT(handle);
+               DEBUG(0, ("talloc_zero() failed\n"));
+               return -1;
+       }
+
+       config->onclose = lp_parm_bool(SNUM(handle->conn), "syncops",
+                                       "onclose", true);
+
+       config->onmeta = lp_parm_bool(SNUM(handle->conn), "syncops",
+                                       "onmeta", true);
+
+       config->disable = lp_parm_bool(SNUM(handle->conn), "syncops",
+                                       "disable", false);
+
+       SMB_VFS_HANDLE_SET_DATA(handle, config,
+                               NULL, struct syncops_config_data,
+                               return -1);
+
+       return 0;
+
+}
 
 static struct vfs_fn_pointers vfs_syncops_fns = {
-        .mkdir = syncops_mkdir,
-        .rmdir = syncops_rmdir,
-        .open = syncops_open,
-        .rename = syncops_rename,
-        .unlink = syncops_unlink,
-        .symlink = syncops_symlink,
-        .link = syncops_link,
-        .mknod = syncops_mknod,
+       .connect_fn = syncops_connect,
+       .mkdir_fn = syncops_mkdir,
+       .rmdir_fn = syncops_rmdir,
+       .open_fn = syncops_open,
+       .rename_fn = syncops_rename,
+       .unlink_fn = syncops_unlink,
+       .symlink_fn = syncops_symlink,
+       .link_fn = syncops_link,
+       .mknod_fn = syncops_mknod,
        .close_fn = syncops_close,
 };
 
-NTSTATUS vfs_syncops_init(void)
+static_decl_vfs;
+NTSTATUS vfs_syncops_init(TALLOC_CTX *ctx)
 {
        NTSTATUS ret;
 
@@ -222,7 +307,5 @@ NTSTATUS vfs_syncops_init(void)
        if (!NT_STATUS_IS_OK(ret))
                return ret;
 
-       sync_onclose = lp_parm_bool(-1, "syncops", "onclose", true);
-       
        return ret;
 }