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 "smb_server/smb_server.h"
36 #include "librpc/gen_ndr/ndr_security.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 smbsrv_request
*,
41 struct ntvfs_module_context
*,
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 smbsrv_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(req
, m
->ntvfs
, 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 smbsrv_request
*req
,
77 struct ntvfs_module_context
*ntvfs
,
81 struct ntvfs_map_async
*m
;
82 m
= talloc_p(req
, struct ntvfs_map_async
);
84 return NT_STATUS_NO_MEMORY
;
90 return ntvfs_async_state_push(req
, m
, ntvfs_map_async_send
, ntvfs
);
95 called when first stage processing is complete.
97 static NTSTATUS
ntvfs_map_async_finish(struct smbsrv_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
= req
->async_states
->private_data
;
111 ntvfs_async_state_pop(req
);
113 return m
->fn(req
, m
->ntvfs
, 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 smbsrv_request
*req
,
143 struct ntvfs_module_context
*ntvfs
,
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
.fnum
= io2
->generic
.out
.fnum
;
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
.fnum
= io2
->generic
.out
.fnum
;
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
.fnum
= io2
->generic
.out
.fnum
;
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
.fnum
= io2
->generic
.out
.fnum
;
201 write_time
= io
->mknew
.in
.write_time
;
205 io
->ctemp
.out
.fnum
= io2
->generic
.out
.fnum
;
206 io
->ctemp
.out
.name
= talloc_strdup(req
, io2
->generic
.in
.fname
+
207 strlen(io
->ctemp
.in
.directory
) + 1);
211 return NT_STATUS_INVALID_LEVEL
;
214 /* doing a secondary request async is more trouble than its
216 state
= req
->async_states
->state
;
217 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
219 if (write_time
!= 0) {
220 sf
= talloc_p(req
, union smb_setfileinfo
);
221 sf
->generic
.level
= RAW_SFILEINFO_STANDARD
;
222 sf
->generic
.file
.fnum
= io2
->generic
.out
.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_p(req
, union smb_setfileinfo
);
231 sf
->generic
.level
= RAW_SFILEINFO_END_OF_FILE_INFORMATION
;
232 sf
->generic
.file
.fnum
= io2
->generic
.out
.fnum
;
233 sf
->end_of_file_info
.in
.size
= set_size
;
234 status
= ntvfs
->ops
->setfileinfo(ntvfs
, req
, sf
);
235 if (NT_STATUS_IS_OK(status
)) {
236 io
->openx
.out
.size
= io
->openx
.in
.size
;
240 req
->async_states
->state
= state
;
246 the core of the mapping between openx style parameters and ntcreatex
249 static NTSTATUS
map_openx_open(uint16_t flags
, uint16_t open_mode
,
250 uint16_t open_func
, const char *fname
,
253 if (flags
& OPENX_FLAGS_REQUEST_OPLOCK
) {
254 io2
->generic
.in
.flags
|= NTCREATEX_FLAGS_REQUEST_OPLOCK
;
256 if (flags
& OPENX_FLAGS_REQUEST_BATCH_OPLOCK
) {
257 io2
->generic
.in
.flags
|= NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
;
260 switch (open_mode
& OPENX_MODE_ACCESS_MASK
) {
261 case OPENX_MODE_ACCESS_READ
:
262 io2
->generic
.in
.access_mask
= SEC_RIGHTS_FILE_READ
;
264 case OPENX_MODE_ACCESS_WRITE
:
265 io2
->generic
.in
.access_mask
= SEC_RIGHTS_FILE_WRITE
;
267 case OPENX_MODE_ACCESS_RDWR
:
268 case OPENX_MODE_ACCESS_FCB
:
269 case OPENX_MODE_ACCESS_EXEC
:
270 io2
->generic
.in
.access_mask
=
271 SEC_RIGHTS_FILE_READ
|
272 SEC_RIGHTS_FILE_WRITE
;
275 return NT_STATUS_INVALID_LOCK_SEQUENCE
;
278 switch (open_mode
& OPENX_MODE_DENY_MASK
) {
279 case OPENX_MODE_DENY_READ
:
280 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_WRITE
;
282 case OPENX_MODE_DENY_WRITE
:
283 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
;
285 case OPENX_MODE_DENY_ALL
:
286 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
288 case OPENX_MODE_DENY_NONE
:
289 io2
->generic
.in
.share_access
=
290 NTCREATEX_SHARE_ACCESS_READ
|
291 NTCREATEX_SHARE_ACCESS_WRITE
;
293 case OPENX_MODE_DENY_DOS
:
294 /* DENY_DOS is quite strange - it depends on the filename! */
295 io2
->generic
.in
.create_options
|=
296 NTCREATEX_OPTIONS_PRIVATE_DENY_DOS
;
297 if (is_exe_filename(fname
)) {
298 io2
->generic
.in
.share_access
=
299 NTCREATEX_SHARE_ACCESS_READ
|
300 NTCREATEX_SHARE_ACCESS_WRITE
;
302 if ((open_mode
& OPENX_MODE_ACCESS_MASK
) == OPENX_MODE_ACCESS_READ
) {
303 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
;
305 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
309 case OPENX_MODE_DENY_FCB
:
310 io2
->generic
.in
.create_options
|= NTCREATEX_OPTIONS_PRIVATE_DENY_FCB
;
311 io2
->generic
.in
.share_access
= NTCREATEX_SHARE_ACCESS_NONE
;
314 return NT_STATUS_INVALID_LOCK_SEQUENCE
;
318 case (OPENX_OPEN_FUNC_OPEN
):
319 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
321 case (OPENX_OPEN_FUNC_TRUNC
):
322 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE
;
324 case (OPENX_OPEN_FUNC_FAIL
| OPENX_OPEN_FUNC_CREATE
):
325 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
327 case (OPENX_OPEN_FUNC_OPEN
| OPENX_OPEN_FUNC_CREATE
):
328 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
330 case (OPENX_OPEN_FUNC_TRUNC
| OPENX_OPEN_FUNC_CREATE
):
331 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OVERWRITE_IF
;
334 /* this one is very strange */
335 if ((open_mode
& OPENX_MODE_ACCESS_MASK
) == OPENX_MODE_ACCESS_EXEC
) {
336 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
339 return NT_STATUS_INVALID_LOCK_SEQUENCE
;
346 NTVFS open generic to any mapper
348 NTSTATUS
ntvfs_map_open(struct smbsrv_request
*req
, union smb_open
*io
,
349 struct ntvfs_module_context
*ntvfs
)
354 io2
= talloc_zero_p(req
, union smb_open
);
356 return NT_STATUS_NO_MEMORY
;
359 status
= ntvfs_map_async_setup(req
, ntvfs
, io
, io2
,
360 (second_stage_t
)ntvfs_map_open_finish
);
361 if (!NT_STATUS_IS_OK(status
)) {
365 io2
->generic
.level
= RAW_OPEN_GENERIC
;
367 switch (io
->generic
.level
) {
369 status
= map_openx_open(io
->openx
.in
.flags
,
370 io
->openx
.in
.open_mode
,
371 io
->openx
.in
.open_func
,
374 if (!NT_STATUS_IS_OK(status
)) {
378 io2
->generic
.in
.file_attr
= io
->openx
.in
.file_attrs
;
379 io2
->generic
.in
.fname
= io
->openx
.in
.fname
;
381 status
= ntvfs
->ops
->openfile(ntvfs
, req
, io2
);
386 status
= map_openx_open(0,
387 io
->openold
.in
.open_mode
,
388 OPENX_OPEN_FUNC_OPEN
,
389 io
->openold
.in
.fname
,
391 if (!NT_STATUS_IS_OK(status
)) {
395 io2
->generic
.in
.file_attr
= io
->openold
.in
.search_attrs
;
396 io2
->generic
.in
.fname
= io
->openold
.in
.fname
;
398 status
= ntvfs
->ops
->openfile(ntvfs
, req
, io2
);
401 case RAW_OPEN_T2OPEN
:
402 io2
->generic
.level
= RAW_OPEN_NTTRANS_CREATE
;
404 if (io
->t2open
.in
.open_func
== 0) {
405 status
= NT_STATUS_OBJECT_NAME_COLLISION
;
409 status
= map_openx_open(io
->t2open
.in
.flags
,
410 io
->t2open
.in
.open_mode
,
411 io
->t2open
.in
.open_func
,
414 if (!NT_STATUS_IS_OK(status
)) {
418 io2
->generic
.in
.file_attr
= io
->t2open
.in
.file_attrs
;
419 io2
->generic
.in
.fname
= io
->t2open
.in
.fname
;
420 io2
->generic
.in
.ea_list
= talloc_p(io2
, struct smb_ea_list
);
421 io2
->generic
.in
.ea_list
->num_eas
= io
->t2open
.in
.num_eas
;
422 io2
->generic
.in
.ea_list
->eas
= io
->t2open
.in
.eas
;
424 status
= ntvfs
->ops
->openfile(ntvfs
, req
, io2
);
428 io2
->generic
.in
.file_attr
= io
->mknew
.in
.attrib
;
429 io2
->generic
.in
.fname
= io
->mknew
.in
.fname
;
430 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
431 io2
->generic
.in
.access_mask
=
432 SEC_RIGHTS_FILE_READ
|
433 SEC_RIGHTS_FILE_WRITE
;
434 io2
->generic
.in
.share_access
=
435 NTCREATEX_SHARE_ACCESS_READ
|
436 NTCREATEX_SHARE_ACCESS_WRITE
;
437 status
= ntvfs
->ops
->openfile(ntvfs
, req
, io2
);
440 case RAW_OPEN_CREATE
:
441 io2
->generic
.in
.file_attr
= io
->mknew
.in
.attrib
;
442 io2
->generic
.in
.fname
= io
->mknew
.in
.fname
;
443 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
444 io2
->generic
.in
.access_mask
=
445 SEC_RIGHTS_FILE_READ
|
446 SEC_RIGHTS_FILE_WRITE
;
447 io2
->generic
.in
.share_access
=
448 NTCREATEX_SHARE_ACCESS_READ
|
449 NTCREATEX_SHARE_ACCESS_WRITE
;
450 status
= ntvfs
->ops
->openfile(ntvfs
, req
, io2
);
454 io2
->generic
.in
.file_attr
= io
->ctemp
.in
.attrib
;
455 io2
->generic
.in
.file_attr
= 0;
456 io2
->generic
.in
.fname
=
457 talloc_asprintf(io2
, "%s\\SRV%s",
458 io
->ctemp
.in
.directory
,
459 generate_random_str_list(io2
, 5, "0123456789"));
460 io2
->generic
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
461 io2
->generic
.in
.access_mask
=
462 SEC_RIGHTS_FILE_READ
|
463 SEC_RIGHTS_FILE_WRITE
;
464 io2
->generic
.in
.share_access
=
465 NTCREATEX_SHARE_ACCESS_READ
|
466 NTCREATEX_SHARE_ACCESS_WRITE
;
467 status
= ntvfs
->ops
->openfile(ntvfs
, req
, io2
);
471 status
= NT_STATUS_INVALID_LEVEL
;
475 return ntvfs_map_async_finish(req
, status
);
480 NTVFS fsinfo generic to any mapper
482 NTSTATUS
ntvfs_map_fsinfo(struct smbsrv_request
*req
, union smb_fsinfo
*fs
,
483 struct ntvfs_module_context
*ntvfs
)
486 union smb_fsinfo
*fs2
;
488 fs2
= talloc_p(req
, union smb_fsinfo
);
490 return NT_STATUS_NO_MEMORY
;
493 if (fs
->generic
.level
== RAW_QFS_GENERIC
) {
494 return NT_STATUS_INVALID_LEVEL
;
497 /* this map function is only used by the simple backend, which
499 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
501 /* ask the backend for the generic info */
502 fs2
->generic
.level
= RAW_QFS_GENERIC
;
504 status
= ntvfs
->ops
->fsinfo(ntvfs
, req
, fs2
);
505 if (!NT_STATUS_IS_OK(status
)) {
509 /* and convert it to the required level */
510 switch (fs
->generic
.level
) {
511 case RAW_QFS_GENERIC
:
512 return NT_STATUS_INVALID_LEVEL
;
514 case RAW_QFS_DSKATTR
: {
515 /* map from generic to DSKATTR */
518 /* we need to scale the sizes to fit */
519 for (bpunit
=64; bpunit
<0x10000; bpunit
*= 2) {
520 if (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
< bpunit
* 512 * 65535.0) {
525 fs
->dskattr
.out
.blocks_per_unit
= bpunit
;
526 fs
->dskattr
.out
.block_size
= 512;
527 fs
->dskattr
.out
.units_total
=
528 (fs2
->generic
.out
.blocks_total
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
529 fs
->dskattr
.out
.units_free
=
530 (fs2
->generic
.out
.blocks_free
* (double)fs2
->generic
.out
.block_size
) / (bpunit
* 512);
532 /* we must return a maximum of 2G to old DOS systems, or they get very confused */
533 if (bpunit
> 64 && req
->smb_conn
->negotiate
.protocol
<= PROTOCOL_LANMAN2
) {
534 fs
->dskattr
.out
.blocks_per_unit
= 64;
535 fs
->dskattr
.out
.units_total
= 0xFFFF;
536 fs
->dskattr
.out
.units_free
= 0xFFFF;
541 case RAW_QFS_ALLOCATION
:
542 fs
->allocation
.out
.fs_id
= fs2
->generic
.out
.fs_id
;
543 fs
->allocation
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
544 fs
->allocation
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
545 fs
->allocation
.out
.sectors_per_unit
= 1;
546 fs
->allocation
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
550 fs
->volume
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
551 fs
->volume
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
554 case RAW_QFS_VOLUME_INFO
:
555 case RAW_QFS_VOLUME_INFORMATION
:
556 fs
->volume_info
.out
.create_time
= fs2
->generic
.out
.create_time
;
557 fs
->volume_info
.out
.serial_number
= fs2
->generic
.out
.serial_number
;
558 fs
->volume_info
.out
.volume_name
.s
= fs2
->generic
.out
.volume_name
;
561 case RAW_QFS_SIZE_INFO
:
562 case RAW_QFS_SIZE_INFORMATION
:
563 fs
->size_info
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
564 fs
->size_info
.out
.avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
565 fs
->size_info
.out
.sectors_per_unit
= 1;
566 fs
->size_info
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
569 case RAW_QFS_DEVICE_INFO
:
570 case RAW_QFS_DEVICE_INFORMATION
:
571 fs
->device_info
.out
.device_type
= fs2
->generic
.out
.device_type
;
572 fs
->device_info
.out
.characteristics
= fs2
->generic
.out
.device_characteristics
;
575 case RAW_QFS_ATTRIBUTE_INFO
:
576 case RAW_QFS_ATTRIBUTE_INFORMATION
:
577 fs
->attribute_info
.out
.fs_attr
= fs2
->generic
.out
.fs_attr
;
578 fs
->attribute_info
.out
.max_file_component_length
= fs2
->generic
.out
.max_file_component_length
;
579 fs
->attribute_info
.out
.fs_type
.s
= fs2
->generic
.out
.fs_type
;
582 case RAW_QFS_QUOTA_INFORMATION
:
583 ZERO_STRUCT(fs
->quota_information
.out
.unknown
);
584 fs
->quota_information
.out
.quota_soft
= fs2
->generic
.out
.quota_soft
;
585 fs
->quota_information
.out
.quota_hard
= fs2
->generic
.out
.quota_hard
;
586 fs
->quota_information
.out
.quota_flags
= fs2
->generic
.out
.quota_flags
;
589 case RAW_QFS_FULL_SIZE_INFORMATION
:
590 fs
->full_size_information
.out
.total_alloc_units
= fs2
->generic
.out
.blocks_total
;
591 fs
->full_size_information
.out
.call_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
592 fs
->full_size_information
.out
.actual_avail_alloc_units
= fs2
->generic
.out
.blocks_free
;
593 fs
->full_size_information
.out
.sectors_per_unit
= 1;
594 fs
->full_size_information
.out
.bytes_per_sector
= fs2
->generic
.out
.block_size
;
597 case RAW_QFS_OBJECTID_INFORMATION
:
598 fs
->objectid_information
.out
.guid
= fs2
->generic
.out
.guid
;
599 ZERO_STRUCT(fs
->objectid_information
.out
.unknown
);
604 return NT_STATUS_INVALID_LEVEL
;
609 NTVFS fileinfo generic to any mapper
611 NTSTATUS
ntvfs_map_fileinfo(struct smbsrv_request
*req
, union smb_fileinfo
*info
,
612 union smb_fileinfo
*info2
)
615 /* and convert it to the required level using results in info2 */
616 switch (info
->generic
.level
) {
617 case RAW_FILEINFO_GENERIC
:
618 return NT_STATUS_INVALID_LEVEL
;
619 case RAW_FILEINFO_GETATTR
:
620 info
->getattr
.out
.attrib
= info2
->generic
.out
.attrib
& 0xff;
621 info
->getattr
.out
.size
= info2
->generic
.out
.size
;
622 info
->getattr
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
625 case RAW_FILEINFO_GETATTRE
:
626 info
->getattre
.out
.attrib
= info2
->generic
.out
.attrib
;
627 info
->getattre
.out
.size
= info2
->generic
.out
.size
;
628 info
->getattre
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
629 info
->getattre
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
630 info
->getattre
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
631 info
->getattre
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
634 case RAW_FILEINFO_NETWORK_OPEN_INFORMATION
:
635 info
->network_open_information
.out
.create_time
= info2
->generic
.out
.create_time
;
636 info
->network_open_information
.out
.access_time
= info2
->generic
.out
.access_time
;
637 info
->network_open_information
.out
.write_time
= info2
->generic
.out
.write_time
;
638 info
->network_open_information
.out
.change_time
= info2
->generic
.out
.change_time
;
639 info
->network_open_information
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
640 info
->network_open_information
.out
.size
= info2
->generic
.out
.size
;
641 info
->network_open_information
.out
.attrib
= info2
->generic
.out
.attrib
;
644 case RAW_FILEINFO_ALL_INFO
:
645 case RAW_FILEINFO_ALL_INFORMATION
:
646 info
->all_info
.out
.create_time
= info2
->generic
.out
.create_time
;
647 info
->all_info
.out
.access_time
= info2
->generic
.out
.access_time
;
648 info
->all_info
.out
.write_time
= info2
->generic
.out
.write_time
;
649 info
->all_info
.out
.change_time
= info2
->generic
.out
.change_time
;
650 info
->all_info
.out
.attrib
= info2
->generic
.out
.attrib
;
651 info
->all_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
652 info
->all_info
.out
.size
= info2
->generic
.out
.size
;
653 info
->all_info
.out
.nlink
= info2
->generic
.out
.nlink
;
654 info
->all_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
655 info
->all_info
.out
.directory
= info2
->generic
.out
.directory
;
656 info
->all_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
657 info
->all_info
.out
.fname
.s
= info2
->generic
.out
.fname
.s
;
658 info
->all_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
661 case RAW_FILEINFO_BASIC_INFO
:
662 case RAW_FILEINFO_BASIC_INFORMATION
:
663 info
->basic_info
.out
.create_time
= info2
->generic
.out
.create_time
;
664 info
->basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
665 info
->basic_info
.out
.write_time
= info2
->generic
.out
.write_time
;
666 info
->basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
667 info
->basic_info
.out
.attrib
= info2
->generic
.out
.attrib
;
670 case RAW_FILEINFO_STANDARD
:
671 info
->standard
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
672 info
->standard
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
673 info
->standard
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
674 info
->standard
.out
.size
= info2
->generic
.out
.size
;
675 info
->standard
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
676 info
->standard
.out
.attrib
= info2
->generic
.out
.attrib
;
679 case RAW_FILEINFO_EA_SIZE
:
680 info
->ea_size
.out
.create_time
= nt_time_to_unix(info2
->generic
.out
.create_time
);
681 info
->ea_size
.out
.access_time
= nt_time_to_unix(info2
->generic
.out
.access_time
);
682 info
->ea_size
.out
.write_time
= nt_time_to_unix(info2
->generic
.out
.write_time
);
683 info
->ea_size
.out
.size
= info2
->generic
.out
.size
;
684 info
->ea_size
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
685 info
->ea_size
.out
.attrib
= info2
->generic
.out
.attrib
;
686 info
->ea_size
.out
.ea_size
= info2
->generic
.out
.ea_size
;
689 case RAW_FILEINFO_STANDARD_INFO
:
690 case RAW_FILEINFO_STANDARD_INFORMATION
:
691 info
->standard_info
.out
.alloc_size
= info2
->generic
.out
.alloc_size
;
692 info
->standard_info
.out
.size
= info2
->generic
.out
.size
;
693 info
->standard_info
.out
.nlink
= info2
->generic
.out
.nlink
;
694 info
->standard_info
.out
.delete_pending
= info2
->generic
.out
.delete_pending
;
695 info
->standard_info
.out
.directory
= info2
->generic
.out
.directory
;
698 case RAW_FILEINFO_INTERNAL_INFORMATION
:
699 info
->internal_information
.out
.file_id
= info2
->generic
.out
.file_id
;
702 case RAW_FILEINFO_EA_INFO
:
703 case RAW_FILEINFO_EA_INFORMATION
:
704 info
->ea_info
.out
.ea_size
= info2
->generic
.out
.ea_size
;
707 case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION
:
708 info
->attribute_tag_information
.out
.attrib
= info2
->generic
.out
.attrib
;
709 info
->attribute_tag_information
.out
.reparse_tag
= info2
->generic
.out
.reparse_tag
;
712 case RAW_FILEINFO_STREAM_INFO
:
713 case RAW_FILEINFO_STREAM_INFORMATION
:
714 info
->stream_info
.out
.num_streams
= info2
->generic
.out
.num_streams
;
715 if (info
->stream_info
.out
.num_streams
> 0) {
716 info
->stream_info
.out
.streams
=
718 struct stream_struct
,
719 info
->stream_info
.out
.num_streams
);
720 if (!info
->stream_info
.out
.streams
) {
721 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
722 info
->stream_info
.out
.num_streams
));
723 return NT_STATUS_NO_MEMORY
;
725 for (i
=0; i
< info
->stream_info
.out
.num_streams
; i
++) {
726 info
->stream_info
.out
.streams
[i
] = info2
->generic
.out
.streams
[i
];
727 info
->stream_info
.out
.streams
[i
].stream_name
.s
=
728 talloc_strdup(req
, info2
->generic
.out
.streams
[i
].stream_name
.s
);
729 if (!info
->stream_info
.out
.streams
[i
].stream_name
.s
) {
730 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
731 return NT_STATUS_NO_MEMORY
;
737 case RAW_FILEINFO_NAME_INFO
:
738 case RAW_FILEINFO_NAME_INFORMATION
:
739 info
->name_info
.out
.fname
.s
= talloc_strdup(req
, info2
->generic
.out
.fname
.s
);
740 info
->name_info
.out
.fname
.private_length
= info2
->generic
.out
.fname
.private_length
;
743 case RAW_FILEINFO_ALT_NAME_INFO
:
744 case RAW_FILEINFO_ALT_NAME_INFORMATION
:
745 info
->alt_name_info
.out
.fname
.s
= talloc_strdup(req
, info2
->generic
.out
.alt_fname
.s
);
746 info
->alt_name_info
.out
.fname
.private_length
= info2
->generic
.out
.alt_fname
.private_length
;
749 case RAW_FILEINFO_POSITION_INFORMATION
:
750 info
->position_information
.out
.position
= info2
->generic
.out
.position
;
753 case RAW_FILEINFO_ALL_EAS
:
754 info
->all_eas
.out
.num_eas
= info2
->generic
.out
.num_eas
;
755 if (info
->all_eas
.out
.num_eas
> 0) {
756 info
->all_eas
.out
.eas
= talloc_array_p(req
,
758 info
->all_eas
.out
.num_eas
);
759 if (!info
->all_eas
.out
.eas
) {
760 DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
761 info
->all_eas
.out
.num_eas
));
762 return NT_STATUS_NO_MEMORY
;
764 for (i
= 0; i
< info
->all_eas
.out
.num_eas
; i
++) {
765 info
->all_eas
.out
.eas
[i
] = info2
->generic
.out
.eas
[i
];
766 info
->all_eas
.out
.eas
[i
].name
.s
=
767 talloc_strdup(req
, info2
->generic
.out
.eas
[i
].name
.s
);
768 if (!info
->all_eas
.out
.eas
[i
].name
.s
) {
769 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
770 return NT_STATUS_NO_MEMORY
;
772 info
->all_eas
.out
.eas
[i
].value
.data
=
774 info2
->generic
.out
.eas
[i
].value
.data
,
775 info2
->generic
.out
.eas
[i
].value
.length
);
776 if (!info
->all_eas
.out
.eas
[i
].value
.data
) {
777 DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
778 return NT_STATUS_NO_MEMORY
;
784 case RAW_FILEINFO_IS_NAME_VALID
:
787 case RAW_FILEINFO_COMPRESSION_INFO
:
788 case RAW_FILEINFO_COMPRESSION_INFORMATION
:
789 info
->compression_info
.out
.compressed_size
= info2
->generic
.out
.compressed_size
;
790 info
->compression_info
.out
.format
= info2
->generic
.out
.format
;
791 info
->compression_info
.out
.unit_shift
= info2
->generic
.out
.unit_shift
;
792 info
->compression_info
.out
.chunk_shift
= info2
->generic
.out
.chunk_shift
;
793 info
->compression_info
.out
.cluster_shift
= info2
->generic
.out
.cluster_shift
;
796 case RAW_FILEINFO_ACCESS_INFORMATION
:
797 info
->access_information
.out
.access_flags
= info2
->generic
.out
.access_flags
;
800 case RAW_FILEINFO_MODE_INFORMATION
:
801 info
->mode_information
.out
.mode
= info2
->generic
.out
.mode
;
804 case RAW_FILEINFO_ALIGNMENT_INFORMATION
:
805 info
->alignment_information
.out
.alignment_requirement
=
806 info2
->generic
.out
.alignment_requirement
;
809 case RAW_FILEINFO_UNIX_BASIC
:
810 info
->unix_basic_info
.out
.end_of_file
= info2
->generic
.out
.end_of_file
;
811 info
->unix_basic_info
.out
.num_bytes
= info2
->generic
.out
.size
;
812 info
->unix_basic_info
.out
.status_change_time
= info2
->generic
.out
.change_time
;
813 info
->unix_basic_info
.out
.access_time
= info2
->generic
.out
.access_time
;
814 info
->unix_basic_info
.out
.change_time
= info2
->generic
.out
.change_time
;
815 info
->unix_basic_info
.out
.uid
= info2
->generic
.out
.uid
;
816 info
->unix_basic_info
.out
.gid
= info2
->generic
.out
.gid
;
817 info
->unix_basic_info
.out
.file_type
= info2
->generic
.out
.file_type
;
818 info
->unix_basic_info
.out
.dev_major
= info2
->generic
.out
.device
;
819 info
->unix_basic_info
.out
.dev_minor
= info2
->generic
.out
.device
;
820 info
->unix_basic_info
.out
.unique_id
= info2
->generic
.out
.inode
;
821 info
->unix_basic_info
.out
.permissions
= info2
->generic
.out
.permissions
;
822 info
->unix_basic_info
.out
.nlink
= info2
->generic
.out
.nlink
;
825 case RAW_FILEINFO_UNIX_LINK
:
826 info
->unix_link_info
.out
.link_dest
= info2
->generic
.out
.link_dest
;
831 return NT_STATUS_INVALID_LEVEL
;
835 NTVFS fileinfo generic to any mapper
837 NTSTATUS
ntvfs_map_qfileinfo(struct smbsrv_request
*req
, union smb_fileinfo
*info
,
838 struct ntvfs_module_context
*ntvfs
)
841 union smb_fileinfo
*info2
;
843 info2
= talloc_p(req
, union smb_fileinfo
);
845 return NT_STATUS_NO_MEMORY
;
848 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
849 return NT_STATUS_INVALID_LEVEL
;
852 /* ask the backend for the generic info */
853 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
854 info2
->generic
.in
.fnum
= info
->generic
.in
.fnum
;
856 status
= ntvfs
->ops
->qfileinfo(ntvfs
, req
, info2
);
857 if (!NT_STATUS_IS_OK(status
)) {
860 return ntvfs_map_fileinfo(req
, info
, info2
);
864 NTVFS pathinfo generic to any mapper
866 NTSTATUS
ntvfs_map_qpathinfo(struct smbsrv_request
*req
, union smb_fileinfo
*info
,
867 struct ntvfs_module_context
*ntvfs
)
870 union smb_fileinfo
*info2
;
872 info2
= talloc_p(req
, union smb_fileinfo
);
874 return NT_STATUS_NO_MEMORY
;
877 if (info
->generic
.level
== RAW_FILEINFO_GENERIC
) {
878 return NT_STATUS_INVALID_LEVEL
;
881 /* ask the backend for the generic info */
882 info2
->generic
.level
= RAW_FILEINFO_GENERIC
;
883 info2
->generic
.in
.fname
= info
->generic
.in
.fname
;
885 /* only used by the simple backend, which doesn't do async */
886 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
888 status
= ntvfs
->ops
->qpathinfo(ntvfs
, req
, info2
);
889 if (!NT_STATUS_IS_OK(status
)) {
892 return ntvfs_map_fileinfo(req
, info
, info2
);
897 NTVFS lock generic to any mapper
899 NTSTATUS
ntvfs_map_lock(struct smbsrv_request
*req
, union smb_lock
*lck
,
900 struct ntvfs_module_context
*ntvfs
)
902 union smb_lock
*lck2
;
903 struct smb_lock_entry
*locks
;
905 lck2
= talloc_p(req
, union smb_lock
);
907 return NT_STATUS_NO_MEMORY
;
910 locks
= talloc_array_p(lck2
, struct smb_lock_entry
, 1);
912 return NT_STATUS_NO_MEMORY
;
915 switch (lck
->generic
.level
) {
917 return NT_STATUS_INVALID_LEVEL
;
920 lck2
->generic
.in
.ulock_cnt
= 0;
921 lck2
->generic
.in
.lock_cnt
= 1;
924 case RAW_LOCK_UNLOCK
:
925 lck2
->generic
.in
.ulock_cnt
= 1;
926 lck2
->generic
.in
.lock_cnt
= 0;
930 lck2
->generic
.level
= RAW_LOCK_GENERIC
;
931 lck2
->generic
.in
.fnum
= lck
->lock
.in
.fnum
;
932 lck2
->generic
.in
.mode
= 0;
933 lck2
->generic
.in
.timeout
= 0;
934 lck2
->generic
.in
.locks
= locks
;
935 locks
->pid
= req
->smbpid
;
936 locks
->offset
= lck
->lock
.in
.offset
;
937 locks
->count
= lck
->lock
.in
.count
;
939 return ntvfs
->ops
->lock(ntvfs
, req
, lck2
);
944 NTVFS write generic to any mapper
946 static NTSTATUS
ntvfs_map_write_finish(struct smbsrv_request
*req
,
947 struct ntvfs_module_context
*ntvfs
,
949 union smb_write
*wr2
,
957 if (NT_STATUS_IS_ERR(status
)) {
961 switch (wr
->generic
.level
) {
962 case RAW_WRITE_WRITE
:
963 wr
->write
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
966 case RAW_WRITE_WRITEUNLOCK
:
967 wr
->writeunlock
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
969 lck
= talloc_p(wr2
, union smb_lock
);
971 return NT_STATUS_NO_MEMORY
;
974 lck
->unlock
.level
= RAW_LOCK_UNLOCK
;
975 lck
->unlock
.in
.fnum
= wr
->writeunlock
.in
.fnum
;
976 lck
->unlock
.in
.count
= wr
->writeunlock
.in
.count
;
977 lck
->unlock
.in
.offset
= wr
->writeunlock
.in
.offset
;
979 if (lck
->unlock
.in
.count
!= 0) {
980 /* do the lock sync for now */
981 state
= req
->async_states
->state
;
982 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
983 status
= ntvfs
->ops
->lock(ntvfs
, req
, lck
);
984 req
->async_states
->state
= state
;
988 case RAW_WRITE_WRITECLOSE
:
989 wr
->writeclose
.out
.nwritten
= wr2
->generic
.out
.nwritten
;
991 cl
= talloc_p(wr2
, union smb_close
);
993 return NT_STATUS_NO_MEMORY
;
996 cl
->close
.level
= RAW_CLOSE_CLOSE
;
997 cl
->close
.in
.fnum
= wr
->writeclose
.in
.fnum
;
998 cl
->close
.in
.write_time
= wr
->writeclose
.in
.mtime
;
1000 if (wr2
->generic
.in
.count
!= 0) {
1001 /* do the close sync for now */
1002 state
= req
->async_states
->state
;
1003 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1004 status
= ntvfs
->ops
->close(ntvfs
, req
, cl
);
1005 req
->async_states
->state
= state
;
1009 case RAW_WRITE_SPLWRITE
:
1012 return NT_STATUS_INVALID_LEVEL
;
1020 NTVFS write generic to any mapper
1022 NTSTATUS
ntvfs_map_write(struct smbsrv_request
*req
, union smb_write
*wr
,
1023 struct ntvfs_module_context
*ntvfs
)
1025 union smb_write
*wr2
;
1028 wr2
= talloc_p(req
, union smb_write
);
1030 return NT_STATUS_NO_MEMORY
;
1033 status
= ntvfs_map_async_setup(req
, ntvfs
, wr
, wr2
,
1034 (second_stage_t
)ntvfs_map_write_finish
);
1035 if (!NT_STATUS_IS_OK(status
)) {
1039 wr2
->writex
.level
= RAW_WRITE_GENERIC
;
1041 switch (wr
->generic
.level
) {
1042 case RAW_WRITE_WRITEX
:
1043 status
= NT_STATUS_INVALID_LEVEL
;
1046 case RAW_WRITE_WRITE
:
1047 wr2
->writex
.in
.fnum
= wr
->write
.in
.fnum
;
1048 wr2
->writex
.in
.offset
= wr
->write
.in
.offset
;
1049 wr2
->writex
.in
.wmode
= 0;
1050 wr2
->writex
.in
.remaining
= wr
->write
.in
.remaining
;
1051 wr2
->writex
.in
.count
= wr
->write
.in
.count
;
1052 wr2
->writex
.in
.data
= wr
->write
.in
.data
;
1053 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1056 case RAW_WRITE_WRITEUNLOCK
:
1057 wr2
->writex
.in
.fnum
= wr
->writeunlock
.in
.fnum
;
1058 wr2
->writex
.in
.offset
= wr
->writeunlock
.in
.offset
;
1059 wr2
->writex
.in
.wmode
= 0;
1060 wr2
->writex
.in
.remaining
= wr
->writeunlock
.in
.remaining
;
1061 wr2
->writex
.in
.count
= wr
->writeunlock
.in
.count
;
1062 wr2
->writex
.in
.data
= wr
->writeunlock
.in
.data
;
1063 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1066 case RAW_WRITE_WRITECLOSE
:
1067 wr2
->writex
.in
.fnum
= wr
->writeclose
.in
.fnum
;
1068 wr2
->writex
.in
.offset
= wr
->writeclose
.in
.offset
;
1069 wr2
->writex
.in
.wmode
= 0;
1070 wr2
->writex
.in
.remaining
= 0;
1071 wr2
->writex
.in
.count
= wr
->writeclose
.in
.count
;
1072 wr2
->writex
.in
.data
= wr
->writeclose
.in
.data
;
1073 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1076 case RAW_WRITE_SPLWRITE
:
1077 wr2
->writex
.in
.fnum
= wr
->splwrite
.in
.fnum
;
1078 wr2
->writex
.in
.offset
= 0;
1079 wr2
->writex
.in
.wmode
= 0;
1080 wr2
->writex
.in
.remaining
= 0;
1081 wr2
->writex
.in
.count
= wr
->splwrite
.in
.count
;
1082 wr2
->writex
.in
.data
= wr
->splwrite
.in
.data
;
1083 status
= ntvfs
->ops
->write(ntvfs
, req
, wr2
);
1087 return ntvfs_map_async_finish(req
, status
);
1092 NTVFS read generic to any mapper - finish the out mapping
1094 static NTSTATUS
ntvfs_map_read_finish(struct smbsrv_request
*req
,
1095 struct ntvfs_module_context
*ntvfs
,
1097 union smb_read
*rd2
,
1100 switch (rd
->generic
.level
) {
1102 rd
->read
.out
.nread
= rd2
->generic
.out
.nread
;
1104 case RAW_READ_READBRAW
:
1105 rd
->readbraw
.out
.nread
= rd2
->generic
.out
.nread
;
1107 case RAW_READ_LOCKREAD
:
1108 rd
->lockread
.out
.nread
= rd2
->generic
.out
.nread
;
1111 return NT_STATUS_INVALID_LEVEL
;
1118 NTVFS read* to readx mapper
1120 NTSTATUS
ntvfs_map_read(struct smbsrv_request
*req
, union smb_read
*rd
,
1121 struct ntvfs_module_context
*ntvfs
)
1123 union smb_read
*rd2
;
1124 union smb_lock
*lck
;
1128 rd2
= talloc_p(req
, union smb_read
);
1130 return NT_STATUS_NO_MEMORY
;
1133 status
= ntvfs_map_async_setup(req
, ntvfs
, rd
, rd2
,
1134 (second_stage_t
)ntvfs_map_read_finish
);
1135 if (!NT_STATUS_IS_OK(status
)) {
1139 rd2
->readx
.level
= RAW_READ_READX
;
1141 switch (rd
->generic
.level
) {
1142 case RAW_READ_READX
:
1143 status
= NT_STATUS_INVALID_LEVEL
;
1147 rd2
->readx
.in
.fnum
= rd
->read
.in
.fnum
;
1148 rd2
->readx
.in
.offset
= rd
->read
.in
.offset
;
1149 rd2
->readx
.in
.mincnt
= rd
->read
.in
.count
;
1150 rd2
->readx
.in
.maxcnt
= rd
->read
.in
.count
;
1151 rd2
->readx
.in
.remaining
= rd
->read
.in
.remaining
;
1152 rd2
->readx
.out
.data
= rd
->read
.out
.data
;
1153 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1156 case RAW_READ_READBRAW
:
1157 rd2
->readx
.in
.fnum
= rd
->readbraw
.in
.fnum
;
1158 rd2
->readx
.in
.offset
= rd
->readbraw
.in
.offset
;
1159 rd2
->readx
.in
.mincnt
= rd
->readbraw
.in
.mincnt
;
1160 rd2
->readx
.in
.maxcnt
= rd
->readbraw
.in
.maxcnt
;
1161 rd2
->readx
.in
.remaining
= 0;
1162 rd2
->readx
.out
.data
= rd
->readbraw
.out
.data
;
1163 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1166 case RAW_READ_LOCKREAD
:
1167 /* do the initial lock sync for now */
1168 state
= req
->async_states
->state
;
1169 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_MAY_ASYNC
;
1171 lck
= talloc_p(rd2
, union smb_lock
);
1173 status
= NT_STATUS_NO_MEMORY
;
1176 lck
->lock
.level
= RAW_LOCK_LOCK
;
1177 lck
->lock
.in
.fnum
= rd
->lockread
.in
.fnum
;
1178 lck
->lock
.in
.count
= rd
->lockread
.in
.count
;
1179 lck
->lock
.in
.offset
= rd
->lockread
.in
.offset
;
1180 status
= ntvfs
->ops
->lock(ntvfs
, req
, lck
);
1181 req
->async_states
->state
= state
;
1183 rd2
->readx
.in
.fnum
= rd
->lockread
.in
.fnum
;
1184 rd2
->readx
.in
.offset
= rd
->lockread
.in
.offset
;
1185 rd2
->readx
.in
.mincnt
= rd
->lockread
.in
.count
;
1186 rd2
->readx
.in
.maxcnt
= rd
->lockread
.in
.count
;
1187 rd2
->readx
.in
.remaining
= rd
->lockread
.in
.remaining
;
1188 rd2
->readx
.out
.data
= rd
->lockread
.out
.data
;
1190 if (NT_STATUS_IS_OK(status
)) {
1191 status
= ntvfs
->ops
->read(ntvfs
, req
, rd2
);
1197 return ntvfs_map_async_finish(req
, status
);
1202 NTVFS close generic to any mapper
1204 NTSTATUS
ntvfs_map_close(struct smbsrv_request
*req
, union smb_close
*cl
,
1205 struct ntvfs_module_context
*ntvfs
)
1207 union smb_close
*cl2
;
1209 cl2
= talloc_p(req
, union smb_close
);
1211 return NT_STATUS_NO_MEMORY
;
1214 switch (cl
->generic
.level
) {
1215 case RAW_CLOSE_CLOSE
:
1216 return NT_STATUS_INVALID_LEVEL
;
1218 case RAW_CLOSE_SPLCLOSE
:
1219 cl2
->close
.level
= RAW_CLOSE_CLOSE
;
1220 cl2
->close
.in
.fnum
= cl
->splclose
.in
.fnum
;
1224 return ntvfs
->ops
->close(ntvfs
, req
, cl2
);