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
.fnum
= 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 any to fsinfo mapper
565 static NTSTATUS
ntvfs_map_fsinfo_finish(struct ntvfs_module_context
*ntvfs
,
566 struct ntvfs_request
*req
,
567 union smb_fsinfo
*fs
,
568 union smb_fsinfo
*fs2
,
571 if (!NT_STATUS_IS_OK(status
)) {
575 /* and convert it to the required level */
576 switch (fs
->generic
.level
) {
577 case RAW_QFS_GENERIC
:
578 return NT_STATUS_INVALID_LEVEL
;
580 case RAW_QFS_DSKATTR
: {
581 /* map from generic to DSKATTR */
584 /* we need to scale the sizes to fit */
585 for (bpunit
=64; bpunit
<0x10000; bpunit
*= 2) {
586 if (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
< bpunit
* 512 * 65535.0) {
591 fs
->dskattr
.out
.blocks_per_unit
= bpunit
;
592 fs
->dskattr
.out
.block_size
= 512;
593 fs
->dskattr
.out
.units_total
=
594 (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
595 fs
->dskattr
.out
.units_free
=
596 (fs2
->generic
.out
.blocks_free
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
598 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
599 if (bpunit
> 64 && req
->ctx
->protocol
<= PROTOCOL_LANMAN2
) {
600 fs
->dskattr
.out
.blocks_per_unit
= 64;
601 fs
->dskattr
.out
.units_total
= 0xFFFF;
602 fs
->dskattr
.out
.units_free
= 0xFFFF;
607 case RAW_QFS_ALLOCATION
:
608 fs
->allocation
.out
.fs_id
= fs2
->generic
.out
.fs_id
;
609 fs
->allocation
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
610 fs
->allocation
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
611 fs
->allocation
.out
.sectors_per_unit
= 1;
612 fs
->allocation
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
616 fs
->volume
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
617 fs
->volume
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
620 case RAW_QFS_VOLUME_INFO
:
621 case RAW_QFS_VOLUME_INFORMATION
:
622 fs
->volume_info
.out
.create_time
= fs2
->generic
.out
.create_time
;
623 fs
->volume_info
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
624 fs
->volume_info
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
627 case RAW_QFS_SIZE_INFO
:
628 case RAW_QFS_SIZE_INFORMATION
:
629 fs
->size_info
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
630 fs
->size_info
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
631 fs
->size_info
.out
.sectors_per_unit
= 1;
632 fs
->size_info
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
635 case RAW_QFS_DEVICE_INFO
:
636 case RAW_QFS_DEVICE_INFORMATION
:
637 fs
->device_info
.out
.device_type
= fs2
->generic
.out
.device_type
;
638 fs
->device_info
.out
.characteristics
= fs2
->generic
.out
.device_characteristics
;
641 case RAW_QFS_ATTRIBUTE_INFO
:
642 case RAW_QFS_ATTRIBUTE_INFORMATION
:
643 fs
->attribute_info
.out
.fs_attr
= fs2
->generic
.out
.fs_attr
;
644 fs
->attribute_info
.out
.max_file_component_length
= fs2
->generic
.out
.max_file_component_length
;
645 fs
->attribute_info
.out
.fs_type
.s
= fs2
->generic
.out
.fs_type
;
648 case RAW_QFS_QUOTA_INFORMATION
:
649 ZERO_STRUCT(fs
->quota_information
.out
.unknown
);
650 fs
->quota_information
.out
.quota_soft
= fs2
->generic
.out
.quota_soft
;
651 fs
->quota_information
.out
.quota_hard
= fs2
->generic
.out
.quota_hard
;
652 fs
->quota_information
.out
.quota_flags
= fs2
->generic
.out
.quota_flags
;
655 case RAW_QFS_FULL_SIZE_INFORMATION
:
656 fs
->full_size_information
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
657 fs
->full_size_information
.out
.call_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
658 fs
->full_size_information
.out
.actual_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
659 fs
->full_size_information
.out
.sectors_per_unit
= 1;
660 fs
->full_size_information
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
663 case RAW_QFS_OBJECTID_INFORMATION
:
664 fs
->objectid_information
.out
.guid
= fs2
->generic
.out
.guid
;
665 ZERO_STRUCT(fs
->objectid_information
.out
.unknown
);
670 return NT_STATUS_INVALID_LEVEL
;
674 NTVFS fsinfo any to generic mapper
676 NTSTATUS
ntvfs_map_fsinfo(struct ntvfs_module_context
*ntvfs
,
677 struct ntvfs_request
*req
,
678 union smb_fsinfo
*fs
)
681 union smb_fsinfo
*fs2
;
683 fs2
= talloc(req
, union smb_fsinfo
);
685 return NT_STATUS_NO_MEMORY
;
688 if (fs
->generic
.level
== RAW_QFS_GENERIC
) {
689 return NT_STATUS_INVALID_LEVEL
;
692 status
= ntvfs_map_async_setup(ntvfs
, req
, fs
, fs2
,
693 (second_stage_t
)ntvfs_map_fsinfo_finish
);
694 if (!NT_STATUS_IS_OK(status
)) {
698 /* ask the backend for the generic info */
699 fs2
->generic
.level
= RAW_QFS_GENERIC
;
701 status
= ntvfs
->ops
->fsinfo(ntvfs
, req
, fs2
);
702 return ntvfs_map_async_finish(req
, status
);
707 NTVFS fileinfo generic to any mapper
709 NTSTATUS
ntvfs_map_fileinfo(TALLOC_CTX
*mem_ctx
,
710 union smb_fileinfo
*info
,
711 union smb_fileinfo
*info2
)
714 /* and convert it to the required level using results in info2 */
715 switch (info
->generic
.level
) {
716 case RAW_FILEINFO_GENERIC
:
717 return NT_STATUS_INVALID_LEVEL
;
718 case RAW_FILEINFO_GETATTR
:
719 info
->getattr
.out
.attrib
= info2
->generic
.out
.attrib
& 0xff;
720 info
->getattr
.out
.size
= info2
->generic
.out
.size
;
721 info
->getattr
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
724 case RAW_FILEINFO_GETATTRE
:
725 info
->getattre
.out
.attrib
= info2
->generic
.out
.attrib
;
726 info
->getattre
.out
.size
= info2
->generic
.out
.size
;
727 info
->getattre
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
728 info
->getattre
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
729 info
->getattre
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
730 info
->getattre
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
733 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
734 info
->network_open_information
.out
.create_time
= info2
->generic
.out
.create_time
;
735 info
->network_open_information
.out
.access_time
= info2
->generic
.out
.access_time
;
736 info
->network_open_information
.out
.write_time
= info2
->generic
.out
.write_time
;
737 info
->network_open_information
.out
.change_time
= info2
->generic
.out
.change_time
;
738 info
->network_open_information
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
739 info
->network_open_information
.out
.size
= info2
->generic
.out
.size
;
740 info
->network_open_information
.out
.attrib
= info2
->generic
.out
.attrib
;
743 case RAW_FILEINFO_ALL_INFO
:
744 case RAW_FILEINFO_ALL_INFORMATION
:
745 info
->all_info
.out
.create_time
= info2
->generic
.out
.create_time
;
746 info
->all_info
.out
.access_time
= info2
->generic
.out
.access_time
;
747 info
->all_info
.out
.write_time
= info2
->generic
.out
.write_time
;
748 info
->all_info
.out
.change_time
= info2
->generic
.out
.change_time
;
749 info
->all_info
.out
.attrib
= info2
->generic
.out
.attrib
;
750 info
->all_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
751 info
->all_info
.out
.size
= info2
->generic
.out
.size
;
752 info
->all_info
.out
.nlink
= info2
->generic
.out
.nlink
;
753 info
->all_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
754 info
->all_info
.out
.directory
= info2
->generic
.out
.directory
;
755 info
->all_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
756 info
->all_info
.out
.fname
.s
= info2
->generic
.out
.fname
.s
;
757 info
->all_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
760 case RAW_FILEINFO_BASIC_INFO
:
761 case RAW_FILEINFO_BASIC_INFORMATION
:
762 info
->basic_info
.out
.create_time
= info2
->generic
.out
.create_time
;
763 info
->basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
764 info
->basic_info
.out
.write_time
= info2
->generic
.out
.write_time
;
765 info
->basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
766 info
->basic_info
.out
.attrib
= info2
->generic
.out
.attrib
;
769 case RAW_FILEINFO_STANDARD
:
770 info
->standard
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
771 info
->standard
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
772 info
->standard
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
773 info
->standard
.out
.size
= info2
->generic
.out
.size
;
774 info
->standard
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
775 info
->standard
.out
.attrib
= info2
->generic
.out
.attrib
;
778 case RAW_FILEINFO_EA_SIZE
:
779 info
->ea_size
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
780 info
->ea_size
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
781 info
->ea_size
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
782 info
->ea_size
.out
.size
= info2
->generic
.out
.size
;
783 info
->ea_size
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
784 info
->ea_size
.out
.attrib
= info2
->generic
.out
.attrib
;
785 info
->ea_size
.out
.ea_size
= info2
->generic
.out
.ea_size
;
788 case RAW_FILEINFO_STANDARD_INFO
:
789 case RAW_FILEINFO_STANDARD_INFORMATION
:
790 info
->standard_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
791 info
->standard_info
.out
.size
= info2
->generic
.out
.size
;
792 info
->standard_info
.out
.nlink
= info2
->generic
.out
.nlink
;
793 info
->standard_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
794 info
->standard_info
.out
.directory
= info2
->generic
.out
.directory
;
797 case RAW_FILEINFO_INTERNAL_INFORMATION
:
798 info
->internal_information
.out
.file_id
= info2
->generic
.out
.file_id
;
801 case RAW_FILEINFO_EA_INFO
:
802 case RAW_FILEINFO_EA_INFORMATION
:
803 info
->ea_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
806 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
807 info
->attribute_tag_information
.out
.attrib
= info2
->generic
.out
.attrib
;
808 info
->attribute_tag_information
.out
.reparse_tag
= info2
->generic
.out
.reparse_tag
;
811 case RAW_FILEINFO_STREAM_INFO
:
812 case RAW_FILEINFO_STREAM_INFORMATION
:
813 info
->stream_info
.out
.num_streams
= info2
->generic
.out
.num_streams
;
814 if (info
->stream_info
.out
.num_streams
> 0) {
815 info
->stream_info
.out
.streams
=
816 talloc_array(mem_ctx
,
817 struct stream_struct
,
818 info
->stream_info
.out
.num_streams
);
819 if (!info
->stream_info
.out
.streams
) {
820 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
821 info
->stream_info
.out
.num_streams
));
822 return NT_STATUS_NO_MEMORY
;
824 for (i
=0; i
< info
->stream_info
.out
.num_streams
; i
++) {
825 info
->stream_info
.out
.streams
[i
] = info2
->generic
.out
.streams
[i
];
826 info
->stream_info
.out
.streams
[i
].stream_name
.s
=
827 talloc_strdup(info
->stream_info
.out
.streams
,
828 info2
->generic
.out
.streams
[i
].stream_name
.s
);
829 if (!info
->stream_info
.out
.streams
[i
].stream_name
.s
) {
830 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
831 return NT_STATUS_NO_MEMORY
;
837 case RAW_FILEINFO_NAME_INFO
:
838 case RAW_FILEINFO_NAME_INFORMATION
:
839 info
->name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.fname
.s
);
840 NT_STATUS_HAVE_NO_MEMORY(info
->name_info
.out
.fname
.s
);
841 info
->name_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
844 case RAW_FILEINFO_ALT_NAME_INFO
:
845 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
846 info
->alt_name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.alt_fname
.s
);
847 NT_STATUS_HAVE_NO_MEMORY(info
->alt_name_info
.out
.fname
.s
);
848 info
->alt_name_info
.out
.fname
.private_length
= info2
->generic
.out
.alt_fname
.private_length
;
851 case RAW_FILEINFO_POSITION_INFORMATION
:
852 info
->position_information
.out
.position
= info2
->generic
.out
.position
;
855 case RAW_FILEINFO_ALL_EAS
:
856 info
->all_eas
.out
.num_eas
= info2
->generic
.out
.num_eas
;
857 if (info
->all_eas
.out
.num_eas
> 0) {
858 info
->all_eas
.out
.eas
= talloc_array(mem_ctx
,
860 info
->all_eas
.out
.num_eas
);
861 if (!info
->all_eas
.out
.eas
) {
862 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
863 info
->all_eas
.out
.num_eas
));
864 return NT_STATUS_NO_MEMORY
;
866 for (i
= 0; i
< info
->all_eas
.out
.num_eas
; i
++) {
867 info
->all_eas
.out
.eas
[i
] = info2
->generic
.out
.eas
[i
];
868 info
->all_eas
.out
.eas
[i
].name
.s
=
869 talloc_strdup(info
->all_eas
.out
.eas
,
870 info2
->generic
.out
.eas
[i
].name
.s
);
871 if (!info
->all_eas
.out
.eas
[i
].name
.s
) {
872 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
873 return NT_STATUS_NO_MEMORY
;
875 info
->all_eas
.out
.eas
[i
].value
.data
=
876 (uint8_t *)talloc_memdup(info
->all_eas
.out
.eas
,
877 info2
->generic
.out
.eas
[i
].value
.data
,
878 info2
->generic
.out
.eas
[i
].value
.length
);
879 if (!info
->all_eas
.out
.eas
[i
].value
.data
) {
880 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
881 return NT_STATUS_NO_MEMORY
;
887 case RAW_FILEINFO_IS_NAME_VALID
:
890 case RAW_FILEINFO_COMPRESSION_INFO
:
891 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
892 info
->compression_info
.out
.compressed_size
= info2
->generic
.out
.compressed_size
;
893 info
->compression_info
.out
.format
= info2
->generic
.out
.format
;
894 info
->compression_info
.out
.unit_shift
= info2
->generic
.out
.unit_shift
;
895 info
->compression_info
.out
.chunk_shift
= info2
->generic
.out
.chunk_shift
;
896 info
->compression_info
.out
.cluster_shift
= info2
->generic
.out
.cluster_shift
;
899 case RAW_FILEINFO_ACCESS_INFORMATION
:
900 info
->access_information
.out
.access_flags
= info2
->generic
.out
.access_flags
;
903 case RAW_FILEINFO_MODE_INFORMATION
:
904 info
->mode_information
.out
.mode
= info2
->generic
.out
.mode
;
907 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
908 info
->alignment_information
.out
.alignment_requirement
=
909 info2
->generic
.out
.alignment_requirement
;
912 case RAW_FILEINFO_UNIX_BASIC
:
913 info
->unix_basic_info
.out
.end_of_file
= info2
->generic
.out
.end_of_file
;
914 info
->unix_basic_info
.out
.num_bytes
= info2
->generic
.out
.size
;
915 info
->unix_basic_info
.out
.status_change_time
= info2
->generic
.out
.change_time
;
916 info
->unix_basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
917 info
->unix_basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
918 info
->unix_basic_info
.out
.uid
= info2
->generic
.out
.uid
;
919 info
->unix_basic_info
.out
.gid
= info2
->generic
.out
.gid
;
920 info
->unix_basic_info
.out
.file_type
= info2
->generic
.out
.file_type
;
921 info
->unix_basic_info
.out
.dev_major
= info2
->generic
.out
.device
;
922 info
->unix_basic_info
.out
.dev_minor
= info2
->generic
.out
.device
;
923 info
->unix_basic_info
.out
.unique_id
= info2
->generic
.out
.inode
;
924 info
->unix_basic_info
.out
.permissions
= info2
->generic
.out
.permissions
;
925 info
->unix_basic_info
.out
.nlink
= info2
->generic
.out
.nlink
;
928 case RAW_FILEINFO_UNIX_LINK
:
929 info
->unix_link_info
.out
.link_dest
= info2
->generic
.out
.link_dest
;
934 return NT_STATUS_INVALID_LEVEL
;
938 NTVFS any to fileinfo mapper
940 static NTSTATUS
ntvfs_map_qfileinfo_finish(struct ntvfs_module_context
*ntvfs
,
941 struct ntvfs_request
*req
,
942 union smb_fileinfo
*info
,
943 union smb_fileinfo
*info2
,
946 if (!NT_STATUS_IS_OK(status
)) {
950 return ntvfs_map_fileinfo(req
, info
, info2
);
954 NTVFS fileinfo generic to any mapper
956 NTSTATUS
ntvfs_map_qfileinfo(struct ntvfs_module_context
*ntvfs
,
957 struct ntvfs_request
*req
,
958 union smb_fileinfo
*info
)
961 union smb_fileinfo
*info2
;
963 info2
= talloc(req
, union smb_fileinfo
);
965 return NT_STATUS_NO_MEMORY
;
968 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
969 return NT_STATUS_INVALID_LEVEL
;
972 status
= ntvfs_map_async_setup(ntvfs
, req
, info
, info2
,
973 (second_stage_t
)ntvfs_map_qfileinfo_finish
);
974 if (!NT_STATUS_IS_OK(status
)) {
978 /* ask the backend for the generic info */
979 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
980 info2
->generic
.in
.file
.ntvfs
= info
->generic
.in
.file
.ntvfs
;
982 status
= ntvfs
->ops
->qfileinfo(ntvfs
, req
, info2
);
983 return ntvfs_map_async_finish(req
, status
);
987 NTVFS any to fileinfo mapper
989 static NTSTATUS
ntvfs_map_qpathinfo_finish(struct ntvfs_module_context
*ntvfs
,
990 struct ntvfs_request
*req
,
991 union smb_fileinfo
*info
,
992 union smb_fileinfo
*info2
,
995 if (!NT_STATUS_IS_OK(status
)) {
999 return ntvfs_map_fileinfo(req
, info
, info2
);
1003 NTVFS pathinfo generic to any mapper
1005 NTSTATUS
ntvfs_map_qpathinfo(struct ntvfs_module_context
*ntvfs
,
1006 struct ntvfs_request
*req
,
1007 union smb_fileinfo
*info
)
1010 union smb_fileinfo
*info2
;
1012 info2
= talloc(req
, union smb_fileinfo
);
1013 if (info2
== NULL
) {
1014 return NT_STATUS_NO_MEMORY
;
1017 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
1018 return NT_STATUS_INVALID_LEVEL
;
1021 status
= ntvfs_map_async_setup(ntvfs
, req
, info
, info2
,
1022 (second_stage_t
)ntvfs_map_qpathinfo_finish
);
1023 if (!NT_STATUS_IS_OK(status
)) {
1027 /* ask the backend for the generic info */
1028 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
1029 info2
->generic
.in
.file
.path
= info
->generic
.in
.file
.path
;
1031 status
= ntvfs
->ops
->qpathinfo(ntvfs
, req
, info2
);
1032 return ntvfs_map_async_finish(req
, status
);
1037 NTVFS lock generic to any mapper
1039 NTSTATUS
ntvfs_map_lock(struct ntvfs_module_context
*ntvfs
,
1040 struct ntvfs_request
*req
,
1041 union smb_lock
*lck
)
1043 union smb_lock
*lck2
;
1044 struct smb_lock_entry
*locks
;
1046 lck2
= talloc(req
, union smb_lock
);
1048 return NT_STATUS_NO_MEMORY
;
1051 locks
= talloc_array(lck2
, struct smb_lock_entry
, 1);
1052 if (locks
== NULL
) {
1053 return NT_STATUS_NO_MEMORY
;
1056 switch (lck
->generic
.level
) {
1057 case RAW_LOCK_LOCKX
:
1058 return NT_STATUS_INVALID_LEVEL
;
1061 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1062 lck2
->generic
.in
.file
.ntvfs
= lck
->lock
.in
.file
.ntvfs
;
1063 lck2
->generic
.in
.mode
= 0;
1064 lck2
->generic
.in
.timeout
= 0;
1065 lck2
->generic
.in
.ulock_cnt
= 0;
1066 lck2
->generic
.in
.lock_cnt
= 1;
1067 lck2
->generic
.in
.locks
= locks
;
1068 locks
->pid
= req
->smbpid
;
1069 locks
->offset
= lck
->lock
.in
.offset
;
1070 locks
->count
= lck
->lock
.in
.count
;
1073 case RAW_LOCK_UNLOCK
:
1074 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1075 lck2
->generic
.in
.file
.ntvfs
= lck
->unlock
.in
.file
.ntvfs
;
1076 lck2
->generic
.in
.mode
= 0;
1077 lck2
->generic
.in
.timeout
= 0;
1078 lck2
->generic
.in
.ulock_cnt
= 1;
1079 lck2
->generic
.in
.lock_cnt
= 0;
1080 lck2
->generic
.in
.locks
= locks
;
1081 locks
->pid
= req
->smbpid
;
1082 locks
->offset
= lck
->unlock
.in
.offset
;
1083 locks
->count
= lck
->unlock
.in
.count
;
1086 case RAW_LOCK_SMB2
: {
1087 /* this is only approximate! We need to change the
1088 generic structure to fix this properly */
1091 if (lck
->smb2
.in
.lock_count
< 1) {
1092 return NT_STATUS_INVALID_PARAMETER
;
1095 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1096 lck2
->generic
.in
.file
.ntvfs
= lck
->smb2
.in
.file
.ntvfs
;
1097 lck2
->generic
.in
.timeout
= UINT32_MAX
;
1098 lck2
->generic
.in
.mode
= 0;
1099 lck2
->generic
.in
.lock_cnt
= 0;
1100 lck2
->generic
.in
.ulock_cnt
= 0;
1101 lck2
->generic
.in
.locks
= talloc_zero_array(lck2
, struct smb_lock_entry
,
1102 lck
->smb2
.in
.lock_count
);
1103 if (lck2
->generic
.in
.locks
== NULL
) {
1104 return NT_STATUS_NO_MEMORY
;
1106 /* only the first lock gives the UNLOCK bit - see
1108 if (lck
->smb2
.in
.locks
[0].flags
& SMB2_LOCK_FLAG_UNLOCK
) {
1109 lck2
->generic
.in
.ulock_cnt
= lck
->smb2
.in
.lock_count
;
1112 lck2
->generic
.in
.lock_cnt
= lck
->smb2
.in
.lock_count
;
1115 for (i
=0;i
<lck
->smb2
.in
.lock_count
;i
++) {
1116 if (lck
->smb2
.in
.locks
[i
].flags
== SMB2_LOCK_FLAG_NONE
) {
1117 return NT_STATUS_INVALID_PARAMETER
;
1120 if (lck
->smb2
.in
.locks
[i
].flags
& ~SMB2_LOCK_FLAG_ALL_MASK
) {
1121 return NT_STATUS_INVALID_PARAMETER
;
1125 (lck
->smb2
.in
.locks
[i
].flags
&
1126 (SMB2_LOCK_FLAG_SHARED
|SMB2_LOCK_FLAG_EXCLUSIVE
))) {
1127 return NT_STATUS_INVALID_PARAMETER
;
1130 (lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_UNLOCK
)) {
1131 return NT_STATUS_INVALID_PARAMETER
;
1133 lck2
->generic
.in
.locks
[i
].pid
= req
->smbpid
;
1134 lck2
->generic
.in
.locks
[i
].offset
= lck
->smb2
.in
.locks
[i
].offset
;
1135 lck2
->generic
.in
.locks
[i
].count
= lck
->smb2
.in
.locks
[i
].length
;
1136 if (!(lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_EXCLUSIVE
)) {
1137 lck2
->generic
.in
.mode
= LOCKING_ANDX_SHARED_LOCK
;
1139 if (lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
) {
1140 lck2
->generic
.in
.timeout
= 0;
1143 /* initialize output value */
1144 lck
->smb2
.out
.reserved
= 0;
1148 case RAW_LOCK_SMB2_BREAK
:
1149 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1150 lck2
->generic
.in
.file
.ntvfs
= lck
->smb2_break
.in
.file
.ntvfs
;
1151 lck2
->generic
.in
.mode
= LOCKING_ANDX_OPLOCK_RELEASE
|
1152 ((lck
->smb2_break
.in
.oplock_level
<< 8) & 0xFF00);
1153 lck2
->generic
.in
.timeout
= 0;
1154 lck2
->generic
.in
.ulock_cnt
= 0;
1155 lck2
->generic
.in
.lock_cnt
= 0;
1156 lck2
->generic
.in
.locks
= NULL
;
1158 /* initialize output value */
1159 lck
->smb2_break
.out
.oplock_level
= lck
->smb2_break
.in
.oplock_level
;
1160 lck
->smb2_break
.out
.reserved
= lck
->smb2_break
.in
.reserved
;
1161 lck
->smb2_break
.out
.reserved2
= lck
->smb2_break
.in
.reserved2
;
1162 lck
->smb2_break
.out
.file
= lck
->smb2_break
.in
.file
;
1167 * we don't need to call ntvfs_map_async_setup() here,
1168 * as lock() doesn't have any output fields
1171 return ntvfs
->ops
->lock(ntvfs
, req
, lck2
);
1176 NTVFS write generic to any mapper
1178 static NTSTATUS
ntvfs_map_write_finish(struct ntvfs_module_context
*ntvfs
,
1179 struct ntvfs_request
*req
,
1180 union smb_write
*wr
,
1181 union smb_write
*wr2
,
1184 union smb_lock
*lck
;
1185 union smb_close
*cl
;
1188 if (NT_STATUS_IS_ERR(status
)) {
1192 switch (wr
->generic
.level
) {
1193 case RAW_WRITE_WRITE
:
1194 wr
->write
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1197 case RAW_WRITE_WRITEUNLOCK
:
1198 wr
->writeunlock
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1200 lck
= talloc(wr2
, union smb_lock
);
1202 return NT_STATUS_NO_MEMORY
;
1205 lck
->unlock
.level
= RAW_LOCK_UNLOCK
;
1206 lck
->unlock
.in
.file
.ntvfs
= wr
->writeunlock
.in
.file
.ntvfs
;
1207 lck
->unlock
.in
.count
= wr
->writeunlock
.in
.count
;
1208 lck
->unlock
.in
.offset
= wr
->writeunlock
.in
.offset
;
1210 if (lck
->unlock
.in
.count
!= 0) {
1211 /* do the lock sync for now */
1212 state
= req
->async_states
->state
;
1213 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1214 status
= ntvfs
->ops
->lock(ntvfs
, req
, lck
);
1215 req
->async_states
->state
= state
;
1219 case RAW_WRITE_WRITECLOSE
:
1220 wr
->writeclose
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1222 cl
= talloc(wr2
, union smb_close
);
1224 return NT_STATUS_NO_MEMORY
;
1227 cl
->close
.level
= RAW_CLOSE_CLOSE
;
1228 cl
->close
.in
.file
.ntvfs
= wr
->writeclose
.in
.file
.ntvfs
;
1229 cl
->close
.in
.write_time
= wr
->writeclose
.in
.mtime
;
1231 if (wr2
->generic
.in
.count
!= 0) {
1232 /* do the close sync for now */
1233 state
= req
->async_states
->state
;
1234 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1235 status
= ntvfs
->ops
->close(ntvfs
, req
, cl
);
1236 req
->async_states
->state
= state
;
1240 case RAW_WRITE_SPLWRITE
:
1243 case RAW_WRITE_SMB2
:
1244 wr
->smb2
.out
._pad
= 0;
1245 wr
->smb2
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1246 wr
->smb2
.out
.unknown1
= 0;
1250 return NT_STATUS_INVALID_LEVEL
;
1258 NTVFS write generic to any mapper
1260 NTSTATUS
ntvfs_map_write(struct ntvfs_module_context
*ntvfs
,
1261 struct ntvfs_request
*req
,
1262 union smb_write
*wr
)
1264 union smb_write
*wr2
;
1267 wr2
= talloc(req
, union smb_write
);
1269 return NT_STATUS_NO_MEMORY
;
1272 status
= ntvfs_map_async_setup(ntvfs
, req
, wr
, wr2
,
1273 (second_stage_t
)ntvfs_map_write_finish
);
1274 if (!NT_STATUS_IS_OK(status
)) {
1278 wr2
->writex
.level
= RAW_WRITE_GENERIC
;
1280 switch (wr
->generic
.level
) {
1281 case RAW_WRITE_WRITEX
:
1282 status
= NT_STATUS_INVALID_LEVEL
;
1285 case RAW_WRITE_WRITE
:
1286 wr2
->writex
.in
.file
.ntvfs
= wr
->write
.in
.file
.ntvfs
;
1287 wr2
->writex
.in
.offset
= wr
->write
.in
.offset
;
1288 wr2
->writex
.in
.wmode
= 0;
1289 wr2
->writex
.in
.remaining
= wr
->write
.in
.remaining
;
1290 wr2
->writex
.in
.count
= wr
->write
.in
.count
;
1291 wr2
->writex
.in
.data
= wr
->write
.in
.data
;
1292 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1295 case RAW_WRITE_WRITEUNLOCK
:
1296 wr2
->writex
.in
.file
.ntvfs
= wr
->writeunlock
.in
.file
.ntvfs
;
1297 wr2
->writex
.in
.offset
= wr
->writeunlock
.in
.offset
;
1298 wr2
->writex
.in
.wmode
= 0;
1299 wr2
->writex
.in
.remaining
= wr
->writeunlock
.in
.remaining
;
1300 wr2
->writex
.in
.count
= wr
->writeunlock
.in
.count
;
1301 wr2
->writex
.in
.data
= wr
->writeunlock
.in
.data
;
1302 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1305 case RAW_WRITE_WRITECLOSE
:
1306 wr2
->writex
.in
.file
.ntvfs
= wr
->writeclose
.in
.file
.ntvfs
;
1307 wr2
->writex
.in
.offset
= wr
->writeclose
.in
.offset
;
1308 wr2
->writex
.in
.wmode
= 0;
1309 wr2
->writex
.in
.remaining
= 0;
1310 wr2
->writex
.in
.count
= wr
->writeclose
.in
.count
;
1311 wr2
->writex
.in
.data
= wr
->writeclose
.in
.data
;
1312 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1315 case RAW_WRITE_SPLWRITE
:
1316 wr2
->writex
.in
.file
.ntvfs
= wr
->splwrite
.in
.file
.ntvfs
;
1317 wr2
->writex
.in
.offset
= 0;
1318 wr2
->writex
.in
.wmode
= 0;
1319 wr2
->writex
.in
.remaining
= 0;
1320 wr2
->writex
.in
.count
= wr
->splwrite
.in
.count
;
1321 wr2
->writex
.in
.data
= wr
->splwrite
.in
.data
;
1322 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1325 case RAW_WRITE_SMB2
:
1326 wr2
->writex
.in
.file
.ntvfs
= wr
->smb2
.in
.file
.ntvfs
;
1327 wr2
->writex
.in
.offset
= wr
->smb2
.in
.offset
;
1328 wr2
->writex
.in
.wmode
= 0;
1329 wr2
->writex
.in
.remaining
= 0;
1330 wr2
->writex
.in
.count
= wr
->smb2
.in
.data
.length
;
1331 wr2
->writex
.in
.data
= wr
->smb2
.in
.data
.data
;
1332 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1335 return ntvfs_map_async_finish(req
, status
);
1340 NTVFS read generic to any mapper - finish the out mapping
1342 static NTSTATUS
ntvfs_map_read_finish(struct ntvfs_module_context
*ntvfs
,
1343 struct ntvfs_request
*req
,
1345 union smb_read
*rd2
,
1348 switch (rd
->generic
.level
) {
1350 rd
->read
.out
.nread
= rd2
->generic
.out
.nread
;
1352 case RAW_READ_READBRAW
:
1353 rd
->readbraw
.out
.nread
= rd2
->generic
.out
.nread
;
1355 case RAW_READ_LOCKREAD
:
1356 rd
->lockread
.out
.nread
= rd2
->generic
.out
.nread
;
1359 rd
->smb2
.out
.data
.length
= rd2
->generic
.out
.nread
;
1360 rd
->smb2
.out
.remaining
= 0;
1361 rd
->smb2
.out
.reserved
= 0;
1364 return NT_STATUS_INVALID_LEVEL
;
1371 NTVFS read* to readx mapper
1373 NTSTATUS
ntvfs_map_read(struct ntvfs_module_context
*ntvfs
,
1374 struct ntvfs_request
*req
,
1377 union smb_read
*rd2
;
1378 union smb_lock
*lck
;
1382 rd2
= talloc(req
, union smb_read
);
1384 return NT_STATUS_NO_MEMORY
;
1387 status
= ntvfs_map_async_setup(ntvfs
, req
, rd
, rd2
,
1388 (second_stage_t
)ntvfs_map_read_finish
);
1389 if (!NT_STATUS_IS_OK(status
)) {
1393 rd2
->readx
.level
= RAW_READ_READX
;
1394 rd2
->readx
.in
.read_for_execute
= false;
1396 switch (rd
->generic
.level
) {
1397 case RAW_READ_READX
:
1398 status
= NT_STATUS_INVALID_LEVEL
;
1402 rd2
->readx
.in
.file
.ntvfs
= rd
->read
.in
.file
.ntvfs
;
1403 rd2
->readx
.in
.offset
= rd
->read
.in
.offset
;
1404 rd2
->readx
.in
.mincnt
= rd
->read
.in
.count
;
1405 rd2
->readx
.in
.maxcnt
= rd
->read
.in
.count
;
1406 rd2
->readx
.in
.remaining
= rd
->read
.in
.remaining
;
1407 rd2
->readx
.out
.data
= rd
->read
.out
.data
;
1408 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1411 case RAW_READ_READBRAW
:
1412 rd2
->readx
.in
.file
.ntvfs
= rd
->readbraw
.in
.file
.ntvfs
;
1413 rd2
->readx
.in
.offset
= rd
->readbraw
.in
.offset
;
1414 rd2
->readx
.in
.mincnt
= rd
->readbraw
.in
.mincnt
;
1415 rd2
->readx
.in
.maxcnt
= rd
->readbraw
.in
.maxcnt
;
1416 rd2
->readx
.in
.remaining
= 0;
1417 rd2
->readx
.out
.data
= rd
->readbraw
.out
.data
;
1418 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1421 case RAW_READ_LOCKREAD
:
1422 /* do the initial lock sync for now */
1423 state
= req
->async_states
->state
;
1424 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1426 lck
= talloc(rd2
, union smb_lock
);
1428 status
= NT_STATUS_NO_MEMORY
;
1431 lck
->lock
.level
= RAW_LOCK_LOCK
;
1432 lck
->lock
.in
.file
.ntvfs
= rd
->lockread
.in
.file
.ntvfs
;
1433 lck
->lock
.in
.count
= rd
->lockread
.in
.count
;
1434 lck
->lock
.in
.offset
= rd
->lockread
.in
.offset
;
1435 status
= ntvfs
->ops
->lock(ntvfs
, req
, lck
);
1436 req
->async_states
->state
= state
;
1438 rd2
->readx
.in
.file
.ntvfs
= rd
->lockread
.in
.file
.ntvfs
;
1439 rd2
->readx
.in
.offset
= rd
->lockread
.in
.offset
;
1440 rd2
->readx
.in
.mincnt
= rd
->lockread
.in
.count
;
1441 rd2
->readx
.in
.maxcnt
= rd
->lockread
.in
.count
;
1442 rd2
->readx
.in
.remaining
= rd
->lockread
.in
.remaining
;
1443 rd2
->readx
.out
.data
= rd
->lockread
.out
.data
;
1445 if (NT_STATUS_IS_OK(status
)) {
1446 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1451 rd2
->readx
.in
.file
.ntvfs
= rd
->smb2
.in
.file
.ntvfs
;
1452 rd2
->readx
.in
.offset
= rd
->smb2
.in
.offset
;
1453 rd2
->readx
.in
.mincnt
= rd
->smb2
.in
.min_count
;
1454 rd2
->readx
.in
.maxcnt
= rd
->smb2
.in
.length
;
1455 rd2
->readx
.in
.remaining
= 0;
1456 rd2
->readx
.out
.data
= rd
->smb2
.out
.data
.data
;
1457 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1462 return ntvfs_map_async_finish(req
, status
);
1467 NTVFS close generic to any mapper
1469 static NTSTATUS
ntvfs_map_close_finish(struct ntvfs_module_context
*ntvfs
,
1470 struct ntvfs_request
*req
,
1471 union smb_close
*cl
,
1472 union smb_close
*cl2
,
1475 NT_STATUS_NOT_OK_RETURN(status
);
1477 switch (cl
->generic
.level
) {
1478 case RAW_CLOSE_SMB2
:
1479 cl
->smb2
.out
.flags
= cl2
->generic
.out
.flags
;
1480 cl
->smb2
.out
._pad
= 0;
1481 cl
->smb2
.out
.create_time
= cl2
->generic
.out
.create_time
;
1482 cl
->smb2
.out
.access_time
= cl2
->generic
.out
.access_time
;
1483 cl
->smb2
.out
.write_time
= cl2
->generic
.out
.write_time
;
1484 cl
->smb2
.out
.change_time
= cl2
->generic
.out
.change_time
;
1485 cl
->smb2
.out
.alloc_size
= cl2
->generic
.out
.alloc_size
;
1486 cl
->smb2
.out
.size
= cl2
->generic
.out
.size
;
1487 cl
->smb2
.out
.file_attr
= cl2
->generic
.out
.file_attr
;
1497 NTVFS close generic to any mapper
1499 NTSTATUS
ntvfs_map_close(struct ntvfs_module_context
*ntvfs
,
1500 struct ntvfs_request
*req
,
1501 union smb_close
*cl
)
1503 union smb_close
*cl2
;
1506 cl2
= talloc(req
, union smb_close
);
1508 return NT_STATUS_NO_MEMORY
;
1511 switch (cl
->generic
.level
) {
1512 case RAW_CLOSE_GENERIC
:
1513 return NT_STATUS_INVALID_LEVEL
;
1515 case RAW_CLOSE_CLOSE
:
1516 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1517 cl2
->generic
.in
.file
= cl
->close
.in
.file
;
1518 cl2
->generic
.in
.write_time
= cl
->close
.in
.write_time
;
1519 cl2
->generic
.in
.flags
= 0;
1522 case RAW_CLOSE_SPLCLOSE
:
1523 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1524 cl2
->generic
.in
.file
= cl
->splclose
.in
.file
;
1525 cl2
->generic
.in
.write_time
= 0;
1526 cl2
->generic
.in
.flags
= 0;
1529 case RAW_CLOSE_SMB2
:
1530 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1531 cl2
->generic
.in
.file
= cl
->smb2
.in
.file
;
1532 cl2
->generic
.in
.write_time
= 0;
1533 cl2
->generic
.in
.flags
= cl
->smb2
.in
.flags
;
1537 status
= ntvfs_map_async_setup(ntvfs
, req
, cl
, cl2
,
1538 (second_stage_t
)ntvfs_map_close_finish
);
1539 NT_STATUS_NOT_OK_RETURN(status
);
1541 status
= ntvfs
->ops
->close(ntvfs
, req
, cl2
);
1543 return ntvfs_map_async_finish(req
, status
);
1547 NTVFS notify generic to any mapper
1549 static NTSTATUS
ntvfs_map_notify_finish(struct ntvfs_module_context
*ntvfs
,
1550 struct ntvfs_request
*req
,
1551 union smb_notify
*nt
,
1552 union smb_notify
*nt2
,
1555 NT_STATUS_NOT_OK_RETURN(status
);
1557 switch (nt
->nttrans
.level
) {
1558 case RAW_NOTIFY_SMB2
:
1559 if (nt2
->nttrans
.out
.num_changes
== 0) {
1560 return STATUS_NOTIFY_ENUM_DIR
;
1562 nt
->smb2
.out
.num_changes
= nt2
->nttrans
.out
.num_changes
;
1563 nt
->smb2
.out
.changes
= talloc_steal(req
, nt2
->nttrans
.out
.changes
);
1567 return NT_STATUS_INVALID_LEVEL
;
1575 NTVFS notify generic to any mapper
1577 NTSTATUS
ntvfs_map_notify(struct ntvfs_module_context
*ntvfs
,
1578 struct ntvfs_request
*req
,
1579 union smb_notify
*nt
)
1581 union smb_notify
*nt2
;
1584 nt2
= talloc(req
, union smb_notify
);
1585 NT_STATUS_HAVE_NO_MEMORY(nt2
);
1587 status
= ntvfs_map_async_setup(ntvfs
, req
, nt
, nt2
,
1588 (second_stage_t
)ntvfs_map_notify_finish
);
1589 NT_STATUS_NOT_OK_RETURN(status
);
1591 nt2
->nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1593 switch (nt
->nttrans
.level
) {
1594 case RAW_NOTIFY_NTTRANS
:
1595 status
= NT_STATUS_INVALID_LEVEL
;
1598 case RAW_NOTIFY_SMB2
:
1599 nt2
->nttrans
.in
.file
.ntvfs
= nt
->smb2
.in
.file
.ntvfs
;
1600 nt2
->nttrans
.in
.buffer_size
= nt
->smb2
.in
.buffer_size
;
1601 nt2
->nttrans
.in
.completion_filter
= nt
->smb2
.in
.completion_filter
;
1602 nt2
->nttrans
.in
.recursive
= nt
->smb2
.in
.recursive
;
1603 status
= ntvfs
->ops
->notify(ntvfs
, req
, nt2
);
1607 return ntvfs_map_async_finish(req
, status
);