r10878: Reply to some comments by tridge and metze:
[garming/samba-autobuild/.git] / source4 / ntvfs / cifs / vfs_cifs.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    CIFS-on-CIFS NTVFS filesystem backend
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) James J Myers 2003 <myersjj@samba.org>
8
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.
13    
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.
18    
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.
22 */
23 /*
24   this implements a CIFS->CIFS NTVFS filesystem backend. 
25   
26 */
27
28 #include "includes.h"
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
36 /* this is stored in ntvfs_private */
37 struct cvfs_private {
38         struct smbcli_tree *tree;
39         struct smbcli_transport *transport;
40         struct smbsrv_tcon *tcon;
41         BOOL map_generic;
42 };
43
44
45 /* a structure used to pass information to an async handler */
46 struct async_info {
47         struct smbsrv_request *req;
48         void *parms;
49 };
50
51 #define SETUP_PID private->tree->session->pid = SVAL(req->in.hdr, HDR_PID)
52
53 /*
54   a handler for oplock break events from the server - these need to be passed
55   along to the client
56  */
57 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
58 {
59         struct cvfs_private *private = p_private;
60         
61         DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
62         return req_send_oplock_break(private->tcon, fnum, level);
63 }
64
65  /*
66   a handler for read events on a connection to a backend server
67 */
68 static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde, 
69                                 uint16_t flags, void *private)
70 {
71         struct cvfs_private *cvfs = talloc_get_type(private, struct cvfs_private);
72         struct smbsrv_tcon *tcon = cvfs->tcon;
73         
74         if (!smbcli_transport_process(cvfs->transport)) {
75                 /* the connection to our server is dead */
76                 talloc_free(tcon);
77         }
78 }
79
80 /*
81   connect to a share - used when a tree_connect operation comes in.
82 */
83 static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, 
84                              struct smbsrv_request *req, const char *sharename)
85 {
86         struct smbsrv_tcon *tcon = req->tcon;
87         NTSTATUS status;
88         struct cvfs_private *private;
89         const char *host, *user, *pass, *domain, *remote_share;
90         struct smb_composite_connect io;
91         struct composite_context *creq;
92         struct fd_event *fde;
93
94         struct cli_credentials *credentials;
95
96         /* Here we need to determine which server to connect to.
97          * For now we use parametric options, type cifs.
98          * Later we will use security=server and auth_server.c.
99          */
100         host = lp_parm_string(req->tcon->service, "cifs", "server");
101         user = lp_parm_string(req->tcon->service, "cifs", "user");
102         pass = lp_parm_string(req->tcon->service, "cifs", "password");
103         domain = lp_parm_string(req->tcon->service, "cifs", "domain");
104         remote_share = lp_parm_string(req->tcon->service, "cifs", "share");
105         if (!remote_share) {
106                 remote_share = sharename;
107         }
108
109         if (!host || !user || !pass || !domain) {
110                 DEBUG(1,("CIFS backend: You must supply server, user, password and domain\n"));
111                 return NT_STATUS_INVALID_PARAMETER;
112         }
113         
114         private = talloc(req->tcon, struct cvfs_private);
115         if (!private) {
116                 return NT_STATUS_NO_MEMORY;
117         }
118         ZERO_STRUCTP(private);
119
120         ntvfs->private_data = private;
121
122         credentials = cli_credentials_init(private);
123         cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
124         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
125         cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
126         cli_credentials_set_workstation(credentials, "vfs_cifs", CRED_SPECIFIED);
127
128         /* connect to the server, using the smbd event context */
129         io.in.dest_host = host;
130         io.in.port = 0;
131         io.in.called_name = host;
132         io.in.credentials = credentials;
133         io.in.fallback_to_anonymous = False;
134         io.in.workgroup = lp_workgroup();
135         io.in.service = remote_share;
136         io.in.service_type = "?????";
137         
138         creq = smb_composite_connect_send(&io, private, tcon->smb_conn->connection->event.ctx);
139         status = smb_composite_connect_recv(creq, private);
140         NT_STATUS_NOT_OK_RETURN(status);
141
142         private->tree = io.out.tree;
143
144         private->transport = private->tree->session->transport;
145         SETUP_PID;
146         private->tcon = req->tcon;
147
148         tcon->fs_type = talloc_strdup(tcon, "NTFS");
149         tcon->dev_type = talloc_strdup(tcon, "A:");
150         
151         /* we need to receive oplock break requests from the server */
152         smbcli_oplock_handler(private->transport, oplock_handler, private);
153
154         /* take over event handling for this socket */
155         talloc_free(private->transport->socket->event.fde);
156         fde = event_add_fd(private->transport->socket->event.ctx,
157                            private,
158                            socket_get_fd(private->transport->socket->sock),
159                            EVENT_FD_READ | EVENT_FD_WRITE,
160                            cifs_socket_handler,
161                            private);
162         private->transport->socket->event.fde = fde;
163
164
165         private->map_generic = lp_parm_bool(req->tcon->service, 
166                                             "cifs", "mapgeneric", False);
167
168         return NT_STATUS_OK;
169 }
170
171 /*
172   disconnect from a share
173 */
174 static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs, 
175                                 struct smbsrv_tcon *tcon)
176 {
177         struct cvfs_private *private = ntvfs->private_data;
178
179         talloc_free(private);
180
181         return NT_STATUS_OK;
182 }
183
184 /*
185   a handler for simple async replies
186   this handler can only be used for functions that don't return any
187   parameters (those that just return a status code)
188  */
189 static void async_simple(struct smbcli_request *c_req)
190 {
191         struct async_info *async = c_req->async.private;
192         struct smbsrv_request *req = async->req;
193         req->async_states->status = smbcli_request_simple_recv(c_req);
194         req->async_states->send_fn(req);
195 }
196
197
198 /* save some typing for the simple functions */
199 #define ASYNC_RECV_TAIL(io, async_fn) do { \
200         if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
201         { \
202                 struct async_info *async; \
203                 async = talloc(req, struct async_info); \
204                 if (!async) return NT_STATUS_NO_MEMORY; \
205                 async->parms = io; \
206                 async->req = req; \
207                 c_req->async.private = async; \
208         } \
209         c_req->async.fn = async_fn; \
210         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
211         return NT_STATUS_OK; \
212 } while (0)
213
214 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
215
216 /*
217   delete a file - the dirtype specifies the file types to include in the search. 
218   The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
219 */
220 static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs, 
221                             struct smbsrv_request *req, struct smb_unlink *unl)
222 {
223         struct cvfs_private *private = ntvfs->private_data;
224         struct smbcli_request *c_req;
225
226         SETUP_PID;
227
228         /* see if the front end will allow us to perform this
229            function asynchronously.  */
230         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
231                 return smb_raw_unlink(private->tree, unl);
232         }
233
234         c_req = smb_raw_unlink_send(private->tree, unl);
235
236         SIMPLE_ASYNC_TAIL;
237 }
238
239 /*
240   a handler for async ioctl replies
241  */
242 static void async_ioctl(struct smbcli_request *c_req)
243 {
244         struct async_info *async = c_req->async.private;
245         struct smbsrv_request *req = async->req;
246         req->async_states->status = smb_raw_ioctl_recv(c_req, req, async->parms);
247         req->async_states->send_fn(req);
248 }
249
250 /*
251   ioctl interface
252 */
253 static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs, 
254                                 struct smbsrv_request *req, union smb_ioctl *io)
255 {
256         struct cvfs_private *private = ntvfs->private_data;
257         struct smbcli_request *c_req;
258
259         SETUP_PID;
260
261         /* see if the front end will allow us to perform this
262            function asynchronously.  */
263         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
264                 return smb_raw_ioctl(private->tree, req, io);
265         }
266
267         c_req = smb_raw_ioctl_send(private->tree, io);
268
269         ASYNC_RECV_TAIL(io, async_ioctl);
270 }
271
272 /*
273   check if a directory exists
274 */
275 static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs, 
276                                 struct smbsrv_request *req, struct smb_chkpath *cp)
277 {
278         struct cvfs_private *private = ntvfs->private_data;
279         struct smbcli_request *c_req;
280
281         SETUP_PID;
282
283         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
284                 return smb_raw_chkpath(private->tree, cp);
285         }
286
287         c_req = smb_raw_chkpath_send(private->tree, cp);
288
289         SIMPLE_ASYNC_TAIL;
290 }
291
292 /*
293   a handler for async qpathinfo replies
294  */
295 static void async_qpathinfo(struct smbcli_request *c_req)
296 {
297         struct async_info *async = c_req->async.private;
298         struct smbsrv_request *req = async->req;
299         req->async_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms);
300         req->async_states->send_fn(req);
301 }
302
303 /*
304   return info on a pathname
305 */
306 static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs, 
307                                 struct smbsrv_request *req, union smb_fileinfo *info)
308 {
309         struct cvfs_private *private = ntvfs->private_data;
310         struct smbcli_request *c_req;
311
312         SETUP_PID;
313
314         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
315                 return smb_raw_pathinfo(private->tree, req, info);
316         }
317
318         c_req = smb_raw_pathinfo_send(private->tree, info);
319
320         ASYNC_RECV_TAIL(info, async_qpathinfo);
321 }
322
323 /*
324   a handler for async qfileinfo replies
325  */
326 static void async_qfileinfo(struct smbcli_request *c_req)
327 {
328         struct async_info *async = c_req->async.private;
329         struct smbsrv_request *req = async->req;
330         req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms);
331         req->async_states->send_fn(req);
332 }
333
334 /*
335   query info on a open file
336 */
337 static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs, 
338                                 struct smbsrv_request *req, union smb_fileinfo *info)
339 {
340         struct cvfs_private *private = ntvfs->private_data;
341         struct smbcli_request *c_req;
342
343         SETUP_PID;
344
345         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
346                 return smb_raw_fileinfo(private->tree, req, info);
347         }
348
349         c_req = smb_raw_fileinfo_send(private->tree, info);
350
351         ASYNC_RECV_TAIL(info, async_qfileinfo);
352 }
353
354
355 /*
356   set info on a pathname
357 */
358 static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs, 
359                                 struct smbsrv_request *req, union smb_setfileinfo *st)
360 {
361         struct cvfs_private *private = ntvfs->private_data;
362         struct smbcli_request *c_req;
363
364         SETUP_PID;
365
366         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
367                 return smb_raw_setpathinfo(private->tree, st);
368         }
369
370         c_req = smb_raw_setpathinfo_send(private->tree, st);
371
372         SIMPLE_ASYNC_TAIL;
373 }
374
375
376 /*
377   a handler for async open replies
378  */
379 static void async_open(struct smbcli_request *c_req)
380 {
381         struct async_info *async = c_req->async.private;
382         struct smbsrv_request *req = async->req;
383         req->async_states->status = smb_raw_open_recv(c_req, req, async->parms);
384         req->async_states->send_fn(req);
385 }
386
387 /*
388   open a file
389 */
390 static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs, 
391                                 struct smbsrv_request *req, union smb_open *io)
392 {
393         struct cvfs_private *private = ntvfs->private_data;
394         struct smbcli_request *c_req;
395
396         SETUP_PID;
397
398         if (io->generic.level != RAW_OPEN_GENERIC &&
399             private->map_generic) {
400                 return ntvfs_map_open(req, io, ntvfs);
401         }
402
403         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
404                 return smb_raw_open(private->tree, req, io);
405         }
406
407         c_req = smb_raw_open_send(private->tree, io);
408
409         ASYNC_RECV_TAIL(io, async_open);
410 }
411
412 /*
413   create a directory
414 */
415 static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs, 
416                                 struct smbsrv_request *req, union smb_mkdir *md)
417 {
418         struct cvfs_private *private = ntvfs->private_data;
419         struct smbcli_request *c_req;
420
421         SETUP_PID;
422
423         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
424                 return smb_raw_mkdir(private->tree, md);
425         }
426
427         c_req = smb_raw_mkdir_send(private->tree, md);
428
429         SIMPLE_ASYNC_TAIL;
430 }
431
432 /*
433   remove a directory
434 */
435 static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs, 
436                                 struct smbsrv_request *req, struct smb_rmdir *rd)
437 {
438         struct cvfs_private *private = ntvfs->private_data;
439         struct smbcli_request *c_req;
440
441         SETUP_PID;
442
443         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
444                 return smb_raw_rmdir(private->tree, rd);
445         }
446         c_req = smb_raw_rmdir_send(private->tree, rd);
447
448         SIMPLE_ASYNC_TAIL;
449 }
450
451 /*
452   rename a set of files
453 */
454 static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs, 
455                                 struct smbsrv_request *req, union smb_rename *ren)
456 {
457         struct cvfs_private *private = ntvfs->private_data;
458         struct smbcli_request *c_req;
459
460         SETUP_PID;
461
462         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
463                 return smb_raw_rename(private->tree, ren);
464         }
465
466         c_req = smb_raw_rename_send(private->tree, ren);
467
468         SIMPLE_ASYNC_TAIL;
469 }
470
471 /*
472   copy a set of files
473 */
474 static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs, 
475                                 struct smbsrv_request *req, struct smb_copy *cp)
476 {
477         return NT_STATUS_NOT_SUPPORTED;
478 }
479
480 /*
481   a handler for async read replies
482  */
483 static void async_read(struct smbcli_request *c_req)
484 {
485         struct async_info *async = c_req->async.private;
486         struct smbsrv_request *req = async->req;
487         req->async_states->status = smb_raw_read_recv(c_req, async->parms);
488         req->async_states->send_fn(req);
489 }
490
491 /*
492   read from a file
493 */
494 static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs, 
495                                 struct smbsrv_request *req, union smb_read *rd)
496 {
497         struct cvfs_private *private = ntvfs->private_data;
498         struct smbcli_request *c_req;
499
500         SETUP_PID;
501
502         if (rd->generic.level != RAW_READ_GENERIC &&
503             private->map_generic) {
504                 return ntvfs_map_read(req, rd, ntvfs);
505         }
506
507         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
508                 return smb_raw_read(private->tree, rd);
509         }
510
511         c_req = smb_raw_read_send(private->tree, rd);
512
513         ASYNC_RECV_TAIL(rd, async_read);
514 }
515
516 /*
517   a handler for async write replies
518  */
519 static void async_write(struct smbcli_request *c_req)
520 {
521         struct async_info *async = c_req->async.private;
522         struct smbsrv_request *req = async->req;
523         req->async_states->status = smb_raw_write_recv(c_req, async->parms);
524         req->async_states->send_fn(req);
525 }
526
527 /*
528   write to a file
529 */
530 static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs, 
531                                 struct smbsrv_request *req, union smb_write *wr)
532 {
533         struct cvfs_private *private = ntvfs->private_data;
534         struct smbcli_request *c_req;
535
536         SETUP_PID;
537
538         if (wr->generic.level != RAW_WRITE_GENERIC &&
539             private->map_generic) {
540                 return ntvfs_map_write(req, wr, ntvfs);
541         }
542
543         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
544                 return smb_raw_write(private->tree, wr);
545         }
546
547         c_req = smb_raw_write_send(private->tree, wr);
548
549         ASYNC_RECV_TAIL(wr, async_write);
550 }
551
552 /*
553   a handler for async seek replies
554  */
555 static void async_seek(struct smbcli_request *c_req)
556 {
557         struct async_info *async = c_req->async.private;
558         struct smbsrv_request *req = async->req;
559         req->async_states->status = smb_raw_seek_recv(c_req, async->parms);
560         req->async_states->send_fn(req);
561 }
562
563 /*
564   seek in a file
565 */
566 static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs, 
567                           struct smbsrv_request *req, struct smb_seek *io)
568 {
569         struct cvfs_private *private = ntvfs->private_data;
570         struct smbcli_request *c_req;
571
572         SETUP_PID;
573
574         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
575                 return smb_raw_seek(private->tree, io);
576         }
577
578         c_req = smb_raw_seek_send(private->tree, io);
579
580         ASYNC_RECV_TAIL(io, async_seek);
581 }
582
583 /*
584   flush a file
585 */
586 static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs, 
587                            struct smbsrv_request *req, struct smb_flush *io)
588 {
589         struct cvfs_private *private = ntvfs->private_data;
590         struct smbcli_request *c_req;
591
592         SETUP_PID;
593
594         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
595                 return smb_raw_flush(private->tree, io);
596         }
597
598         c_req = smb_raw_flush_send(private->tree, io);
599
600         SIMPLE_ASYNC_TAIL;
601 }
602
603 /*
604   close a file
605 */
606 static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs, 
607                                 struct smbsrv_request *req, union smb_close *io)
608 {
609         struct cvfs_private *private = ntvfs->private_data;
610         struct smbcli_request *c_req;
611
612         SETUP_PID;
613
614         if (io->generic.level != RAW_CLOSE_GENERIC &&
615             private->map_generic) {
616                 return ntvfs_map_close(req, io, ntvfs);
617         }
618
619         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
620                 return smb_raw_close(private->tree, io);
621         }
622
623         c_req = smb_raw_close_send(private->tree, io);
624
625         SIMPLE_ASYNC_TAIL;
626 }
627
628 /*
629   exit - closing files open by the pid
630 */
631 static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs, 
632                                 struct smbsrv_request *req)
633 {
634         struct cvfs_private *private = ntvfs->private_data;
635         struct smbcli_request *c_req;
636
637         SETUP_PID;
638
639         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
640                 return smb_raw_exit(private->tree->session);
641         }
642
643         c_req = smb_raw_exit_send(private->tree->session);
644
645         SIMPLE_ASYNC_TAIL;
646 }
647
648 /*
649   logoff - closing files open by the user
650 */
651 static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs, 
652                                 struct smbsrv_request *req)
653 {
654         /* we can't do this right in the cifs backend .... */
655         return NT_STATUS_OK;
656 }
657
658 /*
659   setup for an async call - nothing to do yet
660 */
661 static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs, 
662                                  struct smbsrv_request *req, 
663                                  void *private)
664 {
665         return NT_STATUS_OK;
666 }
667
668 /*
669   cancel an async call
670 */
671 static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs, 
672                             struct smbsrv_request *req)
673 {
674         return NT_STATUS_NOT_IMPLEMENTED;
675 }
676
677 /*
678   lock a byte range
679 */
680 static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs, 
681                                 struct smbsrv_request *req, union smb_lock *lck)
682 {
683         struct cvfs_private *private = ntvfs->private_data;
684         struct smbcli_request *c_req;
685
686         SETUP_PID;
687
688         if (lck->generic.level != RAW_LOCK_GENERIC &&
689             private->map_generic) {
690                 return ntvfs_map_lock(req, lck, ntvfs);
691         }
692
693         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
694                 return smb_raw_lock(private->tree, lck);
695         }
696
697         c_req = smb_raw_lock_send(private->tree, lck);
698         SIMPLE_ASYNC_TAIL;
699 }
700
701 /*
702   set info on a open file
703 */
704 static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs, 
705                                  struct smbsrv_request *req, 
706                                  union smb_setfileinfo *info)
707 {
708         struct cvfs_private *private = ntvfs->private_data;
709         struct smbcli_request *c_req;
710
711         SETUP_PID;
712
713         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
714                 return smb_raw_setfileinfo(private->tree, info);
715         }
716         c_req = smb_raw_setfileinfo_send(private->tree, info);
717
718         SIMPLE_ASYNC_TAIL;
719 }
720
721
722 /*
723   a handler for async fsinfo replies
724  */
725 static void async_fsinfo(struct smbcli_request *c_req)
726 {
727         struct async_info *async = c_req->async.private;
728         struct smbsrv_request *req = async->req;
729         req->async_states->status = smb_raw_fsinfo_recv(c_req, req, async->parms);
730         req->async_states->send_fn(req);
731 }
732
733 /*
734   return filesystem space info
735 */
736 static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs, 
737                                 struct smbsrv_request *req, union smb_fsinfo *fs)
738 {
739         struct cvfs_private *private = ntvfs->private_data;
740         struct smbcli_request *c_req;
741
742         SETUP_PID;
743
744         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
745                 return smb_raw_fsinfo(private->tree, req, fs);
746         }
747
748         c_req = smb_raw_fsinfo_send(private->tree, req, fs);
749
750         ASYNC_RECV_TAIL(fs, async_fsinfo);
751 }
752
753 /*
754   return print queue info
755 */
756 static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs, 
757                                 struct smbsrv_request *req, union smb_lpq *lpq)
758 {
759         return NT_STATUS_NOT_SUPPORTED;
760 }
761
762 /* 
763    list files in a directory matching a wildcard pattern
764 */
765 static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs, 
766                                   struct smbsrv_request *req, union smb_search_first *io, 
767                                   void *search_private, 
768                                   BOOL (*callback)(void *, union smb_search_data *))
769 {
770         struct cvfs_private *private = ntvfs->private_data;
771
772         SETUP_PID;
773
774         return smb_raw_search_first(private->tree, req, io, search_private, callback);
775 }
776
777 /* continue a search */
778 static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs, 
779                                  struct smbsrv_request *req, union smb_search_next *io, 
780                                  void *search_private, 
781                                  BOOL (*callback)(void *, union smb_search_data *))
782 {
783         struct cvfs_private *private = ntvfs->private_data;
784
785         SETUP_PID;
786
787         return smb_raw_search_next(private->tree, req, io, search_private, callback);
788 }
789
790 /* close a search */
791 static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs, 
792                                   struct smbsrv_request *req, union smb_search_close *io)
793 {
794         struct cvfs_private *private = ntvfs->private_data;
795
796         SETUP_PID;
797
798         return smb_raw_search_close(private->tree, io);
799 }
800
801 /*
802   a handler for async trans2 replies
803  */
804 static void async_trans2(struct smbcli_request *c_req)
805 {
806         struct async_info *async = c_req->async.private;
807         struct smbsrv_request *req = async->req;
808         req->async_states->status = smb_raw_trans2_recv(c_req, req, async->parms);
809         req->async_states->send_fn(req);
810 }
811
812 /* raw trans2 */
813 static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs, 
814                                 struct smbsrv_request *req, struct smb_trans2 *trans2)
815 {
816         struct cvfs_private *private = ntvfs->private_data;
817         struct smbcli_request *c_req;
818
819         SETUP_PID;
820
821         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
822                 return smb_raw_trans2(private->tree, req, trans2);
823         }
824
825         c_req = smb_raw_trans2_send(private->tree, trans2);
826
827         ASYNC_RECV_TAIL(trans2, async_trans2);
828 }
829
830
831 /* SMBtrans - not used on file shares */
832 static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs, 
833                                 struct smbsrv_request *req, struct smb_trans2 *trans2)
834 {
835         return NT_STATUS_ACCESS_DENIED;
836 }
837
838 /*
839   initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
840  */
841 NTSTATUS ntvfs_cifs_init(void)
842 {
843         NTSTATUS ret;
844         struct ntvfs_ops ops;
845
846         ZERO_STRUCT(ops);
847
848         /* fill in the name and type */
849         ops.name = "cifs";
850         ops.type = NTVFS_DISK;
851         
852         /* fill in all the operations */
853         ops.connect = cvfs_connect;
854         ops.disconnect = cvfs_disconnect;
855         ops.unlink = cvfs_unlink;
856         ops.chkpath = cvfs_chkpath;
857         ops.qpathinfo = cvfs_qpathinfo;
858         ops.setpathinfo = cvfs_setpathinfo;
859         ops.openfile = cvfs_open;
860         ops.mkdir = cvfs_mkdir;
861         ops.rmdir = cvfs_rmdir;
862         ops.rename = cvfs_rename;
863         ops.copy = cvfs_copy;
864         ops.ioctl = cvfs_ioctl;
865         ops.read = cvfs_read;
866         ops.write = cvfs_write;
867         ops.seek = cvfs_seek;
868         ops.flush = cvfs_flush; 
869         ops.close = cvfs_close;
870         ops.exit = cvfs_exit;
871         ops.lock = cvfs_lock;
872         ops.setfileinfo = cvfs_setfileinfo;
873         ops.qfileinfo = cvfs_qfileinfo;
874         ops.fsinfo = cvfs_fsinfo;
875         ops.lpq = cvfs_lpq;
876         ops.search_first = cvfs_search_first;
877         ops.search_next = cvfs_search_next;
878         ops.search_close = cvfs_search_close;
879         ops.trans = cvfs_trans;
880         ops.logoff = cvfs_logoff;
881         ops.async_setup = cvfs_async_setup;
882         ops.cancel = cvfs_cancel;
883
884         if (lp_parm_bool(-1, "cifs", "maptrans2", False)) {
885                 ops.trans2 = cvfs_trans2;
886         }
887
888         /* register ourselves with the NTVFS subsystem. We register
889            under the name 'cifs'. */
890         ret = ntvfs_register(&ops);
891
892         if (!NT_STATUS_IS_OK(ret)) {
893                 DEBUG(0,("Failed to register CIFS backend!\n"));
894         }
895         
896         return ret;
897 }