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 switch (io2->generic.out.oplock_level) {
212 case BATCH_OPLOCK_RETURN:
213 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
215 case EXCLUSIVE_OPLOCK_RETURN:
216 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
218 case LEVEL_II_OPLOCK_RETURN:
219 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
222 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
225 io->smb2.out.reserved = 0;
226 io->smb2.out.create_action = io2->generic.out.create_action;
227 io->smb2.out.create_time = io2->generic.out.create_time;
228 io->smb2.out.access_time = io2->generic.out.access_time;
229 io->smb2.out.write_time = io2->generic.out.write_time;
230 io->smb2.out.change_time = io2->generic.out.change_time;
231 io->smb2.out.alloc_size = io2->generic.out.alloc_size;
232 io->smb2.out.size = io2->generic.out.size;
233 io->smb2.out.file_attr = io2->generic.out.attrib;
234 io->smb2.out.reserved2 = 0;
235 io->smb2.out.blob = data_blob(NULL, 0);
239 return NT_STATUS_INVALID_LEVEL;
242 /* doing a secondary request async is more trouble than its
244 state = req->async_states->state;
245 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
247 if (write_time != 0) {
248 sf = talloc(req, union smb_setfileinfo);
249 NT_STATUS_HAVE_NO_MEMORY(sf);
250 sf->generic.level = RAW_SFILEINFO_STANDARD;
251 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
252 sf->standard.in.create_time = 0;
253 sf->standard.in.write_time = write_time;
254 sf->standard.in.access_time = 0;
255 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
259 sf = talloc(req, union smb_setfileinfo);
260 NT_STATUS_HAVE_NO_MEMORY(sf);
261 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
262 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
263 sf->end_of_file_info.in.size = set_size;
264 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
265 if (NT_STATUS_IS_OK(status)) {
266 io->openx.out.size = io->openx.in.size;
270 req->async_states->state = state;
276 the core of the mapping between openx style parameters and ntcreatex
279 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
280 uint16_t open_func, const char *fname,
283 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
284 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
286 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
287 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
290 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
291 case OPENX_MODE_ACCESS_READ:
292 case OPENX_MODE_ACCESS_EXEC:
293 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
295 case OPENX_MODE_ACCESS_WRITE:
296 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
298 case OPENX_MODE_ACCESS_RDWR:
299 case OPENX_MODE_ACCESS_FCB:
300 io2->generic.in.access_mask =
301 SEC_RIGHTS_FILE_READ |
302 SEC_RIGHTS_FILE_WRITE;
305 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
308 switch (open_mode & OPENX_MODE_DENY_MASK) {
309 case OPENX_MODE_DENY_READ:
310 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
312 case OPENX_MODE_DENY_WRITE:
313 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
315 case OPENX_MODE_DENY_ALL:
316 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
318 case OPENX_MODE_DENY_NONE:
319 io2->generic.in.share_access =
320 NTCREATEX_SHARE_ACCESS_READ |
321 NTCREATEX_SHARE_ACCESS_WRITE;
323 case OPENX_MODE_DENY_DOS:
324 /* DENY_DOS is quite strange - it depends on the filename! */
325 io2->generic.in.create_options |=
326 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
327 if (is_exe_filename(fname)) {
328 io2->generic.in.share_access =
329 NTCREATEX_SHARE_ACCESS_READ |
330 NTCREATEX_SHARE_ACCESS_WRITE;
332 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
333 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
335 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
339 case OPENX_MODE_DENY_FCB:
340 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
341 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
344 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
348 case (OPENX_OPEN_FUNC_OPEN):
349 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
351 case (OPENX_OPEN_FUNC_TRUNC):
352 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
354 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
355 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
357 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
358 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
360 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
361 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
364 /* this one is very strange */
365 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
366 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
369 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
376 NTVFS open generic to any mapper
378 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
379 struct ntvfs_request *req,
385 io2 = talloc_zero(req, union smb_open);
387 return NT_STATUS_NO_MEMORY;
390 status = ntvfs_map_async_setup(ntvfs, req,
392 (second_stage_t)ntvfs_map_open_finish);
393 if (!NT_STATUS_IS_OK(status)) {
397 io2->generic.level = RAW_OPEN_GENERIC;
399 switch (io->generic.level) {
401 status = map_openx_open(io->openx.in.flags,
402 io->openx.in.open_mode,
403 io->openx.in.open_func,
406 if (!NT_STATUS_IS_OK(status)) {
410 io2->generic.in.file_attr = io->openx.in.file_attrs;
411 io2->generic.in.fname = io->openx.in.fname;
413 status = ntvfs->ops->open(ntvfs, req, io2);
418 status = map_openx_open(0,
419 io->openold.in.open_mode,
420 OPENX_OPEN_FUNC_OPEN,
421 io->openold.in.fname,
423 if (!NT_STATUS_IS_OK(status)) {
427 io2->generic.in.file_attr = io->openold.in.search_attrs;
428 io2->generic.in.fname = io->openold.in.fname;
430 status = ntvfs->ops->open(ntvfs, req, io2);
433 case RAW_OPEN_T2OPEN:
434 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
436 if (io->t2open.in.open_func == 0) {
437 status = NT_STATUS_OBJECT_NAME_COLLISION;
441 status = map_openx_open(io->t2open.in.flags,
442 io->t2open.in.open_mode,
443 io->t2open.in.open_func,
446 if (!NT_STATUS_IS_OK(status)) {
450 io2->generic.in.file_attr = io->t2open.in.file_attrs;
451 io2->generic.in.fname = io->t2open.in.fname;
452 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
453 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
454 io2->generic.in.ea_list->eas = io->t2open.in.eas;
456 status = ntvfs->ops->open(ntvfs, req, io2);
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_CREATE;
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);
472 case RAW_OPEN_CREATE:
473 io2->generic.in.file_attr = io->mknew.in.attrib;
474 io2->generic.in.fname = io->mknew.in.fname;
475 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
476 io2->generic.in.access_mask =
477 SEC_RIGHTS_FILE_READ |
478 SEC_RIGHTS_FILE_WRITE;
479 io2->generic.in.share_access =
480 NTCREATEX_SHARE_ACCESS_READ |
481 NTCREATEX_SHARE_ACCESS_WRITE;
482 status = ntvfs->ops->open(ntvfs, req, io2);
486 io2->generic.in.file_attr = io->ctemp.in.attrib;
487 io2->generic.in.fname =
488 talloc_asprintf(io2, "%s\\SRV%s",
489 io->ctemp.in.directory,
490 generate_random_str_list(io2, 5, "0123456789"));
491 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
492 io2->generic.in.access_mask =
493 SEC_RIGHTS_FILE_READ |
494 SEC_RIGHTS_FILE_WRITE;
495 io2->generic.in.share_access =
496 NTCREATEX_SHARE_ACCESS_READ |
497 NTCREATEX_SHARE_ACCESS_WRITE;
498 status = ntvfs->ops->open(ntvfs, req, io2);
501 switch (io->smb2.in.oplock_level) {
502 case SMB2_OPLOCK_LEVEL_BATCH:
503 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
504 NTCREATEX_FLAGS_REQUEST_OPLOCK;
506 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
507 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
510 io2->generic.in.flags = 0;
513 io2->generic.in.root_fid = 0;
514 io2->generic.in.access_mask = io->smb2.in.desired_access;
515 io2->generic.in.alloc_size = 0;
516 io2->generic.in.file_attr = io->smb2.in.file_attributes;
517 io2->generic.in.share_access = io->smb2.in.share_access;
518 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
519 io2->generic.in.create_options = io->smb2.in.create_options;
520 io2->generic.in.impersonation = io->smb2.in.impersonation_level;
521 io2->generic.in.security_flags = 0;
522 io2->generic.in.fname = io->smb2.in.fname;
523 io2->generic.in.sec_desc = NULL;
524 io2->generic.in.ea_list = NULL;
526 /* we need to check these bits before we check the private mask */
527 if (io2->generic.in.create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
528 status = NT_STATUS_NOT_SUPPORTED;
532 /* we use a couple of bits of the create options internally */
533 if (io2->generic.in.create_options & NTCREATEX_OPTIONS_PRIVATE_MASK) {
534 status = NT_STATUS_INVALID_PARAMETER;
538 status = ntvfs->ops->open(ntvfs, req, io2);
542 status = NT_STATUS_INVALID_LEVEL;
546 return ntvfs_map_async_finish(req, status);
551 NTVFS fsinfo generic to any mapper
553 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
554 struct ntvfs_request *req,
555 union smb_fsinfo *fs)
558 union smb_fsinfo *fs2;
560 fs2 = talloc(req, union smb_fsinfo);
562 return NT_STATUS_NO_MEMORY;
565 if (fs->generic.level == RAW_QFS_GENERIC) {
566 return NT_STATUS_INVALID_LEVEL;
569 /* only used by the simple backend, which doesn't do async */
570 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
572 /* ask the backend for the generic info */
573 fs2->generic.level = RAW_QFS_GENERIC;
575 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
576 if (!NT_STATUS_IS_OK(status)) {
580 /* and convert it to the required level */
581 switch (fs->generic.level) {
582 case RAW_QFS_GENERIC:
583 return NT_STATUS_INVALID_LEVEL;
585 case RAW_QFS_DSKATTR: {
586 /* map from generic to DSKATTR */
589 /* we need to scale the sizes to fit */
590 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
591 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
596 fs->dskattr.out.blocks_per_unit = bpunit;
597 fs->dskattr.out.block_size = 512;
598 fs->dskattr.out.units_total =
599 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
600 fs->dskattr.out.units_free =
601 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
603 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
604 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
605 fs->dskattr.out.blocks_per_unit = 64;
606 fs->dskattr.out.units_total = 0xFFFF;
607 fs->dskattr.out.units_free = 0xFFFF;
612 case RAW_QFS_ALLOCATION:
613 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
614 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
615 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
616 fs->allocation.out.sectors_per_unit = 1;
617 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
621 fs->volume.out.serial_number = fs2->generic.out.serial_number;
622 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
625 case RAW_QFS_VOLUME_INFO:
626 case RAW_QFS_VOLUME_INFORMATION:
627 fs->volume_info.out.create_time = fs2->generic.out.create_time;
628 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
629 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
632 case RAW_QFS_SIZE_INFO:
633 case RAW_QFS_SIZE_INFORMATION:
634 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
635 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
636 fs->size_info.out.sectors_per_unit = 1;
637 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
640 case RAW_QFS_DEVICE_INFO:
641 case RAW_QFS_DEVICE_INFORMATION:
642 fs->device_info.out.device_type = fs2->generic.out.device_type;
643 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
646 case RAW_QFS_ATTRIBUTE_INFO:
647 case RAW_QFS_ATTRIBUTE_INFORMATION:
648 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
649 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
650 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
653 case RAW_QFS_QUOTA_INFORMATION:
654 ZERO_STRUCT(fs->quota_information.out.unknown);
655 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
656 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
657 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
660 case RAW_QFS_FULL_SIZE_INFORMATION:
661 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
662 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
663 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
664 fs->full_size_information.out.sectors_per_unit = 1;
665 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
668 case RAW_QFS_OBJECTID_INFORMATION:
669 fs->objectid_information.out.guid = fs2->generic.out.guid;
670 ZERO_STRUCT(fs->objectid_information.out.unknown);
675 return NT_STATUS_INVALID_LEVEL;
680 NTVFS fileinfo generic to any mapper
682 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
683 union smb_fileinfo *info,
684 union smb_fileinfo *info2)
687 /* and convert it to the required level using results in info2 */
688 switch (info->generic.level) {
689 case RAW_FILEINFO_GENERIC:
690 return NT_STATUS_INVALID_LEVEL;
691 case RAW_FILEINFO_GETATTR:
692 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
693 info->getattr.out.size = info2->generic.out.size;
694 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
697 case RAW_FILEINFO_GETATTRE:
698 info->getattre.out.attrib = info2->generic.out.attrib;
699 info->getattre.out.size = info2->generic.out.size;
700 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
701 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
702 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
703 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
706 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
707 info->network_open_information.out.create_time = info2->generic.out.create_time;
708 info->network_open_information.out.access_time = info2->generic.out.access_time;
709 info->network_open_information.out.write_time = info2->generic.out.write_time;
710 info->network_open_information.out.change_time = info2->generic.out.change_time;
711 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
712 info->network_open_information.out.size = info2->generic.out.size;
713 info->network_open_information.out.attrib = info2->generic.out.attrib;
716 case RAW_FILEINFO_ALL_INFO:
717 case RAW_FILEINFO_ALL_INFORMATION:
718 info->all_info.out.create_time = info2->generic.out.create_time;
719 info->all_info.out.access_time = info2->generic.out.access_time;
720 info->all_info.out.write_time = info2->generic.out.write_time;
721 info->all_info.out.change_time = info2->generic.out.change_time;
722 info->all_info.out.attrib = info2->generic.out.attrib;
723 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
724 info->all_info.out.size = info2->generic.out.size;
725 info->all_info.out.nlink = info2->generic.out.nlink;
726 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
727 info->all_info.out.directory = info2->generic.out.directory;
728 info->all_info.out.ea_size = info2->generic.out.ea_size;
729 info->all_info.out.fname.s = info2->generic.out.fname.s;
730 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
733 case RAW_FILEINFO_BASIC_INFO:
734 case RAW_FILEINFO_BASIC_INFORMATION:
735 info->basic_info.out.create_time = info2->generic.out.create_time;
736 info->basic_info.out.access_time = info2->generic.out.access_time;
737 info->basic_info.out.write_time = info2->generic.out.write_time;
738 info->basic_info.out.change_time = info2->generic.out.change_time;
739 info->basic_info.out.attrib = info2->generic.out.attrib;
742 case RAW_FILEINFO_STANDARD:
743 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
744 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
745 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
746 info->standard.out.size = info2->generic.out.size;
747 info->standard.out.alloc_size = info2->generic.out.alloc_size;
748 info->standard.out.attrib = info2->generic.out.attrib;
751 case RAW_FILEINFO_EA_SIZE:
752 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
753 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
754 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
755 info->ea_size.out.size = info2->generic.out.size;
756 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
757 info->ea_size.out.attrib = info2->generic.out.attrib;
758 info->ea_size.out.ea_size = info2->generic.out.ea_size;
761 case RAW_FILEINFO_STANDARD_INFO:
762 case RAW_FILEINFO_STANDARD_INFORMATION:
763 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
764 info->standard_info.out.size = info2->generic.out.size;
765 info->standard_info.out.nlink = info2->generic.out.nlink;
766 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
767 info->standard_info.out.directory = info2->generic.out.directory;
770 case RAW_FILEINFO_INTERNAL_INFORMATION:
771 info->internal_information.out.file_id = info2->generic.out.file_id;
774 case RAW_FILEINFO_EA_INFO:
775 case RAW_FILEINFO_EA_INFORMATION:
776 info->ea_info.out.ea_size = info2->generic.out.ea_size;
779 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
780 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
781 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
784 case RAW_FILEINFO_STREAM_INFO:
785 case RAW_FILEINFO_STREAM_INFORMATION:
786 info->stream_info.out.num_streams = info2->generic.out.num_streams;
787 if (info->stream_info.out.num_streams > 0) {
788 info->stream_info.out.streams =
789 talloc_array(mem_ctx,
790 struct stream_struct,
791 info->stream_info.out.num_streams);
792 if (!info->stream_info.out.streams) {
793 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
794 info->stream_info.out.num_streams));
795 return NT_STATUS_NO_MEMORY;
797 for (i=0; i < info->stream_info.out.num_streams; i++) {
798 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
799 info->stream_info.out.streams[i].stream_name.s =
800 talloc_strdup(info->stream_info.out.streams,
801 info2->generic.out.streams[i].stream_name.s);
802 if (!info->stream_info.out.streams[i].stream_name.s) {
803 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
804 return NT_STATUS_NO_MEMORY;
810 case RAW_FILEINFO_NAME_INFO:
811 case RAW_FILEINFO_NAME_INFORMATION:
812 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
813 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
814 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
817 case RAW_FILEINFO_ALT_NAME_INFO:
818 case RAW_FILEINFO_ALT_NAME_INFORMATION:
819 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
820 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
821 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
824 case RAW_FILEINFO_POSITION_INFORMATION:
825 info->position_information.out.position = info2->generic.out.position;
828 case RAW_FILEINFO_ALL_EAS:
829 info->all_eas.out.num_eas = info2->generic.out.num_eas;
830 if (info->all_eas.out.num_eas > 0) {
831 info->all_eas.out.eas = talloc_array(mem_ctx,
833 info->all_eas.out.num_eas);
834 if (!info->all_eas.out.eas) {
835 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
836 info->all_eas.out.num_eas));
837 return NT_STATUS_NO_MEMORY;
839 for (i = 0; i < info->all_eas.out.num_eas; i++) {
840 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
841 info->all_eas.out.eas[i].name.s =
842 talloc_strdup(info->all_eas.out.eas,
843 info2->generic.out.eas[i].name.s);
844 if (!info->all_eas.out.eas[i].name.s) {
845 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
846 return NT_STATUS_NO_MEMORY;
848 info->all_eas.out.eas[i].value.data =
849 talloc_memdup(info->all_eas.out.eas,
850 info2->generic.out.eas[i].value.data,
851 info2->generic.out.eas[i].value.length);
852 if (!info->all_eas.out.eas[i].value.data) {
853 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
854 return NT_STATUS_NO_MEMORY;
860 case RAW_FILEINFO_IS_NAME_VALID:
863 case RAW_FILEINFO_COMPRESSION_INFO:
864 case RAW_FILEINFO_COMPRESSION_INFORMATION:
865 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
866 info->compression_info.out.format = info2->generic.out.format;
867 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
868 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
869 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
872 case RAW_FILEINFO_ACCESS_INFORMATION:
873 info->access_information.out.access_flags = info2->generic.out.access_flags;
876 case RAW_FILEINFO_MODE_INFORMATION:
877 info->mode_information.out.mode = info2->generic.out.mode;
880 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
881 info->alignment_information.out.alignment_requirement =
882 info2->generic.out.alignment_requirement;
885 case RAW_FILEINFO_UNIX_BASIC:
886 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
887 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
888 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
889 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
890 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
891 info->unix_basic_info.out.uid = info2->generic.out.uid;
892 info->unix_basic_info.out.gid = info2->generic.out.gid;
893 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
894 info->unix_basic_info.out.dev_major = info2->generic.out.device;
895 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
896 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
897 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
898 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
901 case RAW_FILEINFO_UNIX_LINK:
902 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
907 return NT_STATUS_INVALID_LEVEL;
911 NTVFS fileinfo generic to any mapper
913 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
914 struct ntvfs_request *req,
915 union smb_fileinfo *info)
918 union smb_fileinfo *info2;
920 info2 = talloc(req, union smb_fileinfo);
922 return NT_STATUS_NO_MEMORY;
925 if (info->generic.level == RAW_FILEINFO_GENERIC) {
926 return NT_STATUS_INVALID_LEVEL;
929 /* ask the backend for the generic info */
930 info2->generic.level = RAW_FILEINFO_GENERIC;
931 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
933 /* only used by the simple backend, which doesn't do async */
934 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
936 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
937 if (!NT_STATUS_IS_OK(status)) {
940 return ntvfs_map_fileinfo(req, info, info2);
944 NTVFS pathinfo generic to any mapper
946 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
947 struct ntvfs_request *req,
948 union smb_fileinfo *info)
951 union smb_fileinfo *info2;
953 info2 = talloc(req, union smb_fileinfo);
955 return NT_STATUS_NO_MEMORY;
958 if (info->generic.level == RAW_FILEINFO_GENERIC) {
959 return NT_STATUS_INVALID_LEVEL;
962 /* ask the backend for the generic info */
963 info2->generic.level = RAW_FILEINFO_GENERIC;
964 info2->generic.in.file.path = info->generic.in.file.path;
966 /* only used by the simple backend, which doesn't do async */
967 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
969 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
970 if (!NT_STATUS_IS_OK(status)) {
973 return ntvfs_map_fileinfo(req, info, info2);
978 NTVFS lock generic to any mapper
980 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
981 struct ntvfs_request *req,
984 union smb_lock *lck2;
985 struct smb_lock_entry *locks;
987 lck2 = talloc(req, union smb_lock);
989 return NT_STATUS_NO_MEMORY;
992 locks = talloc_array(lck2, struct smb_lock_entry, 1);
994 return NT_STATUS_NO_MEMORY;
997 switch (lck->generic.level) {
999 return NT_STATUS_INVALID_LEVEL;
1002 lck2->generic.level = RAW_LOCK_GENERIC;
1003 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1004 lck2->generic.in.mode = 0;
1005 lck2->generic.in.timeout = 0;
1006 lck2->generic.in.ulock_cnt = 0;
1007 lck2->generic.in.lock_cnt = 1;
1008 lck2->generic.in.locks = locks;
1009 locks->pid = req->smbpid;
1010 locks->offset = lck->lock.in.offset;
1011 locks->count = lck->lock.in.count;
1014 case RAW_LOCK_UNLOCK:
1015 lck2->generic.level = RAW_LOCK_GENERIC;
1016 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1017 lck2->generic.in.mode = 0;
1018 lck2->generic.in.timeout = 0;
1019 lck2->generic.in.ulock_cnt = 1;
1020 lck2->generic.in.lock_cnt = 0;
1021 lck2->generic.in.locks = locks;
1022 locks->pid = req->smbpid;
1023 locks->offset = lck->unlock.in.offset;
1024 locks->count = lck->unlock.in.count;
1027 case RAW_LOCK_SMB2: {
1028 /* this is only approximate! We need to change the
1029 generic structure to fix this properly */
1031 if (lck->smb2.in.lock_count < 1) {
1032 return NT_STATUS_INVALID_PARAMETER;
1035 lck2->generic.level = RAW_LOCK_GENERIC;
1036 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1037 lck2->generic.in.timeout = UINT32_MAX;
1038 lck2->generic.in.mode = 0;
1039 lck2->generic.in.lock_cnt = 0;
1040 lck2->generic.in.ulock_cnt = 0;
1041 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry,
1042 lck->smb2.in.lock_count);
1043 if (lck2->generic.in.locks == NULL) {
1044 return NT_STATUS_NO_MEMORY;
1046 for (i=0;i<lck->smb2.in.lock_count;i++) {
1047 if (lck->smb2.in.locks[i].flags & ~SMB2_LOCK_FLAG_ALL_MASK) {
1048 return NT_STATUS_INVALID_PARAMETER;
1050 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK) {
1051 int j = lck2->generic.in.ulock_cnt;
1052 lck2->generic.in.ulock_cnt++;
1053 lck2->generic.in.locks[j].pid = 0;
1054 lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1055 lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1056 lck2->generic.in.locks[j].pid = 0;
1059 for (i=0;i<lck->smb2.in.lock_count;i++) {
1060 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1061 int j = lck2->generic.in.ulock_cnt +
1062 lck2->generic.in.lock_cnt;
1063 lck2->generic.in.lock_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;
1068 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1069 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1071 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1072 lck2->generic.in.timeout = 0;
1076 /* initialize output value */
1077 lck->smb2.out.reserved = 0;
1081 case RAW_LOCK_SMB2_BREAK:
1082 lck2->generic.level = RAW_LOCK_GENERIC;
1083 lck2->generic.in.file.ntvfs = lck->smb2_break.in.file.ntvfs;
1084 lck2->generic.in.mode = LOCKING_ANDX_OPLOCK_RELEASE |
1085 ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1086 lck2->generic.in.timeout = 0;
1087 lck2->generic.in.ulock_cnt = 0;
1088 lck2->generic.in.lock_cnt = 0;
1089 lck2->generic.in.locks = NULL;
1091 /* initialize output value */
1092 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1093 lck->smb2_break.out.reserved = lck->smb2_break.in.reserved;
1094 lck->smb2_break.out.reserved2 = lck->smb2_break.in.reserved2;
1095 lck->smb2_break.out.file = lck->smb2_break.in.file;
1100 * we don't need to call ntvfs_map_async_setup() here,
1101 * as lock() doesn't have any output fields
1104 return ntvfs->ops->lock(ntvfs, req, lck2);
1109 NTVFS write generic to any mapper
1111 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1112 struct ntvfs_request *req,
1113 union smb_write *wr,
1114 union smb_write *wr2,
1117 union smb_lock *lck;
1118 union smb_close *cl;
1121 if (NT_STATUS_IS_ERR(status)) {
1125 switch (wr->generic.level) {
1126 case RAW_WRITE_WRITE:
1127 wr->write.out.nwritten = wr2->generic.out.nwritten;
1130 case RAW_WRITE_WRITEUNLOCK:
1131 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1133 lck = talloc(wr2, union smb_lock);
1135 return NT_STATUS_NO_MEMORY;
1138 lck->unlock.level = RAW_LOCK_UNLOCK;
1139 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1140 lck->unlock.in.count = wr->writeunlock.in.count;
1141 lck->unlock.in.offset = wr->writeunlock.in.offset;
1143 if (lck->unlock.in.count != 0) {
1144 /* do the lock sync for now */
1145 state = req->async_states->state;
1146 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1147 status = ntvfs->ops->lock(ntvfs, req, lck);
1148 req->async_states->state = state;
1152 case RAW_WRITE_WRITECLOSE:
1153 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1155 cl = talloc(wr2, union smb_close);
1157 return NT_STATUS_NO_MEMORY;
1160 cl->close.level = RAW_CLOSE_CLOSE;
1161 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1162 cl->close.in.write_time = wr->writeclose.in.mtime;
1164 if (wr2->generic.in.count != 0) {
1165 /* do the close sync for now */
1166 state = req->async_states->state;
1167 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1168 status = ntvfs->ops->close(ntvfs, req, cl);
1169 req->async_states->state = state;
1173 case RAW_WRITE_SPLWRITE:
1176 case RAW_WRITE_SMB2:
1177 wr->smb2.out._pad = 0;
1178 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1179 wr->smb2.out.unknown1 = 0;
1183 return NT_STATUS_INVALID_LEVEL;
1191 NTVFS write generic to any mapper
1193 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1194 struct ntvfs_request *req,
1195 union smb_write *wr)
1197 union smb_write *wr2;
1200 wr2 = talloc(req, union smb_write);
1202 return NT_STATUS_NO_MEMORY;
1205 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1206 (second_stage_t)ntvfs_map_write_finish);
1207 if (!NT_STATUS_IS_OK(status)) {
1211 wr2->writex.level = RAW_WRITE_GENERIC;
1213 switch (wr->generic.level) {
1214 case RAW_WRITE_WRITEX:
1215 status = NT_STATUS_INVALID_LEVEL;
1218 case RAW_WRITE_WRITE:
1219 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1220 wr2->writex.in.offset = wr->write.in.offset;
1221 wr2->writex.in.wmode = 0;
1222 wr2->writex.in.remaining = wr->write.in.remaining;
1223 wr2->writex.in.count = wr->write.in.count;
1224 wr2->writex.in.data = wr->write.in.data;
1225 status = ntvfs->ops->write(ntvfs, req, wr2);
1228 case RAW_WRITE_WRITEUNLOCK:
1229 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1230 wr2->writex.in.offset = wr->writeunlock.in.offset;
1231 wr2->writex.in.wmode = 0;
1232 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1233 wr2->writex.in.count = wr->writeunlock.in.count;
1234 wr2->writex.in.data = wr->writeunlock.in.data;
1235 status = ntvfs->ops->write(ntvfs, req, wr2);
1238 case RAW_WRITE_WRITECLOSE:
1239 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1240 wr2->writex.in.offset = wr->writeclose.in.offset;
1241 wr2->writex.in.wmode = 0;
1242 wr2->writex.in.remaining = 0;
1243 wr2->writex.in.count = wr->writeclose.in.count;
1244 wr2->writex.in.data = wr->writeclose.in.data;
1245 status = ntvfs->ops->write(ntvfs, req, wr2);
1248 case RAW_WRITE_SPLWRITE:
1249 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1250 wr2->writex.in.offset = 0;
1251 wr2->writex.in.wmode = 0;
1252 wr2->writex.in.remaining = 0;
1253 wr2->writex.in.count = wr->splwrite.in.count;
1254 wr2->writex.in.data = wr->splwrite.in.data;
1255 status = ntvfs->ops->write(ntvfs, req, wr2);
1258 case RAW_WRITE_SMB2:
1259 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1260 wr2->writex.in.offset = wr->smb2.in.offset;
1261 wr2->writex.in.wmode = 0;
1262 wr2->writex.in.remaining = 0;
1263 wr2->writex.in.count = wr->smb2.in.data.length;
1264 wr2->writex.in.data = wr->smb2.in.data.data;
1265 status = ntvfs->ops->write(ntvfs, req, wr2);
1268 return ntvfs_map_async_finish(req, status);
1273 NTVFS read generic to any mapper - finish the out mapping
1275 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1276 struct ntvfs_request *req,
1278 union smb_read *rd2,
1281 switch (rd->generic.level) {
1283 rd->read.out.nread = rd2->generic.out.nread;
1285 case RAW_READ_READBRAW:
1286 rd->readbraw.out.nread = rd2->generic.out.nread;
1288 case RAW_READ_LOCKREAD:
1289 rd->lockread.out.nread = rd2->generic.out.nread;
1292 rd->smb2.out.data.length= rd2->generic.out.nread;
1293 rd->smb2.out.remaining = 0;
1294 rd->smb2.out.reserved = 0;
1295 if (NT_STATUS_IS_OK(status) &&
1296 rd->smb2.out.data.length == 0) {
1297 status = NT_STATUS_END_OF_FILE;
1299 /* SMB2 does honor the min_count field, SMB does not */
1300 if (NT_STATUS_IS_OK(status) &&
1301 rd->smb2.in.min_count > rd->smb2.out.data.length) {
1302 rd->smb2.out.data.length = 0;
1303 status = NT_STATUS_END_OF_FILE;
1307 return NT_STATUS_INVALID_LEVEL;
1314 NTVFS read* to readx mapper
1316 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1317 struct ntvfs_request *req,
1320 union smb_read *rd2;
1321 union smb_lock *lck;
1325 rd2 = talloc(req, union smb_read);
1327 return NT_STATUS_NO_MEMORY;
1330 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1331 (second_stage_t)ntvfs_map_read_finish);
1332 if (!NT_STATUS_IS_OK(status)) {
1336 rd2->readx.level = RAW_READ_READX;
1337 rd2->readx.in.read_for_execute = false;
1339 switch (rd->generic.level) {
1340 case RAW_READ_READX:
1341 status = NT_STATUS_INVALID_LEVEL;
1345 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1346 rd2->readx.in.offset = rd->read.in.offset;
1347 rd2->readx.in.mincnt = rd->read.in.count;
1348 rd2->readx.in.maxcnt = rd->read.in.count;
1349 rd2->readx.in.remaining = rd->read.in.remaining;
1350 rd2->readx.out.data = rd->read.out.data;
1351 status = ntvfs->ops->read(ntvfs, req, rd2);
1354 case RAW_READ_READBRAW:
1355 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1356 rd2->readx.in.offset = rd->readbraw.in.offset;
1357 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1358 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1359 rd2->readx.in.remaining = 0;
1360 rd2->readx.out.data = rd->readbraw.out.data;
1361 status = ntvfs->ops->read(ntvfs, req, rd2);
1364 case RAW_READ_LOCKREAD:
1365 /* do the initial lock sync for now */
1366 state = req->async_states->state;
1367 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1369 lck = talloc(rd2, union smb_lock);
1371 status = NT_STATUS_NO_MEMORY;
1374 lck->lock.level = RAW_LOCK_LOCK;
1375 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1376 lck->lock.in.count = rd->lockread.in.count;
1377 lck->lock.in.offset = rd->lockread.in.offset;
1378 status = ntvfs->ops->lock(ntvfs, req, lck);
1379 req->async_states->state = state;
1381 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1382 rd2->readx.in.offset = rd->lockread.in.offset;
1383 rd2->readx.in.mincnt = rd->lockread.in.count;
1384 rd2->readx.in.maxcnt = rd->lockread.in.count;
1385 rd2->readx.in.remaining = rd->lockread.in.remaining;
1386 rd2->readx.out.data = rd->lockread.out.data;
1388 if (NT_STATUS_IS_OK(status)) {
1389 status = ntvfs->ops->read(ntvfs, req, rd2);
1394 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1395 rd2->readx.in.offset = rd->smb2.in.offset;
1396 rd2->readx.in.mincnt = rd->smb2.in.length;
1397 rd2->readx.in.maxcnt = rd->smb2.in.length;
1398 rd2->readx.in.remaining = 0;
1399 rd2->readx.out.data = rd->smb2.out.data.data;
1400 status = ntvfs->ops->read(ntvfs, req, rd2);
1405 return ntvfs_map_async_finish(req, status);
1410 NTVFS close generic to any mapper
1412 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1413 struct ntvfs_request *req,
1414 union smb_close *cl)
1416 union smb_close *cl2;
1418 cl2 = talloc(req, union smb_close);
1420 return NT_STATUS_NO_MEMORY;
1423 switch (cl->generic.level) {
1424 case RAW_CLOSE_CLOSE:
1425 return NT_STATUS_INVALID_LEVEL;
1427 case RAW_CLOSE_SPLCLOSE:
1428 cl2->generic.level = RAW_CLOSE_CLOSE;
1429 cl2->generic.in.file.ntvfs = cl->splclose.in.file.ntvfs;
1430 cl2->generic.in.write_time = 0;
1433 case RAW_CLOSE_SMB2:
1434 cl2->generic.level = RAW_CLOSE_CLOSE;
1435 cl2->generic.in.file.ntvfs = cl->smb2.in.file.ntvfs;
1436 cl2->generic.in.write_time = 0;
1437 /* SMB2 Close has output parameter, but we just zero them */
1438 ZERO_STRUCT(cl->smb2.out);
1443 * we don't need to call ntvfs_map_async_setup() here,
1444 * as close() doesn't have any output fields
1447 return ntvfs->ops->close(ntvfs, req, cl2);
1451 NTVFS notify generic to any mapper
1453 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1454 struct ntvfs_request *req,
1455 union smb_notify *nt,
1456 union smb_notify *nt2,
1459 NT_STATUS_NOT_OK_RETURN(status);
1461 switch (nt->nttrans.level) {
1462 case RAW_NOTIFY_SMB2:
1463 if (nt2->nttrans.out.num_changes == 0) {
1464 return STATUS_NOTIFY_ENUM_DIR;
1466 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1467 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1471 return NT_STATUS_INVALID_LEVEL;
1479 NTVFS notify generic to any mapper
1481 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1482 struct ntvfs_request *req,
1483 union smb_notify *nt)
1485 union smb_notify *nt2;
1488 nt2 = talloc(req, union smb_notify);
1489 NT_STATUS_HAVE_NO_MEMORY(nt2);
1491 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1492 (second_stage_t)ntvfs_map_notify_finish);
1493 NT_STATUS_NOT_OK_RETURN(status);
1495 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1497 switch (nt->nttrans.level) {
1498 case RAW_NOTIFY_NTTRANS:
1499 status = NT_STATUS_INVALID_LEVEL;
1502 case RAW_NOTIFY_SMB2:
1503 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1504 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1505 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1506 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1507 status = ntvfs->ops->notify(ntvfs, req, nt2);
1511 return ntvfs_map_async_finish(req, status);