Merge branch 'master' of ssh://jra@git.samba.org/data/git/samba
[kai/samba-autobuild/.git] / source4 / ntvfs / ntvfs_generic.c
index 9b6c75e5c6510e615da9976a9a2f448b5ef91e6b..6e2e075f1e2db3898a92682caff538c1e5f07e78 100644 (file)
@@ -7,7 +7,7 @@
 
    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
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -16,8 +16,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 /*
   this implements mappings between info levels for NTVFS backend calls
 */
 
 #include "includes.h"
-#include "smb_server/smb_server.h"
-#include "librpc/gen_ndr/ndr_security.h"
+#include "ntvfs/ntvfs.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
 
 /* 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 smbsrv_request *, 
-                                  struct ntvfs_module_context *,
+typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
+                                  struct ntvfs_request *,
                                   void *, void *, NTSTATUS);
 
 /* 
@@ -54,14 +54,15 @@ struct ntvfs_map_async {
   this is a async wrapper, called from the backend when it has completed
   a function that it has decided to reply to in an async fashion
 */
-static void ntvfs_map_async_send(struct smbsrv_request *req)
+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);
 
        /* call the _finish function setup in ntvfs_map_async_setup() */
-       req->async_states->status = m->fn(req, m->ntvfs, m->io, m->io2, req->async_states->status);
+       req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
 
        /* call the send function from the next module up */
        req->async_states->send_fn(req);
@@ -73,8 +74,8 @@ static void ntvfs_map_async_send(struct smbsrv_request *req)
   io2 is the new call structure for the mapped call
   fn is a second stage function for processing the out arguments
 */
-static NTSTATUS ntvfs_map_async_setup(struct smbsrv_request *req,
-                                     struct ntvfs_module_context *ntvfs,
+static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
+                                     struct ntvfs_request *req,
                                      void *io, void *io2,
                                      second_stage_t fn)
 {
@@ -87,14 +88,13 @@ static NTSTATUS ntvfs_map_async_setup(struct smbsrv_request *req,
        m->io = io;
        m->io2 = io2;
        m->fn = fn;
-       return ntvfs_async_state_push(req, m, ntvfs_map_async_send, ntvfs);
+       return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
 }
 
-
 /*
   called when first stage processing is complete. 
 */     
-static NTSTATUS ntvfs_map_async_finish(struct smbsrv_request *req, NTSTATUS status)
+static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
 {
        struct ntvfs_map_async *m;
 
@@ -106,41 +106,41 @@ static NTSTATUS ntvfs_map_async_finish(struct smbsrv_request *req, NTSTATUS stat
 
        /* 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);
 
-       return m->fn(req, m->ntvfs, m->io, m->io2, status);
+       return m->fn(m->ntvfs, req, m->io, m->io2, status);
 }
 
-
 /*
   see if a filename ends in EXE COM DLL or SYM. This is needed for the
   DENY_DOS mapping for OpenX
 */
-BOOL is_exe_filename(const char *fname)
+bool is_exe_filename(const char *fname)
 {
        char *p;
        p = strrchr(fname, '.');
        if (!p) {
-               return False;
+               return false;
        }
        p++;
        if (strcasecmp(p, "EXE") == 0 ||
            strcasecmp(p, "COM") == 0 ||
            strcasecmp(p, "DLL") == 0 ||
            strcasecmp(p, "SYM") == 0) {
-               return True;
+               return true;
        }
-       return False;
+       return false;
 }
 
 
 /* 
    NTVFS openx to ntcreatex mapper
 */
-static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req, 
-                                     struct ntvfs_module_context *ntvfs,
+static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
+                                     struct ntvfs_request *req, 
                                      union smb_open *io, 
                                      union smb_open *io2, 
                                      NTSTATUS status)
@@ -156,7 +156,7 @@ static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req,
 
        switch (io->generic.level) {
        case RAW_OPEN_OPEN:
-               io->openold.out.fnum       = io2->generic.out.fnum;
+               io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
                io->openold.out.attrib     = io2->generic.out.attrib;
                io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
                io->openold.out.size       = io2->generic.out.size;
@@ -164,7 +164,7 @@ static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req,
                break;
 
        case RAW_OPEN_OPENX:
-               io->openx.out.fnum        = io2->generic.out.fnum;
+               io->openx.out.file.ntvfs  = io2->generic.out.file.ntvfs;
                io->openx.out.attrib      = io2->generic.out.attrib;
                io->openx.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
                io->openx.out.size        = io2->generic.out.size;
@@ -184,7 +184,7 @@ static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req,
                break;
 
        case RAW_OPEN_T2OPEN:
-               io->t2open.out.fnum        = io2->generic.out.fnum;
+               io->t2open.out.file.ntvfs  = io2->generic.out.file.ntvfs;
                io->t2open.out.attrib      = io2->generic.out.attrib;
                io->t2open.out.write_time  = nt_time_to_unix(io2->generic.out.write_time);
                io->t2open.out.size        = io2->generic.out.size;
@@ -197,14 +197,45 @@ static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req,
 
        case RAW_OPEN_MKNEW:
        case RAW_OPEN_CREATE:
-               io->mknew.out.fnum = io2->generic.out.fnum;
-               write_time = io->mknew.in.write_time;
+               io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
+               write_time              = io->mknew.in.write_time;
                break;
 
        case RAW_OPEN_CTEMP:
-               io->ctemp.out.fnum  = io2->generic.out.fnum;
-               io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname + 
-                                                  strlen(io->ctemp.in.directory) + 1);
+               io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
+               io->ctemp.out.name      = talloc_strdup(req, io2->generic.in.fname + 
+                                                       strlen(io->ctemp.in.directory) + 1);
+               NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
+               break;
+
+       case RAW_OPEN_SMB2:
+               ZERO_STRUCT(io->smb2.out);
+               io->smb2.out.file.ntvfs         = io2->generic.out.file.ntvfs;
+               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;
+               io->smb2.out.access_time        = io2->generic.out.access_time;
+               io->smb2.out.write_time         = io2->generic.out.write_time;
+               io->smb2.out.change_time        = io2->generic.out.change_time;
+               io->smb2.out.alloc_size         = io2->generic.out.alloc_size;
+               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.maximal_access     = io2->generic.out.maximal_access;
                break;
 
        default:
@@ -217,9 +248,10 @@ static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req,
        req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
 
        if (write_time != 0) {
-               sf = talloc(req, union smb_setfileinfo);                        
-               sf->generic.level            = RAW_SFILEINFO_STANDARD;
-               sf->generic.file.fnum        = io2->generic.out.fnum;
+               sf = talloc(req, union smb_setfileinfo);
+               NT_STATUS_HAVE_NO_MEMORY(sf);
+               sf->generic.level           = RAW_SFILEINFO_STANDARD;
+               sf->generic.in.file.ntvfs   = io2->generic.out.file.ntvfs;
                sf->standard.in.create_time = 0;
                sf->standard.in.write_time  = write_time;
                sf->standard.in.access_time = 0;
@@ -228,8 +260,9 @@ static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req,
 
        if (set_size != 0) {
                sf = talloc(req, union smb_setfileinfo);                        
+               NT_STATUS_HAVE_NO_MEMORY(sf);
                sf->generic.level            = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
-               sf->generic.file.fnum        = io2->generic.out.fnum;
+               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);
                if (NT_STATUS_IS_OK(status)) {
@@ -250,6 +283,8 @@ 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;
+
        if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
                io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
        }
@@ -259,6 +294,7 @@ static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
 
        switch (open_mode & OPENX_MODE_ACCESS_MASK) {
        case OPENX_MODE_ACCESS_READ:
+       case OPENX_MODE_ACCESS_EXEC:
                io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
                break;
        case OPENX_MODE_ACCESS_WRITE:
@@ -266,13 +302,12 @@ static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
                break;
        case OPENX_MODE_ACCESS_RDWR:
        case OPENX_MODE_ACCESS_FCB:
-       case OPENX_MODE_ACCESS_EXEC:
                io2->generic.in.access_mask = 
                        SEC_RIGHTS_FILE_READ | 
                        SEC_RIGHTS_FILE_WRITE;
                break;
        default:
-               return NT_STATUS_INVALID_LOCK_SEQUENCE;
+               return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
        }
 
        switch (open_mode & OPENX_MODE_DENY_MASK) {
@@ -311,7 +346,7 @@ static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
                io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
                break;
        default:
-               return NT_STATUS_INVALID_LOCK_SEQUENCE;
+               return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
        }
 
        switch (open_func) {
@@ -336,7 +371,7 @@ static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
                        io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
                        break;
                }
-               return NT_STATUS_INVALID_LOCK_SEQUENCE;
+               return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
        }
 
        return NT_STATUS_OK;
@@ -345,8 +380,9 @@ static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
 /* 
    NTVFS open generic to any mapper
 */
-NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io, 
-                       struct ntvfs_module_context *ntvfs)
+NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
+                                struct ntvfs_request *req,
+                                union smb_open *io)
 {
        NTSTATUS status;
        union smb_open *io2;
@@ -356,7 +392,8 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = ntvfs_map_async_setup(req, ntvfs, io, io2, 
+       status = ntvfs_map_async_setup(ntvfs, req,
+                                      io, io2, 
                                       (second_stage_t)ntvfs_map_open_finish);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -378,7 +415,7 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
                io2->generic.in.file_attr = io->openx.in.file_attrs;
                io2->generic.in.fname = io->openx.in.fname;
                
-               status = ntvfs->ops->openfile(ntvfs, req, io2);
+               status = ntvfs->ops->open(ntvfs, req, io2);
                break;
                
                
@@ -395,7 +432,7 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
                io2->generic.in.file_attr = io->openold.in.search_attrs;
                io2->generic.in.fname = io->openold.in.fname;
 
-               status = ntvfs->ops->openfile(ntvfs, req, io2);
+               status = ntvfs->ops->open(ntvfs, req, io2);
                break;
 
        case RAW_OPEN_T2OPEN:
@@ -421,7 +458,7 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
                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->openfile(ntvfs, req, io2);
+               status = ntvfs->ops->open(ntvfs, req, io2);
                break;
 
        case RAW_OPEN_MKNEW:
@@ -434,7 +471,7 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
                io2->generic.in.share_access = 
                        NTCREATEX_SHARE_ACCESS_READ | 
                        NTCREATEX_SHARE_ACCESS_WRITE;
-               status = ntvfs->ops->openfile(ntvfs, req, io2);
+               status = ntvfs->ops->open(ntvfs, req, io2);
                break;
 
        case RAW_OPEN_CREATE:
@@ -447,12 +484,11 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
                io2->generic.in.share_access = 
                        NTCREATEX_SHARE_ACCESS_READ | 
                        NTCREATEX_SHARE_ACCESS_WRITE;
-               status = ntvfs->ops->openfile(ntvfs, req, io2);
+               status = ntvfs->ops->open(ntvfs, req, io2);
                break;
 
        case RAW_OPEN_CTEMP:
                io2->generic.in.file_attr = io->ctemp.in.attrib;
-               io2->generic.in.file_attr = 0;
                io2->generic.in.fname = 
                        talloc_asprintf(io2, "%s\\SRV%s", 
                                        io->ctemp.in.directory,
@@ -464,7 +500,54 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
                io2->generic.in.share_access = 
                        NTCREATEX_SHARE_ACCESS_READ | 
                        NTCREATEX_SHARE_ACCESS_WRITE;
-               status = ntvfs->ops->openfile(ntvfs, req, io2);
+               status = ntvfs->ops->open(ntvfs, req, io2);
+               break;
+       case RAW_OPEN_SMB2:
+               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      = 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;
+               io2->generic.in.create_options  = io->smb2.in.create_options;
+               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        = 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; 
+
+               /* 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(ntvfs, req, io2);             
                break;
 
        default:
@@ -477,31 +560,14 @@ done:
 
 
 /* 
-   NTVFS fsinfo generic to any mapper
+   NTVFS any to fsinfo mapper
 */
-NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs, 
-                         struct ntvfs_module_context *ntvfs)
+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;
-       }
-       
-       /* this map function is 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;
        }
@@ -530,7 +596,7 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs,
                        (fs2->generic.out.blocks_free  * (double)fs2->generic.out.block_size) / (bpunit * 512);
 
                /* we must return a maximum of 2G to old DOS systems, or they get very confused */
-               if (bpunit > 64 && req->smb_conn->negotiate.protocol <= PROTOCOL_LANMAN2) {
+               if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
                        fs->dskattr.out.blocks_per_unit = 64;
                        fs->dskattr.out.units_total = 0xFFFF;
                        fs->dskattr.out.units_free = 0xFFFF;
@@ -604,12 +670,45 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs,
        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(ntvfs, req, fs2);
+       return ntvfs_map_async_finish(req, status);
+}
+
 
 /* 
    NTVFS fileinfo generic to any mapper
 */
-NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info, 
-                           union smb_fileinfo *info2)
+NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
+                                    union smb_fileinfo *info, 
+                                    union smb_fileinfo *info2)
 {
        int i;
        /* and convert it to the required level using results in info2 */
@@ -714,7 +813,7 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info
                info->stream_info.out.num_streams = info2->generic.out.num_streams;
                if (info->stream_info.out.num_streams > 0) {
                        info->stream_info.out.streams = 
-                               talloc_array(req
+                               talloc_array(mem_ctx
                                               struct stream_struct,
                                               info->stream_info.out.num_streams);
                        if (!info->stream_info.out.streams) {
@@ -725,7 +824,8 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info
                        for (i=0; i < info->stream_info.out.num_streams; i++) {
                                info->stream_info.out.streams[i] = info2->generic.out.streams[i];
                                info->stream_info.out.streams[i].stream_name.s = 
-                                       talloc_strdup(req, info2->generic.out.streams[i].stream_name.s);
+                                       talloc_strdup(info->stream_info.out.streams,
+                                                     info2->generic.out.streams[i].stream_name.s);
                                if (!info->stream_info.out.streams[i].stream_name.s) {
                                        DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
                                        return NT_STATUS_NO_MEMORY;
@@ -736,13 +836,15 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info
 
        case RAW_FILEINFO_NAME_INFO:
        case RAW_FILEINFO_NAME_INFORMATION:
-               info->name_info.out.fname.s = talloc_strdup(req, info2->generic.out.fname.s);
+               info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
+               NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
                info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
                return NT_STATUS_OK;
                
        case RAW_FILEINFO_ALT_NAME_INFO:
        case RAW_FILEINFO_ALT_NAME_INFORMATION:
-               info->alt_name_info.out.fname.s = talloc_strdup(req, info2->generic.out.alt_fname.s);
+               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;
                return NT_STATUS_OK;
        
@@ -753,7 +855,7 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info
        case RAW_FILEINFO_ALL_EAS:
                info->all_eas.out.num_eas = info2->generic.out.num_eas;
                if (info->all_eas.out.num_eas > 0) {
-                       info->all_eas.out.eas = talloc_array(req
+                       info->all_eas.out.eas = talloc_array(mem_ctx
                                                               struct ea_struct,
                                                               info->all_eas.out.num_eas);
                        if (!info->all_eas.out.eas) {
@@ -764,13 +866,14 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info
                        for (i = 0; i < info->all_eas.out.num_eas; i++) {
                                info->all_eas.out.eas[i] = info2->generic.out.eas[i];
                                info->all_eas.out.eas[i].name.s = 
-                                       talloc_strdup(req, info2->generic.out.eas[i].name.s);
+                                       talloc_strdup(info->all_eas.out.eas,
+                                                     info2->generic.out.eas[i].name.s);
                                if (!info->all_eas.out.eas[i].name.s) {
                                        DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
                                        return NT_STATUS_NO_MEMORY;
                                }
                                info->all_eas.out.eas[i].value.data = 
-                                       talloc_memdup(req,
+                                       (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) {
@@ -832,10 +935,27 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info
 }
 
 /* 
+   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 smbsrv_request *req, union smb_fileinfo *info, 
-                            struct ntvfs_module_context *ntvfs)
+NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
+                                     struct ntvfs_request *req,
+                                     union smb_fileinfo *info)
 {
        NTSTATUS status;
        union smb_fileinfo *info2;
@@ -849,22 +969,42 @@ NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *inf
                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.fnum = info->generic.in.fnum;
+       info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
 
        status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
+       return ntvfs_map_async_finish(req, status);
+}
+
+/*
+   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);
 }
 
 /* 
    NTVFS pathinfo generic to any mapper
 */
-NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info, 
-                            struct ntvfs_module_context *ntvfs)
+NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
+                                     struct ntvfs_request *req,
+                                     union smb_fileinfo *info)
 {
        NTSTATUS status;
        union smb_fileinfo *info2;
@@ -878,26 +1018,27 @@ NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *inf
                return NT_STATUS_INVALID_LEVEL;
        }
 
-       /* ask the backend for the generic info */
-       info2->generic.level = RAW_FILEINFO_GENERIC;
-       info2->generic.in.fname = info->generic.in.fname;
-
-       /* 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);
+       status = ntvfs_map_async_setup(ntvfs, req, info, info2,
+                                      (second_stage_t)ntvfs_map_qpathinfo_finish);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
-       return ntvfs_map_fileinfo(req, info, info2);
+
+       /* ask the backend for the generic info */
+       info2->generic.level            = RAW_FILEINFO_GENERIC;
+       info2->generic.in.file.path     = info->generic.in.file.path;
+
+       status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
+       return ntvfs_map_async_finish(req, status);
 }
 
 
 /* 
    NTVFS lock generic to any mapper
 */
-NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck, 
-                       struct ntvfs_module_context *ntvfs)
+NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
+                       struct ntvfs_request *req,
+                       union smb_lock *lck)
 {
        union smb_lock *lck2;
        struct smb_lock_entry *locks;
@@ -917,24 +1058,107 @@ NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck,
                return NT_STATUS_INVALID_LEVEL;
 
        case RAW_LOCK_LOCK:
+               lck2->generic.level = RAW_LOCK_GENERIC;
+               lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
+               lck2->generic.in.mode = 0;
+               lck2->generic.in.timeout = 0;
                lck2->generic.in.ulock_cnt = 0;
                lck2->generic.in.lock_cnt = 1;
+               lck2->generic.in.locks = locks;
+               locks->pid = req->smbpid;
+               locks->offset = lck->lock.in.offset;
+               locks->count = lck->lock.in.count;
                break;
 
        case RAW_LOCK_UNLOCK:
+               lck2->generic.level = RAW_LOCK_GENERIC;
+               lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
+               lck2->generic.in.mode = 0;
+               lck2->generic.in.timeout = 0;
                lck2->generic.in.ulock_cnt = 1;
                lck2->generic.in.lock_cnt = 0;
+               lck2->generic.in.locks = locks;
+               locks->pid = req->smbpid;
+               locks->offset = lck->unlock.in.offset;
+               locks->count = lck->unlock.in.count;
+               break;
+
+       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;
+               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;
+               }
+               /* 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) {
+                       lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
+                       isunlock = true;
+               } else {
+                       lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
+                       isunlock = false;
+               }
+               for (i=0;i<lck->smb2.in.lock_count;i++) {
+                       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;
+                       }
+               }
+               /* initialize output value */
+               lck->smb2.out.reserved = 0;
                break;
        }
 
-       lck2->generic.level = RAW_LOCK_GENERIC;
-       lck2->generic.in.fnum = lck->lock.in.fnum;
-       lck2->generic.in.mode = 0;
-       lck2->generic.in.timeout = 0;
-       lck2->generic.in.locks = locks;
-       locks->pid = req->smbpid;
-       locks->offset = lck->lock.in.offset;
-       locks->count = lck->lock.in.count;
+       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_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;
+       }
+
+       /* 
+        * we don't need to call ntvfs_map_async_setup() here,
+        * as lock() doesn't have any output fields
+        */
 
        return ntvfs->ops->lock(ntvfs, req, lck2);
 }
@@ -943,12 +1167,11 @@ NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck,
 /* 
    NTVFS write generic to any mapper
 */
-static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req, 
-                                      struct ntvfs_module_context *ntvfs,
+static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
+                                      struct ntvfs_request *req,
                                       union smb_write *wr, 
                                       union smb_write *wr2, 
                                       NTSTATUS status)
-                                      
 {
        union smb_lock *lck;
        union smb_close *cl;
@@ -971,10 +1194,10 @@ static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req,
                        return NT_STATUS_NO_MEMORY;
                }
 
-               lck->unlock.level      = RAW_LOCK_UNLOCK;
-               lck->unlock.in.fnum    = wr->writeunlock.in.fnum;
-               lck->unlock.in.count   = wr->writeunlock.in.count;
-               lck->unlock.in.offset  = wr->writeunlock.in.offset;
+               lck->unlock.level               = RAW_LOCK_UNLOCK;
+               lck->unlock.in.file.ntvfs       = wr->writeunlock.in.file.ntvfs;
+               lck->unlock.in.count            = wr->writeunlock.in.count;
+               lck->unlock.in.offset           = wr->writeunlock.in.offset;
 
                if (lck->unlock.in.count != 0) {
                        /* do the lock sync for now */
@@ -993,9 +1216,9 @@ static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req,
                        return NT_STATUS_NO_MEMORY;
                }
 
-               cl->close.level           = RAW_CLOSE_CLOSE;
-               cl->close.in.fnum         = wr->writeclose.in.fnum;
-               cl->close.in.write_time   = wr->writeclose.in.mtime;
+               cl->close.level         = RAW_CLOSE_CLOSE;
+               cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
+               cl->close.in.write_time = wr->writeclose.in.mtime;
 
                if (wr2->generic.in.count != 0) {
                        /* do the close sync for now */
@@ -1008,6 +1231,13 @@ static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req,
 
        case RAW_WRITE_SPLWRITE:
                break;
+
+       case RAW_WRITE_SMB2:
+               wr->smb2.out._pad       = 0;
+               wr->smb2.out.nwritten   = wr2->generic.out.nwritten;
+               wr->smb2.out.unknown1   = 0;
+               break;
+
        default:
                return NT_STATUS_INVALID_LEVEL;
        }
@@ -1019,8 +1249,9 @@ static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req,
 /* 
    NTVFS write generic to any mapper
 */
-NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, 
-                        struct ntvfs_module_context *ntvfs)
+NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
+                                 struct ntvfs_request *req,
+                                 union smb_write *wr)
 {
        union smb_write *wr2;
        NTSTATUS status;
@@ -1030,7 +1261,7 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr,
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = ntvfs_map_async_setup(req, ntvfs, wr, wr2, 
+       status = ntvfs_map_async_setup(ntvfs, req, wr, wr2, 
                                       (second_stage_t)ntvfs_map_write_finish);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -1044,7 +1275,7 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr,
                break;
 
        case RAW_WRITE_WRITE:
-               wr2->writex.in.fnum      = wr->write.in.fnum;
+               wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
                wr2->writex.in.offset    = wr->write.in.offset;
                wr2->writex.in.wmode     = 0;
                wr2->writex.in.remaining = wr->write.in.remaining;
@@ -1054,7 +1285,7 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr,
                break;
 
        case RAW_WRITE_WRITEUNLOCK:
-               wr2->writex.in.fnum      = wr->writeunlock.in.fnum;
+               wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
                wr2->writex.in.offset    = wr->writeunlock.in.offset;
                wr2->writex.in.wmode     = 0;
                wr2->writex.in.remaining = wr->writeunlock.in.remaining;
@@ -1064,7 +1295,7 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr,
                break;
 
        case RAW_WRITE_WRITECLOSE:
-               wr2->writex.in.fnum      = wr->writeclose.in.fnum;
+               wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
                wr2->writex.in.offset    = wr->writeclose.in.offset;
                wr2->writex.in.wmode     = 0;
                wr2->writex.in.remaining = 0;
@@ -1074,7 +1305,7 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr,
                break;
 
        case RAW_WRITE_SPLWRITE:
-               wr2->writex.in.fnum      = wr->splwrite.in.fnum;
+               wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
                wr2->writex.in.offset    = 0;
                wr2->writex.in.wmode     = 0;
                wr2->writex.in.remaining = 0;
@@ -1082,6 +1313,15 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr,
                wr2->writex.in.data      = wr->splwrite.in.data;
                status = ntvfs->ops->write(ntvfs, req, wr2);
                break;
+
+       case RAW_WRITE_SMB2:
+               wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
+               wr2->writex.in.offset    = wr->smb2.in.offset;
+               wr2->writex.in.wmode     = 0;
+               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);
        }
 
        return ntvfs_map_async_finish(req, status);
@@ -1091,21 +1331,26 @@ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr,
 /* 
    NTVFS read generic to any mapper - finish the out mapping
 */
-static NTSTATUS ntvfs_map_read_finish(struct smbsrv_request *req, 
-                                     struct ntvfs_module_context *ntvfs
+static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
+                                     struct ntvfs_request *req
                                      union smb_read *rd, 
                                      union smb_read *rd2,
                                      NTSTATUS status)
 {
        switch (rd->generic.level) {
        case RAW_READ_READ:
-               rd->read.out.nread        = rd2->generic.out.nread;
+               rd->read.out.nread      = rd2->generic.out.nread;
                break;
        case RAW_READ_READBRAW:
-               rd->readbraw.out.nread    = rd2->generic.out.nread;
+               rd->readbraw.out.nread  = rd2->generic.out.nread;
                break;
        case RAW_READ_LOCKREAD:
-               rd->lockread.out.nread = rd2->generic.out.nread;
+               rd->lockread.out.nread  = rd2->generic.out.nread;
+               break;
+       case RAW_READ_SMB2:
+               rd->smb2.out.data.length= rd2->generic.out.nread;
+               rd->smb2.out.remaining  = 0;
+               rd->smb2.out.reserved   = 0;
                break;
        default:
                return NT_STATUS_INVALID_LEVEL;
@@ -1117,8 +1362,9 @@ static NTSTATUS ntvfs_map_read_finish(struct smbsrv_request *req,
 /* 
    NTVFS read* to readx mapper
 */
-NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd, 
-                        struct ntvfs_module_context *ntvfs)
+NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
+                                struct ntvfs_request *req,
+                                union smb_read *rd)
 {
        union smb_read *rd2;
        union smb_lock *lck;
@@ -1130,13 +1376,14 @@ NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd,
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = ntvfs_map_async_setup(req, ntvfs, rd, rd2, 
+       status = ntvfs_map_async_setup(ntvfs, req, rd, rd2, 
                                       (second_stage_t)ntvfs_map_read_finish);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
        rd2->readx.level = RAW_READ_READX;
+       rd2->readx.in.read_for_execute = false;
 
        switch (rd->generic.level) {
        case RAW_READ_READX:
@@ -1144,7 +1391,7 @@ NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd,
                break;
 
        case RAW_READ_READ:
-               rd2->readx.in.fnum      = rd->read.in.fnum;
+               rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
                rd2->readx.in.offset    = rd->read.in.offset;
                rd2->readx.in.mincnt    = rd->read.in.count;
                rd2->readx.in.maxcnt    = rd->read.in.count;
@@ -1154,7 +1401,7 @@ NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd,
                break;
 
        case RAW_READ_READBRAW:
-               rd2->readx.in.fnum      = rd->readbraw.in.fnum;
+               rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
                rd2->readx.in.offset    = rd->readbraw.in.offset;
                rd2->readx.in.mincnt    = rd->readbraw.in.mincnt;
                rd2->readx.in.maxcnt    = rd->readbraw.in.maxcnt;
@@ -1173,14 +1420,14 @@ NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd,
                        status = NT_STATUS_NO_MEMORY;
                        goto done;
                }
-               lck->lock.level      = RAW_LOCK_LOCK;
-               lck->lock.in.fnum    = rd->lockread.in.fnum;
-               lck->lock.in.count   = rd->lockread.in.count;
-               lck->lock.in.offset  = rd->lockread.in.offset;
+               lck->lock.level         = RAW_LOCK_LOCK;
+               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);
                req->async_states->state = state;
 
-               rd2->readx.in.fnum      = rd->lockread.in.fnum;
+               rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
                rd2->readx.in.offset    = rd->lockread.in.offset;
                rd2->readx.in.mincnt    = rd->lockread.in.count;
                rd2->readx.in.maxcnt    = rd->lockread.in.count;
@@ -1191,6 +1438,16 @@ NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd,
                        status = ntvfs->ops->read(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.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);
+               break;
        }
 
 done:
@@ -1201,10 +1458,42 @@ done:
 /* 
    NTVFS close generic to any mapper
 */
-NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl, 
-                        struct ntvfs_module_context *ntvfs)
+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
+*/
+NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
+                                 struct ntvfs_request *req,
+                                 union smb_close *cl)
 {
        union smb_close *cl2;
+       NTSTATUS status;
 
        cl2 = talloc(req, union smb_close);
        if (cl2 == NULL) {
@@ -1212,14 +1501,100 @@ NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl,
        }
 
        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->close.level   = RAW_CLOSE_CLOSE;
-               cl2->close.in.fnum = cl->splclose.in.fnum;
+               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_GENERIC;
+               cl2->generic.in.file            = cl->smb2.in.file;
+               cl2->generic.in.write_time      = 0;
+               cl2->generic.in.flags           = cl->smb2.in.flags;
                break;
        }
 
-       return ntvfs->ops->close(ntvfs, req, cl2);
+       status = ntvfs_map_async_setup(ntvfs, req, cl, cl2, 
+                                      (second_stage_t)ntvfs_map_close_finish);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       status = ntvfs->ops->close(ntvfs, req, cl2);
+
+       return ntvfs_map_async_finish(req, status);
+}
+
+/* 
+   NTVFS notify generic to any mapper
+*/
+static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
+                                       struct ntvfs_request *req,
+                                       union smb_notify *nt, 
+                                       union smb_notify *nt2, 
+                                       NTSTATUS status)
+{
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       switch (nt->nttrans.level) {
+       case RAW_NOTIFY_SMB2:
+               if (nt2->nttrans.out.num_changes == 0) {
+                       return 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);
+               break;
+
+       default:
+               return NT_STATUS_INVALID_LEVEL;
+       }
+
+       return status;
+}
+
+
+/* 
+   NTVFS notify generic to any mapper
+*/
+NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
+                                  struct ntvfs_request *req,
+                                  union smb_notify *nt)
+{
+       union smb_notify *nt2;
+       NTSTATUS status;
+
+       nt2 = talloc(req, union smb_notify);
+       NT_STATUS_HAVE_NO_MEMORY(nt2);
+
+       status = ntvfs_map_async_setup(ntvfs, req, nt, nt2, 
+                                      (second_stage_t)ntvfs_map_notify_finish);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
+
+       switch (nt->nttrans.level) {
+       case RAW_NOTIFY_NTTRANS:
+               status = NT_STATUS_INVALID_LEVEL;
+               break;
+
+       case RAW_NOTIFY_SMB2:
+               nt2->nttrans.in.file.ntvfs              = nt->smb2.in.file.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);
+               break;
+       }
+
+       return ntvfs_map_async_finish(req, status);
 }