2 Unix SMB/CIFS implementation.
4 CIFS-to-SMB2 NTVFS filesystem backend
6 Copyright (C) Andrew Tridgell 2008
8 largely based on vfs_cifs.c which was
9 Copyright (C) Andrew Tridgell 2003
10 Copyright (C) James J Myers 2003 <myersjj@samba.org>
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 this implements a CIFS->CIFS NTVFS filesystem backend.
31 #include "libcli/raw/libcliraw.h"
32 #include "libcli/raw/raw_proto.h"
33 #include "libcli/composite/composite.h"
34 #include "libcli/smb_composite/smb_composite.h"
35 #include "auth/auth.h"
36 #include "auth/credentials/credentials.h"
37 #include "ntvfs/ntvfs.h"
38 #include "../lib/util/dlinklist.h"
39 #include "param/param.h"
40 #include "libcli/resolve/resolve.h"
41 #include "libcli/smb2/smb2.h"
42 #include "libcli/smb2/smb2_calls.h"
44 NTSTATUS
ntvfs_smb2_init(void);
47 struct cvfs_file
*prev
, *next
;
49 struct ntvfs_handle
*h
;
52 /* this is stored in ntvfs_private */
54 struct smb2_tree
*tree
;
55 struct smb2_transport
*transport
;
56 struct ntvfs_module_context
*ntvfs
;
57 struct async_info
*pending
;
58 struct cvfs_file
*files
;
60 /* a handle on the root of the share */
61 /* TODO: leaving this handle open could prevent other users
62 from opening the share with exclusive access. We probably
63 need to open it on demand */
64 struct smb2_handle roothandle
;
68 /* a structure used to pass information to an async handler */
70 struct async_info
*next
, *prev
;
71 struct cvfs_private
*cvfs
;
72 struct ntvfs_request
*req
;
74 struct composite_context
*c_comp
;
79 #define SETUP_FILE_HERE(f) do { \
80 f = ntvfs_handle_get_backend_data(io->generic.in.file.ntvfs, ntvfs); \
81 if (!f) return NT_STATUS_INVALID_HANDLE; \
82 io->generic.in.file.fnum = f->fnum; \
85 #define SETUP_FILE do { \
86 struct cvfs_file *f; \
90 #define SMB2_SERVER "smb2:server"
91 #define SMB2_USER "smb2:user"
92 #define SMB2_PASSWORD "smb2:password"
93 #define SMB2_DOMAIN "smb2:domain"
94 #define SMB2_SHARE "smb2:share"
95 #define SMB2_USE_MACHINE_ACCT "smb2:use-machine-account"
97 #define SMB2_USE_MACHINE_ACCT_DEFAULT false
100 a handler for oplock break events from the server - these need to be passed
104 static bool oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *p_private
)
106 struct cvfs_private
*p
= p_private
;
108 struct ntvfs_handle
*h
= NULL
;
111 for (f
=p
->files
; f
; f
=f
->next
) {
112 if (f
->fnum
!= fnum
) continue;
118 DEBUG(5,("vfs_smb2: ignoring oplock break level %d for fnum %d\n", level
, fnum
));
122 DEBUG(5,("vfs_smb2: sending oplock break level %d for fnum %d\n", level
, fnum
));
123 status
= ntvfs_send_oplock_break(p
->ntvfs
, h
, level
);
124 if (!NT_STATUS_IS_OK(status
)) return false;
130 return a handle to the root of the share
132 static NTSTATUS
smb2_get_roothandle(struct smb2_tree
*tree
, struct smb2_handle
*handle
)
134 struct smb2_create io
;
138 io
.in
.oplock_level
= 0;
139 io
.in
.desired_access
= SEC_STD_SYNCHRONIZE
| SEC_DIR_READ_ATTRIBUTE
| SEC_DIR_LIST
;
140 io
.in
.file_attributes
= 0;
141 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
143 NTCREATEX_SHARE_ACCESS_READ
|
144 NTCREATEX_SHARE_ACCESS_WRITE
|
145 NTCREATEX_SHARE_ACCESS_DELETE
;
146 io
.in
.create_options
= 0;
149 status
= smb2_create(tree
, tree
, &io
);
150 NT_STATUS_NOT_OK_RETURN(status
);
152 *handle
= io
.out
.file
.handle
;
158 connect to a share - used when a tree_connect operation comes in.
160 static NTSTATUS
cvfs_connect(struct ntvfs_module_context
*ntvfs
,
161 struct ntvfs_request
*req
,
162 union smb_tcon
* tcon
)
165 struct cvfs_private
*p
;
166 const char *host
, *user
, *pass
, *domain
, *remote_share
, *sharename
;
167 struct share_config
*scfg
= ntvfs
->ctx
->config
;
168 struct smb2_tree
*tree
;
169 struct cli_credentials
*credentials
;
170 bool machine_account
;
171 struct smbcli_options options
;
174 tmp_ctx
= talloc_new(req
);
175 if (tmp_ctx
== NULL
) {
176 return NT_STATUS_NO_MEMORY
;
179 switch (tcon
->generic
.level
) {
181 sharename
= tcon
->tcon
.in
.service
;
184 sharename
= tcon
->tconx
.in
.path
;
187 sharename
= tcon
->smb2
.in
.path
;
190 status
= NT_STATUS_INVALID_LEVEL
;
194 if (strncmp(sharename
, "\\\\", 2) == 0) {
195 char *str
= strchr(sharename
+2, '\\');
201 /* Here we need to determine which server to connect to.
202 * For now we use parametric options, type cifs.
204 host
= share_string_option(tmp_ctx
, scfg
, SMB2_SERVER
, NULL
);
205 user
= share_string_option(tmp_ctx
, scfg
, SMB2_USER
, NULL
);
206 pass
= share_string_option(tmp_ctx
, scfg
, SMB2_PASSWORD
, NULL
);
207 domain
= share_string_option(tmp_ctx
, scfg
, SMB2_DOMAIN
, NULL
);
208 remote_share
= share_string_option(tmp_ctx
, scfg
, SMB2_SHARE
, NULL
);
210 remote_share
= sharename
;
213 machine_account
= share_bool_option(scfg
, SMB2_USE_MACHINE_ACCT
, SMB2_USE_MACHINE_ACCT_DEFAULT
);
215 p
= talloc_zero(ntvfs
, struct cvfs_private
);
217 status
= NT_STATUS_NO_MEMORY
;
221 ntvfs
->private_data
= p
;
224 DEBUG(1,("CIFS backend: You must supply server\n"));
225 status
= NT_STATUS_INVALID_PARAMETER
;
230 DEBUG(5, ("CIFS backend: Using specified password\n"));
231 credentials
= cli_credentials_init(p
);
233 status
= NT_STATUS_NO_MEMORY
;
236 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
237 cli_credentials_set_username(credentials
, user
, CRED_SPECIFIED
);
239 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
241 cli_credentials_set_password(credentials
, pass
, CRED_SPECIFIED
);
242 } else if (machine_account
) {
243 DEBUG(5, ("CIFS backend: Using machine account\n"));
244 credentials
= cli_credentials_init(p
);
245 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
247 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
249 status
= cli_credentials_set_machine_account(credentials
, ntvfs
->ctx
->lp_ctx
);
250 if (!NT_STATUS_IS_OK(status
)) {
253 } else if (req
->session_info
->credentials
) {
254 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
255 credentials
= req
->session_info
->credentials
;
257 DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
258 status
= NT_STATUS_INVALID_PARAMETER
;
262 lpcfg_smbcli_options(ntvfs
->ctx
->lp_ctx
, &options
);
264 status
= smb2_connect(p
, host
,
265 lpcfg_parm_string_list(p
, ntvfs
->ctx
->lp_ctx
, NULL
, "smb2", "ports", NULL
),
267 lpcfg_resolve_context(ntvfs
->ctx
->lp_ctx
),
270 ntvfs
->ctx
->event_ctx
, &options
,
271 lpcfg_socket_options(ntvfs
->ctx
->lp_ctx
),
272 lpcfg_gensec_settings(p
, ntvfs
->ctx
->lp_ctx
));
273 if (!NT_STATUS_IS_OK(status
)) {
277 status
= smb2_get_roothandle(tree
, &p
->roothandle
);
278 if (!NT_STATUS_IS_OK(status
)) {
283 p
->transport
= p
->tree
->session
->transport
;
286 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
287 if (ntvfs
->ctx
->fs_type
== NULL
) {
288 status
= NT_STATUS_NO_MEMORY
;
291 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
292 if (ntvfs
->ctx
->dev_type
== NULL
) {
293 status
= NT_STATUS_NO_MEMORY
;
297 if (tcon
->generic
.level
== RAW_TCON_TCONX
) {
298 tcon
->tconx
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
299 tcon
->tconx
.out
.dev_type
= ntvfs
->ctx
->dev_type
;
302 /* we need to receive oplock break requests from the server */
303 /* TODO: enable oplocks
304 smbcli_oplock_handler(p->transport, oplock_handler, p);
307 status
= NT_STATUS_OK
;
310 TALLOC_FREE(tmp_ctx
);
315 disconnect from a share
317 static NTSTATUS
cvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
319 struct cvfs_private
*p
= ntvfs
->private_data
;
320 struct async_info
*a
, *an
;
322 /* first cleanup pending requests */
323 for (a
=p
->pending
; a
; a
= an
) {
325 talloc_free(a
->c_req
);
330 ntvfs
->private_data
= NULL
;
336 destroy an async info structure
338 static int async_info_destructor(struct async_info
*async
)
340 DLIST_REMOVE(async
->cvfs
->pending
, async
);
345 a handler for simple async SMB2 replies
346 this handler can only be used for functions that don't return any
347 parameters (those that just return a status code)
349 static void async_simple_smb2(struct smb2_request
*c_req
)
351 struct async_info
*async
= c_req
->async
.private_data
;
352 struct ntvfs_request
*req
= async
->req
;
354 smb2_request_receive(c_req
);
355 req
->async_states
->status
= smb2_request_destroy(c_req
);
357 req
->async_states
->send_fn(req
);
361 a handler for simple async composite replies
362 this handler can only be used for functions that don't return any
363 parameters (those that just return a status code)
365 static void async_simple_composite(struct composite_context
*c_req
)
367 struct async_info
*async
= c_req
->async
.private_data
;
368 struct ntvfs_request
*req
= async
->req
;
370 req
->async_states
->status
= composite_wait_free(c_req
);
372 req
->async_states
->send_fn(req
);
376 /* save some typing for the simple functions */
377 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
378 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
380 struct async_info *async; \
381 async = talloc(req, struct async_info); \
382 if (!async) return NT_STATUS_NO_MEMORY; \
387 async->c_req = c_req; \
388 DLIST_ADD(p->pending, async); \
389 c_req->async.private_data = async; \
390 talloc_set_destructor(async, async_info_destructor); \
392 c_req->async.fn = async_fn; \
393 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
394 return NT_STATUS_OK; \
397 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
399 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple_smb2)
400 #define SIMPLE_COMPOSITE_TAIL ASYNC_RECV_TAIL(NULL, async_simple_composite)
402 #define CHECK_ASYNC(req) do { \
403 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { \
404 DEBUG(0,("SMB2 proxy backend does not support sync operation at %s\n", \
406 return NT_STATUS_NOT_IMPLEMENTED; \
410 delete a file - the dirtype specifies the file types to include in the search.
411 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
414 - doesn't handle wildcards
415 - doesn't obey attrib restrictions
417 static NTSTATUS
cvfs_unlink(struct ntvfs_module_context
*ntvfs
,
418 struct ntvfs_request
*req
, union smb_unlink
*unl
)
420 struct cvfs_private
*p
= ntvfs
->private_data
;
421 struct composite_context
*c_req
;
425 c_req
= smb2_composite_unlink_send(p
->tree
, unl
);
427 SIMPLE_COMPOSITE_TAIL
;
433 static NTSTATUS
cvfs_ioctl(struct ntvfs_module_context
*ntvfs
,
434 struct ntvfs_request
*req
, union smb_ioctl
*io
)
436 return NT_STATUS_NOT_IMPLEMENTED
;
440 check if a directory exists
442 static NTSTATUS
cvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
443 struct ntvfs_request
*req
, union smb_chkpath
*cp
)
445 struct cvfs_private
*p
= ntvfs
->private_data
;
446 struct smb2_request
*c_req
;
451 /* SMB2 doesn't have a chkpath operation, and also doesn't
452 have a query path info call, so the best seems to be to do a
453 find call, using the roothandle we established at connect
456 f
.in
.file
.handle
= p
->roothandle
;
457 f
.in
.level
= SMB2_FIND_DIRECTORY_INFO
;
458 f
.in
.pattern
= cp
->chkpath
.in
.path
;
459 /* SMB2 find doesn't accept \ or the empty string - this is the best
461 if (strcmp(f
.in
.pattern
, "\\") == 0 ||
462 strcmp(f
.in
.pattern
, "") == 0) {
465 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
| SMB2_CONTINUE_FLAG_RESTART
;
466 f
.in
.max_response_size
= 0x1000;
468 c_req
= smb2_find_send(p
->tree
, &f
);
474 return info on a pathname
476 static NTSTATUS
cvfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
477 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
479 return NT_STATUS_NOT_IMPLEMENTED
;
483 query info on a open file
485 static NTSTATUS
cvfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
486 struct ntvfs_request
*req
, union smb_fileinfo
*io
)
488 return NT_STATUS_NOT_IMPLEMENTED
;
493 set info on a pathname
495 static NTSTATUS
cvfs_setpathinfo(struct ntvfs_module_context
*ntvfs
,
496 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
498 return NT_STATUS_NOT_IMPLEMENTED
;
505 static NTSTATUS
cvfs_open(struct ntvfs_module_context
*ntvfs
,
506 struct ntvfs_request
*req
, union smb_open
*io
)
508 return NT_STATUS_NOT_IMPLEMENTED
;
514 static NTSTATUS
cvfs_mkdir(struct ntvfs_module_context
*ntvfs
,
515 struct ntvfs_request
*req
, union smb_mkdir
*md
)
517 struct cvfs_private
*p
= ntvfs
->private_data
;
518 struct composite_context
*c_req
;
522 c_req
= smb2_composite_mkdir_send(p
->tree
, md
);
524 SIMPLE_COMPOSITE_TAIL
;
530 static NTSTATUS
cvfs_rmdir(struct ntvfs_module_context
*ntvfs
,
531 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
533 struct cvfs_private
*p
= ntvfs
->private_data
;
534 struct composite_context
*c_req
;
538 c_req
= smb2_composite_rmdir_send(p
->tree
, rd
);
540 SIMPLE_COMPOSITE_TAIL
;
544 rename a set of files
546 static NTSTATUS
cvfs_rename(struct ntvfs_module_context
*ntvfs
,
547 struct ntvfs_request
*req
, union smb_rename
*ren
)
549 return NT_STATUS_NOT_IMPLEMENTED
;
555 static NTSTATUS
cvfs_copy(struct ntvfs_module_context
*ntvfs
,
556 struct ntvfs_request
*req
, struct smb_copy
*cp
)
558 return NT_STATUS_NOT_SUPPORTED
;
564 static NTSTATUS
cvfs_read(struct ntvfs_module_context
*ntvfs
,
565 struct ntvfs_request
*req
, union smb_read
*io
)
567 return NT_STATUS_NOT_IMPLEMENTED
;
573 static NTSTATUS
cvfs_write(struct ntvfs_module_context
*ntvfs
,
574 struct ntvfs_request
*req
, union smb_write
*io
)
576 return NT_STATUS_NOT_IMPLEMENTED
;
582 static NTSTATUS
cvfs_seek(struct ntvfs_module_context
*ntvfs
,
583 struct ntvfs_request
*req
,
586 return NT_STATUS_NOT_IMPLEMENTED
;
592 static NTSTATUS
cvfs_flush(struct ntvfs_module_context
*ntvfs
,
593 struct ntvfs_request
*req
,
596 return NT_STATUS_NOT_IMPLEMENTED
;
602 static NTSTATUS
cvfs_close(struct ntvfs_module_context
*ntvfs
,
603 struct ntvfs_request
*req
, union smb_close
*io
)
605 return NT_STATUS_NOT_IMPLEMENTED
;
609 exit - closing files open by the pid
611 static NTSTATUS
cvfs_exit(struct ntvfs_module_context
*ntvfs
,
612 struct ntvfs_request
*req
)
614 return NT_STATUS_NOT_IMPLEMENTED
;
618 logoff - closing files open by the user
620 static NTSTATUS
cvfs_logoff(struct ntvfs_module_context
*ntvfs
,
621 struct ntvfs_request
*req
)
623 /* we can't do this right in the cifs backend .... */
628 setup for an async call - nothing to do yet
630 static NTSTATUS
cvfs_async_setup(struct ntvfs_module_context
*ntvfs
,
631 struct ntvfs_request
*req
,
640 static NTSTATUS
cvfs_cancel(struct ntvfs_module_context
*ntvfs
,
641 struct ntvfs_request
*req
)
643 return NT_STATUS_NOT_IMPLEMENTED
;
649 static NTSTATUS
cvfs_lock(struct ntvfs_module_context
*ntvfs
,
650 struct ntvfs_request
*req
, union smb_lock
*io
)
652 return NT_STATUS_NOT_IMPLEMENTED
;
656 set info on a open file
658 static NTSTATUS
cvfs_setfileinfo(struct ntvfs_module_context
*ntvfs
,
659 struct ntvfs_request
*req
,
660 union smb_setfileinfo
*io
)
662 return NT_STATUS_NOT_IMPLEMENTED
;
667 a handler for async fsinfo replies
669 static void async_fsinfo(struct smb2_request
*c_req
)
671 struct async_info
*async
= c_req
->async
.private_data
;
672 struct ntvfs_request
*req
= async
->req
;
673 req
->async_states
->status
= smb2_getinfo_fs_recv(c_req
, req
, async
->parms
);
675 req
->async_states
->send_fn(req
);
679 return filesystem space info
681 static NTSTATUS
cvfs_fsinfo(struct ntvfs_module_context
*ntvfs
,
682 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
684 struct cvfs_private
*p
= ntvfs
->private_data
;
685 struct smb2_request
*c_req
;
686 enum smb_fsinfo_level level
= fs
->generic
.level
;
691 /* some levels go straight through */
692 case RAW_QFS_VOLUME_INFORMATION
:
693 case RAW_QFS_SIZE_INFORMATION
:
694 case RAW_QFS_DEVICE_INFORMATION
:
695 case RAW_QFS_ATTRIBUTE_INFORMATION
:
696 case RAW_QFS_QUOTA_INFORMATION
:
697 case RAW_QFS_FULL_SIZE_INFORMATION
:
698 case RAW_QFS_OBJECTID_INFORMATION
:
701 /* some get mapped */
702 case RAW_QFS_VOLUME_INFO
:
703 level
= RAW_QFS_VOLUME_INFORMATION
;
705 case RAW_QFS_SIZE_INFO
:
706 level
= RAW_QFS_SIZE_INFORMATION
;
708 case RAW_QFS_DEVICE_INFO
:
709 level
= RAW_QFS_DEVICE_INFORMATION
;
711 case RAW_QFS_ATTRIBUTE_INFO
:
712 level
= RAW_QFS_ATTRIBUTE_INFO
;
716 /* the rest get refused for now */
717 DEBUG(0,("fsinfo level %u not possible on SMB2\n",
718 (unsigned)fs
->generic
.level
));
722 fs
->generic
.level
= level
;
723 fs
->generic
.handle
= p
->roothandle
;
725 c_req
= smb2_getinfo_fs_send(p
->tree
, fs
);
727 ASYNC_RECV_TAIL(fs
, async_fsinfo
);
731 return print queue info
733 static NTSTATUS
cvfs_lpq(struct ntvfs_module_context
*ntvfs
,
734 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
736 return NT_STATUS_NOT_SUPPORTED
;
740 list files in a directory matching a wildcard pattern
742 static NTSTATUS
cvfs_search_first(struct ntvfs_module_context
*ntvfs
,
743 struct ntvfs_request
*req
, union smb_search_first
*io
,
744 void *search_private
,
745 bool (*callback
)(void *, const union smb_search_data
*))
747 struct cvfs_private
*p
= ntvfs
->private_data
;
749 enum smb_search_data_level smb2_level
;
750 unsigned int count
, i
;
751 union smb_search_data
*data
;
754 if (io
->generic
.level
!= RAW_SEARCH_TRANS2
) {
755 DEBUG(0,("We only support trans2 search in smb2 backend\n"));
756 return NT_STATUS_NOT_SUPPORTED
;
759 switch (io
->generic
.data_level
) {
760 case RAW_SEARCH_DATA_DIRECTORY_INFO
:
761 smb2_level
= SMB2_FIND_DIRECTORY_INFO
;
763 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
:
764 smb2_level
= SMB2_FIND_FULL_DIRECTORY_INFO
;
766 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
767 smb2_level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
769 case RAW_SEARCH_DATA_NAME_INFO
:
770 smb2_level
= SMB2_FIND_NAME_INFO
;
772 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
:
773 smb2_level
= SMB2_FIND_ID_FULL_DIRECTORY_INFO
;
775 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
:
776 smb2_level
= SMB2_FIND_ID_BOTH_DIRECTORY_INFO
;
779 DEBUG(0,("Unsupported search level %u for smb2 backend\n",
780 (unsigned)io
->generic
.data_level
));
781 return NT_STATUS_INVALID_INFO_CLASS
;
784 /* we do the search on the roothandle. This only works because
785 search is synchronous, otherwise we'd have no way to
786 distinguish multiple searches happening at once
789 f
.in
.file
.handle
= p
->roothandle
;
790 f
.in
.level
= smb2_level
;
791 f
.in
.pattern
= io
->t2ffirst
.in
.pattern
;
792 while (f
.in
.pattern
[0] == '\\') {
795 f
.in
.continue_flags
= 0;
796 f
.in
.max_response_size
= 0x10000;
798 status
= smb2_find_level(p
->tree
, req
, &f
, &count
, &data
);
799 NT_STATUS_NOT_OK_RETURN(status
);
801 for (i
=0;i
<count
;i
++) {
802 if (!callback(search_private
, &data
[i
])) break;
805 io
->t2ffirst
.out
.handle
= 0;
806 io
->t2ffirst
.out
.count
= i
;
807 /* TODO: fix end_of_file */
808 io
->t2ffirst
.out
.end_of_search
= 1;
815 /* continue a search */
816 static NTSTATUS
cvfs_search_next(struct ntvfs_module_context
*ntvfs
,
817 struct ntvfs_request
*req
, union smb_search_next
*io
,
818 void *search_private
,
819 bool (*callback
)(void *, const union smb_search_data
*))
821 return NT_STATUS_NOT_IMPLEMENTED
;
825 static NTSTATUS
cvfs_search_close(struct ntvfs_module_context
*ntvfs
,
826 struct ntvfs_request
*req
, union smb_search_close
*io
)
828 return NT_STATUS_NOT_IMPLEMENTED
;
831 /* SMBtrans - not used on file shares */
832 static NTSTATUS
cvfs_trans(struct ntvfs_module_context
*ntvfs
,
833 struct ntvfs_request
*req
,
834 struct smb_trans2
*trans2
)
836 return NT_STATUS_ACCESS_DENIED
;
839 /* change notify request - always async */
840 static NTSTATUS
cvfs_notify(struct ntvfs_module_context
*ntvfs
,
841 struct ntvfs_request
*req
,
842 union smb_notify
*io
)
844 return NT_STATUS_NOT_IMPLEMENTED
;
848 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
850 NTSTATUS
ntvfs_smb2_init(void)
853 struct ntvfs_ops ops
;
854 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
858 /* fill in the name and type */
860 ops
.type
= NTVFS_DISK
;
862 /* fill in all the operations */
863 ops
.connect_fn
= cvfs_connect
;
864 ops
.disconnect_fn
= cvfs_disconnect
;
865 ops
.unlink_fn
= cvfs_unlink
;
866 ops
.chkpath_fn
= cvfs_chkpath
;
867 ops
.qpathinfo_fn
= cvfs_qpathinfo
;
868 ops
.setpathinfo_fn
= cvfs_setpathinfo
;
869 ops
.open_fn
= cvfs_open
;
870 ops
.mkdir_fn
= cvfs_mkdir
;
871 ops
.rmdir_fn
= cvfs_rmdir
;
872 ops
.rename_fn
= cvfs_rename
;
873 ops
.copy_fn
= cvfs_copy
;
874 ops
.ioctl_fn
= cvfs_ioctl
;
875 ops
.read_fn
= cvfs_read
;
876 ops
.write_fn
= cvfs_write
;
877 ops
.seek_fn
= cvfs_seek
;
878 ops
.flush_fn
= cvfs_flush
;
879 ops
.close_fn
= cvfs_close
;
880 ops
.exit_fn
= cvfs_exit
;
881 ops
.lock_fn
= cvfs_lock
;
882 ops
.setfileinfo_fn
= cvfs_setfileinfo
;
883 ops
.qfileinfo_fn
= cvfs_qfileinfo
;
884 ops
.fsinfo_fn
= cvfs_fsinfo
;
885 ops
.lpq_fn
= cvfs_lpq
;
886 ops
.search_first_fn
= cvfs_search_first
;
887 ops
.search_next_fn
= cvfs_search_next
;
888 ops
.search_close_fn
= cvfs_search_close
;
889 ops
.trans_fn
= cvfs_trans
;
890 ops
.logoff_fn
= cvfs_logoff
;
891 ops
.async_setup_fn
= cvfs_async_setup
;
892 ops
.cancel_fn
= cvfs_cancel
;
893 ops
.notify_fn
= cvfs_notify
;
895 /* register ourselves with the NTVFS subsystem. We register
896 under the name 'smb2'. */
897 ret
= ntvfs_register(&ops
, &vers
);
899 if (!NT_STATUS_IS_OK(ret
)) {
900 DEBUG(0,("Failed to register SMB2 backend\n"));