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 ntvfs_module_context *,
42 struct ntvfs_request *,
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 ntvfs_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(m->ntvfs, req, 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 ntvfs_module_context *ntvfs,
78 struct ntvfs_request *req,
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(ntvfs, req, m, ntvfs_map_async_send);
95 called when first stage processing is complete.
97 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
99 struct ntvfs_map_async *m;
101 /* if the backend has decided to reply in an async fashion then
102 we don't need to do any work here */
103 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
107 /* the backend is replying immediately. call the 2nd stage function after popping our local
109 m = req->async_states->private_data;
111 ntvfs_async_state_pop(req);
113 return m->fn(m->ntvfs, req, m->io, m->io2, status);
117 see if a filename ends in EXE COM DLL or SYM. This is needed for the
118 DENY_DOS mapping for OpenX
120 BOOL is_exe_filename(const char *fname)
123 p = strrchr(fname, '.');
128 if (strcasecmp(p, "EXE") == 0 ||
129 strcasecmp(p, "COM") == 0 ||
130 strcasecmp(p, "DLL") == 0 ||
131 strcasecmp(p, "SYM") == 0) {
139 NTVFS openx to ntcreatex mapper
141 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
142 struct ntvfs_request *req,
147 time_t write_time = 0;
148 uint32_t set_size = 0;
149 union smb_setfileinfo *sf;
152 if (!NT_STATUS_IS_OK(status)) {
156 switch (io->generic.level) {
158 io->openold.file.fnum = io2->generic.file.fnum;
159 io->openold.out.attrib = io2->generic.out.attrib;
160 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
161 io->openold.out.size = io2->generic.out.size;
162 io->openold.out.rmode = io->openold.in.open_mode;
166 io->openx.file.fnum = io2->generic.file.fnum;
167 io->openx.out.attrib = io2->generic.out.attrib;
168 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
169 io->openx.out.size = io2->generic.out.size;
170 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
171 io->openx.out.ftype = 0;
172 io->openx.out.devstate = 0;
173 io->openx.out.action = io2->generic.out.create_action;
174 io->openx.out.unique_fid = 0;
175 io->openx.out.access_mask = SEC_STD_ALL;
176 io->openx.out.unknown = 0;
178 /* we need to extend the file to the requested size if
179 it was newly created */
180 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
181 set_size = io->openx.in.size;
185 case RAW_OPEN_T2OPEN:
186 io->t2open.file.fnum = io2->generic.file.fnum;
187 io->t2open.out.attrib = io2->generic.out.attrib;
188 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
189 io->t2open.out.size = io2->generic.out.size;
190 io->t2open.out.access = io->t2open.in.open_mode;
191 io->t2open.out.ftype = 0;
192 io->t2open.out.devstate = 0;
193 io->t2open.out.action = io2->generic.out.create_action;
194 io->t2open.out.file_id = 0;
198 case RAW_OPEN_CREATE:
199 io->mknew.file.fnum = io2->generic.file.fnum;
200 write_time = io->mknew.in.write_time;
204 io->ctemp.file.fnum = io2->generic.file.fnum;
205 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
206 strlen(io->ctemp.in.directory) + 1);
207 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
211 return NT_STATUS_INVALID_LEVEL;
214 /* doing a secondary request async is more trouble than its
216 state = req->async_states->state;
217 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
219 if (write_time != 0) {
220 sf = talloc(req, union smb_setfileinfo);
221 NT_STATUS_HAVE_NO_MEMORY(sf);
222 sf->generic.level = RAW_SFILEINFO_STANDARD;
223 sf->generic.file.fnum = io2->generic.file.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 NT_STATUS_HAVE_NO_MEMORY(sf);
233 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
234 sf->generic.file.fnum = io2->generic.file.fnum;
235 sf->end_of_file_info.in.size = set_size;
236 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
237 if (NT_STATUS_IS_OK(status)) {
238 io->openx.out.size = io->openx.in.size;
242 req->async_states->state = state;
248 the core of the mapping between openx style parameters and ntcreatex
251 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
252 uint16_t open_func, const char *fname,
255 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
256 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
258 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
259 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
262 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
263 case OPENX_MODE_ACCESS_READ:
264 case OPENX_MODE_ACCESS_EXEC:
265 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
267 case OPENX_MODE_ACCESS_WRITE:
268 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
270 case OPENX_MODE_ACCESS_RDWR:
271 case OPENX_MODE_ACCESS_FCB:
272 io2->generic.in.access_mask =
273 SEC_RIGHTS_FILE_READ |
274 SEC_RIGHTS_FILE_WRITE;
277 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
280 switch (open_mode & OPENX_MODE_DENY_MASK) {
281 case OPENX_MODE_DENY_READ:
282 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
284 case OPENX_MODE_DENY_WRITE:
285 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
287 case OPENX_MODE_DENY_ALL:
288 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
290 case OPENX_MODE_DENY_NONE:
291 io2->generic.in.share_access =
292 NTCREATEX_SHARE_ACCESS_READ |
293 NTCREATEX_SHARE_ACCESS_WRITE;
295 case OPENX_MODE_DENY_DOS:
296 /* DENY_DOS is quite strange - it depends on the filename! */
297 io2->generic.in.create_options |=
298 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
299 if (is_exe_filename(fname)) {
300 io2->generic.in.share_access =
301 NTCREATEX_SHARE_ACCESS_READ |
302 NTCREATEX_SHARE_ACCESS_WRITE;
304 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
305 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
307 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
311 case OPENX_MODE_DENY_FCB:
312 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
313 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
316 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
320 case (OPENX_OPEN_FUNC_OPEN):
321 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
323 case (OPENX_OPEN_FUNC_TRUNC):
324 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
326 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
327 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
329 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
330 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
332 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
333 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
336 /* this one is very strange */
337 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
338 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
341 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
348 NTVFS open generic to any mapper
350 _PUBLIC_ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
351 struct ntvfs_request *req,
357 io2 = talloc_zero(req, union smb_open);
359 return NT_STATUS_NO_MEMORY;
362 status = ntvfs_map_async_setup(ntvfs, req,
364 (second_stage_t)ntvfs_map_open_finish);
365 if (!NT_STATUS_IS_OK(status)) {
369 io2->generic.level = RAW_OPEN_GENERIC;
371 switch (io->generic.level) {
373 status = map_openx_open(io->openx.in.flags,
374 io->openx.in.open_mode,
375 io->openx.in.open_func,
378 if (!NT_STATUS_IS_OK(status)) {
382 io2->generic.in.file_attr = io->openx.in.file_attrs;
383 io2->generic.in.fname = io->openx.in.fname;
385 status = ntvfs->ops->open(ntvfs, req, io2);
390 status = map_openx_open(0,
391 io->openold.in.open_mode,
392 OPENX_OPEN_FUNC_OPEN,
393 io->openold.in.fname,
395 if (!NT_STATUS_IS_OK(status)) {
399 io2->generic.in.file_attr = io->openold.in.search_attrs;
400 io2->generic.in.fname = io->openold.in.fname;
402 status = ntvfs->ops->open(ntvfs, req, io2);
405 case RAW_OPEN_T2OPEN:
406 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
408 if (io->t2open.in.open_func == 0) {
409 status = NT_STATUS_OBJECT_NAME_COLLISION;
413 status = map_openx_open(io->t2open.in.flags,
414 io->t2open.in.open_mode,
415 io->t2open.in.open_func,
418 if (!NT_STATUS_IS_OK(status)) {
422 io2->generic.in.file_attr = io->t2open.in.file_attrs;
423 io2->generic.in.fname = io->t2open.in.fname;
424 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
425 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
426 io2->generic.in.ea_list->eas = io->t2open.in.eas;
428 status = ntvfs->ops->open(ntvfs, req, io2);
432 io2->generic.in.file_attr = io->mknew.in.attrib;
433 io2->generic.in.fname = io->mknew.in.fname;
434 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
435 io2->generic.in.access_mask =
436 SEC_RIGHTS_FILE_READ |
437 SEC_RIGHTS_FILE_WRITE;
438 io2->generic.in.share_access =
439 NTCREATEX_SHARE_ACCESS_READ |
440 NTCREATEX_SHARE_ACCESS_WRITE;
441 status = ntvfs->ops->open(ntvfs, req, io2);
444 case RAW_OPEN_CREATE:
445 io2->generic.in.file_attr = io->mknew.in.attrib;
446 io2->generic.in.fname = io->mknew.in.fname;
447 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
448 io2->generic.in.access_mask =
449 SEC_RIGHTS_FILE_READ |
450 SEC_RIGHTS_FILE_WRITE;
451 io2->generic.in.share_access =
452 NTCREATEX_SHARE_ACCESS_READ |
453 NTCREATEX_SHARE_ACCESS_WRITE;
454 status = ntvfs->ops->open(ntvfs, req, io2);
458 io2->generic.in.file_attr = io->ctemp.in.attrib;
459 io2->generic.in.file_attr = 0;
460 io2->generic.in.fname =
461 talloc_asprintf(io2, "%s\\SRV%s",
462 io->ctemp.in.directory,
463 generate_random_str_list(io2, 5, "0123456789"));
464 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
465 io2->generic.in.access_mask =
466 SEC_RIGHTS_FILE_READ |
467 SEC_RIGHTS_FILE_WRITE;
468 io2->generic.in.share_access =
469 NTCREATEX_SHARE_ACCESS_READ |
470 NTCREATEX_SHARE_ACCESS_WRITE;
471 status = ntvfs->ops->open(ntvfs, req, io2);
475 status = NT_STATUS_INVALID_LEVEL;
479 return ntvfs_map_async_finish(req, status);
484 NTVFS fsinfo generic to any mapper
486 _PUBLIC_ NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
487 struct ntvfs_request *req,
488 union smb_fsinfo *fs)
491 union smb_fsinfo *fs2;
493 fs2 = talloc(req, union smb_fsinfo);
495 return NT_STATUS_NO_MEMORY;
498 if (fs->generic.level == RAW_QFS_GENERIC) {
499 return NT_STATUS_INVALID_LEVEL;
502 /* only used by the simple backend, which doesn't do async */
503 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
505 /* ask the backend for the generic info */
506 fs2->generic.level = RAW_QFS_GENERIC;
508 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
509 if (!NT_STATUS_IS_OK(status)) {
513 /* and convert it to the required level */
514 switch (fs->generic.level) {
515 case RAW_QFS_GENERIC:
516 return NT_STATUS_INVALID_LEVEL;
518 case RAW_QFS_DSKATTR: {
519 /* map from generic to DSKATTR */
522 /* we need to scale the sizes to fit */
523 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
524 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
529 fs->dskattr.out.blocks_per_unit = bpunit;
530 fs->dskattr.out.block_size = 512;
531 fs->dskattr.out.units_total =
532 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
533 fs->dskattr.out.units_free =
534 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
536 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
537 if (bpunit > 64 && req->smb_conn->negotiate.protocol <= PROTOCOL_LANMAN2) {
538 fs->dskattr.out.blocks_per_unit = 64;
539 fs->dskattr.out.units_total = 0xFFFF;
540 fs->dskattr.out.units_free = 0xFFFF;
545 case RAW_QFS_ALLOCATION:
546 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
547 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
548 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
549 fs->allocation.out.sectors_per_unit = 1;
550 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
554 fs->volume.out.serial_number = fs2->generic.out.serial_number;
555 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
558 case RAW_QFS_VOLUME_INFO:
559 case RAW_QFS_VOLUME_INFORMATION:
560 fs->volume_info.out.create_time = fs2->generic.out.create_time;
561 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
562 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
565 case RAW_QFS_SIZE_INFO:
566 case RAW_QFS_SIZE_INFORMATION:
567 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
568 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
569 fs->size_info.out.sectors_per_unit = 1;
570 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
573 case RAW_QFS_DEVICE_INFO:
574 case RAW_QFS_DEVICE_INFORMATION:
575 fs->device_info.out.device_type = fs2->generic.out.device_type;
576 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
579 case RAW_QFS_ATTRIBUTE_INFO:
580 case RAW_QFS_ATTRIBUTE_INFORMATION:
581 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
582 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
583 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
586 case RAW_QFS_QUOTA_INFORMATION:
587 ZERO_STRUCT(fs->quota_information.out.unknown);
588 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
589 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
590 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
593 case RAW_QFS_FULL_SIZE_INFORMATION:
594 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
595 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
596 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
597 fs->full_size_information.out.sectors_per_unit = 1;
598 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
601 case RAW_QFS_OBJECTID_INFORMATION:
602 fs->objectid_information.out.guid = fs2->generic.out.guid;
603 ZERO_STRUCT(fs->objectid_information.out.unknown);
608 return NT_STATUS_INVALID_LEVEL;
613 NTVFS fileinfo generic to any mapper
615 _PUBLIC_ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
616 union smb_fileinfo *info,
617 union smb_fileinfo *info2)
620 /* and convert it to the required level using results in info2 */
621 switch (info->generic.level) {
622 case RAW_FILEINFO_GENERIC:
623 return NT_STATUS_INVALID_LEVEL;
624 case RAW_FILEINFO_GETATTR:
625 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
626 info->getattr.out.size = info2->generic.out.size;
627 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
630 case RAW_FILEINFO_GETATTRE:
631 info->getattre.out.attrib = info2->generic.out.attrib;
632 info->getattre.out.size = info2->generic.out.size;
633 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
634 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
635 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
636 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
639 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
640 info->network_open_information.out.create_time = info2->generic.out.create_time;
641 info->network_open_information.out.access_time = info2->generic.out.access_time;
642 info->network_open_information.out.write_time = info2->generic.out.write_time;
643 info->network_open_information.out.change_time = info2->generic.out.change_time;
644 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
645 info->network_open_information.out.size = info2->generic.out.size;
646 info->network_open_information.out.attrib = info2->generic.out.attrib;
649 case RAW_FILEINFO_ALL_INFO:
650 case RAW_FILEINFO_ALL_INFORMATION:
651 info->all_info.out.create_time = info2->generic.out.create_time;
652 info->all_info.out.access_time = info2->generic.out.access_time;
653 info->all_info.out.write_time = info2->generic.out.write_time;
654 info->all_info.out.change_time = info2->generic.out.change_time;
655 info->all_info.out.attrib = info2->generic.out.attrib;
656 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
657 info->all_info.out.size = info2->generic.out.size;
658 info->all_info.out.nlink = info2->generic.out.nlink;
659 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
660 info->all_info.out.directory = info2->generic.out.directory;
661 info->all_info.out.ea_size = info2->generic.out.ea_size;
662 info->all_info.out.fname.s = info2->generic.out.fname.s;
663 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
666 case RAW_FILEINFO_BASIC_INFO:
667 case RAW_FILEINFO_BASIC_INFORMATION:
668 info->basic_info.out.create_time = info2->generic.out.create_time;
669 info->basic_info.out.access_time = info2->generic.out.access_time;
670 info->basic_info.out.write_time = info2->generic.out.write_time;
671 info->basic_info.out.change_time = info2->generic.out.change_time;
672 info->basic_info.out.attrib = info2->generic.out.attrib;
675 case RAW_FILEINFO_STANDARD:
676 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
677 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
678 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
679 info->standard.out.size = info2->generic.out.size;
680 info->standard.out.alloc_size = info2->generic.out.alloc_size;
681 info->standard.out.attrib = info2->generic.out.attrib;
684 case RAW_FILEINFO_EA_SIZE:
685 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
686 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
687 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
688 info->ea_size.out.size = info2->generic.out.size;
689 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
690 info->ea_size.out.attrib = info2->generic.out.attrib;
691 info->ea_size.out.ea_size = info2->generic.out.ea_size;
694 case RAW_FILEINFO_STANDARD_INFO:
695 case RAW_FILEINFO_STANDARD_INFORMATION:
696 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
697 info->standard_info.out.size = info2->generic.out.size;
698 info->standard_info.out.nlink = info2->generic.out.nlink;
699 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
700 info->standard_info.out.directory = info2->generic.out.directory;
703 case RAW_FILEINFO_INTERNAL_INFORMATION:
704 info->internal_information.out.file_id = info2->generic.out.file_id;
707 case RAW_FILEINFO_EA_INFO:
708 case RAW_FILEINFO_EA_INFORMATION:
709 info->ea_info.out.ea_size = info2->generic.out.ea_size;
712 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
713 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
714 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
717 case RAW_FILEINFO_STREAM_INFO:
718 case RAW_FILEINFO_STREAM_INFORMATION:
719 info->stream_info.out.num_streams = info2->generic.out.num_streams;
720 if (info->stream_info.out.num_streams > 0) {
721 info->stream_info.out.streams =
722 talloc_array(mem_ctx,
723 struct stream_struct,
724 info->stream_info.out.num_streams);
725 if (!info->stream_info.out.streams) {
726 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
727 info->stream_info.out.num_streams));
728 return NT_STATUS_NO_MEMORY;
730 for (i=0; i < info->stream_info.out.num_streams; i++) {
731 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
732 info->stream_info.out.streams[i].stream_name.s =
733 talloc_strdup(info->stream_info.out.streams,
734 info2->generic.out.streams[i].stream_name.s);
735 if (!info->stream_info.out.streams[i].stream_name.s) {
736 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
737 return NT_STATUS_NO_MEMORY;
743 case RAW_FILEINFO_NAME_INFO:
744 case RAW_FILEINFO_NAME_INFORMATION:
745 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
746 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
747 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
750 case RAW_FILEINFO_ALT_NAME_INFO:
751 case RAW_FILEINFO_ALT_NAME_INFORMATION:
752 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
753 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
754 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
757 case RAW_FILEINFO_POSITION_INFORMATION:
758 info->position_information.out.position = info2->generic.out.position;
761 case RAW_FILEINFO_ALL_EAS:
762 info->all_eas.out.num_eas = info2->generic.out.num_eas;
763 if (info->all_eas.out.num_eas > 0) {
764 info->all_eas.out.eas = talloc_array(mem_ctx,
766 info->all_eas.out.num_eas);
767 if (!info->all_eas.out.eas) {
768 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
769 info->all_eas.out.num_eas));
770 return NT_STATUS_NO_MEMORY;
772 for (i = 0; i < info->all_eas.out.num_eas; i++) {
773 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
774 info->all_eas.out.eas[i].name.s =
775 talloc_strdup(info->all_eas.out.eas,
776 info2->generic.out.eas[i].name.s);
777 if (!info->all_eas.out.eas[i].name.s) {
778 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
779 return NT_STATUS_NO_MEMORY;
781 info->all_eas.out.eas[i].value.data =
782 talloc_memdup(info->all_eas.out.eas,
783 info2->generic.out.eas[i].value.data,
784 info2->generic.out.eas[i].value.length);
785 if (!info->all_eas.out.eas[i].value.data) {
786 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
787 return NT_STATUS_NO_MEMORY;
793 case RAW_FILEINFO_IS_NAME_VALID:
796 case RAW_FILEINFO_COMPRESSION_INFO:
797 case RAW_FILEINFO_COMPRESSION_INFORMATION:
798 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
799 info->compression_info.out.format = info2->generic.out.format;
800 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
801 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
802 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
805 case RAW_FILEINFO_ACCESS_INFORMATION:
806 info->access_information.out.access_flags = info2->generic.out.access_flags;
809 case RAW_FILEINFO_MODE_INFORMATION:
810 info->mode_information.out.mode = info2->generic.out.mode;
813 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
814 info->alignment_information.out.alignment_requirement =
815 info2->generic.out.alignment_requirement;
818 case RAW_FILEINFO_UNIX_BASIC:
819 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
820 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
821 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
822 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
823 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
824 info->unix_basic_info.out.uid = info2->generic.out.uid;
825 info->unix_basic_info.out.gid = info2->generic.out.gid;
826 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
827 info->unix_basic_info.out.dev_major = info2->generic.out.device;
828 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
829 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
830 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
831 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
834 case RAW_FILEINFO_UNIX_LINK:
835 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
840 return NT_STATUS_INVALID_LEVEL;
844 NTVFS fileinfo generic to any mapper
846 _PUBLIC_ NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
847 struct ntvfs_request *req,
848 union smb_fileinfo *info)
851 union smb_fileinfo *info2;
853 info2 = talloc(req, union smb_fileinfo);
855 return NT_STATUS_NO_MEMORY;
858 if (info->generic.level == RAW_FILEINFO_GENERIC) {
859 return NT_STATUS_INVALID_LEVEL;
862 /* ask the backend for the generic info */
863 info2->generic.level = RAW_FILEINFO_GENERIC;
864 info2->generic.file.fnum = info->generic.file.fnum;
866 /* only used by the simple backend, which doesn't do async */
867 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
869 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
870 if (!NT_STATUS_IS_OK(status)) {
873 return ntvfs_map_fileinfo(req, info, info2);
877 NTVFS pathinfo generic to any mapper
879 _PUBLIC_ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
880 struct ntvfs_request *req,
881 union smb_fileinfo *info)
884 union smb_fileinfo *info2;
886 info2 = talloc(req, union smb_fileinfo);
888 return NT_STATUS_NO_MEMORY;
891 if (info->generic.level == RAW_FILEINFO_GENERIC) {
892 return NT_STATUS_INVALID_LEVEL;
895 /* ask the backend for the generic info */
896 info2->generic.level = RAW_FILEINFO_GENERIC;
897 info2->generic.file.path = info->generic.file.path;
899 /* only used by the simple backend, which doesn't do async */
900 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
902 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
903 if (!NT_STATUS_IS_OK(status)) {
906 return ntvfs_map_fileinfo(req, info, info2);
911 NTVFS lock generic to any mapper
913 _PUBLIC_ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
914 struct ntvfs_request *req,
917 union smb_lock *lck2;
918 struct smb_lock_entry *locks;
920 lck2 = talloc(req, union smb_lock);
922 return NT_STATUS_NO_MEMORY;
925 locks = talloc_array(lck2, struct smb_lock_entry, 1);
927 return NT_STATUS_NO_MEMORY;
930 switch (lck->generic.level) {
932 return NT_STATUS_INVALID_LEVEL;
935 lck2->generic.in.ulock_cnt = 0;
936 lck2->generic.in.lock_cnt = 1;
939 case RAW_LOCK_UNLOCK:
940 lck2->generic.in.ulock_cnt = 1;
941 lck2->generic.in.lock_cnt = 0;
945 lck2->generic.level = RAW_LOCK_GENERIC;
946 lck2->generic.file.fnum = lck->lock.file.fnum;
947 lck2->generic.in.mode = 0;
948 lck2->generic.in.timeout = 0;
949 lck2->generic.in.locks = locks;
950 locks->pid = req->smbpid;
951 locks->offset = lck->lock.in.offset;
952 locks->count = lck->lock.in.count;
955 * we don't need to call ntvfs_map_async_setup() here,
956 * as lock() doesn't have any output fields
959 return ntvfs->ops->lock(ntvfs, req, lck2);
964 NTVFS write generic to any mapper
966 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
967 struct ntvfs_request *req,
969 union smb_write *wr2,
976 if (NT_STATUS_IS_ERR(status)) {
980 switch (wr->generic.level) {
981 case RAW_WRITE_WRITE:
982 wr->write.out.nwritten = wr2->generic.out.nwritten;
985 case RAW_WRITE_WRITEUNLOCK:
986 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
988 lck = talloc(wr2, union smb_lock);
990 return NT_STATUS_NO_MEMORY;
993 lck->unlock.level = RAW_LOCK_UNLOCK;
994 lck->unlock.file.fnum = wr->writeunlock.file.fnum;
995 lck->unlock.in.count = wr->writeunlock.in.count;
996 lck->unlock.in.offset = wr->writeunlock.in.offset;
998 if (lck->unlock.in.count != 0) {
999 /* do the lock sync for now */
1000 state = req->async_states->state;
1001 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1002 status = ntvfs->ops->lock(ntvfs, req, lck);
1003 req->async_states->state = state;
1007 case RAW_WRITE_WRITECLOSE:
1008 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1010 cl = talloc(wr2, union smb_close);
1012 return NT_STATUS_NO_MEMORY;
1015 cl->close.level = RAW_CLOSE_CLOSE;
1016 cl->close.file.fnum = wr->writeclose.file.fnum;
1017 cl->close.in.write_time = wr->writeclose.in.mtime;
1019 if (wr2->generic.in.count != 0) {
1020 /* do the close sync for now */
1021 state = req->async_states->state;
1022 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1023 status = ntvfs->ops->close(ntvfs, req, cl);
1024 req->async_states->state = state;
1028 case RAW_WRITE_SPLWRITE:
1031 return NT_STATUS_INVALID_LEVEL;
1039 NTVFS write generic to any mapper
1041 _PUBLIC_ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1042 struct ntvfs_request *req,
1043 union smb_write *wr)
1045 union smb_write *wr2;
1048 wr2 = talloc(req, union smb_write);
1050 return NT_STATUS_NO_MEMORY;
1053 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1054 (second_stage_t)ntvfs_map_write_finish);
1055 if (!NT_STATUS_IS_OK(status)) {
1059 wr2->writex.level = RAW_WRITE_GENERIC;
1061 switch (wr->generic.level) {
1062 case RAW_WRITE_WRITEX:
1063 status = NT_STATUS_INVALID_LEVEL;
1066 case RAW_WRITE_WRITE:
1067 wr2->writex.file.fnum = wr->write.file.fnum;
1068 wr2->writex.in.offset = wr->write.in.offset;
1069 wr2->writex.in.wmode = 0;
1070 wr2->writex.in.remaining = wr->write.in.remaining;
1071 wr2->writex.in.count = wr->write.in.count;
1072 wr2->writex.in.data = wr->write.in.data;
1073 status = ntvfs->ops->write(ntvfs, req, wr2);
1076 case RAW_WRITE_WRITEUNLOCK:
1077 wr2->writex.file.fnum = wr->writeunlock.file.fnum;
1078 wr2->writex.in.offset = wr->writeunlock.in.offset;
1079 wr2->writex.in.wmode = 0;
1080 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1081 wr2->writex.in.count = wr->writeunlock.in.count;
1082 wr2->writex.in.data = wr->writeunlock.in.data;
1083 status = ntvfs->ops->write(ntvfs, req, wr2);
1086 case RAW_WRITE_WRITECLOSE:
1087 wr2->writex.file.fnum = wr->writeclose.file.fnum;
1088 wr2->writex.in.offset = wr->writeclose.in.offset;
1089 wr2->writex.in.wmode = 0;
1090 wr2->writex.in.remaining = 0;
1091 wr2->writex.in.count = wr->writeclose.in.count;
1092 wr2->writex.in.data = wr->writeclose.in.data;
1093 status = ntvfs->ops->write(ntvfs, req, wr2);
1096 case RAW_WRITE_SPLWRITE:
1097 wr2->writex.file.fnum = wr->splwrite.file.fnum;
1098 wr2->writex.in.offset = 0;
1099 wr2->writex.in.wmode = 0;
1100 wr2->writex.in.remaining = 0;
1101 wr2->writex.in.count = wr->splwrite.in.count;
1102 wr2->writex.in.data = wr->splwrite.in.data;
1103 status = ntvfs->ops->write(ntvfs, req, wr2);
1107 return ntvfs_map_async_finish(req, status);
1112 NTVFS read generic to any mapper - finish the out mapping
1114 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1115 struct ntvfs_request *req,
1117 union smb_read *rd2,
1120 switch (rd->generic.level) {
1122 rd->read.out.nread = rd2->generic.out.nread;
1124 case RAW_READ_READBRAW:
1125 rd->readbraw.out.nread = rd2->generic.out.nread;
1127 case RAW_READ_LOCKREAD:
1128 rd->lockread.out.nread = rd2->generic.out.nread;
1131 return NT_STATUS_INVALID_LEVEL;
1138 NTVFS read* to readx mapper
1140 _PUBLIC_ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1141 struct ntvfs_request *req,
1144 union smb_read *rd2;
1145 union smb_lock *lck;
1149 rd2 = talloc(req, union smb_read);
1151 return NT_STATUS_NO_MEMORY;
1154 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1155 (second_stage_t)ntvfs_map_read_finish);
1156 if (!NT_STATUS_IS_OK(status)) {
1160 rd2->readx.level = RAW_READ_READX;
1162 switch (rd->generic.level) {
1163 case RAW_READ_READX:
1164 status = NT_STATUS_INVALID_LEVEL;
1168 rd2->readx.file.fnum = rd->read.file.fnum;
1169 rd2->readx.in.offset = rd->read.in.offset;
1170 rd2->readx.in.mincnt = rd->read.in.count;
1171 rd2->readx.in.maxcnt = rd->read.in.count;
1172 rd2->readx.in.remaining = rd->read.in.remaining;
1173 rd2->readx.out.data = rd->read.out.data;
1174 status = ntvfs->ops->read(ntvfs, req, rd2);
1177 case RAW_READ_READBRAW:
1178 rd2->readx.file.fnum = rd->readbraw.file.fnum;
1179 rd2->readx.in.offset = rd->readbraw.in.offset;
1180 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1181 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1182 rd2->readx.in.remaining = 0;
1183 rd2->readx.out.data = rd->readbraw.out.data;
1184 status = ntvfs->ops->read(ntvfs, req, rd2);
1187 case RAW_READ_LOCKREAD:
1188 /* do the initial lock sync for now */
1189 state = req->async_states->state;
1190 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1192 lck = talloc(rd2, union smb_lock);
1194 status = NT_STATUS_NO_MEMORY;
1197 lck->lock.level = RAW_LOCK_LOCK;
1198 lck->lock.file.fnum = rd->lockread.file.fnum;
1199 lck->lock.in.count = rd->lockread.in.count;
1200 lck->lock.in.offset = rd->lockread.in.offset;
1201 status = ntvfs->ops->lock(ntvfs, req, lck);
1202 req->async_states->state = state;
1204 rd2->readx.file.fnum = rd->lockread.file.fnum;
1205 rd2->readx.in.offset = rd->lockread.in.offset;
1206 rd2->readx.in.mincnt = rd->lockread.in.count;
1207 rd2->readx.in.maxcnt = rd->lockread.in.count;
1208 rd2->readx.in.remaining = rd->lockread.in.remaining;
1209 rd2->readx.out.data = rd->lockread.out.data;
1211 if (NT_STATUS_IS_OK(status)) {
1212 status = ntvfs->ops->read(ntvfs, req, rd2);
1218 return ntvfs_map_async_finish(req, status);
1223 NTVFS close generic to any mapper
1225 _PUBLIC_ NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1226 struct ntvfs_request *req,
1227 union smb_close *cl)
1229 union smb_close *cl2;
1231 cl2 = talloc(req, union smb_close);
1233 return NT_STATUS_NO_MEMORY;
1236 switch (cl->generic.level) {
1237 case RAW_CLOSE_CLOSE:
1238 return NT_STATUS_INVALID_LEVEL;
1240 case RAW_CLOSE_SPLCLOSE:
1241 cl2->close.level = RAW_CLOSE_CLOSE;
1242 cl2->close.file.fnum = cl->splclose.file.fnum;
1247 * we don't need to call ntvfs_map_async_setup() here,
1248 * as close() doesn't have any output fields
1251 return ntvfs->ops->close(ntvfs, req, cl2);