Revert "Revert "s3-printing: update parent smbd pcap cache""
[Samba.git] / source4 / ntvfs / ntvfs_generic.c
blobad13f36c8ab571bd04868a5327a2349b36dd7a73
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 uint_t 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(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(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;
288 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
289 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
291 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
292 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
295 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
296 case OPENX_MODE_ACCESS_READ:
297 case OPENX_MODE_ACCESS_EXEC:
298 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
299 break;
300 case OPENX_MODE_ACCESS_WRITE:
301 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
302 break;
303 case OPENX_MODE_ACCESS_RDWR:
304 case OPENX_MODE_ACCESS_FCB:
305 io2->generic.in.access_mask =
306 SEC_RIGHTS_FILE_READ |
307 SEC_RIGHTS_FILE_WRITE;
308 break;
309 default:
310 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
313 switch (open_mode & OPENX_MODE_DENY_MASK) {
314 case OPENX_MODE_DENY_READ:
315 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
316 break;
317 case OPENX_MODE_DENY_WRITE:
318 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
319 break;
320 case OPENX_MODE_DENY_ALL:
321 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
322 break;
323 case OPENX_MODE_DENY_NONE:
324 io2->generic.in.share_access =
325 NTCREATEX_SHARE_ACCESS_READ |
326 NTCREATEX_SHARE_ACCESS_WRITE;
327 break;
328 case OPENX_MODE_DENY_DOS:
329 /* DENY_DOS is quite strange - it depends on the filename! */
330 io2->generic.in.create_options |=
331 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS;
332 if (is_exe_filename(fname)) {
333 io2->generic.in.share_access =
334 NTCREATEX_SHARE_ACCESS_READ |
335 NTCREATEX_SHARE_ACCESS_WRITE;
336 } else {
337 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
338 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
339 } else {
340 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
343 break;
344 case OPENX_MODE_DENY_FCB:
345 io2->generic.in.create_options |= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB;
346 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
347 break;
348 default:
349 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
352 switch (open_func) {
353 case (OPENX_OPEN_FUNC_OPEN):
354 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
355 break;
356 case (OPENX_OPEN_FUNC_TRUNC):
357 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
358 break;
359 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
360 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
361 break;
362 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
363 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
364 break;
365 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
366 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
367 break;
368 default:
369 /* this one is very strange */
370 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
371 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
372 break;
374 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
377 return NT_STATUS_OK;
381 NTVFS open generic to any mapper
383 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
384 struct ntvfs_request *req,
385 union smb_open *io)
387 NTSTATUS status;
388 union smb_open *io2;
390 io2 = talloc_zero(req, union smb_open);
391 if (io2 == NULL) {
392 return NT_STATUS_NO_MEMORY;
395 status = ntvfs_map_async_setup(ntvfs, req,
396 io, io2,
397 (second_stage_t)ntvfs_map_open_finish);
398 if (!NT_STATUS_IS_OK(status)) {
399 return status;
402 io2->generic.level = RAW_OPEN_GENERIC;
404 switch (io->generic.level) {
405 case RAW_OPEN_OPENX:
406 status = map_openx_open(io->openx.in.flags,
407 io->openx.in.open_mode,
408 io->openx.in.open_func,
409 io->openx.in.fname,
410 io2);
411 if (!NT_STATUS_IS_OK(status)) {
412 goto done;
415 io2->generic.in.file_attr = io->openx.in.file_attrs;
416 io2->generic.in.fname = io->openx.in.fname;
418 status = ntvfs->ops->open(ntvfs, req, io2);
419 break;
422 case RAW_OPEN_OPEN:
423 status = map_openx_open(0,
424 io->openold.in.open_mode,
425 OPENX_OPEN_FUNC_OPEN,
426 io->openold.in.fname,
427 io2);
428 if (!NT_STATUS_IS_OK(status)) {
429 goto done;
432 io2->generic.in.file_attr = io->openold.in.search_attrs;
433 io2->generic.in.fname = io->openold.in.fname;
435 status = ntvfs->ops->open(ntvfs, req, io2);
436 break;
438 case RAW_OPEN_T2OPEN:
439 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
441 if (io->t2open.in.open_func == 0) {
442 status = NT_STATUS_OBJECT_NAME_COLLISION;
443 goto done;
446 status = map_openx_open(io->t2open.in.flags,
447 io->t2open.in.open_mode,
448 io->t2open.in.open_func,
449 io->t2open.in.fname,
450 io2);
451 if (!NT_STATUS_IS_OK(status)) {
452 goto done;
455 io2->generic.in.file_attr = io->t2open.in.file_attrs;
456 io2->generic.in.fname = io->t2open.in.fname;
457 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
458 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
459 io2->generic.in.ea_list->eas = io->t2open.in.eas;
461 status = ntvfs->ops->open(ntvfs, req, io2);
462 break;
464 case RAW_OPEN_MKNEW:
465 io2->generic.in.file_attr = io->mknew.in.attrib;
466 io2->generic.in.fname = io->mknew.in.fname;
467 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
468 io2->generic.in.access_mask =
469 SEC_RIGHTS_FILE_READ |
470 SEC_RIGHTS_FILE_WRITE;
471 io2->generic.in.share_access =
472 NTCREATEX_SHARE_ACCESS_READ |
473 NTCREATEX_SHARE_ACCESS_WRITE;
474 status = ntvfs->ops->open(ntvfs, req, io2);
475 break;
477 case RAW_OPEN_CREATE:
478 io2->generic.in.file_attr = io->mknew.in.attrib;
479 io2->generic.in.fname = io->mknew.in.fname;
480 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
481 io2->generic.in.access_mask =
482 SEC_RIGHTS_FILE_READ |
483 SEC_RIGHTS_FILE_WRITE;
484 io2->generic.in.share_access =
485 NTCREATEX_SHARE_ACCESS_READ |
486 NTCREATEX_SHARE_ACCESS_WRITE;
487 status = ntvfs->ops->open(ntvfs, req, io2);
488 break;
490 case RAW_OPEN_CTEMP:
491 io2->generic.in.file_attr = io->ctemp.in.attrib;
492 io2->generic.in.fname =
493 talloc_asprintf(io2, "%s\\SRV%s",
494 io->ctemp.in.directory,
495 generate_random_str_list(io2, 5, "0123456789"));
496 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
497 io2->generic.in.access_mask =
498 SEC_RIGHTS_FILE_READ |
499 SEC_RIGHTS_FILE_WRITE;
500 io2->generic.in.share_access =
501 NTCREATEX_SHARE_ACCESS_READ |
502 NTCREATEX_SHARE_ACCESS_WRITE;
503 status = ntvfs->ops->open(ntvfs, req, io2);
504 break;
505 case RAW_OPEN_SMB2:
506 switch (io->smb2.in.oplock_level) {
507 case SMB2_OPLOCK_LEVEL_BATCH:
508 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
509 NTCREATEX_FLAGS_REQUEST_OPLOCK;
510 break;
511 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
512 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
513 break;
514 default:
515 io2->generic.in.flags = 0;
516 break;
518 io2->generic.in.root_fid = 0;
519 io2->generic.in.access_mask = io->smb2.in.desired_access;
520 io2->generic.in.alloc_size = io->smb2.in.alloc_size;
521 io2->generic.in.file_attr = io->smb2.in.file_attributes;
522 io2->generic.in.share_access = io->smb2.in.share_access;
523 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
524 io2->generic.in.create_options = io->smb2.in.create_options;
525 io2->generic.in.impersonation = io->smb2.in.impersonation_level;
526 io2->generic.in.security_flags = 0;
527 io2->generic.in.fname = io->smb2.in.fname;
528 io2->generic.in.sec_desc = io->smb2.in.sec_desc;
529 io2->generic.in.ea_list = &io->smb2.in.eas;
530 io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access;
532 /* we don't support timewarp yet */
533 if (io->smb2.in.timewarp != 0) {
534 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
535 break;
538 /* we need to check these bits before we check the private mask */
539 if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
540 DEBUG(2,(__location__ " create_options 0x%x not supported\n",
541 io2->generic.in.create_options));
542 status = NT_STATUS_NOT_SUPPORTED;
543 break;
546 /* TODO: find out why only SMB2 ignores these */
547 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
548 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
550 status = ntvfs->ops->open(ntvfs, req, io2);
551 break;
553 default:
554 status = NT_STATUS_INVALID_LEVEL;
555 break;
557 done:
558 return ntvfs_map_async_finish(req, status);
563 NTVFS fsinfo generic to any mapper
565 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
566 struct ntvfs_request *req,
567 union smb_fsinfo *fs)
569 NTSTATUS status;
570 union smb_fsinfo *fs2;
572 fs2 = talloc(req, union smb_fsinfo);
573 if (fs2 == NULL) {
574 return NT_STATUS_NO_MEMORY;
577 if (fs->generic.level == RAW_QFS_GENERIC) {
578 return NT_STATUS_INVALID_LEVEL;
581 /* only used by the simple backend, which doesn't do async */
582 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
584 /* ask the backend for the generic info */
585 fs2->generic.level = RAW_QFS_GENERIC;
587 status = ntvfs->ops->fsinfo(ntvfs, req, fs2);
588 if (!NT_STATUS_IS_OK(status)) {
589 return status;
592 /* and convert it to the required level */
593 switch (fs->generic.level) {
594 case RAW_QFS_GENERIC:
595 return NT_STATUS_INVALID_LEVEL;
597 case RAW_QFS_DSKATTR: {
598 /* map from generic to DSKATTR */
599 uint_t bpunit = 64;
601 /* we need to scale the sizes to fit */
602 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
603 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
604 break;
608 fs->dskattr.out.blocks_per_unit = bpunit;
609 fs->dskattr.out.block_size = 512;
610 fs->dskattr.out.units_total =
611 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
612 fs->dskattr.out.units_free =
613 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
615 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
616 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
617 fs->dskattr.out.blocks_per_unit = 64;
618 fs->dskattr.out.units_total = 0xFFFF;
619 fs->dskattr.out.units_free = 0xFFFF;
621 return NT_STATUS_OK;
624 case RAW_QFS_ALLOCATION:
625 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
626 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
627 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
628 fs->allocation.out.sectors_per_unit = 1;
629 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
630 return NT_STATUS_OK;
632 case RAW_QFS_VOLUME:
633 fs->volume.out.serial_number = fs2->generic.out.serial_number;
634 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
635 return NT_STATUS_OK;
637 case RAW_QFS_VOLUME_INFO:
638 case RAW_QFS_VOLUME_INFORMATION:
639 fs->volume_info.out.create_time = fs2->generic.out.create_time;
640 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
641 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
642 return NT_STATUS_OK;
644 case RAW_QFS_SIZE_INFO:
645 case RAW_QFS_SIZE_INFORMATION:
646 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
647 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
648 fs->size_info.out.sectors_per_unit = 1;
649 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
650 return NT_STATUS_OK;
652 case RAW_QFS_DEVICE_INFO:
653 case RAW_QFS_DEVICE_INFORMATION:
654 fs->device_info.out.device_type = fs2->generic.out.device_type;
655 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
656 return NT_STATUS_OK;
658 case RAW_QFS_ATTRIBUTE_INFO:
659 case RAW_QFS_ATTRIBUTE_INFORMATION:
660 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
661 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
662 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
663 return NT_STATUS_OK;
665 case RAW_QFS_QUOTA_INFORMATION:
666 ZERO_STRUCT(fs->quota_information.out.unknown);
667 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
668 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
669 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
670 return NT_STATUS_OK;
672 case RAW_QFS_FULL_SIZE_INFORMATION:
673 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
674 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
675 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
676 fs->full_size_information.out.sectors_per_unit = 1;
677 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
678 return NT_STATUS_OK;
680 case RAW_QFS_OBJECTID_INFORMATION:
681 fs->objectid_information.out.guid = fs2->generic.out.guid;
682 ZERO_STRUCT(fs->objectid_information.out.unknown);
683 return NT_STATUS_OK;
687 return NT_STATUS_INVALID_LEVEL;
692 NTVFS fileinfo generic to any mapper
694 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
695 union smb_fileinfo *info,
696 union smb_fileinfo *info2)
698 int i;
699 /* and convert it to the required level using results in info2 */
700 switch (info->generic.level) {
701 case RAW_FILEINFO_GENERIC:
702 return NT_STATUS_INVALID_LEVEL;
703 case RAW_FILEINFO_GETATTR:
704 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
705 info->getattr.out.size = info2->generic.out.size;
706 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
707 return NT_STATUS_OK;
709 case RAW_FILEINFO_GETATTRE:
710 info->getattre.out.attrib = info2->generic.out.attrib;
711 info->getattre.out.size = info2->generic.out.size;
712 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
713 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
714 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
715 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
716 return NT_STATUS_OK;
718 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
719 info->network_open_information.out.create_time = info2->generic.out.create_time;
720 info->network_open_information.out.access_time = info2->generic.out.access_time;
721 info->network_open_information.out.write_time = info2->generic.out.write_time;
722 info->network_open_information.out.change_time = info2->generic.out.change_time;
723 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
724 info->network_open_information.out.size = info2->generic.out.size;
725 info->network_open_information.out.attrib = info2->generic.out.attrib;
726 return NT_STATUS_OK;
728 case RAW_FILEINFO_ALL_INFO:
729 case RAW_FILEINFO_ALL_INFORMATION:
730 info->all_info.out.create_time = info2->generic.out.create_time;
731 info->all_info.out.access_time = info2->generic.out.access_time;
732 info->all_info.out.write_time = info2->generic.out.write_time;
733 info->all_info.out.change_time = info2->generic.out.change_time;
734 info->all_info.out.attrib = info2->generic.out.attrib;
735 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
736 info->all_info.out.size = info2->generic.out.size;
737 info->all_info.out.nlink = info2->generic.out.nlink;
738 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
739 info->all_info.out.directory = info2->generic.out.directory;
740 info->all_info.out.ea_size = info2->generic.out.ea_size;
741 info->all_info.out.fname.s = info2->generic.out.fname.s;
742 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
743 return NT_STATUS_OK;
745 case RAW_FILEINFO_BASIC_INFO:
746 case RAW_FILEINFO_BASIC_INFORMATION:
747 info->basic_info.out.create_time = info2->generic.out.create_time;
748 info->basic_info.out.access_time = info2->generic.out.access_time;
749 info->basic_info.out.write_time = info2->generic.out.write_time;
750 info->basic_info.out.change_time = info2->generic.out.change_time;
751 info->basic_info.out.attrib = info2->generic.out.attrib;
752 return NT_STATUS_OK;
754 case RAW_FILEINFO_STANDARD:
755 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
756 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
757 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
758 info->standard.out.size = info2->generic.out.size;
759 info->standard.out.alloc_size = info2->generic.out.alloc_size;
760 info->standard.out.attrib = info2->generic.out.attrib;
761 return NT_STATUS_OK;
763 case RAW_FILEINFO_EA_SIZE:
764 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
765 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
766 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
767 info->ea_size.out.size = info2->generic.out.size;
768 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
769 info->ea_size.out.attrib = info2->generic.out.attrib;
770 info->ea_size.out.ea_size = info2->generic.out.ea_size;
771 return NT_STATUS_OK;
773 case RAW_FILEINFO_STANDARD_INFO:
774 case RAW_FILEINFO_STANDARD_INFORMATION:
775 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
776 info->standard_info.out.size = info2->generic.out.size;
777 info->standard_info.out.nlink = info2->generic.out.nlink;
778 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
779 info->standard_info.out.directory = info2->generic.out.directory;
780 return NT_STATUS_OK;
782 case RAW_FILEINFO_INTERNAL_INFORMATION:
783 info->internal_information.out.file_id = info2->generic.out.file_id;
784 return NT_STATUS_OK;
786 case RAW_FILEINFO_EA_INFO:
787 case RAW_FILEINFO_EA_INFORMATION:
788 info->ea_info.out.ea_size = info2->generic.out.ea_size;
789 return NT_STATUS_OK;
791 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
792 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
793 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
794 return NT_STATUS_OK;
796 case RAW_FILEINFO_STREAM_INFO:
797 case RAW_FILEINFO_STREAM_INFORMATION:
798 info->stream_info.out.num_streams = info2->generic.out.num_streams;
799 if (info->stream_info.out.num_streams > 0) {
800 info->stream_info.out.streams =
801 talloc_array(mem_ctx,
802 struct stream_struct,
803 info->stream_info.out.num_streams);
804 if (!info->stream_info.out.streams) {
805 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
806 info->stream_info.out.num_streams));
807 return NT_STATUS_NO_MEMORY;
809 for (i=0; i < info->stream_info.out.num_streams; i++) {
810 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
811 info->stream_info.out.streams[i].stream_name.s =
812 talloc_strdup(info->stream_info.out.streams,
813 info2->generic.out.streams[i].stream_name.s);
814 if (!info->stream_info.out.streams[i].stream_name.s) {
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_NAME_INFO:
823 case RAW_FILEINFO_NAME_INFORMATION:
824 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
825 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
826 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
827 return NT_STATUS_OK;
829 case RAW_FILEINFO_ALT_NAME_INFO:
830 case RAW_FILEINFO_ALT_NAME_INFORMATION:
831 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
832 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
833 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
834 return NT_STATUS_OK;
836 case RAW_FILEINFO_POSITION_INFORMATION:
837 info->position_information.out.position = info2->generic.out.position;
838 return NT_STATUS_OK;
840 case RAW_FILEINFO_ALL_EAS:
841 info->all_eas.out.num_eas = info2->generic.out.num_eas;
842 if (info->all_eas.out.num_eas > 0) {
843 info->all_eas.out.eas = talloc_array(mem_ctx,
844 struct ea_struct,
845 info->all_eas.out.num_eas);
846 if (!info->all_eas.out.eas) {
847 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
848 info->all_eas.out.num_eas));
849 return NT_STATUS_NO_MEMORY;
851 for (i = 0; i < info->all_eas.out.num_eas; i++) {
852 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
853 info->all_eas.out.eas[i].name.s =
854 talloc_strdup(info->all_eas.out.eas,
855 info2->generic.out.eas[i].name.s);
856 if (!info->all_eas.out.eas[i].name.s) {
857 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
858 return NT_STATUS_NO_MEMORY;
860 info->all_eas.out.eas[i].value.data =
861 (uint8_t *)talloc_memdup(info->all_eas.out.eas,
862 info2->generic.out.eas[i].value.data,
863 info2->generic.out.eas[i].value.length);
864 if (!info->all_eas.out.eas[i].value.data) {
865 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
866 return NT_STATUS_NO_MEMORY;
870 return NT_STATUS_OK;
872 case RAW_FILEINFO_IS_NAME_VALID:
873 return NT_STATUS_OK;
875 case RAW_FILEINFO_COMPRESSION_INFO:
876 case RAW_FILEINFO_COMPRESSION_INFORMATION:
877 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
878 info->compression_info.out.format = info2->generic.out.format;
879 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
880 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
881 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
882 return NT_STATUS_OK;
884 case RAW_FILEINFO_ACCESS_INFORMATION:
885 info->access_information.out.access_flags = info2->generic.out.access_flags;
886 return NT_STATUS_OK;
888 case RAW_FILEINFO_MODE_INFORMATION:
889 info->mode_information.out.mode = info2->generic.out.mode;
890 return NT_STATUS_OK;
892 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
893 info->alignment_information.out.alignment_requirement =
894 info2->generic.out.alignment_requirement;
895 return NT_STATUS_OK;
896 #if 0
897 case RAW_FILEINFO_UNIX_BASIC:
898 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
899 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
900 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
901 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
902 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
903 info->unix_basic_info.out.uid = info2->generic.out.uid;
904 info->unix_basic_info.out.gid = info2->generic.out.gid;
905 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
906 info->unix_basic_info.out.dev_major = info2->generic.out.device;
907 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
908 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
909 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
910 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
911 return NT_STATUS_OK;
913 case RAW_FILEINFO_UNIX_LINK:
914 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
915 return NT_STATUS_OK;
916 #endif
919 return NT_STATUS_INVALID_LEVEL;
923 NTVFS fileinfo generic to any mapper
925 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
926 struct ntvfs_request *req,
927 union smb_fileinfo *info)
929 NTSTATUS status;
930 union smb_fileinfo *info2;
932 info2 = talloc(req, union smb_fileinfo);
933 if (info2 == NULL) {
934 return NT_STATUS_NO_MEMORY;
937 if (info->generic.level == RAW_FILEINFO_GENERIC) {
938 return NT_STATUS_INVALID_LEVEL;
941 /* ask the backend for the generic info */
942 info2->generic.level = RAW_FILEINFO_GENERIC;
943 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
945 /* only used by the simple backend, which doesn't do async */
946 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
948 status = ntvfs->ops->qfileinfo(ntvfs, req, info2);
949 if (!NT_STATUS_IS_OK(status)) {
950 return status;
952 return ntvfs_map_fileinfo(req, info, info2);
956 NTVFS pathinfo generic to any mapper
958 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
959 struct ntvfs_request *req,
960 union smb_fileinfo *info)
962 NTSTATUS status;
963 union smb_fileinfo *info2;
965 info2 = talloc(req, union smb_fileinfo);
966 if (info2 == NULL) {
967 return NT_STATUS_NO_MEMORY;
970 if (info->generic.level == RAW_FILEINFO_GENERIC) {
971 return NT_STATUS_INVALID_LEVEL;
974 /* ask the backend for the generic info */
975 info2->generic.level = RAW_FILEINFO_GENERIC;
976 info2->generic.in.file.path = info->generic.in.file.path;
978 /* only used by the simple backend, which doesn't do async */
979 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
981 status = ntvfs->ops->qpathinfo(ntvfs, req, info2);
982 if (!NT_STATUS_IS_OK(status)) {
983 return status;
985 return ntvfs_map_fileinfo(req, info, info2);
990 NTVFS lock generic to any mapper
992 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
993 struct ntvfs_request *req,
994 union smb_lock *lck)
996 union smb_lock *lck2;
997 struct smb_lock_entry *locks;
999 lck2 = talloc(req, union smb_lock);
1000 if (lck2 == NULL) {
1001 return NT_STATUS_NO_MEMORY;
1004 locks = talloc_array(lck2, struct smb_lock_entry, 1);
1005 if (locks == NULL) {
1006 return NT_STATUS_NO_MEMORY;
1009 switch (lck->generic.level) {
1010 case RAW_LOCK_LOCKX:
1011 return NT_STATUS_INVALID_LEVEL;
1013 case RAW_LOCK_LOCK:
1014 lck2->generic.level = RAW_LOCK_GENERIC;
1015 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1016 lck2->generic.in.mode = 0;
1017 lck2->generic.in.timeout = 0;
1018 lck2->generic.in.ulock_cnt = 0;
1019 lck2->generic.in.lock_cnt = 1;
1020 lck2->generic.in.locks = locks;
1021 locks->pid = req->smbpid;
1022 locks->offset = lck->lock.in.offset;
1023 locks->count = lck->lock.in.count;
1024 break;
1026 case RAW_LOCK_UNLOCK:
1027 lck2->generic.level = RAW_LOCK_GENERIC;
1028 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1029 lck2->generic.in.mode = 0;
1030 lck2->generic.in.timeout = 0;
1031 lck2->generic.in.ulock_cnt = 1;
1032 lck2->generic.in.lock_cnt = 0;
1033 lck2->generic.in.locks = locks;
1034 locks->pid = req->smbpid;
1035 locks->offset = lck->unlock.in.offset;
1036 locks->count = lck->unlock.in.count;
1037 break;
1039 case RAW_LOCK_SMB2: {
1040 /* this is only approximate! We need to change the
1041 generic structure to fix this properly */
1042 int i;
1043 bool isunlock;
1044 if (lck->smb2.in.lock_count < 1) {
1045 return NT_STATUS_INVALID_PARAMETER;
1048 lck2->generic.level = RAW_LOCK_GENERIC;
1049 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1050 lck2->generic.in.timeout = UINT32_MAX;
1051 lck2->generic.in.mode = 0;
1052 lck2->generic.in.lock_cnt = 0;
1053 lck2->generic.in.ulock_cnt = 0;
1054 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry,
1055 lck->smb2.in.lock_count);
1056 if (lck2->generic.in.locks == NULL) {
1057 return NT_STATUS_NO_MEMORY;
1059 /* only the first lock gives the UNLOCK bit - see
1060 MS-SMB2 3.3.5.14 */
1061 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1062 lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1063 isunlock = true;
1064 } else {
1065 lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1066 isunlock = false;
1068 for (i=0;i<lck->smb2.in.lock_count;i++) {
1069 if (isunlock &&
1070 (lck->smb2.in.locks[i].flags &
1071 (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1072 return NT_STATUS_INVALID_PARAMETER;
1074 if (!isunlock &&
1075 (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1076 return NT_STATUS_INVALID_PARAMETER;
1078 lck2->generic.in.locks[i].pid = req->smbpid;
1079 lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
1080 lck2->generic.in.locks[i].count = lck->smb2.in.locks[i].length;
1081 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1082 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1084 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1085 lck2->generic.in.timeout = 0;
1088 /* initialize output value */
1089 lck->smb2.out.reserved = 0;
1090 break;
1093 case RAW_LOCK_SMB2_BREAK:
1094 lck2->generic.level = RAW_LOCK_GENERIC;
1095 lck2->generic.in.file.ntvfs = lck->smb2_break.in.file.ntvfs;
1096 lck2->generic.in.mode = LOCKING_ANDX_OPLOCK_RELEASE |
1097 ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1098 lck2->generic.in.timeout = 0;
1099 lck2->generic.in.ulock_cnt = 0;
1100 lck2->generic.in.lock_cnt = 0;
1101 lck2->generic.in.locks = NULL;
1103 /* initialize output value */
1104 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1105 lck->smb2_break.out.reserved = lck->smb2_break.in.reserved;
1106 lck->smb2_break.out.reserved2 = lck->smb2_break.in.reserved2;
1107 lck->smb2_break.out.file = lck->smb2_break.in.file;
1108 break;
1112 * we don't need to call ntvfs_map_async_setup() here,
1113 * as lock() doesn't have any output fields
1116 return ntvfs->ops->lock(ntvfs, req, lck2);
1121 NTVFS write generic to any mapper
1123 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1124 struct ntvfs_request *req,
1125 union smb_write *wr,
1126 union smb_write *wr2,
1127 NTSTATUS status)
1129 union smb_lock *lck;
1130 union smb_close *cl;
1131 uint_t state;
1133 if (NT_STATUS_IS_ERR(status)) {
1134 return status;
1137 switch (wr->generic.level) {
1138 case RAW_WRITE_WRITE:
1139 wr->write.out.nwritten = wr2->generic.out.nwritten;
1140 break;
1142 case RAW_WRITE_WRITEUNLOCK:
1143 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1145 lck = talloc(wr2, union smb_lock);
1146 if (lck == NULL) {
1147 return NT_STATUS_NO_MEMORY;
1150 lck->unlock.level = RAW_LOCK_UNLOCK;
1151 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1152 lck->unlock.in.count = wr->writeunlock.in.count;
1153 lck->unlock.in.offset = wr->writeunlock.in.offset;
1155 if (lck->unlock.in.count != 0) {
1156 /* do the lock sync for now */
1157 state = req->async_states->state;
1158 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1159 status = ntvfs->ops->lock(ntvfs, req, lck);
1160 req->async_states->state = state;
1162 break;
1164 case RAW_WRITE_WRITECLOSE:
1165 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1167 cl = talloc(wr2, union smb_close);
1168 if (cl == NULL) {
1169 return NT_STATUS_NO_MEMORY;
1172 cl->close.level = RAW_CLOSE_CLOSE;
1173 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1174 cl->close.in.write_time = wr->writeclose.in.mtime;
1176 if (wr2->generic.in.count != 0) {
1177 /* do the close sync for now */
1178 state = req->async_states->state;
1179 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1180 status = ntvfs->ops->close(ntvfs, req, cl);
1181 req->async_states->state = state;
1183 break;
1185 case RAW_WRITE_SPLWRITE:
1186 break;
1188 case RAW_WRITE_SMB2:
1189 wr->smb2.out._pad = 0;
1190 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1191 wr->smb2.out.unknown1 = 0;
1192 break;
1194 default:
1195 return NT_STATUS_INVALID_LEVEL;
1198 return status;
1203 NTVFS write generic to any mapper
1205 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1206 struct ntvfs_request *req,
1207 union smb_write *wr)
1209 union smb_write *wr2;
1210 NTSTATUS status;
1212 wr2 = talloc(req, union smb_write);
1213 if (wr2 == NULL) {
1214 return NT_STATUS_NO_MEMORY;
1217 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1218 (second_stage_t)ntvfs_map_write_finish);
1219 if (!NT_STATUS_IS_OK(status)) {
1220 return status;
1223 wr2->writex.level = RAW_WRITE_GENERIC;
1225 switch (wr->generic.level) {
1226 case RAW_WRITE_WRITEX:
1227 status = NT_STATUS_INVALID_LEVEL;
1228 break;
1230 case RAW_WRITE_WRITE:
1231 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1232 wr2->writex.in.offset = wr->write.in.offset;
1233 wr2->writex.in.wmode = 0;
1234 wr2->writex.in.remaining = wr->write.in.remaining;
1235 wr2->writex.in.count = wr->write.in.count;
1236 wr2->writex.in.data = wr->write.in.data;
1237 status = ntvfs->ops->write(ntvfs, req, wr2);
1238 break;
1240 case RAW_WRITE_WRITEUNLOCK:
1241 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1242 wr2->writex.in.offset = wr->writeunlock.in.offset;
1243 wr2->writex.in.wmode = 0;
1244 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1245 wr2->writex.in.count = wr->writeunlock.in.count;
1246 wr2->writex.in.data = wr->writeunlock.in.data;
1247 status = ntvfs->ops->write(ntvfs, req, wr2);
1248 break;
1250 case RAW_WRITE_WRITECLOSE:
1251 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1252 wr2->writex.in.offset = wr->writeclose.in.offset;
1253 wr2->writex.in.wmode = 0;
1254 wr2->writex.in.remaining = 0;
1255 wr2->writex.in.count = wr->writeclose.in.count;
1256 wr2->writex.in.data = wr->writeclose.in.data;
1257 status = ntvfs->ops->write(ntvfs, req, wr2);
1258 break;
1260 case RAW_WRITE_SPLWRITE:
1261 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1262 wr2->writex.in.offset = 0;
1263 wr2->writex.in.wmode = 0;
1264 wr2->writex.in.remaining = 0;
1265 wr2->writex.in.count = wr->splwrite.in.count;
1266 wr2->writex.in.data = wr->splwrite.in.data;
1267 status = ntvfs->ops->write(ntvfs, req, wr2);
1268 break;
1270 case RAW_WRITE_SMB2:
1271 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1272 wr2->writex.in.offset = wr->smb2.in.offset;
1273 wr2->writex.in.wmode = 0;
1274 wr2->writex.in.remaining = 0;
1275 wr2->writex.in.count = wr->smb2.in.data.length;
1276 wr2->writex.in.data = wr->smb2.in.data.data;
1277 status = ntvfs->ops->write(ntvfs, req, wr2);
1280 return ntvfs_map_async_finish(req, status);
1285 NTVFS read generic to any mapper - finish the out mapping
1287 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1288 struct ntvfs_request *req,
1289 union smb_read *rd,
1290 union smb_read *rd2,
1291 NTSTATUS status)
1293 switch (rd->generic.level) {
1294 case RAW_READ_READ:
1295 rd->read.out.nread = rd2->generic.out.nread;
1296 break;
1297 case RAW_READ_READBRAW:
1298 rd->readbraw.out.nread = rd2->generic.out.nread;
1299 break;
1300 case RAW_READ_LOCKREAD:
1301 rd->lockread.out.nread = rd2->generic.out.nread;
1302 break;
1303 case RAW_READ_SMB2:
1304 rd->smb2.out.data.length= rd2->generic.out.nread;
1305 rd->smb2.out.remaining = 0;
1306 rd->smb2.out.reserved = 0;
1307 break;
1308 default:
1309 return NT_STATUS_INVALID_LEVEL;
1312 return status;
1316 NTVFS read* to readx mapper
1318 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1319 struct ntvfs_request *req,
1320 union smb_read *rd)
1322 union smb_read *rd2;
1323 union smb_lock *lck;
1324 NTSTATUS status;
1325 uint_t state;
1327 rd2 = talloc(req, union smb_read);
1328 if (rd2 == NULL) {
1329 return NT_STATUS_NO_MEMORY;
1332 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1333 (second_stage_t)ntvfs_map_read_finish);
1334 if (!NT_STATUS_IS_OK(status)) {
1335 return status;
1338 rd2->readx.level = RAW_READ_READX;
1339 rd2->readx.in.read_for_execute = false;
1341 switch (rd->generic.level) {
1342 case RAW_READ_READX:
1343 status = NT_STATUS_INVALID_LEVEL;
1344 break;
1346 case RAW_READ_READ:
1347 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1348 rd2->readx.in.offset = rd->read.in.offset;
1349 rd2->readx.in.mincnt = rd->read.in.count;
1350 rd2->readx.in.maxcnt = rd->read.in.count;
1351 rd2->readx.in.remaining = rd->read.in.remaining;
1352 rd2->readx.out.data = rd->read.out.data;
1353 status = ntvfs->ops->read(ntvfs, req, rd2);
1354 break;
1356 case RAW_READ_READBRAW:
1357 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1358 rd2->readx.in.offset = rd->readbraw.in.offset;
1359 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1360 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1361 rd2->readx.in.remaining = 0;
1362 rd2->readx.out.data = rd->readbraw.out.data;
1363 status = ntvfs->ops->read(ntvfs, req, rd2);
1364 break;
1366 case RAW_READ_LOCKREAD:
1367 /* do the initial lock sync for now */
1368 state = req->async_states->state;
1369 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1371 lck = talloc(rd2, union smb_lock);
1372 if (lck == NULL) {
1373 status = NT_STATUS_NO_MEMORY;
1374 goto done;
1376 lck->lock.level = RAW_LOCK_LOCK;
1377 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1378 lck->lock.in.count = rd->lockread.in.count;
1379 lck->lock.in.offset = rd->lockread.in.offset;
1380 status = ntvfs->ops->lock(ntvfs, req, lck);
1381 req->async_states->state = state;
1383 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1384 rd2->readx.in.offset = rd->lockread.in.offset;
1385 rd2->readx.in.mincnt = rd->lockread.in.count;
1386 rd2->readx.in.maxcnt = rd->lockread.in.count;
1387 rd2->readx.in.remaining = rd->lockread.in.remaining;
1388 rd2->readx.out.data = rd->lockread.out.data;
1390 if (NT_STATUS_IS_OK(status)) {
1391 status = ntvfs->ops->read(ntvfs, req, rd2);
1393 break;
1395 case RAW_READ_SMB2:
1396 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1397 rd2->readx.in.offset = rd->smb2.in.offset;
1398 rd2->readx.in.mincnt = rd->smb2.in.min_count;
1399 rd2->readx.in.maxcnt = rd->smb2.in.length;
1400 rd2->readx.in.remaining = 0;
1401 rd2->readx.out.data = rd->smb2.out.data.data;
1402 status = ntvfs->ops->read(ntvfs, req, rd2);
1403 break;
1406 done:
1407 return ntvfs_map_async_finish(req, status);
1412 NTVFS close generic to any mapper
1414 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1415 struct ntvfs_request *req,
1416 union smb_close *cl,
1417 union smb_close *cl2,
1418 NTSTATUS status)
1420 NT_STATUS_NOT_OK_RETURN(status);
1422 switch (cl->generic.level) {
1423 case RAW_CLOSE_SMB2:
1424 cl->smb2.out.flags = cl2->generic.out.flags;
1425 cl->smb2.out._pad = 0;
1426 cl->smb2.out.create_time = cl2->generic.out.create_time;
1427 cl->smb2.out.access_time = cl2->generic.out.access_time;
1428 cl->smb2.out.write_time = cl2->generic.out.write_time;
1429 cl->smb2.out.change_time = cl2->generic.out.change_time;
1430 cl->smb2.out.alloc_size = cl2->generic.out.alloc_size;
1431 cl->smb2.out.size = cl2->generic.out.size;
1432 cl->smb2.out.file_attr = cl2->generic.out.file_attr;
1433 break;
1434 default:
1435 break;
1438 return status;
1442 NTVFS close generic to any mapper
1444 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1445 struct ntvfs_request *req,
1446 union smb_close *cl)
1448 union smb_close *cl2;
1449 NTSTATUS status;
1451 cl2 = talloc(req, union smb_close);
1452 if (cl2 == NULL) {
1453 return NT_STATUS_NO_MEMORY;
1456 switch (cl->generic.level) {
1457 case RAW_CLOSE_GENERIC:
1458 return NT_STATUS_INVALID_LEVEL;
1460 case RAW_CLOSE_CLOSE:
1461 cl2->generic.level = RAW_CLOSE_GENERIC;
1462 cl2->generic.in.file = cl->close.in.file;
1463 cl2->generic.in.write_time = cl->close.in.write_time;
1464 cl2->generic.in.flags = 0;
1465 break;
1467 case RAW_CLOSE_SPLCLOSE:
1468 cl2->generic.level = RAW_CLOSE_GENERIC;
1469 cl2->generic.in.file = cl->splclose.in.file;
1470 cl2->generic.in.write_time = 0;
1471 cl2->generic.in.flags = 0;
1472 break;
1474 case RAW_CLOSE_SMB2:
1475 cl2->generic.level = RAW_CLOSE_GENERIC;
1476 cl2->generic.in.file = cl->smb2.in.file;
1477 cl2->generic.in.write_time = 0;
1478 cl2->generic.in.flags = cl->smb2.in.flags;
1479 break;
1482 status = ntvfs_map_async_setup(ntvfs, req, cl, cl2,
1483 (second_stage_t)ntvfs_map_close_finish);
1484 NT_STATUS_NOT_OK_RETURN(status);
1486 status = ntvfs->ops->close(ntvfs, req, cl2);
1488 return ntvfs_map_async_finish(req, status);
1492 NTVFS notify generic to any mapper
1494 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1495 struct ntvfs_request *req,
1496 union smb_notify *nt,
1497 union smb_notify *nt2,
1498 NTSTATUS status)
1500 NT_STATUS_NOT_OK_RETURN(status);
1502 switch (nt->nttrans.level) {
1503 case RAW_NOTIFY_SMB2:
1504 if (nt2->nttrans.out.num_changes == 0) {
1505 return STATUS_NOTIFY_ENUM_DIR;
1507 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1508 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1509 break;
1511 default:
1512 return NT_STATUS_INVALID_LEVEL;
1515 return status;
1520 NTVFS notify generic to any mapper
1522 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1523 struct ntvfs_request *req,
1524 union smb_notify *nt)
1526 union smb_notify *nt2;
1527 NTSTATUS status;
1529 nt2 = talloc(req, union smb_notify);
1530 NT_STATUS_HAVE_NO_MEMORY(nt2);
1532 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1533 (second_stage_t)ntvfs_map_notify_finish);
1534 NT_STATUS_NOT_OK_RETURN(status);
1536 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1538 switch (nt->nttrans.level) {
1539 case RAW_NOTIFY_NTTRANS:
1540 status = NT_STATUS_INVALID_LEVEL;
1541 break;
1543 case RAW_NOTIFY_SMB2:
1544 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1545 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1546 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1547 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1548 status = ntvfs->ops->notify(ntvfs, req, nt2);
1549 break;
1552 return ntvfs_map_async_finish(req, status);