r3939: - added "posix:fakeoplocks" option for testing with oplocks forced on
authorAndrew Tridgell <tridge@samba.org>
Wed, 24 Nov 2004 06:09:14 +0000 (06:09 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:06:06 +0000 (13:06 -0500)
- added support for sticky write times after a setfileinfo, by using a
  write_time field in the DosAttrib xattr structure.
(This used to be commit 4a52fae82d8305e999f94f1947daa21dab54cdfd)

source4/include/smb.h
source4/librpc/idl/xattr.idl
source4/ntvfs/posix/pvfs_fileinfo.c
source4/ntvfs/posix/pvfs_open.c
source4/ntvfs/posix/pvfs_setfileinfo.c
source4/ntvfs/posix/pvfs_xattr.c
source4/ntvfs/posix/vfs_posix.c
source4/ntvfs/posix/vfs_posix.h

index 1fc43fd2f3954ea70c3f105a4817b51e13ee2d97..fb30ad1c6714e5ea4ac36196027dace6570b5de2 100644 (file)
@@ -518,7 +518,6 @@ typedef uint64_t HYPER_T;
 #define NEGOTIATE_SECURITY_SIGNATURES_REQUIRED 0x08
 
 /* NT Flags2 bits - cifs6.txt section 3.1.2 */
-   
 #define FLAGS2_LONG_PATH_COMPONENTS    0x0001
 #define FLAGS2_EXTENDED_ATTRIBUTES     0x0002
 #define FLAGS2_SMB_SECURITY_SIGNATURES 0x0004
@@ -529,10 +528,8 @@ typedef uint64_t HYPER_T;
 #define FLAGS2_32_BIT_ERROR_CODES      0x4000 
 #define FLAGS2_UNICODE_STRINGS         0x8000
 
-#define FLAGS2_WIN2K_SIGNATURE         0xC852 /* Hack alert ! For now... JRA. */
-
-/* Capabilities.  see ftp.microsoft.com/developr/drg/cifs/cifs/cifs4.txt */
 
+/* CIFS protocol capabilities */
 #define CAP_RAW_MODE           0x00000001
 #define CAP_MPX_MODE           0x00000002
 #define CAP_UNICODE            0x00000004
@@ -551,7 +548,7 @@ typedef uint64_t HYPER_T;
 #define CAP_EXTENDED_SECURITY  0x80000000
 
 /*
- * Global value meaing that the smb_uid field should be
+ * Global value meaning that the smb_uid field should be
  * ingored (in share level security and protocol level == CORE)
  */
 
@@ -559,24 +556,20 @@ typedef uint64_t HYPER_T;
 #define VUID_OFFSET 100 /* Amount to bias returned vuid numbers */
 
 /* Lock types. */
-#define LOCKING_ANDX_SHARED_LOCK 0x1
-#define LOCKING_ANDX_OPLOCK_RELEASE 0x2
-#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x4
-#define LOCKING_ANDX_CANCEL_LOCK 0x8
-#define LOCKING_ANDX_LARGE_FILES 0x10
-
-/* Oplock levels */
-#define OPLOCKLEVEL_NONE 0
-#define OPLOCKLEVEL_II 1
+#define LOCKING_ANDX_SHARED_LOCK     0x01
+#define LOCKING_ANDX_OPLOCK_RELEASE  0x02
+#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04
+#define LOCKING_ANDX_CANCEL_LOCK     0x08
+#define LOCKING_ANDX_LARGE_FILES     0x10
 
 /*
  * Bits we test with.
  */
 
-#define NO_OPLOCK 0
-#define EXCLUSIVE_OPLOCK 1
-#define BATCH_OPLOCK 2
-#define LEVEL_II_OPLOCK 4
+#define OPLOCK_NONE      0
+#define OPLOCK_EXCLUSIVE 1
+#define OPLOCK_BATCH     2
+#define OPLOCK_LEVEL_II  4
 
 #define CORE_OPLOCK_GRANTED (1<<5)
 #define EXTENDED_OPLOCK_GRANTED (1<<15)
index f7bc38605f70c5edc66c31952d0b24ea6e52db2a..501ac2ab7dc032cbf47078004b76fb77dd572baf 100644 (file)
@@ -19,6 +19,7 @@ interface xattr
        /* we store basic dos attributes in a DosAttrib xattr. By
           using a union we can cope with new version of this
           structure more easily */
+
        typedef struct {
                uint32 attrib;
                uint32 ea_size;
@@ -28,8 +29,23 @@ interface xattr
                NTTIME change_time;
        } xattr_DosInfo1;
 
+       const int XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME = 0x1;
+
+       typedef struct {
+               uint32     flags;
+               uint32     attrib;
+               uint32     ea_size;
+               uint64     size;
+               uint64     alloc_size;
+               NTTIME     create_time;
+               NTTIME     change_time;
+               NTTIME     write_time; /* only used when sticky write time is set */
+               utf8string name;       /* will be used for case-insensitive speedup */
+       } xattr_DosInfo2;
+
        typedef union {
                [case(1)] xattr_DosInfo1 info1;
+               [case(2)] xattr_DosInfo2 info2;
        } xattr_DosInfo;
 
        typedef [public] struct {
@@ -77,7 +93,7 @@ interface xattr
        } xattr_DosStreams;
 
 
-       /* we store the NT ACL a NTAcl xattr. It is versioned so we
+       /* we store the NT ACL a NTACL xattr. It is versioned so we
           can later add other acl attribs (such as posix acl mapping)
           
           we put this xattr in the security namespace to ensure that
index 32c7ae34fa2991aae27dce803ad32fc439a425cf..fa454441598e48b72cc19a73567674b5c64c4930 100644 (file)
@@ -97,6 +97,7 @@ NTSTATUS pvfs_fill_dos_info(struct pvfs_state *pvfs, struct pvfs_filename *name,
        name->dos.nlink = name->st.st_nlink;
        name->dos.ea_size = 0;
        name->dos.file_id = (((uint64_t)name->st.st_dev)<<32) | name->st.st_ino;
+       name->dos.flags = 0;
 
        return pvfs_dosattrib_load(pvfs, name, fd);
 }
index 5a23ffaa677ae504fc1dc5eff3d91d66391be390..3d0e444d29959beee4b6dae945dbd8884136746d 100644 (file)
@@ -26,6 +26,7 @@
 #include "system/filesys.h"
 #include "dlinklist.h"
 #include "messages.h"
+#include "librpc/gen_ndr/ndr_xattr.h"
 
 /*
   create file handles with convenient numbers for sniffers
@@ -160,15 +161,16 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        f->share_access  = io->generic.in.share_access;
        f->impersonation = io->generic.in.impersonation;
 
-       f->handle->pvfs           = pvfs;
-       f->handle->name           = talloc_steal(f->handle, name);
-       f->handle->fd             = -1;
-       f->handle->odb_locking_key    = data_blob(NULL, 0);
-       f->handle->brl_locking_key    = data_blob(NULL, 0);
-       f->handle->create_options = io->generic.in.create_options;
-       f->handle->seek_offset    = 0;
-       f->handle->position       = 0;
-       f->handle->mode           = 0;
+       f->handle->pvfs              = pvfs;
+       f->handle->name              = talloc_steal(f->handle, name);
+       f->handle->fd                = -1;
+       f->handle->odb_locking_key   = data_blob(NULL, 0);
+       f->handle->brl_locking_key   = data_blob(NULL, 0);
+       f->handle->create_options    = io->generic.in.create_options;
+       f->handle->seek_offset       = 0;
+       f->handle->position          = 0;
+       f->handle->mode              = 0;
+       f->handle->sticky_write_time = False;
 
        DLIST_ADD(pvfs->open_files, f);
 
@@ -201,7 +203,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        /* the open succeeded, keep this handle permanently */
        talloc_steal(pvfs, f);
 
-       io->generic.out.oplock_level  = NO_OPLOCK;
+       io->generic.out.oplock_level  = OPLOCK_NONE;
        io->generic.out.fnum          = f->fnum;
        io->generic.out.create_action = create_action;
        io->generic.out.create_time   = name->dos.create_time;
@@ -225,6 +227,16 @@ static int pvfs_handle_destructor(void *p)
 {
        struct pvfs_file_handle *h = p;
 
+       /* the write time is no longer sticky */
+       if (h->sticky_write_time) {
+               NTSTATUS status;
+               status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
+               if (NT_STATUS_IS_OK(status)) {
+                       h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
+                       pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
+               }
+       }
+       
        if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
            h->name->stream_name) {
                NTSTATUS status;
@@ -515,6 +527,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        f->handle->position          = 0;
        f->handle->mode              = 0;
        f->handle->have_opendb_entry = True;
+       f->handle->sticky_write_time = False;
 
        DLIST_ADD(pvfs->open_files, f);
 
@@ -523,7 +536,12 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        talloc_set_destructor(f, pvfs_fnum_destructor);
        talloc_set_destructor(f->handle, pvfs_handle_destructor);
 
-       io->generic.out.oplock_level  = NO_OPLOCK;
+       
+       if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
+               io->generic.out.oplock_level  = OPLOCK_EXCLUSIVE;
+       } else {
+               io->generic.out.oplock_level  = OPLOCK_NONE;
+       }
        io->generic.out.fnum          = f->fnum;
        io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
        io->generic.out.create_time   = name->dos.create_time;
@@ -685,7 +703,7 @@ static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
 
        name = f->handle->name;
 
-       io->generic.out.oplock_level  = NO_OPLOCK;
+       io->generic.out.oplock_level  = OPLOCK_NONE;
        io->generic.out.fnum          = f->fnum;
        io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
        io->generic.out.create_time   = name->dos.create_time;
@@ -963,7 +981,9 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        f->handle->create_options    = io->generic.in.create_options;
        f->handle->seek_offset       = 0;
        f->handle->position          = 0;
+       f->handle->mode              = 0;
        f->handle->have_opendb_entry = False;
+       f->handle->sticky_write_time = False;
 
        /* form the lock context used for byte range locking and
           opendb locking */
@@ -1063,7 +1083,11 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
            
        talloc_free(lck);
 
-       io->generic.out.oplock_level  = NO_OPLOCK;
+       if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
+               io->generic.out.oplock_level  = OPLOCK_EXCLUSIVE;
+       } else {
+               io->generic.out.oplock_level  = OPLOCK_NONE;
+       }
        io->generic.out.fnum          = f->fnum;
        io->generic.out.create_action = stream_existed?
                NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
@@ -1112,8 +1136,12 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
                unix_times.actime = 0;
                unix_times.modtime = io->close.in.write_time;
                utime(f->handle->name->full_name, &unix_times);
+       } else if (f->handle->sticky_write_time) {
+               unix_times.actime = 0;
+               unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
+               utime(f->handle->name->full_name, &unix_times);
        }
-       
+
        talloc_free(f);
 
        return NT_STATUS_OK;
index cc1b69b8ea0cd5fdfd2a41f031bda851ac9f8807..5a758a6b7024ee407abd831fe1ad3784e2f7ceea 100644 (file)
@@ -245,6 +245,8 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
                }
                if (info->basic_info.in.write_time) {
                        newstats.dos.write_time = info->basic_info.in.write_time;
+                       newstats.dos.flags |= XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
+                       h->sticky_write_time = True;
                }
                if (info->basic_info.in.change_time) {
                        newstats.dos.change_time = info->basic_info.in.change_time;
index fda15a2e92f828e535913b44cf333328d64bd836..47549499e6af58e39db0b16bbf685878671a25d4 100644 (file)
@@ -183,6 +183,7 @@ NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name
        struct xattr_DosAttrib attrib;
        TALLOC_CTX *mem_ctx = talloc(name, 0);
        struct xattr_DosInfo1 *info1;
+       struct xattr_DosInfo2 *info2;
 
        if (name->stream_name != NULL) {
                name->stream_exists = False;
@@ -233,6 +234,27 @@ NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name
                if (info1->change_time != 0) {
                        name->dos.change_time = info1->change_time;
                }
+               name->dos.flags = 0;
+               break;
+
+       case 2:
+               info2 = &attrib.info.info2;
+               name->dos.attrib = pvfs_attrib_normalise(info2->attrib);
+               name->dos.ea_size = info2->ea_size;
+               if (name->st.st_size == info2->size) {
+                       name->dos.alloc_size = 
+                               pvfs_round_alloc_size(pvfs, info2->alloc_size);
+               }
+               if (info2->create_time != 0) {
+                       name->dos.create_time = info2->create_time;
+               }
+               if (info2->change_time != 0) {
+                       name->dos.change_time = info2->change_time;
+               }
+               name->dos.flags = info2->flags;
+               if (name->dos.flags & XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME) {
+                       name->dos.write_time = info2->write_time;
+               }
                break;
 
        default:
@@ -255,23 +277,26 @@ NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name
 NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
 {
        struct xattr_DosAttrib attrib;
-       struct xattr_DosInfo1 *info1;
+       struct xattr_DosInfo2 *info2;
 
        if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) {
                return NT_STATUS_OK;
        }
 
-       attrib.version = 1;
-       info1 = &attrib.info.info1;
+       attrib.version = 2;
+       info2 = &attrib.info.info2;
 
        name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib);
 
-       info1->attrib      = name->dos.attrib;
-       info1->ea_size     = name->dos.ea_size;
-       info1->size        = name->st.st_size;
-       info1->alloc_size  = name->dos.alloc_size;
-       info1->create_time = name->dos.create_time;
-       info1->change_time = name->dos.change_time;
+       info2->attrib      = name->dos.attrib;
+       info2->ea_size     = name->dos.ea_size;
+       info2->size        = name->st.st_size;
+       info2->alloc_size  = name->dos.alloc_size;
+       info2->create_time = name->dos.create_time;
+       info2->change_time = name->dos.change_time;
+       info2->write_time  = name->dos.write_time;
+       info2->flags       = name->dos.flags;
+       info2->name        = "";
 
        return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 
                                   XATTR_DOSATTRIB_NAME, &attrib, 
index e19b0739c7504c7f5a893513b4ea3fc94798c999..95b4c20551fa113545e100e0753e771d94490cec 100644 (file)
@@ -44,6 +44,10 @@ static void pvfs_setup_options(struct pvfs_state *pvfs)
        if (lp_strict_locking(snum)) pvfs->flags |= PVFS_FLAG_STRICT_LOCKING;
        if (lp_ci_filesystem(snum))  pvfs->flags |= PVFS_FLAG_CI_FILESYSTEM;
 
+       if (lp_parm_bool(snum, "posix", "fakeoplocks", True)) {
+               pvfs->flags |= PVFS_FLAG_FAKE_OPLOCKS;
+       }
+
 #if HAVE_XATTR_SUPPORT
        if (lp_parm_bool(snum, "posix", "xattr", True)) pvfs->flags |= PVFS_FLAG_XATTR_ENABLE;
 #endif
index a79c53ca2e1e9084bfbe5c099bc2ffc88a1f684a..1ae552b116ea5f774f0e421b937a6c475f830d2d 100644 (file)
@@ -58,7 +58,6 @@ struct pvfs_state {
        uint32_t fs_attribs;
 };
 
-
 /* this is the basic information needed about a file from the filesystem */
 struct pvfs_dos_fileinfo {
        NTTIME create_time;
@@ -70,6 +69,7 @@ struct pvfs_dos_fileinfo {
        uint32_t nlink;
        uint32_t ea_size;
        uint64_t file_id;
+       uint32_t flags;
 };
 
 /*
@@ -120,6 +120,9 @@ struct pvfs_file_handle {
 
        /* we need this hook back to our parent for lock destruction */
        struct pvfs_state *pvfs;
+
+       /* have we set a sticky write time that we should remove on close */
+       BOOL sticky_write_time;
 };
 
 /* open file state */
@@ -189,6 +192,7 @@ struct pvfs_mangle_context {
 #define PVFS_FLAG_STRICT_SYNC    (1<<5)
 #define PVFS_FLAG_STRICT_LOCKING (1<<6)
 #define PVFS_FLAG_XATTR_ENABLE   (1<<7)
+#define PVFS_FLAG_FAKE_OPLOCKS   (1<<8)
 
 /* forward declare some anonymous structures */
 struct pvfs_dir;