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 ZERO_STRUCT(io->smb2.out);
211 io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs;
212 switch (io2->generic.out.oplock_level) {
213 case BATCH_OPLOCK_RETURN:
214 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
216 case EXCLUSIVE_OPLOCK_RETURN:
217 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
219 case LEVEL_II_OPLOCK_RETURN:
220 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
223 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
226 io->smb2.out.reserved = 0;
227 io->smb2.out.create_action = io2->generic.out.create_action;
228 io->smb2.out.create_time = io2->generic.out.create_time;
229 io->smb2.out.access_time = io2->generic.out.access_time;
230 io->smb2.out.write_time = io2->generic.out.write_time;
231 io->smb2.out.change_time = io2->generic.out.change_time;
232 io->smb2.out.alloc_size = io2->generic.out.alloc_size;
233 io->smb2.out.size = io2->generic.out.size;
234 io->smb2.out.file_attr = io2->generic.out.attrib;
235 io->smb2.out.reserved2 = 0;
236 io->smb2.out.maximal_access = io2->generic.out.maximal_access;
240 return NT_STATUS_INVALID_LEVEL;
243 /* doing a secondary request async is more trouble than its
245 state = req->async_states->state;
246 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
248 if (write_time != 0) {
249 sf = talloc(req, union smb_setfileinfo);
250 NT_STATUS_HAVE_NO_MEMORY(sf);
251 sf->generic.level = RAW_SFILEINFO_STANDARD;
252 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
253 sf->standard.in.create_time = 0;
254 sf->standard.in.write_time = write_time;
255 sf->standard.in.access_time = 0;
256 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
260 sf = talloc(req, union smb_setfileinfo);
261 NT_STATUS_HAVE_NO_MEMORY(sf);
262 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
263 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
264 sf->end_of_file_info.in.size = set_size;
265 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
266 if (NT_STATUS_IS_OK(status)) {
267 io->openx.out.size = io->openx.in.size;
271 req->async_states->state = state;
277 the core of the mapping between openx style parameters and ntcreatex
280 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
281 uint16_t open_func, const char *fname,
284 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
285 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
287 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
288 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
291 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
292 case OPENX_MODE_ACCESS_READ:
293 case OPENX_MODE_ACCESS_EXEC:
294 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
296 case OPENX_MODE_ACCESS_WRITE:
297 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
299 case OPENX_MODE_ACCESS_RDWR:
300 case OPENX_MODE_ACCESS_FCB:
301 io2->generic.in.access_mask =
302 SEC_RIGHTS_FILE_READ |
303 SEC_RIGHTS_FILE_WRITE;
306 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
309 switch (open_mode & OPENX_MODE_DENY_MASK) {
310 case OPENX_MODE_DENY_READ:
311 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
313 case OPENX_MODE_DENY_WRITE:
314 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
316 case OPENX_MODE_DENY_ALL:
317 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
319 case OPENX_MODE_DENY_NONE:
320 io2->generic.in.share_access =
321 NTCREATEX_SHARE_ACCESS_READ |
322 NTCREATEX_SHARE_ACCESS_WRITE;
324 case OPENX_MODE_DENY_DOS:
325 /* DENY_DOS is quite strange - it depends on the filename! */
326 io2->generic.in.create_options |=
327 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
328 if (is_exe_filename(fname)) {
329 io2->generic.in.share_access =
330 NTCREATEX_SHARE_ACCESS_READ |
331 NTCREATEX_SHARE_ACCESS_WRITE;
333 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
334 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
336 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
340 case OPENX_MODE_DENY_FCB:
341 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
342 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
345 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
349 case (OPENX_OPEN_FUNC_OPEN):
350 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
352 case (OPENX_OPEN_FUNC_TRUNC):
353 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
355 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
356 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
358 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
359 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
361 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
362 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
365 /* this one is very strange */
366 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
367 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
370 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
377 NTVFS open generic to any mapper
379 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
380 struct ntvfs_request *req,
386 io2 = talloc_zero(req, union smb_open);
388 return NT_STATUS_NO_MEMORY;
391 status = ntvfs_map_async_setup(ntvfs, req,
393 (second_stage_t)ntvfs_map_open_finish);
394 if (!NT_STATUS_IS_OK(status)) {
398 io2->generic.level = RAW_OPEN_GENERIC;
400 switch (io->generic.level) {
402 status = map_openx_open(io->openx.in.flags,
403 io->openx.in.open_mode,
404 io->openx.in.open_func,
407 if (!NT_STATUS_IS_OK(status)) {
411 io2->generic.in.file_attr = io->openx.in.file_attrs;
412 io2->generic.in.fname = io->openx.in.fname;
414 status = ntvfs->ops->open(ntvfs, req, io2);
419 status = map_openx_open(0,
420 io->openold.in.open_mode,
421 OPENX_OPEN_FUNC_OPEN,
422 io->openold.in.fname,
424 if (!NT_STATUS_IS_OK(status)) {
428 io2->generic.in.file_attr = io->openold.in.search_attrs;
429 io2->generic.in.fname = io->openold.in.fname;
431 status = ntvfs->ops->open(ntvfs, req, io2);
434 case RAW_OPEN_T2OPEN:
435 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
437 if (io->t2open.in.open_func == 0) {
438 status = NT_STATUS_OBJECT_NAME_COLLISION;
442 status = map_openx_open(io->t2open.in.flags,
443 io->t2open.in.open_mode,
444 io->t2open.in.open_func,
447 if (!NT_STATUS_IS_OK(status)) {
451 io2->generic.in.file_attr = io->t2open.in.file_attrs;
452 io2->generic.in.fname = io->t2open.in.fname;
453 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
454 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
455 io2->generic.in.ea_list->eas = io->t2open.in.eas;
457 status = ntvfs->ops->open(ntvfs, req, io2);
461 io2->generic.in.file_attr = io->mknew.in.attrib;
462 io2->generic.in.fname = io->mknew.in.fname;
463 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
464 io2->generic.in.access_mask =
465 SEC_RIGHTS_FILE_READ |
466 SEC_RIGHTS_FILE_WRITE;
467 io2->generic.in.share_access =
468 NTCREATEX_SHARE_ACCESS_READ |
469 NTCREATEX_SHARE_ACCESS_WRITE;
470 status = ntvfs->ops->open(ntvfs, req, io2);
473 case RAW_OPEN_CREATE:
474 io2->generic.in.file_attr = io->mknew.in.attrib;
475 io2->generic.in.fname = io->mknew.in.fname;
476 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
477 io2->generic.in.access_mask =
478 SEC_RIGHTS_FILE_READ |
479 SEC_RIGHTS_FILE_WRITE;
480 io2->generic.in.share_access =
481 NTCREATEX_SHARE_ACCESS_READ |
482 NTCREATEX_SHARE_ACCESS_WRITE;
483 status = ntvfs->ops->open(ntvfs, req, io2);
487 io2->generic.in.file_attr = io->ctemp.in.attrib;
488 io2->generic.in.fname =
489 talloc_asprintf(io2, "%s\\SRV%s",
490 io->ctemp.in.directory,
491 generate_random_str_list(io2, 5, "0123456789"));
492 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
493 io2->generic.in.access_mask =
494 SEC_RIGHTS_FILE_READ |
495 SEC_RIGHTS_FILE_WRITE;
496 io2->generic.in.share_access =
497 NTCREATEX_SHARE_ACCESS_READ |
498 NTCREATEX_SHARE_ACCESS_WRITE;
499 status = ntvfs->ops->open(ntvfs, req, io2);
502 switch (io->smb2.in.oplock_level) {
503 case SMB2_OPLOCK_LEVEL_BATCH:
504 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
505 NTCREATEX_FLAGS_REQUEST_OPLOCK;
507 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
508 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
511 io2->generic.in.flags = 0;
514 io2->generic.in.root_fid = 0;
515 io2->generic.in.access_mask = io->smb2.in.desired_access;
516 io2->generic.in.alloc_size = io->smb2.in.alloc_size;
517 io2->generic.in.file_attr = io->smb2.in.file_attributes;
518 io2->generic.in.share_access = io->smb2.in.share_access;
519 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
520 io2->generic.in.create_options = io->smb2.in.create_options;
521 io2->generic.in.impersonation = io->smb2.in.impersonation_level;
522 io2->generic.in.security_flags = 0;
523 io2->generic.in.fname = io->smb2.in.fname;
524 io2->generic.in.sec_desc = io->smb2.in.sec_desc;
525 io2->generic.in.ea_list = &io->smb2.in.eas;
526 io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access;
528 /* we don't support timewarp yet */
529 if (io->smb2.in.timewarp != 0) {
530 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
534 /* we need to check these bits before we check the private mask */
535 if (io2->generic.in.create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
536 status = NT_STATUS_NOT_SUPPORTED;
540 /* we use a couple of bits of the create options internally */
541 if (io2->generic.in.create_options & NTCREATEX_OPTIONS_PRIVATE_MASK) {
542 status = NT_STATUS_INVALID_PARAMETER;
546 status = ntvfs->ops->open(ntvfs, req, io2);
550 status = NT_STATUS_INVALID_LEVEL;
554 return ntvfs_map_async_finish(req, status);
559 NTVFS fsinfo generic to any mapper
561 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
562 struct ntvfs_request *req,
563 union smb_fsinfo *fs)
566 union smb_fsinfo *fs2;
568 fs2 = talloc(req, union smb_fsinfo);
570 return NT_STATUS_NO_MEMORY;
573 if (fs->generic.level == RAW_QFS_GENERIC) {
574 return NT_STATUS_INVALID_LEVEL;
577 /* only used by the simple backend, which doesn't do async */
578 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
580 /* ask the backend for the generic info */
581 fs2->generic.level = RAW_QFS_GENERIC;
583 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
584 if (!NT_STATUS_IS_OK(status)) {
588 /* and convert it to the required level */
589 switch (fs->generic.level) {
590 case RAW_QFS_GENERIC:
591 return NT_STATUS_INVALID_LEVEL;
593 case RAW_QFS_DSKATTR: {
594 /* map from generic to DSKATTR */
597 /* we need to scale the sizes to fit */
598 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
599 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
604 fs->dskattr.out.blocks_per_unit = bpunit;
605 fs->dskattr.out.block_size = 512;
606 fs->dskattr.out.units_total =
607 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
608 fs->dskattr.out.units_free =
609 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
611 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
612 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
613 fs->dskattr.out.blocks_per_unit = 64;
614 fs->dskattr.out.units_total = 0xFFFF;
615 fs->dskattr.out.units_free = 0xFFFF;
620 case RAW_QFS_ALLOCATION:
621 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
622 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
623 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
624 fs->allocation.out.sectors_per_unit = 1;
625 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
629 fs->volume.out.serial_number = fs2->generic.out.serial_number;
630 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
633 case RAW_QFS_VOLUME_INFO:
634 case RAW_QFS_VOLUME_INFORMATION:
635 fs->volume_info.out.create_time = fs2->generic.out.create_time;
636 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
637 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
640 case RAW_QFS_SIZE_INFO:
641 case RAW_QFS_SIZE_INFORMATION:
642 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
643 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
644 fs->size_info.out.sectors_per_unit = 1;
645 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
648 case RAW_QFS_DEVICE_INFO:
649 case RAW_QFS_DEVICE_INFORMATION:
650 fs->device_info.out.device_type = fs2->generic.out.device_type;
651 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
654 case RAW_QFS_ATTRIBUTE_INFO:
655 case RAW_QFS_ATTRIBUTE_INFORMATION:
656 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
657 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
658 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
661 case RAW_QFS_QUOTA_INFORMATION:
662 ZERO_STRUCT(fs->quota_information.out.unknown);
663 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
664 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
665 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
668 case RAW_QFS_FULL_SIZE_INFORMATION:
669 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
670 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
671 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
672 fs->full_size_information.out.sectors_per_unit = 1;
673 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
676 case RAW_QFS_OBJECTID_INFORMATION:
677 fs->objectid_information.out.guid = fs2->generic.out.guid;
678 ZERO_STRUCT(fs->objectid_information.out.unknown);
683 return NT_STATUS_INVALID_LEVEL;
688 NTVFS fileinfo generic to any mapper
690 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
691 union smb_fileinfo *info,
692 union smb_fileinfo *info2)
695 /* and convert it to the required level using results in info2 */
696 switch (info->generic.level) {
697 case RAW_FILEINFO_GENERIC:
698 return NT_STATUS_INVALID_LEVEL;
699 case RAW_FILEINFO_GETATTR:
700 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
701 info->getattr.out.size = info2->generic.out.size;
702 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
705 case RAW_FILEINFO_GETATTRE:
706 info->getattre.out.attrib = info2->generic.out.attrib;
707 info->getattre.out.size = info2->generic.out.size;
708 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
709 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
710 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
711 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
714 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
715 info->network_open_information.out.create_time = info2->generic.out.create_time;
716 info->network_open_information.out.access_time = info2->generic.out.access_time;
717 info->network_open_information.out.write_time = info2->generic.out.write_time;
718 info->network_open_information.out.change_time = info2->generic.out.change_time;
719 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
720 info->network_open_information.out.size = info2->generic.out.size;
721 info->network_open_information.out.attrib = info2->generic.out.attrib;
724 case RAW_FILEINFO_ALL_INFO:
725 case RAW_FILEINFO_ALL_INFORMATION:
726 info->all_info.out.create_time = info2->generic.out.create_time;
727 info->all_info.out.access_time = info2->generic.out.access_time;
728 info->all_info.out.write_time = info2->generic.out.write_time;
729 info->all_info.out.change_time = info2->generic.out.change_time;
730 info->all_info.out.attrib = info2->generic.out.attrib;
731 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
732 info->all_info.out.size = info2->generic.out.size;
733 info->all_info.out.nlink = info2->generic.out.nlink;
734 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
735 info->all_info.out.directory = info2->generic.out.directory;
736 info->all_info.out.ea_size = info2->generic.out.ea_size;
737 info->all_info.out.fname.s = info2->generic.out.fname.s;
738 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
741 case RAW_FILEINFO_BASIC_INFO:
742 case RAW_FILEINFO_BASIC_INFORMATION:
743 info->basic_info.out.create_time = info2->generic.out.create_time;
744 info->basic_info.out.access_time = info2->generic.out.access_time;
745 info->basic_info.out.write_time = info2->generic.out.write_time;
746 info->basic_info.out.change_time = info2->generic.out.change_time;
747 info->basic_info.out.attrib = info2->generic.out.attrib;
750 case RAW_FILEINFO_STANDARD:
751 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
752 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
753 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
754 info->standard.out.size = info2->generic.out.size;
755 info->standard.out.alloc_size = info2->generic.out.alloc_size;
756 info->standard.out.attrib = info2->generic.out.attrib;
759 case RAW_FILEINFO_EA_SIZE:
760 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
761 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
762 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
763 info->ea_size.out.size = info2->generic.out.size;
764 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
765 info->ea_size.out.attrib = info2->generic.out.attrib;
766 info->ea_size.out.ea_size = info2->generic.out.ea_size;
769 case RAW_FILEINFO_STANDARD_INFO:
770 case RAW_FILEINFO_STANDARD_INFORMATION:
771 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
772 info->standard_info.out.size = info2->generic.out.size;
773 info->standard_info.out.nlink = info2->generic.out.nlink;
774 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
775 info->standard_info.out.directory = info2->generic.out.directory;
778 case RAW_FILEINFO_INTERNAL_INFORMATION:
779 info->internal_information.out.file_id = info2->generic.out.file_id;
782 case RAW_FILEINFO_EA_INFO:
783 case RAW_FILEINFO_EA_INFORMATION:
784 info->ea_info.out.ea_size = info2->generic.out.ea_size;
787 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
788 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
789 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
792 case RAW_FILEINFO_STREAM_INFO:
793 case RAW_FILEINFO_STREAM_INFORMATION:
794 info->stream_info.out.num_streams = info2->generic.out.num_streams;
795 if (info->stream_info.out.num_streams > 0) {
796 info->stream_info.out.streams =
797 talloc_array(mem_ctx,
798 struct stream_struct,
799 info->stream_info.out.num_streams);
800 if (!info->stream_info.out.streams) {
801 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
802 info->stream_info.out.num_streams));
803 return NT_STATUS_NO_MEMORY;
805 for (i=0; i < info->stream_info.out.num_streams; i++) {
806 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
807 info->stream_info.out.streams[i].stream_name.s =
808 talloc_strdup(info->stream_info.out.streams,
809 info2->generic.out.streams[i].stream_name.s);
810 if (!info->stream_info.out.streams[i].stream_name.s) {
811 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
812 return NT_STATUS_NO_MEMORY;
818 case RAW_FILEINFO_NAME_INFO:
819 case RAW_FILEINFO_NAME_INFORMATION:
820 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
821 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
822 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
825 case RAW_FILEINFO_ALT_NAME_INFO:
826 case RAW_FILEINFO_ALT_NAME_INFORMATION:
827 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
828 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
829 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
832 case RAW_FILEINFO_POSITION_INFORMATION:
833 info->position_information.out.position = info2->generic.out.position;
836 case RAW_FILEINFO_ALL_EAS:
837 info->all_eas.out.num_eas = info2->generic.out.num_eas;
838 if (info->all_eas.out.num_eas > 0) {
839 info->all_eas.out.eas = talloc_array(mem_ctx,
841 info->all_eas.out.num_eas);
842 if (!info->all_eas.out.eas) {
843 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
844 info->all_eas.out.num_eas));
845 return NT_STATUS_NO_MEMORY;
847 for (i = 0; i < info->all_eas.out.num_eas; i++) {
848 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
849 info->all_eas.out.eas[i].name.s =
850 talloc_strdup(info->all_eas.out.eas,
851 info2->generic.out.eas[i].name.s);
852 if (!info->all_eas.out.eas[i].name.s) {
853 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
854 return NT_STATUS_NO_MEMORY;
856 info->all_eas.out.eas[i].value.data =
857 talloc_memdup(info->all_eas.out.eas,
858 info2->generic.out.eas[i].value.data,
859 info2->generic.out.eas[i].value.length);
860 if (!info->all_eas.out.eas[i].value.data) {
861 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
862 return NT_STATUS_NO_MEMORY;
868 case RAW_FILEINFO_IS_NAME_VALID:
871 case RAW_FILEINFO_COMPRESSION_INFO:
872 case RAW_FILEINFO_COMPRESSION_INFORMATION:
873 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
874 info->compression_info.out.format = info2->generic.out.format;
875 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
876 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
877 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
880 case RAW_FILEINFO_ACCESS_INFORMATION:
881 info->access_information.out.access_flags = info2->generic.out.access_flags;
884 case RAW_FILEINFO_MODE_INFORMATION:
885 info->mode_information.out.mode = info2->generic.out.mode;
888 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
889 info->alignment_information.out.alignment_requirement =
890 info2->generic.out.alignment_requirement;
893 case RAW_FILEINFO_UNIX_BASIC:
894 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
895 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
896 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
897 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
898 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
899 info->unix_basic_info.out.uid = info2->generic.out.uid;
900 info->unix_basic_info.out.gid = info2->generic.out.gid;
901 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
902 info->unix_basic_info.out.dev_major = info2->generic.out.device;
903 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
904 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
905 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
906 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
909 case RAW_FILEINFO_UNIX_LINK:
910 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
915 return NT_STATUS_INVALID_LEVEL;
919 NTVFS fileinfo generic to any mapper
921 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
922 struct ntvfs_request *req,
923 union smb_fileinfo *info)
926 union smb_fileinfo *info2;
928 info2 = talloc(req, union smb_fileinfo);
930 return NT_STATUS_NO_MEMORY;
933 if (info->generic.level == RAW_FILEINFO_GENERIC) {
934 return NT_STATUS_INVALID_LEVEL;
937 /* ask the backend for the generic info */
938 info2->generic.level = RAW_FILEINFO_GENERIC;
939 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
941 /* only used by the simple backend, which doesn't do async */
942 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
944 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
945 if (!NT_STATUS_IS_OK(status)) {
948 return ntvfs_map_fileinfo(req, info, info2);
952 NTVFS pathinfo generic to any mapper
954 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
955 struct ntvfs_request *req,
956 union smb_fileinfo *info)
959 union smb_fileinfo *info2;
961 info2 = talloc(req, union smb_fileinfo);
963 return NT_STATUS_NO_MEMORY;
966 if (info->generic.level == RAW_FILEINFO_GENERIC) {
967 return NT_STATUS_INVALID_LEVEL;
970 /* ask the backend for the generic info */
971 info2->generic.level = RAW_FILEINFO_GENERIC;
972 info2->generic.in.file.path = info->generic.in.file.path;
974 /* only used by the simple backend, which doesn't do async */
975 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
977 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
978 if (!NT_STATUS_IS_OK(status)) {
981 return ntvfs_map_fileinfo(req, info, info2);
986 NTVFS lock generic to any mapper
988 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
989 struct ntvfs_request *req,
992 union smb_lock *lck2;
993 struct smb_lock_entry *locks;
995 lck2 = talloc(req, union smb_lock);
997 return NT_STATUS_NO_MEMORY;
1000 locks = talloc_array(lck2, struct smb_lock_entry, 1);
1001 if (locks == NULL) {
1002 return NT_STATUS_NO_MEMORY;
1005 switch (lck->generic.level) {
1006 case RAW_LOCK_LOCKX:
1007 return NT_STATUS_INVALID_LEVEL;
1010 lck2->generic.level = RAW_LOCK_GENERIC;
1011 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1012 lck2->generic.in.mode = 0;
1013 lck2->generic.in.timeout = 0;
1014 lck2->generic.in.ulock_cnt = 0;
1015 lck2->generic.in.lock_cnt = 1;
1016 lck2->generic.in.locks = locks;
1017 locks->pid = req->smbpid;
1018 locks->offset = lck->lock.in.offset;
1019 locks->count = lck->lock.in.count;
1022 case RAW_LOCK_UNLOCK:
1023 lck2->generic.level = RAW_LOCK_GENERIC;
1024 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1025 lck2->generic.in.mode = 0;
1026 lck2->generic.in.timeout = 0;
1027 lck2->generic.in.ulock_cnt = 1;
1028 lck2->generic.in.lock_cnt = 0;
1029 lck2->generic.in.locks = locks;
1030 locks->pid = req->smbpid;
1031 locks->offset = lck->unlock.in.offset;
1032 locks->count = lck->unlock.in.count;
1035 case RAW_LOCK_SMB2: {
1036 /* this is only approximate! We need to change the
1037 generic structure to fix this properly */
1039 if (lck->smb2.in.lock_count < 1) {
1040 return NT_STATUS_INVALID_PARAMETER;
1043 lck2->generic.level = RAW_LOCK_GENERIC;
1044 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1045 lck2->generic.in.timeout = UINT32_MAX;
1046 lck2->generic.in.mode = 0;
1047 lck2->generic.in.lock_cnt = 0;
1048 lck2->generic.in.ulock_cnt = 0;
1049 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry,
1050 lck->smb2.in.lock_count);
1051 if (lck2->generic.in.locks == NULL) {
1052 return NT_STATUS_NO_MEMORY;
1054 for (i=0;i<lck->smb2.in.lock_count;i++) {
1055 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1058 j = lck2->generic.in.ulock_cnt;
1059 if (lck->smb2.in.locks[i].flags &
1060 (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE)) {
1061 return NT_STATUS_INVALID_PARAMETER;
1063 lck2->generic.in.ulock_cnt++;
1064 lck2->generic.in.locks[j].pid = 0;
1065 lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1066 lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1067 lck2->generic.in.locks[j].pid = 0;
1069 for (;i<lck->smb2.in.lock_count;i++) {
1070 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK) {
1071 /* w2008 requires unlocks to come first */
1072 return NT_STATUS_INVALID_PARAMETER;
1074 j = lck2->generic.in.ulock_cnt + lck2->generic.in.lock_cnt;
1075 lck2->generic.in.lock_cnt++;
1076 lck2->generic.in.locks[j].pid = 0;
1077 lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1078 lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1079 lck2->generic.in.locks[j].pid = 0;
1080 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1081 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1083 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1084 lck2->generic.in.timeout = 0;
1087 /* initialize output value */
1088 lck->smb2.out.reserved = 0;
1092 case RAW_LOCK_SMB2_BREAK:
1093 lck2->generic.level = RAW_LOCK_GENERIC;
1094 lck2->generic.in.file.ntvfs = lck->smb2_break.in.file.ntvfs;
1095 lck2->generic.in.mode = LOCKING_ANDX_OPLOCK_RELEASE |
1096 ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1097 lck2->generic.in.timeout = 0;
1098 lck2->generic.in.ulock_cnt = 0;
1099 lck2->generic.in.lock_cnt = 0;
1100 lck2->generic.in.locks = NULL;
1102 /* initialize output value */
1103 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1104 lck->smb2_break.out.reserved = lck->smb2_break.in.reserved;
1105 lck->smb2_break.out.reserved2 = lck->smb2_break.in.reserved2;
1106 lck->smb2_break.out.file = lck->smb2_break.in.file;
1111 * we don't need to call ntvfs_map_async_setup() here,
1112 * as lock() doesn't have any output fields
1115 return ntvfs->ops->lock(ntvfs, req, lck2);
1120 NTVFS write generic to any mapper
1122 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1123 struct ntvfs_request *req,
1124 union smb_write *wr,
1125 union smb_write *wr2,
1128 union smb_lock *lck;
1129 union smb_close *cl;
1132 if (NT_STATUS_IS_ERR(status)) {
1136 switch (wr->generic.level) {
1137 case RAW_WRITE_WRITE:
1138 wr->write.out.nwritten = wr2->generic.out.nwritten;
1141 case RAW_WRITE_WRITEUNLOCK:
1142 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1144 lck = talloc(wr2, union smb_lock);
1146 return NT_STATUS_NO_MEMORY;
1149 lck->unlock.level = RAW_LOCK_UNLOCK;
1150 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1151 lck->unlock.in.count = wr->writeunlock.in.count;
1152 lck->unlock.in.offset = wr->writeunlock.in.offset;
1154 if (lck->unlock.in.count != 0) {
1155 /* do the lock sync for now */
1156 state = req->async_states->state;
1157 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1158 status = ntvfs->ops->lock(ntvfs, req, lck);
1159 req->async_states->state = state;
1163 case RAW_WRITE_WRITECLOSE:
1164 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1166 cl = talloc(wr2, union smb_close);
1168 return NT_STATUS_NO_MEMORY;
1171 cl->close.level = RAW_CLOSE_CLOSE;
1172 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1173 cl->close.in.write_time = wr->writeclose.in.mtime;
1175 if (wr2->generic.in.count != 0) {
1176 /* do the close sync for now */
1177 state = req->async_states->state;
1178 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1179 status = ntvfs->ops->close(ntvfs, req, cl);
1180 req->async_states->state = state;
1184 case RAW_WRITE_SPLWRITE:
1187 case RAW_WRITE_SMB2:
1188 wr->smb2.out._pad = 0;
1189 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1190 wr->smb2.out.unknown1 = 0;
1194 return NT_STATUS_INVALID_LEVEL;
1202 NTVFS write generic to any mapper
1204 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1205 struct ntvfs_request *req,
1206 union smb_write *wr)
1208 union smb_write *wr2;
1211 wr2 = talloc(req, union smb_write);
1213 return NT_STATUS_NO_MEMORY;
1216 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1217 (second_stage_t)ntvfs_map_write_finish);
1218 if (!NT_STATUS_IS_OK(status)) {
1222 wr2->writex.level = RAW_WRITE_GENERIC;
1224 switch (wr->generic.level) {
1225 case RAW_WRITE_WRITEX:
1226 status = NT_STATUS_INVALID_LEVEL;
1229 case RAW_WRITE_WRITE:
1230 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1231 wr2->writex.in.offset = wr->write.in.offset;
1232 wr2->writex.in.wmode = 0;
1233 wr2->writex.in.remaining = wr->write.in.remaining;
1234 wr2->writex.in.count = wr->write.in.count;
1235 wr2->writex.in.data = wr->write.in.data;
1236 status = ntvfs->ops->write(ntvfs, req, wr2);
1239 case RAW_WRITE_WRITEUNLOCK:
1240 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1241 wr2->writex.in.offset = wr->writeunlock.in.offset;
1242 wr2->writex.in.wmode = 0;
1243 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1244 wr2->writex.in.count = wr->writeunlock.in.count;
1245 wr2->writex.in.data = wr->writeunlock.in.data;
1246 status = ntvfs->ops->write(ntvfs, req, wr2);
1249 case RAW_WRITE_WRITECLOSE:
1250 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1251 wr2->writex.in.offset = wr->writeclose.in.offset;
1252 wr2->writex.in.wmode = 0;
1253 wr2->writex.in.remaining = 0;
1254 wr2->writex.in.count = wr->writeclose.in.count;
1255 wr2->writex.in.data = wr->writeclose.in.data;
1256 status = ntvfs->ops->write(ntvfs, req, wr2);
1259 case RAW_WRITE_SPLWRITE:
1260 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1261 wr2->writex.in.offset = 0;
1262 wr2->writex.in.wmode = 0;
1263 wr2->writex.in.remaining = 0;
1264 wr2->writex.in.count = wr->splwrite.in.count;
1265 wr2->writex.in.data = wr->splwrite.in.data;
1266 status = ntvfs->ops->write(ntvfs, req, wr2);
1269 case RAW_WRITE_SMB2:
1270 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1271 wr2->writex.in.offset = wr->smb2.in.offset;
1272 wr2->writex.in.wmode = 0;
1273 wr2->writex.in.remaining = 0;
1274 wr2->writex.in.count = wr->smb2.in.data.length;
1275 wr2->writex.in.data = wr->smb2.in.data.data;
1276 status = ntvfs->ops->write(ntvfs, req, wr2);
1279 return ntvfs_map_async_finish(req, status);
1284 NTVFS read generic to any mapper - finish the out mapping
1286 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1287 struct ntvfs_request *req,
1289 union smb_read *rd2,
1292 switch (rd->generic.level) {
1294 rd->read.out.nread = rd2->generic.out.nread;
1296 case RAW_READ_READBRAW:
1297 rd->readbraw.out.nread = rd2->generic.out.nread;
1299 case RAW_READ_LOCKREAD:
1300 rd->lockread.out.nread = rd2->generic.out.nread;
1303 rd->smb2.out.data.length= rd2->generic.out.nread;
1304 rd->smb2.out.remaining = 0;
1305 rd->smb2.out.reserved = 0;
1308 return NT_STATUS_INVALID_LEVEL;
1315 NTVFS read* to readx mapper
1317 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1318 struct ntvfs_request *req,
1321 union smb_read *rd2;
1322 union smb_lock *lck;
1326 rd2 = talloc(req, union smb_read);
1328 return NT_STATUS_NO_MEMORY;
1331 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1332 (second_stage_t)ntvfs_map_read_finish);
1333 if (!NT_STATUS_IS_OK(status)) {
1337 rd2->readx.level = RAW_READ_READX;
1338 rd2->readx.in.read_for_execute = false;
1340 switch (rd->generic.level) {
1341 case RAW_READ_READX:
1342 status = NT_STATUS_INVALID_LEVEL;
1346 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1347 rd2->readx.in.offset = rd->read.in.offset;
1348 rd2->readx.in.mincnt = rd->read.in.count;
1349 rd2->readx.in.maxcnt = rd->read.in.count;
1350 rd2->readx.in.remaining = rd->read.in.remaining;
1351 rd2->readx.out.data = rd->read.out.data;
1352 status = ntvfs->ops->read(ntvfs, req, rd2);
1355 case RAW_READ_READBRAW:
1356 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1357 rd2->readx.in.offset = rd->readbraw.in.offset;
1358 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1359 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1360 rd2->readx.in.remaining = 0;
1361 rd2->readx.out.data = rd->readbraw.out.data;
1362 status = ntvfs->ops->read(ntvfs, req, rd2);
1365 case RAW_READ_LOCKREAD:
1366 /* do the initial lock sync for now */
1367 state = req->async_states->state;
1368 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1370 lck = talloc(rd2, union smb_lock);
1372 status = NT_STATUS_NO_MEMORY;
1375 lck->lock.level = RAW_LOCK_LOCK;
1376 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1377 lck->lock.in.count = rd->lockread.in.count;
1378 lck->lock.in.offset = rd->lockread.in.offset;
1379 status = ntvfs->ops->lock(ntvfs, req, lck);
1380 req->async_states->state = state;
1382 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1383 rd2->readx.in.offset = rd->lockread.in.offset;
1384 rd2->readx.in.mincnt = rd->lockread.in.count;
1385 rd2->readx.in.maxcnt = rd->lockread.in.count;
1386 rd2->readx.in.remaining = rd->lockread.in.remaining;
1387 rd2->readx.out.data = rd->lockread.out.data;
1389 if (NT_STATUS_IS_OK(status)) {
1390 status = ntvfs->ops->read(ntvfs, req, rd2);
1395 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1396 rd2->readx.in.offset = rd->smb2.in.offset;
1397 rd2->readx.in.mincnt = rd->smb2.in.min_count;
1398 rd2->readx.in.maxcnt = rd->smb2.in.length;
1399 rd2->readx.in.remaining = 0;
1400 rd2->readx.out.data = rd->smb2.out.data.data;
1401 status = ntvfs->ops->read(ntvfs, req, rd2);
1406 return ntvfs_map_async_finish(req, status);
1411 NTVFS close generic to any mapper
1413 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1414 struct ntvfs_request *req,
1415 union smb_close *cl,
1416 union smb_close *cl2,
1419 NT_STATUS_NOT_OK_RETURN(status);
1421 switch (cl->generic.level) {
1422 case RAW_CLOSE_SMB2:
1423 cl->smb2.out.flags = cl2->generic.out.flags;
1424 cl->smb2.out._pad = 0;
1425 cl->smb2.out.create_time = cl2->generic.out.create_time;
1426 cl->smb2.out.access_time = cl2->generic.out.access_time;
1427 cl->smb2.out.write_time = cl2->generic.out.write_time;
1428 cl->smb2.out.change_time = cl2->generic.out.change_time;
1429 cl->smb2.out.alloc_size = cl2->generic.out.alloc_size;
1430 cl->smb2.out.size = cl2->generic.out.size;
1431 cl->smb2.out.file_attr = cl2->generic.out.file_attr;
1441 NTVFS close generic to any mapper
1443 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1444 struct ntvfs_request *req,
1445 union smb_close *cl)
1447 union smb_close *cl2;
1450 cl2 = talloc(req, union smb_close);
1452 return NT_STATUS_NO_MEMORY;
1455 switch (cl->generic.level) {
1456 case RAW_CLOSE_GENERIC:
1457 return NT_STATUS_INVALID_LEVEL;
1459 case RAW_CLOSE_CLOSE:
1460 cl2->generic.level = RAW_CLOSE_GENERIC;
1461 cl2->generic.in.file = cl->close.in.file;
1462 cl2->generic.in.write_time = cl->close.in.write_time;
1463 cl2->generic.in.flags = 0;
1466 case RAW_CLOSE_SPLCLOSE:
1467 cl2->generic.level = RAW_CLOSE_GENERIC;
1468 cl2->generic.in.file = cl->splclose.in.file;
1469 cl2->generic.in.write_time = 0;
1470 cl2->generic.in.flags = 0;
1473 case RAW_CLOSE_SMB2:
1474 cl2->generic.level = RAW_CLOSE_GENERIC;
1475 cl2->generic.in.file = cl->smb2.in.file;
1476 cl2->generic.in.write_time = 0;
1477 cl2->generic.in.flags = cl->smb2.in.flags;
1481 status = ntvfs_map_async_setup(ntvfs, req, cl, cl2,
1482 (second_stage_t)ntvfs_map_close_finish);
1483 NT_STATUS_NOT_OK_RETURN(status);
1485 status = ntvfs->ops->close(ntvfs, req, cl2);
1487 return ntvfs_map_async_finish(req, status);
1491 NTVFS notify generic to any mapper
1493 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1494 struct ntvfs_request *req,
1495 union smb_notify *nt,
1496 union smb_notify *nt2,
1499 NT_STATUS_NOT_OK_RETURN(status);
1501 switch (nt->nttrans.level) {
1502 case RAW_NOTIFY_SMB2:
1503 if (nt2->nttrans.out.num_changes == 0) {
1504 return STATUS_NOTIFY_ENUM_DIR;
1506 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1507 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1511 return NT_STATUS_INVALID_LEVEL;
1519 NTVFS notify generic to any mapper
1521 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1522 struct ntvfs_request *req,
1523 union smb_notify *nt)
1525 union smb_notify *nt2;
1528 nt2 = talloc(req, union smb_notify);
1529 NT_STATUS_HAVE_NO_MEMORY(nt2);
1531 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1532 (second_stage_t)ntvfs_map_notify_finish);
1533 NT_STATUS_NOT_OK_RETURN(status);
1535 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1537 switch (nt->nttrans.level) {
1538 case RAW_NOTIFY_NTTRANS:
1539 status = NT_STATUS_INVALID_LEVEL;
1542 case RAW_NOTIFY_SMB2:
1543 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1544 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1545 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1546 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1547 status = ntvfs->ops->notify(ntvfs, req, nt2);
1551 return ntvfs_map_async_finish(req, status);