r3466: split out request.h, signing.h, and smb_server.h
[jra/samba/.git] / source4 / ntvfs / ntvfs_generic.c
index 29f21b18633020ca27401a1c4363d431de1d8cca..6e8caf787b19edcda8aa634916471bcc05f3fad3 100644 (file)
@@ -3,7 +3,7 @@
 
    NTVFS generic level mapping code
 
-   Copyright (C) Andrew Tridgell 2003
+   Copyright (C) Andrew Tridgell 2003-2004
 
    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
 */
 
 #include "includes.h"
+#include "smb_server/smb_server.h"
+
 
 /*
-  see if a filename ends in EXE COM DLL or SYM. This is needed for the DENY_DOS mapping for OpenX
+  see if a filename ends in EXE COM DLL or SYM. This is needed for the
+  DENY_DOS mapping for OpenX
 */
 static BOOL is_exe_file(const char *fname)
 {
@@ -55,189 +58,246 @@ static BOOL is_exe_file(const char *fname)
 
 
 /* 
-   NTVFS open generic to any mapper
+   NTVFS openx to ntcreatex mapper
 */
-NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io)
+NTSTATUS ntvfs_map_open_openx(struct smbsrv_request *req, 
+                             union smb_open *io, 
+                             union smb_open *io2,
+                             struct ntvfs_module_context *ntvfs)
 {
        NTSTATUS status;
-       union smb_open io2;
 
-       if (io->generic.level == RAW_OPEN_GENERIC) {
-               return NT_STATUS_INVALID_LEVEL;
+       ZERO_STRUCT(io2->generic.in);
+       io2->generic.level = RAW_OPEN_GENERIC;
+       if (io->openx.in.flags & OPENX_FLAGS_REQUEST_OPLOCK) {
+               io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
        }
-
-       switch (io->generic.level) {
-       case RAW_OPEN_OPENX:
-               ZERO_STRUCT(io2.generic.in);
-               io2.generic.level = RAW_OPEN_GENERIC;
-               if (io->openx.in.flags & OPENX_FLAGS_REQUEST_OPLOCK) {
-                       io2.generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
-               }
-               if (io->openx.in.flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
-                       io2.generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       if (io->openx.in.flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
+               io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       }
+       
+       switch (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) {
+       case OPENX_MODE_ACCESS_READ:
+               io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ;
+               io->openx.out.access = OPENX_MODE_ACCESS_READ;
+               break;
+       case OPENX_MODE_ACCESS_WRITE:
+               io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
+               io->openx.out.access = OPENX_MODE_ACCESS_WRITE;
+               break;
+       case OPENX_MODE_ACCESS_RDWR:
+       case OPENX_MODE_ACCESS_FCB:
+       case OPENX_MODE_ACCESS_EXEC:
+               io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ | GENERIC_RIGHTS_FILE_WRITE;
+               io->openx.out.access = OPENX_MODE_ACCESS_RDWR;
+               break;
+       default:
+               return NT_STATUS_INVALID_LOCK_SEQUENCE;
+       }
+       
+       switch (io->openx.in.open_mode & OPENX_MODE_DENY_MASK) {
+       case OPENX_MODE_DENY_READ:
+               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
+               break;
+       case OPENX_MODE_DENY_WRITE:
+               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
+               break;
+       case OPENX_MODE_DENY_ALL:
+               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+               break;
+       case OPENX_MODE_DENY_NONE:
+               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+               break;
+       case OPENX_MODE_DENY_DOS:
+               /* DENY_DOS is quite strange - it depends on the filename! */
+               if (is_exe_file(io->openx.in.fname)) {
+                       io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+               } else {
+                       if ((io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) == 
+                           OPENX_MODE_ACCESS_READ) {
+                               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
+                       } else {
+                               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+                       }
                }
-
-               switch (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) {
-               case OPENX_MODE_ACCESS_READ:
-                       io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_READ;
-                       break;
-               case OPENX_MODE_ACCESS_WRITE:
-                       io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
-                       break;
-               case OPENX_MODE_ACCESS_RDWR:
-               case OPENX_MODE_ACCESS_FCB:
-                       io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_ALL_ACCESS;
+               break;
+       case OPENX_MODE_DENY_FCB:
+               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+               break;
+       default:
+               return NT_STATUS_INVALID_LOCK_SEQUENCE;
+       }
+       
+       switch (io->openx.in.open_func) {
+       case (OPENX_OPEN_FUNC_OPEN):
+               io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
+               break;
+       case (OPENX_OPEN_FUNC_TRUNC):
+               io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
+               break;
+       case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
+               io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
+               break;
+       case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
+               io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+               break;
+       case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
+               io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+               break;                  
+       default:
+               /* this one is very strange */
+               if ((io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) ==
+                   OPENX_MODE_ACCESS_EXEC) {
+                       io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
                        break;
                }
-
-               switch (io->openx.in.open_mode & OPENX_MODE_DENY_MASK) {
-               case OPENX_MODE_DENY_READ:
-                       io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
-                       break;
-               case OPENX_MODE_DENY_WRITE:
-                       io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
-                       break;
-               case OPENX_MODE_DENY_ALL:
-                       io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
-                       break;
-               case OPENX_MODE_DENY_NONE:
-                       io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
-                       break;
-               case OPENX_MODE_DENY_DOS:
-                       /* DENY_DOS is quite strange - it depends on the filename! */
-                       if (is_exe_file(io->openx.in.fname)) {
-                               io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
-                       } else {
-                               if ((io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK) == 
-                                   OPENX_MODE_ACCESS_READ) {
-                                       io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
-                               } else {
-                                       io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
-                               }
+               return NT_STATUS_INVALID_LOCK_SEQUENCE;
+       }
+       
+       io2->generic.in.alloc_size = 0;
+       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);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       
+       io->openx.out.fnum        = io2->generic.out.fnum;
+       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;
+       io->openx.out.ftype       = 0;
+       io->openx.out.devstate    = 0;
+       io->openx.out.action      = io2->generic.out.create_action;
+       io->openx.out.unique_fid  = 0;
+       io->openx.out.access_mask = io2->generic.in.access_mask;
+       io->openx.out.unknown     = 0;
+       
+       /* we need to extend the file to the requested size if
+          it was newly created */
+       if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED &&
+           io->openx.in.size != 0) {
+               union smb_setfileinfo *sf;
+               sf = talloc_p(req, union smb_setfileinfo);
+               if (sf != NULL) {
+                       sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+                       sf->generic.file.fnum = io2->generic.out.fnum;
+                       sf->end_of_file_info.in.size = io->openx.in.size;
+                       status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
+                       if (NT_STATUS_IS_OK(status)) {
+                               io->openx.out.size = io->openx.in.size;
                        }
-                       break;
-               case OPENX_MODE_DENY_FCB:
-                       io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
-                       break;
                }
+       }
+       
+       return NT_STATUS_OK;
+}
 
-               switch (io->openx.in.open_func) {
-               case (OPENX_OPEN_FUNC_FAIL):
-                       io2.generic.in.open_disposition = NTCREATEX_DISP_CREATE;
-                       break;
-               case (OPENX_OPEN_FUNC_OPEN):
-                       io2.generic.in.open_disposition = NTCREATEX_DISP_OPEN;
-                       break;
-               case (OPENX_OPEN_FUNC_TRUNC):
-                       io2.generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
-                       break;
-               case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
-                       io2.generic.in.open_disposition = NTCREATEX_DISP_CREATE;
-                       break;
-               case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
-                       io2.generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
-                       break;
-               case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
-                       io2.generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
-                       break;                  
-               }
-               io2.generic.in.alloc_size = io->openx.in.size;
-               io2.generic.in.file_attr = io->openx.in.file_attrs;
-               io2.generic.in.fname = io->openx.in.fname;
+/* 
+   NTVFS open generic to any mapper
+*/
+NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io, 
+                       struct ntvfs_module_context *ntvfs)
+{
+       NTSTATUS status;
+       union smb_open *io2;
 
-               status = req->tcon->ntvfs_ops->open(req, &io2);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-               
-               ZERO_STRUCT(io->openx.out);
-               io->openx.out.fnum = io2.generic.out.fnum;
-               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;
-               
-               return NT_STATUS_OK;
+       io2 = talloc_p(req, union smb_open);
+       if (io2 == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* must be synchronous, or we won't be called to do the 
+          translation */
+       req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
+
+       switch (io->generic.level) {
+       case RAW_OPEN_GENERIC:
+               return NT_STATUS_INVALID_LEVEL;
+
+       case RAW_OPEN_OPENX:
+               return ntvfs_map_open_openx(req, io, io2, ntvfs);
 
 
        case RAW_OPEN_OPEN:
-               ZERO_STRUCT(io2.generic.in);
-               io2.generic.level = RAW_OPEN_GENERIC;
-               io2.generic.in.file_attr = io->open.in.search_attrs;
-               io2.generic.in.fname = io->open.in.fname;
-               io2.generic.in.open_disposition = NTCREATEX_DISP_OPEN;
+               ZERO_STRUCT(io2->generic.in);
+               io2->generic.level = RAW_OPEN_GENERIC;
+               io2->generic.in.file_attr = io->openold.in.search_attrs;
+               io2->generic.in.fname = io->openold.in.fname;
+               io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
                DEBUG(9,("ntvfs_map_open(OPEN): mapping flags=0x%x\n",
-                       io->open.in.flags));
-               switch (io->open.in.flags & OPEN_FLAGS_MODE_MASK) {
+                       io->openold.in.flags));
+               switch (io->openold.in.flags & OPEN_FLAGS_MODE_MASK) {
                        case OPEN_FLAGS_OPEN_READ:
-                               io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_READ;
-                               io->open.out.rmode = DOS_OPEN_RDONLY;
+                               io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ;
+                               io->openold.out.rmode = DOS_OPEN_RDONLY;
                                break;
                        case OPEN_FLAGS_OPEN_WRITE:
-                               io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
-                               io->open.out.rmode = DOS_OPEN_WRONLY;
+                               io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
+                               io->openold.out.rmode = DOS_OPEN_WRONLY;
                                break;
                        case OPEN_FLAGS_OPEN_RDWR:
                        case 0xf: /* FCB mode */
-                               io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_READ |
+                               io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_READ |
                                        GENERIC_RIGHTS_FILE_WRITE;
-                               io->open.out.rmode = DOS_OPEN_RDWR; /* assume we got r/w */
+                               io->openold.out.rmode = DOS_OPEN_RDWR; /* assume we got r/w */
                                break;
                        default:
                                DEBUG(2,("ntvfs_map_open(OPEN): invalid mode 0x%x\n",
-                                       io->open.in.flags & OPEN_FLAGS_MODE_MASK));
+                                       io->openold.in.flags & OPEN_FLAGS_MODE_MASK));
                                return NT_STATUS_INVALID_PARAMETER;
                }
                
-               switch(io->open.in.flags & OPEN_FLAGS_DENY_MASK) {
+               switch(io->openold.in.flags & OPEN_FLAGS_DENY_MASK) {
                        case OPEN_FLAGS_DENY_DOS:
                                /* DENY_DOS is quite strange - it depends on the filename! */
-                               /* REWRITE: is this necessary for OPEN? */
-                               if (is_exe_file(io->open.in.fname)) {
-                                       io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+                               if (is_exe_file(io->openold.in.fname)) {
+                                       io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
                                } else {
-                                       if ((io->open.in.flags & OPEN_FLAGS_MODE_MASK) == 
+                                       if ((io->openold.in.flags & OPEN_FLAGS_MODE_MASK) == 
                                            OPEN_FLAGS_OPEN_READ) {
-                                               io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
+                                               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
                                        } else {
-                                               io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+                                               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
                                        }
                                }
                                break;
                        case OPEN_FLAGS_DENY_ALL:
-                               io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+                               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
                                break;
                        case OPEN_FLAGS_DENY_WRITE:
-                               io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
+                               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
                                break;
                        case OPEN_FLAGS_DENY_READ:
-                               io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
+                               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
                                break;
                        case OPEN_FLAGS_DENY_NONE:
-                               io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE |
+                               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE |
                                                NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE;
                                break;
                        case 0x70: /* FCB mode */
-                               io2.generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+                               io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
                                break;
                        default:
                                DEBUG(2,("ntvfs_map_open(OPEN): invalid DENY 0x%x\n",
-                                       io->open.in.flags & OPEN_FLAGS_DENY_MASK));
+                                       io->openold.in.flags & OPEN_FLAGS_DENY_MASK));
                                return NT_STATUS_INVALID_PARAMETER;
                }
                DEBUG(9,("ntvfs_map_open(OPEN): mapped flags=0x%x to access_mask=0x%x and share_access=0x%x\n",
-                       io->open.in.flags, io2.generic.in.access_mask, io2.generic.in.share_access));
+                       io->openold.in.flags, io2->generic.in.access_mask, io2->generic.in.share_access));
 
-               status = req->tcon->ntvfs_ops->open(req, &io2);
+               status = ntvfs->ops->openfile(ntvfs, req, io2);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
                
                ZERO_STRUCT(io->openx.out);
-               io->open.out.fnum = io2.generic.out.fnum;
-               io->open.out.attrib = io2.generic.out.attrib;
-               io->open.out.write_time = nt_time_to_unix(io2.generic.out.write_time);
-               io->open.out.size = io2.generic.out.size;
-               io->open.out.rmode = DOS_OPEN_RDWR;
+               io->openold.out.fnum = io2->generic.out.fnum;
+               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;
+               io->openold.out.rmode = DOS_OPEN_RDWR;
                
                return NT_STATUS_OK;
        }
@@ -249,19 +309,25 @@ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io)
 /* 
    NTVFS fsinfo generic to any mapper
 */
-NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs)
+NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs, 
+                         struct ntvfs_module_context *ntvfs)
 {
        NTSTATUS status;
-       union smb_fsinfo fs2;
+       union smb_fsinfo *fs2;
+
+       fs2 = talloc_p(req, union smb_fsinfo);
+       if (fs2 == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        if (fs->generic.level == RAW_QFS_GENERIC) {
                return NT_STATUS_INVALID_LEVEL;
        }
 
        /* ask the backend for the generic info */
-       fs2.generic.level = RAW_QFS_GENERIC;
+       fs2->generic.level = RAW_QFS_GENERIC;
 
-       status = req->tcon->ntvfs_ops->fsinfo(req, &fs2);
+       status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -277,7 +343,7 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs)
 
                /* we need to scale the sizes to fit */
                for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
-                       if (fs2.generic.out.blocks_total * (double)fs2.generic.out.block_size < bpunit * 512 * 65535.0) {
+                       if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
                                break;
                        }
                }
@@ -285,9 +351,9 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs)
                fs->dskattr.out.blocks_per_unit = bpunit;
                fs->dskattr.out.block_size = 512;
                fs->dskattr.out.units_total = 
-                       (fs2.generic.out.blocks_total * (double)fs2.generic.out.block_size) / (bpunit * 512);
+                       (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
                fs->dskattr.out.units_free  = 
-                       (fs2.generic.out.blocks_free  * (double)fs2.generic.out.block_size) / (bpunit * 512);
+                       (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) {
@@ -299,63 +365,63 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs)
        }
 
        case RAW_QFS_ALLOCATION:
-               fs->allocation.out.fs_id = fs2.generic.out.fs_id;
-               fs->allocation.out.total_alloc_units = fs2.generic.out.blocks_total;
-               fs->allocation.out.avail_alloc_units = fs2.generic.out.blocks_free;
+               fs->allocation.out.fs_id = fs2->generic.out.fs_id;
+               fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
+               fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
                fs->allocation.out.sectors_per_unit = 1;
-               fs->allocation.out.bytes_per_sector = fs2.generic.out.block_size;
+               fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
                return NT_STATUS_OK;
 
        case RAW_QFS_VOLUME:
-               fs->volume.out.serial_number = fs2.generic.out.serial_number;
-               fs->volume.out.volume_name.s = fs2.generic.out.volume_name;
+               fs->volume.out.serial_number = fs2->generic.out.serial_number;
+               fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
                return NT_STATUS_OK;
 
        case RAW_QFS_VOLUME_INFO:
        case RAW_QFS_VOLUME_INFORMATION:
-               fs->volume_info.out.create_time = fs2.generic.out.create_time;
-               fs->volume_info.out.serial_number = fs2.generic.out.serial_number;
-               fs->volume_info.out.volume_name.s = fs2.generic.out.volume_name;
+               fs->volume_info.out.create_time = fs2->generic.out.create_time;
+               fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
+               fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
                return NT_STATUS_OK;
 
        case RAW_QFS_SIZE_INFO:
        case RAW_QFS_SIZE_INFORMATION:
-               fs->size_info.out.total_alloc_units = fs2.generic.out.blocks_total;
-               fs->size_info.out.avail_alloc_units = fs2.generic.out.blocks_free;
+               fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
+               fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
                fs->size_info.out.sectors_per_unit = 1;
-               fs->size_info.out.bytes_per_sector = fs2.generic.out.block_size;
+               fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
                return NT_STATUS_OK;
 
        case RAW_QFS_DEVICE_INFO:
        case RAW_QFS_DEVICE_INFORMATION:
-               fs->device_info.out.device_type = fs2.generic.out.device_type;
-               fs->device_info.out.characteristics = fs2.generic.out.device_characteristics;
+               fs->device_info.out.device_type = fs2->generic.out.device_type;
+               fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
                return NT_STATUS_OK;
 
        case RAW_QFS_ATTRIBUTE_INFO:
        case RAW_QFS_ATTRIBUTE_INFORMATION:
-               fs->attribute_info.out.fs_attr = fs2.generic.out.fs_attr;
-               fs->attribute_info.out.max_file_component_length = fs2.generic.out.max_file_component_length;
-               fs->attribute_info.out.fs_type.s = fs2.generic.out.fs_type;
+               fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
+               fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
+               fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
                return NT_STATUS_OK;
 
        case RAW_QFS_QUOTA_INFORMATION:
                ZERO_STRUCT(fs->quota_information.out.unknown);
-               fs->quota_information.out.quota_soft = fs2.generic.out.quota_soft;
-               fs->quota_information.out.quota_hard = fs2.generic.out.quota_hard;
-               fs->quota_information.out.quota_flags = fs2.generic.out.quota_flags;
+               fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
+               fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
+               fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
                return NT_STATUS_OK;
 
        case RAW_QFS_FULL_SIZE_INFORMATION:
-               fs->full_size_information.out.total_alloc_units = fs2.generic.out.blocks_total;
-               fs->full_size_information.out.call_avail_alloc_units = fs2.generic.out.blocks_free;
-               fs->full_size_information.out.actual_avail_alloc_units = fs2.generic.out.blocks_free;
+               fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
+               fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
+               fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
                fs->full_size_information.out.sectors_per_unit = 1;
-               fs->full_size_information.out.bytes_per_sector = fs2.generic.out.block_size;
+               fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
                return NT_STATUS_OK;
 
        case RAW_QFS_OBJECTID_INFORMATION:
-               fs->objectid_information.out.guid = fs2.generic.out.guid;
+               fs->objectid_information.out.guid = fs2->generic.out.guid;
                ZERO_STRUCT(fs->objectid_information.out.unknown);
                return NT_STATUS_OK;
        }
@@ -368,7 +434,8 @@ NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs)
 /* 
    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(struct smbsrv_request *req, union smb_fileinfo *info, 
+                           union smb_fileinfo *info2)
 {
        int i;
        /* and convert it to the required level using results in info2 */
@@ -590,45 +657,321 @@ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info
 /* 
    NTVFS fileinfo generic to any mapper
 */
-NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info)
+NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info, 
+                            struct ntvfs_module_context *ntvfs)
 {
        NTSTATUS status;
-       union smb_fileinfo info2;
+       union smb_fileinfo *info2;
+
+       info2 = talloc_p(req, union smb_fileinfo);
+       if (info2 == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        if (info->generic.level == RAW_FILEINFO_GENERIC) {
                return NT_STATUS_INVALID_LEVEL;
        }
 
        /* ask the backend for the generic info */
-       info2.generic.level = RAW_FILEINFO_GENERIC;
-       info2.generic.in.fnum = info->generic.in.fnum;
+       info2->generic.level = RAW_FILEINFO_GENERIC;
+       info2->generic.in.fnum = info->generic.in.fnum;
 
-       status = req->tcon->ntvfs_ops->qfileinfo(req, &info2);
+       status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
-       return ntvfs_map_fileinfo(req, info, &info2);
+       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)
+NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info, 
+                            struct ntvfs_module_context *ntvfs)
 {
        NTSTATUS status;
-       union smb_fileinfo info2;
+       union smb_fileinfo *info2;
+
+       info2 = talloc_p(req, union smb_fileinfo);
+       if (info2 == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        if (info->generic.level == RAW_FILEINFO_GENERIC) {
                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;
+       info2->generic.level = RAW_FILEINFO_GENERIC;
+       info2->generic.in.fname = info->generic.in.fname;
 
-       status = req->tcon->ntvfs_ops->qpathinfo(req, &info2);
+       /* must be synchronous, or we won't be called to do the 
+          translation */
+       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);
+       return ntvfs_map_fileinfo(req, info, info2);
+}
+
+
+/* 
+   NTVFS lock generic to any mapper
+*/
+NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck, 
+                       struct ntvfs_module_context *ntvfs)
+{
+       union smb_lock *lck2;
+       struct smb_lock_entry *locks;
+
+       lck2 = talloc_p(req, union smb_lock);
+       if (lck2 == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       locks = talloc_array_p(lck2, struct smb_lock_entry, 1);
+       if (locks == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       switch (lck->generic.level) {
+       case RAW_LOCK_LOCKX:
+               return NT_STATUS_INVALID_LEVEL;
+
+       case RAW_LOCK_LOCK:
+               lck2->generic.in.ulock_cnt = 0;
+               lck2->generic.in.lock_cnt = 1;
+               break;
+
+       case RAW_LOCK_UNLOCK:
+               lck2->generic.in.ulock_cnt = 1;
+               lck2->generic.in.lock_cnt = 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;
+
+       return ntvfs->ops->lock(ntvfs, req, lck2);
+}
+
+
+/* 
+   NTVFS write generic to any mapper
+*/
+NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr, 
+                        struct ntvfs_module_context *ntvfs)
+{
+       union smb_write *wr2;
+       union smb_lock *lck;
+       union smb_close *cl;
+       NTSTATUS status;
+
+       wr2 = talloc_p(req, union smb_write);
+       if (wr2 == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       wr2->generic.level = RAW_WRITE_GENERIC;
+
+       /* we can't map asynchronously */
+       req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
+
+       switch (wr->generic.level) {
+       case RAW_WRITE_WRITEX:
+               status = NT_STATUS_INVALID_LEVEL;
+               break;
+
+       case RAW_WRITE_WRITE:
+               wr2->generic.in.fnum      = wr->write.in.fnum;
+               wr2->generic.in.offset    = wr->write.in.offset;
+               wr2->generic.in.wmode     = 0;
+               wr2->generic.in.remaining = wr->write.in.remaining;
+               wr2->generic.in.count     = wr->write.in.count;
+               wr2->generic.in.data      = wr->write.in.data;
+               status = ntvfs->ops->write(ntvfs, req, wr2);
+               wr->write.out.nwritten    = wr2->generic.out.nwritten;
+               break;
+
+       case RAW_WRITE_WRITEUNLOCK:
+               lck = talloc_p(wr2, union smb_lock);
+               if (lck == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               wr2->generic.in.fnum      = wr->writeunlock.in.fnum;
+               wr2->generic.in.offset    = wr->writeunlock.in.offset;
+               wr2->generic.in.wmode     = 0;
+               wr2->generic.in.remaining = wr->writeunlock.in.remaining;
+               wr2->generic.in.count     = wr->writeunlock.in.count;
+               wr2->generic.in.data      = wr->writeunlock.in.data;
+
+               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;
+
+               status = ntvfs->ops->write(ntvfs, req, wr2);
+
+               wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
+
+               if (NT_STATUS_IS_OK(status) && 
+                   lck->unlock.in.count != 0) {
+                       status = ntvfs->ops->lock(ntvfs, req, lck);
+               }
+               break;
+
+       case RAW_WRITE_WRITECLOSE:
+               cl = talloc_p(wr2, union smb_close);
+               if (cl == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               wr2->generic.in.fnum      = wr->writeclose.in.fnum;
+               wr2->generic.in.offset    = wr->writeclose.in.offset;
+               wr2->generic.in.wmode     = 0;
+               wr2->generic.in.remaining = 0;
+               wr2->generic.in.count     = wr->writeclose.in.count;
+               wr2->generic.in.data      = wr->writeclose.in.data;
+
+               cl->close.level           = RAW_CLOSE_CLOSE;
+               cl->close.in.fnum         = wr->writeclose.in.fnum;
+               cl->close.in.write_time   = wr->writeclose.in.mtime;
+
+               status = ntvfs->ops->write(ntvfs, req, wr2);
+               wr->writeclose.out.nwritten    = wr2->generic.out.nwritten;
+
+               if (NT_STATUS_IS_OK(status) &&
+                   wr2->generic.in.count != 0) {
+                       status = ntvfs->ops->close(ntvfs, req, cl);
+               }
+               break;
+
+       case RAW_WRITE_SPLWRITE:
+               wr2->generic.in.fnum      = wr->splwrite.in.fnum;
+               wr2->generic.in.offset    = 0;
+               wr2->generic.in.wmode     = 0;
+               wr2->generic.in.remaining = 0;
+               wr2->generic.in.count     = wr->splwrite.in.count;
+               wr2->generic.in.data      = wr->splwrite.in.data;
+               status = ntvfs->ops->write(ntvfs, req, wr2);
+               break;
+       }
+
+
+       return status;
+}
+
+
+/* 
+   NTVFS read generic to any mapper
+*/
+NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd, 
+                        struct ntvfs_module_context *ntvfs)
+{
+       union smb_read *rd2;
+       union smb_lock *lck;
+       NTSTATUS status;
+
+       rd2 = talloc_p(req, union smb_read);
+       if (rd2 == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       rd2->generic.level = RAW_READ_GENERIC;
+
+       /* we can't map asynchronously */
+       req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
+
+       switch (rd->generic.level) {
+       case RAW_READ_READX:
+               status = NT_STATUS_INVALID_LEVEL;
+               break;
+
+       case RAW_READ_READ:
+               rd2->generic.in.fnum      = rd->read.in.fnum;
+               rd2->generic.in.offset    = rd->read.in.offset;
+               rd2->generic.in.mincnt    = rd->read.in.count;
+               rd2->generic.in.maxcnt    = rd->read.in.count;
+               rd2->generic.in.remaining = rd->read.in.remaining;
+               rd2->generic.out.data     = rd->read.out.data;
+               status = ntvfs->ops->read(ntvfs, req, rd2);
+               rd->read.out.nread        = rd2->generic.out.nread;
+               break;
+
+       case RAW_READ_READBRAW:
+               rd2->generic.in.fnum      = rd->readbraw.in.fnum;
+               rd2->generic.in.offset    = rd->readbraw.in.offset;
+               rd2->generic.in.mincnt    = rd->readbraw.in.mincnt;
+               rd2->generic.in.maxcnt    = rd->readbraw.in.maxcnt;
+               rd2->generic.in.remaining = 0;
+               rd2->generic.out.data     = rd->readbraw.out.data;
+               status = ntvfs->ops->read(ntvfs, req, rd2);
+               rd->readbraw.out.nread    = rd2->generic.out.nread;
+               break;
+
+       case RAW_READ_LOCKREAD:
+               lck = talloc_p(rd2, union smb_lock);
+               if (lck == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               rd2->generic.in.fnum      = rd->lockread.in.fnum;
+               rd2->generic.in.offset    = rd->lockread.in.offset;
+               rd2->generic.in.mincnt    = rd->lockread.in.count;
+               rd2->generic.in.maxcnt    = rd->lockread.in.count;
+               rd2->generic.in.remaining = rd->lockread.in.remaining;
+               rd2->generic.out.data     = rd->lockread.out.data;
+
+               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;
+
+               status = ntvfs->ops->lock(ntvfs, req, lck);
+
+               if (NT_STATUS_IS_OK(status)) {
+                       status = ntvfs->ops->read(ntvfs, req, rd2);
+                       rd->lockread.out.nread = rd2->generic.out.nread;
+               }
+               break;
+       }
+
+
+       return status;
+}
+
+
+/* 
+   NTVFS close generic to any mapper
+*/
+NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl, 
+                        struct ntvfs_module_context *ntvfs)
+{
+       union smb_close *cl2;
+
+       cl2 = talloc_p(req, union smb_close);
+       if (cl2 == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       switch (cl->generic.level) {
+       case RAW_CLOSE_CLOSE:
+               return NT_STATUS_INVALID_LEVEL;
+
+       case RAW_CLOSE_SPLCLOSE:
+               cl2->close.level   = RAW_CLOSE_CLOSE;
+               cl2->close.in.fnum = cl->splclose.in.fnum;
+               break;
+       }
+
+       return ntvfs->ops->close(ntvfs, req, cl2);
 }