2 Unix SMB/CIFS implementation.
4 NTVFS generic level mapping code
6 Copyright (C) Andrew Tridgell 2003-2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 this implements mappings between info levels for NTVFS backend calls
24 the idea is that each of these functions implements one of the NTVFS
25 backend calls in terms of the 'generic' call. All backends that use
26 these functions must supply the generic call, but can if it wants to
27 also implement other levels if the need arises
29 this allows backend writers to only implement one variant of each
30 call unless they need fine grained control of the calls.
34 #include "ntvfs/ntvfs.h"
35 #include "libcli/smb2/smb2.h"
36 #include "libcli/smb2/smb2_calls.h"
38 /* a second stage function converts from the out parameters of the generic
39 call onto the out parameters of the specific call made */
40 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
41 struct ntvfs_request *,
42 void *, void *, NTSTATUS);
45 this structure holds the async state for pending mapped async calls
47 struct ntvfs_map_async {
48 struct ntvfs_module_context *ntvfs;
54 this is a async wrapper, called from the backend when it has completed
55 a function that it has decided to reply to in an async fashion
57 static void ntvfs_map_async_send(struct ntvfs_request *req)
59 struct ntvfs_map_async *m = req->async_states->private_data;
61 ntvfs_async_state_pop(req);
63 /* call the _finish function setup in ntvfs_map_async_setup() */
64 req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
66 /* call the send function from the next module up */
67 req->async_states->send_fn(req);
71 prepare for calling a ntvfs backend with async support
72 io is the original call structure
73 io2 is the new call structure for the mapped call
74 fn is a second stage function for processing the out arguments
76 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
77 struct ntvfs_request *req,
81 struct ntvfs_map_async *m;
82 m = talloc(req, struct ntvfs_map_async);
84 return NT_STATUS_NO_MEMORY;
90 return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
94 called when first stage processing is complete.
96 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
98 struct ntvfs_map_async *m;
100 /* if the backend has decided to reply in an async fashion then
101 we don't need to do any work here */
102 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
106 /* the backend is replying immediately. call the 2nd stage function after popping our local
108 m = req->async_states->private_data;
110 ntvfs_async_state_pop(req);
112 return m->fn(m->ntvfs, req, m->io, m->io2, status);
116 see if a filename ends in EXE COM DLL or SYM. This is needed for the
117 DENY_DOS mapping for OpenX
119 bool is_exe_filename(const char *fname)
122 p = strrchr(fname, '.');
127 if (strcasecmp(p, "EXE") == 0 ||
128 strcasecmp(p, "COM") == 0 ||
129 strcasecmp(p, "DLL") == 0 ||
130 strcasecmp(p, "SYM") == 0) {
138 NTVFS openx to ntcreatex mapper
140 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
141 struct ntvfs_request *req,
146 time_t write_time = 0;
147 uint32_t set_size = 0;
148 union smb_setfileinfo *sf;
151 if (!NT_STATUS_IS_OK(status)) {
155 switch (io->generic.level) {
157 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
158 io->openold.out.attrib = io2->generic.out.attrib;
159 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
160 io->openold.out.size = io2->generic.out.size;
161 io->openold.out.rmode = io->openold.in.open_mode;
165 io->openx.out.file.ntvfs = io2->generic.out.file.ntvfs;
166 io->openx.out.attrib = io2->generic.out.attrib;
167 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
168 io->openx.out.size = io2->generic.out.size;
169 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
170 io->openx.out.ftype = 0;
171 io->openx.out.devstate = 0;
172 io->openx.out.action = io2->generic.out.create_action;
173 io->openx.out.unique_fid = 0;
174 io->openx.out.access_mask = SEC_STD_ALL;
175 io->openx.out.unknown = 0;
177 /* we need to extend the file to the requested size if
178 it was newly created */
179 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
180 set_size = io->openx.in.size;
184 case RAW_OPEN_T2OPEN:
185 io->t2open.out.file.ntvfs = io2->generic.out.file.ntvfs;
186 io->t2open.out.attrib = io2->generic.out.attrib;
187 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
188 io->t2open.out.size = io2->generic.out.size;
189 io->t2open.out.access = io->t2open.in.open_mode;
190 io->t2open.out.ftype = 0;
191 io->t2open.out.devstate = 0;
192 io->t2open.out.action = io2->generic.out.create_action;
193 io->t2open.out.file_id = 0;
197 case RAW_OPEN_CREATE:
198 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
199 write_time = io->mknew.in.write_time;
203 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
204 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
205 strlen(io->ctemp.in.directory) + 1);
206 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
210 io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs;
211 io->smb2.out.oplock_level = 0;
212 io->smb2.out.reserved = 0;
213 io->smb2.out.create_action = io2->generic.out.create_action;
214 io->smb2.out.create_time = io2->generic.out.create_time;
215 io->smb2.out.access_time = io2->generic.out.access_time;
216 io->smb2.out.write_time = io2->generic.out.write_time;
217 io->smb2.out.change_time = io2->generic.out.change_time;
218 io->smb2.out.alloc_size = io2->generic.out.alloc_size;
219 io->smb2.out.size = io2->generic.out.size;
220 io->smb2.out.file_attr = io2->generic.out.attrib;
221 io->smb2.out.reserved2 = 0;
222 io->smb2.out.blob = data_blob(NULL, 0);
226 return NT_STATUS_INVALID_LEVEL;
229 /* doing a secondary request async is more trouble than its
231 state = req->async_states->state;
232 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
234 if (write_time != 0) {
235 sf = talloc(req, union smb_setfileinfo);
236 NT_STATUS_HAVE_NO_MEMORY(sf);
237 sf->generic.level = RAW_SFILEINFO_STANDARD;
238 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
239 sf->standard.in.create_time = 0;
240 sf->standard.in.write_time = write_time;
241 sf->standard.in.access_time = 0;
242 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
246 sf = talloc(req, union smb_setfileinfo);
247 NT_STATUS_HAVE_NO_MEMORY(sf);
248 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
249 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
250 sf->end_of_file_info.in.size = set_size;
251 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
252 if (NT_STATUS_IS_OK(status)) {
253 io->openx.out.size = io->openx.in.size;
257 req->async_states->state = state;
263 the core of the mapping between openx style parameters and ntcreatex
266 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
267 uint16_t open_func, const char *fname,
270 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
271 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
273 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
274 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
277 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
278 case OPENX_MODE_ACCESS_READ:
279 case OPENX_MODE_ACCESS_EXEC:
280 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
282 case OPENX_MODE_ACCESS_WRITE:
283 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
285 case OPENX_MODE_ACCESS_RDWR:
286 case OPENX_MODE_ACCESS_FCB:
287 io2->generic.in.access_mask =
288 SEC_RIGHTS_FILE_READ |
289 SEC_RIGHTS_FILE_WRITE;
292 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
295 switch (open_mode & OPENX_MODE_DENY_MASK) {
296 case OPENX_MODE_DENY_READ:
297 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
299 case OPENX_MODE_DENY_WRITE:
300 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
302 case OPENX_MODE_DENY_ALL:
303 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
305 case OPENX_MODE_DENY_NONE:
306 io2->generic.in.share_access =
307 NTCREATEX_SHARE_ACCESS_READ |
308 NTCREATEX_SHARE_ACCESS_WRITE;
310 case OPENX_MODE_DENY_DOS:
311 /* DENY_DOS is quite strange - it depends on the filename! */
312 io2->generic.in.create_options |=
313 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
314 if (is_exe_filename(fname)) {
315 io2->generic.in.share_access =
316 NTCREATEX_SHARE_ACCESS_READ |
317 NTCREATEX_SHARE_ACCESS_WRITE;
319 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
320 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
322 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
326 case OPENX_MODE_DENY_FCB:
327 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
328 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
331 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
335 case (OPENX_OPEN_FUNC_OPEN):
336 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
338 case (OPENX_OPEN_FUNC_TRUNC):
339 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
341 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
342 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
344 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
345 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
347 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
348 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
351 /* this one is very strange */
352 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
353 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
356 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
363 NTVFS open generic to any mapper
365 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
366 struct ntvfs_request *req,
372 io2 = talloc_zero(req, union smb_open);
374 return NT_STATUS_NO_MEMORY;
377 status = ntvfs_map_async_setup(ntvfs, req,
379 (second_stage_t)ntvfs_map_open_finish);
380 if (!NT_STATUS_IS_OK(status)) {
384 io2->generic.level = RAW_OPEN_GENERIC;
386 switch (io->generic.level) {
388 status = map_openx_open(io->openx.in.flags,
389 io->openx.in.open_mode,
390 io->openx.in.open_func,
393 if (!NT_STATUS_IS_OK(status)) {
397 io2->generic.in.file_attr = io->openx.in.file_attrs;
398 io2->generic.in.fname = io->openx.in.fname;
400 status = ntvfs->ops->open(ntvfs, req, io2);
405 status = map_openx_open(0,
406 io->openold.in.open_mode,
407 OPENX_OPEN_FUNC_OPEN,
408 io->openold.in.fname,
410 if (!NT_STATUS_IS_OK(status)) {
414 io2->generic.in.file_attr = io->openold.in.search_attrs;
415 io2->generic.in.fname = io->openold.in.fname;
417 status = ntvfs->ops->open(ntvfs, req, io2);
420 case RAW_OPEN_T2OPEN:
421 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
423 if (io->t2open.in.open_func == 0) {
424 status = NT_STATUS_OBJECT_NAME_COLLISION;
428 status = map_openx_open(io->t2open.in.flags,
429 io->t2open.in.open_mode,
430 io->t2open.in.open_func,
433 if (!NT_STATUS_IS_OK(status)) {
437 io2->generic.in.file_attr = io->t2open.in.file_attrs;
438 io2->generic.in.fname = io->t2open.in.fname;
439 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
440 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
441 io2->generic.in.ea_list->eas = io->t2open.in.eas;
443 status = ntvfs->ops->open(ntvfs, req, io2);
447 io2->generic.in.file_attr = io->mknew.in.attrib;
448 io2->generic.in.fname = io->mknew.in.fname;
449 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
450 io2->generic.in.access_mask =
451 SEC_RIGHTS_FILE_READ |
452 SEC_RIGHTS_FILE_WRITE;
453 io2->generic.in.share_access =
454 NTCREATEX_SHARE_ACCESS_READ |
455 NTCREATEX_SHARE_ACCESS_WRITE;
456 status = ntvfs->ops->open(ntvfs, req, io2);
459 case RAW_OPEN_CREATE:
460 io2->generic.in.file_attr = io->mknew.in.attrib;
461 io2->generic.in.fname = io->mknew.in.fname;
462 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
463 io2->generic.in.access_mask =
464 SEC_RIGHTS_FILE_READ |
465 SEC_RIGHTS_FILE_WRITE;
466 io2->generic.in.share_access =
467 NTCREATEX_SHARE_ACCESS_READ |
468 NTCREATEX_SHARE_ACCESS_WRITE;
469 status = ntvfs->ops->open(ntvfs, req, io2);
473 io2->generic.in.file_attr = io->ctemp.in.attrib;
474 io2->generic.in.fname =
475 talloc_asprintf(io2, "%s\\SRV%s",
476 io->ctemp.in.directory,
477 generate_random_str_list(io2, 5, "0123456789"));
478 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
479 io2->generic.in.access_mask =
480 SEC_RIGHTS_FILE_READ |
481 SEC_RIGHTS_FILE_WRITE;
482 io2->generic.in.share_access =
483 NTCREATEX_SHARE_ACCESS_READ |
484 NTCREATEX_SHARE_ACCESS_WRITE;
485 status = ntvfs->ops->open(ntvfs, req, io2);
488 io2->generic.in.flags = 0;
489 io2->generic.in.root_fid = 0;
490 io2->generic.in.access_mask = io->smb2.in.desired_access;
491 io2->generic.in.alloc_size = 0;
492 io2->generic.in.file_attr = io->smb2.in.file_attributes;
493 io2->generic.in.share_access = io->smb2.in.share_access;
494 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
495 io2->generic.in.create_options = io->smb2.in.create_options;
496 io2->generic.in.impersonation = io->smb2.in.impersonation_level;
497 io2->generic.in.security_flags = 0;
498 io2->generic.in.fname = io->smb2.in.fname;
499 io2->generic.in.sec_desc = NULL;
500 io2->generic.in.ea_list = NULL;
501 status = ntvfs->ops->open(ntvfs, req, io2);
505 status = NT_STATUS_INVALID_LEVEL;
509 return ntvfs_map_async_finish(req, status);
514 NTVFS fsinfo generic to any mapper
516 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
517 struct ntvfs_request *req,
518 union smb_fsinfo *fs)
521 union smb_fsinfo *fs2;
523 fs2 = talloc(req, union smb_fsinfo);
525 return NT_STATUS_NO_MEMORY;
528 if (fs->generic.level == RAW_QFS_GENERIC) {
529 return NT_STATUS_INVALID_LEVEL;
532 /* only used by the simple backend, which doesn't do async */
533 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
535 /* ask the backend for the generic info */
536 fs2->generic.level = RAW_QFS_GENERIC;
538 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
539 if (!NT_STATUS_IS_OK(status)) {
543 /* and convert it to the required level */
544 switch (fs->generic.level) {
545 case RAW_QFS_GENERIC:
546 return NT_STATUS_INVALID_LEVEL;
548 case RAW_QFS_DSKATTR: {
549 /* map from generic to DSKATTR */
552 /* we need to scale the sizes to fit */
553 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
554 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
559 fs->dskattr.out.blocks_per_unit = bpunit;
560 fs->dskattr.out.block_size = 512;
561 fs->dskattr.out.units_total =
562 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
563 fs->dskattr.out.units_free =
564 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
566 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
567 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
568 fs->dskattr.out.blocks_per_unit = 64;
569 fs->dskattr.out.units_total = 0xFFFF;
570 fs->dskattr.out.units_free = 0xFFFF;
575 case RAW_QFS_ALLOCATION:
576 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
577 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
578 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
579 fs->allocation.out.sectors_per_unit = 1;
580 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
584 fs->volume.out.serial_number = fs2->generic.out.serial_number;
585 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
588 case RAW_QFS_VOLUME_INFO:
589 case RAW_QFS_VOLUME_INFORMATION:
590 fs->volume_info.out.create_time = fs2->generic.out.create_time;
591 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
592 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
595 case RAW_QFS_SIZE_INFO:
596 case RAW_QFS_SIZE_INFORMATION:
597 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
598 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
599 fs->size_info.out.sectors_per_unit = 1;
600 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
603 case RAW_QFS_DEVICE_INFO:
604 case RAW_QFS_DEVICE_INFORMATION:
605 fs->device_info.out.device_type = fs2->generic.out.device_type;
606 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
609 case RAW_QFS_ATTRIBUTE_INFO:
610 case RAW_QFS_ATTRIBUTE_INFORMATION:
611 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
612 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
613 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
616 case RAW_QFS_QUOTA_INFORMATION:
617 ZERO_STRUCT(fs->quota_information.out.unknown);
618 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
619 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
620 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
623 case RAW_QFS_FULL_SIZE_INFORMATION:
624 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
625 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
626 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
627 fs->full_size_information.out.sectors_per_unit = 1;
628 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
631 case RAW_QFS_OBJECTID_INFORMATION:
632 fs->objectid_information.out.guid = fs2->generic.out.guid;
633 ZERO_STRUCT(fs->objectid_information.out.unknown);
638 return NT_STATUS_INVALID_LEVEL;
643 NTVFS fileinfo generic to any mapper
645 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
646 union smb_fileinfo *info,
647 union smb_fileinfo *info2)
650 /* and convert it to the required level using results in info2 */
651 switch (info->generic.level) {
652 case RAW_FILEINFO_GENERIC:
653 return NT_STATUS_INVALID_LEVEL;
654 case RAW_FILEINFO_GETATTR:
655 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
656 info->getattr.out.size = info2->generic.out.size;
657 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
660 case RAW_FILEINFO_GETATTRE:
661 info->getattre.out.attrib = info2->generic.out.attrib;
662 info->getattre.out.size = info2->generic.out.size;
663 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
664 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
665 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
666 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
669 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
670 info->network_open_information.out.create_time = info2->generic.out.create_time;
671 info->network_open_information.out.access_time = info2->generic.out.access_time;
672 info->network_open_information.out.write_time = info2->generic.out.write_time;
673 info->network_open_information.out.change_time = info2->generic.out.change_time;
674 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
675 info->network_open_information.out.size = info2->generic.out.size;
676 info->network_open_information.out.attrib = info2->generic.out.attrib;
679 case RAW_FILEINFO_ALL_INFO:
680 case RAW_FILEINFO_ALL_INFORMATION:
681 info->all_info.out.create_time = info2->generic.out.create_time;
682 info->all_info.out.access_time = info2->generic.out.access_time;
683 info->all_info.out.write_time = info2->generic.out.write_time;
684 info->all_info.out.change_time = info2->generic.out.change_time;
685 info->all_info.out.attrib = info2->generic.out.attrib;
686 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
687 info->all_info.out.size = info2->generic.out.size;
688 info->all_info.out.nlink = info2->generic.out.nlink;
689 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
690 info->all_info.out.directory = info2->generic.out.directory;
691 info->all_info.out.ea_size = info2->generic.out.ea_size;
692 info->all_info.out.fname.s = info2->generic.out.fname.s;
693 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
696 case RAW_FILEINFO_BASIC_INFO:
697 case RAW_FILEINFO_BASIC_INFORMATION:
698 info->basic_info.out.create_time = info2->generic.out.create_time;
699 info->basic_info.out.access_time = info2->generic.out.access_time;
700 info->basic_info.out.write_time = info2->generic.out.write_time;
701 info->basic_info.out.change_time = info2->generic.out.change_time;
702 info->basic_info.out.attrib = info2->generic.out.attrib;
705 case RAW_FILEINFO_STANDARD:
706 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
707 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
708 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
709 info->standard.out.size = info2->generic.out.size;
710 info->standard.out.alloc_size = info2->generic.out.alloc_size;
711 info->standard.out.attrib = info2->generic.out.attrib;
714 case RAW_FILEINFO_EA_SIZE:
715 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
716 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
717 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
718 info->ea_size.out.size = info2->generic.out.size;
719 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
720 info->ea_size.out.attrib = info2->generic.out.attrib;
721 info->ea_size.out.ea_size = info2->generic.out.ea_size;
724 case RAW_FILEINFO_STANDARD_INFO:
725 case RAW_FILEINFO_STANDARD_INFORMATION:
726 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
727 info->standard_info.out.size = info2->generic.out.size;
728 info->standard_info.out.nlink = info2->generic.out.nlink;
729 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
730 info->standard_info.out.directory = info2->generic.out.directory;
733 case RAW_FILEINFO_INTERNAL_INFORMATION:
734 info->internal_information.out.file_id = info2->generic.out.file_id;
737 case RAW_FILEINFO_EA_INFO:
738 case RAW_FILEINFO_EA_INFORMATION:
739 info->ea_info.out.ea_size = info2->generic.out.ea_size;
742 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
743 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
744 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
747 case RAW_FILEINFO_STREAM_INFO:
748 case RAW_FILEINFO_STREAM_INFORMATION:
749 info->stream_info.out.num_streams = info2->generic.out.num_streams;
750 if (info->stream_info.out.num_streams > 0) {
751 info->stream_info.out.streams =
752 talloc_array(mem_ctx,
753 struct stream_struct,
754 info->stream_info.out.num_streams);
755 if (!info->stream_info.out.streams) {
756 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
757 info->stream_info.out.num_streams));
758 return NT_STATUS_NO_MEMORY;
760 for (i=0; i < info->stream_info.out.num_streams; i++) {
761 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
762 info->stream_info.out.streams[i].stream_name.s =
763 talloc_strdup(info->stream_info.out.streams,
764 info2->generic.out.streams[i].stream_name.s);
765 if (!info->stream_info.out.streams[i].stream_name.s) {
766 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
767 return NT_STATUS_NO_MEMORY;
773 case RAW_FILEINFO_NAME_INFO:
774 case RAW_FILEINFO_NAME_INFORMATION:
775 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
776 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
777 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
780 case RAW_FILEINFO_ALT_NAME_INFO:
781 case RAW_FILEINFO_ALT_NAME_INFORMATION:
782 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
783 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
784 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
787 case RAW_FILEINFO_POSITION_INFORMATION:
788 info->position_information.out.position = info2->generic.out.position;
791 case RAW_FILEINFO_ALL_EAS:
792 info->all_eas.out.num_eas = info2->generic.out.num_eas;
793 if (info->all_eas.out.num_eas > 0) {
794 info->all_eas.out.eas = talloc_array(mem_ctx,
796 info->all_eas.out.num_eas);
797 if (!info->all_eas.out.eas) {
798 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
799 info->all_eas.out.num_eas));
800 return NT_STATUS_NO_MEMORY;
802 for (i = 0; i < info->all_eas.out.num_eas; i++) {
803 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
804 info->all_eas.out.eas[i].name.s =
805 talloc_strdup(info->all_eas.out.eas,
806 info2->generic.out.eas[i].name.s);
807 if (!info->all_eas.out.eas[i].name.s) {
808 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
809 return NT_STATUS_NO_MEMORY;
811 info->all_eas.out.eas[i].value.data =
812 talloc_memdup(info->all_eas.out.eas,
813 info2->generic.out.eas[i].value.data,
814 info2->generic.out.eas[i].value.length);
815 if (!info->all_eas.out.eas[i].value.data) {
816 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
817 return NT_STATUS_NO_MEMORY;
823 case RAW_FILEINFO_IS_NAME_VALID:
826 case RAW_FILEINFO_COMPRESSION_INFO:
827 case RAW_FILEINFO_COMPRESSION_INFORMATION:
828 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
829 info->compression_info.out.format = info2->generic.out.format;
830 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
831 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
832 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
835 case RAW_FILEINFO_ACCESS_INFORMATION:
836 info->access_information.out.access_flags = info2->generic.out.access_flags;
839 case RAW_FILEINFO_MODE_INFORMATION:
840 info->mode_information.out.mode = info2->generic.out.mode;
843 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
844 info->alignment_information.out.alignment_requirement =
845 info2->generic.out.alignment_requirement;
848 case RAW_FILEINFO_UNIX_BASIC:
849 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
850 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
851 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
852 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
853 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
854 info->unix_basic_info.out.uid = info2->generic.out.uid;
855 info->unix_basic_info.out.gid = info2->generic.out.gid;
856 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
857 info->unix_basic_info.out.dev_major = info2->generic.out.device;
858 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
859 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
860 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
861 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
864 case RAW_FILEINFO_UNIX_LINK:
865 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
870 return NT_STATUS_INVALID_LEVEL;
874 NTVFS fileinfo generic to any mapper
876 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
877 struct ntvfs_request *req,
878 union smb_fileinfo *info)
881 union smb_fileinfo *info2;
883 info2 = talloc(req, union smb_fileinfo);
885 return NT_STATUS_NO_MEMORY;
888 if (info->generic.level == RAW_FILEINFO_GENERIC) {
889 return NT_STATUS_INVALID_LEVEL;
892 /* ask the backend for the generic info */
893 info2->generic.level = RAW_FILEINFO_GENERIC;
894 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
896 /* only used by the simple backend, which doesn't do async */
897 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
899 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
900 if (!NT_STATUS_IS_OK(status)) {
903 return ntvfs_map_fileinfo(req, info, info2);
907 NTVFS pathinfo generic to any mapper
909 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
910 struct ntvfs_request *req,
911 union smb_fileinfo *info)
914 union smb_fileinfo *info2;
916 info2 = talloc(req, union smb_fileinfo);
918 return NT_STATUS_NO_MEMORY;
921 if (info->generic.level == RAW_FILEINFO_GENERIC) {
922 return NT_STATUS_INVALID_LEVEL;
925 /* ask the backend for the generic info */
926 info2->generic.level = RAW_FILEINFO_GENERIC;
927 info2->generic.in.file.path = info->generic.in.file.path;
929 /* only used by the simple backend, which doesn't do async */
930 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
932 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
933 if (!NT_STATUS_IS_OK(status)) {
936 return ntvfs_map_fileinfo(req, info, info2);
941 NTVFS lock generic to any mapper
943 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
944 struct ntvfs_request *req,
947 union smb_lock *lck2;
948 struct smb_lock_entry *locks;
950 lck2 = talloc(req, union smb_lock);
952 return NT_STATUS_NO_MEMORY;
955 locks = talloc_array(lck2, struct smb_lock_entry, 1);
957 return NT_STATUS_NO_MEMORY;
960 switch (lck->generic.level) {
962 return NT_STATUS_INVALID_LEVEL;
965 lck2->generic.level = RAW_LOCK_GENERIC;
966 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
967 lck2->generic.in.mode = 0;
968 lck2->generic.in.timeout = 0;
969 lck2->generic.in.ulock_cnt = 0;
970 lck2->generic.in.lock_cnt = 1;
971 lck2->generic.in.locks = locks;
972 locks->pid = req->smbpid;
973 locks->offset = lck->lock.in.offset;
974 locks->count = lck->lock.in.count;
977 case RAW_LOCK_UNLOCK:
978 lck2->generic.level = RAW_LOCK_GENERIC;
979 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
980 lck2->generic.in.mode = 0;
981 lck2->generic.in.timeout = 0;
982 lck2->generic.in.ulock_cnt = 1;
983 lck2->generic.in.lock_cnt = 0;
984 lck2->generic.in.locks = locks;
985 locks->pid = req->smbpid;
986 locks->offset = lck->unlock.in.offset;
987 locks->count = lck->unlock.in.count;
991 if (lck->smb2.in.unknown1 != 1) {
992 return NT_STATUS_INVALID_PARAMETER;
995 lck2->generic.level = RAW_LOCK_GENERIC;
996 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
997 if (lck->smb2.in.flags & SMB2_LOCK_FLAG_EXCLUSIV) {
998 lck2->generic.in.mode = 0;
1000 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1002 if (lck->smb2.in.flags & SMB2_LOCK_FLAG_NO_PENDING) {
1003 lck2->generic.in.timeout = 0;
1005 lck2->generic.in.timeout = UINT32_MAX;
1007 if (lck->smb2.in.flags & SMB2_LOCK_FLAG_UNLOCK) {
1008 lck2->generic.in.ulock_cnt = 1;
1009 lck2->generic.in.lock_cnt = 0;
1011 lck2->generic.in.ulock_cnt = 0;
1012 lck2->generic.in.lock_cnt = 1;
1014 lck2->generic.in.locks = locks;
1016 locks->offset = lck->smb2.in.offset;
1017 locks->count = lck->smb2.in.count;
1019 /* initialize output value */
1020 lck->smb2.out.unknown1 = 0;
1025 * we don't need to call ntvfs_map_async_setup() here,
1026 * as lock() doesn't have any output fields
1029 return ntvfs->ops->lock(ntvfs, req, lck2);
1034 NTVFS write generic to any mapper
1036 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1037 struct ntvfs_request *req,
1038 union smb_write *wr,
1039 union smb_write *wr2,
1042 union smb_lock *lck;
1043 union smb_close *cl;
1046 if (NT_STATUS_IS_ERR(status)) {
1050 switch (wr->generic.level) {
1051 case RAW_WRITE_WRITE:
1052 wr->write.out.nwritten = wr2->generic.out.nwritten;
1055 case RAW_WRITE_WRITEUNLOCK:
1056 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1058 lck = talloc(wr2, union smb_lock);
1060 return NT_STATUS_NO_MEMORY;
1063 lck->unlock.level = RAW_LOCK_UNLOCK;
1064 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1065 lck->unlock.in.count = wr->writeunlock.in.count;
1066 lck->unlock.in.offset = wr->writeunlock.in.offset;
1068 if (lck->unlock.in.count != 0) {
1069 /* do the lock sync for now */
1070 state = req->async_states->state;
1071 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1072 status = ntvfs->ops->lock(ntvfs, req, lck);
1073 req->async_states->state = state;
1077 case RAW_WRITE_WRITECLOSE:
1078 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1080 cl = talloc(wr2, union smb_close);
1082 return NT_STATUS_NO_MEMORY;
1085 cl->close.level = RAW_CLOSE_CLOSE;
1086 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1087 cl->close.in.write_time = wr->writeclose.in.mtime;
1089 if (wr2->generic.in.count != 0) {
1090 /* do the close sync for now */
1091 state = req->async_states->state;
1092 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1093 status = ntvfs->ops->close(ntvfs, req, cl);
1094 req->async_states->state = state;
1098 case RAW_WRITE_SPLWRITE:
1101 case RAW_WRITE_SMB2:
1102 wr->smb2.out._pad = 0;
1103 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1104 wr->smb2.out.unknown1 = 0;
1108 return NT_STATUS_INVALID_LEVEL;
1116 NTVFS write generic to any mapper
1118 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1119 struct ntvfs_request *req,
1120 union smb_write *wr)
1122 union smb_write *wr2;
1125 wr2 = talloc(req, union smb_write);
1127 return NT_STATUS_NO_MEMORY;
1130 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1131 (second_stage_t)ntvfs_map_write_finish);
1132 if (!NT_STATUS_IS_OK(status)) {
1136 wr2->writex.level = RAW_WRITE_GENERIC;
1138 switch (wr->generic.level) {
1139 case RAW_WRITE_WRITEX:
1140 status = NT_STATUS_INVALID_LEVEL;
1143 case RAW_WRITE_WRITE:
1144 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1145 wr2->writex.in.offset = wr->write.in.offset;
1146 wr2->writex.in.wmode = 0;
1147 wr2->writex.in.remaining = wr->write.in.remaining;
1148 wr2->writex.in.count = wr->write.in.count;
1149 wr2->writex.in.data = wr->write.in.data;
1150 status = ntvfs->ops->write(ntvfs, req, wr2);
1153 case RAW_WRITE_WRITEUNLOCK:
1154 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1155 wr2->writex.in.offset = wr->writeunlock.in.offset;
1156 wr2->writex.in.wmode = 0;
1157 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1158 wr2->writex.in.count = wr->writeunlock.in.count;
1159 wr2->writex.in.data = wr->writeunlock.in.data;
1160 status = ntvfs->ops->write(ntvfs, req, wr2);
1163 case RAW_WRITE_WRITECLOSE:
1164 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1165 wr2->writex.in.offset = wr->writeclose.in.offset;
1166 wr2->writex.in.wmode = 0;
1167 wr2->writex.in.remaining = 0;
1168 wr2->writex.in.count = wr->writeclose.in.count;
1169 wr2->writex.in.data = wr->writeclose.in.data;
1170 status = ntvfs->ops->write(ntvfs, req, wr2);
1173 case RAW_WRITE_SPLWRITE:
1174 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1175 wr2->writex.in.offset = 0;
1176 wr2->writex.in.wmode = 0;
1177 wr2->writex.in.remaining = 0;
1178 wr2->writex.in.count = wr->splwrite.in.count;
1179 wr2->writex.in.data = wr->splwrite.in.data;
1180 status = ntvfs->ops->write(ntvfs, req, wr2);
1183 case RAW_WRITE_SMB2:
1184 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1185 wr2->writex.in.offset = wr->smb2.in.offset;
1186 wr2->writex.in.wmode = 0;
1187 wr2->writex.in.remaining = 0;
1188 wr2->writex.in.count = wr->smb2.in.data.length;
1189 wr2->writex.in.data = wr->smb2.in.data.data;
1190 status = ntvfs->ops->write(ntvfs, req, wr2);
1193 return ntvfs_map_async_finish(req, status);
1198 NTVFS read generic to any mapper - finish the out mapping
1200 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1201 struct ntvfs_request *req,
1203 union smb_read *rd2,
1206 switch (rd->generic.level) {
1208 rd->read.out.nread = rd2->generic.out.nread;
1210 case RAW_READ_READBRAW:
1211 rd->readbraw.out.nread = rd2->generic.out.nread;
1213 case RAW_READ_LOCKREAD:
1214 rd->lockread.out.nread = rd2->generic.out.nread;
1217 rd->smb2.out.data.length= rd2->generic.out.nread;
1218 rd->smb2.out.remaining = 0;
1219 rd->smb2.out.reserved = 0;
1222 return NT_STATUS_INVALID_LEVEL;
1229 NTVFS read* to readx mapper
1231 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1232 struct ntvfs_request *req,
1235 union smb_read *rd2;
1236 union smb_lock *lck;
1240 rd2 = talloc(req, union smb_read);
1242 return NT_STATUS_NO_MEMORY;
1245 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1246 (second_stage_t)ntvfs_map_read_finish);
1247 if (!NT_STATUS_IS_OK(status)) {
1251 rd2->readx.level = RAW_READ_READX;
1252 rd2->readx.in.read_for_execute = false;
1254 switch (rd->generic.level) {
1255 case RAW_READ_READX:
1256 status = NT_STATUS_INVALID_LEVEL;
1260 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1261 rd2->readx.in.offset = rd->read.in.offset;
1262 rd2->readx.in.mincnt = rd->read.in.count;
1263 rd2->readx.in.maxcnt = rd->read.in.count;
1264 rd2->readx.in.remaining = rd->read.in.remaining;
1265 rd2->readx.out.data = rd->read.out.data;
1266 status = ntvfs->ops->read(ntvfs, req, rd2);
1269 case RAW_READ_READBRAW:
1270 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1271 rd2->readx.in.offset = rd->readbraw.in.offset;
1272 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1273 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1274 rd2->readx.in.remaining = 0;
1275 rd2->readx.out.data = rd->readbraw.out.data;
1276 status = ntvfs->ops->read(ntvfs, req, rd2);
1279 case RAW_READ_LOCKREAD:
1280 /* do the initial lock sync for now */
1281 state = req->async_states->state;
1282 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1284 lck = talloc(rd2, union smb_lock);
1286 status = NT_STATUS_NO_MEMORY;
1289 lck->lock.level = RAW_LOCK_LOCK;
1290 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1291 lck->lock.in.count = rd->lockread.in.count;
1292 lck->lock.in.offset = rd->lockread.in.offset;
1293 status = ntvfs->ops->lock(ntvfs, req, lck);
1294 req->async_states->state = state;
1296 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1297 rd2->readx.in.offset = rd->lockread.in.offset;
1298 rd2->readx.in.mincnt = rd->lockread.in.count;
1299 rd2->readx.in.maxcnt = rd->lockread.in.count;
1300 rd2->readx.in.remaining = rd->lockread.in.remaining;
1301 rd2->readx.out.data = rd->lockread.out.data;
1303 if (NT_STATUS_IS_OK(status)) {
1304 status = ntvfs->ops->read(ntvfs, req, rd2);
1309 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1310 rd2->readx.in.offset = rd->smb2.in.offset;
1311 rd2->readx.in.mincnt = rd->smb2.in.length;
1312 rd2->readx.in.maxcnt = rd->smb2.in.length;
1313 rd2->readx.in.remaining = 0;
1314 rd2->readx.out.data = rd->smb2.out.data.data;
1315 status = ntvfs->ops->read(ntvfs, req, rd2);
1320 return ntvfs_map_async_finish(req, status);
1325 NTVFS close generic to any mapper
1327 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1328 struct ntvfs_request *req,
1329 union smb_close *cl)
1331 union smb_close *cl2;
1333 cl2 = talloc(req, union smb_close);
1335 return NT_STATUS_NO_MEMORY;
1338 switch (cl->generic.level) {
1339 case RAW_CLOSE_CLOSE:
1340 return NT_STATUS_INVALID_LEVEL;
1342 case RAW_CLOSE_SPLCLOSE:
1343 cl2->generic.level = RAW_CLOSE_CLOSE;
1344 cl2->generic.in.file.ntvfs = cl->splclose.in.file.ntvfs;
1345 cl2->generic.in.write_time = 0;
1348 case RAW_CLOSE_SMB2:
1349 cl2->generic.level = RAW_CLOSE_CLOSE;
1350 cl2->generic.in.file.ntvfs = cl->smb2.in.file.ntvfs;
1351 cl2->generic.in.write_time = 0;
1352 /* SMB2 Close has output parameter, but we just zero them */
1353 ZERO_STRUCT(cl->smb2.out);
1358 * we don't need to call ntvfs_map_async_setup() here,
1359 * as close() doesn't have any output fields
1362 return ntvfs->ops->close(ntvfs, req, cl2);
1366 NTVFS notify generic to any mapper
1368 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1369 struct ntvfs_request *req,
1370 union smb_notify *nt,
1371 union smb_notify *nt2,
1374 NT_STATUS_NOT_OK_RETURN(status);
1376 switch (nt->nttrans.level) {
1377 case RAW_NOTIFY_SMB2:
1378 if (nt2->nttrans.out.num_changes == 0) {
1379 return STATUS_NOTIFY_ENUM_DIR;
1381 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1382 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1386 return NT_STATUS_INVALID_LEVEL;
1394 NTVFS notify generic to any mapper
1396 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1397 struct ntvfs_request *req,
1398 union smb_notify *nt)
1400 union smb_notify *nt2;
1403 nt2 = talloc(req, union smb_notify);
1404 NT_STATUS_HAVE_NO_MEMORY(nt2);
1406 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1407 (second_stage_t)ntvfs_map_notify_finish);
1408 NT_STATUS_NOT_OK_RETURN(status);
1410 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1412 switch (nt->nttrans.level) {
1413 case RAW_NOTIFY_NTTRANS:
1414 status = NT_STATUS_INVALID_LEVEL;
1417 case RAW_NOTIFY_SMB2:
1418 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1419 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1420 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1421 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1422 status = ntvfs->ops->notify(ntvfs, req, nt2);
1426 return ntvfs_map_async_finish(req, status);