*/
#include "includes.h"
+#include "smb_server/smb_server.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "ntvfs/ntvfs.h"
+
+/* a second stage function converts from the out parameters of the generic
+ call onto the out parameters of the specific call made */
+typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
+ struct ntvfs_request *,
+ void *, void *, NTSTATUS);
+
+/*
+ this structure holds the async state for pending mapped async calls
+*/
+struct ntvfs_map_async {
+ struct ntvfs_module_context *ntvfs;
+ void *io, *io2;
+ second_stage_t fn;
+};
+
+/*
+ this is a async wrapper, called from the backend when it has completed
+ a function that it has decided to reply to in an async fashion
+*/
+static void ntvfs_map_async_send(struct ntvfs_request *req)
+{
+ struct ntvfs_map_async *m = req->async_states->private_data;
+
+ ntvfs_async_state_pop(req);
+
+ /* call the _finish function setup in ntvfs_map_async_setup() */
+ req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
+
+ /* call the send function from the next module up */
+ req->async_states->send_fn(req);
+}
+
+/*
+ prepare for calling a ntvfs backend with async support
+ io is the original call structure
+ io2 is the new call structure for the mapped call
+ fn is a second stage function for processing the out arguments
+*/
+static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ void *io, void *io2,
+ second_stage_t fn)
+{
+ struct ntvfs_map_async *m;
+ m = talloc(req, struct ntvfs_map_async);
+ if (m == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ m->ntvfs = ntvfs;
+ m->io = io;
+ m->io2 = io2;
+ m->fn = fn;
+ return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
+}
+
+/*
+ called when first stage processing is complete.
+*/
+static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
+{
+ struct ntvfs_map_async *m;
+
+ /* if the backend has decided to reply in an async fashion then
+ we don't need to do any work here */
+ if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
+ return status;
+ }
+
+ /* the backend is replying immediately. call the 2nd stage function after popping our local
+ async state */
+ m = req->async_states->private_data;
+
+ ntvfs_async_state_pop(req);
+
+ return m->fn(m->ntvfs, req, m->io, m->io2, status);
+}
/*
see if a filename ends in EXE COM DLL or SYM. This is needed for the
DENY_DOS mapping for OpenX
*/
-static BOOL is_exe_file(const char *fname)
+BOOL is_exe_filename(const char *fname)
{
char *p;
p = strrchr(fname, '.');
/*
- NTVFS open generic to any mapper
+ NTVFS openx to ntcreatex mapper
*/
-NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
- struct ntvfs_module_context *ntvfs)
+static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_open *io,
+ union smb_open *io2,
+ NTSTATUS status)
{
- NTSTATUS status;
- union smb_open *io2;
+ time_t write_time = 0;
+ uint32_t set_size = 0;
+ union smb_setfileinfo *sf;
+ uint_t state;
- io2 = talloc_p(req, union smb_open);
- if (io2 == NULL) {
- return NT_STATUS_NO_MEMORY;
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
- /* must be synchronous, or we won't be called to do the
- translation */
- req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
-
switch (io->generic.level) {
- case RAW_OPEN_GENERIC:
- return NT_STATUS_INVALID_LEVEL;
+ case RAW_OPEN_OPEN:
+ io->openold.file.fnum = io2->generic.file.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 = io->openold.in.open_mode;
+ break;
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;
+ io->openx.file.fnum = io2->generic.file.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.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
+ 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 = SEC_STD_ALL;
+ 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) {
+ set_size = io->openx.in.size;
}
+ break;
- 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 RAW_OPEN_T2OPEN:
+ io->t2open.file.fnum = io2->generic.file.fnum;
+ io->t2open.out.attrib = io2->generic.out.attrib;
+ io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
+ io->t2open.out.size = io2->generic.out.size;
+ io->t2open.out.access = io->t2open.in.open_mode;
+ io->t2open.out.ftype = 0;
+ io->t2open.out.devstate = 0;
+ io->t2open.out.action = io2->generic.out.create_action;
+ io->t2open.out.file_id = 0;
+ break;
+
+ case RAW_OPEN_MKNEW:
+ case RAW_OPEN_CREATE:
+ io->mknew.file.fnum = io2->generic.file.fnum;
+ write_time = io->mknew.in.write_time;
+ break;
+
+ case RAW_OPEN_CTEMP:
+ io->ctemp.file.fnum = io2->generic.file.fnum;
+ io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
+ strlen(io->ctemp.in.directory) + 1);
+ NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
+ break;
+
+ default:
+ return NT_STATUS_INVALID_LEVEL;
+ }
+
+ /* doing a secondary request async is more trouble than its
+ worth */
+ state = req->async_states->state;
+ req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
+
+ if (write_time != 0) {
+ sf = talloc(req, union smb_setfileinfo);
+ NT_STATUS_HAVE_NO_MEMORY(sf);
+ sf->generic.level = RAW_SFILEINFO_STANDARD;
+ sf->generic.file.fnum = io2->generic.file.fnum;
+ sf->standard.in.create_time = 0;
+ sf->standard.in.write_time = write_time;
+ sf->standard.in.access_time = 0;
+ status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
+ }
+
+ if (set_size != 0) {
+ sf = talloc(req, union smb_setfileinfo);
+ NT_STATUS_HAVE_NO_MEMORY(sf);
+ sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+ sf->generic.file.fnum = io2->generic.file.fnum;
+ sf->end_of_file_info.in.size = set_size;
+ status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
+ if (NT_STATUS_IS_OK(status)) {
+ io->openx.out.size = io->openx.in.size;
}
+ }
- 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;
+ req->async_states->state = state;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ the core of the mapping between openx style parameters and ntcreatex
+ parameters
+*/
+static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
+ uint16_t open_func, const char *fname,
+ union smb_open *io2)
+{
+ if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
+ io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
+ }
+ if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
+ io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+ }
+
+ switch (open_mode & OPENX_MODE_ACCESS_MASK) {
+ case OPENX_MODE_ACCESS_READ:
+ case OPENX_MODE_ACCESS_EXEC:
+ io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
+ break;
+ case OPENX_MODE_ACCESS_WRITE:
+ io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
+ break;
+ case OPENX_MODE_ACCESS_RDWR:
+ case OPENX_MODE_ACCESS_FCB:
+ io2->generic.in.access_mask =
+ SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ break;
+ default:
+ return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
+ }
+
+ switch (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! */
+ io2->generic.in.create_options |=
+ NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
+ if (is_exe_filename(fname)) {
+ io2->generic.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ } else {
+ if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
} 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;
- }
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
}
- break;
- case OPENX_MODE_DENY_FCB:
- io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
- break;
}
+ break;
+ case OPENX_MODE_DENY_FCB:
+ io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
+ io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+ break;
+ default:
+ return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
+ }
- 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):
+ switch (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 ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
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;
+ return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
+ }
- status = ntvfs->ops->open(ntvfs, req, io2);
+ return NT_STATUS_OK;
+}
+
+/*
+ NTVFS open generic to any mapper
+*/
+_PUBLIC_ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_open *io)
+{
+ NTSTATUS status;
+ union smb_open *io2;
+
+ io2 = talloc_zero(req, union smb_open);
+ if (io2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ntvfs_map_async_setup(ntvfs, req,
+ io, io2,
+ (second_stage_t)ntvfs_map_open_finish);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ io2->generic.level = RAW_OPEN_GENERIC;
+
+ switch (io->generic.level) {
+ case RAW_OPEN_OPENX:
+ status = map_openx_open(io->openx.in.flags,
+ io->openx.in.open_mode,
+ io->openx.in.open_func,
+ io->openx.in.fname,
+ io2);
if (!NT_STATUS_IS_OK(status)) {
- return status;
+ goto done;
}
- 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;
+ io2->generic.in.file_attr = io->openx.in.file_attrs;
+ io2->generic.in.fname = io->openx.in.fname;
- return NT_STATUS_OK;
-
-
- 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;
- DEBUG(9,("ntvfs_map_open(OPEN): mapping flags=0x%x\n",
- io->open.in.flags));
- switch (io->open.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;
- break;
- case OPEN_FLAGS_OPEN_WRITE:
- io2->generic.in.access_mask = GENERIC_RIGHTS_FILE_WRITE;
- io->open.out.rmode = DOS_OPEN_WRONLY;
- break;
- case OPEN_FLAGS_OPEN_RDWR:
- case 0xf: /* FCB mode */
- 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 */
- break;
- default:
- DEBUG(2,("ntvfs_map_open(OPEN): invalid mode 0x%x\n",
- io->open.in.flags & OPEN_FLAGS_MODE_MASK));
- return NT_STATUS_INVALID_PARAMETER;
- }
+ status = ntvfs->ops->open(ntvfs, req, io2);
+ break;
- switch(io->open.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;
- } else {
- if ((io->open.in.flags & OPEN_FLAGS_MODE_MASK) ==
- OPEN_FLAGS_OPEN_READ) {
- io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
- } else {
- io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
- }
- }
- break;
- case OPEN_FLAGS_DENY_ALL:
- io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
- break;
- case OPEN_FLAGS_DENY_WRITE:
- io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
- break;
- case OPEN_FLAGS_DENY_READ:
- io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
- break;
- case OPEN_FLAGS_DENY_NONE:
- 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;
- break;
- default:
- DEBUG(2,("ntvfs_map_open(OPEN): invalid DENY 0x%x\n",
- io->open.in.flags & OPEN_FLAGS_DENY_MASK));
- return NT_STATUS_INVALID_PARAMETER;
+
+ case RAW_OPEN_OPEN:
+ status = map_openx_open(0,
+ io->openold.in.open_mode,
+ OPENX_OPEN_FUNC_OPEN,
+ io->openold.in.fname,
+ io2);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
}
- 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));
+
+ io2->generic.in.file_attr = io->openold.in.search_attrs;
+ io2->generic.in.fname = io->openold.in.fname;
status = ntvfs->ops->open(ntvfs, req, io2);
+ break;
+
+ case RAW_OPEN_T2OPEN:
+ io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
+
+ if (io->t2open.in.open_func == 0) {
+ status = NT_STATUS_OBJECT_NAME_COLLISION;
+ goto done;
+ }
+
+ status = map_openx_open(io->t2open.in.flags,
+ io->t2open.in.open_mode,
+ io->t2open.in.open_func,
+ io->t2open.in.fname,
+ io2);
if (!NT_STATUS_IS_OK(status)) {
- return status;
+ goto done;
}
-
- 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;
-
- return NT_STATUS_OK;
- }
- return NT_STATUS_INVALID_LEVEL;
+ io2->generic.in.file_attr = io->t2open.in.file_attrs;
+ io2->generic.in.fname = io->t2open.in.fname;
+ io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
+ io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
+ io2->generic.in.ea_list->eas = io->t2open.in.eas;
+
+ status = ntvfs->ops->open(ntvfs, req, io2);
+ break;
+
+ case RAW_OPEN_MKNEW:
+ io2->generic.in.file_attr = io->mknew.in.attrib;
+ io2->generic.in.fname = io->mknew.in.fname;
+ io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io2->generic.in.access_mask =
+ SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io2->generic.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = ntvfs->ops->open(ntvfs, req, io2);
+ break;
+
+ case RAW_OPEN_CREATE:
+ io2->generic.in.file_attr = io->mknew.in.attrib;
+ io2->generic.in.fname = io->mknew.in.fname;
+ io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+ io2->generic.in.access_mask =
+ SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io2->generic.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = ntvfs->ops->open(ntvfs, req, io2);
+ break;
+
+ case RAW_OPEN_CTEMP:
+ io2->generic.in.file_attr = io->ctemp.in.attrib;
+ io2->generic.in.file_attr = 0;
+ io2->generic.in.fname =
+ talloc_asprintf(io2, "%s\\SRV%s",
+ io->ctemp.in.directory,
+ generate_random_str_list(io2, 5, "0123456789"));
+ io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
+ io2->generic.in.access_mask =
+ SEC_RIGHTS_FILE_READ |
+ SEC_RIGHTS_FILE_WRITE;
+ io2->generic.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ status = ntvfs->ops->open(ntvfs, req, io2);
+ break;
+
+ default:
+ status = NT_STATUS_INVALID_LEVEL;
+ break;
+ }
+done:
+ return ntvfs_map_async_finish(req, status);
}
/*
NTVFS fsinfo generic to any mapper
*/
-NTSTATUS ntvfs_map_fsinfo(struct smbsrv_request *req, union smb_fsinfo *fs,
- struct ntvfs_module_context *ntvfs)
+_PUBLIC_ NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_fsinfo *fs)
{
NTSTATUS status;
union smb_fsinfo *fs2;
- fs2 = talloc_p(req, union smb_fsinfo);
+ fs2 = talloc(req, union smb_fsinfo);
if (fs2 == NULL) {
return NT_STATUS_NO_MEMORY;
}
if (fs->generic.level == RAW_QFS_GENERIC) {
return NT_STATUS_INVALID_LEVEL;
}
+
+ /* only used by the simple backend, which doesn't do async */
+ req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
/* ask the backend for the generic info */
fs2->generic.level = RAW_QFS_GENERIC;
/*
NTVFS fileinfo generic to any mapper
*/
-NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info,
- union smb_fileinfo *info2)
+_PUBLIC_ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
+ union smb_fileinfo *info,
+ union smb_fileinfo *info2)
{
int i;
/* and convert it to the required level using results in info2 */
case RAW_FILEINFO_STREAM_INFORMATION:
info->stream_info.out.num_streams = info2->generic.out.num_streams;
if (info->stream_info.out.num_streams > 0) {
- info->stream_info.out.streams = talloc(req,
- info->stream_info.out.num_streams * sizeof(struct stream_struct));
+ info->stream_info.out.streams =
+ talloc_array(mem_ctx,
+ struct stream_struct,
+ info->stream_info.out.num_streams);
if (!info->stream_info.out.streams) {
DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
info->stream_info.out.num_streams));
for (i=0; i < info->stream_info.out.num_streams; i++) {
info->stream_info.out.streams[i] = info2->generic.out.streams[i];
info->stream_info.out.streams[i].stream_name.s =
- talloc_strdup(req, info2->generic.out.streams[i].stream_name.s);
+ talloc_strdup(info->stream_info.out.streams,
+ info2->generic.out.streams[i].stream_name.s);
if (!info->stream_info.out.streams[i].stream_name.s) {
DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
return NT_STATUS_NO_MEMORY;
case RAW_FILEINFO_NAME_INFO:
case RAW_FILEINFO_NAME_INFORMATION:
- info->name_info.out.fname.s = talloc_strdup(req, info2->generic.out.fname.s);
+ info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
+ NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
return NT_STATUS_OK;
case RAW_FILEINFO_ALT_NAME_INFO:
case RAW_FILEINFO_ALT_NAME_INFORMATION:
- info->alt_name_info.out.fname.s = talloc_strdup(req, info2->generic.out.alt_fname.s);
+ info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
+ NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
return NT_STATUS_OK;
case RAW_FILEINFO_ALL_EAS:
info->all_eas.out.num_eas = info2->generic.out.num_eas;
if (info->all_eas.out.num_eas > 0) {
- info->all_eas.out.eas = talloc(req,
- info->all_eas.out.num_eas * sizeof(struct ea_struct));
+ info->all_eas.out.eas = talloc_array(mem_ctx,
+ struct ea_struct,
+ info->all_eas.out.num_eas);
if (!info->all_eas.out.eas) {
DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
info->all_eas.out.num_eas));
for (i = 0; i < info->all_eas.out.num_eas; i++) {
info->all_eas.out.eas[i] = info2->generic.out.eas[i];
info->all_eas.out.eas[i].name.s =
- talloc_strdup(req, info2->generic.out.eas[i].name.s);
+ talloc_strdup(info->all_eas.out.eas,
+ info2->generic.out.eas[i].name.s);
if (!info->all_eas.out.eas[i].name.s) {
DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
return NT_STATUS_NO_MEMORY;
}
info->all_eas.out.eas[i].value.data =
- talloc_memdup(req,
+ talloc_memdup(info->all_eas.out.eas,
info2->generic.out.eas[i].value.data,
info2->generic.out.eas[i].value.length);
if (!info->all_eas.out.eas[i].value.data) {
/*
NTVFS fileinfo generic to any mapper
*/
-NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info,
- struct ntvfs_module_context *ntvfs)
+_PUBLIC_ NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_fileinfo *info)
{
NTSTATUS status;
union smb_fileinfo *info2;
- info2 = talloc_p(req, union smb_fileinfo);
+ info2 = talloc(req, union smb_fileinfo);
if (info2 == NULL) {
return NT_STATUS_NO_MEMORY;
}
/* ask the backend for the generic info */
info2->generic.level = RAW_FILEINFO_GENERIC;
- info2->generic.in.fnum = info->generic.in.fnum;
+ info2->generic.file.fnum = info->generic.file.fnum;
+
+ /* only used by the simple backend, which doesn't do async */
+ req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
if (!NT_STATUS_IS_OK(status)) {
/*
NTVFS pathinfo generic to any mapper
*/
-NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info,
- struct ntvfs_module_context *ntvfs)
+_PUBLIC_ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_fileinfo *info)
{
NTSTATUS status;
union smb_fileinfo *info2;
- info2 = talloc_p(req, union smb_fileinfo);
+ info2 = talloc(req, union smb_fileinfo);
if (info2 == NULL) {
return NT_STATUS_NO_MEMORY;
}
/* ask the backend for the generic info */
info2->generic.level = RAW_FILEINFO_GENERIC;
- info2->generic.in.fname = info->generic.in.fname;
+ info2->generic.file.path = info->generic.file.path;
- /* must be synchronous, or we won't be called to do the
- translation */
- req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
+ /* only used by the simple backend, which doesn't do async */
+ req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
if (!NT_STATUS_IS_OK(status)) {
/*
NTVFS lock generic to any mapper
*/
-NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck,
- struct ntvfs_module_context *ntvfs)
+_PUBLIC_ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_lock *lck)
{
union smb_lock *lck2;
struct smb_lock_entry *locks;
- lck2 = talloc_p(req, union smb_lock);
+ lck2 = talloc(req, union smb_lock);
if (lck2 == NULL) {
return NT_STATUS_NO_MEMORY;
}
- locks = talloc_array_p(lck2, struct smb_lock_entry, 1);
+ locks = talloc_array(lck2, struct smb_lock_entry, 1);
if (locks == NULL) {
return NT_STATUS_NO_MEMORY;
}
}
lck2->generic.level = RAW_LOCK_GENERIC;
- lck2->generic.in.fnum = lck->lock.in.fnum;
+ lck2->generic.file.fnum = lck->lock.file.fnum;
lck2->generic.in.mode = 0;
lck2->generic.in.timeout = 0;
lck2->generic.in.locks = locks;
locks->offset = lck->lock.in.offset;
locks->count = lck->lock.in.count;
+ /*
+ * we don't need to call ntvfs_map_async_setup() here,
+ * as lock() doesn't have any output fields
+ */
+
return ntvfs->ops->lock(ntvfs, req, lck2);
}
/*
NTVFS write generic to any mapper
*/
-NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr,
- struct ntvfs_module_context *ntvfs)
+static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_write *wr,
+ union smb_write *wr2,
+ NTSTATUS status)
{
- union smb_write *wr2;
union smb_lock *lck;
union smb_close *cl;
- NTSTATUS status;
+ uint_t state;
- wr2 = talloc_p(req, union smb_write);
- if (wr2 == NULL) {
- return NT_STATUS_NO_MEMORY;
+ if (NT_STATUS_IS_ERR(status)) {
+ return status;
}
- wr2->generic.level = RAW_WRITE_GENERIC;
-
- /* we can't map asynchronously */
- req->control_flags &= ~REQ_CONTROL_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);
+ wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
+
+ lck = talloc(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.file.fnum = wr->writeunlock.file.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)) {
+ if (lck->unlock.in.count != 0) {
+ /* do the lock sync for now */
+ state = req->async_states->state;
+ req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
status = ntvfs->ops->lock(ntvfs, req, lck);
+ req->async_states->state = state;
}
break;
case RAW_WRITE_WRITECLOSE:
- cl = talloc_p(wr2, union smb_close);
+ wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
+
+ cl = talloc(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.file.fnum = wr->writeclose.file.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)) {
+ if (wr2->generic.in.count != 0) {
+ /* do the close sync for now */
+ state = req->async_states->state;
+ req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
status = ntvfs->ops->close(ntvfs, req, cl);
+ req->async_states->state = state;
}
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;
+ break;
+ default:
+ return NT_STATUS_INVALID_LEVEL;
+ }
+
+ return status;
+}
+
+
+/*
+ NTVFS write generic to any mapper
+*/
+_PUBLIC_ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_write *wr)
+{
+ union smb_write *wr2;
+ NTSTATUS status;
+
+ wr2 = talloc(req, union smb_write);
+ if (wr2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
+ (second_stage_t)ntvfs_map_write_finish);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ wr2->writex.level = RAW_WRITE_GENERIC;
+
+ switch (wr->generic.level) {
+ case RAW_WRITE_WRITEX:
+ status = NT_STATUS_INVALID_LEVEL;
+ break;
+
+ case RAW_WRITE_WRITE:
+ wr2->writex.file.fnum = wr->write.file.fnum;
+ wr2->writex.in.offset = wr->write.in.offset;
+ wr2->writex.in.wmode = 0;
+ wr2->writex.in.remaining = wr->write.in.remaining;
+ wr2->writex.in.count = wr->write.in.count;
+ wr2->writex.in.data = wr->write.in.data;
+ status = ntvfs->ops->write(ntvfs, req, wr2);
+ break;
+
+ case RAW_WRITE_WRITEUNLOCK:
+ wr2->writex.file.fnum = wr->writeunlock.file.fnum;
+ wr2->writex.in.offset = wr->writeunlock.in.offset;
+ wr2->writex.in.wmode = 0;
+ wr2->writex.in.remaining = wr->writeunlock.in.remaining;
+ wr2->writex.in.count = wr->writeunlock.in.count;
+ wr2->writex.in.data = wr->writeunlock.in.data;
+ status = ntvfs->ops->write(ntvfs, req, wr2);
+ break;
+
+ case RAW_WRITE_WRITECLOSE:
+ wr2->writex.file.fnum = wr->writeclose.file.fnum;
+ wr2->writex.in.offset = wr->writeclose.in.offset;
+ wr2->writex.in.wmode = 0;
+ wr2->writex.in.remaining = 0;
+ wr2->writex.in.count = wr->writeclose.in.count;
+ wr2->writex.in.data = wr->writeclose.in.data;
+ status = ntvfs->ops->write(ntvfs, req, wr2);
+ break;
+
+ case RAW_WRITE_SPLWRITE:
+ wr2->writex.file.fnum = wr->splwrite.file.fnum;
+ wr2->writex.in.offset = 0;
+ wr2->writex.in.wmode = 0;
+ wr2->writex.in.remaining = 0;
+ wr2->writex.in.count = wr->splwrite.in.count;
+ wr2->writex.in.data = wr->splwrite.in.data;
status = ntvfs->ops->write(ntvfs, req, wr2);
break;
}
+ return ntvfs_map_async_finish(req, status);
+}
+
+
+/*
+ NTVFS read generic to any mapper - finish the out mapping
+*/
+static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_read *rd,
+ union smb_read *rd2,
+ NTSTATUS status)
+{
+ switch (rd->generic.level) {
+ case RAW_READ_READ:
+ rd->read.out.nread = rd2->generic.out.nread;
+ break;
+ case RAW_READ_READBRAW:
+ rd->readbraw.out.nread = rd2->generic.out.nread;
+ break;
+ case RAW_READ_LOCKREAD:
+ rd->lockread.out.nread = rd2->generic.out.nread;
+ break;
+ default:
+ return NT_STATUS_INVALID_LEVEL;
+ }
return status;
}
-
/*
- NTVFS read generic to any mapper
+ NTVFS read* to readx mapper
*/
-NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd,
- struct ntvfs_module_context *ntvfs)
+_PUBLIC_ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_read *rd)
{
union smb_read *rd2;
union smb_lock *lck;
NTSTATUS status;
+ uint_t state;
- rd2 = talloc_p(req, union smb_read);
+ rd2 = talloc(req, union smb_read);
if (rd2 == NULL) {
return NT_STATUS_NO_MEMORY;
}
- rd2->generic.level = RAW_READ_GENERIC;
+ status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
+ (second_stage_t)ntvfs_map_read_finish);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
- /* we can't map asynchronously */
- req->control_flags &= ~REQ_CONTROL_MAY_ASYNC;
+ rd2->readx.level = RAW_READ_READX;
switch (rd->generic.level) {
case RAW_READ_READX:
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;
+ rd2->readx.file.fnum = rd->read.file.fnum;
+ rd2->readx.in.offset = rd->read.in.offset;
+ rd2->readx.in.mincnt = rd->read.in.count;
+ rd2->readx.in.maxcnt = rd->read.in.count;
+ rd2->readx.in.remaining = rd->read.in.remaining;
+ rd2->readx.out.data = rd->read.out.data;
status = ntvfs->ops->read(ntvfs, req, rd2);
- 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;
+ rd2->readx.file.fnum = rd->readbraw.file.fnum;
+ rd2->readx.in.offset = rd->readbraw.in.offset;
+ rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
+ rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
+ rd2->readx.in.remaining = 0;
+ rd2->readx.out.data = rd->readbraw.out.data;
status = ntvfs->ops->read(ntvfs, req, rd2);
- rd->readbraw.out.nread = rd2->generic.out.nread;
break;
case RAW_READ_LOCKREAD:
- lck = talloc_p(rd2, union smb_lock);
+ /* do the initial lock sync for now */
+ state = req->async_states->state;
+ req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
+
+ lck = talloc(rd2, union smb_lock);
if (lck == NULL) {
- return NT_STATUS_NO_MEMORY;
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
}
-
- 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.file.fnum = rd->lockread.file.fnum;
lck->lock.in.count = rd->lockread.in.count;
lck->lock.in.offset = rd->lockread.in.offset;
-
status = ntvfs->ops->lock(ntvfs, req, lck);
+ req->async_states->state = state;
+
+ rd2->readx.file.fnum = rd->lockread.file.fnum;
+ rd2->readx.in.offset = rd->lockread.in.offset;
+ rd2->readx.in.mincnt = rd->lockread.in.count;
+ rd2->readx.in.maxcnt = rd->lockread.in.count;
+ rd2->readx.in.remaining = rd->lockread.in.remaining;
+ rd2->readx.out.data = rd->lockread.out.data;
if (NT_STATUS_IS_OK(status)) {
status = ntvfs->ops->read(ntvfs, req, rd2);
- rd->lockread.out.nread = rd2->generic.out.nread;
}
break;
}
-
- return status;
+done:
+ return ntvfs_map_async_finish(req, status);
}
/*
NTVFS close generic to any mapper
*/
-NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl,
- struct ntvfs_module_context *ntvfs)
+_PUBLIC_ NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
+ struct ntvfs_request *req,
+ union smb_close *cl)
{
union smb_close *cl2;
- cl2 = talloc_p(req, union smb_close);
+ cl2 = talloc(req, union smb_close);
if (cl2 == NULL) {
return NT_STATUS_NO_MEMORY;
}
- switch (cl2->generic.level) {
+ 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;
+ cl2->close.level = RAW_CLOSE_CLOSE;
+ cl2->close.file.fnum = cl->splclose.file.fnum;
break;
}
+ /*
+ * we don't need to call ntvfs_map_async_setup() here,
+ * as close() doesn't have any output fields
+ */
+
return ntvfs->ops->close(ntvfs, req, cl2);
}