#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
#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
#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)
*/
#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)
/* 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;
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 {
} 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
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);
}
#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
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);
/* 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;
{
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;
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);
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;
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;
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 */
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;
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;
}
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;
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;
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:
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,
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
uint32_t fs_attribs;
};
-
/* this is the basic information needed about a file from the filesystem */
struct pvfs_dos_fileinfo {
NTTIME create_time;
uint32_t nlink;
uint32_t ea_size;
uint64_t file_id;
+ uint32_t flags;
};
/*
/* 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 */
#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;