2 Unix SMB/CIFS implementation.
4 NTVFS generic level mapping code
6 Copyright (C) Andrew Tridgell 2003-2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 this implements mappings between info levels for NTVFS backend calls
24 the idea is that each of these functions implements one of the NTVFS
25 backend calls in terms of the 'generic' call. All backends that use
26 these functions must supply the generic call, but can if it wants to
27 also implement other levels if the need arises
29 this allows backend writers to only implement one variant of each
30 call unless they need fine grained control of the calls.
34 #include "ntvfs/ntvfs.h"
35 #include "libcli/smb2/smb2.h"
36 #include "libcli/smb2/smb2_calls.h"
38 /* a second stage function converts from the out parameters of the generic
39 call onto the out parameters of the specific call made */
40 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
41 struct ntvfs_request *,
42 void *, void *, NTSTATUS);
45 this structure holds the async state for pending mapped async calls
47 struct ntvfs_map_async {
48 struct ntvfs_module_context *ntvfs;
54 this is a async wrapper, called from the backend when it has completed
55 a function that it has decided to reply to in an async fashion
57 static void ntvfs_map_async_send(struct ntvfs_request *req)
59 struct ntvfs_map_async *m = req->async_states->private_data;
61 ntvfs_async_state_pop(req);
63 /* call the _finish function setup in ntvfs_map_async_setup() */
64 req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
66 /* call the send function from the next module up */
67 req->async_states->send_fn(req);
71 prepare for calling a ntvfs backend with async support
72 io is the original call structure
73 io2 is the new call structure for the mapped call
74 fn is a second stage function for processing the out arguments
76 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
77 struct ntvfs_request *req,
81 struct ntvfs_map_async *m;
82 m = talloc(req, struct ntvfs_map_async);
84 return NT_STATUS_NO_MEMORY;
90 return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
94 called when first stage processing is complete.
96 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
98 struct ntvfs_map_async *m;
100 /* if the backend has decided to reply in an async fashion then
101 we don't need to do any work here */
102 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
106 /* the backend is replying immediately. call the 2nd stage function after popping our local
108 m = req->async_states->private_data;
110 ntvfs_async_state_pop(req);
112 return m->fn(m->ntvfs, req, m->io, m->io2, status);
116 see if a filename ends in EXE COM DLL or SYM. This is needed for the
117 DENY_DOS mapping for OpenX
119 bool is_exe_filename(const char *fname)
122 p = strrchr(fname, '.');
127 if (strcasecmp(p, "EXE") == 0 ||
128 strcasecmp(p, "COM") == 0 ||
129 strcasecmp(p, "DLL") == 0 ||
130 strcasecmp(p, "SYM") == 0) {
138 NTVFS openx to ntcreatex mapper
140 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
141 struct ntvfs_request *req,
146 time_t write_time = 0;
147 uint32_t set_size = 0;
148 union smb_setfileinfo *sf;
151 if (!NT_STATUS_IS_OK(status)) {
155 switch (io->generic.level) {
157 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
158 io->openold.out.attrib = io2->generic.out.attrib;
159 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
160 io->openold.out.size = io2->generic.out.size;
161 io->openold.out.rmode = io->openold.in.open_mode;
165 io->openx.out.file.ntvfs = io2->generic.out.file.ntvfs;
166 io->openx.out.attrib = io2->generic.out.attrib;
167 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
168 io->openx.out.size = io2->generic.out.size;
169 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
170 io->openx.out.ftype = 0;
171 io->openx.out.devstate = 0;
172 io->openx.out.action = io2->generic.out.create_action;
173 io->openx.out.unique_fid = 0;
174 io->openx.out.access_mask = SEC_STD_ALL;
175 io->openx.out.unknown = 0;
177 /* we need to extend the file to the requested size if
178 it was newly created */
179 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
180 set_size = io->openx.in.size;
184 case RAW_OPEN_T2OPEN:
185 io->t2open.out.file.ntvfs = io2->generic.out.file.ntvfs;
186 io->t2open.out.attrib = io2->generic.out.attrib;
187 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
188 io->t2open.out.size = io2->generic.out.size;
189 io->t2open.out.access = io->t2open.in.open_mode;
190 io->t2open.out.ftype = 0;
191 io->t2open.out.devstate = 0;
192 io->t2open.out.action = io2->generic.out.create_action;
193 io->t2open.out.file_id = 0;
197 case RAW_OPEN_CREATE:
198 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
199 write_time = io->mknew.in.write_time;
203 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
204 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
205 strlen(io->ctemp.in.directory) + 1);
206 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
210 io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs;
211 switch (io2->generic.out.oplock_level) {
212 case BATCH_OPLOCK_RETURN:
213 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
215 case EXCLUSIVE_OPLOCK_RETURN:
216 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
218 case LEVEL_II_OPLOCK_RETURN:
219 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
222 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
225 io->smb2.out.reserved = 0;
226 io->smb2.out.create_action = io2->generic.out.create_action;
227 io->smb2.out.create_time = io2->generic.out.create_time;
228 io->smb2.out.access_time = io2->generic.out.access_time;
229 io->smb2.out.write_time = io2->generic.out.write_time;
230 io->smb2.out.change_time = io2->generic.out.change_time;
231 io->smb2.out.alloc_size = io2->generic.out.alloc_size;
232 io->smb2.out.size = io2->generic.out.size;
233 io->smb2.out.file_attr = io2->generic.out.attrib;
234 io->smb2.out.reserved2 = 0;
235 io->smb2.out.blob = data_blob(NULL, 0);
239 return NT_STATUS_INVALID_LEVEL;
242 /* doing a secondary request async is more trouble than its
244 state = req->async_states->state;
245 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
247 if (write_time != 0) {
248 sf = talloc(req, union smb_setfileinfo);
249 NT_STATUS_HAVE_NO_MEMORY(sf);
250 sf->generic.level = RAW_SFILEINFO_STANDARD;
251 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
252 sf->standard.in.create_time = 0;
253 sf->standard.in.write_time = write_time;
254 sf->standard.in.access_time = 0;
255 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
259 sf = talloc(req, union smb_setfileinfo);
260 NT_STATUS_HAVE_NO_MEMORY(sf);
261 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
262 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
263 sf->end_of_file_info.in.size = set_size;
264 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
265 if (NT_STATUS_IS_OK(status)) {
266 io->openx.out.size = io->openx.in.size;
270 req->async_states->state = state;
276 the core of the mapping between openx style parameters and ntcreatex
279 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
280 uint16_t open_func, const char *fname,
283 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
284 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
286 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
287 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
290 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
291 case OPENX_MODE_ACCESS_READ:
292 case OPENX_MODE_ACCESS_EXEC:
293 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
295 case OPENX_MODE_ACCESS_WRITE:
296 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
298 case OPENX_MODE_ACCESS_RDWR:
299 case OPENX_MODE_ACCESS_FCB:
300 io2->generic.in.access_mask =
301 SEC_RIGHTS_FILE_READ |
302 SEC_RIGHTS_FILE_WRITE;
305 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
308 switch (open_mode & OPENX_MODE_DENY_MASK) {
309 case OPENX_MODE_DENY_READ:
310 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
312 case OPENX_MODE_DENY_WRITE:
313 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
315 case OPENX_MODE_DENY_ALL:
316 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
318 case OPENX_MODE_DENY_NONE:
319 io2->generic.in.share_access =
320 NTCREATEX_SHARE_ACCESS_READ |
321 NTCREATEX_SHARE_ACCESS_WRITE;
323 case OPENX_MODE_DENY_DOS:
324 /* DENY_DOS is quite strange - it depends on the filename! */
325 io2->generic.in.create_options |=
326 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
327 if (is_exe_filename(fname)) {
328 io2->generic.in.share_access =
329 NTCREATEX_SHARE_ACCESS_READ |
330 NTCREATEX_SHARE_ACCESS_WRITE;
332 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
333 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
335 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
339 case OPENX_MODE_DENY_FCB:
340 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
341 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
344 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
348 case (OPENX_OPEN_FUNC_OPEN):
349 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
351 case (OPENX_OPEN_FUNC_TRUNC):
352 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
354 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
355 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
357 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
358 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
360 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
361 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
364 /* this one is very strange */
365 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
366 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
369 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
376 NTVFS open generic to any mapper
378 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
379 struct ntvfs_request *req,
385 io2 = talloc_zero(req, union smb_open);
387 return NT_STATUS_NO_MEMORY;
390 status = ntvfs_map_async_setup(ntvfs, req,
392 (second_stage_t)ntvfs_map_open_finish);
393 if (!NT_STATUS_IS_OK(status)) {
397 io2->generic.level = RAW_OPEN_GENERIC;
399 switch (io->generic.level) {
401 status = map_openx_open(io->openx.in.flags,
402 io->openx.in.open_mode,
403 io->openx.in.open_func,
406 if (!NT_STATUS_IS_OK(status)) {
410 io2->generic.in.file_attr = io->openx.in.file_attrs;
411 io2->generic.in.fname = io->openx.in.fname;
413 status = ntvfs->ops->open(ntvfs, req, io2);
418 status = map_openx_open(0,
419 io->openold.in.open_mode,
420 OPENX_OPEN_FUNC_OPEN,
421 io->openold.in.fname,
423 if (!NT_STATUS_IS_OK(status)) {
427 io2->generic.in.file_attr = io->openold.in.search_attrs;
428 io2->generic.in.fname = io->openold.in.fname;
430 status = ntvfs->ops->open(ntvfs, req, io2);
433 case RAW_OPEN_T2OPEN:
434 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
436 if (io->t2open.in.open_func == 0) {
437 status = NT_STATUS_OBJECT_NAME_COLLISION;
441 status = map_openx_open(io->t2open.in.flags,
442 io->t2open.in.open_mode,
443 io->t2open.in.open_func,
446 if (!NT_STATUS_IS_OK(status)) {
450 io2->generic.in.file_attr = io->t2open.in.file_attrs;
451 io2->generic.in.fname = io->t2open.in.fname;
452 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
453 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
454 io2->generic.in.ea_list->eas = io->t2open.in.eas;
456 status = ntvfs->ops->open(ntvfs, req, io2);
460 io2->generic.in.file_attr = io->mknew.in.attrib;
461 io2->generic.in.fname = io->mknew.in.fname;
462 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
463 io2->generic.in.access_mask =
464 SEC_RIGHTS_FILE_READ |
465 SEC_RIGHTS_FILE_WRITE;
466 io2->generic.in.share_access =
467 NTCREATEX_SHARE_ACCESS_READ |
468 NTCREATEX_SHARE_ACCESS_WRITE;
469 status = ntvfs->ops->open(ntvfs, req, io2);
472 case RAW_OPEN_CREATE:
473 io2->generic.in.file_attr = io->mknew.in.attrib;
474 io2->generic.in.fname = io->mknew.in.fname;
475 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
476 io2->generic.in.access_mask =
477 SEC_RIGHTS_FILE_READ |
478 SEC_RIGHTS_FILE_WRITE;
479 io2->generic.in.share_access =
480 NTCREATEX_SHARE_ACCESS_READ |
481 NTCREATEX_SHARE_ACCESS_WRITE;
482 status = ntvfs->ops->open(ntvfs, req, io2);
486 io2->generic.in.file_attr = io->ctemp.in.attrib;
487 io2->generic.in.fname =
488 talloc_asprintf(io2, "%s\\SRV%s",
489 io->ctemp.in.directory,
490 generate_random_str_list(io2, 5, "0123456789"));
491 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
492 io2->generic.in.access_mask =
493 SEC_RIGHTS_FILE_READ |
494 SEC_RIGHTS_FILE_WRITE;
495 io2->generic.in.share_access =
496 NTCREATEX_SHARE_ACCESS_READ |
497 NTCREATEX_SHARE_ACCESS_WRITE;
498 status = ntvfs->ops->open(ntvfs, req, io2);
501 switch (io->smb2.in.oplock_level) {
502 case SMB2_OPLOCK_LEVEL_BATCH:
503 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
504 NTCREATEX_FLAGS_REQUEST_OPLOCK;
506 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
507 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
510 io2->generic.in.flags = 0;
513 io2->generic.in.root_fid = 0;
514 io2->generic.in.access_mask = io->smb2.in.desired_access;
515 io2->generic.in.alloc_size = 0;
516 io2->generic.in.file_attr = io->smb2.in.file_attributes;
517 io2->generic.in.share_access = io->smb2.in.share_access;
518 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
519 io2->generic.in.create_options = io->smb2.in.create_options;
520 io2->generic.in.impersonation = io->smb2.in.impersonation_level;
521 io2->generic.in.security_flags = 0;
522 io2->generic.in.fname = io->smb2.in.fname;
523 io2->generic.in.sec_desc = NULL;
524 io2->generic.in.ea_list = NULL;
526 /* we use a couple of bits of the create options internally */
527 if (io2->generic.in.create_options & NTCREATEX_OPTIONS_PRIVATE_MASK) {
528 return NT_STATUS_INVALID_PARAMETER;
531 status = ntvfs->ops->open(ntvfs, req, io2);
535 status = NT_STATUS_INVALID_LEVEL;
539 return ntvfs_map_async_finish(req, status);
544 NTVFS fsinfo generic to any mapper
546 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
547 struct ntvfs_request *req,
548 union smb_fsinfo *fs)
551 union smb_fsinfo *fs2;
553 fs2 = talloc(req, union smb_fsinfo);
555 return NT_STATUS_NO_MEMORY;
558 if (fs->generic.level == RAW_QFS_GENERIC) {
559 return NT_STATUS_INVALID_LEVEL;
562 /* only used by the simple backend, which doesn't do async */
563 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
565 /* ask the backend for the generic info */
566 fs2->generic.level = RAW_QFS_GENERIC;
568 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
569 if (!NT_STATUS_IS_OK(status)) {
573 /* and convert it to the required level */
574 switch (fs->generic.level) {
575 case RAW_QFS_GENERIC:
576 return NT_STATUS_INVALID_LEVEL;
578 case RAW_QFS_DSKATTR: {
579 /* map from generic to DSKATTR */
582 /* we need to scale the sizes to fit */
583 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
584 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
589 fs->dskattr.out.blocks_per_unit = bpunit;
590 fs->dskattr.out.block_size = 512;
591 fs->dskattr.out.units_total =
592 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
593 fs->dskattr.out.units_free =
594 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
596 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
597 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
598 fs->dskattr.out.blocks_per_unit = 64;
599 fs->dskattr.out.units_total = 0xFFFF;
600 fs->dskattr.out.units_free = 0xFFFF;
605 case RAW_QFS_ALLOCATION:
606 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
607 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
608 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
609 fs->allocation.out.sectors_per_unit = 1;
610 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
614 fs->volume.out.serial_number = fs2->generic.out.serial_number;
615 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
618 case RAW_QFS_VOLUME_INFO:
619 case RAW_QFS_VOLUME_INFORMATION:
620 fs->volume_info.out.create_time = fs2->generic.out.create_time;
621 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
622 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
625 case RAW_QFS_SIZE_INFO:
626 case RAW_QFS_SIZE_INFORMATION:
627 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
628 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
629 fs->size_info.out.sectors_per_unit = 1;
630 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
633 case RAW_QFS_DEVICE_INFO:
634 case RAW_QFS_DEVICE_INFORMATION:
635 fs->device_info.out.device_type = fs2->generic.out.device_type;
636 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
639 case RAW_QFS_ATTRIBUTE_INFO:
640 case RAW_QFS_ATTRIBUTE_INFORMATION:
641 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
642 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
643 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
646 case RAW_QFS_QUOTA_INFORMATION:
647 ZERO_STRUCT(fs->quota_information.out.unknown);
648 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
649 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
650 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
653 case RAW_QFS_FULL_SIZE_INFORMATION:
654 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
655 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
656 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
657 fs->full_size_information.out.sectors_per_unit = 1;
658 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
661 case RAW_QFS_OBJECTID_INFORMATION:
662 fs->objectid_information.out.guid = fs2->generic.out.guid;
663 ZERO_STRUCT(fs->objectid_information.out.unknown);
668 return NT_STATUS_INVALID_LEVEL;
673 NTVFS fileinfo generic to any mapper
675 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
676 union smb_fileinfo *info,
677 union smb_fileinfo *info2)
680 /* and convert it to the required level using results in info2 */
681 switch (info->generic.level) {
682 case RAW_FILEINFO_GENERIC:
683 return NT_STATUS_INVALID_LEVEL;
684 case RAW_FILEINFO_GETATTR:
685 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
686 info->getattr.out.size = info2->generic.out.size;
687 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
690 case RAW_FILEINFO_GETATTRE:
691 info->getattre.out.attrib = info2->generic.out.attrib;
692 info->getattre.out.size = info2->generic.out.size;
693 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
694 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
695 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
696 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
699 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
700 info->network_open_information.out.create_time = info2->generic.out.create_time;
701 info->network_open_information.out.access_time = info2->generic.out.access_time;
702 info->network_open_information.out.write_time = info2->generic.out.write_time;
703 info->network_open_information.out.change_time = info2->generic.out.change_time;
704 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
705 info->network_open_information.out.size = info2->generic.out.size;
706 info->network_open_information.out.attrib = info2->generic.out.attrib;
709 case RAW_FILEINFO_ALL_INFO:
710 case RAW_FILEINFO_ALL_INFORMATION:
711 info->all_info.out.create_time = info2->generic.out.create_time;
712 info->all_info.out.access_time = info2->generic.out.access_time;
713 info->all_info.out.write_time = info2->generic.out.write_time;
714 info->all_info.out.change_time = info2->generic.out.change_time;
715 info->all_info.out.attrib = info2->generic.out.attrib;
716 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
717 info->all_info.out.size = info2->generic.out.size;
718 info->all_info.out.nlink = info2->generic.out.nlink;
719 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
720 info->all_info.out.directory = info2->generic.out.directory;
721 info->all_info.out.ea_size = info2->generic.out.ea_size;
722 info->all_info.out.fname.s = info2->generic.out.fname.s;
723 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
726 case RAW_FILEINFO_BASIC_INFO:
727 case RAW_FILEINFO_BASIC_INFORMATION:
728 info->basic_info.out.create_time = info2->generic.out.create_time;
729 info->basic_info.out.access_time = info2->generic.out.access_time;
730 info->basic_info.out.write_time = info2->generic.out.write_time;
731 info->basic_info.out.change_time = info2->generic.out.change_time;
732 info->basic_info.out.attrib = info2->generic.out.attrib;
735 case RAW_FILEINFO_STANDARD:
736 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
737 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
738 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
739 info->standard.out.size = info2->generic.out.size;
740 info->standard.out.alloc_size = info2->generic.out.alloc_size;
741 info->standard.out.attrib = info2->generic.out.attrib;
744 case RAW_FILEINFO_EA_SIZE:
745 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
746 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
747 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
748 info->ea_size.out.size = info2->generic.out.size;
749 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
750 info->ea_size.out.attrib = info2->generic.out.attrib;
751 info->ea_size.out.ea_size = info2->generic.out.ea_size;
754 case RAW_FILEINFO_STANDARD_INFO:
755 case RAW_FILEINFO_STANDARD_INFORMATION:
756 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
757 info->standard_info.out.size = info2->generic.out.size;
758 info->standard_info.out.nlink = info2->generic.out.nlink;
759 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
760 info->standard_info.out.directory = info2->generic.out.directory;
763 case RAW_FILEINFO_INTERNAL_INFORMATION:
764 info->internal_information.out.file_id = info2->generic.out.file_id;
767 case RAW_FILEINFO_EA_INFO:
768 case RAW_FILEINFO_EA_INFORMATION:
769 info->ea_info.out.ea_size = info2->generic.out.ea_size;
772 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
773 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
774 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
777 case RAW_FILEINFO_STREAM_INFO:
778 case RAW_FILEINFO_STREAM_INFORMATION:
779 info->stream_info.out.num_streams = info2->generic.out.num_streams;
780 if (info->stream_info.out.num_streams > 0) {
781 info->stream_info.out.streams =
782 talloc_array(mem_ctx,
783 struct stream_struct,
784 info->stream_info.out.num_streams);
785 if (!info->stream_info.out.streams) {
786 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
787 info->stream_info.out.num_streams));
788 return NT_STATUS_NO_MEMORY;
790 for (i=0; i < info->stream_info.out.num_streams; i++) {
791 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
792 info->stream_info.out.streams[i].stream_name.s =
793 talloc_strdup(info->stream_info.out.streams,
794 info2->generic.out.streams[i].stream_name.s);
795 if (!info->stream_info.out.streams[i].stream_name.s) {
796 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
797 return NT_STATUS_NO_MEMORY;
803 case RAW_FILEINFO_NAME_INFO:
804 case RAW_FILEINFO_NAME_INFORMATION:
805 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
806 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
807 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
810 case RAW_FILEINFO_ALT_NAME_INFO:
811 case RAW_FILEINFO_ALT_NAME_INFORMATION:
812 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
813 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
814 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
817 case RAW_FILEINFO_POSITION_INFORMATION:
818 info->position_information.out.position = info2->generic.out.position;
821 case RAW_FILEINFO_ALL_EAS:
822 info->all_eas.out.num_eas = info2->generic.out.num_eas;
823 if (info->all_eas.out.num_eas > 0) {
824 info->all_eas.out.eas = talloc_array(mem_ctx,
826 info->all_eas.out.num_eas);
827 if (!info->all_eas.out.eas) {
828 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
829 info->all_eas.out.num_eas));
830 return NT_STATUS_NO_MEMORY;
832 for (i = 0; i < info->all_eas.out.num_eas; i++) {
833 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
834 info->all_eas.out.eas[i].name.s =
835 talloc_strdup(info->all_eas.out.eas,
836 info2->generic.out.eas[i].name.s);
837 if (!info->all_eas.out.eas[i].name.s) {
838 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
839 return NT_STATUS_NO_MEMORY;
841 info->all_eas.out.eas[i].value.data =
842 talloc_memdup(info->all_eas.out.eas,
843 info2->generic.out.eas[i].value.data,
844 info2->generic.out.eas[i].value.length);
845 if (!info->all_eas.out.eas[i].value.data) {
846 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
847 return NT_STATUS_NO_MEMORY;
853 case RAW_FILEINFO_IS_NAME_VALID:
856 case RAW_FILEINFO_COMPRESSION_INFO:
857 case RAW_FILEINFO_COMPRESSION_INFORMATION:
858 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
859 info->compression_info.out.format = info2->generic.out.format;
860 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
861 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
862 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
865 case RAW_FILEINFO_ACCESS_INFORMATION:
866 info->access_information.out.access_flags = info2->generic.out.access_flags;
869 case RAW_FILEINFO_MODE_INFORMATION:
870 info->mode_information.out.mode = info2->generic.out.mode;
873 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
874 info->alignment_information.out.alignment_requirement =
875 info2->generic.out.alignment_requirement;
878 case RAW_FILEINFO_UNIX_BASIC:
879 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
880 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
881 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
882 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
883 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
884 info->unix_basic_info.out.uid = info2->generic.out.uid;
885 info->unix_basic_info.out.gid = info2->generic.out.gid;
886 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
887 info->unix_basic_info.out.dev_major = info2->generic.out.device;
888 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
889 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
890 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
891 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
894 case RAW_FILEINFO_UNIX_LINK:
895 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
900 return NT_STATUS_INVALID_LEVEL;
904 NTVFS fileinfo generic to any mapper
906 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
907 struct ntvfs_request *req,
908 union smb_fileinfo *info)
911 union smb_fileinfo *info2;
913 info2 = talloc(req, union smb_fileinfo);
915 return NT_STATUS_NO_MEMORY;
918 if (info->generic.level == RAW_FILEINFO_GENERIC) {
919 return NT_STATUS_INVALID_LEVEL;
922 /* ask the backend for the generic info */
923 info2->generic.level = RAW_FILEINFO_GENERIC;
924 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
926 /* only used by the simple backend, which doesn't do async */
927 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
929 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
930 if (!NT_STATUS_IS_OK(status)) {
933 return ntvfs_map_fileinfo(req, info, info2);
937 NTVFS pathinfo generic to any mapper
939 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
940 struct ntvfs_request *req,
941 union smb_fileinfo *info)
944 union smb_fileinfo *info2;
946 info2 = talloc(req, union smb_fileinfo);
948 return NT_STATUS_NO_MEMORY;
951 if (info->generic.level == RAW_FILEINFO_GENERIC) {
952 return NT_STATUS_INVALID_LEVEL;
955 /* ask the backend for the generic info */
956 info2->generic.level = RAW_FILEINFO_GENERIC;
957 info2->generic.in.file.path = info->generic.in.file.path;
959 /* only used by the simple backend, which doesn't do async */
960 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
962 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
963 if (!NT_STATUS_IS_OK(status)) {
966 return ntvfs_map_fileinfo(req, info, info2);
971 NTVFS lock generic to any mapper
973 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
974 struct ntvfs_request *req,
977 union smb_lock *lck2;
978 struct smb_lock_entry *locks;
980 lck2 = talloc(req, union smb_lock);
982 return NT_STATUS_NO_MEMORY;
985 locks = talloc_array(lck2, struct smb_lock_entry, 1);
987 return NT_STATUS_NO_MEMORY;
990 switch (lck->generic.level) {
992 return NT_STATUS_INVALID_LEVEL;
995 lck2->generic.level = RAW_LOCK_GENERIC;
996 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
997 lck2->generic.in.mode = 0;
998 lck2->generic.in.timeout = 0;
999 lck2->generic.in.ulock_cnt = 0;
1000 lck2->generic.in.lock_cnt = 1;
1001 lck2->generic.in.locks = locks;
1002 locks->pid = req->smbpid;
1003 locks->offset = lck->lock.in.offset;
1004 locks->count = lck->lock.in.count;
1007 case RAW_LOCK_UNLOCK:
1008 lck2->generic.level = RAW_LOCK_GENERIC;
1009 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1010 lck2->generic.in.mode = 0;
1011 lck2->generic.in.timeout = 0;
1012 lck2->generic.in.ulock_cnt = 1;
1013 lck2->generic.in.lock_cnt = 0;
1014 lck2->generic.in.locks = locks;
1015 locks->pid = req->smbpid;
1016 locks->offset = lck->unlock.in.offset;
1017 locks->count = lck->unlock.in.count;
1020 case RAW_LOCK_SMB2: {
1021 /* this is only approximate! We need to change the
1022 generic structure to fix this properly */
1024 if (lck->smb2.in.lock_count < 1) {
1025 return NT_STATUS_INVALID_PARAMETER;
1028 lck2->generic.level = RAW_LOCK_GENERIC;
1029 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1030 lck2->generic.in.timeout = UINT32_MAX;
1031 lck2->generic.in.mode = 0;
1032 lck2->generic.in.lock_cnt = 0;
1033 lck2->generic.in.ulock_cnt = 0;
1034 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry,
1035 lck->smb2.in.lock_count);
1036 if (lck2->generic.in.locks == NULL) {
1037 return NT_STATUS_NO_MEMORY;
1039 for (i=0;i<lck->smb2.in.lock_count;i++) {
1040 if (lck->smb2.in.locks[i].flags & ~SMB2_LOCK_FLAG_ALL_MASK) {
1041 return NT_STATUS_INVALID_PARAMETER;
1043 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK) {
1044 int j = lck2->generic.in.ulock_cnt;
1045 lck2->generic.in.ulock_cnt++;
1046 lck2->generic.in.locks[j].pid = 0;
1047 lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1048 lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1049 lck2->generic.in.locks[j].pid = 0;
1052 for (i=0;i<lck->smb2.in.lock_count;i++) {
1053 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1054 int j = lck2->generic.in.ulock_cnt +
1055 lck2->generic.in.lock_cnt;
1056 lck2->generic.in.lock_cnt++;
1057 lck2->generic.in.locks[j].pid = 0;
1058 lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset;
1059 lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length;
1060 lck2->generic.in.locks[j].pid = 0;
1061 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1062 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1064 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1065 lck2->generic.in.timeout = 0;
1069 /* initialize output value */
1070 lck->smb2.out.reserved = 0;
1074 case RAW_LOCK_SMB2_BREAK:
1075 lck2->generic.level = RAW_LOCK_GENERIC;
1076 lck2->generic.in.file.ntvfs = lck->smb2_break.in.file.ntvfs;
1077 lck2->generic.in.mode = LOCKING_ANDX_OPLOCK_RELEASE |
1078 ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1079 lck2->generic.in.timeout = 0;
1080 lck2->generic.in.ulock_cnt = 0;
1081 lck2->generic.in.lock_cnt = 0;
1082 lck2->generic.in.locks = NULL;
1084 /* initialize output value */
1085 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1086 lck->smb2_break.out.reserved = lck->smb2_break.in.reserved;
1087 lck->smb2_break.out.reserved2 = lck->smb2_break.in.reserved2;
1088 lck->smb2_break.out.file = lck->smb2_break.in.file;
1093 * we don't need to call ntvfs_map_async_setup() here,
1094 * as lock() doesn't have any output fields
1097 return ntvfs->ops->lock(ntvfs, req, lck2);
1102 NTVFS write generic to any mapper
1104 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1105 struct ntvfs_request *req,
1106 union smb_write *wr,
1107 union smb_write *wr2,
1110 union smb_lock *lck;
1111 union smb_close *cl;
1114 if (NT_STATUS_IS_ERR(status)) {
1118 switch (wr->generic.level) {
1119 case RAW_WRITE_WRITE:
1120 wr->write.out.nwritten = wr2->generic.out.nwritten;
1123 case RAW_WRITE_WRITEUNLOCK:
1124 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1126 lck = talloc(wr2, union smb_lock);
1128 return NT_STATUS_NO_MEMORY;
1131 lck->unlock.level = RAW_LOCK_UNLOCK;
1132 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1133 lck->unlock.in.count = wr->writeunlock.in.count;
1134 lck->unlock.in.offset = wr->writeunlock.in.offset;
1136 if (lck->unlock.in.count != 0) {
1137 /* do the lock sync for now */
1138 state = req->async_states->state;
1139 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1140 status = ntvfs->ops->lock(ntvfs, req, lck);
1141 req->async_states->state = state;
1145 case RAW_WRITE_WRITECLOSE:
1146 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1148 cl = talloc(wr2, union smb_close);
1150 return NT_STATUS_NO_MEMORY;
1153 cl->close.level = RAW_CLOSE_CLOSE;
1154 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1155 cl->close.in.write_time = wr->writeclose.in.mtime;
1157 if (wr2->generic.in.count != 0) {
1158 /* do the close sync for now */
1159 state = req->async_states->state;
1160 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1161 status = ntvfs->ops->close(ntvfs, req, cl);
1162 req->async_states->state = state;
1166 case RAW_WRITE_SPLWRITE:
1169 case RAW_WRITE_SMB2:
1170 wr->smb2.out._pad = 0;
1171 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1172 wr->smb2.out.unknown1 = 0;
1176 return NT_STATUS_INVALID_LEVEL;
1184 NTVFS write generic to any mapper
1186 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1187 struct ntvfs_request *req,
1188 union smb_write *wr)
1190 union smb_write *wr2;
1193 wr2 = talloc(req, union smb_write);
1195 return NT_STATUS_NO_MEMORY;
1198 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1199 (second_stage_t)ntvfs_map_write_finish);
1200 if (!NT_STATUS_IS_OK(status)) {
1204 wr2->writex.level = RAW_WRITE_GENERIC;
1206 switch (wr->generic.level) {
1207 case RAW_WRITE_WRITEX:
1208 status = NT_STATUS_INVALID_LEVEL;
1211 case RAW_WRITE_WRITE:
1212 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1213 wr2->writex.in.offset = wr->write.in.offset;
1214 wr2->writex.in.wmode = 0;
1215 wr2->writex.in.remaining = wr->write.in.remaining;
1216 wr2->writex.in.count = wr->write.in.count;
1217 wr2->writex.in.data = wr->write.in.data;
1218 status = ntvfs->ops->write(ntvfs, req, wr2);
1221 case RAW_WRITE_WRITEUNLOCK:
1222 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1223 wr2->writex.in.offset = wr->writeunlock.in.offset;
1224 wr2->writex.in.wmode = 0;
1225 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1226 wr2->writex.in.count = wr->writeunlock.in.count;
1227 wr2->writex.in.data = wr->writeunlock.in.data;
1228 status = ntvfs->ops->write(ntvfs, req, wr2);
1231 case RAW_WRITE_WRITECLOSE:
1232 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1233 wr2->writex.in.offset = wr->writeclose.in.offset;
1234 wr2->writex.in.wmode = 0;
1235 wr2->writex.in.remaining = 0;
1236 wr2->writex.in.count = wr->writeclose.in.count;
1237 wr2->writex.in.data = wr->writeclose.in.data;
1238 status = ntvfs->ops->write(ntvfs, req, wr2);
1241 case RAW_WRITE_SPLWRITE:
1242 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1243 wr2->writex.in.offset = 0;
1244 wr2->writex.in.wmode = 0;
1245 wr2->writex.in.remaining = 0;
1246 wr2->writex.in.count = wr->splwrite.in.count;
1247 wr2->writex.in.data = wr->splwrite.in.data;
1248 status = ntvfs->ops->write(ntvfs, req, wr2);
1251 case RAW_WRITE_SMB2:
1252 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1253 wr2->writex.in.offset = wr->smb2.in.offset;
1254 wr2->writex.in.wmode = 0;
1255 wr2->writex.in.remaining = 0;
1256 wr2->writex.in.count = wr->smb2.in.data.length;
1257 wr2->writex.in.data = wr->smb2.in.data.data;
1258 status = ntvfs->ops->write(ntvfs, req, wr2);
1261 return ntvfs_map_async_finish(req, status);
1266 NTVFS read generic to any mapper - finish the out mapping
1268 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1269 struct ntvfs_request *req,
1271 union smb_read *rd2,
1274 switch (rd->generic.level) {
1276 rd->read.out.nread = rd2->generic.out.nread;
1278 case RAW_READ_READBRAW:
1279 rd->readbraw.out.nread = rd2->generic.out.nread;
1281 case RAW_READ_LOCKREAD:
1282 rd->lockread.out.nread = rd2->generic.out.nread;
1285 rd->smb2.out.data.length= rd2->generic.out.nread;
1286 rd->smb2.out.remaining = 0;
1287 rd->smb2.out.reserved = 0;
1288 if (NT_STATUS_IS_OK(status) &&
1289 rd->smb2.out.data.length == 0) {
1290 status = NT_STATUS_END_OF_FILE;
1292 /* SMB2 does honor the min_count field, SMB does not */
1293 if (NT_STATUS_IS_OK(status) &&
1294 rd->smb2.in.min_count > rd->smb2.out.data.length) {
1295 rd->smb2.out.data.length = 0;
1296 status = NT_STATUS_END_OF_FILE;
1300 return NT_STATUS_INVALID_LEVEL;
1307 NTVFS read* to readx mapper
1309 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1310 struct ntvfs_request *req,
1313 union smb_read *rd2;
1314 union smb_lock *lck;
1318 rd2 = talloc(req, union smb_read);
1320 return NT_STATUS_NO_MEMORY;
1323 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1324 (second_stage_t)ntvfs_map_read_finish);
1325 if (!NT_STATUS_IS_OK(status)) {
1329 rd2->readx.level = RAW_READ_READX;
1330 rd2->readx.in.read_for_execute = false;
1332 switch (rd->generic.level) {
1333 case RAW_READ_READX:
1334 status = NT_STATUS_INVALID_LEVEL;
1338 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1339 rd2->readx.in.offset = rd->read.in.offset;
1340 rd2->readx.in.mincnt = rd->read.in.count;
1341 rd2->readx.in.maxcnt = rd->read.in.count;
1342 rd2->readx.in.remaining = rd->read.in.remaining;
1343 rd2->readx.out.data = rd->read.out.data;
1344 status = ntvfs->ops->read(ntvfs, req, rd2);
1347 case RAW_READ_READBRAW:
1348 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1349 rd2->readx.in.offset = rd->readbraw.in.offset;
1350 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1351 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1352 rd2->readx.in.remaining = 0;
1353 rd2->readx.out.data = rd->readbraw.out.data;
1354 status = ntvfs->ops->read(ntvfs, req, rd2);
1357 case RAW_READ_LOCKREAD:
1358 /* do the initial lock sync for now */
1359 state = req->async_states->state;
1360 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1362 lck = talloc(rd2, union smb_lock);
1364 status = NT_STATUS_NO_MEMORY;
1367 lck->lock.level = RAW_LOCK_LOCK;
1368 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1369 lck->lock.in.count = rd->lockread.in.count;
1370 lck->lock.in.offset = rd->lockread.in.offset;
1371 status = ntvfs->ops->lock(ntvfs, req, lck);
1372 req->async_states->state = state;
1374 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1375 rd2->readx.in.offset = rd->lockread.in.offset;
1376 rd2->readx.in.mincnt = rd->lockread.in.count;
1377 rd2->readx.in.maxcnt = rd->lockread.in.count;
1378 rd2->readx.in.remaining = rd->lockread.in.remaining;
1379 rd2->readx.out.data = rd->lockread.out.data;
1381 if (NT_STATUS_IS_OK(status)) {
1382 status = ntvfs->ops->read(ntvfs, req, rd2);
1387 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1388 rd2->readx.in.offset = rd->smb2.in.offset;
1389 rd2->readx.in.mincnt = rd->smb2.in.length;
1390 rd2->readx.in.maxcnt = rd->smb2.in.length;
1391 rd2->readx.in.remaining = 0;
1392 rd2->readx.out.data = rd->smb2.out.data.data;
1393 status = ntvfs->ops->read(ntvfs, req, rd2);
1398 return ntvfs_map_async_finish(req, status);
1403 NTVFS close generic to any mapper
1405 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1406 struct ntvfs_request *req,
1407 union smb_close *cl)
1409 union smb_close *cl2;
1411 cl2 = talloc(req, union smb_close);
1413 return NT_STATUS_NO_MEMORY;
1416 switch (cl->generic.level) {
1417 case RAW_CLOSE_CLOSE:
1418 return NT_STATUS_INVALID_LEVEL;
1420 case RAW_CLOSE_SPLCLOSE:
1421 cl2->generic.level = RAW_CLOSE_CLOSE;
1422 cl2->generic.in.file.ntvfs = cl->splclose.in.file.ntvfs;
1423 cl2->generic.in.write_time = 0;
1426 case RAW_CLOSE_SMB2:
1427 cl2->generic.level = RAW_CLOSE_CLOSE;
1428 cl2->generic.in.file.ntvfs = cl->smb2.in.file.ntvfs;
1429 cl2->generic.in.write_time = 0;
1430 /* SMB2 Close has output parameter, but we just zero them */
1431 ZERO_STRUCT(cl->smb2.out);
1436 * we don't need to call ntvfs_map_async_setup() here,
1437 * as close() doesn't have any output fields
1440 return ntvfs->ops->close(ntvfs, req, cl2);
1444 NTVFS notify generic to any mapper
1446 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1447 struct ntvfs_request *req,
1448 union smb_notify *nt,
1449 union smb_notify *nt2,
1452 NT_STATUS_NOT_OK_RETURN(status);
1454 switch (nt->nttrans.level) {
1455 case RAW_NOTIFY_SMB2:
1456 if (nt2->nttrans.out.num_changes == 0) {
1457 return STATUS_NOTIFY_ENUM_DIR;
1459 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1460 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1464 return NT_STATUS_INVALID_LEVEL;
1472 NTVFS notify generic to any mapper
1474 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1475 struct ntvfs_request *req,
1476 union smb_notify *nt)
1478 union smb_notify *nt2;
1481 nt2 = talloc(req, union smb_notify);
1482 NT_STATUS_HAVE_NO_MEMORY(nt2);
1484 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1485 (second_stage_t)ntvfs_map_notify_finish);
1486 NT_STATUS_NOT_OK_RETURN(status);
1488 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1490 switch (nt->nttrans.level) {
1491 case RAW_NOTIFY_NTTRANS:
1492 status = NT_STATUS_INVALID_LEVEL;
1495 case RAW_NOTIFY_SMB2:
1496 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1497 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1498 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1499 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1500 status = ntvfs->ops->notify(ntvfs, req, nt2);
1504 return ntvfs_map_async_finish(req, status);