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 io2->generic.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
286 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
287 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
289 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
290 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
293 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
294 case OPENX_MODE_ACCESS_READ:
295 case OPENX_MODE_ACCESS_EXEC:
296 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
298 case OPENX_MODE_ACCESS_WRITE:
299 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
301 case OPENX_MODE_ACCESS_RDWR:
302 case OPENX_MODE_ACCESS_FCB:
303 io2->generic.in.access_mask =
304 SEC_RIGHTS_FILE_READ |
305 SEC_RIGHTS_FILE_WRITE;
308 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
311 switch (open_mode & OPENX_MODE_DENY_MASK) {
312 case OPENX_MODE_DENY_READ:
313 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
315 case OPENX_MODE_DENY_WRITE:
316 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
318 case OPENX_MODE_DENY_ALL:
319 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
321 case OPENX_MODE_DENY_NONE:
322 io2->generic.in.share_access =
323 NTCREATEX_SHARE_ACCESS_READ |
324 NTCREATEX_SHARE_ACCESS_WRITE;
326 case OPENX_MODE_DENY_DOS:
327 /* DENY_DOS is quite strange - it depends on the filename! */
328 io2->generic.in.create_options |=
329 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
330 if (is_exe_filename(fname)) {
331 io2->generic.in.share_access =
332 NTCREATEX_SHARE_ACCESS_READ |
333 NTCREATEX_SHARE_ACCESS_WRITE;
335 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
336 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
338 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
342 case OPENX_MODE_DENY_FCB:
343 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
344 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
347 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
351 case (OPENX_OPEN_FUNC_OPEN):
352 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
354 case (OPENX_OPEN_FUNC_TRUNC):
355 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
357 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
358 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
360 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
361 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
363 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
364 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
367 /* this one is very strange */
368 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
369 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
372 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
379 NTVFS open generic to any mapper
381 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
382 struct ntvfs_request *req,
388 io2 = talloc_zero(req, union smb_open);
390 return NT_STATUS_NO_MEMORY;
393 status = ntvfs_map_async_setup(ntvfs, req,
395 (second_stage_t)ntvfs_map_open_finish);
396 if (!NT_STATUS_IS_OK(status)) {
400 io2->generic.level = RAW_OPEN_GENERIC;
402 switch (io->generic.level) {
404 status = map_openx_open(io->openx.in.flags,
405 io->openx.in.open_mode,
406 io->openx.in.open_func,
409 if (!NT_STATUS_IS_OK(status)) {
413 io2->generic.in.file_attr = io->openx.in.file_attrs;
414 io2->generic.in.fname = io->openx.in.fname;
416 status = ntvfs->ops->open(ntvfs, req, io2);
421 status = map_openx_open(0,
422 io->openold.in.open_mode,
423 OPENX_OPEN_FUNC_OPEN,
424 io->openold.in.fname,
426 if (!NT_STATUS_IS_OK(status)) {
430 io2->generic.in.file_attr = io->openold.in.search_attrs;
431 io2->generic.in.fname = io->openold.in.fname;
433 status = ntvfs->ops->open(ntvfs, req, io2);
436 case RAW_OPEN_T2OPEN:
437 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
439 if (io->t2open.in.open_func == 0) {
440 status = NT_STATUS_OBJECT_NAME_COLLISION;
444 status = map_openx_open(io->t2open.in.flags,
445 io->t2open.in.open_mode,
446 io->t2open.in.open_func,
449 if (!NT_STATUS_IS_OK(status)) {
453 io2->generic.in.file_attr = io->t2open.in.file_attrs;
454 io2->generic.in.fname = io->t2open.in.fname;
455 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
456 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
457 io2->generic.in.ea_list->eas = io->t2open.in.eas;
459 status = ntvfs->ops->open(ntvfs, req, io2);
463 io2->generic.in.file_attr = io->mknew.in.attrib;
464 io2->generic.in.fname = io->mknew.in.fname;
465 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
466 io2->generic.in.access_mask =
467 SEC_RIGHTS_FILE_READ |
468 SEC_RIGHTS_FILE_WRITE;
469 io2->generic.in.share_access =
470 NTCREATEX_SHARE_ACCESS_READ |
471 NTCREATEX_SHARE_ACCESS_WRITE;
472 status = ntvfs->ops->open(ntvfs, req, io2);
475 case RAW_OPEN_CREATE:
476 io2->generic.in.file_attr = io->mknew.in.attrib;
477 io2->generic.in.fname = io->mknew.in.fname;
478 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
479 io2->generic.in.access_mask =
480 SEC_RIGHTS_FILE_READ |
481 SEC_RIGHTS_FILE_WRITE;
482 io2->generic.in.share_access =
483 NTCREATEX_SHARE_ACCESS_READ |
484 NTCREATEX_SHARE_ACCESS_WRITE;
485 status = ntvfs->ops->open(ntvfs, req, io2);
489 io2->generic.in.file_attr = io->ctemp.in.attrib;
490 io2->generic.in.fname =
491 talloc_asprintf(io2, "%s\\SRV%s",
492 io->ctemp.in.directory,
493 generate_random_str_list(io2, 5, "0123456789"));
494 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
495 io2->generic.in.access_mask =
496 SEC_RIGHTS_FILE_READ |
497 SEC_RIGHTS_FILE_WRITE;
498 io2->generic.in.share_access =
499 NTCREATEX_SHARE_ACCESS_READ |
500 NTCREATEX_SHARE_ACCESS_WRITE;
501 status = ntvfs->ops->open(ntvfs, req, io2);
504 switch (io->smb2.in.oplock_level) {
505 case SMB2_OPLOCK_LEVEL_BATCH:
506 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
507 NTCREATEX_FLAGS_REQUEST_OPLOCK;
509 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
510 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
513 io2->generic.in.flags = 0;
516 io2->generic.in.root_fid = 0;
517 io2->generic.in.access_mask = io->smb2.in.desired_access;
518 io2->generic.in.alloc_size = io->smb2.in.alloc_size;
519 io2->generic.in.file_attr = io->smb2.in.file_attributes;
520 io2->generic.in.share_access = io->smb2.in.share_access;
521 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
522 io2->generic.in.create_options = io->smb2.in.create_options;
523 io2->generic.in.impersonation = io->smb2.in.impersonation_level;
524 io2->generic.in.security_flags = 0;
525 io2->generic.in.fname = io->smb2.in.fname;
526 io2->generic.in.sec_desc = io->smb2.in.sec_desc;
527 io2->generic.in.ea_list = &io->smb2.in.eas;
528 io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access;
530 /* we don't support timewarp yet */
531 if (io->smb2.in.timewarp != 0) {
532 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
536 /* we need to check these bits before we check the private mask */
537 if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
538 DEBUG(2,(__location__ " create_options 0x%x not supported\n",
539 io2->generic.in.create_options));
540 status = NT_STATUS_NOT_SUPPORTED;
544 /* TODO: find out why only SMB2 ignores these */
545 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
546 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
548 status = ntvfs->ops->open(ntvfs, req, io2);
552 status = NT_STATUS_INVALID_LEVEL;
556 return ntvfs_map_async_finish(req, status);
561 NTVFS fsinfo generic to any mapper
563 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
564 struct ntvfs_request *req,
565 union smb_fsinfo *fs)
568 union smb_fsinfo *fs2;
570 fs2 = talloc(req, union smb_fsinfo);
572 return NT_STATUS_NO_MEMORY;
575 if (fs->generic.level == RAW_QFS_GENERIC) {
576 return NT_STATUS_INVALID_LEVEL;
579 /* only used by the simple backend, which doesn't do async */
580 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
582 /* ask the backend for the generic info */
583 fs2->generic.level = RAW_QFS_GENERIC;
585 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
586 if (!NT_STATUS_IS_OK(status)) {
590 /* and convert it to the required level */
591 switch (fs->generic.level) {
592 case RAW_QFS_GENERIC:
593 return NT_STATUS_INVALID_LEVEL;
595 case RAW_QFS_DSKATTR: {
596 /* map from generic to DSKATTR */
599 /* we need to scale the sizes to fit */
600 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
601 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
606 fs->dskattr.out.blocks_per_unit = bpunit;
607 fs->dskattr.out.block_size = 512;
608 fs->dskattr.out.units_total =
609 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
610 fs->dskattr.out.units_free =
611 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
613 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
614 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
615 fs->dskattr.out.blocks_per_unit = 64;
616 fs->dskattr.out.units_total = 0xFFFF;
617 fs->dskattr.out.units_free = 0xFFFF;
622 case RAW_QFS_ALLOCATION:
623 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
624 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
625 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
626 fs->allocation.out.sectors_per_unit = 1;
627 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
631 fs->volume.out.serial_number = fs2->generic.out.serial_number;
632 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
635 case RAW_QFS_VOLUME_INFO:
636 case RAW_QFS_VOLUME_INFORMATION:
637 fs->volume_info.out.create_time = fs2->generic.out.create_time;
638 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
639 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
642 case RAW_QFS_SIZE_INFO:
643 case RAW_QFS_SIZE_INFORMATION:
644 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
645 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
646 fs->size_info.out.sectors_per_unit = 1;
647 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
650 case RAW_QFS_DEVICE_INFO:
651 case RAW_QFS_DEVICE_INFORMATION:
652 fs->device_info.out.device_type = fs2->generic.out.device_type;
653 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
656 case RAW_QFS_ATTRIBUTE_INFO:
657 case RAW_QFS_ATTRIBUTE_INFORMATION:
658 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
659 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
660 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
663 case RAW_QFS_QUOTA_INFORMATION:
664 ZERO_STRUCT(fs->quota_information.out.unknown);
665 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
666 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
667 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
670 case RAW_QFS_FULL_SIZE_INFORMATION:
671 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
672 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
673 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
674 fs->full_size_information.out.sectors_per_unit = 1;
675 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
678 case RAW_QFS_OBJECTID_INFORMATION:
679 fs->objectid_information.out.guid = fs2->generic.out.guid;
680 ZERO_STRUCT(fs->objectid_information.out.unknown);
685 return NT_STATUS_INVALID_LEVEL;
690 NTVFS fileinfo generic to any mapper
692 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
693 union smb_fileinfo *info,
694 union smb_fileinfo *info2)
697 /* and convert it to the required level using results in info2 */
698 switch (info->generic.level) {
699 case RAW_FILEINFO_GENERIC:
700 return NT_STATUS_INVALID_LEVEL;
701 case RAW_FILEINFO_GETATTR:
702 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
703 info->getattr.out.size = info2->generic.out.size;
704 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
707 case RAW_FILEINFO_GETATTRE:
708 info->getattre.out.attrib = info2->generic.out.attrib;
709 info->getattre.out.size = info2->generic.out.size;
710 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
711 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
712 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
713 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
716 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
717 info->network_open_information.out.create_time = info2->generic.out.create_time;
718 info->network_open_information.out.access_time = info2->generic.out.access_time;
719 info->network_open_information.out.write_time = info2->generic.out.write_time;
720 info->network_open_information.out.change_time = info2->generic.out.change_time;
721 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
722 info->network_open_information.out.size = info2->generic.out.size;
723 info->network_open_information.out.attrib = info2->generic.out.attrib;
726 case RAW_FILEINFO_ALL_INFO:
727 case RAW_FILEINFO_ALL_INFORMATION:
728 info->all_info.out.create_time = info2->generic.out.create_time;
729 info->all_info.out.access_time = info2->generic.out.access_time;
730 info->all_info.out.write_time = info2->generic.out.write_time;
731 info->all_info.out.change_time = info2->generic.out.change_time;
732 info->all_info.out.attrib = info2->generic.out.attrib;
733 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
734 info->all_info.out.size = info2->generic.out.size;
735 info->all_info.out.nlink = info2->generic.out.nlink;
736 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
737 info->all_info.out.directory = info2->generic.out.directory;
738 info->all_info.out.ea_size = info2->generic.out.ea_size;
739 info->all_info.out.fname.s = info2->generic.out.fname.s;
740 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
743 case RAW_FILEINFO_BASIC_INFO:
744 case RAW_FILEINFO_BASIC_INFORMATION:
745 info->basic_info.out.create_time = info2->generic.out.create_time;
746 info->basic_info.out.access_time = info2->generic.out.access_time;
747 info->basic_info.out.write_time = info2->generic.out.write_time;
748 info->basic_info.out.change_time = info2->generic.out.change_time;
749 info->basic_info.out.attrib = info2->generic.out.attrib;
752 case RAW_FILEINFO_STANDARD:
753 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
754 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
755 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
756 info->standard.out.size = info2->generic.out.size;
757 info->standard.out.alloc_size = info2->generic.out.alloc_size;
758 info->standard.out.attrib = info2->generic.out.attrib;
761 case RAW_FILEINFO_EA_SIZE:
762 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
763 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
764 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
765 info->ea_size.out.size = info2->generic.out.size;
766 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
767 info->ea_size.out.attrib = info2->generic.out.attrib;
768 info->ea_size.out.ea_size = info2->generic.out.ea_size;
771 case RAW_FILEINFO_STANDARD_INFO:
772 case RAW_FILEINFO_STANDARD_INFORMATION:
773 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
774 info->standard_info.out.size = info2->generic.out.size;
775 info->standard_info.out.nlink = info2->generic.out.nlink;
776 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
777 info->standard_info.out.directory = info2->generic.out.directory;
780 case RAW_FILEINFO_INTERNAL_INFORMATION:
781 info->internal_information.out.file_id = info2->generic.out.file_id;
784 case RAW_FILEINFO_EA_INFO:
785 case RAW_FILEINFO_EA_INFORMATION:
786 info->ea_info.out.ea_size = info2->generic.out.ea_size;
789 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
790 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
791 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
794 case RAW_FILEINFO_STREAM_INFO:
795 case RAW_FILEINFO_STREAM_INFORMATION:
796 info->stream_info.out.num_streams = info2->generic.out.num_streams;
797 if (info->stream_info.out.num_streams > 0) {
798 info->stream_info.out.streams =
799 talloc_array(mem_ctx,
800 struct stream_struct,
801 info->stream_info.out.num_streams);
802 if (!info->stream_info.out.streams) {
803 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
804 info->stream_info.out.num_streams));
805 return NT_STATUS_NO_MEMORY;
807 for (i=0; i < info->stream_info.out.num_streams; i++) {
808 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
809 info->stream_info.out.streams[i].stream_name.s =
810 talloc_strdup(info->stream_info.out.streams,
811 info2->generic.out.streams[i].stream_name.s);
812 if (!info->stream_info.out.streams[i].stream_name.s) {
813 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
814 return NT_STATUS_NO_MEMORY;
820 case RAW_FILEINFO_NAME_INFO:
821 case RAW_FILEINFO_NAME_INFORMATION:
822 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
823 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
824 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
827 case RAW_FILEINFO_ALT_NAME_INFO:
828 case RAW_FILEINFO_ALT_NAME_INFORMATION:
829 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
830 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
831 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
834 case RAW_FILEINFO_POSITION_INFORMATION:
835 info->position_information.out.position = info2->generic.out.position;
838 case RAW_FILEINFO_ALL_EAS:
839 info->all_eas.out.num_eas = info2->generic.out.num_eas;
840 if (info->all_eas.out.num_eas > 0) {
841 info->all_eas.out.eas = talloc_array(mem_ctx,
843 info->all_eas.out.num_eas);
844 if (!info->all_eas.out.eas) {
845 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
846 info->all_eas.out.num_eas));
847 return NT_STATUS_NO_MEMORY;
849 for (i = 0; i < info->all_eas.out.num_eas; i++) {
850 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
851 info->all_eas.out.eas[i].name.s =
852 talloc_strdup(info->all_eas.out.eas,
853 info2->generic.out.eas[i].name.s);
854 if (!info->all_eas.out.eas[i].name.s) {
855 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
856 return NT_STATUS_NO_MEMORY;
858 info->all_eas.out.eas[i].value.data =
859 talloc_memdup(info->all_eas.out.eas,
860 info2->generic.out.eas[i].value.data,
861 info2->generic.out.eas[i].value.length);
862 if (!info->all_eas.out.eas[i].value.data) {
863 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
864 return NT_STATUS_NO_MEMORY;
870 case RAW_FILEINFO_IS_NAME_VALID:
873 case RAW_FILEINFO_COMPRESSION_INFO:
874 case RAW_FILEINFO_COMPRESSION_INFORMATION:
875 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
876 info->compression_info.out.format = info2->generic.out.format;
877 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
878 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
879 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
882 case RAW_FILEINFO_ACCESS_INFORMATION:
883 info->access_information.out.access_flags = info2->generic.out.access_flags;
886 case RAW_FILEINFO_MODE_INFORMATION:
887 info->mode_information.out.mode = info2->generic.out.mode;
890 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
891 info->alignment_information.out.alignment_requirement =
892 info2->generic.out.alignment_requirement;
895 case RAW_FILEINFO_UNIX_BASIC:
896 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
897 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
898 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
899 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
900 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
901 info->unix_basic_info.out.uid = info2->generic.out.uid;
902 info->unix_basic_info.out.gid = info2->generic.out.gid;
903 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
904 info->unix_basic_info.out.dev_major = info2->generic.out.device;
905 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
906 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
907 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
908 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
911 case RAW_FILEINFO_UNIX_LINK:
912 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
917 return NT_STATUS_INVALID_LEVEL;
921 NTVFS fileinfo generic to any mapper
923 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
924 struct ntvfs_request *req,
925 union smb_fileinfo *info)
928 union smb_fileinfo *info2;
930 info2 = talloc(req, union smb_fileinfo);
932 return NT_STATUS_NO_MEMORY;
935 if (info->generic.level == RAW_FILEINFO_GENERIC) {
936 return NT_STATUS_INVALID_LEVEL;
939 /* ask the backend for the generic info */
940 info2->generic.level = RAW_FILEINFO_GENERIC;
941 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
943 /* only used by the simple backend, which doesn't do async */
944 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
946 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
947 if (!NT_STATUS_IS_OK(status)) {
950 return ntvfs_map_fileinfo(req, info, info2);
954 NTVFS pathinfo generic to any mapper
956 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
957 struct ntvfs_request *req,
958 union smb_fileinfo *info)
961 union smb_fileinfo *info2;
963 info2 = talloc(req, union smb_fileinfo);
965 return NT_STATUS_NO_MEMORY;
968 if (info->generic.level == RAW_FILEINFO_GENERIC) {
969 return NT_STATUS_INVALID_LEVEL;
972 /* ask the backend for the generic info */
973 info2->generic.level = RAW_FILEINFO_GENERIC;
974 info2->generic.in.file.path = info->generic.in.file.path;
976 /* only used by the simple backend, which doesn't do async */
977 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
979 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
980 if (!NT_STATUS_IS_OK(status)) {
983 return ntvfs_map_fileinfo(req, info, info2);
988 NTVFS lock generic to any mapper
990 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
991 struct ntvfs_request *req,
994 union smb_lock *lck2;
995 struct smb_lock_entry *locks;
997 lck2 = talloc(req, union smb_lock);
999 return NT_STATUS_NO_MEMORY;
1002 locks = talloc_array(lck2, struct smb_lock_entry, 1);
1003 if (locks == NULL) {
1004 return NT_STATUS_NO_MEMORY;
1007 switch (lck->generic.level) {
1008 case RAW_LOCK_LOCKX:
1009 return NT_STATUS_INVALID_LEVEL;
1012 lck2->generic.level = RAW_LOCK_GENERIC;
1013 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1014 lck2->generic.in.mode = 0;
1015 lck2->generic.in.timeout = 0;
1016 lck2->generic.in.ulock_cnt = 0;
1017 lck2->generic.in.lock_cnt = 1;
1018 lck2->generic.in.locks = locks;
1019 locks->pid = req->smbpid;
1020 locks->offset = lck->lock.in.offset;
1021 locks->count = lck->lock.in.count;
1024 case RAW_LOCK_UNLOCK:
1025 lck2->generic.level = RAW_LOCK_GENERIC;
1026 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1027 lck2->generic.in.mode = 0;
1028 lck2->generic.in.timeout = 0;
1029 lck2->generic.in.ulock_cnt = 1;
1030 lck2->generic.in.lock_cnt = 0;
1031 lck2->generic.in.locks = locks;
1032 locks->pid = req->smbpid;
1033 locks->offset = lck->unlock.in.offset;
1034 locks->count = lck->unlock.in.count;
1037 case RAW_LOCK_SMB2: {
1038 /* this is only approximate! We need to change the
1039 generic structure to fix this properly */
1042 if (lck->smb2.in.lock_count < 1) {
1043 return NT_STATUS_INVALID_PARAMETER;
1046 lck2->generic.level = RAW_LOCK_GENERIC;
1047 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1048 lck2->generic.in.timeout = UINT32_MAX;
1049 lck2->generic.in.mode = 0;
1050 lck2->generic.in.lock_cnt = 0;
1051 lck2->generic.in.ulock_cnt = 0;
1052 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry,
1053 lck->smb2.in.lock_count);
1054 if (lck2->generic.in.locks == NULL) {
1055 return NT_STATUS_NO_MEMORY;
1057 /* only the first lock gives the UNLOCK bit - see
1059 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1060 lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1063 lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1066 for (i=0;i<lck->smb2.in.lock_count;i++) {
1068 (lck->smb2.in.locks[i].flags &
1069 (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1070 return NT_STATUS_INVALID_PARAMETER;
1073 (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1074 return NT_STATUS_INVALID_PARAMETER;
1076 lck2->generic.in.locks[i].pid = req->smbpid;
1077 lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
1078 lck2->generic.in.locks[i].count = lck->smb2.in.locks[i].length;
1079 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1080 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1082 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1083 lck2->generic.in.timeout = 0;
1086 /* initialize output value */
1087 lck->smb2.out.reserved = 0;
1091 case RAW_LOCK_SMB2_BREAK:
1092 lck2->generic.level = RAW_LOCK_GENERIC;
1093 lck2->generic.in.file.ntvfs = lck->smb2_break.in.file.ntvfs;
1094 lck2->generic.in.mode = LOCKING_ANDX_OPLOCK_RELEASE |
1095 ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1096 lck2->generic.in.timeout = 0;
1097 lck2->generic.in.ulock_cnt = 0;
1098 lck2->generic.in.lock_cnt = 0;
1099 lck2->generic.in.locks = NULL;
1101 /* initialize output value */
1102 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1103 lck->smb2_break.out.reserved = lck->smb2_break.in.reserved;
1104 lck->smb2_break.out.reserved2 = lck->smb2_break.in.reserved2;
1105 lck->smb2_break.out.file = lck->smb2_break.in.file;
1110 * we don't need to call ntvfs_map_async_setup() here,
1111 * as lock() doesn't have any output fields
1114 return ntvfs->ops->lock(ntvfs, req, lck2);
1119 NTVFS write generic to any mapper
1121 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1122 struct ntvfs_request *req,
1123 union smb_write *wr,
1124 union smb_write *wr2,
1127 union smb_lock *lck;
1128 union smb_close *cl;
1131 if (NT_STATUS_IS_ERR(status)) {
1135 switch (wr->generic.level) {
1136 case RAW_WRITE_WRITE:
1137 wr->write.out.nwritten = wr2->generic.out.nwritten;
1140 case RAW_WRITE_WRITEUNLOCK:
1141 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1143 lck = talloc(wr2, union smb_lock);
1145 return NT_STATUS_NO_MEMORY;
1148 lck->unlock.level = RAW_LOCK_UNLOCK;
1149 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1150 lck->unlock.in.count = wr->writeunlock.in.count;
1151 lck->unlock.in.offset = wr->writeunlock.in.offset;
1153 if (lck->unlock.in.count != 0) {
1154 /* do the lock sync for now */
1155 state = req->async_states->state;
1156 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1157 status = ntvfs->ops->lock(ntvfs, req, lck);
1158 req->async_states->state = state;
1162 case RAW_WRITE_WRITECLOSE:
1163 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1165 cl = talloc(wr2, union smb_close);
1167 return NT_STATUS_NO_MEMORY;
1170 cl->close.level = RAW_CLOSE_CLOSE;
1171 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1172 cl->close.in.write_time = wr->writeclose.in.mtime;
1174 if (wr2->generic.in.count != 0) {
1175 /* do the close sync for now */
1176 state = req->async_states->state;
1177 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1178 status = ntvfs->ops->close(ntvfs, req, cl);
1179 req->async_states->state = state;
1183 case RAW_WRITE_SPLWRITE:
1186 case RAW_WRITE_SMB2:
1187 wr->smb2.out._pad = 0;
1188 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1189 wr->smb2.out.unknown1 = 0;
1193 return NT_STATUS_INVALID_LEVEL;
1201 NTVFS write generic to any mapper
1203 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1204 struct ntvfs_request *req,
1205 union smb_write *wr)
1207 union smb_write *wr2;
1210 wr2 = talloc(req, union smb_write);
1212 return NT_STATUS_NO_MEMORY;
1215 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1216 (second_stage_t)ntvfs_map_write_finish);
1217 if (!NT_STATUS_IS_OK(status)) {
1221 wr2->writex.level = RAW_WRITE_GENERIC;
1223 switch (wr->generic.level) {
1224 case RAW_WRITE_WRITEX:
1225 status = NT_STATUS_INVALID_LEVEL;
1228 case RAW_WRITE_WRITE:
1229 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1230 wr2->writex.in.offset = wr->write.in.offset;
1231 wr2->writex.in.wmode = 0;
1232 wr2->writex.in.remaining = wr->write.in.remaining;
1233 wr2->writex.in.count = wr->write.in.count;
1234 wr2->writex.in.data = wr->write.in.data;
1235 status = ntvfs->ops->write(ntvfs, req, wr2);
1238 case RAW_WRITE_WRITEUNLOCK:
1239 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1240 wr2->writex.in.offset = wr->writeunlock.in.offset;
1241 wr2->writex.in.wmode = 0;
1242 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1243 wr2->writex.in.count = wr->writeunlock.in.count;
1244 wr2->writex.in.data = wr->writeunlock.in.data;
1245 status = ntvfs->ops->write(ntvfs, req, wr2);
1248 case RAW_WRITE_WRITECLOSE:
1249 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1250 wr2->writex.in.offset = wr->writeclose.in.offset;
1251 wr2->writex.in.wmode = 0;
1252 wr2->writex.in.remaining = 0;
1253 wr2->writex.in.count = wr->writeclose.in.count;
1254 wr2->writex.in.data = wr->writeclose.in.data;
1255 status = ntvfs->ops->write(ntvfs, req, wr2);
1258 case RAW_WRITE_SPLWRITE:
1259 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1260 wr2->writex.in.offset = 0;
1261 wr2->writex.in.wmode = 0;
1262 wr2->writex.in.remaining = 0;
1263 wr2->writex.in.count = wr->splwrite.in.count;
1264 wr2->writex.in.data = wr->splwrite.in.data;
1265 status = ntvfs->ops->write(ntvfs, req, wr2);
1268 case RAW_WRITE_SMB2:
1269 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1270 wr2->writex.in.offset = wr->smb2.in.offset;
1271 wr2->writex.in.wmode = 0;
1272 wr2->writex.in.remaining = 0;
1273 wr2->writex.in.count = wr->smb2.in.data.length;
1274 wr2->writex.in.data = wr->smb2.in.data.data;
1275 status = ntvfs->ops->write(ntvfs, req, wr2);
1278 return ntvfs_map_async_finish(req, status);
1283 NTVFS read generic to any mapper - finish the out mapping
1285 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1286 struct ntvfs_request *req,
1288 union smb_read *rd2,
1291 switch (rd->generic.level) {
1293 rd->read.out.nread = rd2->generic.out.nread;
1295 case RAW_READ_READBRAW:
1296 rd->readbraw.out.nread = rd2->generic.out.nread;
1298 case RAW_READ_LOCKREAD:
1299 rd->lockread.out.nread = rd2->generic.out.nread;
1302 rd->smb2.out.data.length= rd2->generic.out.nread;
1303 rd->smb2.out.remaining = 0;
1304 rd->smb2.out.reserved = 0;
1307 return NT_STATUS_INVALID_LEVEL;
1314 NTVFS read* to readx mapper
1316 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1317 struct ntvfs_request *req,
1320 union smb_read *rd2;
1321 union smb_lock *lck;
1325 rd2 = talloc(req, union smb_read);
1327 return NT_STATUS_NO_MEMORY;
1330 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1331 (second_stage_t)ntvfs_map_read_finish);
1332 if (!NT_STATUS_IS_OK(status)) {
1336 rd2->readx.level = RAW_READ_READX;
1337 rd2->readx.in.read_for_execute = false;
1339 switch (rd->generic.level) {
1340 case RAW_READ_READX:
1341 status = NT_STATUS_INVALID_LEVEL;
1345 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1346 rd2->readx.in.offset = rd->read.in.offset;
1347 rd2->readx.in.mincnt = rd->read.in.count;
1348 rd2->readx.in.maxcnt = rd->read.in.count;
1349 rd2->readx.in.remaining = rd->read.in.remaining;
1350 rd2->readx.out.data = rd->read.out.data;
1351 status = ntvfs->ops->read(ntvfs, req, rd2);
1354 case RAW_READ_READBRAW:
1355 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1356 rd2->readx.in.offset = rd->readbraw.in.offset;
1357 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1358 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1359 rd2->readx.in.remaining = 0;
1360 rd2->readx.out.data = rd->readbraw.out.data;
1361 status = ntvfs->ops->read(ntvfs, req, rd2);
1364 case RAW_READ_LOCKREAD:
1365 /* do the initial lock sync for now */
1366 state = req->async_states->state;
1367 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1369 lck = talloc(rd2, union smb_lock);
1371 status = NT_STATUS_NO_MEMORY;
1374 lck->lock.level = RAW_LOCK_LOCK;
1375 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1376 lck->lock.in.count = rd->lockread.in.count;
1377 lck->lock.in.offset = rd->lockread.in.offset;
1378 status = ntvfs->ops->lock(ntvfs, req, lck);
1379 req->async_states->state = state;
1381 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1382 rd2->readx.in.offset = rd->lockread.in.offset;
1383 rd2->readx.in.mincnt = rd->lockread.in.count;
1384 rd2->readx.in.maxcnt = rd->lockread.in.count;
1385 rd2->readx.in.remaining = rd->lockread.in.remaining;
1386 rd2->readx.out.data = rd->lockread.out.data;
1388 if (NT_STATUS_IS_OK(status)) {
1389 status = ntvfs->ops->read(ntvfs, req, rd2);
1394 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1395 rd2->readx.in.offset = rd->smb2.in.offset;
1396 rd2->readx.in.mincnt = rd->smb2.in.min_count;
1397 rd2->readx.in.maxcnt = rd->smb2.in.length;
1398 rd2->readx.in.remaining = 0;
1399 rd2->readx.out.data = rd->smb2.out.data.data;
1400 status = ntvfs->ops->read(ntvfs, req, rd2);
1405 return ntvfs_map_async_finish(req, status);
1410 NTVFS close generic to any mapper
1412 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1413 struct ntvfs_request *req,
1414 union smb_close *cl,
1415 union smb_close *cl2,
1418 NT_STATUS_NOT_OK_RETURN(status);
1420 switch (cl->generic.level) {
1421 case RAW_CLOSE_SMB2:
1422 cl->smb2.out.flags = cl2->generic.out.flags;
1423 cl->smb2.out._pad = 0;
1424 cl->smb2.out.create_time = cl2->generic.out.create_time;
1425 cl->smb2.out.access_time = cl2->generic.out.access_time;
1426 cl->smb2.out.write_time = cl2->generic.out.write_time;
1427 cl->smb2.out.change_time = cl2->generic.out.change_time;
1428 cl->smb2.out.alloc_size = cl2->generic.out.alloc_size;
1429 cl->smb2.out.size = cl2->generic.out.size;
1430 cl->smb2.out.file_attr = cl2->generic.out.file_attr;
1440 NTVFS close generic to any mapper
1442 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1443 struct ntvfs_request *req,
1444 union smb_close *cl)
1446 union smb_close *cl2;
1449 cl2 = talloc(req, union smb_close);
1451 return NT_STATUS_NO_MEMORY;
1454 switch (cl->generic.level) {
1455 case RAW_CLOSE_GENERIC:
1456 return NT_STATUS_INVALID_LEVEL;
1458 case RAW_CLOSE_CLOSE:
1459 cl2->generic.level = RAW_CLOSE_GENERIC;
1460 cl2->generic.in.file = cl->close.in.file;
1461 cl2->generic.in.write_time = cl->close.in.write_time;
1462 cl2->generic.in.flags = 0;
1465 case RAW_CLOSE_SPLCLOSE:
1466 cl2->generic.level = RAW_CLOSE_GENERIC;
1467 cl2->generic.in.file = cl->splclose.in.file;
1468 cl2->generic.in.write_time = 0;
1469 cl2->generic.in.flags = 0;
1472 case RAW_CLOSE_SMB2:
1473 cl2->generic.level = RAW_CLOSE_GENERIC;
1474 cl2->generic.in.file = cl->smb2.in.file;
1475 cl2->generic.in.write_time = 0;
1476 cl2->generic.in.flags = cl->smb2.in.flags;
1480 status = ntvfs_map_async_setup(ntvfs, req, cl, cl2,
1481 (second_stage_t)ntvfs_map_close_finish);
1482 NT_STATUS_NOT_OK_RETURN(status);
1484 status = ntvfs->ops->close(ntvfs, req, cl2);
1486 return ntvfs_map_async_finish(req, status);
1490 NTVFS notify generic to any mapper
1492 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1493 struct ntvfs_request *req,
1494 union smb_notify *nt,
1495 union smb_notify *nt2,
1498 NT_STATUS_NOT_OK_RETURN(status);
1500 switch (nt->nttrans.level) {
1501 case RAW_NOTIFY_SMB2:
1502 if (nt2->nttrans.out.num_changes == 0) {
1503 return STATUS_NOTIFY_ENUM_DIR;
1505 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1506 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1510 return NT_STATUS_INVALID_LEVEL;
1518 NTVFS notify generic to any mapper
1520 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1521 struct ntvfs_request *req,
1522 union smb_notify *nt)
1524 union smb_notify *nt2;
1527 nt2 = talloc(req, union smb_notify);
1528 NT_STATUS_HAVE_NO_MEMORY(nt2);
1530 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1531 (second_stage_t)ntvfs_map_notify_finish);
1532 NT_STATUS_NOT_OK_RETURN(status);
1534 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1536 switch (nt->nttrans.level) {
1537 case RAW_NOTIFY_NTTRANS:
1538 status = NT_STATUS_INVALID_LEVEL;
1541 case RAW_NOTIFY_SMB2:
1542 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1543 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1544 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1545 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1546 status = ntvfs->ops->notify(ntvfs, req, nt2);
1550 return ntvfs_map_async_finish(req, status);