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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 this implements mappings between info levels for NTVFS backend calls
25 the idea is that each of these functions implements one of the NTVFS
26 backend calls in terms of the 'generic' call. All backends that use
27 these functions must supply the generic call, but can if it wants to
28 also implement other levels if the need arises
30 this allows backend writers to only implement one variant of each
31 call unless they need fine grained control of the calls.
35 #include "ntvfs/ntvfs.h"
37 /* a second stage function converts from the out parameters of the generic
38 call onto the out parameters of the specific call made */
39 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
40 struct ntvfs_request *,
41 void *, void *, NTSTATUS);
44 this structure holds the async state for pending mapped async calls
46 struct ntvfs_map_async {
47 struct ntvfs_module_context *ntvfs;
53 this is a async wrapper, called from the backend when it has completed
54 a function that it has decided to reply to in an async fashion
56 static void ntvfs_map_async_send(struct ntvfs_request *req)
58 struct ntvfs_map_async *m = req->async_states->private_data;
60 ntvfs_async_state_pop(req);
62 /* call the _finish function setup in ntvfs_map_async_setup() */
63 req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
65 /* call the send function from the next module up */
66 req->async_states->send_fn(req);
70 prepare for calling a ntvfs backend with async support
71 io is the original call structure
72 io2 is the new call structure for the mapped call
73 fn is a second stage function for processing the out arguments
75 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
76 struct ntvfs_request *req,
80 struct ntvfs_map_async *m;
81 m = talloc(req, struct ntvfs_map_async);
83 return NT_STATUS_NO_MEMORY;
89 return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
93 called when first stage processing is complete.
95 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
97 struct ntvfs_map_async *m;
99 /* if the backend has decided to reply in an async fashion then
100 we don't need to do any work here */
101 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
105 /* the backend is replying immediately. call the 2nd stage function after popping our local
107 m = req->async_states->private_data;
109 ntvfs_async_state_pop(req);
111 return m->fn(m->ntvfs, req, m->io, m->io2, status);
115 see if a filename ends in EXE COM DLL or SYM. This is needed for the
116 DENY_DOS mapping for OpenX
118 BOOL is_exe_filename(const char *fname)
121 p = strrchr(fname, '.');
126 if (strcasecmp(p, "EXE") == 0 ||
127 strcasecmp(p, "COM") == 0 ||
128 strcasecmp(p, "DLL") == 0 ||
129 strcasecmp(p, "SYM") == 0) {
137 NTVFS openx to ntcreatex mapper
139 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
140 struct ntvfs_request *req,
145 time_t write_time = 0;
146 uint32_t set_size = 0;
147 union smb_setfileinfo *sf;
150 if (!NT_STATUS_IS_OK(status)) {
154 switch (io->generic.level) {
156 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
157 io->openold.out.attrib = io2->generic.out.attrib;
158 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
159 io->openold.out.size = io2->generic.out.size;
160 io->openold.out.rmode = io->openold.in.open_mode;
164 io->openx.out.file.ntvfs = io2->generic.out.file.ntvfs;
165 io->openx.out.attrib = io2->generic.out.attrib;
166 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
167 io->openx.out.size = io2->generic.out.size;
168 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
169 io->openx.out.ftype = 0;
170 io->openx.out.devstate = 0;
171 io->openx.out.action = io2->generic.out.create_action;
172 io->openx.out.unique_fid = 0;
173 io->openx.out.access_mask = SEC_STD_ALL;
174 io->openx.out.unknown = 0;
176 /* we need to extend the file to the requested size if
177 it was newly created */
178 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
179 set_size = io->openx.in.size;
183 case RAW_OPEN_T2OPEN:
184 io->t2open.out.file.ntvfs = io2->generic.out.file.ntvfs;
185 io->t2open.out.attrib = io2->generic.out.attrib;
186 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
187 io->t2open.out.size = io2->generic.out.size;
188 io->t2open.out.access = io->t2open.in.open_mode;
189 io->t2open.out.ftype = 0;
190 io->t2open.out.devstate = 0;
191 io->t2open.out.action = io2->generic.out.create_action;
192 io->t2open.out.file_id = 0;
196 case RAW_OPEN_CREATE:
197 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
198 write_time = io->mknew.in.write_time;
202 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
203 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
204 strlen(io->ctemp.in.directory) + 1);
205 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
209 io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs;
210 io->smb2.out.oplock_flags = 0;
211 io->smb2.out.create_action = io2->generic.out.create_action;
212 io->smb2.out.create_time = io2->generic.out.create_time;
213 io->smb2.out.access_time = io2->generic.out.access_time;
214 io->smb2.out.write_time = io2->generic.out.write_time;
215 io->smb2.out.change_time = io2->generic.out.change_time;
216 io->smb2.out.alloc_size = io2->generic.out.alloc_size;
217 io->smb2.out.size = io2->generic.out.size;
218 /*io->smb2.out.file_attr = io2->generic.out.attrib; would this be correct? */
219 io->smb2.out.file_attr = 0;
220 io->smb2.out._pad = 0;
221 io->smb2.out.blob = data_blob(NULL, 0);
225 return NT_STATUS_INVALID_LEVEL;
228 /* doing a secondary request async is more trouble than its
230 state = req->async_states->state;
231 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
233 if (write_time != 0) {
234 sf = talloc(req, union smb_setfileinfo);
235 NT_STATUS_HAVE_NO_MEMORY(sf);
236 sf->generic.level = RAW_SFILEINFO_STANDARD;
237 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
238 sf->standard.in.create_time = 0;
239 sf->standard.in.write_time = write_time;
240 sf->standard.in.access_time = 0;
241 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
245 sf = talloc(req, union smb_setfileinfo);
246 NT_STATUS_HAVE_NO_MEMORY(sf);
247 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
248 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
249 sf->end_of_file_info.in.size = set_size;
250 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
251 if (NT_STATUS_IS_OK(status)) {
252 io->openx.out.size = io->openx.in.size;
256 req->async_states->state = state;
262 the core of the mapping between openx style parameters and ntcreatex
265 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
266 uint16_t open_func, const char *fname,
269 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
270 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
272 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
273 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
276 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
277 case OPENX_MODE_ACCESS_READ:
278 case OPENX_MODE_ACCESS_EXEC:
279 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
281 case OPENX_MODE_ACCESS_WRITE:
282 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
284 case OPENX_MODE_ACCESS_RDWR:
285 case OPENX_MODE_ACCESS_FCB:
286 io2->generic.in.access_mask =
287 SEC_RIGHTS_FILE_READ |
288 SEC_RIGHTS_FILE_WRITE;
291 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
294 switch (open_mode & OPENX_MODE_DENY_MASK) {
295 case OPENX_MODE_DENY_READ:
296 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
298 case OPENX_MODE_DENY_WRITE:
299 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
301 case OPENX_MODE_DENY_ALL:
302 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
304 case OPENX_MODE_DENY_NONE:
305 io2->generic.in.share_access =
306 NTCREATEX_SHARE_ACCESS_READ |
307 NTCREATEX_SHARE_ACCESS_WRITE;
309 case OPENX_MODE_DENY_DOS:
310 /* DENY_DOS is quite strange - it depends on the filename! */
311 io2->generic.in.create_options |=
312 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
313 if (is_exe_filename(fname)) {
314 io2->generic.in.share_access =
315 NTCREATEX_SHARE_ACCESS_READ |
316 NTCREATEX_SHARE_ACCESS_WRITE;
318 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
319 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
321 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
325 case OPENX_MODE_DENY_FCB:
326 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
327 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
330 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
334 case (OPENX_OPEN_FUNC_OPEN):
335 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
337 case (OPENX_OPEN_FUNC_TRUNC):
338 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
340 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
341 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
343 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
344 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
346 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
347 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
350 /* this one is very strange */
351 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
352 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
355 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
362 NTVFS open generic to any mapper
364 _PUBLIC_ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
365 struct ntvfs_request *req,
371 io2 = talloc_zero(req, union smb_open);
373 return NT_STATUS_NO_MEMORY;
376 status = ntvfs_map_async_setup(ntvfs, req,
378 (second_stage_t)ntvfs_map_open_finish);
379 if (!NT_STATUS_IS_OK(status)) {
383 io2->generic.level = RAW_OPEN_GENERIC;
385 switch (io->generic.level) {
387 status = map_openx_open(io->openx.in.flags,
388 io->openx.in.open_mode,
389 io->openx.in.open_func,
392 if (!NT_STATUS_IS_OK(status)) {
396 io2->generic.in.file_attr = io->openx.in.file_attrs;
397 io2->generic.in.fname = io->openx.in.fname;
399 status = ntvfs->ops->open(ntvfs, req, io2);
404 status = map_openx_open(0,
405 io->openold.in.open_mode,
406 OPENX_OPEN_FUNC_OPEN,
407 io->openold.in.fname,
409 if (!NT_STATUS_IS_OK(status)) {
413 io2->generic.in.file_attr = io->openold.in.search_attrs;
414 io2->generic.in.fname = io->openold.in.fname;
416 status = ntvfs->ops->open(ntvfs, req, io2);
419 case RAW_OPEN_T2OPEN:
420 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
422 if (io->t2open.in.open_func == 0) {
423 status = NT_STATUS_OBJECT_NAME_COLLISION;
427 status = map_openx_open(io->t2open.in.flags,
428 io->t2open.in.open_mode,
429 io->t2open.in.open_func,
432 if (!NT_STATUS_IS_OK(status)) {
436 io2->generic.in.file_attr = io->t2open.in.file_attrs;
437 io2->generic.in.fname = io->t2open.in.fname;
438 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
439 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
440 io2->generic.in.ea_list->eas = io->t2open.in.eas;
442 status = ntvfs->ops->open(ntvfs, req, io2);
446 io2->generic.in.file_attr = io->mknew.in.attrib;
447 io2->generic.in.fname = io->mknew.in.fname;
448 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
449 io2->generic.in.access_mask =
450 SEC_RIGHTS_FILE_READ |
451 SEC_RIGHTS_FILE_WRITE;
452 io2->generic.in.share_access =
453 NTCREATEX_SHARE_ACCESS_READ |
454 NTCREATEX_SHARE_ACCESS_WRITE;
455 status = ntvfs->ops->open(ntvfs, req, io2);
458 case RAW_OPEN_CREATE:
459 io2->generic.in.file_attr = io->mknew.in.attrib;
460 io2->generic.in.fname = io->mknew.in.fname;
461 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
462 io2->generic.in.access_mask =
463 SEC_RIGHTS_FILE_READ |
464 SEC_RIGHTS_FILE_WRITE;
465 io2->generic.in.share_access =
466 NTCREATEX_SHARE_ACCESS_READ |
467 NTCREATEX_SHARE_ACCESS_WRITE;
468 status = ntvfs->ops->open(ntvfs, req, io2);
472 io2->generic.in.file_attr = io->ctemp.in.attrib;
473 io2->generic.in.fname =
474 talloc_asprintf(io2, "%s\\SRV%s",
475 io->ctemp.in.directory,
476 generate_random_str_list(io2, 5, "0123456789"));
477 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
478 io2->generic.in.access_mask =
479 SEC_RIGHTS_FILE_READ |
480 SEC_RIGHTS_FILE_WRITE;
481 io2->generic.in.share_access =
482 NTCREATEX_SHARE_ACCESS_READ |
483 NTCREATEX_SHARE_ACCESS_WRITE;
484 status = ntvfs->ops->open(ntvfs, req, io2);
487 io2->generic.in.flags = 0;
488 io2->generic.in.root_fid = 0;
489 io2->generic.in.access_mask = io->smb2.in.access_mask;
490 io2->generic.in.alloc_size = 0;
491 io2->generic.in.file_attr = io->smb2.in.file_attr;
492 io2->generic.in.share_access = io->smb2.in.share_access;
493 io2->generic.in.open_disposition= io->smb2.in.open_disposition;
494 io2->generic.in.create_options = io->smb2.in.create_options;
495 io2->generic.in.impersonation = io->smb2.in.impersonation;
496 io2->generic.in.security_flags = 0;
497 io2->generic.in.fname = io->smb2.in.fname;
498 io2->generic.in.sec_desc = NULL;
499 io2->generic.in.ea_list = NULL;
500 status = ntvfs->ops->open(ntvfs, req, io2);
504 status = NT_STATUS_INVALID_LEVEL;
508 return ntvfs_map_async_finish(req, status);
513 NTVFS fsinfo generic to any mapper
515 _PUBLIC_ NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
516 struct ntvfs_request *req,
517 union smb_fsinfo *fs)
520 union smb_fsinfo *fs2;
522 fs2 = talloc(req, union smb_fsinfo);
524 return NT_STATUS_NO_MEMORY;
527 if (fs->generic.level == RAW_QFS_GENERIC) {
528 return NT_STATUS_INVALID_LEVEL;
531 /* only used by the simple backend, which doesn't do async */
532 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
534 /* ask the backend for the generic info */
535 fs2->generic.level = RAW_QFS_GENERIC;
537 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
538 if (!NT_STATUS_IS_OK(status)) {
542 /* and convert it to the required level */
543 switch (fs->generic.level) {
544 case RAW_QFS_GENERIC:
545 return NT_STATUS_INVALID_LEVEL;
547 case RAW_QFS_DSKATTR: {
548 /* map from generic to DSKATTR */
551 /* we need to scale the sizes to fit */
552 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
553 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
558 fs->dskattr.out.blocks_per_unit = bpunit;
559 fs->dskattr.out.block_size = 512;
560 fs->dskattr.out.units_total =
561 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
562 fs->dskattr.out.units_free =
563 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
565 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
566 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
567 fs->dskattr.out.blocks_per_unit = 64;
568 fs->dskattr.out.units_total = 0xFFFF;
569 fs->dskattr.out.units_free = 0xFFFF;
574 case RAW_QFS_ALLOCATION:
575 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
576 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
577 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
578 fs->allocation.out.sectors_per_unit = 1;
579 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
583 fs->volume.out.serial_number = fs2->generic.out.serial_number;
584 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
587 case RAW_QFS_VOLUME_INFO:
588 case RAW_QFS_VOLUME_INFORMATION:
589 fs->volume_info.out.create_time = fs2->generic.out.create_time;
590 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
591 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
594 case RAW_QFS_SIZE_INFO:
595 case RAW_QFS_SIZE_INFORMATION:
596 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
597 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
598 fs->size_info.out.sectors_per_unit = 1;
599 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
602 case RAW_QFS_DEVICE_INFO:
603 case RAW_QFS_DEVICE_INFORMATION:
604 fs->device_info.out.device_type = fs2->generic.out.device_type;
605 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
608 case RAW_QFS_ATTRIBUTE_INFO:
609 case RAW_QFS_ATTRIBUTE_INFORMATION:
610 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
611 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
612 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
615 case RAW_QFS_QUOTA_INFORMATION:
616 ZERO_STRUCT(fs->quota_information.out.unknown);
617 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
618 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
619 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
622 case RAW_QFS_FULL_SIZE_INFORMATION:
623 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
624 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
625 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
626 fs->full_size_information.out.sectors_per_unit = 1;
627 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
630 case RAW_QFS_OBJECTID_INFORMATION:
631 fs->objectid_information.out.guid = fs2->generic.out.guid;
632 ZERO_STRUCT(fs->objectid_information.out.unknown);
637 return NT_STATUS_INVALID_LEVEL;
642 NTVFS fileinfo generic to any mapper
644 _PUBLIC_ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
645 union smb_fileinfo *info,
646 union smb_fileinfo *info2)
649 /* and convert it to the required level using results in info2 */
650 switch (info->generic.level) {
651 case RAW_FILEINFO_GENERIC:
652 return NT_STATUS_INVALID_LEVEL;
653 case RAW_FILEINFO_GETATTR:
654 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
655 info->getattr.out.size = info2->generic.out.size;
656 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
659 case RAW_FILEINFO_GETATTRE:
660 info->getattre.out.attrib = info2->generic.out.attrib;
661 info->getattre.out.size = info2->generic.out.size;
662 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
663 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
664 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
665 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
668 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
669 info->network_open_information.out.create_time = info2->generic.out.create_time;
670 info->network_open_information.out.access_time = info2->generic.out.access_time;
671 info->network_open_information.out.write_time = info2->generic.out.write_time;
672 info->network_open_information.out.change_time = info2->generic.out.change_time;
673 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
674 info->network_open_information.out.size = info2->generic.out.size;
675 info->network_open_information.out.attrib = info2->generic.out.attrib;
678 case RAW_FILEINFO_ALL_INFO:
679 case RAW_FILEINFO_ALL_INFORMATION:
680 info->all_info.out.create_time = info2->generic.out.create_time;
681 info->all_info.out.access_time = info2->generic.out.access_time;
682 info->all_info.out.write_time = info2->generic.out.write_time;
683 info->all_info.out.change_time = info2->generic.out.change_time;
684 info->all_info.out.attrib = info2->generic.out.attrib;
685 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
686 info->all_info.out.size = info2->generic.out.size;
687 info->all_info.out.nlink = info2->generic.out.nlink;
688 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
689 info->all_info.out.directory = info2->generic.out.directory;
690 info->all_info.out.ea_size = info2->generic.out.ea_size;
691 info->all_info.out.fname.s = info2->generic.out.fname.s;
692 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
695 case RAW_FILEINFO_BASIC_INFO:
696 case RAW_FILEINFO_BASIC_INFORMATION:
697 info->basic_info.out.create_time = info2->generic.out.create_time;
698 info->basic_info.out.access_time = info2->generic.out.access_time;
699 info->basic_info.out.write_time = info2->generic.out.write_time;
700 info->basic_info.out.change_time = info2->generic.out.change_time;
701 info->basic_info.out.attrib = info2->generic.out.attrib;
704 case RAW_FILEINFO_STANDARD:
705 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
706 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
707 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
708 info->standard.out.size = info2->generic.out.size;
709 info->standard.out.alloc_size = info2->generic.out.alloc_size;
710 info->standard.out.attrib = info2->generic.out.attrib;
713 case RAW_FILEINFO_EA_SIZE:
714 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
715 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
716 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
717 info->ea_size.out.size = info2->generic.out.size;
718 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
719 info->ea_size.out.attrib = info2->generic.out.attrib;
720 info->ea_size.out.ea_size = info2->generic.out.ea_size;
723 case RAW_FILEINFO_STANDARD_INFO:
724 case RAW_FILEINFO_STANDARD_INFORMATION:
725 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
726 info->standard_info.out.size = info2->generic.out.size;
727 info->standard_info.out.nlink = info2->generic.out.nlink;
728 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
729 info->standard_info.out.directory = info2->generic.out.directory;
732 case RAW_FILEINFO_INTERNAL_INFORMATION:
733 info->internal_information.out.file_id = info2->generic.out.file_id;
736 case RAW_FILEINFO_EA_INFO:
737 case RAW_FILEINFO_EA_INFORMATION:
738 info->ea_info.out.ea_size = info2->generic.out.ea_size;
741 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
742 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
743 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
746 case RAW_FILEINFO_STREAM_INFO:
747 case RAW_FILEINFO_STREAM_INFORMATION:
748 info->stream_info.out.num_streams = info2->generic.out.num_streams;
749 if (info->stream_info.out.num_streams > 0) {
750 info->stream_info.out.streams =
751 talloc_array(mem_ctx,
752 struct stream_struct,
753 info->stream_info.out.num_streams);
754 if (!info->stream_info.out.streams) {
755 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
756 info->stream_info.out.num_streams));
757 return NT_STATUS_NO_MEMORY;
759 for (i=0; i < info->stream_info.out.num_streams; i++) {
760 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
761 info->stream_info.out.streams[i].stream_name.s =
762 talloc_strdup(info->stream_info.out.streams,
763 info2->generic.out.streams[i].stream_name.s);
764 if (!info->stream_info.out.streams[i].stream_name.s) {
765 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
766 return NT_STATUS_NO_MEMORY;
772 case RAW_FILEINFO_NAME_INFO:
773 case RAW_FILEINFO_NAME_INFORMATION:
774 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
775 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
776 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
779 case RAW_FILEINFO_ALT_NAME_INFO:
780 case RAW_FILEINFO_ALT_NAME_INFORMATION:
781 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
782 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
783 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
786 case RAW_FILEINFO_POSITION_INFORMATION:
787 info->position_information.out.position = info2->generic.out.position;
790 case RAW_FILEINFO_ALL_EAS:
791 info->all_eas.out.num_eas = info2->generic.out.num_eas;
792 if (info->all_eas.out.num_eas > 0) {
793 info->all_eas.out.eas = talloc_array(mem_ctx,
795 info->all_eas.out.num_eas);
796 if (!info->all_eas.out.eas) {
797 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
798 info->all_eas.out.num_eas));
799 return NT_STATUS_NO_MEMORY;
801 for (i = 0; i < info->all_eas.out.num_eas; i++) {
802 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
803 info->all_eas.out.eas[i].name.s =
804 talloc_strdup(info->all_eas.out.eas,
805 info2->generic.out.eas[i].name.s);
806 if (!info->all_eas.out.eas[i].name.s) {
807 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
808 return NT_STATUS_NO_MEMORY;
810 info->all_eas.out.eas[i].value.data =
811 talloc_memdup(info->all_eas.out.eas,
812 info2->generic.out.eas[i].value.data,
813 info2->generic.out.eas[i].value.length);
814 if (!info->all_eas.out.eas[i].value.data) {
815 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
816 return NT_STATUS_NO_MEMORY;
822 case RAW_FILEINFO_IS_NAME_VALID:
825 case RAW_FILEINFO_COMPRESSION_INFO:
826 case RAW_FILEINFO_COMPRESSION_INFORMATION:
827 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
828 info->compression_info.out.format = info2->generic.out.format;
829 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
830 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
831 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
834 case RAW_FILEINFO_ACCESS_INFORMATION:
835 info->access_information.out.access_flags = info2->generic.out.access_flags;
838 case RAW_FILEINFO_MODE_INFORMATION:
839 info->mode_information.out.mode = info2->generic.out.mode;
842 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
843 info->alignment_information.out.alignment_requirement =
844 info2->generic.out.alignment_requirement;
847 case RAW_FILEINFO_UNIX_BASIC:
848 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
849 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
850 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
851 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
852 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
853 info->unix_basic_info.out.uid = info2->generic.out.uid;
854 info->unix_basic_info.out.gid = info2->generic.out.gid;
855 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
856 info->unix_basic_info.out.dev_major = info2->generic.out.device;
857 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
858 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
859 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
860 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
863 case RAW_FILEINFO_UNIX_LINK:
864 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
869 return NT_STATUS_INVALID_LEVEL;
873 NTVFS fileinfo generic to any mapper
875 _PUBLIC_ NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
876 struct ntvfs_request *req,
877 union smb_fileinfo *info)
880 union smb_fileinfo *info2;
882 info2 = talloc(req, union smb_fileinfo);
884 return NT_STATUS_NO_MEMORY;
887 if (info->generic.level == RAW_FILEINFO_GENERIC) {
888 return NT_STATUS_INVALID_LEVEL;
891 /* ask the backend for the generic info */
892 info2->generic.level = RAW_FILEINFO_GENERIC;
893 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
895 /* only used by the simple backend, which doesn't do async */
896 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
898 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
899 if (!NT_STATUS_IS_OK(status)) {
902 return ntvfs_map_fileinfo(req, info, info2);
906 NTVFS pathinfo generic to any mapper
908 _PUBLIC_ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
909 struct ntvfs_request *req,
910 union smb_fileinfo *info)
913 union smb_fileinfo *info2;
915 info2 = talloc(req, union smb_fileinfo);
917 return NT_STATUS_NO_MEMORY;
920 if (info->generic.level == RAW_FILEINFO_GENERIC) {
921 return NT_STATUS_INVALID_LEVEL;
924 /* ask the backend for the generic info */
925 info2->generic.level = RAW_FILEINFO_GENERIC;
926 info2->generic.in.file.path = info->generic.in.file.path;
928 /* only used by the simple backend, which doesn't do async */
929 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
931 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
932 if (!NT_STATUS_IS_OK(status)) {
935 return ntvfs_map_fileinfo(req, info, info2);
940 NTVFS lock generic to any mapper
942 _PUBLIC_ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
943 struct ntvfs_request *req,
946 union smb_lock *lck2;
947 struct smb_lock_entry *locks;
949 lck2 = talloc(req, union smb_lock);
951 return NT_STATUS_NO_MEMORY;
954 locks = talloc_array(lck2, struct smb_lock_entry, 1);
956 return NT_STATUS_NO_MEMORY;
959 switch (lck->generic.level) {
961 return NT_STATUS_INVALID_LEVEL;
964 lck2->generic.in.ulock_cnt = 0;
965 lck2->generic.in.lock_cnt = 1;
968 case RAW_LOCK_UNLOCK:
969 lck2->generic.in.ulock_cnt = 1;
970 lck2->generic.in.lock_cnt = 0;
974 lck2->generic.level = RAW_LOCK_GENERIC;
975 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
976 lck2->generic.in.mode = 0;
977 lck2->generic.in.timeout = 0;
978 lck2->generic.in.locks = locks;
979 locks->pid = req->smbpid;
980 locks->offset = lck->lock.in.offset;
981 locks->count = lck->lock.in.count;
984 * we don't need to call ntvfs_map_async_setup() here,
985 * as lock() doesn't have any output fields
988 return ntvfs->ops->lock(ntvfs, req, lck2);
993 NTVFS write generic to any mapper
995 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
996 struct ntvfs_request *req,
998 union smb_write *wr2,
1001 union smb_lock *lck;
1002 union smb_close *cl;
1005 if (NT_STATUS_IS_ERR(status)) {
1009 switch (wr->generic.level) {
1010 case RAW_WRITE_WRITE:
1011 wr->write.out.nwritten = wr2->generic.out.nwritten;
1014 case RAW_WRITE_WRITEUNLOCK:
1015 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1017 lck = talloc(wr2, union smb_lock);
1019 return NT_STATUS_NO_MEMORY;
1022 lck->unlock.level = RAW_LOCK_UNLOCK;
1023 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1024 lck->unlock.in.count = wr->writeunlock.in.count;
1025 lck->unlock.in.offset = wr->writeunlock.in.offset;
1027 if (lck->unlock.in.count != 0) {
1028 /* do the lock sync for now */
1029 state = req->async_states->state;
1030 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1031 status = ntvfs->ops->lock(ntvfs, req, lck);
1032 req->async_states->state = state;
1036 case RAW_WRITE_WRITECLOSE:
1037 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1039 cl = talloc(wr2, union smb_close);
1041 return NT_STATUS_NO_MEMORY;
1044 cl->close.level = RAW_CLOSE_CLOSE;
1045 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1046 cl->close.in.write_time = wr->writeclose.in.mtime;
1048 if (wr2->generic.in.count != 0) {
1049 /* do the close sync for now */
1050 state = req->async_states->state;
1051 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1052 status = ntvfs->ops->close(ntvfs, req, cl);
1053 req->async_states->state = state;
1057 case RAW_WRITE_SPLWRITE:
1060 return NT_STATUS_INVALID_LEVEL;
1068 NTVFS write generic to any mapper
1070 _PUBLIC_ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1071 struct ntvfs_request *req,
1072 union smb_write *wr)
1074 union smb_write *wr2;
1077 wr2 = talloc(req, union smb_write);
1079 return NT_STATUS_NO_MEMORY;
1082 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1083 (second_stage_t)ntvfs_map_write_finish);
1084 if (!NT_STATUS_IS_OK(status)) {
1088 wr2->writex.level = RAW_WRITE_GENERIC;
1090 switch (wr->generic.level) {
1091 case RAW_WRITE_WRITEX:
1092 status = NT_STATUS_INVALID_LEVEL;
1095 case RAW_WRITE_WRITE:
1096 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1097 wr2->writex.in.offset = wr->write.in.offset;
1098 wr2->writex.in.wmode = 0;
1099 wr2->writex.in.remaining = wr->write.in.remaining;
1100 wr2->writex.in.count = wr->write.in.count;
1101 wr2->writex.in.data = wr->write.in.data;
1102 status = ntvfs->ops->write(ntvfs, req, wr2);
1105 case RAW_WRITE_WRITEUNLOCK:
1106 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1107 wr2->writex.in.offset = wr->writeunlock.in.offset;
1108 wr2->writex.in.wmode = 0;
1109 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1110 wr2->writex.in.count = wr->writeunlock.in.count;
1111 wr2->writex.in.data = wr->writeunlock.in.data;
1112 status = ntvfs->ops->write(ntvfs, req, wr2);
1115 case RAW_WRITE_WRITECLOSE:
1116 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1117 wr2->writex.in.offset = wr->writeclose.in.offset;
1118 wr2->writex.in.wmode = 0;
1119 wr2->writex.in.remaining = 0;
1120 wr2->writex.in.count = wr->writeclose.in.count;
1121 wr2->writex.in.data = wr->writeclose.in.data;
1122 status = ntvfs->ops->write(ntvfs, req, wr2);
1125 case RAW_WRITE_SPLWRITE:
1126 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1127 wr2->writex.in.offset = 0;
1128 wr2->writex.in.wmode = 0;
1129 wr2->writex.in.remaining = 0;
1130 wr2->writex.in.count = wr->splwrite.in.count;
1131 wr2->writex.in.data = wr->splwrite.in.data;
1132 status = ntvfs->ops->write(ntvfs, req, wr2);
1136 return ntvfs_map_async_finish(req, status);
1141 NTVFS read generic to any mapper - finish the out mapping
1143 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1144 struct ntvfs_request *req,
1146 union smb_read *rd2,
1149 switch (rd->generic.level) {
1151 rd->read.out.nread = rd2->generic.out.nread;
1153 case RAW_READ_READBRAW:
1154 rd->readbraw.out.nread = rd2->generic.out.nread;
1156 case RAW_READ_LOCKREAD:
1157 rd->lockread.out.nread = rd2->generic.out.nread;
1160 return NT_STATUS_INVALID_LEVEL;
1167 NTVFS read* to readx mapper
1169 _PUBLIC_ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1170 struct ntvfs_request *req,
1173 union smb_read *rd2;
1174 union smb_lock *lck;
1178 rd2 = talloc(req, union smb_read);
1180 return NT_STATUS_NO_MEMORY;
1183 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1184 (second_stage_t)ntvfs_map_read_finish);
1185 if (!NT_STATUS_IS_OK(status)) {
1189 rd2->readx.level = RAW_READ_READX;
1190 rd2->readx.in.read_for_execute = False;
1192 switch (rd->generic.level) {
1193 case RAW_READ_READX:
1194 status = NT_STATUS_INVALID_LEVEL;
1198 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1199 rd2->readx.in.offset = rd->read.in.offset;
1200 rd2->readx.in.mincnt = rd->read.in.count;
1201 rd2->readx.in.maxcnt = rd->read.in.count;
1202 rd2->readx.in.remaining = rd->read.in.remaining;
1203 rd2->readx.out.data = rd->read.out.data;
1204 status = ntvfs->ops->read(ntvfs, req, rd2);
1207 case RAW_READ_READBRAW:
1208 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1209 rd2->readx.in.offset = rd->readbraw.in.offset;
1210 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1211 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1212 rd2->readx.in.remaining = 0;
1213 rd2->readx.out.data = rd->readbraw.out.data;
1214 status = ntvfs->ops->read(ntvfs, req, rd2);
1217 case RAW_READ_LOCKREAD:
1218 /* do the initial lock sync for now */
1219 state = req->async_states->state;
1220 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1222 lck = talloc(rd2, union smb_lock);
1224 status = NT_STATUS_NO_MEMORY;
1227 lck->lock.level = RAW_LOCK_LOCK;
1228 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1229 lck->lock.in.count = rd->lockread.in.count;
1230 lck->lock.in.offset = rd->lockread.in.offset;
1231 status = ntvfs->ops->lock(ntvfs, req, lck);
1232 req->async_states->state = state;
1234 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1235 rd2->readx.in.offset = rd->lockread.in.offset;
1236 rd2->readx.in.mincnt = rd->lockread.in.count;
1237 rd2->readx.in.maxcnt = rd->lockread.in.count;
1238 rd2->readx.in.remaining = rd->lockread.in.remaining;
1239 rd2->readx.out.data = rd->lockread.out.data;
1241 if (NT_STATUS_IS_OK(status)) {
1242 status = ntvfs->ops->read(ntvfs, req, rd2);
1248 return ntvfs_map_async_finish(req, status);
1253 NTVFS close generic to any mapper
1255 _PUBLIC_ NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1256 struct ntvfs_request *req,
1257 union smb_close *cl)
1259 union smb_close *cl2;
1261 cl2 = talloc(req, union smb_close);
1263 return NT_STATUS_NO_MEMORY;
1266 switch (cl->generic.level) {
1267 case RAW_CLOSE_CLOSE:
1268 return NT_STATUS_INVALID_LEVEL;
1270 case RAW_CLOSE_SPLCLOSE:
1271 cl2->generic.level = RAW_CLOSE_CLOSE;
1272 cl2->generic.in.file.ntvfs = cl->splclose.in.file.ntvfs;
1275 case RAW_CLOSE_SMB2:
1276 cl2->generic.level = RAW_CLOSE_CLOSE;
1277 cl2->generic.in.file.ntvfs = cl->smb2.in.file.ntvfs;
1278 /* SMB2 Close has output parameter, but we just zero them */
1279 ZERO_STRUCT(cl->smb2.out);
1284 * we don't need to call ntvfs_map_async_setup() here,
1285 * as close() doesn't have any output fields
1288 return ntvfs->ops->close(ntvfs, req, cl2);