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.
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);
45
this structure holds the async state for pending mapped async calls
47
struct ntvfs_map_async {
48
struct ntvfs_module_context *ntvfs;
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,
82
struct ntvfs_map_async *m;
83
m = talloc(req, struct ntvfs_map_async);
85
return NT_STATUS_NO_MEMORY;
91
return ntvfs_async_state_push(ntvfs, req, m, ntvfs_map_async_send);
95
called when first stage processing is complete.
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) {
107
/* the backend is replying immediately. call the 2nd stage function after popping our local
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)
124
p = strrchr(fname, '.');
129
if (strcasecmp(p, "EXE") == 0 ||
130
strcasecmp(p, "COM") == 0 ||
131
strcasecmp(p, "DLL") == 0 ||
132
strcasecmp(p, "SYM") == 0) {
140
NTVFS openx to ntcreatex mapper
142
static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs,
143
struct ntvfs_request *req,
148
time_t write_time = 0;
149
uint32_t set_size = 0;
150
union smb_setfileinfo *sf;
153
if (!NT_STATUS_IS_OK(status)) {
157
switch (io->generic.level) {
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;
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;
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;
199
case RAW_OPEN_CREATE:
200
io->mknew.out.file.ntvfs= io2->generic.out.file.ntvfs;
201
write_time = io->mknew.in.write_time;
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);
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;
218
case EXCLUSIVE_OPLOCK_RETURN:
219
io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
221
case LEVEL_II_OPLOCK_RETURN:
222
io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_II;
225
io->smb2.out.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
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;
242
return NT_STATUS_INVALID_LEVEL;
245
/* doing a secondary request async is more trouble than its
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);
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;
279
the core of the mapping between openx style parameters and ntcreatex
282
static NTSTATUS map_openx_open(uint16_t flags, uint16_t open_mode,
283
uint16_t open_func, const char *fname,
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;
300
case OPENX_MODE_ACCESS_WRITE:
301
io2->generic.in.access_mask = SEC_RIGHTS_FILE_WRITE;
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;
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;
317
case OPENX_MODE_DENY_WRITE:
318
io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
320
case OPENX_MODE_DENY_ALL:
321
io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
323
case OPENX_MODE_DENY_NONE:
324
io2->generic.in.share_access =
325
NTCREATEX_SHARE_ACCESS_READ |
326
NTCREATEX_SHARE_ACCESS_WRITE;
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;
337
if ((open_mode & OPENX_MODE_ACCESS_MASK) == OPENX_MODE_ACCESS_READ) {
338
io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_READ;
340
io2->generic.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
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;
349
return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
353
case (OPENX_OPEN_FUNC_OPEN):
354
io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN;
356
case (OPENX_OPEN_FUNC_TRUNC):
357
io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
359
case (OPENX_OPEN_FUNC_FAIL | OPENX_OPEN_FUNC_CREATE):
360
io2->generic.in.open_disposition = NTCREATEX_DISP_CREATE;
362
case (OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE):
363
io2->generic.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
365
case (OPENX_OPEN_FUNC_TRUNC | OPENX_OPEN_FUNC_CREATE):
366
io2->generic.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
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;
374
return NT_STATUS_DOS(ERRDOS, ERRbadaccess);
381
NTVFS open generic to any mapper
383
NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs,
384
struct ntvfs_request *req,
390
io2 = talloc_zero(req, union smb_open);
392
return NT_STATUS_NO_MEMORY;
395
status = ntvfs_map_async_setup(ntvfs, req,
397
(second_stage_t)ntvfs_map_open_finish);
398
if (!NT_STATUS_IS_OK(status)) {
402
io2->generic.level = RAW_OPEN_GENERIC;
404
switch (io->generic.level) {
406
status = map_openx_open(io->openx.in.flags,
407
io->openx.in.open_mode,
408
io->openx.in.open_func,
411
if (!NT_STATUS_IS_OK(status)) {
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);
423
status = map_openx_open(0,
424
io->openold.in.open_mode,
425
OPENX_OPEN_FUNC_OPEN,
426
io->openold.in.fname,
428
if (!NT_STATUS_IS_OK(status)) {
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);
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;
446
status = map_openx_open(io->t2open.in.flags,
447
io->t2open.in.open_mode,
448
io->t2open.in.open_func,
451
if (!NT_STATUS_IS_OK(status)) {
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);
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);
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);
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);
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;
511
case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
512
io2->generic.in.flags = NTCREATEX_FLAGS_REQUEST_OPLOCK;
515
io2->generic.in.flags = 0;
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;
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;
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);
554
status = NT_STATUS_INVALID_LEVEL;
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)
570
union smb_fsinfo *fs2;
572
fs2 = talloc(req, union smb_fsinfo);
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)) {
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 */
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) {
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;
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;
633
fs->volume.out.serial_number = fs2->generic.out.serial_number;
634
fs->volume.out.volume_name.s = fs2->generic.out.volume_name;
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;
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;
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;
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;
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;
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;
680
case RAW_QFS_OBJECTID_INFORMATION:
681
fs->objectid_information.out.guid = fs2->generic.out.guid;
682
ZERO_STRUCT(fs->objectid_information.out.unknown);
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)
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);
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;
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;
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;
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;
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;
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;
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;
782
case RAW_FILEINFO_INTERNAL_INFORMATION:
783
info->internal_information.out.file_id = info2->generic.out.file_id;
786
case RAW_FILEINFO_EA_INFO:
787
case RAW_FILEINFO_EA_INFORMATION:
788
info->ea_info.out.ea_size = info2->generic.out.ea_size;
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;
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;
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;
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;
836
case RAW_FILEINFO_POSITION_INFORMATION:
837
info->position_information.out.position = info2->generic.out.position;
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,
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;
872
case RAW_FILEINFO_IS_NAME_VALID:
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;
884
case RAW_FILEINFO_ACCESS_INFORMATION:
885
info->access_information.out.access_flags = info2->generic.out.access_flags;
888
case RAW_FILEINFO_MODE_INFORMATION:
889
info->mode_information.out.mode = info2->generic.out.mode;
892
case RAW_FILEINFO_ALIGNMENT_INFORMATION:
893
info->alignment_information.out.alignment_requirement =
894
info2->generic.out.alignment_requirement;
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;
913
case RAW_FILEINFO_UNIX_LINK:
914
info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
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)
930
union smb_fileinfo *info2;
932
info2 = talloc(req, union smb_fileinfo);
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)) {
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)
963
union smb_fileinfo *info2;
965
info2 = talloc(req, union smb_fileinfo);
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)) {
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,
996
union smb_lock *lck2;
997
struct smb_lock_entry *locks;
999
lck2 = talloc(req, union smb_lock);
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;
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;
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;
1039
case RAW_LOCK_SMB2: {
1040
/* this is only approximate! We need to change the
1041
generic structure to fix this properly */
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
1061
if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) {
1062
lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count;
1065
lck2->generic.in.lock_cnt = lck->smb2.in.lock_count;
1068
for (i=0;i<lck->smb2.in.lock_count;i++) {
1070
(lck->smb2.in.locks[i].flags &
1071
(SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) {
1072
return NT_STATUS_INVALID_PARAMETER;
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;
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;
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,
1129
union smb_lock *lck;
1130
union smb_close *cl;
1133
if (NT_STATUS_IS_ERR(status)) {
1137
switch (wr->generic.level) {
1138
case RAW_WRITE_WRITE:
1139
wr->write.out.nwritten = wr2->generic.out.nwritten;
1142
case RAW_WRITE_WRITEUNLOCK:
1143
wr->writeunlock.out.nwritten = wr2->generic.out.nwritten;
1145
lck = talloc(wr2, union smb_lock);
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;
1164
case RAW_WRITE_WRITECLOSE:
1165
wr->writeclose.out.nwritten = wr2->generic.out.nwritten;
1167
cl = talloc(wr2, union smb_close);
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;
1185
case RAW_WRITE_SPLWRITE:
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;
1195
return NT_STATUS_INVALID_LEVEL;
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;
1212
wr2 = talloc(req, union smb_write);
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)) {
1223
wr2->writex.level = RAW_WRITE_GENERIC;
1225
switch (wr->generic.level) {
1226
case RAW_WRITE_WRITEX:
1227
status = NT_STATUS_INVALID_LEVEL;
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);
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);
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);
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);
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,
1290
union smb_read *rd2,
1293
switch (rd->generic.level) {
1295
rd->read.out.nread = rd2->generic.out.nread;
1297
case RAW_READ_READBRAW:
1298
rd->readbraw.out.nread = rd2->generic.out.nread;
1300
case RAW_READ_LOCKREAD:
1301
rd->lockread.out.nread = rd2->generic.out.nread;
1304
rd->smb2.out.data.length= rd2->generic.out.nread;
1305
rd->smb2.out.remaining = 0;
1306
rd->smb2.out.reserved = 0;
1309
return NT_STATUS_INVALID_LEVEL;
1316
NTVFS read* to readx mapper
1318
NTSTATUS ntvfs_map_read(struct ntvfs_module_context *ntvfs,
1319
struct ntvfs_request *req,
1322
union smb_read *rd2;
1323
union smb_lock *lck;
1327
rd2 = talloc(req, union smb_read);
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)) {
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;
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);
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);
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);
1373
status = NT_STATUS_NO_MEMORY;
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);
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);
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,
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;
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;
1451
cl2 = talloc(req, union smb_close);
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;
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;
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;
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,
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);
1512
return NT_STATUS_INVALID_LEVEL;
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;
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;
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);
1552
return ntvfs_map_async_finish(req, status);