Fix PReg write support.
[Samba/eduardoll.git] / source4 / ntvfs / ntvfs_generic.c
blobe1a86c07c0468d112f12a291f5c7982032a768fe
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 3 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, see <http://www.gnu.org/licenses/>.
22 this implements mappings between info levels for NTVFS backend calls
24 the idea is that each of these functions implements one of the NTVFS
25 backend calls in terms of the 'generic' call. All backends that use
26 these functions must supply the generic call, but can if it wants to
27 also implement other levels if the need arises
29 this allows backend writers to only implement one variant of each
30 call unless they need fine grained control of the calls.
33 #include "includes.h"
34 #include "ntvfs/ntvfs.h"
35 #include "libcli/smb2/smb2.h"
36 #include "libcli/smb2/smb2_calls.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.ntvfs = io2->generic.out.file.ntvfs;
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.ntvfs = io2->generic.out.file.ntvfs;
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.ntvfs = io2->generic.out.file.ntvfs;
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.ntvfs= io2->generic.out.file.ntvfs;
199 write_time = io->mknew.in.write_time;
200 break;
202 case RAW_OPEN_CTEMP:
203 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
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 case RAW_OPEN_SMB2:
210 io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs;
211 io->smb2.out.oplock_level = 0;
212 io->smb2.out.create_action = io2->generic.out.create_action;
213 io->smb2.out.create_time = io2->generic.out.create_time;
214 io->smb2.out.access_time = io2->generic.out.access_time;
215 io->smb2.out.write_time = io2->generic.out.write_time;
216 io->smb2.out.change_time = io2->generic.out.change_time;
217 io->smb2.out.alloc_size = io2->generic.out.alloc_size;
218 io->smb2.out.size = io2->generic.out.size;
219 io->smb2.out.file_attr = io2->generic.out.attrib;
220 io->smb2.out.reserved2 = 0;
221 io->smb2.out.blob = data_blob(NULL, 0);
222 break;
224 default:
225 return NT_STATUS_INVALID_LEVEL;
228 /* doing a secondary request async is more trouble than its
229 worth */
230 state = req->async_states->state;
231 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
233 if (write_time != 0) {
234 sf = talloc(req, union smb_setfileinfo);
235 NT_STATUS_HAVE_NO_MEMORY(sf);
236 sf->generic.level = RAW_SFILEINFO_STANDARD;
237 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
238 sf->standard.in.create_time = 0;
239 sf->standard.in.write_time = write_time;
240 sf->standard.in.access_time = 0;
241 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
244 if (set_size != 0) {
245 sf = talloc(req, union smb_setfileinfo);
246 NT_STATUS_HAVE_NO_MEMORY(sf);
247 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
248 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
249 sf->end_of_file_info.in.size = set_size;
250 status = ntvfs->ops->setfileinfo(ntvfs, req, sf);
251 if (NT_STATUS_IS_OK(status)) {
252 io->openx.out.size = io->openx.in.size;
256 req->async_states->state = state;
258 return NT_STATUS_OK;
262 the core of the mapping between openx style parameters and ntcreatex
263 parameters
265 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
266 uint16_t open_func, const char *fname,
267 union smb_open *io2)
269 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
270 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
272 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
273 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
276 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
277 case OPENX_MODE_ACCESS_READ:
278 case OPENX_MODE_ACCESS_EXEC:
279 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
280 break;
281 case OPENX_MODE_ACCESS_WRITE:
282 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
283 break;
284 case OPENX_MODE_ACCESS_RDWR:
285 case OPENX_MODE_ACCESS_FCB:
286 io2->generic.in.access_mask =
287 SEC_RIGHTS_FILE_READ |
288 SEC_RIGHTS_FILE_WRITE;
289 break;
290 default:
291 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
294 switch (open_mode & OPENX_MODE_DENY_MASK) {
295 case OPENX_MODE_DENY_READ:
296 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
297 break;
298 case OPENX_MODE_DENY_WRITE:
299 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
300 break;
301 case OPENX_MODE_DENY_ALL:
302 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
303 break;
304 case OPENX_MODE_DENY_NONE:
305 io2->generic.in.share_access =
306 NTCREATEX_SHARE_ACCESS_READ |
307 NTCREATEX_SHARE_ACCESS_WRITE;
308 break;
309 case OPENX_MODE_DENY_DOS:
310 /* DENY_DOS is quite strange - it depends on the filename! */
311 io2->generic.in.create_options |=
312 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
313 if (is_exe_filename(fname)) {
314 io2->generic.in.share_access =
315 NTCREATEX_SHARE_ACCESS_READ |
316 NTCREATEX_SHARE_ACCESS_WRITE;
317 } else {
318 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
319 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
320 } else {
321 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
324 break;
325 case OPENX_MODE_DENY_FCB:
326 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
327 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
328 break;
329 default:
330 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
333 switch (open_func) {
334 case (OPENX_OPEN_FUNC_OPEN):
335 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
336 break;
337 case (OPENX_OPEN_FUNC_TRUNC):
338 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
339 break;
340 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
341 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
342 break;
343 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
344 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
345 break;
346 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
347 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
348 break;
349 default:
350 /* this one is very strange */
351 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
352 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
353 break;
355 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
358 return NT_STATUS_OK;
362 NTVFS open generic to any mapper
364 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
365 struct ntvfs_request *req,
366 union smb_open *io)
368 NTSTATUS status;
369 union smb_open *io2;
371 io2 = talloc_zero(req, union smb_open);
372 if (io2 == NULL) {
373 return NT_STATUS_NO_MEMORY;
376 status = ntvfs_map_async_setup(ntvfs, req,
377 io, io2,
378 (second_stage_t)ntvfs_map_open_finish);
379 if (!NT_STATUS_IS_OK(status)) {
380 return status;
383 io2->generic.level = RAW_OPEN_GENERIC;
385 switch (io->generic.level) {
386 case RAW_OPEN_OPENX:
387 status = map_openx_open(io->openx.in.flags,
388 io->openx.in.open_mode,
389 io->openx.in.open_func,
390 io->openx.in.fname,
391 io2);
392 if (!NT_STATUS_IS_OK(status)) {
393 goto done;
396 io2->generic.in.file_attr = io->openx.in.file_attrs;
397 io2->generic.in.fname = io->openx.in.fname;
399 status = ntvfs->ops->open(ntvfs, req, io2);
400 break;
403 case RAW_OPEN_OPEN:
404 status = map_openx_open(0,
405 io->openold.in.open_mode,
406 OPENX_OPEN_FUNC_OPEN,
407 io->openold.in.fname,
408 io2);
409 if (!NT_STATUS_IS_OK(status)) {
410 goto done;
413 io2->generic.in.file_attr = io->openold.in.search_attrs;
414 io2->generic.in.fname = io->openold.in.fname;
416 status = ntvfs->ops->open(ntvfs, req, io2);
417 break;
419 case RAW_OPEN_T2OPEN:
420 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
422 if (io->t2open.in.open_func == 0) {
423 status = NT_STATUS_OBJECT_NAME_COLLISION;
424 goto done;
427 status = map_openx_open(io->t2open.in.flags,
428 io->t2open.in.open_mode,
429 io->t2open.in.open_func,
430 io->t2open.in.fname,
431 io2);
432 if (!NT_STATUS_IS_OK(status)) {
433 goto done;
436 io2->generic.in.file_attr = io->t2open.in.file_attrs;
437 io2->generic.in.fname = io->t2open.in.fname;
438 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
439 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
440 io2->generic.in.ea_list->eas = io->t2open.in.eas;
442 status = ntvfs->ops->open(ntvfs, req, io2);
443 break;
445 case RAW_OPEN_MKNEW:
446 io2->generic.in.file_attr = io->mknew.in.attrib;
447 io2->generic.in.fname = io->mknew.in.fname;
448 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
449 io2->generic.in.access_mask =
450 SEC_RIGHTS_FILE_READ |
451 SEC_RIGHTS_FILE_WRITE;
452 io2->generic.in.share_access =
453 NTCREATEX_SHARE_ACCESS_READ |
454 NTCREATEX_SHARE_ACCESS_WRITE;
455 status = ntvfs->ops->open(ntvfs, req, io2);
456 break;
458 case RAW_OPEN_CREATE:
459 io2->generic.in.file_attr = io->mknew.in.attrib;
460 io2->generic.in.fname = io->mknew.in.fname;
461 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
462 io2->generic.in.access_mask =
463 SEC_RIGHTS_FILE_READ |
464 SEC_RIGHTS_FILE_WRITE;
465 io2->generic.in.share_access =
466 NTCREATEX_SHARE_ACCESS_READ |
467 NTCREATEX_SHARE_ACCESS_WRITE;
468 status = ntvfs->ops->open(ntvfs, req, io2);
469 break;
471 case RAW_OPEN_CTEMP:
472 io2->generic.in.file_attr = io->ctemp.in.attrib;
473 io2->generic.in.fname =
474 talloc_asprintf(io2, "%s\\SRV%s",
475 io->ctemp.in.directory,
476 generate_random_str_list(io2, 5, "0123456789"));
477 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
478 io2->generic.in.access_mask =
479 SEC_RIGHTS_FILE_READ |
480 SEC_RIGHTS_FILE_WRITE;
481 io2->generic.in.share_access =
482 NTCREATEX_SHARE_ACCESS_READ |
483 NTCREATEX_SHARE_ACCESS_WRITE;
484 status = ntvfs->ops->open(ntvfs, req, io2);
485 break;
486 case RAW_OPEN_SMB2:
487 io2->generic.in.flags = 0;
488 io2->generic.in.root_fid = 0;
489 io2->generic.in.access_mask = io->smb2.in.desired_access;
490 io2->generic.in.alloc_size = 0;
491 io2->generic.in.file_attr = io->smb2.in.file_attributes;
492 io2->generic.in.share_access = io->smb2.in.share_access;
493 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
494 io2->generic.in.create_options = io->smb2.in.create_options;
495 io2->generic.in.impersonation = io->smb2.in.impersonation_level;
496 io2->generic.in.security_flags = 0;
497 io2->generic.in.fname = io->smb2.in.fname;
498 io2->generic.in.sec_desc = NULL;
499 io2->generic.in.ea_list = NULL;
500 status = ntvfs->ops->open(ntvfs, req, io2);
501 break;
503 default:
504 status = NT_STATUS_INVALID_LEVEL;
505 break;
507 done:
508 return ntvfs_map_async_finish(req, status);
513 NTVFS fsinfo generic to any mapper
515 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
516 struct ntvfs_request *req,
517 union smb_fsinfo *fs)
519 NTSTATUS status;
520 union smb_fsinfo *fs2;
522 fs2 = talloc(req, union smb_fsinfo);
523 if (fs2 == NULL) {
524 return NT_STATUS_NO_MEMORY;
527 if (fs->generic.level == RAW_QFS_GENERIC) {
528 return NT_STATUS_INVALID_LEVEL;
531 /* only used by the simple backend, which doesn't do async */
532 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
534 /* ask the backend for the generic info */
535 fs2->generic.level = RAW_QFS_GENERIC;
537 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
538 if (!NT_STATUS_IS_OK(status)) {
539 return status;
542 /* and convert it to the required level */
543 switch (fs->generic.level) {
544 case RAW_QFS_GENERIC:
545 return NT_STATUS_INVALID_LEVEL;
547 case RAW_QFS_DSKATTR: {
548 /* map from generic to DSKATTR */
549 uint_t bpunit = 64;
551 /* we need to scale the sizes to fit */
552 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
553 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
554 break;
558 fs->dskattr.out.blocks_per_unit = bpunit;
559 fs->dskattr.out.block_size = 512;
560 fs->dskattr.out.units_total =
561 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
562 fs->dskattr.out.units_free =
563 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
565 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
566 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
567 fs->dskattr.out.blocks_per_unit = 64;
568 fs->dskattr.out.units_total = 0xFFFF;
569 fs->dskattr.out.units_free = 0xFFFF;
571 return NT_STATUS_OK;
574 case RAW_QFS_ALLOCATION:
575 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
576 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
577 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
578 fs->allocation.out.sectors_per_unit = 1;
579 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
580 return NT_STATUS_OK;
582 case RAW_QFS_VOLUME:
583 fs->volume.out.serial_number = fs2->generic.out.serial_number;
584 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
585 return NT_STATUS_OK;
587 case RAW_QFS_VOLUME_INFO:
588 case RAW_QFS_VOLUME_INFORMATION:
589 fs->volume_info.out.create_time = fs2->generic.out.create_time;
590 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
591 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
592 return NT_STATUS_OK;
594 case RAW_QFS_SIZE_INFO:
595 case RAW_QFS_SIZE_INFORMATION:
596 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
597 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
598 fs->size_info.out.sectors_per_unit = 1;
599 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
600 return NT_STATUS_OK;
602 case RAW_QFS_DEVICE_INFO:
603 case RAW_QFS_DEVICE_INFORMATION:
604 fs->device_info.out.device_type = fs2->generic.out.device_type;
605 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
606 return NT_STATUS_OK;
608 case RAW_QFS_ATTRIBUTE_INFO:
609 case RAW_QFS_ATTRIBUTE_INFORMATION:
610 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
611 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
612 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
613 return NT_STATUS_OK;
615 case RAW_QFS_QUOTA_INFORMATION:
616 ZERO_STRUCT(fs->quota_information.out.unknown);
617 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
618 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
619 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
620 return NT_STATUS_OK;
622 case RAW_QFS_FULL_SIZE_INFORMATION:
623 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
624 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
625 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
626 fs->full_size_information.out.sectors_per_unit = 1;
627 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
628 return NT_STATUS_OK;
630 case RAW_QFS_OBJECTID_INFORMATION:
631 fs->objectid_information.out.guid = fs2->generic.out.guid;
632 ZERO_STRUCT(fs->objectid_information.out.unknown);
633 return NT_STATUS_OK;
637 return NT_STATUS_INVALID_LEVEL;
642 NTVFS fileinfo generic to any mapper
644 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
645 union smb_fileinfo *info,
646 union smb_fileinfo *info2)
648 int i;
649 /* and convert it to the required level using results in info2 */
650 switch (info->generic.level) {
651 case RAW_FILEINFO_GENERIC:
652 return NT_STATUS_INVALID_LEVEL;
653 case RAW_FILEINFO_GETATTR:
654 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
655 info->getattr.out.size = info2->generic.out.size;
656 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
657 return NT_STATUS_OK;
659 case RAW_FILEINFO_GETATTRE:
660 info->getattre.out.attrib = info2->generic.out.attrib;
661 info->getattre.out.size = info2->generic.out.size;
662 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
663 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
664 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
665 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
666 return NT_STATUS_OK;
668 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
669 info->network_open_information.out.create_time = info2->generic.out.create_time;
670 info->network_open_information.out.access_time = info2->generic.out.access_time;
671 info->network_open_information.out.write_time = info2->generic.out.write_time;
672 info->network_open_information.out.change_time = info2->generic.out.change_time;
673 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
674 info->network_open_information.out.size = info2->generic.out.size;
675 info->network_open_information.out.attrib = info2->generic.out.attrib;
676 return NT_STATUS_OK;
678 case RAW_FILEINFO_ALL_INFO:
679 case RAW_FILEINFO_ALL_INFORMATION:
680 info->all_info.out.create_time = info2->generic.out.create_time;
681 info->all_info.out.access_time = info2->generic.out.access_time;
682 info->all_info.out.write_time = info2->generic.out.write_time;
683 info->all_info.out.change_time = info2->generic.out.change_time;
684 info->all_info.out.attrib = info2->generic.out.attrib;
685 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
686 info->all_info.out.size = info2->generic.out.size;
687 info->all_info.out.nlink = info2->generic.out.nlink;
688 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
689 info->all_info.out.directory = info2->generic.out.directory;
690 info->all_info.out.ea_size = info2->generic.out.ea_size;
691 info->all_info.out.fname.s = info2->generic.out.fname.s;
692 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
693 return NT_STATUS_OK;
695 case RAW_FILEINFO_BASIC_INFO:
696 case RAW_FILEINFO_BASIC_INFORMATION:
697 info->basic_info.out.create_time = info2->generic.out.create_time;
698 info->basic_info.out.access_time = info2->generic.out.access_time;
699 info->basic_info.out.write_time = info2->generic.out.write_time;
700 info->basic_info.out.change_time = info2->generic.out.change_time;
701 info->basic_info.out.attrib = info2->generic.out.attrib;
702 return NT_STATUS_OK;
704 case RAW_FILEINFO_STANDARD:
705 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
706 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
707 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
708 info->standard.out.size = info2->generic.out.size;
709 info->standard.out.alloc_size = info2->generic.out.alloc_size;
710 info->standard.out.attrib = info2->generic.out.attrib;
711 return NT_STATUS_OK;
713 case RAW_FILEINFO_EA_SIZE:
714 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
715 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
716 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
717 info->ea_size.out.size = info2->generic.out.size;
718 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
719 info->ea_size.out.attrib = info2->generic.out.attrib;
720 info->ea_size.out.ea_size = info2->generic.out.ea_size;
721 return NT_STATUS_OK;
723 case RAW_FILEINFO_STANDARD_INFO:
724 case RAW_FILEINFO_STANDARD_INFORMATION:
725 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
726 info->standard_info.out.size = info2->generic.out.size;
727 info->standard_info.out.nlink = info2->generic.out.nlink;
728 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
729 info->standard_info.out.directory = info2->generic.out.directory;
730 return NT_STATUS_OK;
732 case RAW_FILEINFO_INTERNAL_INFORMATION:
733 info->internal_information.out.file_id = info2->generic.out.file_id;
734 return NT_STATUS_OK;
736 case RAW_FILEINFO_EA_INFO:
737 case RAW_FILEINFO_EA_INFORMATION:
738 info->ea_info.out.ea_size = info2->generic.out.ea_size;
739 return NT_STATUS_OK;
741 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
742 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
743 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
744 return NT_STATUS_OK;
746 case RAW_FILEINFO_STREAM_INFO:
747 case RAW_FILEINFO_STREAM_INFORMATION:
748 info->stream_info.out.num_streams = info2->generic.out.num_streams;
749 if (info->stream_info.out.num_streams > 0) {
750 info->stream_info.out.streams =
751 talloc_array(mem_ctx,
752 struct stream_struct,
753 info->stream_info.out.num_streams);
754 if (!info->stream_info.out.streams) {
755 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
756 info->stream_info.out.num_streams));
757 return NT_STATUS_NO_MEMORY;
759 for (i=0; i < info->stream_info.out.num_streams; i++) {
760 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
761 info->stream_info.out.streams[i].stream_name.s =
762 talloc_strdup(info->stream_info.out.streams,
763 info2->generic.out.streams[i].stream_name.s);
764 if (!info->stream_info.out.streams[i].stream_name.s) {
765 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
766 return NT_STATUS_NO_MEMORY;
770 return NT_STATUS_OK;
772 case RAW_FILEINFO_NAME_INFO:
773 case RAW_FILEINFO_NAME_INFORMATION:
774 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
775 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
776 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
777 return NT_STATUS_OK;
779 case RAW_FILEINFO_ALT_NAME_INFO:
780 case RAW_FILEINFO_ALT_NAME_INFORMATION:
781 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
782 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
783 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
784 return NT_STATUS_OK;
786 case RAW_FILEINFO_POSITION_INFORMATION:
787 info->position_information.out.position = info2->generic.out.position;
788 return NT_STATUS_OK;
790 case RAW_FILEINFO_ALL_EAS:
791 info->all_eas.out.num_eas = info2->generic.out.num_eas;
792 if (info->all_eas.out.num_eas > 0) {
793 info->all_eas.out.eas = talloc_array(mem_ctx,
794 struct ea_struct,
795 info->all_eas.out.num_eas);
796 if (!info->all_eas.out.eas) {
797 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
798 info->all_eas.out.num_eas));
799 return NT_STATUS_NO_MEMORY;
801 for (i = 0; i < info->all_eas.out.num_eas; i++) {
802 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
803 info->all_eas.out.eas[i].name.s =
804 talloc_strdup(info->all_eas.out.eas,
805 info2->generic.out.eas[i].name.s);
806 if (!info->all_eas.out.eas[i].name.s) {
807 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
808 return NT_STATUS_NO_MEMORY;
810 info->all_eas.out.eas[i].value.data =
811 talloc_memdup(info->all_eas.out.eas,
812 info2->generic.out.eas[i].value.data,
813 info2->generic.out.eas[i].value.length);
814 if (!info->all_eas.out.eas[i].value.data) {
815 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
816 return NT_STATUS_NO_MEMORY;
820 return NT_STATUS_OK;
822 case RAW_FILEINFO_IS_NAME_VALID:
823 return NT_STATUS_OK;
825 case RAW_FILEINFO_COMPRESSION_INFO:
826 case RAW_FILEINFO_COMPRESSION_INFORMATION:
827 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
828 info->compression_info.out.format = info2->generic.out.format;
829 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
830 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
831 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
832 return NT_STATUS_OK;
834 case RAW_FILEINFO_ACCESS_INFORMATION:
835 info->access_information.out.access_flags = info2->generic.out.access_flags;
836 return NT_STATUS_OK;
838 case RAW_FILEINFO_MODE_INFORMATION:
839 info->mode_information.out.mode = info2->generic.out.mode;
840 return NT_STATUS_OK;
842 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
843 info->alignment_information.out.alignment_requirement =
844 info2->generic.out.alignment_requirement;
845 return NT_STATUS_OK;
846 #if 0
847 case RAW_FILEINFO_UNIX_BASIC:
848 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
849 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
850 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
851 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
852 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
853 info->unix_basic_info.out.uid = info2->generic.out.uid;
854 info->unix_basic_info.out.gid = info2->generic.out.gid;
855 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
856 info->unix_basic_info.out.dev_major = info2->generic.out.device;
857 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
858 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
859 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
860 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
861 return NT_STATUS_OK;
863 case RAW_FILEINFO_UNIX_LINK:
864 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
865 return NT_STATUS_OK;
866 #endif
869 return NT_STATUS_INVALID_LEVEL;
873 NTVFS fileinfo generic to any mapper
875 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
876 struct ntvfs_request *req,
877 union smb_fileinfo *info)
879 NTSTATUS status;
880 union smb_fileinfo *info2;
882 info2 = talloc(req, union smb_fileinfo);
883 if (info2 == NULL) {
884 return NT_STATUS_NO_MEMORY;
887 if (info->generic.level == RAW_FILEINFO_GENERIC) {
888 return NT_STATUS_INVALID_LEVEL;
891 /* ask the backend for the generic info */
892 info2->generic.level = RAW_FILEINFO_GENERIC;
893 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
895 /* only used by the simple backend, which doesn't do async */
896 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
898 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
899 if (!NT_STATUS_IS_OK(status)) {
900 return status;
902 return ntvfs_map_fileinfo(req, info, info2);
906 NTVFS pathinfo generic to any mapper
908 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
909 struct ntvfs_request *req,
910 union smb_fileinfo *info)
912 NTSTATUS status;
913 union smb_fileinfo *info2;
915 info2 = talloc(req, union smb_fileinfo);
916 if (info2 == NULL) {
917 return NT_STATUS_NO_MEMORY;
920 if (info->generic.level == RAW_FILEINFO_GENERIC) {
921 return NT_STATUS_INVALID_LEVEL;
924 /* ask the backend for the generic info */
925 info2->generic.level = RAW_FILEINFO_GENERIC;
926 info2->generic.in.file.path = info->generic.in.file.path;
928 /* only used by the simple backend, which doesn't do async */
929 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
931 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
932 if (!NT_STATUS_IS_OK(status)) {
933 return status;
935 return ntvfs_map_fileinfo(req, info, info2);
940 NTVFS lock generic to any mapper
942 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
943 struct ntvfs_request *req,
944 union smb_lock *lck)
946 union smb_lock *lck2;
947 struct smb_lock_entry *locks;
949 lck2 = talloc(req, union smb_lock);
950 if (lck2 == NULL) {
951 return NT_STATUS_NO_MEMORY;
954 locks = talloc_array(lck2, struct smb_lock_entry, 1);
955 if (locks == NULL) {
956 return NT_STATUS_NO_MEMORY;
959 switch (lck->generic.level) {
960 case RAW_LOCK_LOCKX:
961 return NT_STATUS_INVALID_LEVEL;
963 case RAW_LOCK_LOCK:
964 lck2->generic.level = RAW_LOCK_GENERIC;
965 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
966 lck2->generic.in.mode = 0;
967 lck2->generic.in.timeout = 0;
968 lck2->generic.in.ulock_cnt = 0;
969 lck2->generic.in.lock_cnt = 1;
970 lck2->generic.in.locks = locks;
971 locks->pid = req->smbpid;
972 locks->offset = lck->lock.in.offset;
973 locks->count = lck->lock.in.count;
974 break;
976 case RAW_LOCK_UNLOCK:
977 lck2->generic.level = RAW_LOCK_GENERIC;
978 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
979 lck2->generic.in.mode = 0;
980 lck2->generic.in.timeout = 0;
981 lck2->generic.in.ulock_cnt = 1;
982 lck2->generic.in.lock_cnt = 0;
983 lck2->generic.in.locks = locks;
984 locks->pid = req->smbpid;
985 locks->offset = lck->unlock.in.offset;
986 locks->count = lck->unlock.in.count;
987 break;
989 case RAW_LOCK_SMB2:
990 if (lck->smb2.in.unknown1 != 1) {
991 return NT_STATUS_INVALID_PARAMETER;
994 lck2->generic.level = RAW_LOCK_GENERIC;
995 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
996 if (lck->smb2.in.flags & SMB2_LOCK_FLAG_EXCLUSIV) {
997 lck2->generic.in.mode = 0;
998 } else {
999 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1001 if (lck->smb2.in.flags & SMB2_LOCK_FLAG_NO_PENDING) {
1002 lck2->generic.in.timeout = 0;
1003 } else {
1004 lck2->generic.in.timeout = UINT32_MAX;
1006 if (lck->smb2.in.flags & SMB2_LOCK_FLAG_UNLOCK) {
1007 lck2->generic.in.ulock_cnt = 1;
1008 lck2->generic.in.lock_cnt = 0;
1009 } else {
1010 lck2->generic.in.ulock_cnt = 0;
1011 lck2->generic.in.lock_cnt = 1;
1013 lck2->generic.in.locks = locks;
1014 locks->pid = 0;
1015 locks->offset = lck->smb2.in.offset;
1016 locks->count = lck->smb2.in.count;
1018 /* initialize output value */
1019 lck->smb2.out.unknown1 = 0;
1020 break;
1024 * we don't need to call ntvfs_map_async_setup() here,
1025 * as lock() doesn't have any output fields
1028 return ntvfs->ops->lock(ntvfs, req, lck2);
1033 NTVFS write generic to any mapper
1035 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1036 struct ntvfs_request *req,
1037 union smb_write *wr,
1038 union smb_write *wr2,
1039 NTSTATUS status)
1041 union smb_lock *lck;
1042 union smb_close *cl;
1043 uint_t state;
1045 if (NT_STATUS_IS_ERR(status)) {
1046 return status;
1049 switch (wr->generic.level) {
1050 case RAW_WRITE_WRITE:
1051 wr->write.out.nwritten = wr2->generic.out.nwritten;
1052 break;
1054 case RAW_WRITE_WRITEUNLOCK:
1055 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1057 lck = talloc(wr2, union smb_lock);
1058 if (lck == NULL) {
1059 return NT_STATUS_NO_MEMORY;
1062 lck->unlock.level = RAW_LOCK_UNLOCK;
1063 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1064 lck->unlock.in.count = wr->writeunlock.in.count;
1065 lck->unlock.in.offset = wr->writeunlock.in.offset;
1067 if (lck->unlock.in.count != 0) {
1068 /* do the lock sync for now */
1069 state = req->async_states->state;
1070 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1071 status = ntvfs->ops->lock(ntvfs, req, lck);
1072 req->async_states->state = state;
1074 break;
1076 case RAW_WRITE_WRITECLOSE:
1077 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1079 cl = talloc(wr2, union smb_close);
1080 if (cl == NULL) {
1081 return NT_STATUS_NO_MEMORY;
1084 cl->close.level = RAW_CLOSE_CLOSE;
1085 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1086 cl->close.in.write_time = wr->writeclose.in.mtime;
1088 if (wr2->generic.in.count != 0) {
1089 /* do the close sync for now */
1090 state = req->async_states->state;
1091 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1092 status = ntvfs->ops->close(ntvfs, req, cl);
1093 req->async_states->state = state;
1095 break;
1097 case RAW_WRITE_SPLWRITE:
1098 break;
1100 case RAW_WRITE_SMB2:
1101 wr->smb2.out._pad = 0;
1102 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1103 wr->smb2.out.unknown1 = 0;
1104 break;
1106 default:
1107 return NT_STATUS_INVALID_LEVEL;
1110 return status;
1115 NTVFS write generic to any mapper
1117 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1118 struct ntvfs_request *req,
1119 union smb_write *wr)
1121 union smb_write *wr2;
1122 NTSTATUS status;
1124 wr2 = talloc(req, union smb_write);
1125 if (wr2 == NULL) {
1126 return NT_STATUS_NO_MEMORY;
1129 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1130 (second_stage_t)ntvfs_map_write_finish);
1131 if (!NT_STATUS_IS_OK(status)) {
1132 return status;
1135 wr2->writex.level = RAW_WRITE_GENERIC;
1137 switch (wr->generic.level) {
1138 case RAW_WRITE_WRITEX:
1139 status = NT_STATUS_INVALID_LEVEL;
1140 break;
1142 case RAW_WRITE_WRITE:
1143 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1144 wr2->writex.in.offset = wr->write.in.offset;
1145 wr2->writex.in.wmode = 0;
1146 wr2->writex.in.remaining = wr->write.in.remaining;
1147 wr2->writex.in.count = wr->write.in.count;
1148 wr2->writex.in.data = wr->write.in.data;
1149 status = ntvfs->ops->write(ntvfs, req, wr2);
1150 break;
1152 case RAW_WRITE_WRITEUNLOCK:
1153 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1154 wr2->writex.in.offset = wr->writeunlock.in.offset;
1155 wr2->writex.in.wmode = 0;
1156 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1157 wr2->writex.in.count = wr->writeunlock.in.count;
1158 wr2->writex.in.data = wr->writeunlock.in.data;
1159 status = ntvfs->ops->write(ntvfs, req, wr2);
1160 break;
1162 case RAW_WRITE_WRITECLOSE:
1163 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1164 wr2->writex.in.offset = wr->writeclose.in.offset;
1165 wr2->writex.in.wmode = 0;
1166 wr2->writex.in.remaining = 0;
1167 wr2->writex.in.count = wr->writeclose.in.count;
1168 wr2->writex.in.data = wr->writeclose.in.data;
1169 status = ntvfs->ops->write(ntvfs, req, wr2);
1170 break;
1172 case RAW_WRITE_SPLWRITE:
1173 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1174 wr2->writex.in.offset = 0;
1175 wr2->writex.in.wmode = 0;
1176 wr2->writex.in.remaining = 0;
1177 wr2->writex.in.count = wr->splwrite.in.count;
1178 wr2->writex.in.data = wr->splwrite.in.data;
1179 status = ntvfs->ops->write(ntvfs, req, wr2);
1180 break;
1182 case RAW_WRITE_SMB2:
1183 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1184 wr2->writex.in.offset = wr->smb2.in.offset;
1185 wr2->writex.in.wmode = 0;
1186 wr2->writex.in.remaining = 0;
1187 wr2->writex.in.count = wr->smb2.in.data.length;
1188 wr2->writex.in.data = wr->smb2.in.data.data;
1189 status = ntvfs->ops->write(ntvfs, req, wr2);
1192 return ntvfs_map_async_finish(req, status);
1197 NTVFS read generic to any mapper - finish the out mapping
1199 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1200 struct ntvfs_request *req,
1201 union smb_read *rd,
1202 union smb_read *rd2,
1203 NTSTATUS status)
1205 switch (rd->generic.level) {
1206 case RAW_READ_READ:
1207 rd->read.out.nread = rd2->generic.out.nread;
1208 break;
1209 case RAW_READ_READBRAW:
1210 rd->readbraw.out.nread = rd2->generic.out.nread;
1211 break;
1212 case RAW_READ_LOCKREAD:
1213 rd->lockread.out.nread = rd2->generic.out.nread;
1214 break;
1215 case RAW_READ_SMB2:
1216 rd->smb2.out.data.length= rd2->generic.out.nread;
1217 rd->smb2.out.unknown1 = 0;
1218 break;
1219 default:
1220 return NT_STATUS_INVALID_LEVEL;
1223 return status;
1227 NTVFS read* to readx mapper
1229 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1230 struct ntvfs_request *req,
1231 union smb_read *rd)
1233 union smb_read *rd2;
1234 union smb_lock *lck;
1235 NTSTATUS status;
1236 uint_t state;
1238 rd2 = talloc(req, union smb_read);
1239 if (rd2 == NULL) {
1240 return NT_STATUS_NO_MEMORY;
1243 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1244 (second_stage_t)ntvfs_map_read_finish);
1245 if (!NT_STATUS_IS_OK(status)) {
1246 return status;
1249 rd2->readx.level = RAW_READ_READX;
1250 rd2->readx.in.read_for_execute = false;
1252 switch (rd->generic.level) {
1253 case RAW_READ_READX:
1254 status = NT_STATUS_INVALID_LEVEL;
1255 break;
1257 case RAW_READ_READ:
1258 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1259 rd2->readx.in.offset = rd->read.in.offset;
1260 rd2->readx.in.mincnt = rd->read.in.count;
1261 rd2->readx.in.maxcnt = rd->read.in.count;
1262 rd2->readx.in.remaining = rd->read.in.remaining;
1263 rd2->readx.out.data = rd->read.out.data;
1264 status = ntvfs->ops->read(ntvfs, req, rd2);
1265 break;
1267 case RAW_READ_READBRAW:
1268 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1269 rd2->readx.in.offset = rd->readbraw.in.offset;
1270 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1271 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1272 rd2->readx.in.remaining = 0;
1273 rd2->readx.out.data = rd->readbraw.out.data;
1274 status = ntvfs->ops->read(ntvfs, req, rd2);
1275 break;
1277 case RAW_READ_LOCKREAD:
1278 /* do the initial lock sync for now */
1279 state = req->async_states->state;
1280 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1282 lck = talloc(rd2, union smb_lock);
1283 if (lck == NULL) {
1284 status = NT_STATUS_NO_MEMORY;
1285 goto done;
1287 lck->lock.level = RAW_LOCK_LOCK;
1288 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1289 lck->lock.in.count = rd->lockread.in.count;
1290 lck->lock.in.offset = rd->lockread.in.offset;
1291 status = ntvfs->ops->lock(ntvfs, req, lck);
1292 req->async_states->state = state;
1294 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1295 rd2->readx.in.offset = rd->lockread.in.offset;
1296 rd2->readx.in.mincnt = rd->lockread.in.count;
1297 rd2->readx.in.maxcnt = rd->lockread.in.count;
1298 rd2->readx.in.remaining = rd->lockread.in.remaining;
1299 rd2->readx.out.data = rd->lockread.out.data;
1301 if (NT_STATUS_IS_OK(status)) {
1302 status = ntvfs->ops->read(ntvfs, req, rd2);
1304 break;
1306 case RAW_READ_SMB2:
1307 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1308 rd2->readx.in.offset = rd->smb2.in.offset;
1309 rd2->readx.in.mincnt = rd->smb2.in.length;
1310 rd2->readx.in.maxcnt = rd->smb2.in.length;
1311 rd2->readx.in.remaining = 0;
1312 rd2->readx.out.data = rd->smb2.out.data.data;
1313 status = ntvfs->ops->read(ntvfs, req, rd2);
1314 break;
1317 done:
1318 return ntvfs_map_async_finish(req, status);
1323 NTVFS close generic to any mapper
1325 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1326 struct ntvfs_request *req,
1327 union smb_close *cl)
1329 union smb_close *cl2;
1331 cl2 = talloc(req, union smb_close);
1332 if (cl2 == NULL) {
1333 return NT_STATUS_NO_MEMORY;
1336 switch (cl->generic.level) {
1337 case RAW_CLOSE_CLOSE:
1338 return NT_STATUS_INVALID_LEVEL;
1340 case RAW_CLOSE_SPLCLOSE:
1341 cl2->generic.level = RAW_CLOSE_CLOSE;
1342 cl2->generic.in.file.ntvfs = cl->splclose.in.file.ntvfs;
1343 cl2->generic.in.write_time = 0;
1344 break;
1346 case RAW_CLOSE_SMB2:
1347 cl2->generic.level = RAW_CLOSE_CLOSE;
1348 cl2->generic.in.file.ntvfs = cl->smb2.in.file.ntvfs;
1349 cl2->generic.in.write_time = 0;
1350 /* SMB2 Close has output parameter, but we just zero them */
1351 ZERO_STRUCT(cl->smb2.out);
1352 break;
1356 * we don't need to call ntvfs_map_async_setup() here,
1357 * as close() doesn't have any output fields
1360 return ntvfs->ops->close(ntvfs, req, cl2);
1364 NTVFS notify generic to any mapper
1366 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1367 struct ntvfs_request *req,
1368 union smb_notify *nt,
1369 union smb_notify *nt2,
1370 NTSTATUS status)
1372 NT_STATUS_NOT_OK_RETURN(status);
1374 switch (nt->nttrans.level) {
1375 case RAW_NOTIFY_SMB2:
1376 if (nt2->nttrans.out.num_changes == 0) {
1377 return STATUS_NOTIFY_ENUM_DIR;
1379 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1380 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1381 break;
1383 default:
1384 return NT_STATUS_INVALID_LEVEL;
1387 return status;
1392 NTVFS notify generic to any mapper
1394 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1395 struct ntvfs_request *req,
1396 union smb_notify *nt)
1398 union smb_notify *nt2;
1399 NTSTATUS status;
1401 nt2 = talloc(req, union smb_notify);
1402 NT_STATUS_HAVE_NO_MEMORY(nt2);
1404 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1405 (second_stage_t)ntvfs_map_notify_finish);
1406 NT_STATUS_NOT_OK_RETURN(status);
1408 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1410 switch (nt->nttrans.level) {
1411 case RAW_NOTIFY_NTTRANS:
1412 status = NT_STATUS_INVALID_LEVEL;
1413 break;
1415 case RAW_NOTIFY_SMB2:
1416 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1417 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1418 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1419 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1420 status = ntvfs->ops->notify(ntvfs, req, nt2);
1421 break;
1424 return ntvfs_map_async_finish(req, status);