2 Unix SMB/CIFS implementation.
4 NTVFS generic level mapping code
6 Copyright (C) Andrew Tridgell 2003-2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 this implements mappings between info levels for NTVFS backend calls
24 the idea is that each of these functions implements one of the NTVFS
25 backend calls in terms of the 'generic' call. All backends that use
26 these functions must supply the generic call, but can if it wants to
27 also implement other levels if the need arises
29 this allows backend writers to only implement one variant of each
30 call unless they need fine grained control of the calls.
34 #include "ntvfs/ntvfs.h"
35 #include "libcli/smb2/smb2.h"
36 #include "libcli/smb2/smb2_calls.h"
38 /* a second stage function converts from the out parameters of the generic
39 call onto the out parameters of the specific call made */
40 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
41 struct ntvfs_request *,
42 void *, void *, NTSTATUS);
45 this structure holds the async state for pending mapped async calls
47 struct ntvfs_map_async {
48 struct ntvfs_module_context *ntvfs;
54 this is a async wrapper, called from the backend when it has completed
55 a function that it has decided to reply to in an async fashion
57 static void ntvfs_map_async_send(struct ntvfs_request *req)
59 struct ntvfs_map_async *m = req->async_states->private_data;
61 ntvfs_async_state_pop(req);
63 /* call the _finish function setup in ntvfs_map_async_setup() */
64 req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
66 /* call the send function from the next module up */
67 req->async_states->send_fn(req);
71 prepare for calling a ntvfs backend with async support
72 io is the original call structure
73 io2 is the new call structure for the mapped call
74 fn is a second stage function for processing the out arguments
76 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
77 struct ntvfs_request *req,
81 struct ntvfs_map_async *m;
82 m = talloc(req, struct ntvfs_map_async);
84 return NT_STATUS_NO_MEMORY;
90 return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
94 called when first stage processing is complete.
96 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
98 struct ntvfs_map_async *m;
100 /* if the backend has decided to reply in an async fashion then
101 we don't need to do any work here */
102 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
106 /* the backend is replying immediately. call the 2nd stage function after popping our local
108 m = req->async_states->private_data;
110 ntvfs_async_state_pop(req);
112 return m->fn(m->ntvfs, req, m->io, m->io2, status);
116 see if a filename ends in EXE COM DLL or SYM. This is needed for the
117 DENY_DOS mapping for OpenX
119 bool is_exe_filename(const char *fname)
122 p = strrchr(fname, '.');
127 if (strcasecmp(p, "EXE") == 0 ||
128 strcasecmp(p, "COM") == 0 ||
129 strcasecmp(p, "DLL") == 0 ||
130 strcasecmp(p, "SYM") == 0) {
138 NTVFS openx to ntcreatex mapper
140 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
141 struct ntvfs_request *req,
146 time_t write_time = 0;
147 uint32_t set_size = 0;
148 union smb_setfileinfo *sf;
151 if (!NT_STATUS_IS_OK(status)) {
155 switch (io->generic.level) {
157 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
158 io->openold.out.attrib = io2->generic.out.attrib;
159 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
160 io->openold.out.size = io2->generic.out.size;
161 io->openold.out.rmode = io->openold.in.open_mode;
165 io->openx.out.file.ntvfs = io2->generic.out.file.ntvfs;
166 io->openx.out.attrib = io2->generic.out.attrib;
167 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
168 io->openx.out.size = io2->generic.out.size;
169 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
170 io->openx.out.ftype = 0;
171 io->openx.out.devstate = 0;
172 io->openx.out.action = io2->generic.out.create_action;
173 io->openx.out.unique_fid = 0;
174 io->openx.out.access_mask = SEC_STD_ALL;
175 io->openx.out.unknown = 0;
177 /* we need to extend the file to the requested size if
178 it was newly created */
179 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
180 set_size = io->openx.in.size;
184 case RAW_OPEN_T2OPEN:
185 io->t2open.out.file.ntvfs = io2->generic.out.file.ntvfs;
186 io->t2open.out.attrib = io2->generic.out.attrib;
187 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
188 io->t2open.out.size = io2->generic.out.size;
189 io->t2open.out.access = io->t2open.in.open_mode;
190 io->t2open.out.ftype = 0;
191 io->t2open.out.devstate = 0;
192 io->t2open.out.action = io2->generic.out.create_action;
193 io->t2open.out.file_id = 0;
197 case RAW_OPEN_CREATE:
198 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
199 write_time = io->mknew.in.write_time;
203 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
204 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
205 strlen(io->ctemp.in.directory) + 1);
206 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
210 io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs;
211 switch (io2->generic.out.oplock_level) {
212 case BATCH_OPLOCK_RETURN:
213 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
215 case EXCLUSIVE_OPLOCK_RETURN:
216 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
218 case LEVEL_II_OPLOCK_RETURN:
219 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
222 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
225 io->smb2.out.reserved = 0;
226 io->smb2.out.create_action = io2->generic.out.create_action;
227 io->smb2.out.create_time = io2->generic.out.create_time;
228 io->smb2.out.access_time = io2->generic.out.access_time;
229 io->smb2.out.write_time = io2->generic.out.write_time;
230 io->smb2.out.change_time = io2->generic.out.change_time;
231 io->smb2.out.alloc_size = io2->generic.out.alloc_size;
232 io->smb2.out.size = io2->generic.out.size;
233 io->smb2.out.file_attr = io2->generic.out.attrib;
234 io->smb2.out.reserved2 = 0;
235 io->smb2.out.blob = data_blob(NULL, 0);
239 return NT_STATUS_INVALID_LEVEL;
242 /* doing a secondary request async is more trouble than its
244 state = req->async_states->state;
245 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
247 if (write_time != 0) {
248 sf = talloc(req, union smb_setfileinfo);
249 NT_STATUS_HAVE_NO_MEMORY(sf);
250 sf->generic.level = RAW_SFILEINFO_STANDARD;
251 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
252 sf->standard.in.create_time = 0;
253 sf->standard.in.write_time = write_time;
254 sf->standard.in.access_time = 0;
255 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
259 sf = talloc(req, union smb_setfileinfo);
260 NT_STATUS_HAVE_NO_MEMORY(sf);
261 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
262 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
263 sf->end_of_file_info.in.size = set_size;
264 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
265 if (NT_STATUS_IS_OK(status)) {
266 io->openx.out.size = io->openx.in.size;
270 req->async_states->state = state;
276 the core of the mapping between openx style parameters and ntcreatex
279 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
280 uint16_t open_func, const char *fname,
283 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
284 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
286 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
287 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
290 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
291 case OPENX_MODE_ACCESS_READ:
292 case OPENX_MODE_ACCESS_EXEC:
293 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
295 case OPENX_MODE_ACCESS_WRITE:
296 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
298 case OPENX_MODE_ACCESS_RDWR:
299 case OPENX_MODE_ACCESS_FCB:
300 io2->generic.in.access_mask =
301 SEC_RIGHTS_FILE_READ |
302 SEC_RIGHTS_FILE_WRITE;
305 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
308 switch (open_mode & OPENX_MODE_DENY_MASK) {
309 case OPENX_MODE_DENY_READ:
310 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
312 case OPENX_MODE_DENY_WRITE:
313 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
315 case OPENX_MODE_DENY_ALL:
316 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
318 case OPENX_MODE_DENY_NONE:
319 io2->generic.in.share_access =
320 NTCREATEX_SHARE_ACCESS_READ |
321 NTCREATEX_SHARE_ACCESS_WRITE;
323 case OPENX_MODE_DENY_DOS:
324 /* DENY_DOS is quite strange - it depends on the filename! */
325 io2->generic.in.create_options |=
326 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
327 if (is_exe_filename(fname)) {
328 io2->generic.in.share_access =
329 NTCREATEX_SHARE_ACCESS_READ |
330 NTCREATEX_SHARE_ACCESS_WRITE;
332 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
333 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
335 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
339 case OPENX_MODE_DENY_FCB:
340 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
341 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
344 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
348 case (OPENX_OPEN_FUNC_OPEN):
349 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
351 case (OPENX_OPEN_FUNC_TRUNC):
352 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
354 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
355 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
357 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
358 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
360 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
361 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
364 /* this one is very strange */
365 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
366 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
369 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
376 NTVFS open generic to any mapper
378 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
379 struct ntvfs_request *req,
385 io2 = talloc_zero(req, union smb_open);
387 return NT_STATUS_NO_MEMORY;
390 status = ntvfs_map_async_setup(ntvfs, req,
392 (second_stage_t)ntvfs_map_open_finish);
393 if (!NT_STATUS_IS_OK(status)) {
397 io2->generic.level = RAW_OPEN_GENERIC;
399 switch (io->generic.level) {
401 status = map_openx_open(io->openx.in.flags,
402 io->openx.in.open_mode,
403 io->openx.in.open_func,
406 if (!NT_STATUS_IS_OK(status)) {
410 io2->generic.in.file_attr = io->openx.in.file_attrs;
411 io2->generic.in.fname = io->openx.in.fname;
413 status = ntvfs->ops->open(ntvfs, req, io2);
418 status = map_openx_open(0,
419 io->openold.in.open_mode,
420 OPENX_OPEN_FUNC_OPEN,
421 io->openold.in.fname,
423 if (!NT_STATUS_IS_OK(status)) {
427 io2->generic.in.file_attr = io->openold.in.search_attrs;
428 io2->generic.in.fname = io->openold.in.fname;
430 status = ntvfs->ops->open(ntvfs, req, io2);
433 case RAW_OPEN_T2OPEN:
434 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
436 if (io->t2open.in.open_func == 0) {
437 status = NT_STATUS_OBJECT_NAME_COLLISION;
441 status = map_openx_open(io->t2open.in.flags,
442 io->t2open.in.open_mode,
443 io->t2open.in.open_func,
446 if (!NT_STATUS_IS_OK(status)) {
450 io2->generic.in.file_attr = io->t2open.in.file_attrs;
451 io2->generic.in.fname = io->t2open.in.fname;
452 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
453 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
454 io2->generic.in.ea_list->eas = io->t2open.in.eas;
456 status = ntvfs->ops->open(ntvfs, req, io2);
460 io2->generic.in.file_attr = io->mknew.in.attrib;
461 io2->generic.in.fname = io->mknew.in.fname;
462 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
463 io2->generic.in.access_mask =
464 SEC_RIGHTS_FILE_READ |
465 SEC_RIGHTS_FILE_WRITE;
466 io2->generic.in.share_access =
467 NTCREATEX_SHARE_ACCESS_READ |
468 NTCREATEX_SHARE_ACCESS_WRITE;
469 status = ntvfs->ops->open(ntvfs, req, io2);
472 case RAW_OPEN_CREATE:
473 io2->generic.in.file_attr = io->mknew.in.attrib;
474 io2->generic.in.fname = io->mknew.in.fname;
475 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
476 io2->generic.in.access_mask =
477 SEC_RIGHTS_FILE_READ |
478 SEC_RIGHTS_FILE_WRITE;
479 io2->generic.in.share_access =
480 NTCREATEX_SHARE_ACCESS_READ |
481 NTCREATEX_SHARE_ACCESS_WRITE;
482 status = ntvfs->ops->open(ntvfs, req, io2);
486 io2->generic.in.file_attr = io->ctemp.in.attrib;
487 io2->generic.in.fname =
488 talloc_asprintf(io2, "%s\\SRV%s",
489 io->ctemp.in.directory,
490 generate_random_str_list(io2, 5, "0123456789"));
491 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
492 io2->generic.in.access_mask =
493 SEC_RIGHTS_FILE_READ |
494 SEC_RIGHTS_FILE_WRITE;
495 io2->generic.in.share_access =
496 NTCREATEX_SHARE_ACCESS_READ |
497 NTCREATEX_SHARE_ACCESS_WRITE;
498 status = ntvfs->ops->open(ntvfs, req, io2);
501 switch (io->smb2.in.oplock_level) {
502 case SMB2_OPLOCK_LEVEL_BATCH:
503 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
504 NTCREATEX_FLAGS_REQUEST_OPLOCK;
506 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
507 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
510 io2->generic.in.flags = 0;
513 io2->generic.in.root_fid = 0;
514 io2->generic.in.access_mask = io->smb2.in.desired_access;
515 io2->generic.in.alloc_size = 0;
516 io2->generic.in.file_attr = io->smb2.in.file_attributes;
517 io2->generic.in.share_access = io->smb2.in.share_access;
518 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
519 io2->generic.in.create_options = io->smb2.in.create_options;
520 io2->generic.in.impersonation = io->smb2.in.impersonation_level;
521 io2->generic.in.security_flags = 0;
522 io2->generic.in.fname = io->smb2.in.fname;
523 io2->generic.in.sec_desc = NULL;
524 io2->generic.in.ea_list = NULL;
525 status = ntvfs->ops->open(ntvfs, req, io2);
529 status = NT_STATUS_INVALID_LEVEL;
533 return ntvfs_map_async_finish(req, status);
538 NTVFS fsinfo generic to any mapper
540 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
541 struct ntvfs_request *req,
542 union smb_fsinfo *fs)
545 union smb_fsinfo *fs2;
547 fs2 = talloc(req, union smb_fsinfo);
549 return NT_STATUS_NO_MEMORY;
552 if (fs->generic.level == RAW_QFS_GENERIC) {
553 return NT_STATUS_INVALID_LEVEL;
556 /* only used by the simple backend, which doesn't do async */
557 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
559 /* ask the backend for the generic info */
560 fs2->generic.level = RAW_QFS_GENERIC;
562 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
563 if (!NT_STATUS_IS_OK(status)) {
567 /* and convert it to the required level */
568 switch (fs->generic.level) {
569 case RAW_QFS_GENERIC:
570 return NT_STATUS_INVALID_LEVEL;
572 case RAW_QFS_DSKATTR: {
573 /* map from generic to DSKATTR */
576 /* we need to scale the sizes to fit */
577 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
578 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
583 fs->dskattr.out.blocks_per_unit = bpunit;
584 fs->dskattr.out.block_size = 512;
585 fs->dskattr.out.units_total =
586 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
587 fs->dskattr.out.units_free =
588 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
590 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
591 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
592 fs->dskattr.out.blocks_per_unit = 64;
593 fs->dskattr.out.units_total = 0xFFFF;
594 fs->dskattr.out.units_free = 0xFFFF;
599 case RAW_QFS_ALLOCATION:
600 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
601 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
602 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
603 fs->allocation.out.sectors_per_unit = 1;
604 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
608 fs->volume.out.serial_number = fs2->generic.out.serial_number;
609 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
612 case RAW_QFS_VOLUME_INFO:
613 case RAW_QFS_VOLUME_INFORMATION:
614 fs->volume_info.out.create_time = fs2->generic.out.create_time;
615 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
616 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
619 case RAW_QFS_SIZE_INFO:
620 case RAW_QFS_SIZE_INFORMATION:
621 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
622 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
623 fs->size_info.out.sectors_per_unit = 1;
624 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
627 case RAW_QFS_DEVICE_INFO:
628 case RAW_QFS_DEVICE_INFORMATION:
629 fs->device_info.out.device_type = fs2->generic.out.device_type;
630 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
633 case RAW_QFS_ATTRIBUTE_INFO:
634 case RAW_QFS_ATTRIBUTE_INFORMATION:
635 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
636 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
637 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
640 case RAW_QFS_QUOTA_INFORMATION:
641 ZERO_STRUCT(fs->quota_information.out.unknown);
642 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
643 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
644 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
647 case RAW_QFS_FULL_SIZE_INFORMATION:
648 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
649 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
650 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
651 fs->full_size_information.out.sectors_per_unit = 1;
652 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
655 case RAW_QFS_OBJECTID_INFORMATION:
656 fs->objectid_information.out.guid = fs2->generic.out.guid;
657 ZERO_STRUCT(fs->objectid_information.out.unknown);
662 return NT_STATUS_INVALID_LEVEL;
667 NTVFS fileinfo generic to any mapper
669 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
670 union smb_fileinfo *info,
671 union smb_fileinfo *info2)
674 /* and convert it to the required level using results in info2 */
675 switch (info->generic.level) {
676 case RAW_FILEINFO_GENERIC:
677 return NT_STATUS_INVALID_LEVEL;
678 case RAW_FILEINFO_GETATTR:
679 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
680 info->getattr.out.size = info2->generic.out.size;
681 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
684 case RAW_FILEINFO_GETATTRE:
685 info->getattre.out.attrib = info2->generic.out.attrib;
686 info->getattre.out.size = info2->generic.out.size;
687 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
688 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
689 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
690 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
693 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
694 info->network_open_information.out.create_time = info2->generic.out.create_time;
695 info->network_open_information.out.access_time = info2->generic.out.access_time;
696 info->network_open_information.out.write_time = info2->generic.out.write_time;
697 info->network_open_information.out.change_time = info2->generic.out.change_time;
698 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
699 info->network_open_information.out.size = info2->generic.out.size;
700 info->network_open_information.out.attrib = info2->generic.out.attrib;
703 case RAW_FILEINFO_ALL_INFO:
704 case RAW_FILEINFO_ALL_INFORMATION:
705 info->all_info.out.create_time = info2->generic.out.create_time;
706 info->all_info.out.access_time = info2->generic.out.access_time;
707 info->all_info.out.write_time = info2->generic.out.write_time;
708 info->all_info.out.change_time = info2->generic.out.change_time;
709 info->all_info.out.attrib = info2->generic.out.attrib;
710 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
711 info->all_info.out.size = info2->generic.out.size;
712 info->all_info.out.nlink = info2->generic.out.nlink;
713 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
714 info->all_info.out.directory = info2->generic.out.directory;
715 info->all_info.out.ea_size = info2->generic.out.ea_size;
716 info->all_info.out.fname.s = info2->generic.out.fname.s;
717 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
720 case RAW_FILEINFO_BASIC_INFO:
721 case RAW_FILEINFO_BASIC_INFORMATION:
722 info->basic_info.out.create_time = info2->generic.out.create_time;
723 info->basic_info.out.access_time = info2->generic.out.access_time;
724 info->basic_info.out.write_time = info2->generic.out.write_time;
725 info->basic_info.out.change_time = info2->generic.out.change_time;
726 info->basic_info.out.attrib = info2->generic.out.attrib;
729 case RAW_FILEINFO_STANDARD:
730 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
731 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
732 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
733 info->standard.out.size = info2->generic.out.size;
734 info->standard.out.alloc_size = info2->generic.out.alloc_size;
735 info->standard.out.attrib = info2->generic.out.attrib;
738 case RAW_FILEINFO_EA_SIZE:
739 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
740 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
741 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
742 info->ea_size.out.size = info2->generic.out.size;
743 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
744 info->ea_size.out.attrib = info2->generic.out.attrib;
745 info->ea_size.out.ea_size = info2->generic.out.ea_size;
748 case RAW_FILEINFO_STANDARD_INFO:
749 case RAW_FILEINFO_STANDARD_INFORMATION:
750 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
751 info->standard_info.out.size = info2->generic.out.size;
752 info->standard_info.out.nlink = info2->generic.out.nlink;
753 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
754 info->standard_info.out.directory = info2->generic.out.directory;
757 case RAW_FILEINFO_INTERNAL_INFORMATION:
758 info->internal_information.out.file_id = info2->generic.out.file_id;
761 case RAW_FILEINFO_EA_INFO:
762 case RAW_FILEINFO_EA_INFORMATION:
763 info->ea_info.out.ea_size = info2->generic.out.ea_size;
766 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
767 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
768 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
771 case RAW_FILEINFO_STREAM_INFO:
772 case RAW_FILEINFO_STREAM_INFORMATION:
773 info->stream_info.out.num_streams = info2->generic.out.num_streams;
774 if (info->stream_info.out.num_streams > 0) {
775 info->stream_info.out.streams =
776 talloc_array(mem_ctx,
777 struct stream_struct,
778 info->stream_info.out.num_streams);
779 if (!info->stream_info.out.streams) {
780 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
781 info->stream_info.out.num_streams));
782 return NT_STATUS_NO_MEMORY;
784 for (i=0; i < info->stream_info.out.num_streams; i++) {
785 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
786 info->stream_info.out.streams[i].stream_name.s =
787 talloc_strdup(info->stream_info.out.streams,
788 info2->generic.out.streams[i].stream_name.s);
789 if (!info->stream_info.out.streams[i].stream_name.s) {
790 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
791 return NT_STATUS_NO_MEMORY;
797 case RAW_FILEINFO_NAME_INFO:
798 case RAW_FILEINFO_NAME_INFORMATION:
799 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
800 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
801 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
804 case RAW_FILEINFO_ALT_NAME_INFO:
805 case RAW_FILEINFO_ALT_NAME_INFORMATION:
806 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
807 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
808 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
811 case RAW_FILEINFO_POSITION_INFORMATION:
812 info->position_information.out.position = info2->generic.out.position;
815 case RAW_FILEINFO_ALL_EAS:
816 info->all_eas.out.num_eas = info2->generic.out.num_eas;
817 if (info->all_eas.out.num_eas > 0) {
818 info->all_eas.out.eas = talloc_array(mem_ctx,
820 info->all_eas.out.num_eas);
821 if (!info->all_eas.out.eas) {
822 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
823 info->all_eas.out.num_eas));
824 return NT_STATUS_NO_MEMORY;
826 for (i = 0; i < info->all_eas.out.num_eas; i++) {
827 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
828 info->all_eas.out.eas[i].name.s =
829 talloc_strdup(info->all_eas.out.eas,
830 info2->generic.out.eas[i].name.s);
831 if (!info->all_eas.out.eas[i].name.s) {
832 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
833 return NT_STATUS_NO_MEMORY;
835 info->all_eas.out.eas[i].value.data =
836 talloc_memdup(info->all_eas.out.eas,
837 info2->generic.out.eas[i].value.data,
838 info2->generic.out.eas[i].value.length);
839 if (!info->all_eas.out.eas[i].value.data) {
840 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
841 return NT_STATUS_NO_MEMORY;
847 case RAW_FILEINFO_IS_NAME_VALID:
850 case RAW_FILEINFO_COMPRESSION_INFO:
851 case RAW_FILEINFO_COMPRESSION_INFORMATION:
852 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
853 info->compression_info.out.format = info2->generic.out.format;
854 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
855 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
856 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
859 case RAW_FILEINFO_ACCESS_INFORMATION:
860 info->access_information.out.access_flags = info2->generic.out.access_flags;
863 case RAW_FILEINFO_MODE_INFORMATION:
864 info->mode_information.out.mode = info2->generic.out.mode;
867 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
868 info->alignment_information.out.alignment_requirement =
869 info2->generic.out.alignment_requirement;
872 case RAW_FILEINFO_UNIX_BASIC:
873 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
874 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
875 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
876 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
877 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
878 info->unix_basic_info.out.uid = info2->generic.out.uid;
879 info->unix_basic_info.out.gid = info2->generic.out.gid;
880 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
881 info->unix_basic_info.out.dev_major = info2->generic.out.device;
882 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
883 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
884 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
885 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
888 case RAW_FILEINFO_UNIX_LINK:
889 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
894 return NT_STATUS_INVALID_LEVEL;
898 NTVFS fileinfo generic to any mapper
900 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
901 struct ntvfs_request *req,
902 union smb_fileinfo *info)
905 union smb_fileinfo *info2;
907 info2 = talloc(req, union smb_fileinfo);
909 return NT_STATUS_NO_MEMORY;
912 if (info->generic.level == RAW_FILEINFO_GENERIC) {
913 return NT_STATUS_INVALID_LEVEL;
916 /* ask the backend for the generic info */
917 info2->generic.level = RAW_FILEINFO_GENERIC;
918 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
920 /* only used by the simple backend, which doesn't do async */
921 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
923 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
924 if (!NT_STATUS_IS_OK(status)) {
927 return ntvfs_map_fileinfo(req, info, info2);
931 NTVFS pathinfo generic to any mapper
933 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
934 struct ntvfs_request *req,
935 union smb_fileinfo *info)
938 union smb_fileinfo *info2;
940 info2 = talloc(req, union smb_fileinfo);
942 return NT_STATUS_NO_MEMORY;
945 if (info->generic.level == RAW_FILEINFO_GENERIC) {
946 return NT_STATUS_INVALID_LEVEL;
949 /* ask the backend for the generic info */
950 info2->generic.level = RAW_FILEINFO_GENERIC;
951 info2->generic.in.file.path = info->generic.in.file.path;
953 /* only used by the simple backend, which doesn't do async */
954 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
956 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
957 if (!NT_STATUS_IS_OK(status)) {
960 return ntvfs_map_fileinfo(req, info, info2);
965 NTVFS lock generic to any mapper
967 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
968 struct ntvfs_request *req,
971 union smb_lock *lck2;
972 struct smb_lock_entry *locks;
974 lck2 = talloc(req, union smb_lock);
976 return NT_STATUS_NO_MEMORY;
979 locks = talloc_array(lck2, struct smb_lock_entry, 1);
981 return NT_STATUS_NO_MEMORY;
984 switch (lck->generic.level) {
986 return NT_STATUS_INVALID_LEVEL;
989 lck2->generic.level = RAW_LOCK_GENERIC;
990 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
991 lck2->generic.in.mode = 0;
992 lck2->generic.in.timeout = 0;
993 lck2->generic.in.ulock_cnt = 0;
994 lck2->generic.in.lock_cnt = 1;
995 lck2->generic.in.locks = locks;
996 locks->pid = req->smbpid;
997 locks->offset = lck->lock.in.offset;
998 locks->count = lck->lock.in.count;
1001 case RAW_LOCK_UNLOCK:
1002 lck2->generic.level = RAW_LOCK_GENERIC;
1003 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1004 lck2->generic.in.mode = 0;
1005 lck2->generic.in.timeout = 0;
1006 lck2->generic.in.ulock_cnt = 1;
1007 lck2->generic.in.lock_cnt = 0;
1008 lck2->generic.in.locks = locks;
1009 locks->pid = req->smbpid;
1010 locks->offset = lck->unlock.in.offset;
1011 locks->count = lck->unlock.in.count;
1014 case RAW_LOCK_SMB2: {
1015 /* this is only approximate! We need to change the
1016 generic structure to fix this properly */
1018 if (lck->smb2.in.lock_count < 1) {
1019 return NT_STATUS_INVALID_PARAMETER;
1022 lck2->generic.level = RAW_LOCK_GENERIC;
1023 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1024 lck2->generic.in.timeout = UINT32_MAX;
1025 lck2->generic.in.mode = 0;
1026 lck2->generic.in.lock_cnt = 0;
1027 lck2->generic.in.ulock_cnt = 0;
1028 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry,
1029 lck->smb2.in.lock_count);
1030 if (lck2->generic.in.locks == NULL) {
1031 return NT_STATUS_NO_MEMORY;
1033 for (i=0;i<lck->smb2.in.lock_count;i++) {
1034 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK) {
1035 int j = lck2->generic.in.ulock_cnt;
1036 lck2->generic.in.ulock_cnt++;
1037 lck2->generic.in.locks[j].pid = 0;
1038 lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1039 lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1040 lck2->generic.in.locks[j].pid = 0;
1043 for (i=0;i<lck->smb2.in.lock_count;i++) {
1044 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1045 int j = lck2->generic.in.ulock_cnt +
1046 lck2->generic.in.lock_cnt;
1047 lck2->generic.in.lock_cnt++;
1048 lck2->generic.in.locks[j].pid = 0;
1049 lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1050 lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1051 lck2->generic.in.locks[j].pid = 0;
1052 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1053 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1055 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1056 lck2->generic.in.timeout = 0;
1060 /* initialize output value */
1061 lck->smb2.out.reserved = 0;
1065 case RAW_LOCK_SMB2_BREAK:
1066 lck2->generic.level = RAW_LOCK_GENERIC;
1067 lck2->generic.in.file.ntvfs = lck->smb2_break.in.file.ntvfs;
1068 lck2->generic.in.mode = LOCKING_ANDX_OPLOCK_RELEASE |
1069 ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1070 lck2->generic.in.timeout = 0;
1071 lck2->generic.in.ulock_cnt = 0;
1072 lck2->generic.in.lock_cnt = 0;
1073 lck2->generic.in.locks = NULL;
1075 /* initialize output value */
1076 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1077 lck->smb2_break.out.reserved = lck->smb2_break.in.reserved;
1078 lck->smb2_break.out.reserved2 = lck->smb2_break.in.reserved2;
1079 lck->smb2_break.out.file = lck->smb2_break.in.file;
1084 * we don't need to call ntvfs_map_async_setup() here,
1085 * as lock() doesn't have any output fields
1088 return ntvfs->ops->lock(ntvfs, req, lck2);
1093 NTVFS write generic to any mapper
1095 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1096 struct ntvfs_request *req,
1097 union smb_write *wr,
1098 union smb_write *wr2,
1101 union smb_lock *lck;
1102 union smb_close *cl;
1105 if (NT_STATUS_IS_ERR(status)) {
1109 switch (wr->generic.level) {
1110 case RAW_WRITE_WRITE:
1111 wr->write.out.nwritten = wr2->generic.out.nwritten;
1114 case RAW_WRITE_WRITEUNLOCK:
1115 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1117 lck = talloc(wr2, union smb_lock);
1119 return NT_STATUS_NO_MEMORY;
1122 lck->unlock.level = RAW_LOCK_UNLOCK;
1123 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1124 lck->unlock.in.count = wr->writeunlock.in.count;
1125 lck->unlock.in.offset = wr->writeunlock.in.offset;
1127 if (lck->unlock.in.count != 0) {
1128 /* do the lock sync for now */
1129 state = req->async_states->state;
1130 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1131 status = ntvfs->ops->lock(ntvfs, req, lck);
1132 req->async_states->state = state;
1136 case RAW_WRITE_WRITECLOSE:
1137 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1139 cl = talloc(wr2, union smb_close);
1141 return NT_STATUS_NO_MEMORY;
1144 cl->close.level = RAW_CLOSE_CLOSE;
1145 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1146 cl->close.in.write_time = wr->writeclose.in.mtime;
1148 if (wr2->generic.in.count != 0) {
1149 /* do the close sync for now */
1150 state = req->async_states->state;
1151 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1152 status = ntvfs->ops->close(ntvfs, req, cl);
1153 req->async_states->state = state;
1157 case RAW_WRITE_SPLWRITE:
1160 case RAW_WRITE_SMB2:
1161 wr->smb2.out._pad = 0;
1162 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1163 wr->smb2.out.unknown1 = 0;
1167 return NT_STATUS_INVALID_LEVEL;
1175 NTVFS write generic to any mapper
1177 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1178 struct ntvfs_request *req,
1179 union smb_write *wr)
1181 union smb_write *wr2;
1184 wr2 = talloc(req, union smb_write);
1186 return NT_STATUS_NO_MEMORY;
1189 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1190 (second_stage_t)ntvfs_map_write_finish);
1191 if (!NT_STATUS_IS_OK(status)) {
1195 wr2->writex.level = RAW_WRITE_GENERIC;
1197 switch (wr->generic.level) {
1198 case RAW_WRITE_WRITEX:
1199 status = NT_STATUS_INVALID_LEVEL;
1202 case RAW_WRITE_WRITE:
1203 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1204 wr2->writex.in.offset = wr->write.in.offset;
1205 wr2->writex.in.wmode = 0;
1206 wr2->writex.in.remaining = wr->write.in.remaining;
1207 wr2->writex.in.count = wr->write.in.count;
1208 wr2->writex.in.data = wr->write.in.data;
1209 status = ntvfs->ops->write(ntvfs, req, wr2);
1212 case RAW_WRITE_WRITEUNLOCK:
1213 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1214 wr2->writex.in.offset = wr->writeunlock.in.offset;
1215 wr2->writex.in.wmode = 0;
1216 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1217 wr2->writex.in.count = wr->writeunlock.in.count;
1218 wr2->writex.in.data = wr->writeunlock.in.data;
1219 status = ntvfs->ops->write(ntvfs, req, wr2);
1222 case RAW_WRITE_WRITECLOSE:
1223 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1224 wr2->writex.in.offset = wr->writeclose.in.offset;
1225 wr2->writex.in.wmode = 0;
1226 wr2->writex.in.remaining = 0;
1227 wr2->writex.in.count = wr->writeclose.in.count;
1228 wr2->writex.in.data = wr->writeclose.in.data;
1229 status = ntvfs->ops->write(ntvfs, req, wr2);
1232 case RAW_WRITE_SPLWRITE:
1233 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1234 wr2->writex.in.offset = 0;
1235 wr2->writex.in.wmode = 0;
1236 wr2->writex.in.remaining = 0;
1237 wr2->writex.in.count = wr->splwrite.in.count;
1238 wr2->writex.in.data = wr->splwrite.in.data;
1239 status = ntvfs->ops->write(ntvfs, req, wr2);
1242 case RAW_WRITE_SMB2:
1243 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1244 wr2->writex.in.offset = wr->smb2.in.offset;
1245 wr2->writex.in.wmode = 0;
1246 wr2->writex.in.remaining = 0;
1247 wr2->writex.in.count = wr->smb2.in.data.length;
1248 wr2->writex.in.data = wr->smb2.in.data.data;
1249 status = ntvfs->ops->write(ntvfs, req, wr2);
1252 return ntvfs_map_async_finish(req, status);
1257 NTVFS read generic to any mapper - finish the out mapping
1259 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1260 struct ntvfs_request *req,
1262 union smb_read *rd2,
1265 switch (rd->generic.level) {
1267 rd->read.out.nread = rd2->generic.out.nread;
1269 case RAW_READ_READBRAW:
1270 rd->readbraw.out.nread = rd2->generic.out.nread;
1272 case RAW_READ_LOCKREAD:
1273 rd->lockread.out.nread = rd2->generic.out.nread;
1276 rd->smb2.out.data.length= rd2->generic.out.nread;
1277 rd->smb2.out.remaining = 0;
1278 rd->smb2.out.reserved = 0;
1281 return NT_STATUS_INVALID_LEVEL;
1288 NTVFS read* to readx mapper
1290 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1291 struct ntvfs_request *req,
1294 union smb_read *rd2;
1295 union smb_lock *lck;
1299 rd2 = talloc(req, union smb_read);
1301 return NT_STATUS_NO_MEMORY;
1304 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1305 (second_stage_t)ntvfs_map_read_finish);
1306 if (!NT_STATUS_IS_OK(status)) {
1310 rd2->readx.level = RAW_READ_READX;
1311 rd2->readx.in.read_for_execute = false;
1313 switch (rd->generic.level) {
1314 case RAW_READ_READX:
1315 status = NT_STATUS_INVALID_LEVEL;
1319 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1320 rd2->readx.in.offset = rd->read.in.offset;
1321 rd2->readx.in.mincnt = rd->read.in.count;
1322 rd2->readx.in.maxcnt = rd->read.in.count;
1323 rd2->readx.in.remaining = rd->read.in.remaining;
1324 rd2->readx.out.data = rd->read.out.data;
1325 status = ntvfs->ops->read(ntvfs, req, rd2);
1328 case RAW_READ_READBRAW:
1329 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1330 rd2->readx.in.offset = rd->readbraw.in.offset;
1331 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1332 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1333 rd2->readx.in.remaining = 0;
1334 rd2->readx.out.data = rd->readbraw.out.data;
1335 status = ntvfs->ops->read(ntvfs, req, rd2);
1338 case RAW_READ_LOCKREAD:
1339 /* do the initial lock sync for now */
1340 state = req->async_states->state;
1341 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1343 lck = talloc(rd2, union smb_lock);
1345 status = NT_STATUS_NO_MEMORY;
1348 lck->lock.level = RAW_LOCK_LOCK;
1349 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1350 lck->lock.in.count = rd->lockread.in.count;
1351 lck->lock.in.offset = rd->lockread.in.offset;
1352 status = ntvfs->ops->lock(ntvfs, req, lck);
1353 req->async_states->state = state;
1355 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1356 rd2->readx.in.offset = rd->lockread.in.offset;
1357 rd2->readx.in.mincnt = rd->lockread.in.count;
1358 rd2->readx.in.maxcnt = rd->lockread.in.count;
1359 rd2->readx.in.remaining = rd->lockread.in.remaining;
1360 rd2->readx.out.data = rd->lockread.out.data;
1362 if (NT_STATUS_IS_OK(status)) {
1363 status = ntvfs->ops->read(ntvfs, req, rd2);
1368 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1369 rd2->readx.in.offset = rd->smb2.in.offset;
1370 rd2->readx.in.mincnt = rd->smb2.in.length;
1371 rd2->readx.in.maxcnt = rd->smb2.in.length;
1372 rd2->readx.in.remaining = 0;
1373 rd2->readx.out.data = rd->smb2.out.data.data;
1374 status = ntvfs->ops->read(ntvfs, req, rd2);
1379 return ntvfs_map_async_finish(req, status);
1384 NTVFS close generic to any mapper
1386 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1387 struct ntvfs_request *req,
1388 union smb_close *cl)
1390 union smb_close *cl2;
1392 cl2 = talloc(req, union smb_close);
1394 return NT_STATUS_NO_MEMORY;
1397 switch (cl->generic.level) {
1398 case RAW_CLOSE_CLOSE:
1399 return NT_STATUS_INVALID_LEVEL;
1401 case RAW_CLOSE_SPLCLOSE:
1402 cl2->generic.level = RAW_CLOSE_CLOSE;
1403 cl2->generic.in.file.ntvfs = cl->splclose.in.file.ntvfs;
1404 cl2->generic.in.write_time = 0;
1407 case RAW_CLOSE_SMB2:
1408 cl2->generic.level = RAW_CLOSE_CLOSE;
1409 cl2->generic.in.file.ntvfs = cl->smb2.in.file.ntvfs;
1410 cl2->generic.in.write_time = 0;
1411 /* SMB2 Close has output parameter, but we just zero them */
1412 ZERO_STRUCT(cl->smb2.out);
1417 * we don't need to call ntvfs_map_async_setup() here,
1418 * as close() doesn't have any output fields
1421 return ntvfs->ops->close(ntvfs, req, cl2);
1425 NTVFS notify generic to any mapper
1427 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1428 struct ntvfs_request *req,
1429 union smb_notify *nt,
1430 union smb_notify *nt2,
1433 NT_STATUS_NOT_OK_RETURN(status);
1435 switch (nt->nttrans.level) {
1436 case RAW_NOTIFY_SMB2:
1437 if (nt2->nttrans.out.num_changes == 0) {
1438 return STATUS_NOTIFY_ENUM_DIR;
1440 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1441 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1445 return NT_STATUS_INVALID_LEVEL;
1453 NTVFS notify generic to any mapper
1455 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1456 struct ntvfs_request *req,
1457 union smb_notify *nt)
1459 union smb_notify *nt2;
1462 nt2 = talloc(req, union smb_notify);
1463 NT_STATUS_HAVE_NO_MEMORY(nt2);
1465 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1466 (second_stage_t)ntvfs_map_notify_finish);
1467 NT_STATUS_NOT_OK_RETURN(status);
1469 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1471 switch (nt->nttrans.level) {
1472 case RAW_NOTIFY_NTTRANS:
1473 status = NT_STATUS_INVALID_LEVEL;
1476 case RAW_NOTIFY_SMB2:
1477 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1478 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1479 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1480 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1481 status = ntvfs->ops->notify(ntvfs, req, nt2);
1485 return ntvfs_map_async_finish(req, status);