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
;
239 memcpy(io
->smb2
.out
.on_disk_id
, io2
->generic
.out
.on_disk_id
,
240 sizeof(io2
->generic
.out
.on_disk_id
));
244 return NT_STATUS_INVALID_LEVEL
;
247 /* doing a secondary request async is more trouble than its
249 state
= req
->async_states
->state
;
250 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
252 if (write_time
!= 0) {
253 sf
= talloc(req
, union smb_setfileinfo
);
254 NT_STATUS_HAVE_NO_MEMORY(sf
);
255 sf
->generic
.level
= RAW_SFILEINFO_STANDARD
;
256 sf
->generic
.in
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
257 sf
->standard
.in
.create_time
= 0;
258 sf
->standard
.in
.write_time
= write_time
;
259 sf
->standard
.in
.access_time
= 0;
260 status
= ntvfs
->ops
->setfileinfo_fn(ntvfs
, req
, sf
);
264 sf
= talloc(req
, union smb_setfileinfo
);
265 NT_STATUS_HAVE_NO_MEMORY(sf
);
266 sf
->generic
.level
= RAW_SFILEINFO_END_OF_FILE_INFORMATION
;
267 sf
->generic
.in
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
268 sf
->end_of_file_info
.in
.size
= set_size
;
269 status
= ntvfs
->ops
->setfileinfo_fn(ntvfs
, req
, sf
);
270 if (NT_STATUS_IS_OK(status
)) {
271 io
->openx
.out
.size
= io
->openx
.in
.size
;
275 req
->async_states
->state
= state
;
281 the core of the mapping between openx style parameters and ntcreatex
284 static NTSTATUS
map_openx_open(uint16_t flags
, uint16_t open_mode
,
285 uint16_t open_func
, const char *fname
,
288 io2
->generic
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
289 io2
->generic
.in
.private_flags
= 0;
291 if (flags
& OPENX_FLAGS_REQUEST_OPLOCK
) {
292 io2
->generic
.in
.flags
|= NTCREATEX_FLAGS_REQUEST_OPLOCK
;
294 if (flags
& OPENX_FLAGS_REQUEST_BATCH_OPLOCK
) {
295 io2
->generic
.in
.flags
|= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
;
298 switch (open_mode
& OPENX_MODE_ACCESS_MASK
) {
299 case OPENX_MODE_ACCESS_READ
:
300 case OPENX_MODE_ACCESS_EXEC
:
301 io2
->generic
.in
.access_mask
= SEC_RIGHTS_FILE_READ
;
303 case OPENX_MODE_ACCESS_WRITE
:
304 io2
->generic
.in
.access_mask
= SEC_RIGHTS_FILE_WRITE
;
306 case OPENX_MODE_ACCESS_RDWR
:
307 case OPENX_MODE_ACCESS_FCB
:
308 io2
->generic
.in
.access_mask
=
309 SEC_RIGHTS_FILE_READ
|
310 SEC_RIGHTS_FILE_WRITE
;
313 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
316 switch (open_mode
& OPENX_MODE_DENY_MASK
) {
317 case OPENX_MODE_DENY_READ
:
318 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_WRITE
;
320 case OPENX_MODE_DENY_WRITE
:
321 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
;
323 case OPENX_MODE_DENY_ALL
:
324 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
326 case OPENX_MODE_DENY_NONE
:
327 io2
->generic
.in
.share_access
=
328 NTCREATEX_SHARE_ACCESS_READ
|
329 NTCREATEX_SHARE_ACCESS_WRITE
;
331 case OPENX_MODE_DENY_DOS
:
332 /* DENY_DOS is quite strange - it depends on the filename! */
333 io2
->generic
.in
.private_flags
|=
334 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS
;
335 if (is_exe_filename(fname
)) {
336 io2
->generic
.in
.share_access
=
337 NTCREATEX_SHARE_ACCESS_READ
|
338 NTCREATEX_SHARE_ACCESS_WRITE
;
340 if ((open_mode
& OPENX_MODE_ACCESS_MASK
) == OPENX_MODE_ACCESS_READ
) {
341 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
;
343 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
347 case OPENX_MODE_DENY_FCB
:
348 io2
->generic
.in
.private_flags
|= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB
;
349 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
352 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
356 case (OPENX_OPEN_FUNC_OPEN
):
357 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
359 case (OPENX_OPEN_FUNC_TRUNC
):
360 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE
;
362 case (OPENX_OPEN_FUNC_FAIL
| OPENX_OPEN_FUNC_CREATE
):
363 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
365 case (OPENX_OPEN_FUNC_OPEN
| OPENX_OPEN_FUNC_CREATE
):
366 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
368 case (OPENX_OPEN_FUNC_TRUNC
| OPENX_OPEN_FUNC_CREATE
):
369 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
372 /* this one is very strange */
373 if ((open_mode
& OPENX_MODE_ACCESS_MASK
) == OPENX_MODE_ACCESS_EXEC
) {
374 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
377 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
384 NTVFS open generic to any mapper
386 NTSTATUS
ntvfs_map_open(struct ntvfs_module_context
*ntvfs
,
387 struct ntvfs_request
*req
,
393 io2
= talloc_zero(req
, union smb_open
);
395 return NT_STATUS_NO_MEMORY
;
398 status
= ntvfs_map_async_setup(ntvfs
, req
,
400 (second_stage_t
)ntvfs_map_open_finish
);
401 if (!NT_STATUS_IS_OK(status
)) {
405 io2
->generic
.level
= RAW_OPEN_GENERIC
;
407 switch (io
->generic
.level
) {
409 status
= map_openx_open(io
->openx
.in
.flags
,
410 io
->openx
.in
.open_mode
,
411 io
->openx
.in
.open_func
,
414 if (!NT_STATUS_IS_OK(status
)) {
418 io2
->generic
.in
.file_attr
= io
->openx
.in
.file_attrs
;
419 io2
->generic
.in
.fname
= io
->openx
.in
.fname
;
421 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
426 status
= map_openx_open(0,
427 io
->openold
.in
.open_mode
,
428 OPENX_OPEN_FUNC_OPEN
,
429 io
->openold
.in
.fname
,
431 if (!NT_STATUS_IS_OK(status
)) {
435 io2
->generic
.in
.file_attr
= io
->openold
.in
.search_attrs
;
436 io2
->generic
.in
.fname
= io
->openold
.in
.fname
;
438 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
441 case RAW_OPEN_T2OPEN
:
442 io2
->generic
.level
= RAW_OPEN_NTTRANS_CREATE
;
444 if (io
->t2open
.in
.open_func
== 0) {
445 status
= NT_STATUS_OBJECT_NAME_COLLISION
;
449 status
= map_openx_open(io
->t2open
.in
.flags
,
450 io
->t2open
.in
.open_mode
,
451 io
->t2open
.in
.open_func
,
454 if (!NT_STATUS_IS_OK(status
)) {
458 io2
->generic
.in
.file_attr
= io
->t2open
.in
.file_attrs
;
459 io2
->generic
.in
.fname
= io
->t2open
.in
.fname
;
460 io2
->generic
.in
.ea_list
= talloc(io2
, struct smb_ea_list
);
461 io2
->generic
.in
.ea_list
->num_eas
= io
->t2open
.in
.num_eas
;
462 io2
->generic
.in
.ea_list
->eas
= io
->t2open
.in
.eas
;
464 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
468 io2
->generic
.in
.file_attr
= io
->mknew
.in
.attrib
;
469 io2
->generic
.in
.fname
= io
->mknew
.in
.fname
;
470 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
471 io2
->generic
.in
.access_mask
=
472 SEC_RIGHTS_FILE_READ
|
473 SEC_RIGHTS_FILE_WRITE
;
474 io2
->generic
.in
.share_access
=
475 NTCREATEX_SHARE_ACCESS_READ
|
476 NTCREATEX_SHARE_ACCESS_WRITE
;
477 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
480 case RAW_OPEN_CREATE
:
481 io2
->generic
.in
.file_attr
= io
->mknew
.in
.attrib
;
482 io2
->generic
.in
.fname
= io
->mknew
.in
.fname
;
483 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
484 io2
->generic
.in
.access_mask
=
485 SEC_RIGHTS_FILE_READ
|
486 SEC_RIGHTS_FILE_WRITE
;
487 io2
->generic
.in
.share_access
=
488 NTCREATEX_SHARE_ACCESS_READ
|
489 NTCREATEX_SHARE_ACCESS_WRITE
;
490 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
494 io2
->generic
.in
.file_attr
= io
->ctemp
.in
.attrib
;
495 io2
->generic
.in
.fname
=
496 talloc_asprintf(io2
, "%s\\SRV%s",
497 io
->ctemp
.in
.directory
,
498 generate_random_str_list(io2
, 5, "0123456789"));
499 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
500 io2
->generic
.in
.access_mask
=
501 SEC_RIGHTS_FILE_READ
|
502 SEC_RIGHTS_FILE_WRITE
;
503 io2
->generic
.in
.share_access
=
504 NTCREATEX_SHARE_ACCESS_READ
|
505 NTCREATEX_SHARE_ACCESS_WRITE
;
506 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
509 switch (io
->smb2
.in
.oplock_level
) {
510 case SMB2_OPLOCK_LEVEL_BATCH
:
511 io2
->generic
.in
.flags
= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
|
512 NTCREATEX_FLAGS_REQUEST_OPLOCK
;
514 case SMB2_OPLOCK_LEVEL_EXCLUSIVE
:
515 io2
->generic
.in
.flags
= NTCREATEX_FLAGS_REQUEST_OPLOCK
;
518 io2
->generic
.in
.flags
= 0;
521 io2
->generic
.in
.root_fid
.fnum
= 0;
522 io2
->generic
.in
.access_mask
= io
->smb2
.in
.desired_access
;
523 io2
->generic
.in
.alloc_size
= io
->smb2
.in
.alloc_size
;
524 io2
->generic
.in
.file_attr
= io
->smb2
.in
.file_attributes
;
525 io2
->generic
.in
.share_access
= io
->smb2
.in
.share_access
;
526 io2
->generic
.in
.open_disposition
= io
->smb2
.in
.create_disposition
;
527 io2
->generic
.in
.create_options
= io
->smb2
.in
.create_options
;
528 io2
->generic
.in
.impersonation
= io
->smb2
.in
.impersonation_level
;
529 io2
->generic
.in
.security_flags
= 0;
530 io2
->generic
.in
.fname
= io
->smb2
.in
.fname
;
531 io2
->generic
.in
.sec_desc
= io
->smb2
.in
.sec_desc
;
532 io2
->generic
.in
.ea_list
= &io
->smb2
.in
.eas
;
533 io2
->generic
.in
.query_maximal_access
= io
->smb2
.in
.query_maximal_access
;
534 io2
->generic
.in
.query_on_disk_id
= io
->smb2
.in
.query_on_disk_id
;
535 io2
->generic
.in
.private_flags
= 0;
537 /* we don't support timewarp yet */
538 if (io
->smb2
.in
.timewarp
!= 0) {
539 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
543 /* we need to check these bits before we check the private mask */
544 if (io2
->generic
.in
.create_options
& SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK
) {
545 DEBUG(2,(__location__
" create_options 0x%x not supported\n",
546 io2
->generic
.in
.create_options
));
547 status
= NT_STATUS_NOT_SUPPORTED
;
551 /* TODO: find out why only SMB2 ignores these */
552 io2
->generic
.in
.create_options
&= ~NTCREATEX_OPTIONS_SYNC_ALERT
;
553 io2
->generic
.in
.create_options
&= ~NTCREATEX_OPTIONS_ASYNC_ALERT
;
555 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
559 status
= NT_STATUS_INVALID_LEVEL
;
563 return ntvfs_map_async_finish(req
, status
);
568 NTVFS any to fsinfo mapper
570 static NTSTATUS
ntvfs_map_fsinfo_finish(struct ntvfs_module_context
*ntvfs
,
571 struct ntvfs_request
*req
,
572 union smb_fsinfo
*fs
,
573 union smb_fsinfo
*fs2
,
576 if (!NT_STATUS_IS_OK(status
)) {
580 /* and convert it to the required level */
581 switch (fs
->generic
.level
) {
582 case RAW_QFS_DSKATTR
: {
583 /* map from generic to DSKATTR */
584 unsigned int bpunit
= 64;
586 /* we need to scale the sizes to fit */
587 for (bpunit
=64; bpunit
<0x10000; bpunit
*= 2) {
588 if (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
< bpunit
* 512 * 65535.0) {
593 fs
->dskattr
.out
.blocks_per_unit
= bpunit
;
594 fs
->dskattr
.out
.block_size
= 512;
595 fs
->dskattr
.out
.units_total
=
596 (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
597 fs
->dskattr
.out
.units_free
=
598 (fs2
->generic
.out
.blocks_free
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
600 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
601 if (bpunit
> 64 && req
->ctx
->protocol
<= PROTOCOL_LANMAN2
) {
602 fs
->dskattr
.out
.blocks_per_unit
= 64;
603 fs
->dskattr
.out
.units_total
= 0xFFFF;
604 fs
->dskattr
.out
.units_free
= 0xFFFF;
609 case RAW_QFS_ALLOCATION
:
610 fs
->allocation
.out
.fs_id
= fs2
->generic
.out
.fs_id
;
611 fs
->allocation
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
612 fs
->allocation
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
613 fs
->allocation
.out
.sectors_per_unit
= 1;
614 fs
->allocation
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
618 fs
->volume
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
619 fs
->volume
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
622 case RAW_QFS_VOLUME_INFO
:
623 case RAW_QFS_VOLUME_INFORMATION
:
624 fs
->volume_info
.out
.create_time
= fs2
->generic
.out
.create_time
;
625 fs
->volume_info
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
626 fs
->volume_info
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
629 case RAW_QFS_SIZE_INFO
:
630 case RAW_QFS_SIZE_INFORMATION
:
631 fs
->size_info
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
632 fs
->size_info
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
633 fs
->size_info
.out
.sectors_per_unit
= 1;
634 fs
->size_info
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
637 case RAW_QFS_DEVICE_INFO
:
638 case RAW_QFS_DEVICE_INFORMATION
:
639 fs
->device_info
.out
.device_type
= fs2
->generic
.out
.device_type
;
640 fs
->device_info
.out
.characteristics
= fs2
->generic
.out
.device_characteristics
;
643 case RAW_QFS_ATTRIBUTE_INFO
:
644 case RAW_QFS_ATTRIBUTE_INFORMATION
:
645 fs
->attribute_info
.out
.fs_attr
= fs2
->generic
.out
.fs_attr
;
646 fs
->attribute_info
.out
.max_file_component_length
= fs2
->generic
.out
.max_file_component_length
;
647 fs
->attribute_info
.out
.fs_type
.s
= fs2
->generic
.out
.fs_type
;
650 case RAW_QFS_QUOTA_INFORMATION
:
651 ZERO_STRUCT(fs
->quota_information
.out
.unknown
);
652 fs
->quota_information
.out
.quota_soft
= fs2
->generic
.out
.quota_soft
;
653 fs
->quota_information
.out
.quota_hard
= fs2
->generic
.out
.quota_hard
;
654 fs
->quota_information
.out
.quota_flags
= fs2
->generic
.out
.quota_flags
;
657 case RAW_QFS_FULL_SIZE_INFORMATION
:
658 fs
->full_size_information
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
659 fs
->full_size_information
.out
.call_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
660 fs
->full_size_information
.out
.actual_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
661 fs
->full_size_information
.out
.sectors_per_unit
= 1;
662 fs
->full_size_information
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
665 case RAW_QFS_OBJECTID_INFORMATION
:
666 fs
->objectid_information
.out
.guid
= fs2
->generic
.out
.guid
;
667 ZERO_STRUCT(fs
->objectid_information
.out
.unknown
);
670 case RAW_QFS_SECTOR_SIZE_INFORMATION
:
671 fs
->sector_size_info
.out
.logical_bytes_per_sector
672 = fs2
->generic
.out
.block_size
;
673 fs
->sector_size_info
.out
.phys_bytes_per_sector_atomic
674 = fs2
->generic
.out
.block_size
;
675 fs
->sector_size_info
.out
.phys_bytes_per_sector_perf
676 = fs2
->generic
.out
.block_size
;
677 fs
->sector_size_info
.out
.fs_effective_phys_bytes_per_sector_atomic
678 = fs2
->generic
.out
.block_size
;
679 fs
->sector_size_info
.out
.flags
680 = QFS_SSINFO_FLAGS_ALIGNED_DEVICE
681 | QFS_SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE
;
682 fs
->sector_size_info
.out
.byte_off_sector_align
= 0;
683 fs
->sector_size_info
.out
.byte_off_partition_align
= 0;
686 case RAW_QFS_GENERIC
:
687 case RAW_QFS_UNIX_INFO
:
688 return NT_STATUS_INVALID_LEVEL
;
691 return NT_STATUS_INVALID_LEVEL
;
695 NTVFS fsinfo any to generic mapper
697 NTSTATUS
ntvfs_map_fsinfo(struct ntvfs_module_context
*ntvfs
,
698 struct ntvfs_request
*req
,
699 union smb_fsinfo
*fs
)
702 union smb_fsinfo
*fs2
;
704 fs2
= talloc(req
, union smb_fsinfo
);
706 return NT_STATUS_NO_MEMORY
;
709 if (fs
->generic
.level
== RAW_QFS_GENERIC
) {
710 return NT_STATUS_INVALID_LEVEL
;
713 status
= ntvfs_map_async_setup(ntvfs
, req
, fs
, fs2
,
714 (second_stage_t
)ntvfs_map_fsinfo_finish
);
715 if (!NT_STATUS_IS_OK(status
)) {
719 /* ask the backend for the generic info */
720 fs2
->generic
.level
= RAW_QFS_GENERIC
;
722 status
= ntvfs
->ops
->fsinfo_fn(ntvfs
, req
, fs2
);
723 return ntvfs_map_async_finish(req
, status
);
728 NTVFS fileinfo generic to any mapper
730 NTSTATUS
ntvfs_map_fileinfo(TALLOC_CTX
*mem_ctx
,
731 union smb_fileinfo
*info
,
732 union smb_fileinfo
*info2
)
735 /* and convert it to the required level using results in info2 */
736 switch (info
->generic
.level
) {
737 case RAW_FILEINFO_GETATTR
:
738 info
->getattr
.out
.attrib
= info2
->generic
.out
.attrib
& 0xff;
739 info
->getattr
.out
.size
= info2
->generic
.out
.size
;
740 info
->getattr
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
743 case RAW_FILEINFO_GETATTRE
:
744 info
->getattre
.out
.attrib
= info2
->generic
.out
.attrib
;
745 info
->getattre
.out
.size
= info2
->generic
.out
.size
;
746 info
->getattre
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
747 info
->getattre
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
748 info
->getattre
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
749 info
->getattre
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
752 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
753 info
->network_open_information
.out
.create_time
= info2
->generic
.out
.create_time
;
754 info
->network_open_information
.out
.access_time
= info2
->generic
.out
.access_time
;
755 info
->network_open_information
.out
.write_time
= info2
->generic
.out
.write_time
;
756 info
->network_open_information
.out
.change_time
= info2
->generic
.out
.change_time
;
757 info
->network_open_information
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
758 info
->network_open_information
.out
.size
= info2
->generic
.out
.size
;
759 info
->network_open_information
.out
.attrib
= info2
->generic
.out
.attrib
;
762 case RAW_FILEINFO_ALL_INFO
:
763 case RAW_FILEINFO_ALL_INFORMATION
:
764 info
->all_info
.out
.create_time
= info2
->generic
.out
.create_time
;
765 info
->all_info
.out
.access_time
= info2
->generic
.out
.access_time
;
766 info
->all_info
.out
.write_time
= info2
->generic
.out
.write_time
;
767 info
->all_info
.out
.change_time
= info2
->generic
.out
.change_time
;
768 info
->all_info
.out
.attrib
= info2
->generic
.out
.attrib
;
769 info
->all_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
770 info
->all_info
.out
.size
= info2
->generic
.out
.size
;
771 info
->all_info
.out
.nlink
= info2
->generic
.out
.nlink
;
772 info
->all_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
773 info
->all_info
.out
.directory
= info2
->generic
.out
.directory
;
774 info
->all_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
775 info
->all_info
.out
.fname
.s
= info2
->generic
.out
.fname
.s
;
776 info
->all_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
779 case RAW_FILEINFO_BASIC_INFO
:
780 case RAW_FILEINFO_BASIC_INFORMATION
:
781 info
->basic_info
.out
.create_time
= info2
->generic
.out
.create_time
;
782 info
->basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
783 info
->basic_info
.out
.write_time
= info2
->generic
.out
.write_time
;
784 info
->basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
785 info
->basic_info
.out
.attrib
= info2
->generic
.out
.attrib
;
788 case RAW_FILEINFO_STANDARD
:
789 info
->standard
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
790 info
->standard
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
791 info
->standard
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
792 info
->standard
.out
.size
= info2
->generic
.out
.size
;
793 info
->standard
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
794 info
->standard
.out
.attrib
= info2
->generic
.out
.attrib
;
797 case RAW_FILEINFO_EA_SIZE
:
798 info
->ea_size
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
799 info
->ea_size
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
800 info
->ea_size
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
801 info
->ea_size
.out
.size
= info2
->generic
.out
.size
;
802 info
->ea_size
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
803 info
->ea_size
.out
.attrib
= info2
->generic
.out
.attrib
;
804 info
->ea_size
.out
.ea_size
= info2
->generic
.out
.ea_size
;
807 case RAW_FILEINFO_STANDARD_INFO
:
808 case RAW_FILEINFO_STANDARD_INFORMATION
:
809 info
->standard_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
810 info
->standard_info
.out
.size
= info2
->generic
.out
.size
;
811 info
->standard_info
.out
.nlink
= info2
->generic
.out
.nlink
;
812 info
->standard_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
813 info
->standard_info
.out
.directory
= info2
->generic
.out
.directory
;
816 case RAW_FILEINFO_INTERNAL_INFORMATION
:
817 info
->internal_information
.out
.file_id
= info2
->generic
.out
.file_id
;
820 case RAW_FILEINFO_EA_INFO
:
821 case RAW_FILEINFO_EA_INFORMATION
:
822 info
->ea_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
825 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
826 info
->attribute_tag_information
.out
.attrib
= info2
->generic
.out
.attrib
;
827 info
->attribute_tag_information
.out
.reparse_tag
= info2
->generic
.out
.reparse_tag
;
830 case RAW_FILEINFO_STREAM_INFO
:
831 case RAW_FILEINFO_STREAM_INFORMATION
:
832 info
->stream_info
.out
.num_streams
= info2
->generic
.out
.num_streams
;
833 if (info
->stream_info
.out
.num_streams
> 0) {
834 info
->stream_info
.out
.streams
=
835 talloc_array(mem_ctx
,
836 struct stream_struct
,
837 info
->stream_info
.out
.num_streams
);
838 if (!info
->stream_info
.out
.streams
) {
839 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
840 info
->stream_info
.out
.num_streams
));
841 return NT_STATUS_NO_MEMORY
;
843 for (i
=0; i
< info
->stream_info
.out
.num_streams
; i
++) {
844 info
->stream_info
.out
.streams
[i
] = info2
->generic
.out
.streams
[i
];
845 info
->stream_info
.out
.streams
[i
].stream_name
.s
=
846 talloc_strdup(info
->stream_info
.out
.streams
,
847 info2
->generic
.out
.streams
[i
].stream_name
.s
);
848 if (!info
->stream_info
.out
.streams
[i
].stream_name
.s
) {
849 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
850 return NT_STATUS_NO_MEMORY
;
856 case RAW_FILEINFO_NAME_INFO
:
857 case RAW_FILEINFO_NAME_INFORMATION
:
858 info
->name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.fname
.s
);
859 NT_STATUS_HAVE_NO_MEMORY(info
->name_info
.out
.fname
.s
);
860 info
->name_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
863 case RAW_FILEINFO_ALT_NAME_INFO
:
864 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
865 info
->alt_name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.alt_fname
.s
);
866 NT_STATUS_HAVE_NO_MEMORY(info
->alt_name_info
.out
.fname
.s
);
867 info
->alt_name_info
.out
.fname
.private_length
= info2
->generic
.out
.alt_fname
.private_length
;
870 case RAW_FILEINFO_POSITION_INFORMATION
:
871 info
->position_information
.out
.position
= info2
->generic
.out
.position
;
874 case RAW_FILEINFO_ALL_EAS
:
875 info
->all_eas
.out
.num_eas
= info2
->generic
.out
.num_eas
;
876 if (info
->all_eas
.out
.num_eas
> 0) {
877 info
->all_eas
.out
.eas
= talloc_array(mem_ctx
,
879 info
->all_eas
.out
.num_eas
);
880 if (!info
->all_eas
.out
.eas
) {
881 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
882 info
->all_eas
.out
.num_eas
));
883 return NT_STATUS_NO_MEMORY
;
885 for (i
= 0; i
< info
->all_eas
.out
.num_eas
; i
++) {
886 info
->all_eas
.out
.eas
[i
] = info2
->generic
.out
.eas
[i
];
887 info
->all_eas
.out
.eas
[i
].name
.s
=
888 talloc_strdup(info
->all_eas
.out
.eas
,
889 info2
->generic
.out
.eas
[i
].name
.s
);
890 if (!info
->all_eas
.out
.eas
[i
].name
.s
) {
891 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
892 return NT_STATUS_NO_MEMORY
;
894 info
->all_eas
.out
.eas
[i
].value
.data
=
895 (uint8_t *)talloc_memdup(info
->all_eas
.out
.eas
,
896 info2
->generic
.out
.eas
[i
].value
.data
,
897 info2
->generic
.out
.eas
[i
].value
.length
);
898 if (!info
->all_eas
.out
.eas
[i
].value
.data
) {
899 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
900 return NT_STATUS_NO_MEMORY
;
906 case RAW_FILEINFO_IS_NAME_VALID
:
909 case RAW_FILEINFO_COMPRESSION_INFO
:
910 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
911 info
->compression_info
.out
.compressed_size
= info2
->generic
.out
.compressed_size
;
912 info
->compression_info
.out
.format
= info2
->generic
.out
.format
;
913 info
->compression_info
.out
.unit_shift
= info2
->generic
.out
.unit_shift
;
914 info
->compression_info
.out
.chunk_shift
= info2
->generic
.out
.chunk_shift
;
915 info
->compression_info
.out
.cluster_shift
= info2
->generic
.out
.cluster_shift
;
918 case RAW_FILEINFO_ACCESS_INFORMATION
:
919 info
->access_information
.out
.access_flags
= info2
->generic
.out
.access_flags
;
922 case RAW_FILEINFO_MODE_INFORMATION
:
923 info
->mode_information
.out
.mode
= info2
->generic
.out
.mode
;
926 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
927 info
->alignment_information
.out
.alignment_requirement
=
928 info2
->generic
.out
.alignment_requirement
;
930 case RAW_FILEINFO_UNIX_BASIC
:
932 return NT_STATUS_INVALID_LEVEL
;
934 info
->unix_basic_info
.out
.end_of_file
= info2
->generic
.out
.end_of_file
;
935 info
->unix_basic_info
.out
.num_bytes
= info2
->generic
.out
.size
;
936 info
->unix_basic_info
.out
.status_change_time
= info2
->generic
.out
.change_time
;
937 info
->unix_basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
938 info
->unix_basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
939 info
->unix_basic_info
.out
.uid
= info2
->generic
.out
.uid
;
940 info
->unix_basic_info
.out
.gid
= info2
->generic
.out
.gid
;
941 info
->unix_basic_info
.out
.file_type
= info2
->generic
.out
.file_type
;
942 info
->unix_basic_info
.out
.dev_major
= info2
->generic
.out
.device
;
943 info
->unix_basic_info
.out
.dev_minor
= info2
->generic
.out
.device
;
944 info
->unix_basic_info
.out
.unique_id
= info2
->generic
.out
.inode
;
945 info
->unix_basic_info
.out
.permissions
= info2
->generic
.out
.permissions
;
946 info
->unix_basic_info
.out
.nlink
= info2
->generic
.out
.nlink
;
949 case RAW_FILEINFO_UNIX_LINK
:
951 return NT_STATUS_INVALID_LEVEL
;
953 info
->unix_link_info
.out
.link_dest
= info2
->generic
.out
.link_dest
;
956 case RAW_FILEINFO_GENERIC
:
957 case RAW_FILEINFO_SEC_DESC
:
958 case RAW_FILEINFO_EA_LIST
:
959 case RAW_FILEINFO_UNIX_INFO2
:
960 case RAW_FILEINFO_SMB2_ALL_EAS
:
961 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
962 return NT_STATUS_INVALID_LEVEL
;
963 case RAW_FILEINFO_NORMALIZED_NAME_INFORMATION
:
964 return NT_STATUS_NOT_SUPPORTED
;
967 return NT_STATUS_INVALID_LEVEL
;
971 NTVFS any to fileinfo mapper
973 static NTSTATUS
ntvfs_map_qfileinfo_finish(struct ntvfs_module_context
*ntvfs
,
974 struct ntvfs_request
*req
,
975 union smb_fileinfo
*info
,
976 union smb_fileinfo
*info2
,
979 if (!NT_STATUS_IS_OK(status
)) {
983 return ntvfs_map_fileinfo(req
, info
, info2
);
987 NTVFS fileinfo generic to any mapper
989 NTSTATUS
ntvfs_map_qfileinfo(struct ntvfs_module_context
*ntvfs
,
990 struct ntvfs_request
*req
,
991 union smb_fileinfo
*info
)
994 union smb_fileinfo
*info2
;
996 info2
= talloc(req
, union smb_fileinfo
);
998 return NT_STATUS_NO_MEMORY
;
1001 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
1002 return NT_STATUS_INVALID_LEVEL
;
1005 status
= ntvfs_map_async_setup(ntvfs
, req
, info
, info2
,
1006 (second_stage_t
)ntvfs_map_qfileinfo_finish
);
1007 if (!NT_STATUS_IS_OK(status
)) {
1011 /* ask the backend for the generic info */
1012 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
1013 info2
->generic
.in
.file
.ntvfs
= info
->generic
.in
.file
.ntvfs
;
1015 status
= ntvfs
->ops
->qfileinfo_fn(ntvfs
, req
, info2
);
1016 return ntvfs_map_async_finish(req
, status
);
1020 NTVFS any to fileinfo mapper
1022 static NTSTATUS
ntvfs_map_qpathinfo_finish(struct ntvfs_module_context
*ntvfs
,
1023 struct ntvfs_request
*req
,
1024 union smb_fileinfo
*info
,
1025 union smb_fileinfo
*info2
,
1028 if (!NT_STATUS_IS_OK(status
)) {
1032 return ntvfs_map_fileinfo(req
, info
, info2
);
1036 NTVFS pathinfo generic to any mapper
1038 NTSTATUS
ntvfs_map_qpathinfo(struct ntvfs_module_context
*ntvfs
,
1039 struct ntvfs_request
*req
,
1040 union smb_fileinfo
*info
)
1043 union smb_fileinfo
*info2
;
1045 info2
= talloc(req
, union smb_fileinfo
);
1046 if (info2
== NULL
) {
1047 return NT_STATUS_NO_MEMORY
;
1050 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
1051 return NT_STATUS_INVALID_LEVEL
;
1054 status
= ntvfs_map_async_setup(ntvfs
, req
, info
, info2
,
1055 (second_stage_t
)ntvfs_map_qpathinfo_finish
);
1056 if (!NT_STATUS_IS_OK(status
)) {
1060 /* ask the backend for the generic info */
1061 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
1062 info2
->generic
.in
.file
.path
= info
->generic
.in
.file
.path
;
1064 status
= ntvfs
->ops
->qpathinfo_fn(ntvfs
, req
, info2
);
1065 return ntvfs_map_async_finish(req
, status
);
1070 NTVFS lock generic to any mapper
1072 NTSTATUS
ntvfs_map_lock(struct ntvfs_module_context
*ntvfs
,
1073 struct ntvfs_request
*req
,
1074 union smb_lock
*lck
)
1076 union smb_lock
*lck2
;
1077 struct smb_lock_entry
*locks
;
1079 lck2
= talloc(req
, union smb_lock
);
1081 return NT_STATUS_NO_MEMORY
;
1084 locks
= talloc_array(lck2
, struct smb_lock_entry
, 1);
1085 if (locks
== NULL
) {
1086 return NT_STATUS_NO_MEMORY
;
1089 switch (lck
->generic
.level
) {
1090 case RAW_LOCK_LOCKX
:
1091 return NT_STATUS_INVALID_LEVEL
;
1094 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1095 lck2
->generic
.in
.file
.ntvfs
= lck
->lock
.in
.file
.ntvfs
;
1096 lck2
->generic
.in
.mode
= 0;
1097 lck2
->generic
.in
.timeout
= 0;
1098 lck2
->generic
.in
.ulock_cnt
= 0;
1099 lck2
->generic
.in
.lock_cnt
= 1;
1100 lck2
->generic
.in
.locks
= locks
;
1101 locks
->pid
= req
->smbpid
;
1102 locks
->offset
= lck
->lock
.in
.offset
;
1103 locks
->count
= lck
->lock
.in
.count
;
1106 case RAW_LOCK_UNLOCK
:
1107 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1108 lck2
->generic
.in
.file
.ntvfs
= lck
->unlock
.in
.file
.ntvfs
;
1109 lck2
->generic
.in
.mode
= 0;
1110 lck2
->generic
.in
.timeout
= 0;
1111 lck2
->generic
.in
.ulock_cnt
= 1;
1112 lck2
->generic
.in
.lock_cnt
= 0;
1113 lck2
->generic
.in
.locks
= locks
;
1114 locks
->pid
= req
->smbpid
;
1115 locks
->offset
= lck
->unlock
.in
.offset
;
1116 locks
->count
= lck
->unlock
.in
.count
;
1119 case RAW_LOCK_SMB2
: {
1120 /* this is only approximate! We need to change the
1121 generic structure to fix this properly */
1124 if (lck
->smb2
.in
.lock_count
< 1) {
1125 return NT_STATUS_INVALID_PARAMETER
;
1128 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1129 lck2
->generic
.in
.file
.ntvfs
= lck
->smb2
.in
.file
.ntvfs
;
1130 lck2
->generic
.in
.timeout
= UINT32_MAX
;
1131 lck2
->generic
.in
.mode
= 0;
1132 lck2
->generic
.in
.lock_cnt
= 0;
1133 lck2
->generic
.in
.ulock_cnt
= 0;
1134 lck2
->generic
.in
.locks
= talloc_zero_array(lck2
, struct smb_lock_entry
,
1135 lck
->smb2
.in
.lock_count
);
1136 if (lck2
->generic
.in
.locks
== NULL
) {
1137 return NT_STATUS_NO_MEMORY
;
1139 /* only the first lock gives the UNLOCK bit - see
1141 if (lck
->smb2
.in
.locks
[0].flags
& SMB2_LOCK_FLAG_UNLOCK
) {
1142 if (lck
->smb2
.in
.locks
[0].flags
& SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
) {
1143 return NT_STATUS_INVALID_PARAMETER
;
1145 lck2
->generic
.in
.ulock_cnt
= lck
->smb2
.in
.lock_count
;
1148 lck2
->generic
.in
.lock_cnt
= lck
->smb2
.in
.lock_count
;
1151 for (i
=0;i
<lck
->smb2
.in
.lock_count
;i
++) {
1153 lck
->smb2
.in
.locks
[i
].flags
== SMB2_LOCK_FLAG_NONE
) {
1154 return NT_STATUS_INVALID_PARAMETER
;
1157 if (lck
->smb2
.in
.locks
[i
].flags
& ~SMB2_LOCK_FLAG_ALL_MASK
) {
1158 return NT_STATUS_INVALID_PARAMETER
;
1162 (lck
->smb2
.in
.locks
[i
].flags
&
1163 (SMB2_LOCK_FLAG_SHARED
|SMB2_LOCK_FLAG_EXCLUSIVE
))) {
1164 return NT_STATUS_INVALID_PARAMETER
;
1167 (lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_UNLOCK
)) {
1168 return NT_STATUS_INVALID_PARAMETER
;
1170 lck2
->generic
.in
.locks
[i
].pid
= req
->smbpid
;
1171 lck2
->generic
.in
.locks
[i
].offset
= lck
->smb2
.in
.locks
[i
].offset
;
1172 lck2
->generic
.in
.locks
[i
].count
= lck
->smb2
.in
.locks
[i
].length
;
1173 if (!(lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_EXCLUSIVE
)) {
1174 lck2
->generic
.in
.mode
= LOCKING_ANDX_SHARED_LOCK
;
1176 if (lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
) {
1177 lck2
->generic
.in
.timeout
= 0;
1180 /* initialize output value */
1181 lck
->smb2
.out
.reserved
= 0;
1185 case RAW_LOCK_SMB2_BREAK
:
1186 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1187 lck2
->generic
.in
.file
.ntvfs
= lck
->smb2_break
.in
.file
.ntvfs
;
1188 lck2
->generic
.in
.mode
= LOCKING_ANDX_OPLOCK_RELEASE
|
1189 ((lck
->smb2_break
.in
.oplock_level
<< 8) & 0xFF00);
1190 lck2
->generic
.in
.timeout
= 0;
1191 lck2
->generic
.in
.ulock_cnt
= 0;
1192 lck2
->generic
.in
.lock_cnt
= 0;
1193 lck2
->generic
.in
.locks
= NULL
;
1195 /* initialize output value */
1196 lck
->smb2_break
.out
.oplock_level
= lck
->smb2_break
.in
.oplock_level
;
1197 lck
->smb2_break
.out
.reserved
= lck
->smb2_break
.in
.reserved
;
1198 lck
->smb2_break
.out
.reserved2
= lck
->smb2_break
.in
.reserved2
;
1199 lck
->smb2_break
.out
.file
= lck
->smb2_break
.in
.file
;
1204 * we don't need to call ntvfs_map_async_setup() here,
1205 * as lock() doesn't have any output fields
1208 return ntvfs
->ops
->lock_fn(ntvfs
, req
, lck2
);
1213 NTVFS write generic to any mapper
1215 static NTSTATUS
ntvfs_map_write_finish(struct ntvfs_module_context
*ntvfs
,
1216 struct ntvfs_request
*req
,
1217 union smb_write
*wr
,
1218 union smb_write
*wr2
,
1221 union smb_lock
*lck
;
1222 union smb_close
*cl
;
1225 if (NT_STATUS_IS_ERR(status
)) {
1229 switch (wr
->generic
.level
) {
1230 case RAW_WRITE_WRITE
:
1231 wr
->write
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1234 case RAW_WRITE_WRITEUNLOCK
:
1235 wr
->writeunlock
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1237 lck
= talloc(wr2
, union smb_lock
);
1239 return NT_STATUS_NO_MEMORY
;
1242 lck
->unlock
.level
= RAW_LOCK_UNLOCK
;
1243 lck
->unlock
.in
.file
.ntvfs
= wr
->writeunlock
.in
.file
.ntvfs
;
1244 lck
->unlock
.in
.count
= wr
->writeunlock
.in
.count
;
1245 lck
->unlock
.in
.offset
= wr
->writeunlock
.in
.offset
;
1247 if (lck
->unlock
.in
.count
!= 0) {
1248 /* do the lock sync for now */
1249 state
= req
->async_states
->state
;
1250 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1251 status
= ntvfs
->ops
->lock_fn(ntvfs
, req
, lck
);
1252 req
->async_states
->state
= state
;
1256 case RAW_WRITE_WRITECLOSE
:
1257 wr
->writeclose
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1259 cl
= talloc(wr2
, union smb_close
);
1261 return NT_STATUS_NO_MEMORY
;
1264 cl
->close
.level
= RAW_CLOSE_CLOSE
;
1265 cl
->close
.in
.file
.ntvfs
= wr
->writeclose
.in
.file
.ntvfs
;
1266 cl
->close
.in
.write_time
= wr
->writeclose
.in
.mtime
;
1268 if (wr2
->generic
.in
.count
!= 0) {
1269 /* do the close sync for now */
1270 state
= req
->async_states
->state
;
1271 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1272 status
= ntvfs
->ops
->close_fn(ntvfs
, req
, cl
);
1273 req
->async_states
->state
= state
;
1277 case RAW_WRITE_SPLWRITE
:
1280 case RAW_WRITE_SMB2
:
1281 wr
->smb2
.out
._pad
= 0;
1282 wr
->smb2
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1283 wr
->smb2
.out
.unknown1
= 0;
1287 return NT_STATUS_INVALID_LEVEL
;
1295 NTVFS write generic to any mapper
1297 NTSTATUS
ntvfs_map_write(struct ntvfs_module_context
*ntvfs
,
1298 struct ntvfs_request
*req
,
1299 union smb_write
*wr
)
1301 union smb_write
*wr2
;
1304 wr2
= talloc(req
, union smb_write
);
1306 return NT_STATUS_NO_MEMORY
;
1309 status
= ntvfs_map_async_setup(ntvfs
, req
, wr
, wr2
,
1310 (second_stage_t
)ntvfs_map_write_finish
);
1311 if (!NT_STATUS_IS_OK(status
)) {
1315 wr2
->writex
.level
= RAW_WRITE_GENERIC
;
1317 switch (wr
->generic
.level
) {
1318 case RAW_WRITE_WRITEX
:
1319 status
= NT_STATUS_INVALID_LEVEL
;
1322 case RAW_WRITE_WRITE
:
1323 wr2
->writex
.in
.file
.ntvfs
= wr
->write
.in
.file
.ntvfs
;
1324 wr2
->writex
.in
.offset
= wr
->write
.in
.offset
;
1325 wr2
->writex
.in
.wmode
= 0;
1326 wr2
->writex
.in
.remaining
= wr
->write
.in
.remaining
;
1327 wr2
->writex
.in
.count
= wr
->write
.in
.count
;
1328 wr2
->writex
.in
.data
= wr
->write
.in
.data
;
1329 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1332 case RAW_WRITE_WRITEUNLOCK
:
1333 wr2
->writex
.in
.file
.ntvfs
= wr
->writeunlock
.in
.file
.ntvfs
;
1334 wr2
->writex
.in
.offset
= wr
->writeunlock
.in
.offset
;
1335 wr2
->writex
.in
.wmode
= 0;
1336 wr2
->writex
.in
.remaining
= wr
->writeunlock
.in
.remaining
;
1337 wr2
->writex
.in
.count
= wr
->writeunlock
.in
.count
;
1338 wr2
->writex
.in
.data
= wr
->writeunlock
.in
.data
;
1339 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1342 case RAW_WRITE_WRITECLOSE
:
1343 wr2
->writex
.in
.file
.ntvfs
= wr
->writeclose
.in
.file
.ntvfs
;
1344 wr2
->writex
.in
.offset
= wr
->writeclose
.in
.offset
;
1345 wr2
->writex
.in
.wmode
= 0;
1346 wr2
->writex
.in
.remaining
= 0;
1347 wr2
->writex
.in
.count
= wr
->writeclose
.in
.count
;
1348 wr2
->writex
.in
.data
= wr
->writeclose
.in
.data
;
1349 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1352 case RAW_WRITE_SPLWRITE
:
1353 wr2
->writex
.in
.file
.ntvfs
= wr
->splwrite
.in
.file
.ntvfs
;
1354 wr2
->writex
.in
.offset
= 0;
1355 wr2
->writex
.in
.wmode
= 0;
1356 wr2
->writex
.in
.remaining
= 0;
1357 wr2
->writex
.in
.count
= wr
->splwrite
.in
.count
;
1358 wr2
->writex
.in
.data
= wr
->splwrite
.in
.data
;
1359 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1362 case RAW_WRITE_SMB2
:
1363 wr2
->writex
.in
.file
.ntvfs
= wr
->smb2
.in
.file
.ntvfs
;
1364 wr2
->writex
.in
.offset
= wr
->smb2
.in
.offset
;
1365 wr2
->writex
.in
.wmode
= 0;
1366 wr2
->writex
.in
.remaining
= 0;
1367 wr2
->writex
.in
.count
= wr
->smb2
.in
.data
.length
;
1368 wr2
->writex
.in
.data
= wr
->smb2
.in
.data
.data
;
1369 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1372 return ntvfs_map_async_finish(req
, status
);
1377 NTVFS read generic to any mapper - finish the out mapping
1379 static NTSTATUS
ntvfs_map_read_finish(struct ntvfs_module_context
*ntvfs
,
1380 struct ntvfs_request
*req
,
1382 union smb_read
*rd2
,
1385 switch (rd
->generic
.level
) {
1387 rd
->read
.out
.nread
= rd2
->generic
.out
.nread
;
1389 case RAW_READ_READBRAW
:
1390 rd
->readbraw
.out
.nread
= rd2
->generic
.out
.nread
;
1392 case RAW_READ_LOCKREAD
:
1393 rd
->lockread
.out
.nread
= rd2
->generic
.out
.nread
;
1396 rd
->smb2
.out
.data
.length
= rd2
->generic
.out
.nread
;
1397 rd
->smb2
.out
.remaining
= 0;
1398 rd
->smb2
.out
.reserved
= 0;
1401 return NT_STATUS_INVALID_LEVEL
;
1408 NTVFS read* to readx mapper
1410 NTSTATUS
ntvfs_map_read(struct ntvfs_module_context
*ntvfs
,
1411 struct ntvfs_request
*req
,
1414 union smb_read
*rd2
;
1415 union smb_lock
*lck
;
1419 rd2
= talloc(req
, union smb_read
);
1421 return NT_STATUS_NO_MEMORY
;
1424 status
= ntvfs_map_async_setup(ntvfs
, req
, rd
, rd2
,
1425 (second_stage_t
)ntvfs_map_read_finish
);
1426 if (!NT_STATUS_IS_OK(status
)) {
1430 rd2
->readx
.level
= RAW_READ_READX
;
1431 rd2
->readx
.in
.read_for_execute
= false;
1433 switch (rd
->generic
.level
) {
1434 case RAW_READ_READX
:
1435 status
= NT_STATUS_INVALID_LEVEL
;
1439 rd2
->readx
.in
.file
.ntvfs
= rd
->read
.in
.file
.ntvfs
;
1440 rd2
->readx
.in
.offset
= rd
->read
.in
.offset
;
1441 rd2
->readx
.in
.mincnt
= rd
->read
.in
.count
;
1442 rd2
->readx
.in
.maxcnt
= rd
->read
.in
.count
;
1443 rd2
->readx
.in
.remaining
= rd
->read
.in
.remaining
;
1444 rd2
->readx
.out
.data
= rd
->read
.out
.data
;
1445 status
= ntvfs
->ops
->read_fn(ntvfs
, req
, rd2
);
1448 case RAW_READ_READBRAW
:
1449 rd2
->readx
.in
.file
.ntvfs
= rd
->readbraw
.in
.file
.ntvfs
;
1450 rd2
->readx
.in
.offset
= rd
->readbraw
.in
.offset
;
1451 rd2
->readx
.in
.mincnt
= rd
->readbraw
.in
.mincnt
;
1452 rd2
->readx
.in
.maxcnt
= rd
->readbraw
.in
.maxcnt
;
1453 rd2
->readx
.in
.remaining
= 0;
1454 rd2
->readx
.out
.data
= rd
->readbraw
.out
.data
;
1455 status
= ntvfs
->ops
->read_fn(ntvfs
, req
, rd2
);
1458 case RAW_READ_LOCKREAD
:
1459 /* do the initial lock sync for now */
1460 state
= req
->async_states
->state
;
1461 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1463 lck
= talloc(rd2
, union smb_lock
);
1465 status
= NT_STATUS_NO_MEMORY
;
1468 lck
->lock
.level
= RAW_LOCK_LOCK
;
1469 lck
->lock
.in
.file
.ntvfs
= rd
->lockread
.in
.file
.ntvfs
;
1470 lck
->lock
.in
.count
= rd
->lockread
.in
.count
;
1471 lck
->lock
.in
.offset
= rd
->lockread
.in
.offset
;
1472 status
= ntvfs
->ops
->lock_fn(ntvfs
, req
, lck
);
1473 req
->async_states
->state
= state
;
1475 rd2
->readx
.in
.file
.ntvfs
= rd
->lockread
.in
.file
.ntvfs
;
1476 rd2
->readx
.in
.offset
= rd
->lockread
.in
.offset
;
1477 rd2
->readx
.in
.mincnt
= rd
->lockread
.in
.count
;
1478 rd2
->readx
.in
.maxcnt
= rd
->lockread
.in
.count
;
1479 rd2
->readx
.in
.remaining
= rd
->lockread
.in
.remaining
;
1480 rd2
->readx
.out
.data
= rd
->lockread
.out
.data
;
1482 if (NT_STATUS_IS_OK(status
)) {
1483 status
= ntvfs
->ops
->read_fn(ntvfs
, req
, rd2
);
1488 rd2
->readx
.in
.file
.ntvfs
= rd
->smb2
.in
.file
.ntvfs
;
1489 rd2
->readx
.in
.offset
= rd
->smb2
.in
.offset
;
1490 rd2
->readx
.in
.mincnt
= rd
->smb2
.in
.min_count
;
1491 rd2
->readx
.in
.maxcnt
= rd
->smb2
.in
.length
;
1492 rd2
->readx
.in
.remaining
= 0;
1493 rd2
->readx
.out
.data
= rd
->smb2
.out
.data
.data
;
1494 status
= ntvfs
->ops
->read_fn(ntvfs
, req
, rd2
);
1499 return ntvfs_map_async_finish(req
, status
);
1504 NTVFS close generic to any mapper
1506 static NTSTATUS
ntvfs_map_close_finish(struct ntvfs_module_context
*ntvfs
,
1507 struct ntvfs_request
*req
,
1508 union smb_close
*cl
,
1509 union smb_close
*cl2
,
1512 NT_STATUS_NOT_OK_RETURN(status
);
1514 switch (cl
->generic
.level
) {
1515 case RAW_CLOSE_SMB2
:
1516 cl
->smb2
.out
.flags
= cl2
->generic
.out
.flags
;
1517 cl
->smb2
.out
._pad
= 0;
1518 cl
->smb2
.out
.create_time
= cl2
->generic
.out
.create_time
;
1519 cl
->smb2
.out
.access_time
= cl2
->generic
.out
.access_time
;
1520 cl
->smb2
.out
.write_time
= cl2
->generic
.out
.write_time
;
1521 cl
->smb2
.out
.change_time
= cl2
->generic
.out
.change_time
;
1522 cl
->smb2
.out
.alloc_size
= cl2
->generic
.out
.alloc_size
;
1523 cl
->smb2
.out
.size
= cl2
->generic
.out
.size
;
1524 cl
->smb2
.out
.file_attr
= cl2
->generic
.out
.file_attr
;
1534 NTVFS close generic to any mapper
1536 NTSTATUS
ntvfs_map_close(struct ntvfs_module_context
*ntvfs
,
1537 struct ntvfs_request
*req
,
1538 union smb_close
*cl
)
1540 union smb_close
*cl2
;
1543 cl2
= talloc(req
, union smb_close
);
1545 return NT_STATUS_NO_MEMORY
;
1548 switch (cl
->generic
.level
) {
1549 case RAW_CLOSE_GENERIC
:
1550 return NT_STATUS_INVALID_LEVEL
;
1552 case RAW_CLOSE_CLOSE
:
1553 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1554 cl2
->generic
.in
.file
= cl
->close
.in
.file
;
1555 cl2
->generic
.in
.write_time
= cl
->close
.in
.write_time
;
1556 cl2
->generic
.in
.flags
= 0;
1559 case RAW_CLOSE_SPLCLOSE
:
1560 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1561 cl2
->generic
.in
.file
= cl
->splclose
.in
.file
;
1562 cl2
->generic
.in
.write_time
= 0;
1563 cl2
->generic
.in
.flags
= 0;
1566 case RAW_CLOSE_SMB2
:
1567 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1568 cl2
->generic
.in
.file
= cl
->smb2
.in
.file
;
1569 cl2
->generic
.in
.write_time
= 0;
1570 cl2
->generic
.in
.flags
= cl
->smb2
.in
.flags
;
1574 status
= ntvfs_map_async_setup(ntvfs
, req
, cl
, cl2
,
1575 (second_stage_t
)ntvfs_map_close_finish
);
1576 NT_STATUS_NOT_OK_RETURN(status
);
1578 status
= ntvfs
->ops
->close_fn(ntvfs
, req
, cl2
);
1580 return ntvfs_map_async_finish(req
, status
);
1584 NTVFS notify generic to any mapper
1586 static NTSTATUS
ntvfs_map_notify_finish(struct ntvfs_module_context
*ntvfs
,
1587 struct ntvfs_request
*req
,
1588 union smb_notify
*nt
,
1589 union smb_notify
*nt2
,
1592 NT_STATUS_NOT_OK_RETURN(status
);
1594 switch (nt
->nttrans
.level
) {
1595 case RAW_NOTIFY_SMB2
:
1596 if (nt2
->nttrans
.out
.num_changes
== 0) {
1597 return STATUS_NOTIFY_ENUM_DIR
;
1599 nt
->smb2
.out
.num_changes
= nt2
->nttrans
.out
.num_changes
;
1600 nt
->smb2
.out
.changes
= talloc_steal(req
, nt2
->nttrans
.out
.changes
);
1604 return NT_STATUS_INVALID_LEVEL
;
1612 NTVFS notify generic to any mapper
1614 NTSTATUS
ntvfs_map_notify(struct ntvfs_module_context
*ntvfs
,
1615 struct ntvfs_request
*req
,
1616 union smb_notify
*nt
)
1618 union smb_notify
*nt2
;
1621 nt2
= talloc(req
, union smb_notify
);
1622 NT_STATUS_HAVE_NO_MEMORY(nt2
);
1624 status
= ntvfs_map_async_setup(ntvfs
, req
, nt
, nt2
,
1625 (second_stage_t
)ntvfs_map_notify_finish
);
1626 NT_STATUS_NOT_OK_RETURN(status
);
1628 nt2
->nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1630 switch (nt
->nttrans
.level
) {
1631 case RAW_NOTIFY_NTTRANS
:
1632 status
= NT_STATUS_INVALID_LEVEL
;
1635 case RAW_NOTIFY_SMB2
:
1636 nt2
->nttrans
.in
.file
.ntvfs
= nt
->smb2
.in
.file
.ntvfs
;
1637 nt2
->nttrans
.in
.buffer_size
= nt
->smb2
.in
.buffer_size
;
1638 nt2
->nttrans
.in
.completion_filter
= nt
->smb2
.in
.completion_filter
;
1639 nt2
->nttrans
.in
.recursive
= nt
->smb2
.in
.recursive
;
1640 status
= ntvfs
->ops
->notify_fn(ntvfs
, req
, nt2
);
1644 return ntvfs_map_async_finish(req
, status
);