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 return NT_STATUS_INVALID_LEVEL;
212 /* doing a secondary request async is more trouble than its
214 state = req->async_states->state;
215 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
217 if (write_time != 0) {
218 sf = talloc(req, union smb_setfileinfo);
219 NT_STATUS_HAVE_NO_MEMORY(sf);
220 sf->generic.level = RAW_SFILEINFO_STANDARD;
221 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
222 sf->standard.in.create_time = 0;
223 sf->standard.in.write_time = write_time;
224 sf->standard.in.access_time = 0;
225 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
229 sf = talloc(req, union smb_setfileinfo);
230 NT_STATUS_HAVE_NO_MEMORY(sf);
231 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
232 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
233 sf->end_of_file_info.in.size = set_size;
234 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
235 if (NT_STATUS_IS_OK(status)) {
236 io->openx.out.size = io->openx.in.size;
240 req->async_states->state = state;
246 the core of the mapping between openx style parameters and ntcreatex
249 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
250 uint16_t open_func, const char *fname,
253 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
254 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
256 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
257 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
260 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
261 case OPENX_MODE_ACCESS_READ:
262 case OPENX_MODE_ACCESS_EXEC:
263 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
265 case OPENX_MODE_ACCESS_WRITE:
266 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
268 case OPENX_MODE_ACCESS_RDWR:
269 case OPENX_MODE_ACCESS_FCB:
270 io2->generic.in.access_mask =
271 SEC_RIGHTS_FILE_READ |
272 SEC_RIGHTS_FILE_WRITE;
275 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
278 switch (open_mode & OPENX_MODE_DENY_MASK) {
279 case OPENX_MODE_DENY_READ:
280 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
282 case OPENX_MODE_DENY_WRITE:
283 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
285 case OPENX_MODE_DENY_ALL:
286 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
288 case OPENX_MODE_DENY_NONE:
289 io2->generic.in.share_access =
290 NTCREATEX_SHARE_ACCESS_READ |
291 NTCREATEX_SHARE_ACCESS_WRITE;
293 case OPENX_MODE_DENY_DOS:
294 /* DENY_DOS is quite strange - it depends on the filename! */
295 io2->generic.in.create_options |=
296 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
297 if (is_exe_filename(fname)) {
298 io2->generic.in.share_access =
299 NTCREATEX_SHARE_ACCESS_READ |
300 NTCREATEX_SHARE_ACCESS_WRITE;
302 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
303 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
305 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
309 case OPENX_MODE_DENY_FCB:
310 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
311 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
314 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
318 case (OPENX_OPEN_FUNC_OPEN):
319 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
321 case (OPENX_OPEN_FUNC_TRUNC):
322 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
324 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
325 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
327 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
328 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
330 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
331 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
334 /* this one is very strange */
335 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
336 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
339 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
346 NTVFS open generic to any mapper
348 _PUBLIC_ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
349 struct ntvfs_request *req,
355 io2 = talloc_zero(req, union smb_open);
357 return NT_STATUS_NO_MEMORY;
360 status = ntvfs_map_async_setup(ntvfs, req,
362 (second_stage_t)ntvfs_map_open_finish);
363 if (!NT_STATUS_IS_OK(status)) {
367 io2->generic.level = RAW_OPEN_GENERIC;
369 switch (io->generic.level) {
371 status = map_openx_open(io->openx.in.flags,
372 io->openx.in.open_mode,
373 io->openx.in.open_func,
376 if (!NT_STATUS_IS_OK(status)) {
380 io2->generic.in.file_attr = io->openx.in.file_attrs;
381 io2->generic.in.fname = io->openx.in.fname;
383 status = ntvfs->ops->open(ntvfs, req, io2);
388 status = map_openx_open(0,
389 io->openold.in.open_mode,
390 OPENX_OPEN_FUNC_OPEN,
391 io->openold.in.fname,
393 if (!NT_STATUS_IS_OK(status)) {
397 io2->generic.in.file_attr = io->openold.in.search_attrs;
398 io2->generic.in.fname = io->openold.in.fname;
400 status = ntvfs->ops->open(ntvfs, req, io2);
403 case RAW_OPEN_T2OPEN:
404 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
406 if (io->t2open.in.open_func == 0) {
407 status = NT_STATUS_OBJECT_NAME_COLLISION;
411 status = map_openx_open(io->t2open.in.flags,
412 io->t2open.in.open_mode,
413 io->t2open.in.open_func,
416 if (!NT_STATUS_IS_OK(status)) {
420 io2->generic.in.file_attr = io->t2open.in.file_attrs;
421 io2->generic.in.fname = io->t2open.in.fname;
422 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
423 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
424 io2->generic.in.ea_list->eas = io->t2open.in.eas;
426 status = ntvfs->ops->open(ntvfs, req, io2);
430 io2->generic.in.file_attr = io->mknew.in.attrib;
431 io2->generic.in.fname = io->mknew.in.fname;
432 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
433 io2->generic.in.access_mask =
434 SEC_RIGHTS_FILE_READ |
435 SEC_RIGHTS_FILE_WRITE;
436 io2->generic.in.share_access =
437 NTCREATEX_SHARE_ACCESS_READ |
438 NTCREATEX_SHARE_ACCESS_WRITE;
439 status = ntvfs->ops->open(ntvfs, req, io2);
442 case RAW_OPEN_CREATE:
443 io2->generic.in.file_attr = io->mknew.in.attrib;
444 io2->generic.in.fname = io->mknew.in.fname;
445 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
446 io2->generic.in.access_mask =
447 SEC_RIGHTS_FILE_READ |
448 SEC_RIGHTS_FILE_WRITE;
449 io2->generic.in.share_access =
450 NTCREATEX_SHARE_ACCESS_READ |
451 NTCREATEX_SHARE_ACCESS_WRITE;
452 status = ntvfs->ops->open(ntvfs, req, io2);
456 io2->generic.in.file_attr = io->ctemp.in.attrib;
457 io2->generic.in.fname =
458 talloc_asprintf(io2, "%s\\SRV%s",
459 io->ctemp.in.directory,
460 generate_random_str_list(io2, 5, "0123456789"));
461 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
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 status = NT_STATUS_INVALID_LEVEL;
476 return ntvfs_map_async_finish(req, status);
481 NTVFS fsinfo generic to any mapper
483 _PUBLIC_ NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
484 struct ntvfs_request *req,
485 union smb_fsinfo *fs)
488 union smb_fsinfo *fs2;
490 fs2 = talloc(req, union smb_fsinfo);
492 return NT_STATUS_NO_MEMORY;
495 if (fs->generic.level == RAW_QFS_GENERIC) {
496 return NT_STATUS_INVALID_LEVEL;
499 /* only used by the simple backend, which doesn't do async */
500 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
502 /* ask the backend for the generic info */
503 fs2->generic.level = RAW_QFS_GENERIC;
505 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
506 if (!NT_STATUS_IS_OK(status)) {
510 /* and convert it to the required level */
511 switch (fs->generic.level) {
512 case RAW_QFS_GENERIC:
513 return NT_STATUS_INVALID_LEVEL;
515 case RAW_QFS_DSKATTR: {
516 /* map from generic to DSKATTR */
519 /* we need to scale the sizes to fit */
520 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
521 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
526 fs->dskattr.out.blocks_per_unit = bpunit;
527 fs->dskattr.out.block_size = 512;
528 fs->dskattr.out.units_total =
529 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
530 fs->dskattr.out.units_free =
531 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
533 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
534 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
535 fs->dskattr.out.blocks_per_unit = 64;
536 fs->dskattr.out.units_total = 0xFFFF;
537 fs->dskattr.out.units_free = 0xFFFF;
542 case RAW_QFS_ALLOCATION:
543 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
544 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
545 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
546 fs->allocation.out.sectors_per_unit = 1;
547 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
551 fs->volume.out.serial_number = fs2->generic.out.serial_number;
552 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
555 case RAW_QFS_VOLUME_INFO:
556 case RAW_QFS_VOLUME_INFORMATION:
557 fs->volume_info.out.create_time = fs2->generic.out.create_time;
558 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
559 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
562 case RAW_QFS_SIZE_INFO:
563 case RAW_QFS_SIZE_INFORMATION:
564 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
565 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
566 fs->size_info.out.sectors_per_unit = 1;
567 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
570 case RAW_QFS_DEVICE_INFO:
571 case RAW_QFS_DEVICE_INFORMATION:
572 fs->device_info.out.device_type = fs2->generic.out.device_type;
573 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
576 case RAW_QFS_ATTRIBUTE_INFO:
577 case RAW_QFS_ATTRIBUTE_INFORMATION:
578 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
579 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
580 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
583 case RAW_QFS_QUOTA_INFORMATION:
584 ZERO_STRUCT(fs->quota_information.out.unknown);
585 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
586 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
587 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
590 case RAW_QFS_FULL_SIZE_INFORMATION:
591 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
592 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
593 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
594 fs->full_size_information.out.sectors_per_unit = 1;
595 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
598 case RAW_QFS_OBJECTID_INFORMATION:
599 fs->objectid_information.out.guid = fs2->generic.out.guid;
600 ZERO_STRUCT(fs->objectid_information.out.unknown);
605 return NT_STATUS_INVALID_LEVEL;
610 NTVFS fileinfo generic to any mapper
612 _PUBLIC_ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
613 union smb_fileinfo *info,
614 union smb_fileinfo *info2)
617 /* and convert it to the required level using results in info2 */
618 switch (info->generic.level) {
619 case RAW_FILEINFO_GENERIC:
620 return NT_STATUS_INVALID_LEVEL;
621 case RAW_FILEINFO_GETATTR:
622 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
623 info->getattr.out.size = info2->generic.out.size;
624 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
627 case RAW_FILEINFO_GETATTRE:
628 info->getattre.out.attrib = info2->generic.out.attrib;
629 info->getattre.out.size = info2->generic.out.size;
630 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
631 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
632 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
633 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
636 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
637 info->network_open_information.out.create_time = info2->generic.out.create_time;
638 info->network_open_information.out.access_time = info2->generic.out.access_time;
639 info->network_open_information.out.write_time = info2->generic.out.write_time;
640 info->network_open_information.out.change_time = info2->generic.out.change_time;
641 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
642 info->network_open_information.out.size = info2->generic.out.size;
643 info->network_open_information.out.attrib = info2->generic.out.attrib;
646 case RAW_FILEINFO_ALL_INFO:
647 case RAW_FILEINFO_ALL_INFORMATION:
648 info->all_info.out.create_time = info2->generic.out.create_time;
649 info->all_info.out.access_time = info2->generic.out.access_time;
650 info->all_info.out.write_time = info2->generic.out.write_time;
651 info->all_info.out.change_time = info2->generic.out.change_time;
652 info->all_info.out.attrib = info2->generic.out.attrib;
653 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
654 info->all_info.out.size = info2->generic.out.size;
655 info->all_info.out.nlink = info2->generic.out.nlink;
656 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
657 info->all_info.out.directory = info2->generic.out.directory;
658 info->all_info.out.ea_size = info2->generic.out.ea_size;
659 info->all_info.out.fname.s = info2->generic.out.fname.s;
660 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
663 case RAW_FILEINFO_BASIC_INFO:
664 case RAW_FILEINFO_BASIC_INFORMATION:
665 info->basic_info.out.create_time = info2->generic.out.create_time;
666 info->basic_info.out.access_time = info2->generic.out.access_time;
667 info->basic_info.out.write_time = info2->generic.out.write_time;
668 info->basic_info.out.change_time = info2->generic.out.change_time;
669 info->basic_info.out.attrib = info2->generic.out.attrib;
672 case RAW_FILEINFO_STANDARD:
673 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
674 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
675 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
676 info->standard.out.size = info2->generic.out.size;
677 info->standard.out.alloc_size = info2->generic.out.alloc_size;
678 info->standard.out.attrib = info2->generic.out.attrib;
681 case RAW_FILEINFO_EA_SIZE:
682 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
683 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
684 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
685 info->ea_size.out.size = info2->generic.out.size;
686 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
687 info->ea_size.out.attrib = info2->generic.out.attrib;
688 info->ea_size.out.ea_size = info2->generic.out.ea_size;
691 case RAW_FILEINFO_STANDARD_INFO:
692 case RAW_FILEINFO_STANDARD_INFORMATION:
693 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
694 info->standard_info.out.size = info2->generic.out.size;
695 info->standard_info.out.nlink = info2->generic.out.nlink;
696 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
697 info->standard_info.out.directory = info2->generic.out.directory;
700 case RAW_FILEINFO_INTERNAL_INFORMATION:
701 info->internal_information.out.file_id = info2->generic.out.file_id;
704 case RAW_FILEINFO_EA_INFO:
705 case RAW_FILEINFO_EA_INFORMATION:
706 info->ea_info.out.ea_size = info2->generic.out.ea_size;
709 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
710 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
711 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
714 case RAW_FILEINFO_STREAM_INFO:
715 case RAW_FILEINFO_STREAM_INFORMATION:
716 info->stream_info.out.num_streams = info2->generic.out.num_streams;
717 if (info->stream_info.out.num_streams > 0) {
718 info->stream_info.out.streams =
719 talloc_array(mem_ctx,
720 struct stream_struct,
721 info->stream_info.out.num_streams);
722 if (!info->stream_info.out.streams) {
723 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
724 info->stream_info.out.num_streams));
725 return NT_STATUS_NO_MEMORY;
727 for (i=0; i < info->stream_info.out.num_streams; i++) {
728 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
729 info->stream_info.out.streams[i].stream_name.s =
730 talloc_strdup(info->stream_info.out.streams,
731 info2->generic.out.streams[i].stream_name.s);
732 if (!info->stream_info.out.streams[i].stream_name.s) {
733 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
734 return NT_STATUS_NO_MEMORY;
740 case RAW_FILEINFO_NAME_INFO:
741 case RAW_FILEINFO_NAME_INFORMATION:
742 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
743 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
744 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
747 case RAW_FILEINFO_ALT_NAME_INFO:
748 case RAW_FILEINFO_ALT_NAME_INFORMATION:
749 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
750 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
751 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
754 case RAW_FILEINFO_POSITION_INFORMATION:
755 info->position_information.out.position = info2->generic.out.position;
758 case RAW_FILEINFO_ALL_EAS:
759 info->all_eas.out.num_eas = info2->generic.out.num_eas;
760 if (info->all_eas.out.num_eas > 0) {
761 info->all_eas.out.eas = talloc_array(mem_ctx,
763 info->all_eas.out.num_eas);
764 if (!info->all_eas.out.eas) {
765 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
766 info->all_eas.out.num_eas));
767 return NT_STATUS_NO_MEMORY;
769 for (i = 0; i < info->all_eas.out.num_eas; i++) {
770 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
771 info->all_eas.out.eas[i].name.s =
772 talloc_strdup(info->all_eas.out.eas,
773 info2->generic.out.eas[i].name.s);
774 if (!info->all_eas.out.eas[i].name.s) {
775 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
776 return NT_STATUS_NO_MEMORY;
778 info->all_eas.out.eas[i].value.data =
779 talloc_memdup(info->all_eas.out.eas,
780 info2->generic.out.eas[i].value.data,
781 info2->generic.out.eas[i].value.length);
782 if (!info->all_eas.out.eas[i].value.data) {
783 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
784 return NT_STATUS_NO_MEMORY;
790 case RAW_FILEINFO_IS_NAME_VALID:
793 case RAW_FILEINFO_COMPRESSION_INFO:
794 case RAW_FILEINFO_COMPRESSION_INFORMATION:
795 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
796 info->compression_info.out.format = info2->generic.out.format;
797 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
798 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
799 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
802 case RAW_FILEINFO_ACCESS_INFORMATION:
803 info->access_information.out.access_flags = info2->generic.out.access_flags;
806 case RAW_FILEINFO_MODE_INFORMATION:
807 info->mode_information.out.mode = info2->generic.out.mode;
810 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
811 info->alignment_information.out.alignment_requirement =
812 info2->generic.out.alignment_requirement;
815 case RAW_FILEINFO_UNIX_BASIC:
816 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
817 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
818 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
819 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
820 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
821 info->unix_basic_info.out.uid = info2->generic.out.uid;
822 info->unix_basic_info.out.gid = info2->generic.out.gid;
823 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
824 info->unix_basic_info.out.dev_major = info2->generic.out.device;
825 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
826 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
827 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
828 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
831 case RAW_FILEINFO_UNIX_LINK:
832 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
837 return NT_STATUS_INVALID_LEVEL;
841 NTVFS fileinfo generic to any mapper
843 _PUBLIC_ NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
844 struct ntvfs_request *req,
845 union smb_fileinfo *info)
848 union smb_fileinfo *info2;
850 info2 = talloc(req, union smb_fileinfo);
852 return NT_STATUS_NO_MEMORY;
855 if (info->generic.level == RAW_FILEINFO_GENERIC) {
856 return NT_STATUS_INVALID_LEVEL;
859 /* ask the backend for the generic info */
860 info2->generic.level = RAW_FILEINFO_GENERIC;
861 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
863 /* only used by the simple backend, which doesn't do async */
864 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
866 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
867 if (!NT_STATUS_IS_OK(status)) {
870 return ntvfs_map_fileinfo(req, info, info2);
874 NTVFS pathinfo generic to any mapper
876 _PUBLIC_ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
877 struct ntvfs_request *req,
878 union smb_fileinfo *info)
881 union smb_fileinfo *info2;
883 info2 = talloc(req, union smb_fileinfo);
885 return NT_STATUS_NO_MEMORY;
888 if (info->generic.level == RAW_FILEINFO_GENERIC) {
889 return NT_STATUS_INVALID_LEVEL;
892 /* ask the backend for the generic info */
893 info2->generic.level = RAW_FILEINFO_GENERIC;
894 info2->generic.in.file.path = info->generic.in.file.path;
896 /* only used by the simple backend, which doesn't do async */
897 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
899 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
900 if (!NT_STATUS_IS_OK(status)) {
903 return ntvfs_map_fileinfo(req, info, info2);
908 NTVFS lock generic to any mapper
910 _PUBLIC_ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
911 struct ntvfs_request *req,
914 union smb_lock *lck2;
915 struct smb_lock_entry *locks;
917 lck2 = talloc(req, union smb_lock);
919 return NT_STATUS_NO_MEMORY;
922 locks = talloc_array(lck2, struct smb_lock_entry, 1);
924 return NT_STATUS_NO_MEMORY;
927 switch (lck->generic.level) {
929 return NT_STATUS_INVALID_LEVEL;
932 lck2->generic.in.ulock_cnt = 0;
933 lck2->generic.in.lock_cnt = 1;
936 case RAW_LOCK_UNLOCK:
937 lck2->generic.in.ulock_cnt = 1;
938 lck2->generic.in.lock_cnt = 0;
942 lck2->generic.level = RAW_LOCK_GENERIC;
943 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
944 lck2->generic.in.mode = 0;
945 lck2->generic.in.timeout = 0;
946 lck2->generic.in.locks = locks;
947 locks->pid = req->smbpid;
948 locks->offset = lck->lock.in.offset;
949 locks->count = lck->lock.in.count;
952 * we don't need to call ntvfs_map_async_setup() here,
953 * as lock() doesn't have any output fields
956 return ntvfs->ops->lock(ntvfs, req, lck2);
961 NTVFS write generic to any mapper
963 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
964 struct ntvfs_request *req,
966 union smb_write *wr2,
973 if (NT_STATUS_IS_ERR(status)) {
977 switch (wr->generic.level) {
978 case RAW_WRITE_WRITE:
979 wr->write.out.nwritten = wr2->generic.out.nwritten;
982 case RAW_WRITE_WRITEUNLOCK:
983 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
985 lck = talloc(wr2, union smb_lock);
987 return NT_STATUS_NO_MEMORY;
990 lck->unlock.level = RAW_LOCK_UNLOCK;
991 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
992 lck->unlock.in.count = wr->writeunlock.in.count;
993 lck->unlock.in.offset = wr->writeunlock.in.offset;
995 if (lck->unlock.in.count != 0) {
996 /* do the lock sync for now */
997 state = req->async_states->state;
998 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
999 status = ntvfs->ops->lock(ntvfs, req, lck);
1000 req->async_states->state = state;
1004 case RAW_WRITE_WRITECLOSE:
1005 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1007 cl = talloc(wr2, union smb_close);
1009 return NT_STATUS_NO_MEMORY;
1012 cl->close.level = RAW_CLOSE_CLOSE;
1013 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1014 cl->close.in.write_time = wr->writeclose.in.mtime;
1016 if (wr2->generic.in.count != 0) {
1017 /* do the close sync for now */
1018 state = req->async_states->state;
1019 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1020 status = ntvfs->ops->close(ntvfs, req, cl);
1021 req->async_states->state = state;
1025 case RAW_WRITE_SPLWRITE:
1028 return NT_STATUS_INVALID_LEVEL;
1036 NTVFS write generic to any mapper
1038 _PUBLIC_ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1039 struct ntvfs_request *req,
1040 union smb_write *wr)
1042 union smb_write *wr2;
1045 wr2 = talloc(req, union smb_write);
1047 return NT_STATUS_NO_MEMORY;
1050 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1051 (second_stage_t)ntvfs_map_write_finish);
1052 if (!NT_STATUS_IS_OK(status)) {
1056 wr2->writex.level = RAW_WRITE_GENERIC;
1058 switch (wr->generic.level) {
1059 case RAW_WRITE_WRITEX:
1060 status = NT_STATUS_INVALID_LEVEL;
1063 case RAW_WRITE_WRITE:
1064 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1065 wr2->writex.in.offset = wr->write.in.offset;
1066 wr2->writex.in.wmode = 0;
1067 wr2->writex.in.remaining = wr->write.in.remaining;
1068 wr2->writex.in.count = wr->write.in.count;
1069 wr2->writex.in.data = wr->write.in.data;
1070 status = ntvfs->ops->write(ntvfs, req, wr2);
1073 case RAW_WRITE_WRITEUNLOCK:
1074 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1075 wr2->writex.in.offset = wr->writeunlock.in.offset;
1076 wr2->writex.in.wmode = 0;
1077 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1078 wr2->writex.in.count = wr->writeunlock.in.count;
1079 wr2->writex.in.data = wr->writeunlock.in.data;
1080 status = ntvfs->ops->write(ntvfs, req, wr2);
1083 case RAW_WRITE_WRITECLOSE:
1084 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1085 wr2->writex.in.offset = wr->writeclose.in.offset;
1086 wr2->writex.in.wmode = 0;
1087 wr2->writex.in.remaining = 0;
1088 wr2->writex.in.count = wr->writeclose.in.count;
1089 wr2->writex.in.data = wr->writeclose.in.data;
1090 status = ntvfs->ops->write(ntvfs, req, wr2);
1093 case RAW_WRITE_SPLWRITE:
1094 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1095 wr2->writex.in.offset = 0;
1096 wr2->writex.in.wmode = 0;
1097 wr2->writex.in.remaining = 0;
1098 wr2->writex.in.count = wr->splwrite.in.count;
1099 wr2->writex.in.data = wr->splwrite.in.data;
1100 status = ntvfs->ops->write(ntvfs, req, wr2);
1104 return ntvfs_map_async_finish(req, status);
1109 NTVFS read generic to any mapper - finish the out mapping
1111 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1112 struct ntvfs_request *req,
1114 union smb_read *rd2,
1117 switch (rd->generic.level) {
1119 rd->read.out.nread = rd2->generic.out.nread;
1121 case RAW_READ_READBRAW:
1122 rd->readbraw.out.nread = rd2->generic.out.nread;
1124 case RAW_READ_LOCKREAD:
1125 rd->lockread.out.nread = rd2->generic.out.nread;
1128 return NT_STATUS_INVALID_LEVEL;
1135 NTVFS read* to readx mapper
1137 _PUBLIC_ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1138 struct ntvfs_request *req,
1141 union smb_read *rd2;
1142 union smb_lock *lck;
1146 rd2 = talloc(req, union smb_read);
1148 return NT_STATUS_NO_MEMORY;
1151 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1152 (second_stage_t)ntvfs_map_read_finish);
1153 if (!NT_STATUS_IS_OK(status)) {
1157 rd2->readx.level = RAW_READ_READX;
1158 rd2->readx.in.read_for_execute = False;
1160 switch (rd->generic.level) {
1161 case RAW_READ_READX:
1162 status = NT_STATUS_INVALID_LEVEL;
1166 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1167 rd2->readx.in.offset = rd->read.in.offset;
1168 rd2->readx.in.mincnt = rd->read.in.count;
1169 rd2->readx.in.maxcnt = rd->read.in.count;
1170 rd2->readx.in.remaining = rd->read.in.remaining;
1171 rd2->readx.out.data = rd->read.out.data;
1172 status = ntvfs->ops->read(ntvfs, req, rd2);
1175 case RAW_READ_READBRAW:
1176 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1177 rd2->readx.in.offset = rd->readbraw.in.offset;
1178 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1179 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1180 rd2->readx.in.remaining = 0;
1181 rd2->readx.out.data = rd->readbraw.out.data;
1182 status = ntvfs->ops->read(ntvfs, req, rd2);
1185 case RAW_READ_LOCKREAD:
1186 /* do the initial lock sync for now */
1187 state = req->async_states->state;
1188 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1190 lck = talloc(rd2, union smb_lock);
1192 status = NT_STATUS_NO_MEMORY;
1195 lck->lock.level = RAW_LOCK_LOCK;
1196 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1197 lck->lock.in.count = rd->lockread.in.count;
1198 lck->lock.in.offset = rd->lockread.in.offset;
1199 status = ntvfs->ops->lock(ntvfs, req, lck);
1200 req->async_states->state = state;
1202 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1203 rd2->readx.in.offset = rd->lockread.in.offset;
1204 rd2->readx.in.mincnt = rd->lockread.in.count;
1205 rd2->readx.in.maxcnt = rd->lockread.in.count;
1206 rd2->readx.in.remaining = rd->lockread.in.remaining;
1207 rd2->readx.out.data = rd->lockread.out.data;
1209 if (NT_STATUS_IS_OK(status)) {
1210 status = ntvfs->ops->read(ntvfs, req, rd2);
1216 return ntvfs_map_async_finish(req, status);
1221 NTVFS close generic to any mapper
1223 _PUBLIC_ NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1224 struct ntvfs_request *req,
1225 union smb_close *cl)
1227 union smb_close *cl2;
1229 cl2 = talloc(req, union smb_close);
1231 return NT_STATUS_NO_MEMORY;
1234 switch (cl->generic.level) {
1235 case RAW_CLOSE_CLOSE:
1236 return NT_STATUS_INVALID_LEVEL;
1238 case RAW_CLOSE_SPLCLOSE:
1239 cl2->close.level = RAW_CLOSE_CLOSE;
1240 cl2->close.in.file.ntvfs= cl->splclose.in.file.ntvfs;
1245 * we don't need to call ntvfs_map_async_setup() here,
1246 * as close() doesn't have any output fields
1249 return ntvfs->ops->close(ntvfs, req, cl2);