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 3 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, see <http://www.gnu.org/licenses/>.
23 this implements a CIFS->CIFS NTVFS filesystem backend.
28 #include "libcli/raw/libcliraw.h"
29 #include "libcli/smb_composite/smb_composite.h"
30 #include "auth/auth.h"
31 #include "auth/credentials/credentials.h"
32 #include "ntvfs/ntvfs.h"
33 #include "lib/util/dlinklist.h"
34 #include "param/param.h"
37 struct cvfs_file *prev, *next;
39 struct ntvfs_handle *h;
42 /* this is stored in ntvfs_private */
44 struct smbcli_tree *tree;
45 struct smbcli_transport *transport;
46 struct ntvfs_module_context *ntvfs;
47 struct async_info *pending;
48 struct cvfs_file *files;
54 /* a structure used to pass information to an async handler */
56 struct async_info *next, *prev;
57 struct cvfs_private *cvfs;
58 struct ntvfs_request *req;
59 struct smbcli_request *c_req;
64 #define SETUP_PID private->tree->session->pid = req->smbpid
66 #define SETUP_FILE do { \
67 struct cvfs_file *f; \
68 f = ntvfs_handle_get_backend_data(io->generic.in.file.ntvfs, ntvfs); \
69 if (!f) return NT_STATUS_INVALID_HANDLE; \
70 io->generic.in.file.fnum = f->fnum; \
73 #define SETUP_PID_AND_FILE do { \
78 #define CIFS_SERVER "cifs:server"
79 #define CIFS_USER "cifs:user"
80 #define CIFS_PASSWORD "cifs:password"
81 #define CIFS_DOMAIN "cifs:domain"
82 #define CIFS_SHARE "cifs:share"
83 #define CIFS_USE_MACHINE_ACCT "cifs:use-machine-account"
84 #define CIFS_MAP_GENERIC "cifs:map-generic"
85 #define CIFS_MAP_TRANS2 "cifs:map-trans2"
87 #define CIFS_USE_MACHINE_ACCT_DEFAULT false
88 #define CIFS_MAP_GENERIC_DEFAULT false
89 #define CIFS_MAP_TRANS2_DEFAULT true
92 a handler for oplock break events from the server - these need to be passed
95 static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
97 struct cvfs_private *private = p_private;
99 struct ntvfs_handle *h = NULL;
102 for (f=private->files; f; f=f->next) {
103 if (f->fnum != fnum) continue;
109 DEBUG(5,("vfs_cifs: ignoring oplock break level %d for fnum %d\n", level, fnum));
113 DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
114 status = ntvfs_send_oplock_break(private->ntvfs, h, level);
115 if (!NT_STATUS_IS_OK(status)) return false;
120 connect to a share - used when a tree_connect operation comes in.
122 static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
123 struct ntvfs_request *req, const char *sharename)
126 struct cvfs_private *private;
127 const char *host, *user, *pass, *domain, *remote_share;
128 struct smb_composite_connect io;
129 struct composite_context *creq;
130 struct share_config *scfg = ntvfs->ctx->config;
132 struct cli_credentials *credentials;
133 bool machine_account;
135 /* Here we need to determine which server to connect to.
136 * For now we use parametric options, type cifs.
137 * Later we will use security=server and auth_server.c.
139 host = share_string_option(scfg, CIFS_SERVER, NULL);
140 user = share_string_option(scfg, CIFS_USER, NULL);
141 pass = share_string_option(scfg, CIFS_PASSWORD, NULL);
142 domain = share_string_option(scfg, CIFS_DOMAIN, NULL);
143 remote_share = share_string_option(scfg, CIFS_SHARE, NULL);
145 remote_share = sharename;
148 machine_account = share_bool_option(scfg, CIFS_USE_MACHINE_ACCT, CIFS_USE_MACHINE_ACCT_DEFAULT);
150 private = talloc_zero(ntvfs, struct cvfs_private);
152 return NT_STATUS_NO_MEMORY;
155 ntvfs->private_data = private;
158 DEBUG(1,("CIFS backend: You must supply server\n"));
159 return NT_STATUS_INVALID_PARAMETER;
163 DEBUG(5, ("CIFS backend: Using specified password\n"));
164 credentials = cli_credentials_init(private);
166 return NT_STATUS_NO_MEMORY;
168 cli_credentials_set_event_context(credentials, ntvfs->ctx->event_ctx);
169 cli_credentials_set_conf(credentials, global_loadparm);
170 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
172 cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
174 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
175 } else if (machine_account) {
176 DEBUG(5, ("CIFS backend: Using machine account\n"));
177 credentials = cli_credentials_init(private);
178 cli_credentials_set_event_context(credentials, ntvfs->ctx->event_ctx);
179 cli_credentials_set_conf(credentials, global_loadparm);
181 cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
183 status = cli_credentials_set_machine_account(credentials);
184 if (!NT_STATUS_IS_OK(status)) {
187 } else if (req->session_info->credentials) {
188 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
189 credentials = req->session_info->credentials;
191 DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
192 return NT_STATUS_INVALID_PARAMETER;
195 /* connect to the server, using the smbd event context */
196 io.in.dest_host = host;
198 io.in.called_name = host;
199 io.in.credentials = credentials;
200 io.in.fallback_to_anonymous = false;
201 io.in.workgroup = lp_workgroup(global_loadparm);
202 io.in.service = remote_share;
203 io.in.service_type = "?????";
205 creq = smb_composite_connect_send(&io, private, ntvfs->ctx->event_ctx);
206 status = smb_composite_connect_recv(creq, private);
207 NT_STATUS_NOT_OK_RETURN(status);
209 private->tree = io.out.tree;
211 private->transport = private->tree->session->transport;
213 private->ntvfs = ntvfs;
215 ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
216 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
217 ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
218 NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
220 /* we need to receive oplock break requests from the server */
221 smbcli_oplock_handler(private->transport, oplock_handler, private);
223 private->map_generic = share_bool_option(scfg, CIFS_MAP_GENERIC, CIFS_MAP_GENERIC_DEFAULT);
225 private->map_trans2 = share_bool_option(scfg, CIFS_MAP_TRANS2, CIFS_MAP_TRANS2_DEFAULT);
231 disconnect from a share
233 static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs)
235 struct cvfs_private *private = ntvfs->private_data;
236 struct async_info *a, *an;
238 /* first cleanup pending requests */
239 for (a=private->pending; a; a = an) {
241 smbcli_request_destroy(a->c_req);
245 talloc_free(private);
246 ntvfs->private_data = NULL;
252 destroy an async info structure
254 static int async_info_destructor(struct async_info *async)
256 DLIST_REMOVE(async->cvfs->pending, async);
261 a handler for simple async replies
262 this handler can only be used for functions that don't return any
263 parameters (those that just return a status code)
265 static void async_simple(struct smbcli_request *c_req)
267 struct async_info *async = c_req->async.private;
268 struct ntvfs_request *req = async->req;
269 req->async_states->status = smbcli_request_simple_recv(c_req);
271 req->async_states->send_fn(req);
275 /* save some typing for the simple functions */
276 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
277 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
279 struct async_info *async; \
280 async = talloc(req, struct async_info); \
281 if (!async) return NT_STATUS_NO_MEMORY; \
285 async->cvfs = private; \
286 async->c_req = c_req; \
287 DLIST_ADD(private->pending, async); \
288 c_req->async.private = async; \
289 talloc_set_destructor(async, async_info_destructor); \
291 c_req->async.fn = async_fn; \
292 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
293 return NT_STATUS_OK; \
296 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
298 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
301 delete a file - the dirtype specifies the file types to include in the search.
302 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
304 static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs,
305 struct ntvfs_request *req, union smb_unlink *unl)
307 struct cvfs_private *private = ntvfs->private_data;
308 struct smbcli_request *c_req;
312 /* see if the front end will allow us to perform this
313 function asynchronously. */
314 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
315 return smb_raw_unlink(private->tree, unl);
318 c_req = smb_raw_unlink_send(private->tree, unl);
324 a handler for async ioctl replies
326 static void async_ioctl(struct smbcli_request *c_req)
328 struct async_info *async = c_req->async.private;
329 struct ntvfs_request *req = async->req;
330 req->async_states->status = smb_raw_ioctl_recv(c_req, req, async->parms);
332 req->async_states->send_fn(req);
338 static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs,
339 struct ntvfs_request *req, union smb_ioctl *io)
341 struct cvfs_private *private = ntvfs->private_data;
342 struct smbcli_request *c_req;
346 /* see if the front end will allow us to perform this
347 function asynchronously. */
348 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
349 return smb_raw_ioctl(private->tree, req, io);
352 c_req = smb_raw_ioctl_send(private->tree, io);
354 ASYNC_RECV_TAIL(io, async_ioctl);
358 check if a directory exists
360 static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs,
361 struct ntvfs_request *req, union smb_chkpath *cp)
363 struct cvfs_private *private = ntvfs->private_data;
364 struct smbcli_request *c_req;
368 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
369 return smb_raw_chkpath(private->tree, cp);
372 c_req = smb_raw_chkpath_send(private->tree, cp);
378 a handler for async qpathinfo replies
380 static void async_qpathinfo(struct smbcli_request *c_req)
382 struct async_info *async = c_req->async.private;
383 struct ntvfs_request *req = async->req;
384 req->async_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms);
386 req->async_states->send_fn(req);
390 return info on a pathname
392 static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs,
393 struct ntvfs_request *req, union smb_fileinfo *info)
395 struct cvfs_private *private = ntvfs->private_data;
396 struct smbcli_request *c_req;
400 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
401 return smb_raw_pathinfo(private->tree, req, info);
404 c_req = smb_raw_pathinfo_send(private->tree, info);
406 ASYNC_RECV_TAIL(info, async_qpathinfo);
410 a handler for async qfileinfo replies
412 static void async_qfileinfo(struct smbcli_request *c_req)
414 struct async_info *async = c_req->async.private;
415 struct ntvfs_request *req = async->req;
416 req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms);
418 req->async_states->send_fn(req);
422 query info on a open file
424 static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
425 struct ntvfs_request *req, union smb_fileinfo *io)
427 struct cvfs_private *private = ntvfs->private_data;
428 struct smbcli_request *c_req;
432 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
433 return smb_raw_fileinfo(private->tree, req, io);
436 c_req = smb_raw_fileinfo_send(private->tree, io);
438 ASYNC_RECV_TAIL(io, async_qfileinfo);
443 set info on a pathname
445 static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
446 struct ntvfs_request *req, union smb_setfileinfo *st)
448 struct cvfs_private *private = ntvfs->private_data;
449 struct smbcli_request *c_req;
453 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
454 return smb_raw_setpathinfo(private->tree, st);
457 c_req = smb_raw_setpathinfo_send(private->tree, st);
464 a handler for async open replies
466 static void async_open(struct smbcli_request *c_req)
468 struct async_info *async = c_req->async.private;
469 struct cvfs_private *cvfs = async->cvfs;
470 struct ntvfs_request *req = async->req;
471 struct cvfs_file *f = async->f;
472 union smb_open *io = async->parms;
473 union smb_handle *file;
475 req->async_states->status = smb_raw_open_recv(c_req, req, io);
476 SMB_OPEN_OUT_FILE(io, file);
477 f->fnum = file->fnum;
479 if (!NT_STATUS_IS_OK(req->async_states->status)) goto failed;
480 req->async_states->status = ntvfs_handle_set_backend_data(f->h, cvfs->ntvfs, f);
481 if (!NT_STATUS_IS_OK(req->async_states->status)) goto failed;
484 req->async_states->send_fn(req);
490 static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs,
491 struct ntvfs_request *req, union smb_open *io)
493 struct cvfs_private *private = ntvfs->private_data;
494 struct smbcli_request *c_req;
495 struct ntvfs_handle *h;
501 if (io->generic.level != RAW_OPEN_GENERIC &&
502 private->map_generic) {
503 return ntvfs_map_open(ntvfs, req, io);
506 status = ntvfs_handle_new(ntvfs, req, &h);
507 NT_STATUS_NOT_OK_RETURN(status);
509 f = talloc_zero(h, struct cvfs_file);
510 NT_STATUS_HAVE_NO_MEMORY(f);
513 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
514 union smb_handle *file;
516 status = smb_raw_open(private->tree, req, io);
517 NT_STATUS_NOT_OK_RETURN(status);
519 SMB_OPEN_OUT_FILE(io, file);
520 f->fnum = file->fnum;
522 status = ntvfs_handle_set_backend_data(f->h, private->ntvfs, f);
523 NT_STATUS_NOT_OK_RETURN(status);
529 c_req = smb_raw_open_send(private->tree, io);
531 ASYNC_RECV_TAIL_F(io, async_open, f);
537 static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs,
538 struct ntvfs_request *req, union smb_mkdir *md)
540 struct cvfs_private *private = ntvfs->private_data;
541 struct smbcli_request *c_req;
545 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
546 return smb_raw_mkdir(private->tree, md);
549 c_req = smb_raw_mkdir_send(private->tree, md);
557 static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs,
558 struct ntvfs_request *req, struct smb_rmdir *rd)
560 struct cvfs_private *private = ntvfs->private_data;
561 struct smbcli_request *c_req;
565 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
566 return smb_raw_rmdir(private->tree, rd);
568 c_req = smb_raw_rmdir_send(private->tree, rd);
574 rename a set of files
576 static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs,
577 struct ntvfs_request *req, union smb_rename *ren)
579 struct cvfs_private *private = ntvfs->private_data;
580 struct smbcli_request *c_req;
584 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
585 return smb_raw_rename(private->tree, ren);
588 c_req = smb_raw_rename_send(private->tree, ren);
596 static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs,
597 struct ntvfs_request *req, struct smb_copy *cp)
599 return NT_STATUS_NOT_SUPPORTED;
603 a handler for async read replies
605 static void async_read(struct smbcli_request *c_req)
607 struct async_info *async = c_req->async.private;
608 struct ntvfs_request *req = async->req;
609 req->async_states->status = smb_raw_read_recv(c_req, async->parms);
611 req->async_states->send_fn(req);
617 static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs,
618 struct ntvfs_request *req, union smb_read *io)
620 struct cvfs_private *private = ntvfs->private_data;
621 struct smbcli_request *c_req;
625 if (io->generic.level != RAW_READ_GENERIC &&
626 private->map_generic) {
627 return ntvfs_map_read(ntvfs, req, io);
632 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
633 return smb_raw_read(private->tree, io);
636 c_req = smb_raw_read_send(private->tree, io);
638 ASYNC_RECV_TAIL(io, async_read);
642 a handler for async write replies
644 static void async_write(struct smbcli_request *c_req)
646 struct async_info *async = c_req->async.private;
647 struct ntvfs_request *req = async->req;
648 req->async_states->status = smb_raw_write_recv(c_req, async->parms);
650 req->async_states->send_fn(req);
656 static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs,
657 struct ntvfs_request *req, union smb_write *io)
659 struct cvfs_private *private = ntvfs->private_data;
660 struct smbcli_request *c_req;
664 if (io->generic.level != RAW_WRITE_GENERIC &&
665 private->map_generic) {
666 return ntvfs_map_write(ntvfs, req, io);
670 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
671 return smb_raw_write(private->tree, io);
674 c_req = smb_raw_write_send(private->tree, io);
676 ASYNC_RECV_TAIL(io, async_write);
680 a handler for async seek replies
682 static void async_seek(struct smbcli_request *c_req)
684 struct async_info *async = c_req->async.private;
685 struct ntvfs_request *req = async->req;
686 req->async_states->status = smb_raw_seek_recv(c_req, async->parms);
688 req->async_states->send_fn(req);
694 static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs,
695 struct ntvfs_request *req,
698 struct cvfs_private *private = ntvfs->private_data;
699 struct smbcli_request *c_req;
703 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
704 return smb_raw_seek(private->tree, io);
707 c_req = smb_raw_seek_send(private->tree, io);
709 ASYNC_RECV_TAIL(io, async_seek);
715 static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs,
716 struct ntvfs_request *req,
719 struct cvfs_private *private = ntvfs->private_data;
720 struct smbcli_request *c_req;
723 switch (io->generic.level) {
724 case RAW_FLUSH_FLUSH:
728 io->generic.in.file.fnum = 0xFFFF;
731 return NT_STATUS_INVALID_LEVEL;
734 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
735 return smb_raw_flush(private->tree, io);
738 c_req = smb_raw_flush_send(private->tree, io);
746 static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs,
747 struct ntvfs_request *req, union smb_close *io)
749 struct cvfs_private *private = ntvfs->private_data;
750 struct smbcli_request *c_req;
754 if (io->generic.level != RAW_CLOSE_GENERIC &&
755 private->map_generic) {
756 return ntvfs_map_close(ntvfs, req, io);
760 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
761 return smb_raw_close(private->tree, io);
764 c_req = smb_raw_close_send(private->tree, io);
770 exit - closing files open by the pid
772 static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs,
773 struct ntvfs_request *req)
775 struct cvfs_private *private = ntvfs->private_data;
776 struct smbcli_request *c_req;
780 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
781 return smb_raw_exit(private->tree->session);
784 c_req = smb_raw_exit_send(private->tree->session);
790 logoff - closing files open by the user
792 static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs,
793 struct ntvfs_request *req)
795 /* we can't do this right in the cifs backend .... */
800 setup for an async call - nothing to do yet
802 static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs,
803 struct ntvfs_request *req,
812 static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs,
813 struct ntvfs_request *req)
815 struct cvfs_private *private = ntvfs->private_data;
816 struct async_info *a;
818 /* find the matching request */
819 for (a=private->pending;a;a=a->next) {
826 return NT_STATUS_INVALID_PARAMETER;
829 return smb_raw_ntcancel(a->c_req);
835 static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs,
836 struct ntvfs_request *req, union smb_lock *io)
838 struct cvfs_private *private = ntvfs->private_data;
839 struct smbcli_request *c_req;
843 if (io->generic.level != RAW_LOCK_GENERIC &&
844 private->map_generic) {
845 return ntvfs_map_lock(ntvfs, req, io);
849 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
850 return smb_raw_lock(private->tree, io);
853 c_req = smb_raw_lock_send(private->tree, io);
858 set info on a open file
860 static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
861 struct ntvfs_request *req,
862 union smb_setfileinfo *io)
864 struct cvfs_private *private = ntvfs->private_data;
865 struct smbcli_request *c_req;
869 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
870 return smb_raw_setfileinfo(private->tree, io);
872 c_req = smb_raw_setfileinfo_send(private->tree, io);
879 a handler for async fsinfo replies
881 static void async_fsinfo(struct smbcli_request *c_req)
883 struct async_info *async = c_req->async.private;
884 struct ntvfs_request *req = async->req;
885 req->async_states->status = smb_raw_fsinfo_recv(c_req, req, async->parms);
887 req->async_states->send_fn(req);
891 return filesystem space info
893 static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs,
894 struct ntvfs_request *req, union smb_fsinfo *fs)
896 struct cvfs_private *private = ntvfs->private_data;
897 struct smbcli_request *c_req;
901 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
902 return smb_raw_fsinfo(private->tree, req, fs);
905 c_req = smb_raw_fsinfo_send(private->tree, req, fs);
907 ASYNC_RECV_TAIL(fs, async_fsinfo);
911 return print queue info
913 static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs,
914 struct ntvfs_request *req, union smb_lpq *lpq)
916 return NT_STATUS_NOT_SUPPORTED;
920 list files in a directory matching a wildcard pattern
922 static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs,
923 struct ntvfs_request *req, union smb_search_first *io,
924 void *search_private,
925 bool (*callback)(void *, const union smb_search_data *))
927 struct cvfs_private *private = ntvfs->private_data;
931 return smb_raw_search_first(private->tree, req, io, search_private, callback);
934 /* continue a search */
935 static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs,
936 struct ntvfs_request *req, union smb_search_next *io,
937 void *search_private,
938 bool (*callback)(void *, const union smb_search_data *))
940 struct cvfs_private *private = ntvfs->private_data;
944 return smb_raw_search_next(private->tree, req, io, search_private, callback);
948 static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs,
949 struct ntvfs_request *req, union smb_search_close *io)
951 struct cvfs_private *private = ntvfs->private_data;
955 return smb_raw_search_close(private->tree, io);
959 a handler for async trans2 replies
961 static void async_trans2(struct smbcli_request *c_req)
963 struct async_info *async = c_req->async.private;
964 struct ntvfs_request *req = async->req;
965 req->async_states->status = smb_raw_trans2_recv(c_req, req, async->parms);
967 req->async_states->send_fn(req);
971 static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs,
972 struct ntvfs_request *req,
973 struct smb_trans2 *trans2)
975 struct cvfs_private *private = ntvfs->private_data;
976 struct smbcli_request *c_req;
978 if (private->map_trans2) {
979 return NT_STATUS_NOT_IMPLEMENTED;
984 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
985 return smb_raw_trans2(private->tree, req, trans2);
988 c_req = smb_raw_trans2_send(private->tree, trans2);
990 ASYNC_RECV_TAIL(trans2, async_trans2);
994 /* SMBtrans - not used on file shares */
995 static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs,
996 struct ntvfs_request *req,
997 struct smb_trans2 *trans2)
999 return NT_STATUS_ACCESS_DENIED;
1003 a handler for async change notify replies
1005 static void async_changenotify(struct smbcli_request *c_req)
1007 struct async_info *async = c_req->async.private;
1008 struct ntvfs_request *req = async->req;
1009 req->async_states->status = smb_raw_changenotify_recv(c_req, req, async->parms);
1011 req->async_states->send_fn(req);
1014 /* change notify request - always async */
1015 static NTSTATUS cvfs_notify(struct ntvfs_module_context *ntvfs,
1016 struct ntvfs_request *req,
1017 union smb_notify *io)
1019 struct cvfs_private *private = ntvfs->private_data;
1020 struct smbcli_request *c_req;
1021 int saved_timeout = private->transport->options.request_timeout;
1022 struct cvfs_file *f;
1024 if (io->nttrans.level != RAW_NOTIFY_NTTRANS) {
1025 return NT_STATUS_NOT_IMPLEMENTED;
1030 f = ntvfs_handle_get_backend_data(io->nttrans.in.file.ntvfs, ntvfs);
1031 if (!f) return NT_STATUS_INVALID_HANDLE;
1032 io->nttrans.in.file.fnum = f->fnum;
1034 /* this request doesn't make sense unless its async */
1035 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1036 return NT_STATUS_INVALID_PARAMETER;
1039 /* we must not timeout on notify requests - they wait
1041 private->transport->options.request_timeout = 0;
1043 c_req = smb_raw_changenotify_send(private->tree, io);
1045 private->transport->options.request_timeout = saved_timeout;
1047 ASYNC_RECV_TAIL(io, async_changenotify);
1051 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
1053 NTSTATUS ntvfs_cifs_init(void)
1056 struct ntvfs_ops ops;
1057 NTVFS_CURRENT_CRITICAL_SIZES(vers);
1061 /* fill in the name and type */
1063 ops.type = NTVFS_DISK;
1065 /* fill in all the operations */
1066 ops.connect = cvfs_connect;
1067 ops.disconnect = cvfs_disconnect;
1068 ops.unlink = cvfs_unlink;
1069 ops.chkpath = cvfs_chkpath;
1070 ops.qpathinfo = cvfs_qpathinfo;
1071 ops.setpathinfo = cvfs_setpathinfo;
1072 ops.open = cvfs_open;
1073 ops.mkdir = cvfs_mkdir;
1074 ops.rmdir = cvfs_rmdir;
1075 ops.rename = cvfs_rename;
1076 ops.copy = cvfs_copy;
1077 ops.ioctl = cvfs_ioctl;
1078 ops.read = cvfs_read;
1079 ops.write = cvfs_write;
1080 ops.seek = cvfs_seek;
1081 ops.flush = cvfs_flush;
1082 ops.close = cvfs_close;
1083 ops.exit = cvfs_exit;
1084 ops.lock = cvfs_lock;
1085 ops.setfileinfo = cvfs_setfileinfo;
1086 ops.qfileinfo = cvfs_qfileinfo;
1087 ops.fsinfo = cvfs_fsinfo;
1089 ops.search_first = cvfs_search_first;
1090 ops.search_next = cvfs_search_next;
1091 ops.search_close = cvfs_search_close;
1092 ops.trans = cvfs_trans;
1093 ops.logoff = cvfs_logoff;
1094 ops.async_setup = cvfs_async_setup;
1095 ops.cancel = cvfs_cancel;
1096 ops.notify = cvfs_notify;
1097 ops.trans2 = cvfs_trans2;
1099 /* register ourselves with the NTVFS subsystem. We register
1100 under the name 'cifs'. */
1101 ret = ntvfs_register(&ops, &vers);
1103 if (!NT_STATUS_IS_OK(ret)) {
1104 DEBUG(0,("Failed to register CIFS backend!\n"));