smb: rename NTCREATEX_OPTIONS_PRIVATE_DENY_FCB to NTCREATEX_FLAG_DENY_FCB
[samba.git] / source4 / ntvfs / ntvfs_generic.c
index 01c3a16433de704ff7fd00478d75e2b9eea18ad8..de0ae2ce8280363c4eaf7b4afe3d11b7e0078cfb 100644 (file)
@@ -35,6 +35,8 @@
 #include "libcli/smb2/smb2.h"
 #include "libcli/smb2/smb2_calls.h"
 
+#undef strcasecmp
+
 /* a second stage function converts from the out parameters of the generic
    call onto the out parameters of the specific call made */
 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
@@ -56,7 +58,8 @@ struct ntvfs_map_async {
 */
 static void ntvfs_map_async_send(struct ntvfs_request *req)
 {
-       struct ntvfs_map_async *m = req->async_states->private_data;
+       struct ntvfs_map_async *m = talloc_get_type(req->async_states->private_data,
+                                   struct ntvfs_map_async);
 
        ntvfs_async_state_pop(req);
 
@@ -105,7 +108,8 @@ static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS statu
 
        /* the backend is replying immediately. call the 2nd stage function after popping our local
           async state */
-       m = req->async_states->private_data;
+       m = talloc_get_type(req->async_states->private_data,
+                           struct ntvfs_map_async);
 
        ntvfs_async_state_pop(req);
 
@@ -146,7 +150,7 @@ static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
        time_t write_time = 0;
        uint32_t set_size = 0;
        union smb_setfileinfo *sf;
-       uint_t state;
+       unsigned int state;
 
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -207,8 +211,22 @@ static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
                break;
 
        case RAW_OPEN_SMB2:
+               ZERO_STRUCT(io->smb2.out);
                io->smb2.out.file.ntvfs         = io2->generic.out.file.ntvfs;
-               io->smb2.out.oplock_level       = 0;
+               switch (io2->generic.out.oplock_level) {
+               case BATCH_OPLOCK_RETURN:
+                       io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
+                       break;
+               case EXCLUSIVE_OPLOCK_RETURN:
+                       io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+                       break;
+               case LEVEL_II_OPLOCK_RETURN:
+                       io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
+                       break;
+               default:
+                       io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+                       break;
+               }
                io->smb2.out.reserved           = 0;
                io->smb2.out.create_action      = io2->generic.out.create_action;
                io->smb2.out.create_time        = io2->generic.out.create_time;
@@ -219,7 +237,9 @@ static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
                io->smb2.out.size               = io2->generic.out.size;
                io->smb2.out.file_attr          = io2->generic.out.attrib;
                io->smb2.out.reserved2          = 0;
-               io->smb2.out.blob               = data_blob(NULL, 0);
+               io->smb2.out.maximal_access     = io2->generic.out.maximal_access;
+               memcpy(io->smb2.out.on_disk_id, io2->generic.out.on_disk_id,
+                      sizeof(io2->generic.out.on_disk_id));
                break;
 
        default:
@@ -239,7 +259,7 @@ static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
                sf->standard.in.create_time = 0;
                sf->standard.in.write_time  = write_time;
                sf->standard.in.access_time = 0;
-               status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
+               status = ntvfs->ops->setfileinfo_fn(ntvfs, req, sf);
        }
 
        if (set_size != 0) {
@@ -248,7 +268,7 @@ static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
                sf->generic.level            = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
                sf->generic.in.file.ntvfs    = io2->generic.out.file.ntvfs;
                sf->end_of_file_info.in.size = set_size;
-               status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
+               status = ntvfs->ops->setfileinfo_fn(ntvfs, req, sf);
                if (NT_STATUS_IS_OK(status)) {
                        io->openx.out.size = io->openx.in.size;
                }
@@ -267,6 +287,9 @@ static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
                               uint16_t open_func, const char *fname,
                               union smb_open *io2)
 {
+       io2->generic.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+       io2->generic.in.private_flags = 0;
+
        if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
                io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
        }
@@ -309,8 +332,8 @@ static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
                break;
        case OPENX_MODE_DENY_DOS:
                /* DENY_DOS is quite strange - it depends on the filename! */
-               io2->generic.in.create_options |= 
-                       NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
+               io2->generic.in.private_flags |=
+                       NTCREATEX_FLAG_DENY_DOS;
                if (is_exe_filename(fname)) {
                        io2->generic.in.share_access = 
                                NTCREATEX_SHARE_ACCESS_READ | 
@@ -324,7 +347,7 @@ static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
                }
                break;
        case OPENX_MODE_DENY_FCB:
-               io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
+               io2->generic.in.private_flags |= NTCREATEX_FLAG_DENY_FCB;
                io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
                break;
        default:
@@ -397,7 +420,7 @@ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
                io2->generic.in.file_attr = io->openx.in.file_attrs;
                io2->generic.in.fname = io->openx.in.fname;
                
-               status = ntvfs->ops->open(ntvfs, req, io2);
+               status = ntvfs->ops->open_fn(ntvfs, req, io2);
                break;
                
                
@@ -414,7 +437,7 @@ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
                io2->generic.in.file_attr = io->openold.in.search_attrs;
                io2->generic.in.fname = io->openold.in.fname;
 
-               status = ntvfs->ops->open(ntvfs, req, io2);
+               status = ntvfs->ops->open_fn(ntvfs, req, io2);
                break;
 
        case RAW_OPEN_T2OPEN:
@@ -440,7 +463,7 @@ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
                io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
                io2->generic.in.ea_list->eas     = io->t2open.in.eas;
 
-               status = ntvfs->ops->open(ntvfs, req, io2);
+               status = ntvfs->ops->open_fn(ntvfs, req, io2);
                break;
 
        case RAW_OPEN_MKNEW:
@@ -453,7 +476,7 @@ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
                io2->generic.in.share_access = 
                        NTCREATEX_SHARE_ACCESS_READ | 
                        NTCREATEX_SHARE_ACCESS_WRITE;
-               status = ntvfs->ops->open(ntvfs, req, io2);
+               status = ntvfs->ops->open_fn(ntvfs, req, io2);
                break;
 
        case RAW_OPEN_CREATE:
@@ -466,7 +489,7 @@ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
                io2->generic.in.share_access = 
                        NTCREATEX_SHARE_ACCESS_READ | 
                        NTCREATEX_SHARE_ACCESS_WRITE;
-               status = ntvfs->ops->open(ntvfs, req, io2);
+               status = ntvfs->ops->open_fn(ntvfs, req, io2);
                break;
 
        case RAW_OPEN_CTEMP:
@@ -482,13 +505,24 @@ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
                io2->generic.in.share_access = 
                        NTCREATEX_SHARE_ACCESS_READ | 
                        NTCREATEX_SHARE_ACCESS_WRITE;
-               status = ntvfs->ops->open(ntvfs, req, io2);
+               status = ntvfs->ops->open_fn(ntvfs, req, io2);
                break;
        case RAW_OPEN_SMB2:
-               io2->generic.in.flags           = 0;
-               io2->generic.in.root_fid        = 0;
+               switch (io->smb2.in.oplock_level) {
+               case SMB2_OPLOCK_LEVEL_BATCH:
+                       io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
+                                               NTCREATEX_FLAGS_REQUEST_OPLOCK;
+                       break;
+               case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
+                       io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
+                       break;
+               default:
+                       io2->generic.in.flags = 0;
+                       break;
+               }
+               io2->generic.in.root_fid.fnum   = 0;
                io2->generic.in.access_mask     = io->smb2.in.desired_access;
-               io2->generic.in.alloc_size      = 0;
+               io2->generic.in.alloc_size      = io->smb2.in.alloc_size;
                io2->generic.in.file_attr       = io->smb2.in.file_attributes;
                io2->generic.in.share_access    = io->smb2.in.share_access;
                io2->generic.in.open_disposition= io->smb2.in.create_disposition;
@@ -496,9 +530,31 @@ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
                io2->generic.in.impersonation   = io->smb2.in.impersonation_level;
                io2->generic.in.security_flags  = 0;
                io2->generic.in.fname           = io->smb2.in.fname;
-               io2->generic.in.sec_desc        = NULL;
-               io2->generic.in.ea_list         = NULL;
-               status = ntvfs->ops->open(ntvfs, req, io2);             
+               io2->generic.in.sec_desc        = io->smb2.in.sec_desc;
+               io2->generic.in.ea_list         = &io->smb2.in.eas;
+               io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access; 
+               io2->generic.in.query_on_disk_id = io->smb2.in.query_on_disk_id;
+               io2->generic.in.private_flags   = 0;
+
+               /* we don't support timewarp yet */
+               if (io->smb2.in.timewarp != 0) {
+                       status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                       break;
+               }
+
+               /* we need to check these bits before we check the private mask */
+               if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
+                       DEBUG(2,(__location__ " create_options 0x%x not supported\n",
+                                io2->generic.in.create_options));
+                       status = NT_STATUS_NOT_SUPPORTED;
+                       break;
+               }
+
+               /* TODO: find out why only SMB2 ignores these */
+               io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
+               io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
+
+               status = ntvfs->ops->open_fn(ntvfs, req, io2);
                break;
 
        default:
@@ -511,43 +567,23 @@ done:
 
 
 /* 
-   NTVFS fsinfo generic to any mapper
+   NTVFS any to fsinfo mapper
 */
-NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
-                                  struct ntvfs_request *req,
-                                  union smb_fsinfo *fs)
+static NTSTATUS ntvfs_map_fsinfo_finish(struct ntvfs_module_context *ntvfs,
+                                     struct ntvfs_request *req,
+                                     union smb_fsinfo *fs,
+                                     union smb_fsinfo *fs2,
+                                     NTSTATUS status)
 {
-       NTSTATUS status;
-       union smb_fsinfo *fs2;
-
-       fs2 = talloc(req, union smb_fsinfo);
-       if (fs2 == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       if (fs->generic.level == RAW_QFS_GENERIC) {
-               return NT_STATUS_INVALID_LEVEL;
-       }
-       
-       /* only used by the simple backend, which doesn't do async */
-       req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
-
-       /* ask the backend for the generic info */
-       fs2->generic.level = RAW_QFS_GENERIC;
-
-       status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
        /* and convert it to the required level */
        switch (fs->generic.level) {
-       case RAW_QFS_GENERIC:
-               return NT_STATUS_INVALID_LEVEL;
-
        case RAW_QFS_DSKATTR: {
                /* map from generic to DSKATTR */
-               uint_t bpunit = 64;
+               unsigned int bpunit = 64;
 
                /* we need to scale the sizes to fit */
                for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
@@ -632,12 +668,63 @@ NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
                fs->objectid_information.out.guid = fs2->generic.out.guid;
                ZERO_STRUCT(fs->objectid_information.out.unknown);
                return NT_STATUS_OK;
-       }
 
+       case RAW_QFS_SECTOR_SIZE_INFORMATION:
+               fs->sector_size_info.out.logical_bytes_per_sector
+                                               = fs2->generic.out.block_size;
+               fs->sector_size_info.out.phys_bytes_per_sector_atomic
+                                               = fs2->generic.out.block_size;
+               fs->sector_size_info.out.phys_bytes_per_sector_perf
+                                               = fs2->generic.out.block_size;
+               fs->sector_size_info.out.fs_effective_phys_bytes_per_sector_atomic
+                                               = fs2->generic.out.block_size;
+               fs->sector_size_info.out.flags
+                                       = QFS_SSINFO_FLAGS_ALIGNED_DEVICE
+                               | QFS_SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE;
+               fs->sector_size_info.out.byte_off_sector_align = 0;
+               fs->sector_size_info.out.byte_off_partition_align = 0;
+               return NT_STATUS_OK;
+
+       case RAW_QFS_GENERIC:
+       case RAW_QFS_UNIX_INFO:
+               return NT_STATUS_INVALID_LEVEL;
+       }
 
        return NT_STATUS_INVALID_LEVEL;
 }
 
+/*
+   NTVFS fsinfo any to generic mapper
+*/
+NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
+                         struct ntvfs_request *req,
+                         union smb_fsinfo *fs)
+{
+       NTSTATUS status;
+       union smb_fsinfo *fs2;
+
+       fs2 = talloc(req, union smb_fsinfo);
+       if (fs2 == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (fs->generic.level == RAW_QFS_GENERIC) {
+               return NT_STATUS_INVALID_LEVEL;
+       }
+
+       status = ntvfs_map_async_setup(ntvfs, req, fs, fs2,
+                                      (second_stage_t)ntvfs_map_fsinfo_finish);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       /* ask the backend for the generic info */
+       fs2->generic.level = RAW_QFS_GENERIC;
+
+       status = ntvfs->ops->fsinfo_fn(ntvfs, req, fs2);
+       return ntvfs_map_async_finish(req, status);
+}
+
 
 /* 
    NTVFS fileinfo generic to any mapper
@@ -649,8 +736,6 @@ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
        int i;
        /* and convert it to the required level using results in info2 */
        switch (info->generic.level) {
-               case RAW_FILEINFO_GENERIC:
-               return NT_STATUS_INVALID_LEVEL;
        case RAW_FILEINFO_GETATTR:
                info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
                info->getattr.out.size = info2->generic.out.size;
@@ -779,6 +864,7 @@ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
                
        case RAW_FILEINFO_ALT_NAME_INFO:
        case RAW_FILEINFO_ALT_NAME_INFORMATION:
+       case RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION:
                info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
                NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
                info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
@@ -809,7 +895,7 @@ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
                                        return NT_STATUS_NO_MEMORY;
                                }
                                info->all_eas.out.eas[i].value.data = 
-                                       talloc_memdup(info->all_eas.out.eas,
+                                       (uint8_t *)talloc_memdup(info->all_eas.out.eas,
                                                info2->generic.out.eas[i].value.data,
                                                info2->generic.out.eas[i].value.length);
                                if (!info->all_eas.out.eas[i].value.data) {
@@ -844,8 +930,10 @@ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
                info->alignment_information.out.alignment_requirement =
                        info2->generic.out.alignment_requirement;
                return NT_STATUS_OK;
-#if 0  
        case RAW_FILEINFO_UNIX_BASIC:
+#if 1
+               return NT_STATUS_INVALID_LEVEL;
+#else
                info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
                info->unix_basic_info.out.num_bytes = info2->generic.out.size;
                info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
@@ -860,17 +948,45 @@ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
                info->unix_basic_info.out.permissions = info2->generic.out.permissions;
                info->unix_basic_info.out.nlink = info2->generic.out.nlink;
                return NT_STATUS_OK;
-               
+#endif
        case RAW_FILEINFO_UNIX_LINK:
+#if 1
+               return NT_STATUS_INVALID_LEVEL;
+#else
                info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
                return NT_STATUS_OK;
 #endif
+       case RAW_FILEINFO_GENERIC:
+       case RAW_FILEINFO_SEC_DESC:
+       case RAW_FILEINFO_EA_LIST:
+       case RAW_FILEINFO_UNIX_INFO2:
+       case RAW_FILEINFO_SMB2_ALL_EAS:
+       case RAW_FILEINFO_SMB2_ALL_INFORMATION:
+               return NT_STATUS_INVALID_LEVEL;
+       case RAW_FILEINFO_NORMALIZED_NAME_INFORMATION:
+               return NT_STATUS_NOT_SUPPORTED;
        }
 
        return NT_STATUS_INVALID_LEVEL;
 }
 
 /* 
+   NTVFS any to fileinfo mapper
+*/
+static NTSTATUS ntvfs_map_qfileinfo_finish(struct ntvfs_module_context *ntvfs,
+                                     struct ntvfs_request *req,
+                                     union smb_fileinfo *info,
+                                     union smb_fileinfo *info2,
+                                     NTSTATUS status)
+{
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       return ntvfs_map_fileinfo(req, info, info2);
+}
+
+/*
    NTVFS fileinfo generic to any mapper
 */
 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
@@ -889,17 +1005,33 @@ NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_INVALID_LEVEL;
        }
 
+       status = ntvfs_map_async_setup(ntvfs, req, info, info2,
+                                      (second_stage_t)ntvfs_map_qfileinfo_finish);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        /* ask the backend for the generic info */
        info2->generic.level = RAW_FILEINFO_GENERIC;
        info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
 
-       /* only used by the simple backend, which doesn't do async */
-       req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
+       status = ntvfs->ops->qfileinfo_fn(ntvfs, req, info2);
+       return ntvfs_map_async_finish(req, status);
+}
 
-       status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
+/*
+   NTVFS any to fileinfo mapper
+*/
+static NTSTATUS ntvfs_map_qpathinfo_finish(struct ntvfs_module_context *ntvfs,
+                                     struct ntvfs_request *req,
+                                     union smb_fileinfo *info,
+                                     union smb_fileinfo *info2,
+                                     NTSTATUS status)
+{
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
+
        return ntvfs_map_fileinfo(req, info, info2);
 }
 
@@ -922,18 +1054,18 @@ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_INVALID_LEVEL;
        }
 
+       status = ntvfs_map_async_setup(ntvfs, req, info, info2,
+                                      (second_stage_t)ntvfs_map_qpathinfo_finish);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        /* ask the backend for the generic info */
        info2->generic.level            = RAW_FILEINFO_GENERIC;
        info2->generic.in.file.path     = info->generic.in.file.path;
 
-       /* only used by the simple backend, which doesn't do async */
-       req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
-
-       status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-       return ntvfs_map_fileinfo(req, info, info2);
+       status = ntvfs->ops->qpathinfo_fn(ntvfs, req, info2);
+       return ntvfs_map_async_finish(req, status);
 }
 
 
@@ -941,8 +1073,8 @@ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
    NTVFS lock generic to any mapper
 */
 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
-                                struct ntvfs_request *req,
-                                union smb_lock *lck)
+                       struct ntvfs_request *req,
+                       union smb_lock *lck)
 {
        union smb_lock *lck2;
        struct smb_lock_entry *locks;
@@ -987,37 +1119,87 @@ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
                locks->count = lck->unlock.in.count;
                break;
 
-       case RAW_LOCK_SMB2:
-               if (lck->smb2.in.unknown1 != 1) {
+       case RAW_LOCK_SMB2: {
+               /* this is only approximate! We need to change the
+                  generic structure to fix this properly */
+               int i;
+               bool isunlock;
+               if (lck->smb2.in.lock_count < 1) {
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
                lck2->generic.level = RAW_LOCK_GENERIC;
                lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
-               if (lck->smb2.in.flags & SMB2_LOCK_FLAG_EXCLUSIV) {
-                       lck2->generic.in.mode = 0;
-               } else {
-                       lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
+               lck2->generic.in.timeout = UINT32_MAX;
+               lck2->generic.in.mode = 0;
+               lck2->generic.in.lock_cnt = 0;
+               lck2->generic.in.ulock_cnt = 0;
+               lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry, 
+                                                          lck->smb2.in.lock_count);
+               if (lck2->generic.in.locks == NULL) {
+                       return NT_STATUS_NO_MEMORY;
                }
-               if (lck->smb2.in.flags & SMB2_LOCK_FLAG_NO_PENDING) {
-                       lck2->generic.in.timeout = 0;
+               /* only the first lock gives the UNLOCK bit - see
+                  MS-SMB2 3.3.5.14 */
+               if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
+                       if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+                       lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
+                       isunlock = true;
                } else {
-                       lck2->generic.in.timeout = UINT32_MAX;
+                       lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
+                       isunlock = false;
                }
-               if (lck->smb2.in.flags & SMB2_LOCK_FLAG_UNLOCK) {
-                       lck2->generic.in.ulock_cnt = 1;
-                       lck2->generic.in.lock_cnt = 0;
-               } else {
-                       lck2->generic.in.ulock_cnt = 0;
-                       lck2->generic.in.lock_cnt = 1;
+               for (i=0;i<lck->smb2.in.lock_count;i++) {
+                       if (!isunlock &&
+                           lck->smb2.in.locks[i].flags == SMB2_LOCK_FLAG_NONE) {
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+
+                       if (lck->smb2.in.locks[i].flags & ~SMB2_LOCK_FLAG_ALL_MASK) {
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+
+                       if (isunlock && 
+                           (lck->smb2.in.locks[i].flags & 
+                            (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+                       if (!isunlock && 
+                           (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+                       lck2->generic.in.locks[i].pid    = req->smbpid;
+                       lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
+                       lck2->generic.in.locks[i].count  = lck->smb2.in.locks[i].length;
+                       if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
+                               lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
+                       }
+                       if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
+                               lck2->generic.in.timeout = 0;
+                       }
                }
-               lck2->generic.in.locks = locks;
-               locks->pid = 0;
-               locks->offset = lck->smb2.in.offset;
-               locks->count = lck->smb2.in.count;
+               /* initialize output value */
+               lck->smb2.out.reserved = 0;
+               break;
+       }
+
+       case RAW_LOCK_SMB2_BREAK:
+               lck2->generic.level             = RAW_LOCK_GENERIC;
+               lck2->generic.in.file.ntvfs     = lck->smb2_break.in.file.ntvfs;
+               lck2->generic.in.mode           = LOCKING_ANDX_OPLOCK_RELEASE |
+                                                 ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
+               lck2->generic.in.timeout        = 0;
+               lck2->generic.in.ulock_cnt      = 0;
+               lck2->generic.in.lock_cnt       = 0;
+               lck2->generic.in.locks          = NULL;
 
                /* initialize output value */
-               lck->smb2.out.unknown1 = 0;
+               lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
+               lck->smb2_break.out.reserved    = lck->smb2_break.in.reserved;
+               lck->smb2_break.out.reserved2   = lck->smb2_break.in.reserved2;
+               lck->smb2_break.out.file        = lck->smb2_break.in.file;
                break;
        }
 
@@ -1026,7 +1208,7 @@ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
         * as lock() doesn't have any output fields
         */
 
-       return ntvfs->ops->lock(ntvfs, req, lck2);
+       return ntvfs->ops->lock_fn(ntvfs, req, lck2);
 }
 
 
@@ -1041,7 +1223,7 @@ static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
 {
        union smb_lock *lck;
        union smb_close *cl;
-       uint_t state;
+       unsigned int state;
 
        if (NT_STATUS_IS_ERR(status)) {
                return status;
@@ -1069,7 +1251,7 @@ static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
                        /* do the lock sync for now */
                        state = req->async_states->state;
                        req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
-                       status = ntvfs->ops->lock(ntvfs, req, lck);
+                       status = ntvfs->ops->lock_fn(ntvfs, req, lck);
                        req->async_states->state = state;
                }
                break;
@@ -1090,7 +1272,7 @@ static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
                        /* do the close sync for now */
                        state = req->async_states->state;
                        req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
-                       status = ntvfs->ops->close(ntvfs, req, cl);
+                       status = ntvfs->ops->close_fn(ntvfs, req, cl);
                        req->async_states->state = state;
                }
                break;
@@ -1147,7 +1329,7 @@ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
                wr2->writex.in.remaining = wr->write.in.remaining;
                wr2->writex.in.count     = wr->write.in.count;
                wr2->writex.in.data      = wr->write.in.data;
-               status = ntvfs->ops->write(ntvfs, req, wr2);
+               status = ntvfs->ops->write_fn(ntvfs, req, wr2);
                break;
 
        case RAW_WRITE_WRITEUNLOCK:
@@ -1157,7 +1339,7 @@ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
                wr2->writex.in.remaining = wr->writeunlock.in.remaining;
                wr2->writex.in.count     = wr->writeunlock.in.count;
                wr2->writex.in.data      = wr->writeunlock.in.data;
-               status = ntvfs->ops->write(ntvfs, req, wr2);
+               status = ntvfs->ops->write_fn(ntvfs, req, wr2);
                break;
 
        case RAW_WRITE_WRITECLOSE:
@@ -1167,7 +1349,7 @@ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
                wr2->writex.in.remaining = 0;
                wr2->writex.in.count     = wr->writeclose.in.count;
                wr2->writex.in.data      = wr->writeclose.in.data;
-               status = ntvfs->ops->write(ntvfs, req, wr2);
+               status = ntvfs->ops->write_fn(ntvfs, req, wr2);
                break;
 
        case RAW_WRITE_SPLWRITE:
@@ -1177,7 +1359,7 @@ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
                wr2->writex.in.remaining = 0;
                wr2->writex.in.count     = wr->splwrite.in.count;
                wr2->writex.in.data      = wr->splwrite.in.data;
-               status = ntvfs->ops->write(ntvfs, req, wr2);
+               status = ntvfs->ops->write_fn(ntvfs, req, wr2);
                break;
 
        case RAW_WRITE_SMB2:
@@ -1187,7 +1369,7 @@ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
                wr2->writex.in.remaining = 0;
                wr2->writex.in.count     = wr->smb2.in.data.length;
                wr2->writex.in.data      = wr->smb2.in.data.data;
-               status = ntvfs->ops->write(ntvfs, req, wr2);
+               status = ntvfs->ops->write_fn(ntvfs, req, wr2);
        }
 
        return ntvfs_map_async_finish(req, status);
@@ -1235,7 +1417,7 @@ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
        union smb_read *rd2;
        union smb_lock *lck;
        NTSTATUS status;
-       uint_t state;
+       unsigned int state;
 
        rd2 = talloc(req, union smb_read);
        if (rd2 == NULL) {
@@ -1263,7 +1445,7 @@ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
                rd2->readx.in.maxcnt    = rd->read.in.count;
                rd2->readx.in.remaining = rd->read.in.remaining;
                rd2->readx.out.data     = rd->read.out.data;
-               status = ntvfs->ops->read(ntvfs, req, rd2);
+               status = ntvfs->ops->read_fn(ntvfs, req, rd2);
                break;
 
        case RAW_READ_READBRAW:
@@ -1273,7 +1455,7 @@ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
                rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
                rd2->readx.in.remaining = 0;
                rd2->readx.out.data     = rd->readbraw.out.data;
-               status = ntvfs->ops->read(ntvfs, req, rd2);
+               status = ntvfs->ops->read_fn(ntvfs, req, rd2);
                break;
 
        case RAW_READ_LOCKREAD:
@@ -1290,7 +1472,7 @@ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
                lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
                lck->lock.in.count      = rd->lockread.in.count;
                lck->lock.in.offset     = rd->lockread.in.offset;
-               status = ntvfs->ops->lock(ntvfs, req, lck);
+               status = ntvfs->ops->lock_fn(ntvfs, req, lck);
                req->async_states->state = state;
 
                rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
@@ -1301,18 +1483,18 @@ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
                rd2->readx.out.data     = rd->lockread.out.data;
 
                if (NT_STATUS_IS_OK(status)) {
-                       status = ntvfs->ops->read(ntvfs, req, rd2);
+                       status = ntvfs->ops->read_fn(ntvfs, req, rd2);
                }
                break;
 
        case RAW_READ_SMB2:
                rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
                rd2->readx.in.offset    = rd->smb2.in.offset;
-               rd2->readx.in.mincnt    = rd->smb2.in.length;
+               rd2->readx.in.mincnt    = rd->smb2.in.min_count;
                rd2->readx.in.maxcnt    = rd->smb2.in.length;
                rd2->readx.in.remaining = 0;
                rd2->readx.out.data     = rd->smb2.out.data.data;
-               status = ntvfs->ops->read(ntvfs, req, rd2);
+               status = ntvfs->ops->read_fn(ntvfs, req, rd2);
                break;
        }
 
@@ -1321,6 +1503,36 @@ done:
 }
 
 
+/* 
+   NTVFS close generic to any mapper
+*/
+static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
+                                       struct ntvfs_request *req,
+                                       union smb_close *cl, 
+                                       union smb_close *cl2, 
+                                       NTSTATUS status)
+{
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       switch (cl->generic.level) {
+       case RAW_CLOSE_SMB2:
+               cl->smb2.out.flags        = cl2->generic.out.flags;
+               cl->smb2.out._pad         = 0;
+               cl->smb2.out.create_time  = cl2->generic.out.create_time;
+               cl->smb2.out.access_time  = cl2->generic.out.access_time;
+               cl->smb2.out.write_time   = cl2->generic.out.write_time;
+               cl->smb2.out.change_time  = cl2->generic.out.change_time;
+               cl->smb2.out.alloc_size   = cl2->generic.out.alloc_size;
+               cl->smb2.out.size         = cl2->generic.out.size;
+               cl->smb2.out.file_attr    = cl2->generic.out.file_attr;
+               break;
+       default:
+               break;
+       }
+
+       return status;
+}
+
 /* 
    NTVFS close generic to any mapper
 */
@@ -1329,6 +1541,7 @@ NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
                                  union smb_close *cl)
 {
        union smb_close *cl2;
+       NTSTATUS status;
 
        cl2 = talloc(req, union smb_close);
        if (cl2 == NULL) {
@@ -1336,30 +1549,38 @@ NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
        }
 
        switch (cl->generic.level) {
-       case RAW_CLOSE_CLOSE:
+       case RAW_CLOSE_GENERIC:
                return NT_STATUS_INVALID_LEVEL;
 
+       case RAW_CLOSE_CLOSE:
+               cl2->generic.level              = RAW_CLOSE_GENERIC;
+               cl2->generic.in.file            = cl->close.in.file;
+               cl2->generic.in.write_time      = cl->close.in.write_time;
+               cl2->generic.in.flags           = 0;
+               break;
+
        case RAW_CLOSE_SPLCLOSE:
-               cl2->generic.level              = RAW_CLOSE_CLOSE;
-               cl2->generic.in.file.ntvfs      = cl->splclose.in.file.ntvfs;
+               cl2->generic.level              = RAW_CLOSE_GENERIC;
+               cl2->generic.in.file            = cl->splclose.in.file;
                cl2->generic.in.write_time      = 0;
+               cl2->generic.in.flags           = 0;
                break;
 
        case RAW_CLOSE_SMB2:
-               cl2->generic.level              = RAW_CLOSE_CLOSE;
-               cl2->generic.in.file.ntvfs      = cl->smb2.in.file.ntvfs;
+               cl2->generic.level              = RAW_CLOSE_GENERIC;
+               cl2->generic.in.file            = cl->smb2.in.file;
                cl2->generic.in.write_time      = 0;
-               /* SMB2 Close has output parameter, but we just zero them */
-               ZERO_STRUCT(cl->smb2.out);
+               cl2->generic.in.flags           = cl->smb2.in.flags;
                break;
        }
 
-       /* 
-        * we don't need to call ntvfs_map_async_setup() here,
-        * as close() doesn't have any output fields
-        */
+       status = ntvfs_map_async_setup(ntvfs, req, cl, cl2, 
+                                      (second_stage_t)ntvfs_map_close_finish);
+       NT_STATUS_NOT_OK_RETURN(status);
 
-       return ntvfs->ops->close(ntvfs, req, cl2);
+       status = ntvfs->ops->close_fn(ntvfs, req, cl2);
+
+       return ntvfs_map_async_finish(req, status);
 }
 
 /* 
@@ -1376,7 +1597,7 @@ static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
        switch (nt->nttrans.level) {
        case RAW_NOTIFY_SMB2:
                if (nt2->nttrans.out.num_changes == 0) {
-                       return STATUS_NOTIFY_ENUM_DIR;
+                       return NT_STATUS_NOTIFY_ENUM_DIR;
                }
                nt->smb2.out.num_changes        = nt2->nttrans.out.num_changes;
                nt->smb2.out.changes            = talloc_steal(req, nt2->nttrans.out.changes);
@@ -1419,7 +1640,7 @@ NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
                nt2->nttrans.in.buffer_size             = nt->smb2.in.buffer_size;
                nt2->nttrans.in.completion_filter       = nt->smb2.in.completion_filter;
                nt2->nttrans.in.recursive               = nt->smb2.in.recursive;
-               status = ntvfs->ops->notify(ntvfs, req, nt2);
+               status = ntvfs->ops->notify_fn(ntvfs, req, nt2);
                break;
        }