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 "smb_server/smb_server.h"
36 #include "librpc/gen_ndr/ndr_security.h"
37 #include "ntvfs/ntvfs.h"
39 /* a second stage function converts from the out parameters of the generic
40 call onto the out parameters of the specific call made */
41 typedef NTSTATUS (*second_stage_t)(struct smbsrv_request *,
42 struct ntvfs_module_context *,
43 void *, void *, NTSTATUS);
46 this structure holds the async state for pending mapped async calls
48 struct ntvfs_map_async {
49 struct ntvfs_module_context *ntvfs;
55 this is a async wrapper, called from the backend when it has completed
56 a function that it has decided to reply to in an async fashion
58 static void ntvfs_map_async_send(struct smbsrv_request *req)
60 struct ntvfs_map_async *m = req->async_states->private_data;
62 ntvfs_async_state_pop(req);
64 /* call the _finish function setup in ntvfs_map_async_setup() */
65 req->async_states->status = m->fn(req, m->ntvfs, m->io, m->io2, req->async_states->status);
67 /* call the send function from the next module up */
68 req->async_states->send_fn(req);
72 prepare for calling a ntvfs backend with async support
73 io is the original call structure
74 io2 is the new call structure for the mapped call
75 fn is a second stage function for processing the out arguments
77 static NTSTATUS ntvfs_map_async_setup(struct smbsrv_request *req,
78 struct ntvfs_module_context *ntvfs,
82 struct ntvfs_map_async *m;
83 m = talloc(req, struct ntvfs_map_async);
85 return NT_STATUS_NO_MEMORY;
91 return ntvfs_async_state_push(req, m, ntvfs_map_async_send, ntvfs);
96 called when first stage processing is complete.
98 static NTSTATUS ntvfs_map_async_finish(struct smbsrv_request *req, NTSTATUS status)
100 struct ntvfs_map_async *m;
102 /* if the backend has decided to reply in an async fashion then
103 we don't need to do any work here */
104 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
108 /* the backend is replying immediately. call the 2nd stage function after popping our local
110 m = req->async_states->private_data;
112 ntvfs_async_state_pop(req);
114 return m->fn(req, m->ntvfs, m->io, m->io2, status);
119 see if a filename ends in EXE COM DLL or SYM. This is needed for the
120 DENY_DOS mapping for OpenX
122 BOOL is_exe_filename(const char *fname)
125 p = strrchr(fname, '.');
130 if (strcasecmp(p, "EXE") == 0 ||
131 strcasecmp(p, "COM") == 0 ||
132 strcasecmp(p, "DLL") == 0 ||
133 strcasecmp(p, "SYM") == 0) {
141 NTVFS openx to ntcreatex mapper
143 static NTSTATUS ntvfs_map_open_finish(struct smbsrv_request *req,
144 struct ntvfs_module_context *ntvfs,
149 time_t write_time = 0;
150 uint32_t set_size = 0;
151 union smb_setfileinfo *sf;
154 if (!NT_STATUS_IS_OK(status)) {
158 switch (io->generic.level) {
160 io->openold.out.fnum = io2->generic.out.fnum;
161 io->openold.out.attrib = io2->generic.out.attrib;
162 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
163 io->openold.out.size = io2->generic.out.size;
164 io->openold.out.rmode = io->openold.in.open_mode;
168 io->openx.out.fnum = io2->generic.out.fnum;
169 io->openx.out.attrib = io2->generic.out.attrib;
170 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
171 io->openx.out.size = io2->generic.out.size;
172 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
173 io->openx.out.ftype = 0;
174 io->openx.out.devstate = 0;
175 io->openx.out.action = io2->generic.out.create_action;
176 io->openx.out.unique_fid = 0;
177 io->openx.out.access_mask = SEC_STD_ALL;
178 io->openx.out.unknown = 0;
180 /* we need to extend the file to the requested size if
181 it was newly created */
182 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
183 set_size = io->openx.in.size;
187 case RAW_OPEN_T2OPEN:
188 io->t2open.out.fnum = io2->generic.out.fnum;
189 io->t2open.out.attrib = io2->generic.out.attrib;
190 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
191 io->t2open.out.size = io2->generic.out.size;
192 io->t2open.out.access = io->t2open.in.open_mode;
193 io->t2open.out.ftype = 0;
194 io->t2open.out.devstate = 0;
195 io->t2open.out.action = io2->generic.out.create_action;
196 io->t2open.out.file_id = 0;
200 case RAW_OPEN_CREATE:
201 io->mknew.out.fnum = io2->generic.out.fnum;
202 write_time = io->mknew.in.write_time;
206 io->ctemp.out.fnum = io2->generic.out.fnum;
207 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
208 strlen(io->ctemp.in.directory) + 1);
212 return NT_STATUS_INVALID_LEVEL;
215 /* doing a secondary request async is more trouble than its
217 state = req->async_states->state;
218 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
220 if (write_time != 0) {
221 sf = talloc(req, union smb_setfileinfo);
222 sf->generic.level = RAW_SFILEINFO_STANDARD;
223 sf->generic.file.fnum = io2->generic.out.fnum;
224 sf->standard.in.create_time = 0;
225 sf->standard.in.write_time = write_time;
226 sf->standard.in.access_time = 0;
227 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
231 sf = talloc(req, union smb_setfileinfo);
232 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
233 sf->generic.file.fnum = io2->generic.out.fnum;
234 sf->end_of_file_info.in.size = set_size;
235 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
236 if (NT_STATUS_IS_OK(status)) {
237 io->openx.out.size = io->openx.in.size;
241 req->async_states->state = state;
247 the core of the mapping between openx style parameters and ntcreatex
250 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
251 uint16_t open_func, const char *fname,
254 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
255 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
257 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
258 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
261 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
262 case OPENX_MODE_ACCESS_READ:
263 case OPENX_MODE_ACCESS_EXEC:
264 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
266 case OPENX_MODE_ACCESS_WRITE:
267 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
269 case OPENX_MODE_ACCESS_RDWR:
270 case OPENX_MODE_ACCESS_FCB:
271 io2->generic.in.access_mask =
272 SEC_RIGHTS_FILE_READ |
273 SEC_RIGHTS_FILE_WRITE;
276 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
279 switch (open_mode & OPENX_MODE_DENY_MASK) {
280 case OPENX_MODE_DENY_READ:
281 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
283 case OPENX_MODE_DENY_WRITE:
284 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
286 case OPENX_MODE_DENY_ALL:
287 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
289 case OPENX_MODE_DENY_NONE:
290 io2->generic.in.share_access =
291 NTCREATEX_SHARE_ACCESS_READ |
292 NTCREATEX_SHARE_ACCESS_WRITE;
294 case OPENX_MODE_DENY_DOS:
295 /* DENY_DOS is quite strange - it depends on the filename! */
296 io2->generic.in.create_options |=
297 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
298 if (is_exe_filename(fname)) {
299 io2->generic.in.share_access =
300 NTCREATEX_SHARE_ACCESS_READ |
301 NTCREATEX_SHARE_ACCESS_WRITE;
303 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
304 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
306 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
310 case OPENX_MODE_DENY_FCB:
311 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
312 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
315 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
319 case (OPENX_OPEN_FUNC_OPEN):
320 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
322 case (OPENX_OPEN_FUNC_TRUNC):
323 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
325 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
326 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
328 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
329 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
331 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
332 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
335 /* this one is very strange */
336 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
337 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
340 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
347 NTVFS open generic to any mapper
349 _PUBLIC_ NTSTATUS ntvfs_map_open(struct smbsrv_request *req, union smb_open *io,
350 struct ntvfs_module_context *ntvfs)
355 io2 = talloc_zero(req, union smb_open);
357 return NT_STATUS_NO_MEMORY;
360 status = ntvfs_map_async_setup(req, ntvfs, io, io2,
361 (second_stage_t)ntvfs_map_open_finish);
362 if (!NT_STATUS_IS_OK(status)) {
366 io2->generic.level = RAW_OPEN_GENERIC;
368 switch (io->generic.level) {
370 status = map_openx_open(io->openx.in.flags,
371 io->openx.in.open_mode,
372 io->openx.in.open_func,
375 if (!NT_STATUS_IS_OK(status)) {
379 io2->generic.in.file_attr = io->openx.in.file_attrs;
380 io2->generic.in.fname = io->openx.in.fname;
382 status = ntvfs->ops->openfile(ntvfs, req, io2);
387 status = map_openx_open(0,
388 io->openold.in.open_mode,
389 OPENX_OPEN_FUNC_OPEN,
390 io->openold.in.fname,
392 if (!NT_STATUS_IS_OK(status)) {
396 io2->generic.in.file_attr = io->openold.in.search_attrs;
397 io2->generic.in.fname = io->openold.in.fname;
399 status = ntvfs->ops->openfile(ntvfs, req, io2);
402 case RAW_OPEN_T2OPEN:
403 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
405 if (io->t2open.in.open_func == 0) {
406 status = NT_STATUS_OBJECT_NAME_COLLISION;
410 status = map_openx_open(io->t2open.in.flags,
411 io->t2open.in.open_mode,
412 io->t2open.in.open_func,
415 if (!NT_STATUS_IS_OK(status)) {
419 io2->generic.in.file_attr = io->t2open.in.file_attrs;
420 io2->generic.in.fname = io->t2open.in.fname;
421 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
422 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
423 io2->generic.in.ea_list->eas = io->t2open.in.eas;
425 status = ntvfs->ops->openfile(ntvfs, req, io2);
429 io2->generic.in.file_attr = io->mknew.in.attrib;
430 io2->generic.in.fname = io->mknew.in.fname;
431 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
432 io2->generic.in.access_mask =
433 SEC_RIGHTS_FILE_READ |
434 SEC_RIGHTS_FILE_WRITE;
435 io2->generic.in.share_access =
436 NTCREATEX_SHARE_ACCESS_READ |
437 NTCREATEX_SHARE_ACCESS_WRITE;
438 status = ntvfs->ops->openfile(ntvfs, req, io2);
441 case RAW_OPEN_CREATE:
442 io2->generic.in.file_attr = io->mknew.in.attrib;
443 io2->generic.in.fname = io->mknew.in.fname;
444 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
445 io2->generic.in.access_mask =
446 SEC_RIGHTS_FILE_READ |
447 SEC_RIGHTS_FILE_WRITE;
448 io2->generic.in.share_access =
449 NTCREATEX_SHARE_ACCESS_READ |
450 NTCREATEX_SHARE_ACCESS_WRITE;
451 status = ntvfs->ops->openfile(ntvfs, req, io2);
455 io2->generic.in.file_attr = io->ctemp.in.attrib;
456 io2->generic.in.file_attr = 0;
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->openfile(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 smbsrv_request *req, union smb_fsinfo *fs,
484 struct ntvfs_module_context *ntvfs)
487 union smb_fsinfo *fs2;
489 fs2 = talloc(req, union smb_fsinfo);
491 return NT_STATUS_NO_MEMORY;
494 if (fs->generic.level == RAW_QFS_GENERIC) {
495 return NT_STATUS_INVALID_LEVEL;
498 /* only used by the simple backend, which doesn't do async */
499 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
501 /* ask the backend for the generic info */
502 fs2->generic.level = RAW_QFS_GENERIC;
504 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
505 if (!NT_STATUS_IS_OK(status)) {
509 /* and convert it to the required level */
510 switch (fs->generic.level) {
511 case RAW_QFS_GENERIC:
512 return NT_STATUS_INVALID_LEVEL;
514 case RAW_QFS_DSKATTR: {
515 /* map from generic to DSKATTR */
518 /* we need to scale the sizes to fit */
519 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
520 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
525 fs->dskattr.out.blocks_per_unit = bpunit;
526 fs->dskattr.out.block_size = 512;
527 fs->dskattr.out.units_total =
528 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
529 fs->dskattr.out.units_free =
530 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
532 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
533 if (bpunit > 64 && req->smb_conn->negotiate.protocol <= PROTOCOL_LANMAN2) {
534 fs->dskattr.out.blocks_per_unit = 64;
535 fs->dskattr.out.units_total = 0xFFFF;
536 fs->dskattr.out.units_free = 0xFFFF;
541 case RAW_QFS_ALLOCATION:
542 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
543 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
544 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
545 fs->allocation.out.sectors_per_unit = 1;
546 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
550 fs->volume.out.serial_number = fs2->generic.out.serial_number;
551 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
554 case RAW_QFS_VOLUME_INFO:
555 case RAW_QFS_VOLUME_INFORMATION:
556 fs->volume_info.out.create_time = fs2->generic.out.create_time;
557 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
558 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
561 case RAW_QFS_SIZE_INFO:
562 case RAW_QFS_SIZE_INFORMATION:
563 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
564 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
565 fs->size_info.out.sectors_per_unit = 1;
566 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
569 case RAW_QFS_DEVICE_INFO:
570 case RAW_QFS_DEVICE_INFORMATION:
571 fs->device_info.out.device_type = fs2->generic.out.device_type;
572 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
575 case RAW_QFS_ATTRIBUTE_INFO:
576 case RAW_QFS_ATTRIBUTE_INFORMATION:
577 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
578 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
579 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
582 case RAW_QFS_QUOTA_INFORMATION:
583 ZERO_STRUCT(fs->quota_information.out.unknown);
584 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
585 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
586 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
589 case RAW_QFS_FULL_SIZE_INFORMATION:
590 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
591 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
592 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
593 fs->full_size_information.out.sectors_per_unit = 1;
594 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
597 case RAW_QFS_OBJECTID_INFORMATION:
598 fs->objectid_information.out.guid = fs2->generic.out.guid;
599 ZERO_STRUCT(fs->objectid_information.out.unknown);
604 return NT_STATUS_INVALID_LEVEL;
609 NTVFS fileinfo generic to any mapper
611 _PUBLIC_ NTSTATUS ntvfs_map_fileinfo(struct smbsrv_request *req, union smb_fileinfo *info,
612 union smb_fileinfo *info2)
615 /* and convert it to the required level using results in info2 */
616 switch (info->generic.level) {
617 case RAW_FILEINFO_GENERIC:
618 return NT_STATUS_INVALID_LEVEL;
619 case RAW_FILEINFO_GETATTR:
620 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
621 info->getattr.out.size = info2->generic.out.size;
622 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
625 case RAW_FILEINFO_GETATTRE:
626 info->getattre.out.attrib = info2->generic.out.attrib;
627 info->getattre.out.size = info2->generic.out.size;
628 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
629 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
630 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
631 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
634 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
635 info->network_open_information.out.create_time = info2->generic.out.create_time;
636 info->network_open_information.out.access_time = info2->generic.out.access_time;
637 info->network_open_information.out.write_time = info2->generic.out.write_time;
638 info->network_open_information.out.change_time = info2->generic.out.change_time;
639 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
640 info->network_open_information.out.size = info2->generic.out.size;
641 info->network_open_information.out.attrib = info2->generic.out.attrib;
644 case RAW_FILEINFO_ALL_INFO:
645 case RAW_FILEINFO_ALL_INFORMATION:
646 info->all_info.out.create_time = info2->generic.out.create_time;
647 info->all_info.out.access_time = info2->generic.out.access_time;
648 info->all_info.out.write_time = info2->generic.out.write_time;
649 info->all_info.out.change_time = info2->generic.out.change_time;
650 info->all_info.out.attrib = info2->generic.out.attrib;
651 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
652 info->all_info.out.size = info2->generic.out.size;
653 info->all_info.out.nlink = info2->generic.out.nlink;
654 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
655 info->all_info.out.directory = info2->generic.out.directory;
656 info->all_info.out.ea_size = info2->generic.out.ea_size;
657 info->all_info.out.fname.s = info2->generic.out.fname.s;
658 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
661 case RAW_FILEINFO_BASIC_INFO:
662 case RAW_FILEINFO_BASIC_INFORMATION:
663 info->basic_info.out.create_time = info2->generic.out.create_time;
664 info->basic_info.out.access_time = info2->generic.out.access_time;
665 info->basic_info.out.write_time = info2->generic.out.write_time;
666 info->basic_info.out.change_time = info2->generic.out.change_time;
667 info->basic_info.out.attrib = info2->generic.out.attrib;
670 case RAW_FILEINFO_STANDARD:
671 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
672 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
673 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
674 info->standard.out.size = info2->generic.out.size;
675 info->standard.out.alloc_size = info2->generic.out.alloc_size;
676 info->standard.out.attrib = info2->generic.out.attrib;
679 case RAW_FILEINFO_EA_SIZE:
680 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
681 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
682 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
683 info->ea_size.out.size = info2->generic.out.size;
684 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
685 info->ea_size.out.attrib = info2->generic.out.attrib;
686 info->ea_size.out.ea_size = info2->generic.out.ea_size;
689 case RAW_FILEINFO_STANDARD_INFO:
690 case RAW_FILEINFO_STANDARD_INFORMATION:
691 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
692 info->standard_info.out.size = info2->generic.out.size;
693 info->standard_info.out.nlink = info2->generic.out.nlink;
694 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
695 info->standard_info.out.directory = info2->generic.out.directory;
698 case RAW_FILEINFO_INTERNAL_INFORMATION:
699 info->internal_information.out.file_id = info2->generic.out.file_id;
702 case RAW_FILEINFO_EA_INFO:
703 case RAW_FILEINFO_EA_INFORMATION:
704 info->ea_info.out.ea_size = info2->generic.out.ea_size;
707 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
708 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
709 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
712 case RAW_FILEINFO_STREAM_INFO:
713 case RAW_FILEINFO_STREAM_INFORMATION:
714 info->stream_info.out.num_streams = info2->generic.out.num_streams;
715 if (info->stream_info.out.num_streams > 0) {
716 info->stream_info.out.streams =
718 struct stream_struct,
719 info->stream_info.out.num_streams);
720 if (!info->stream_info.out.streams) {
721 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
722 info->stream_info.out.num_streams));
723 return NT_STATUS_NO_MEMORY;
725 for (i=0; i < info->stream_info.out.num_streams; i++) {
726 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
727 info->stream_info.out.streams[i].stream_name.s =
728 talloc_strdup(req, info2->generic.out.streams[i].stream_name.s);
729 if (!info->stream_info.out.streams[i].stream_name.s) {
730 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
731 return NT_STATUS_NO_MEMORY;
737 case RAW_FILEINFO_NAME_INFO:
738 case RAW_FILEINFO_NAME_INFORMATION:
739 info->name_info.out.fname.s = talloc_strdup(req, info2->generic.out.fname.s);
740 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
743 case RAW_FILEINFO_ALT_NAME_INFO:
744 case RAW_FILEINFO_ALT_NAME_INFORMATION:
745 info->alt_name_info.out.fname.s = talloc_strdup(req, info2->generic.out.alt_fname.s);
746 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
749 case RAW_FILEINFO_POSITION_INFORMATION:
750 info->position_information.out.position = info2->generic.out.position;
753 case RAW_FILEINFO_ALL_EAS:
754 info->all_eas.out.num_eas = info2->generic.out.num_eas;
755 if (info->all_eas.out.num_eas > 0) {
756 info->all_eas.out.eas = talloc_array(req,
758 info->all_eas.out.num_eas);
759 if (!info->all_eas.out.eas) {
760 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
761 info->all_eas.out.num_eas));
762 return NT_STATUS_NO_MEMORY;
764 for (i = 0; i < info->all_eas.out.num_eas; i++) {
765 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
766 info->all_eas.out.eas[i].name.s =
767 talloc_strdup(req, info2->generic.out.eas[i].name.s);
768 if (!info->all_eas.out.eas[i].name.s) {
769 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
770 return NT_STATUS_NO_MEMORY;
772 info->all_eas.out.eas[i].value.data =
774 info2->generic.out.eas[i].value.data,
775 info2->generic.out.eas[i].value.length);
776 if (!info->all_eas.out.eas[i].value.data) {
777 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
778 return NT_STATUS_NO_MEMORY;
784 case RAW_FILEINFO_IS_NAME_VALID:
787 case RAW_FILEINFO_COMPRESSION_INFO:
788 case RAW_FILEINFO_COMPRESSION_INFORMATION:
789 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
790 info->compression_info.out.format = info2->generic.out.format;
791 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
792 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
793 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
796 case RAW_FILEINFO_ACCESS_INFORMATION:
797 info->access_information.out.access_flags = info2->generic.out.access_flags;
800 case RAW_FILEINFO_MODE_INFORMATION:
801 info->mode_information.out.mode = info2->generic.out.mode;
804 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
805 info->alignment_information.out.alignment_requirement =
806 info2->generic.out.alignment_requirement;
809 case RAW_FILEINFO_UNIX_BASIC:
810 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
811 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
812 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
813 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
814 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
815 info->unix_basic_info.out.uid = info2->generic.out.uid;
816 info->unix_basic_info.out.gid = info2->generic.out.gid;
817 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
818 info->unix_basic_info.out.dev_major = info2->generic.out.device;
819 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
820 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
821 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
822 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
825 case RAW_FILEINFO_UNIX_LINK:
826 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
831 return NT_STATUS_INVALID_LEVEL;
835 NTVFS fileinfo generic to any mapper
837 _PUBLIC_ NTSTATUS ntvfs_map_qfileinfo(struct smbsrv_request *req, union smb_fileinfo *info,
838 struct ntvfs_module_context *ntvfs)
841 union smb_fileinfo *info2;
843 info2 = talloc(req, union smb_fileinfo);
845 return NT_STATUS_NO_MEMORY;
848 if (info->generic.level == RAW_FILEINFO_GENERIC) {
849 return NT_STATUS_INVALID_LEVEL;
852 /* ask the backend for the generic info */
853 info2->generic.level = RAW_FILEINFO_GENERIC;
854 info2->generic.in.fnum = info->generic.in.fnum;
856 /* only used by the simple backend, which doesn't do async */
857 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
859 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
860 if (!NT_STATUS_IS_OK(status)) {
863 return ntvfs_map_fileinfo(req, info, info2);
867 NTVFS pathinfo generic to any mapper
869 _PUBLIC_ NTSTATUS ntvfs_map_qpathinfo(struct smbsrv_request *req, union smb_fileinfo *info,
870 struct ntvfs_module_context *ntvfs)
873 union smb_fileinfo *info2;
875 info2 = talloc(req, union smb_fileinfo);
877 return NT_STATUS_NO_MEMORY;
880 if (info->generic.level == RAW_FILEINFO_GENERIC) {
881 return NT_STATUS_INVALID_LEVEL;
884 /* ask the backend for the generic info */
885 info2->generic.level = RAW_FILEINFO_GENERIC;
886 info2->generic.in.fname = info->generic.in.fname;
888 /* only used by the simple backend, which doesn't do async */
889 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
891 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
892 if (!NT_STATUS_IS_OK(status)) {
895 return ntvfs_map_fileinfo(req, info, info2);
900 NTVFS lock generic to any mapper
902 _PUBLIC_ NTSTATUS ntvfs_map_lock(struct smbsrv_request *req, union smb_lock *lck,
903 struct ntvfs_module_context *ntvfs)
905 union smb_lock *lck2;
906 struct smb_lock_entry *locks;
908 lck2 = talloc(req, union smb_lock);
910 return NT_STATUS_NO_MEMORY;
913 locks = talloc_array(lck2, struct smb_lock_entry, 1);
915 return NT_STATUS_NO_MEMORY;
918 switch (lck->generic.level) {
920 return NT_STATUS_INVALID_LEVEL;
923 lck2->generic.in.ulock_cnt = 0;
924 lck2->generic.in.lock_cnt = 1;
927 case RAW_LOCK_UNLOCK:
928 lck2->generic.in.ulock_cnt = 1;
929 lck2->generic.in.lock_cnt = 0;
933 lck2->generic.level = RAW_LOCK_GENERIC;
934 lck2->generic.in.fnum = lck->lock.in.fnum;
935 lck2->generic.in.mode = 0;
936 lck2->generic.in.timeout = 0;
937 lck2->generic.in.locks = locks;
938 locks->pid = req->smbpid;
939 locks->offset = lck->lock.in.offset;
940 locks->count = lck->lock.in.count;
943 * we don't need to call ntvfs_map_async_setup() here,
944 * as lock() doesn't have any output fields
947 return ntvfs->ops->lock(ntvfs, req, lck2);
952 NTVFS write generic to any mapper
954 static NTSTATUS ntvfs_map_write_finish(struct smbsrv_request *req,
955 struct ntvfs_module_context *ntvfs,
957 union smb_write *wr2,
965 if (NT_STATUS_IS_ERR(status)) {
969 switch (wr->generic.level) {
970 case RAW_WRITE_WRITE:
971 wr->write.out.nwritten = wr2->generic.out.nwritten;
974 case RAW_WRITE_WRITEUNLOCK:
975 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
977 lck = talloc(wr2, union smb_lock);
979 return NT_STATUS_NO_MEMORY;
982 lck->unlock.level = RAW_LOCK_UNLOCK;
983 lck->unlock.in.fnum = wr->writeunlock.in.fnum;
984 lck->unlock.in.count = wr->writeunlock.in.count;
985 lck->unlock.in.offset = wr->writeunlock.in.offset;
987 if (lck->unlock.in.count != 0) {
988 /* do the lock sync for now */
989 state = req->async_states->state;
990 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
991 status = ntvfs->ops->lock(ntvfs, req, lck);
992 req->async_states->state = state;
996 case RAW_WRITE_WRITECLOSE:
997 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
999 cl = talloc(wr2, union smb_close);
1001 return NT_STATUS_NO_MEMORY;
1004 cl->close.level = RAW_CLOSE_CLOSE;
1005 cl->close.in.fnum = wr->writeclose.in.fnum;
1006 cl->close.in.write_time = wr->writeclose.in.mtime;
1008 if (wr2->generic.in.count != 0) {
1009 /* do the close sync for now */
1010 state = req->async_states->state;
1011 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1012 status = ntvfs->ops->close(ntvfs, req, cl);
1013 req->async_states->state = state;
1017 case RAW_WRITE_SPLWRITE:
1020 return NT_STATUS_INVALID_LEVEL;
1028 NTVFS write generic to any mapper
1030 _PUBLIC_ NTSTATUS ntvfs_map_write(struct smbsrv_request *req, union smb_write *wr,
1031 struct ntvfs_module_context *ntvfs)
1033 union smb_write *wr2;
1036 wr2 = talloc(req, union smb_write);
1038 return NT_STATUS_NO_MEMORY;
1041 status = ntvfs_map_async_setup(req, ntvfs, wr, wr2,
1042 (second_stage_t)ntvfs_map_write_finish);
1043 if (!NT_STATUS_IS_OK(status)) {
1047 wr2->writex.level = RAW_WRITE_GENERIC;
1049 switch (wr->generic.level) {
1050 case RAW_WRITE_WRITEX:
1051 status = NT_STATUS_INVALID_LEVEL;
1054 case RAW_WRITE_WRITE:
1055 wr2->writex.in.fnum = wr->write.in.fnum;
1056 wr2->writex.in.offset = wr->write.in.offset;
1057 wr2->writex.in.wmode = 0;
1058 wr2->writex.in.remaining = wr->write.in.remaining;
1059 wr2->writex.in.count = wr->write.in.count;
1060 wr2->writex.in.data = wr->write.in.data;
1061 status = ntvfs->ops->write(ntvfs, req, wr2);
1064 case RAW_WRITE_WRITEUNLOCK:
1065 wr2->writex.in.fnum = wr->writeunlock.in.fnum;
1066 wr2->writex.in.offset = wr->writeunlock.in.offset;
1067 wr2->writex.in.wmode = 0;
1068 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1069 wr2->writex.in.count = wr->writeunlock.in.count;
1070 wr2->writex.in.data = wr->writeunlock.in.data;
1071 status = ntvfs->ops->write(ntvfs, req, wr2);
1074 case RAW_WRITE_WRITECLOSE:
1075 wr2->writex.in.fnum = wr->writeclose.in.fnum;
1076 wr2->writex.in.offset = wr->writeclose.in.offset;
1077 wr2->writex.in.wmode = 0;
1078 wr2->writex.in.remaining = 0;
1079 wr2->writex.in.count = wr->writeclose.in.count;
1080 wr2->writex.in.data = wr->writeclose.in.data;
1081 status = ntvfs->ops->write(ntvfs, req, wr2);
1084 case RAW_WRITE_SPLWRITE:
1085 wr2->writex.in.fnum = wr->splwrite.in.fnum;
1086 wr2->writex.in.offset = 0;
1087 wr2->writex.in.wmode = 0;
1088 wr2->writex.in.remaining = 0;
1089 wr2->writex.in.count = wr->splwrite.in.count;
1090 wr2->writex.in.data = wr->splwrite.in.data;
1091 status = ntvfs->ops->write(ntvfs, req, wr2);
1095 return ntvfs_map_async_finish(req, status);
1100 NTVFS read generic to any mapper - finish the out mapping
1102 static NTSTATUS ntvfs_map_read_finish(struct smbsrv_request *req,
1103 struct ntvfs_module_context *ntvfs,
1105 union smb_read *rd2,
1108 switch (rd->generic.level) {
1110 rd->read.out.nread = rd2->generic.out.nread;
1112 case RAW_READ_READBRAW:
1113 rd->readbraw.out.nread = rd2->generic.out.nread;
1115 case RAW_READ_LOCKREAD:
1116 rd->lockread.out.nread = rd2->generic.out.nread;
1119 return NT_STATUS_INVALID_LEVEL;
1126 NTVFS read* to readx mapper
1128 _PUBLIC_ NTSTATUS ntvfs_map_read(struct smbsrv_request *req, union smb_read *rd,
1129 struct ntvfs_module_context *ntvfs)
1131 union smb_read *rd2;
1132 union smb_lock *lck;
1136 rd2 = talloc(req, union smb_read);
1138 return NT_STATUS_NO_MEMORY;
1141 status = ntvfs_map_async_setup(req, ntvfs, rd, rd2,
1142 (second_stage_t)ntvfs_map_read_finish);
1143 if (!NT_STATUS_IS_OK(status)) {
1147 rd2->readx.level = RAW_READ_READX;
1149 switch (rd->generic.level) {
1150 case RAW_READ_READX:
1151 status = NT_STATUS_INVALID_LEVEL;
1155 rd2->readx.in.fnum = rd->read.in.fnum;
1156 rd2->readx.in.offset = rd->read.in.offset;
1157 rd2->readx.in.mincnt = rd->read.in.count;
1158 rd2->readx.in.maxcnt = rd->read.in.count;
1159 rd2->readx.in.remaining = rd->read.in.remaining;
1160 rd2->readx.out.data = rd->read.out.data;
1161 status = ntvfs->ops->read(ntvfs, req, rd2);
1164 case RAW_READ_READBRAW:
1165 rd2->readx.in.fnum = rd->readbraw.in.fnum;
1166 rd2->readx.in.offset = rd->readbraw.in.offset;
1167 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1168 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1169 rd2->readx.in.remaining = 0;
1170 rd2->readx.out.data = rd->readbraw.out.data;
1171 status = ntvfs->ops->read(ntvfs, req, rd2);
1174 case RAW_READ_LOCKREAD:
1175 /* do the initial lock sync for now */
1176 state = req->async_states->state;
1177 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1179 lck = talloc(rd2, union smb_lock);
1181 status = NT_STATUS_NO_MEMORY;
1184 lck->lock.level = RAW_LOCK_LOCK;
1185 lck->lock.in.fnum = rd->lockread.in.fnum;
1186 lck->lock.in.count = rd->lockread.in.count;
1187 lck->lock.in.offset = rd->lockread.in.offset;
1188 status = ntvfs->ops->lock(ntvfs, req, lck);
1189 req->async_states->state = state;
1191 rd2->readx.in.fnum = rd->lockread.in.fnum;
1192 rd2->readx.in.offset = rd->lockread.in.offset;
1193 rd2->readx.in.mincnt = rd->lockread.in.count;
1194 rd2->readx.in.maxcnt = rd->lockread.in.count;
1195 rd2->readx.in.remaining = rd->lockread.in.remaining;
1196 rd2->readx.out.data = rd->lockread.out.data;
1198 if (NT_STATUS_IS_OK(status)) {
1199 status = ntvfs->ops->read(ntvfs, req, rd2);
1205 return ntvfs_map_async_finish(req, status);
1210 NTVFS close generic to any mapper
1212 _PUBLIC_ NTSTATUS ntvfs_map_close(struct smbsrv_request *req, union smb_close *cl,
1213 struct ntvfs_module_context *ntvfs)
1215 union smb_close *cl2;
1217 cl2 = talloc(req, union smb_close);
1219 return NT_STATUS_NO_MEMORY;
1222 switch (cl->generic.level) {
1223 case RAW_CLOSE_CLOSE:
1224 return NT_STATUS_INVALID_LEVEL;
1226 case RAW_CLOSE_SPLCLOSE:
1227 cl2->close.level = RAW_CLOSE_CLOSE;
1228 cl2->close.in.fnum = cl->splclose.in.fnum;
1233 * we don't need to call ntvfs_map_async_setup() here,
1234 * as close() doesn't have any output fields
1237 return ntvfs->ops->close(ntvfs, req, cl2);