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_fn(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_fn(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_fn(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_fn(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_fn(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_fn(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_fn(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_fn(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_fn(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_DSKATTR
: {
580 /* map from generic to DSKATTR */
581 unsigned int bpunit
= 64;
583 /* we need to scale the sizes to fit */
584 for (bpunit
=64; bpunit
<0x10000; bpunit
*= 2) {
585 if (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
< bpunit
* 512 * 65535.0) {
590 fs
->dskattr
.out
.blocks_per_unit
= bpunit
;
591 fs
->dskattr
.out
.block_size
= 512;
592 fs
->dskattr
.out
.units_total
=
593 (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
594 fs
->dskattr
.out
.units_free
=
595 (fs2
->generic
.out
.blocks_free
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
597 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
598 if (bpunit
> 64 && req
->ctx
->protocol
<= PROTOCOL_LANMAN2
) {
599 fs
->dskattr
.out
.blocks_per_unit
= 64;
600 fs
->dskattr
.out
.units_total
= 0xFFFF;
601 fs
->dskattr
.out
.units_free
= 0xFFFF;
606 case RAW_QFS_ALLOCATION
:
607 fs
->allocation
.out
.fs_id
= fs2
->generic
.out
.fs_id
;
608 fs
->allocation
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
609 fs
->allocation
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
610 fs
->allocation
.out
.sectors_per_unit
= 1;
611 fs
->allocation
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
615 fs
->volume
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
616 fs
->volume
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
619 case RAW_QFS_VOLUME_INFO
:
620 case RAW_QFS_VOLUME_INFORMATION
:
621 fs
->volume_info
.out
.create_time
= fs2
->generic
.out
.create_time
;
622 fs
->volume_info
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
623 fs
->volume_info
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
626 case RAW_QFS_SIZE_INFO
:
627 case RAW_QFS_SIZE_INFORMATION
:
628 fs
->size_info
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
629 fs
->size_info
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
630 fs
->size_info
.out
.sectors_per_unit
= 1;
631 fs
->size_info
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
634 case RAW_QFS_DEVICE_INFO
:
635 case RAW_QFS_DEVICE_INFORMATION
:
636 fs
->device_info
.out
.device_type
= fs2
->generic
.out
.device_type
;
637 fs
->device_info
.out
.characteristics
= fs2
->generic
.out
.device_characteristics
;
640 case RAW_QFS_ATTRIBUTE_INFO
:
641 case RAW_QFS_ATTRIBUTE_INFORMATION
:
642 fs
->attribute_info
.out
.fs_attr
= fs2
->generic
.out
.fs_attr
;
643 fs
->attribute_info
.out
.max_file_component_length
= fs2
->generic
.out
.max_file_component_length
;
644 fs
->attribute_info
.out
.fs_type
.s
= fs2
->generic
.out
.fs_type
;
647 case RAW_QFS_QUOTA_INFORMATION
:
648 ZERO_STRUCT(fs
->quota_information
.out
.unknown
);
649 fs
->quota_information
.out
.quota_soft
= fs2
->generic
.out
.quota_soft
;
650 fs
->quota_information
.out
.quota_hard
= fs2
->generic
.out
.quota_hard
;
651 fs
->quota_information
.out
.quota_flags
= fs2
->generic
.out
.quota_flags
;
654 case RAW_QFS_FULL_SIZE_INFORMATION
:
655 fs
->full_size_information
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
656 fs
->full_size_information
.out
.call_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
657 fs
->full_size_information
.out
.actual_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
658 fs
->full_size_information
.out
.sectors_per_unit
= 1;
659 fs
->full_size_information
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
662 case RAW_QFS_OBJECTID_INFORMATION
:
663 fs
->objectid_information
.out
.guid
= fs2
->generic
.out
.guid
;
664 ZERO_STRUCT(fs
->objectid_information
.out
.unknown
);
667 case RAW_QFS_SECTOR_SIZE_INFORMATION
:
668 fs
->sector_size_info
.out
.logical_bytes_per_sector
669 = fs2
->generic
.out
.block_size
;
670 fs
->sector_size_info
.out
.phys_bytes_per_sector_atomic
671 = fs2
->generic
.out
.block_size
;
672 fs
->sector_size_info
.out
.phys_bytes_per_sector_perf
673 = fs2
->generic
.out
.block_size
;
674 fs
->sector_size_info
.out
.fs_effective_phys_bytes_per_sector_atomic
675 = fs2
->generic
.out
.block_size
;
676 fs
->sector_size_info
.out
.flags
677 = QFS_SSINFO_FLAGS_ALIGNED_DEVICE
678 | QFS_SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE
;
679 fs
->sector_size_info
.out
.byte_off_sector_align
= 0;
680 fs
->sector_size_info
.out
.byte_off_partition_align
= 0;
683 case RAW_QFS_GENERIC
:
684 case RAW_QFS_UNIX_INFO
:
685 return NT_STATUS_INVALID_LEVEL
;
688 return NT_STATUS_INVALID_LEVEL
;
692 NTVFS fsinfo any to generic mapper
694 NTSTATUS
ntvfs_map_fsinfo(struct ntvfs_module_context
*ntvfs
,
695 struct ntvfs_request
*req
,
696 union smb_fsinfo
*fs
)
699 union smb_fsinfo
*fs2
;
701 fs2
= talloc(req
, union smb_fsinfo
);
703 return NT_STATUS_NO_MEMORY
;
706 if (fs
->generic
.level
== RAW_QFS_GENERIC
) {
707 return NT_STATUS_INVALID_LEVEL
;
710 status
= ntvfs_map_async_setup(ntvfs
, req
, fs
, fs2
,
711 (second_stage_t
)ntvfs_map_fsinfo_finish
);
712 if (!NT_STATUS_IS_OK(status
)) {
716 /* ask the backend for the generic info */
717 fs2
->generic
.level
= RAW_QFS_GENERIC
;
719 status
= ntvfs
->ops
->fsinfo_fn(ntvfs
, req
, fs2
);
720 return ntvfs_map_async_finish(req
, status
);
725 NTVFS fileinfo generic to any mapper
727 NTSTATUS
ntvfs_map_fileinfo(TALLOC_CTX
*mem_ctx
,
728 union smb_fileinfo
*info
,
729 union smb_fileinfo
*info2
)
732 /* and convert it to the required level using results in info2 */
733 switch (info
->generic
.level
) {
734 case RAW_FILEINFO_GETATTR
:
735 info
->getattr
.out
.attrib
= info2
->generic
.out
.attrib
& 0xff;
736 info
->getattr
.out
.size
= info2
->generic
.out
.size
;
737 info
->getattr
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
740 case RAW_FILEINFO_GETATTRE
:
741 info
->getattre
.out
.attrib
= info2
->generic
.out
.attrib
;
742 info
->getattre
.out
.size
= info2
->generic
.out
.size
;
743 info
->getattre
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
744 info
->getattre
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
745 info
->getattre
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
746 info
->getattre
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
749 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
750 info
->network_open_information
.out
.create_time
= info2
->generic
.out
.create_time
;
751 info
->network_open_information
.out
.access_time
= info2
->generic
.out
.access_time
;
752 info
->network_open_information
.out
.write_time
= info2
->generic
.out
.write_time
;
753 info
->network_open_information
.out
.change_time
= info2
->generic
.out
.change_time
;
754 info
->network_open_information
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
755 info
->network_open_information
.out
.size
= info2
->generic
.out
.size
;
756 info
->network_open_information
.out
.attrib
= info2
->generic
.out
.attrib
;
759 case RAW_FILEINFO_ALL_INFO
:
760 case RAW_FILEINFO_ALL_INFORMATION
:
761 info
->all_info
.out
.create_time
= info2
->generic
.out
.create_time
;
762 info
->all_info
.out
.access_time
= info2
->generic
.out
.access_time
;
763 info
->all_info
.out
.write_time
= info2
->generic
.out
.write_time
;
764 info
->all_info
.out
.change_time
= info2
->generic
.out
.change_time
;
765 info
->all_info
.out
.attrib
= info2
->generic
.out
.attrib
;
766 info
->all_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
767 info
->all_info
.out
.size
= info2
->generic
.out
.size
;
768 info
->all_info
.out
.nlink
= info2
->generic
.out
.nlink
;
769 info
->all_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
770 info
->all_info
.out
.directory
= info2
->generic
.out
.directory
;
771 info
->all_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
772 info
->all_info
.out
.fname
.s
= info2
->generic
.out
.fname
.s
;
773 info
->all_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
776 case RAW_FILEINFO_BASIC_INFO
:
777 case RAW_FILEINFO_BASIC_INFORMATION
:
778 info
->basic_info
.out
.create_time
= info2
->generic
.out
.create_time
;
779 info
->basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
780 info
->basic_info
.out
.write_time
= info2
->generic
.out
.write_time
;
781 info
->basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
782 info
->basic_info
.out
.attrib
= info2
->generic
.out
.attrib
;
785 case RAW_FILEINFO_STANDARD
:
786 info
->standard
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
787 info
->standard
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
788 info
->standard
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
789 info
->standard
.out
.size
= info2
->generic
.out
.size
;
790 info
->standard
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
791 info
->standard
.out
.attrib
= info2
->generic
.out
.attrib
;
794 case RAW_FILEINFO_EA_SIZE
:
795 info
->ea_size
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
796 info
->ea_size
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
797 info
->ea_size
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
798 info
->ea_size
.out
.size
= info2
->generic
.out
.size
;
799 info
->ea_size
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
800 info
->ea_size
.out
.attrib
= info2
->generic
.out
.attrib
;
801 info
->ea_size
.out
.ea_size
= info2
->generic
.out
.ea_size
;
804 case RAW_FILEINFO_STANDARD_INFO
:
805 case RAW_FILEINFO_STANDARD_INFORMATION
:
806 info
->standard_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
807 info
->standard_info
.out
.size
= info2
->generic
.out
.size
;
808 info
->standard_info
.out
.nlink
= info2
->generic
.out
.nlink
;
809 info
->standard_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
810 info
->standard_info
.out
.directory
= info2
->generic
.out
.directory
;
813 case RAW_FILEINFO_INTERNAL_INFORMATION
:
814 info
->internal_information
.out
.file_id
= info2
->generic
.out
.file_id
;
817 case RAW_FILEINFO_EA_INFO
:
818 case RAW_FILEINFO_EA_INFORMATION
:
819 info
->ea_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
822 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
823 info
->attribute_tag_information
.out
.attrib
= info2
->generic
.out
.attrib
;
824 info
->attribute_tag_information
.out
.reparse_tag
= info2
->generic
.out
.reparse_tag
;
827 case RAW_FILEINFO_STREAM_INFO
:
828 case RAW_FILEINFO_STREAM_INFORMATION
:
829 info
->stream_info
.out
.num_streams
= info2
->generic
.out
.num_streams
;
830 if (info
->stream_info
.out
.num_streams
> 0) {
831 info
->stream_info
.out
.streams
=
832 talloc_array(mem_ctx
,
833 struct stream_struct
,
834 info
->stream_info
.out
.num_streams
);
835 if (!info
->stream_info
.out
.streams
) {
836 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
837 info
->stream_info
.out
.num_streams
));
838 return NT_STATUS_NO_MEMORY
;
840 for (i
=0; i
< info
->stream_info
.out
.num_streams
; i
++) {
841 info
->stream_info
.out
.streams
[i
] = info2
->generic
.out
.streams
[i
];
842 info
->stream_info
.out
.streams
[i
].stream_name
.s
=
843 talloc_strdup(info
->stream_info
.out
.streams
,
844 info2
->generic
.out
.streams
[i
].stream_name
.s
);
845 if (!info
->stream_info
.out
.streams
[i
].stream_name
.s
) {
846 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
847 return NT_STATUS_NO_MEMORY
;
853 case RAW_FILEINFO_NAME_INFO
:
854 case RAW_FILEINFO_NAME_INFORMATION
:
855 info
->name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.fname
.s
);
856 NT_STATUS_HAVE_NO_MEMORY(info
->name_info
.out
.fname
.s
);
857 info
->name_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
860 case RAW_FILEINFO_ALT_NAME_INFO
:
861 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
862 info
->alt_name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.alt_fname
.s
);
863 NT_STATUS_HAVE_NO_MEMORY(info
->alt_name_info
.out
.fname
.s
);
864 info
->alt_name_info
.out
.fname
.private_length
= info2
->generic
.out
.alt_fname
.private_length
;
867 case RAW_FILEINFO_POSITION_INFORMATION
:
868 info
->position_information
.out
.position
= info2
->generic
.out
.position
;
871 case RAW_FILEINFO_ALL_EAS
:
872 info
->all_eas
.out
.num_eas
= info2
->generic
.out
.num_eas
;
873 if (info
->all_eas
.out
.num_eas
> 0) {
874 info
->all_eas
.out
.eas
= talloc_array(mem_ctx
,
876 info
->all_eas
.out
.num_eas
);
877 if (!info
->all_eas
.out
.eas
) {
878 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
879 info
->all_eas
.out
.num_eas
));
880 return NT_STATUS_NO_MEMORY
;
882 for (i
= 0; i
< info
->all_eas
.out
.num_eas
; i
++) {
883 info
->all_eas
.out
.eas
[i
] = info2
->generic
.out
.eas
[i
];
884 info
->all_eas
.out
.eas
[i
].name
.s
=
885 talloc_strdup(info
->all_eas
.out
.eas
,
886 info2
->generic
.out
.eas
[i
].name
.s
);
887 if (!info
->all_eas
.out
.eas
[i
].name
.s
) {
888 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
889 return NT_STATUS_NO_MEMORY
;
891 info
->all_eas
.out
.eas
[i
].value
.data
=
892 (uint8_t *)talloc_memdup(info
->all_eas
.out
.eas
,
893 info2
->generic
.out
.eas
[i
].value
.data
,
894 info2
->generic
.out
.eas
[i
].value
.length
);
895 if (!info
->all_eas
.out
.eas
[i
].value
.data
) {
896 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
897 return NT_STATUS_NO_MEMORY
;
903 case RAW_FILEINFO_IS_NAME_VALID
:
906 case RAW_FILEINFO_COMPRESSION_INFO
:
907 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
908 info
->compression_info
.out
.compressed_size
= info2
->generic
.out
.compressed_size
;
909 info
->compression_info
.out
.format
= info2
->generic
.out
.format
;
910 info
->compression_info
.out
.unit_shift
= info2
->generic
.out
.unit_shift
;
911 info
->compression_info
.out
.chunk_shift
= info2
->generic
.out
.chunk_shift
;
912 info
->compression_info
.out
.cluster_shift
= info2
->generic
.out
.cluster_shift
;
915 case RAW_FILEINFO_ACCESS_INFORMATION
:
916 info
->access_information
.out
.access_flags
= info2
->generic
.out
.access_flags
;
919 case RAW_FILEINFO_MODE_INFORMATION
:
920 info
->mode_information
.out
.mode
= info2
->generic
.out
.mode
;
923 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
924 info
->alignment_information
.out
.alignment_requirement
=
925 info2
->generic
.out
.alignment_requirement
;
927 case RAW_FILEINFO_UNIX_BASIC
:
929 return NT_STATUS_INVALID_LEVEL
;
931 info
->unix_basic_info
.out
.end_of_file
= info2
->generic
.out
.end_of_file
;
932 info
->unix_basic_info
.out
.num_bytes
= info2
->generic
.out
.size
;
933 info
->unix_basic_info
.out
.status_change_time
= info2
->generic
.out
.change_time
;
934 info
->unix_basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
935 info
->unix_basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
936 info
->unix_basic_info
.out
.uid
= info2
->generic
.out
.uid
;
937 info
->unix_basic_info
.out
.gid
= info2
->generic
.out
.gid
;
938 info
->unix_basic_info
.out
.file_type
= info2
->generic
.out
.file_type
;
939 info
->unix_basic_info
.out
.dev_major
= info2
->generic
.out
.device
;
940 info
->unix_basic_info
.out
.dev_minor
= info2
->generic
.out
.device
;
941 info
->unix_basic_info
.out
.unique_id
= info2
->generic
.out
.inode
;
942 info
->unix_basic_info
.out
.permissions
= info2
->generic
.out
.permissions
;
943 info
->unix_basic_info
.out
.nlink
= info2
->generic
.out
.nlink
;
946 case RAW_FILEINFO_UNIX_LINK
:
948 return NT_STATUS_INVALID_LEVEL
;
950 info
->unix_link_info
.out
.link_dest
= info2
->generic
.out
.link_dest
;
953 case RAW_FILEINFO_GENERIC
:
954 case RAW_FILEINFO_SEC_DESC
:
955 case RAW_FILEINFO_EA_LIST
:
956 case RAW_FILEINFO_UNIX_INFO2
:
957 case RAW_FILEINFO_SMB2_ALL_EAS
:
958 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
959 return NT_STATUS_INVALID_LEVEL
;
962 return NT_STATUS_INVALID_LEVEL
;
966 NTVFS any to fileinfo mapper
968 static NTSTATUS
ntvfs_map_qfileinfo_finish(struct ntvfs_module_context
*ntvfs
,
969 struct ntvfs_request
*req
,
970 union smb_fileinfo
*info
,
971 union smb_fileinfo
*info2
,
974 if (!NT_STATUS_IS_OK(status
)) {
978 return ntvfs_map_fileinfo(req
, info
, info2
);
982 NTVFS fileinfo generic to any mapper
984 NTSTATUS
ntvfs_map_qfileinfo(struct ntvfs_module_context
*ntvfs
,
985 struct ntvfs_request
*req
,
986 union smb_fileinfo
*info
)
989 union smb_fileinfo
*info2
;
991 info2
= talloc(req
, union smb_fileinfo
);
993 return NT_STATUS_NO_MEMORY
;
996 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
997 return NT_STATUS_INVALID_LEVEL
;
1000 status
= ntvfs_map_async_setup(ntvfs
, req
, info
, info2
,
1001 (second_stage_t
)ntvfs_map_qfileinfo_finish
);
1002 if (!NT_STATUS_IS_OK(status
)) {
1006 /* ask the backend for the generic info */
1007 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
1008 info2
->generic
.in
.file
.ntvfs
= info
->generic
.in
.file
.ntvfs
;
1010 status
= ntvfs
->ops
->qfileinfo_fn(ntvfs
, req
, info2
);
1011 return ntvfs_map_async_finish(req
, status
);
1015 NTVFS any to fileinfo mapper
1017 static NTSTATUS
ntvfs_map_qpathinfo_finish(struct ntvfs_module_context
*ntvfs
,
1018 struct ntvfs_request
*req
,
1019 union smb_fileinfo
*info
,
1020 union smb_fileinfo
*info2
,
1023 if (!NT_STATUS_IS_OK(status
)) {
1027 return ntvfs_map_fileinfo(req
, info
, info2
);
1031 NTVFS pathinfo generic to any mapper
1033 NTSTATUS
ntvfs_map_qpathinfo(struct ntvfs_module_context
*ntvfs
,
1034 struct ntvfs_request
*req
,
1035 union smb_fileinfo
*info
)
1038 union smb_fileinfo
*info2
;
1040 info2
= talloc(req
, union smb_fileinfo
);
1041 if (info2
== NULL
) {
1042 return NT_STATUS_NO_MEMORY
;
1045 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
1046 return NT_STATUS_INVALID_LEVEL
;
1049 status
= ntvfs_map_async_setup(ntvfs
, req
, info
, info2
,
1050 (second_stage_t
)ntvfs_map_qpathinfo_finish
);
1051 if (!NT_STATUS_IS_OK(status
)) {
1055 /* ask the backend for the generic info */
1056 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
1057 info2
->generic
.in
.file
.path
= info
->generic
.in
.file
.path
;
1059 status
= ntvfs
->ops
->qpathinfo_fn(ntvfs
, req
, info2
);
1060 return ntvfs_map_async_finish(req
, status
);
1065 NTVFS lock generic to any mapper
1067 NTSTATUS
ntvfs_map_lock(struct ntvfs_module_context
*ntvfs
,
1068 struct ntvfs_request
*req
,
1069 union smb_lock
*lck
)
1071 union smb_lock
*lck2
;
1072 struct smb_lock_entry
*locks
;
1074 lck2
= talloc(req
, union smb_lock
);
1076 return NT_STATUS_NO_MEMORY
;
1079 locks
= talloc_array(lck2
, struct smb_lock_entry
, 1);
1080 if (locks
== NULL
) {
1081 return NT_STATUS_NO_MEMORY
;
1084 switch (lck
->generic
.level
) {
1085 case RAW_LOCK_LOCKX
:
1086 return NT_STATUS_INVALID_LEVEL
;
1089 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1090 lck2
->generic
.in
.file
.ntvfs
= lck
->lock
.in
.file
.ntvfs
;
1091 lck2
->generic
.in
.mode
= 0;
1092 lck2
->generic
.in
.timeout
= 0;
1093 lck2
->generic
.in
.ulock_cnt
= 0;
1094 lck2
->generic
.in
.lock_cnt
= 1;
1095 lck2
->generic
.in
.locks
= locks
;
1096 locks
->pid
= req
->smbpid
;
1097 locks
->offset
= lck
->lock
.in
.offset
;
1098 locks
->count
= lck
->lock
.in
.count
;
1101 case RAW_LOCK_UNLOCK
:
1102 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1103 lck2
->generic
.in
.file
.ntvfs
= lck
->unlock
.in
.file
.ntvfs
;
1104 lck2
->generic
.in
.mode
= 0;
1105 lck2
->generic
.in
.timeout
= 0;
1106 lck2
->generic
.in
.ulock_cnt
= 1;
1107 lck2
->generic
.in
.lock_cnt
= 0;
1108 lck2
->generic
.in
.locks
= locks
;
1109 locks
->pid
= req
->smbpid
;
1110 locks
->offset
= lck
->unlock
.in
.offset
;
1111 locks
->count
= lck
->unlock
.in
.count
;
1114 case RAW_LOCK_SMB2
: {
1115 /* this is only approximate! We need to change the
1116 generic structure to fix this properly */
1119 if (lck
->smb2
.in
.lock_count
< 1) {
1120 return NT_STATUS_INVALID_PARAMETER
;
1123 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1124 lck2
->generic
.in
.file
.ntvfs
= lck
->smb2
.in
.file
.ntvfs
;
1125 lck2
->generic
.in
.timeout
= UINT32_MAX
;
1126 lck2
->generic
.in
.mode
= 0;
1127 lck2
->generic
.in
.lock_cnt
= 0;
1128 lck2
->generic
.in
.ulock_cnt
= 0;
1129 lck2
->generic
.in
.locks
= talloc_zero_array(lck2
, struct smb_lock_entry
,
1130 lck
->smb2
.in
.lock_count
);
1131 if (lck2
->generic
.in
.locks
== NULL
) {
1132 return NT_STATUS_NO_MEMORY
;
1134 /* only the first lock gives the UNLOCK bit - see
1136 if (lck
->smb2
.in
.locks
[0].flags
& SMB2_LOCK_FLAG_UNLOCK
) {
1137 if (lck
->smb2
.in
.locks
[0].flags
& SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
) {
1138 return NT_STATUS_INVALID_PARAMETER
;
1140 lck2
->generic
.in
.ulock_cnt
= lck
->smb2
.in
.lock_count
;
1143 lck2
->generic
.in
.lock_cnt
= lck
->smb2
.in
.lock_count
;
1146 for (i
=0;i
<lck
->smb2
.in
.lock_count
;i
++) {
1148 lck
->smb2
.in
.locks
[i
].flags
== SMB2_LOCK_FLAG_NONE
) {
1149 return NT_STATUS_INVALID_PARAMETER
;
1152 if (lck
->smb2
.in
.locks
[i
].flags
& ~SMB2_LOCK_FLAG_ALL_MASK
) {
1153 return NT_STATUS_INVALID_PARAMETER
;
1157 (lck
->smb2
.in
.locks
[i
].flags
&
1158 (SMB2_LOCK_FLAG_SHARED
|SMB2_LOCK_FLAG_EXCLUSIVE
))) {
1159 return NT_STATUS_INVALID_PARAMETER
;
1162 (lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_UNLOCK
)) {
1163 return NT_STATUS_INVALID_PARAMETER
;
1165 lck2
->generic
.in
.locks
[i
].pid
= req
->smbpid
;
1166 lck2
->generic
.in
.locks
[i
].offset
= lck
->smb2
.in
.locks
[i
].offset
;
1167 lck2
->generic
.in
.locks
[i
].count
= lck
->smb2
.in
.locks
[i
].length
;
1168 if (!(lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_EXCLUSIVE
)) {
1169 lck2
->generic
.in
.mode
= LOCKING_ANDX_SHARED_LOCK
;
1171 if (lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
) {
1172 lck2
->generic
.in
.timeout
= 0;
1175 /* initialize output value */
1176 lck
->smb2
.out
.reserved
= 0;
1180 case RAW_LOCK_SMB2_BREAK
:
1181 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1182 lck2
->generic
.in
.file
.ntvfs
= lck
->smb2_break
.in
.file
.ntvfs
;
1183 lck2
->generic
.in
.mode
= LOCKING_ANDX_OPLOCK_RELEASE
|
1184 ((lck
->smb2_break
.in
.oplock_level
<< 8) & 0xFF00);
1185 lck2
->generic
.in
.timeout
= 0;
1186 lck2
->generic
.in
.ulock_cnt
= 0;
1187 lck2
->generic
.in
.lock_cnt
= 0;
1188 lck2
->generic
.in
.locks
= NULL
;
1190 /* initialize output value */
1191 lck
->smb2_break
.out
.oplock_level
= lck
->smb2_break
.in
.oplock_level
;
1192 lck
->smb2_break
.out
.reserved
= lck
->smb2_break
.in
.reserved
;
1193 lck
->smb2_break
.out
.reserved2
= lck
->smb2_break
.in
.reserved2
;
1194 lck
->smb2_break
.out
.file
= lck
->smb2_break
.in
.file
;
1199 * we don't need to call ntvfs_map_async_setup() here,
1200 * as lock() doesn't have any output fields
1203 return ntvfs
->ops
->lock_fn(ntvfs
, req
, lck2
);
1208 NTVFS write generic to any mapper
1210 static NTSTATUS
ntvfs_map_write_finish(struct ntvfs_module_context
*ntvfs
,
1211 struct ntvfs_request
*req
,
1212 union smb_write
*wr
,
1213 union smb_write
*wr2
,
1216 union smb_lock
*lck
;
1217 union smb_close
*cl
;
1220 if (NT_STATUS_IS_ERR(status
)) {
1224 switch (wr
->generic
.level
) {
1225 case RAW_WRITE_WRITE
:
1226 wr
->write
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1229 case RAW_WRITE_WRITEUNLOCK
:
1230 wr
->writeunlock
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1232 lck
= talloc(wr2
, union smb_lock
);
1234 return NT_STATUS_NO_MEMORY
;
1237 lck
->unlock
.level
= RAW_LOCK_UNLOCK
;
1238 lck
->unlock
.in
.file
.ntvfs
= wr
->writeunlock
.in
.file
.ntvfs
;
1239 lck
->unlock
.in
.count
= wr
->writeunlock
.in
.count
;
1240 lck
->unlock
.in
.offset
= wr
->writeunlock
.in
.offset
;
1242 if (lck
->unlock
.in
.count
!= 0) {
1243 /* do the lock sync for now */
1244 state
= req
->async_states
->state
;
1245 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1246 status
= ntvfs
->ops
->lock_fn(ntvfs
, req
, lck
);
1247 req
->async_states
->state
= state
;
1251 case RAW_WRITE_WRITECLOSE
:
1252 wr
->writeclose
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1254 cl
= talloc(wr2
, union smb_close
);
1256 return NT_STATUS_NO_MEMORY
;
1259 cl
->close
.level
= RAW_CLOSE_CLOSE
;
1260 cl
->close
.in
.file
.ntvfs
= wr
->writeclose
.in
.file
.ntvfs
;
1261 cl
->close
.in
.write_time
= wr
->writeclose
.in
.mtime
;
1263 if (wr2
->generic
.in
.count
!= 0) {
1264 /* do the close sync for now */
1265 state
= req
->async_states
->state
;
1266 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1267 status
= ntvfs
->ops
->close_fn(ntvfs
, req
, cl
);
1268 req
->async_states
->state
= state
;
1272 case RAW_WRITE_SPLWRITE
:
1275 case RAW_WRITE_SMB2
:
1276 wr
->smb2
.out
._pad
= 0;
1277 wr
->smb2
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1278 wr
->smb2
.out
.unknown1
= 0;
1282 return NT_STATUS_INVALID_LEVEL
;
1290 NTVFS write generic to any mapper
1292 NTSTATUS
ntvfs_map_write(struct ntvfs_module_context
*ntvfs
,
1293 struct ntvfs_request
*req
,
1294 union smb_write
*wr
)
1296 union smb_write
*wr2
;
1299 wr2
= talloc(req
, union smb_write
);
1301 return NT_STATUS_NO_MEMORY
;
1304 status
= ntvfs_map_async_setup(ntvfs
, req
, wr
, wr2
,
1305 (second_stage_t
)ntvfs_map_write_finish
);
1306 if (!NT_STATUS_IS_OK(status
)) {
1310 wr2
->writex
.level
= RAW_WRITE_GENERIC
;
1312 switch (wr
->generic
.level
) {
1313 case RAW_WRITE_WRITEX
:
1314 status
= NT_STATUS_INVALID_LEVEL
;
1317 case RAW_WRITE_WRITE
:
1318 wr2
->writex
.in
.file
.ntvfs
= wr
->write
.in
.file
.ntvfs
;
1319 wr2
->writex
.in
.offset
= wr
->write
.in
.offset
;
1320 wr2
->writex
.in
.wmode
= 0;
1321 wr2
->writex
.in
.remaining
= wr
->write
.in
.remaining
;
1322 wr2
->writex
.in
.count
= wr
->write
.in
.count
;
1323 wr2
->writex
.in
.data
= wr
->write
.in
.data
;
1324 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1327 case RAW_WRITE_WRITEUNLOCK
:
1328 wr2
->writex
.in
.file
.ntvfs
= wr
->writeunlock
.in
.file
.ntvfs
;
1329 wr2
->writex
.in
.offset
= wr
->writeunlock
.in
.offset
;
1330 wr2
->writex
.in
.wmode
= 0;
1331 wr2
->writex
.in
.remaining
= wr
->writeunlock
.in
.remaining
;
1332 wr2
->writex
.in
.count
= wr
->writeunlock
.in
.count
;
1333 wr2
->writex
.in
.data
= wr
->writeunlock
.in
.data
;
1334 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1337 case RAW_WRITE_WRITECLOSE
:
1338 wr2
->writex
.in
.file
.ntvfs
= wr
->writeclose
.in
.file
.ntvfs
;
1339 wr2
->writex
.in
.offset
= wr
->writeclose
.in
.offset
;
1340 wr2
->writex
.in
.wmode
= 0;
1341 wr2
->writex
.in
.remaining
= 0;
1342 wr2
->writex
.in
.count
= wr
->writeclose
.in
.count
;
1343 wr2
->writex
.in
.data
= wr
->writeclose
.in
.data
;
1344 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1347 case RAW_WRITE_SPLWRITE
:
1348 wr2
->writex
.in
.file
.ntvfs
= wr
->splwrite
.in
.file
.ntvfs
;
1349 wr2
->writex
.in
.offset
= 0;
1350 wr2
->writex
.in
.wmode
= 0;
1351 wr2
->writex
.in
.remaining
= 0;
1352 wr2
->writex
.in
.count
= wr
->splwrite
.in
.count
;
1353 wr2
->writex
.in
.data
= wr
->splwrite
.in
.data
;
1354 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1357 case RAW_WRITE_SMB2
:
1358 wr2
->writex
.in
.file
.ntvfs
= wr
->smb2
.in
.file
.ntvfs
;
1359 wr2
->writex
.in
.offset
= wr
->smb2
.in
.offset
;
1360 wr2
->writex
.in
.wmode
= 0;
1361 wr2
->writex
.in
.remaining
= 0;
1362 wr2
->writex
.in
.count
= wr
->smb2
.in
.data
.length
;
1363 wr2
->writex
.in
.data
= wr
->smb2
.in
.data
.data
;
1364 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1367 return ntvfs_map_async_finish(req
, status
);
1372 NTVFS read generic to any mapper - finish the out mapping
1374 static NTSTATUS
ntvfs_map_read_finish(struct ntvfs_module_context
*ntvfs
,
1375 struct ntvfs_request
*req
,
1377 union smb_read
*rd2
,
1380 switch (rd
->generic
.level
) {
1382 rd
->read
.out
.nread
= rd2
->generic
.out
.nread
;
1384 case RAW_READ_READBRAW
:
1385 rd
->readbraw
.out
.nread
= rd2
->generic
.out
.nread
;
1387 case RAW_READ_LOCKREAD
:
1388 rd
->lockread
.out
.nread
= rd2
->generic
.out
.nread
;
1391 rd
->smb2
.out
.data
.length
= rd2
->generic
.out
.nread
;
1392 rd
->smb2
.out
.remaining
= 0;
1393 rd
->smb2
.out
.reserved
= 0;
1396 return NT_STATUS_INVALID_LEVEL
;
1403 NTVFS read* to readx mapper
1405 NTSTATUS
ntvfs_map_read(struct ntvfs_module_context
*ntvfs
,
1406 struct ntvfs_request
*req
,
1409 union smb_read
*rd2
;
1410 union smb_lock
*lck
;
1414 rd2
= talloc(req
, union smb_read
);
1416 return NT_STATUS_NO_MEMORY
;
1419 status
= ntvfs_map_async_setup(ntvfs
, req
, rd
, rd2
,
1420 (second_stage_t
)ntvfs_map_read_finish
);
1421 if (!NT_STATUS_IS_OK(status
)) {
1425 rd2
->readx
.level
= RAW_READ_READX
;
1426 rd2
->readx
.in
.read_for_execute
= false;
1428 switch (rd
->generic
.level
) {
1429 case RAW_READ_READX
:
1430 status
= NT_STATUS_INVALID_LEVEL
;
1434 rd2
->readx
.in
.file
.ntvfs
= rd
->read
.in
.file
.ntvfs
;
1435 rd2
->readx
.in
.offset
= rd
->read
.in
.offset
;
1436 rd2
->readx
.in
.mincnt
= rd
->read
.in
.count
;
1437 rd2
->readx
.in
.maxcnt
= rd
->read
.in
.count
;
1438 rd2
->readx
.in
.remaining
= rd
->read
.in
.remaining
;
1439 rd2
->readx
.out
.data
= rd
->read
.out
.data
;
1440 status
= ntvfs
->ops
->read_fn(ntvfs
, req
, rd2
);
1443 case RAW_READ_READBRAW
:
1444 rd2
->readx
.in
.file
.ntvfs
= rd
->readbraw
.in
.file
.ntvfs
;
1445 rd2
->readx
.in
.offset
= rd
->readbraw
.in
.offset
;
1446 rd2
->readx
.in
.mincnt
= rd
->readbraw
.in
.mincnt
;
1447 rd2
->readx
.in
.maxcnt
= rd
->readbraw
.in
.maxcnt
;
1448 rd2
->readx
.in
.remaining
= 0;
1449 rd2
->readx
.out
.data
= rd
->readbraw
.out
.data
;
1450 status
= ntvfs
->ops
->read_fn(ntvfs
, req
, rd2
);
1453 case RAW_READ_LOCKREAD
:
1454 /* do the initial lock sync for now */
1455 state
= req
->async_states
->state
;
1456 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1458 lck
= talloc(rd2
, union smb_lock
);
1460 status
= NT_STATUS_NO_MEMORY
;
1463 lck
->lock
.level
= RAW_LOCK_LOCK
;
1464 lck
->lock
.in
.file
.ntvfs
= rd
->lockread
.in
.file
.ntvfs
;
1465 lck
->lock
.in
.count
= rd
->lockread
.in
.count
;
1466 lck
->lock
.in
.offset
= rd
->lockread
.in
.offset
;
1467 status
= ntvfs
->ops
->lock_fn(ntvfs
, req
, lck
);
1468 req
->async_states
->state
= state
;
1470 rd2
->readx
.in
.file
.ntvfs
= rd
->lockread
.in
.file
.ntvfs
;
1471 rd2
->readx
.in
.offset
= rd
->lockread
.in
.offset
;
1472 rd2
->readx
.in
.mincnt
= rd
->lockread
.in
.count
;
1473 rd2
->readx
.in
.maxcnt
= rd
->lockread
.in
.count
;
1474 rd2
->readx
.in
.remaining
= rd
->lockread
.in
.remaining
;
1475 rd2
->readx
.out
.data
= rd
->lockread
.out
.data
;
1477 if (NT_STATUS_IS_OK(status
)) {
1478 status
= ntvfs
->ops
->read_fn(ntvfs
, req
, rd2
);
1483 rd2
->readx
.in
.file
.ntvfs
= rd
->smb2
.in
.file
.ntvfs
;
1484 rd2
->readx
.in
.offset
= rd
->smb2
.in
.offset
;
1485 rd2
->readx
.in
.mincnt
= rd
->smb2
.in
.min_count
;
1486 rd2
->readx
.in
.maxcnt
= rd
->smb2
.in
.length
;
1487 rd2
->readx
.in
.remaining
= 0;
1488 rd2
->readx
.out
.data
= rd
->smb2
.out
.data
.data
;
1489 status
= ntvfs
->ops
->read_fn(ntvfs
, req
, rd2
);
1494 return ntvfs_map_async_finish(req
, status
);
1499 NTVFS close generic to any mapper
1501 static NTSTATUS
ntvfs_map_close_finish(struct ntvfs_module_context
*ntvfs
,
1502 struct ntvfs_request
*req
,
1503 union smb_close
*cl
,
1504 union smb_close
*cl2
,
1507 NT_STATUS_NOT_OK_RETURN(status
);
1509 switch (cl
->generic
.level
) {
1510 case RAW_CLOSE_SMB2
:
1511 cl
->smb2
.out
.flags
= cl2
->generic
.out
.flags
;
1512 cl
->smb2
.out
._pad
= 0;
1513 cl
->smb2
.out
.create_time
= cl2
->generic
.out
.create_time
;
1514 cl
->smb2
.out
.access_time
= cl2
->generic
.out
.access_time
;
1515 cl
->smb2
.out
.write_time
= cl2
->generic
.out
.write_time
;
1516 cl
->smb2
.out
.change_time
= cl2
->generic
.out
.change_time
;
1517 cl
->smb2
.out
.alloc_size
= cl2
->generic
.out
.alloc_size
;
1518 cl
->smb2
.out
.size
= cl2
->generic
.out
.size
;
1519 cl
->smb2
.out
.file_attr
= cl2
->generic
.out
.file_attr
;
1529 NTVFS close generic to any mapper
1531 NTSTATUS
ntvfs_map_close(struct ntvfs_module_context
*ntvfs
,
1532 struct ntvfs_request
*req
,
1533 union smb_close
*cl
)
1535 union smb_close
*cl2
;
1538 cl2
= talloc(req
, union smb_close
);
1540 return NT_STATUS_NO_MEMORY
;
1543 switch (cl
->generic
.level
) {
1544 case RAW_CLOSE_GENERIC
:
1545 return NT_STATUS_INVALID_LEVEL
;
1547 case RAW_CLOSE_CLOSE
:
1548 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1549 cl2
->generic
.in
.file
= cl
->close
.in
.file
;
1550 cl2
->generic
.in
.write_time
= cl
->close
.in
.write_time
;
1551 cl2
->generic
.in
.flags
= 0;
1554 case RAW_CLOSE_SPLCLOSE
:
1555 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1556 cl2
->generic
.in
.file
= cl
->splclose
.in
.file
;
1557 cl2
->generic
.in
.write_time
= 0;
1558 cl2
->generic
.in
.flags
= 0;
1561 case RAW_CLOSE_SMB2
:
1562 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1563 cl2
->generic
.in
.file
= cl
->smb2
.in
.file
;
1564 cl2
->generic
.in
.write_time
= 0;
1565 cl2
->generic
.in
.flags
= cl
->smb2
.in
.flags
;
1569 status
= ntvfs_map_async_setup(ntvfs
, req
, cl
, cl2
,
1570 (second_stage_t
)ntvfs_map_close_finish
);
1571 NT_STATUS_NOT_OK_RETURN(status
);
1573 status
= ntvfs
->ops
->close_fn(ntvfs
, req
, cl2
);
1575 return ntvfs_map_async_finish(req
, status
);
1579 NTVFS notify generic to any mapper
1581 static NTSTATUS
ntvfs_map_notify_finish(struct ntvfs_module_context
*ntvfs
,
1582 struct ntvfs_request
*req
,
1583 union smb_notify
*nt
,
1584 union smb_notify
*nt2
,
1587 NT_STATUS_NOT_OK_RETURN(status
);
1589 switch (nt
->nttrans
.level
) {
1590 case RAW_NOTIFY_SMB2
:
1591 if (nt2
->nttrans
.out
.num_changes
== 0) {
1592 return STATUS_NOTIFY_ENUM_DIR
;
1594 nt
->smb2
.out
.num_changes
= nt2
->nttrans
.out
.num_changes
;
1595 nt
->smb2
.out
.changes
= talloc_steal(req
, nt2
->nttrans
.out
.changes
);
1599 return NT_STATUS_INVALID_LEVEL
;
1607 NTVFS notify generic to any mapper
1609 NTSTATUS
ntvfs_map_notify(struct ntvfs_module_context
*ntvfs
,
1610 struct ntvfs_request
*req
,
1611 union smb_notify
*nt
)
1613 union smb_notify
*nt2
;
1616 nt2
= talloc(req
, union smb_notify
);
1617 NT_STATUS_HAVE_NO_MEMORY(nt2
);
1619 status
= ntvfs_map_async_setup(ntvfs
, req
, nt
, nt2
,
1620 (second_stage_t
)ntvfs_map_notify_finish
);
1621 NT_STATUS_NOT_OK_RETURN(status
);
1623 nt2
->nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1625 switch (nt
->nttrans
.level
) {
1626 case RAW_NOTIFY_NTTRANS
:
1627 status
= NT_STATUS_INVALID_LEVEL
;
1630 case RAW_NOTIFY_SMB2
:
1631 nt2
->nttrans
.in
.file
.ntvfs
= nt
->smb2
.in
.file
.ntvfs
;
1632 nt2
->nttrans
.in
.buffer_size
= nt
->smb2
.in
.buffer_size
;
1633 nt2
->nttrans
.in
.completion_filter
= nt
->smb2
.in
.completion_filter
;
1634 nt2
->nttrans
.in
.recursive
= nt
->smb2
.in
.recursive
;
1635 status
= ntvfs
->ops
->notify_fn(ntvfs
, req
, nt2
);
1639 return ntvfs_map_async_finish(req
, status
);