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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 this implements mappings between info levels for NTVFS backend calls
25 the idea is that each of these functions implements one of the NTVFS
26 backend calls in terms of the 'generic' call. All backends that use
27 these functions must supply the generic call, but can if it wants to
28 also implement other levels if the need arises
30 this allows backend writers to only implement one variant of each
31 call unless they need fine grained control of the calls.
35 #include "librpc/gen_ndr/ndr_security.h"
36 #include "ntvfs/ntvfs.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
= req
->async_states
->private_data
;
61 ntvfs_async_state_pop(req
);
63 /* call the _finish function setup in ntvfs_map_async_setup() */
64 req
->async_states
->status
= m
->fn(m
->ntvfs
, req
, m
->io
, m
->io2
, req
->async_states
->status
);
66 /* call the send function from the next module up */
67 req
->async_states
->send_fn(req
);
71 prepare for calling a ntvfs backend with async support
72 io is the original call structure
73 io2 is the new call structure for the mapped call
74 fn is a second stage function for processing the out arguments
76 static NTSTATUS
ntvfs_map_async_setup(struct ntvfs_module_context
*ntvfs
,
77 struct ntvfs_request
*req
,
81 struct ntvfs_map_async
*m
;
82 m
= talloc(req
, struct ntvfs_map_async
);
84 return NT_STATUS_NO_MEMORY
;
90 return ntvfs_async_state_push(ntvfs
, req
, m
, ntvfs_map_async_send
);
94 called when first stage processing is complete.
96 static NTSTATUS
ntvfs_map_async_finish(struct ntvfs_request
*req
, NTSTATUS status
)
98 struct ntvfs_map_async
*m
;
100 /* if the backend has decided to reply in an async fashion then
101 we don't need to do any work here */
102 if (req
->async_states
->state
& NTVFS_ASYNC_STATE_ASYNC
) {
106 /* the backend is replying immediately. call the 2nd stage function after popping our local
108 m
= req
->async_states
->private_data
;
110 ntvfs_async_state_pop(req
);
112 return m
->fn(m
->ntvfs
, req
, m
->io
, m
->io2
, status
);
116 see if a filename ends in EXE COM DLL or SYM. This is needed for the
117 DENY_DOS mapping for OpenX
119 BOOL
is_exe_filename(const char *fname
)
122 p
= strrchr(fname
, '.');
127 if (strcasecmp(p
, "EXE") == 0 ||
128 strcasecmp(p
, "COM") == 0 ||
129 strcasecmp(p
, "DLL") == 0 ||
130 strcasecmp(p
, "SYM") == 0) {
138 NTVFS openx to ntcreatex mapper
140 static NTSTATUS
ntvfs_map_open_finish(struct ntvfs_module_context
*ntvfs
,
141 struct ntvfs_request
*req
,
146 time_t write_time
= 0;
147 uint32_t set_size
= 0;
148 union smb_setfileinfo
*sf
;
151 if (!NT_STATUS_IS_OK(status
)) {
155 switch (io
->generic
.level
) {
157 io
->openold
.out
.file
.fnum
= io2
->generic
.out
.file
.fnum
;
158 io
->openold
.out
.attrib
= io2
->generic
.out
.attrib
;
159 io
->openold
.out
.write_time
= nt_time_to_unix(io2
->generic
.out
.write_time
);
160 io
->openold
.out
.size
= io2
->generic
.out
.size
;
161 io
->openold
.out
.rmode
= io
->openold
.in
.open_mode
;
165 io
->openx
.out
.file
.fnum
= io2
->generic
.out
.file
.fnum
;
166 io
->openx
.out
.attrib
= io2
->generic
.out
.attrib
;
167 io
->openx
.out
.write_time
= nt_time_to_unix(io2
->generic
.out
.write_time
);
168 io
->openx
.out
.size
= io2
->generic
.out
.size
;
169 io
->openx
.out
.access
= (io
->openx
.in
.open_mode
& OPENX_MODE_ACCESS_MASK
);
170 io
->openx
.out
.ftype
= 0;
171 io
->openx
.out
.devstate
= 0;
172 io
->openx
.out
.action
= io2
->generic
.out
.create_action
;
173 io
->openx
.out
.unique_fid
= 0;
174 io
->openx
.out
.access_mask
= SEC_STD_ALL
;
175 io
->openx
.out
.unknown
= 0;
177 /* we need to extend the file to the requested size if
178 it was newly created */
179 if (io2
->generic
.out
.create_action
== NTCREATEX_ACTION_CREATED
) {
180 set_size
= io
->openx
.in
.size
;
184 case RAW_OPEN_T2OPEN
:
185 io
->t2open
.out
.file
.fnum
= io2
->generic
.out
.file
.fnum
;
186 io
->t2open
.out
.attrib
= io2
->generic
.out
.attrib
;
187 io
->t2open
.out
.write_time
= nt_time_to_unix(io2
->generic
.out
.write_time
);
188 io
->t2open
.out
.size
= io2
->generic
.out
.size
;
189 io
->t2open
.out
.access
= io
->t2open
.in
.open_mode
;
190 io
->t2open
.out
.ftype
= 0;
191 io
->t2open
.out
.devstate
= 0;
192 io
->t2open
.out
.action
= io2
->generic
.out
.create_action
;
193 io
->t2open
.out
.file_id
= 0;
197 case RAW_OPEN_CREATE
:
198 io
->mknew
.out
.file
.fnum
= io2
->generic
.out
.file
.fnum
;
199 write_time
= io
->mknew
.in
.write_time
;
203 io
->ctemp
.out
.file
.fnum
= io2
->generic
.out
.file
.fnum
;
204 io
->ctemp
.out
.name
= talloc_strdup(req
, io2
->generic
.in
.fname
+
205 strlen(io
->ctemp
.in
.directory
) + 1);
206 NT_STATUS_HAVE_NO_MEMORY(io
->ctemp
.out
.name
);
210 return NT_STATUS_INVALID_LEVEL
;
213 /* doing a secondary request async is more trouble than its
215 state
= req
->async_states
->state
;
216 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
218 if (write_time
!= 0) {
219 sf
= talloc(req
, union smb_setfileinfo
);
220 NT_STATUS_HAVE_NO_MEMORY(sf
);
221 sf
->generic
.level
= RAW_SFILEINFO_STANDARD
;
222 sf
->generic
.in
.file
.fnum
= io2
->generic
.out
.file
.fnum
;
223 sf
->standard
.in
.create_time
= 0;
224 sf
->standard
.in
.write_time
= write_time
;
225 sf
->standard
.in
.access_time
= 0;
226 status
= ntvfs
->ops
->setfileinfo(ntvfs
, req
, sf
);
230 sf
= talloc(req
, union smb_setfileinfo
);
231 NT_STATUS_HAVE_NO_MEMORY(sf
);
232 sf
->generic
.level
= RAW_SFILEINFO_END_OF_FILE_INFORMATION
;
233 sf
->generic
.in
.file
.fnum
= io2
->generic
.out
.file
.fnum
;
234 sf
->end_of_file_info
.in
.size
= set_size
;
235 status
= ntvfs
->ops
->setfileinfo(ntvfs
, req
, sf
);
236 if (NT_STATUS_IS_OK(status
)) {
237 io
->openx
.out
.size
= io
->openx
.in
.size
;
241 req
->async_states
->state
= state
;
247 the core of the mapping between openx style parameters and ntcreatex
250 static NTSTATUS
map_openx_open(uint16_t flags
, uint16_t open_mode
,
251 uint16_t open_func
, const char *fname
,
254 if (flags
& OPENX_FLAGS_REQUEST_OPLOCK
) {
255 io2
->generic
.in
.flags
|= NTCREATEX_FLAGS_REQUEST_OPLOCK
;
257 if (flags
& OPENX_FLAGS_REQUEST_BATCH_OPLOCK
) {
258 io2
->generic
.in
.flags
|= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
;
261 switch (open_mode
& OPENX_MODE_ACCESS_MASK
) {
262 case OPENX_MODE_ACCESS_READ
:
263 case OPENX_MODE_ACCESS_EXEC
:
264 io2
->generic
.in
.access_mask
= SEC_RIGHTS_FILE_READ
;
266 case OPENX_MODE_ACCESS_WRITE
:
267 io2
->generic
.in
.access_mask
= SEC_RIGHTS_FILE_WRITE
;
269 case OPENX_MODE_ACCESS_RDWR
:
270 case OPENX_MODE_ACCESS_FCB
:
271 io2
->generic
.in
.access_mask
=
272 SEC_RIGHTS_FILE_READ
|
273 SEC_RIGHTS_FILE_WRITE
;
276 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
279 switch (open_mode
& OPENX_MODE_DENY_MASK
) {
280 case OPENX_MODE_DENY_READ
:
281 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_WRITE
;
283 case OPENX_MODE_DENY_WRITE
:
284 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
;
286 case OPENX_MODE_DENY_ALL
:
287 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
289 case OPENX_MODE_DENY_NONE
:
290 io2
->generic
.in
.share_access
=
291 NTCREATEX_SHARE_ACCESS_READ
|
292 NTCREATEX_SHARE_ACCESS_WRITE
;
294 case OPENX_MODE_DENY_DOS
:
295 /* DENY_DOS is quite strange - it depends on the filename! */
296 io2
->generic
.in
.create_options
|=
297 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS
;
298 if (is_exe_filename(fname
)) {
299 io2
->generic
.in
.share_access
=
300 NTCREATEX_SHARE_ACCESS_READ
|
301 NTCREATEX_SHARE_ACCESS_WRITE
;
303 if ((open_mode
& OPENX_MODE_ACCESS_MASK
) == OPENX_MODE_ACCESS_READ
) {
304 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
;
306 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
310 case OPENX_MODE_DENY_FCB
:
311 io2
->generic
.in
.create_options
|= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB
;
312 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
315 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
319 case (OPENX_OPEN_FUNC_OPEN
):
320 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
322 case (OPENX_OPEN_FUNC_TRUNC
):
323 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE
;
325 case (OPENX_OPEN_FUNC_FAIL
| OPENX_OPEN_FUNC_CREATE
):
326 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
328 case (OPENX_OPEN_FUNC_OPEN
| OPENX_OPEN_FUNC_CREATE
):
329 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
331 case (OPENX_OPEN_FUNC_TRUNC
| OPENX_OPEN_FUNC_CREATE
):
332 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
335 /* this one is very strange */
336 if ((open_mode
& OPENX_MODE_ACCESS_MASK
) == OPENX_MODE_ACCESS_EXEC
) {
337 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
340 return NT_STATUS_DOS(ERRDOS
, ERRbadaccess
);
347 NTVFS open generic to any mapper
349 _PUBLIC_ NTSTATUS
ntvfs_map_open(struct ntvfs_module_context
*ntvfs
,
350 struct ntvfs_request
*req
,
356 io2
= talloc_zero(req
, union smb_open
);
358 return NT_STATUS_NO_MEMORY
;
361 status
= ntvfs_map_async_setup(ntvfs
, req
,
363 (second_stage_t
)ntvfs_map_open_finish
);
364 if (!NT_STATUS_IS_OK(status
)) {
368 io2
->generic
.level
= RAW_OPEN_GENERIC
;
370 switch (io
->generic
.level
) {
372 status
= map_openx_open(io
->openx
.in
.flags
,
373 io
->openx
.in
.open_mode
,
374 io
->openx
.in
.open_func
,
377 if (!NT_STATUS_IS_OK(status
)) {
381 io2
->generic
.in
.file_attr
= io
->openx
.in
.file_attrs
;
382 io2
->generic
.in
.fname
= io
->openx
.in
.fname
;
384 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
389 status
= map_openx_open(0,
390 io
->openold
.in
.open_mode
,
391 OPENX_OPEN_FUNC_OPEN
,
392 io
->openold
.in
.fname
,
394 if (!NT_STATUS_IS_OK(status
)) {
398 io2
->generic
.in
.file_attr
= io
->openold
.in
.search_attrs
;
399 io2
->generic
.in
.fname
= io
->openold
.in
.fname
;
401 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
404 case RAW_OPEN_T2OPEN
:
405 io2
->generic
.level
= RAW_OPEN_NTTRANS_CREATE
;
407 if (io
->t2open
.in
.open_func
== 0) {
408 status
= NT_STATUS_OBJECT_NAME_COLLISION
;
412 status
= map_openx_open(io
->t2open
.in
.flags
,
413 io
->t2open
.in
.open_mode
,
414 io
->t2open
.in
.open_func
,
417 if (!NT_STATUS_IS_OK(status
)) {
421 io2
->generic
.in
.file_attr
= io
->t2open
.in
.file_attrs
;
422 io2
->generic
.in
.fname
= io
->t2open
.in
.fname
;
423 io2
->generic
.in
.ea_list
= talloc(io2
, struct smb_ea_list
);
424 io2
->generic
.in
.ea_list
->num_eas
= io
->t2open
.in
.num_eas
;
425 io2
->generic
.in
.ea_list
->eas
= io
->t2open
.in
.eas
;
427 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
431 io2
->generic
.in
.file_attr
= io
->mknew
.in
.attrib
;
432 io2
->generic
.in
.fname
= io
->mknew
.in
.fname
;
433 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
434 io2
->generic
.in
.access_mask
=
435 SEC_RIGHTS_FILE_READ
|
436 SEC_RIGHTS_FILE_WRITE
;
437 io2
->generic
.in
.share_access
=
438 NTCREATEX_SHARE_ACCESS_READ
|
439 NTCREATEX_SHARE_ACCESS_WRITE
;
440 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
443 case RAW_OPEN_CREATE
:
444 io2
->generic
.in
.file_attr
= io
->mknew
.in
.attrib
;
445 io2
->generic
.in
.fname
= io
->mknew
.in
.fname
;
446 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
447 io2
->generic
.in
.access_mask
=
448 SEC_RIGHTS_FILE_READ
|
449 SEC_RIGHTS_FILE_WRITE
;
450 io2
->generic
.in
.share_access
=
451 NTCREATEX_SHARE_ACCESS_READ
|
452 NTCREATEX_SHARE_ACCESS_WRITE
;
453 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
457 io2
->generic
.in
.file_attr
= io
->ctemp
.in
.attrib
;
458 io2
->generic
.in
.file_attr
= 0;
459 io2
->generic
.in
.fname
=
460 talloc_asprintf(io2
, "%s\\SRV%s",
461 io
->ctemp
.in
.directory
,
462 generate_random_str_list(io2
, 5, "0123456789"));
463 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
464 io2
->generic
.in
.access_mask
=
465 SEC_RIGHTS_FILE_READ
|
466 SEC_RIGHTS_FILE_WRITE
;
467 io2
->generic
.in
.share_access
=
468 NTCREATEX_SHARE_ACCESS_READ
|
469 NTCREATEX_SHARE_ACCESS_WRITE
;
470 status
= ntvfs
->ops
->open(ntvfs
, req
, io2
);
474 status
= NT_STATUS_INVALID_LEVEL
;
478 return ntvfs_map_async_finish(req
, status
);
483 NTVFS fsinfo generic to any mapper
485 _PUBLIC_ NTSTATUS
ntvfs_map_fsinfo(struct ntvfs_module_context
*ntvfs
,
486 struct ntvfs_request
*req
,
487 union smb_fsinfo
*fs
)
490 union smb_fsinfo
*fs2
;
492 fs2
= talloc(req
, union smb_fsinfo
);
494 return NT_STATUS_NO_MEMORY
;
497 if (fs
->generic
.level
== RAW_QFS_GENERIC
) {
498 return NT_STATUS_INVALID_LEVEL
;
501 /* only used by the simple backend, which doesn't do async */
502 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
504 /* ask the backend for the generic info */
505 fs2
->generic
.level
= RAW_QFS_GENERIC
;
507 status
= ntvfs
->ops
->fsinfo(ntvfs
, req
, fs2
);
508 if (!NT_STATUS_IS_OK(status
)) {
512 /* and convert it to the required level */
513 switch (fs
->generic
.level
) {
514 case RAW_QFS_GENERIC
:
515 return NT_STATUS_INVALID_LEVEL
;
517 case RAW_QFS_DSKATTR
: {
518 /* map from generic to DSKATTR */
521 /* we need to scale the sizes to fit */
522 for (bpunit
=64; bpunit
<0x10000; bpunit
*= 2) {
523 if (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
< bpunit
* 512 * 65535.0) {
528 fs
->dskattr
.out
.blocks_per_unit
= bpunit
;
529 fs
->dskattr
.out
.block_size
= 512;
530 fs
->dskattr
.out
.units_total
=
531 (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
532 fs
->dskattr
.out
.units_free
=
533 (fs2
->generic
.out
.blocks_free
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
535 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
536 if (bpunit
> 64 && req
->ctx
->protocol
<= PROTOCOL_LANMAN2
) {
537 fs
->dskattr
.out
.blocks_per_unit
= 64;
538 fs
->dskattr
.out
.units_total
= 0xFFFF;
539 fs
->dskattr
.out
.units_free
= 0xFFFF;
544 case RAW_QFS_ALLOCATION
:
545 fs
->allocation
.out
.fs_id
= fs2
->generic
.out
.fs_id
;
546 fs
->allocation
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
547 fs
->allocation
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
548 fs
->allocation
.out
.sectors_per_unit
= 1;
549 fs
->allocation
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
553 fs
->volume
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
554 fs
->volume
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
557 case RAW_QFS_VOLUME_INFO
:
558 case RAW_QFS_VOLUME_INFORMATION
:
559 fs
->volume_info
.out
.create_time
= fs2
->generic
.out
.create_time
;
560 fs
->volume_info
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
561 fs
->volume_info
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
564 case RAW_QFS_SIZE_INFO
:
565 case RAW_QFS_SIZE_INFORMATION
:
566 fs
->size_info
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
567 fs
->size_info
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
568 fs
->size_info
.out
.sectors_per_unit
= 1;
569 fs
->size_info
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
572 case RAW_QFS_DEVICE_INFO
:
573 case RAW_QFS_DEVICE_INFORMATION
:
574 fs
->device_info
.out
.device_type
= fs2
->generic
.out
.device_type
;
575 fs
->device_info
.out
.characteristics
= fs2
->generic
.out
.device_characteristics
;
578 case RAW_QFS_ATTRIBUTE_INFO
:
579 case RAW_QFS_ATTRIBUTE_INFORMATION
:
580 fs
->attribute_info
.out
.fs_attr
= fs2
->generic
.out
.fs_attr
;
581 fs
->attribute_info
.out
.max_file_component_length
= fs2
->generic
.out
.max_file_component_length
;
582 fs
->attribute_info
.out
.fs_type
.s
= fs2
->generic
.out
.fs_type
;
585 case RAW_QFS_QUOTA_INFORMATION
:
586 ZERO_STRUCT(fs
->quota_information
.out
.unknown
);
587 fs
->quota_information
.out
.quota_soft
= fs2
->generic
.out
.quota_soft
;
588 fs
->quota_information
.out
.quota_hard
= fs2
->generic
.out
.quota_hard
;
589 fs
->quota_information
.out
.quota_flags
= fs2
->generic
.out
.quota_flags
;
592 case RAW_QFS_FULL_SIZE_INFORMATION
:
593 fs
->full_size_information
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
594 fs
->full_size_information
.out
.call_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
595 fs
->full_size_information
.out
.actual_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
596 fs
->full_size_information
.out
.sectors_per_unit
= 1;
597 fs
->full_size_information
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
600 case RAW_QFS_OBJECTID_INFORMATION
:
601 fs
->objectid_information
.out
.guid
= fs2
->generic
.out
.guid
;
602 ZERO_STRUCT(fs
->objectid_information
.out
.unknown
);
607 return NT_STATUS_INVALID_LEVEL
;
612 NTVFS fileinfo generic to any mapper
614 _PUBLIC_ NTSTATUS
ntvfs_map_fileinfo(TALLOC_CTX
*mem_ctx
,
615 union smb_fileinfo
*info
,
616 union smb_fileinfo
*info2
)
619 /* and convert it to the required level using results in info2 */
620 switch (info
->generic
.level
) {
621 case RAW_FILEINFO_GENERIC
:
622 return NT_STATUS_INVALID_LEVEL
;
623 case RAW_FILEINFO_GETATTR
:
624 info
->getattr
.out
.attrib
= info2
->generic
.out
.attrib
& 0xff;
625 info
->getattr
.out
.size
= info2
->generic
.out
.size
;
626 info
->getattr
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
629 case RAW_FILEINFO_GETATTRE
:
630 info
->getattre
.out
.attrib
= info2
->generic
.out
.attrib
;
631 info
->getattre
.out
.size
= info2
->generic
.out
.size
;
632 info
->getattre
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
633 info
->getattre
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
634 info
->getattre
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
635 info
->getattre
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
638 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
639 info
->network_open_information
.out
.create_time
= info2
->generic
.out
.create_time
;
640 info
->network_open_information
.out
.access_time
= info2
->generic
.out
.access_time
;
641 info
->network_open_information
.out
.write_time
= info2
->generic
.out
.write_time
;
642 info
->network_open_information
.out
.change_time
= info2
->generic
.out
.change_time
;
643 info
->network_open_information
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
644 info
->network_open_information
.out
.size
= info2
->generic
.out
.size
;
645 info
->network_open_information
.out
.attrib
= info2
->generic
.out
.attrib
;
648 case RAW_FILEINFO_ALL_INFO
:
649 case RAW_FILEINFO_ALL_INFORMATION
:
650 info
->all_info
.out
.create_time
= info2
->generic
.out
.create_time
;
651 info
->all_info
.out
.access_time
= info2
->generic
.out
.access_time
;
652 info
->all_info
.out
.write_time
= info2
->generic
.out
.write_time
;
653 info
->all_info
.out
.change_time
= info2
->generic
.out
.change_time
;
654 info
->all_info
.out
.attrib
= info2
->generic
.out
.attrib
;
655 info
->all_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
656 info
->all_info
.out
.size
= info2
->generic
.out
.size
;
657 info
->all_info
.out
.nlink
= info2
->generic
.out
.nlink
;
658 info
->all_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
659 info
->all_info
.out
.directory
= info2
->generic
.out
.directory
;
660 info
->all_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
661 info
->all_info
.out
.fname
.s
= info2
->generic
.out
.fname
.s
;
662 info
->all_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
665 case RAW_FILEINFO_BASIC_INFO
:
666 case RAW_FILEINFO_BASIC_INFORMATION
:
667 info
->basic_info
.out
.create_time
= info2
->generic
.out
.create_time
;
668 info
->basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
669 info
->basic_info
.out
.write_time
= info2
->generic
.out
.write_time
;
670 info
->basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
671 info
->basic_info
.out
.attrib
= info2
->generic
.out
.attrib
;
674 case RAW_FILEINFO_STANDARD
:
675 info
->standard
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
676 info
->standard
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
677 info
->standard
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
678 info
->standard
.out
.size
= info2
->generic
.out
.size
;
679 info
->standard
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
680 info
->standard
.out
.attrib
= info2
->generic
.out
.attrib
;
683 case RAW_FILEINFO_EA_SIZE
:
684 info
->ea_size
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
685 info
->ea_size
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
686 info
->ea_size
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
687 info
->ea_size
.out
.size
= info2
->generic
.out
.size
;
688 info
->ea_size
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
689 info
->ea_size
.out
.attrib
= info2
->generic
.out
.attrib
;
690 info
->ea_size
.out
.ea_size
= info2
->generic
.out
.ea_size
;
693 case RAW_FILEINFO_STANDARD_INFO
:
694 case RAW_FILEINFO_STANDARD_INFORMATION
:
695 info
->standard_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
696 info
->standard_info
.out
.size
= info2
->generic
.out
.size
;
697 info
->standard_info
.out
.nlink
= info2
->generic
.out
.nlink
;
698 info
->standard_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
699 info
->standard_info
.out
.directory
= info2
->generic
.out
.directory
;
702 case RAW_FILEINFO_INTERNAL_INFORMATION
:
703 info
->internal_information
.out
.file_id
= info2
->generic
.out
.file_id
;
706 case RAW_FILEINFO_EA_INFO
:
707 case RAW_FILEINFO_EA_INFORMATION
:
708 info
->ea_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
711 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
712 info
->attribute_tag_information
.out
.attrib
= info2
->generic
.out
.attrib
;
713 info
->attribute_tag_information
.out
.reparse_tag
= info2
->generic
.out
.reparse_tag
;
716 case RAW_FILEINFO_STREAM_INFO
:
717 case RAW_FILEINFO_STREAM_INFORMATION
:
718 info
->stream_info
.out
.num_streams
= info2
->generic
.out
.num_streams
;
719 if (info
->stream_info
.out
.num_streams
> 0) {
720 info
->stream_info
.out
.streams
=
721 talloc_array(mem_ctx
,
722 struct stream_struct
,
723 info
->stream_info
.out
.num_streams
);
724 if (!info
->stream_info
.out
.streams
) {
725 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
726 info
->stream_info
.out
.num_streams
));
727 return NT_STATUS_NO_MEMORY
;
729 for (i
=0; i
< info
->stream_info
.out
.num_streams
; i
++) {
730 info
->stream_info
.out
.streams
[i
] = info2
->generic
.out
.streams
[i
];
731 info
->stream_info
.out
.streams
[i
].stream_name
.s
=
732 talloc_strdup(info
->stream_info
.out
.streams
,
733 info2
->generic
.out
.streams
[i
].stream_name
.s
);
734 if (!info
->stream_info
.out
.streams
[i
].stream_name
.s
) {
735 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
736 return NT_STATUS_NO_MEMORY
;
742 case RAW_FILEINFO_NAME_INFO
:
743 case RAW_FILEINFO_NAME_INFORMATION
:
744 info
->name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.fname
.s
);
745 NT_STATUS_HAVE_NO_MEMORY(info
->name_info
.out
.fname
.s
);
746 info
->name_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
749 case RAW_FILEINFO_ALT_NAME_INFO
:
750 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
751 info
->alt_name_info
.out
.fname
.s
= talloc_strdup(mem_ctx
, info2
->generic
.out
.alt_fname
.s
);
752 NT_STATUS_HAVE_NO_MEMORY(info
->alt_name_info
.out
.fname
.s
);
753 info
->alt_name_info
.out
.fname
.private_length
= info2
->generic
.out
.alt_fname
.private_length
;
756 case RAW_FILEINFO_POSITION_INFORMATION
:
757 info
->position_information
.out
.position
= info2
->generic
.out
.position
;
760 case RAW_FILEINFO_ALL_EAS
:
761 info
->all_eas
.out
.num_eas
= info2
->generic
.out
.num_eas
;
762 if (info
->all_eas
.out
.num_eas
> 0) {
763 info
->all_eas
.out
.eas
= talloc_array(mem_ctx
,
765 info
->all_eas
.out
.num_eas
);
766 if (!info
->all_eas
.out
.eas
) {
767 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
768 info
->all_eas
.out
.num_eas
));
769 return NT_STATUS_NO_MEMORY
;
771 for (i
= 0; i
< info
->all_eas
.out
.num_eas
; i
++) {
772 info
->all_eas
.out
.eas
[i
] = info2
->generic
.out
.eas
[i
];
773 info
->all_eas
.out
.eas
[i
].name
.s
=
774 talloc_strdup(info
->all_eas
.out
.eas
,
775 info2
->generic
.out
.eas
[i
].name
.s
);
776 if (!info
->all_eas
.out
.eas
[i
].name
.s
) {
777 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
778 return NT_STATUS_NO_MEMORY
;
780 info
->all_eas
.out
.eas
[i
].value
.data
=
781 talloc_memdup(info
->all_eas
.out
.eas
,
782 info2
->generic
.out
.eas
[i
].value
.data
,
783 info2
->generic
.out
.eas
[i
].value
.length
);
784 if (!info
->all_eas
.out
.eas
[i
].value
.data
) {
785 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
786 return NT_STATUS_NO_MEMORY
;
792 case RAW_FILEINFO_IS_NAME_VALID
:
795 case RAW_FILEINFO_COMPRESSION_INFO
:
796 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
797 info
->compression_info
.out
.compressed_size
= info2
->generic
.out
.compressed_size
;
798 info
->compression_info
.out
.format
= info2
->generic
.out
.format
;
799 info
->compression_info
.out
.unit_shift
= info2
->generic
.out
.unit_shift
;
800 info
->compression_info
.out
.chunk_shift
= info2
->generic
.out
.chunk_shift
;
801 info
->compression_info
.out
.cluster_shift
= info2
->generic
.out
.cluster_shift
;
804 case RAW_FILEINFO_ACCESS_INFORMATION
:
805 info
->access_information
.out
.access_flags
= info2
->generic
.out
.access_flags
;
808 case RAW_FILEINFO_MODE_INFORMATION
:
809 info
->mode_information
.out
.mode
= info2
->generic
.out
.mode
;
812 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
813 info
->alignment_information
.out
.alignment_requirement
=
814 info2
->generic
.out
.alignment_requirement
;
817 case RAW_FILEINFO_UNIX_BASIC
:
818 info
->unix_basic_info
.out
.end_of_file
= info2
->generic
.out
.end_of_file
;
819 info
->unix_basic_info
.out
.num_bytes
= info2
->generic
.out
.size
;
820 info
->unix_basic_info
.out
.status_change_time
= info2
->generic
.out
.change_time
;
821 info
->unix_basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
822 info
->unix_basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
823 info
->unix_basic_info
.out
.uid
= info2
->generic
.out
.uid
;
824 info
->unix_basic_info
.out
.gid
= info2
->generic
.out
.gid
;
825 info
->unix_basic_info
.out
.file_type
= info2
->generic
.out
.file_type
;
826 info
->unix_basic_info
.out
.dev_major
= info2
->generic
.out
.device
;
827 info
->unix_basic_info
.out
.dev_minor
= info2
->generic
.out
.device
;
828 info
->unix_basic_info
.out
.unique_id
= info2
->generic
.out
.inode
;
829 info
->unix_basic_info
.out
.permissions
= info2
->generic
.out
.permissions
;
830 info
->unix_basic_info
.out
.nlink
= info2
->generic
.out
.nlink
;
833 case RAW_FILEINFO_UNIX_LINK
:
834 info
->unix_link_info
.out
.link_dest
= info2
->generic
.out
.link_dest
;
839 return NT_STATUS_INVALID_LEVEL
;
843 NTVFS fileinfo generic to any mapper
845 _PUBLIC_ NTSTATUS
ntvfs_map_qfileinfo(struct ntvfs_module_context
*ntvfs
,
846 struct ntvfs_request
*req
,
847 union smb_fileinfo
*info
)
850 union smb_fileinfo
*info2
;
852 info2
= talloc(req
, union smb_fileinfo
);
854 return NT_STATUS_NO_MEMORY
;
857 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
858 return NT_STATUS_INVALID_LEVEL
;
861 /* ask the backend for the generic info */
862 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
863 info2
->generic
.in
.file
.fnum
= info
->generic
.in
.file
.fnum
;
865 /* only used by the simple backend, which doesn't do async */
866 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
868 status
= ntvfs
->ops
->qfileinfo(ntvfs
, req
, info2
);
869 if (!NT_STATUS_IS_OK(status
)) {
872 return ntvfs_map_fileinfo(req
, info
, info2
);
876 NTVFS pathinfo generic to any mapper
878 _PUBLIC_ NTSTATUS
ntvfs_map_qpathinfo(struct ntvfs_module_context
*ntvfs
,
879 struct ntvfs_request
*req
,
880 union smb_fileinfo
*info
)
883 union smb_fileinfo
*info2
;
885 info2
= talloc(req
, union smb_fileinfo
);
887 return NT_STATUS_NO_MEMORY
;
890 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
891 return NT_STATUS_INVALID_LEVEL
;
894 /* ask the backend for the generic info */
895 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
896 info2
->generic
.in
.file
.path
= info
->generic
.in
.file
.path
;
898 /* only used by the simple backend, which doesn't do async */
899 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
901 status
= ntvfs
->ops
->qpathinfo(ntvfs
, req
, info2
);
902 if (!NT_STATUS_IS_OK(status
)) {
905 return ntvfs_map_fileinfo(req
, info
, info2
);
910 NTVFS lock generic to any mapper
912 _PUBLIC_ NTSTATUS
ntvfs_map_lock(struct ntvfs_module_context
*ntvfs
,
913 struct ntvfs_request
*req
,
916 union smb_lock
*lck2
;
917 struct smb_lock_entry
*locks
;
919 lck2
= talloc(req
, union smb_lock
);
921 return NT_STATUS_NO_MEMORY
;
924 locks
= talloc_array(lck2
, struct smb_lock_entry
, 1);
926 return NT_STATUS_NO_MEMORY
;
929 switch (lck
->generic
.level
) {
931 return NT_STATUS_INVALID_LEVEL
;
934 lck2
->generic
.in
.ulock_cnt
= 0;
935 lck2
->generic
.in
.lock_cnt
= 1;
938 case RAW_LOCK_UNLOCK
:
939 lck2
->generic
.in
.ulock_cnt
= 1;
940 lck2
->generic
.in
.lock_cnt
= 0;
944 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
945 lck2
->generic
.in
.file
.fnum
= lck
->lock
.in
.file
.fnum
;
946 lck2
->generic
.in
.mode
= 0;
947 lck2
->generic
.in
.timeout
= 0;
948 lck2
->generic
.in
.locks
= locks
;
949 locks
->pid
= req
->smbpid
;
950 locks
->offset
= lck
->lock
.in
.offset
;
951 locks
->count
= lck
->lock
.in
.count
;
954 * we don't need to call ntvfs_map_async_setup() here,
955 * as lock() doesn't have any output fields
958 return ntvfs
->ops
->lock(ntvfs
, req
, lck2
);
963 NTVFS write generic to any mapper
965 static NTSTATUS
ntvfs_map_write_finish(struct ntvfs_module_context
*ntvfs
,
966 struct ntvfs_request
*req
,
968 union smb_write
*wr2
,
975 if (NT_STATUS_IS_ERR(status
)) {
979 switch (wr
->generic
.level
) {
980 case RAW_WRITE_WRITE
:
981 wr
->write
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
984 case RAW_WRITE_WRITEUNLOCK
:
985 wr
->writeunlock
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
987 lck
= talloc(wr2
, union smb_lock
);
989 return NT_STATUS_NO_MEMORY
;
992 lck
->unlock
.level
= RAW_LOCK_UNLOCK
;
993 lck
->unlock
.in
.file
.fnum
= wr
->writeunlock
.in
.file
.fnum
;
994 lck
->unlock
.in
.count
= wr
->writeunlock
.in
.count
;
995 lck
->unlock
.in
.offset
= wr
->writeunlock
.in
.offset
;
997 if (lck
->unlock
.in
.count
!= 0) {
998 /* do the lock sync for now */
999 state
= req
->async_states
->state
;
1000 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1001 status
= ntvfs
->ops
->lock(ntvfs
, req
, lck
);
1002 req
->async_states
->state
= state
;
1006 case RAW_WRITE_WRITECLOSE
:
1007 wr
->writeclose
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
1009 cl
= talloc(wr2
, union smb_close
);
1011 return NT_STATUS_NO_MEMORY
;
1014 cl
->close
.level
= RAW_CLOSE_CLOSE
;
1015 cl
->close
.in
.file
.fnum
= wr
->writeclose
.in
.file
.fnum
;
1016 cl
->close
.in
.write_time
= wr
->writeclose
.in
.mtime
;
1018 if (wr2
->generic
.in
.count
!= 0) {
1019 /* do the close sync for now */
1020 state
= req
->async_states
->state
;
1021 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1022 status
= ntvfs
->ops
->close(ntvfs
, req
, cl
);
1023 req
->async_states
->state
= state
;
1027 case RAW_WRITE_SPLWRITE
:
1030 return NT_STATUS_INVALID_LEVEL
;
1038 NTVFS write generic to any mapper
1040 _PUBLIC_ NTSTATUS
ntvfs_map_write(struct ntvfs_module_context
*ntvfs
,
1041 struct ntvfs_request
*req
,
1042 union smb_write
*wr
)
1044 union smb_write
*wr2
;
1047 wr2
= talloc(req
, union smb_write
);
1049 return NT_STATUS_NO_MEMORY
;
1052 status
= ntvfs_map_async_setup(ntvfs
, req
, wr
, wr2
,
1053 (second_stage_t
)ntvfs_map_write_finish
);
1054 if (!NT_STATUS_IS_OK(status
)) {
1058 wr2
->writex
.level
= RAW_WRITE_GENERIC
;
1060 switch (wr
->generic
.level
) {
1061 case RAW_WRITE_WRITEX
:
1062 status
= NT_STATUS_INVALID_LEVEL
;
1065 case RAW_WRITE_WRITE
:
1066 wr2
->writex
.in
.file
.fnum
= wr
->write
.in
.file
.fnum
;
1067 wr2
->writex
.in
.offset
= wr
->write
.in
.offset
;
1068 wr2
->writex
.in
.wmode
= 0;
1069 wr2
->writex
.in
.remaining
= wr
->write
.in
.remaining
;
1070 wr2
->writex
.in
.count
= wr
->write
.in
.count
;
1071 wr2
->writex
.in
.data
= wr
->write
.in
.data
;
1072 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1075 case RAW_WRITE_WRITEUNLOCK
:
1076 wr2
->writex
.in
.file
.fnum
= wr
->writeunlock
.in
.file
.fnum
;
1077 wr2
->writex
.in
.offset
= wr
->writeunlock
.in
.offset
;
1078 wr2
->writex
.in
.wmode
= 0;
1079 wr2
->writex
.in
.remaining
= wr
->writeunlock
.in
.remaining
;
1080 wr2
->writex
.in
.count
= wr
->writeunlock
.in
.count
;
1081 wr2
->writex
.in
.data
= wr
->writeunlock
.in
.data
;
1082 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1085 case RAW_WRITE_WRITECLOSE
:
1086 wr2
->writex
.in
.file
.fnum
= wr
->writeclose
.in
.file
.fnum
;
1087 wr2
->writex
.in
.offset
= wr
->writeclose
.in
.offset
;
1088 wr2
->writex
.in
.wmode
= 0;
1089 wr2
->writex
.in
.remaining
= 0;
1090 wr2
->writex
.in
.count
= wr
->writeclose
.in
.count
;
1091 wr2
->writex
.in
.data
= wr
->writeclose
.in
.data
;
1092 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1095 case RAW_WRITE_SPLWRITE
:
1096 wr2
->writex
.in
.file
.fnum
= wr
->splwrite
.in
.file
.fnum
;
1097 wr2
->writex
.in
.offset
= 0;
1098 wr2
->writex
.in
.wmode
= 0;
1099 wr2
->writex
.in
.remaining
= 0;
1100 wr2
->writex
.in
.count
= wr
->splwrite
.in
.count
;
1101 wr2
->writex
.in
.data
= wr
->splwrite
.in
.data
;
1102 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1106 return ntvfs_map_async_finish(req
, status
);
1111 NTVFS read generic to any mapper - finish the out mapping
1113 static NTSTATUS
ntvfs_map_read_finish(struct ntvfs_module_context
*ntvfs
,
1114 struct ntvfs_request
*req
,
1116 union smb_read
*rd2
,
1119 switch (rd
->generic
.level
) {
1121 rd
->read
.out
.nread
= rd2
->generic
.out
.nread
;
1123 case RAW_READ_READBRAW
:
1124 rd
->readbraw
.out
.nread
= rd2
->generic
.out
.nread
;
1126 case RAW_READ_LOCKREAD
:
1127 rd
->lockread
.out
.nread
= rd2
->generic
.out
.nread
;
1130 return NT_STATUS_INVALID_LEVEL
;
1137 NTVFS read* to readx mapper
1139 _PUBLIC_ NTSTATUS
ntvfs_map_read(struct ntvfs_module_context
*ntvfs
,
1140 struct ntvfs_request
*req
,
1143 union smb_read
*rd2
;
1144 union smb_lock
*lck
;
1148 rd2
= talloc(req
, union smb_read
);
1150 return NT_STATUS_NO_MEMORY
;
1153 status
= ntvfs_map_async_setup(ntvfs
, req
, rd
, rd2
,
1154 (second_stage_t
)ntvfs_map_read_finish
);
1155 if (!NT_STATUS_IS_OK(status
)) {
1159 rd2
->readx
.level
= RAW_READ_READX
;
1160 rd2
->readx
.in
.read_for_execute
= False
;
1162 switch (rd
->generic
.level
) {
1163 case RAW_READ_READX
:
1164 status
= NT_STATUS_INVALID_LEVEL
;
1168 rd2
->readx
.in
.file
.fnum
= rd
->read
.in
.file
.fnum
;
1169 rd2
->readx
.in
.offset
= rd
->read
.in
.offset
;
1170 rd2
->readx
.in
.mincnt
= rd
->read
.in
.count
;
1171 rd2
->readx
.in
.maxcnt
= rd
->read
.in
.count
;
1172 rd2
->readx
.in
.remaining
= rd
->read
.in
.remaining
;
1173 rd2
->readx
.out
.data
= rd
->read
.out
.data
;
1174 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1177 case RAW_READ_READBRAW
:
1178 rd2
->readx
.in
.file
.fnum
= rd
->readbraw
.in
.file
.fnum
;
1179 rd2
->readx
.in
.offset
= rd
->readbraw
.in
.offset
;
1180 rd2
->readx
.in
.mincnt
= rd
->readbraw
.in
.mincnt
;
1181 rd2
->readx
.in
.maxcnt
= rd
->readbraw
.in
.maxcnt
;
1182 rd2
->readx
.in
.remaining
= 0;
1183 rd2
->readx
.out
.data
= rd
->readbraw
.out
.data
;
1184 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1187 case RAW_READ_LOCKREAD
:
1188 /* do the initial lock sync for now */
1189 state
= req
->async_states
->state
;
1190 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1192 lck
= talloc(rd2
, union smb_lock
);
1194 status
= NT_STATUS_NO_MEMORY
;
1197 lck
->lock
.level
= RAW_LOCK_LOCK
;
1198 lck
->lock
.in
.file
.fnum
= rd
->lockread
.in
.file
.fnum
;
1199 lck
->lock
.in
.count
= rd
->lockread
.in
.count
;
1200 lck
->lock
.in
.offset
= rd
->lockread
.in
.offset
;
1201 status
= ntvfs
->ops
->lock(ntvfs
, req
, lck
);
1202 req
->async_states
->state
= state
;
1204 rd2
->readx
.in
.file
.fnum
= rd
->lockread
.in
.file
.fnum
;
1205 rd2
->readx
.in
.offset
= rd
->lockread
.in
.offset
;
1206 rd2
->readx
.in
.mincnt
= rd
->lockread
.in
.count
;
1207 rd2
->readx
.in
.maxcnt
= rd
->lockread
.in
.count
;
1208 rd2
->readx
.in
.remaining
= rd
->lockread
.in
.remaining
;
1209 rd2
->readx
.out
.data
= rd
->lockread
.out
.data
;
1211 if (NT_STATUS_IS_OK(status
)) {
1212 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1218 return ntvfs_map_async_finish(req
, status
);
1223 NTVFS close generic to any mapper
1225 _PUBLIC_ NTSTATUS
ntvfs_map_close(struct ntvfs_module_context
*ntvfs
,
1226 struct ntvfs_request
*req
,
1227 union smb_close
*cl
)
1229 union smb_close
*cl2
;
1231 cl2
= talloc(req
, union smb_close
);
1233 return NT_STATUS_NO_MEMORY
;
1236 switch (cl
->generic
.level
) {
1237 case RAW_CLOSE_CLOSE
:
1238 return NT_STATUS_INVALID_LEVEL
;
1240 case RAW_CLOSE_SPLCLOSE
:
1241 cl2
->close
.level
= RAW_CLOSE_CLOSE
;
1242 cl2
->close
.in
.file
.fnum
= cl
->splclose
.in
.file
.fnum
;
1247 * we don't need to call ntvfs_map_async_setup() here,
1248 * as close() doesn't have any output fields
1251 return ntvfs
->ops
->close(ntvfs
, req
, cl2
);