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.
194 * Later we will use security=server and auth_server.c.
196 host
= share_string_option(scfg
, SMB2_SERVER
, NULL
);
197 user
= share_string_option(scfg
, SMB2_USER
, NULL
);
198 pass
= share_string_option(scfg
, SMB2_PASSWORD
, NULL
);
199 domain
= share_string_option(scfg
, SMB2_DOMAIN
, NULL
);
200 remote_share
= share_string_option(scfg
, SMB2_SHARE
, NULL
);
202 remote_share
= sharename
;
205 machine_account
= share_bool_option(scfg
, SMB2_USE_MACHINE_ACCT
, SMB2_USE_MACHINE_ACCT_DEFAULT
);
207 p
= talloc_zero(ntvfs
, struct cvfs_private
);
209 return NT_STATUS_NO_MEMORY
;
212 ntvfs
->private_data
= p
;
215 DEBUG(1,("CIFS backend: You must supply server\n"));
216 return NT_STATUS_INVALID_PARAMETER
;
220 DEBUG(5, ("CIFS backend: Using specified password\n"));
221 credentials
= cli_credentials_init(p
);
223 return NT_STATUS_NO_MEMORY
;
225 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
226 cli_credentials_set_username(credentials
, user
, CRED_SPECIFIED
);
228 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
230 cli_credentials_set_password(credentials
, pass
, CRED_SPECIFIED
);
231 } else if (machine_account
) {
232 DEBUG(5, ("CIFS backend: Using machine account\n"));
233 credentials
= cli_credentials_init(p
);
234 cli_credentials_set_conf(credentials
, ntvfs
->ctx
->lp_ctx
);
236 cli_credentials_set_domain(credentials
, domain
, CRED_SPECIFIED
);
238 status
= cli_credentials_set_machine_account(credentials
, ntvfs
->ctx
->lp_ctx
);
239 if (!NT_STATUS_IS_OK(status
)) {
242 } else if (req
->session_info
->credentials
) {
243 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
244 credentials
= req
->session_info
->credentials
;
246 DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
247 return NT_STATUS_INVALID_PARAMETER
;
250 lpcfg_smbcli_options(ntvfs
->ctx
->lp_ctx
, &options
);
252 status
= smb2_connect(p
, host
,
253 lpcfg_parm_string_list(p
, ntvfs
->ctx
->lp_ctx
, NULL
, "smb2", "ports", NULL
),
255 lpcfg_resolve_context(ntvfs
->ctx
->lp_ctx
),
258 ntvfs
->ctx
->event_ctx
, &options
,
259 lpcfg_socket_options(ntvfs
->ctx
->lp_ctx
),
260 lpcfg_gensec_settings(p
, ntvfs
->ctx
->lp_ctx
));
261 NT_STATUS_NOT_OK_RETURN(status
);
263 status
= smb2_get_roothandle(tree
, &p
->roothandle
);
264 NT_STATUS_NOT_OK_RETURN(status
);
267 p
->transport
= p
->tree
->session
->transport
;
270 ntvfs
->ctx
->fs_type
= talloc_strdup(ntvfs
->ctx
, "NTFS");
271 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->fs_type
);
272 ntvfs
->ctx
->dev_type
= talloc_strdup(ntvfs
->ctx
, "A:");
273 NT_STATUS_HAVE_NO_MEMORY(ntvfs
->ctx
->dev_type
);
275 if (tcon
->generic
.level
== RAW_TCON_TCONX
) {
276 tcon
->tconx
.out
.fs_type
= ntvfs
->ctx
->fs_type
;
277 tcon
->tconx
.out
.dev_type
= ntvfs
->ctx
->dev_type
;
280 /* we need to receive oplock break requests from the server */
281 /* TODO: enable oplocks
282 smbcli_oplock_handler(p->transport, oplock_handler, p);
288 disconnect from a share
290 static NTSTATUS
cvfs_disconnect(struct ntvfs_module_context
*ntvfs
)
292 struct cvfs_private
*p
= ntvfs
->private_data
;
293 struct async_info
*a
, *an
;
295 /* first cleanup pending requests */
296 for (a
=p
->pending
; a
; a
= an
) {
298 talloc_free(a
->c_req
);
303 ntvfs
->private_data
= NULL
;
309 destroy an async info structure
311 static int async_info_destructor(struct async_info
*async
)
313 DLIST_REMOVE(async
->cvfs
->pending
, async
);
318 a handler for simple async SMB2 replies
319 this handler can only be used for functions that don't return any
320 parameters (those that just return a status code)
322 static void async_simple_smb2(struct smb2_request
*c_req
)
324 struct async_info
*async
= c_req
->async
.private_data
;
325 struct ntvfs_request
*req
= async
->req
;
327 smb2_request_receive(c_req
);
328 req
->async_states
->status
= smb2_request_destroy(c_req
);
330 req
->async_states
->send_fn(req
);
334 a handler for simple async composite replies
335 this handler can only be used for functions that don't return any
336 parameters (those that just return a status code)
338 static void async_simple_composite(struct composite_context
*c_req
)
340 struct async_info
*async
= c_req
->async
.private_data
;
341 struct ntvfs_request
*req
= async
->req
;
343 req
->async_states
->status
= composite_wait_free(c_req
);
345 req
->async_states
->send_fn(req
);
349 /* save some typing for the simple functions */
350 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
351 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
353 struct async_info *async; \
354 async = talloc(req, struct async_info); \
355 if (!async) return NT_STATUS_NO_MEMORY; \
360 async->c_req = c_req; \
361 DLIST_ADD(p->pending, async); \
362 c_req->async.private_data = async; \
363 talloc_set_destructor(async, async_info_destructor); \
365 c_req->async.fn = async_fn; \
366 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
367 return NT_STATUS_OK; \
370 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
372 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple_smb2)
373 #define SIMPLE_COMPOSITE_TAIL ASYNC_RECV_TAIL(NULL, async_simple_composite)
375 #define CHECK_ASYNC(req) do { \
376 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { \
377 DEBUG(0,("SMB2 proxy backend does not support sync operation at %s\n", \
379 return NT_STATUS_NOT_IMPLEMENTED; \
383 delete a file - the dirtype specifies the file types to include in the search.
384 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
387 - doesn't handle wildcards
388 - doesn't obey attrib restrictions
390 static NTSTATUS
cvfs_unlink(struct ntvfs_module_context
*ntvfs
,
391 struct ntvfs_request
*req
, union smb_unlink
*unl
)
393 struct cvfs_private
*p
= ntvfs
->private_data
;
394 struct composite_context
*c_req
;
398 c_req
= smb2_composite_unlink_send(p
->tree
, unl
);
400 SIMPLE_COMPOSITE_TAIL
;
406 static NTSTATUS
cvfs_ioctl(struct ntvfs_module_context
*ntvfs
,
407 struct ntvfs_request
*req
, union smb_ioctl
*io
)
409 return NT_STATUS_NOT_IMPLEMENTED
;
413 check if a directory exists
415 static NTSTATUS
cvfs_chkpath(struct ntvfs_module_context
*ntvfs
,
416 struct ntvfs_request
*req
, union smb_chkpath
*cp
)
418 struct cvfs_private
*p
= ntvfs
->private_data
;
419 struct smb2_request
*c_req
;
424 /* SMB2 doesn't have a chkpath operation, and also doesn't
425 have a query path info call, so the best seems to be to do a
426 find call, using the roothandle we established at connect
429 f
.in
.file
.handle
= p
->roothandle
;
430 f
.in
.level
= SMB2_FIND_DIRECTORY_INFO
;
431 f
.in
.pattern
= cp
->chkpath
.in
.path
;
432 /* SMB2 find doesn't accept \ or the empty string - this is the best
434 if (strcmp(f
.in
.pattern
, "\\") == 0 ||
435 strcmp(f
.in
.pattern
, "") == 0) {
438 f
.in
.continue_flags
= SMB2_CONTINUE_FLAG_SINGLE
| SMB2_CONTINUE_FLAG_RESTART
;
439 f
.in
.max_response_size
= 0x1000;
441 c_req
= smb2_find_send(p
->tree
, &f
);
447 return info on a pathname
449 static NTSTATUS
cvfs_qpathinfo(struct ntvfs_module_context
*ntvfs
,
450 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
452 return NT_STATUS_NOT_IMPLEMENTED
;
456 query info on a open file
458 static NTSTATUS
cvfs_qfileinfo(struct ntvfs_module_context
*ntvfs
,
459 struct ntvfs_request
*req
, union smb_fileinfo
*io
)
461 return NT_STATUS_NOT_IMPLEMENTED
;
466 set info on a pathname
468 static NTSTATUS
cvfs_setpathinfo(struct ntvfs_module_context
*ntvfs
,
469 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
471 return NT_STATUS_NOT_IMPLEMENTED
;
478 static NTSTATUS
cvfs_open(struct ntvfs_module_context
*ntvfs
,
479 struct ntvfs_request
*req
, union smb_open
*io
)
481 return NT_STATUS_NOT_IMPLEMENTED
;
487 static NTSTATUS
cvfs_mkdir(struct ntvfs_module_context
*ntvfs
,
488 struct ntvfs_request
*req
, union smb_mkdir
*md
)
490 struct cvfs_private
*p
= ntvfs
->private_data
;
491 struct composite_context
*c_req
;
495 c_req
= smb2_composite_mkdir_send(p
->tree
, md
);
497 SIMPLE_COMPOSITE_TAIL
;
503 static NTSTATUS
cvfs_rmdir(struct ntvfs_module_context
*ntvfs
,
504 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
506 struct cvfs_private
*p
= ntvfs
->private_data
;
507 struct composite_context
*c_req
;
511 c_req
= smb2_composite_rmdir_send(p
->tree
, rd
);
513 SIMPLE_COMPOSITE_TAIL
;
517 rename a set of files
519 static NTSTATUS
cvfs_rename(struct ntvfs_module_context
*ntvfs
,
520 struct ntvfs_request
*req
, union smb_rename
*ren
)
522 return NT_STATUS_NOT_IMPLEMENTED
;
528 static NTSTATUS
cvfs_copy(struct ntvfs_module_context
*ntvfs
,
529 struct ntvfs_request
*req
, struct smb_copy
*cp
)
531 return NT_STATUS_NOT_SUPPORTED
;
537 static NTSTATUS
cvfs_read(struct ntvfs_module_context
*ntvfs
,
538 struct ntvfs_request
*req
, union smb_read
*io
)
540 return NT_STATUS_NOT_IMPLEMENTED
;
546 static NTSTATUS
cvfs_write(struct ntvfs_module_context
*ntvfs
,
547 struct ntvfs_request
*req
, union smb_write
*io
)
549 return NT_STATUS_NOT_IMPLEMENTED
;
555 static NTSTATUS
cvfs_seek(struct ntvfs_module_context
*ntvfs
,
556 struct ntvfs_request
*req
,
559 return NT_STATUS_NOT_IMPLEMENTED
;
565 static NTSTATUS
cvfs_flush(struct ntvfs_module_context
*ntvfs
,
566 struct ntvfs_request
*req
,
569 return NT_STATUS_NOT_IMPLEMENTED
;
575 static NTSTATUS
cvfs_close(struct ntvfs_module_context
*ntvfs
,
576 struct ntvfs_request
*req
, union smb_close
*io
)
578 return NT_STATUS_NOT_IMPLEMENTED
;
582 exit - closing files open by the pid
584 static NTSTATUS
cvfs_exit(struct ntvfs_module_context
*ntvfs
,
585 struct ntvfs_request
*req
)
587 return NT_STATUS_NOT_IMPLEMENTED
;
591 logoff - closing files open by the user
593 static NTSTATUS
cvfs_logoff(struct ntvfs_module_context
*ntvfs
,
594 struct ntvfs_request
*req
)
596 /* we can't do this right in the cifs backend .... */
601 setup for an async call - nothing to do yet
603 static NTSTATUS
cvfs_async_setup(struct ntvfs_module_context
*ntvfs
,
604 struct ntvfs_request
*req
,
613 static NTSTATUS
cvfs_cancel(struct ntvfs_module_context
*ntvfs
,
614 struct ntvfs_request
*req
)
616 return NT_STATUS_NOT_IMPLEMENTED
;
622 static NTSTATUS
cvfs_lock(struct ntvfs_module_context
*ntvfs
,
623 struct ntvfs_request
*req
, union smb_lock
*io
)
625 return NT_STATUS_NOT_IMPLEMENTED
;
629 set info on a open file
631 static NTSTATUS
cvfs_setfileinfo(struct ntvfs_module_context
*ntvfs
,
632 struct ntvfs_request
*req
,
633 union smb_setfileinfo
*io
)
635 return NT_STATUS_NOT_IMPLEMENTED
;
640 a handler for async fsinfo replies
642 static void async_fsinfo(struct smb2_request
*c_req
)
644 struct async_info
*async
= c_req
->async
.private_data
;
645 struct ntvfs_request
*req
= async
->req
;
646 req
->async_states
->status
= smb2_getinfo_fs_recv(c_req
, req
, async
->parms
);
648 req
->async_states
->send_fn(req
);
652 return filesystem space info
654 static NTSTATUS
cvfs_fsinfo(struct ntvfs_module_context
*ntvfs
,
655 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
657 struct cvfs_private
*p
= ntvfs
->private_data
;
658 struct smb2_request
*c_req
;
659 enum smb_fsinfo_level level
= fs
->generic
.level
;
664 /* some levels go straight through */
665 case RAW_QFS_VOLUME_INFORMATION
:
666 case RAW_QFS_SIZE_INFORMATION
:
667 case RAW_QFS_DEVICE_INFORMATION
:
668 case RAW_QFS_ATTRIBUTE_INFORMATION
:
669 case RAW_QFS_QUOTA_INFORMATION
:
670 case RAW_QFS_FULL_SIZE_INFORMATION
:
671 case RAW_QFS_OBJECTID_INFORMATION
:
674 /* some get mapped */
675 case RAW_QFS_VOLUME_INFO
:
676 level
= RAW_QFS_VOLUME_INFORMATION
;
678 case RAW_QFS_SIZE_INFO
:
679 level
= RAW_QFS_SIZE_INFORMATION
;
681 case RAW_QFS_DEVICE_INFO
:
682 level
= RAW_QFS_DEVICE_INFORMATION
;
684 case RAW_QFS_ATTRIBUTE_INFO
:
685 level
= RAW_QFS_ATTRIBUTE_INFO
;
689 /* the rest get refused for now */
690 DEBUG(0,("fsinfo level %u not possible on SMB2\n",
691 (unsigned)fs
->generic
.level
));
695 fs
->generic
.level
= level
;
696 fs
->generic
.handle
= p
->roothandle
;
698 c_req
= smb2_getinfo_fs_send(p
->tree
, fs
);
700 ASYNC_RECV_TAIL(fs
, async_fsinfo
);
704 return print queue info
706 static NTSTATUS
cvfs_lpq(struct ntvfs_module_context
*ntvfs
,
707 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
709 return NT_STATUS_NOT_SUPPORTED
;
713 list files in a directory matching a wildcard pattern
715 static NTSTATUS
cvfs_search_first(struct ntvfs_module_context
*ntvfs
,
716 struct ntvfs_request
*req
, union smb_search_first
*io
,
717 void *search_private
,
718 bool (*callback
)(void *, const union smb_search_data
*))
720 struct cvfs_private
*p
= ntvfs
->private_data
;
722 enum smb_search_data_level smb2_level
;
723 unsigned int count
, i
;
724 union smb_search_data
*data
;
727 if (io
->generic
.level
!= RAW_SEARCH_TRANS2
) {
728 DEBUG(0,("We only support trans2 search in smb2 backend\n"));
729 return NT_STATUS_NOT_SUPPORTED
;
732 switch (io
->generic
.data_level
) {
733 case RAW_SEARCH_DATA_DIRECTORY_INFO
:
734 smb2_level
= SMB2_FIND_DIRECTORY_INFO
;
736 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO
:
737 smb2_level
= SMB2_FIND_FULL_DIRECTORY_INFO
;
739 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO
:
740 smb2_level
= SMB2_FIND_BOTH_DIRECTORY_INFO
;
742 case RAW_SEARCH_DATA_NAME_INFO
:
743 smb2_level
= SMB2_FIND_NAME_INFO
;
745 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO
:
746 smb2_level
= SMB2_FIND_ID_FULL_DIRECTORY_INFO
;
748 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO
:
749 smb2_level
= SMB2_FIND_ID_BOTH_DIRECTORY_INFO
;
752 DEBUG(0,("Unsupported search level %u for smb2 backend\n",
753 (unsigned)io
->generic
.data_level
));
754 return NT_STATUS_INVALID_INFO_CLASS
;
757 /* we do the search on the roothandle. This only works because
758 search is synchronous, otherwise we'd have no way to
759 distinguish multiple searches happening at once
762 f
.in
.file
.handle
= p
->roothandle
;
763 f
.in
.level
= smb2_level
;
764 f
.in
.pattern
= io
->t2ffirst
.in
.pattern
;
765 while (f
.in
.pattern
[0] == '\\') {
768 f
.in
.continue_flags
= 0;
769 f
.in
.max_response_size
= 0x10000;
771 status
= smb2_find_level(p
->tree
, req
, &f
, &count
, &data
);
772 NT_STATUS_NOT_OK_RETURN(status
);
774 for (i
=0;i
<count
;i
++) {
775 if (!callback(search_private
, &data
[i
])) break;
778 io
->t2ffirst
.out
.handle
= 0;
779 io
->t2ffirst
.out
.count
= i
;
780 /* TODO: fix end_of_file */
781 io
->t2ffirst
.out
.end_of_search
= 1;
788 /* continue a search */
789 static NTSTATUS
cvfs_search_next(struct ntvfs_module_context
*ntvfs
,
790 struct ntvfs_request
*req
, union smb_search_next
*io
,
791 void *search_private
,
792 bool (*callback
)(void *, const union smb_search_data
*))
794 return NT_STATUS_NOT_IMPLEMENTED
;
798 static NTSTATUS
cvfs_search_close(struct ntvfs_module_context
*ntvfs
,
799 struct ntvfs_request
*req
, union smb_search_close
*io
)
801 return NT_STATUS_NOT_IMPLEMENTED
;
804 /* SMBtrans - not used on file shares */
805 static NTSTATUS
cvfs_trans(struct ntvfs_module_context
*ntvfs
,
806 struct ntvfs_request
*req
,
807 struct smb_trans2
*trans2
)
809 return NT_STATUS_ACCESS_DENIED
;
812 /* change notify request - always async */
813 static NTSTATUS
cvfs_notify(struct ntvfs_module_context
*ntvfs
,
814 struct ntvfs_request
*req
,
815 union smb_notify
*io
)
817 return NT_STATUS_NOT_IMPLEMENTED
;
821 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
823 NTSTATUS
ntvfs_smb2_init(void)
826 struct ntvfs_ops ops
;
827 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
831 /* fill in the name and type */
833 ops
.type
= NTVFS_DISK
;
835 /* fill in all the operations */
836 ops
.connect
= cvfs_connect
;
837 ops
.disconnect
= cvfs_disconnect
;
838 ops
.unlink
= cvfs_unlink
;
839 ops
.chkpath
= cvfs_chkpath
;
840 ops
.qpathinfo
= cvfs_qpathinfo
;
841 ops
.setpathinfo
= cvfs_setpathinfo
;
842 ops
.open
= cvfs_open
;
843 ops
.mkdir
= cvfs_mkdir
;
844 ops
.rmdir
= cvfs_rmdir
;
845 ops
.rename
= cvfs_rename
;
846 ops
.copy
= cvfs_copy
;
847 ops
.ioctl
= cvfs_ioctl
;
848 ops
.read
= cvfs_read
;
849 ops
.write
= cvfs_write
;
850 ops
.seek
= cvfs_seek
;
851 ops
.flush
= cvfs_flush
;
852 ops
.close
= cvfs_close
;
853 ops
.exit
= cvfs_exit
;
854 ops
.lock
= cvfs_lock
;
855 ops
.setfileinfo
= cvfs_setfileinfo
;
856 ops
.qfileinfo
= cvfs_qfileinfo
;
857 ops
.fsinfo
= cvfs_fsinfo
;
859 ops
.search_first
= cvfs_search_first
;
860 ops
.search_next
= cvfs_search_next
;
861 ops
.search_close
= cvfs_search_close
;
862 ops
.trans
= cvfs_trans
;
863 ops
.logoff
= cvfs_logoff
;
864 ops
.async_setup
= cvfs_async_setup
;
865 ops
.cancel
= cvfs_cancel
;
866 ops
.notify
= cvfs_notify
;
868 /* register ourselves with the NTVFS subsystem. We register
869 under the name 'smb2'. */
870 ret
= ntvfs_register(&ops
, &vers
);
872 if (!NT_STATUS_IS_OK(ret
)) {
873 DEBUG(0,("Failed to register SMB2 backend\n"));