r23792: convert Samba4 to GPLv3
[kai/samba-autobuild/.git] / source4 / smb_server / smb / trans2.c
index ed53ce4daf66fc6942c996e643a65db1a7cf314f..75a03fbe7967109d95c77e2118a98228743f05f0 100644 (file)
@@ -5,7 +5,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,
    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 file handles the parsing of transact2 requests
 */
 
 #include "includes.h"
-#include "dlinklist.h"
+#include "lib/util/dlinklist.h"
 #include "smb_server/smb_server.h"
 #include "librpc/gen_ndr/ndr_misc.h"
 #include "ntvfs/ntvfs.h"
 #include "libcli/raw/libcliraw.h"
 
+#define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
+       if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
+               trans2_setup_reply(trans, 0, 0, 0);\
+               return req->ntvfs->async_states->status; \
+       } \
+} while (0)
+#define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
+       TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
+       ptr = talloc_get_type(op->op_info, type); \
+} while (0)
+#define TRANS2_CHECK(cmd) do { \
+       NTSTATUS _status; \
+       _status = cmd; \
+       NT_STATUS_NOT_OK_RETURN(_status); \
+} while (0)
+
+/*
+  hold the state of a nttrans op while in progress. Needed to allow for async backend
+  functions.
+*/
+struct trans_op {
+       struct smbsrv_request *req;
+       struct smb_trans2 *trans;
+       uint8_t command;
+       NTSTATUS (*send_fn)(struct trans_op *);
+       void *op_info;
+};
+
 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
        if ((blob)->length < (size)) { \
                return NT_STATUS_INFO_LENGTH_MISMATCH; \
        }} while (0)
 
-/* grow the data allocation size of a trans2 reply - this guarantees
-   that requests to grow the data size later will not change the
-   pointer */
-static BOOL trans2_grow_data_allocation(struct smbsrv_request *req, 
-                                       struct smb_trans2 *trans,
-                                       uint32_t new_size)
+/* setup a trans2 reply, given the data and params sizes */
+static NTSTATUS trans2_setup_reply(struct smb_trans2 *trans,
+                                  uint16_t param_size, uint16_t data_size,
+                                  uint16_t setup_count)
 {
-       if (new_size <= trans->out.data.length) {
-               return True;
+       trans->out.setup_count = setup_count;
+       if (setup_count > 0) {
+               trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
+               NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
        }
-       trans->out.data.data = talloc_realloc(req, trans->out.data.data, 
-                                             uint8_t, new_size);
-       return (trans->out.data.data != NULL);
-}
+       trans->out.params = data_blob_talloc(trans, NULL, param_size);
+       if (param_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
 
+       trans->out.data = data_blob_talloc(trans, NULL, data_size);
+       if (data_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
 
-/* grow the data size of a trans2 reply */
-static BOOL trans2_grow_data(struct smbsrv_request *req, 
-                            struct smb_trans2 *trans,
-                            uint32_t new_size)
-{
-       if (!trans2_grow_data_allocation(req, trans, new_size)) {
-               return False;
-       }
-       trans->out.data.length = new_size;
-       return True;
+       return NT_STATUS_OK;
 }
 
-/* grow the data, zero filling any new bytes */
-static BOOL trans2_grow_data_fill(struct smbsrv_request *req, 
-                                 struct smb_trans2 *trans,
-                                 uint32_t new_size)
+static NTSTATUS trans2_push_fsinfo(struct smbsrv_connection *smb_conn,
+                                  TALLOC_CTX *mem_ctx,
+                                  DATA_BLOB *blob,
+                                  union smb_fsinfo *fsinfo,
+                                  int default_str_flags)
 {
-       uint32_t old_size = trans->out.data.length;
-       if (!trans2_grow_data(req, trans, new_size)) {
-               return False;
-       }
-       if (new_size > old_size) {
-               memset(trans->out.data.data + old_size, 0, new_size - old_size);
-       }
-       return True;
-}
-
+       enum smb_fsinfo_level passthru_level;
 
-/* setup a trans2 reply, given the data and params sizes */
-static void trans2_setup_reply(struct smbsrv_request *req, 
-                              struct smb_trans2 *trans,
-                              uint16_t param_size, uint16_t data_size,
-                              uint16_t setup_count)
-{
-       trans->out.setup_count = setup_count;
-       if (setup_count != 0) {
-               trans->out.setup = talloc_zero_array(req, uint16_t, setup_count);
-       }
-       trans->out.params = data_blob_talloc(req, NULL, param_size);
-       trans->out.data = data_blob_talloc(req, NULL, data_size);
-}
+       switch (fsinfo->generic.level) {
+       case RAW_QFS_ALLOCATION:
+               TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 18));
 
+               SIVAL(blob->data,  0, fsinfo->allocation.out.fs_id);
+               SIVAL(blob->data,  4, fsinfo->allocation.out.sectors_per_unit);
+               SIVAL(blob->data,  8, fsinfo->allocation.out.total_alloc_units);
+               SIVAL(blob->data, 12, fsinfo->allocation.out.avail_alloc_units);
+               SSVAL(blob->data, 16, fsinfo->allocation.out.bytes_per_sector);
 
-/*
-  pull a string from a blob in a trans2 request
-*/
-static size_t trans2_pull_blob_string(struct smbsrv_request *req, 
-                                     const DATA_BLOB *blob,
-                                     uint16_t offset,
-                                     const char **str,
-                                     int flags)
-{
-       /* we use STR_NO_RANGE_CHECK because the params are allocated
-          separately in a DATA_BLOB, so we need to do our own range
-          checking */
-       if (offset >= blob->length) {
-               *str = NULL;
-               return 0;
-       }
-       
-       return req_pull_string(req, str, 
-                              blob->data + offset, 
-                              blob->length - offset,
-                              STR_NO_RANGE_CHECK | flags);
-}
+               return NT_STATUS_OK;
 
-/*
-  push a string into the data section of a trans2 request
-  return the number of bytes consumed in the output
-*/
-static size_t trans2_push_data_string(struct smbsrv_request *req, 
-                                     struct smb_trans2 *trans,
-                                     uint32_t len_offset,
-                                     uint32_t offset,
-                                     const WIRE_STRING *str,
-                                     int dest_len,
-                                     int flags)
-{
-       int alignment = 0, ret = 0, pkt_len;
-
-       /* we use STR_NO_RANGE_CHECK because the params are allocated
-          separately in a DATA_BLOB, so we need to do our own range
-          checking */
-       if (!str->s || offset >= trans->out.data.length) {
-               if (flags & STR_LEN8BIT) {
-                       SCVAL(trans->out.data.data, len_offset, 0);
-               } else {
-                       SIVAL(trans->out.data.data, len_offset, 0);
-               }
-               return 0;
-       }
+       case RAW_QFS_VOLUME:
+               TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 5));
 
-       flags |= STR_NO_RANGE_CHECK;
+               SIVAL(blob->data,       0, fsinfo->volume.out.serial_number);
+               /* w2k3 implements this incorrectly for unicode - it
+                * leaves the last byte off the string */
+               TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx, blob,
+                                                      fsinfo->volume.out.volume_name.s,
+                                                      4, default_str_flags,
+                                                      STR_LEN8BIT|STR_NOALIGN));
 
-       if (dest_len == -1 || (dest_len > trans->out.data.length - offset)) {
-               dest_len = trans->out.data.length - offset;
-       }
+               return NT_STATUS_OK;
 
-       if (!(flags & (STR_ASCII|STR_UNICODE))) {
-               flags |= (req->flags2 & FLAGS2_UNICODE_STRINGS) ? STR_UNICODE : STR_ASCII;
-       }
+       case RAW_QFS_VOLUME_INFO:
+               passthru_level = RAW_QFS_VOLUME_INFORMATION;
+               break;
 
-       if ((offset&1) && (flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
-               alignment = 1;
-               if (dest_len > 0) {
-                       SCVAL(trans->out.data.data + offset, 0, 0);
-                       ret = push_string(trans->out.data.data + offset + 1, str->s, dest_len-1, flags);
-               }
-       } else {
-               ret = push_string(trans->out.data.data + offset, str->s, dest_len, flags);
-       }
+       case RAW_QFS_SIZE_INFO:
+               passthru_level = RAW_QFS_SIZE_INFORMATION;
+               break;
 
-       /* sometimes the string needs to be terminated, but the length
-          on the wire must not include the termination! */
-       pkt_len = ret;
+       case RAW_QFS_DEVICE_INFO:
+               passthru_level = RAW_QFS_DEVICE_INFORMATION;
+               break;
 
-       if ((flags & STR_LEN_NOTERM) && (flags & STR_TERMINATE)) {
-               if ((flags & STR_UNICODE) && ret >= 2) {
-                       pkt_len = ret-2;
-               }
-               if ((flags & STR_ASCII) && ret >= 1) {
-                       pkt_len = ret-1;
-               }
-       }       
+       case RAW_QFS_ATTRIBUTE_INFO:
+               passthru_level = RAW_QFS_ATTRIBUTE_INFORMATION;
+               break;
 
-       if (flags & STR_LEN8BIT) {
-               SCVAL(trans->out.data.data, len_offset, pkt_len);
-       } else {
-               SIVAL(trans->out.data.data, len_offset, pkt_len);
+       default:
+               passthru_level = fsinfo->generic.level;
+               break;
        }
 
-       return ret + alignment;
+       return smbsrv_push_passthru_fsinfo(mem_ctx, blob,
+                                          passthru_level, fsinfo,
+                                          default_str_flags);
 }
 
 /*
-  append a string to the data section of a trans2 reply
-  len_offset points to the place in the packet where the length field
-  should go
+  trans2 qfsinfo implementation send
 */
-static void trans2_append_data_string(struct smbsrv_request *req, 
-                                       struct smb_trans2 *trans,
-                                       const WIRE_STRING *str,
-                                       uint_t len_offset,
-                                       int flags)
+static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
 {
-       size_t ret;
-       uint32_t offset;
-       const int max_bytes_per_char = 3;
-
-       offset = trans->out.data.length;
-       trans2_grow_data(req, trans, offset + (2+strlen_m(str->s))*max_bytes_per_char);
-       ret = trans2_push_data_string(req, trans, len_offset, offset, str, -1, flags);
-       trans2_grow_data(req, trans, offset + ret);
-}
+       struct smbsrv_request *req = op->req;
+       struct smb_trans2 *trans = op->trans;
+       union smb_fsinfo *fsinfo;
 
-/*
-  align the end of the data section of a trans reply on an even boundary
-*/
-static void trans2_align_data(struct smbsrv_request *req, struct smb_trans2 *trans)
-{
-       if ((trans->out.data.length & 1) == 0) {
-               return;
-       }
-       trans2_grow_data(req, trans, trans->out.data.length+1);
-       SCVAL(trans->out.data.data, trans->out.data.length-1, 0);
-}
+       TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
+
+       TRANS2_CHECK(trans2_setup_reply(trans, 0, 0, 0));
+
+       TRANS2_CHECK(trans2_push_fsinfo(req->smb_conn, trans,
+                                       &trans->out.data, fsinfo,
+                                       SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
 
+       return NT_STATUS_OK;
+}
 
 /*
   trans2 qfsinfo implementation
 */
-static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op)
 {
-       union smb_fsinfo fsinfo;
-       NTSTATUS status;
+       struct smb_trans2 *trans = op->trans;
+       union smb_fsinfo *fsinfo;
        uint16_t level;
-       uint_t i;
-       DATA_BLOB guid_blob;
 
        /* make sure we got enough parameters */
        if (trans->in.params.length != 2) {
                return NT_STATUS_FOOBAR;
        }
 
-       level = SVAL(trans->in.params.data, 0);
-
-       switch (level) {
-       case SMB_QFS_ALLOCATION:
-               fsinfo.allocation.level = RAW_QFS_ALLOCATION;
-
-               status = ntvfs_fsinfo(req, &fsinfo);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-
-               trans2_setup_reply(req, trans, 0, 18, 0);
-
-               SIVAL(trans->out.data.data,  0, fsinfo.allocation.out.fs_id);
-               SIVAL(trans->out.data.data,  4, fsinfo.allocation.out.sectors_per_unit);
-               SIVAL(trans->out.data.data,  8, fsinfo.allocation.out.total_alloc_units);
-               SIVAL(trans->out.data.data, 12, fsinfo.allocation.out.avail_alloc_units);
-               SSVAL(trans->out.data.data, 16, fsinfo.allocation.out.bytes_per_sector);
-
-               return NT_STATUS_OK;
-
-       case SMB_QFS_VOLUME:
-               fsinfo.volume.level = RAW_QFS_VOLUME;
-
-               status = ntvfs_fsinfo(req, &fsinfo);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-
-               trans2_setup_reply(req, trans, 0, 5, 0);
-
-               SIVAL(trans->out.data.data,       0, fsinfo.volume.out.serial_number);
-               /* w2k3 implements this incorrectly for unicode - it
-                * leaves the last byte off the string */
-               trans2_append_data_string(req, trans, 
-                                         &fsinfo.volume.out.volume_name, 
-                                         4, STR_LEN8BIT|STR_NOALIGN);
-
-               return NT_STATUS_OK;
-
-       case SMB_QFS_VOLUME_INFO:
-       case SMB_QFS_VOLUME_INFORMATION:
-               fsinfo.volume_info.level = RAW_QFS_VOLUME_INFO;
-
-               status = ntvfs_fsinfo(req, &fsinfo);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-
-               trans2_setup_reply(req, trans, 0, 18, 0);
-
-               push_nttime(trans->out.data.data, 0, fsinfo.volume_info.out.create_time);
-               SIVAL(trans->out.data.data,       8, fsinfo.volume_info.out.serial_number);
-               SSVAL(trans->out.data.data,      16, 0); /* padding */
-               trans2_append_data_string(req, trans, 
-                                         &fsinfo.volume_info.out.volume_name, 
-                                         12, STR_UNICODE);
-
-               return NT_STATUS_OK;
-
-       case SMB_QFS_SIZE_INFO:
-       case SMB_QFS_SIZE_INFORMATION:
-               fsinfo.size_info.level = RAW_QFS_SIZE_INFO;
-
-               status = ntvfs_fsinfo(req, &fsinfo);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-
-               trans2_setup_reply(req, trans, 0, 24, 0);
-
-               SBVAL(trans->out.data.data,  0, fsinfo.size_info.out.total_alloc_units);
-               SBVAL(trans->out.data.data,  8, fsinfo.size_info.out.avail_alloc_units);
-               SIVAL(trans->out.data.data, 16, fsinfo.size_info.out.sectors_per_unit);
-               SIVAL(trans->out.data.data, 20, fsinfo.size_info.out.bytes_per_sector);
-
-               return NT_STATUS_OK;
-
-       case SMB_QFS_DEVICE_INFO:
-       case SMB_QFS_DEVICE_INFORMATION:
-               fsinfo.device_info.level = RAW_QFS_DEVICE_INFO;
-
-               status = ntvfs_fsinfo(req, &fsinfo);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-               trans2_setup_reply(req, trans, 0, 8, 0);
-               SIVAL(trans->out.data.data,      0, fsinfo.device_info.out.device_type);
-               SIVAL(trans->out.data.data,      4, fsinfo.device_info.out.characteristics);
-               return NT_STATUS_OK;
-
-
-       case SMB_QFS_ATTRIBUTE_INFO:
-       case SMB_QFS_ATTRIBUTE_INFORMATION:
-               fsinfo.attribute_info.level = RAW_QFS_ATTRIBUTE_INFO;
-
-               status = ntvfs_fsinfo(req, &fsinfo);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-
-               trans2_setup_reply(req, trans, 0, 12, 0);
+       fsinfo = talloc(op, union smb_fsinfo);
+       NT_STATUS_HAVE_NO_MEMORY(fsinfo);
 
-               SIVAL(trans->out.data.data, 0, fsinfo.attribute_info.out.fs_attr);
-               SIVAL(trans->out.data.data, 4, fsinfo.attribute_info.out.max_file_component_length);
-               /* this must not be null terminated or win98 gets
-                  confused!  also note that w2k3 returns this as
-                  unicode even when ascii is negotiated */
-               trans2_append_data_string(req, trans, 
-                                         &fsinfo.attribute_info.out.fs_type,
-                                         8, STR_UNICODE);
-               return NT_STATUS_OK;
-
-
-       case SMB_QFS_QUOTA_INFORMATION:
-               fsinfo.quota_information.level = RAW_QFS_QUOTA_INFORMATION;
-
-               status = ntvfs_fsinfo(req, &fsinfo);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-
-               trans2_setup_reply(req, trans, 0, 48, 0);
-
-               SBVAL(trans->out.data.data,   0, fsinfo.quota_information.out.unknown[0]);
-               SBVAL(trans->out.data.data,   8, fsinfo.quota_information.out.unknown[1]);
-               SBVAL(trans->out.data.data,  16, fsinfo.quota_information.out.unknown[2]);
-               SBVAL(trans->out.data.data,  24, fsinfo.quota_information.out.quota_soft);
-               SBVAL(trans->out.data.data,  32, fsinfo.quota_information.out.quota_hard);
-               SBVAL(trans->out.data.data,  40, fsinfo.quota_information.out.quota_flags);
-
-               return NT_STATUS_OK;
-
-
-       case SMB_QFS_FULL_SIZE_INFORMATION:
-               fsinfo.full_size_information.level = RAW_QFS_FULL_SIZE_INFORMATION;
-
-               status = ntvfs_fsinfo(req, &fsinfo);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-
-               trans2_setup_reply(req, trans, 0, 32, 0);
+       level = SVAL(trans->in.params.data, 0);
 
-               SBVAL(trans->out.data.data,  0, fsinfo.full_size_information.out.total_alloc_units);
-               SBVAL(trans->out.data.data,  8, fsinfo.full_size_information.out.call_avail_alloc_units);
-               SBVAL(trans->out.data.data, 16, fsinfo.full_size_information.out.actual_avail_alloc_units);
-               SIVAL(trans->out.data.data, 24, fsinfo.full_size_information.out.sectors_per_unit);
-               SIVAL(trans->out.data.data, 28, fsinfo.full_size_information.out.bytes_per_sector);
+       /* work out the backend level - we make it 1-1 in the header */
+       fsinfo->generic.level = (enum smb_fsinfo_level)level;
+       if (fsinfo->generic.level >= RAW_QFS_GENERIC) {
+               return NT_STATUS_INVALID_LEVEL;
+       }
 
-               return NT_STATUS_OK;
+       op->op_info = fsinfo;
+       op->send_fn = trans2_qfsinfo_send;
 
-       case SMB_QFS_OBJECTID_INFORMATION:
-               fsinfo.objectid_information.level = RAW_QFS_OBJECTID_INFORMATION;
+       return ntvfs_fsinfo(req->ntvfs, fsinfo);
+}
 
-               status = ntvfs_fsinfo(req, &fsinfo);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
 
-               trans2_setup_reply(req, trans, 0, 64, 0);
+/*
+  trans2 open implementation send
+*/
+static NTSTATUS trans2_open_send(struct trans_op *op)
+{
+       struct smbsrv_request *req = op->req;
+       struct smb_trans2 *trans = op->trans;
+       union smb_open *io;
 
-               status = ndr_push_struct_blob(&guid_blob, req, 
-                                             &fsinfo.objectid_information.out.guid,
-                                             (ndr_push_flags_fn_t)ndr_push_GUID);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
+       TRANS2_CHECK_ASYNC_STATUS(io, union smb_open);
 
-               memcpy(trans->out.data.data, guid_blob.data, guid_blob.length);
+       TRANS2_CHECK(trans2_setup_reply(trans, 30, 0, 0));
 
-               for (i=0;i<6;i++) {
-                       SBVAL(trans->out.data.data, 16 + 8*i, fsinfo.objectid_information.out.unknown[i]);
-               }
-               return NT_STATUS_OK;
-       }
+       smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
+       SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
+       srv_push_dos_date3(req->smb_conn, trans->out.params.data, 
+                          VWV(2), io->t2open.out.write_time);
+       SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
+       SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
+       SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
+       SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
+       SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
+       SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
+       SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
+       SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
 
-       return NT_STATUS_INVALID_LEVEL;
+       return NT_STATUS_OK;
 }
 
-
 /*
   trans2 open implementation
 */
-static NTSTATUS trans2_open(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
 {
+       struct smb_trans2 *trans = op->trans;
        union smb_open *io;
-       NTSTATUS status;
 
        /* make sure we got enough parameters */
        if (trans->in.params.length < 29) {
                return NT_STATUS_FOOBAR;
        }
 
-       io = talloc(req, union smb_open);
-       if (io == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
+       io = talloc(op, union smb_open);
+       NT_STATUS_HAVE_NO_MEMORY(io);
 
        io->t2open.level           = RAW_OPEN_T2OPEN;
        io->t2open.in.flags        = SVAL(trans->in.params.data, VWV(0));
@@ -438,328 +241,214 @@ static NTSTATUS trans2_open(struct smbsrv_request *req, struct smb_trans2 *trans
        io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2));
        io->t2open.in.file_attrs   = SVAL(trans->in.params.data, VWV(3));
        io->t2open.in.write_time   = srv_pull_dos_date(req->smb_conn, 
-                                                   trans->in.params.data + VWV(4));;
+                                                   trans->in.params.data + VWV(4));
        io->t2open.in.open_func    = SVAL(trans->in.params.data, VWV(6));
        io->t2open.in.size         = IVAL(trans->in.params.data, VWV(7));
        io->t2open.in.timeout      = IVAL(trans->in.params.data, VWV(9));
        io->t2open.in.num_eas      = 0;
        io->t2open.in.eas          = NULL;
 
-       trans2_pull_blob_string(req, &trans->in.params, 28, &io->t2open.in.fname, 0);
-
-       status = ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       status = ntvfs_open(req, io);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       smbsrv_blob_pull_string(req, &trans->in.params, 28, &io->t2open.in.fname, 0);
+       if (io->t2open.in.fname == NULL) {
+               return NT_STATUS_FOOBAR;
        }
 
-       trans2_setup_reply(req, trans, 30, 0, 0);
+       TRANS2_CHECK(ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas));
 
-       SSVAL(trans->out.params.data, VWV(0), io->t2open.out.fnum);
-       SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
-       srv_push_dos_date3(req->smb_conn, trans->out.params.data, 
-                          VWV(2), io->t2open.out.write_time);
-       SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
-       SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
-       SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
-       SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
-       SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
-       SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
-       SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
-       SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
+       op->op_info = io;
+       op->send_fn = trans2_open_send;
 
-       return status;
+       return ntvfs_open(req->ntvfs, io);
 }
 
 
+/*
+  trans2 simple send
+*/
+static NTSTATUS trans2_simple_send(struct trans_op *op)
+{
+       struct smbsrv_request *req = op->req;
+       struct smb_trans2 *trans = op->trans;
+
+       TRANS2_CHECK_ASYNC_STATUS_SIMPLE;
+
+       TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
+
+       SSVAL(trans->out.params.data, VWV(0), 0);
+
+       return NT_STATUS_OK;
+}
+
 /*
   trans2 mkdir implementation
 */
-static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
 {
+       struct smb_trans2 *trans = op->trans;
        union smb_mkdir *io;
-       NTSTATUS status;
 
        /* make sure we got enough parameters */
        if (trans->in.params.length < 5) {
                return NT_STATUS_FOOBAR;
        }
 
-       io = talloc(req, union smb_mkdir);
-       if (io == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
+       io = talloc(op, union smb_mkdir);
+       NT_STATUS_HAVE_NO_MEMORY(io);
 
        io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
-       trans2_pull_blob_string(req, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
-
-       status = ea_pull_list(&trans->in.data, io, 
-                             &io->t2mkdir.in.num_eas, 
-                             &io->t2mkdir.in.eas);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       status = ntvfs_mkdir(req, io);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       smbsrv_blob_pull_string(req, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
+       if (io->t2mkdir.in.path == NULL) {
+               return NT_STATUS_FOOBAR;
        }
 
-       trans2_setup_reply(req, trans, 2, 0, 0);
+       TRANS2_CHECK(ea_pull_list(&trans->in.data, io, 
+                                 &io->t2mkdir.in.num_eas, 
+                                 &io->t2mkdir.in.eas));
 
-       SSVAL(trans->out.params.data, VWV(0), 0);
+       op->op_info = io;
+       op->send_fn = trans2_simple_send;
 
-       return status;
+       return ntvfs_mkdir(req->ntvfs, io);
 }
 
-/*
-  fill in the reply from a qpathinfo or qfileinfo call
-*/
-static NTSTATUS trans2_fileinfo_fill(struct smbsrv_request *req, struct smb_trans2 *trans,
-                                    union smb_fileinfo *st)
+static NTSTATUS trans2_push_fileinfo(struct smbsrv_connection *smb_conn,
+                                    TALLOC_CTX *mem_ctx,
+                                    DATA_BLOB *blob,
+                                    union smb_fileinfo *st,
+                                    int default_str_flags)
 {
-       uint_t i;
        uint32_t list_size;
-       
+       enum smb_fileinfo_level passthru_level;
+
        switch (st->generic.level) {
        case RAW_FILEINFO_GENERIC:
        case RAW_FILEINFO_GETATTR:
        case RAW_FILEINFO_GETATTRE:
        case RAW_FILEINFO_SEC_DESC:
+       case RAW_FILEINFO_SMB2_ALL_EAS:
+       case RAW_FILEINFO_SMB2_ALL_INFORMATION:
                /* handled elsewhere */
                return NT_STATUS_INVALID_LEVEL;
 
-       case RAW_FILEINFO_BASIC_INFO:
-       case RAW_FILEINFO_BASIC_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 40, 0);
-
-               SSVAL(trans->out.params.data, 0, 0);
-               push_nttime(trans->out.data.data,  0, st->basic_info.out.create_time);
-               push_nttime(trans->out.data.data,  8, st->basic_info.out.access_time);
-               push_nttime(trans->out.data.data, 16, st->basic_info.out.write_time);
-               push_nttime(trans->out.data.data, 24, st->basic_info.out.change_time);
-               SIVAL(trans->out.data.data,       32, st->basic_info.out.attrib);
-               SIVAL(trans->out.data.data,       36, 0); /* padding */
-               return NT_STATUS_OK;
+       case RAW_FILEINFO_UNIX_BASIC:
+       case RAW_FILEINFO_UNIX_LINK:
+               /* not implemented yet */
+               return NT_STATUS_INVALID_LEVEL;
 
        case RAW_FILEINFO_STANDARD:
-               trans2_setup_reply(req, trans, 2, 22, 0);
-
-               SSVAL(trans->out.params.data, 0, 0);
-               srv_push_dos_date2(req->smb_conn, trans->out.data.data, 0, st->standard.out.create_time);
-               srv_push_dos_date2(req->smb_conn, trans->out.data.data, 4, st->standard.out.access_time);
-               srv_push_dos_date2(req->smb_conn, trans->out.data.data, 8, st->standard.out.write_time);
-               SIVAL(trans->out.data.data,        12, st->standard.out.size);
-               SIVAL(trans->out.data.data,        16, st->standard.out.alloc_size);
-               SSVAL(trans->out.data.data,        20, st->standard.out.attrib);
+               TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 22));
+
+               srv_push_dos_date2(smb_conn, blob->data, 0, st->standard.out.create_time);
+               srv_push_dos_date2(smb_conn, blob->data, 4, st->standard.out.access_time);
+               srv_push_dos_date2(smb_conn, blob->data, 8, st->standard.out.write_time);
+               SIVAL(blob->data,        12, st->standard.out.size);
+               SIVAL(blob->data,        16, st->standard.out.alloc_size);
+               SSVAL(blob->data,        20, st->standard.out.attrib);
                return NT_STATUS_OK;
 
        case RAW_FILEINFO_EA_SIZE:
-               trans2_setup_reply(req, trans, 2, 26, 0);
-
-               SSVAL(trans->out.params.data, 0, 0);
-               srv_push_dos_date2(req->smb_conn, trans->out.data.data, 0, st->ea_size.out.create_time);
-               srv_push_dos_date2(req->smb_conn, trans->out.data.data, 4, st->ea_size.out.access_time);
-               srv_push_dos_date2(req->smb_conn, trans->out.data.data, 8, st->ea_size.out.write_time);
-               SIVAL(trans->out.data.data,        12, st->ea_size.out.size);
-               SIVAL(trans->out.data.data,        16, st->ea_size.out.alloc_size);
-               SSVAL(trans->out.data.data,        20, st->ea_size.out.attrib);
-               SIVAL(trans->out.data.data,        22, st->ea_size.out.ea_size);
-               return NT_STATUS_OK;
-
-       case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 56, 0);
-
-               SSVAL(trans->out.params.data, 0, 0);
-               push_nttime(trans->out.data.data,  0, st->network_open_information.out.create_time);
-               push_nttime(trans->out.data.data,  8, st->network_open_information.out.access_time);
-               push_nttime(trans->out.data.data, 16, st->network_open_information.out.write_time);
-               push_nttime(trans->out.data.data, 24, st->network_open_information.out.change_time);
-               SBVAL(trans->out.data.data,       32, st->network_open_information.out.alloc_size);
-               SBVAL(trans->out.data.data,       40, st->network_open_information.out.size);
-               SIVAL(trans->out.data.data,       48, st->network_open_information.out.attrib);
-               SIVAL(trans->out.data.data,       52, 0); /* padding */
-               return NT_STATUS_OK;
-
-       case RAW_FILEINFO_STANDARD_INFO:
-       case RAW_FILEINFO_STANDARD_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 24, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               SBVAL(trans->out.data.data,  0, st->standard_info.out.alloc_size);
-               SBVAL(trans->out.data.data,  8, st->standard_info.out.size);
-               SIVAL(trans->out.data.data, 16, st->standard_info.out.nlink);
-               SCVAL(trans->out.data.data, 20, st->standard_info.out.delete_pending);
-               SCVAL(trans->out.data.data, 21, st->standard_info.out.directory);
-               SSVAL(trans->out.data.data, 22, 0); /* padding */
-               return NT_STATUS_OK;
-
-       case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 8, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               SIVAL(trans->out.data.data,  0, st->attribute_tag_information.out.attrib);
-               SIVAL(trans->out.data.data,  4, st->attribute_tag_information.out.reparse_tag);
-               return NT_STATUS_OK;
-
-       case RAW_FILEINFO_EA_INFO:
-       case RAW_FILEINFO_EA_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 4, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               SIVAL(trans->out.data.data,  0, st->ea_info.out.ea_size);
-               return NT_STATUS_OK;
-
-       case RAW_FILEINFO_MODE_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 4, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               SIVAL(trans->out.data.data,  0, st->mode_information.out.mode);
-               return NT_STATUS_OK;
-
-       case RAW_FILEINFO_ALIGNMENT_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 4, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               SIVAL(trans->out.data.data,  0, 
-                     st->alignment_information.out.alignment_requirement);
+               TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 26));
+
+               srv_push_dos_date2(smb_conn, blob->data, 0, st->ea_size.out.create_time);
+               srv_push_dos_date2(smb_conn, blob->data, 4, st->ea_size.out.access_time);
+               srv_push_dos_date2(smb_conn, blob->data, 8, st->ea_size.out.write_time);
+               SIVAL(blob->data,        12, st->ea_size.out.size);
+               SIVAL(blob->data,        16, st->ea_size.out.alloc_size);
+               SSVAL(blob->data,        20, st->ea_size.out.attrib);
+               SIVAL(blob->data,        22, st->ea_size.out.ea_size);
                return NT_STATUS_OK;
 
        case RAW_FILEINFO_EA_LIST:
                list_size = ea_list_size(st->ea_list.out.num_eas,
                                         st->ea_list.out.eas);
-               trans2_setup_reply(req, trans, 2, list_size, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               ea_put_list(trans->out.data.data, 
+               TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
+
+               ea_put_list(blob->data, 
                            st->ea_list.out.num_eas, st->ea_list.out.eas);
                return NT_STATUS_OK;
 
        case RAW_FILEINFO_ALL_EAS:
                list_size = ea_list_size(st->all_eas.out.num_eas,
                                                  st->all_eas.out.eas);
-               trans2_setup_reply(req, trans, 2, list_size, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               ea_put_list(trans->out.data.data, 
+               TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
+
+               ea_put_list(blob->data, 
                            st->all_eas.out.num_eas, st->all_eas.out.eas);
                return NT_STATUS_OK;
 
-       case RAW_FILEINFO_ACCESS_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 4, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               SIVAL(trans->out.data.data,  0, st->access_information.out.access_flags);
+       case RAW_FILEINFO_IS_NAME_VALID:
                return NT_STATUS_OK;
 
-       case RAW_FILEINFO_POSITION_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 8, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               SBVAL(trans->out.data.data,  0, st->position_information.out.position);
-               return NT_STATUS_OK;
+       case RAW_FILEINFO_BASIC_INFO:
+               passthru_level = RAW_FILEINFO_BASIC_INFORMATION;
+               break;
 
-       case RAW_FILEINFO_COMPRESSION_INFO:
-       case RAW_FILEINFO_COMPRESSION_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 16, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               SBVAL(trans->out.data.data,  0, st->compression_info.out.compressed_size);
-               SSVAL(trans->out.data.data,  8, st->compression_info.out.format);
-               SCVAL(trans->out.data.data, 10, st->compression_info.out.unit_shift);
-               SCVAL(trans->out.data.data, 11, st->compression_info.out.chunk_shift);
-               SCVAL(trans->out.data.data, 12, st->compression_info.out.cluster_shift);
-               SSVAL(trans->out.data.data, 13, 0); /* 3 bytes padding */
-               SCVAL(trans->out.data.data, 15, 0);
-               return NT_STATUS_OK;
+       case RAW_FILEINFO_STANDARD_INFO:
+               passthru_level = RAW_FILEINFO_STANDARD_INFORMATION;
+               break;
 
-       case RAW_FILEINFO_IS_NAME_VALID:
-               trans2_setup_reply(req, trans, 2, 0, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               return NT_STATUS_OK;
+       case RAW_FILEINFO_EA_INFO:
+               passthru_level = RAW_FILEINFO_EA_INFORMATION;
+               break;
 
-       case RAW_FILEINFO_INTERNAL_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 8, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               SBVAL(trans->out.data.data,  0, st->internal_information.out.file_id);
-               return NT_STATUS_OK;
+       case RAW_FILEINFO_COMPRESSION_INFO:
+               passthru_level = RAW_FILEINFO_COMPRESSION_INFORMATION;
+               break;
 
        case RAW_FILEINFO_ALL_INFO:
-       case RAW_FILEINFO_ALL_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 72, 0);
-
-               SSVAL(trans->out.params.data, 0, 0);
-               push_nttime(trans->out.data.data,  0, st->all_info.out.create_time);
-               push_nttime(trans->out.data.data,  8, st->all_info.out.access_time);
-               push_nttime(trans->out.data.data, 16, st->all_info.out.write_time);
-               push_nttime(trans->out.data.data, 24, st->all_info.out.change_time);
-               SIVAL(trans->out.data.data,       32, st->all_info.out.attrib);
-               SIVAL(trans->out.data.data,       36, 0);
-               SBVAL(trans->out.data.data,       40, st->all_info.out.alloc_size);
-               SBVAL(trans->out.data.data,       48, st->all_info.out.size);
-               SIVAL(trans->out.data.data,       56, st->all_info.out.nlink);
-               SCVAL(trans->out.data.data,       60, st->all_info.out.delete_pending);
-               SCVAL(trans->out.data.data,       61, st->all_info.out.directory);
-               SSVAL(trans->out.data.data,       62, 0); /* padding */
-               SIVAL(trans->out.data.data,       64, st->all_info.out.ea_size);
-               trans2_append_data_string(req, trans, &st->all_info.out.fname, 
-                                         68, STR_UNICODE);
-               return NT_STATUS_OK;
+               passthru_level = RAW_FILEINFO_ALL_INFORMATION;
+               break;
 
        case RAW_FILEINFO_NAME_INFO:
-       case RAW_FILEINFO_NAME_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 4, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               trans2_append_data_string(req, trans, &st->name_info.out.fname, 0, STR_UNICODE);
-               return NT_STATUS_OK;
+               passthru_level = RAW_FILEINFO_NAME_INFORMATION;
+               break;
 
        case RAW_FILEINFO_ALT_NAME_INFO:
-       case RAW_FILEINFO_ALT_NAME_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 4, 0);
-               SSVAL(trans->out.params.data, 0, 0);
-               trans2_append_data_string(req, trans, &st->alt_name_info.out.fname, 0, STR_UNICODE);
-               return NT_STATUS_OK;
+               passthru_level = RAW_FILEINFO_ALT_NAME_INFORMATION;
+               break;
 
        case RAW_FILEINFO_STREAM_INFO:
-       case RAW_FILEINFO_STREAM_INFORMATION:
-               trans2_setup_reply(req, trans, 2, 0, 0);
-
-               SSVAL(trans->out.params.data, 0, 0);
-
-               for (i=0;i<st->stream_info.out.num_streams;i++) {
-                       uint32_t data_size = trans->out.data.length;
-                       uint8_t *data;
-
-                       trans2_grow_data(req, trans, data_size + 24);
-                       data = trans->out.data.data + data_size;
-                       SBVAL(data,  8, st->stream_info.out.streams[i].size);
-                       SBVAL(data, 16, st->stream_info.out.streams[i].alloc_size);
-                       trans2_append_data_string(req, trans, 
-                                                 &st->stream_info.out.streams[i].stream_name, 
-                                                 data_size + 4, STR_UNICODE);
-                       if (i == st->stream_info.out.num_streams - 1) {
-                               SIVAL(trans->out.data.data, data_size, 0);
-                       } else {
-                               trans2_grow_data_fill(req, trans, (trans->out.data.length+7)&~7);
-                               SIVAL(trans->out.data.data, data_size, 
-                                     trans->out.data.length - data_size);
-                       }
-               }
-               return NT_STATUS_OK;
-               
-       case RAW_FILEINFO_UNIX_BASIC:
-       case RAW_FILEINFO_UNIX_LINK:
-               return NT_STATUS_INVALID_LEVEL;
+               passthru_level = RAW_FILEINFO_STREAM_INFORMATION;
+               break;
 
-       case RAW_FILEINFO_SMB2_ALL_EAS:
-       case RAW_FILEINFO_SMB2_ALL_INFORMATION:
-               return NT_STATUS_INVALID_LEVEL;
+       default:
+               passthru_level = st->generic.level;
+               break;
        }
 
-       return NT_STATUS_INVALID_LEVEL;
+       return smbsrv_push_passthru_fileinfo(mem_ctx, blob,
+                                            passthru_level, st,
+                                            default_str_flags);
+}
+
+/*
+  fill in the reply from a qpathinfo or qfileinfo call
+*/
+static NTSTATUS trans2_fileinfo_send(struct trans_op *op)
+{
+       struct smbsrv_request *req = op->req;
+       struct smb_trans2 *trans = op->trans;
+       union smb_fileinfo *st;
+
+       TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
+
+       TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
+       SSVAL(trans->out.params.data, 0, 0);
+
+       TRANS2_CHECK(trans2_push_fileinfo(req->smb_conn, trans,
+                                         &trans->out.data, st,
+                                         SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
+
+       return NT_STATUS_OK;
 }
 
 /*
   trans2 qpathinfo implementation
 */
-static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op)
 {
-       union smb_fileinfo st;
-       NTSTATUS status;
+       struct smb_trans2 *trans = op->trans;
+       union smb_fileinfo *st;
        uint16_t level;
 
        /* make sure we got enough parameters */
@@ -767,83 +456,74 @@ static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct smb_trans2 *
                return NT_STATUS_FOOBAR;
        }
 
+       st = talloc(op, union smb_fileinfo);
+       NT_STATUS_HAVE_NO_MEMORY(st);
+
        level = SVAL(trans->in.params.data, 0);
 
-       trans2_pull_blob_string(req, &trans->in.params, 6, &st.generic.in.fname, 0);
-       if (st.generic.in.fname == NULL) {
+       smbsrv_blob_pull_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
+       if (st->generic.in.file.path == NULL) {
                return NT_STATUS_FOOBAR;
        }
 
        /* work out the backend level - we make it 1-1 in the header */
-       st.generic.level = (enum smb_fileinfo_level)level;
-       if (st.generic.level >= RAW_FILEINFO_GENERIC) {
+       st->generic.level = (enum smb_fileinfo_level)level;
+       if (st->generic.level >= RAW_FILEINFO_GENERIC) {
                return NT_STATUS_INVALID_LEVEL;
        }
 
-       if (st.generic.level == RAW_FILEINFO_EA_LIST) {
-               status = ea_pull_name_list(&trans->in.data, req, 
-                                          &st.ea_list.in.num_names,
-                                          &st.ea_list.in.ea_names);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-       }
-
-       /* call the backend */
-       status = ntvfs_qpathinfo(req, &st);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       if (st->generic.level == RAW_FILEINFO_EA_LIST) {
+               TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req, 
+                                              &st->ea_list.in.num_names,
+                                              &st->ea_list.in.ea_names));
        }
 
-       /* fill in the reply parameters */
-       status = trans2_fileinfo_fill(req, trans, &st);
+       op->op_info = st;
+       op->send_fn = trans2_fileinfo_send;
 
-       return status;
+       return ntvfs_qpathinfo(req->ntvfs, st);
 }
 
 
 /*
   trans2 qpathinfo implementation
 */
-static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op)
 {
-       union smb_fileinfo st;
-       NTSTATUS status;
+       struct smb_trans2 *trans = op->trans;
+       union smb_fileinfo *st;
        uint16_t level;
+       struct ntvfs_handle *h;
 
        /* make sure we got enough parameters */
        if (trans->in.params.length < 4) {
                return NT_STATUS_FOOBAR;
        }
 
-       st.generic.in.fnum  = SVAL(trans->in.params.data, 0);
+       st = talloc(op, union smb_fileinfo);
+       NT_STATUS_HAVE_NO_MEMORY(st);
+
+       h     = smbsrv_pull_fnum(req, trans->in.params.data, 0);
        level = SVAL(trans->in.params.data, 2);
 
+       st->generic.in.file.ntvfs = h;
        /* work out the backend level - we make it 1-1 in the header */
-       st.generic.level = (enum smb_fileinfo_level)level;
-       if (st.generic.level >= RAW_FILEINFO_GENERIC) {
+       st->generic.level = (enum smb_fileinfo_level)level;
+       if (st->generic.level >= RAW_FILEINFO_GENERIC) {
                return NT_STATUS_INVALID_LEVEL;
        }
 
-       if (st.generic.level == RAW_FILEINFO_EA_LIST) {
-               status = ea_pull_name_list(&trans->in.data, req, 
-                                          &st.ea_list.in.num_names,
-                                          &st.ea_list.in.ea_names);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
+       if (st->generic.level == RAW_FILEINFO_EA_LIST) {
+               TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req, 
+                                              &st->ea_list.in.num_names,
+                                              &st->ea_list.in.ea_names));
        }
 
-       /* call the backend */
-       status = ntvfs_qfileinfo(req, &st);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
+       op->op_info = st;
+       op->send_fn = trans2_fileinfo_send;
 
-       /* fill in the reply parameters */
-       status = trans2_fileinfo_fill(req, trans, &st);
-
-       return status;
+       SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
+       return ntvfs_qfileinfo(req->ntvfs, st);
 }
 
 
@@ -854,7 +534,7 @@ static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
                                       union smb_setfileinfo *st,
                                       const DATA_BLOB *blob)
 {
-       uint32_t len;
+       enum smb_setfileinfo_level passthru_level;
 
        switch (st->generic.level) {
        case RAW_SFILEINFO_GENERIC:
@@ -866,9 +546,11 @@ static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
 
        case RAW_SFILEINFO_STANDARD:
                CHECK_MIN_BLOB_SIZE(blob, 12);
+
                st->standard.in.create_time = srv_pull_dos_date2(req->smb_conn, blob->data + 0);
                st->standard.in.access_time = srv_pull_dos_date2(req->smb_conn, blob->data + 4);
                st->standard.in.write_time  = srv_pull_dos_date2(req->smb_conn, blob->data + 8);
+
                return NT_STATUS_OK;
 
        case RAW_SFILEINFO_EA_SET:
@@ -878,55 +560,29 @@ static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
 
        case SMB_SFILEINFO_BASIC_INFO:
        case SMB_SFILEINFO_BASIC_INFORMATION:
-               CHECK_MIN_BLOB_SIZE(blob, 36);
-               st->basic_info.in.create_time = pull_nttime(blob->data,  0);
-               st->basic_info.in.access_time = pull_nttime(blob->data,  8);
-               st->basic_info.in.write_time =  pull_nttime(blob->data, 16);
-               st->basic_info.in.change_time = pull_nttime(blob->data, 24);
-               st->basic_info.in.attrib =      IVAL(blob->data,        32);
-               return NT_STATUS_OK;
+               passthru_level = SMB_SFILEINFO_BASIC_INFORMATION;
+               break;
 
        case SMB_SFILEINFO_DISPOSITION_INFO:
        case SMB_SFILEINFO_DISPOSITION_INFORMATION:
-               CHECK_MIN_BLOB_SIZE(blob, 1);
-               st->disposition_info.in.delete_on_close = CVAL(blob->data, 0);
-               return NT_STATUS_OK;
+               passthru_level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
+               break;
 
        case SMB_SFILEINFO_ALLOCATION_INFO:
        case SMB_SFILEINFO_ALLOCATION_INFORMATION:
-               CHECK_MIN_BLOB_SIZE(blob, 8);
-               st->allocation_info.in.alloc_size = BVAL(blob->data, 0);
-               return NT_STATUS_OK;                            
+               passthru_level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
+               break;
 
        case RAW_SFILEINFO_END_OF_FILE_INFO:
        case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
-               CHECK_MIN_BLOB_SIZE(blob, 8);
-               st->end_of_file_info.in.size = BVAL(blob->data, 0);
-               return NT_STATUS_OK;
-
-       case RAW_SFILEINFO_RENAME_INFORMATION: {
-               DATA_BLOB blob2;
-
-               CHECK_MIN_BLOB_SIZE(blob, 12);
-               st->rename_information.in.overwrite = CVAL(blob->data, 0);
-               st->rename_information.in.root_fid  = IVAL(blob->data, 4);
-               len                                 = IVAL(blob->data, 8);
-               blob2.data = blob->data+12;
-               blob2.length = MIN(blob->length, len);
-               trans2_pull_blob_string(req, &blob2, 0, 
-                                       &st->rename_information.in.new_name, STR_UNICODE);
-               return NT_STATUS_OK;
-       }
+               passthru_level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+               break;
 
+       case RAW_SFILEINFO_RENAME_INFORMATION:
        case RAW_SFILEINFO_POSITION_INFORMATION:
-               CHECK_MIN_BLOB_SIZE(blob, 8);
-               st->position_information.in.position = BVAL(blob->data, 0);
-               return NT_STATUS_OK;
-
        case RAW_SFILEINFO_MODE_INFORMATION:
-               CHECK_MIN_BLOB_SIZE(blob, 4);
-               st->mode_information.in.mode = IVAL(blob->data, 0);
-               return NT_STATUS_OK;
+               passthru_level = st->generic.level;
+               break;
 
        case RAW_SFILEINFO_UNIX_BASIC:
        case RAW_SFILEINFO_UNIX_LINK:
@@ -938,94 +594,98 @@ static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
        case RAW_SFILEINFO_1039:
        case RAW_SFILEINFO_1040:
                return NT_STATUS_INVALID_LEVEL;
+
+       default:
+               /* we need a default here to cope with invalid values on the wire */
+               return NT_STATUS_INVALID_LEVEL;
        }
 
-       return NT_STATUS_INVALID_LEVEL;
+       return smbsrv_pull_passthru_sfileinfo(st, passthru_level, st,
+                                             blob, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
+                                             req);
 }
 
 /*
   trans2 setfileinfo implementation
 */
-static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
 {
-       union smb_setfileinfo st;
-       NTSTATUS status;
-       uint16_t level, fnum;
-       DATA_BLOB *blob;
+       struct smb_trans2 *trans = op->trans;
+       union smb_setfileinfo *st;
+       uint16_t level;
+       struct ntvfs_handle *h;
 
        /* make sure we got enough parameters */
        if (trans->in.params.length < 4) {
                return NT_STATUS_FOOBAR;
        }
 
-       fnum  = SVAL(trans->in.params.data, 0);
-       level = SVAL(trans->in.params.data, 2);
-
-       blob = &trans->in.data;
+       st = talloc(op, union smb_setfileinfo);
+       NT_STATUS_HAVE_NO_MEMORY(st);
 
-       st.generic.file.fnum = fnum;
-       st.generic.level = (enum smb_setfileinfo_level)level;
+       h     = smbsrv_pull_fnum(req, trans->in.params.data, 0);
+       level = SVAL(trans->in.params.data, 2);
 
-       status = trans2_parse_sfileinfo(req, &st, blob);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       st->generic.in.file.ntvfs = h;
+       /* work out the backend level - we make it 1-1 in the header */
+       st->generic.level = (enum smb_setfileinfo_level)level;
+       if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
+               return NT_STATUS_INVALID_LEVEL;
        }
 
-       status = ntvfs_setfileinfo(req, &st);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
+       TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
 
-       trans2_setup_reply(req, trans, 2, 0, 0);
-       SSVAL(trans->out.params.data, 0, 0);
-       return NT_STATUS_OK;
+       op->op_info = st;
+       op->send_fn = trans2_simple_send;
+
+       SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
+       return ntvfs_setfileinfo(req->ntvfs, st);
 }
 
 /*
   trans2 setpathinfo implementation
 */
-static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
 {
-       union smb_setfileinfo st;
-       NTSTATUS status;
+       struct smb_trans2 *trans = op->trans;
+       union smb_setfileinfo *st;
        uint16_t level;
-       DATA_BLOB *blob;
 
        /* make sure we got enough parameters */
        if (trans->in.params.length < 4) {
                return NT_STATUS_FOOBAR;
        }
 
+       st = talloc(op, union smb_setfileinfo);
+       NT_STATUS_HAVE_NO_MEMORY(st);
+
        level = SVAL(trans->in.params.data, 0);
-       blob = &trans->in.data;
-       st.generic.level = (enum smb_setfileinfo_level)level;
 
-       trans2_pull_blob_string(req, &trans->in.params, 6, &st.generic.file.fname, 0);
-       if (st.generic.file.fname == NULL) {
+       smbsrv_blob_pull_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
+       if (st->generic.in.file.path == NULL) {
                return NT_STATUS_FOOBAR;
        }
 
-       status = trans2_parse_sfileinfo(req, &st, blob);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       /* work out the backend level - we make it 1-1 in the header */
+       st->generic.level = (enum smb_setfileinfo_level)level;
+       if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
+               return NT_STATUS_INVALID_LEVEL;
        }
 
-       status = ntvfs_setpathinfo(req, &st);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
+       TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
 
-       trans2_setup_reply(req, trans, 2, 0, 0);
-       SSVAL(trans->out.params.data, 0, 0);
-       return NT_STATUS_OK;
+       op->op_info = st;
+       op->send_fn = trans2_simple_send;
+
+       return ntvfs_setpathinfo(req->ntvfs, st);
 }
 
 
 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
 struct find_state {
-       struct smbsrv_request *req;
-       struct smb_trans2 *trans;
-       enum smb_search_level level;
+       struct trans_op *op;
+       void *search;
+       enum smb_search_data_level data_level;
        uint16_t last_entry_offset;
        uint16_t flags;
 };
@@ -1033,30 +693,28 @@ struct find_state {
 /*
   fill a single entry in a trans2 find reply 
 */
-static BOOL find_fill_info(struct smbsrv_request *req,
-                          struct smb_trans2 *trans, 
-                          struct find_state *state,
-                          union smb_search_data *file)
+static NTSTATUS find_fill_info(struct find_state *state,
+                              const union smb_search_data *file)
 {
+       struct smbsrv_request *req = state->op->req;
+       struct smb_trans2 *trans = state->op->trans;
        uint8_t *data;
        uint_t ofs = trans->out.data.length;
        uint32_t ea_size;
 
-       switch (state->level) {
-       case RAW_SEARCH_SEARCH:
-       case RAW_SEARCH_FFIRST:
-       case RAW_SEARCH_FUNIQUE:
-       case RAW_SEARCH_GENERIC:
+       switch (state->data_level) {
+       case RAW_SEARCH_DATA_GENERIC:
+       case RAW_SEARCH_DATA_SEARCH:
                /* handled elsewhere */
-               break;
+               return NT_STATUS_INVALID_LEVEL;
 
-       case RAW_SEARCH_STANDARD:
+       case RAW_SEARCH_DATA_STANDARD:
                if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
-                       trans2_grow_data(req, trans, ofs + 27);
+                       TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
                        SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
                        ofs += 4;
                } else {
-                       trans2_grow_data(req, trans, ofs + 23);
+                       TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23));
                }
                data = trans->out.data.data + ofs;
                srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
@@ -1065,17 +723,18 @@ static BOOL find_fill_info(struct smbsrv_request *req,
                SIVAL(data, 12, file->standard.size);
                SIVAL(data, 16, file->standard.alloc_size);
                SSVAL(data, 20, file->standard.attrib);
-               trans2_append_data_string(req, trans, &file->standard.name, 
-                                         ofs + 22, STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM);
+               TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->standard.name.s, 
+                                                      ofs + 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
+                                                      STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM));
                break;
 
-       case RAW_SEARCH_EA_SIZE:
+       case RAW_SEARCH_DATA_EA_SIZE:
                if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
-                       trans2_grow_data(req, trans, ofs + 31);
+                       TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 31));
                        SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
                        ofs += 4;
                } else {
-                       trans2_grow_data(req, trans, ofs + 27);
+                       TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
                }
                data = trans->out.data.data + ofs;
                srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
@@ -1085,24 +744,20 @@ static BOOL find_fill_info(struct smbsrv_request *req,
                SIVAL(data, 16, file->ea_size.alloc_size);
                SSVAL(data, 20, file->ea_size.attrib);
                SIVAL(data, 22, file->ea_size.ea_size);
-               trans2_append_data_string(req, trans, &file->ea_size.name
-                                         ofs + 26, STR_LEN8BIT | STR_NOALIGN);
-               trans2_grow_data(req, trans, trans->out.data.length + 1);
-               trans->out.data.data[trans->out.data.length-1] = 0;
+               TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_size.name.s
+                                                      ofs + 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
+                                                      STR_LEN8BIT | STR_NOALIGN));
+               TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
                break;
 
-       case RAW_SEARCH_EA_LIST:
+       case RAW_SEARCH_DATA_EA_LIST:
                ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
                if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
-                       if (!trans2_grow_data(req, trans, ofs + 27 + ea_size)) {
-                               return False;
-                       }
+                       TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27 + ea_size));
                        SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
                        ofs += 4;
                } else {
-                       if (!trans2_grow_data(req, trans, ofs + 23 + ea_size)) {
-                               return False;
-                       }
+                       TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23 + ea_size));
                }
                data = trans->out.data.data + ofs;
                srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
@@ -1112,144 +767,41 @@ static BOOL find_fill_info(struct smbsrv_request *req,
                SIVAL(data, 16, file->ea_list.alloc_size);
                SSVAL(data, 20, file->ea_list.attrib);
                ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
-               trans2_append_data_string(req, trans, &file->ea_list.name, 
-                                         ofs + 22 + ea_size, STR_LEN8BIT | STR_NOALIGN);
-               trans2_grow_data(req, trans, trans->out.data.length + 1);
-               trans->out.data.data[trans->out.data.length-1] = 0;
-               break;
-
-       case RAW_SEARCH_DIRECTORY_INFO:
-               trans2_grow_data(req, trans, ofs + 64);
-               data = trans->out.data.data + ofs;
-               SIVAL(data,          4, file->directory_info.file_index);
-               push_nttime(data,    8, file->directory_info.create_time);
-               push_nttime(data,   16, file->directory_info.access_time);
-               push_nttime(data,   24, file->directory_info.write_time);
-               push_nttime(data,   32, file->directory_info.change_time);
-               SBVAL(data,         40, file->directory_info.size);
-               SBVAL(data,         48, file->directory_info.alloc_size);
-               SIVAL(data,         56, file->directory_info.attrib);
-               trans2_append_data_string(req, trans, &file->directory_info.name, 
-                                         ofs + 60, STR_TERMINATE_ASCII);
-               data = trans->out.data.data + ofs;
-               SIVAL(data,          0, trans->out.data.length - ofs);
+               TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_list.name.s, 
+                                                      ofs + 22 + ea_size, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
+                                                      STR_LEN8BIT | STR_NOALIGN));
+               TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
                break;
 
-       case RAW_SEARCH_FULL_DIRECTORY_INFO:
-               trans2_grow_data(req, trans, ofs + 68);
-               data = trans->out.data.data + ofs;
-               SIVAL(data,          4, file->full_directory_info.file_index);
-               push_nttime(data,    8, file->full_directory_info.create_time);
-               push_nttime(data,   16, file->full_directory_info.access_time);
-               push_nttime(data,   24, file->full_directory_info.write_time);
-               push_nttime(data,   32, file->full_directory_info.change_time);
-               SBVAL(data,         40, file->full_directory_info.size);
-               SBVAL(data,         48, file->full_directory_info.alloc_size);
-               SIVAL(data,         56, file->full_directory_info.attrib);
-               SIVAL(data,         64, file->full_directory_info.ea_size);
-               trans2_append_data_string(req, trans, &file->full_directory_info.name, 
-                                         ofs + 60, STR_TERMINATE_ASCII);
-               data = trans->out.data.data + ofs;
-               SIVAL(data,          0, trans->out.data.length - ofs);
-               break;
+       case RAW_SEARCH_DATA_DIRECTORY_INFO:
+       case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
+       case RAW_SEARCH_DATA_NAME_INFO:
+       case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
+       case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
+       case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
+               return smbsrv_push_passthru_search(trans, &trans->out.data, state->data_level, file,
+                                                  SMBSRV_REQ_DEFAULT_STR_FLAGS(req));
 
-       case RAW_SEARCH_NAME_INFO:
-               trans2_grow_data(req, trans, ofs + 12);
-               data = trans->out.data.data + ofs;
-               SIVAL(data,          4, file->name_info.file_index);
-               trans2_append_data_string(req, trans, &file->name_info.name, 
-                                         ofs + 8, STR_TERMINATE_ASCII);
-               data = trans->out.data.data + ofs;
-               SIVAL(data,          0, trans->out.data.length - ofs);
-               break;
-
-       case RAW_SEARCH_BOTH_DIRECTORY_INFO:
-               trans2_grow_data(req, trans, ofs + 94);
-               data = trans->out.data.data + ofs;
-               SIVAL(data,          4, file->both_directory_info.file_index);
-               push_nttime(data,    8, file->both_directory_info.create_time);
-               push_nttime(data,   16, file->both_directory_info.access_time);
-               push_nttime(data,   24, file->both_directory_info.write_time);
-               push_nttime(data,   32, file->both_directory_info.change_time);
-               SBVAL(data,         40, file->both_directory_info.size);
-               SBVAL(data,         48, file->both_directory_info.alloc_size);
-               SIVAL(data,         56, file->both_directory_info.attrib);
-               SIVAL(data,         64, file->both_directory_info.ea_size);
-               SCVAL(data,         69, 0); /* reserved */
-               memset(data+70,0,24);
-               trans2_push_data_string(req, trans, 
-                                       68 + ofs, 70 + ofs, 
-                                       &file->both_directory_info.short_name, 
-                                       24, STR_UNICODE | STR_LEN8BIT);
-               trans2_append_data_string(req, trans, &file->both_directory_info.name, 
-                                         ofs + 60, STR_TERMINATE_ASCII);
-               trans2_align_data(req, trans);
-               data = trans->out.data.data + ofs;
-               SIVAL(data,          0, trans->out.data.length - ofs);
-               break;
-
-       case RAW_SEARCH_ID_FULL_DIRECTORY_INFO:
-               trans2_grow_data(req, trans, ofs + 80);
-               data = trans->out.data.data + ofs;
-               SIVAL(data,          4, file->id_full_directory_info.file_index);
-               push_nttime(data,    8, file->id_full_directory_info.create_time);
-               push_nttime(data,   16, file->id_full_directory_info.access_time);
-               push_nttime(data,   24, file->id_full_directory_info.write_time);
-               push_nttime(data,   32, file->id_full_directory_info.change_time);
-               SBVAL(data,         40, file->id_full_directory_info.size);
-               SBVAL(data,         48, file->id_full_directory_info.alloc_size);
-               SIVAL(data,         56, file->id_full_directory_info.attrib);
-               SIVAL(data,         64, file->id_full_directory_info.ea_size);
-               SIVAL(data,         68, 0); /* padding */
-               SBVAL(data,         72, file->id_full_directory_info.file_id);
-               trans2_append_data_string(req, trans, &file->id_full_directory_info.name, 
-                                         ofs + 60, STR_TERMINATE_ASCII);
-               data = trans->out.data.data + ofs;
-               SIVAL(data,          0, trans->out.data.length - ofs);
-               break;
-
-       case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO:
-               trans2_grow_data(req, trans, ofs + 104);
-               data = trans->out.data.data + ofs;
-               SIVAL(data,          4, file->id_both_directory_info.file_index);
-               push_nttime(data,    8, file->id_both_directory_info.create_time);
-               push_nttime(data,   16, file->id_both_directory_info.access_time);
-               push_nttime(data,   24, file->id_both_directory_info.write_time);
-               push_nttime(data,   32, file->id_both_directory_info.change_time);
-               SBVAL(data,         40, file->id_both_directory_info.size);
-               SBVAL(data,         48, file->id_both_directory_info.alloc_size);
-               SIVAL(data,         56, file->id_both_directory_info.attrib);
-               SIVAL(data,         64, file->id_both_directory_info.ea_size);
-               SCVAL(data,         69, 0); /* reserved */
-               memset(data+70,0,26);
-               trans2_push_data_string(req, trans, 
-                                       68 + ofs, 70 + ofs, 
-                                       &file->id_both_directory_info.short_name, 
-                                       24, STR_UNICODE | STR_LEN8BIT);
-               SBVAL(data,         96, file->id_both_directory_info.file_id);
-               trans2_append_data_string(req, trans, &file->id_both_directory_info.name, 
-                                         ofs + 60, STR_TERMINATE_ASCII);
-               data = trans->out.data.data + ofs;
-               SIVAL(data,          0, trans->out.data.length - ofs);
-               break;
+       case RAW_SEARCH_DATA_UNIX_INFO:
+               return NT_STATUS_INVALID_LEVEL;
        }
 
-       return True;
+       return NT_STATUS_OK;
 }
 
 /* callback function for trans2 findfirst/findnext */
-static BOOL find_callback(void *private, union smb_search_data *file)
+static BOOL find_callback(void *private, const union smb_search_data *file)
 {
-       struct find_state *state = (struct find_state *)private;
-       struct smb_trans2 *trans = state->trans;
+       struct find_state *state = talloc_get_type(private, struct find_state);
+       struct smb_trans2 *trans = state->op->trans;
        uint_t old_length;
 
        old_length = trans->out.data.length;
 
-       if (!find_fill_info(state->req, trans, state, file) ||
+       if (!NT_STATUS_IS_OK(find_fill_info(state, file)) ||
            trans->out.data.length > trans->in.max_data) {
                /* restore the old length and tell the backend to stop */
-               trans2_grow_data(state->req, trans, old_length);
+               smbsrv_blob_grow_data(trans, &trans->out.data, old_length);
                return False;
        }
 
@@ -1257,74 +809,114 @@ static BOOL find_callback(void *private, union smb_search_data *file)
        return True;
 }
 
+/*
+  trans2 findfirst send
+ */
+static NTSTATUS trans2_findfirst_send(struct trans_op *op)
+{
+       struct smbsrv_request *req = op->req;
+       struct smb_trans2 *trans = op->trans;
+       union smb_search_first *search;
+       struct find_state *state;
+       uint8_t *param;
+
+       TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
+       search = talloc_get_type(state->search, union smb_search_first);
+
+       /* fill in the findfirst reply header */
+       param = trans->out.params.data;
+       SSVAL(param, VWV(0), search->t2ffirst.out.handle);
+       SSVAL(param, VWV(1), search->t2ffirst.out.count);
+       SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
+       SSVAL(param, VWV(3), 0);
+       SSVAL(param, VWV(4), state->last_entry_offset);
+
+       return NT_STATUS_OK;
+}
+
 
 /*
   trans2 findfirst implementation
 */
-static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
 {
-       union smb_search_first search;
-       NTSTATUS status;
+       struct smb_trans2 *trans = op->trans;
+       union smb_search_first *search;
        uint16_t level;
-       uint8_t *param;
-       struct find_state state;
+       struct find_state *state;
 
        /* make sure we got all the parameters */
        if (trans->in.params.length < 14) {
                return NT_STATUS_FOOBAR;
        }
 
-       search.t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
-       search.t2ffirst.in.max_count     = SVAL(trans->in.params.data, 2);
-       search.t2ffirst.in.flags         = SVAL(trans->in.params.data, 4);
-       level                            = SVAL(trans->in.params.data, 6);
-       search.t2ffirst.in.storage_type  = IVAL(trans->in.params.data, 8);
+       search = talloc(op, union smb_search_first);
+       NT_STATUS_HAVE_NO_MEMORY(search);
+
+       search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
+       search->t2ffirst.in.max_count     = SVAL(trans->in.params.data, 2);
+       search->t2ffirst.in.flags         = SVAL(trans->in.params.data, 4);
+       level                             = SVAL(trans->in.params.data, 6);
+       search->t2ffirst.in.storage_type  = IVAL(trans->in.params.data, 8);
 
-       trans2_pull_blob_string(req, &trans->in.params, 12, &search.t2ffirst.in.pattern, 0);
-       if (search.t2ffirst.in.pattern == NULL) {
+       smbsrv_blob_pull_string(req, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
+       if (search->t2ffirst.in.pattern == NULL) {
                return NT_STATUS_FOOBAR;
        }
 
-       search.t2ffirst.level = (enum smb_search_level)level;
-       if (search.t2ffirst.level >= RAW_SEARCH_GENERIC) {
+       search->t2ffirst.level = RAW_SEARCH_TRANS2;
+       search->t2ffirst.data_level = (enum smb_search_data_level)level;
+       if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
                return NT_STATUS_INVALID_LEVEL;
        }
 
-       if (search.t2ffirst.level == RAW_SEARCH_EA_LIST) {
-               status = ea_pull_name_list(&trans->in.data, req,
-                                          &search.t2ffirst.in.num_names, 
-                                          &search.t2ffirst.in.ea_names);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
+       if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
+               TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
+                                              &search->t2ffirst.in.num_names, 
+                                              &search->t2ffirst.in.ea_names));
        }
 
        /* setup the private state structure that the backend will
           give us in the callback */
-       state.req = req;
-       state.trans = trans;
-       state.level = search.t2ffirst.level;
-       state.last_entry_offset = 0;
-       state.flags = search.t2ffirst.in.flags;
+       state = talloc(op, struct find_state);
+       NT_STATUS_HAVE_NO_MEMORY(state);
+       state->op               = op;
+       state->search           = search;
+       state->data_level       = search->t2ffirst.data_level;
+       state->last_entry_offset= 0;
+       state->flags            = search->t2ffirst.in.flags;
 
        /* setup for just a header in the reply */
-       trans2_setup_reply(req, trans, 10, 0, 0);
+       TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
 
-       /* call the backend */
-       status = ntvfs_search_first(req, &search, &state, find_callback);
-       if (!NT_STATUS_IS_OK(status)) {
-               trans2_setup_reply(req, trans, 0, 0, 0);
-               return status;
-       }
+       op->op_info = state;
+       op->send_fn = trans2_findfirst_send;
+
+       return ntvfs_search_first(req->ntvfs, search, state, find_callback);
+}
+
+
+/*
+  trans2 findnext send
+*/
+static NTSTATUS trans2_findnext_send(struct trans_op *op)
+{
+       struct smbsrv_request *req = op->req;
+       struct smb_trans2 *trans = op->trans;
+       union smb_search_next *search;
+       struct find_state *state;
+       uint8_t *param;
+
+       TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
+       search = talloc_get_type(state->search, union smb_search_next);
 
        /* fill in the findfirst reply header */
        param = trans->out.params.data;
-       SSVAL(param, VWV(0), search.t2ffirst.out.handle);
-       SSVAL(param, VWV(1), search.t2ffirst.out.count);
-       SSVAL(param, VWV(2), search.t2ffirst.out.end_of_search);
-       SSVAL(param, VWV(3), 0);
-       SSVAL(param, VWV(4), state.last_entry_offset);
-
+       SSVAL(param, VWV(0), search->t2fnext.out.count);
+       SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
+       SSVAL(param, VWV(2), 0);
+       SSVAL(param, VWV(3), state->last_entry_offset);
+       
        return NT_STATUS_OK;
 }
 
@@ -1332,80 +924,73 @@ static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct smb_trans2 *
 /*
   trans2 findnext implementation
 */
-static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
 {
-       union smb_search_next search;
-       NTSTATUS status;
+       struct smb_trans2 *trans = op->trans;
+       union smb_search_next *search;
        uint16_t level;
-       uint8_t *param;
-       struct find_state state;
+       struct find_state *state;
 
        /* make sure we got all the parameters */
        if (trans->in.params.length < 12) {
                return NT_STATUS_FOOBAR;
        }
 
-       search.t2fnext.in.handle        = SVAL(trans->in.params.data, 0);
-       search.t2fnext.in.max_count     = SVAL(trans->in.params.data, 2);
-       level                           = SVAL(trans->in.params.data, 4);
-       search.t2fnext.in.resume_key    = IVAL(trans->in.params.data, 6);
-       search.t2fnext.in.flags         = SVAL(trans->in.params.data, 10);
+       search = talloc(op, union smb_search_next);
+       NT_STATUS_HAVE_NO_MEMORY(search);
 
-       trans2_pull_blob_string(req, &trans->in.params, 12, &search.t2fnext.in.last_name, 0);
-       if (search.t2fnext.in.last_name == NULL) {
+       search->t2fnext.in.handle        = SVAL(trans->in.params.data, 0);
+       search->t2fnext.in.max_count     = SVAL(trans->in.params.data, 2);
+       level                            = SVAL(trans->in.params.data, 4);
+       search->t2fnext.in.resume_key    = IVAL(trans->in.params.data, 6);
+       search->t2fnext.in.flags         = SVAL(trans->in.params.data, 10);
+
+       smbsrv_blob_pull_string(req, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
+       if (search->t2fnext.in.last_name == NULL) {
                return NT_STATUS_FOOBAR;
        }
 
-       search.t2fnext.level = (enum smb_search_level)level;
-       if (search.t2fnext.level >= RAW_SEARCH_GENERIC) {
+       search->t2fnext.level = RAW_SEARCH_TRANS2;
+       search->t2fnext.data_level = (enum smb_search_data_level)level;
+       if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
                return NT_STATUS_INVALID_LEVEL;
        }
 
-       if (search.t2fnext.level == RAW_SEARCH_EA_LIST) {
-               status = ea_pull_name_list(&trans->in.data, req,
-                                          &search.t2fnext.in.num_names, 
-                                          &search.t2fnext.in.ea_names);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
+       if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
+               TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
+                                              &search->t2fnext.in.num_names, 
+                                              &search->t2fnext.in.ea_names));
        }
 
        /* setup the private state structure that the backend will give us in the callback */
-       state.req = req;
-       state.trans = trans;
-       state.level = search.t2fnext.level;
-       state.last_entry_offset = 0;
-       state.flags = search.t2fnext.in.flags;
+       state = talloc(op, struct find_state);
+       NT_STATUS_HAVE_NO_MEMORY(state);
+       state->op               = op;
+       state->search           = search;
+       state->data_level       = search->t2fnext.data_level;
+       state->last_entry_offset= 0;
+       state->flags            = search->t2fnext.in.flags;
 
        /* setup for just a header in the reply */
-       trans2_setup_reply(req, trans, 8, 0, 0);
+       TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
 
-       /* call the backend */
-       status = ntvfs_search_next(req, &search, &state, find_callback);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
+       op->op_info = state;
+       op->send_fn = trans2_findnext_send;
 
-       /* fill in the findfirst reply header */
-       param = trans->out.params.data;
-       SSVAL(param, VWV(0), search.t2fnext.out.count);
-       SSVAL(param, VWV(1), search.t2fnext.out.end_of_search);
-       SSVAL(param, VWV(2), 0);
-       SSVAL(param, VWV(3), state.last_entry_offset);
-       
-       return NT_STATUS_OK;
+       return ntvfs_search_next(req->ntvfs, search, state, find_callback);
 }
 
 
 /*
   backend for trans2 requests
 */
-static NTSTATUS trans2_backend(struct smbsrv_request *req, struct smb_trans2 *trans)
+static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
 {
+       struct smb_trans2 *trans = op->trans;
        NTSTATUS status;
 
        /* direct trans2 pass thru */
-       status = ntvfs_trans2(req, trans);
+       status = ntvfs_trans2(req->ntvfs, trans);
        if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
                return status;
        }
@@ -1418,23 +1003,23 @@ static NTSTATUS trans2_backend(struct smbsrv_request *req, struct smb_trans2 *tr
        /* the trans2 command is in setup[0] */
        switch (trans->in.setup[0]) {
        case TRANSACT2_FINDFIRST:
-               return trans2_findfirst(req, trans);
+               return trans2_findfirst(req, op);
        case TRANSACT2_FINDNEXT:
-               return trans2_findnext(req, trans);
+               return trans2_findnext(req, op);
        case TRANSACT2_QPATHINFO:
-               return trans2_qpathinfo(req, trans);
+               return trans2_qpathinfo(req, op);
        case TRANSACT2_QFILEINFO:
-               return trans2_qfileinfo(req, trans);
+               return trans2_qfileinfo(req, op);
        case TRANSACT2_SETFILEINFO:
-               return trans2_setfileinfo(req, trans);
+               return trans2_setfileinfo(req, op);
        case TRANSACT2_SETPATHINFO:
-               return trans2_setpathinfo(req, trans);
+               return trans2_setpathinfo(req, op);
        case TRANSACT2_QFSINFO:
-               return trans2_qfsinfo(req, trans);
+               return trans2_qfsinfo(req, op);
        case TRANSACT2_OPEN:
-               return trans2_open(req, trans);
+               return trans2_open(req, op);
        case TRANSACT2_MKDIR:
-               return trans2_mkdir(req, trans);
+               return trans2_mkdir(req, op);
        }
 
        /* an unknown trans2 command */
@@ -1445,7 +1030,7 @@ static NTSTATUS trans2_backend(struct smbsrv_request *req, struct smb_trans2 *tr
 /*
   send a continue request
 */
-static void reply_trans_continue(struct smbsrv_request *req, uint8_t command, 
+static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
                                 struct smb_trans2 *trans)
 {
        struct smbsrv_trans_partial *tp;
@@ -1475,24 +1060,27 @@ static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
 /*
   answer a reconstructed trans request
 */
-static void reply_trans_complete(struct smbsrv_request *req, uint8_t command, 
-                                struct smb_trans2 *trans)
+static void reply_trans_send(struct ntvfs_request *ntvfs)
 {
+       struct smbsrv_request *req;
+       struct trans_op *op;
+       struct smb_trans2 *trans;
        uint16_t params_left, data_left;
        uint8_t *params, *data;
-       NTSTATUS status;
        int i;
 
-       /* its a full request, give it to the backend */
-       if (command == SMBtrans) {
-               status = ntvfs_trans(req, trans);
-       } else {
-               status = trans2_backend(req, trans);
-       }
+       SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
+       trans = op->trans;
 
-       if (NT_STATUS_IS_ERR(status)) {
-               smbsrv_send_error(req, status);
-               return;
+       /* if this function needs work to form the nttrans reply buffer, then
+          call that now */
+       if (op->send_fn != NULL) {
+               NTSTATUS status;
+               status = op->send_fn(op);
+               if (!NT_STATUS_IS_OK(status)) {
+                       smbsrv_send_error(req, status);
+                       return;
+               }
        }
 
        params_left = trans->out.params.length;
@@ -1502,8 +1090,8 @@ static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
 
        smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
 
-       if (!NT_STATUS_IS_OK(status)) {
-               smbsrv_setup_error(req, status);
+       if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
+               smbsrv_setup_error(req, req->ntvfs->async_states->status);
        }
 
        /* we need to divide up the reply into chunks that fit into
@@ -1573,6 +1161,33 @@ static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
 }
 
 
+/*
+  answer a reconstructed trans request
+*/
+static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
+                                struct smb_trans2 *trans)
+{
+       struct trans_op *op;
+
+       SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
+       SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
+
+       op->req         = req;
+       op->trans       = trans;
+       op->command     = command;
+       op->op_info     = NULL;
+       op->send_fn     = NULL;
+
+       /* its a full request, give it to the backend */
+       if (command == SMBtrans) {
+               SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
+               return;
+       } else {
+               SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
+               return;
+       }
+}
+
 /*
   Reply to an SMBtrans or SMBtrans2 request
 */
@@ -1584,18 +1199,18 @@ static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
        uint16_t param_count, data_count;
        uint16_t param_total, data_total;
 
-       trans = talloc(req, struct smb_trans2);
-       if (trans == NULL) {
-               smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
-               return;
-       }
-
        /* parse request */
        if (req->in.wct < 14) {
                smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
                return;
        }
 
+       trans = talloc(req, struct smb_trans2);
+       if (trans == NULL) {
+               smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
+               return;
+       }
+
        param_total           = SVAL(req->in.vwv, VWV(0));
        data_total            = SVAL(req->in.vwv, VWV(1));
        trans->in.max_param   = SVAL(req->in.vwv, VWV(2));
@@ -1615,7 +1230,7 @@ static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
        }
 
        /* parse out the setup words */
-       trans->in.setup = talloc_array(req, uint16_t, trans->in.setup_count);
+       trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
        if (trans->in.setup_count && !trans->in.setup) {
                smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
                return;
@@ -1657,9 +1272,16 @@ static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
        uint16_t param_total, data_total;
        DATA_BLOB params, data;
 
+       /* parse request */
+       if (req->in.wct < 8) {
+               smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
        for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
                if (tp->command == command &&
                    SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
+/* TODO: check the VUID, PID and TID too? */
                        break;
                }
        }
@@ -1671,12 +1293,6 @@ static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
 
        trans = tp->trans;
 
-       /* parse request */
-       if (req->in.wct < 8) {
-               smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
-               return;
-       }
-
        param_total           = SVAL(req->in.vwv, VWV(0));
        data_total            = SVAL(req->in.vwv, VWV(1));
        param_count           = SVAL(req->in.vwv, VWV(2));