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"
40 /* a second stage function converts from the out parameters of the generic
41 call onto the out parameters of the specific call made */
42 typedef NTSTATUS (*second_stage_t
)(struct ntvfs_module_context
*,
43 struct ntvfs_request
*,
44 void *, void *, NTSTATUS
);
47 this structure holds the async state for pending mapped async calls
49 struct ntvfs_map_async
{
50 struct ntvfs_module_context
*ntvfs
;
56 this is a async wrapper, called from the backend when it has completed
57 a function that it has decided to reply to in an async fashion
59 static void ntvfs_map_async_send(struct ntvfs_request
*req
)
61 struct ntvfs_map_async
*m
= talloc_get_type(req
->async_states
->private_data
,
62 struct ntvfs_map_async
);
64 ntvfs_async_state_pop(req
);
66 /* call the _finish function setup in ntvfs_map_async_setup() */
67 req
->async_states
->status
= m
->fn(m
->ntvfs
, req
, m
->io
, m
->io2
, req
->async_states
->status
);
69 /* call the send function from the next module up */
70 req
->async_states
->send_fn(req
);
74 prepare for calling a ntvfs backend with async support
75 io is the original call structure
76 io2 is the new call structure for the mapped call
77 fn is a second stage function for processing the out arguments
79 static NTSTATUS
ntvfs_map_async_setup(struct ntvfs_module_context
*ntvfs
,
80 struct ntvfs_request
*req
,
84 struct ntvfs_map_async
*m
;
85 m
= talloc(req
, struct ntvfs_map_async
);
87 return NT_STATUS_NO_MEMORY
;
93 return ntvfs_async_state_push(ntvfs
, req
, m
, ntvfs_map_async_send
);
97 called when first stage processing is complete.
99 static NTSTATUS
ntvfs_map_async_finish(struct ntvfs_request
*req
, NTSTATUS status
)
101 struct ntvfs_map_async
*m
;
103 /* if the backend has decided to reply in an async fashion then
104 we don't need to do any work here */
105 if (req
->async_states
->state
& NTVFS_ASYNC_STATE_ASYNC
) {
109 /* the backend is replying immediately. call the 2nd stage function after popping our local
111 m
= talloc_get_type(req
->async_states
->private_data
,
112 struct ntvfs_map_async
);
114 ntvfs_async_state_pop(req
);
116 return m
->fn(m
->ntvfs
, req
, m
->io
, m
->io2
, status
);
120 see if a filename ends in EXE COM DLL or SYM. This is needed for the
121 DENY_DOS mapping for OpenX
123 bool is_exe_filename(const char *fname
)
126 p
= strrchr(fname
, '.');
131 if (strcasecmp(p
, "EXE") == 0 ||
132 strcasecmp(p
, "COM") == 0 ||
133 strcasecmp(p
, "DLL") == 0 ||
134 strcasecmp(p
, "SYM") == 0) {
142 NTVFS openx to ntcreatex mapper
144 static NTSTATUS
ntvfs_map_open_finish(struct ntvfs_module_context
*ntvfs
,
145 struct ntvfs_request
*req
,
150 time_t write_time
= 0;
151 uint32_t set_size
= 0;
152 union smb_setfileinfo
*sf
;
155 if (!NT_STATUS_IS_OK(status
)) {
159 switch (io
->generic
.level
) {
161 io
->openold
.out
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
162 io
->openold
.out
.attrib
= io2
->generic
.out
.attrib
;
163 io
->openold
.out
.write_time
= nt_time_to_unix(io2
->generic
.out
.write_time
);
164 io
->openold
.out
.size
= io2
->generic
.out
.size
;
165 io
->openold
.out
.rmode
= io
->openold
.in
.open_mode
;
169 io
->openx
.out
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
170 io
->openx
.out
.attrib
= io2
->generic
.out
.attrib
;
171 io
->openx
.out
.write_time
= nt_time_to_unix(io2
->generic
.out
.write_time
);
172 io
->openx
.out
.size
= io2
->generic
.out
.size
;
173 io
->openx
.out
.access
= (io
->openx
.in
.open_mode
& OPENX_MODE_ACCESS_MASK
);
174 io
->openx
.out
.ftype
= 0;
175 io
->openx
.out
.devstate
= 0;
176 io
->openx
.out
.action
= io2
->generic
.out
.create_action
;
177 io
->openx
.out
.unique_fid
= 0;
178 io
->openx
.out
.access_mask
= SEC_STD_ALL
;
179 io
->openx
.out
.unknown
= 0;
181 /* we need to extend the file to the requested size if
182 it was newly created */
183 if (io2
->generic
.out
.create_action
== NTCREATEX_ACTION_CREATED
) {
184 set_size
= io
->openx
.in
.size
;
188 case RAW_OPEN_T2OPEN
:
189 io
->t2open
.out
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
190 io
->t2open
.out
.attrib
= io2
->generic
.out
.attrib
;
191 io
->t2open
.out
.write_time
= nt_time_to_unix(io2
->generic
.out
.write_time
);
192 io
->t2open
.out
.size
= io2
->generic
.out
.size
;
193 io
->t2open
.out
.access
= io
->t2open
.in
.open_mode
;
194 io
->t2open
.out
.ftype
= 0;
195 io
->t2open
.out
.devstate
= 0;
196 io
->t2open
.out
.action
= io2
->generic
.out
.create_action
;
197 io
->t2open
.out
.file_id
= 0;
201 case RAW_OPEN_CREATE
:
202 io
->mknew
.out
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
203 write_time
= io
->mknew
.in
.write_time
;
207 io
->ctemp
.out
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
208 io
->ctemp
.out
.name
= talloc_strdup(req
, io2
->generic
.in
.fname
+
209 strlen(io
->ctemp
.in
.directory
) + 1);
210 NT_STATUS_HAVE_NO_MEMORY(io
->ctemp
.out
.name
);
214 ZERO_STRUCT(io
->smb2
.out
);
215 io
->smb2
.out
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
216 switch (io2
->generic
.out
.oplock_level
) {
217 case BATCH_OPLOCK_RETURN
:
218 io
->smb2
.out
.oplock_level
= SMB2_OPLOCK_LEVEL_BATCH
;
220 case EXCLUSIVE_OPLOCK_RETURN
:
221 io
->smb2
.out
.oplock_level
= SMB2_OPLOCK_LEVEL_EXCLUSIVE
;
223 case LEVEL_II_OPLOCK_RETURN
:
224 io
->smb2
.out
.oplock_level
= SMB2_OPLOCK_LEVEL_II
;
227 io
->smb2
.out
.oplock_level
= SMB2_OPLOCK_LEVEL_NONE
;
230 io
->smb2
.out
.reserved
= 0;
231 io
->smb2
.out
.create_action
= io2
->generic
.out
.create_action
;
232 io
->smb2
.out
.create_time
= io2
->generic
.out
.create_time
;
233 io
->smb2
.out
.access_time
= io2
->generic
.out
.access_time
;
234 io
->smb2
.out
.write_time
= io2
->generic
.out
.write_time
;
235 io
->smb2
.out
.change_time
= io2
->generic
.out
.change_time
;
236 io
->smb2
.out
.alloc_size
= io2
->generic
.out
.alloc_size
;
237 io
->smb2
.out
.size
= io2
->generic
.out
.size
;
238 io
->smb2
.out
.file_attr
= io2
->generic
.out
.attrib
;
239 io
->smb2
.out
.reserved2
= 0;
240 io
->smb2
.out
.maximal_access
= io2
->generic
.out
.maximal_access
;
241 memcpy(io
->smb2
.out
.on_disk_id
, io2
->generic
.out
.on_disk_id
,
242 sizeof(io2
->generic
.out
.on_disk_id
));
246 return NT_STATUS_INVALID_LEVEL
;
249 /* doing a secondary request async is more trouble than its
251 state
= req
->async_states
->state
;
252 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
254 if (write_time
!= 0) {
255 sf
= talloc(req
, union smb_setfileinfo
);
256 NT_STATUS_HAVE_NO_MEMORY(sf
);
257 sf
->generic
.level
= RAW_SFILEINFO_STANDARD
;
258 sf
->generic
.in
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
259 sf
->standard
.in
.create_time
= 0;
260 sf
->standard
.in
.write_time
= write_time
;
261 sf
->standard
.in
.access_time
= 0;
262 status
= ntvfs
->ops
->setfileinfo_fn(ntvfs
, req
, sf
);
266 sf
= talloc(req
, union smb_setfileinfo
);
267 NT_STATUS_HAVE_NO_MEMORY(sf
);
268 sf
->generic
.level
= RAW_SFILEINFO_END_OF_FILE_INFORMATION
;
269 sf
->generic
.in
.file
.ntvfs
= io2
->generic
.out
.file
.ntvfs
;
270 sf
->end_of_file_info
.in
.size
= set_size
;
271 status
= ntvfs
->ops
->setfileinfo_fn(ntvfs
, req
, sf
);
272 if (NT_STATUS_IS_OK(status
)) {
273 io
->openx
.out
.size
= io
->openx
.in
.size
;
277 req
->async_states
->state
= state
;
283 the core of the mapping between openx style parameters and ntcreatex
286 static NTSTATUS
map_openx_open(uint16_t flags
, uint16_t open_mode
,
287 uint16_t open_func
, const char *fname
,
290 io2
->generic
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
291 io2
->generic
.in
.private_flags
= 0;
293 if (flags
& OPENX_FLAGS_REQUEST_OPLOCK
) {
294 io2
->generic
.in
.flags
|= NTCREATEX_FLAGS_REQUEST_OPLOCK
;
296 if (flags
& OPENX_FLAGS_REQUEST_BATCH_OPLOCK
) {
297 io2
->generic
.in
.flags
|= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
;
300 switch (open_mode
& OPENX_MODE_ACCESS_MASK
) {
301 case OPENX_MODE_ACCESS_READ
:
302 case OPENX_MODE_ACCESS_EXEC
:
303 io2
->generic
.in
.access_mask
= SEC_RIGHTS_FILE_READ
;
305 case OPENX_MODE_ACCESS_WRITE
:
306 io2
->generic
.in
.access_mask
= SEC_RIGHTS_FILE_WRITE
;
308 case OPENX_MODE_ACCESS_RDWR
:
309 case OPENX_MODE_ACCESS_FCB
:
310 io2
->generic
.in
.access_mask
=
311 SEC_RIGHTS_FILE_READ
|
312 SEC_RIGHTS_FILE_WRITE
;
315 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
318 switch (open_mode
& OPENX_MODE_DENY_MASK
) {
319 case OPENX_MODE_DENY_READ
:
320 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_WRITE
;
322 case OPENX_MODE_DENY_WRITE
:
323 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
;
325 case OPENX_MODE_DENY_ALL
:
326 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
328 case OPENX_MODE_DENY_NONE
:
329 io2
->generic
.in
.share_access
=
330 NTCREATEX_SHARE_ACCESS_READ
|
331 NTCREATEX_SHARE_ACCESS_WRITE
;
333 case OPENX_MODE_DENY_DOS
:
334 /* DENY_DOS is quite strange - it depends on the filename! */
335 io2
->generic
.in
.private_flags
|=
336 NTCREATEX_FLAG_DENY_DOS
;
337 if (is_exe_filename(fname
)) {
338 io2
->generic
.in
.share_access
=
339 NTCREATEX_SHARE_ACCESS_READ
|
340 NTCREATEX_SHARE_ACCESS_WRITE
;
342 if ((open_mode
& OPENX_MODE_ACCESS_MASK
) == OPENX_MODE_ACCESS_READ
) {
343 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
;
345 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
349 case OPENX_MODE_DENY_FCB
:
350 io2
->generic
.in
.private_flags
|= NTCREATEX_FLAG_DENY_FCB
;
351 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
354 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
358 case (OPENX_OPEN_FUNC_OPEN
):
359 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
361 case (OPENX_OPEN_FUNC_TRUNC
):
362 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE
;
364 case (OPENX_OPEN_FUNC_FAIL
| OPENX_OPEN_FUNC_CREATE
):
365 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
367 case (OPENX_OPEN_FUNC_OPEN
| OPENX_OPEN_FUNC_CREATE
):
368 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
370 case (OPENX_OPEN_FUNC_TRUNC
| OPENX_OPEN_FUNC_CREATE
):
371 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
374 /* this one is very strange */
375 if ((open_mode
& OPENX_MODE_ACCESS_MASK
) == OPENX_MODE_ACCESS_EXEC
) {
376 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
379 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
386 NTVFS open generic to any mapper
388 NTSTATUS
ntvfs_map_open(struct ntvfs_module_context
*ntvfs
,
389 struct ntvfs_request
*req
,
395 io2
= talloc_zero(req
, union smb_open
);
397 return NT_STATUS_NO_MEMORY
;
400 status
= ntvfs_map_async_setup(ntvfs
, req
,
402 (second_stage_t
)ntvfs_map_open_finish
);
403 if (!NT_STATUS_IS_OK(status
)) {
407 io2
->generic
.level
= RAW_OPEN_GENERIC
;
409 switch (io
->generic
.level
) {
411 status
= map_openx_open(io
->openx
.in
.flags
,
412 io
->openx
.in
.open_mode
,
413 io
->openx
.in
.open_func
,
416 if (!NT_STATUS_IS_OK(status
)) {
420 io2
->generic
.in
.file_attr
= io
->openx
.in
.file_attrs
;
421 io2
->generic
.in
.fname
= io
->openx
.in
.fname
;
423 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
428 status
= map_openx_open(0,
429 io
->openold
.in
.open_mode
,
430 OPENX_OPEN_FUNC_OPEN
,
431 io
->openold
.in
.fname
,
433 if (!NT_STATUS_IS_OK(status
)) {
437 io2
->generic
.in
.file_attr
= io
->openold
.in
.search_attrs
;
438 io2
->generic
.in
.fname
= io
->openold
.in
.fname
;
440 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
443 case RAW_OPEN_T2OPEN
:
444 io2
->generic
.level
= RAW_OPEN_NTTRANS_CREATE
;
446 if (io
->t2open
.in
.open_func
== 0) {
447 status
= NT_STATUS_OBJECT_NAME_COLLISION
;
451 status
= map_openx_open(io
->t2open
.in
.flags
,
452 io
->t2open
.in
.open_mode
,
453 io
->t2open
.in
.open_func
,
456 if (!NT_STATUS_IS_OK(status
)) {
460 io2
->generic
.in
.file_attr
= io
->t2open
.in
.file_attrs
;
461 io2
->generic
.in
.fname
= io
->t2open
.in
.fname
;
462 io2
->generic
.in
.ea_list
= talloc(io2
, struct smb_ea_list
);
463 io2
->generic
.in
.ea_list
->num_eas
= io
->t2open
.in
.num_eas
;
464 io2
->generic
.in
.ea_list
->eas
= io
->t2open
.in
.eas
;
466 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
470 io2
->generic
.in
.file_attr
= io
->mknew
.in
.attrib
;
471 io2
->generic
.in
.fname
= io
->mknew
.in
.fname
;
472 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
473 io2
->generic
.in
.access_mask
=
474 SEC_RIGHTS_FILE_READ
|
475 SEC_RIGHTS_FILE_WRITE
;
476 io2
->generic
.in
.share_access
=
477 NTCREATEX_SHARE_ACCESS_READ
|
478 NTCREATEX_SHARE_ACCESS_WRITE
;
479 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
482 case RAW_OPEN_CREATE
:
483 io2
->generic
.in
.file_attr
= io
->mknew
.in
.attrib
;
484 io2
->generic
.in
.fname
= io
->mknew
.in
.fname
;
485 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
486 io2
->generic
.in
.access_mask
=
487 SEC_RIGHTS_FILE_READ
|
488 SEC_RIGHTS_FILE_WRITE
;
489 io2
->generic
.in
.share_access
=
490 NTCREATEX_SHARE_ACCESS_READ
|
491 NTCREATEX_SHARE_ACCESS_WRITE
;
492 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
496 io2
->generic
.in
.file_attr
= io
->ctemp
.in
.attrib
;
497 io2
->generic
.in
.fname
=
498 talloc_asprintf(io2
, "%s\\SRV%s",
499 io
->ctemp
.in
.directory
,
500 generate_random_str_list(io2
, 5, "0123456789"));
501 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
502 io2
->generic
.in
.access_mask
=
503 SEC_RIGHTS_FILE_READ
|
504 SEC_RIGHTS_FILE_WRITE
;
505 io2
->generic
.in
.share_access
=
506 NTCREATEX_SHARE_ACCESS_READ
|
507 NTCREATEX_SHARE_ACCESS_WRITE
;
508 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
511 switch (io
->smb2
.in
.oplock_level
) {
512 case SMB2_OPLOCK_LEVEL_BATCH
:
513 io2
->generic
.in
.flags
= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
|
514 NTCREATEX_FLAGS_REQUEST_OPLOCK
;
516 case SMB2_OPLOCK_LEVEL_EXCLUSIVE
:
517 io2
->generic
.in
.flags
= NTCREATEX_FLAGS_REQUEST_OPLOCK
;
520 io2
->generic
.in
.flags
= 0;
523 io2
->generic
.in
.root_fid
.fnum
= 0;
524 io2
->generic
.in
.access_mask
= io
->smb2
.in
.desired_access
;
525 io2
->generic
.in
.alloc_size
= io
->smb2
.in
.alloc_size
;
526 io2
->generic
.in
.file_attr
= io
->smb2
.in
.file_attributes
;
527 io2
->generic
.in
.share_access
= io
->smb2
.in
.share_access
;
528 io2
->generic
.in
.open_disposition
= io
->smb2
.in
.create_disposition
;
529 io2
->generic
.in
.create_options
= io
->smb2
.in
.create_options
;
530 io2
->generic
.in
.impersonation
= io
->smb2
.in
.impersonation_level
;
531 io2
->generic
.in
.security_flags
= 0;
532 io2
->generic
.in
.fname
= io
->smb2
.in
.fname
;
533 io2
->generic
.in
.sec_desc
= io
->smb2
.in
.sec_desc
;
534 io2
->generic
.in
.ea_list
= &io
->smb2
.in
.eas
;
535 io2
->generic
.in
.query_maximal_access
= io
->smb2
.in
.query_maximal_access
;
536 io2
->generic
.in
.query_on_disk_id
= io
->smb2
.in
.query_on_disk_id
;
537 io2
->generic
.in
.private_flags
= 0;
539 /* we don't support timewarp yet */
540 if (io
->smb2
.in
.timewarp
!= 0) {
541 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
545 /* we need to check these bits before we check the private mask */
546 if (io2
->generic
.in
.create_options
& SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK
) {
547 DEBUG(2,(__location__
" create_options 0x%x not supported\n",
548 io2
->generic
.in
.create_options
));
549 status
= NT_STATUS_NOT_SUPPORTED
;
553 /* TODO: find out why only SMB2 ignores these */
554 io2
->generic
.in
.create_options
&= ~NTCREATEX_OPTIONS_SYNC_ALERT
;
555 io2
->generic
.in
.create_options
&= ~NTCREATEX_OPTIONS_ASYNC_ALERT
;
557 status
= ntvfs
->ops
->open_fn(ntvfs
, req
, io2
);
561 status
= NT_STATUS_INVALID_LEVEL
;
565 return ntvfs_map_async_finish(req
, status
);
570 NTVFS any to fsinfo mapper
572 static NTSTATUS
ntvfs_map_fsinfo_finish(struct ntvfs_module_context
*ntvfs
,
573 struct ntvfs_request
*req
,
574 union smb_fsinfo
*fs
,
575 union smb_fsinfo
*fs2
,
578 if (!NT_STATUS_IS_OK(status
)) {
582 /* and convert it to the required level */
583 switch (fs
->generic
.level
) {
584 case RAW_QFS_DSKATTR
: {
585 /* map from generic to DSKATTR */
586 unsigned int bpunit
= 64;
588 /* we need to scale the sizes to fit */
589 for (bpunit
=64; bpunit
<0x10000; bpunit
*= 2) {
590 if (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
< bpunit
* 512 * 65535.0) {
595 fs
->dskattr
.out
.blocks_per_unit
= bpunit
;
596 fs
->dskattr
.out
.block_size
= 512;
597 fs
->dskattr
.out
.units_total
=
598 (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
599 fs
->dskattr
.out
.units_free
=
600 (fs2
->generic
.out
.blocks_free
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
602 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
603 if (bpunit
> 64 && req
->ctx
->protocol
<= PROTOCOL_LANMAN2
) {
604 fs
->dskattr
.out
.blocks_per_unit
= 64;
605 fs
->dskattr
.out
.units_total
= 0xFFFF;
606 fs
->dskattr
.out
.units_free
= 0xFFFF;
611 case RAW_QFS_ALLOCATION
:
612 fs
->allocation
.out
.fs_id
= fs2
->generic
.out
.fs_id
;
613 fs
->allocation
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
614 fs
->allocation
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
615 fs
->allocation
.out
.sectors_per_unit
= 1;
616 fs
->allocation
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
620 fs
->volume
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
621 fs
->volume
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
624 case RAW_QFS_VOLUME_INFO
:
625 case RAW_QFS_VOLUME_INFORMATION
:
626 fs
->volume_info
.out
.create_time
= fs2
->generic
.out
.create_time
;
627 fs
->volume_info
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
628 fs
->volume_info
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
631 case RAW_QFS_SIZE_INFO
:
632 case RAW_QFS_SIZE_INFORMATION
:
633 fs
->size_info
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
634 fs
->size_info
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
635 fs
->size_info
.out
.sectors_per_unit
= 1;
636 fs
->size_info
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
639 case RAW_QFS_DEVICE_INFO
:
640 case RAW_QFS_DEVICE_INFORMATION
:
641 fs
->device_info
.out
.device_type
= fs2
->generic
.out
.device_type
;
642 fs
->device_info
.out
.characteristics
= fs2
->generic
.out
.device_characteristics
;
645 case RAW_QFS_ATTRIBUTE_INFO
:
646 case RAW_QFS_ATTRIBUTE_INFORMATION
:
647 fs
->attribute_info
.out
.fs_attr
= fs2
->generic
.out
.fs_attr
;
648 fs
->attribute_info
.out
.max_file_component_length
= fs2
->generic
.out
.max_file_component_length
;
649 fs
->attribute_info
.out
.fs_type
.s
= fs2
->generic
.out
.fs_type
;
652 case RAW_QFS_QUOTA_INFORMATION
:
653 ZERO_STRUCT(fs
->quota_information
.out
.unknown
);
654 fs
->quota_information
.out
.quota_soft
= fs2
->generic
.out
.quota_soft
;
655 fs
->quota_information
.out
.quota_hard
= fs2
->generic
.out
.quota_hard
;
656 fs
->quota_information
.out
.quota_flags
= fs2
->generic
.out
.quota_flags
;
659 case RAW_QFS_FULL_SIZE_INFORMATION
:
660 fs
->full_size_information
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
661 fs
->full_size_information
.out
.call_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
662 fs
->full_size_information
.out
.actual_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
663 fs
->full_size_information
.out
.sectors_per_unit
= 1;
664 fs
->full_size_information
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
667 case RAW_QFS_OBJECTID_INFORMATION
:
668 fs
->objectid_information
.out
.guid
= fs2
->generic
.out
.guid
;
669 ZERO_STRUCT(fs
->objectid_information
.out
.unknown
);
672 case RAW_QFS_SECTOR_SIZE_INFORMATION
:
673 fs
->sector_size_info
.out
.logical_bytes_per_sector
674 = fs2
->generic
.out
.block_size
;
675 fs
->sector_size_info
.out
.phys_bytes_per_sector_atomic
676 = fs2
->generic
.out
.block_size
;
677 fs
->sector_size_info
.out
.phys_bytes_per_sector_perf
678 = fs2
->generic
.out
.block_size
;
679 fs
->sector_size_info
.out
.fs_effective_phys_bytes_per_sector_atomic
680 = fs2
->generic
.out
.block_size
;
681 fs
->sector_size_info
.out
.flags
682 = QFS_SSINFO_FLAGS_ALIGNED_DEVICE
683 | QFS_SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE
;
684 fs
->sector_size_info
.out
.byte_off_sector_align
= 0;
685 fs
->sector_size_info
.out
.byte_off_partition_align
= 0;
688 case RAW_QFS_GENERIC
:
689 case RAW_QFS_UNIX_INFO
:
690 return NT_STATUS_INVALID_LEVEL
;
693 return NT_STATUS_INVALID_LEVEL
;
697 NTVFS fsinfo any to generic mapper
699 NTSTATUS
ntvfs_map_fsinfo(struct ntvfs_module_context
*ntvfs
,
700 struct ntvfs_request
*req
,
701 union smb_fsinfo
*fs
)
704 union smb_fsinfo
*fs2
;
706 fs2
= talloc(req
, union smb_fsinfo
);
708 return NT_STATUS_NO_MEMORY
;
711 if (fs
->generic
.level
== RAW_QFS_GENERIC
) {
712 return NT_STATUS_INVALID_LEVEL
;
715 status
= ntvfs_map_async_setup(ntvfs
, req
, fs
, fs2
,
716 (second_stage_t
)ntvfs_map_fsinfo_finish
);
717 if (!NT_STATUS_IS_OK(status
)) {
721 /* ask the backend for the generic info */
722 fs2
->generic
.level
= RAW_QFS_GENERIC
;
724 status
= ntvfs
->ops
->fsinfo_fn(ntvfs
, req
, fs2
);
725 return ntvfs_map_async_finish(req
, status
);
730 NTVFS fileinfo generic to any mapper
732 NTSTATUS
ntvfs_map_fileinfo(TALLOC_CTX
*mem_ctx
,
733 union smb_fileinfo
*info
,
734 union smb_fileinfo
*info2
)
737 /* and convert it to the required level using results in info2 */
738 switch (info
->generic
.level
) {
739 case RAW_FILEINFO_GETATTR
:
740 info
->getattr
.out
.attrib
= info2
->generic
.out
.attrib
& 0xff;
741 info
->getattr
.out
.size
= info2
->generic
.out
.size
;
742 info
->getattr
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
745 case RAW_FILEINFO_GETATTRE
:
746 info
->getattre
.out
.attrib
= info2
->generic
.out
.attrib
;
747 info
->getattre
.out
.size
= info2
->generic
.out
.size
;
748 info
->getattre
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
749 info
->getattre
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
750 info
->getattre
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
751 info
->getattre
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
754 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
755 info
->network_open_information
.out
.create_time
= info2
->generic
.out
.create_time
;
756 info
->network_open_information
.out
.access_time
= info2
->generic
.out
.access_time
;
757 info
->network_open_information
.out
.write_time
= info2
->generic
.out
.write_time
;
758 info
->network_open_information
.out
.change_time
= info2
->generic
.out
.change_time
;
759 info
->network_open_information
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
760 info
->network_open_information
.out
.size
= info2
->generic
.out
.size
;
761 info
->network_open_information
.out
.attrib
= info2
->generic
.out
.attrib
;
764 case RAW_FILEINFO_ALL_INFO
:
765 case RAW_FILEINFO_ALL_INFORMATION
:
766 info
->all_info
.out
.create_time
= info2
->generic
.out
.create_time
;
767 info
->all_info
.out
.access_time
= info2
->generic
.out
.access_time
;
768 info
->all_info
.out
.write_time
= info2
->generic
.out
.write_time
;
769 info
->all_info
.out
.change_time
= info2
->generic
.out
.change_time
;
770 info
->all_info
.out
.attrib
= info2
->generic
.out
.attrib
;
771 info
->all_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
772 info
->all_info
.out
.size
= info2
->generic
.out
.size
;
773 info
->all_info
.out
.nlink
= info2
->generic
.out
.nlink
;
774 info
->all_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
775 info
->all_info
.out
.directory
= info2
->generic
.out
.directory
;
776 info
->all_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
777 info
->all_info
.out
.fname
.s
= info2
->generic
.out
.fname
.s
;
778 info
->all_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
781 case RAW_FILEINFO_BASIC_INFO
:
782 case RAW_FILEINFO_BASIC_INFORMATION
:
783 info
->basic_info
.out
.create_time
= info2
->generic
.out
.create_time
;
784 info
->basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
785 info
->basic_info
.out
.write_time
= info2
->generic
.out
.write_time
;
786 info
->basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
787 info
->basic_info
.out
.attrib
= info2
->generic
.out
.attrib
;
790 case RAW_FILEINFO_STANDARD
:
791 info
->standard
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
792 info
->standard
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
793 info
->standard
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
794 info
->standard
.out
.size
= info2
->generic
.out
.size
;
795 info
->standard
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
796 info
->standard
.out
.attrib
= info2
->generic
.out
.attrib
;
799 case RAW_FILEINFO_EA_SIZE
:
800 info
->ea_size
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
801 info
->ea_size
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
802 info
->ea_size
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
803 info
->ea_size
.out
.size
= info2
->generic
.out
.size
;
804 info
->ea_size
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
805 info
->ea_size
.out
.attrib
= info2
->generic
.out
.attrib
;
806 info
->ea_size
.out
.ea_size
= info2
->generic
.out
.ea_size
;
809 case RAW_FILEINFO_STANDARD_INFO
:
810 case RAW_FILEINFO_STANDARD_INFORMATION
:
811 info
->standard_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
812 info
->standard_info
.out
.size
= info2
->generic
.out
.size
;
813 info
->standard_info
.out
.nlink
= info2
->generic
.out
.nlink
;
814 info
->standard_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
815 info
->standard_info
.out
.directory
= info2
->generic
.out
.directory
;
818 case RAW_FILEINFO_INTERNAL_INFORMATION
:
819 info
->internal_information
.out
.file_id
= info2
->generic
.out
.file_id
;
822 case RAW_FILEINFO_EA_INFO
:
823 case RAW_FILEINFO_EA_INFORMATION
:
824 info
->ea_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
827 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
828 info
->attribute_tag_information
.out
.attrib
= info2
->generic
.out
.attrib
;
829 info
->attribute_tag_information
.out
.reparse_tag
= info2
->generic
.out
.reparse_tag
;
832 case RAW_FILEINFO_STREAM_INFO
:
833 case RAW_FILEINFO_STREAM_INFORMATION
:
834 info
->stream_info
.out
.num_streams
= info2
->generic
.out
.num_streams
;
835 if (info
->stream_info
.out
.num_streams
> 0) {
836 info
->stream_info
.out
.streams
=
837 talloc_array(mem_ctx
,
838 struct stream_struct
,
839 info
->stream_info
.out
.num_streams
);
840 if (!info
->stream_info
.out
.streams
) {
841 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
842 info
->stream_info
.out
.num_streams
));
843 return NT_STATUS_NO_MEMORY
;
845 for (i
=0; i
< info
->stream_info
.out
.num_streams
; i
++) {
846 info
->stream_info
.out
.streams
[i
] = info2
->generic
.out
.streams
[i
];
847 info
->stream_info
.out
.streams
[i
].stream_name
.s
=
848 talloc_strdup(info
->stream_info
.out
.streams
,
849 info2
->generic
.out
.streams
[i
].stream_name
.s
);
850 if (!info
->stream_info
.out
.streams
[i
].stream_name
.s
) {
851 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
852 return NT_STATUS_NO_MEMORY
;
858 case RAW_FILEINFO_NAME_INFO
:
859 case RAW_FILEINFO_NAME_INFORMATION
:
860 info
->name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.fname
.s
);
861 NT_STATUS_HAVE_NO_MEMORY(info
->name_info
.out
.fname
.s
);
862 info
->name_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
865 case RAW_FILEINFO_ALT_NAME_INFO
:
866 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
867 case RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION
:
868 info
->alt_name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.alt_fname
.s
);
869 NT_STATUS_HAVE_NO_MEMORY(info
->alt_name_info
.out
.fname
.s
);
870 info
->alt_name_info
.out
.fname
.private_length
= info2
->generic
.out
.alt_fname
.private_length
;
873 case RAW_FILEINFO_POSITION_INFORMATION
:
874 info
->position_information
.out
.position
= info2
->generic
.out
.position
;
877 case RAW_FILEINFO_ALL_EAS
:
878 info
->all_eas
.out
.num_eas
= info2
->generic
.out
.num_eas
;
879 if (info
->all_eas
.out
.num_eas
> 0) {
880 info
->all_eas
.out
.eas
= talloc_array(mem_ctx
,
882 info
->all_eas
.out
.num_eas
);
883 if (!info
->all_eas
.out
.eas
) {
884 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
885 info
->all_eas
.out
.num_eas
));
886 return NT_STATUS_NO_MEMORY
;
888 for (i
= 0; i
< info
->all_eas
.out
.num_eas
; i
++) {
889 info
->all_eas
.out
.eas
[i
] = info2
->generic
.out
.eas
[i
];
890 info
->all_eas
.out
.eas
[i
].name
.s
=
891 talloc_strdup(info
->all_eas
.out
.eas
,
892 info2
->generic
.out
.eas
[i
].name
.s
);
893 if (!info
->all_eas
.out
.eas
[i
].name
.s
) {
894 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
895 return NT_STATUS_NO_MEMORY
;
897 info
->all_eas
.out
.eas
[i
].value
.data
=
898 (uint8_t *)talloc_memdup(info
->all_eas
.out
.eas
,
899 info2
->generic
.out
.eas
[i
].value
.data
,
900 info2
->generic
.out
.eas
[i
].value
.length
);
901 if (!info
->all_eas
.out
.eas
[i
].value
.data
) {
902 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
903 return NT_STATUS_NO_MEMORY
;
909 case RAW_FILEINFO_IS_NAME_VALID
:
912 case RAW_FILEINFO_COMPRESSION_INFO
:
913 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
914 info
->compression_info
.out
.compressed_size
= info2
->generic
.out
.compressed_size
;
915 info
->compression_info
.out
.format
= info2
->generic
.out
.format
;
916 info
->compression_info
.out
.unit_shift
= info2
->generic
.out
.unit_shift
;
917 info
->compression_info
.out
.chunk_shift
= info2
->generic
.out
.chunk_shift
;
918 info
->compression_info
.out
.cluster_shift
= info2
->generic
.out
.cluster_shift
;
921 case RAW_FILEINFO_ACCESS_INFORMATION
:
922 info
->access_information
.out
.access_flags
= info2
->generic
.out
.access_flags
;
925 case RAW_FILEINFO_MODE_INFORMATION
:
926 info
->mode_information
.out
.mode
= info2
->generic
.out
.mode
;
929 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
930 info
->alignment_information
.out
.alignment_requirement
=
931 info2
->generic
.out
.alignment_requirement
;
933 case RAW_FILEINFO_UNIX_BASIC
:
935 return NT_STATUS_INVALID_LEVEL
;
937 info
->unix_basic_info
.out
.end_of_file
= info2
->generic
.out
.end_of_file
;
938 info
->unix_basic_info
.out
.num_bytes
= info2
->generic
.out
.size
;
939 info
->unix_basic_info
.out
.status_change_time
= info2
->generic
.out
.change_time
;
940 info
->unix_basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
941 info
->unix_basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
942 info
->unix_basic_info
.out
.uid
= info2
->generic
.out
.uid
;
943 info
->unix_basic_info
.out
.gid
= info2
->generic
.out
.gid
;
944 info
->unix_basic_info
.out
.file_type
= info2
->generic
.out
.file_type
;
945 info
->unix_basic_info
.out
.dev_major
= info2
->generic
.out
.device
;
946 info
->unix_basic_info
.out
.dev_minor
= info2
->generic
.out
.device
;
947 info
->unix_basic_info
.out
.unique_id
= info2
->generic
.out
.inode
;
948 info
->unix_basic_info
.out
.permissions
= info2
->generic
.out
.permissions
;
949 info
->unix_basic_info
.out
.nlink
= info2
->generic
.out
.nlink
;
952 case RAW_FILEINFO_UNIX_LINK
:
954 return NT_STATUS_INVALID_LEVEL
;
956 info
->unix_link_info
.out
.link_dest
= info2
->generic
.out
.link_dest
;
959 case RAW_FILEINFO_GENERIC
:
960 case RAW_FILEINFO_SEC_DESC
:
961 case RAW_FILEINFO_EA_LIST
:
962 case RAW_FILEINFO_UNIX_INFO2
:
963 case RAW_FILEINFO_SMB2_ALL_EAS
:
964 case RAW_FILEINFO_SMB2_ALL_INFORMATION
:
965 return NT_STATUS_INVALID_LEVEL
;
966 case RAW_FILEINFO_NORMALIZED_NAME_INFORMATION
:
967 return NT_STATUS_NOT_SUPPORTED
;
970 return NT_STATUS_INVALID_LEVEL
;
974 NTVFS any to fileinfo mapper
976 static NTSTATUS
ntvfs_map_qfileinfo_finish(struct ntvfs_module_context
*ntvfs
,
977 struct ntvfs_request
*req
,
978 union smb_fileinfo
*info
,
979 union smb_fileinfo
*info2
,
982 if (!NT_STATUS_IS_OK(status
)) {
986 return ntvfs_map_fileinfo(req
, info
, info2
);
990 NTVFS fileinfo generic to any mapper
992 NTSTATUS
ntvfs_map_qfileinfo(struct ntvfs_module_context
*ntvfs
,
993 struct ntvfs_request
*req
,
994 union smb_fileinfo
*info
)
997 union smb_fileinfo
*info2
;
999 info2
= talloc(req
, union smb_fileinfo
);
1000 if (info2
== NULL
) {
1001 return NT_STATUS_NO_MEMORY
;
1004 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
1005 return NT_STATUS_INVALID_LEVEL
;
1008 status
= ntvfs_map_async_setup(ntvfs
, req
, info
, info2
,
1009 (second_stage_t
)ntvfs_map_qfileinfo_finish
);
1010 if (!NT_STATUS_IS_OK(status
)) {
1014 /* ask the backend for the generic info */
1015 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
1016 info2
->generic
.in
.file
.ntvfs
= info
->generic
.in
.file
.ntvfs
;
1018 status
= ntvfs
->ops
->qfileinfo_fn(ntvfs
, req
, info2
);
1019 return ntvfs_map_async_finish(req
, status
);
1023 NTVFS any to fileinfo mapper
1025 static NTSTATUS
ntvfs_map_qpathinfo_finish(struct ntvfs_module_context
*ntvfs
,
1026 struct ntvfs_request
*req
,
1027 union smb_fileinfo
*info
,
1028 union smb_fileinfo
*info2
,
1031 if (!NT_STATUS_IS_OK(status
)) {
1035 return ntvfs_map_fileinfo(req
, info
, info2
);
1039 NTVFS pathinfo generic to any mapper
1041 NTSTATUS
ntvfs_map_qpathinfo(struct ntvfs_module_context
*ntvfs
,
1042 struct ntvfs_request
*req
,
1043 union smb_fileinfo
*info
)
1046 union smb_fileinfo
*info2
;
1048 info2
= talloc(req
, union smb_fileinfo
);
1049 if (info2
== NULL
) {
1050 return NT_STATUS_NO_MEMORY
;
1053 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
1054 return NT_STATUS_INVALID_LEVEL
;
1057 status
= ntvfs_map_async_setup(ntvfs
, req
, info
, info2
,
1058 (second_stage_t
)ntvfs_map_qpathinfo_finish
);
1059 if (!NT_STATUS_IS_OK(status
)) {
1063 /* ask the backend for the generic info */
1064 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
1065 info2
->generic
.in
.file
.path
= info
->generic
.in
.file
.path
;
1067 status
= ntvfs
->ops
->qpathinfo_fn(ntvfs
, req
, info2
);
1068 return ntvfs_map_async_finish(req
, status
);
1073 NTVFS lock generic to any mapper
1075 NTSTATUS
ntvfs_map_lock(struct ntvfs_module_context
*ntvfs
,
1076 struct ntvfs_request
*req
,
1077 union smb_lock
*lck
)
1079 union smb_lock
*lck2
;
1080 struct smb_lock_entry
*locks
;
1082 lck2
= talloc(req
, union smb_lock
);
1084 return NT_STATUS_NO_MEMORY
;
1087 locks
= talloc_array(lck2
, struct smb_lock_entry
, 1);
1088 if (locks
== NULL
) {
1089 return NT_STATUS_NO_MEMORY
;
1092 switch (lck
->generic
.level
) {
1093 case RAW_LOCK_LOCKX
:
1094 return NT_STATUS_INVALID_LEVEL
;
1097 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1098 lck2
->generic
.in
.file
.ntvfs
= lck
->lock
.in
.file
.ntvfs
;
1099 lck2
->generic
.in
.mode
= 0;
1100 lck2
->generic
.in
.timeout
= 0;
1101 lck2
->generic
.in
.ulock_cnt
= 0;
1102 lck2
->generic
.in
.lock_cnt
= 1;
1103 lck2
->generic
.in
.locks
= locks
;
1104 locks
->pid
= req
->smbpid
;
1105 locks
->offset
= lck
->lock
.in
.offset
;
1106 locks
->count
= lck
->lock
.in
.count
;
1109 case RAW_LOCK_UNLOCK
:
1110 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1111 lck2
->generic
.in
.file
.ntvfs
= lck
->unlock
.in
.file
.ntvfs
;
1112 lck2
->generic
.in
.mode
= 0;
1113 lck2
->generic
.in
.timeout
= 0;
1114 lck2
->generic
.in
.ulock_cnt
= 1;
1115 lck2
->generic
.in
.lock_cnt
= 0;
1116 lck2
->generic
.in
.locks
= locks
;
1117 locks
->pid
= req
->smbpid
;
1118 locks
->offset
= lck
->unlock
.in
.offset
;
1119 locks
->count
= lck
->unlock
.in
.count
;
1122 case RAW_LOCK_SMB2
: {
1123 /* this is only approximate! We need to change the
1124 generic structure to fix this properly */
1127 if (lck
->smb2
.in
.lock_count
< 1) {
1128 return NT_STATUS_INVALID_PARAMETER
;
1131 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1132 lck2
->generic
.in
.file
.ntvfs
= lck
->smb2
.in
.file
.ntvfs
;
1133 lck2
->generic
.in
.timeout
= UINT32_MAX
;
1134 lck2
->generic
.in
.mode
= 0;
1135 lck2
->generic
.in
.lock_cnt
= 0;
1136 lck2
->generic
.in
.ulock_cnt
= 0;
1137 lck2
->generic
.in
.locks
= talloc_zero_array(lck2
, struct smb_lock_entry
,
1138 lck
->smb2
.in
.lock_count
);
1139 if (lck2
->generic
.in
.locks
== NULL
) {
1140 return NT_STATUS_NO_MEMORY
;
1142 /* only the first lock gives the UNLOCK bit - see
1144 if (lck
->smb2
.in
.locks
[0].flags
& SMB2_LOCK_FLAG_UNLOCK
) {
1145 if (lck
->smb2
.in
.locks
[0].flags
& SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
) {
1146 return NT_STATUS_INVALID_PARAMETER
;
1148 lck2
->generic
.in
.ulock_cnt
= lck
->smb2
.in
.lock_count
;
1151 lck2
->generic
.in
.lock_cnt
= lck
->smb2
.in
.lock_count
;
1154 for (i
=0;i
<lck
->smb2
.in
.lock_count
;i
++) {
1156 lck
->smb2
.in
.locks
[i
].flags
== SMB2_LOCK_FLAG_NONE
) {
1157 return NT_STATUS_INVALID_PARAMETER
;
1160 if (lck
->smb2
.in
.locks
[i
].flags
& ~SMB2_LOCK_FLAG_ALL_MASK
) {
1161 return NT_STATUS_INVALID_PARAMETER
;
1165 (lck
->smb2
.in
.locks
[i
].flags
&
1166 (SMB2_LOCK_FLAG_SHARED
|SMB2_LOCK_FLAG_EXCLUSIVE
))) {
1167 return NT_STATUS_INVALID_PARAMETER
;
1170 (lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_UNLOCK
)) {
1171 return NT_STATUS_INVALID_PARAMETER
;
1173 lck2
->generic
.in
.locks
[i
].pid
= req
->smbpid
;
1174 lck2
->generic
.in
.locks
[i
].offset
= lck
->smb2
.in
.locks
[i
].offset
;
1175 lck2
->generic
.in
.locks
[i
].count
= lck
->smb2
.in
.locks
[i
].length
;
1176 if (!(lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_EXCLUSIVE
)) {
1177 lck2
->generic
.in
.mode
= LOCKING_ANDX_SHARED_LOCK
;
1179 if (lck
->smb2
.in
.locks
[i
].flags
& SMB2_LOCK_FLAG_FAIL_IMMEDIATELY
) {
1180 lck2
->generic
.in
.timeout
= 0;
1183 /* initialize output value */
1184 lck
->smb2
.out
.reserved
= 0;
1188 case RAW_LOCK_SMB2_BREAK
:
1189 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
1190 lck2
->generic
.in
.file
.ntvfs
= lck
->smb2_break
.in
.file
.ntvfs
;
1191 lck2
->generic
.in
.mode
= LOCKING_ANDX_OPLOCK_RELEASE
|
1192 ((lck
->smb2_break
.in
.oplock_level
<< 8) & 0xFF00);
1193 lck2
->generic
.in
.timeout
= 0;
1194 lck2
->generic
.in
.ulock_cnt
= 0;
1195 lck2
->generic
.in
.lock_cnt
= 0;
1196 lck2
->generic
.in
.locks
= NULL
;
1198 /* initialize output value */
1199 lck
->smb2_break
.out
.oplock_level
= lck
->smb2_break
.in
.oplock_level
;
1200 lck
->smb2_break
.out
.reserved
= lck
->smb2_break
.in
.reserved
;
1201 lck
->smb2_break
.out
.reserved2
= lck
->smb2_break
.in
.reserved2
;
1202 lck
->smb2_break
.out
.file
= lck
->smb2_break
.in
.file
;
1207 * we don't need to call ntvfs_map_async_setup() here,
1208 * as lock() doesn't have any output fields
1211 return ntvfs
->ops
->lock_fn(ntvfs
, req
, lck2
);
1216 NTVFS write generic to any mapper
1218 static NTSTATUS
ntvfs_map_write_finish(struct ntvfs_module_context
*ntvfs
,
1219 struct ntvfs_request
*req
,
1220 union smb_write
*wr
,
1221 union smb_write
*wr2
,
1224 union smb_lock
*lck
;
1225 union smb_close
*cl
;
1228 if (NT_STATUS_IS_ERR(status
)) {
1232 switch (wr
->generic
.level
) {
1233 case RAW_WRITE_WRITE
:
1234 wr
->write
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1237 case RAW_WRITE_WRITEUNLOCK
:
1238 wr
->writeunlock
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1240 lck
= talloc(wr2
, union smb_lock
);
1242 return NT_STATUS_NO_MEMORY
;
1245 lck
->unlock
.level
= RAW_LOCK_UNLOCK
;
1246 lck
->unlock
.in
.file
.ntvfs
= wr
->writeunlock
.in
.file
.ntvfs
;
1247 lck
->unlock
.in
.count
= wr
->writeunlock
.in
.count
;
1248 lck
->unlock
.in
.offset
= wr
->writeunlock
.in
.offset
;
1250 if (lck
->unlock
.in
.count
!= 0) {
1251 /* do the lock sync for now */
1252 state
= req
->async_states
->state
;
1253 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1254 status
= ntvfs
->ops
->lock_fn(ntvfs
, req
, lck
);
1255 req
->async_states
->state
= state
;
1259 case RAW_WRITE_WRITECLOSE
:
1260 wr
->writeclose
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1262 cl
= talloc(wr2
, union smb_close
);
1264 return NT_STATUS_NO_MEMORY
;
1267 cl
->close
.level
= RAW_CLOSE_CLOSE
;
1268 cl
->close
.in
.file
.ntvfs
= wr
->writeclose
.in
.file
.ntvfs
;
1269 cl
->close
.in
.write_time
= wr
->writeclose
.in
.mtime
;
1271 if (wr2
->generic
.in
.count
!= 0) {
1272 /* do the close sync for now */
1273 state
= req
->async_states
->state
;
1274 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1275 status
= ntvfs
->ops
->close_fn(ntvfs
, req
, cl
);
1276 req
->async_states
->state
= state
;
1280 case RAW_WRITE_SPLWRITE
:
1283 case RAW_WRITE_SMB2
:
1284 wr
->smb2
.out
._pad
= 0;
1285 wr
->smb2
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1286 wr
->smb2
.out
.unknown1
= 0;
1290 return NT_STATUS_INVALID_LEVEL
;
1298 NTVFS write generic to any mapper
1300 NTSTATUS
ntvfs_map_write(struct ntvfs_module_context
*ntvfs
,
1301 struct ntvfs_request
*req
,
1302 union smb_write
*wr
)
1304 union smb_write
*wr2
;
1307 wr2
= talloc(req
, union smb_write
);
1309 return NT_STATUS_NO_MEMORY
;
1312 status
= ntvfs_map_async_setup(ntvfs
, req
, wr
, wr2
,
1313 (second_stage_t
)ntvfs_map_write_finish
);
1314 if (!NT_STATUS_IS_OK(status
)) {
1318 wr2
->writex
.level
= RAW_WRITE_GENERIC
;
1320 switch (wr
->generic
.level
) {
1321 case RAW_WRITE_WRITEX
:
1322 status
= NT_STATUS_INVALID_LEVEL
;
1325 case RAW_WRITE_WRITE
:
1326 wr2
->writex
.in
.file
.ntvfs
= wr
->write
.in
.file
.ntvfs
;
1327 wr2
->writex
.in
.offset
= wr
->write
.in
.offset
;
1328 wr2
->writex
.in
.wmode
= 0;
1329 wr2
->writex
.in
.remaining
= wr
->write
.in
.remaining
;
1330 wr2
->writex
.in
.count
= wr
->write
.in
.count
;
1331 wr2
->writex
.in
.data
= wr
->write
.in
.data
;
1332 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1335 case RAW_WRITE_WRITEUNLOCK
:
1336 wr2
->writex
.in
.file
.ntvfs
= wr
->writeunlock
.in
.file
.ntvfs
;
1337 wr2
->writex
.in
.offset
= wr
->writeunlock
.in
.offset
;
1338 wr2
->writex
.in
.wmode
= 0;
1339 wr2
->writex
.in
.remaining
= wr
->writeunlock
.in
.remaining
;
1340 wr2
->writex
.in
.count
= wr
->writeunlock
.in
.count
;
1341 wr2
->writex
.in
.data
= wr
->writeunlock
.in
.data
;
1342 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1345 case RAW_WRITE_WRITECLOSE
:
1346 wr2
->writex
.in
.file
.ntvfs
= wr
->writeclose
.in
.file
.ntvfs
;
1347 wr2
->writex
.in
.offset
= wr
->writeclose
.in
.offset
;
1348 wr2
->writex
.in
.wmode
= 0;
1349 wr2
->writex
.in
.remaining
= 0;
1350 wr2
->writex
.in
.count
= wr
->writeclose
.in
.count
;
1351 wr2
->writex
.in
.data
= wr
->writeclose
.in
.data
;
1352 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1355 case RAW_WRITE_SPLWRITE
:
1356 wr2
->writex
.in
.file
.ntvfs
= wr
->splwrite
.in
.file
.ntvfs
;
1357 wr2
->writex
.in
.offset
= 0;
1358 wr2
->writex
.in
.wmode
= 0;
1359 wr2
->writex
.in
.remaining
= 0;
1360 wr2
->writex
.in
.count
= wr
->splwrite
.in
.count
;
1361 wr2
->writex
.in
.data
= wr
->splwrite
.in
.data
;
1362 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1365 case RAW_WRITE_SMB2
:
1366 wr2
->writex
.in
.file
.ntvfs
= wr
->smb2
.in
.file
.ntvfs
;
1367 wr2
->writex
.in
.offset
= wr
->smb2
.in
.offset
;
1368 wr2
->writex
.in
.wmode
= 0;
1369 wr2
->writex
.in
.remaining
= 0;
1370 wr2
->writex
.in
.count
= wr
->smb2
.in
.data
.length
;
1371 wr2
->writex
.in
.data
= wr
->smb2
.in
.data
.data
;
1372 status
= ntvfs
->ops
->write_fn(ntvfs
, req
, wr2
);
1375 return ntvfs_map_async_finish(req
, status
);
1380 NTVFS read generic to any mapper - finish the out mapping
1382 static NTSTATUS
ntvfs_map_read_finish(struct ntvfs_module_context
*ntvfs
,
1383 struct ntvfs_request
*req
,
1385 union smb_read
*rd2
,
1388 switch (rd
->generic
.level
) {
1390 rd
->read
.out
.nread
= rd2
->generic
.out
.nread
;
1392 case RAW_READ_READBRAW
:
1393 rd
->readbraw
.out
.nread
= rd2
->generic
.out
.nread
;
1395 case RAW_READ_LOCKREAD
:
1396 rd
->lockread
.out
.nread
= rd2
->generic
.out
.nread
;
1399 rd
->smb2
.out
.data
.length
= rd2
->generic
.out
.nread
;
1400 rd
->smb2
.out
.remaining
= 0;
1401 rd
->smb2
.out
.reserved
= 0;
1404 return NT_STATUS_INVALID_LEVEL
;
1411 NTVFS read* to readx mapper
1413 NTSTATUS
ntvfs_map_read(struct ntvfs_module_context
*ntvfs
,
1414 struct ntvfs_request
*req
,
1417 union smb_read
*rd2
;
1418 union smb_lock
*lck
;
1422 rd2
= talloc(req
, union smb_read
);
1424 return NT_STATUS_NO_MEMORY
;
1427 status
= ntvfs_map_async_setup(ntvfs
, req
, rd
, rd2
,
1428 (second_stage_t
)ntvfs_map_read_finish
);
1429 if (!NT_STATUS_IS_OK(status
)) {
1433 rd2
->readx
.level
= RAW_READ_READX
;
1434 rd2
->readx
.in
.read_for_execute
= false;
1436 switch (rd
->generic
.level
) {
1437 case RAW_READ_READX
:
1438 status
= NT_STATUS_INVALID_LEVEL
;
1442 rd2
->readx
.in
.file
.ntvfs
= rd
->read
.in
.file
.ntvfs
;
1443 rd2
->readx
.in
.offset
= rd
->read
.in
.offset
;
1444 rd2
->readx
.in
.mincnt
= rd
->read
.in
.count
;
1445 rd2
->readx
.in
.maxcnt
= rd
->read
.in
.count
;
1446 rd2
->readx
.in
.remaining
= rd
->read
.in
.remaining
;
1447 rd2
->readx
.out
.data
= rd
->read
.out
.data
;
1448 status
= ntvfs
->ops
->read_fn(ntvfs
, req
, rd2
);
1451 case RAW_READ_READBRAW
:
1452 rd2
->readx
.in
.file
.ntvfs
= rd
->readbraw
.in
.file
.ntvfs
;
1453 rd2
->readx
.in
.offset
= rd
->readbraw
.in
.offset
;
1454 rd2
->readx
.in
.mincnt
= rd
->readbraw
.in
.mincnt
;
1455 rd2
->readx
.in
.maxcnt
= rd
->readbraw
.in
.maxcnt
;
1456 rd2
->readx
.in
.remaining
= 0;
1457 rd2
->readx
.out
.data
= rd
->readbraw
.out
.data
;
1458 status
= ntvfs
->ops
->read_fn(ntvfs
, req
, rd2
);
1461 case RAW_READ_LOCKREAD
:
1462 /* do the initial lock sync for now */
1463 state
= req
->async_states
->state
;
1464 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1466 lck
= talloc(rd2
, union smb_lock
);
1468 status
= NT_STATUS_NO_MEMORY
;
1471 lck
->lock
.level
= RAW_LOCK_LOCK
;
1472 lck
->lock
.in
.file
.ntvfs
= rd
->lockread
.in
.file
.ntvfs
;
1473 lck
->lock
.in
.count
= rd
->lockread
.in
.count
;
1474 lck
->lock
.in
.offset
= rd
->lockread
.in
.offset
;
1475 status
= ntvfs
->ops
->lock_fn(ntvfs
, req
, lck
);
1476 req
->async_states
->state
= state
;
1478 rd2
->readx
.in
.file
.ntvfs
= rd
->lockread
.in
.file
.ntvfs
;
1479 rd2
->readx
.in
.offset
= rd
->lockread
.in
.offset
;
1480 rd2
->readx
.in
.mincnt
= rd
->lockread
.in
.count
;
1481 rd2
->readx
.in
.maxcnt
= rd
->lockread
.in
.count
;
1482 rd2
->readx
.in
.remaining
= rd
->lockread
.in
.remaining
;
1483 rd2
->readx
.out
.data
= rd
->lockread
.out
.data
;
1485 if (NT_STATUS_IS_OK(status
)) {
1486 status
= ntvfs
->ops
->read_fn(ntvfs
, req
, rd2
);
1491 rd2
->readx
.in
.file
.ntvfs
= rd
->smb2
.in
.file
.ntvfs
;
1492 rd2
->readx
.in
.offset
= rd
->smb2
.in
.offset
;
1493 rd2
->readx
.in
.mincnt
= rd
->smb2
.in
.min_count
;
1494 rd2
->readx
.in
.maxcnt
= rd
->smb2
.in
.length
;
1495 rd2
->readx
.in
.remaining
= 0;
1496 rd2
->readx
.out
.data
= rd
->smb2
.out
.data
.data
;
1497 status
= ntvfs
->ops
->read_fn(ntvfs
, req
, rd2
);
1502 return ntvfs_map_async_finish(req
, status
);
1507 NTVFS close generic to any mapper
1509 static NTSTATUS
ntvfs_map_close_finish(struct ntvfs_module_context
*ntvfs
,
1510 struct ntvfs_request
*req
,
1511 union smb_close
*cl
,
1512 union smb_close
*cl2
,
1515 NT_STATUS_NOT_OK_RETURN(status
);
1517 switch (cl
->generic
.level
) {
1518 case RAW_CLOSE_SMB2
:
1519 cl
->smb2
.out
.flags
= cl2
->generic
.out
.flags
;
1520 cl
->smb2
.out
._pad
= 0;
1521 cl
->smb2
.out
.create_time
= cl2
->generic
.out
.create_time
;
1522 cl
->smb2
.out
.access_time
= cl2
->generic
.out
.access_time
;
1523 cl
->smb2
.out
.write_time
= cl2
->generic
.out
.write_time
;
1524 cl
->smb2
.out
.change_time
= cl2
->generic
.out
.change_time
;
1525 cl
->smb2
.out
.alloc_size
= cl2
->generic
.out
.alloc_size
;
1526 cl
->smb2
.out
.size
= cl2
->generic
.out
.size
;
1527 cl
->smb2
.out
.file_attr
= cl2
->generic
.out
.file_attr
;
1537 NTVFS close generic to any mapper
1539 NTSTATUS
ntvfs_map_close(struct ntvfs_module_context
*ntvfs
,
1540 struct ntvfs_request
*req
,
1541 union smb_close
*cl
)
1543 union smb_close
*cl2
;
1546 cl2
= talloc(req
, union smb_close
);
1548 return NT_STATUS_NO_MEMORY
;
1551 switch (cl
->generic
.level
) {
1552 case RAW_CLOSE_GENERIC
:
1553 return NT_STATUS_INVALID_LEVEL
;
1555 case RAW_CLOSE_CLOSE
:
1556 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1557 cl2
->generic
.in
.file
= cl
->close
.in
.file
;
1558 cl2
->generic
.in
.write_time
= cl
->close
.in
.write_time
;
1559 cl2
->generic
.in
.flags
= 0;
1562 case RAW_CLOSE_SPLCLOSE
:
1563 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1564 cl2
->generic
.in
.file
= cl
->splclose
.in
.file
;
1565 cl2
->generic
.in
.write_time
= 0;
1566 cl2
->generic
.in
.flags
= 0;
1569 case RAW_CLOSE_SMB2
:
1570 cl2
->generic
.level
= RAW_CLOSE_GENERIC
;
1571 cl2
->generic
.in
.file
= cl
->smb2
.in
.file
;
1572 cl2
->generic
.in
.write_time
= 0;
1573 cl2
->generic
.in
.flags
= cl
->smb2
.in
.flags
;
1577 status
= ntvfs_map_async_setup(ntvfs
, req
, cl
, cl2
,
1578 (second_stage_t
)ntvfs_map_close_finish
);
1579 NT_STATUS_NOT_OK_RETURN(status
);
1581 status
= ntvfs
->ops
->close_fn(ntvfs
, req
, cl2
);
1583 return ntvfs_map_async_finish(req
, status
);
1587 NTVFS notify generic to any mapper
1589 static NTSTATUS
ntvfs_map_notify_finish(struct ntvfs_module_context
*ntvfs
,
1590 struct ntvfs_request
*req
,
1591 union smb_notify
*nt
,
1592 union smb_notify
*nt2
,
1595 NT_STATUS_NOT_OK_RETURN(status
);
1597 switch (nt
->nttrans
.level
) {
1598 case RAW_NOTIFY_SMB2
:
1599 if (nt2
->nttrans
.out
.num_changes
== 0) {
1600 return NT_STATUS_NOTIFY_ENUM_DIR
;
1602 nt
->smb2
.out
.num_changes
= nt2
->nttrans
.out
.num_changes
;
1603 nt
->smb2
.out
.changes
= talloc_steal(req
, nt2
->nttrans
.out
.changes
);
1607 return NT_STATUS_INVALID_LEVEL
;
1615 NTVFS notify generic to any mapper
1617 NTSTATUS
ntvfs_map_notify(struct ntvfs_module_context
*ntvfs
,
1618 struct ntvfs_request
*req
,
1619 union smb_notify
*nt
)
1621 union smb_notify
*nt2
;
1624 nt2
= talloc(req
, union smb_notify
);
1625 NT_STATUS_HAVE_NO_MEMORY(nt2
);
1627 status
= ntvfs_map_async_setup(ntvfs
, req
, nt
, nt2
,
1628 (second_stage_t
)ntvfs_map_notify_finish
);
1629 NT_STATUS_NOT_OK_RETURN(status
);
1631 nt2
->nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1633 switch (nt
->nttrans
.level
) {
1634 case RAW_NOTIFY_NTTRANS
:
1635 status
= NT_STATUS_INVALID_LEVEL
;
1638 case RAW_NOTIFY_SMB2
:
1639 nt2
->nttrans
.in
.file
.ntvfs
= nt
->smb2
.in
.file
.ntvfs
;
1640 nt2
->nttrans
.in
.buffer_size
= nt
->smb2
.in
.buffer_size
;
1641 nt2
->nttrans
.in
.completion_filter
= nt
->smb2
.in
.completion_filter
;
1642 nt2
->nttrans
.in
.recursive
= nt
->smb2
.in
.recursive
;
1643 status
= ntvfs
->ops
->notify_fn(ntvfs
, req
, nt2
);
1647 return ntvfs_map_async_finish(req
, status
);