s4:torture:smb2: in the durable-v2-reopen1 test, use a minimal request
[Samba/gebeck_regimport.git] / source4 / ntvfs / ntvfs_generic.c
blob0854aa30d30cf06235b39953602d164b1f672d4c
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 = talloc_get_type(req->async_states->private_data,
60 struct ntvfs_map_async);
62 ntvfs_async_state_pop(req);
64 /* call the _finish function setup in ntvfs_map_async_setup() */
65 req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
67 /* call the send function from the next module up */
68 req->async_states->send_fn(req);
72 prepare for calling a ntvfs backend with async support
73 io is the original call structure
74 io2 is the new call structure for the mapped call
75 fn is a second stage function for processing the out arguments
77 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
78 struct ntvfs_request *req,
79 void *io, void *io2,
80 second_stage_t fn)
82 struct ntvfs_map_async *m;
83 m = talloc(req, struct ntvfs_map_async);
84 if (m == NULL) {
85 return NT_STATUS_NO_MEMORY;
87 m->ntvfs = ntvfs;
88 m->io = io;
89 m->io2 = io2;
90 m->fn = fn;
91 return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
95 called when first stage processing is complete.
96 */
97 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
99 struct ntvfs_map_async *m;
101 /* if the backend has decided to reply in an async fashion then
102 we don't need to do any work here */
103 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
104 return status;
107 /* the backend is replying immediately. call the 2nd stage function after popping our local
108 async state */
109 m = talloc_get_type(req->async_states->private_data,
110 struct ntvfs_map_async);
112 ntvfs_async_state_pop(req);
114 return m->fn(m->ntvfs, req, m->io, m->io2, status);
118 see if a filename ends in EXE COM DLL or SYM. This is needed for the
119 DENY_DOS mapping for OpenX
121 bool is_exe_filename(const char *fname)
123 char *p;
124 p = strrchr(fname, '.');
125 if (!p) {
126 return false;
128 p++;
129 if (strcasecmp(p, "EXE") == 0 ||
130 strcasecmp(p, "COM") == 0 ||
131 strcasecmp(p, "DLL") == 0 ||
132 strcasecmp(p, "SYM") == 0) {
133 return true;
135 return false;
140 NTVFS openx to ntcreatex mapper
142 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
143 struct ntvfs_request *req,
144 union smb_open *io,
145 union smb_open *io2,
146 NTSTATUS status)
148 time_t write_time = 0;
149 uint32_t set_size = 0;
150 union smb_setfileinfo *sf;
151 unsigned int state;
153 if (!NT_STATUS_IS_OK(status)) {
154 return status;
157 switch (io->generic.level) {
158 case RAW_OPEN_OPEN:
159 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
160 io->openold.out.attrib = io2->generic.out.attrib;
161 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
162 io->openold.out.size = io2->generic.out.size;
163 io->openold.out.rmode = io->openold.in.open_mode;
164 break;
166 case RAW_OPEN_OPENX:
167 io->openx.out.file.ntvfs = io2->generic.out.file.ntvfs;
168 io->openx.out.attrib = io2->generic.out.attrib;
169 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
170 io->openx.out.size = io2->generic.out.size;
171 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
172 io->openx.out.ftype = 0;
173 io->openx.out.devstate = 0;
174 io->openx.out.action = io2->generic.out.create_action;
175 io->openx.out.unique_fid = 0;
176 io->openx.out.access_mask = SEC_STD_ALL;
177 io->openx.out.unknown = 0;
179 /* we need to extend the file to the requested size if
180 it was newly created */
181 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
182 set_size = io->openx.in.size;
184 break;
186 case RAW_OPEN_T2OPEN:
187 io->t2open.out.file.ntvfs = io2->generic.out.file.ntvfs;
188 io->t2open.out.attrib = io2->generic.out.attrib;
189 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
190 io->t2open.out.size = io2->generic.out.size;
191 io->t2open.out.access = io->t2open.in.open_mode;
192 io->t2open.out.ftype = 0;
193 io->t2open.out.devstate = 0;
194 io->t2open.out.action = io2->generic.out.create_action;
195 io->t2open.out.file_id = 0;
196 break;
198 case RAW_OPEN_MKNEW:
199 case RAW_OPEN_CREATE:
200 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
201 write_time = io->mknew.in.write_time;
202 break;
204 case RAW_OPEN_CTEMP:
205 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
206 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
207 strlen(io->ctemp.in.directory) + 1);
208 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
209 break;
211 case RAW_OPEN_SMB2:
212 ZERO_STRUCT(io->smb2.out);
213 io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs;
214 switch (io2->generic.out.oplock_level) {
215 case BATCH_OPLOCK_RETURN:
216 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
217 break;
218 case EXCLUSIVE_OPLOCK_RETURN:
219 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
220 break;
221 case LEVEL_II_OPLOCK_RETURN:
222 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
223 break;
224 default:
225 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
226 break;
228 io->smb2.out.reserved = 0;
229 io->smb2.out.create_action = io2->generic.out.create_action;
230 io->smb2.out.create_time = io2->generic.out.create_time;
231 io->smb2.out.access_time = io2->generic.out.access_time;
232 io->smb2.out.write_time = io2->generic.out.write_time;
233 io->smb2.out.change_time = io2->generic.out.change_time;
234 io->smb2.out.alloc_size = io2->generic.out.alloc_size;
235 io->smb2.out.size = io2->generic.out.size;
236 io->smb2.out.file_attr = io2->generic.out.attrib;
237 io->smb2.out.reserved2 = 0;
238 io->smb2.out.maximal_access = io2->generic.out.maximal_access;
239 break;
241 default:
242 return NT_STATUS_INVALID_LEVEL;
245 /* doing a secondary request async is more trouble than its
246 worth */
247 state = req->async_states->state;
248 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
250 if (write_time != 0) {
251 sf = talloc(req, union smb_setfileinfo);
252 NT_STATUS_HAVE_NO_MEMORY(sf);
253 sf->generic.level = RAW_SFILEINFO_STANDARD;
254 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
255 sf->standard.in.create_time = 0;
256 sf->standard.in.write_time = write_time;
257 sf->standard.in.access_time = 0;
258 status = ntvfs->ops->setfileinfo_fn(ntvfs, req, sf);
261 if (set_size != 0) {
262 sf = talloc(req, union smb_setfileinfo);
263 NT_STATUS_HAVE_NO_MEMORY(sf);
264 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
265 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
266 sf->end_of_file_info.in.size = set_size;
267 status = ntvfs->ops->setfileinfo_fn(ntvfs, req, sf);
268 if (NT_STATUS_IS_OK(status)) {
269 io->openx.out.size = io->openx.in.size;
273 req->async_states->state = state;
275 return NT_STATUS_OK;
279 the core of the mapping between openx style parameters and ntcreatex
280 parameters
282 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
283 uint16_t open_func, const char *fname,
284 union smb_open *io2)
286 io2->generic.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
287 io2->generic.in.private_flags = 0;
289 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
290 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
292 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
293 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
296 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
297 case OPENX_MODE_ACCESS_READ:
298 case OPENX_MODE_ACCESS_EXEC:
299 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
300 break;
301 case OPENX_MODE_ACCESS_WRITE:
302 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
303 break;
304 case OPENX_MODE_ACCESS_RDWR:
305 case OPENX_MODE_ACCESS_FCB:
306 io2->generic.in.access_mask =
307 SEC_RIGHTS_FILE_READ |
308 SEC_RIGHTS_FILE_WRITE;
309 break;
310 default:
311 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
314 switch (open_mode & OPENX_MODE_DENY_MASK) {
315 case OPENX_MODE_DENY_READ:
316 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
317 break;
318 case OPENX_MODE_DENY_WRITE:
319 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
320 break;
321 case OPENX_MODE_DENY_ALL:
322 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
323 break;
324 case OPENX_MODE_DENY_NONE:
325 io2->generic.in.share_access =
326 NTCREATEX_SHARE_ACCESS_READ |
327 NTCREATEX_SHARE_ACCESS_WRITE;
328 break;
329 case OPENX_MODE_DENY_DOS:
330 /* DENY_DOS is quite strange - it depends on the filename! */
331 io2->generic.in.private_flags |=
332 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
333 if (is_exe_filename(fname)) {
334 io2->generic.in.share_access =
335 NTCREATEX_SHARE_ACCESS_READ |
336 NTCREATEX_SHARE_ACCESS_WRITE;
337 } else {
338 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
339 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
340 } else {
341 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
344 break;
345 case OPENX_MODE_DENY_FCB:
346 io2->generic.in.private_flags |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
347 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
348 break;
349 default:
350 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
353 switch (open_func) {
354 case (OPENX_OPEN_FUNC_OPEN):
355 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
356 break;
357 case (OPENX_OPEN_FUNC_TRUNC):
358 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
359 break;
360 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
361 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
362 break;
363 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
364 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
365 break;
366 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
367 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
368 break;
369 default:
370 /* this one is very strange */
371 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
372 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
373 break;
375 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
378 return NT_STATUS_OK;
382 NTVFS open generic to any mapper
384 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
385 struct ntvfs_request *req,
386 union smb_open *io)
388 NTSTATUS status;
389 union smb_open *io2;
391 io2 = talloc_zero(req, union smb_open);
392 if (io2 == NULL) {
393 return NT_STATUS_NO_MEMORY;
396 status = ntvfs_map_async_setup(ntvfs, req,
397 io, io2,
398 (second_stage_t)ntvfs_map_open_finish);
399 if (!NT_STATUS_IS_OK(status)) {
400 return status;
403 io2->generic.level = RAW_OPEN_GENERIC;
405 switch (io->generic.level) {
406 case RAW_OPEN_OPENX:
407 status = map_openx_open(io->openx.in.flags,
408 io->openx.in.open_mode,
409 io->openx.in.open_func,
410 io->openx.in.fname,
411 io2);
412 if (!NT_STATUS_IS_OK(status)) {
413 goto done;
416 io2->generic.in.file_attr = io->openx.in.file_attrs;
417 io2->generic.in.fname = io->openx.in.fname;
419 status = ntvfs->ops->open_fn(ntvfs, req, io2);
420 break;
423 case RAW_OPEN_OPEN:
424 status = map_openx_open(0,
425 io->openold.in.open_mode,
426 OPENX_OPEN_FUNC_OPEN,
427 io->openold.in.fname,
428 io2);
429 if (!NT_STATUS_IS_OK(status)) {
430 goto done;
433 io2->generic.in.file_attr = io->openold.in.search_attrs;
434 io2->generic.in.fname = io->openold.in.fname;
436 status = ntvfs->ops->open_fn(ntvfs, req, io2);
437 break;
439 case RAW_OPEN_T2OPEN:
440 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
442 if (io->t2open.in.open_func == 0) {
443 status = NT_STATUS_OBJECT_NAME_COLLISION;
444 goto done;
447 status = map_openx_open(io->t2open.in.flags,
448 io->t2open.in.open_mode,
449 io->t2open.in.open_func,
450 io->t2open.in.fname,
451 io2);
452 if (!NT_STATUS_IS_OK(status)) {
453 goto done;
456 io2->generic.in.file_attr = io->t2open.in.file_attrs;
457 io2->generic.in.fname = io->t2open.in.fname;
458 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
459 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
460 io2->generic.in.ea_list->eas = io->t2open.in.eas;
462 status = ntvfs->ops->open_fn(ntvfs, req, io2);
463 break;
465 case RAW_OPEN_MKNEW:
466 io2->generic.in.file_attr = io->mknew.in.attrib;
467 io2->generic.in.fname = io->mknew.in.fname;
468 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
469 io2->generic.in.access_mask =
470 SEC_RIGHTS_FILE_READ |
471 SEC_RIGHTS_FILE_WRITE;
472 io2->generic.in.share_access =
473 NTCREATEX_SHARE_ACCESS_READ |
474 NTCREATEX_SHARE_ACCESS_WRITE;
475 status = ntvfs->ops->open_fn(ntvfs, req, io2);
476 break;
478 case RAW_OPEN_CREATE:
479 io2->generic.in.file_attr = io->mknew.in.attrib;
480 io2->generic.in.fname = io->mknew.in.fname;
481 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
482 io2->generic.in.access_mask =
483 SEC_RIGHTS_FILE_READ |
484 SEC_RIGHTS_FILE_WRITE;
485 io2->generic.in.share_access =
486 NTCREATEX_SHARE_ACCESS_READ |
487 NTCREATEX_SHARE_ACCESS_WRITE;
488 status = ntvfs->ops->open_fn(ntvfs, req, io2);
489 break;
491 case RAW_OPEN_CTEMP:
492 io2->generic.in.file_attr = io->ctemp.in.attrib;
493 io2->generic.in.fname =
494 talloc_asprintf(io2, "%s\\SRV%s",
495 io->ctemp.in.directory,
496 generate_random_str_list(io2, 5, "0123456789"));
497 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
498 io2->generic.in.access_mask =
499 SEC_RIGHTS_FILE_READ |
500 SEC_RIGHTS_FILE_WRITE;
501 io2->generic.in.share_access =
502 NTCREATEX_SHARE_ACCESS_READ |
503 NTCREATEX_SHARE_ACCESS_WRITE;
504 status = ntvfs->ops->open_fn(ntvfs, req, io2);
505 break;
506 case RAW_OPEN_SMB2:
507 switch (io->smb2.in.oplock_level) {
508 case SMB2_OPLOCK_LEVEL_BATCH:
509 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
510 NTCREATEX_FLAGS_REQUEST_OPLOCK;
511 break;
512 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
513 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
514 break;
515 default:
516 io2->generic.in.flags = 0;
517 break;
519 io2->generic.in.root_fid.fnum = 0;
520 io2->generic.in.access_mask = io->smb2.in.desired_access;
521 io2->generic.in.alloc_size = io->smb2.in.alloc_size;
522 io2->generic.in.file_attr = io->smb2.in.file_attributes;
523 io2->generic.in.share_access = io->smb2.in.share_access;
524 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
525 io2->generic.in.create_options = io->smb2.in.create_options;
526 io2->generic.in.impersonation = io->smb2.in.impersonation_level;
527 io2->generic.in.security_flags = 0;
528 io2->generic.in.fname = io->smb2.in.fname;
529 io2->generic.in.sec_desc = io->smb2.in.sec_desc;
530 io2->generic.in.ea_list = &io->smb2.in.eas;
531 io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access;
532 io2->generic.in.private_flags = 0;
534 /* we don't support timewarp yet */
535 if (io->smb2.in.timewarp != 0) {
536 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
537 break;
540 /* we need to check these bits before we check the private mask */
541 if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
542 DEBUG(2,(__location__ " create_options 0x%x not supported\n",
543 io2->generic.in.create_options));
544 status = NT_STATUS_NOT_SUPPORTED;
545 break;
548 /* TODO: find out why only SMB2 ignores these */
549 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
550 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
552 status = ntvfs->ops->open_fn(ntvfs, req, io2);
553 break;
555 default:
556 status = NT_STATUS_INVALID_LEVEL;
557 break;
559 done:
560 return ntvfs_map_async_finish(req, status);
565 NTVFS any to fsinfo mapper
567 static NTSTATUS ntvfs_map_fsinfo_finish(struct ntvfs_module_context *ntvfs,
568 struct ntvfs_request *req,
569 union smb_fsinfo *fs,
570 union smb_fsinfo *fs2,
571 NTSTATUS status)
573 if (!NT_STATUS_IS_OK(status)) {
574 return status;
577 /* and convert it to the required level */
578 switch (fs->generic.level) {
579 case RAW_QFS_DSKATTR: {
580 /* map from generic to DSKATTR */
581 unsigned int bpunit = 64;
583 /* we need to scale the sizes to fit */
584 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
585 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
586 break;
590 fs->dskattr.out.blocks_per_unit = bpunit;
591 fs->dskattr.out.block_size = 512;
592 fs->dskattr.out.units_total =
593 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
594 fs->dskattr.out.units_free =
595 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
597 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
598 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
599 fs->dskattr.out.blocks_per_unit = 64;
600 fs->dskattr.out.units_total = 0xFFFF;
601 fs->dskattr.out.units_free = 0xFFFF;
603 return NT_STATUS_OK;
606 case RAW_QFS_ALLOCATION:
607 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
608 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
609 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
610 fs->allocation.out.sectors_per_unit = 1;
611 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
612 return NT_STATUS_OK;
614 case RAW_QFS_VOLUME:
615 fs->volume.out.serial_number = fs2->generic.out.serial_number;
616 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
617 return NT_STATUS_OK;
619 case RAW_QFS_VOLUME_INFO:
620 case RAW_QFS_VOLUME_INFORMATION:
621 fs->volume_info.out.create_time = fs2->generic.out.create_time;
622 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
623 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
624 return NT_STATUS_OK;
626 case RAW_QFS_SIZE_INFO:
627 case RAW_QFS_SIZE_INFORMATION:
628 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
629 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
630 fs->size_info.out.sectors_per_unit = 1;
631 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
632 return NT_STATUS_OK;
634 case RAW_QFS_DEVICE_INFO:
635 case RAW_QFS_DEVICE_INFORMATION:
636 fs->device_info.out.device_type = fs2->generic.out.device_type;
637 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
638 return NT_STATUS_OK;
640 case RAW_QFS_ATTRIBUTE_INFO:
641 case RAW_QFS_ATTRIBUTE_INFORMATION:
642 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
643 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
644 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
645 return NT_STATUS_OK;
647 case RAW_QFS_QUOTA_INFORMATION:
648 ZERO_STRUCT(fs->quota_information.out.unknown);
649 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
650 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
651 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
652 return NT_STATUS_OK;
654 case RAW_QFS_FULL_SIZE_INFORMATION:
655 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
656 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
657 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
658 fs->full_size_information.out.sectors_per_unit = 1;
659 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
660 return NT_STATUS_OK;
662 case RAW_QFS_OBJECTID_INFORMATION:
663 fs->objectid_information.out.guid = fs2->generic.out.guid;
664 ZERO_STRUCT(fs->objectid_information.out.unknown);
665 return NT_STATUS_OK;
667 case RAW_QFS_GENERIC:
668 case RAW_QFS_UNIX_INFO:
669 return NT_STATUS_INVALID_LEVEL;
672 return NT_STATUS_INVALID_LEVEL;
676 NTVFS fsinfo any to generic mapper
678 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
679 struct ntvfs_request *req,
680 union smb_fsinfo *fs)
682 NTSTATUS status;
683 union smb_fsinfo *fs2;
685 fs2 = talloc(req, union smb_fsinfo);
686 if (fs2 == NULL) {
687 return NT_STATUS_NO_MEMORY;
690 if (fs->generic.level == RAW_QFS_GENERIC) {
691 return NT_STATUS_INVALID_LEVEL;
694 status = ntvfs_map_async_setup(ntvfs, req, fs, fs2,
695 (second_stage_t)ntvfs_map_fsinfo_finish);
696 if (!NT_STATUS_IS_OK(status)) {
697 return status;
700 /* ask the backend for the generic info */
701 fs2->generic.level = RAW_QFS_GENERIC;
703 status = ntvfs->ops->fsinfo_fn(ntvfs, req, fs2);
704 return ntvfs_map_async_finish(req, status);
709 NTVFS fileinfo generic to any mapper
711 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
712 union smb_fileinfo *info,
713 union smb_fileinfo *info2)
715 int i;
716 /* and convert it to the required level using results in info2 */
717 switch (info->generic.level) {
718 case RAW_FILEINFO_GETATTR:
719 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
720 info->getattr.out.size = info2->generic.out.size;
721 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
722 return NT_STATUS_OK;
724 case RAW_FILEINFO_GETATTRE:
725 info->getattre.out.attrib = info2->generic.out.attrib;
726 info->getattre.out.size = info2->generic.out.size;
727 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
728 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
729 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
730 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
731 return NT_STATUS_OK;
733 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
734 info->network_open_information.out.create_time = info2->generic.out.create_time;
735 info->network_open_information.out.access_time = info2->generic.out.access_time;
736 info->network_open_information.out.write_time = info2->generic.out.write_time;
737 info->network_open_information.out.change_time = info2->generic.out.change_time;
738 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
739 info->network_open_information.out.size = info2->generic.out.size;
740 info->network_open_information.out.attrib = info2->generic.out.attrib;
741 return NT_STATUS_OK;
743 case RAW_FILEINFO_ALL_INFO:
744 case RAW_FILEINFO_ALL_INFORMATION:
745 info->all_info.out.create_time = info2->generic.out.create_time;
746 info->all_info.out.access_time = info2->generic.out.access_time;
747 info->all_info.out.write_time = info2->generic.out.write_time;
748 info->all_info.out.change_time = info2->generic.out.change_time;
749 info->all_info.out.attrib = info2->generic.out.attrib;
750 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
751 info->all_info.out.size = info2->generic.out.size;
752 info->all_info.out.nlink = info2->generic.out.nlink;
753 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
754 info->all_info.out.directory = info2->generic.out.directory;
755 info->all_info.out.ea_size = info2->generic.out.ea_size;
756 info->all_info.out.fname.s = info2->generic.out.fname.s;
757 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
758 return NT_STATUS_OK;
760 case RAW_FILEINFO_BASIC_INFO:
761 case RAW_FILEINFO_BASIC_INFORMATION:
762 info->basic_info.out.create_time = info2->generic.out.create_time;
763 info->basic_info.out.access_time = info2->generic.out.access_time;
764 info->basic_info.out.write_time = info2->generic.out.write_time;
765 info->basic_info.out.change_time = info2->generic.out.change_time;
766 info->basic_info.out.attrib = info2->generic.out.attrib;
767 return NT_STATUS_OK;
769 case RAW_FILEINFO_STANDARD:
770 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
771 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
772 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
773 info->standard.out.size = info2->generic.out.size;
774 info->standard.out.alloc_size = info2->generic.out.alloc_size;
775 info->standard.out.attrib = info2->generic.out.attrib;
776 return NT_STATUS_OK;
778 case RAW_FILEINFO_EA_SIZE:
779 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
780 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
781 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
782 info->ea_size.out.size = info2->generic.out.size;
783 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
784 info->ea_size.out.attrib = info2->generic.out.attrib;
785 info->ea_size.out.ea_size = info2->generic.out.ea_size;
786 return NT_STATUS_OK;
788 case RAW_FILEINFO_STANDARD_INFO:
789 case RAW_FILEINFO_STANDARD_INFORMATION:
790 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
791 info->standard_info.out.size = info2->generic.out.size;
792 info->standard_info.out.nlink = info2->generic.out.nlink;
793 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
794 info->standard_info.out.directory = info2->generic.out.directory;
795 return NT_STATUS_OK;
797 case RAW_FILEINFO_INTERNAL_INFORMATION:
798 info->internal_information.out.file_id = info2->generic.out.file_id;
799 return NT_STATUS_OK;
801 case RAW_FILEINFO_EA_INFO:
802 case RAW_FILEINFO_EA_INFORMATION:
803 info->ea_info.out.ea_size = info2->generic.out.ea_size;
804 return NT_STATUS_OK;
806 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
807 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
808 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
809 return NT_STATUS_OK;
811 case RAW_FILEINFO_STREAM_INFO:
812 case RAW_FILEINFO_STREAM_INFORMATION:
813 info->stream_info.out.num_streams = info2->generic.out.num_streams;
814 if (info->stream_info.out.num_streams > 0) {
815 info->stream_info.out.streams =
816 talloc_array(mem_ctx,
817 struct stream_struct,
818 info->stream_info.out.num_streams);
819 if (!info->stream_info.out.streams) {
820 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
821 info->stream_info.out.num_streams));
822 return NT_STATUS_NO_MEMORY;
824 for (i=0; i < info->stream_info.out.num_streams; i++) {
825 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
826 info->stream_info.out.streams[i].stream_name.s =
827 talloc_strdup(info->stream_info.out.streams,
828 info2->generic.out.streams[i].stream_name.s);
829 if (!info->stream_info.out.streams[i].stream_name.s) {
830 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
831 return NT_STATUS_NO_MEMORY;
835 return NT_STATUS_OK;
837 case RAW_FILEINFO_NAME_INFO:
838 case RAW_FILEINFO_NAME_INFORMATION:
839 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
840 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
841 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
842 return NT_STATUS_OK;
844 case RAW_FILEINFO_ALT_NAME_INFO:
845 case RAW_FILEINFO_ALT_NAME_INFORMATION:
846 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
847 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
848 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
849 return NT_STATUS_OK;
851 case RAW_FILEINFO_POSITION_INFORMATION:
852 info->position_information.out.position = info2->generic.out.position;
853 return NT_STATUS_OK;
855 case RAW_FILEINFO_ALL_EAS:
856 info->all_eas.out.num_eas = info2->generic.out.num_eas;
857 if (info->all_eas.out.num_eas > 0) {
858 info->all_eas.out.eas = talloc_array(mem_ctx,
859 struct ea_struct,
860 info->all_eas.out.num_eas);
861 if (!info->all_eas.out.eas) {
862 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
863 info->all_eas.out.num_eas));
864 return NT_STATUS_NO_MEMORY;
866 for (i = 0; i < info->all_eas.out.num_eas; i++) {
867 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
868 info->all_eas.out.eas[i].name.s =
869 talloc_strdup(info->all_eas.out.eas,
870 info2->generic.out.eas[i].name.s);
871 if (!info->all_eas.out.eas[i].name.s) {
872 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
873 return NT_STATUS_NO_MEMORY;
875 info->all_eas.out.eas[i].value.data =
876 (uint8_t *)talloc_memdup(info->all_eas.out.eas,
877 info2->generic.out.eas[i].value.data,
878 info2->generic.out.eas[i].value.length);
879 if (!info->all_eas.out.eas[i].value.data) {
880 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
881 return NT_STATUS_NO_MEMORY;
885 return NT_STATUS_OK;
887 case RAW_FILEINFO_IS_NAME_VALID:
888 return NT_STATUS_OK;
890 case RAW_FILEINFO_COMPRESSION_INFO:
891 case RAW_FILEINFO_COMPRESSION_INFORMATION:
892 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
893 info->compression_info.out.format = info2->generic.out.format;
894 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
895 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
896 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
897 return NT_STATUS_OK;
899 case RAW_FILEINFO_ACCESS_INFORMATION:
900 info->access_information.out.access_flags = info2->generic.out.access_flags;
901 return NT_STATUS_OK;
903 case RAW_FILEINFO_MODE_INFORMATION:
904 info->mode_information.out.mode = info2->generic.out.mode;
905 return NT_STATUS_OK;
907 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
908 info->alignment_information.out.alignment_requirement =
909 info2->generic.out.alignment_requirement;
910 return NT_STATUS_OK;
911 #if 0
912 case RAW_FILEINFO_UNIX_BASIC:
913 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
914 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
915 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
916 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
917 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
918 info->unix_basic_info.out.uid = info2->generic.out.uid;
919 info->unix_basic_info.out.gid = info2->generic.out.gid;
920 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
921 info->unix_basic_info.out.dev_major = info2->generic.out.device;
922 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
923 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
924 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
925 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
926 return NT_STATUS_OK;
928 case RAW_FILEINFO_UNIX_LINK:
929 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
930 return NT_STATUS_OK;
931 #endif
932 case RAW_FILEINFO_GENERIC:
933 case RAW_FILEINFO_SEC_DESC:
934 case RAW_FILEINFO_EA_LIST:
935 case RAW_FILEINFO_UNIX_INFO2:
936 case RAW_FILEINFO_SMB2_ALL_EAS:
937 case RAW_FILEINFO_SMB2_ALL_INFORMATION:
938 return NT_STATUS_INVALID_LEVEL;
941 return NT_STATUS_INVALID_LEVEL;
945 NTVFS any to fileinfo mapper
947 static NTSTATUS ntvfs_map_qfileinfo_finish(struct ntvfs_module_context *ntvfs,
948 struct ntvfs_request *req,
949 union smb_fileinfo *info,
950 union smb_fileinfo *info2,
951 NTSTATUS status)
953 if (!NT_STATUS_IS_OK(status)) {
954 return status;
957 return ntvfs_map_fileinfo(req, info, info2);
961 NTVFS fileinfo generic to any mapper
963 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
964 struct ntvfs_request *req,
965 union smb_fileinfo *info)
967 NTSTATUS status;
968 union smb_fileinfo *info2;
970 info2 = talloc(req, union smb_fileinfo);
971 if (info2 == NULL) {
972 return NT_STATUS_NO_MEMORY;
975 if (info->generic.level == RAW_FILEINFO_GENERIC) {
976 return NT_STATUS_INVALID_LEVEL;
979 status = ntvfs_map_async_setup(ntvfs, req, info, info2,
980 (second_stage_t)ntvfs_map_qfileinfo_finish);
981 if (!NT_STATUS_IS_OK(status)) {
982 return status;
985 /* ask the backend for the generic info */
986 info2->generic.level = RAW_FILEINFO_GENERIC;
987 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
989 status = ntvfs->ops->qfileinfo_fn(ntvfs, req, info2);
990 return ntvfs_map_async_finish(req, status);
994 NTVFS any to fileinfo mapper
996 static NTSTATUS ntvfs_map_qpathinfo_finish(struct ntvfs_module_context *ntvfs,
997 struct ntvfs_request *req,
998 union smb_fileinfo *info,
999 union smb_fileinfo *info2,
1000 NTSTATUS status)
1002 if (!NT_STATUS_IS_OK(status)) {
1003 return status;
1006 return ntvfs_map_fileinfo(req, info, info2);
1010 NTVFS pathinfo generic to any mapper
1012 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
1013 struct ntvfs_request *req,
1014 union smb_fileinfo *info)
1016 NTSTATUS status;
1017 union smb_fileinfo *info2;
1019 info2 = talloc(req, union smb_fileinfo);
1020 if (info2 == NULL) {
1021 return NT_STATUS_NO_MEMORY;
1024 if (info->generic.level == RAW_FILEINFO_GENERIC) {
1025 return NT_STATUS_INVALID_LEVEL;
1028 status = ntvfs_map_async_setup(ntvfs, req, info, info2,
1029 (second_stage_t)ntvfs_map_qpathinfo_finish);
1030 if (!NT_STATUS_IS_OK(status)) {
1031 return status;
1034 /* ask the backend for the generic info */
1035 info2->generic.level = RAW_FILEINFO_GENERIC;
1036 info2->generic.in.file.path = info->generic.in.file.path;
1038 status = ntvfs->ops->qpathinfo_fn(ntvfs, req, info2);
1039 return ntvfs_map_async_finish(req, status);
1044 NTVFS lock generic to any mapper
1046 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
1047 struct ntvfs_request *req,
1048 union smb_lock *lck)
1050 union smb_lock *lck2;
1051 struct smb_lock_entry *locks;
1053 lck2 = talloc(req, union smb_lock);
1054 if (lck2 == NULL) {
1055 return NT_STATUS_NO_MEMORY;
1058 locks = talloc_array(lck2, struct smb_lock_entry, 1);
1059 if (locks == NULL) {
1060 return NT_STATUS_NO_MEMORY;
1063 switch (lck->generic.level) {
1064 case RAW_LOCK_LOCKX:
1065 return NT_STATUS_INVALID_LEVEL;
1067 case RAW_LOCK_LOCK:
1068 lck2->generic.level = RAW_LOCK_GENERIC;
1069 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1070 lck2->generic.in.mode = 0;
1071 lck2->generic.in.timeout = 0;
1072 lck2->generic.in.ulock_cnt = 0;
1073 lck2->generic.in.lock_cnt = 1;
1074 lck2->generic.in.locks = locks;
1075 locks->pid = req->smbpid;
1076 locks->offset = lck->lock.in.offset;
1077 locks->count = lck->lock.in.count;
1078 break;
1080 case RAW_LOCK_UNLOCK:
1081 lck2->generic.level = RAW_LOCK_GENERIC;
1082 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1083 lck2->generic.in.mode = 0;
1084 lck2->generic.in.timeout = 0;
1085 lck2->generic.in.ulock_cnt = 1;
1086 lck2->generic.in.lock_cnt = 0;
1087 lck2->generic.in.locks = locks;
1088 locks->pid = req->smbpid;
1089 locks->offset = lck->unlock.in.offset;
1090 locks->count = lck->unlock.in.count;
1091 break;
1093 case RAW_LOCK_SMB2: {
1094 /* this is only approximate! We need to change the
1095 generic structure to fix this properly */
1096 int i;
1097 bool isunlock;
1098 if (lck->smb2.in.lock_count < 1) {
1099 return NT_STATUS_INVALID_PARAMETER;
1102 lck2->generic.level = RAW_LOCK_GENERIC;
1103 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1104 lck2->generic.in.timeout = UINT32_MAX;
1105 lck2->generic.in.mode = 0;
1106 lck2->generic.in.lock_cnt = 0;
1107 lck2->generic.in.ulock_cnt = 0;
1108 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry,
1109 lck->smb2.in.lock_count);
1110 if (lck2->generic.in.locks == NULL) {
1111 return NT_STATUS_NO_MEMORY;
1113 /* only the first lock gives the UNLOCK bit - see
1114 MS-SMB2 3.3.5.14 */
1115 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1116 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1117 return NT_STATUS_INVALID_PARAMETER;
1119 lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1120 isunlock = true;
1121 } else {
1122 lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1123 isunlock = false;
1125 for (i=0;i<lck->smb2.in.lock_count;i++) {
1126 if (!isunlock &&
1127 lck->smb2.in.locks[i].flags == SMB2_LOCK_FLAG_NONE) {
1128 return NT_STATUS_INVALID_PARAMETER;
1131 if (lck->smb2.in.locks[i].flags & ~SMB2_LOCK_FLAG_ALL_MASK) {
1132 return NT_STATUS_INVALID_PARAMETER;
1135 if (isunlock &&
1136 (lck->smb2.in.locks[i].flags &
1137 (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1138 return NT_STATUS_INVALID_PARAMETER;
1140 if (!isunlock &&
1141 (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1142 return NT_STATUS_INVALID_PARAMETER;
1144 lck2->generic.in.locks[i].pid = req->smbpid;
1145 lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
1146 lck2->generic.in.locks[i].count = lck->smb2.in.locks[i].length;
1147 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1148 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1150 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1151 lck2->generic.in.timeout = 0;
1154 /* initialize output value */
1155 lck->smb2.out.reserved = 0;
1156 break;
1159 case RAW_LOCK_SMB2_BREAK:
1160 lck2->generic.level = RAW_LOCK_GENERIC;
1161 lck2->generic.in.file.ntvfs = lck->smb2_break.in.file.ntvfs;
1162 lck2->generic.in.mode = LOCKING_ANDX_OPLOCK_RELEASE |
1163 ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1164 lck2->generic.in.timeout = 0;
1165 lck2->generic.in.ulock_cnt = 0;
1166 lck2->generic.in.lock_cnt = 0;
1167 lck2->generic.in.locks = NULL;
1169 /* initialize output value */
1170 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1171 lck->smb2_break.out.reserved = lck->smb2_break.in.reserved;
1172 lck->smb2_break.out.reserved2 = lck->smb2_break.in.reserved2;
1173 lck->smb2_break.out.file = lck->smb2_break.in.file;
1174 break;
1178 * we don't need to call ntvfs_map_async_setup() here,
1179 * as lock() doesn't have any output fields
1182 return ntvfs->ops->lock_fn(ntvfs, req, lck2);
1187 NTVFS write generic to any mapper
1189 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1190 struct ntvfs_request *req,
1191 union smb_write *wr,
1192 union smb_write *wr2,
1193 NTSTATUS status)
1195 union smb_lock *lck;
1196 union smb_close *cl;
1197 unsigned int state;
1199 if (NT_STATUS_IS_ERR(status)) {
1200 return status;
1203 switch (wr->generic.level) {
1204 case RAW_WRITE_WRITE:
1205 wr->write.out.nwritten = wr2->generic.out.nwritten;
1206 break;
1208 case RAW_WRITE_WRITEUNLOCK:
1209 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1211 lck = talloc(wr2, union smb_lock);
1212 if (lck == NULL) {
1213 return NT_STATUS_NO_MEMORY;
1216 lck->unlock.level = RAW_LOCK_UNLOCK;
1217 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1218 lck->unlock.in.count = wr->writeunlock.in.count;
1219 lck->unlock.in.offset = wr->writeunlock.in.offset;
1221 if (lck->unlock.in.count != 0) {
1222 /* do the lock sync for now */
1223 state = req->async_states->state;
1224 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1225 status = ntvfs->ops->lock_fn(ntvfs, req, lck);
1226 req->async_states->state = state;
1228 break;
1230 case RAW_WRITE_WRITECLOSE:
1231 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1233 cl = talloc(wr2, union smb_close);
1234 if (cl == NULL) {
1235 return NT_STATUS_NO_MEMORY;
1238 cl->close.level = RAW_CLOSE_CLOSE;
1239 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1240 cl->close.in.write_time = wr->writeclose.in.mtime;
1242 if (wr2->generic.in.count != 0) {
1243 /* do the close sync for now */
1244 state = req->async_states->state;
1245 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1246 status = ntvfs->ops->close_fn(ntvfs, req, cl);
1247 req->async_states->state = state;
1249 break;
1251 case RAW_WRITE_SPLWRITE:
1252 break;
1254 case RAW_WRITE_SMB2:
1255 wr->smb2.out._pad = 0;
1256 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1257 wr->smb2.out.unknown1 = 0;
1258 break;
1260 default:
1261 return NT_STATUS_INVALID_LEVEL;
1264 return status;
1269 NTVFS write generic to any mapper
1271 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1272 struct ntvfs_request *req,
1273 union smb_write *wr)
1275 union smb_write *wr2;
1276 NTSTATUS status;
1278 wr2 = talloc(req, union smb_write);
1279 if (wr2 == NULL) {
1280 return NT_STATUS_NO_MEMORY;
1283 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1284 (second_stage_t)ntvfs_map_write_finish);
1285 if (!NT_STATUS_IS_OK(status)) {
1286 return status;
1289 wr2->writex.level = RAW_WRITE_GENERIC;
1291 switch (wr->generic.level) {
1292 case RAW_WRITE_WRITEX:
1293 status = NT_STATUS_INVALID_LEVEL;
1294 break;
1296 case RAW_WRITE_WRITE:
1297 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1298 wr2->writex.in.offset = wr->write.in.offset;
1299 wr2->writex.in.wmode = 0;
1300 wr2->writex.in.remaining = wr->write.in.remaining;
1301 wr2->writex.in.count = wr->write.in.count;
1302 wr2->writex.in.data = wr->write.in.data;
1303 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1304 break;
1306 case RAW_WRITE_WRITEUNLOCK:
1307 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1308 wr2->writex.in.offset = wr->writeunlock.in.offset;
1309 wr2->writex.in.wmode = 0;
1310 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1311 wr2->writex.in.count = wr->writeunlock.in.count;
1312 wr2->writex.in.data = wr->writeunlock.in.data;
1313 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1314 break;
1316 case RAW_WRITE_WRITECLOSE:
1317 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1318 wr2->writex.in.offset = wr->writeclose.in.offset;
1319 wr2->writex.in.wmode = 0;
1320 wr2->writex.in.remaining = 0;
1321 wr2->writex.in.count = wr->writeclose.in.count;
1322 wr2->writex.in.data = wr->writeclose.in.data;
1323 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1324 break;
1326 case RAW_WRITE_SPLWRITE:
1327 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1328 wr2->writex.in.offset = 0;
1329 wr2->writex.in.wmode = 0;
1330 wr2->writex.in.remaining = 0;
1331 wr2->writex.in.count = wr->splwrite.in.count;
1332 wr2->writex.in.data = wr->splwrite.in.data;
1333 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1334 break;
1336 case RAW_WRITE_SMB2:
1337 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1338 wr2->writex.in.offset = wr->smb2.in.offset;
1339 wr2->writex.in.wmode = 0;
1340 wr2->writex.in.remaining = 0;
1341 wr2->writex.in.count = wr->smb2.in.data.length;
1342 wr2->writex.in.data = wr->smb2.in.data.data;
1343 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1346 return ntvfs_map_async_finish(req, status);
1351 NTVFS read generic to any mapper - finish the out mapping
1353 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1354 struct ntvfs_request *req,
1355 union smb_read *rd,
1356 union smb_read *rd2,
1357 NTSTATUS status)
1359 switch (rd->generic.level) {
1360 case RAW_READ_READ:
1361 rd->read.out.nread = rd2->generic.out.nread;
1362 break;
1363 case RAW_READ_READBRAW:
1364 rd->readbraw.out.nread = rd2->generic.out.nread;
1365 break;
1366 case RAW_READ_LOCKREAD:
1367 rd->lockread.out.nread = rd2->generic.out.nread;
1368 break;
1369 case RAW_READ_SMB2:
1370 rd->smb2.out.data.length= rd2->generic.out.nread;
1371 rd->smb2.out.remaining = 0;
1372 rd->smb2.out.reserved = 0;
1373 break;
1374 default:
1375 return NT_STATUS_INVALID_LEVEL;
1378 return status;
1382 NTVFS read* to readx mapper
1384 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1385 struct ntvfs_request *req,
1386 union smb_read *rd)
1388 union smb_read *rd2;
1389 union smb_lock *lck;
1390 NTSTATUS status;
1391 unsigned int state;
1393 rd2 = talloc(req, union smb_read);
1394 if (rd2 == NULL) {
1395 return NT_STATUS_NO_MEMORY;
1398 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1399 (second_stage_t)ntvfs_map_read_finish);
1400 if (!NT_STATUS_IS_OK(status)) {
1401 return status;
1404 rd2->readx.level = RAW_READ_READX;
1405 rd2->readx.in.read_for_execute = false;
1407 switch (rd->generic.level) {
1408 case RAW_READ_READX:
1409 status = NT_STATUS_INVALID_LEVEL;
1410 break;
1412 case RAW_READ_READ:
1413 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1414 rd2->readx.in.offset = rd->read.in.offset;
1415 rd2->readx.in.mincnt = rd->read.in.count;
1416 rd2->readx.in.maxcnt = rd->read.in.count;
1417 rd2->readx.in.remaining = rd->read.in.remaining;
1418 rd2->readx.out.data = rd->read.out.data;
1419 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1420 break;
1422 case RAW_READ_READBRAW:
1423 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1424 rd2->readx.in.offset = rd->readbraw.in.offset;
1425 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1426 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1427 rd2->readx.in.remaining = 0;
1428 rd2->readx.out.data = rd->readbraw.out.data;
1429 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1430 break;
1432 case RAW_READ_LOCKREAD:
1433 /* do the initial lock sync for now */
1434 state = req->async_states->state;
1435 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1437 lck = talloc(rd2, union smb_lock);
1438 if (lck == NULL) {
1439 status = NT_STATUS_NO_MEMORY;
1440 goto done;
1442 lck->lock.level = RAW_LOCK_LOCK;
1443 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1444 lck->lock.in.count = rd->lockread.in.count;
1445 lck->lock.in.offset = rd->lockread.in.offset;
1446 status = ntvfs->ops->lock_fn(ntvfs, req, lck);
1447 req->async_states->state = state;
1449 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1450 rd2->readx.in.offset = rd->lockread.in.offset;
1451 rd2->readx.in.mincnt = rd->lockread.in.count;
1452 rd2->readx.in.maxcnt = rd->lockread.in.count;
1453 rd2->readx.in.remaining = rd->lockread.in.remaining;
1454 rd2->readx.out.data = rd->lockread.out.data;
1456 if (NT_STATUS_IS_OK(status)) {
1457 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1459 break;
1461 case RAW_READ_SMB2:
1462 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1463 rd2->readx.in.offset = rd->smb2.in.offset;
1464 rd2->readx.in.mincnt = rd->smb2.in.min_count;
1465 rd2->readx.in.maxcnt = rd->smb2.in.length;
1466 rd2->readx.in.remaining = 0;
1467 rd2->readx.out.data = rd->smb2.out.data.data;
1468 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1469 break;
1472 done:
1473 return ntvfs_map_async_finish(req, status);
1478 NTVFS close generic to any mapper
1480 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1481 struct ntvfs_request *req,
1482 union smb_close *cl,
1483 union smb_close *cl2,
1484 NTSTATUS status)
1486 NT_STATUS_NOT_OK_RETURN(status);
1488 switch (cl->generic.level) {
1489 case RAW_CLOSE_SMB2:
1490 cl->smb2.out.flags = cl2->generic.out.flags;
1491 cl->smb2.out._pad = 0;
1492 cl->smb2.out.create_time = cl2->generic.out.create_time;
1493 cl->smb2.out.access_time = cl2->generic.out.access_time;
1494 cl->smb2.out.write_time = cl2->generic.out.write_time;
1495 cl->smb2.out.change_time = cl2->generic.out.change_time;
1496 cl->smb2.out.alloc_size = cl2->generic.out.alloc_size;
1497 cl->smb2.out.size = cl2->generic.out.size;
1498 cl->smb2.out.file_attr = cl2->generic.out.file_attr;
1499 break;
1500 default:
1501 break;
1504 return status;
1508 NTVFS close generic to any mapper
1510 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1511 struct ntvfs_request *req,
1512 union smb_close *cl)
1514 union smb_close *cl2;
1515 NTSTATUS status;
1517 cl2 = talloc(req, union smb_close);
1518 if (cl2 == NULL) {
1519 return NT_STATUS_NO_MEMORY;
1522 switch (cl->generic.level) {
1523 case RAW_CLOSE_GENERIC:
1524 return NT_STATUS_INVALID_LEVEL;
1526 case RAW_CLOSE_CLOSE:
1527 cl2->generic.level = RAW_CLOSE_GENERIC;
1528 cl2->generic.in.file = cl->close.in.file;
1529 cl2->generic.in.write_time = cl->close.in.write_time;
1530 cl2->generic.in.flags = 0;
1531 break;
1533 case RAW_CLOSE_SPLCLOSE:
1534 cl2->generic.level = RAW_CLOSE_GENERIC;
1535 cl2->generic.in.file = cl->splclose.in.file;
1536 cl2->generic.in.write_time = 0;
1537 cl2->generic.in.flags = 0;
1538 break;
1540 case RAW_CLOSE_SMB2:
1541 cl2->generic.level = RAW_CLOSE_GENERIC;
1542 cl2->generic.in.file = cl->smb2.in.file;
1543 cl2->generic.in.write_time = 0;
1544 cl2->generic.in.flags = cl->smb2.in.flags;
1545 break;
1548 status = ntvfs_map_async_setup(ntvfs, req, cl, cl2,
1549 (second_stage_t)ntvfs_map_close_finish);
1550 NT_STATUS_NOT_OK_RETURN(status);
1552 status = ntvfs->ops->close_fn(ntvfs, req, cl2);
1554 return ntvfs_map_async_finish(req, status);
1558 NTVFS notify generic to any mapper
1560 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1561 struct ntvfs_request *req,
1562 union smb_notify *nt,
1563 union smb_notify *nt2,
1564 NTSTATUS status)
1566 NT_STATUS_NOT_OK_RETURN(status);
1568 switch (nt->nttrans.level) {
1569 case RAW_NOTIFY_SMB2:
1570 if (nt2->nttrans.out.num_changes == 0) {
1571 return STATUS_NOTIFY_ENUM_DIR;
1573 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1574 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1575 break;
1577 default:
1578 return NT_STATUS_INVALID_LEVEL;
1581 return status;
1586 NTVFS notify generic to any mapper
1588 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1589 struct ntvfs_request *req,
1590 union smb_notify *nt)
1592 union smb_notify *nt2;
1593 NTSTATUS status;
1595 nt2 = talloc(req, union smb_notify);
1596 NT_STATUS_HAVE_NO_MEMORY(nt2);
1598 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1599 (second_stage_t)ntvfs_map_notify_finish);
1600 NT_STATUS_NOT_OK_RETURN(status);
1602 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1604 switch (nt->nttrans.level) {
1605 case RAW_NOTIFY_NTTRANS:
1606 status = NT_STATUS_INVALID_LEVEL;
1607 break;
1609 case RAW_NOTIFY_SMB2:
1610 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1611 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1612 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1613 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1614 status = ntvfs->ops->notify_fn(ntvfs, req, nt2);
1615 break;
1618 return ntvfs_map_async_finish(req, status);