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
103 static bool oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
, uint16_t fnum
, uint8_t level
, void *p_private
)
105 struct cvfs_private
*p
= p_private
;
107 struct ntvfs_handle
*h
= NULL
;
110 for (f
=p
->files
; f
; f
=f
->next
) {
111 if (f
->fnum
!= fnum
) continue;
117 DEBUG(5,("vfs_smb2: ignoring oplock break level %d for fnum %d\n", level
, fnum
));
121 DEBUG(5,("vfs_smb2: sending oplock break level %d for fnum %d\n", level
, fnum
));
122 status
= ntvfs_send_oplock_break(p
->ntvfs
, h
, level
);
123 if (!NT_STATUS_IS_OK(status
)) return false;
128 return a handle to the root of the share
130 static NTSTATUS
smb2_get_roothandle(struct smb2_tree
*tree
, struct smb2_handle
*handle
)
132 struct smb2_create io
;
136 io
.in
.oplock_level
= 0;
137 io
.in
.desired_access
= SEC_STD_SYNCHRONIZE
| SEC_DIR_READ_ATTRIBUTE
| SEC_DIR_LIST
;
138 io
.in
.file_attributes
= 0;
139 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
141 NTCREATEX_SHARE_ACCESS_READ
|
142 NTCREATEX_SHARE_ACCESS_WRITE
|
143 NTCREATEX_SHARE_ACCESS_DELETE
;
144 io
.in
.create_options
= 0;
147 status
= smb2_create(tree
, tree
, &io
);
148 NT_STATUS_NOT_OK_RETURN(status
);
150 *handle
= io
.out
.file
.handle
;
156 connect to a share - used when a tree_connect operation comes in.
158 static NTSTATUS
cvfs_connect(struct ntvfs_module_context
*ntvfs
,
159 struct ntvfs_request
*req
,
160 union smb_tcon
* tcon
)
163 struct cvfs_private
*p
;
164 const char *host
, *user
, *pass
, *domain
, *remote_share
, *sharename
;
165 struct share_config
*scfg
= ntvfs
->ctx
->config
;
166 struct smb2_tree
*tree
;
167 struct cli_credentials
*credentials
;
168 bool machine_account
;
169 struct smbcli_options options
;
171 switch (tcon
->generic
.level
) {
173 sharename
= tcon
->tcon
.in
.service
;
176 sharename
= tcon
->tconx
.in
.path
;
179 sharename
= tcon
->smb2
.in
.path
;
182 return NT_STATUS_INVALID_LEVEL
;
185 if (strncmp(sharename
, "\\\\", 2) == 0) {
186 char *str
= strchr(sharename
+2, '\\');
192 /* Here we need to determine which server to connect to.
193 * For now we use parametric options, type cifs.
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 lpcfg_smbcli_options(ntvfs
->ctx
->lp_ctx
, &options
);
251 status
= smb2_connect(p
, host
,
252 lpcfg_parm_string_list(p
, ntvfs
->ctx
->lp_ctx
, NULL
, "smb2", "ports", NULL
),
254 lpcfg_resolve_context(ntvfs
->ctx
->lp_ctx
),
257 ntvfs
->ctx
->event_ctx
, &options
,
258 lpcfg_socket_options(ntvfs
->ctx
->lp_ctx
),
259 lpcfg_gensec_settings(p
, ntvfs
->ctx
->lp_ctx
));
260 NT_STATUS_NOT_OK_RETURN(status
);
262 status
= smb2_get_roothandle(tree
, &p
->roothandle
);
263 NT_STATUS_NOT_OK_RETURN(status
);
266 p
->transport
= p
->tree
->session
->transport
;
269 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
270 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->fs_type
);
271 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
272 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->dev_type
);
274 if (tcon
->generic
.level
== RAW_TCON_TCONX
) {
275 tcon
->tconx
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
276 tcon
->tconx
.out
.dev_type
= ntvfs
->ctx
->dev_type
;
279 /* we need to receive oplock break requests from the server */
280 /* TODO: enable oplocks
281 smbcli_oplock_handler(p->transport, oplock_handler, p);
287 disconnect from a share
289 static NTSTATUS
cvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
291 struct cvfs_private
*p
= ntvfs
->private_data
;
292 struct async_info
*a
, *an
;
294 /* first cleanup pending requests */
295 for (a
=p
->pending
; a
; a
= an
) {
297 talloc_free(a
->c_req
);
302 ntvfs
->private_data
= NULL
;
308 destroy an async info structure
310 static int async_info_destructor(struct async_info
*async
)
312 DLIST_REMOVE(async
->cvfs
->pending
, async
);
317 a handler for simple async SMB2 replies
318 this handler can only be used for functions that don't return any
319 parameters (those that just return a status code)
321 static void async_simple_smb2(struct smb2_request
*c_req
)
323 struct async_info
*async
= c_req
->async
.private_data
;
324 struct ntvfs_request
*req
= async
->req
;
326 smb2_request_receive(c_req
);
327 req
->async_states
->status
= smb2_request_destroy(c_req
);
329 req
->async_states
->send_fn(req
);
333 a handler for simple async composite replies
334 this handler can only be used for functions that don't return any
335 parameters (those that just return a status code)
337 static void async_simple_composite(struct composite_context
*c_req
)
339 struct async_info
*async
= c_req
->async
.private_data
;
340 struct ntvfs_request
*req
= async
->req
;
342 req
->async_states
->status
= composite_wait_free(c_req
);
344 req
->async_states
->send_fn(req
);
348 /* save some typing for the simple functions */
349 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
350 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
352 struct async_info *async; \
353 async = talloc(req, struct async_info); \
354 if (!async) return NT_STATUS_NO_MEMORY; \
359 async->c_req = c_req; \
360 DLIST_ADD(p->pending, async); \
361 c_req->async.private_data = async; \
362 talloc_set_destructor(async, async_info_destructor); \
364 c_req->async.fn = async_fn; \
365 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
366 return NT_STATUS_OK; \
369 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
371 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple_smb2)
372 #define SIMPLE_COMPOSITE_TAIL ASYNC_RECV_TAIL(NULL, async_simple_composite)
374 #define CHECK_ASYNC(req) do { \
375 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { \
376 DEBUG(0,("SMB2 proxy backend does not support sync operation at %s\n", \
378 return NT_STATUS_NOT_IMPLEMENTED; \
382 delete a file - the dirtype specifies the file types to include in the search.
383 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
386 - doesn't handle wildcards
387 - doesn't obey attrib restrictions
389 static NTSTATUS
cvfs_unlink(struct ntvfs_module_context
*ntvfs
,
390 struct ntvfs_request
*req
, union smb_unlink
*unl
)
392 struct cvfs_private
*p
= ntvfs
->private_data
;
393 struct composite_context
*c_req
;
397 c_req
= smb2_composite_unlink_send(p
->tree
, unl
);
399 SIMPLE_COMPOSITE_TAIL
;
405 static NTSTATUS
cvfs_ioctl(struct ntvfs_module_context
*ntvfs
,
406 struct ntvfs_request
*req
, union smb_ioctl
*io
)
408 return NT_STATUS_NOT_IMPLEMENTED
;
412 check if a directory exists
414 static NTSTATUS
cvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
415 struct ntvfs_request
*req
, union smb_chkpath
*cp
)
417 struct cvfs_private
*p
= ntvfs
->private_data
;
418 struct smb2_request
*c_req
;
423 /* SMB2 doesn't have a chkpath operation, and also doesn't
424 have a query path info call, so the best seems to be to do a
425 find call, using the roothandle we established at connect
428 f
.in
.file
.handle
= p
->roothandle
;
429 f
.in
.level
= SMB2_FIND_DIRECTORY_INFO
;
430 f
.in
.pattern
= cp
->chkpath
.in
.path
;
431 /* SMB2 find doesn't accept \ or the empty string - this is the best
433 if (strcmp(f
.in
.pattern
, "\\") == 0 ||
434 strcmp(f
.in
.pattern
, "") == 0) {
437 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
| SMB2_CONTINUE_FLAG_RESTART
;
438 f
.in
.max_response_size
= 0x1000;
440 c_req
= smb2_find_send(p
->tree
, &f
);
446 return info on a pathname
448 static NTSTATUS
cvfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
449 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
451 return NT_STATUS_NOT_IMPLEMENTED
;
455 query info on a open file
457 static NTSTATUS
cvfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
458 struct ntvfs_request
*req
, union smb_fileinfo
*io
)
460 return NT_STATUS_NOT_IMPLEMENTED
;
465 set info on a pathname
467 static NTSTATUS
cvfs_setpathinfo(struct ntvfs_module_context
*ntvfs
,
468 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
470 return NT_STATUS_NOT_IMPLEMENTED
;
477 static NTSTATUS
cvfs_open(struct ntvfs_module_context
*ntvfs
,
478 struct ntvfs_request
*req
, union smb_open
*io
)
480 return NT_STATUS_NOT_IMPLEMENTED
;
486 static NTSTATUS
cvfs_mkdir(struct ntvfs_module_context
*ntvfs
,
487 struct ntvfs_request
*req
, union smb_mkdir
*md
)
489 struct cvfs_private
*p
= ntvfs
->private_data
;
490 struct composite_context
*c_req
;
494 c_req
= smb2_composite_mkdir_send(p
->tree
, md
);
496 SIMPLE_COMPOSITE_TAIL
;
502 static NTSTATUS
cvfs_rmdir(struct ntvfs_module_context
*ntvfs
,
503 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
505 struct cvfs_private
*p
= ntvfs
->private_data
;
506 struct composite_context
*c_req
;
510 c_req
= smb2_composite_rmdir_send(p
->tree
, rd
);
512 SIMPLE_COMPOSITE_TAIL
;
516 rename a set of files
518 static NTSTATUS
cvfs_rename(struct ntvfs_module_context
*ntvfs
,
519 struct ntvfs_request
*req
, union smb_rename
*ren
)
521 return NT_STATUS_NOT_IMPLEMENTED
;
527 static NTSTATUS
cvfs_copy(struct ntvfs_module_context
*ntvfs
,
528 struct ntvfs_request
*req
, struct smb_copy
*cp
)
530 return NT_STATUS_NOT_SUPPORTED
;
536 static NTSTATUS
cvfs_read(struct ntvfs_module_context
*ntvfs
,
537 struct ntvfs_request
*req
, union smb_read
*io
)
539 return NT_STATUS_NOT_IMPLEMENTED
;
545 static NTSTATUS
cvfs_write(struct ntvfs_module_context
*ntvfs
,
546 struct ntvfs_request
*req
, union smb_write
*io
)
548 return NT_STATUS_NOT_IMPLEMENTED
;
554 static NTSTATUS
cvfs_seek(struct ntvfs_module_context
*ntvfs
,
555 struct ntvfs_request
*req
,
558 return NT_STATUS_NOT_IMPLEMENTED
;
564 static NTSTATUS
cvfs_flush(struct ntvfs_module_context
*ntvfs
,
565 struct ntvfs_request
*req
,
568 return NT_STATUS_NOT_IMPLEMENTED
;
574 static NTSTATUS
cvfs_close(struct ntvfs_module_context
*ntvfs
,
575 struct ntvfs_request
*req
, union smb_close
*io
)
577 return NT_STATUS_NOT_IMPLEMENTED
;
581 exit - closing files open by the pid
583 static NTSTATUS
cvfs_exit(struct ntvfs_module_context
*ntvfs
,
584 struct ntvfs_request
*req
)
586 return NT_STATUS_NOT_IMPLEMENTED
;
590 logoff - closing files open by the user
592 static NTSTATUS
cvfs_logoff(struct ntvfs_module_context
*ntvfs
,
593 struct ntvfs_request
*req
)
595 /* we can't do this right in the cifs backend .... */
600 setup for an async call - nothing to do yet
602 static NTSTATUS
cvfs_async_setup(struct ntvfs_module_context
*ntvfs
,
603 struct ntvfs_request
*req
,
612 static NTSTATUS
cvfs_cancel(struct ntvfs_module_context
*ntvfs
,
613 struct ntvfs_request
*req
)
615 return NT_STATUS_NOT_IMPLEMENTED
;
621 static NTSTATUS
cvfs_lock(struct ntvfs_module_context
*ntvfs
,
622 struct ntvfs_request
*req
, union smb_lock
*io
)
624 return NT_STATUS_NOT_IMPLEMENTED
;
628 set info on a open file
630 static NTSTATUS
cvfs_setfileinfo(struct ntvfs_module_context
*ntvfs
,
631 struct ntvfs_request
*req
,
632 union smb_setfileinfo
*io
)
634 return NT_STATUS_NOT_IMPLEMENTED
;
639 a handler for async fsinfo replies
641 static void async_fsinfo(struct smb2_request
*c_req
)
643 struct async_info
*async
= c_req
->async
.private_data
;
644 struct ntvfs_request
*req
= async
->req
;
645 req
->async_states
->status
= smb2_getinfo_fs_recv(c_req
, req
, async
->parms
);
647 req
->async_states
->send_fn(req
);
651 return filesystem space info
653 static NTSTATUS
cvfs_fsinfo(struct ntvfs_module_context
*ntvfs
,
654 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
656 struct cvfs_private
*p
= ntvfs
->private_data
;
657 struct smb2_request
*c_req
;
658 enum smb_fsinfo_level level
= fs
->generic
.level
;
663 /* some levels go straight through */
664 case RAW_QFS_VOLUME_INFORMATION
:
665 case RAW_QFS_SIZE_INFORMATION
:
666 case RAW_QFS_DEVICE_INFORMATION
:
667 case RAW_QFS_ATTRIBUTE_INFORMATION
:
668 case RAW_QFS_QUOTA_INFORMATION
:
669 case RAW_QFS_FULL_SIZE_INFORMATION
:
670 case RAW_QFS_OBJECTID_INFORMATION
:
673 /* some get mapped */
674 case RAW_QFS_VOLUME_INFO
:
675 level
= RAW_QFS_VOLUME_INFORMATION
;
677 case RAW_QFS_SIZE_INFO
:
678 level
= RAW_QFS_SIZE_INFORMATION
;
680 case RAW_QFS_DEVICE_INFO
:
681 level
= RAW_QFS_DEVICE_INFORMATION
;
683 case RAW_QFS_ATTRIBUTE_INFO
:
684 level
= RAW_QFS_ATTRIBUTE_INFO
;
688 /* the rest get refused for now */
689 DEBUG(0,("fsinfo level %u not possible on SMB2\n",
690 (unsigned)fs
->generic
.level
));
694 fs
->generic
.level
= level
;
695 fs
->generic
.handle
= p
->roothandle
;
697 c_req
= smb2_getinfo_fs_send(p
->tree
, fs
);
699 ASYNC_RECV_TAIL(fs
, async_fsinfo
);
703 return print queue info
705 static NTSTATUS
cvfs_lpq(struct ntvfs_module_context
*ntvfs
,
706 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
708 return NT_STATUS_NOT_SUPPORTED
;
712 list files in a directory matching a wildcard pattern
714 static NTSTATUS
cvfs_search_first(struct ntvfs_module_context
*ntvfs
,
715 struct ntvfs_request
*req
, union smb_search_first
*io
,
716 void *search_private
,
717 bool (*callback
)(void *, const union smb_search_data
*))
719 struct cvfs_private
*p
= ntvfs
->private_data
;
721 enum smb_search_data_level smb2_level
;
722 unsigned int count
, i
;
723 union smb_search_data
*data
;
726 if (io
->generic
.level
!= RAW_SEARCH_TRANS2
) {
727 DEBUG(0,("We only support trans2 search in smb2 backend\n"));
728 return NT_STATUS_NOT_SUPPORTED
;
731 switch (io
->generic
.data_level
) {
732 case RAW_SEARCH_DATA_DIRECTORY_INFO
:
733 smb2_level
= SMB2_FIND_DIRECTORY_INFO
;
735 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
:
736 smb2_level
= SMB2_FIND_FULL_DIRECTORY_INFO
;
738 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
739 smb2_level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
741 case RAW_SEARCH_DATA_NAME_INFO
:
742 smb2_level
= SMB2_FIND_NAME_INFO
;
744 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
:
745 smb2_level
= SMB2_FIND_ID_FULL_DIRECTORY_INFO
;
747 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
:
748 smb2_level
= SMB2_FIND_ID_BOTH_DIRECTORY_INFO
;
751 DEBUG(0,("Unsupported search level %u for smb2 backend\n",
752 (unsigned)io
->generic
.data_level
));
753 return NT_STATUS_INVALID_INFO_CLASS
;
756 /* we do the search on the roothandle. This only works because
757 search is synchronous, otherwise we'd have no way to
758 distinguish multiple searches happening at once
761 f
.in
.file
.handle
= p
->roothandle
;
762 f
.in
.level
= smb2_level
;
763 f
.in
.pattern
= io
->t2ffirst
.in
.pattern
;
764 while (f
.in
.pattern
[0] == '\\') {
767 f
.in
.continue_flags
= 0;
768 f
.in
.max_response_size
= 0x10000;
770 status
= smb2_find_level(p
->tree
, req
, &f
, &count
, &data
);
771 NT_STATUS_NOT_OK_RETURN(status
);
773 for (i
=0;i
<count
;i
++) {
774 if (!callback(search_private
, &data
[i
])) break;
777 io
->t2ffirst
.out
.handle
= 0;
778 io
->t2ffirst
.out
.count
= i
;
779 /* TODO: fix end_of_file */
780 io
->t2ffirst
.out
.end_of_search
= 1;
787 /* continue a search */
788 static NTSTATUS
cvfs_search_next(struct ntvfs_module_context
*ntvfs
,
789 struct ntvfs_request
*req
, union smb_search_next
*io
,
790 void *search_private
,
791 bool (*callback
)(void *, const union smb_search_data
*))
793 return NT_STATUS_NOT_IMPLEMENTED
;
797 static NTSTATUS
cvfs_search_close(struct ntvfs_module_context
*ntvfs
,
798 struct ntvfs_request
*req
, union smb_search_close
*io
)
800 return NT_STATUS_NOT_IMPLEMENTED
;
803 /* SMBtrans - not used on file shares */
804 static NTSTATUS
cvfs_trans(struct ntvfs_module_context
*ntvfs
,
805 struct ntvfs_request
*req
,
806 struct smb_trans2
*trans2
)
808 return NT_STATUS_ACCESS_DENIED
;
811 /* change notify request - always async */
812 static NTSTATUS
cvfs_notify(struct ntvfs_module_context
*ntvfs
,
813 struct ntvfs_request
*req
,
814 union smb_notify
*io
)
816 return NT_STATUS_NOT_IMPLEMENTED
;
820 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
822 NTSTATUS
ntvfs_smb2_init(void)
825 struct ntvfs_ops ops
;
826 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
830 /* fill in the name and type */
832 ops
.type
= NTVFS_DISK
;
834 /* fill in all the operations */
835 ops
.connect_fn
= cvfs_connect
;
836 ops
.disconnect_fn
= cvfs_disconnect
;
837 ops
.unlink_fn
= cvfs_unlink
;
838 ops
.chkpath_fn
= cvfs_chkpath
;
839 ops
.qpathinfo_fn
= cvfs_qpathinfo
;
840 ops
.setpathinfo_fn
= cvfs_setpathinfo
;
841 ops
.open_fn
= cvfs_open
;
842 ops
.mkdir_fn
= cvfs_mkdir
;
843 ops
.rmdir_fn
= cvfs_rmdir
;
844 ops
.rename_fn
= cvfs_rename
;
845 ops
.copy_fn
= cvfs_copy
;
846 ops
.ioctl_fn
= cvfs_ioctl
;
847 ops
.read_fn
= cvfs_read
;
848 ops
.write_fn
= cvfs_write
;
849 ops
.seek_fn
= cvfs_seek
;
850 ops
.flush_fn
= cvfs_flush
;
851 ops
.close_fn
= cvfs_close
;
852 ops
.exit_fn
= cvfs_exit
;
853 ops
.lock_fn
= cvfs_lock
;
854 ops
.setfileinfo_fn
= cvfs_setfileinfo
;
855 ops
.qfileinfo_fn
= cvfs_qfileinfo
;
856 ops
.fsinfo_fn
= cvfs_fsinfo
;
857 ops
.lpq_fn
= cvfs_lpq
;
858 ops
.search_first_fn
= cvfs_search_first
;
859 ops
.search_next_fn
= cvfs_search_next
;
860 ops
.search_close_fn
= cvfs_search_close
;
861 ops
.trans_fn
= cvfs_trans
;
862 ops
.logoff_fn
= cvfs_logoff
;
863 ops
.async_setup_fn
= cvfs_async_setup
;
864 ops
.cancel_fn
= cvfs_cancel
;
865 ops
.notify_fn
= cvfs_notify
;
867 /* register ourselves with the NTVFS subsystem. We register
868 under the name 'smb2'. */
869 ret
= ntvfs_register(&ops
, &vers
);
871 if (!NT_STATUS_IS_OK(ret
)) {
872 DEBUG(0,("Failed to register SMB2 backend\n"));