vfs_fruit: never return AFP_Resource stream for directories
[Samba.git] / source4 / ntvfs / ntvfs_generic.c
blobde0ae2ce8280363c4eaf7b4afe3d11b7e0078cfb
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 #undef strcasecmp
40 /* a second stage function converts from the out parameters of the generic
41 call onto the out parameters of the specific call made */
42 typedef NTSTATUS (*second_stage_t)(struct ntvfs_module_context *,
43 struct ntvfs_request *,
44 void *, void *, NTSTATUS);
46 /*
47 this structure holds the async state for pending mapped async calls
49 struct ntvfs_map_async {
50 struct ntvfs_module_context *ntvfs;
51 void *io, *io2;
52 second_stage_t fn;
56 this is a async wrapper, called from the backend when it has completed
57 a function that it has decided to reply to in an async fashion
59 static void ntvfs_map_async_send(struct ntvfs_request *req)
61 struct ntvfs_map_async *m = talloc_get_type(req->async_states->private_data,
62 struct ntvfs_map_async);
64 ntvfs_async_state_pop(req);
66 /* call the _finish function setup in ntvfs_map_async_setup() */
67 req->async_states->status = m->fn(m->ntvfs, req, m->io, m->io2, req->async_states->status);
69 /* call the send function from the next module up */
70 req->async_states->send_fn(req);
74 prepare for calling a ntvfs backend with async support
75 io is the original call structure
76 io2 is the new call structure for the mapped call
77 fn is a second stage function for processing the out arguments
79 static NTSTATUS ntvfs_map_async_setup(struct ntvfs_module_context *ntvfs,
80 struct ntvfs_request *req,
81 void *io, void *io2,
82 second_stage_t fn)
84 struct ntvfs_map_async *m;
85 m = talloc(req, struct ntvfs_map_async);
86 if (m == NULL) {
87 return NT_STATUS_NO_MEMORY;
89 m->ntvfs = ntvfs;
90 m->io = io;
91 m->io2 = io2;
92 m->fn = fn;
93 return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
97 called when first stage processing is complete.
98 */
99 static NTSTATUS ntvfs_map_async_finish(struct ntvfs_request *req, NTSTATUS status)
101 struct ntvfs_map_async *m;
103 /* if the backend has decided to reply in an async fashion then
104 we don't need to do any work here */
105 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
106 return status;
109 /* the backend is replying immediately. call the 2nd stage function after popping our local
110 async state */
111 m = talloc_get_type(req->async_states->private_data,
112 struct ntvfs_map_async);
114 ntvfs_async_state_pop(req);
116 return m->fn(m->ntvfs, req, m->io, m->io2, status);
120 see if a filename ends in EXE COM DLL or SYM. This is needed for the
121 DENY_DOS mapping for OpenX
123 bool is_exe_filename(const char *fname)
125 char *p;
126 p = strrchr(fname, '.');
127 if (!p) {
128 return false;
130 p++;
131 if (strcasecmp(p, "EXE") == 0 ||
132 strcasecmp(p, "COM") == 0 ||
133 strcasecmp(p, "DLL") == 0 ||
134 strcasecmp(p, "SYM") == 0) {
135 return true;
137 return false;
142 NTVFS openx to ntcreatex mapper
144 static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
145 struct ntvfs_request *req,
146 union smb_open *io,
147 union smb_open *io2,
148 NTSTATUS status)
150 time_t write_time = 0;
151 uint32_t set_size = 0;
152 union smb_setfileinfo *sf;
153 unsigned int state;
155 if (!NT_STATUS_IS_OK(status)) {
156 return status;
159 switch (io->generic.level) {
160 case RAW_OPEN_OPEN:
161 io->openold.out.file.ntvfs = io2->generic.out.file.ntvfs;
162 io->openold.out.attrib = io2->generic.out.attrib;
163 io->openold.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
164 io->openold.out.size = io2->generic.out.size;
165 io->openold.out.rmode = io->openold.in.open_mode;
166 break;
168 case RAW_OPEN_OPENX:
169 io->openx.out.file.ntvfs = io2->generic.out.file.ntvfs;
170 io->openx.out.attrib = io2->generic.out.attrib;
171 io->openx.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
172 io->openx.out.size = io2->generic.out.size;
173 io->openx.out.access = (io->openx.in.open_mode & OPENX_MODE_ACCESS_MASK);
174 io->openx.out.ftype = 0;
175 io->openx.out.devstate = 0;
176 io->openx.out.action = io2->generic.out.create_action;
177 io->openx.out.unique_fid = 0;
178 io->openx.out.access_mask = SEC_STD_ALL;
179 io->openx.out.unknown = 0;
181 /* we need to extend the file to the requested size if
182 it was newly created */
183 if (io2->generic.out.create_action == NTCREATEX_ACTION_CREATED) {
184 set_size = io->openx.in.size;
186 break;
188 case RAW_OPEN_T2OPEN:
189 io->t2open.out.file.ntvfs = io2->generic.out.file.ntvfs;
190 io->t2open.out.attrib = io2->generic.out.attrib;
191 io->t2open.out.write_time = nt_time_to_unix(io2->generic.out.write_time);
192 io->t2open.out.size = io2->generic.out.size;
193 io->t2open.out.access = io->t2open.in.open_mode;
194 io->t2open.out.ftype = 0;
195 io->t2open.out.devstate = 0;
196 io->t2open.out.action = io2->generic.out.create_action;
197 io->t2open.out.file_id = 0;
198 break;
200 case RAW_OPEN_MKNEW:
201 case RAW_OPEN_CREATE:
202 io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
203 write_time = io->mknew.in.write_time;
204 break;
206 case RAW_OPEN_CTEMP:
207 io->ctemp.out.file.ntvfs= io2->generic.out.file.ntvfs;
208 io->ctemp.out.name = talloc_strdup(req, io2->generic.in.fname +
209 strlen(io->ctemp.in.directory) + 1);
210 NT_STATUS_HAVE_NO_MEMORY(io->ctemp.out.name);
211 break;
213 case RAW_OPEN_SMB2:
214 ZERO_STRUCT(io->smb2.out);
215 io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs;
216 switch (io2->generic.out.oplock_level) {
217 case BATCH_OPLOCK_RETURN:
218 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
219 break;
220 case EXCLUSIVE_OPLOCK_RETURN:
221 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
222 break;
223 case LEVEL_II_OPLOCK_RETURN:
224 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
225 break;
226 default:
227 io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
228 break;
230 io->smb2.out.reserved = 0;
231 io->smb2.out.create_action = io2->generic.out.create_action;
232 io->smb2.out.create_time = io2->generic.out.create_time;
233 io->smb2.out.access_time = io2->generic.out.access_time;
234 io->smb2.out.write_time = io2->generic.out.write_time;
235 io->smb2.out.change_time = io2->generic.out.change_time;
236 io->smb2.out.alloc_size = io2->generic.out.alloc_size;
237 io->smb2.out.size = io2->generic.out.size;
238 io->smb2.out.file_attr = io2->generic.out.attrib;
239 io->smb2.out.reserved2 = 0;
240 io->smb2.out.maximal_access = io2->generic.out.maximal_access;
241 memcpy(io->smb2.out.on_disk_id, io2->generic.out.on_disk_id,
242 sizeof(io2->generic.out.on_disk_id));
243 break;
245 default:
246 return NT_STATUS_INVALID_LEVEL;
249 /* doing a secondary request async is more trouble than its
250 worth */
251 state = req->async_states->state;
252 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
254 if (write_time != 0) {
255 sf = talloc(req, union smb_setfileinfo);
256 NT_STATUS_HAVE_NO_MEMORY(sf);
257 sf->generic.level = RAW_SFILEINFO_STANDARD;
258 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
259 sf->standard.in.create_time = 0;
260 sf->standard.in.write_time = write_time;
261 sf->standard.in.access_time = 0;
262 status = ntvfs->ops->setfileinfo_fn(ntvfs, req, sf);
265 if (set_size != 0) {
266 sf = talloc(req, union smb_setfileinfo);
267 NT_STATUS_HAVE_NO_MEMORY(sf);
268 sf->generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
269 sf->generic.in.file.ntvfs = io2->generic.out.file.ntvfs;
270 sf->end_of_file_info.in.size = set_size;
271 status = ntvfs->ops->setfileinfo_fn(ntvfs, req, sf);
272 if (NT_STATUS_IS_OK(status)) {
273 io->openx.out.size = io->openx.in.size;
277 req->async_states->state = state;
279 return NT_STATUS_OK;
283 the core of the mapping between openx style parameters and ntcreatex
284 parameters
286 static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
287 uint16_t open_func, const char *fname,
288 union smb_open *io2)
290 io2->generic.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
291 io2->generic.in.private_flags = 0;
293 if (flags & OPENX_FLAGS_REQUEST_OPLOCK) {
294 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_OPLOCK;
296 if (flags & OPENX_FLAGS_REQUEST_BATCH_OPLOCK) {
297 io2->generic.in.flags |= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
300 switch (open_mode & OPENX_MODE_ACCESS_MASK) {
301 case OPENX_MODE_ACCESS_READ:
302 case OPENX_MODE_ACCESS_EXEC:
303 io2->generic.in.access_mask = SEC_RIGHTS_FILE_READ;
304 break;
305 case OPENX_MODE_ACCESS_WRITE:
306 io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
307 break;
308 case OPENX_MODE_ACCESS_RDWR:
309 case OPENX_MODE_ACCESS_FCB:
310 io2->generic.in.access_mask =
311 SEC_RIGHTS_FILE_READ |
312 SEC_RIGHTS_FILE_WRITE;
313 break;
314 default:
315 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
318 switch (open_mode & OPENX_MODE_DENY_MASK) {
319 case OPENX_MODE_DENY_READ:
320 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_WRITE;
321 break;
322 case OPENX_MODE_DENY_WRITE:
323 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
324 break;
325 case OPENX_MODE_DENY_ALL:
326 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
327 break;
328 case OPENX_MODE_DENY_NONE:
329 io2->generic.in.share_access =
330 NTCREATEX_SHARE_ACCESS_READ |
331 NTCREATEX_SHARE_ACCESS_WRITE;
332 break;
333 case OPENX_MODE_DENY_DOS:
334 /* DENY_DOS is quite strange - it depends on the filename! */
335 io2->generic.in.private_flags |=
336 NTCREATEX_FLAG_DENY_DOS;
337 if (is_exe_filename(fname)) {
338 io2->generic.in.share_access =
339 NTCREATEX_SHARE_ACCESS_READ |
340 NTCREATEX_SHARE_ACCESS_WRITE;
341 } else {
342 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
343 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
344 } else {
345 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
348 break;
349 case OPENX_MODE_DENY_FCB:
350 io2->generic.in.private_flags |= NTCREATEX_FLAG_DENY_FCB;
351 io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
352 break;
353 default:
354 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
357 switch (open_func) {
358 case (OPENX_OPEN_FUNC_OPEN):
359 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
360 break;
361 case (OPENX_OPEN_FUNC_TRUNC):
362 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
363 break;
364 case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
365 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
366 break;
367 case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
368 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
369 break;
370 case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
371 io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
372 break;
373 default:
374 /* this one is very strange */
375 if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_EXEC) {
376 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
377 break;
379 return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
382 return NT_STATUS_OK;
386 NTVFS open generic to any mapper
388 NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
389 struct ntvfs_request *req,
390 union smb_open *io)
392 NTSTATUS status;
393 union smb_open *io2;
395 io2 = talloc_zero(req, union smb_open);
396 if (io2 == NULL) {
397 return NT_STATUS_NO_MEMORY;
400 status = ntvfs_map_async_setup(ntvfs, req,
401 io, io2,
402 (second_stage_t)ntvfs_map_open_finish);
403 if (!NT_STATUS_IS_OK(status)) {
404 return status;
407 io2->generic.level = RAW_OPEN_GENERIC;
409 switch (io->generic.level) {
410 case RAW_OPEN_OPENX:
411 status = map_openx_open(io->openx.in.flags,
412 io->openx.in.open_mode,
413 io->openx.in.open_func,
414 io->openx.in.fname,
415 io2);
416 if (!NT_STATUS_IS_OK(status)) {
417 goto done;
420 io2->generic.in.file_attr = io->openx.in.file_attrs;
421 io2->generic.in.fname = io->openx.in.fname;
423 status = ntvfs->ops->open_fn(ntvfs, req, io2);
424 break;
427 case RAW_OPEN_OPEN:
428 status = map_openx_open(0,
429 io->openold.in.open_mode,
430 OPENX_OPEN_FUNC_OPEN,
431 io->openold.in.fname,
432 io2);
433 if (!NT_STATUS_IS_OK(status)) {
434 goto done;
437 io2->generic.in.file_attr = io->openold.in.search_attrs;
438 io2->generic.in.fname = io->openold.in.fname;
440 status = ntvfs->ops->open_fn(ntvfs, req, io2);
441 break;
443 case RAW_OPEN_T2OPEN:
444 io2->generic.level = RAW_OPEN_NTTRANS_CREATE;
446 if (io->t2open.in.open_func == 0) {
447 status = NT_STATUS_OBJECT_NAME_COLLISION;
448 goto done;
451 status = map_openx_open(io->t2open.in.flags,
452 io->t2open.in.open_mode,
453 io->t2open.in.open_func,
454 io->t2open.in.fname,
455 io2);
456 if (!NT_STATUS_IS_OK(status)) {
457 goto done;
460 io2->generic.in.file_attr = io->t2open.in.file_attrs;
461 io2->generic.in.fname = io->t2open.in.fname;
462 io2->generic.in.ea_list = talloc(io2, struct smb_ea_list);
463 io2->generic.in.ea_list->num_eas = io->t2open.in.num_eas;
464 io2->generic.in.ea_list->eas = io->t2open.in.eas;
466 status = ntvfs->ops->open_fn(ntvfs, req, io2);
467 break;
469 case RAW_OPEN_MKNEW:
470 io2->generic.in.file_attr = io->mknew.in.attrib;
471 io2->generic.in.fname = io->mknew.in.fname;
472 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
473 io2->generic.in.access_mask =
474 SEC_RIGHTS_FILE_READ |
475 SEC_RIGHTS_FILE_WRITE;
476 io2->generic.in.share_access =
477 NTCREATEX_SHARE_ACCESS_READ |
478 NTCREATEX_SHARE_ACCESS_WRITE;
479 status = ntvfs->ops->open_fn(ntvfs, req, io2);
480 break;
482 case RAW_OPEN_CREATE:
483 io2->generic.in.file_attr = io->mknew.in.attrib;
484 io2->generic.in.fname = io->mknew.in.fname;
485 io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
486 io2->generic.in.access_mask =
487 SEC_RIGHTS_FILE_READ |
488 SEC_RIGHTS_FILE_WRITE;
489 io2->generic.in.share_access =
490 NTCREATEX_SHARE_ACCESS_READ |
491 NTCREATEX_SHARE_ACCESS_WRITE;
492 status = ntvfs->ops->open_fn(ntvfs, req, io2);
493 break;
495 case RAW_OPEN_CTEMP:
496 io2->generic.in.file_attr = io->ctemp.in.attrib;
497 io2->generic.in.fname =
498 talloc_asprintf(io2, "%s\\SRV%s",
499 io->ctemp.in.directory,
500 generate_random_str_list(io2, 5, "0123456789"));
501 io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
502 io2->generic.in.access_mask =
503 SEC_RIGHTS_FILE_READ |
504 SEC_RIGHTS_FILE_WRITE;
505 io2->generic.in.share_access =
506 NTCREATEX_SHARE_ACCESS_READ |
507 NTCREATEX_SHARE_ACCESS_WRITE;
508 status = ntvfs->ops->open_fn(ntvfs, req, io2);
509 break;
510 case RAW_OPEN_SMB2:
511 switch (io->smb2.in.oplock_level) {
512 case SMB2_OPLOCK_LEVEL_BATCH:
513 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK |
514 NTCREATEX_FLAGS_REQUEST_OPLOCK;
515 break;
516 case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
517 io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
518 break;
519 default:
520 io2->generic.in.flags = 0;
521 break;
523 io2->generic.in.root_fid.fnum = 0;
524 io2->generic.in.access_mask = io->smb2.in.desired_access;
525 io2->generic.in.alloc_size = io->smb2.in.alloc_size;
526 io2->generic.in.file_attr = io->smb2.in.file_attributes;
527 io2->generic.in.share_access = io->smb2.in.share_access;
528 io2->generic.in.open_disposition= io->smb2.in.create_disposition;
529 io2->generic.in.create_options = io->smb2.in.create_options;
530 io2->generic.in.impersonation = io->smb2.in.impersonation_level;
531 io2->generic.in.security_flags = 0;
532 io2->generic.in.fname = io->smb2.in.fname;
533 io2->generic.in.sec_desc = io->smb2.in.sec_desc;
534 io2->generic.in.ea_list = &io->smb2.in.eas;
535 io2->generic.in.query_maximal_access = io->smb2.in.query_maximal_access;
536 io2->generic.in.query_on_disk_id = io->smb2.in.query_on_disk_id;
537 io2->generic.in.private_flags = 0;
539 /* we don't support timewarp yet */
540 if (io->smb2.in.timewarp != 0) {
541 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
542 break;
545 /* we need to check these bits before we check the private mask */
546 if (io2->generic.in.create_options & SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK) {
547 DEBUG(2,(__location__ " create_options 0x%x not supported\n",
548 io2->generic.in.create_options));
549 status = NT_STATUS_NOT_SUPPORTED;
550 break;
553 /* TODO: find out why only SMB2 ignores these */
554 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_SYNC_ALERT;
555 io2->generic.in.create_options &= ~NTCREATEX_OPTIONS_ASYNC_ALERT;
557 status = ntvfs->ops->open_fn(ntvfs, req, io2);
558 break;
560 default:
561 status = NT_STATUS_INVALID_LEVEL;
562 break;
564 done:
565 return ntvfs_map_async_finish(req, status);
570 NTVFS any to fsinfo mapper
572 static NTSTATUS ntvfs_map_fsinfo_finish(struct ntvfs_module_context *ntvfs,
573 struct ntvfs_request *req,
574 union smb_fsinfo *fs,
575 union smb_fsinfo *fs2,
576 NTSTATUS status)
578 if (!NT_STATUS_IS_OK(status)) {
579 return status;
582 /* and convert it to the required level */
583 switch (fs->generic.level) {
584 case RAW_QFS_DSKATTR: {
585 /* map from generic to DSKATTR */
586 unsigned int bpunit = 64;
588 /* we need to scale the sizes to fit */
589 for (bpunit=64; bpunit<0x10000; bpunit *= 2) {
590 if (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size < bpunit * 512 * 65535.0) {
591 break;
595 fs->dskattr.out.blocks_per_unit = bpunit;
596 fs->dskattr.out.block_size = 512;
597 fs->dskattr.out.units_total =
598 (fs2->generic.out.blocks_total * (double)fs2->generic.out.block_size) / (bpunit * 512);
599 fs->dskattr.out.units_free =
600 (fs2->generic.out.blocks_free * (double)fs2->generic.out.block_size) / (bpunit * 512);
602 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
603 if (bpunit > 64 && req->ctx->protocol <= PROTOCOL_LANMAN2) {
604 fs->dskattr.out.blocks_per_unit = 64;
605 fs->dskattr.out.units_total = 0xFFFF;
606 fs->dskattr.out.units_free = 0xFFFF;
608 return NT_STATUS_OK;
611 case RAW_QFS_ALLOCATION:
612 fs->allocation.out.fs_id = fs2->generic.out.fs_id;
613 fs->allocation.out.total_alloc_units = fs2->generic.out.blocks_total;
614 fs->allocation.out.avail_alloc_units = fs2->generic.out.blocks_free;
615 fs->allocation.out.sectors_per_unit = 1;
616 fs->allocation.out.bytes_per_sector = fs2->generic.out.block_size;
617 return NT_STATUS_OK;
619 case RAW_QFS_VOLUME:
620 fs->volume.out.serial_number = fs2->generic.out.serial_number;
621 fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
622 return NT_STATUS_OK;
624 case RAW_QFS_VOLUME_INFO:
625 case RAW_QFS_VOLUME_INFORMATION:
626 fs->volume_info.out.create_time = fs2->generic.out.create_time;
627 fs->volume_info.out.serial_number = fs2->generic.out.serial_number;
628 fs->volume_info.out.volume_name.s = fs2->generic.out.volume_name;
629 return NT_STATUS_OK;
631 case RAW_QFS_SIZE_INFO:
632 case RAW_QFS_SIZE_INFORMATION:
633 fs->size_info.out.total_alloc_units = fs2->generic.out.blocks_total;
634 fs->size_info.out.avail_alloc_units = fs2->generic.out.blocks_free;
635 fs->size_info.out.sectors_per_unit = 1;
636 fs->size_info.out.bytes_per_sector = fs2->generic.out.block_size;
637 return NT_STATUS_OK;
639 case RAW_QFS_DEVICE_INFO:
640 case RAW_QFS_DEVICE_INFORMATION:
641 fs->device_info.out.device_type = fs2->generic.out.device_type;
642 fs->device_info.out.characteristics = fs2->generic.out.device_characteristics;
643 return NT_STATUS_OK;
645 case RAW_QFS_ATTRIBUTE_INFO:
646 case RAW_QFS_ATTRIBUTE_INFORMATION:
647 fs->attribute_info.out.fs_attr = fs2->generic.out.fs_attr;
648 fs->attribute_info.out.max_file_component_length = fs2->generic.out.max_file_component_length;
649 fs->attribute_info.out.fs_type.s = fs2->generic.out.fs_type;
650 return NT_STATUS_OK;
652 case RAW_QFS_QUOTA_INFORMATION:
653 ZERO_STRUCT(fs->quota_information.out.unknown);
654 fs->quota_information.out.quota_soft = fs2->generic.out.quota_soft;
655 fs->quota_information.out.quota_hard = fs2->generic.out.quota_hard;
656 fs->quota_information.out.quota_flags = fs2->generic.out.quota_flags;
657 return NT_STATUS_OK;
659 case RAW_QFS_FULL_SIZE_INFORMATION:
660 fs->full_size_information.out.total_alloc_units = fs2->generic.out.blocks_total;
661 fs->full_size_information.out.call_avail_alloc_units = fs2->generic.out.blocks_free;
662 fs->full_size_information.out.actual_avail_alloc_units = fs2->generic.out.blocks_free;
663 fs->full_size_information.out.sectors_per_unit = 1;
664 fs->full_size_information.out.bytes_per_sector = fs2->generic.out.block_size;
665 return NT_STATUS_OK;
667 case RAW_QFS_OBJECTID_INFORMATION:
668 fs->objectid_information.out.guid = fs2->generic.out.guid;
669 ZERO_STRUCT(fs->objectid_information.out.unknown);
670 return NT_STATUS_OK;
672 case RAW_QFS_SECTOR_SIZE_INFORMATION:
673 fs->sector_size_info.out.logical_bytes_per_sector
674 = fs2->generic.out.block_size;
675 fs->sector_size_info.out.phys_bytes_per_sector_atomic
676 = fs2->generic.out.block_size;
677 fs->sector_size_info.out.phys_bytes_per_sector_perf
678 = fs2->generic.out.block_size;
679 fs->sector_size_info.out.fs_effective_phys_bytes_per_sector_atomic
680 = fs2->generic.out.block_size;
681 fs->sector_size_info.out.flags
682 = QFS_SSINFO_FLAGS_ALIGNED_DEVICE
683 | QFS_SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE;
684 fs->sector_size_info.out.byte_off_sector_align = 0;
685 fs->sector_size_info.out.byte_off_partition_align = 0;
686 return NT_STATUS_OK;
688 case RAW_QFS_GENERIC:
689 case RAW_QFS_UNIX_INFO:
690 return NT_STATUS_INVALID_LEVEL;
693 return NT_STATUS_INVALID_LEVEL;
697 NTVFS fsinfo any to generic mapper
699 NTSTATUS ntvfs_map_fsinfo(struct ntvfs_module_context *ntvfs,
700 struct ntvfs_request *req,
701 union smb_fsinfo *fs)
703 NTSTATUS status;
704 union smb_fsinfo *fs2;
706 fs2 = talloc(req, union smb_fsinfo);
707 if (fs2 == NULL) {
708 return NT_STATUS_NO_MEMORY;
711 if (fs->generic.level == RAW_QFS_GENERIC) {
712 return NT_STATUS_INVALID_LEVEL;
715 status = ntvfs_map_async_setup(ntvfs, req, fs, fs2,
716 (second_stage_t)ntvfs_map_fsinfo_finish);
717 if (!NT_STATUS_IS_OK(status)) {
718 return status;
721 /* ask the backend for the generic info */
722 fs2->generic.level = RAW_QFS_GENERIC;
724 status = ntvfs->ops->fsinfo_fn(ntvfs, req, fs2);
725 return ntvfs_map_async_finish(req, status);
730 NTVFS fileinfo generic to any mapper
732 NTSTATUS ntvfs_map_fileinfo(TALLOC_CTX *mem_ctx,
733 union smb_fileinfo *info,
734 union smb_fileinfo *info2)
736 int i;
737 /* and convert it to the required level using results in info2 */
738 switch (info->generic.level) {
739 case RAW_FILEINFO_GETATTR:
740 info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
741 info->getattr.out.size = info2->generic.out.size;
742 info->getattr.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
743 return NT_STATUS_OK;
745 case RAW_FILEINFO_GETATTRE:
746 info->getattre.out.attrib = info2->generic.out.attrib;
747 info->getattre.out.size = info2->generic.out.size;
748 info->getattre.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
749 info->getattre.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
750 info->getattre.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
751 info->getattre.out.alloc_size = info2->generic.out.alloc_size;
752 return NT_STATUS_OK;
754 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
755 info->network_open_information.out.create_time = info2->generic.out.create_time;
756 info->network_open_information.out.access_time = info2->generic.out.access_time;
757 info->network_open_information.out.write_time = info2->generic.out.write_time;
758 info->network_open_information.out.change_time = info2->generic.out.change_time;
759 info->network_open_information.out.alloc_size = info2->generic.out.alloc_size;
760 info->network_open_information.out.size = info2->generic.out.size;
761 info->network_open_information.out.attrib = info2->generic.out.attrib;
762 return NT_STATUS_OK;
764 case RAW_FILEINFO_ALL_INFO:
765 case RAW_FILEINFO_ALL_INFORMATION:
766 info->all_info.out.create_time = info2->generic.out.create_time;
767 info->all_info.out.access_time = info2->generic.out.access_time;
768 info->all_info.out.write_time = info2->generic.out.write_time;
769 info->all_info.out.change_time = info2->generic.out.change_time;
770 info->all_info.out.attrib = info2->generic.out.attrib;
771 info->all_info.out.alloc_size = info2->generic.out.alloc_size;
772 info->all_info.out.size = info2->generic.out.size;
773 info->all_info.out.nlink = info2->generic.out.nlink;
774 info->all_info.out.delete_pending = info2->generic.out.delete_pending;
775 info->all_info.out.directory = info2->generic.out.directory;
776 info->all_info.out.ea_size = info2->generic.out.ea_size;
777 info->all_info.out.fname.s = info2->generic.out.fname.s;
778 info->all_info.out.fname.private_length = info2->generic.out.fname.private_length;
779 return NT_STATUS_OK;
781 case RAW_FILEINFO_BASIC_INFO:
782 case RAW_FILEINFO_BASIC_INFORMATION:
783 info->basic_info.out.create_time = info2->generic.out.create_time;
784 info->basic_info.out.access_time = info2->generic.out.access_time;
785 info->basic_info.out.write_time = info2->generic.out.write_time;
786 info->basic_info.out.change_time = info2->generic.out.change_time;
787 info->basic_info.out.attrib = info2->generic.out.attrib;
788 return NT_STATUS_OK;
790 case RAW_FILEINFO_STANDARD:
791 info->standard.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
792 info->standard.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
793 info->standard.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
794 info->standard.out.size = info2->generic.out.size;
795 info->standard.out.alloc_size = info2->generic.out.alloc_size;
796 info->standard.out.attrib = info2->generic.out.attrib;
797 return NT_STATUS_OK;
799 case RAW_FILEINFO_EA_SIZE:
800 info->ea_size.out.create_time = nt_time_to_unix(info2->generic.out.create_time);
801 info->ea_size.out.access_time = nt_time_to_unix(info2->generic.out.access_time);
802 info->ea_size.out.write_time = nt_time_to_unix(info2->generic.out.write_time);
803 info->ea_size.out.size = info2->generic.out.size;
804 info->ea_size.out.alloc_size = info2->generic.out.alloc_size;
805 info->ea_size.out.attrib = info2->generic.out.attrib;
806 info->ea_size.out.ea_size = info2->generic.out.ea_size;
807 return NT_STATUS_OK;
809 case RAW_FILEINFO_STANDARD_INFO:
810 case RAW_FILEINFO_STANDARD_INFORMATION:
811 info->standard_info.out.alloc_size = info2->generic.out.alloc_size;
812 info->standard_info.out.size = info2->generic.out.size;
813 info->standard_info.out.nlink = info2->generic.out.nlink;
814 info->standard_info.out.delete_pending = info2->generic.out.delete_pending;
815 info->standard_info.out.directory = info2->generic.out.directory;
816 return NT_STATUS_OK;
818 case RAW_FILEINFO_INTERNAL_INFORMATION:
819 info->internal_information.out.file_id = info2->generic.out.file_id;
820 return NT_STATUS_OK;
822 case RAW_FILEINFO_EA_INFO:
823 case RAW_FILEINFO_EA_INFORMATION:
824 info->ea_info.out.ea_size = info2->generic.out.ea_size;
825 return NT_STATUS_OK;
827 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
828 info->attribute_tag_information.out.attrib = info2->generic.out.attrib;
829 info->attribute_tag_information.out.reparse_tag = info2->generic.out.reparse_tag;
830 return NT_STATUS_OK;
832 case RAW_FILEINFO_STREAM_INFO:
833 case RAW_FILEINFO_STREAM_INFORMATION:
834 info->stream_info.out.num_streams = info2->generic.out.num_streams;
835 if (info->stream_info.out.num_streams > 0) {
836 info->stream_info.out.streams =
837 talloc_array(mem_ctx,
838 struct stream_struct,
839 info->stream_info.out.num_streams);
840 if (!info->stream_info.out.streams) {
841 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
842 info->stream_info.out.num_streams));
843 return NT_STATUS_NO_MEMORY;
845 for (i=0; i < info->stream_info.out.num_streams; i++) {
846 info->stream_info.out.streams[i] = info2->generic.out.streams[i];
847 info->stream_info.out.streams[i].stream_name.s =
848 talloc_strdup(info->stream_info.out.streams,
849 info2->generic.out.streams[i].stream_name.s);
850 if (!info->stream_info.out.streams[i].stream_name.s) {
851 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
852 return NT_STATUS_NO_MEMORY;
856 return NT_STATUS_OK;
858 case RAW_FILEINFO_NAME_INFO:
859 case RAW_FILEINFO_NAME_INFORMATION:
860 info->name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.fname.s);
861 NT_STATUS_HAVE_NO_MEMORY(info->name_info.out.fname.s);
862 info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
863 return NT_STATUS_OK;
865 case RAW_FILEINFO_ALT_NAME_INFO:
866 case RAW_FILEINFO_ALT_NAME_INFORMATION:
867 case RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION:
868 info->alt_name_info.out.fname.s = talloc_strdup(mem_ctx, info2->generic.out.alt_fname.s);
869 NT_STATUS_HAVE_NO_MEMORY(info->alt_name_info.out.fname.s);
870 info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
871 return NT_STATUS_OK;
873 case RAW_FILEINFO_POSITION_INFORMATION:
874 info->position_information.out.position = info2->generic.out.position;
875 return NT_STATUS_OK;
877 case RAW_FILEINFO_ALL_EAS:
878 info->all_eas.out.num_eas = info2->generic.out.num_eas;
879 if (info->all_eas.out.num_eas > 0) {
880 info->all_eas.out.eas = talloc_array(mem_ctx,
881 struct ea_struct,
882 info->all_eas.out.num_eas);
883 if (!info->all_eas.out.eas) {
884 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
885 info->all_eas.out.num_eas));
886 return NT_STATUS_NO_MEMORY;
888 for (i = 0; i < info->all_eas.out.num_eas; i++) {
889 info->all_eas.out.eas[i] = info2->generic.out.eas[i];
890 info->all_eas.out.eas[i].name.s =
891 talloc_strdup(info->all_eas.out.eas,
892 info2->generic.out.eas[i].name.s);
893 if (!info->all_eas.out.eas[i].name.s) {
894 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
895 return NT_STATUS_NO_MEMORY;
897 info->all_eas.out.eas[i].value.data =
898 (uint8_t *)talloc_memdup(info->all_eas.out.eas,
899 info2->generic.out.eas[i].value.data,
900 info2->generic.out.eas[i].value.length);
901 if (!info->all_eas.out.eas[i].value.data) {
902 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
903 return NT_STATUS_NO_MEMORY;
907 return NT_STATUS_OK;
909 case RAW_FILEINFO_IS_NAME_VALID:
910 return NT_STATUS_OK;
912 case RAW_FILEINFO_COMPRESSION_INFO:
913 case RAW_FILEINFO_COMPRESSION_INFORMATION:
914 info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
915 info->compression_info.out.format = info2->generic.out.format;
916 info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
917 info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
918 info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
919 return NT_STATUS_OK;
921 case RAW_FILEINFO_ACCESS_INFORMATION:
922 info->access_information.out.access_flags = info2->generic.out.access_flags;
923 return NT_STATUS_OK;
925 case RAW_FILEINFO_MODE_INFORMATION:
926 info->mode_information.out.mode = info2->generic.out.mode;
927 return NT_STATUS_OK;
929 case RAW_FILEINFO_ALIGNMENT_INFORMATION:
930 info->alignment_information.out.alignment_requirement =
931 info2->generic.out.alignment_requirement;
932 return NT_STATUS_OK;
933 case RAW_FILEINFO_UNIX_BASIC:
934 #if 1
935 return NT_STATUS_INVALID_LEVEL;
936 #else
937 info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
938 info->unix_basic_info.out.num_bytes = info2->generic.out.size;
939 info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
940 info->unix_basic_info.out.access_time = info2->generic.out.access_time;
941 info->unix_basic_info.out.change_time = info2->generic.out.change_time;
942 info->unix_basic_info.out.uid = info2->generic.out.uid;
943 info->unix_basic_info.out.gid = info2->generic.out.gid;
944 info->unix_basic_info.out.file_type = info2->generic.out.file_type;
945 info->unix_basic_info.out.dev_major = info2->generic.out.device;
946 info->unix_basic_info.out.dev_minor = info2->generic.out.device;
947 info->unix_basic_info.out.unique_id = info2->generic.out.inode;
948 info->unix_basic_info.out.permissions = info2->generic.out.permissions;
949 info->unix_basic_info.out.nlink = info2->generic.out.nlink;
950 return NT_STATUS_OK;
951 #endif
952 case RAW_FILEINFO_UNIX_LINK:
953 #if 1
954 return NT_STATUS_INVALID_LEVEL;
955 #else
956 info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
957 return NT_STATUS_OK;
958 #endif
959 case RAW_FILEINFO_GENERIC:
960 case RAW_FILEINFO_SEC_DESC:
961 case RAW_FILEINFO_EA_LIST:
962 case RAW_FILEINFO_UNIX_INFO2:
963 case RAW_FILEINFO_SMB2_ALL_EAS:
964 case RAW_FILEINFO_SMB2_ALL_INFORMATION:
965 return NT_STATUS_INVALID_LEVEL;
966 case RAW_FILEINFO_NORMALIZED_NAME_INFORMATION:
967 return NT_STATUS_NOT_SUPPORTED;
970 return NT_STATUS_INVALID_LEVEL;
974 NTVFS any to fileinfo mapper
976 static NTSTATUS ntvfs_map_qfileinfo_finish(struct ntvfs_module_context *ntvfs,
977 struct ntvfs_request *req,
978 union smb_fileinfo *info,
979 union smb_fileinfo *info2,
980 NTSTATUS status)
982 if (!NT_STATUS_IS_OK(status)) {
983 return status;
986 return ntvfs_map_fileinfo(req, info, info2);
990 NTVFS fileinfo generic to any mapper
992 NTSTATUS ntvfs_map_qfileinfo(struct ntvfs_module_context *ntvfs,
993 struct ntvfs_request *req,
994 union smb_fileinfo *info)
996 NTSTATUS status;
997 union smb_fileinfo *info2;
999 info2 = talloc(req, union smb_fileinfo);
1000 if (info2 == NULL) {
1001 return NT_STATUS_NO_MEMORY;
1004 if (info->generic.level == RAW_FILEINFO_GENERIC) {
1005 return NT_STATUS_INVALID_LEVEL;
1008 status = ntvfs_map_async_setup(ntvfs, req, info, info2,
1009 (second_stage_t)ntvfs_map_qfileinfo_finish);
1010 if (!NT_STATUS_IS_OK(status)) {
1011 return status;
1014 /* ask the backend for the generic info */
1015 info2->generic.level = RAW_FILEINFO_GENERIC;
1016 info2->generic.in.file.ntvfs= info->generic.in.file.ntvfs;
1018 status = ntvfs->ops->qfileinfo_fn(ntvfs, req, info2);
1019 return ntvfs_map_async_finish(req, status);
1023 NTVFS any to fileinfo mapper
1025 static NTSTATUS ntvfs_map_qpathinfo_finish(struct ntvfs_module_context *ntvfs,
1026 struct ntvfs_request *req,
1027 union smb_fileinfo *info,
1028 union smb_fileinfo *info2,
1029 NTSTATUS status)
1031 if (!NT_STATUS_IS_OK(status)) {
1032 return status;
1035 return ntvfs_map_fileinfo(req, info, info2);
1039 NTVFS pathinfo generic to any mapper
1041 NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs,
1042 struct ntvfs_request *req,
1043 union smb_fileinfo *info)
1045 NTSTATUS status;
1046 union smb_fileinfo *info2;
1048 info2 = talloc(req, union smb_fileinfo);
1049 if (info2 == NULL) {
1050 return NT_STATUS_NO_MEMORY;
1053 if (info->generic.level == RAW_FILEINFO_GENERIC) {
1054 return NT_STATUS_INVALID_LEVEL;
1057 status = ntvfs_map_async_setup(ntvfs, req, info, info2,
1058 (second_stage_t)ntvfs_map_qpathinfo_finish);
1059 if (!NT_STATUS_IS_OK(status)) {
1060 return status;
1063 /* ask the backend for the generic info */
1064 info2->generic.level = RAW_FILEINFO_GENERIC;
1065 info2->generic.in.file.path = info->generic.in.file.path;
1067 status = ntvfs->ops->qpathinfo_fn(ntvfs, req, info2);
1068 return ntvfs_map_async_finish(req, status);
1073 NTVFS lock generic to any mapper
1075 NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs,
1076 struct ntvfs_request *req,
1077 union smb_lock *lck)
1079 union smb_lock *lck2;
1080 struct smb_lock_entry *locks;
1082 lck2 = talloc(req, union smb_lock);
1083 if (lck2 == NULL) {
1084 return NT_STATUS_NO_MEMORY;
1087 locks = talloc_array(lck2, struct smb_lock_entry, 1);
1088 if (locks == NULL) {
1089 return NT_STATUS_NO_MEMORY;
1092 switch (lck->generic.level) {
1093 case RAW_LOCK_LOCKX:
1094 return NT_STATUS_INVALID_LEVEL;
1096 case RAW_LOCK_LOCK:
1097 lck2->generic.level = RAW_LOCK_GENERIC;
1098 lck2->generic.in.file.ntvfs= lck->lock.in.file.ntvfs;
1099 lck2->generic.in.mode = 0;
1100 lck2->generic.in.timeout = 0;
1101 lck2->generic.in.ulock_cnt = 0;
1102 lck2->generic.in.lock_cnt = 1;
1103 lck2->generic.in.locks = locks;
1104 locks->pid = req->smbpid;
1105 locks->offset = lck->lock.in.offset;
1106 locks->count = lck->lock.in.count;
1107 break;
1109 case RAW_LOCK_UNLOCK:
1110 lck2->generic.level = RAW_LOCK_GENERIC;
1111 lck2->generic.in.file.ntvfs= lck->unlock.in.file.ntvfs;
1112 lck2->generic.in.mode = 0;
1113 lck2->generic.in.timeout = 0;
1114 lck2->generic.in.ulock_cnt = 1;
1115 lck2->generic.in.lock_cnt = 0;
1116 lck2->generic.in.locks = locks;
1117 locks->pid = req->smbpid;
1118 locks->offset = lck->unlock.in.offset;
1119 locks->count = lck->unlock.in.count;
1120 break;
1122 case RAW_LOCK_SMB2: {
1123 /* this is only approximate! We need to change the
1124 generic structure to fix this properly */
1125 int i;
1126 bool isunlock;
1127 if (lck->smb2.in.lock_count < 1) {
1128 return NT_STATUS_INVALID_PARAMETER;
1131 lck2->generic.level = RAW_LOCK_GENERIC;
1132 lck2->generic.in.file.ntvfs= lck->smb2.in.file.ntvfs;
1133 lck2->generic.in.timeout = UINT32_MAX;
1134 lck2->generic.in.mode = 0;
1135 lck2->generic.in.lock_cnt = 0;
1136 lck2->generic.in.ulock_cnt = 0;
1137 lck2->generic.in.locks = talloc_zero_array(lck2, struct smb_lock_entry,
1138 lck->smb2.in.lock_count);
1139 if (lck2->generic.in.locks == NULL) {
1140 return NT_STATUS_NO_MEMORY;
1142 /* only the first lock gives the UNLOCK bit - see
1143 MS-SMB2 3.3.5.14 */
1144 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1145 if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1146 return NT_STATUS_INVALID_PARAMETER;
1148 lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1149 isunlock = true;
1150 } else {
1151 lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1152 isunlock = false;
1154 for (i=0;i<lck->smb2.in.lock_count;i++) {
1155 if (!isunlock &&
1156 lck->smb2.in.locks[i].flags == SMB2_LOCK_FLAG_NONE) {
1157 return NT_STATUS_INVALID_PARAMETER;
1160 if (lck->smb2.in.locks[i].flags & ~SMB2_LOCK_FLAG_ALL_MASK) {
1161 return NT_STATUS_INVALID_PARAMETER;
1164 if (isunlock &&
1165 (lck->smb2.in.locks[i].flags &
1166 (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1167 return NT_STATUS_INVALID_PARAMETER;
1169 if (!isunlock &&
1170 (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) {
1171 return NT_STATUS_INVALID_PARAMETER;
1173 lck2->generic.in.locks[i].pid = req->smbpid;
1174 lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset;
1175 lck2->generic.in.locks[i].count = lck->smb2.in.locks[i].length;
1176 if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) {
1177 lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK;
1179 if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) {
1180 lck2->generic.in.timeout = 0;
1183 /* initialize output value */
1184 lck->smb2.out.reserved = 0;
1185 break;
1188 case RAW_LOCK_SMB2_BREAK:
1189 lck2->generic.level = RAW_LOCK_GENERIC;
1190 lck2->generic.in.file.ntvfs = lck->smb2_break.in.file.ntvfs;
1191 lck2->generic.in.mode = LOCKING_ANDX_OPLOCK_RELEASE |
1192 ((lck->smb2_break.in.oplock_level << 8) & 0xFF00);
1193 lck2->generic.in.timeout = 0;
1194 lck2->generic.in.ulock_cnt = 0;
1195 lck2->generic.in.lock_cnt = 0;
1196 lck2->generic.in.locks = NULL;
1198 /* initialize output value */
1199 lck->smb2_break.out.oplock_level= lck->smb2_break.in.oplock_level;
1200 lck->smb2_break.out.reserved = lck->smb2_break.in.reserved;
1201 lck->smb2_break.out.reserved2 = lck->smb2_break.in.reserved2;
1202 lck->smb2_break.out.file = lck->smb2_break.in.file;
1203 break;
1207 * we don't need to call ntvfs_map_async_setup() here,
1208 * as lock() doesn't have any output fields
1211 return ntvfs->ops->lock_fn(ntvfs, req, lck2);
1216 NTVFS write generic to any mapper
1218 static NTSTATUS ntvfs_map_write_finish(struct ntvfs_module_context *ntvfs,
1219 struct ntvfs_request *req,
1220 union smb_write *wr,
1221 union smb_write *wr2,
1222 NTSTATUS status)
1224 union smb_lock *lck;
1225 union smb_close *cl;
1226 unsigned int state;
1228 if (NT_STATUS_IS_ERR(status)) {
1229 return status;
1232 switch (wr->generic.level) {
1233 case RAW_WRITE_WRITE:
1234 wr->write.out.nwritten = wr2->generic.out.nwritten;
1235 break;
1237 case RAW_WRITE_WRITEUNLOCK:
1238 wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1240 lck = talloc(wr2, union smb_lock);
1241 if (lck == NULL) {
1242 return NT_STATUS_NO_MEMORY;
1245 lck->unlock.level = RAW_LOCK_UNLOCK;
1246 lck->unlock.in.file.ntvfs = wr->writeunlock.in.file.ntvfs;
1247 lck->unlock.in.count = wr->writeunlock.in.count;
1248 lck->unlock.in.offset = wr->writeunlock.in.offset;
1250 if (lck->unlock.in.count != 0) {
1251 /* do the lock sync for now */
1252 state = req->async_states->state;
1253 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1254 status = ntvfs->ops->lock_fn(ntvfs, req, lck);
1255 req->async_states->state = state;
1257 break;
1259 case RAW_WRITE_WRITECLOSE:
1260 wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1262 cl = talloc(wr2, union smb_close);
1263 if (cl == NULL) {
1264 return NT_STATUS_NO_MEMORY;
1267 cl->close.level = RAW_CLOSE_CLOSE;
1268 cl->close.in.file.ntvfs = wr->writeclose.in.file.ntvfs;
1269 cl->close.in.write_time = wr->writeclose.in.mtime;
1271 if (wr2->generic.in.count != 0) {
1272 /* do the close sync for now */
1273 state = req->async_states->state;
1274 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1275 status = ntvfs->ops->close_fn(ntvfs, req, cl);
1276 req->async_states->state = state;
1278 break;
1280 case RAW_WRITE_SPLWRITE:
1281 break;
1283 case RAW_WRITE_SMB2:
1284 wr->smb2.out._pad = 0;
1285 wr->smb2.out.nwritten = wr2->generic.out.nwritten;
1286 wr->smb2.out.unknown1 = 0;
1287 break;
1289 default:
1290 return NT_STATUS_INVALID_LEVEL;
1293 return status;
1298 NTVFS write generic to any mapper
1300 NTSTATUS ntvfs_map_write(struct ntvfs_module_context *ntvfs,
1301 struct ntvfs_request *req,
1302 union smb_write *wr)
1304 union smb_write *wr2;
1305 NTSTATUS status;
1307 wr2 = talloc(req, union smb_write);
1308 if (wr2 == NULL) {
1309 return NT_STATUS_NO_MEMORY;
1312 status = ntvfs_map_async_setup(ntvfs, req, wr, wr2,
1313 (second_stage_t)ntvfs_map_write_finish);
1314 if (!NT_STATUS_IS_OK(status)) {
1315 return status;
1318 wr2->writex.level = RAW_WRITE_GENERIC;
1320 switch (wr->generic.level) {
1321 case RAW_WRITE_WRITEX:
1322 status = NT_STATUS_INVALID_LEVEL;
1323 break;
1325 case RAW_WRITE_WRITE:
1326 wr2->writex.in.file.ntvfs= wr->write.in.file.ntvfs;
1327 wr2->writex.in.offset = wr->write.in.offset;
1328 wr2->writex.in.wmode = 0;
1329 wr2->writex.in.remaining = wr->write.in.remaining;
1330 wr2->writex.in.count = wr->write.in.count;
1331 wr2->writex.in.data = wr->write.in.data;
1332 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1333 break;
1335 case RAW_WRITE_WRITEUNLOCK:
1336 wr2->writex.in.file.ntvfs= wr->writeunlock.in.file.ntvfs;
1337 wr2->writex.in.offset = wr->writeunlock.in.offset;
1338 wr2->writex.in.wmode = 0;
1339 wr2->writex.in.remaining = wr->writeunlock.in.remaining;
1340 wr2->writex.in.count = wr->writeunlock.in.count;
1341 wr2->writex.in.data = wr->writeunlock.in.data;
1342 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1343 break;
1345 case RAW_WRITE_WRITECLOSE:
1346 wr2->writex.in.file.ntvfs= wr->writeclose.in.file.ntvfs;
1347 wr2->writex.in.offset = wr->writeclose.in.offset;
1348 wr2->writex.in.wmode = 0;
1349 wr2->writex.in.remaining = 0;
1350 wr2->writex.in.count = wr->writeclose.in.count;
1351 wr2->writex.in.data = wr->writeclose.in.data;
1352 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1353 break;
1355 case RAW_WRITE_SPLWRITE:
1356 wr2->writex.in.file.ntvfs= wr->splwrite.in.file.ntvfs;
1357 wr2->writex.in.offset = 0;
1358 wr2->writex.in.wmode = 0;
1359 wr2->writex.in.remaining = 0;
1360 wr2->writex.in.count = wr->splwrite.in.count;
1361 wr2->writex.in.data = wr->splwrite.in.data;
1362 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1363 break;
1365 case RAW_WRITE_SMB2:
1366 wr2->writex.in.file.ntvfs= wr->smb2.in.file.ntvfs;
1367 wr2->writex.in.offset = wr->smb2.in.offset;
1368 wr2->writex.in.wmode = 0;
1369 wr2->writex.in.remaining = 0;
1370 wr2->writex.in.count = wr->smb2.in.data.length;
1371 wr2->writex.in.data = wr->smb2.in.data.data;
1372 status = ntvfs->ops->write_fn(ntvfs, req, wr2);
1375 return ntvfs_map_async_finish(req, status);
1380 NTVFS read generic to any mapper - finish the out mapping
1382 static NTSTATUS ntvfs_map_read_finish(struct ntvfs_module_context *ntvfs,
1383 struct ntvfs_request *req,
1384 union smb_read *rd,
1385 union smb_read *rd2,
1386 NTSTATUS status)
1388 switch (rd->generic.level) {
1389 case RAW_READ_READ:
1390 rd->read.out.nread = rd2->generic.out.nread;
1391 break;
1392 case RAW_READ_READBRAW:
1393 rd->readbraw.out.nread = rd2->generic.out.nread;
1394 break;
1395 case RAW_READ_LOCKREAD:
1396 rd->lockread.out.nread = rd2->generic.out.nread;
1397 break;
1398 case RAW_READ_SMB2:
1399 rd->smb2.out.data.length= rd2->generic.out.nread;
1400 rd->smb2.out.remaining = 0;
1401 rd->smb2.out.reserved = 0;
1402 break;
1403 default:
1404 return NT_STATUS_INVALID_LEVEL;
1407 return status;
1411 NTVFS read* to readx mapper
1413 NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1414 struct ntvfs_request *req,
1415 union smb_read *rd)
1417 union smb_read *rd2;
1418 union smb_lock *lck;
1419 NTSTATUS status;
1420 unsigned int state;
1422 rd2 = talloc(req, union smb_read);
1423 if (rd2 == NULL) {
1424 return NT_STATUS_NO_MEMORY;
1427 status = ntvfs_map_async_setup(ntvfs, req, rd, rd2,
1428 (second_stage_t)ntvfs_map_read_finish);
1429 if (!NT_STATUS_IS_OK(status)) {
1430 return status;
1433 rd2->readx.level = RAW_READ_READX;
1434 rd2->readx.in.read_for_execute = false;
1436 switch (rd->generic.level) {
1437 case RAW_READ_READX:
1438 status = NT_STATUS_INVALID_LEVEL;
1439 break;
1441 case RAW_READ_READ:
1442 rd2->readx.in.file.ntvfs= rd->read.in.file.ntvfs;
1443 rd2->readx.in.offset = rd->read.in.offset;
1444 rd2->readx.in.mincnt = rd->read.in.count;
1445 rd2->readx.in.maxcnt = rd->read.in.count;
1446 rd2->readx.in.remaining = rd->read.in.remaining;
1447 rd2->readx.out.data = rd->read.out.data;
1448 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1449 break;
1451 case RAW_READ_READBRAW:
1452 rd2->readx.in.file.ntvfs= rd->readbraw.in.file.ntvfs;
1453 rd2->readx.in.offset = rd->readbraw.in.offset;
1454 rd2->readx.in.mincnt = rd->readbraw.in.mincnt;
1455 rd2->readx.in.maxcnt = rd->readbraw.in.maxcnt;
1456 rd2->readx.in.remaining = 0;
1457 rd2->readx.out.data = rd->readbraw.out.data;
1458 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1459 break;
1461 case RAW_READ_LOCKREAD:
1462 /* do the initial lock sync for now */
1463 state = req->async_states->state;
1464 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
1466 lck = talloc(rd2, union smb_lock);
1467 if (lck == NULL) {
1468 status = NT_STATUS_NO_MEMORY;
1469 goto done;
1471 lck->lock.level = RAW_LOCK_LOCK;
1472 lck->lock.in.file.ntvfs = rd->lockread.in.file.ntvfs;
1473 lck->lock.in.count = rd->lockread.in.count;
1474 lck->lock.in.offset = rd->lockread.in.offset;
1475 status = ntvfs->ops->lock_fn(ntvfs, req, lck);
1476 req->async_states->state = state;
1478 rd2->readx.in.file.ntvfs= rd->lockread.in.file.ntvfs;
1479 rd2->readx.in.offset = rd->lockread.in.offset;
1480 rd2->readx.in.mincnt = rd->lockread.in.count;
1481 rd2->readx.in.maxcnt = rd->lockread.in.count;
1482 rd2->readx.in.remaining = rd->lockread.in.remaining;
1483 rd2->readx.out.data = rd->lockread.out.data;
1485 if (NT_STATUS_IS_OK(status)) {
1486 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1488 break;
1490 case RAW_READ_SMB2:
1491 rd2->readx.in.file.ntvfs= rd->smb2.in.file.ntvfs;
1492 rd2->readx.in.offset = rd->smb2.in.offset;
1493 rd2->readx.in.mincnt = rd->smb2.in.min_count;
1494 rd2->readx.in.maxcnt = rd->smb2.in.length;
1495 rd2->readx.in.remaining = 0;
1496 rd2->readx.out.data = rd->smb2.out.data.data;
1497 status = ntvfs->ops->read_fn(ntvfs, req, rd2);
1498 break;
1501 done:
1502 return ntvfs_map_async_finish(req, status);
1507 NTVFS close generic to any mapper
1509 static NTSTATUS ntvfs_map_close_finish(struct ntvfs_module_context *ntvfs,
1510 struct ntvfs_request *req,
1511 union smb_close *cl,
1512 union smb_close *cl2,
1513 NTSTATUS status)
1515 NT_STATUS_NOT_OK_RETURN(status);
1517 switch (cl->generic.level) {
1518 case RAW_CLOSE_SMB2:
1519 cl->smb2.out.flags = cl2->generic.out.flags;
1520 cl->smb2.out._pad = 0;
1521 cl->smb2.out.create_time = cl2->generic.out.create_time;
1522 cl->smb2.out.access_time = cl2->generic.out.access_time;
1523 cl->smb2.out.write_time = cl2->generic.out.write_time;
1524 cl->smb2.out.change_time = cl2->generic.out.change_time;
1525 cl->smb2.out.alloc_size = cl2->generic.out.alloc_size;
1526 cl->smb2.out.size = cl2->generic.out.size;
1527 cl->smb2.out.file_attr = cl2->generic.out.file_attr;
1528 break;
1529 default:
1530 break;
1533 return status;
1537 NTVFS close generic to any mapper
1539 NTSTATUS ntvfs_map_close(struct ntvfs_module_context *ntvfs,
1540 struct ntvfs_request *req,
1541 union smb_close *cl)
1543 union smb_close *cl2;
1544 NTSTATUS status;
1546 cl2 = talloc(req, union smb_close);
1547 if (cl2 == NULL) {
1548 return NT_STATUS_NO_MEMORY;
1551 switch (cl->generic.level) {
1552 case RAW_CLOSE_GENERIC:
1553 return NT_STATUS_INVALID_LEVEL;
1555 case RAW_CLOSE_CLOSE:
1556 cl2->generic.level = RAW_CLOSE_GENERIC;
1557 cl2->generic.in.file = cl->close.in.file;
1558 cl2->generic.in.write_time = cl->close.in.write_time;
1559 cl2->generic.in.flags = 0;
1560 break;
1562 case RAW_CLOSE_SPLCLOSE:
1563 cl2->generic.level = RAW_CLOSE_GENERIC;
1564 cl2->generic.in.file = cl->splclose.in.file;
1565 cl2->generic.in.write_time = 0;
1566 cl2->generic.in.flags = 0;
1567 break;
1569 case RAW_CLOSE_SMB2:
1570 cl2->generic.level = RAW_CLOSE_GENERIC;
1571 cl2->generic.in.file = cl->smb2.in.file;
1572 cl2->generic.in.write_time = 0;
1573 cl2->generic.in.flags = cl->smb2.in.flags;
1574 break;
1577 status = ntvfs_map_async_setup(ntvfs, req, cl, cl2,
1578 (second_stage_t)ntvfs_map_close_finish);
1579 NT_STATUS_NOT_OK_RETURN(status);
1581 status = ntvfs->ops->close_fn(ntvfs, req, cl2);
1583 return ntvfs_map_async_finish(req, status);
1587 NTVFS notify generic to any mapper
1589 static NTSTATUS ntvfs_map_notify_finish(struct ntvfs_module_context *ntvfs,
1590 struct ntvfs_request *req,
1591 union smb_notify *nt,
1592 union smb_notify *nt2,
1593 NTSTATUS status)
1595 NT_STATUS_NOT_OK_RETURN(status);
1597 switch (nt->nttrans.level) {
1598 case RAW_NOTIFY_SMB2:
1599 if (nt2->nttrans.out.num_changes == 0) {
1600 return NT_STATUS_NOTIFY_ENUM_DIR;
1602 nt->smb2.out.num_changes = nt2->nttrans.out.num_changes;
1603 nt->smb2.out.changes = talloc_steal(req, nt2->nttrans.out.changes);
1604 break;
1606 default:
1607 return NT_STATUS_INVALID_LEVEL;
1610 return status;
1615 NTVFS notify generic to any mapper
1617 NTSTATUS ntvfs_map_notify(struct ntvfs_module_context *ntvfs,
1618 struct ntvfs_request *req,
1619 union smb_notify *nt)
1621 union smb_notify *nt2;
1622 NTSTATUS status;
1624 nt2 = talloc(req, union smb_notify);
1625 NT_STATUS_HAVE_NO_MEMORY(nt2);
1627 status = ntvfs_map_async_setup(ntvfs, req, nt, nt2,
1628 (second_stage_t)ntvfs_map_notify_finish);
1629 NT_STATUS_NOT_OK_RETURN(status);
1631 nt2->nttrans.level = RAW_NOTIFY_NTTRANS;
1633 switch (nt->nttrans.level) {
1634 case RAW_NOTIFY_NTTRANS:
1635 status = NT_STATUS_INVALID_LEVEL;
1636 break;
1638 case RAW_NOTIFY_SMB2:
1639 nt2->nttrans.in.file.ntvfs = nt->smb2.in.file.ntvfs;
1640 nt2->nttrans.in.buffer_size = nt->smb2.in.buffer_size;
1641 nt2->nttrans.in.completion_filter = nt->smb2.in.completion_filter;
1642 nt2->nttrans.in.recursive = nt->smb2.in.recursive;
1643 status = ntvfs->ops->notify_fn(ntvfs, req, nt2);
1644 break;
1647 return ntvfs_map_async_finish(req, status);