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"
45 struct cvfs_file
*prev
, *next
;
47 struct ntvfs_handle
*h
;
50 /* this is stored in ntvfs_private */
52 struct smb2_tree
*tree
;
53 struct smb2_transport
*transport
;
54 struct ntvfs_module_context
*ntvfs
;
55 struct async_info
*pending
;
56 struct cvfs_file
*files
;
58 /* a handle on the root of the share */
59 /* TODO: leaving this handle open could prevent other users
60 from opening the share with exclusive access. We probably
61 need to open it on demand */
62 struct smb2_handle roothandle
;
66 /* a structure used to pass information to an async handler */
68 struct async_info
*next
, *prev
;
69 struct cvfs_private
*cvfs
;
70 struct ntvfs_request
*req
;
72 struct composite_context
*c_comp
;
77 #define SETUP_FILE_HERE(f) do { \
78 f = ntvfs_handle_get_backend_data(io->generic.in.file.ntvfs, ntvfs); \
79 if (!f) return NT_STATUS_INVALID_HANDLE; \
80 io->generic.in.file.fnum = f->fnum; \
83 #define SETUP_FILE do { \
84 struct cvfs_file *f; \
88 #define SMB2_SERVER "smb2:server"
89 #define SMB2_USER "smb2:user"
90 #define SMB2_PASSWORD "smb2:password"
91 #define SMB2_DOMAIN "smb2:domain"
92 #define SMB2_SHARE "smb2:share"
93 #define SMB2_USE_MACHINE_ACCT "smb2:use-machine-account"
95 #define SMB2_USE_MACHINE_ACCT_DEFAULT false
98 a handler for oplock break events from the server - these need to be passed
101 static bool oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *p_private
)
103 struct cvfs_private
*p
= p_private
;
105 struct ntvfs_handle
*h
= NULL
;
108 for (f
=p
->files
; f
; f
=f
->next
) {
109 if (f
->fnum
!= fnum
) continue;
115 DEBUG(5,("vfs_smb2: ignoring oplock break level %d for fnum %d\n", level
, fnum
));
119 DEBUG(5,("vfs_smb2: sending oplock break level %d for fnum %d\n", level
, fnum
));
120 status
= ntvfs_send_oplock_break(p
->ntvfs
, h
, level
);
121 if (!NT_STATUS_IS_OK(status
)) return false;
126 return a handle to the root of the share
128 static NTSTATUS
smb2_get_roothandle(struct smb2_tree
*tree
, struct smb2_handle
*handle
)
130 struct smb2_create io
;
134 io
.in
.oplock_level
= 0;
135 io
.in
.desired_access
= SEC_STD_SYNCHRONIZE
| SEC_DIR_READ_ATTRIBUTE
| SEC_DIR_LIST
;
136 io
.in
.file_attributes
= 0;
137 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
139 NTCREATEX_SHARE_ACCESS_READ
|
140 NTCREATEX_SHARE_ACCESS_WRITE
|
141 NTCREATEX_SHARE_ACCESS_DELETE
;
142 io
.in
.create_options
= 0;
145 status
= smb2_create(tree
, tree
, &io
);
146 NT_STATUS_NOT_OK_RETURN(status
);
148 *handle
= io
.out
.file
.handle
;
154 connect to a share - used when a tree_connect operation comes in.
156 static NTSTATUS
cvfs_connect(struct ntvfs_module_context
*ntvfs
,
157 struct ntvfs_request
*req
,
158 union smb_tcon
* tcon
)
161 struct cvfs_private
*p
;
162 const char *host
, *user
, *pass
, *domain
, *remote_share
, *sharename
;
163 struct composite_context
*creq
;
164 struct share_config
*scfg
= ntvfs
->ctx
->config
;
165 struct smb2_tree
*tree
;
166 struct cli_credentials
*credentials
;
167 bool machine_account
;
168 struct smbcli_options options
;
170 switch (tcon
->generic
.level
) {
172 sharename
= tcon
->tcon
.in
.service
;
175 sharename
= tcon
->tconx
.in
.path
;
178 sharename
= tcon
->smb2
.in
.path
;
181 return NT_STATUS_INVALID_LEVEL
;
184 if (strncmp(sharename
, "\\\\", 2) == 0) {
185 char *str
= strchr(sharename
+2, '\\');
191 /* Here we need to determine which server to connect to.
192 * For now we use parametric options, type cifs.
193 * Later we will use security=server and auth_server.c.
195 host
= share_string_option(scfg
, SMB2_SERVER
, NULL
);
196 user
= share_string_option(scfg
, SMB2_USER
, NULL
);
197 pass
= share_string_option(scfg
, SMB2_PASSWORD
, NULL
);
198 domain
= share_string_option(scfg
, SMB2_DOMAIN
, NULL
);
199 remote_share
= share_string_option(scfg
, SMB2_SHARE
, NULL
);
201 remote_share
= sharename
;
204 machine_account
= share_bool_option(scfg
, SMB2_USE_MACHINE_ACCT
, SMB2_USE_MACHINE_ACCT_DEFAULT
);
206 p
= talloc_zero(ntvfs
, struct cvfs_private
);
208 return NT_STATUS_NO_MEMORY
;
211 ntvfs
->private_data
= p
;
214 DEBUG(1,("CIFS backend: You must supply server\n"));
215 return NT_STATUS_INVALID_PARAMETER
;
219 DEBUG(5, ("CIFS backend: Using specified password\n"));
220 credentials
= cli_credentials_init(p
);
222 return NT_STATUS_NO_MEMORY
;
224 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
225 cli_credentials_set_username(credentials
, user
, CRED_SPECIFIED
);
227 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
229 cli_credentials_set_password(credentials
, pass
, CRED_SPECIFIED
);
230 } else if (machine_account
) {
231 DEBUG(5, ("CIFS backend: Using machine account\n"));
232 credentials
= cli_credentials_init(p
);
233 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
235 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
237 status
= cli_credentials_set_machine_account(credentials
, ntvfs
->ctx
->lp_ctx
);
238 if (!NT_STATUS_IS_OK(status
)) {
241 } else if (req
->session_info
->credentials
) {
242 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
243 credentials
= req
->session_info
->credentials
;
245 DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
246 return NT_STATUS_INVALID_PARAMETER
;
249 lp_smbcli_options(ntvfs
->ctx
->lp_ctx
, &options
);
251 creq
= smb2_connect_send(p
, host
,
252 lp_parm_string_list(p
, ntvfs
->ctx
->lp_ctx
, NULL
, "smb2", "ports", NULL
),
254 lp_resolve_context(ntvfs
->ctx
->lp_ctx
),
256 ntvfs
->ctx
->event_ctx
, &options
,
257 lp_socket_options(ntvfs
->ctx
->lp_ctx
),
258 lp_gensec_settings(p
, ntvfs
->ctx
->lp_ctx
)
261 status
= smb2_connect_recv(creq
, p
, &tree
);
262 NT_STATUS_NOT_OK_RETURN(status
);
264 status
= smb2_get_roothandle(tree
, &p
->roothandle
);
265 NT_STATUS_NOT_OK_RETURN(status
);
268 p
->transport
= p
->tree
->session
->transport
;
271 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
272 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->fs_type
);
273 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
274 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->dev_type
);
276 if (tcon
->generic
.level
== RAW_TCON_TCONX
) {
277 tcon
->tconx
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
278 tcon
->tconx
.out
.dev_type
= ntvfs
->ctx
->dev_type
;
281 /* we need to receive oplock break requests from the server */
282 /* TODO: enable oplocks
283 smbcli_oplock_handler(p->transport, oplock_handler, p);
289 disconnect from a share
291 static NTSTATUS
cvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
293 struct cvfs_private
*p
= ntvfs
->private_data
;
294 struct async_info
*a
, *an
;
296 /* first cleanup pending requests */
297 for (a
=p
->pending
; a
; a
= an
) {
299 talloc_free(a
->c_req
);
304 ntvfs
->private_data
= NULL
;
310 destroy an async info structure
312 static int async_info_destructor(struct async_info
*async
)
314 DLIST_REMOVE(async
->cvfs
->pending
, async
);
319 a handler for simple async SMB2 replies
320 this handler can only be used for functions that don't return any
321 parameters (those that just return a status code)
323 static void async_simple_smb2(struct smb2_request
*c_req
)
325 struct async_info
*async
= c_req
->async
.private_data
;
326 struct ntvfs_request
*req
= async
->req
;
328 smb2_request_receive(c_req
);
329 req
->async_states
->status
= smb2_request_destroy(c_req
);
331 req
->async_states
->send_fn(req
);
335 a handler for simple async composite replies
336 this handler can only be used for functions that don't return any
337 parameters (those that just return a status code)
339 static void async_simple_composite(struct composite_context
*c_req
)
341 struct async_info
*async
= c_req
->async
.private_data
;
342 struct ntvfs_request
*req
= async
->req
;
344 req
->async_states
->status
= composite_wait_free(c_req
);
346 req
->async_states
->send_fn(req
);
350 /* save some typing for the simple functions */
351 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
352 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
354 struct async_info *async; \
355 async = talloc(req, struct async_info); \
356 if (!async) return NT_STATUS_NO_MEMORY; \
361 async->c_req = c_req; \
362 DLIST_ADD(p->pending, async); \
363 c_req->async.private_data = async; \
364 talloc_set_destructor(async, async_info_destructor); \
366 c_req->async.fn = async_fn; \
367 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
368 return NT_STATUS_OK; \
371 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
373 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple_smb2)
374 #define SIMPLE_COMPOSITE_TAIL ASYNC_RECV_TAIL(NULL, async_simple_composite)
376 #define CHECK_ASYNC(req) do { \
377 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { \
378 DEBUG(0,("SMB2 proxy backend does not support sync operation at %s\n", \
380 return NT_STATUS_NOT_IMPLEMENTED; \
384 delete a file - the dirtype specifies the file types to include in the search.
385 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
388 - doesn't handle wildcards
389 - doesn't obey attrib restrictions
391 static NTSTATUS
cvfs_unlink(struct ntvfs_module_context
*ntvfs
,
392 struct ntvfs_request
*req
, union smb_unlink
*unl
)
394 struct cvfs_private
*p
= ntvfs
->private_data
;
395 struct composite_context
*c_req
;
399 c_req
= smb2_composite_unlink_send(p
->tree
, unl
);
401 SIMPLE_COMPOSITE_TAIL
;
407 static NTSTATUS
cvfs_ioctl(struct ntvfs_module_context
*ntvfs
,
408 struct ntvfs_request
*req
, union smb_ioctl
*io
)
410 return NT_STATUS_NOT_IMPLEMENTED
;
414 check if a directory exists
416 static NTSTATUS
cvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
417 struct ntvfs_request
*req
, union smb_chkpath
*cp
)
419 struct cvfs_private
*p
= ntvfs
->private_data
;
420 struct smb2_request
*c_req
;
425 /* SMB2 doesn't have a chkpath operation, and also doesn't
426 have a query path info call, so the best seems to be to do a
427 find call, using the roothandle we established at connect
430 f
.in
.file
.handle
= p
->roothandle
;
431 f
.in
.level
= SMB2_FIND_DIRECTORY_INFO
;
432 f
.in
.pattern
= cp
->chkpath
.in
.path
;
433 /* SMB2 find doesn't accept \ or the empty string - this is the best
435 if (strcmp(f
.in
.pattern
, "\\") == 0 ||
436 strcmp(f
.in
.pattern
, "") == 0) {
439 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
| SMB2_CONTINUE_FLAG_RESTART
;
440 f
.in
.max_response_size
= 0x1000;
442 c_req
= smb2_find_send(p
->tree
, &f
);
448 return info on a pathname
450 static NTSTATUS
cvfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
451 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
453 return NT_STATUS_NOT_IMPLEMENTED
;
457 query info on a open file
459 static NTSTATUS
cvfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
460 struct ntvfs_request
*req
, union smb_fileinfo
*io
)
462 return NT_STATUS_NOT_IMPLEMENTED
;
467 set info on a pathname
469 static NTSTATUS
cvfs_setpathinfo(struct ntvfs_module_context
*ntvfs
,
470 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
472 return NT_STATUS_NOT_IMPLEMENTED
;
479 static NTSTATUS
cvfs_open(struct ntvfs_module_context
*ntvfs
,
480 struct ntvfs_request
*req
, union smb_open
*io
)
482 return NT_STATUS_NOT_IMPLEMENTED
;
488 static NTSTATUS
cvfs_mkdir(struct ntvfs_module_context
*ntvfs
,
489 struct ntvfs_request
*req
, union smb_mkdir
*md
)
491 struct cvfs_private
*p
= ntvfs
->private_data
;
492 struct composite_context
*c_req
;
496 c_req
= smb2_composite_mkdir_send(p
->tree
, md
);
498 SIMPLE_COMPOSITE_TAIL
;
504 static NTSTATUS
cvfs_rmdir(struct ntvfs_module_context
*ntvfs
,
505 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
507 struct cvfs_private
*p
= ntvfs
->private_data
;
508 struct composite_context
*c_req
;
512 c_req
= smb2_composite_rmdir_send(p
->tree
, rd
);
514 SIMPLE_COMPOSITE_TAIL
;
518 rename a set of files
520 static NTSTATUS
cvfs_rename(struct ntvfs_module_context
*ntvfs
,
521 struct ntvfs_request
*req
, union smb_rename
*ren
)
523 return NT_STATUS_NOT_IMPLEMENTED
;
529 static NTSTATUS
cvfs_copy(struct ntvfs_module_context
*ntvfs
,
530 struct ntvfs_request
*req
, struct smb_copy
*cp
)
532 return NT_STATUS_NOT_SUPPORTED
;
538 static NTSTATUS
cvfs_read(struct ntvfs_module_context
*ntvfs
,
539 struct ntvfs_request
*req
, union smb_read
*io
)
541 return NT_STATUS_NOT_IMPLEMENTED
;
547 static NTSTATUS
cvfs_write(struct ntvfs_module_context
*ntvfs
,
548 struct ntvfs_request
*req
, union smb_write
*io
)
550 return NT_STATUS_NOT_IMPLEMENTED
;
556 static NTSTATUS
cvfs_seek(struct ntvfs_module_context
*ntvfs
,
557 struct ntvfs_request
*req
,
560 return NT_STATUS_NOT_IMPLEMENTED
;
566 static NTSTATUS
cvfs_flush(struct ntvfs_module_context
*ntvfs
,
567 struct ntvfs_request
*req
,
570 return NT_STATUS_NOT_IMPLEMENTED
;
576 static NTSTATUS
cvfs_close(struct ntvfs_module_context
*ntvfs
,
577 struct ntvfs_request
*req
, union smb_close
*io
)
579 return NT_STATUS_NOT_IMPLEMENTED
;
583 exit - closing files open by the pid
585 static NTSTATUS
cvfs_exit(struct ntvfs_module_context
*ntvfs
,
586 struct ntvfs_request
*req
)
588 return NT_STATUS_NOT_IMPLEMENTED
;
592 logoff - closing files open by the user
594 static NTSTATUS
cvfs_logoff(struct ntvfs_module_context
*ntvfs
,
595 struct ntvfs_request
*req
)
597 /* we can't do this right in the cifs backend .... */
602 setup for an async call - nothing to do yet
604 static NTSTATUS
cvfs_async_setup(struct ntvfs_module_context
*ntvfs
,
605 struct ntvfs_request
*req
,
614 static NTSTATUS
cvfs_cancel(struct ntvfs_module_context
*ntvfs
,
615 struct ntvfs_request
*req
)
617 return NT_STATUS_NOT_IMPLEMENTED
;
623 static NTSTATUS
cvfs_lock(struct ntvfs_module_context
*ntvfs
,
624 struct ntvfs_request
*req
, union smb_lock
*io
)
626 return NT_STATUS_NOT_IMPLEMENTED
;
630 set info on a open file
632 static NTSTATUS
cvfs_setfileinfo(struct ntvfs_module_context
*ntvfs
,
633 struct ntvfs_request
*req
,
634 union smb_setfileinfo
*io
)
636 return NT_STATUS_NOT_IMPLEMENTED
;
641 a handler for async fsinfo replies
643 static void async_fsinfo(struct smb2_request
*c_req
)
645 struct async_info
*async
= c_req
->async
.private_data
;
646 struct ntvfs_request
*req
= async
->req
;
647 req
->async_states
->status
= smb2_getinfo_fs_recv(c_req
, req
, async
->parms
);
649 req
->async_states
->send_fn(req
);
653 return filesystem space info
655 static NTSTATUS
cvfs_fsinfo(struct ntvfs_module_context
*ntvfs
,
656 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
658 struct cvfs_private
*p
= ntvfs
->private_data
;
659 struct smb2_request
*c_req
;
660 enum smb_fsinfo_level level
= fs
->generic
.level
;
665 /* some levels go straight through */
666 case RAW_QFS_VOLUME_INFORMATION
:
667 case RAW_QFS_SIZE_INFORMATION
:
668 case RAW_QFS_DEVICE_INFORMATION
:
669 case RAW_QFS_ATTRIBUTE_INFORMATION
:
670 case RAW_QFS_QUOTA_INFORMATION
:
671 case RAW_QFS_FULL_SIZE_INFORMATION
:
672 case RAW_QFS_OBJECTID_INFORMATION
:
675 /* some get mapped */
676 case RAW_QFS_VOLUME_INFO
:
677 level
= RAW_QFS_VOLUME_INFORMATION
;
679 case RAW_QFS_SIZE_INFO
:
680 level
= RAW_QFS_SIZE_INFORMATION
;
682 case RAW_QFS_DEVICE_INFO
:
683 level
= RAW_QFS_DEVICE_INFORMATION
;
685 case RAW_QFS_ATTRIBUTE_INFO
:
686 level
= RAW_QFS_ATTRIBUTE_INFO
;
690 /* the rest get refused for now */
691 DEBUG(0,("fsinfo level %u not possible on SMB2\n",
692 (unsigned)fs
->generic
.level
));
696 fs
->generic
.level
= level
;
697 fs
->generic
.handle
= p
->roothandle
;
699 c_req
= smb2_getinfo_fs_send(p
->tree
, fs
);
701 ASYNC_RECV_TAIL(fs
, async_fsinfo
);
705 return print queue info
707 static NTSTATUS
cvfs_lpq(struct ntvfs_module_context
*ntvfs
,
708 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
710 return NT_STATUS_NOT_SUPPORTED
;
714 list files in a directory matching a wildcard pattern
716 static NTSTATUS
cvfs_search_first(struct ntvfs_module_context
*ntvfs
,
717 struct ntvfs_request
*req
, union smb_search_first
*io
,
718 void *search_private
,
719 bool (*callback
)(void *, const union smb_search_data
*))
721 struct cvfs_private
*p
= ntvfs
->private_data
;
723 enum smb_search_data_level smb2_level
;
724 unsigned int count
, i
;
725 union smb_search_data
*data
;
728 if (io
->generic
.level
!= RAW_SEARCH_TRANS2
) {
729 DEBUG(0,("We only support trans2 search in smb2 backend\n"));
730 return NT_STATUS_NOT_SUPPORTED
;
733 switch (io
->generic
.data_level
) {
734 case RAW_SEARCH_DATA_DIRECTORY_INFO
:
735 smb2_level
= SMB2_FIND_DIRECTORY_INFO
;
737 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
:
738 smb2_level
= SMB2_FIND_FULL_DIRECTORY_INFO
;
740 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
741 smb2_level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
743 case RAW_SEARCH_DATA_NAME_INFO
:
744 smb2_level
= SMB2_FIND_NAME_INFO
;
746 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
:
747 smb2_level
= SMB2_FIND_ID_FULL_DIRECTORY_INFO
;
749 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
:
750 smb2_level
= SMB2_FIND_ID_BOTH_DIRECTORY_INFO
;
753 DEBUG(0,("Unsupported search level %u for smb2 backend\n",
754 (unsigned)io
->generic
.data_level
));
755 return NT_STATUS_INVALID_INFO_CLASS
;
758 /* we do the search on the roothandle. This only works because
759 search is synchronous, otherwise we'd have no way to
760 distinguish multiple searches happening at once
763 f
.in
.file
.handle
= p
->roothandle
;
764 f
.in
.level
= smb2_level
;
765 f
.in
.pattern
= io
->t2ffirst
.in
.pattern
;
766 while (f
.in
.pattern
[0] == '\\') {
769 f
.in
.continue_flags
= 0;
770 f
.in
.max_response_size
= 0x10000;
772 status
= smb2_find_level(p
->tree
, req
, &f
, &count
, &data
);
773 NT_STATUS_NOT_OK_RETURN(status
);
775 for (i
=0;i
<count
;i
++) {
776 if (!callback(search_private
, &data
[i
])) break;
779 io
->t2ffirst
.out
.handle
= 0;
780 io
->t2ffirst
.out
.count
= i
;
781 /* TODO: fix end_of_file */
782 io
->t2ffirst
.out
.end_of_search
= 1;
789 /* continue a search */
790 static NTSTATUS
cvfs_search_next(struct ntvfs_module_context
*ntvfs
,
791 struct ntvfs_request
*req
, union smb_search_next
*io
,
792 void *search_private
,
793 bool (*callback
)(void *, const union smb_search_data
*))
795 return NT_STATUS_NOT_IMPLEMENTED
;
799 static NTSTATUS
cvfs_search_close(struct ntvfs_module_context
*ntvfs
,
800 struct ntvfs_request
*req
, union smb_search_close
*io
)
802 return NT_STATUS_NOT_IMPLEMENTED
;
805 /* SMBtrans - not used on file shares */
806 static NTSTATUS
cvfs_trans(struct ntvfs_module_context
*ntvfs
,
807 struct ntvfs_request
*req
,
808 struct smb_trans2
*trans2
)
810 return NT_STATUS_ACCESS_DENIED
;
813 /* change notify request - always async */
814 static NTSTATUS
cvfs_notify(struct ntvfs_module_context
*ntvfs
,
815 struct ntvfs_request
*req
,
816 union smb_notify
*io
)
818 return NT_STATUS_NOT_IMPLEMENTED
;
822 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
824 NTSTATUS
ntvfs_smb2_init(void)
827 struct ntvfs_ops ops
;
828 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
832 /* fill in the name and type */
834 ops
.type
= NTVFS_DISK
;
836 /* fill in all the operations */
837 ops
.connect
= cvfs_connect
;
838 ops
.disconnect
= cvfs_disconnect
;
839 ops
.unlink
= cvfs_unlink
;
840 ops
.chkpath
= cvfs_chkpath
;
841 ops
.qpathinfo
= cvfs_qpathinfo
;
842 ops
.setpathinfo
= cvfs_setpathinfo
;
843 ops
.open
= cvfs_open
;
844 ops
.mkdir
= cvfs_mkdir
;
845 ops
.rmdir
= cvfs_rmdir
;
846 ops
.rename
= cvfs_rename
;
847 ops
.copy
= cvfs_copy
;
848 ops
.ioctl
= cvfs_ioctl
;
849 ops
.read
= cvfs_read
;
850 ops
.write
= cvfs_write
;
851 ops
.seek
= cvfs_seek
;
852 ops
.flush
= cvfs_flush
;
853 ops
.close
= cvfs_close
;
854 ops
.exit
= cvfs_exit
;
855 ops
.lock
= cvfs_lock
;
856 ops
.setfileinfo
= cvfs_setfileinfo
;
857 ops
.qfileinfo
= cvfs_qfileinfo
;
858 ops
.fsinfo
= cvfs_fsinfo
;
860 ops
.search_first
= cvfs_search_first
;
861 ops
.search_next
= cvfs_search_next
;
862 ops
.search_close
= cvfs_search_close
;
863 ops
.trans
= cvfs_trans
;
864 ops
.logoff
= cvfs_logoff
;
865 ops
.async_setup
= cvfs_async_setup
;
866 ops
.cancel
= cvfs_cancel
;
867 ops
.notify
= cvfs_notify
;
869 /* register ourselves with the NTVFS subsystem. We register
870 under the name 'smb2'. */
871 ret
= ntvfs_register(&ops
, &vers
);
873 if (!NT_STATUS_IS_OK(ret
)) {
874 DEBUG(0,("Failed to register SMB2 backend\n"));