r14736: - the ntvfs subsystem should not know about smb_server.h
[Samba/aatanasov.git] / source / ntvfs / ntvfs_generic.c
blobfdc186c710295bc9b56bed28f9ee45fdfa6fe57a
1 /*
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.
34 #include "includes.h"
35 #include "librpc/gen_ndr/ndr_security.h"
36 #include "ntvfs/ntvfs.h"
38 /* a second stage function converts from the out parameters of the generic
39 call onto the out parameters of the specific call made */
40 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
41 struct ntvfs_request *,
42 void *, void *, NTSTATUS);
44 /*
45 this structure holds the async state for pending mapped async calls
47 struct ntvfs_map_async {
48 struct ntvfs_module_context *ntvfs;
49 void *io, *io2;
50 second_stage_t fn;
54 this is a async wrapper, called from the backend when it has completed
55 a function that it has decided to reply to in an async fashion
57 static void ntvfs_map_async_send(struct ntvfs_request *req)
59 struct ntvfs_map_async *m = req->async_states->private_data;
61 ntvfs_async_state_pop(req);
63 /* call the _finish function setup in ntvfs_map_async_setup() */
64 req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
66 /* call the send function from the next module up */
67 req->async_states->send_fn(req);
71 prepare for calling a ntvfs backend with async support
72 io is the original call structure
73 io2 is the new call structure for the mapped call
74 fn is a second stage function for processing the out arguments
76 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
77 struct ntvfs_request *req,
78 void *io, void *io2,
79 second_stage_t fn)
81 struct ntvfs_map_async *m;
82 m = talloc(req, struct ntvfs_map_async);
83 if (m == NULL) {
84 return NT_STATUS_NO_MEMORY;
86 m->ntvfs = ntvfs;
87 m->io = io;
88 m->io2 = io2;
89 m->fn = fn;
90 return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
94 called when first stage processing is complete.
95 */
96 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
98 struct ntvfs_map_async *m;
100 /* if the backend has decided to reply in an async fashion then
101 we don't need to do any work here */
102 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
103 return status;
106 /* the backend is replying immediately. call the 2nd stage function after popping our local
107 async state */
108 m = req->async_states->private_data;
110 ntvfs_async_state_pop(req);
112 return m->fn(m->ntvfs, req, m->io, m->io2, status);
116 see if a filename ends in EXE COM DLL or SYM. This is needed for the
117 DENY_DOS mapping for OpenX
119 BOOL is_exe_filename(const char *fname)
121 char *p;
122 p = strrchr(fname, '.');
123 if (!p) {
124 return False;
126 p++;
127 if (strcasecmp(p, "EXE") == 0 ||
128 strcasecmp(p, "COM") == 0 ||
129 strcasecmp(p, "DLL") == 0 ||
130 strcasecmp(p, "SYM") == 0) {
131 return True;
133 return False;
138 NTVFS openx to ntcreatex mapper
140 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
141 struct ntvfs_request *req,
142 union smb_open *io,
143 union smb_open *io2,
144 NTSTATUS status)
146 time_t write_time = 0;
147 uint32_t set_size = 0;
148 union smb_setfileinfo *sf;
149 uint_t state;
151 if (!NT_STATUS_IS_OK(status)) {
152 return status;
155 switch (io->generic.level) {
156 case RAW_OPEN_OPEN:
157 io->openold.out.file.fnum = io2->generic.out.file.fnum;
158 io->openold.out.attrib = io2->generic.out.attrib;
159 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
160 io->openold.out.size = io2->generic.out.size;
161 io->openold.out.rmode = io->openold.in.open_mode;
162 break;
164 case RAW_OPEN_OPENX:
165 io->openx.out.file.fnum = io2->generic.out.file.fnum;
166 io->openx.out.attrib = io2->generic.out.attrib;
167 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
168 io->openx.out.size = io2->generic.out.size;
169 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
170 io->openx.out.ftype = 0;
171 io->openx.out.devstate = 0;
172 io->openx.out.action = io2->generic.out.create_action;
173 io->openx.out.unique_fid = 0;
174 io->openx.out.access_mask = SEC_STD_ALL;
175 io->openx.out.unknown = 0;
177 /* we need to extend the file to the requested size if
178 it was newly created */
179 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
180 set_size = io->openx.in.size;
182 break;
184 case RAW_OPEN_T2OPEN:
185 io->t2open.out.file.fnum = io2->generic.out.file.fnum;
186 io->t2open.out.attrib = io2->generic.out.attrib;
187 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
188 io->t2open.out.size = io2->generic.out.size;
189 io->t2open.out.access = io->t2open.in.open_mode;
190 io->t2open.out.ftype = 0;
191 io->t2open.out.devstate = 0;
192 io->t2open.out.action = io2->generic.out.create_action;
193 io->t2open.out.file_id = 0;
194 break;
196 case RAW_OPEN_MKNEW:
197 case RAW_OPEN_CREATE:
198 io->mknew.out.file.fnum = io2->generic.out.file.fnum;
199 write_time = io->mknew.in.write_time;
200 break;
202 case RAW_OPEN_CTEMP:
203 io->ctemp.out.file.fnum = io2->generic.out.file.fnum;
204 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
205 strlen(io->ctemp.in.directory) + 1);
206 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
207 break;
209 default:
210 return NT_STATUS_INVALID_LEVEL;
213 /* doing a secondary request async is more trouble than its
214 worth */
215 state = req->async_states->state;
216 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
218 if (write_time != 0) {
219 sf = talloc(req, union smb_setfileinfo);
220 NT_STATUS_HAVE_NO_MEMORY(sf);
221 sf->generic.level = RAW_SFILEINFO_STANDARD;
222 sf->generic.in.file.fnum = io2->generic.out.file.fnum;
223 sf->standard.in.create_time = 0;
224 sf->standard.in.write_time = write_time;
225 sf->standard.in.access_time = 0;
226 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
229 if (set_size != 0) {
230 sf = talloc(req, union smb_setfileinfo);
231 NT_STATUS_HAVE_NO_MEMORY(sf);
232 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
233 sf->generic.in.file.fnum = io2->generic.out.file.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;
243 return NT_STATUS_OK;
247 the core of the mapping between openx style parameters and ntcreatex
248 parameters
250 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
251 uint16_t open_func, const char *fname,
252 union smb_open *io2)
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;
265 break;
266 case OPENX_MODE_ACCESS_WRITE:
267 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
268 break;
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;
274 break;
275 default:
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;
282 break;
283 case OPENX_MODE_DENY_WRITE:
284 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
285 break;
286 case OPENX_MODE_DENY_ALL:
287 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
288 break;
289 case OPENX_MODE_DENY_NONE:
290 io2->generic.in.share_access =
291 NTCREATEX_SHARE_ACCESS_READ |
292 NTCREATEX_SHARE_ACCESS_WRITE;
293 break;
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;
302 } else {
303 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
304 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
305 } else {
306 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
309 break;
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;
313 break;
314 default:
315 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
318 switch (open_func) {
319 case (OPENX_OPEN_FUNC_OPEN):
320 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
321 break;
322 case (OPENX_OPEN_FUNC_TRUNC):
323 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
324 break;
325 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
326 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
327 break;
328 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
329 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
330 break;
331 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
332 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
333 break;
334 default:
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;
338 break;
340 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
343 return NT_STATUS_OK;
347 NTVFS open generic to any mapper
349 _PUBLIC_ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
350 struct ntvfs_request *req,
351 union smb_open *io)
353 NTSTATUS status;
354 union smb_open *io2;
356 io2 = talloc_zero(req, union smb_open);
357 if (io2 == NULL) {
358 return NT_STATUS_NO_MEMORY;
361 status = ntvfs_map_async_setup(ntvfs, req,
362 io, io2,
363 (second_stage_t)ntvfs_map_open_finish);
364 if (!NT_STATUS_IS_OK(status)) {
365 return status;
368 io2->generic.level = RAW_OPEN_GENERIC;
370 switch (io->generic.level) {
371 case RAW_OPEN_OPENX:
372 status = map_openx_open(io->openx.in.flags,
373 io->openx.in.open_mode,
374 io->openx.in.open_func,
375 io->openx.in.fname,
376 io2);
377 if (!NT_STATUS_IS_OK(status)) {
378 goto done;
381 io2->generic.in.file_attr = io->openx.in.file_attrs;
382 io2->generic.in.fname = io->openx.in.fname;
384 status = ntvfs->ops->open(ntvfs, req, io2);
385 break;
388 case RAW_OPEN_OPEN:
389 status = map_openx_open(0,
390 io->openold.in.open_mode,
391 OPENX_OPEN_FUNC_OPEN,
392 io->openold.in.fname,
393 io2);
394 if (!NT_STATUS_IS_OK(status)) {
395 goto done;
398 io2->generic.in.file_attr = io->openold.in.search_attrs;
399 io2->generic.in.fname = io->openold.in.fname;
401 status = ntvfs->ops->open(ntvfs, req, io2);
402 break;
404 case RAW_OPEN_T2OPEN:
405 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
407 if (io->t2open.in.open_func == 0) {
408 status = NT_STATUS_OBJECT_NAME_COLLISION;
409 goto done;
412 status = map_openx_open(io->t2open.in.flags,
413 io->t2open.in.open_mode,
414 io->t2open.in.open_func,
415 io->t2open.in.fname,
416 io2);
417 if (!NT_STATUS_IS_OK(status)) {
418 goto done;
421 io2->generic.in.file_attr = io->t2open.in.file_attrs;
422 io2->generic.in.fname = io->t2open.in.fname;
423 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
424 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
425 io2->generic.in.ea_list->eas = io->t2open.in.eas;
427 status = ntvfs->ops->open(ntvfs, req, io2);
428 break;
430 case RAW_OPEN_MKNEW:
431 io2->generic.in.file_attr = io->mknew.in.attrib;
432 io2->generic.in.fname = io->mknew.in.fname;
433 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
434 io2->generic.in.access_mask =
435 SEC_RIGHTS_FILE_READ |
436 SEC_RIGHTS_FILE_WRITE;
437 io2->generic.in.share_access =
438 NTCREATEX_SHARE_ACCESS_READ |
439 NTCREATEX_SHARE_ACCESS_WRITE;
440 status = ntvfs->ops->open(ntvfs, req, io2);
441 break;
443 case RAW_OPEN_CREATE:
444 io2->generic.in.file_attr = io->mknew.in.attrib;
445 io2->generic.in.fname = io->mknew.in.fname;
446 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
447 io2->generic.in.access_mask =
448 SEC_RIGHTS_FILE_READ |
449 SEC_RIGHTS_FILE_WRITE;
450 io2->generic.in.share_access =
451 NTCREATEX_SHARE_ACCESS_READ |
452 NTCREATEX_SHARE_ACCESS_WRITE;
453 status = ntvfs->ops->open(ntvfs, req, io2);
454 break;
456 case RAW_OPEN_CTEMP:
457 io2->generic.in.file_attr = io->ctemp.in.attrib;
458 io2->generic.in.file_attr = 0;
459 io2->generic.in.fname =
460 talloc_asprintf(io2, "%s\\SRV%s",
461 io->ctemp.in.directory,
462 generate_random_str_list(io2, 5, "0123456789"));
463 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
464 io2->generic.in.access_mask =
465 SEC_RIGHTS_FILE_READ |
466 SEC_RIGHTS_FILE_WRITE;
467 io2->generic.in.share_access =
468 NTCREATEX_SHARE_ACCESS_READ |
469 NTCREATEX_SHARE_ACCESS_WRITE;
470 status = ntvfs->ops->open(ntvfs, req, io2);
471 break;
473 default:
474 status = NT_STATUS_INVALID_LEVEL;
475 break;
477 done:
478 return ntvfs_map_async_finish(req, status);
483 NTVFS fsinfo generic to any mapper
485 _PUBLIC_ NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
486 struct ntvfs_request *req,
487 union smb_fsinfo *fs)
489 NTSTATUS status;
490 union smb_fsinfo *fs2;
492 fs2 = talloc(req, union smb_fsinfo);
493 if (fs2 == NULL) {
494 return NT_STATUS_NO_MEMORY;
497 if (fs->generic.level == RAW_QFS_GENERIC) {
498 return NT_STATUS_INVALID_LEVEL;
501 /* only used by the simple backend, which doesn't do async */
502 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
504 /* ask the backend for the generic info */
505 fs2->generic.level = RAW_QFS_GENERIC;
507 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
508 if (!NT_STATUS_IS_OK(status)) {
509 return status;
512 /* and convert it to the required level */
513 switch (fs->generic.level) {
514 case RAW_QFS_GENERIC:
515 return NT_STATUS_INVALID_LEVEL;
517 case RAW_QFS_DSKATTR: {
518 /* map from generic to DSKATTR */
519 uint_t bpunit = 64;
521 /* we need to scale the sizes to fit */
522 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
523 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
524 break;
528 fs->dskattr.out.blocks_per_unit = bpunit;
529 fs->dskattr.out.block_size = 512;
530 fs->dskattr.out.units_total =
531 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
532 fs->dskattr.out.units_free =
533 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
535 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
536 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
537 fs->dskattr.out.blocks_per_unit = 64;
538 fs->dskattr.out.units_total = 0xFFFF;
539 fs->dskattr.out.units_free = 0xFFFF;
541 return NT_STATUS_OK;
544 case RAW_QFS_ALLOCATION:
545 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
546 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
547 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
548 fs->allocation.out.sectors_per_unit = 1;
549 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
550 return NT_STATUS_OK;
552 case RAW_QFS_VOLUME:
553 fs->volume.out.serial_number = fs2->generic.out.serial_number;
554 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
555 return NT_STATUS_OK;
557 case RAW_QFS_VOLUME_INFO:
558 case RAW_QFS_VOLUME_INFORMATION:
559 fs->volume_info.out.create_time = fs2->generic.out.create_time;
560 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
561 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
562 return NT_STATUS_OK;
564 case RAW_QFS_SIZE_INFO:
565 case RAW_QFS_SIZE_INFORMATION:
566 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
567 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
568 fs->size_info.out.sectors_per_unit = 1;
569 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
570 return NT_STATUS_OK;
572 case RAW_QFS_DEVICE_INFO:
573 case RAW_QFS_DEVICE_INFORMATION:
574 fs->device_info.out.device_type = fs2->generic.out.device_type;
575 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
576 return NT_STATUS_OK;
578 case RAW_QFS_ATTRIBUTE_INFO:
579 case RAW_QFS_ATTRIBUTE_INFORMATION:
580 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
581 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
582 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
583 return NT_STATUS_OK;
585 case RAW_QFS_QUOTA_INFORMATION:
586 ZERO_STRUCT(fs->quota_information.out.unknown);
587 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
588 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
589 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
590 return NT_STATUS_OK;
592 case RAW_QFS_FULL_SIZE_INFORMATION:
593 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
594 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
595 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
596 fs->full_size_information.out.sectors_per_unit = 1;
597 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
598 return NT_STATUS_OK;
600 case RAW_QFS_OBJECTID_INFORMATION:
601 fs->objectid_information.out.guid = fs2->generic.out.guid;
602 ZERO_STRUCT(fs->objectid_information.out.unknown);
603 return NT_STATUS_OK;
607 return NT_STATUS_INVALID_LEVEL;
612 NTVFS fileinfo generic to any mapper
614 _PUBLIC_ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
615 union smb_fileinfo *info,
616 union smb_fileinfo *info2)
618 int i;
619 /* and convert it to the required level using results in info2 */
620 switch (info->generic.level) {
621 case RAW_FILEINFO_GENERIC:
622 return NT_STATUS_INVALID_LEVEL;
623 case RAW_FILEINFO_GETATTR:
624 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
625 info->getattr.out.size = info2->generic.out.size;
626 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
627 return NT_STATUS_OK;
629 case RAW_FILEINFO_GETATTRE:
630 info->getattre.out.attrib = info2->generic.out.attrib;
631 info->getattre.out.size = info2->generic.out.size;
632 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
633 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
634 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
635 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
636 return NT_STATUS_OK;
638 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
639 info->network_open_information.out.create_time = info2->generic.out.create_time;
640 info->network_open_information.out.access_time = info2->generic.out.access_time;
641 info->network_open_information.out.write_time = info2->generic.out.write_time;
642 info->network_open_information.out.change_time = info2->generic.out.change_time;
643 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
644 info->network_open_information.out.size = info2->generic.out.size;
645 info->network_open_information.out.attrib = info2->generic.out.attrib;
646 return NT_STATUS_OK;
648 case RAW_FILEINFO_ALL_INFO:
649 case RAW_FILEINFO_ALL_INFORMATION:
650 info->all_info.out.create_time = info2->generic.out.create_time;
651 info->all_info.out.access_time = info2->generic.out.access_time;
652 info->all_info.out.write_time = info2->generic.out.write_time;
653 info->all_info.out.change_time = info2->generic.out.change_time;
654 info->all_info.out.attrib = info2->generic.out.attrib;
655 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
656 info->all_info.out.size = info2->generic.out.size;
657 info->all_info.out.nlink = info2->generic.out.nlink;
658 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
659 info->all_info.out.directory = info2->generic.out.directory;
660 info->all_info.out.ea_size = info2->generic.out.ea_size;
661 info->all_info.out.fname.s = info2->generic.out.fname.s;
662 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
663 return NT_STATUS_OK;
665 case RAW_FILEINFO_BASIC_INFO:
666 case RAW_FILEINFO_BASIC_INFORMATION:
667 info->basic_info.out.create_time = info2->generic.out.create_time;
668 info->basic_info.out.access_time = info2->generic.out.access_time;
669 info->basic_info.out.write_time = info2->generic.out.write_time;
670 info->basic_info.out.change_time = info2->generic.out.change_time;
671 info->basic_info.out.attrib = info2->generic.out.attrib;
672 return NT_STATUS_OK;
674 case RAW_FILEINFO_STANDARD:
675 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
676 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
677 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
678 info->standard.out.size = info2->generic.out.size;
679 info->standard.out.alloc_size = info2->generic.out.alloc_size;
680 info->standard.out.attrib = info2->generic.out.attrib;
681 return NT_STATUS_OK;
683 case RAW_FILEINFO_EA_SIZE:
684 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
685 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
686 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
687 info->ea_size.out.size = info2->generic.out.size;
688 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
689 info->ea_size.out.attrib = info2->generic.out.attrib;
690 info->ea_size.out.ea_size = info2->generic.out.ea_size;
691 return NT_STATUS_OK;
693 case RAW_FILEINFO_STANDARD_INFO:
694 case RAW_FILEINFO_STANDARD_INFORMATION:
695 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
696 info->standard_info.out.size = info2->generic.out.size;
697 info->standard_info.out.nlink = info2->generic.out.nlink;
698 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
699 info->standard_info.out.directory = info2->generic.out.directory;
700 return NT_STATUS_OK;
702 case RAW_FILEINFO_INTERNAL_INFORMATION:
703 info->internal_information.out.file_id = info2->generic.out.file_id;
704 return NT_STATUS_OK;
706 case RAW_FILEINFO_EA_INFO:
707 case RAW_FILEINFO_EA_INFORMATION:
708 info->ea_info.out.ea_size = info2->generic.out.ea_size;
709 return NT_STATUS_OK;
711 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
712 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
713 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
714 return NT_STATUS_OK;
716 case RAW_FILEINFO_STREAM_INFO:
717 case RAW_FILEINFO_STREAM_INFORMATION:
718 info->stream_info.out.num_streams = info2->generic.out.num_streams;
719 if (info->stream_info.out.num_streams > 0) {
720 info->stream_info.out.streams =
721 talloc_array(mem_ctx,
722 struct stream_struct,
723 info->stream_info.out.num_streams);
724 if (!info->stream_info.out.streams) {
725 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
726 info->stream_info.out.num_streams));
727 return NT_STATUS_NO_MEMORY;
729 for (i=0; i < info->stream_info.out.num_streams; i++) {
730 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
731 info->stream_info.out.streams[i].stream_name.s =
732 talloc_strdup(info->stream_info.out.streams,
733 info2->generic.out.streams[i].stream_name.s);
734 if (!info->stream_info.out.streams[i].stream_name.s) {
735 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
736 return NT_STATUS_NO_MEMORY;
740 return NT_STATUS_OK;
742 case RAW_FILEINFO_NAME_INFO:
743 case RAW_FILEINFO_NAME_INFORMATION:
744 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
745 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
746 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
747 return NT_STATUS_OK;
749 case RAW_FILEINFO_ALT_NAME_INFO:
750 case RAW_FILEINFO_ALT_NAME_INFORMATION:
751 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
752 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
753 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
754 return NT_STATUS_OK;
756 case RAW_FILEINFO_POSITION_INFORMATION:
757 info->position_information.out.position = info2->generic.out.position;
758 return NT_STATUS_OK;
760 case RAW_FILEINFO_ALL_EAS:
761 info->all_eas.out.num_eas = info2->generic.out.num_eas;
762 if (info->all_eas.out.num_eas > 0) {
763 info->all_eas.out.eas = talloc_array(mem_ctx,
764 struct ea_struct,
765 info->all_eas.out.num_eas);
766 if (!info->all_eas.out.eas) {
767 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
768 info->all_eas.out.num_eas));
769 return NT_STATUS_NO_MEMORY;
771 for (i = 0; i < info->all_eas.out.num_eas; i++) {
772 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
773 info->all_eas.out.eas[i].name.s =
774 talloc_strdup(info->all_eas.out.eas,
775 info2->generic.out.eas[i].name.s);
776 if (!info->all_eas.out.eas[i].name.s) {
777 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
778 return NT_STATUS_NO_MEMORY;
780 info->all_eas.out.eas[i].value.data =
781 talloc_memdup(info->all_eas.out.eas,
782 info2->generic.out.eas[i].value.data,
783 info2->generic.out.eas[i].value.length);
784 if (!info->all_eas.out.eas[i].value.data) {
785 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
786 return NT_STATUS_NO_MEMORY;
790 return NT_STATUS_OK;
792 case RAW_FILEINFO_IS_NAME_VALID:
793 return NT_STATUS_OK;
795 case RAW_FILEINFO_COMPRESSION_INFO:
796 case RAW_FILEINFO_COMPRESSION_INFORMATION:
797 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
798 info->compression_info.out.format = info2->generic.out.format;
799 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
800 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
801 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
802 return NT_STATUS_OK;
804 case RAW_FILEINFO_ACCESS_INFORMATION:
805 info->access_information.out.access_flags = info2->generic.out.access_flags;
806 return NT_STATUS_OK;
808 case RAW_FILEINFO_MODE_INFORMATION:
809 info->mode_information.out.mode = info2->generic.out.mode;
810 return NT_STATUS_OK;
812 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
813 info->alignment_information.out.alignment_requirement =
814 info2->generic.out.alignment_requirement;
815 return NT_STATUS_OK;
816 #if 0
817 case RAW_FILEINFO_UNIX_BASIC:
818 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
819 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
820 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
821 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
822 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
823 info->unix_basic_info.out.uid = info2->generic.out.uid;
824 info->unix_basic_info.out.gid = info2->generic.out.gid;
825 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
826 info->unix_basic_info.out.dev_major = info2->generic.out.device;
827 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
828 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
829 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
830 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
831 return NT_STATUS_OK;
833 case RAW_FILEINFO_UNIX_LINK:
834 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
835 return NT_STATUS_OK;
836 #endif
839 return NT_STATUS_INVALID_LEVEL;
843 NTVFS fileinfo generic to any mapper
845 _PUBLIC_ NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
846 struct ntvfs_request *req,
847 union smb_fileinfo *info)
849 NTSTATUS status;
850 union smb_fileinfo *info2;
852 info2 = talloc(req, union smb_fileinfo);
853 if (info2 == NULL) {
854 return NT_STATUS_NO_MEMORY;
857 if (info->generic.level == RAW_FILEINFO_GENERIC) {
858 return NT_STATUS_INVALID_LEVEL;
861 /* ask the backend for the generic info */
862 info2->generic.level = RAW_FILEINFO_GENERIC;
863 info2->generic.in.file.fnum = info->generic.in.file.fnum;
865 /* only used by the simple backend, which doesn't do async */
866 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
868 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
869 if (!NT_STATUS_IS_OK(status)) {
870 return status;
872 return ntvfs_map_fileinfo(req, info, info2);
876 NTVFS pathinfo generic to any mapper
878 _PUBLIC_ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
879 struct ntvfs_request *req,
880 union smb_fileinfo *info)
882 NTSTATUS status;
883 union smb_fileinfo *info2;
885 info2 = talloc(req, union smb_fileinfo);
886 if (info2 == NULL) {
887 return NT_STATUS_NO_MEMORY;
890 if (info->generic.level == RAW_FILEINFO_GENERIC) {
891 return NT_STATUS_INVALID_LEVEL;
894 /* ask the backend for the generic info */
895 info2->generic.level = RAW_FILEINFO_GENERIC;
896 info2->generic.in.file.path = info->generic.in.file.path;
898 /* only used by the simple backend, which doesn't do async */
899 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
901 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
902 if (!NT_STATUS_IS_OK(status)) {
903 return status;
905 return ntvfs_map_fileinfo(req, info, info2);
910 NTVFS lock generic to any mapper
912 _PUBLIC_ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
913 struct ntvfs_request *req,
914 union smb_lock *lck)
916 union smb_lock *lck2;
917 struct smb_lock_entry *locks;
919 lck2 = talloc(req, union smb_lock);
920 if (lck2 == NULL) {
921 return NT_STATUS_NO_MEMORY;
924 locks = talloc_array(lck2, struct smb_lock_entry, 1);
925 if (locks == NULL) {
926 return NT_STATUS_NO_MEMORY;
929 switch (lck->generic.level) {
930 case RAW_LOCK_LOCKX:
931 return NT_STATUS_INVALID_LEVEL;
933 case RAW_LOCK_LOCK:
934 lck2->generic.in.ulock_cnt = 0;
935 lck2->generic.in.lock_cnt = 1;
936 break;
938 case RAW_LOCK_UNLOCK:
939 lck2->generic.in.ulock_cnt = 1;
940 lck2->generic.in.lock_cnt = 0;
941 break;
944 lck2->generic.level = RAW_LOCK_GENERIC;
945 lck2->generic.in.file.fnum = lck->lock.in.file.fnum;
946 lck2->generic.in.mode = 0;
947 lck2->generic.in.timeout = 0;
948 lck2->generic.in.locks = locks;
949 locks->pid = req->smbpid;
950 locks->offset = lck->lock.in.offset;
951 locks->count = lck->lock.in.count;
954 * we don't need to call ntvfs_map_async_setup() here,
955 * as lock() doesn't have any output fields
958 return ntvfs->ops->lock(ntvfs, req, lck2);
963 NTVFS write generic to any mapper
965 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
966 struct ntvfs_request *req,
967 union smb_write *wr,
968 union smb_write *wr2,
969 NTSTATUS status)
971 union smb_lock *lck;
972 union smb_close *cl;
973 uint_t state;
975 if (NT_STATUS_IS_ERR(status)) {
976 return status;
979 switch (wr->generic.level) {
980 case RAW_WRITE_WRITE:
981 wr->write.out.nwritten = wr2->generic.out.nwritten;
982 break;
984 case RAW_WRITE_WRITEUNLOCK:
985 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
987 lck = talloc(wr2, union smb_lock);
988 if (lck == NULL) {
989 return NT_STATUS_NO_MEMORY;
992 lck->unlock.level = RAW_LOCK_UNLOCK;
993 lck->unlock.in.file.fnum= wr->writeunlock.in.file.fnum;
994 lck->unlock.in.count = wr->writeunlock.in.count;
995 lck->unlock.in.offset = wr->writeunlock.in.offset;
997 if (lck->unlock.in.count != 0) {
998 /* do the lock sync for now */
999 state = req->async_states->state;
1000 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1001 status = ntvfs->ops->lock(ntvfs, req, lck);
1002 req->async_states->state = state;
1004 break;
1006 case RAW_WRITE_WRITECLOSE:
1007 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1009 cl = talloc(wr2, union smb_close);
1010 if (cl == NULL) {
1011 return NT_STATUS_NO_MEMORY;
1014 cl->close.level = RAW_CLOSE_CLOSE;
1015 cl->close.in.file.fnum = wr->writeclose.in.file.fnum;
1016 cl->close.in.write_time = wr->writeclose.in.mtime;
1018 if (wr2->generic.in.count != 0) {
1019 /* do the close sync for now */
1020 state = req->async_states->state;
1021 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1022 status = ntvfs->ops->close(ntvfs, req, cl);
1023 req->async_states->state = state;
1025 break;
1027 case RAW_WRITE_SPLWRITE:
1028 break;
1029 default:
1030 return NT_STATUS_INVALID_LEVEL;
1033 return status;
1038 NTVFS write generic to any mapper
1040 _PUBLIC_ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1041 struct ntvfs_request *req,
1042 union smb_write *wr)
1044 union smb_write *wr2;
1045 NTSTATUS status;
1047 wr2 = talloc(req, union smb_write);
1048 if (wr2 == NULL) {
1049 return NT_STATUS_NO_MEMORY;
1052 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1053 (second_stage_t)ntvfs_map_write_finish);
1054 if (!NT_STATUS_IS_OK(status)) {
1055 return status;
1058 wr2->writex.level = RAW_WRITE_GENERIC;
1060 switch (wr->generic.level) {
1061 case RAW_WRITE_WRITEX:
1062 status = NT_STATUS_INVALID_LEVEL;
1063 break;
1065 case RAW_WRITE_WRITE:
1066 wr2->writex.in.file.fnum = wr->write.in.file.fnum;
1067 wr2->writex.in.offset = wr->write.in.offset;
1068 wr2->writex.in.wmode = 0;
1069 wr2->writex.in.remaining = wr->write.in.remaining;
1070 wr2->writex.in.count = wr->write.in.count;
1071 wr2->writex.in.data = wr->write.in.data;
1072 status = ntvfs->ops->write(ntvfs, req, wr2);
1073 break;
1075 case RAW_WRITE_WRITEUNLOCK:
1076 wr2->writex.in.file.fnum = wr->writeunlock.in.file.fnum;
1077 wr2->writex.in.offset = wr->writeunlock.in.offset;
1078 wr2->writex.in.wmode = 0;
1079 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1080 wr2->writex.in.count = wr->writeunlock.in.count;
1081 wr2->writex.in.data = wr->writeunlock.in.data;
1082 status = ntvfs->ops->write(ntvfs, req, wr2);
1083 break;
1085 case RAW_WRITE_WRITECLOSE:
1086 wr2->writex.in.file.fnum = wr->writeclose.in.file.fnum;
1087 wr2->writex.in.offset = wr->writeclose.in.offset;
1088 wr2->writex.in.wmode = 0;
1089 wr2->writex.in.remaining = 0;
1090 wr2->writex.in.count = wr->writeclose.in.count;
1091 wr2->writex.in.data = wr->writeclose.in.data;
1092 status = ntvfs->ops->write(ntvfs, req, wr2);
1093 break;
1095 case RAW_WRITE_SPLWRITE:
1096 wr2->writex.in.file.fnum = wr->splwrite.in.file.fnum;
1097 wr2->writex.in.offset = 0;
1098 wr2->writex.in.wmode = 0;
1099 wr2->writex.in.remaining = 0;
1100 wr2->writex.in.count = wr->splwrite.in.count;
1101 wr2->writex.in.data = wr->splwrite.in.data;
1102 status = ntvfs->ops->write(ntvfs, req, wr2);
1103 break;
1106 return ntvfs_map_async_finish(req, status);
1111 NTVFS read generic to any mapper - finish the out mapping
1113 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1114 struct ntvfs_request *req,
1115 union smb_read *rd,
1116 union smb_read *rd2,
1117 NTSTATUS status)
1119 switch (rd->generic.level) {
1120 case RAW_READ_READ:
1121 rd->read.out.nread = rd2->generic.out.nread;
1122 break;
1123 case RAW_READ_READBRAW:
1124 rd->readbraw.out.nread = rd2->generic.out.nread;
1125 break;
1126 case RAW_READ_LOCKREAD:
1127 rd->lockread.out.nread = rd2->generic.out.nread;
1128 break;
1129 default:
1130 return NT_STATUS_INVALID_LEVEL;
1133 return status;
1137 NTVFS read* to readx mapper
1139 _PUBLIC_ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1140 struct ntvfs_request *req,
1141 union smb_read *rd)
1143 union smb_read *rd2;
1144 union smb_lock *lck;
1145 NTSTATUS status;
1146 uint_t state;
1148 rd2 = talloc(req, union smb_read);
1149 if (rd2 == NULL) {
1150 return NT_STATUS_NO_MEMORY;
1153 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1154 (second_stage_t)ntvfs_map_read_finish);
1155 if (!NT_STATUS_IS_OK(status)) {
1156 return status;
1159 rd2->readx.level = RAW_READ_READX;
1160 rd2->readx.in.read_for_execute = False;
1162 switch (rd->generic.level) {
1163 case RAW_READ_READX:
1164 status = NT_STATUS_INVALID_LEVEL;
1165 break;
1167 case RAW_READ_READ:
1168 rd2->readx.in.file.fnum = rd->read.in.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);
1175 break;
1177 case RAW_READ_READBRAW:
1178 rd2->readx.in.file.fnum = rd->readbraw.in.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);
1185 break;
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);
1193 if (lck == NULL) {
1194 status = NT_STATUS_NO_MEMORY;
1195 goto done;
1197 lck->lock.level = RAW_LOCK_LOCK;
1198 lck->lock.in.file.fnum = rd->lockread.in.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.in.file.fnum = rd->lockread.in.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);
1214 break;
1217 done:
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);
1232 if (cl2 == NULL) {
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.in.file.fnum = cl->splclose.in.file.fnum;
1243 break;
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);