2 Unix SMB/CIFS implementation.
4 NTVFS generic level mapping code
6 Copyright (C) Andrew Tridgell 2003-2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 this implements mappings between info levels for NTVFS backend calls
24 the idea is that each of these functions implements one of the NTVFS
25 backend calls in terms of the 'generic' call. All backends that use
26 these functions must supply the generic call, but can if it wants to
27 also implement other levels if the need arises
29 this allows backend writers to only implement one variant of each
30 call unless they need fine grained control of the calls.
34 #include "ntvfs/ntvfs.h"
35 #include "libcli/smb2/smb2.h"
36 #include "libcli/smb2/smb2_calls.h"
38 /* a second stage function converts from the out parameters of the generic
39 call onto the out parameters of the specific call made */
40 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
41 struct ntvfs_request *,
42 void *, void *, NTSTATUS);
45 this structure holds the async state for pending mapped async calls
47 struct ntvfs_map_async {
48 struct ntvfs_module_context *ntvfs;
54 this is a async wrapper, called from the backend when it has completed
55 a function that it has decided to reply to in an async fashion
57 static void ntvfs_map_async_send(struct ntvfs_request *req)
59 struct ntvfs_map_async *m = req->async_states->private_data;
61 ntvfs_async_state_pop(req);
63 /* call the _finish function setup in ntvfs_map_async_setup() */
64 req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
66 /* call the send function from the next module up */
67 req->async_states->send_fn(req);
71 prepare for calling a ntvfs backend with async support
72 io is the original call structure
73 io2 is the new call structure for the mapped call
74 fn is a second stage function for processing the out arguments
76 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
77 struct ntvfs_request *req,
81 struct ntvfs_map_async *m;
82 m = talloc(req, struct ntvfs_map_async);
84 return NT_STATUS_NO_MEMORY;
90 return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
94 called when first stage processing is complete.
96 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
98 struct ntvfs_map_async *m;
100 /* if the backend has decided to reply in an async fashion then
101 we don't need to do any work here */
102 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
106 /* the backend is replying immediately. call the 2nd stage function after popping our local
108 m = req->async_states->private_data;
110 ntvfs_async_state_pop(req);
112 return m->fn(m->ntvfs, req, m->io, m->io2, status);
116 see if a filename ends in EXE COM DLL or SYM. This is needed for the
117 DENY_DOS mapping for OpenX
119 bool is_exe_filename(const char *fname)
122 p = strrchr(fname, '.');
127 if (strcasecmp(p, "EXE") == 0 ||
128 strcasecmp(p, "COM") == 0 ||
129 strcasecmp(p, "DLL") == 0 ||
130 strcasecmp(p, "SYM") == 0) {
138 NTVFS openx to ntcreatex mapper
140 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
141 struct ntvfs_request *req,
146 time_t write_time = 0;
147 uint32_t set_size = 0;
148 union smb_setfileinfo *sf;
151 if (!NT_STATUS_IS_OK(status)) {
155 switch (io->generic.level) {
157 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
158 io->openold.out.attrib = io2->generic.out.attrib;
159 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
160 io->openold.out.size = io2->generic.out.size;
161 io->openold.out.rmode = io->openold.in.open_mode;
165 io->openx.out.file.ntvfs = io2->generic.out.file.ntvfs;
166 io->openx.out.attrib = io2->generic.out.attrib;
167 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
168 io->openx.out.size = io2->generic.out.size;
169 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
170 io->openx.out.ftype = 0;
171 io->openx.out.devstate = 0;
172 io->openx.out.action = io2->generic.out.create_action;
173 io->openx.out.unique_fid = 0;
174 io->openx.out.access_mask = SEC_STD_ALL;
175 io->openx.out.unknown = 0;
177 /* we need to extend the file to the requested size if
178 it was newly created */
179 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
180 set_size = io->openx.in.size;
184 case RAW_OPEN_T2OPEN:
185 io->t2open.out.file.ntvfs = io2->generic.out.file.ntvfs;
186 io->t2open.out.attrib = io2->generic.out.attrib;
187 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
188 io->t2open.out.size = io2->generic.out.size;
189 io->t2open.out.access = io->t2open.in.open_mode;
190 io->t2open.out.ftype = 0;
191 io->t2open.out.devstate = 0;
192 io->t2open.out.action = io2->generic.out.create_action;
193 io->t2open.out.file_id = 0;
197 case RAW_OPEN_CREATE:
198 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
199 write_time = io->mknew.in.write_time;
203 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
204 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
205 strlen(io->ctemp.in.directory) + 1);
206 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
210 ZERO_STRUCT(io->smb2.out);
211 io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs;
212 switch (io2->generic.out.oplock_level) {
213 case BATCH_OPLOCK_RETURN:
214 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
216 case EXCLUSIVE_OPLOCK_RETURN:
217 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
219 case LEVEL_II_OPLOCK_RETURN:
220 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
223 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
226 io->smb2.out.reserved = 0;
227 io->smb2.out.create_action = io2->generic.out.create_action;
228 io->smb2.out.create_time = io2->generic.out.create_time;
229 io->smb2.out.access_time = io2->generic.out.access_time;
230 io->smb2.out.write_time = io2->generic.out.write_time;
231 io->smb2.out.change_time = io2->generic.out.change_time;
232 io->smb2.out.alloc_size = io2->generic.out.alloc_size;
233 io->smb2.out.size = io2->generic.out.size;
234 io->smb2.out.file_attr = io2->generic.out.attrib;
235 io->smb2.out.reserved2 = 0;
236 io->smb2.out.maximal_access = io2->generic.out.maximal_access;
240 return NT_STATUS_INVALID_LEVEL;
243 /* doing a secondary request async is more trouble than its
245 state = req->async_states->state;
246 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
248 if (write_time != 0) {
249 sf = talloc(req, union smb_setfileinfo);
250 NT_STATUS_HAVE_NO_MEMORY(sf);
251 sf->generic.level = RAW_SFILEINFO_STANDARD;
252 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
253 sf->standard.in.create_time = 0;
254 sf->standard.in.write_time = write_time;
255 sf->standard.in.access_time = 0;
256 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
260 sf = talloc(req, union smb_setfileinfo);
261 NT_STATUS_HAVE_NO_MEMORY(sf);
262 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
263 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
264 sf->end_of_file_info.in.size = set_size;
265 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
266 if (NT_STATUS_IS_OK(status)) {
267 io->openx.out.size = io->openx.in.size;
271 req->async_states->state = state;
277 the core of the mapping between openx style parameters and ntcreatex
280 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
281 uint16_t open_func, const char *fname,
284 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
285 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
287 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
288 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
291 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
292 case OPENX_MODE_ACCESS_READ:
293 case OPENX_MODE_ACCESS_EXEC:
294 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
296 case OPENX_MODE_ACCESS_WRITE:
297 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
299 case OPENX_MODE_ACCESS_RDWR:
300 case OPENX_MODE_ACCESS_FCB:
301 io2->generic.in.access_mask =
302 SEC_RIGHTS_FILE_READ |
303 SEC_RIGHTS_FILE_WRITE;
306 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
309 switch (open_mode & OPENX_MODE_DENY_MASK) {
310 case OPENX_MODE_DENY_READ:
311 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
313 case OPENX_MODE_DENY_WRITE:
314 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
316 case OPENX_MODE_DENY_ALL:
317 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
319 case OPENX_MODE_DENY_NONE:
320 io2->generic.in.share_access =
321 NTCREATEX_SHARE_ACCESS_READ |
322 NTCREATEX_SHARE_ACCESS_WRITE;
324 case OPENX_MODE_DENY_DOS:
325 /* DENY_DOS is quite strange - it depends on the filename! */
326 io2->generic.in.create_options |=
327 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
328 if (is_exe_filename(fname)) {
329 io2->generic.in.share_access =
330 NTCREATEX_SHARE_ACCESS_READ |
331 NTCREATEX_SHARE_ACCESS_WRITE;
333 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
334 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
336 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
340 case OPENX_MODE_DENY_FCB:
341 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
342 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
345 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
349 case (OPENX_OPEN_FUNC_OPEN):
350 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
352 case (OPENX_OPEN_FUNC_TRUNC):
353 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
355 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
356 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
358 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
359 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
361 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
362 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
365 /* this one is very strange */
366 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
367 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
370 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
377 NTVFS open generic to any mapper
379 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
380 struct ntvfs_request *req,
386 io2 = talloc_zero(req, union smb_open);
388 return NT_STATUS_NO_MEMORY;
391 status = ntvfs_map_async_setup(ntvfs, req,
393 (second_stage_t)ntvfs_map_open_finish);
394 if (!NT_STATUS_IS_OK(status)) {
398 io2->generic.level = RAW_OPEN_GENERIC;
400 switch (io->generic.level) {
402 status = map_openx_open(io->openx.in.flags,
403 io->openx.in.open_mode,
404 io->openx.in.open_func,
407 if (!NT_STATUS_IS_OK(status)) {
411 io2->generic.in.file_attr = io->openx.in.file_attrs;
412 io2->generic.in.fname = io->openx.in.fname;
414 status = ntvfs->ops->open(ntvfs, req, io2);
419 status = map_openx_open(0,
420 io->openold.in.open_mode,
421 OPENX_OPEN_FUNC_OPEN,
422 io->openold.in.fname,
424 if (!NT_STATUS_IS_OK(status)) {
428 io2->generic.in.file_attr = io->openold.in.search_attrs;
429 io2->generic.in.fname = io->openold.in.fname;
431 status = ntvfs->ops->open(ntvfs, req, io2);
434 case RAW_OPEN_T2OPEN:
435 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
437 if (io->t2open.in.open_func == 0) {
438 status = NT_STATUS_OBJECT_NAME_COLLISION;
442 status = map_openx_open(io->t2open.in.flags,
443 io->t2open.in.open_mode,
444 io->t2open.in.open_func,
447 if (!NT_STATUS_IS_OK(status)) {
451 io2->generic.in.file_attr = io->t2open.in.file_attrs;
452 io2->generic.in.fname = io->t2open.in.fname;
453 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
454 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
455 io2->generic.in.ea_list->eas = io->t2open.in.eas;
457 status = ntvfs->ops->open(ntvfs, req, io2);
461 io2->generic.in.file_attr = io->mknew.in.attrib;
462 io2->generic.in.fname = io->mknew.in.fname;
463 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
464 io2->generic.in.access_mask =
465 SEC_RIGHTS_FILE_READ |
466 SEC_RIGHTS_FILE_WRITE;
467 io2->generic.in.share_access =
468 NTCREATEX_SHARE_ACCESS_READ |
469 NTCREATEX_SHARE_ACCESS_WRITE;
470 status = ntvfs->ops->open(ntvfs, req, io2);
473 case RAW_OPEN_CREATE:
474 io2->generic.in.file_attr = io->mknew.in.attrib;
475 io2->generic.in.fname = io->mknew.in.fname;
476 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
477 io2->generic.in.access_mask =
478 SEC_RIGHTS_FILE_READ |
479 SEC_RIGHTS_FILE_WRITE;
480 io2->generic.in.share_access =
481 NTCREATEX_SHARE_ACCESS_READ |
482 NTCREATEX_SHARE_ACCESS_WRITE;
483 status = ntvfs->ops->open(ntvfs, req, io2);
487 io2->generic.in.file_attr = io->ctemp.in.attrib;
488 io2->generic.in.fname =
489 talloc_asprintf(io2, "%s\\SRV%s",
490 io->ctemp.in.directory,
491 generate_random_str_list(io2, 5, "0123456789"));
492 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
493 io2->generic.in.access_mask =
494 SEC_RIGHTS_FILE_READ |
495 SEC_RIGHTS_FILE_WRITE;
496 io2->generic.in.share_access =
497 NTCREATEX_SHARE_ACCESS_READ |
498 NTCREATEX_SHARE_ACCESS_WRITE;
499 status = ntvfs->ops->open(ntvfs, req, io2);
502 switch (io->smb2.in.oplock_level) {
503 case SMB2_OPLOCK_LEVEL_BATCH:
504 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
505 NTCREATEX_FLAGS_REQUEST_OPLOCK;
507 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
508 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
511 io2->generic.in.flags = 0;
514 io2->generic.in.root_fid = 0;
515 io2->generic.in.access_mask = io->smb2.in.desired_access;
516 io2->generic.in.alloc_size = io->smb2.in.alloc_size;
517 io2->generic.in.file_attr = io->smb2.in.file_attributes;
518 io2->generic.in.share_access = io->smb2.in.share_access;
519 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
520 io2->generic.in.create_options = io->smb2.in.create_options;
521 io2->generic.in.impersonation = io->smb2.in.impersonation_level;
522 io2->generic.in.security_flags = 0;
523 io2->generic.in.fname = io->smb2.in.fname;
524 io2->generic.in.sec_desc = io->smb2.in.sec_desc;
525 io2->generic.in.ea_list = &io->smb2.in.eas;
526 io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access;
528 /* we don't support timewarp yet */
529 if (io->smb2.in.timewarp != 0) {
530 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
534 /* we need to check these bits before we check the private mask */
535 if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
536 status = NT_STATUS_NOT_SUPPORTED;
540 /* TODO: find out why only SMB2 ignores these */
541 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
542 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
544 status = ntvfs->ops->open(ntvfs, req, io2);
548 status = NT_STATUS_INVALID_LEVEL;
552 return ntvfs_map_async_finish(req, status);
557 NTVFS fsinfo generic to any mapper
559 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
560 struct ntvfs_request *req,
561 union smb_fsinfo *fs)
564 union smb_fsinfo *fs2;
566 fs2 = talloc(req, union smb_fsinfo);
568 return NT_STATUS_NO_MEMORY;
571 if (fs->generic.level == RAW_QFS_GENERIC) {
572 return NT_STATUS_INVALID_LEVEL;
575 /* only used by the simple backend, which doesn't do async */
576 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
578 /* ask the backend for the generic info */
579 fs2->generic.level = RAW_QFS_GENERIC;
581 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
582 if (!NT_STATUS_IS_OK(status)) {
586 /* and convert it to the required level */
587 switch (fs->generic.level) {
588 case RAW_QFS_GENERIC:
589 return NT_STATUS_INVALID_LEVEL;
591 case RAW_QFS_DSKATTR: {
592 /* map from generic to DSKATTR */
595 /* we need to scale the sizes to fit */
596 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
597 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
602 fs->dskattr.out.blocks_per_unit = bpunit;
603 fs->dskattr.out.block_size = 512;
604 fs->dskattr.out.units_total =
605 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
606 fs->dskattr.out.units_free =
607 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
609 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
610 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
611 fs->dskattr.out.blocks_per_unit = 64;
612 fs->dskattr.out.units_total = 0xFFFF;
613 fs->dskattr.out.units_free = 0xFFFF;
618 case RAW_QFS_ALLOCATION:
619 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
620 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
621 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
622 fs->allocation.out.sectors_per_unit = 1;
623 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
627 fs->volume.out.serial_number = fs2->generic.out.serial_number;
628 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
631 case RAW_QFS_VOLUME_INFO:
632 case RAW_QFS_VOLUME_INFORMATION:
633 fs->volume_info.out.create_time = fs2->generic.out.create_time;
634 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
635 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
638 case RAW_QFS_SIZE_INFO:
639 case RAW_QFS_SIZE_INFORMATION:
640 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
641 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
642 fs->size_info.out.sectors_per_unit = 1;
643 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
646 case RAW_QFS_DEVICE_INFO:
647 case RAW_QFS_DEVICE_INFORMATION:
648 fs->device_info.out.device_type = fs2->generic.out.device_type;
649 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
652 case RAW_QFS_ATTRIBUTE_INFO:
653 case RAW_QFS_ATTRIBUTE_INFORMATION:
654 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
655 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
656 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
659 case RAW_QFS_QUOTA_INFORMATION:
660 ZERO_STRUCT(fs->quota_information.out.unknown);
661 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
662 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
663 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
666 case RAW_QFS_FULL_SIZE_INFORMATION:
667 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
668 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
669 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
670 fs->full_size_information.out.sectors_per_unit = 1;
671 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
674 case RAW_QFS_OBJECTID_INFORMATION:
675 fs->objectid_information.out.guid = fs2->generic.out.guid;
676 ZERO_STRUCT(fs->objectid_information.out.unknown);
681 return NT_STATUS_INVALID_LEVEL;
686 NTVFS fileinfo generic to any mapper
688 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
689 union smb_fileinfo *info,
690 union smb_fileinfo *info2)
693 /* and convert it to the required level using results in info2 */
694 switch (info->generic.level) {
695 case RAW_FILEINFO_GENERIC:
696 return NT_STATUS_INVALID_LEVEL;
697 case RAW_FILEINFO_GETATTR:
698 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
699 info->getattr.out.size = info2->generic.out.size;
700 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
703 case RAW_FILEINFO_GETATTRE:
704 info->getattre.out.attrib = info2->generic.out.attrib;
705 info->getattre.out.size = info2->generic.out.size;
706 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
707 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
708 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
709 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
712 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
713 info->network_open_information.out.create_time = info2->generic.out.create_time;
714 info->network_open_information.out.access_time = info2->generic.out.access_time;
715 info->network_open_information.out.write_time = info2->generic.out.write_time;
716 info->network_open_information.out.change_time = info2->generic.out.change_time;
717 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
718 info->network_open_information.out.size = info2->generic.out.size;
719 info->network_open_information.out.attrib = info2->generic.out.attrib;
722 case RAW_FILEINFO_ALL_INFO:
723 case RAW_FILEINFO_ALL_INFORMATION:
724 info->all_info.out.create_time = info2->generic.out.create_time;
725 info->all_info.out.access_time = info2->generic.out.access_time;
726 info->all_info.out.write_time = info2->generic.out.write_time;
727 info->all_info.out.change_time = info2->generic.out.change_time;
728 info->all_info.out.attrib = info2->generic.out.attrib;
729 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
730 info->all_info.out.size = info2->generic.out.size;
731 info->all_info.out.nlink = info2->generic.out.nlink;
732 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
733 info->all_info.out.directory = info2->generic.out.directory;
734 info->all_info.out.ea_size = info2->generic.out.ea_size;
735 info->all_info.out.fname.s = info2->generic.out.fname.s;
736 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
739 case RAW_FILEINFO_BASIC_INFO:
740 case RAW_FILEINFO_BASIC_INFORMATION:
741 info->basic_info.out.create_time = info2->generic.out.create_time;
742 info->basic_info.out.access_time = info2->generic.out.access_time;
743 info->basic_info.out.write_time = info2->generic.out.write_time;
744 info->basic_info.out.change_time = info2->generic.out.change_time;
745 info->basic_info.out.attrib = info2->generic.out.attrib;
748 case RAW_FILEINFO_STANDARD:
749 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
750 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
751 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
752 info->standard.out.size = info2->generic.out.size;
753 info->standard.out.alloc_size = info2->generic.out.alloc_size;
754 info->standard.out.attrib = info2->generic.out.attrib;
757 case RAW_FILEINFO_EA_SIZE:
758 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
759 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
760 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
761 info->ea_size.out.size = info2->generic.out.size;
762 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
763 info->ea_size.out.attrib = info2->generic.out.attrib;
764 info->ea_size.out.ea_size = info2->generic.out.ea_size;
767 case RAW_FILEINFO_STANDARD_INFO:
768 case RAW_FILEINFO_STANDARD_INFORMATION:
769 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
770 info->standard_info.out.size = info2->generic.out.size;
771 info->standard_info.out.nlink = info2->generic.out.nlink;
772 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
773 info->standard_info.out.directory = info2->generic.out.directory;
776 case RAW_FILEINFO_INTERNAL_INFORMATION:
777 info->internal_information.out.file_id = info2->generic.out.file_id;
780 case RAW_FILEINFO_EA_INFO:
781 case RAW_FILEINFO_EA_INFORMATION:
782 info->ea_info.out.ea_size = info2->generic.out.ea_size;
785 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
786 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
787 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
790 case RAW_FILEINFO_STREAM_INFO:
791 case RAW_FILEINFO_STREAM_INFORMATION:
792 info->stream_info.out.num_streams = info2->generic.out.num_streams;
793 if (info->stream_info.out.num_streams > 0) {
794 info->stream_info.out.streams =
795 talloc_array(mem_ctx,
796 struct stream_struct,
797 info->stream_info.out.num_streams);
798 if (!info->stream_info.out.streams) {
799 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
800 info->stream_info.out.num_streams));
801 return NT_STATUS_NO_MEMORY;
803 for (i=0; i < info->stream_info.out.num_streams; i++) {
804 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
805 info->stream_info.out.streams[i].stream_name.s =
806 talloc_strdup(info->stream_info.out.streams,
807 info2->generic.out.streams[i].stream_name.s);
808 if (!info->stream_info.out.streams[i].stream_name.s) {
809 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
810 return NT_STATUS_NO_MEMORY;
816 case RAW_FILEINFO_NAME_INFO:
817 case RAW_FILEINFO_NAME_INFORMATION:
818 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
819 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
820 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
823 case RAW_FILEINFO_ALT_NAME_INFO:
824 case RAW_FILEINFO_ALT_NAME_INFORMATION:
825 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
826 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
827 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
830 case RAW_FILEINFO_POSITION_INFORMATION:
831 info->position_information.out.position = info2->generic.out.position;
834 case RAW_FILEINFO_ALL_EAS:
835 info->all_eas.out.num_eas = info2->generic.out.num_eas;
836 if (info->all_eas.out.num_eas > 0) {
837 info->all_eas.out.eas = talloc_array(mem_ctx,
839 info->all_eas.out.num_eas);
840 if (!info->all_eas.out.eas) {
841 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
842 info->all_eas.out.num_eas));
843 return NT_STATUS_NO_MEMORY;
845 for (i = 0; i < info->all_eas.out.num_eas; i++) {
846 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
847 info->all_eas.out.eas[i].name.s =
848 talloc_strdup(info->all_eas.out.eas,
849 info2->generic.out.eas[i].name.s);
850 if (!info->all_eas.out.eas[i].name.s) {
851 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
852 return NT_STATUS_NO_MEMORY;
854 info->all_eas.out.eas[i].value.data =
855 talloc_memdup(info->all_eas.out.eas,
856 info2->generic.out.eas[i].value.data,
857 info2->generic.out.eas[i].value.length);
858 if (!info->all_eas.out.eas[i].value.data) {
859 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
860 return NT_STATUS_NO_MEMORY;
866 case RAW_FILEINFO_IS_NAME_VALID:
869 case RAW_FILEINFO_COMPRESSION_INFO:
870 case RAW_FILEINFO_COMPRESSION_INFORMATION:
871 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
872 info->compression_info.out.format = info2->generic.out.format;
873 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
874 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
875 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
878 case RAW_FILEINFO_ACCESS_INFORMATION:
879 info->access_information.out.access_flags = info2->generic.out.access_flags;
882 case RAW_FILEINFO_MODE_INFORMATION:
883 info->mode_information.out.mode = info2->generic.out.mode;
886 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
887 info->alignment_information.out.alignment_requirement =
888 info2->generic.out.alignment_requirement;
891 case RAW_FILEINFO_UNIX_BASIC:
892 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
893 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
894 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
895 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
896 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
897 info->unix_basic_info.out.uid = info2->generic.out.uid;
898 info->unix_basic_info.out.gid = info2->generic.out.gid;
899 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
900 info->unix_basic_info.out.dev_major = info2->generic.out.device;
901 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
902 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
903 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
904 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
907 case RAW_FILEINFO_UNIX_LINK:
908 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
913 return NT_STATUS_INVALID_LEVEL;
917 NTVFS fileinfo generic to any mapper
919 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
920 struct ntvfs_request *req,
921 union smb_fileinfo *info)
924 union smb_fileinfo *info2;
926 info2 = talloc(req, union smb_fileinfo);
928 return NT_STATUS_NO_MEMORY;
931 if (info->generic.level == RAW_FILEINFO_GENERIC) {
932 return NT_STATUS_INVALID_LEVEL;
935 /* ask the backend for the generic info */
936 info2->generic.level = RAW_FILEINFO_GENERIC;
937 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
939 /* only used by the simple backend, which doesn't do async */
940 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
942 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
943 if (!NT_STATUS_IS_OK(status)) {
946 return ntvfs_map_fileinfo(req, info, info2);
950 NTVFS pathinfo generic to any mapper
952 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
953 struct ntvfs_request *req,
954 union smb_fileinfo *info)
957 union smb_fileinfo *info2;
959 info2 = talloc(req, union smb_fileinfo);
961 return NT_STATUS_NO_MEMORY;
964 if (info->generic.level == RAW_FILEINFO_GENERIC) {
965 return NT_STATUS_INVALID_LEVEL;
968 /* ask the backend for the generic info */
969 info2->generic.level = RAW_FILEINFO_GENERIC;
970 info2->generic.in.file.path = info->generic.in.file.path;
972 /* only used by the simple backend, which doesn't do async */
973 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
975 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
976 if (!NT_STATUS_IS_OK(status)) {
979 return ntvfs_map_fileinfo(req, info, info2);
984 NTVFS lock generic to any mapper
986 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
987 struct ntvfs_request *req,
990 union smb_lock *lck2;
991 struct smb_lock_entry *locks;
993 lck2 = talloc(req, union smb_lock);
995 return NT_STATUS_NO_MEMORY;
998 locks = talloc_array(lck2, struct smb_lock_entry, 1);
1000 return NT_STATUS_NO_MEMORY;
1003 switch (lck->generic.level) {
1004 case RAW_LOCK_LOCKX:
1005 return NT_STATUS_INVALID_LEVEL;
1008 lck2->generic.level = RAW_LOCK_GENERIC;
1009 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1010 lck2->generic.in.mode = 0;
1011 lck2->generic.in.timeout = 0;
1012 lck2->generic.in.ulock_cnt = 0;
1013 lck2->generic.in.lock_cnt = 1;
1014 lck2->generic.in.locks = locks;
1015 locks->pid = req->smbpid;
1016 locks->offset = lck->lock.in.offset;
1017 locks->count = lck->lock.in.count;
1020 case RAW_LOCK_UNLOCK:
1021 lck2->generic.level = RAW_LOCK_GENERIC;
1022 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1023 lck2->generic.in.mode = 0;
1024 lck2->generic.in.timeout = 0;
1025 lck2->generic.in.ulock_cnt = 1;
1026 lck2->generic.in.lock_cnt = 0;
1027 lck2->generic.in.locks = locks;
1028 locks->pid = req->smbpid;
1029 locks->offset = lck->unlock.in.offset;
1030 locks->count = lck->unlock.in.count;
1033 case RAW_LOCK_SMB2: {
1034 /* this is only approximate! We need to change the
1035 generic structure to fix this properly */
1038 if (lck->smb2.in.lock_count < 1) {
1039 return NT_STATUS_INVALID_PARAMETER;
1042 lck2->generic.level = RAW_LOCK_GENERIC;
1043 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1044 lck2->generic.in.timeout = UINT32_MAX;
1045 lck2->generic.in.mode = 0;
1046 lck2->generic.in.lock_cnt = 0;
1047 lck2->generic.in.ulock_cnt = 0;
1048 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry,
1049 lck->smb2.in.lock_count);
1050 if (lck2->generic.in.locks == NULL) {
1051 return NT_STATUS_NO_MEMORY;
1053 /* only the first lock gives the UNLOCK bit - see
1055 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1056 lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1059 lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1062 for (i=0;i<lck->smb2.in.lock_count;i++) {
1064 (lck->smb2.in.locks[i].flags &
1065 (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1066 return NT_STATUS_INVALID_PARAMETER;
1069 (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1070 return NT_STATUS_INVALID_PARAMETER;
1072 lck2->generic.in.locks[i].pid = req->smbpid;
1073 lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
1074 lck2->generic.in.locks[i].count = lck->smb2.in.locks[i].length;
1075 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1076 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1078 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1079 lck2->generic.in.timeout = 0;
1082 /* initialize output value */
1083 lck->smb2.out.reserved = 0;
1087 case RAW_LOCK_SMB2_BREAK:
1088 lck2->generic.level = RAW_LOCK_GENERIC;
1089 lck2->generic.in.file.ntvfs = lck->smb2_break.in.file.ntvfs;
1090 lck2->generic.in.mode = LOCKING_ANDX_OPLOCK_RELEASE |
1091 ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1092 lck2->generic.in.timeout = 0;
1093 lck2->generic.in.ulock_cnt = 0;
1094 lck2->generic.in.lock_cnt = 0;
1095 lck2->generic.in.locks = NULL;
1097 /* initialize output value */
1098 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1099 lck->smb2_break.out.reserved = lck->smb2_break.in.reserved;
1100 lck->smb2_break.out.reserved2 = lck->smb2_break.in.reserved2;
1101 lck->smb2_break.out.file = lck->smb2_break.in.file;
1106 * we don't need to call ntvfs_map_async_setup() here,
1107 * as lock() doesn't have any output fields
1110 return ntvfs->ops->lock(ntvfs, req, lck2);
1115 NTVFS write generic to any mapper
1117 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1118 struct ntvfs_request *req,
1119 union smb_write *wr,
1120 union smb_write *wr2,
1123 union smb_lock *lck;
1124 union smb_close *cl;
1127 if (NT_STATUS_IS_ERR(status)) {
1131 switch (wr->generic.level) {
1132 case RAW_WRITE_WRITE:
1133 wr->write.out.nwritten = wr2->generic.out.nwritten;
1136 case RAW_WRITE_WRITEUNLOCK:
1137 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1139 lck = talloc(wr2, union smb_lock);
1141 return NT_STATUS_NO_MEMORY;
1144 lck->unlock.level = RAW_LOCK_UNLOCK;
1145 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1146 lck->unlock.in.count = wr->writeunlock.in.count;
1147 lck->unlock.in.offset = wr->writeunlock.in.offset;
1149 if (lck->unlock.in.count != 0) {
1150 /* do the lock sync for now */
1151 state = req->async_states->state;
1152 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1153 status = ntvfs->ops->lock(ntvfs, req, lck);
1154 req->async_states->state = state;
1158 case RAW_WRITE_WRITECLOSE:
1159 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1161 cl = talloc(wr2, union smb_close);
1163 return NT_STATUS_NO_MEMORY;
1166 cl->close.level = RAW_CLOSE_CLOSE;
1167 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1168 cl->close.in.write_time = wr->writeclose.in.mtime;
1170 if (wr2->generic.in.count != 0) {
1171 /* do the close sync for now */
1172 state = req->async_states->state;
1173 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1174 status = ntvfs->ops->close(ntvfs, req, cl);
1175 req->async_states->state = state;
1179 case RAW_WRITE_SPLWRITE:
1182 case RAW_WRITE_SMB2:
1183 wr->smb2.out._pad = 0;
1184 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1185 wr->smb2.out.unknown1 = 0;
1189 return NT_STATUS_INVALID_LEVEL;
1197 NTVFS write generic to any mapper
1199 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1200 struct ntvfs_request *req,
1201 union smb_write *wr)
1203 union smb_write *wr2;
1206 wr2 = talloc(req, union smb_write);
1208 return NT_STATUS_NO_MEMORY;
1211 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1212 (second_stage_t)ntvfs_map_write_finish);
1213 if (!NT_STATUS_IS_OK(status)) {
1217 wr2->writex.level = RAW_WRITE_GENERIC;
1219 switch (wr->generic.level) {
1220 case RAW_WRITE_WRITEX:
1221 status = NT_STATUS_INVALID_LEVEL;
1224 case RAW_WRITE_WRITE:
1225 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1226 wr2->writex.in.offset = wr->write.in.offset;
1227 wr2->writex.in.wmode = 0;
1228 wr2->writex.in.remaining = wr->write.in.remaining;
1229 wr2->writex.in.count = wr->write.in.count;
1230 wr2->writex.in.data = wr->write.in.data;
1231 status = ntvfs->ops->write(ntvfs, req, wr2);
1234 case RAW_WRITE_WRITEUNLOCK:
1235 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1236 wr2->writex.in.offset = wr->writeunlock.in.offset;
1237 wr2->writex.in.wmode = 0;
1238 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1239 wr2->writex.in.count = wr->writeunlock.in.count;
1240 wr2->writex.in.data = wr->writeunlock.in.data;
1241 status = ntvfs->ops->write(ntvfs, req, wr2);
1244 case RAW_WRITE_WRITECLOSE:
1245 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1246 wr2->writex.in.offset = wr->writeclose.in.offset;
1247 wr2->writex.in.wmode = 0;
1248 wr2->writex.in.remaining = 0;
1249 wr2->writex.in.count = wr->writeclose.in.count;
1250 wr2->writex.in.data = wr->writeclose.in.data;
1251 status = ntvfs->ops->write(ntvfs, req, wr2);
1254 case RAW_WRITE_SPLWRITE:
1255 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1256 wr2->writex.in.offset = 0;
1257 wr2->writex.in.wmode = 0;
1258 wr2->writex.in.remaining = 0;
1259 wr2->writex.in.count = wr->splwrite.in.count;
1260 wr2->writex.in.data = wr->splwrite.in.data;
1261 status = ntvfs->ops->write(ntvfs, req, wr2);
1264 case RAW_WRITE_SMB2:
1265 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1266 wr2->writex.in.offset = wr->smb2.in.offset;
1267 wr2->writex.in.wmode = 0;
1268 wr2->writex.in.remaining = 0;
1269 wr2->writex.in.count = wr->smb2.in.data.length;
1270 wr2->writex.in.data = wr->smb2.in.data.data;
1271 status = ntvfs->ops->write(ntvfs, req, wr2);
1274 return ntvfs_map_async_finish(req, status);
1279 NTVFS read generic to any mapper - finish the out mapping
1281 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1282 struct ntvfs_request *req,
1284 union smb_read *rd2,
1287 switch (rd->generic.level) {
1289 rd->read.out.nread = rd2->generic.out.nread;
1291 case RAW_READ_READBRAW:
1292 rd->readbraw.out.nread = rd2->generic.out.nread;
1294 case RAW_READ_LOCKREAD:
1295 rd->lockread.out.nread = rd2->generic.out.nread;
1298 rd->smb2.out.data.length= rd2->generic.out.nread;
1299 rd->smb2.out.remaining = 0;
1300 rd->smb2.out.reserved = 0;
1303 return NT_STATUS_INVALID_LEVEL;
1310 NTVFS read* to readx mapper
1312 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1313 struct ntvfs_request *req,
1316 union smb_read *rd2;
1317 union smb_lock *lck;
1321 rd2 = talloc(req, union smb_read);
1323 return NT_STATUS_NO_MEMORY;
1326 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1327 (second_stage_t)ntvfs_map_read_finish);
1328 if (!NT_STATUS_IS_OK(status)) {
1332 rd2->readx.level = RAW_READ_READX;
1333 rd2->readx.in.read_for_execute = false;
1335 switch (rd->generic.level) {
1336 case RAW_READ_READX:
1337 status = NT_STATUS_INVALID_LEVEL;
1341 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1342 rd2->readx.in.offset = rd->read.in.offset;
1343 rd2->readx.in.mincnt = rd->read.in.count;
1344 rd2->readx.in.maxcnt = rd->read.in.count;
1345 rd2->readx.in.remaining = rd->read.in.remaining;
1346 rd2->readx.out.data = rd->read.out.data;
1347 status = ntvfs->ops->read(ntvfs, req, rd2);
1350 case RAW_READ_READBRAW:
1351 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1352 rd2->readx.in.offset = rd->readbraw.in.offset;
1353 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1354 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1355 rd2->readx.in.remaining = 0;
1356 rd2->readx.out.data = rd->readbraw.out.data;
1357 status = ntvfs->ops->read(ntvfs, req, rd2);
1360 case RAW_READ_LOCKREAD:
1361 /* do the initial lock sync for now */
1362 state = req->async_states->state;
1363 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1365 lck = talloc(rd2, union smb_lock);
1367 status = NT_STATUS_NO_MEMORY;
1370 lck->lock.level = RAW_LOCK_LOCK;
1371 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1372 lck->lock.in.count = rd->lockread.in.count;
1373 lck->lock.in.offset = rd->lockread.in.offset;
1374 status = ntvfs->ops->lock(ntvfs, req, lck);
1375 req->async_states->state = state;
1377 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1378 rd2->readx.in.offset = rd->lockread.in.offset;
1379 rd2->readx.in.mincnt = rd->lockread.in.count;
1380 rd2->readx.in.maxcnt = rd->lockread.in.count;
1381 rd2->readx.in.remaining = rd->lockread.in.remaining;
1382 rd2->readx.out.data = rd->lockread.out.data;
1384 if (NT_STATUS_IS_OK(status)) {
1385 status = ntvfs->ops->read(ntvfs, req, rd2);
1390 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1391 rd2->readx.in.offset = rd->smb2.in.offset;
1392 rd2->readx.in.mincnt = rd->smb2.in.min_count;
1393 rd2->readx.in.maxcnt = rd->smb2.in.length;
1394 rd2->readx.in.remaining = 0;
1395 rd2->readx.out.data = rd->smb2.out.data.data;
1396 status = ntvfs->ops->read(ntvfs, req, rd2);
1401 return ntvfs_map_async_finish(req, status);
1406 NTVFS close generic to any mapper
1408 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1409 struct ntvfs_request *req,
1410 union smb_close *cl,
1411 union smb_close *cl2,
1414 NT_STATUS_NOT_OK_RETURN(status);
1416 switch (cl->generic.level) {
1417 case RAW_CLOSE_SMB2:
1418 cl->smb2.out.flags = cl2->generic.out.flags;
1419 cl->smb2.out._pad = 0;
1420 cl->smb2.out.create_time = cl2->generic.out.create_time;
1421 cl->smb2.out.access_time = cl2->generic.out.access_time;
1422 cl->smb2.out.write_time = cl2->generic.out.write_time;
1423 cl->smb2.out.change_time = cl2->generic.out.change_time;
1424 cl->smb2.out.alloc_size = cl2->generic.out.alloc_size;
1425 cl->smb2.out.size = cl2->generic.out.size;
1426 cl->smb2.out.file_attr = cl2->generic.out.file_attr;
1436 NTVFS close generic to any mapper
1438 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1439 struct ntvfs_request *req,
1440 union smb_close *cl)
1442 union smb_close *cl2;
1445 cl2 = talloc(req, union smb_close);
1447 return NT_STATUS_NO_MEMORY;
1450 switch (cl->generic.level) {
1451 case RAW_CLOSE_GENERIC:
1452 return NT_STATUS_INVALID_LEVEL;
1454 case RAW_CLOSE_CLOSE:
1455 cl2->generic.level = RAW_CLOSE_GENERIC;
1456 cl2->generic.in.file = cl->close.in.file;
1457 cl2->generic.in.write_time = cl->close.in.write_time;
1458 cl2->generic.in.flags = 0;
1461 case RAW_CLOSE_SPLCLOSE:
1462 cl2->generic.level = RAW_CLOSE_GENERIC;
1463 cl2->generic.in.file = cl->splclose.in.file;
1464 cl2->generic.in.write_time = 0;
1465 cl2->generic.in.flags = 0;
1468 case RAW_CLOSE_SMB2:
1469 cl2->generic.level = RAW_CLOSE_GENERIC;
1470 cl2->generic.in.file = cl->smb2.in.file;
1471 cl2->generic.in.write_time = 0;
1472 cl2->generic.in.flags = cl->smb2.in.flags;
1476 status = ntvfs_map_async_setup(ntvfs, req, cl, cl2,
1477 (second_stage_t)ntvfs_map_close_finish);
1478 NT_STATUS_NOT_OK_RETURN(status);
1480 status = ntvfs->ops->close(ntvfs, req, cl2);
1482 return ntvfs_map_async_finish(req, status);
1486 NTVFS notify generic to any mapper
1488 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1489 struct ntvfs_request *req,
1490 union smb_notify *nt,
1491 union smb_notify *nt2,
1494 NT_STATUS_NOT_OK_RETURN(status);
1496 switch (nt->nttrans.level) {
1497 case RAW_NOTIFY_SMB2:
1498 if (nt2->nttrans.out.num_changes == 0) {
1499 return STATUS_NOTIFY_ENUM_DIR;
1501 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1502 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1506 return NT_STATUS_INVALID_LEVEL;
1514 NTVFS notify generic to any mapper
1516 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1517 struct ntvfs_request *req,
1518 union smb_notify *nt)
1520 union smb_notify *nt2;
1523 nt2 = talloc(req, union smb_notify);
1524 NT_STATUS_HAVE_NO_MEMORY(nt2);
1526 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1527 (second_stage_t)ntvfs_map_notify_finish);
1528 NT_STATUS_NOT_OK_RETURN(status);
1530 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1532 switch (nt->nttrans.level) {
1533 case RAW_NOTIFY_NTTRANS:
1534 status = NT_STATUS_INVALID_LEVEL;
1537 case RAW_NOTIFY_SMB2:
1538 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1539 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1540 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1541 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1542 status = ntvfs->ops->notify(ntvfs, req, nt2);
1546 return ntvfs_map_async_finish(req, status);