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