r21513: I don't know how long this has been wrong, but fix this up so we can
[Samba/ekacnet.git] / source4 / ntvfs / ntvfs_generic.c
blobaa6edcdf423e2e4584e736da0ad3d0c2f05f6546
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 "ntvfs/ntvfs.h"
37 /* a second stage function converts from the out parameters of the generic
38 call onto the out parameters of the specific call made */
39 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
40 struct ntvfs_request *,
41 void *, void *, NTSTATUS);
43 /*
44 this structure holds the async state for pending mapped async calls
46 struct ntvfs_map_async {
47 struct ntvfs_module_context *ntvfs;
48 void *io, *io2;
49 second_stage_t fn;
53 this is a async wrapper, called from the backend when it has completed
54 a function that it has decided to reply to in an async fashion
56 static void ntvfs_map_async_send(struct ntvfs_request *req)
58 struct ntvfs_map_async *m = req->async_states->private_data;
60 ntvfs_async_state_pop(req);
62 /* call the _finish function setup in ntvfs_map_async_setup() */
63 req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
65 /* call the send function from the next module up */
66 req->async_states->send_fn(req);
70 prepare for calling a ntvfs backend with async support
71 io is the original call structure
72 io2 is the new call structure for the mapped call
73 fn is a second stage function for processing the out arguments
75 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
76 struct ntvfs_request *req,
77 void *io, void *io2,
78 second_stage_t fn)
80 struct ntvfs_map_async *m;
81 m = talloc(req, struct ntvfs_map_async);
82 if (m == NULL) {
83 return NT_STATUS_NO_MEMORY;
85 m->ntvfs = ntvfs;
86 m->io = io;
87 m->io2 = io2;
88 m->fn = fn;
89 return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
93 called when first stage processing is complete.
94 */
95 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
97 struct ntvfs_map_async *m;
99 /* if the backend has decided to reply in an async fashion then
100 we don't need to do any work here */
101 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
102 return status;
105 /* the backend is replying immediately. call the 2nd stage function after popping our local
106 async state */
107 m = req->async_states->private_data;
109 ntvfs_async_state_pop(req);
111 return m->fn(m->ntvfs, req, m->io, m->io2, status);
115 see if a filename ends in EXE COM DLL or SYM. This is needed for the
116 DENY_DOS mapping for OpenX
118 BOOL is_exe_filename(const char *fname)
120 char *p;
121 p = strrchr(fname, '.');
122 if (!p) {
123 return False;
125 p++;
126 if (strcasecmp(p, "EXE") == 0 ||
127 strcasecmp(p, "COM") == 0 ||
128 strcasecmp(p, "DLL") == 0 ||
129 strcasecmp(p, "SYM") == 0) {
130 return True;
132 return False;
137 NTVFS openx to ntcreatex mapper
139 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
140 struct ntvfs_request *req,
141 union smb_open *io,
142 union smb_open *io2,
143 NTSTATUS status)
145 time_t write_time = 0;
146 uint32_t set_size = 0;
147 union smb_setfileinfo *sf;
148 uint_t state;
150 if (!NT_STATUS_IS_OK(status)) {
151 return status;
154 switch (io->generic.level) {
155 case RAW_OPEN_OPEN:
156 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
157 io->openold.out.attrib = io2->generic.out.attrib;
158 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
159 io->openold.out.size = io2->generic.out.size;
160 io->openold.out.rmode = io->openold.in.open_mode;
161 break;
163 case RAW_OPEN_OPENX:
164 io->openx.out.file.ntvfs = io2->generic.out.file.ntvfs;
165 io->openx.out.attrib = io2->generic.out.attrib;
166 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
167 io->openx.out.size = io2->generic.out.size;
168 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
169 io->openx.out.ftype = 0;
170 io->openx.out.devstate = 0;
171 io->openx.out.action = io2->generic.out.create_action;
172 io->openx.out.unique_fid = 0;
173 io->openx.out.access_mask = SEC_STD_ALL;
174 io->openx.out.unknown = 0;
176 /* we need to extend the file to the requested size if
177 it was newly created */
178 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
179 set_size = io->openx.in.size;
181 break;
183 case RAW_OPEN_T2OPEN:
184 io->t2open.out.file.ntvfs = io2->generic.out.file.ntvfs;
185 io->t2open.out.attrib = io2->generic.out.attrib;
186 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
187 io->t2open.out.size = io2->generic.out.size;
188 io->t2open.out.access = io->t2open.in.open_mode;
189 io->t2open.out.ftype = 0;
190 io->t2open.out.devstate = 0;
191 io->t2open.out.action = io2->generic.out.create_action;
192 io->t2open.out.file_id = 0;
193 break;
195 case RAW_OPEN_MKNEW:
196 case RAW_OPEN_CREATE:
197 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
198 write_time = io->mknew.in.write_time;
199 break;
201 case RAW_OPEN_CTEMP:
202 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
203 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
204 strlen(io->ctemp.in.directory) + 1);
205 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
206 break;
208 case RAW_OPEN_SMB2:
209 io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs;
210 io->smb2.out.oplock_flags = 0;
211 io->smb2.out.create_action = io2->generic.out.create_action;
212 io->smb2.out.create_time = io2->generic.out.create_time;
213 io->smb2.out.access_time = io2->generic.out.access_time;
214 io->smb2.out.write_time = io2->generic.out.write_time;
215 io->smb2.out.change_time = io2->generic.out.change_time;
216 io->smb2.out.alloc_size = io2->generic.out.alloc_size;
217 io->smb2.out.size = io2->generic.out.size;
218 io->smb2.out.file_attr = io2->generic.out.attrib;
219 io->smb2.out._pad = 0;
220 io->smb2.out.blob = data_blob(NULL, 0);
221 break;
223 default:
224 return NT_STATUS_INVALID_LEVEL;
227 /* doing a secondary request async is more trouble than its
228 worth */
229 state = req->async_states->state;
230 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
232 if (write_time != 0) {
233 sf = talloc(req, union smb_setfileinfo);
234 NT_STATUS_HAVE_NO_MEMORY(sf);
235 sf->generic.level = RAW_SFILEINFO_STANDARD;
236 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
237 sf->standard.in.create_time = 0;
238 sf->standard.in.write_time = write_time;
239 sf->standard.in.access_time = 0;
240 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
243 if (set_size != 0) {
244 sf = talloc(req, union smb_setfileinfo);
245 NT_STATUS_HAVE_NO_MEMORY(sf);
246 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
247 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
248 sf->end_of_file_info.in.size = set_size;
249 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
250 if (NT_STATUS_IS_OK(status)) {
251 io->openx.out.size = io->openx.in.size;
255 req->async_states->state = state;
257 return NT_STATUS_OK;
261 the core of the mapping between openx style parameters and ntcreatex
262 parameters
264 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
265 uint16_t open_func, const char *fname,
266 union smb_open *io2)
268 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
269 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
271 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
272 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
275 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
276 case OPENX_MODE_ACCESS_READ:
277 case OPENX_MODE_ACCESS_EXEC:
278 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
279 break;
280 case OPENX_MODE_ACCESS_WRITE:
281 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
282 break;
283 case OPENX_MODE_ACCESS_RDWR:
284 case OPENX_MODE_ACCESS_FCB:
285 io2->generic.in.access_mask =
286 SEC_RIGHTS_FILE_READ |
287 SEC_RIGHTS_FILE_WRITE;
288 break;
289 default:
290 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
293 switch (open_mode & OPENX_MODE_DENY_MASK) {
294 case OPENX_MODE_DENY_READ:
295 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
296 break;
297 case OPENX_MODE_DENY_WRITE:
298 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
299 break;
300 case OPENX_MODE_DENY_ALL:
301 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
302 break;
303 case OPENX_MODE_DENY_NONE:
304 io2->generic.in.share_access =
305 NTCREATEX_SHARE_ACCESS_READ |
306 NTCREATEX_SHARE_ACCESS_WRITE;
307 break;
308 case OPENX_MODE_DENY_DOS:
309 /* DENY_DOS is quite strange - it depends on the filename! */
310 io2->generic.in.create_options |=
311 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
312 if (is_exe_filename(fname)) {
313 io2->generic.in.share_access =
314 NTCREATEX_SHARE_ACCESS_READ |
315 NTCREATEX_SHARE_ACCESS_WRITE;
316 } else {
317 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
318 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
319 } else {
320 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
323 break;
324 case OPENX_MODE_DENY_FCB:
325 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
326 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
327 break;
328 default:
329 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
332 switch (open_func) {
333 case (OPENX_OPEN_FUNC_OPEN):
334 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
335 break;
336 case (OPENX_OPEN_FUNC_TRUNC):
337 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
338 break;
339 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
340 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
341 break;
342 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
343 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
344 break;
345 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
346 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
347 break;
348 default:
349 /* this one is very strange */
350 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
351 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
352 break;
354 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
357 return NT_STATUS_OK;
361 NTVFS open generic to any mapper
363 _PUBLIC_ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
364 struct ntvfs_request *req,
365 union smb_open *io)
367 NTSTATUS status;
368 union smb_open *io2;
370 io2 = talloc_zero(req, union smb_open);
371 if (io2 == NULL) {
372 return NT_STATUS_NO_MEMORY;
375 status = ntvfs_map_async_setup(ntvfs, req,
376 io, io2,
377 (second_stage_t)ntvfs_map_open_finish);
378 if (!NT_STATUS_IS_OK(status)) {
379 return status;
382 io2->generic.level = RAW_OPEN_GENERIC;
384 switch (io->generic.level) {
385 case RAW_OPEN_OPENX:
386 status = map_openx_open(io->openx.in.flags,
387 io->openx.in.open_mode,
388 io->openx.in.open_func,
389 io->openx.in.fname,
390 io2);
391 if (!NT_STATUS_IS_OK(status)) {
392 goto done;
395 io2->generic.in.file_attr = io->openx.in.file_attrs;
396 io2->generic.in.fname = io->openx.in.fname;
398 status = ntvfs->ops->open(ntvfs, req, io2);
399 break;
402 case RAW_OPEN_OPEN:
403 status = map_openx_open(0,
404 io->openold.in.open_mode,
405 OPENX_OPEN_FUNC_OPEN,
406 io->openold.in.fname,
407 io2);
408 if (!NT_STATUS_IS_OK(status)) {
409 goto done;
412 io2->generic.in.file_attr = io->openold.in.search_attrs;
413 io2->generic.in.fname = io->openold.in.fname;
415 status = ntvfs->ops->open(ntvfs, req, io2);
416 break;
418 case RAW_OPEN_T2OPEN:
419 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
421 if (io->t2open.in.open_func == 0) {
422 status = NT_STATUS_OBJECT_NAME_COLLISION;
423 goto done;
426 status = map_openx_open(io->t2open.in.flags,
427 io->t2open.in.open_mode,
428 io->t2open.in.open_func,
429 io->t2open.in.fname,
430 io2);
431 if (!NT_STATUS_IS_OK(status)) {
432 goto done;
435 io2->generic.in.file_attr = io->t2open.in.file_attrs;
436 io2->generic.in.fname = io->t2open.in.fname;
437 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
438 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
439 io2->generic.in.ea_list->eas = io->t2open.in.eas;
441 status = ntvfs->ops->open(ntvfs, req, io2);
442 break;
444 case RAW_OPEN_MKNEW:
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_CREATE;
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);
455 break;
457 case RAW_OPEN_CREATE:
458 io2->generic.in.file_attr = io->mknew.in.attrib;
459 io2->generic.in.fname = io->mknew.in.fname;
460 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
461 io2->generic.in.access_mask =
462 SEC_RIGHTS_FILE_READ |
463 SEC_RIGHTS_FILE_WRITE;
464 io2->generic.in.share_access =
465 NTCREATEX_SHARE_ACCESS_READ |
466 NTCREATEX_SHARE_ACCESS_WRITE;
467 status = ntvfs->ops->open(ntvfs, req, io2);
468 break;
470 case RAW_OPEN_CTEMP:
471 io2->generic.in.file_attr = io->ctemp.in.attrib;
472 io2->generic.in.fname =
473 talloc_asprintf(io2, "%s\\SRV%s",
474 io->ctemp.in.directory,
475 generate_random_str_list(io2, 5, "0123456789"));
476 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
477 io2->generic.in.access_mask =
478 SEC_RIGHTS_FILE_READ |
479 SEC_RIGHTS_FILE_WRITE;
480 io2->generic.in.share_access =
481 NTCREATEX_SHARE_ACCESS_READ |
482 NTCREATEX_SHARE_ACCESS_WRITE;
483 status = ntvfs->ops->open(ntvfs, req, io2);
484 break;
485 case RAW_OPEN_SMB2:
486 io2->generic.in.flags = 0;
487 io2->generic.in.root_fid = 0;
488 io2->generic.in.access_mask = io->smb2.in.access_mask;
489 io2->generic.in.alloc_size = 0;
490 io2->generic.in.file_attr = io->smb2.in.file_attr;
491 io2->generic.in.share_access = io->smb2.in.share_access;
492 io2->generic.in.open_disposition= io->smb2.in.open_disposition;
493 io2->generic.in.create_options = io->smb2.in.create_options;
494 io2->generic.in.impersonation = io->smb2.in.impersonation;
495 io2->generic.in.security_flags = 0;
496 io2->generic.in.fname = io->smb2.in.fname;
497 io2->generic.in.sec_desc = NULL;
498 io2->generic.in.ea_list = NULL;
499 status = ntvfs->ops->open(ntvfs, req, io2);
500 break;
502 default:
503 status = NT_STATUS_INVALID_LEVEL;
504 break;
506 done:
507 return ntvfs_map_async_finish(req, status);
512 NTVFS fsinfo generic to any mapper
514 _PUBLIC_ NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
515 struct ntvfs_request *req,
516 union smb_fsinfo *fs)
518 NTSTATUS status;
519 union smb_fsinfo *fs2;
521 fs2 = talloc(req, union smb_fsinfo);
522 if (fs2 == NULL) {
523 return NT_STATUS_NO_MEMORY;
526 if (fs->generic.level == RAW_QFS_GENERIC) {
527 return NT_STATUS_INVALID_LEVEL;
530 /* only used by the simple backend, which doesn't do async */
531 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
533 /* ask the backend for the generic info */
534 fs2->generic.level = RAW_QFS_GENERIC;
536 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
537 if (!NT_STATUS_IS_OK(status)) {
538 return status;
541 /* and convert it to the required level */
542 switch (fs->generic.level) {
543 case RAW_QFS_GENERIC:
544 return NT_STATUS_INVALID_LEVEL;
546 case RAW_QFS_DSKATTR: {
547 /* map from generic to DSKATTR */
548 uint_t bpunit = 64;
550 /* we need to scale the sizes to fit */
551 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
552 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
553 break;
557 fs->dskattr.out.blocks_per_unit = bpunit;
558 fs->dskattr.out.block_size = 512;
559 fs->dskattr.out.units_total =
560 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
561 fs->dskattr.out.units_free =
562 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
564 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
565 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
566 fs->dskattr.out.blocks_per_unit = 64;
567 fs->dskattr.out.units_total = 0xFFFF;
568 fs->dskattr.out.units_free = 0xFFFF;
570 return NT_STATUS_OK;
573 case RAW_QFS_ALLOCATION:
574 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
575 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
576 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
577 fs->allocation.out.sectors_per_unit = 1;
578 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
579 return NT_STATUS_OK;
581 case RAW_QFS_VOLUME:
582 fs->volume.out.serial_number = fs2->generic.out.serial_number;
583 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
584 return NT_STATUS_OK;
586 case RAW_QFS_VOLUME_INFO:
587 case RAW_QFS_VOLUME_INFORMATION:
588 fs->volume_info.out.create_time = fs2->generic.out.create_time;
589 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
590 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
591 return NT_STATUS_OK;
593 case RAW_QFS_SIZE_INFO:
594 case RAW_QFS_SIZE_INFORMATION:
595 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
596 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
597 fs->size_info.out.sectors_per_unit = 1;
598 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
599 return NT_STATUS_OK;
601 case RAW_QFS_DEVICE_INFO:
602 case RAW_QFS_DEVICE_INFORMATION:
603 fs->device_info.out.device_type = fs2->generic.out.device_type;
604 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
605 return NT_STATUS_OK;
607 case RAW_QFS_ATTRIBUTE_INFO:
608 case RAW_QFS_ATTRIBUTE_INFORMATION:
609 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
610 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
611 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
612 return NT_STATUS_OK;
614 case RAW_QFS_QUOTA_INFORMATION:
615 ZERO_STRUCT(fs->quota_information.out.unknown);
616 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
617 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
618 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
619 return NT_STATUS_OK;
621 case RAW_QFS_FULL_SIZE_INFORMATION:
622 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
623 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
624 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
625 fs->full_size_information.out.sectors_per_unit = 1;
626 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
627 return NT_STATUS_OK;
629 case RAW_QFS_OBJECTID_INFORMATION:
630 fs->objectid_information.out.guid = fs2->generic.out.guid;
631 ZERO_STRUCT(fs->objectid_information.out.unknown);
632 return NT_STATUS_OK;
636 return NT_STATUS_INVALID_LEVEL;
641 NTVFS fileinfo generic to any mapper
643 _PUBLIC_ NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
644 union smb_fileinfo *info,
645 union smb_fileinfo *info2)
647 int i;
648 /* and convert it to the required level using results in info2 */
649 switch (info->generic.level) {
650 case RAW_FILEINFO_GENERIC:
651 return NT_STATUS_INVALID_LEVEL;
652 case RAW_FILEINFO_GETATTR:
653 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
654 info->getattr.out.size = info2->generic.out.size;
655 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
656 return NT_STATUS_OK;
658 case RAW_FILEINFO_GETATTRE:
659 info->getattre.out.attrib = info2->generic.out.attrib;
660 info->getattre.out.size = info2->generic.out.size;
661 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
662 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
663 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
664 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
665 return NT_STATUS_OK;
667 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
668 info->network_open_information.out.create_time = info2->generic.out.create_time;
669 info->network_open_information.out.access_time = info2->generic.out.access_time;
670 info->network_open_information.out.write_time = info2->generic.out.write_time;
671 info->network_open_information.out.change_time = info2->generic.out.change_time;
672 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
673 info->network_open_information.out.size = info2->generic.out.size;
674 info->network_open_information.out.attrib = info2->generic.out.attrib;
675 return NT_STATUS_OK;
677 case RAW_FILEINFO_ALL_INFO:
678 case RAW_FILEINFO_ALL_INFORMATION:
679 info->all_info.out.create_time = info2->generic.out.create_time;
680 info->all_info.out.access_time = info2->generic.out.access_time;
681 info->all_info.out.write_time = info2->generic.out.write_time;
682 info->all_info.out.change_time = info2->generic.out.change_time;
683 info->all_info.out.attrib = info2->generic.out.attrib;
684 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
685 info->all_info.out.size = info2->generic.out.size;
686 info->all_info.out.nlink = info2->generic.out.nlink;
687 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
688 info->all_info.out.directory = info2->generic.out.directory;
689 info->all_info.out.ea_size = info2->generic.out.ea_size;
690 info->all_info.out.fname.s = info2->generic.out.fname.s;
691 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
692 return NT_STATUS_OK;
694 case RAW_FILEINFO_BASIC_INFO:
695 case RAW_FILEINFO_BASIC_INFORMATION:
696 info->basic_info.out.create_time = info2->generic.out.create_time;
697 info->basic_info.out.access_time = info2->generic.out.access_time;
698 info->basic_info.out.write_time = info2->generic.out.write_time;
699 info->basic_info.out.change_time = info2->generic.out.change_time;
700 info->basic_info.out.attrib = info2->generic.out.attrib;
701 return NT_STATUS_OK;
703 case RAW_FILEINFO_STANDARD:
704 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
705 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
706 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
707 info->standard.out.size = info2->generic.out.size;
708 info->standard.out.alloc_size = info2->generic.out.alloc_size;
709 info->standard.out.attrib = info2->generic.out.attrib;
710 return NT_STATUS_OK;
712 case RAW_FILEINFO_EA_SIZE:
713 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
714 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
715 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
716 info->ea_size.out.size = info2->generic.out.size;
717 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
718 info->ea_size.out.attrib = info2->generic.out.attrib;
719 info->ea_size.out.ea_size = info2->generic.out.ea_size;
720 return NT_STATUS_OK;
722 case RAW_FILEINFO_STANDARD_INFO:
723 case RAW_FILEINFO_STANDARD_INFORMATION:
724 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
725 info->standard_info.out.size = info2->generic.out.size;
726 info->standard_info.out.nlink = info2->generic.out.nlink;
727 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
728 info->standard_info.out.directory = info2->generic.out.directory;
729 return NT_STATUS_OK;
731 case RAW_FILEINFO_INTERNAL_INFORMATION:
732 info->internal_information.out.file_id = info2->generic.out.file_id;
733 return NT_STATUS_OK;
735 case RAW_FILEINFO_EA_INFO:
736 case RAW_FILEINFO_EA_INFORMATION:
737 info->ea_info.out.ea_size = info2->generic.out.ea_size;
738 return NT_STATUS_OK;
740 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
741 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
742 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
743 return NT_STATUS_OK;
745 case RAW_FILEINFO_STREAM_INFO:
746 case RAW_FILEINFO_STREAM_INFORMATION:
747 info->stream_info.out.num_streams = info2->generic.out.num_streams;
748 if (info->stream_info.out.num_streams > 0) {
749 info->stream_info.out.streams =
750 talloc_array(mem_ctx,
751 struct stream_struct,
752 info->stream_info.out.num_streams);
753 if (!info->stream_info.out.streams) {
754 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
755 info->stream_info.out.num_streams));
756 return NT_STATUS_NO_MEMORY;
758 for (i=0; i < info->stream_info.out.num_streams; i++) {
759 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
760 info->stream_info.out.streams[i].stream_name.s =
761 talloc_strdup(info->stream_info.out.streams,
762 info2->generic.out.streams[i].stream_name.s);
763 if (!info->stream_info.out.streams[i].stream_name.s) {
764 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
765 return NT_STATUS_NO_MEMORY;
769 return NT_STATUS_OK;
771 case RAW_FILEINFO_NAME_INFO:
772 case RAW_FILEINFO_NAME_INFORMATION:
773 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
774 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
775 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
776 return NT_STATUS_OK;
778 case RAW_FILEINFO_ALT_NAME_INFO:
779 case RAW_FILEINFO_ALT_NAME_INFORMATION:
780 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
781 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
782 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
783 return NT_STATUS_OK;
785 case RAW_FILEINFO_POSITION_INFORMATION:
786 info->position_information.out.position = info2->generic.out.position;
787 return NT_STATUS_OK;
789 case RAW_FILEINFO_ALL_EAS:
790 info->all_eas.out.num_eas = info2->generic.out.num_eas;
791 if (info->all_eas.out.num_eas > 0) {
792 info->all_eas.out.eas = talloc_array(mem_ctx,
793 struct ea_struct,
794 info->all_eas.out.num_eas);
795 if (!info->all_eas.out.eas) {
796 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
797 info->all_eas.out.num_eas));
798 return NT_STATUS_NO_MEMORY;
800 for (i = 0; i < info->all_eas.out.num_eas; i++) {
801 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
802 info->all_eas.out.eas[i].name.s =
803 talloc_strdup(info->all_eas.out.eas,
804 info2->generic.out.eas[i].name.s);
805 if (!info->all_eas.out.eas[i].name.s) {
806 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
807 return NT_STATUS_NO_MEMORY;
809 info->all_eas.out.eas[i].value.data =
810 talloc_memdup(info->all_eas.out.eas,
811 info2->generic.out.eas[i].value.data,
812 info2->generic.out.eas[i].value.length);
813 if (!info->all_eas.out.eas[i].value.data) {
814 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
815 return NT_STATUS_NO_MEMORY;
819 return NT_STATUS_OK;
821 case RAW_FILEINFO_IS_NAME_VALID:
822 return NT_STATUS_OK;
824 case RAW_FILEINFO_COMPRESSION_INFO:
825 case RAW_FILEINFO_COMPRESSION_INFORMATION:
826 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
827 info->compression_info.out.format = info2->generic.out.format;
828 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
829 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
830 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
831 return NT_STATUS_OK;
833 case RAW_FILEINFO_ACCESS_INFORMATION:
834 info->access_information.out.access_flags = info2->generic.out.access_flags;
835 return NT_STATUS_OK;
837 case RAW_FILEINFO_MODE_INFORMATION:
838 info->mode_information.out.mode = info2->generic.out.mode;
839 return NT_STATUS_OK;
841 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
842 info->alignment_information.out.alignment_requirement =
843 info2->generic.out.alignment_requirement;
844 return NT_STATUS_OK;
845 #if 0
846 case RAW_FILEINFO_UNIX_BASIC:
847 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
848 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
849 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
850 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
851 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
852 info->unix_basic_info.out.uid = info2->generic.out.uid;
853 info->unix_basic_info.out.gid = info2->generic.out.gid;
854 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
855 info->unix_basic_info.out.dev_major = info2->generic.out.device;
856 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
857 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
858 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
859 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
860 return NT_STATUS_OK;
862 case RAW_FILEINFO_UNIX_LINK:
863 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
864 return NT_STATUS_OK;
865 #endif
868 return NT_STATUS_INVALID_LEVEL;
872 NTVFS fileinfo generic to any mapper
874 _PUBLIC_ NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
875 struct ntvfs_request *req,
876 union smb_fileinfo *info)
878 NTSTATUS status;
879 union smb_fileinfo *info2;
881 info2 = talloc(req, union smb_fileinfo);
882 if (info2 == NULL) {
883 return NT_STATUS_NO_MEMORY;
886 if (info->generic.level == RAW_FILEINFO_GENERIC) {
887 return NT_STATUS_INVALID_LEVEL;
890 /* ask the backend for the generic info */
891 info2->generic.level = RAW_FILEINFO_GENERIC;
892 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
894 /* only used by the simple backend, which doesn't do async */
895 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
897 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
898 if (!NT_STATUS_IS_OK(status)) {
899 return status;
901 return ntvfs_map_fileinfo(req, info, info2);
905 NTVFS pathinfo generic to any mapper
907 _PUBLIC_ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
908 struct ntvfs_request *req,
909 union smb_fileinfo *info)
911 NTSTATUS status;
912 union smb_fileinfo *info2;
914 info2 = talloc(req, union smb_fileinfo);
915 if (info2 == NULL) {
916 return NT_STATUS_NO_MEMORY;
919 if (info->generic.level == RAW_FILEINFO_GENERIC) {
920 return NT_STATUS_INVALID_LEVEL;
923 /* ask the backend for the generic info */
924 info2->generic.level = RAW_FILEINFO_GENERIC;
925 info2->generic.in.file.path = info->generic.in.file.path;
927 /* only used by the simple backend, which doesn't do async */
928 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
930 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
931 if (!NT_STATUS_IS_OK(status)) {
932 return status;
934 return ntvfs_map_fileinfo(req, info, info2);
939 NTVFS lock generic to any mapper
941 _PUBLIC_ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
942 struct ntvfs_request *req,
943 union smb_lock *lck)
945 union smb_lock *lck2;
946 struct smb_lock_entry *locks;
948 lck2 = talloc(req, union smb_lock);
949 if (lck2 == NULL) {
950 return NT_STATUS_NO_MEMORY;
953 locks = talloc_array(lck2, struct smb_lock_entry, 1);
954 if (locks == NULL) {
955 return NT_STATUS_NO_MEMORY;
958 switch (lck->generic.level) {
959 case RAW_LOCK_LOCKX:
960 return NT_STATUS_INVALID_LEVEL;
962 case RAW_LOCK_LOCK:
963 lck2->generic.in.ulock_cnt = 0;
964 lck2->generic.in.lock_cnt = 1;
965 break;
967 case RAW_LOCK_UNLOCK:
968 lck2->generic.in.ulock_cnt = 1;
969 lck2->generic.in.lock_cnt = 0;
970 break;
972 case RAW_LOCK_SMB2:
973 return NT_STATUS_INVALID_LEVEL;
976 lck2->generic.level = RAW_LOCK_GENERIC;
977 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
978 lck2->generic.in.mode = 0;
979 lck2->generic.in.timeout = 0;
980 lck2->generic.in.locks = locks;
981 locks->pid = req->smbpid;
982 locks->offset = lck->lock.in.offset;
983 locks->count = lck->lock.in.count;
986 * we don't need to call ntvfs_map_async_setup() here,
987 * as lock() doesn't have any output fields
990 return ntvfs->ops->lock(ntvfs, req, lck2);
995 NTVFS write generic to any mapper
997 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
998 struct ntvfs_request *req,
999 union smb_write *wr,
1000 union smb_write *wr2,
1001 NTSTATUS status)
1003 union smb_lock *lck;
1004 union smb_close *cl;
1005 uint_t state;
1007 if (NT_STATUS_IS_ERR(status)) {
1008 return status;
1011 switch (wr->generic.level) {
1012 case RAW_WRITE_WRITE:
1013 wr->write.out.nwritten = wr2->generic.out.nwritten;
1014 break;
1016 case RAW_WRITE_WRITEUNLOCK:
1017 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1019 lck = talloc(wr2, union smb_lock);
1020 if (lck == NULL) {
1021 return NT_STATUS_NO_MEMORY;
1024 lck->unlock.level = RAW_LOCK_UNLOCK;
1025 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1026 lck->unlock.in.count = wr->writeunlock.in.count;
1027 lck->unlock.in.offset = wr->writeunlock.in.offset;
1029 if (lck->unlock.in.count != 0) {
1030 /* do the lock sync for now */
1031 state = req->async_states->state;
1032 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1033 status = ntvfs->ops->lock(ntvfs, req, lck);
1034 req->async_states->state = state;
1036 break;
1038 case RAW_WRITE_WRITECLOSE:
1039 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1041 cl = talloc(wr2, union smb_close);
1042 if (cl == NULL) {
1043 return NT_STATUS_NO_MEMORY;
1046 cl->close.level = RAW_CLOSE_CLOSE;
1047 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1048 cl->close.in.write_time = wr->writeclose.in.mtime;
1050 if (wr2->generic.in.count != 0) {
1051 /* do the close sync for now */
1052 state = req->async_states->state;
1053 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1054 status = ntvfs->ops->close(ntvfs, req, cl);
1055 req->async_states->state = state;
1057 break;
1059 case RAW_WRITE_SPLWRITE:
1060 break;
1062 case RAW_WRITE_SMB2:
1063 wr->smb2.out._pad = 0;
1064 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1065 wr->smb2.out.unknown1 = 0;
1066 break;
1068 default:
1069 return NT_STATUS_INVALID_LEVEL;
1072 return status;
1077 NTVFS write generic to any mapper
1079 _PUBLIC_ NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1080 struct ntvfs_request *req,
1081 union smb_write *wr)
1083 union smb_write *wr2;
1084 NTSTATUS status;
1086 wr2 = talloc(req, union smb_write);
1087 if (wr2 == NULL) {
1088 return NT_STATUS_NO_MEMORY;
1091 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1092 (second_stage_t)ntvfs_map_write_finish);
1093 if (!NT_STATUS_IS_OK(status)) {
1094 return status;
1097 wr2->writex.level = RAW_WRITE_GENERIC;
1099 switch (wr->generic.level) {
1100 case RAW_WRITE_WRITEX:
1101 status = NT_STATUS_INVALID_LEVEL;
1102 break;
1104 case RAW_WRITE_WRITE:
1105 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1106 wr2->writex.in.offset = wr->write.in.offset;
1107 wr2->writex.in.wmode = 0;
1108 wr2->writex.in.remaining = wr->write.in.remaining;
1109 wr2->writex.in.count = wr->write.in.count;
1110 wr2->writex.in.data = wr->write.in.data;
1111 status = ntvfs->ops->write(ntvfs, req, wr2);
1112 break;
1114 case RAW_WRITE_WRITEUNLOCK:
1115 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1116 wr2->writex.in.offset = wr->writeunlock.in.offset;
1117 wr2->writex.in.wmode = 0;
1118 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1119 wr2->writex.in.count = wr->writeunlock.in.count;
1120 wr2->writex.in.data = wr->writeunlock.in.data;
1121 status = ntvfs->ops->write(ntvfs, req, wr2);
1122 break;
1124 case RAW_WRITE_WRITECLOSE:
1125 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1126 wr2->writex.in.offset = wr->writeclose.in.offset;
1127 wr2->writex.in.wmode = 0;
1128 wr2->writex.in.remaining = 0;
1129 wr2->writex.in.count = wr->writeclose.in.count;
1130 wr2->writex.in.data = wr->writeclose.in.data;
1131 status = ntvfs->ops->write(ntvfs, req, wr2);
1132 break;
1134 case RAW_WRITE_SPLWRITE:
1135 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1136 wr2->writex.in.offset = 0;
1137 wr2->writex.in.wmode = 0;
1138 wr2->writex.in.remaining = 0;
1139 wr2->writex.in.count = wr->splwrite.in.count;
1140 wr2->writex.in.data = wr->splwrite.in.data;
1141 status = ntvfs->ops->write(ntvfs, req, wr2);
1142 break;
1144 case RAW_WRITE_SMB2:
1145 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1146 wr2->writex.in.offset = wr->smb2.in.offset;
1147 wr2->writex.in.wmode = 0;
1148 wr2->writex.in.remaining = 0;
1149 wr2->writex.in.count = wr->smb2.in.data.length;
1150 wr2->writex.in.data = wr->smb2.in.data.data;
1151 status = ntvfs->ops->write(ntvfs, req, wr2);
1154 return ntvfs_map_async_finish(req, status);
1159 NTVFS read generic to any mapper - finish the out mapping
1161 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1162 struct ntvfs_request *req,
1163 union smb_read *rd,
1164 union smb_read *rd2,
1165 NTSTATUS status)
1167 switch (rd->generic.level) {
1168 case RAW_READ_READ:
1169 rd->read.out.nread = rd2->generic.out.nread;
1170 break;
1171 case RAW_READ_READBRAW:
1172 rd->readbraw.out.nread = rd2->generic.out.nread;
1173 break;
1174 case RAW_READ_LOCKREAD:
1175 rd->lockread.out.nread = rd2->generic.out.nread;
1176 break;
1177 case RAW_READ_SMB2:
1178 rd->smb2.out.data.length= rd2->generic.out.nread;
1179 rd->smb2.out.unknown1 = 0;
1180 break;
1181 default:
1182 return NT_STATUS_INVALID_LEVEL;
1185 return status;
1189 NTVFS read* to readx mapper
1191 _PUBLIC_ NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1192 struct ntvfs_request *req,
1193 union smb_read *rd)
1195 union smb_read *rd2;
1196 union smb_lock *lck;
1197 NTSTATUS status;
1198 uint_t state;
1200 rd2 = talloc(req, union smb_read);
1201 if (rd2 == NULL) {
1202 return NT_STATUS_NO_MEMORY;
1205 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1206 (second_stage_t)ntvfs_map_read_finish);
1207 if (!NT_STATUS_IS_OK(status)) {
1208 return status;
1211 rd2->readx.level = RAW_READ_READX;
1212 rd2->readx.in.read_for_execute = False;
1214 switch (rd->generic.level) {
1215 case RAW_READ_READX:
1216 status = NT_STATUS_INVALID_LEVEL;
1217 break;
1219 case RAW_READ_READ:
1220 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1221 rd2->readx.in.offset = rd->read.in.offset;
1222 rd2->readx.in.mincnt = rd->read.in.count;
1223 rd2->readx.in.maxcnt = rd->read.in.count;
1224 rd2->readx.in.remaining = rd->read.in.remaining;
1225 rd2->readx.out.data = rd->read.out.data;
1226 status = ntvfs->ops->read(ntvfs, req, rd2);
1227 break;
1229 case RAW_READ_READBRAW:
1230 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1231 rd2->readx.in.offset = rd->readbraw.in.offset;
1232 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1233 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1234 rd2->readx.in.remaining = 0;
1235 rd2->readx.out.data = rd->readbraw.out.data;
1236 status = ntvfs->ops->read(ntvfs, req, rd2);
1237 break;
1239 case RAW_READ_LOCKREAD:
1240 /* do the initial lock sync for now */
1241 state = req->async_states->state;
1242 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1244 lck = talloc(rd2, union smb_lock);
1245 if (lck == NULL) {
1246 status = NT_STATUS_NO_MEMORY;
1247 goto done;
1249 lck->lock.level = RAW_LOCK_LOCK;
1250 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1251 lck->lock.in.count = rd->lockread.in.count;
1252 lck->lock.in.offset = rd->lockread.in.offset;
1253 status = ntvfs->ops->lock(ntvfs, req, lck);
1254 req->async_states->state = state;
1256 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1257 rd2->readx.in.offset = rd->lockread.in.offset;
1258 rd2->readx.in.mincnt = rd->lockread.in.count;
1259 rd2->readx.in.maxcnt = rd->lockread.in.count;
1260 rd2->readx.in.remaining = rd->lockread.in.remaining;
1261 rd2->readx.out.data = rd->lockread.out.data;
1263 if (NT_STATUS_IS_OK(status)) {
1264 status = ntvfs->ops->read(ntvfs, req, rd2);
1266 break;
1268 case RAW_READ_SMB2:
1269 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1270 rd2->readx.in.offset = rd->smb2.in.offset;
1271 rd2->readx.in.mincnt = rd->smb2.in.length;
1272 rd2->readx.in.maxcnt = rd->smb2.in.length;
1273 rd2->readx.in.remaining = 0;
1274 rd2->readx.out.data = rd->smb2.out.data.data;
1275 status = ntvfs->ops->read(ntvfs, req, rd2);
1276 break;
1279 done:
1280 return ntvfs_map_async_finish(req, status);
1285 NTVFS close generic to any mapper
1287 _PUBLIC_ NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1288 struct ntvfs_request *req,
1289 union smb_close *cl)
1291 union smb_close *cl2;
1293 cl2 = talloc(req, union smb_close);
1294 if (cl2 == NULL) {
1295 return NT_STATUS_NO_MEMORY;
1298 switch (cl->generic.level) {
1299 case RAW_CLOSE_CLOSE:
1300 return NT_STATUS_INVALID_LEVEL;
1302 case RAW_CLOSE_SPLCLOSE:
1303 cl2->generic.level = RAW_CLOSE_CLOSE;
1304 cl2->generic.in.file.ntvfs = cl->splclose.in.file.ntvfs;
1305 cl2->generic.in.write_time = 0;
1306 break;
1308 case RAW_CLOSE_SMB2:
1309 cl2->generic.level = RAW_CLOSE_CLOSE;
1310 cl2->generic.in.file.ntvfs = cl->smb2.in.file.ntvfs;
1311 cl2->generic.in.write_time = 0;
1312 /* SMB2 Close has output parameter, but we just zero them */
1313 ZERO_STRUCT(cl->smb2.out);
1314 break;
1318 * we don't need to call ntvfs_map_async_setup() here,
1319 * as close() doesn't have any output fields
1322 return ntvfs->ops->close(ntvfs, req, cl2);
1326 NTVFS notify generic to any mapper
1328 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1329 struct ntvfs_request *req,
1330 union smb_notify *nt,
1331 union smb_notify *nt2,
1332 NTSTATUS status)
1334 NT_STATUS_NOT_OK_RETURN(status);
1336 switch (nt->nttrans.level) {
1337 case RAW_NOTIFY_SMB2:
1338 if (nt2->nttrans.out.num_changes == 0) {
1339 return STATUS_NOTIFY_ENUM_DIR;
1341 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1342 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1343 break;
1345 default:
1346 return NT_STATUS_INVALID_LEVEL;
1349 return status;
1354 NTVFS notify generic to any mapper
1356 _PUBLIC_ NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1357 struct ntvfs_request *req,
1358 union smb_notify *nt)
1360 union smb_notify *nt2;
1361 NTSTATUS status;
1363 nt2 = talloc(req, union smb_notify);
1364 NT_STATUS_HAVE_NO_MEMORY(nt2);
1366 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1367 (second_stage_t)ntvfs_map_notify_finish);
1368 NT_STATUS_NOT_OK_RETURN(status);
1370 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1372 switch (nt->nttrans.level) {
1373 case RAW_NOTIFY_NTTRANS:
1374 status = NT_STATUS_INVALID_LEVEL;
1375 break;
1377 case RAW_NOTIFY_SMB2:
1378 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1379 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1380 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1381 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1382 status = ntvfs->ops->notify(ntvfs, req, nt2);
1383 break;
1386 return ntvfs_map_async_finish(req, status);