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 = talloc_get_type(req->async_states->private_data,
60 struct ntvfs_map_async);
62 ntvfs_async_state_pop(req);
64 /* call the _finish function setup in ntvfs_map_async_setup() */
65 req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
67 /* call the send function from the next module up */
68 req->async_states->send_fn(req);
72 prepare for calling a ntvfs backend with async support
73 io is the original call structure
74 io2 is the new call structure for the mapped call
75 fn is a second stage function for processing the out arguments
77 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
78 struct ntvfs_request *req,
82 struct ntvfs_map_async *m;
83 m = talloc(req, struct ntvfs_map_async);
85 return NT_STATUS_NO_MEMORY;
91 return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
95 called when first stage processing is complete.
97 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
99 struct ntvfs_map_async *m;
101 /* if the backend has decided to reply in an async fashion then
102 we don't need to do any work here */
103 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
107 /* the backend is replying immediately. call the 2nd stage function after popping our local
109 m = talloc_get_type(req->async_states->private_data,
110 struct ntvfs_map_async);
112 ntvfs_async_state_pop(req);
114 return m->fn(m->ntvfs, req, m->io, m->io2, status);
118 see if a filename ends in EXE COM DLL or SYM. This is needed for the
119 DENY_DOS mapping for OpenX
121 bool is_exe_filename(const char *fname)
124 p = strrchr(fname, '.');
129 if (strcasecmp(p, "EXE") == 0 ||
130 strcasecmp(p, "COM") == 0 ||
131 strcasecmp(p, "DLL") == 0 ||
132 strcasecmp(p, "SYM") == 0) {
140 NTVFS openx to ntcreatex mapper
142 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
143 struct ntvfs_request *req,
148 time_t write_time = 0;
149 uint32_t set_size = 0;
150 union smb_setfileinfo *sf;
153 if (!NT_STATUS_IS_OK(status)) {
157 switch (io->generic.level) {
159 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
160 io->openold.out.attrib = io2->generic.out.attrib;
161 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
162 io->openold.out.size = io2->generic.out.size;
163 io->openold.out.rmode = io->openold.in.open_mode;
167 io->openx.out.file.ntvfs = io2->generic.out.file.ntvfs;
168 io->openx.out.attrib = io2->generic.out.attrib;
169 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
170 io->openx.out.size = io2->generic.out.size;
171 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
172 io->openx.out.ftype = 0;
173 io->openx.out.devstate = 0;
174 io->openx.out.action = io2->generic.out.create_action;
175 io->openx.out.unique_fid = 0;
176 io->openx.out.access_mask = SEC_STD_ALL;
177 io->openx.out.unknown = 0;
179 /* we need to extend the file to the requested size if
180 it was newly created */
181 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
182 set_size = io->openx.in.size;
186 case RAW_OPEN_T2OPEN:
187 io->t2open.out.file.ntvfs = io2->generic.out.file.ntvfs;
188 io->t2open.out.attrib = io2->generic.out.attrib;
189 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
190 io->t2open.out.size = io2->generic.out.size;
191 io->t2open.out.access = io->t2open.in.open_mode;
192 io->t2open.out.ftype = 0;
193 io->t2open.out.devstate = 0;
194 io->t2open.out.action = io2->generic.out.create_action;
195 io->t2open.out.file_id = 0;
199 case RAW_OPEN_CREATE:
200 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
201 write_time = io->mknew.in.write_time;
205 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
206 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
207 strlen(io->ctemp.in.directory) + 1);
208 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
212 ZERO_STRUCT(io->smb2.out);
213 io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs;
214 switch (io2->generic.out.oplock_level) {
215 case BATCH_OPLOCK_RETURN:
216 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
218 case EXCLUSIVE_OPLOCK_RETURN:
219 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
221 case LEVEL_II_OPLOCK_RETURN:
222 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
225 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
228 io->smb2.out.reserved = 0;
229 io->smb2.out.create_action = io2->generic.out.create_action;
230 io->smb2.out.create_time = io2->generic.out.create_time;
231 io->smb2.out.access_time = io2->generic.out.access_time;
232 io->smb2.out.write_time = io2->generic.out.write_time;
233 io->smb2.out.change_time = io2->generic.out.change_time;
234 io->smb2.out.alloc_size = io2->generic.out.alloc_size;
235 io->smb2.out.size = io2->generic.out.size;
236 io->smb2.out.file_attr = io2->generic.out.attrib;
237 io->smb2.out.reserved2 = 0;
238 io->smb2.out.maximal_access = io2->generic.out.maximal_access;
242 return NT_STATUS_INVALID_LEVEL;
245 /* doing a secondary request async is more trouble than its
247 state = req->async_states->state;
248 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
250 if (write_time != 0) {
251 sf = talloc(req, union smb_setfileinfo);
252 NT_STATUS_HAVE_NO_MEMORY(sf);
253 sf->generic.level = RAW_SFILEINFO_STANDARD;
254 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
255 sf->standard.in.create_time = 0;
256 sf->standard.in.write_time = write_time;
257 sf->standard.in.access_time = 0;
258 status = ntvfs->ops->setfileinfo_fn(ntvfs, req, sf);
262 sf = talloc(req, union smb_setfileinfo);
263 NT_STATUS_HAVE_NO_MEMORY(sf);
264 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
265 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
266 sf->end_of_file_info.in.size = set_size;
267 status = ntvfs->ops->setfileinfo_fn(ntvfs, req, sf);
268 if (NT_STATUS_IS_OK(status)) {
269 io->openx.out.size = io->openx.in.size;
273 req->async_states->state = state;
279 the core of the mapping between openx style parameters and ntcreatex
282 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
283 uint16_t open_func, const char *fname,
286 io2->generic.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
287 io2->generic.in.private_flags = 0;
289 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
290 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
292 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
293 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
296 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
297 case OPENX_MODE_ACCESS_READ:
298 case OPENX_MODE_ACCESS_EXEC:
299 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
301 case OPENX_MODE_ACCESS_WRITE:
302 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
304 case OPENX_MODE_ACCESS_RDWR:
305 case OPENX_MODE_ACCESS_FCB:
306 io2->generic.in.access_mask =
307 SEC_RIGHTS_FILE_READ |
308 SEC_RIGHTS_FILE_WRITE;
311 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
314 switch (open_mode & OPENX_MODE_DENY_MASK) {
315 case OPENX_MODE_DENY_READ:
316 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
318 case OPENX_MODE_DENY_WRITE:
319 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
321 case OPENX_MODE_DENY_ALL:
322 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
324 case OPENX_MODE_DENY_NONE:
325 io2->generic.in.share_access =
326 NTCREATEX_SHARE_ACCESS_READ |
327 NTCREATEX_SHARE_ACCESS_WRITE;
329 case OPENX_MODE_DENY_DOS:
330 /* DENY_DOS is quite strange - it depends on the filename! */
331 io2->generic.in.private_flags |=
332 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
333 if (is_exe_filename(fname)) {
334 io2->generic.in.share_access =
335 NTCREATEX_SHARE_ACCESS_READ |
336 NTCREATEX_SHARE_ACCESS_WRITE;
338 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
339 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
341 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
345 case OPENX_MODE_DENY_FCB:
346 io2->generic.in.private_flags |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
347 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
350 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
354 case (OPENX_OPEN_FUNC_OPEN):
355 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
357 case (OPENX_OPEN_FUNC_TRUNC):
358 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
360 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
361 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
363 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
364 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
366 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
367 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
370 /* this one is very strange */
371 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
372 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
375 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
382 NTVFS open generic to any mapper
384 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
385 struct ntvfs_request *req,
391 io2 = talloc_zero(req, union smb_open);
393 return NT_STATUS_NO_MEMORY;
396 status = ntvfs_map_async_setup(ntvfs, req,
398 (second_stage_t)ntvfs_map_open_finish);
399 if (!NT_STATUS_IS_OK(status)) {
403 io2->generic.level = RAW_OPEN_GENERIC;
405 switch (io->generic.level) {
407 status = map_openx_open(io->openx.in.flags,
408 io->openx.in.open_mode,
409 io->openx.in.open_func,
412 if (!NT_STATUS_IS_OK(status)) {
416 io2->generic.in.file_attr = io->openx.in.file_attrs;
417 io2->generic.in.fname = io->openx.in.fname;
419 status = ntvfs->ops->open_fn(ntvfs, req, io2);
424 status = map_openx_open(0,
425 io->openold.in.open_mode,
426 OPENX_OPEN_FUNC_OPEN,
427 io->openold.in.fname,
429 if (!NT_STATUS_IS_OK(status)) {
433 io2->generic.in.file_attr = io->openold.in.search_attrs;
434 io2->generic.in.fname = io->openold.in.fname;
436 status = ntvfs->ops->open_fn(ntvfs, req, io2);
439 case RAW_OPEN_T2OPEN:
440 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
442 if (io->t2open.in.open_func == 0) {
443 status = NT_STATUS_OBJECT_NAME_COLLISION;
447 status = map_openx_open(io->t2open.in.flags,
448 io->t2open.in.open_mode,
449 io->t2open.in.open_func,
452 if (!NT_STATUS_IS_OK(status)) {
456 io2->generic.in.file_attr = io->t2open.in.file_attrs;
457 io2->generic.in.fname = io->t2open.in.fname;
458 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
459 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
460 io2->generic.in.ea_list->eas = io->t2open.in.eas;
462 status = ntvfs->ops->open_fn(ntvfs, req, io2);
466 io2->generic.in.file_attr = io->mknew.in.attrib;
467 io2->generic.in.fname = io->mknew.in.fname;
468 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
469 io2->generic.in.access_mask =
470 SEC_RIGHTS_FILE_READ |
471 SEC_RIGHTS_FILE_WRITE;
472 io2->generic.in.share_access =
473 NTCREATEX_SHARE_ACCESS_READ |
474 NTCREATEX_SHARE_ACCESS_WRITE;
475 status = ntvfs->ops->open_fn(ntvfs, req, io2);
478 case RAW_OPEN_CREATE:
479 io2->generic.in.file_attr = io->mknew.in.attrib;
480 io2->generic.in.fname = io->mknew.in.fname;
481 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
482 io2->generic.in.access_mask =
483 SEC_RIGHTS_FILE_READ |
484 SEC_RIGHTS_FILE_WRITE;
485 io2->generic.in.share_access =
486 NTCREATEX_SHARE_ACCESS_READ |
487 NTCREATEX_SHARE_ACCESS_WRITE;
488 status = ntvfs->ops->open_fn(ntvfs, req, io2);
492 io2->generic.in.file_attr = io->ctemp.in.attrib;
493 io2->generic.in.fname =
494 talloc_asprintf(io2, "%s\\SRV%s",
495 io->ctemp.in.directory,
496 generate_random_str_list(io2, 5, "0123456789"));
497 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
498 io2->generic.in.access_mask =
499 SEC_RIGHTS_FILE_READ |
500 SEC_RIGHTS_FILE_WRITE;
501 io2->generic.in.share_access =
502 NTCREATEX_SHARE_ACCESS_READ |
503 NTCREATEX_SHARE_ACCESS_WRITE;
504 status = ntvfs->ops->open_fn(ntvfs, req, io2);
507 switch (io->smb2.in.oplock_level) {
508 case SMB2_OPLOCK_LEVEL_BATCH:
509 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
510 NTCREATEX_FLAGS_REQUEST_OPLOCK;
512 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
513 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
516 io2->generic.in.flags = 0;
519 io2->generic.in.root_fid.fnum = 0;
520 io2->generic.in.access_mask = io->smb2.in.desired_access;
521 io2->generic.in.alloc_size = io->smb2.in.alloc_size;
522 io2->generic.in.file_attr = io->smb2.in.file_attributes;
523 io2->generic.in.share_access = io->smb2.in.share_access;
524 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
525 io2->generic.in.create_options = io->smb2.in.create_options;
526 io2->generic.in.impersonation = io->smb2.in.impersonation_level;
527 io2->generic.in.security_flags = 0;
528 io2->generic.in.fname = io->smb2.in.fname;
529 io2->generic.in.sec_desc = io->smb2.in.sec_desc;
530 io2->generic.in.ea_list = &io->smb2.in.eas;
531 io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access;
532 io2->generic.in.private_flags = 0;
534 /* we don't support timewarp yet */
535 if (io->smb2.in.timewarp != 0) {
536 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
540 /* we need to check these bits before we check the private mask */
541 if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
542 DEBUG(2,(__location__ " create_options 0x%x not supported\n",
543 io2->generic.in.create_options));
544 status = NT_STATUS_NOT_SUPPORTED;
548 /* TODO: find out why only SMB2 ignores these */
549 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
550 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
552 status = ntvfs->ops->open_fn(ntvfs, req, io2);
556 status = NT_STATUS_INVALID_LEVEL;
560 return ntvfs_map_async_finish(req, status);
565 NTVFS any to fsinfo mapper
567 static NTSTATUS ntvfs_map_fsinfo_finish(struct ntvfs_module_context *ntvfs,
568 struct ntvfs_request *req,
569 union smb_fsinfo *fs,
570 union smb_fsinfo *fs2,
573 if (!NT_STATUS_IS_OK(status)) {
577 /* and convert it to the required level */
578 switch (fs->generic.level) {
579 case RAW_QFS_DSKATTR: {
580 /* map from generic to DSKATTR */
581 unsigned int bpunit = 64;
583 /* we need to scale the sizes to fit */
584 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
585 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
590 fs->dskattr.out.blocks_per_unit = bpunit;
591 fs->dskattr.out.block_size = 512;
592 fs->dskattr.out.units_total =
593 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
594 fs->dskattr.out.units_free =
595 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
597 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
598 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
599 fs->dskattr.out.blocks_per_unit = 64;
600 fs->dskattr.out.units_total = 0xFFFF;
601 fs->dskattr.out.units_free = 0xFFFF;
606 case RAW_QFS_ALLOCATION:
607 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
608 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
609 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
610 fs->allocation.out.sectors_per_unit = 1;
611 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
615 fs->volume.out.serial_number = fs2->generic.out.serial_number;
616 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
619 case RAW_QFS_VOLUME_INFO:
620 case RAW_QFS_VOLUME_INFORMATION:
621 fs->volume_info.out.create_time = fs2->generic.out.create_time;
622 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
623 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
626 case RAW_QFS_SIZE_INFO:
627 case RAW_QFS_SIZE_INFORMATION:
628 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
629 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
630 fs->size_info.out.sectors_per_unit = 1;
631 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
634 case RAW_QFS_DEVICE_INFO:
635 case RAW_QFS_DEVICE_INFORMATION:
636 fs->device_info.out.device_type = fs2->generic.out.device_type;
637 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
640 case RAW_QFS_ATTRIBUTE_INFO:
641 case RAW_QFS_ATTRIBUTE_INFORMATION:
642 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
643 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
644 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
647 case RAW_QFS_QUOTA_INFORMATION:
648 ZERO_STRUCT(fs->quota_information.out.unknown);
649 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
650 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
651 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
654 case RAW_QFS_FULL_SIZE_INFORMATION:
655 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
656 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
657 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
658 fs->full_size_information.out.sectors_per_unit = 1;
659 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
662 case RAW_QFS_OBJECTID_INFORMATION:
663 fs->objectid_information.out.guid = fs2->generic.out.guid;
664 ZERO_STRUCT(fs->objectid_information.out.unknown);
667 case RAW_QFS_GENERIC:
668 case RAW_QFS_UNIX_INFO:
669 return NT_STATUS_INVALID_LEVEL;
672 return NT_STATUS_INVALID_LEVEL;
676 NTVFS fsinfo any to generic mapper
678 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
679 struct ntvfs_request *req,
680 union smb_fsinfo *fs)
683 union smb_fsinfo *fs2;
685 fs2 = talloc(req, union smb_fsinfo);
687 return NT_STATUS_NO_MEMORY;
690 if (fs->generic.level == RAW_QFS_GENERIC) {
691 return NT_STATUS_INVALID_LEVEL;
694 status = ntvfs_map_async_setup(ntvfs, req, fs, fs2,
695 (second_stage_t)ntvfs_map_fsinfo_finish);
696 if (!NT_STATUS_IS_OK(status)) {
700 /* ask the backend for the generic info */
701 fs2->generic.level = RAW_QFS_GENERIC;
703 status = ntvfs->ops->fsinfo_fn(ntvfs, req, fs2);
704 return ntvfs_map_async_finish(req, status);
709 NTVFS fileinfo generic to any mapper
711 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
712 union smb_fileinfo *info,
713 union smb_fileinfo *info2)
716 /* and convert it to the required level using results in info2 */
717 switch (info->generic.level) {
718 case RAW_FILEINFO_GETATTR:
719 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
720 info->getattr.out.size = info2->generic.out.size;
721 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
724 case RAW_FILEINFO_GETATTRE:
725 info->getattre.out.attrib = info2->generic.out.attrib;
726 info->getattre.out.size = info2->generic.out.size;
727 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
728 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
729 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
730 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
733 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
734 info->network_open_information.out.create_time = info2->generic.out.create_time;
735 info->network_open_information.out.access_time = info2->generic.out.access_time;
736 info->network_open_information.out.write_time = info2->generic.out.write_time;
737 info->network_open_information.out.change_time = info2->generic.out.change_time;
738 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
739 info->network_open_information.out.size = info2->generic.out.size;
740 info->network_open_information.out.attrib = info2->generic.out.attrib;
743 case RAW_FILEINFO_ALL_INFO:
744 case RAW_FILEINFO_ALL_INFORMATION:
745 info->all_info.out.create_time = info2->generic.out.create_time;
746 info->all_info.out.access_time = info2->generic.out.access_time;
747 info->all_info.out.write_time = info2->generic.out.write_time;
748 info->all_info.out.change_time = info2->generic.out.change_time;
749 info->all_info.out.attrib = info2->generic.out.attrib;
750 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
751 info->all_info.out.size = info2->generic.out.size;
752 info->all_info.out.nlink = info2->generic.out.nlink;
753 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
754 info->all_info.out.directory = info2->generic.out.directory;
755 info->all_info.out.ea_size = info2->generic.out.ea_size;
756 info->all_info.out.fname.s = info2->generic.out.fname.s;
757 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
760 case RAW_FILEINFO_BASIC_INFO:
761 case RAW_FILEINFO_BASIC_INFORMATION:
762 info->basic_info.out.create_time = info2->generic.out.create_time;
763 info->basic_info.out.access_time = info2->generic.out.access_time;
764 info->basic_info.out.write_time = info2->generic.out.write_time;
765 info->basic_info.out.change_time = info2->generic.out.change_time;
766 info->basic_info.out.attrib = info2->generic.out.attrib;
769 case RAW_FILEINFO_STANDARD:
770 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
771 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
772 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
773 info->standard.out.size = info2->generic.out.size;
774 info->standard.out.alloc_size = info2->generic.out.alloc_size;
775 info->standard.out.attrib = info2->generic.out.attrib;
778 case RAW_FILEINFO_EA_SIZE:
779 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
780 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
781 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
782 info->ea_size.out.size = info2->generic.out.size;
783 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
784 info->ea_size.out.attrib = info2->generic.out.attrib;
785 info->ea_size.out.ea_size = info2->generic.out.ea_size;
788 case RAW_FILEINFO_STANDARD_INFO:
789 case RAW_FILEINFO_STANDARD_INFORMATION:
790 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
791 info->standard_info.out.size = info2->generic.out.size;
792 info->standard_info.out.nlink = info2->generic.out.nlink;
793 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
794 info->standard_info.out.directory = info2->generic.out.directory;
797 case RAW_FILEINFO_INTERNAL_INFORMATION:
798 info->internal_information.out.file_id = info2->generic.out.file_id;
801 case RAW_FILEINFO_EA_INFO:
802 case RAW_FILEINFO_EA_INFORMATION:
803 info->ea_info.out.ea_size = info2->generic.out.ea_size;
806 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
807 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
808 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
811 case RAW_FILEINFO_STREAM_INFO:
812 case RAW_FILEINFO_STREAM_INFORMATION:
813 info->stream_info.out.num_streams = info2->generic.out.num_streams;
814 if (info->stream_info.out.num_streams > 0) {
815 info->stream_info.out.streams =
816 talloc_array(mem_ctx,
817 struct stream_struct,
818 info->stream_info.out.num_streams);
819 if (!info->stream_info.out.streams) {
820 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
821 info->stream_info.out.num_streams));
822 return NT_STATUS_NO_MEMORY;
824 for (i=0; i < info->stream_info.out.num_streams; i++) {
825 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
826 info->stream_info.out.streams[i].stream_name.s =
827 talloc_strdup(info->stream_info.out.streams,
828 info2->generic.out.streams[i].stream_name.s);
829 if (!info->stream_info.out.streams[i].stream_name.s) {
830 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
831 return NT_STATUS_NO_MEMORY;
837 case RAW_FILEINFO_NAME_INFO:
838 case RAW_FILEINFO_NAME_INFORMATION:
839 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
840 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
841 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
844 case RAW_FILEINFO_ALT_NAME_INFO:
845 case RAW_FILEINFO_ALT_NAME_INFORMATION:
846 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
847 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
848 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
851 case RAW_FILEINFO_POSITION_INFORMATION:
852 info->position_information.out.position = info2->generic.out.position;
855 case RAW_FILEINFO_ALL_EAS:
856 info->all_eas.out.num_eas = info2->generic.out.num_eas;
857 if (info->all_eas.out.num_eas > 0) {
858 info->all_eas.out.eas = talloc_array(mem_ctx,
860 info->all_eas.out.num_eas);
861 if (!info->all_eas.out.eas) {
862 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
863 info->all_eas.out.num_eas));
864 return NT_STATUS_NO_MEMORY;
866 for (i = 0; i < info->all_eas.out.num_eas; i++) {
867 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
868 info->all_eas.out.eas[i].name.s =
869 talloc_strdup(info->all_eas.out.eas,
870 info2->generic.out.eas[i].name.s);
871 if (!info->all_eas.out.eas[i].name.s) {
872 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
873 return NT_STATUS_NO_MEMORY;
875 info->all_eas.out.eas[i].value.data =
876 (uint8_t *)talloc_memdup(info->all_eas.out.eas,
877 info2->generic.out.eas[i].value.data,
878 info2->generic.out.eas[i].value.length);
879 if (!info->all_eas.out.eas[i].value.data) {
880 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
881 return NT_STATUS_NO_MEMORY;
887 case RAW_FILEINFO_IS_NAME_VALID:
890 case RAW_FILEINFO_COMPRESSION_INFO:
891 case RAW_FILEINFO_COMPRESSION_INFORMATION:
892 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
893 info->compression_info.out.format = info2->generic.out.format;
894 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
895 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
896 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
899 case RAW_FILEINFO_ACCESS_INFORMATION:
900 info->access_information.out.access_flags = info2->generic.out.access_flags;
903 case RAW_FILEINFO_MODE_INFORMATION:
904 info->mode_information.out.mode = info2->generic.out.mode;
907 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
908 info->alignment_information.out.alignment_requirement =
909 info2->generic.out.alignment_requirement;
911 case RAW_FILEINFO_UNIX_BASIC:
913 return NT_STATUS_INVALID_LEVEL;
915 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
916 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
917 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
918 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
919 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
920 info->unix_basic_info.out.uid = info2->generic.out.uid;
921 info->unix_basic_info.out.gid = info2->generic.out.gid;
922 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
923 info->unix_basic_info.out.dev_major = info2->generic.out.device;
924 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
925 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
926 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
927 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
930 case RAW_FILEINFO_UNIX_LINK:
932 return NT_STATUS_INVALID_LEVEL;
934 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
937 case RAW_FILEINFO_GENERIC:
938 case RAW_FILEINFO_SEC_DESC:
939 case RAW_FILEINFO_EA_LIST:
940 case RAW_FILEINFO_UNIX_INFO2:
941 case RAW_FILEINFO_SMB2_ALL_EAS:
942 case RAW_FILEINFO_SMB2_ALL_INFORMATION:
943 return NT_STATUS_INVALID_LEVEL;
946 return NT_STATUS_INVALID_LEVEL;
950 NTVFS any to fileinfo mapper
952 static NTSTATUS ntvfs_map_qfileinfo_finish(struct ntvfs_module_context *ntvfs,
953 struct ntvfs_request *req,
954 union smb_fileinfo *info,
955 union smb_fileinfo *info2,
958 if (!NT_STATUS_IS_OK(status)) {
962 return ntvfs_map_fileinfo(req, info, info2);
966 NTVFS fileinfo generic to any mapper
968 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
969 struct ntvfs_request *req,
970 union smb_fileinfo *info)
973 union smb_fileinfo *info2;
975 info2 = talloc(req, union smb_fileinfo);
977 return NT_STATUS_NO_MEMORY;
980 if (info->generic.level == RAW_FILEINFO_GENERIC) {
981 return NT_STATUS_INVALID_LEVEL;
984 status = ntvfs_map_async_setup(ntvfs, req, info, info2,
985 (second_stage_t)ntvfs_map_qfileinfo_finish);
986 if (!NT_STATUS_IS_OK(status)) {
990 /* ask the backend for the generic info */
991 info2->generic.level = RAW_FILEINFO_GENERIC;
992 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
994 status = ntvfs->ops->qfileinfo_fn(ntvfs, req, info2);
995 return ntvfs_map_async_finish(req, status);
999 NTVFS any to fileinfo mapper
1001 static NTSTATUS ntvfs_map_qpathinfo_finish(struct ntvfs_module_context *ntvfs,
1002 struct ntvfs_request *req,
1003 union smb_fileinfo *info,
1004 union smb_fileinfo *info2,
1007 if (!NT_STATUS_IS_OK(status)) {
1011 return ntvfs_map_fileinfo(req, info, info2);
1015 NTVFS pathinfo generic to any mapper
1017 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
1018 struct ntvfs_request *req,
1019 union smb_fileinfo *info)
1022 union smb_fileinfo *info2;
1024 info2 = talloc(req, union smb_fileinfo);
1025 if (info2 == NULL) {
1026 return NT_STATUS_NO_MEMORY;
1029 if (info->generic.level == RAW_FILEINFO_GENERIC) {
1030 return NT_STATUS_INVALID_LEVEL;
1033 status = ntvfs_map_async_setup(ntvfs, req, info, info2,
1034 (second_stage_t)ntvfs_map_qpathinfo_finish);
1035 if (!NT_STATUS_IS_OK(status)) {
1039 /* ask the backend for the generic info */
1040 info2->generic.level = RAW_FILEINFO_GENERIC;
1041 info2->generic.in.file.path = info->generic.in.file.path;
1043 status = ntvfs->ops->qpathinfo_fn(ntvfs, req, info2);
1044 return ntvfs_map_async_finish(req, status);
1049 NTVFS lock generic to any mapper
1051 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
1052 struct ntvfs_request *req,
1053 union smb_lock *lck)
1055 union smb_lock *lck2;
1056 struct smb_lock_entry *locks;
1058 lck2 = talloc(req, union smb_lock);
1060 return NT_STATUS_NO_MEMORY;
1063 locks = talloc_array(lck2, struct smb_lock_entry, 1);
1064 if (locks == NULL) {
1065 return NT_STATUS_NO_MEMORY;
1068 switch (lck->generic.level) {
1069 case RAW_LOCK_LOCKX:
1070 return NT_STATUS_INVALID_LEVEL;
1073 lck2->generic.level = RAW_LOCK_GENERIC;
1074 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1075 lck2->generic.in.mode = 0;
1076 lck2->generic.in.timeout = 0;
1077 lck2->generic.in.ulock_cnt = 0;
1078 lck2->generic.in.lock_cnt = 1;
1079 lck2->generic.in.locks = locks;
1080 locks->pid = req->smbpid;
1081 locks->offset = lck->lock.in.offset;
1082 locks->count = lck->lock.in.count;
1085 case RAW_LOCK_UNLOCK:
1086 lck2->generic.level = RAW_LOCK_GENERIC;
1087 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1088 lck2->generic.in.mode = 0;
1089 lck2->generic.in.timeout = 0;
1090 lck2->generic.in.ulock_cnt = 1;
1091 lck2->generic.in.lock_cnt = 0;
1092 lck2->generic.in.locks = locks;
1093 locks->pid = req->smbpid;
1094 locks->offset = lck->unlock.in.offset;
1095 locks->count = lck->unlock.in.count;
1098 case RAW_LOCK_SMB2: {
1099 /* this is only approximate! We need to change the
1100 generic structure to fix this properly */
1103 if (lck->smb2.in.lock_count < 1) {
1104 return NT_STATUS_INVALID_PARAMETER;
1107 lck2->generic.level = RAW_LOCK_GENERIC;
1108 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1109 lck2->generic.in.timeout = UINT32_MAX;
1110 lck2->generic.in.mode = 0;
1111 lck2->generic.in.lock_cnt = 0;
1112 lck2->generic.in.ulock_cnt = 0;
1113 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry,
1114 lck->smb2.in.lock_count);
1115 if (lck2->generic.in.locks == NULL) {
1116 return NT_STATUS_NO_MEMORY;
1118 /* only the first lock gives the UNLOCK bit - see
1120 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1121 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1122 return NT_STATUS_INVALID_PARAMETER;
1124 lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1127 lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1130 for (i=0;i<lck->smb2.in.lock_count;i++) {
1132 lck->smb2.in.locks[i].flags == SMB2_LOCK_FLAG_NONE) {
1133 return NT_STATUS_INVALID_PARAMETER;
1136 if (lck->smb2.in.locks[i].flags & ~SMB2_LOCK_FLAG_ALL_MASK) {
1137 return NT_STATUS_INVALID_PARAMETER;
1141 (lck->smb2.in.locks[i].flags &
1142 (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1143 return NT_STATUS_INVALID_PARAMETER;
1146 (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1147 return NT_STATUS_INVALID_PARAMETER;
1149 lck2->generic.in.locks[i].pid = req->smbpid;
1150 lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
1151 lck2->generic.in.locks[i].count = lck->smb2.in.locks[i].length;
1152 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1153 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1155 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1156 lck2->generic.in.timeout = 0;
1159 /* initialize output value */
1160 lck->smb2.out.reserved = 0;
1164 case RAW_LOCK_SMB2_BREAK:
1165 lck2->generic.level = RAW_LOCK_GENERIC;
1166 lck2->generic.in.file.ntvfs = lck->smb2_break.in.file.ntvfs;
1167 lck2->generic.in.mode = LOCKING_ANDX_OPLOCK_RELEASE |
1168 ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1169 lck2->generic.in.timeout = 0;
1170 lck2->generic.in.ulock_cnt = 0;
1171 lck2->generic.in.lock_cnt = 0;
1172 lck2->generic.in.locks = NULL;
1174 /* initialize output value */
1175 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1176 lck->smb2_break.out.reserved = lck->smb2_break.in.reserved;
1177 lck->smb2_break.out.reserved2 = lck->smb2_break.in.reserved2;
1178 lck->smb2_break.out.file = lck->smb2_break.in.file;
1183 * we don't need to call ntvfs_map_async_setup() here,
1184 * as lock() doesn't have any output fields
1187 return ntvfs->ops->lock_fn(ntvfs, req, lck2);
1192 NTVFS write generic to any mapper
1194 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1195 struct ntvfs_request *req,
1196 union smb_write *wr,
1197 union smb_write *wr2,
1200 union smb_lock *lck;
1201 union smb_close *cl;
1204 if (NT_STATUS_IS_ERR(status)) {
1208 switch (wr->generic.level) {
1209 case RAW_WRITE_WRITE:
1210 wr->write.out.nwritten = wr2->generic.out.nwritten;
1213 case RAW_WRITE_WRITEUNLOCK:
1214 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1216 lck = talloc(wr2, union smb_lock);
1218 return NT_STATUS_NO_MEMORY;
1221 lck->unlock.level = RAW_LOCK_UNLOCK;
1222 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1223 lck->unlock.in.count = wr->writeunlock.in.count;
1224 lck->unlock.in.offset = wr->writeunlock.in.offset;
1226 if (lck->unlock.in.count != 0) {
1227 /* do the lock sync for now */
1228 state = req->async_states->state;
1229 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1230 status = ntvfs->ops->lock_fn(ntvfs, req, lck);
1231 req->async_states->state = state;
1235 case RAW_WRITE_WRITECLOSE:
1236 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1238 cl = talloc(wr2, union smb_close);
1240 return NT_STATUS_NO_MEMORY;
1243 cl->close.level = RAW_CLOSE_CLOSE;
1244 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1245 cl->close.in.write_time = wr->writeclose.in.mtime;
1247 if (wr2->generic.in.count != 0) {
1248 /* do the close sync for now */
1249 state = req->async_states->state;
1250 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1251 status = ntvfs->ops->close_fn(ntvfs, req, cl);
1252 req->async_states->state = state;
1256 case RAW_WRITE_SPLWRITE:
1259 case RAW_WRITE_SMB2:
1260 wr->smb2.out._pad = 0;
1261 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1262 wr->smb2.out.unknown1 = 0;
1266 return NT_STATUS_INVALID_LEVEL;
1274 NTVFS write generic to any mapper
1276 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1277 struct ntvfs_request *req,
1278 union smb_write *wr)
1280 union smb_write *wr2;
1283 wr2 = talloc(req, union smb_write);
1285 return NT_STATUS_NO_MEMORY;
1288 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1289 (second_stage_t)ntvfs_map_write_finish);
1290 if (!NT_STATUS_IS_OK(status)) {
1294 wr2->writex.level = RAW_WRITE_GENERIC;
1296 switch (wr->generic.level) {
1297 case RAW_WRITE_WRITEX:
1298 status = NT_STATUS_INVALID_LEVEL;
1301 case RAW_WRITE_WRITE:
1302 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1303 wr2->writex.in.offset = wr->write.in.offset;
1304 wr2->writex.in.wmode = 0;
1305 wr2->writex.in.remaining = wr->write.in.remaining;
1306 wr2->writex.in.count = wr->write.in.count;
1307 wr2->writex.in.data = wr->write.in.data;
1308 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1311 case RAW_WRITE_WRITEUNLOCK:
1312 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1313 wr2->writex.in.offset = wr->writeunlock.in.offset;
1314 wr2->writex.in.wmode = 0;
1315 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1316 wr2->writex.in.count = wr->writeunlock.in.count;
1317 wr2->writex.in.data = wr->writeunlock.in.data;
1318 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1321 case RAW_WRITE_WRITECLOSE:
1322 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1323 wr2->writex.in.offset = wr->writeclose.in.offset;
1324 wr2->writex.in.wmode = 0;
1325 wr2->writex.in.remaining = 0;
1326 wr2->writex.in.count = wr->writeclose.in.count;
1327 wr2->writex.in.data = wr->writeclose.in.data;
1328 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1331 case RAW_WRITE_SPLWRITE:
1332 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1333 wr2->writex.in.offset = 0;
1334 wr2->writex.in.wmode = 0;
1335 wr2->writex.in.remaining = 0;
1336 wr2->writex.in.count = wr->splwrite.in.count;
1337 wr2->writex.in.data = wr->splwrite.in.data;
1338 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1341 case RAW_WRITE_SMB2:
1342 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1343 wr2->writex.in.offset = wr->smb2.in.offset;
1344 wr2->writex.in.wmode = 0;
1345 wr2->writex.in.remaining = 0;
1346 wr2->writex.in.count = wr->smb2.in.data.length;
1347 wr2->writex.in.data = wr->smb2.in.data.data;
1348 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1351 return ntvfs_map_async_finish(req, status);
1356 NTVFS read generic to any mapper - finish the out mapping
1358 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1359 struct ntvfs_request *req,
1361 union smb_read *rd2,
1364 switch (rd->generic.level) {
1366 rd->read.out.nread = rd2->generic.out.nread;
1368 case RAW_READ_READBRAW:
1369 rd->readbraw.out.nread = rd2->generic.out.nread;
1371 case RAW_READ_LOCKREAD:
1372 rd->lockread.out.nread = rd2->generic.out.nread;
1375 rd->smb2.out.data.length= rd2->generic.out.nread;
1376 rd->smb2.out.remaining = 0;
1377 rd->smb2.out.reserved = 0;
1380 return NT_STATUS_INVALID_LEVEL;
1387 NTVFS read* to readx mapper
1389 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1390 struct ntvfs_request *req,
1393 union smb_read *rd2;
1394 union smb_lock *lck;
1398 rd2 = talloc(req, union smb_read);
1400 return NT_STATUS_NO_MEMORY;
1403 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1404 (second_stage_t)ntvfs_map_read_finish);
1405 if (!NT_STATUS_IS_OK(status)) {
1409 rd2->readx.level = RAW_READ_READX;
1410 rd2->readx.in.read_for_execute = false;
1412 switch (rd->generic.level) {
1413 case RAW_READ_READX:
1414 status = NT_STATUS_INVALID_LEVEL;
1418 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1419 rd2->readx.in.offset = rd->read.in.offset;
1420 rd2->readx.in.mincnt = rd->read.in.count;
1421 rd2->readx.in.maxcnt = rd->read.in.count;
1422 rd2->readx.in.remaining = rd->read.in.remaining;
1423 rd2->readx.out.data = rd->read.out.data;
1424 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1427 case RAW_READ_READBRAW:
1428 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1429 rd2->readx.in.offset = rd->readbraw.in.offset;
1430 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1431 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1432 rd2->readx.in.remaining = 0;
1433 rd2->readx.out.data = rd->readbraw.out.data;
1434 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1437 case RAW_READ_LOCKREAD:
1438 /* do the initial lock sync for now */
1439 state = req->async_states->state;
1440 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1442 lck = talloc(rd2, union smb_lock);
1444 status = NT_STATUS_NO_MEMORY;
1447 lck->lock.level = RAW_LOCK_LOCK;
1448 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1449 lck->lock.in.count = rd->lockread.in.count;
1450 lck->lock.in.offset = rd->lockread.in.offset;
1451 status = ntvfs->ops->lock_fn(ntvfs, req, lck);
1452 req->async_states->state = state;
1454 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1455 rd2->readx.in.offset = rd->lockread.in.offset;
1456 rd2->readx.in.mincnt = rd->lockread.in.count;
1457 rd2->readx.in.maxcnt = rd->lockread.in.count;
1458 rd2->readx.in.remaining = rd->lockread.in.remaining;
1459 rd2->readx.out.data = rd->lockread.out.data;
1461 if (NT_STATUS_IS_OK(status)) {
1462 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1467 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1468 rd2->readx.in.offset = rd->smb2.in.offset;
1469 rd2->readx.in.mincnt = rd->smb2.in.min_count;
1470 rd2->readx.in.maxcnt = rd->smb2.in.length;
1471 rd2->readx.in.remaining = 0;
1472 rd2->readx.out.data = rd->smb2.out.data.data;
1473 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1478 return ntvfs_map_async_finish(req, status);
1483 NTVFS close generic to any mapper
1485 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1486 struct ntvfs_request *req,
1487 union smb_close *cl,
1488 union smb_close *cl2,
1491 NT_STATUS_NOT_OK_RETURN(status);
1493 switch (cl->generic.level) {
1494 case RAW_CLOSE_SMB2:
1495 cl->smb2.out.flags = cl2->generic.out.flags;
1496 cl->smb2.out._pad = 0;
1497 cl->smb2.out.create_time = cl2->generic.out.create_time;
1498 cl->smb2.out.access_time = cl2->generic.out.access_time;
1499 cl->smb2.out.write_time = cl2->generic.out.write_time;
1500 cl->smb2.out.change_time = cl2->generic.out.change_time;
1501 cl->smb2.out.alloc_size = cl2->generic.out.alloc_size;
1502 cl->smb2.out.size = cl2->generic.out.size;
1503 cl->smb2.out.file_attr = cl2->generic.out.file_attr;
1513 NTVFS close generic to any mapper
1515 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1516 struct ntvfs_request *req,
1517 union smb_close *cl)
1519 union smb_close *cl2;
1522 cl2 = talloc(req, union smb_close);
1524 return NT_STATUS_NO_MEMORY;
1527 switch (cl->generic.level) {
1528 case RAW_CLOSE_GENERIC:
1529 return NT_STATUS_INVALID_LEVEL;
1531 case RAW_CLOSE_CLOSE:
1532 cl2->generic.level = RAW_CLOSE_GENERIC;
1533 cl2->generic.in.file = cl->close.in.file;
1534 cl2->generic.in.write_time = cl->close.in.write_time;
1535 cl2->generic.in.flags = 0;
1538 case RAW_CLOSE_SPLCLOSE:
1539 cl2->generic.level = RAW_CLOSE_GENERIC;
1540 cl2->generic.in.file = cl->splclose.in.file;
1541 cl2->generic.in.write_time = 0;
1542 cl2->generic.in.flags = 0;
1545 case RAW_CLOSE_SMB2:
1546 cl2->generic.level = RAW_CLOSE_GENERIC;
1547 cl2->generic.in.file = cl->smb2.in.file;
1548 cl2->generic.in.write_time = 0;
1549 cl2->generic.in.flags = cl->smb2.in.flags;
1553 status = ntvfs_map_async_setup(ntvfs, req, cl, cl2,
1554 (second_stage_t)ntvfs_map_close_finish);
1555 NT_STATUS_NOT_OK_RETURN(status);
1557 status = ntvfs->ops->close_fn(ntvfs, req, cl2);
1559 return ntvfs_map_async_finish(req, status);
1563 NTVFS notify generic to any mapper
1565 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1566 struct ntvfs_request *req,
1567 union smb_notify *nt,
1568 union smb_notify *nt2,
1571 NT_STATUS_NOT_OK_RETURN(status);
1573 switch (nt->nttrans.level) {
1574 case RAW_NOTIFY_SMB2:
1575 if (nt2->nttrans.out.num_changes == 0) {
1576 return STATUS_NOTIFY_ENUM_DIR;
1578 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1579 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1583 return NT_STATUS_INVALID_LEVEL;
1591 NTVFS notify generic to any mapper
1593 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1594 struct ntvfs_request *req,
1595 union smb_notify *nt)
1597 union smb_notify *nt2;
1600 nt2 = talloc(req, union smb_notify);
1601 NT_STATUS_HAVE_NO_MEMORY(nt2);
1603 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1604 (second_stage_t)ntvfs_map_notify_finish);
1605 NT_STATUS_NOT_OK_RETURN(status);
1607 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1609 switch (nt->nttrans.level) {
1610 case RAW_NOTIFY_NTTRANS:
1611 status = NT_STATUS_INVALID_LEVEL;
1614 case RAW_NOTIFY_SMB2:
1615 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1616 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1617 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1618 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1619 status = ntvfs->ops->notify_fn(ntvfs, req, nt2);
1623 return ntvfs_map_async_finish(req, status);