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
= req
->async_states
->private_data
;
61 ntvfs_async_state_pop(req
);
63 /* call the _finish function setup in ntvfs_map_async_setup() */
64 req
->async_states
->status
= m
->fn(m
->ntvfs
, req
, m
->io
, m
->io2
, req
->async_states
->status
);
66 /* call the send function from the next module up */
67 req
->async_states
->send_fn(req
);
71 prepare for calling a ntvfs backend with async support
72 io is the original call structure
73 io2 is the new call structure for the mapped call
74 fn is a second stage function for processing the out arguments
76 static NTSTATUS
ntvfs_map_async_setup(struct ntvfs_module_context
*ntvfs
,
77 struct ntvfs_request
*req
,
81 struct ntvfs_map_async
*m
;
82 m
= talloc(req
, struct ntvfs_map_async
);
84 return NT_STATUS_NO_MEMORY
;
90 return ntvfs_async_state_push(ntvfs
, req
, m
, ntvfs_map_async_send
);
94 called when first stage processing is complete.
96 static NTSTATUS
ntvfs_map_async_finish(struct ntvfs_request
*req
, NTSTATUS status
)
98 struct ntvfs_map_async
*m
;
100 /* if the backend has decided to reply in an async fashion then
101 we don't need to do any work here */
102 if (req
->async_states
->state
& NTVFS_ASYNC_STATE_ASYNC
) {
106 /* the backend is replying immediately. call the 2nd stage function after popping our local
108 m
= req
->async_states
->private_data
;
110 ntvfs_async_state_pop(req
);
112 return m
->fn(m
->ntvfs
, req
, m
->io
, m
->io2
, status
);
116 see if a filename ends in EXE COM DLL or SYM. This is needed for the
117 DENY_DOS mapping for OpenX
119 bool is_exe_filename(const char *fname
)
122 p
= strrchr(fname
, '.');
127 if (strcasecmp(p
, "EXE") == 0 ||
128 strcasecmp(p
, "COM") == 0 ||
129 strcasecmp(p
, "DLL") == 0 ||
130 strcasecmp(p
, "SYM") == 0) {
138 NTVFS openx to ntcreatex mapper
140 static NTSTATUS
ntvfs_map_open_finish(struct ntvfs_module_context
*ntvfs
,
141 struct ntvfs_request
*req
,
146 time_t write_time
= 0;
147 uint32_t set_size
= 0;
148 union smb_setfileinfo
*sf
;
151 if (!NT_STATUS_IS_OK(status
)) {
155 switch (io
->generic
.level
) {
157 io
->openold
.out
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
158 io
->openold
.out
.attrib
= io2
->generic
.out
.attrib
;
159 io
->openold
.out
.write_time
= nt_time_to_unix(io2
->generic
.out
.write_time
);
160 io
->openold
.out
.size
= io2
->generic
.out
.size
;
161 io
->openold
.out
.rmode
= io
->openold
.in
.open_mode
;
165 io
->openx
.out
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
166 io
->openx
.out
.attrib
= io2
->generic
.out
.attrib
;
167 io
->openx
.out
.write_time
= nt_time_to_unix(io2
->generic
.out
.write_time
);
168 io
->openx
.out
.size
= io2
->generic
.out
.size
;
169 io
->openx
.out
.access
= (io
->openx
.in
.open_mode
& OPENX_MODE_ACCESS_MASK
);
170 io
->openx
.out
.ftype
= 0;
171 io
->openx
.out
.devstate
= 0;
172 io
->openx
.out
.action
= io2
->generic
.out
.create_action
;
173 io
->openx
.out
.unique_fid
= 0;
174 io
->openx
.out
.access_mask
= SEC_STD_ALL
;
175 io
->openx
.out
.unknown
= 0;
177 /* we need to extend the file to the requested size if
178 it was newly created */
179 if (io2
->generic
.out
.create_action
== NTCREATEX_ACTION_CREATED
) {
180 set_size
= io
->openx
.in
.size
;
184 case RAW_OPEN_T2OPEN
:
185 io
->t2open
.out
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
186 io
->t2open
.out
.attrib
= io2
->generic
.out
.attrib
;
187 io
->t2open
.out
.write_time
= nt_time_to_unix(io2
->generic
.out
.write_time
);
188 io
->t2open
.out
.size
= io2
->generic
.out
.size
;
189 io
->t2open
.out
.access
= io
->t2open
.in
.open_mode
;
190 io
->t2open
.out
.ftype
= 0;
191 io
->t2open
.out
.devstate
= 0;
192 io
->t2open
.out
.action
= io2
->generic
.out
.create_action
;
193 io
->t2open
.out
.file_id
= 0;
197 case RAW_OPEN_CREATE
:
198 io
->mknew
.out
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
199 write_time
= io
->mknew
.in
.write_time
;
203 io
->ctemp
.out
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
204 io
->ctemp
.out
.name
= talloc_strdup(req
, io2
->generic
.in
.fname
+
205 strlen(io
->ctemp
.in
.directory
) + 1);
206 NT_STATUS_HAVE_NO_MEMORY(io
->ctemp
.out
.name
);
210 io
->smb2
.out
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
211 io
->smb2
.out
.oplock_level
= 0;
212 io
->smb2
.out
.create_action
= io2
->generic
.out
.create_action
;
213 io
->smb2
.out
.create_time
= io2
->generic
.out
.create_time
;
214 io
->smb2
.out
.access_time
= io2
->generic
.out
.access_time
;
215 io
->smb2
.out
.write_time
= io2
->generic
.out
.write_time
;
216 io
->smb2
.out
.change_time
= io2
->generic
.out
.change_time
;
217 io
->smb2
.out
.alloc_size
= io2
->generic
.out
.alloc_size
;
218 io
->smb2
.out
.size
= io2
->generic
.out
.size
;
219 io
->smb2
.out
.file_attr
= io2
->generic
.out
.attrib
;
220 io
->smb2
.out
.reserved2
= 0;
221 io
->smb2
.out
.blob
= data_blob(NULL
, 0);
225 return NT_STATUS_INVALID_LEVEL
;
228 /* doing a secondary request async is more trouble than its
230 state
= req
->async_states
->state
;
231 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
233 if (write_time
!= 0) {
234 sf
= talloc(req
, union smb_setfileinfo
);
235 NT_STATUS_HAVE_NO_MEMORY(sf
);
236 sf
->generic
.level
= RAW_SFILEINFO_STANDARD
;
237 sf
->generic
.in
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
238 sf
->standard
.in
.create_time
= 0;
239 sf
->standard
.in
.write_time
= write_time
;
240 sf
->standard
.in
.access_time
= 0;
241 status
= ntvfs
->ops
->setfileinfo(ntvfs
, req
, sf
);
245 sf
= talloc(req
, union smb_setfileinfo
);
246 NT_STATUS_HAVE_NO_MEMORY(sf
);
247 sf
->generic
.level
= RAW_SFILEINFO_END_OF_FILE_INFORMATION
;
248 sf
->generic
.in
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
249 sf
->end_of_file_info
.in
.size
= set_size
;
250 status
= ntvfs
->ops
->setfileinfo(ntvfs
, req
, sf
);
251 if (NT_STATUS_IS_OK(status
)) {
252 io
->openx
.out
.size
= io
->openx
.in
.size
;
256 req
->async_states
->state
= state
;
262 the core of the mapping between openx style parameters and ntcreatex
265 static NTSTATUS
map_openx_open(uint16_t flags
, uint16_t open_mode
,
266 uint16_t open_func
, const char *fname
,
269 if (flags
& OPENX_FLAGS_REQUEST_OPLOCK
) {
270 io2
->generic
.in
.flags
|= NTCREATEX_FLAGS_REQUEST_OPLOCK
;
272 if (flags
& OPENX_FLAGS_REQUEST_BATCH_OPLOCK
) {
273 io2
->generic
.in
.flags
|= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
;
276 switch (open_mode
& OPENX_MODE_ACCESS_MASK
) {
277 case OPENX_MODE_ACCESS_READ
:
278 case OPENX_MODE_ACCESS_EXEC
:
279 io2
->generic
.in
.access_mask
= SEC_RIGHTS_FILE_READ
;
281 case OPENX_MODE_ACCESS_WRITE
:
282 io2
->generic
.in
.access_mask
= SEC_RIGHTS_FILE_WRITE
;
284 case OPENX_MODE_ACCESS_RDWR
:
285 case OPENX_MODE_ACCESS_FCB
:
286 io2
->generic
.in
.access_mask
=
287 SEC_RIGHTS_FILE_READ
|
288 SEC_RIGHTS_FILE_WRITE
;
291 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
294 switch (open_mode
& OPENX_MODE_DENY_MASK
) {
295 case OPENX_MODE_DENY_READ
:
296 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_WRITE
;
298 case OPENX_MODE_DENY_WRITE
:
299 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
;
301 case OPENX_MODE_DENY_ALL
:
302 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
304 case OPENX_MODE_DENY_NONE
:
305 io2
->generic
.in
.share_access
=
306 NTCREATEX_SHARE_ACCESS_READ
|
307 NTCREATEX_SHARE_ACCESS_WRITE
;
309 case OPENX_MODE_DENY_DOS
:
310 /* DENY_DOS is quite strange - it depends on the filename! */
311 io2
->generic
.in
.create_options
|=
312 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS
;
313 if (is_exe_filename(fname
)) {
314 io2
->generic
.in
.share_access
=
315 NTCREATEX_SHARE_ACCESS_READ
|
316 NTCREATEX_SHARE_ACCESS_WRITE
;
318 if ((open_mode
& OPENX_MODE_ACCESS_MASK
) == OPENX_MODE_ACCESS_READ
) {
319 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
;
321 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
325 case OPENX_MODE_DENY_FCB
:
326 io2
->generic
.in
.create_options
|= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB
;
327 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
330 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
334 case (OPENX_OPEN_FUNC_OPEN
):
335 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
337 case (OPENX_OPEN_FUNC_TRUNC
):
338 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE
;
340 case (OPENX_OPEN_FUNC_FAIL
| OPENX_OPEN_FUNC_CREATE
):
341 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
343 case (OPENX_OPEN_FUNC_OPEN
| OPENX_OPEN_FUNC_CREATE
):
344 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
346 case (OPENX_OPEN_FUNC_TRUNC
| OPENX_OPEN_FUNC_CREATE
):
347 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
350 /* this one is very strange */
351 if ((open_mode
& OPENX_MODE_ACCESS_MASK
) == OPENX_MODE_ACCESS_EXEC
) {
352 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
355 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
362 NTVFS open generic to any mapper
364 NTSTATUS
ntvfs_map_open(struct ntvfs_module_context
*ntvfs
,
365 struct ntvfs_request
*req
,
371 io2
= talloc_zero(req
, union smb_open
);
373 return NT_STATUS_NO_MEMORY
;
376 status
= ntvfs_map_async_setup(ntvfs
, req
,
378 (second_stage_t
)ntvfs_map_open_finish
);
379 if (!NT_STATUS_IS_OK(status
)) {
383 io2
->generic
.level
= RAW_OPEN_GENERIC
;
385 switch (io
->generic
.level
) {
387 status
= map_openx_open(io
->openx
.in
.flags
,
388 io
->openx
.in
.open_mode
,
389 io
->openx
.in
.open_func
,
392 if (!NT_STATUS_IS_OK(status
)) {
396 io2
->generic
.in
.file_attr
= io
->openx
.in
.file_attrs
;
397 io2
->generic
.in
.fname
= io
->openx
.in
.fname
;
399 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
404 status
= map_openx_open(0,
405 io
->openold
.in
.open_mode
,
406 OPENX_OPEN_FUNC_OPEN
,
407 io
->openold
.in
.fname
,
409 if (!NT_STATUS_IS_OK(status
)) {
413 io2
->generic
.in
.file_attr
= io
->openold
.in
.search_attrs
;
414 io2
->generic
.in
.fname
= io
->openold
.in
.fname
;
416 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
419 case RAW_OPEN_T2OPEN
:
420 io2
->generic
.level
= RAW_OPEN_NTTRANS_CREATE
;
422 if (io
->t2open
.in
.open_func
== 0) {
423 status
= NT_STATUS_OBJECT_NAME_COLLISION
;
427 status
= map_openx_open(io
->t2open
.in
.flags
,
428 io
->t2open
.in
.open_mode
,
429 io
->t2open
.in
.open_func
,
432 if (!NT_STATUS_IS_OK(status
)) {
436 io2
->generic
.in
.file_attr
= io
->t2open
.in
.file_attrs
;
437 io2
->generic
.in
.fname
= io
->t2open
.in
.fname
;
438 io2
->generic
.in
.ea_list
= talloc(io2
, struct smb_ea_list
);
439 io2
->generic
.in
.ea_list
->num_eas
= io
->t2open
.in
.num_eas
;
440 io2
->generic
.in
.ea_list
->eas
= io
->t2open
.in
.eas
;
442 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
446 io2
->generic
.in
.file_attr
= io
->mknew
.in
.attrib
;
447 io2
->generic
.in
.fname
= io
->mknew
.in
.fname
;
448 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
449 io2
->generic
.in
.access_mask
=
450 SEC_RIGHTS_FILE_READ
|
451 SEC_RIGHTS_FILE_WRITE
;
452 io2
->generic
.in
.share_access
=
453 NTCREATEX_SHARE_ACCESS_READ
|
454 NTCREATEX_SHARE_ACCESS_WRITE
;
455 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
458 case RAW_OPEN_CREATE
:
459 io2
->generic
.in
.file_attr
= io
->mknew
.in
.attrib
;
460 io2
->generic
.in
.fname
= io
->mknew
.in
.fname
;
461 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
462 io2
->generic
.in
.access_mask
=
463 SEC_RIGHTS_FILE_READ
|
464 SEC_RIGHTS_FILE_WRITE
;
465 io2
->generic
.in
.share_access
=
466 NTCREATEX_SHARE_ACCESS_READ
|
467 NTCREATEX_SHARE_ACCESS_WRITE
;
468 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
472 io2
->generic
.in
.file_attr
= io
->ctemp
.in
.attrib
;
473 io2
->generic
.in
.fname
=
474 talloc_asprintf(io2
, "%s\\SRV%s",
475 io
->ctemp
.in
.directory
,
476 generate_random_str_list(io2
, 5, "0123456789"));
477 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
478 io2
->generic
.in
.access_mask
=
479 SEC_RIGHTS_FILE_READ
|
480 SEC_RIGHTS_FILE_WRITE
;
481 io2
->generic
.in
.share_access
=
482 NTCREATEX_SHARE_ACCESS_READ
|
483 NTCREATEX_SHARE_ACCESS_WRITE
;
484 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
487 io2
->generic
.in
.flags
= 0;
488 io2
->generic
.in
.root_fid
= 0;
489 io2
->generic
.in
.access_mask
= io
->smb2
.in
.desired_access
;
490 io2
->generic
.in
.alloc_size
= 0;
491 io2
->generic
.in
.file_attr
= io
->smb2
.in
.file_attributes
;
492 io2
->generic
.in
.share_access
= io
->smb2
.in
.share_access
;
493 io2
->generic
.in
.open_disposition
= io
->smb2
.in
.create_disposition
;
494 io2
->generic
.in
.create_options
= io
->smb2
.in
.create_options
;
495 io2
->generic
.in
.impersonation
= io
->smb2
.in
.impersonation_level
;
496 io2
->generic
.in
.security_flags
= 0;
497 io2
->generic
.in
.fname
= io
->smb2
.in
.fname
;
498 io2
->generic
.in
.sec_desc
= NULL
;
499 io2
->generic
.in
.ea_list
= NULL
;
500 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
504 status
= NT_STATUS_INVALID_LEVEL
;
508 return ntvfs_map_async_finish(req
, status
);
513 NTVFS fsinfo generic to any mapper
515 NTSTATUS
ntvfs_map_fsinfo(struct ntvfs_module_context
*ntvfs
,
516 struct ntvfs_request
*req
,
517 union smb_fsinfo
*fs
)
520 union smb_fsinfo
*fs2
;
522 fs2
= talloc(req
, union smb_fsinfo
);
524 return NT_STATUS_NO_MEMORY
;
527 if (fs
->generic
.level
== RAW_QFS_GENERIC
) {
528 return NT_STATUS_INVALID_LEVEL
;
531 /* only used by the simple backend, which doesn't do async */
532 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
534 /* ask the backend for the generic info */
535 fs2
->generic
.level
= RAW_QFS_GENERIC
;
537 status
= ntvfs
->ops
->fsinfo(ntvfs
, req
, fs2
);
538 if (!NT_STATUS_IS_OK(status
)) {
542 /* and convert it to the required level */
543 switch (fs
->generic
.level
) {
544 case RAW_QFS_GENERIC
:
545 return NT_STATUS_INVALID_LEVEL
;
547 case RAW_QFS_DSKATTR
: {
548 /* map from generic to DSKATTR */
551 /* we need to scale the sizes to fit */
552 for (bpunit
=64; bpunit
<0x10000; bpunit
*= 2) {
553 if (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
< bpunit
* 512 * 65535.0) {
558 fs
->dskattr
.out
.blocks_per_unit
= bpunit
;
559 fs
->dskattr
.out
.block_size
= 512;
560 fs
->dskattr
.out
.units_total
=
561 (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
562 fs
->dskattr
.out
.units_free
=
563 (fs2
->generic
.out
.blocks_free
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
565 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
566 if (bpunit
> 64 && req
->ctx
->protocol
<= PROTOCOL_LANMAN2
) {
567 fs
->dskattr
.out
.blocks_per_unit
= 64;
568 fs
->dskattr
.out
.units_total
= 0xFFFF;
569 fs
->dskattr
.out
.units_free
= 0xFFFF;
574 case RAW_QFS_ALLOCATION
:
575 fs
->allocation
.out
.fs_id
= fs2
->generic
.out
.fs_id
;
576 fs
->allocation
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
577 fs
->allocation
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
578 fs
->allocation
.out
.sectors_per_unit
= 1;
579 fs
->allocation
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
583 fs
->volume
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
584 fs
->volume
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
587 case RAW_QFS_VOLUME_INFO
:
588 case RAW_QFS_VOLUME_INFORMATION
:
589 fs
->volume_info
.out
.create_time
= fs2
->generic
.out
.create_time
;
590 fs
->volume_info
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
591 fs
->volume_info
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
594 case RAW_QFS_SIZE_INFO
:
595 case RAW_QFS_SIZE_INFORMATION
:
596 fs
->size_info
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
597 fs
->size_info
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
598 fs
->size_info
.out
.sectors_per_unit
= 1;
599 fs
->size_info
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
602 case RAW_QFS_DEVICE_INFO
:
603 case RAW_QFS_DEVICE_INFORMATION
:
604 fs
->device_info
.out
.device_type
= fs2
->generic
.out
.device_type
;
605 fs
->device_info
.out
.characteristics
= fs2
->generic
.out
.device_characteristics
;
608 case RAW_QFS_ATTRIBUTE_INFO
:
609 case RAW_QFS_ATTRIBUTE_INFORMATION
:
610 fs
->attribute_info
.out
.fs_attr
= fs2
->generic
.out
.fs_attr
;
611 fs
->attribute_info
.out
.max_file_component_length
= fs2
->generic
.out
.max_file_component_length
;
612 fs
->attribute_info
.out
.fs_type
.s
= fs2
->generic
.out
.fs_type
;
615 case RAW_QFS_QUOTA_INFORMATION
:
616 ZERO_STRUCT(fs
->quota_information
.out
.unknown
);
617 fs
->quota_information
.out
.quota_soft
= fs2
->generic
.out
.quota_soft
;
618 fs
->quota_information
.out
.quota_hard
= fs2
->generic
.out
.quota_hard
;
619 fs
->quota_information
.out
.quota_flags
= fs2
->generic
.out
.quota_flags
;
622 case RAW_QFS_FULL_SIZE_INFORMATION
:
623 fs
->full_size_information
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
624 fs
->full_size_information
.out
.call_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
625 fs
->full_size_information
.out
.actual_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
626 fs
->full_size_information
.out
.sectors_per_unit
= 1;
627 fs
->full_size_information
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
630 case RAW_QFS_OBJECTID_INFORMATION
:
631 fs
->objectid_information
.out
.guid
= fs2
->generic
.out
.guid
;
632 ZERO_STRUCT(fs
->objectid_information
.out
.unknown
);
637 return NT_STATUS_INVALID_LEVEL
;
642 NTVFS fileinfo generic to any mapper
644 NTSTATUS
ntvfs_map_fileinfo(TALLOC_CTX
*mem_ctx
,
645 union smb_fileinfo
*info
,
646 union smb_fileinfo
*info2
)
649 /* and convert it to the required level using results in info2 */
650 switch (info
->generic
.level
) {
651 case RAW_FILEINFO_GENERIC
:
652 return NT_STATUS_INVALID_LEVEL
;
653 case RAW_FILEINFO_GETATTR
:
654 info
->getattr
.out
.attrib
= info2
->generic
.out
.attrib
& 0xff;
655 info
->getattr
.out
.size
= info2
->generic
.out
.size
;
656 info
->getattr
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
659 case RAW_FILEINFO_GETATTRE
:
660 info
->getattre
.out
.attrib
= info2
->generic
.out
.attrib
;
661 info
->getattre
.out
.size
= info2
->generic
.out
.size
;
662 info
->getattre
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
663 info
->getattre
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
664 info
->getattre
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
665 info
->getattre
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
668 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
669 info
->network_open_information
.out
.create_time
= info2
->generic
.out
.create_time
;
670 info
->network_open_information
.out
.access_time
= info2
->generic
.out
.access_time
;
671 info
->network_open_information
.out
.write_time
= info2
->generic
.out
.write_time
;
672 info
->network_open_information
.out
.change_time
= info2
->generic
.out
.change_time
;
673 info
->network_open_information
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
674 info
->network_open_information
.out
.size
= info2
->generic
.out
.size
;
675 info
->network_open_information
.out
.attrib
= info2
->generic
.out
.attrib
;
678 case RAW_FILEINFO_ALL_INFO
:
679 case RAW_FILEINFO_ALL_INFORMATION
:
680 info
->all_info
.out
.create_time
= info2
->generic
.out
.create_time
;
681 info
->all_info
.out
.access_time
= info2
->generic
.out
.access_time
;
682 info
->all_info
.out
.write_time
= info2
->generic
.out
.write_time
;
683 info
->all_info
.out
.change_time
= info2
->generic
.out
.change_time
;
684 info
->all_info
.out
.attrib
= info2
->generic
.out
.attrib
;
685 info
->all_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
686 info
->all_info
.out
.size
= info2
->generic
.out
.size
;
687 info
->all_info
.out
.nlink
= info2
->generic
.out
.nlink
;
688 info
->all_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
689 info
->all_info
.out
.directory
= info2
->generic
.out
.directory
;
690 info
->all_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
691 info
->all_info
.out
.fname
.s
= info2
->generic
.out
.fname
.s
;
692 info
->all_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
695 case RAW_FILEINFO_BASIC_INFO
:
696 case RAW_FILEINFO_BASIC_INFORMATION
:
697 info
->basic_info
.out
.create_time
= info2
->generic
.out
.create_time
;
698 info
->basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
699 info
->basic_info
.out
.write_time
= info2
->generic
.out
.write_time
;
700 info
->basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
701 info
->basic_info
.out
.attrib
= info2
->generic
.out
.attrib
;
704 case RAW_FILEINFO_STANDARD
:
705 info
->standard
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
706 info
->standard
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
707 info
->standard
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
708 info
->standard
.out
.size
= info2
->generic
.out
.size
;
709 info
->standard
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
710 info
->standard
.out
.attrib
= info2
->generic
.out
.attrib
;
713 case RAW_FILEINFO_EA_SIZE
:
714 info
->ea_size
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
715 info
->ea_size
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
716 info
->ea_size
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
717 info
->ea_size
.out
.size
= info2
->generic
.out
.size
;
718 info
->ea_size
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
719 info
->ea_size
.out
.attrib
= info2
->generic
.out
.attrib
;
720 info
->ea_size
.out
.ea_size
= info2
->generic
.out
.ea_size
;
723 case RAW_FILEINFO_STANDARD_INFO
:
724 case RAW_FILEINFO_STANDARD_INFORMATION
:
725 info
->standard_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
726 info
->standard_info
.out
.size
= info2
->generic
.out
.size
;
727 info
->standard_info
.out
.nlink
= info2
->generic
.out
.nlink
;
728 info
->standard_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
729 info
->standard_info
.out
.directory
= info2
->generic
.out
.directory
;
732 case RAW_FILEINFO_INTERNAL_INFORMATION
:
733 info
->internal_information
.out
.file_id
= info2
->generic
.out
.file_id
;
736 case RAW_FILEINFO_EA_INFO
:
737 case RAW_FILEINFO_EA_INFORMATION
:
738 info
->ea_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
741 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
742 info
->attribute_tag_information
.out
.attrib
= info2
->generic
.out
.attrib
;
743 info
->attribute_tag_information
.out
.reparse_tag
= info2
->generic
.out
.reparse_tag
;
746 case RAW_FILEINFO_STREAM_INFO
:
747 case RAW_FILEINFO_STREAM_INFORMATION
:
748 info
->stream_info
.out
.num_streams
= info2
->generic
.out
.num_streams
;
749 if (info
->stream_info
.out
.num_streams
> 0) {
750 info
->stream_info
.out
.streams
=
751 talloc_array(mem_ctx
,
752 struct stream_struct
,
753 info
->stream_info
.out
.num_streams
);
754 if (!info
->stream_info
.out
.streams
) {
755 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
756 info
->stream_info
.out
.num_streams
));
757 return NT_STATUS_NO_MEMORY
;
759 for (i
=0; i
< info
->stream_info
.out
.num_streams
; i
++) {
760 info
->stream_info
.out
.streams
[i
] = info2
->generic
.out
.streams
[i
];
761 info
->stream_info
.out
.streams
[i
].stream_name
.s
=
762 talloc_strdup(info
->stream_info
.out
.streams
,
763 info2
->generic
.out
.streams
[i
].stream_name
.s
);
764 if (!info
->stream_info
.out
.streams
[i
].stream_name
.s
) {
765 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
766 return NT_STATUS_NO_MEMORY
;
772 case RAW_FILEINFO_NAME_INFO
:
773 case RAW_FILEINFO_NAME_INFORMATION
:
774 info
->name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.fname
.s
);
775 NT_STATUS_HAVE_NO_MEMORY(info
->name_info
.out
.fname
.s
);
776 info
->name_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
779 case RAW_FILEINFO_ALT_NAME_INFO
:
780 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
781 info
->alt_name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.alt_fname
.s
);
782 NT_STATUS_HAVE_NO_MEMORY(info
->alt_name_info
.out
.fname
.s
);
783 info
->alt_name_info
.out
.fname
.private_length
= info2
->generic
.out
.alt_fname
.private_length
;
786 case RAW_FILEINFO_POSITION_INFORMATION
:
787 info
->position_information
.out
.position
= info2
->generic
.out
.position
;
790 case RAW_FILEINFO_ALL_EAS
:
791 info
->all_eas
.out
.num_eas
= info2
->generic
.out
.num_eas
;
792 if (info
->all_eas
.out
.num_eas
> 0) {
793 info
->all_eas
.out
.eas
= talloc_array(mem_ctx
,
795 info
->all_eas
.out
.num_eas
);
796 if (!info
->all_eas
.out
.eas
) {
797 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
798 info
->all_eas
.out
.num_eas
));
799 return NT_STATUS_NO_MEMORY
;
801 for (i
= 0; i
< info
->all_eas
.out
.num_eas
; i
++) {
802 info
->all_eas
.out
.eas
[i
] = info2
->generic
.out
.eas
[i
];
803 info
->all_eas
.out
.eas
[i
].name
.s
=
804 talloc_strdup(info
->all_eas
.out
.eas
,
805 info2
->generic
.out
.eas
[i
].name
.s
);
806 if (!info
->all_eas
.out
.eas
[i
].name
.s
) {
807 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
808 return NT_STATUS_NO_MEMORY
;
810 info
->all_eas
.out
.eas
[i
].value
.data
=
811 talloc_memdup(info
->all_eas
.out
.eas
,
812 info2
->generic
.out
.eas
[i
].value
.data
,
813 info2
->generic
.out
.eas
[i
].value
.length
);
814 if (!info
->all_eas
.out
.eas
[i
].value
.data
) {
815 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
816 return NT_STATUS_NO_MEMORY
;
822 case RAW_FILEINFO_IS_NAME_VALID
:
825 case RAW_FILEINFO_COMPRESSION_INFO
:
826 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
827 info
->compression_info
.out
.compressed_size
= info2
->generic
.out
.compressed_size
;
828 info
->compression_info
.out
.format
= info2
->generic
.out
.format
;
829 info
->compression_info
.out
.unit_shift
= info2
->generic
.out
.unit_shift
;
830 info
->compression_info
.out
.chunk_shift
= info2
->generic
.out
.chunk_shift
;
831 info
->compression_info
.out
.cluster_shift
= info2
->generic
.out
.cluster_shift
;
834 case RAW_FILEINFO_ACCESS_INFORMATION
:
835 info
->access_information
.out
.access_flags
= info2
->generic
.out
.access_flags
;
838 case RAW_FILEINFO_MODE_INFORMATION
:
839 info
->mode_information
.out
.mode
= info2
->generic
.out
.mode
;
842 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
843 info
->alignment_information
.out
.alignment_requirement
=
844 info2
->generic
.out
.alignment_requirement
;
847 case RAW_FILEINFO_UNIX_BASIC
:
848 info
->unix_basic_info
.out
.end_of_file
= info2
->generic
.out
.end_of_file
;
849 info
->unix_basic_info
.out
.num_bytes
= info2
->generic
.out
.size
;
850 info
->unix_basic_info
.out
.status_change_time
= info2
->generic
.out
.change_time
;
851 info
->unix_basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
852 info
->unix_basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
853 info
->unix_basic_info
.out
.uid
= info2
->generic
.out
.uid
;
854 info
->unix_basic_info
.out
.gid
= info2
->generic
.out
.gid
;
855 info
->unix_basic_info
.out
.file_type
= info2
->generic
.out
.file_type
;
856 info
->unix_basic_info
.out
.dev_major
= info2
->generic
.out
.device
;
857 info
->unix_basic_info
.out
.dev_minor
= info2
->generic
.out
.device
;
858 info
->unix_basic_info
.out
.unique_id
= info2
->generic
.out
.inode
;
859 info
->unix_basic_info
.out
.permissions
= info2
->generic
.out
.permissions
;
860 info
->unix_basic_info
.out
.nlink
= info2
->generic
.out
.nlink
;
863 case RAW_FILEINFO_UNIX_LINK
:
864 info
->unix_link_info
.out
.link_dest
= info2
->generic
.out
.link_dest
;
869 return NT_STATUS_INVALID_LEVEL
;
873 NTVFS fileinfo generic to any mapper
875 NTSTATUS
ntvfs_map_qfileinfo(struct ntvfs_module_context
*ntvfs
,
876 struct ntvfs_request
*req
,
877 union smb_fileinfo
*info
)
880 union smb_fileinfo
*info2
;
882 info2
= talloc(req
, union smb_fileinfo
);
884 return NT_STATUS_NO_MEMORY
;
887 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
888 return NT_STATUS_INVALID_LEVEL
;
891 /* ask the backend for the generic info */
892 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
893 info2
->generic
.in
.file
.ntvfs
= info
->generic
.in
.file
.ntvfs
;
895 /* only used by the simple backend, which doesn't do async */
896 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
898 status
= ntvfs
->ops
->qfileinfo(ntvfs
, req
, info2
);
899 if (!NT_STATUS_IS_OK(status
)) {
902 return ntvfs_map_fileinfo(req
, info
, info2
);
906 NTVFS pathinfo generic to any mapper
908 NTSTATUS
ntvfs_map_qpathinfo(struct ntvfs_module_context
*ntvfs
,
909 struct ntvfs_request
*req
,
910 union smb_fileinfo
*info
)
913 union smb_fileinfo
*info2
;
915 info2
= talloc(req
, union smb_fileinfo
);
917 return NT_STATUS_NO_MEMORY
;
920 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
921 return NT_STATUS_INVALID_LEVEL
;
924 /* ask the backend for the generic info */
925 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
926 info2
->generic
.in
.file
.path
= info
->generic
.in
.file
.path
;
928 /* only used by the simple backend, which doesn't do async */
929 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
931 status
= ntvfs
->ops
->qpathinfo(ntvfs
, req
, info2
);
932 if (!NT_STATUS_IS_OK(status
)) {
935 return ntvfs_map_fileinfo(req
, info
, info2
);
940 NTVFS lock generic to any mapper
942 NTSTATUS
ntvfs_map_lock(struct ntvfs_module_context
*ntvfs
,
943 struct ntvfs_request
*req
,
946 union smb_lock
*lck2
;
947 struct smb_lock_entry
*locks
;
949 lck2
= talloc(req
, union smb_lock
);
951 return NT_STATUS_NO_MEMORY
;
954 locks
= talloc_array(lck2
, struct smb_lock_entry
, 1);
956 return NT_STATUS_NO_MEMORY
;
959 switch (lck
->generic
.level
) {
961 return NT_STATUS_INVALID_LEVEL
;
964 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
965 lck2
->generic
.in
.file
.ntvfs
= lck
->lock
.in
.file
.ntvfs
;
966 lck2
->generic
.in
.mode
= 0;
967 lck2
->generic
.in
.timeout
= 0;
968 lck2
->generic
.in
.ulock_cnt
= 0;
969 lck2
->generic
.in
.lock_cnt
= 1;
970 lck2
->generic
.in
.locks
= locks
;
971 locks
->pid
= req
->smbpid
;
972 locks
->offset
= lck
->lock
.in
.offset
;
973 locks
->count
= lck
->lock
.in
.count
;
976 case RAW_LOCK_UNLOCK
:
977 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
978 lck2
->generic
.in
.file
.ntvfs
= lck
->unlock
.in
.file
.ntvfs
;
979 lck2
->generic
.in
.mode
= 0;
980 lck2
->generic
.in
.timeout
= 0;
981 lck2
->generic
.in
.ulock_cnt
= 1;
982 lck2
->generic
.in
.lock_cnt
= 0;
983 lck2
->generic
.in
.locks
= locks
;
984 locks
->pid
= req
->smbpid
;
985 locks
->offset
= lck
->unlock
.in
.offset
;
986 locks
->count
= lck
->unlock
.in
.count
;
990 if (lck
->smb2
.in
.unknown1
!= 1) {
991 return NT_STATUS_INVALID_PARAMETER
;
994 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
995 lck2
->generic
.in
.file
.ntvfs
= lck
->smb2
.in
.file
.ntvfs
;
996 if (lck
->smb2
.in
.flags
& SMB2_LOCK_FLAG_EXCLUSIV
) {
997 lck2
->generic
.in
.mode
= 0;
999 lck2
->generic
.in
.mode
= LOCKING_ANDX_SHARED_LOCK
;
1001 if (lck
->smb2
.in
.flags
& SMB2_LOCK_FLAG_NO_PENDING
) {
1002 lck2
->generic
.in
.timeout
= 0;
1004 lck2
->generic
.in
.timeout
= UINT32_MAX
;
1006 if (lck
->smb2
.in
.flags
& SMB2_LOCK_FLAG_UNLOCK
) {
1007 lck2
->generic
.in
.ulock_cnt
= 1;
1008 lck2
->generic
.in
.lock_cnt
= 0;
1010 lck2
->generic
.in
.ulock_cnt
= 0;
1011 lck2
->generic
.in
.lock_cnt
= 1;
1013 lck2
->generic
.in
.locks
= locks
;
1015 locks
->offset
= lck
->smb2
.in
.offset
;
1016 locks
->count
= lck
->smb2
.in
.count
;
1018 /* initialize output value */
1019 lck
->smb2
.out
.unknown1
= 0;
1024 * we don't need to call ntvfs_map_async_setup() here,
1025 * as lock() doesn't have any output fields
1028 return ntvfs
->ops
->lock(ntvfs
, req
, lck2
);
1033 NTVFS write generic to any mapper
1035 static NTSTATUS
ntvfs_map_write_finish(struct ntvfs_module_context
*ntvfs
,
1036 struct ntvfs_request
*req
,
1037 union smb_write
*wr
,
1038 union smb_write
*wr2
,
1041 union smb_lock
*lck
;
1042 union smb_close
*cl
;
1045 if (NT_STATUS_IS_ERR(status
)) {
1049 switch (wr
->generic
.level
) {
1050 case RAW_WRITE_WRITE
:
1051 wr
->write
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1054 case RAW_WRITE_WRITEUNLOCK
:
1055 wr
->writeunlock
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1057 lck
= talloc(wr2
, union smb_lock
);
1059 return NT_STATUS_NO_MEMORY
;
1062 lck
->unlock
.level
= RAW_LOCK_UNLOCK
;
1063 lck
->unlock
.in
.file
.ntvfs
= wr
->writeunlock
.in
.file
.ntvfs
;
1064 lck
->unlock
.in
.count
= wr
->writeunlock
.in
.count
;
1065 lck
->unlock
.in
.offset
= wr
->writeunlock
.in
.offset
;
1067 if (lck
->unlock
.in
.count
!= 0) {
1068 /* do the lock sync for now */
1069 state
= req
->async_states
->state
;
1070 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1071 status
= ntvfs
->ops
->lock(ntvfs
, req
, lck
);
1072 req
->async_states
->state
= state
;
1076 case RAW_WRITE_WRITECLOSE
:
1077 wr
->writeclose
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1079 cl
= talloc(wr2
, union smb_close
);
1081 return NT_STATUS_NO_MEMORY
;
1084 cl
->close
.level
= RAW_CLOSE_CLOSE
;
1085 cl
->close
.in
.file
.ntvfs
= wr
->writeclose
.in
.file
.ntvfs
;
1086 cl
->close
.in
.write_time
= wr
->writeclose
.in
.mtime
;
1088 if (wr2
->generic
.in
.count
!= 0) {
1089 /* do the close sync for now */
1090 state
= req
->async_states
->state
;
1091 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1092 status
= ntvfs
->ops
->close(ntvfs
, req
, cl
);
1093 req
->async_states
->state
= state
;
1097 case RAW_WRITE_SPLWRITE
:
1100 case RAW_WRITE_SMB2
:
1101 wr
->smb2
.out
._pad
= 0;
1102 wr
->smb2
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1103 wr
->smb2
.out
.unknown1
= 0;
1107 return NT_STATUS_INVALID_LEVEL
;
1115 NTVFS write generic to any mapper
1117 NTSTATUS
ntvfs_map_write(struct ntvfs_module_context
*ntvfs
,
1118 struct ntvfs_request
*req
,
1119 union smb_write
*wr
)
1121 union smb_write
*wr2
;
1124 wr2
= talloc(req
, union smb_write
);
1126 return NT_STATUS_NO_MEMORY
;
1129 status
= ntvfs_map_async_setup(ntvfs
, req
, wr
, wr2
,
1130 (second_stage_t
)ntvfs_map_write_finish
);
1131 if (!NT_STATUS_IS_OK(status
)) {
1135 wr2
->writex
.level
= RAW_WRITE_GENERIC
;
1137 switch (wr
->generic
.level
) {
1138 case RAW_WRITE_WRITEX
:
1139 status
= NT_STATUS_INVALID_LEVEL
;
1142 case RAW_WRITE_WRITE
:
1143 wr2
->writex
.in
.file
.ntvfs
= wr
->write
.in
.file
.ntvfs
;
1144 wr2
->writex
.in
.offset
= wr
->write
.in
.offset
;
1145 wr2
->writex
.in
.wmode
= 0;
1146 wr2
->writex
.in
.remaining
= wr
->write
.in
.remaining
;
1147 wr2
->writex
.in
.count
= wr
->write
.in
.count
;
1148 wr2
->writex
.in
.data
= wr
->write
.in
.data
;
1149 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1152 case RAW_WRITE_WRITEUNLOCK
:
1153 wr2
->writex
.in
.file
.ntvfs
= wr
->writeunlock
.in
.file
.ntvfs
;
1154 wr2
->writex
.in
.offset
= wr
->writeunlock
.in
.offset
;
1155 wr2
->writex
.in
.wmode
= 0;
1156 wr2
->writex
.in
.remaining
= wr
->writeunlock
.in
.remaining
;
1157 wr2
->writex
.in
.count
= wr
->writeunlock
.in
.count
;
1158 wr2
->writex
.in
.data
= wr
->writeunlock
.in
.data
;
1159 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1162 case RAW_WRITE_WRITECLOSE
:
1163 wr2
->writex
.in
.file
.ntvfs
= wr
->writeclose
.in
.file
.ntvfs
;
1164 wr2
->writex
.in
.offset
= wr
->writeclose
.in
.offset
;
1165 wr2
->writex
.in
.wmode
= 0;
1166 wr2
->writex
.in
.remaining
= 0;
1167 wr2
->writex
.in
.count
= wr
->writeclose
.in
.count
;
1168 wr2
->writex
.in
.data
= wr
->writeclose
.in
.data
;
1169 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1172 case RAW_WRITE_SPLWRITE
:
1173 wr2
->writex
.in
.file
.ntvfs
= wr
->splwrite
.in
.file
.ntvfs
;
1174 wr2
->writex
.in
.offset
= 0;
1175 wr2
->writex
.in
.wmode
= 0;
1176 wr2
->writex
.in
.remaining
= 0;
1177 wr2
->writex
.in
.count
= wr
->splwrite
.in
.count
;
1178 wr2
->writex
.in
.data
= wr
->splwrite
.in
.data
;
1179 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1182 case RAW_WRITE_SMB2
:
1183 wr2
->writex
.in
.file
.ntvfs
= wr
->smb2
.in
.file
.ntvfs
;
1184 wr2
->writex
.in
.offset
= wr
->smb2
.in
.offset
;
1185 wr2
->writex
.in
.wmode
= 0;
1186 wr2
->writex
.in
.remaining
= 0;
1187 wr2
->writex
.in
.count
= wr
->smb2
.in
.data
.length
;
1188 wr2
->writex
.in
.data
= wr
->smb2
.in
.data
.data
;
1189 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1192 return ntvfs_map_async_finish(req
, status
);
1197 NTVFS read generic to any mapper - finish the out mapping
1199 static NTSTATUS
ntvfs_map_read_finish(struct ntvfs_module_context
*ntvfs
,
1200 struct ntvfs_request
*req
,
1202 union smb_read
*rd2
,
1205 switch (rd
->generic
.level
) {
1207 rd
->read
.out
.nread
= rd2
->generic
.out
.nread
;
1209 case RAW_READ_READBRAW
:
1210 rd
->readbraw
.out
.nread
= rd2
->generic
.out
.nread
;
1212 case RAW_READ_LOCKREAD
:
1213 rd
->lockread
.out
.nread
= rd2
->generic
.out
.nread
;
1216 rd
->smb2
.out
.data
.length
= rd2
->generic
.out
.nread
;
1217 rd
->smb2
.out
.unknown1
= 0;
1220 return NT_STATUS_INVALID_LEVEL
;
1227 NTVFS read* to readx mapper
1229 NTSTATUS
ntvfs_map_read(struct ntvfs_module_context
*ntvfs
,
1230 struct ntvfs_request
*req
,
1233 union smb_read
*rd2
;
1234 union smb_lock
*lck
;
1238 rd2
= talloc(req
, union smb_read
);
1240 return NT_STATUS_NO_MEMORY
;
1243 status
= ntvfs_map_async_setup(ntvfs
, req
, rd
, rd2
,
1244 (second_stage_t
)ntvfs_map_read_finish
);
1245 if (!NT_STATUS_IS_OK(status
)) {
1249 rd2
->readx
.level
= RAW_READ_READX
;
1250 rd2
->readx
.in
.read_for_execute
= false;
1252 switch (rd
->generic
.level
) {
1253 case RAW_READ_READX
:
1254 status
= NT_STATUS_INVALID_LEVEL
;
1258 rd2
->readx
.in
.file
.ntvfs
= rd
->read
.in
.file
.ntvfs
;
1259 rd2
->readx
.in
.offset
= rd
->read
.in
.offset
;
1260 rd2
->readx
.in
.mincnt
= rd
->read
.in
.count
;
1261 rd2
->readx
.in
.maxcnt
= rd
->read
.in
.count
;
1262 rd2
->readx
.in
.remaining
= rd
->read
.in
.remaining
;
1263 rd2
->readx
.out
.data
= rd
->read
.out
.data
;
1264 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1267 case RAW_READ_READBRAW
:
1268 rd2
->readx
.in
.file
.ntvfs
= rd
->readbraw
.in
.file
.ntvfs
;
1269 rd2
->readx
.in
.offset
= rd
->readbraw
.in
.offset
;
1270 rd2
->readx
.in
.mincnt
= rd
->readbraw
.in
.mincnt
;
1271 rd2
->readx
.in
.maxcnt
= rd
->readbraw
.in
.maxcnt
;
1272 rd2
->readx
.in
.remaining
= 0;
1273 rd2
->readx
.out
.data
= rd
->readbraw
.out
.data
;
1274 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1277 case RAW_READ_LOCKREAD
:
1278 /* do the initial lock sync for now */
1279 state
= req
->async_states
->state
;
1280 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1282 lck
= talloc(rd2
, union smb_lock
);
1284 status
= NT_STATUS_NO_MEMORY
;
1287 lck
->lock
.level
= RAW_LOCK_LOCK
;
1288 lck
->lock
.in
.file
.ntvfs
= rd
->lockread
.in
.file
.ntvfs
;
1289 lck
->lock
.in
.count
= rd
->lockread
.in
.count
;
1290 lck
->lock
.in
.offset
= rd
->lockread
.in
.offset
;
1291 status
= ntvfs
->ops
->lock(ntvfs
, req
, lck
);
1292 req
->async_states
->state
= state
;
1294 rd2
->readx
.in
.file
.ntvfs
= rd
->lockread
.in
.file
.ntvfs
;
1295 rd2
->readx
.in
.offset
= rd
->lockread
.in
.offset
;
1296 rd2
->readx
.in
.mincnt
= rd
->lockread
.in
.count
;
1297 rd2
->readx
.in
.maxcnt
= rd
->lockread
.in
.count
;
1298 rd2
->readx
.in
.remaining
= rd
->lockread
.in
.remaining
;
1299 rd2
->readx
.out
.data
= rd
->lockread
.out
.data
;
1301 if (NT_STATUS_IS_OK(status
)) {
1302 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1307 rd2
->readx
.in
.file
.ntvfs
= rd
->smb2
.in
.file
.ntvfs
;
1308 rd2
->readx
.in
.offset
= rd
->smb2
.in
.offset
;
1309 rd2
->readx
.in
.mincnt
= rd
->smb2
.in
.length
;
1310 rd2
->readx
.in
.maxcnt
= rd
->smb2
.in
.length
;
1311 rd2
->readx
.in
.remaining
= 0;
1312 rd2
->readx
.out
.data
= rd
->smb2
.out
.data
.data
;
1313 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1318 return ntvfs_map_async_finish(req
, status
);
1323 NTVFS close generic to any mapper
1325 NTSTATUS
ntvfs_map_close(struct ntvfs_module_context
*ntvfs
,
1326 struct ntvfs_request
*req
,
1327 union smb_close
*cl
)
1329 union smb_close
*cl2
;
1331 cl2
= talloc(req
, union smb_close
);
1333 return NT_STATUS_NO_MEMORY
;
1336 switch (cl
->generic
.level
) {
1337 case RAW_CLOSE_CLOSE
:
1338 return NT_STATUS_INVALID_LEVEL
;
1340 case RAW_CLOSE_SPLCLOSE
:
1341 cl2
->generic
.level
= RAW_CLOSE_CLOSE
;
1342 cl2
->generic
.in
.file
.ntvfs
= cl
->splclose
.in
.file
.ntvfs
;
1343 cl2
->generic
.in
.write_time
= 0;
1346 case RAW_CLOSE_SMB2
:
1347 cl2
->generic
.level
= RAW_CLOSE_CLOSE
;
1348 cl2
->generic
.in
.file
.ntvfs
= cl
->smb2
.in
.file
.ntvfs
;
1349 cl2
->generic
.in
.write_time
= 0;
1350 /* SMB2 Close has output parameter, but we just zero them */
1351 ZERO_STRUCT(cl
->smb2
.out
);
1356 * we don't need to call ntvfs_map_async_setup() here,
1357 * as close() doesn't have any output fields
1360 return ntvfs
->ops
->close(ntvfs
, req
, cl2
);
1364 NTVFS notify generic to any mapper
1366 static NTSTATUS
ntvfs_map_notify_finish(struct ntvfs_module_context
*ntvfs
,
1367 struct ntvfs_request
*req
,
1368 union smb_notify
*nt
,
1369 union smb_notify
*nt2
,
1372 NT_STATUS_NOT_OK_RETURN(status
);
1374 switch (nt
->nttrans
.level
) {
1375 case RAW_NOTIFY_SMB2
:
1376 if (nt2
->nttrans
.out
.num_changes
== 0) {
1377 return STATUS_NOTIFY_ENUM_DIR
;
1379 nt
->smb2
.out
.num_changes
= nt2
->nttrans
.out
.num_changes
;
1380 nt
->smb2
.out
.changes
= talloc_steal(req
, nt2
->nttrans
.out
.changes
);
1384 return NT_STATUS_INVALID_LEVEL
;
1392 NTVFS notify generic to any mapper
1394 NTSTATUS
ntvfs_map_notify(struct ntvfs_module_context
*ntvfs
,
1395 struct ntvfs_request
*req
,
1396 union smb_notify
*nt
)
1398 union smb_notify
*nt2
;
1401 nt2
= talloc(req
, union smb_notify
);
1402 NT_STATUS_HAVE_NO_MEMORY(nt2
);
1404 status
= ntvfs_map_async_setup(ntvfs
, req
, nt
, nt2
,
1405 (second_stage_t
)ntvfs_map_notify_finish
);
1406 NT_STATUS_NOT_OK_RETURN(status
);
1408 nt2
->nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1410 switch (nt
->nttrans
.level
) {
1411 case RAW_NOTIFY_NTTRANS
:
1412 status
= NT_STATUS_INVALID_LEVEL
;
1415 case RAW_NOTIFY_SMB2
:
1416 nt2
->nttrans
.in
.file
.ntvfs
= nt
->smb2
.in
.file
.ntvfs
;
1417 nt2
->nttrans
.in
.buffer_size
= nt
->smb2
.in
.buffer_size
;
1418 nt2
->nttrans
.in
.completion_filter
= nt
->smb2
.in
.completion_filter
;
1419 nt2
->nttrans
.in
.recursive
= nt
->smb2
.in
.recursive
;
1420 status
= ntvfs
->ops
->notify(ntvfs
, req
, nt2
);
1424 return ntvfs_map_async_finish(req
, status
);