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
;
287 io2
->generic
.in
.private_flags
= 0;
289 if (flags
& OPENX_FLAGS_REQUEST_OPLOCK
) {
290 io2
->generic
.in
.flags
|= NTCREATEX_FLAGS_REQUEST_OPLOCK
;
292 if (flags
& OPENX_FLAGS_REQUEST_BATCH_OPLOCK
) {
293 io2
->generic
.in
.flags
|= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
;
296 switch (open_mode
& OPENX_MODE_ACCESS_MASK
) {
297 case OPENX_MODE_ACCESS_READ
:
298 case OPENX_MODE_ACCESS_EXEC
:
299 io2
->generic
.in
.access_mask
= SEC_RIGHTS_FILE_READ
;
301 case OPENX_MODE_ACCESS_WRITE
:
302 io2
->generic
.in
.access_mask
= SEC_RIGHTS_FILE_WRITE
;
304 case OPENX_MODE_ACCESS_RDWR
:
305 case OPENX_MODE_ACCESS_FCB
:
306 io2
->generic
.in
.access_mask
=
307 SEC_RIGHTS_FILE_READ
|
308 SEC_RIGHTS_FILE_WRITE
;
311 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
314 switch (open_mode
& OPENX_MODE_DENY_MASK
) {
315 case OPENX_MODE_DENY_READ
:
316 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_WRITE
;
318 case OPENX_MODE_DENY_WRITE
:
319 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
;
321 case OPENX_MODE_DENY_ALL
:
322 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
324 case OPENX_MODE_DENY_NONE
:
325 io2
->generic
.in
.share_access
=
326 NTCREATEX_SHARE_ACCESS_READ
|
327 NTCREATEX_SHARE_ACCESS_WRITE
;
329 case OPENX_MODE_DENY_DOS
:
330 /* DENY_DOS is quite strange - it depends on the filename! */
331 io2
->generic
.in
.private_flags
|=
332 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS
;
333 if (is_exe_filename(fname
)) {
334 io2
->generic
.in
.share_access
=
335 NTCREATEX_SHARE_ACCESS_READ
|
336 NTCREATEX_SHARE_ACCESS_WRITE
;
338 if ((open_mode
& OPENX_MODE_ACCESS_MASK
) == OPENX_MODE_ACCESS_READ
) {
339 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
;
341 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
345 case OPENX_MODE_DENY_FCB
:
346 io2
->generic
.in
.private_flags
|= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB
;
347 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
350 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
354 case (OPENX_OPEN_FUNC_OPEN
):
355 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
357 case (OPENX_OPEN_FUNC_TRUNC
):
358 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE
;
360 case (OPENX_OPEN_FUNC_FAIL
| OPENX_OPEN_FUNC_CREATE
):
361 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
363 case (OPENX_OPEN_FUNC_OPEN
| OPENX_OPEN_FUNC_CREATE
):
364 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
366 case (OPENX_OPEN_FUNC_TRUNC
| OPENX_OPEN_FUNC_CREATE
):
367 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
370 /* this one is very strange */
371 if ((open_mode
& OPENX_MODE_ACCESS_MASK
) == OPENX_MODE_ACCESS_EXEC
) {
372 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
375 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
382 NTVFS open generic to any mapper
384 NTSTATUS
ntvfs_map_open(struct ntvfs_module_context
*ntvfs
,
385 struct ntvfs_request
*req
,
391 io2
= talloc_zero(req
, union smb_open
);
393 return NT_STATUS_NO_MEMORY
;
396 status
= ntvfs_map_async_setup(ntvfs
, req
,
398 (second_stage_t
)ntvfs_map_open_finish
);
399 if (!NT_STATUS_IS_OK(status
)) {
403 io2
->generic
.level
= RAW_OPEN_GENERIC
;
405 switch (io
->generic
.level
) {
407 status
= map_openx_open(io
->openx
.in
.flags
,
408 io
->openx
.in
.open_mode
,
409 io
->openx
.in
.open_func
,
412 if (!NT_STATUS_IS_OK(status
)) {
416 io2
->generic
.in
.file_attr
= io
->openx
.in
.file_attrs
;
417 io2
->generic
.in
.fname
= io
->openx
.in
.fname
;
419 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
424 status
= map_openx_open(0,
425 io
->openold
.in
.open_mode
,
426 OPENX_OPEN_FUNC_OPEN
,
427 io
->openold
.in
.fname
,
429 if (!NT_STATUS_IS_OK(status
)) {
433 io2
->generic
.in
.file_attr
= io
->openold
.in
.search_attrs
;
434 io2
->generic
.in
.fname
= io
->openold
.in
.fname
;
436 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
439 case RAW_OPEN_T2OPEN
:
440 io2
->generic
.level
= RAW_OPEN_NTTRANS_CREATE
;
442 if (io
->t2open
.in
.open_func
== 0) {
443 status
= NT_STATUS_OBJECT_NAME_COLLISION
;
447 status
= map_openx_open(io
->t2open
.in
.flags
,
448 io
->t2open
.in
.open_mode
,
449 io
->t2open
.in
.open_func
,
452 if (!NT_STATUS_IS_OK(status
)) {
456 io2
->generic
.in
.file_attr
= io
->t2open
.in
.file_attrs
;
457 io2
->generic
.in
.fname
= io
->t2open
.in
.fname
;
458 io2
->generic
.in
.ea_list
= talloc(io2
, struct smb_ea_list
);
459 io2
->generic
.in
.ea_list
->num_eas
= io
->t2open
.in
.num_eas
;
460 io2
->generic
.in
.ea_list
->eas
= io
->t2open
.in
.eas
;
462 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
466 io2
->generic
.in
.file_attr
= io
->mknew
.in
.attrib
;
467 io2
->generic
.in
.fname
= io
->mknew
.in
.fname
;
468 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
469 io2
->generic
.in
.access_mask
=
470 SEC_RIGHTS_FILE_READ
|
471 SEC_RIGHTS_FILE_WRITE
;
472 io2
->generic
.in
.share_access
=
473 NTCREATEX_SHARE_ACCESS_READ
|
474 NTCREATEX_SHARE_ACCESS_WRITE
;
475 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
478 case RAW_OPEN_CREATE
:
479 io2
->generic
.in
.file_attr
= io
->mknew
.in
.attrib
;
480 io2
->generic
.in
.fname
= io
->mknew
.in
.fname
;
481 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
482 io2
->generic
.in
.access_mask
=
483 SEC_RIGHTS_FILE_READ
|
484 SEC_RIGHTS_FILE_WRITE
;
485 io2
->generic
.in
.share_access
=
486 NTCREATEX_SHARE_ACCESS_READ
|
487 NTCREATEX_SHARE_ACCESS_WRITE
;
488 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
492 io2
->generic
.in
.file_attr
= io
->ctemp
.in
.attrib
;
493 io2
->generic
.in
.fname
=
494 talloc_asprintf(io2
, "%s\\SRV%s",
495 io
->ctemp
.in
.directory
,
496 generate_random_str_list(io2
, 5, "0123456789"));
497 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
498 io2
->generic
.in
.access_mask
=
499 SEC_RIGHTS_FILE_READ
|
500 SEC_RIGHTS_FILE_WRITE
;
501 io2
->generic
.in
.share_access
=
502 NTCREATEX_SHARE_ACCESS_READ
|
503 NTCREATEX_SHARE_ACCESS_WRITE
;
504 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
507 switch (io
->smb2
.in
.oplock_level
) {
508 case SMB2_OPLOCK_LEVEL_BATCH
:
509 io2
->generic
.in
.flags
= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
|
510 NTCREATEX_FLAGS_REQUEST_OPLOCK
;
512 case SMB2_OPLOCK_LEVEL_EXCLUSIVE
:
513 io2
->generic
.in
.flags
= NTCREATEX_FLAGS_REQUEST_OPLOCK
;
516 io2
->generic
.in
.flags
= 0;
519 io2
->generic
.in
.root_fid
.fnum
= 0;
520 io2
->generic
.in
.access_mask
= io
->smb2
.in
.desired_access
;
521 io2
->generic
.in
.alloc_size
= io
->smb2
.in
.alloc_size
;
522 io2
->generic
.in
.file_attr
= io
->smb2
.in
.file_attributes
;
523 io2
->generic
.in
.share_access
= io
->smb2
.in
.share_access
;
524 io2
->generic
.in
.open_disposition
= io
->smb2
.in
.create_disposition
;
525 io2
->generic
.in
.create_options
= io
->smb2
.in
.create_options
;
526 io2
->generic
.in
.impersonation
= io
->smb2
.in
.impersonation_level
;
527 io2
->generic
.in
.security_flags
= 0;
528 io2
->generic
.in
.fname
= io
->smb2
.in
.fname
;
529 io2
->generic
.in
.sec_desc
= io
->smb2
.in
.sec_desc
;
530 io2
->generic
.in
.ea_list
= &io
->smb2
.in
.eas
;
531 io2
->generic
.in
.query_maximal_access
= io
->smb2
.in
.query_maximal_access
;
532 io2
->generic
.in
.private_flags
= 0;
534 /* we don't support timewarp yet */
535 if (io
->smb2
.in
.timewarp
!= 0) {
536 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
540 /* we need to check these bits before we check the private mask */
541 if (io2
->generic
.in
.create_options
& SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK
) {
542 DEBUG(2,(__location__
" create_options 0x%x not supported\n",
543 io2
->generic
.in
.create_options
));
544 status
= NT_STATUS_NOT_SUPPORTED
;
548 /* TODO: find out why only SMB2 ignores these */
549 io2
->generic
.in
.create_options
&= ~NTCREATEX_OPTIONS_SYNC_ALERT
;
550 io2
->generic
.in
.create_options
&= ~NTCREATEX_OPTIONS_ASYNC_ALERT
;
552 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
556 status
= NT_STATUS_INVALID_LEVEL
;
560 return ntvfs_map_async_finish(req
, status
);
565 NTVFS any to fsinfo mapper
567 static NTSTATUS
ntvfs_map_fsinfo_finish(struct ntvfs_module_context
*ntvfs
,
568 struct ntvfs_request
*req
,
569 union smb_fsinfo
*fs
,
570 union smb_fsinfo
*fs2
,
573 if (!NT_STATUS_IS_OK(status
)) {
577 /* and convert it to the required level */
578 switch (fs
->generic
.level
) {
579 case RAW_QFS_GENERIC
:
580 return NT_STATUS_INVALID_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
);
672 return NT_STATUS_INVALID_LEVEL
;
676 NTVFS fsinfo any to generic mapper
678 NTSTATUS
ntvfs_map_fsinfo(struct ntvfs_module_context
*ntvfs
,
679 struct ntvfs_request
*req
,
680 union smb_fsinfo
*fs
)
683 union smb_fsinfo
*fs2
;
685 fs2
= talloc(req
, union smb_fsinfo
);
687 return NT_STATUS_NO_MEMORY
;
690 if (fs
->generic
.level
== RAW_QFS_GENERIC
) {
691 return NT_STATUS_INVALID_LEVEL
;
694 status
= ntvfs_map_async_setup(ntvfs
, req
, fs
, fs2
,
695 (second_stage_t
)ntvfs_map_fsinfo_finish
);
696 if (!NT_STATUS_IS_OK(status
)) {
700 /* ask the backend for the generic info */
701 fs2
->generic
.level
= RAW_QFS_GENERIC
;
703 status
= ntvfs
->ops
->fsinfo(ntvfs
, req
, fs2
);
704 return ntvfs_map_async_finish(req
, status
);
709 NTVFS fileinfo generic to any mapper
711 NTSTATUS
ntvfs_map_fileinfo(TALLOC_CTX
*mem_ctx
,
712 union smb_fileinfo
*info
,
713 union smb_fileinfo
*info2
)
716 /* and convert it to the required level using results in info2 */
717 switch (info
->generic
.level
) {
718 case RAW_FILEINFO_GENERIC
:
719 return NT_STATUS_INVALID_LEVEL
;
720 case RAW_FILEINFO_GETATTR
:
721 info
->getattr
.out
.attrib
= info2
->generic
.out
.attrib
& 0xff;
722 info
->getattr
.out
.size
= info2
->generic
.out
.size
;
723 info
->getattr
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
726 case RAW_FILEINFO_GETATTRE
:
727 info
->getattre
.out
.attrib
= info2
->generic
.out
.attrib
;
728 info
->getattre
.out
.size
= info2
->generic
.out
.size
;
729 info
->getattre
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
730 info
->getattre
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
731 info
->getattre
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
732 info
->getattre
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
735 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
736 info
->network_open_information
.out
.create_time
= info2
->generic
.out
.create_time
;
737 info
->network_open_information
.out
.access_time
= info2
->generic
.out
.access_time
;
738 info
->network_open_information
.out
.write_time
= info2
->generic
.out
.write_time
;
739 info
->network_open_information
.out
.change_time
= info2
->generic
.out
.change_time
;
740 info
->network_open_information
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
741 info
->network_open_information
.out
.size
= info2
->generic
.out
.size
;
742 info
->network_open_information
.out
.attrib
= info2
->generic
.out
.attrib
;
745 case RAW_FILEINFO_ALL_INFO
:
746 case RAW_FILEINFO_ALL_INFORMATION
:
747 info
->all_info
.out
.create_time
= info2
->generic
.out
.create_time
;
748 info
->all_info
.out
.access_time
= info2
->generic
.out
.access_time
;
749 info
->all_info
.out
.write_time
= info2
->generic
.out
.write_time
;
750 info
->all_info
.out
.change_time
= info2
->generic
.out
.change_time
;
751 info
->all_info
.out
.attrib
= info2
->generic
.out
.attrib
;
752 info
->all_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
753 info
->all_info
.out
.size
= info2
->generic
.out
.size
;
754 info
->all_info
.out
.nlink
= info2
->generic
.out
.nlink
;
755 info
->all_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
756 info
->all_info
.out
.directory
= info2
->generic
.out
.directory
;
757 info
->all_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
758 info
->all_info
.out
.fname
.s
= info2
->generic
.out
.fname
.s
;
759 info
->all_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
762 case RAW_FILEINFO_BASIC_INFO
:
763 case RAW_FILEINFO_BASIC_INFORMATION
:
764 info
->basic_info
.out
.create_time
= info2
->generic
.out
.create_time
;
765 info
->basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
766 info
->basic_info
.out
.write_time
= info2
->generic
.out
.write_time
;
767 info
->basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
768 info
->basic_info
.out
.attrib
= info2
->generic
.out
.attrib
;
771 case RAW_FILEINFO_STANDARD
:
772 info
->standard
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
773 info
->standard
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
774 info
->standard
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
775 info
->standard
.out
.size
= info2
->generic
.out
.size
;
776 info
->standard
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
777 info
->standard
.out
.attrib
= info2
->generic
.out
.attrib
;
780 case RAW_FILEINFO_EA_SIZE
:
781 info
->ea_size
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
782 info
->ea_size
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
783 info
->ea_size
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
784 info
->ea_size
.out
.size
= info2
->generic
.out
.size
;
785 info
->ea_size
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
786 info
->ea_size
.out
.attrib
= info2
->generic
.out
.attrib
;
787 info
->ea_size
.out
.ea_size
= info2
->generic
.out
.ea_size
;
790 case RAW_FILEINFO_STANDARD_INFO
:
791 case RAW_FILEINFO_STANDARD_INFORMATION
:
792 info
->standard_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
793 info
->standard_info
.out
.size
= info2
->generic
.out
.size
;
794 info
->standard_info
.out
.nlink
= info2
->generic
.out
.nlink
;
795 info
->standard_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
796 info
->standard_info
.out
.directory
= info2
->generic
.out
.directory
;
799 case RAW_FILEINFO_INTERNAL_INFORMATION
:
800 info
->internal_information
.out
.file_id
= info2
->generic
.out
.file_id
;
803 case RAW_FILEINFO_EA_INFO
:
804 case RAW_FILEINFO_EA_INFORMATION
:
805 info
->ea_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
808 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
809 info
->attribute_tag_information
.out
.attrib
= info2
->generic
.out
.attrib
;
810 info
->attribute_tag_information
.out
.reparse_tag
= info2
->generic
.out
.reparse_tag
;
813 case RAW_FILEINFO_STREAM_INFO
:
814 case RAW_FILEINFO_STREAM_INFORMATION
:
815 info
->stream_info
.out
.num_streams
= info2
->generic
.out
.num_streams
;
816 if (info
->stream_info
.out
.num_streams
> 0) {
817 info
->stream_info
.out
.streams
=
818 talloc_array(mem_ctx
,
819 struct stream_struct
,
820 info
->stream_info
.out
.num_streams
);
821 if (!info
->stream_info
.out
.streams
) {
822 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
823 info
->stream_info
.out
.num_streams
));
824 return NT_STATUS_NO_MEMORY
;
826 for (i
=0; i
< info
->stream_info
.out
.num_streams
; i
++) {
827 info
->stream_info
.out
.streams
[i
] = info2
->generic
.out
.streams
[i
];
828 info
->stream_info
.out
.streams
[i
].stream_name
.s
=
829 talloc_strdup(info
->stream_info
.out
.streams
,
830 info2
->generic
.out
.streams
[i
].stream_name
.s
);
831 if (!info
->stream_info
.out
.streams
[i
].stream_name
.s
) {
832 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
833 return NT_STATUS_NO_MEMORY
;
839 case RAW_FILEINFO_NAME_INFO
:
840 case RAW_FILEINFO_NAME_INFORMATION
:
841 info
->name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.fname
.s
);
842 NT_STATUS_HAVE_NO_MEMORY(info
->name_info
.out
.fname
.s
);
843 info
->name_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
846 case RAW_FILEINFO_ALT_NAME_INFO
:
847 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
848 info
->alt_name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.alt_fname
.s
);
849 NT_STATUS_HAVE_NO_MEMORY(info
->alt_name_info
.out
.fname
.s
);
850 info
->alt_name_info
.out
.fname
.private_length
= info2
->generic
.out
.alt_fname
.private_length
;
853 case RAW_FILEINFO_POSITION_INFORMATION
:
854 info
->position_information
.out
.position
= info2
->generic
.out
.position
;
857 case RAW_FILEINFO_ALL_EAS
:
858 info
->all_eas
.out
.num_eas
= info2
->generic
.out
.num_eas
;
859 if (info
->all_eas
.out
.num_eas
> 0) {
860 info
->all_eas
.out
.eas
= talloc_array(mem_ctx
,
862 info
->all_eas
.out
.num_eas
);
863 if (!info
->all_eas
.out
.eas
) {
864 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
865 info
->all_eas
.out
.num_eas
));
866 return NT_STATUS_NO_MEMORY
;
868 for (i
= 0; i
< info
->all_eas
.out
.num_eas
; i
++) {
869 info
->all_eas
.out
.eas
[i
] = info2
->generic
.out
.eas
[i
];
870 info
->all_eas
.out
.eas
[i
].name
.s
=
871 talloc_strdup(info
->all_eas
.out
.eas
,
872 info2
->generic
.out
.eas
[i
].name
.s
);
873 if (!info
->all_eas
.out
.eas
[i
].name
.s
) {
874 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
875 return NT_STATUS_NO_MEMORY
;
877 info
->all_eas
.out
.eas
[i
].value
.data
=
878 (uint8_t *)talloc_memdup(info
->all_eas
.out
.eas
,
879 info2
->generic
.out
.eas
[i
].value
.data
,
880 info2
->generic
.out
.eas
[i
].value
.length
);
881 if (!info
->all_eas
.out
.eas
[i
].value
.data
) {
882 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
883 return NT_STATUS_NO_MEMORY
;
889 case RAW_FILEINFO_IS_NAME_VALID
:
892 case RAW_FILEINFO_COMPRESSION_INFO
:
893 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
894 info
->compression_info
.out
.compressed_size
= info2
->generic
.out
.compressed_size
;
895 info
->compression_info
.out
.format
= info2
->generic
.out
.format
;
896 info
->compression_info
.out
.unit_shift
= info2
->generic
.out
.unit_shift
;
897 info
->compression_info
.out
.chunk_shift
= info2
->generic
.out
.chunk_shift
;
898 info
->compression_info
.out
.cluster_shift
= info2
->generic
.out
.cluster_shift
;
901 case RAW_FILEINFO_ACCESS_INFORMATION
:
902 info
->access_information
.out
.access_flags
= info2
->generic
.out
.access_flags
;
905 case RAW_FILEINFO_MODE_INFORMATION
:
906 info
->mode_information
.out
.mode
= info2
->generic
.out
.mode
;
909 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
910 info
->alignment_information
.out
.alignment_requirement
=
911 info2
->generic
.out
.alignment_requirement
;
914 case RAW_FILEINFO_UNIX_BASIC
:
915 info
->unix_basic_info
.out
.end_of_file
= info2
->generic
.out
.end_of_file
;
916 info
->unix_basic_info
.out
.num_bytes
= info2
->generic
.out
.size
;
917 info
->unix_basic_info
.out
.status_change_time
= info2
->generic
.out
.change_time
;
918 info
->unix_basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
919 info
->unix_basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
920 info
->unix_basic_info
.out
.uid
= info2
->generic
.out
.uid
;
921 info
->unix_basic_info
.out
.gid
= info2
->generic
.out
.gid
;
922 info
->unix_basic_info
.out
.file_type
= info2
->generic
.out
.file_type
;
923 info
->unix_basic_info
.out
.dev_major
= info2
->generic
.out
.device
;
924 info
->unix_basic_info
.out
.dev_minor
= info2
->generic
.out
.device
;
925 info
->unix_basic_info
.out
.unique_id
= info2
->generic
.out
.inode
;
926 info
->unix_basic_info
.out
.permissions
= info2
->generic
.out
.permissions
;
927 info
->unix_basic_info
.out
.nlink
= info2
->generic
.out
.nlink
;
930 case RAW_FILEINFO_UNIX_LINK
:
931 info
->unix_link_info
.out
.link_dest
= info2
->generic
.out
.link_dest
;
936 return NT_STATUS_INVALID_LEVEL
;
940 NTVFS any to fileinfo mapper
942 static NTSTATUS
ntvfs_map_qfileinfo_finish(struct ntvfs_module_context
*ntvfs
,
943 struct ntvfs_request
*req
,
944 union smb_fileinfo
*info
,
945 union smb_fileinfo
*info2
,
948 if (!NT_STATUS_IS_OK(status
)) {
952 return ntvfs_map_fileinfo(req
, info
, info2
);
956 NTVFS fileinfo generic to any mapper
958 NTSTATUS
ntvfs_map_qfileinfo(struct ntvfs_module_context
*ntvfs
,
959 struct ntvfs_request
*req
,
960 union smb_fileinfo
*info
)
963 union smb_fileinfo
*info2
;
965 info2
= talloc(req
, union smb_fileinfo
);
967 return NT_STATUS_NO_MEMORY
;
970 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
971 return NT_STATUS_INVALID_LEVEL
;
974 status
= ntvfs_map_async_setup(ntvfs
, req
, info
, info2
,
975 (second_stage_t
)ntvfs_map_qfileinfo_finish
);
976 if (!NT_STATUS_IS_OK(status
)) {
980 /* ask the backend for the generic info */
981 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
982 info2
->generic
.in
.file
.ntvfs
= info
->generic
.in
.file
.ntvfs
;
984 status
= ntvfs
->ops
->qfileinfo(ntvfs
, req
, info2
);
985 return ntvfs_map_async_finish(req
, status
);
989 NTVFS any to fileinfo mapper
991 static NTSTATUS
ntvfs_map_qpathinfo_finish(struct ntvfs_module_context
*ntvfs
,
992 struct ntvfs_request
*req
,
993 union smb_fileinfo
*info
,
994 union smb_fileinfo
*info2
,
997 if (!NT_STATUS_IS_OK(status
)) {
1001 return ntvfs_map_fileinfo(req
, info
, info2
);
1005 NTVFS pathinfo generic to any mapper
1007 NTSTATUS
ntvfs_map_qpathinfo(struct ntvfs_module_context
*ntvfs
,
1008 struct ntvfs_request
*req
,
1009 union smb_fileinfo
*info
)
1012 union smb_fileinfo
*info2
;
1014 info2
= talloc(req
, union smb_fileinfo
);
1015 if (info2
== NULL
) {
1016 return NT_STATUS_NO_MEMORY
;
1019 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
1020 return NT_STATUS_INVALID_LEVEL
;
1023 status
= ntvfs_map_async_setup(ntvfs
, req
, info
, info2
,
1024 (second_stage_t
)ntvfs_map_qpathinfo_finish
);
1025 if (!NT_STATUS_IS_OK(status
)) {
1029 /* ask the backend for the generic info */
1030 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
1031 info2
->generic
.in
.file
.path
= info
->generic
.in
.file
.path
;
1033 status
= ntvfs
->ops
->qpathinfo(ntvfs
, req
, info2
);
1034 return ntvfs_map_async_finish(req
, status
);
1039 NTVFS lock generic to any mapper
1041 NTSTATUS
ntvfs_map_lock(struct ntvfs_module_context
*ntvfs
,
1042 struct ntvfs_request
*req
,
1043 union smb_lock
*lck
)
1045 union smb_lock
*lck2
;
1046 struct smb_lock_entry
*locks
;
1048 lck2
= talloc(req
, union smb_lock
);
1050 return NT_STATUS_NO_MEMORY
;
1053 locks
= talloc_array(lck2
, struct smb_lock_entry
, 1);
1054 if (locks
== NULL
) {
1055 return NT_STATUS_NO_MEMORY
;
1058 switch (lck
->generic
.level
) {
1059 case RAW_LOCK_LOCKX
:
1060 return NT_STATUS_INVALID_LEVEL
;
1063 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1064 lck2
->generic
.in
.file
.ntvfs
= lck
->lock
.in
.file
.ntvfs
;
1065 lck2
->generic
.in
.mode
= 0;
1066 lck2
->generic
.in
.timeout
= 0;
1067 lck2
->generic
.in
.ulock_cnt
= 0;
1068 lck2
->generic
.in
.lock_cnt
= 1;
1069 lck2
->generic
.in
.locks
= locks
;
1070 locks
->pid
= req
->smbpid
;
1071 locks
->offset
= lck
->lock
.in
.offset
;
1072 locks
->count
= lck
->lock
.in
.count
;
1075 case RAW_LOCK_UNLOCK
:
1076 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1077 lck2
->generic
.in
.file
.ntvfs
= lck
->unlock
.in
.file
.ntvfs
;
1078 lck2
->generic
.in
.mode
= 0;
1079 lck2
->generic
.in
.timeout
= 0;
1080 lck2
->generic
.in
.ulock_cnt
= 1;
1081 lck2
->generic
.in
.lock_cnt
= 0;
1082 lck2
->generic
.in
.locks
= locks
;
1083 locks
->pid
= req
->smbpid
;
1084 locks
->offset
= lck
->unlock
.in
.offset
;
1085 locks
->count
= lck
->unlock
.in
.count
;
1088 case RAW_LOCK_SMB2
: {
1089 /* this is only approximate! We need to change the
1090 generic structure to fix this properly */
1093 if (lck
->smb2
.in
.lock_count
< 1) {
1094 return NT_STATUS_INVALID_PARAMETER
;
1097 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1098 lck2
->generic
.in
.file
.ntvfs
= lck
->smb2
.in
.file
.ntvfs
;
1099 lck2
->generic
.in
.timeout
= UINT32_MAX
;
1100 lck2
->generic
.in
.mode
= 0;
1101 lck2
->generic
.in
.lock_cnt
= 0;
1102 lck2
->generic
.in
.ulock_cnt
= 0;
1103 lck2
->generic
.in
.locks
= talloc_zero_array(lck2
, struct smb_lock_entry
,
1104 lck
->smb2
.in
.lock_count
);
1105 if (lck2
->generic
.in
.locks
== NULL
) {
1106 return NT_STATUS_NO_MEMORY
;
1108 /* only the first lock gives the UNLOCK bit - see
1110 if (lck
->smb2
.in
.locks
[0].flags
& SMB2_LOCK_FLAG_UNLOCK
) {
1111 if (lck
->smb2
.in
.locks
[0].flags
& SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
) {
1112 return NT_STATUS_INVALID_PARAMETER
;
1114 lck2
->generic
.in
.ulock_cnt
= lck
->smb2
.in
.lock_count
;
1117 lck2
->generic
.in
.lock_cnt
= lck
->smb2
.in
.lock_count
;
1120 for (i
=0;i
<lck
->smb2
.in
.lock_count
;i
++) {
1122 lck
->smb2
.in
.locks
[i
].flags
== SMB2_LOCK_FLAG_NONE
) {
1123 return NT_STATUS_INVALID_PARAMETER
;
1126 if (lck
->smb2
.in
.locks
[i
].flags
& ~SMB2_LOCK_FLAG_ALL_MASK
) {
1127 return NT_STATUS_INVALID_PARAMETER
;
1131 (lck
->smb2
.in
.locks
[i
].flags
&
1132 (SMB2_LOCK_FLAG_SHARED
|SMB2_LOCK_FLAG_EXCLUSIVE
))) {
1133 return NT_STATUS_INVALID_PARAMETER
;
1136 (lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_UNLOCK
)) {
1137 return NT_STATUS_INVALID_PARAMETER
;
1139 lck2
->generic
.in
.locks
[i
].pid
= req
->smbpid
;
1140 lck2
->generic
.in
.locks
[i
].offset
= lck
->smb2
.in
.locks
[i
].offset
;
1141 lck2
->generic
.in
.locks
[i
].count
= lck
->smb2
.in
.locks
[i
].length
;
1142 if (!(lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_EXCLUSIVE
)) {
1143 lck2
->generic
.in
.mode
= LOCKING_ANDX_SHARED_LOCK
;
1145 if (lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
) {
1146 lck2
->generic
.in
.timeout
= 0;
1149 /* initialize output value */
1150 lck
->smb2
.out
.reserved
= 0;
1154 case RAW_LOCK_SMB2_BREAK
:
1155 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1156 lck2
->generic
.in
.file
.ntvfs
= lck
->smb2_break
.in
.file
.ntvfs
;
1157 lck2
->generic
.in
.mode
= LOCKING_ANDX_OPLOCK_RELEASE
|
1158 ((lck
->smb2_break
.in
.oplock_level
<< 8) & 0xFF00);
1159 lck2
->generic
.in
.timeout
= 0;
1160 lck2
->generic
.in
.ulock_cnt
= 0;
1161 lck2
->generic
.in
.lock_cnt
= 0;
1162 lck2
->generic
.in
.locks
= NULL
;
1164 /* initialize output value */
1165 lck
->smb2_break
.out
.oplock_level
= lck
->smb2_break
.in
.oplock_level
;
1166 lck
->smb2_break
.out
.reserved
= lck
->smb2_break
.in
.reserved
;
1167 lck
->smb2_break
.out
.reserved2
= lck
->smb2_break
.in
.reserved2
;
1168 lck
->smb2_break
.out
.file
= lck
->smb2_break
.in
.file
;
1173 * we don't need to call ntvfs_map_async_setup() here,
1174 * as lock() doesn't have any output fields
1177 return ntvfs
->ops
->lock(ntvfs
, req
, lck2
);
1182 NTVFS write generic to any mapper
1184 static NTSTATUS
ntvfs_map_write_finish(struct ntvfs_module_context
*ntvfs
,
1185 struct ntvfs_request
*req
,
1186 union smb_write
*wr
,
1187 union smb_write
*wr2
,
1190 union smb_lock
*lck
;
1191 union smb_close
*cl
;
1194 if (NT_STATUS_IS_ERR(status
)) {
1198 switch (wr
->generic
.level
) {
1199 case RAW_WRITE_WRITE
:
1200 wr
->write
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1203 case RAW_WRITE_WRITEUNLOCK
:
1204 wr
->writeunlock
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1206 lck
= talloc(wr2
, union smb_lock
);
1208 return NT_STATUS_NO_MEMORY
;
1211 lck
->unlock
.level
= RAW_LOCK_UNLOCK
;
1212 lck
->unlock
.in
.file
.ntvfs
= wr
->writeunlock
.in
.file
.ntvfs
;
1213 lck
->unlock
.in
.count
= wr
->writeunlock
.in
.count
;
1214 lck
->unlock
.in
.offset
= wr
->writeunlock
.in
.offset
;
1216 if (lck
->unlock
.in
.count
!= 0) {
1217 /* do the lock sync for now */
1218 state
= req
->async_states
->state
;
1219 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1220 status
= ntvfs
->ops
->lock(ntvfs
, req
, lck
);
1221 req
->async_states
->state
= state
;
1225 case RAW_WRITE_WRITECLOSE
:
1226 wr
->writeclose
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1228 cl
= talloc(wr2
, union smb_close
);
1230 return NT_STATUS_NO_MEMORY
;
1233 cl
->close
.level
= RAW_CLOSE_CLOSE
;
1234 cl
->close
.in
.file
.ntvfs
= wr
->writeclose
.in
.file
.ntvfs
;
1235 cl
->close
.in
.write_time
= wr
->writeclose
.in
.mtime
;
1237 if (wr2
->generic
.in
.count
!= 0) {
1238 /* do the close sync for now */
1239 state
= req
->async_states
->state
;
1240 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1241 status
= ntvfs
->ops
->close(ntvfs
, req
, cl
);
1242 req
->async_states
->state
= state
;
1246 case RAW_WRITE_SPLWRITE
:
1249 case RAW_WRITE_SMB2
:
1250 wr
->smb2
.out
._pad
= 0;
1251 wr
->smb2
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1252 wr
->smb2
.out
.unknown1
= 0;
1256 return NT_STATUS_INVALID_LEVEL
;
1264 NTVFS write generic to any mapper
1266 NTSTATUS
ntvfs_map_write(struct ntvfs_module_context
*ntvfs
,
1267 struct ntvfs_request
*req
,
1268 union smb_write
*wr
)
1270 union smb_write
*wr2
;
1273 wr2
= talloc(req
, union smb_write
);
1275 return NT_STATUS_NO_MEMORY
;
1278 status
= ntvfs_map_async_setup(ntvfs
, req
, wr
, wr2
,
1279 (second_stage_t
)ntvfs_map_write_finish
);
1280 if (!NT_STATUS_IS_OK(status
)) {
1284 wr2
->writex
.level
= RAW_WRITE_GENERIC
;
1286 switch (wr
->generic
.level
) {
1287 case RAW_WRITE_WRITEX
:
1288 status
= NT_STATUS_INVALID_LEVEL
;
1291 case RAW_WRITE_WRITE
:
1292 wr2
->writex
.in
.file
.ntvfs
= wr
->write
.in
.file
.ntvfs
;
1293 wr2
->writex
.in
.offset
= wr
->write
.in
.offset
;
1294 wr2
->writex
.in
.wmode
= 0;
1295 wr2
->writex
.in
.remaining
= wr
->write
.in
.remaining
;
1296 wr2
->writex
.in
.count
= wr
->write
.in
.count
;
1297 wr2
->writex
.in
.data
= wr
->write
.in
.data
;
1298 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1301 case RAW_WRITE_WRITEUNLOCK
:
1302 wr2
->writex
.in
.file
.ntvfs
= wr
->writeunlock
.in
.file
.ntvfs
;
1303 wr2
->writex
.in
.offset
= wr
->writeunlock
.in
.offset
;
1304 wr2
->writex
.in
.wmode
= 0;
1305 wr2
->writex
.in
.remaining
= wr
->writeunlock
.in
.remaining
;
1306 wr2
->writex
.in
.count
= wr
->writeunlock
.in
.count
;
1307 wr2
->writex
.in
.data
= wr
->writeunlock
.in
.data
;
1308 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1311 case RAW_WRITE_WRITECLOSE
:
1312 wr2
->writex
.in
.file
.ntvfs
= wr
->writeclose
.in
.file
.ntvfs
;
1313 wr2
->writex
.in
.offset
= wr
->writeclose
.in
.offset
;
1314 wr2
->writex
.in
.wmode
= 0;
1315 wr2
->writex
.in
.remaining
= 0;
1316 wr2
->writex
.in
.count
= wr
->writeclose
.in
.count
;
1317 wr2
->writex
.in
.data
= wr
->writeclose
.in
.data
;
1318 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1321 case RAW_WRITE_SPLWRITE
:
1322 wr2
->writex
.in
.file
.ntvfs
= wr
->splwrite
.in
.file
.ntvfs
;
1323 wr2
->writex
.in
.offset
= 0;
1324 wr2
->writex
.in
.wmode
= 0;
1325 wr2
->writex
.in
.remaining
= 0;
1326 wr2
->writex
.in
.count
= wr
->splwrite
.in
.count
;
1327 wr2
->writex
.in
.data
= wr
->splwrite
.in
.data
;
1328 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1331 case RAW_WRITE_SMB2
:
1332 wr2
->writex
.in
.file
.ntvfs
= wr
->smb2
.in
.file
.ntvfs
;
1333 wr2
->writex
.in
.offset
= wr
->smb2
.in
.offset
;
1334 wr2
->writex
.in
.wmode
= 0;
1335 wr2
->writex
.in
.remaining
= 0;
1336 wr2
->writex
.in
.count
= wr
->smb2
.in
.data
.length
;
1337 wr2
->writex
.in
.data
= wr
->smb2
.in
.data
.data
;
1338 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1341 return ntvfs_map_async_finish(req
, status
);
1346 NTVFS read generic to any mapper - finish the out mapping
1348 static NTSTATUS
ntvfs_map_read_finish(struct ntvfs_module_context
*ntvfs
,
1349 struct ntvfs_request
*req
,
1351 union smb_read
*rd2
,
1354 switch (rd
->generic
.level
) {
1356 rd
->read
.out
.nread
= rd2
->generic
.out
.nread
;
1358 case RAW_READ_READBRAW
:
1359 rd
->readbraw
.out
.nread
= rd2
->generic
.out
.nread
;
1361 case RAW_READ_LOCKREAD
:
1362 rd
->lockread
.out
.nread
= rd2
->generic
.out
.nread
;
1365 rd
->smb2
.out
.data
.length
= rd2
->generic
.out
.nread
;
1366 rd
->smb2
.out
.remaining
= 0;
1367 rd
->smb2
.out
.reserved
= 0;
1370 return NT_STATUS_INVALID_LEVEL
;
1377 NTVFS read* to readx mapper
1379 NTSTATUS
ntvfs_map_read(struct ntvfs_module_context
*ntvfs
,
1380 struct ntvfs_request
*req
,
1383 union smb_read
*rd2
;
1384 union smb_lock
*lck
;
1388 rd2
= talloc(req
, union smb_read
);
1390 return NT_STATUS_NO_MEMORY
;
1393 status
= ntvfs_map_async_setup(ntvfs
, req
, rd
, rd2
,
1394 (second_stage_t
)ntvfs_map_read_finish
);
1395 if (!NT_STATUS_IS_OK(status
)) {
1399 rd2
->readx
.level
= RAW_READ_READX
;
1400 rd2
->readx
.in
.read_for_execute
= false;
1402 switch (rd
->generic
.level
) {
1403 case RAW_READ_READX
:
1404 status
= NT_STATUS_INVALID_LEVEL
;
1408 rd2
->readx
.in
.file
.ntvfs
= rd
->read
.in
.file
.ntvfs
;
1409 rd2
->readx
.in
.offset
= rd
->read
.in
.offset
;
1410 rd2
->readx
.in
.mincnt
= rd
->read
.in
.count
;
1411 rd2
->readx
.in
.maxcnt
= rd
->read
.in
.count
;
1412 rd2
->readx
.in
.remaining
= rd
->read
.in
.remaining
;
1413 rd2
->readx
.out
.data
= rd
->read
.out
.data
;
1414 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1417 case RAW_READ_READBRAW
:
1418 rd2
->readx
.in
.file
.ntvfs
= rd
->readbraw
.in
.file
.ntvfs
;
1419 rd2
->readx
.in
.offset
= rd
->readbraw
.in
.offset
;
1420 rd2
->readx
.in
.mincnt
= rd
->readbraw
.in
.mincnt
;
1421 rd2
->readx
.in
.maxcnt
= rd
->readbraw
.in
.maxcnt
;
1422 rd2
->readx
.in
.remaining
= 0;
1423 rd2
->readx
.out
.data
= rd
->readbraw
.out
.data
;
1424 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1427 case RAW_READ_LOCKREAD
:
1428 /* do the initial lock sync for now */
1429 state
= req
->async_states
->state
;
1430 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1432 lck
= talloc(rd2
, union smb_lock
);
1434 status
= NT_STATUS_NO_MEMORY
;
1437 lck
->lock
.level
= RAW_LOCK_LOCK
;
1438 lck
->lock
.in
.file
.ntvfs
= rd
->lockread
.in
.file
.ntvfs
;
1439 lck
->lock
.in
.count
= rd
->lockread
.in
.count
;
1440 lck
->lock
.in
.offset
= rd
->lockread
.in
.offset
;
1441 status
= ntvfs
->ops
->lock(ntvfs
, req
, lck
);
1442 req
->async_states
->state
= state
;
1444 rd2
->readx
.in
.file
.ntvfs
= rd
->lockread
.in
.file
.ntvfs
;
1445 rd2
->readx
.in
.offset
= rd
->lockread
.in
.offset
;
1446 rd2
->readx
.in
.mincnt
= rd
->lockread
.in
.count
;
1447 rd2
->readx
.in
.maxcnt
= rd
->lockread
.in
.count
;
1448 rd2
->readx
.in
.remaining
= rd
->lockread
.in
.remaining
;
1449 rd2
->readx
.out
.data
= rd
->lockread
.out
.data
;
1451 if (NT_STATUS_IS_OK(status
)) {
1452 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1457 rd2
->readx
.in
.file
.ntvfs
= rd
->smb2
.in
.file
.ntvfs
;
1458 rd2
->readx
.in
.offset
= rd
->smb2
.in
.offset
;
1459 rd2
->readx
.in
.mincnt
= rd
->smb2
.in
.min_count
;
1460 rd2
->readx
.in
.maxcnt
= rd
->smb2
.in
.length
;
1461 rd2
->readx
.in
.remaining
= 0;
1462 rd2
->readx
.out
.data
= rd
->smb2
.out
.data
.data
;
1463 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1468 return ntvfs_map_async_finish(req
, status
);
1473 NTVFS close generic to any mapper
1475 static NTSTATUS
ntvfs_map_close_finish(struct ntvfs_module_context
*ntvfs
,
1476 struct ntvfs_request
*req
,
1477 union smb_close
*cl
,
1478 union smb_close
*cl2
,
1481 NT_STATUS_NOT_OK_RETURN(status
);
1483 switch (cl
->generic
.level
) {
1484 case RAW_CLOSE_SMB2
:
1485 cl
->smb2
.out
.flags
= cl2
->generic
.out
.flags
;
1486 cl
->smb2
.out
._pad
= 0;
1487 cl
->smb2
.out
.create_time
= cl2
->generic
.out
.create_time
;
1488 cl
->smb2
.out
.access_time
= cl2
->generic
.out
.access_time
;
1489 cl
->smb2
.out
.write_time
= cl2
->generic
.out
.write_time
;
1490 cl
->smb2
.out
.change_time
= cl2
->generic
.out
.change_time
;
1491 cl
->smb2
.out
.alloc_size
= cl2
->generic
.out
.alloc_size
;
1492 cl
->smb2
.out
.size
= cl2
->generic
.out
.size
;
1493 cl
->smb2
.out
.file_attr
= cl2
->generic
.out
.file_attr
;
1503 NTVFS close generic to any mapper
1505 NTSTATUS
ntvfs_map_close(struct ntvfs_module_context
*ntvfs
,
1506 struct ntvfs_request
*req
,
1507 union smb_close
*cl
)
1509 union smb_close
*cl2
;
1512 cl2
= talloc(req
, union smb_close
);
1514 return NT_STATUS_NO_MEMORY
;
1517 switch (cl
->generic
.level
) {
1518 case RAW_CLOSE_GENERIC
:
1519 return NT_STATUS_INVALID_LEVEL
;
1521 case RAW_CLOSE_CLOSE
:
1522 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1523 cl2
->generic
.in
.file
= cl
->close
.in
.file
;
1524 cl2
->generic
.in
.write_time
= cl
->close
.in
.write_time
;
1525 cl2
->generic
.in
.flags
= 0;
1528 case RAW_CLOSE_SPLCLOSE
:
1529 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1530 cl2
->generic
.in
.file
= cl
->splclose
.in
.file
;
1531 cl2
->generic
.in
.write_time
= 0;
1532 cl2
->generic
.in
.flags
= 0;
1535 case RAW_CLOSE_SMB2
:
1536 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1537 cl2
->generic
.in
.file
= cl
->smb2
.in
.file
;
1538 cl2
->generic
.in
.write_time
= 0;
1539 cl2
->generic
.in
.flags
= cl
->smb2
.in
.flags
;
1543 status
= ntvfs_map_async_setup(ntvfs
, req
, cl
, cl2
,
1544 (second_stage_t
)ntvfs_map_close_finish
);
1545 NT_STATUS_NOT_OK_RETURN(status
);
1547 status
= ntvfs
->ops
->close(ntvfs
, req
, cl2
);
1549 return ntvfs_map_async_finish(req
, status
);
1553 NTVFS notify generic to any mapper
1555 static NTSTATUS
ntvfs_map_notify_finish(struct ntvfs_module_context
*ntvfs
,
1556 struct ntvfs_request
*req
,
1557 union smb_notify
*nt
,
1558 union smb_notify
*nt2
,
1561 NT_STATUS_NOT_OK_RETURN(status
);
1563 switch (nt
->nttrans
.level
) {
1564 case RAW_NOTIFY_SMB2
:
1565 if (nt2
->nttrans
.out
.num_changes
== 0) {
1566 return STATUS_NOTIFY_ENUM_DIR
;
1568 nt
->smb2
.out
.num_changes
= nt2
->nttrans
.out
.num_changes
;
1569 nt
->smb2
.out
.changes
= talloc_steal(req
, nt2
->nttrans
.out
.changes
);
1573 return NT_STATUS_INVALID_LEVEL
;
1581 NTVFS notify generic to any mapper
1583 NTSTATUS
ntvfs_map_notify(struct ntvfs_module_context
*ntvfs
,
1584 struct ntvfs_request
*req
,
1585 union smb_notify
*nt
)
1587 union smb_notify
*nt2
;
1590 nt2
= talloc(req
, union smb_notify
);
1591 NT_STATUS_HAVE_NO_MEMORY(nt2
);
1593 status
= ntvfs_map_async_setup(ntvfs
, req
, nt
, nt2
,
1594 (second_stage_t
)ntvfs_map_notify_finish
);
1595 NT_STATUS_NOT_OK_RETURN(status
);
1597 nt2
->nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1599 switch (nt
->nttrans
.level
) {
1600 case RAW_NOTIFY_NTTRANS
:
1601 status
= NT_STATUS_INVALID_LEVEL
;
1604 case RAW_NOTIFY_SMB2
:
1605 nt2
->nttrans
.in
.file
.ntvfs
= nt
->smb2
.in
.file
.ntvfs
;
1606 nt2
->nttrans
.in
.buffer_size
= nt
->smb2
.in
.buffer_size
;
1607 nt2
->nttrans
.in
.completion_filter
= nt
->smb2
.in
.completion_filter
;
1608 nt2
->nttrans
.in
.recursive
= nt
->smb2
.in
.recursive
;
1609 status
= ntvfs
->ops
->notify(ntvfs
, req
, nt2
);
1613 return ntvfs_map_async_finish(req
, status
);