2 Unix SMB/CIFS implementation.
4 CIFS-on-CIFS NTVFS filesystem backend
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) James J Myers 2003 <myersjj@samba.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 this implements a CIFS->CIFS NTVFS filesystem backend.
29 #include "lib/events/events.h"
30 #include "libcli/raw/libcliraw.h"
31 #include "libcli/composite/composite.h"
32 #include "libcli/smb_composite/smb_composite.h"
33 #include "smb_server/smb_server.h"
34 #include "smbd/service_stream.h"
35 #include "auth/auth.h"
37 /* this is stored in ntvfs_private */
39 struct smbcli_tree *tree;
40 struct smbcli_transport *transport;
41 struct smbsrv_tcon *tcon;
46 /* a structure used to pass information to an async handler */
48 struct smbsrv_request *req;
52 #define SETUP_PID private->tree->session->pid = SVAL(req->in.hdr, HDR_PID)
55 a handler for oplock break events from the server - these need to be passed
58 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
60 struct cvfs_private *private = p_private;
62 DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
63 return req_send_oplock_break(private->tcon, fnum, level);
67 a handler for read events on a connection to a backend server
69 static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde,
70 uint16_t flags, void *private)
72 struct cvfs_private *cvfs = talloc_get_type(private, struct cvfs_private);
73 struct smbsrv_tcon *tcon = cvfs->tcon;
75 if (!smbcli_transport_process(cvfs->transport)) {
76 /* the connection to our server is dead */
82 connect to a share - used when a tree_connect operation comes in.
84 static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
85 struct smbsrv_request *req, const char *sharename)
87 struct smbsrv_tcon *tcon = req->tcon;
89 struct cvfs_private *private;
90 const char *host, *user, *pass, *domain, *remote_share;
91 struct smb_composite_connect io;
92 struct composite_context *creq;
95 struct cli_credentials *credentials;
97 /* Here we need to determine which server to connect to.
98 * For now we use parametric options, type cifs.
99 * Later we will use security=server and auth_server.c.
101 host = lp_parm_string(req->tcon->service, "cifs", "server");
102 user = lp_parm_string(req->tcon->service, "cifs", "user");
103 pass = lp_parm_string(req->tcon->service, "cifs", "password");
104 domain = lp_parm_string(req->tcon->service, "cifs", "domain");
105 remote_share = lp_parm_string(req->tcon->service, "cifs", "share");
107 remote_share = sharename;
110 private = talloc(req->tcon, struct cvfs_private);
112 return NT_STATUS_NO_MEMORY;
114 ZERO_STRUCTP(private);
116 ntvfs->private_data = private;
119 DEBUG(1,("CIFS backend: You must supply server\n"));
120 return NT_STATUS_INVALID_PARAMETER;
123 if (user && pass && domain) {
124 credentials = cli_credentials_init(private);
125 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
126 cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
127 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
128 cli_credentials_set_workstation(credentials, "vfs_cifs", CRED_SPECIFIED);
129 } else if (req->session->session_info->credentials) {
130 credentials = req->session->session_info->credentials;
132 DEBUG(1,("CIFS backend: You must supply server, user, password and domain or have delegated credentials\n"));
133 return NT_STATUS_INVALID_PARAMETER;
136 /* connect to the server, using the smbd event context */
137 io.in.dest_host = host;
139 io.in.called_name = host;
140 io.in.credentials = credentials;
141 io.in.fallback_to_anonymous = False;
142 io.in.workgroup = lp_workgroup();
143 io.in.service = remote_share;
144 io.in.service_type = "?????";
146 creq = smb_composite_connect_send(&io, private, tcon->smb_conn->connection->event.ctx);
147 status = smb_composite_connect_recv(creq, private);
148 NT_STATUS_NOT_OK_RETURN(status);
150 private->tree = io.out.tree;
152 private->transport = private->tree->session->transport;
154 private->tcon = req->tcon;
156 tcon->fs_type = talloc_strdup(tcon, "NTFS");
157 tcon->dev_type = talloc_strdup(tcon, "A:");
159 /* we need to receive oplock break requests from the server */
160 smbcli_oplock_handler(private->transport, oplock_handler, private);
162 /* take over event handling for this socket */
163 talloc_free(private->transport->socket->event.fde);
164 fde = event_add_fd(private->transport->socket->event.ctx,
166 socket_get_fd(private->transport->socket->sock),
167 EVENT_FD_READ | EVENT_FD_WRITE,
170 private->transport->socket->event.fde = fde;
173 private->map_generic = lp_parm_bool(req->tcon->service,
174 "cifs", "mapgeneric", False);
180 disconnect from a share
182 static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs,
183 struct smbsrv_tcon *tcon)
185 struct cvfs_private *private = ntvfs->private_data;
187 talloc_free(private);
193 a handler for simple async replies
194 this handler can only be used for functions that don't return any
195 parameters (those that just return a status code)
197 static void async_simple(struct smbcli_request *c_req)
199 struct async_info *async = c_req->async.private;
200 struct smbsrv_request *req = async->req;
201 req->async_states->status = smbcli_request_simple_recv(c_req);
202 req->async_states->send_fn(req);
206 /* save some typing for the simple functions */
207 #define ASYNC_RECV_TAIL(io, async_fn) do { \
208 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
210 struct async_info *async; \
211 async = talloc(req, struct async_info); \
212 if (!async) return NT_STATUS_NO_MEMORY; \
215 c_req->async.private = async; \
217 c_req->async.fn = async_fn; \
218 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
219 return NT_STATUS_OK; \
222 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
225 delete a file - the dirtype specifies the file types to include in the search.
226 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
228 static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs,
229 struct smbsrv_request *req, struct smb_unlink *unl)
231 struct cvfs_private *private = ntvfs->private_data;
232 struct smbcli_request *c_req;
236 /* see if the front end will allow us to perform this
237 function asynchronously. */
238 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
239 return smb_raw_unlink(private->tree, unl);
242 c_req = smb_raw_unlink_send(private->tree, unl);
248 a handler for async ioctl replies
250 static void async_ioctl(struct smbcli_request *c_req)
252 struct async_info *async = c_req->async.private;
253 struct smbsrv_request *req = async->req;
254 req->async_states->status = smb_raw_ioctl_recv(c_req, req, async->parms);
255 req->async_states->send_fn(req);
261 static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs,
262 struct smbsrv_request *req, union smb_ioctl *io)
264 struct cvfs_private *private = ntvfs->private_data;
265 struct smbcli_request *c_req;
269 /* see if the front end will allow us to perform this
270 function asynchronously. */
271 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
272 return smb_raw_ioctl(private->tree, req, io);
275 c_req = smb_raw_ioctl_send(private->tree, io);
277 ASYNC_RECV_TAIL(io, async_ioctl);
281 check if a directory exists
283 static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs,
284 struct smbsrv_request *req, struct smb_chkpath *cp)
286 struct cvfs_private *private = ntvfs->private_data;
287 struct smbcli_request *c_req;
291 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
292 return smb_raw_chkpath(private->tree, cp);
295 c_req = smb_raw_chkpath_send(private->tree, cp);
301 a handler for async qpathinfo replies
303 static void async_qpathinfo(struct smbcli_request *c_req)
305 struct async_info *async = c_req->async.private;
306 struct smbsrv_request *req = async->req;
307 req->async_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms);
308 req->async_states->send_fn(req);
312 return info on a pathname
314 static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs,
315 struct smbsrv_request *req, union smb_fileinfo *info)
317 struct cvfs_private *private = ntvfs->private_data;
318 struct smbcli_request *c_req;
322 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
323 return smb_raw_pathinfo(private->tree, req, info);
326 c_req = smb_raw_pathinfo_send(private->tree, info);
328 ASYNC_RECV_TAIL(info, async_qpathinfo);
332 a handler for async qfileinfo replies
334 static void async_qfileinfo(struct smbcli_request *c_req)
336 struct async_info *async = c_req->async.private;
337 struct smbsrv_request *req = async->req;
338 req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms);
339 req->async_states->send_fn(req);
343 query info on a open file
345 static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
346 struct smbsrv_request *req, union smb_fileinfo *info)
348 struct cvfs_private *private = ntvfs->private_data;
349 struct smbcli_request *c_req;
353 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
354 return smb_raw_fileinfo(private->tree, req, info);
357 c_req = smb_raw_fileinfo_send(private->tree, info);
359 ASYNC_RECV_TAIL(info, async_qfileinfo);
364 set info on a pathname
366 static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
367 struct smbsrv_request *req, union smb_setfileinfo *st)
369 struct cvfs_private *private = ntvfs->private_data;
370 struct smbcli_request *c_req;
374 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
375 return smb_raw_setpathinfo(private->tree, st);
378 c_req = smb_raw_setpathinfo_send(private->tree, st);
385 a handler for async open replies
387 static void async_open(struct smbcli_request *c_req)
389 struct async_info *async = c_req->async.private;
390 struct smbsrv_request *req = async->req;
391 req->async_states->status = smb_raw_open_recv(c_req, req, async->parms);
392 req->async_states->send_fn(req);
398 static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs,
399 struct smbsrv_request *req, union smb_open *io)
401 struct cvfs_private *private = ntvfs->private_data;
402 struct smbcli_request *c_req;
406 if (io->generic.level != RAW_OPEN_GENERIC &&
407 private->map_generic) {
408 return ntvfs_map_open(req, io, ntvfs);
411 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
412 return smb_raw_open(private->tree, req, io);
415 c_req = smb_raw_open_send(private->tree, io);
417 ASYNC_RECV_TAIL(io, async_open);
423 static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs,
424 struct smbsrv_request *req, union smb_mkdir *md)
426 struct cvfs_private *private = ntvfs->private_data;
427 struct smbcli_request *c_req;
431 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
432 return smb_raw_mkdir(private->tree, md);
435 c_req = smb_raw_mkdir_send(private->tree, md);
443 static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs,
444 struct smbsrv_request *req, struct smb_rmdir *rd)
446 struct cvfs_private *private = ntvfs->private_data;
447 struct smbcli_request *c_req;
451 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
452 return smb_raw_rmdir(private->tree, rd);
454 c_req = smb_raw_rmdir_send(private->tree, rd);
460 rename a set of files
462 static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs,
463 struct smbsrv_request *req, union smb_rename *ren)
465 struct cvfs_private *private = ntvfs->private_data;
466 struct smbcli_request *c_req;
470 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
471 return smb_raw_rename(private->tree, ren);
474 c_req = smb_raw_rename_send(private->tree, ren);
482 static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs,
483 struct smbsrv_request *req, struct smb_copy *cp)
485 return NT_STATUS_NOT_SUPPORTED;
489 a handler for async read replies
491 static void async_read(struct smbcli_request *c_req)
493 struct async_info *async = c_req->async.private;
494 struct smbsrv_request *req = async->req;
495 req->async_states->status = smb_raw_read_recv(c_req, async->parms);
496 req->async_states->send_fn(req);
502 static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs,
503 struct smbsrv_request *req, union smb_read *rd)
505 struct cvfs_private *private = ntvfs->private_data;
506 struct smbcli_request *c_req;
510 if (rd->generic.level != RAW_READ_GENERIC &&
511 private->map_generic) {
512 return ntvfs_map_read(req, rd, ntvfs);
515 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
516 return smb_raw_read(private->tree, rd);
519 c_req = smb_raw_read_send(private->tree, rd);
521 ASYNC_RECV_TAIL(rd, async_read);
525 a handler for async write replies
527 static void async_write(struct smbcli_request *c_req)
529 struct async_info *async = c_req->async.private;
530 struct smbsrv_request *req = async->req;
531 req->async_states->status = smb_raw_write_recv(c_req, async->parms);
532 req->async_states->send_fn(req);
538 static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs,
539 struct smbsrv_request *req, union smb_write *wr)
541 struct cvfs_private *private = ntvfs->private_data;
542 struct smbcli_request *c_req;
546 if (wr->generic.level != RAW_WRITE_GENERIC &&
547 private->map_generic) {
548 return ntvfs_map_write(req, wr, ntvfs);
551 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
552 return smb_raw_write(private->tree, wr);
555 c_req = smb_raw_write_send(private->tree, wr);
557 ASYNC_RECV_TAIL(wr, async_write);
561 a handler for async seek replies
563 static void async_seek(struct smbcli_request *c_req)
565 struct async_info *async = c_req->async.private;
566 struct smbsrv_request *req = async->req;
567 req->async_states->status = smb_raw_seek_recv(c_req, async->parms);
568 req->async_states->send_fn(req);
574 static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs,
575 struct smbsrv_request *req, struct smb_seek *io)
577 struct cvfs_private *private = ntvfs->private_data;
578 struct smbcli_request *c_req;
582 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
583 return smb_raw_seek(private->tree, io);
586 c_req = smb_raw_seek_send(private->tree, io);
588 ASYNC_RECV_TAIL(io, async_seek);
594 static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs,
595 struct smbsrv_request *req, struct smb_flush *io)
597 struct cvfs_private *private = ntvfs->private_data;
598 struct smbcli_request *c_req;
602 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
603 return smb_raw_flush(private->tree, io);
606 c_req = smb_raw_flush_send(private->tree, io);
614 static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs,
615 struct smbsrv_request *req, union smb_close *io)
617 struct cvfs_private *private = ntvfs->private_data;
618 struct smbcli_request *c_req;
622 if (io->generic.level != RAW_CLOSE_GENERIC &&
623 private->map_generic) {
624 return ntvfs_map_close(req, io, ntvfs);
627 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
628 return smb_raw_close(private->tree, io);
631 c_req = smb_raw_close_send(private->tree, io);
637 exit - closing files open by the pid
639 static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs,
640 struct smbsrv_request *req)
642 struct cvfs_private *private = ntvfs->private_data;
643 struct smbcli_request *c_req;
647 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
648 return smb_raw_exit(private->tree->session);
651 c_req = smb_raw_exit_send(private->tree->session);
657 logoff - closing files open by the user
659 static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs,
660 struct smbsrv_request *req)
662 /* we can't do this right in the cifs backend .... */
667 setup for an async call - nothing to do yet
669 static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs,
670 struct smbsrv_request *req,
679 static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs,
680 struct smbsrv_request *req)
682 return NT_STATUS_NOT_IMPLEMENTED;
688 static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs,
689 struct smbsrv_request *req, union smb_lock *lck)
691 struct cvfs_private *private = ntvfs->private_data;
692 struct smbcli_request *c_req;
696 if (lck->generic.level != RAW_LOCK_GENERIC &&
697 private->map_generic) {
698 return ntvfs_map_lock(req, lck, ntvfs);
701 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
702 return smb_raw_lock(private->tree, lck);
705 c_req = smb_raw_lock_send(private->tree, lck);
710 set info on a open file
712 static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
713 struct smbsrv_request *req,
714 union smb_setfileinfo *info)
716 struct cvfs_private *private = ntvfs->private_data;
717 struct smbcli_request *c_req;
721 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
722 return smb_raw_setfileinfo(private->tree, info);
724 c_req = smb_raw_setfileinfo_send(private->tree, info);
731 a handler for async fsinfo replies
733 static void async_fsinfo(struct smbcli_request *c_req)
735 struct async_info *async = c_req->async.private;
736 struct smbsrv_request *req = async->req;
737 req->async_states->status = smb_raw_fsinfo_recv(c_req, req, async->parms);
738 req->async_states->send_fn(req);
742 return filesystem space info
744 static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs,
745 struct smbsrv_request *req, union smb_fsinfo *fs)
747 struct cvfs_private *private = ntvfs->private_data;
748 struct smbcli_request *c_req;
752 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
753 return smb_raw_fsinfo(private->tree, req, fs);
756 c_req = smb_raw_fsinfo_send(private->tree, req, fs);
758 ASYNC_RECV_TAIL(fs, async_fsinfo);
762 return print queue info
764 static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs,
765 struct smbsrv_request *req, union smb_lpq *lpq)
767 return NT_STATUS_NOT_SUPPORTED;
771 list files in a directory matching a wildcard pattern
773 static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs,
774 struct smbsrv_request *req, union smb_search_first *io,
775 void *search_private,
776 BOOL (*callback)(void *, union smb_search_data *))
778 struct cvfs_private *private = ntvfs->private_data;
782 return smb_raw_search_first(private->tree, req, io, search_private, callback);
785 /* continue a search */
786 static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs,
787 struct smbsrv_request *req, union smb_search_next *io,
788 void *search_private,
789 BOOL (*callback)(void *, union smb_search_data *))
791 struct cvfs_private *private = ntvfs->private_data;
795 return smb_raw_search_next(private->tree, req, io, search_private, callback);
799 static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs,
800 struct smbsrv_request *req, union smb_search_close *io)
802 struct cvfs_private *private = ntvfs->private_data;
806 return smb_raw_search_close(private->tree, io);
810 a handler for async trans2 replies
812 static void async_trans2(struct smbcli_request *c_req)
814 struct async_info *async = c_req->async.private;
815 struct smbsrv_request *req = async->req;
816 req->async_states->status = smb_raw_trans2_recv(c_req, req, async->parms);
817 req->async_states->send_fn(req);
821 static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs,
822 struct smbsrv_request *req, struct smb_trans2 *trans2)
824 struct cvfs_private *private = ntvfs->private_data;
825 struct smbcli_request *c_req;
829 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
830 return smb_raw_trans2(private->tree, req, trans2);
833 c_req = smb_raw_trans2_send(private->tree, trans2);
835 ASYNC_RECV_TAIL(trans2, async_trans2);
839 /* SMBtrans - not used on file shares */
840 static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs,
841 struct smbsrv_request *req, struct smb_trans2 *trans2)
843 return NT_STATUS_ACCESS_DENIED;
847 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
849 NTSTATUS ntvfs_cifs_init(void)
852 struct ntvfs_ops ops;
856 /* fill in the name and type */
858 ops.type = NTVFS_DISK;
860 /* fill in all the operations */
861 ops.connect = cvfs_connect;
862 ops.disconnect = cvfs_disconnect;
863 ops.unlink = cvfs_unlink;
864 ops.chkpath = cvfs_chkpath;
865 ops.qpathinfo = cvfs_qpathinfo;
866 ops.setpathinfo = cvfs_setpathinfo;
867 ops.openfile = cvfs_open;
868 ops.mkdir = cvfs_mkdir;
869 ops.rmdir = cvfs_rmdir;
870 ops.rename = cvfs_rename;
871 ops.copy = cvfs_copy;
872 ops.ioctl = cvfs_ioctl;
873 ops.read = cvfs_read;
874 ops.write = cvfs_write;
875 ops.seek = cvfs_seek;
876 ops.flush = cvfs_flush;
877 ops.close = cvfs_close;
878 ops.exit = cvfs_exit;
879 ops.lock = cvfs_lock;
880 ops.setfileinfo = cvfs_setfileinfo;
881 ops.qfileinfo = cvfs_qfileinfo;
882 ops.fsinfo = cvfs_fsinfo;
884 ops.search_first = cvfs_search_first;
885 ops.search_next = cvfs_search_next;
886 ops.search_close = cvfs_search_close;
887 ops.trans = cvfs_trans;
888 ops.logoff = cvfs_logoff;
889 ops.async_setup = cvfs_async_setup;
890 ops.cancel = cvfs_cancel;
892 if (lp_parm_bool(-1, "cifs", "maptrans2", False)) {
893 ops.trans2 = cvfs_trans2;
896 /* register ourselves with the NTVFS subsystem. We register
897 under the name 'cifs'. */
898 ret = ntvfs_register(&ops);
900 if (!NT_STATUS_IS_OK(ret)) {
901 DEBUG(0,("Failed to register CIFS backend!\n"));