r16980: - make struct smb_notify a union and add levels RAW_NOTIFY_NTTRANS,RAW_NOTIFY...
[amitay/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 "libcli/raw/libcliraw.h"
30 #include "libcli/smb_composite/smb_composite.h"
31 #include "auth/auth.h"
32 #include "ntvfs/ntvfs.h"
33 #include "include/dlinklist.h"
34
35 struct cvfs_file {
36         struct cvfs_file *prev, *next;
37         uint16_t fnum;
38         struct ntvfs_handle *h;
39 };
40
41 /* this is stored in ntvfs_private */
42 struct cvfs_private {
43         struct smbcli_tree *tree;
44         struct smbcli_transport *transport;
45         struct ntvfs_module_context *ntvfs;
46         struct async_info *pending;
47         struct cvfs_file *files;
48         BOOL map_generic;
49         BOOL map_trans2;
50 };
51
52
53 /* a structure used to pass information to an async handler */
54 struct async_info {
55         struct async_info *next, *prev;
56         struct cvfs_private *cvfs;
57         struct ntvfs_request *req;
58         struct smbcli_request *c_req;
59         struct cvfs_file *f;
60         void *parms;
61 };
62
63 #define SETUP_PID private->tree->session->pid = req->smbpid
64
65 #define SETUP_FILE do { \
66         struct cvfs_file *f; \
67         f = ntvfs_handle_get_backend_data(io->generic.in.file.ntvfs, ntvfs); \
68         if (!f) return NT_STATUS_INVALID_HANDLE; \
69         io->generic.in.file.fnum = f->fnum; \
70 } while (0) 
71
72 #define SETUP_PID_AND_FILE do { \
73         SETUP_PID; \
74         SETUP_FILE; \
75 } while (0)
76
77 /*
78   a handler for oplock break events from the server - these need to be passed
79   along to the client
80  */
81 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
82 {
83         struct cvfs_private *private = p_private;
84         NTSTATUS status;
85         struct ntvfs_handle *h = NULL;
86         struct cvfs_file *f;
87
88         for (f=private->files; f; f=f->next) {
89                 if (f->fnum != fnum) continue;
90                 h = f->h;
91                 break;
92         }
93
94         if (!h) {
95                 DEBUG(5,("vfs_cifs: ignoring oplock break level %d for fnum %d\n", level, fnum));
96                 return True;
97         }
98
99         DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
100         status = ntvfs_send_oplock_break(private->ntvfs, h, level);
101         if (!NT_STATUS_IS_OK(status)) return False;
102         return True;
103 }
104
105 /*
106   connect to a share - used when a tree_connect operation comes in.
107 */
108 static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, 
109                              struct ntvfs_request *req, const char *sharename)
110 {
111         NTSTATUS status;
112         struct cvfs_private *private;
113         const char *host, *user, *pass, *domain, *remote_share;
114         struct smb_composite_connect io;
115         struct composite_context *creq;
116         int snum = ntvfs->ctx->config.snum;
117
118         struct cli_credentials *credentials;
119         BOOL machine_account;
120
121         /* Here we need to determine which server to connect to.
122          * For now we use parametric options, type cifs.
123          * Later we will use security=server and auth_server.c.
124          */
125         host = lp_parm_string(snum, "cifs", "server");
126         user = lp_parm_string(snum, "cifs", "user");
127         pass = lp_parm_string(snum, "cifs", "password");
128         domain = lp_parm_string(snum, "cifs", "domain");
129         remote_share = lp_parm_string(snum, "cifs", "share");
130         if (!remote_share) {
131                 remote_share = sharename;
132         }
133
134         machine_account = lp_parm_bool(snum, "cifs", "use_machine_account", False);
135
136         private = talloc_zero(ntvfs, struct cvfs_private);
137         if (!private) {
138                 return NT_STATUS_NO_MEMORY;
139         }
140
141         ntvfs->private_data = private;
142
143         if (!host) {
144                 DEBUG(1,("CIFS backend: You must supply server\n"));
145                 return NT_STATUS_INVALID_PARAMETER;
146         } 
147         
148         if (user && pass) {
149                 DEBUG(5, ("CIFS backend: Using specified password\n"));
150                 credentials = cli_credentials_init(private);
151                 if (!credentials) {
152                         return NT_STATUS_NO_MEMORY;
153                 }
154                 cli_credentials_set_conf(credentials);
155                 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
156                 if (domain) {
157                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
158                 }
159                 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
160         } else if (machine_account) {
161                 DEBUG(5, ("CIFS backend: Using machine account\n"));
162                 credentials = cli_credentials_init(private);
163                 cli_credentials_set_conf(credentials);
164                 if (domain) {
165                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
166                 }
167                 status = cli_credentials_set_machine_account(credentials);
168                 if (!NT_STATUS_IS_OK(status)) {
169                         return status;
170                 }
171         } else if (req->session_info->credentials) {
172                 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
173                 credentials = req->session_info->credentials;
174         } else {
175                 DEBUG(1,("CIFS backend: You must supply server, user and password and or have delegated credentials\n"));
176                 return NT_STATUS_INVALID_PARAMETER;
177         }
178
179         /* connect to the server, using the smbd event context */
180         io.in.dest_host = host;
181         io.in.port = 0;
182         io.in.called_name = host;
183         io.in.credentials = credentials;
184         io.in.fallback_to_anonymous = False;
185         io.in.workgroup = lp_workgroup();
186         io.in.service = remote_share;
187         io.in.service_type = "?????";
188         
189         creq = smb_composite_connect_send(&io, private, ntvfs->ctx->event_ctx);
190         status = smb_composite_connect_recv(creq, private);
191         NT_STATUS_NOT_OK_RETURN(status);
192
193         private->tree = io.out.tree;
194
195         private->transport = private->tree->session->transport;
196         SETUP_PID;
197         private->ntvfs = ntvfs;
198
199         ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
200         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->fs_type);
201         ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
202         NT_STATUS_HAVE_NO_MEMORY(ntvfs->ctx->dev_type);
203
204         /* we need to receive oplock break requests from the server */
205         smbcli_oplock_handler(private->transport, oplock_handler, private);
206
207         private->map_generic = lp_parm_bool(ntvfs->ctx->config.snum, 
208                                             "cifs", "mapgeneric", False);
209
210         private->map_trans2 = lp_parm_bool(ntvfs->ctx->config.snum,
211                                            "cifs", "maptrans2", True);
212
213         return NT_STATUS_OK;
214 }
215
216 /*
217   disconnect from a share
218 */
219 static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs)
220 {
221         struct cvfs_private *private = ntvfs->private_data;
222         struct async_info *a, *an;
223
224         /* first cleanup pending requests */
225         for (a=private->pending; a; a = an) {
226                 an = a->next;
227                 smbcli_request_destroy(a->c_req);
228                 talloc_free(a);
229         }
230
231         talloc_free(private);
232         ntvfs->private_data = NULL;
233
234         return NT_STATUS_OK;
235 }
236
237 /*
238   destroy an async info structure
239 */
240 static int async_info_destructor(struct async_info *async)
241 {
242         DLIST_REMOVE(async->cvfs->pending, async);
243         return 0;
244 }
245
246 /*
247   a handler for simple async replies
248   this handler can only be used for functions that don't return any
249   parameters (those that just return a status code)
250  */
251 static void async_simple(struct smbcli_request *c_req)
252 {
253         struct async_info *async = c_req->async.private;
254         struct ntvfs_request *req = async->req;
255         req->async_states->status = smbcli_request_simple_recv(c_req);
256         talloc_free(async);
257         req->async_states->send_fn(req);
258 }
259
260
261 /* save some typing for the simple functions */
262 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
263         if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
264         { \
265                 struct async_info *async; \
266                 async = talloc(req, struct async_info); \
267                 if (!async) return NT_STATUS_NO_MEMORY; \
268                 async->parms = io; \
269                 async->req = req; \
270                 async->f = file; \
271                 async->cvfs = private; \
272                 async->c_req = c_req; \
273                 DLIST_ADD(private->pending, async); \
274                 c_req->async.private = async; \
275                 talloc_set_destructor(async, async_info_destructor); \
276         } \
277         c_req->async.fn = async_fn; \
278         req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
279         return NT_STATUS_OK; \
280 } while (0)
281
282 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
283
284 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
285
286 /*
287   delete a file - the dirtype specifies the file types to include in the search. 
288   The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
289 */
290 static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs, 
291                             struct ntvfs_request *req, union smb_unlink *unl)
292 {
293         struct cvfs_private *private = ntvfs->private_data;
294         struct smbcli_request *c_req;
295
296         SETUP_PID;
297
298         /* see if the front end will allow us to perform this
299            function asynchronously.  */
300         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
301                 return smb_raw_unlink(private->tree, unl);
302         }
303
304         c_req = smb_raw_unlink_send(private->tree, unl);
305
306         SIMPLE_ASYNC_TAIL;
307 }
308
309 /*
310   a handler for async ioctl replies
311  */
312 static void async_ioctl(struct smbcli_request *c_req)
313 {
314         struct async_info *async = c_req->async.private;
315         struct ntvfs_request *req = async->req;
316         req->async_states->status = smb_raw_ioctl_recv(c_req, req, async->parms);
317         talloc_free(async);
318         req->async_states->send_fn(req);
319 }
320
321 /*
322   ioctl interface
323 */
324 static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs, 
325                            struct ntvfs_request *req, union smb_ioctl *io)
326 {
327         struct cvfs_private *private = ntvfs->private_data;
328         struct smbcli_request *c_req;
329
330         SETUP_PID_AND_FILE;
331
332         /* see if the front end will allow us to perform this
333            function asynchronously.  */
334         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
335                 return smb_raw_ioctl(private->tree, req, io);
336         }
337
338         c_req = smb_raw_ioctl_send(private->tree, io);
339
340         ASYNC_RECV_TAIL(io, async_ioctl);
341 }
342
343 /*
344   check if a directory exists
345 */
346 static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs, 
347                              struct ntvfs_request *req, union smb_chkpath *cp)
348 {
349         struct cvfs_private *private = ntvfs->private_data;
350         struct smbcli_request *c_req;
351
352         SETUP_PID;
353
354         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
355                 return smb_raw_chkpath(private->tree, cp);
356         }
357
358         c_req = smb_raw_chkpath_send(private->tree, cp);
359
360         SIMPLE_ASYNC_TAIL;
361 }
362
363 /*
364   a handler for async qpathinfo replies
365  */
366 static void async_qpathinfo(struct smbcli_request *c_req)
367 {
368         struct async_info *async = c_req->async.private;
369         struct ntvfs_request *req = async->req;
370         req->async_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms);
371         talloc_free(async);
372         req->async_states->send_fn(req);
373 }
374
375 /*
376   return info on a pathname
377 */
378 static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs, 
379                                struct ntvfs_request *req, union smb_fileinfo *info)
380 {
381         struct cvfs_private *private = ntvfs->private_data;
382         struct smbcli_request *c_req;
383
384         SETUP_PID;
385
386         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
387                 return smb_raw_pathinfo(private->tree, req, info);
388         }
389
390         c_req = smb_raw_pathinfo_send(private->tree, info);
391
392         ASYNC_RECV_TAIL(info, async_qpathinfo);
393 }
394
395 /*
396   a handler for async qfileinfo replies
397  */
398 static void async_qfileinfo(struct smbcli_request *c_req)
399 {
400         struct async_info *async = c_req->async.private;
401         struct ntvfs_request *req = async->req;
402         req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms);
403         talloc_free(async);
404         req->async_states->send_fn(req);
405 }
406
407 /*
408   query info on a open file
409 */
410 static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs, 
411                                struct ntvfs_request *req, union smb_fileinfo *io)
412 {
413         struct cvfs_private *private = ntvfs->private_data;
414         struct smbcli_request *c_req;
415
416         SETUP_PID_AND_FILE;
417
418         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
419                 return smb_raw_fileinfo(private->tree, req, io);
420         }
421
422         c_req = smb_raw_fileinfo_send(private->tree, io);
423
424         ASYNC_RECV_TAIL(io, async_qfileinfo);
425 }
426
427
428 /*
429   set info on a pathname
430 */
431 static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs, 
432                                  struct ntvfs_request *req, union smb_setfileinfo *st)
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_setpathinfo(private->tree, st);
441         }
442
443         c_req = smb_raw_setpathinfo_send(private->tree, st);
444
445         SIMPLE_ASYNC_TAIL;
446 }
447
448
449 /*
450   a handler for async open replies
451  */
452 static void async_open(struct smbcli_request *c_req)
453 {
454         struct async_info *async = c_req->async.private;
455         struct cvfs_private *cvfs = async->cvfs;
456         struct ntvfs_request *req = async->req;
457         struct cvfs_file *f = async->f;
458         union smb_open *io = async->parms;
459         union smb_handle *file;
460         talloc_free(async);
461         req->async_states->status = smb_raw_open_recv(c_req, req, io);
462         SMB_OPEN_OUT_FILE(io, file);
463         f->fnum = file->fnum;
464         file->ntvfs = NULL;
465         if (!NT_STATUS_IS_OK(req->async_states->status)) goto failed;
466         req->async_states->status = ntvfs_handle_set_backend_data(f->h, cvfs->ntvfs, f);
467         if (!NT_STATUS_IS_OK(req->async_states->status)) goto failed;
468         file->ntvfs = f->h;
469 failed:
470         req->async_states->send_fn(req);
471 }
472
473 /*
474   open a file
475 */
476 static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs, 
477                           struct ntvfs_request *req, union smb_open *io)
478 {
479         struct cvfs_private *private = ntvfs->private_data;
480         struct smbcli_request *c_req;
481         struct ntvfs_handle *h;
482         struct cvfs_file *f;
483         NTSTATUS status;
484
485         SETUP_PID;
486
487         if (io->generic.level != RAW_OPEN_GENERIC &&
488             private->map_generic) {
489                 return ntvfs_map_open(ntvfs, req, io);
490         }
491
492         status = ntvfs_handle_new(ntvfs, req, &h);
493         NT_STATUS_NOT_OK_RETURN(status);
494
495         f = talloc_zero(h, struct cvfs_file);
496         NT_STATUS_HAVE_NO_MEMORY(f);
497         f->h = h;
498
499         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
500                 union smb_handle *file;
501
502                 status = smb_raw_open(private->tree, req, io);
503                 NT_STATUS_NOT_OK_RETURN(status);
504
505                 SMB_OPEN_OUT_FILE(io, file);
506                 f->fnum = file->fnum;
507                 file->ntvfs = NULL;
508                 status = ntvfs_handle_set_backend_data(f->h, private->ntvfs, f);
509                 NT_STATUS_NOT_OK_RETURN(status);
510                 file->ntvfs = f->h;
511
512                 return NT_STATUS_OK;
513         }
514
515         c_req = smb_raw_open_send(private->tree, io);
516
517         ASYNC_RECV_TAIL_F(io, async_open, f);
518 }
519
520 /*
521   create a directory
522 */
523 static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs, 
524                            struct ntvfs_request *req, union smb_mkdir *md)
525 {
526         struct cvfs_private *private = ntvfs->private_data;
527         struct smbcli_request *c_req;
528
529         SETUP_PID;
530
531         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
532                 return smb_raw_mkdir(private->tree, md);
533         }
534
535         c_req = smb_raw_mkdir_send(private->tree, md);
536
537         SIMPLE_ASYNC_TAIL;
538 }
539
540 /*
541   remove a directory
542 */
543 static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs, 
544                            struct ntvfs_request *req, struct smb_rmdir *rd)
545 {
546         struct cvfs_private *private = ntvfs->private_data;
547         struct smbcli_request *c_req;
548
549         SETUP_PID;
550
551         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
552                 return smb_raw_rmdir(private->tree, rd);
553         }
554         c_req = smb_raw_rmdir_send(private->tree, rd);
555
556         SIMPLE_ASYNC_TAIL;
557 }
558
559 /*
560   rename a set of files
561 */
562 static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs, 
563                             struct ntvfs_request *req, union smb_rename *ren)
564 {
565         struct cvfs_private *private = ntvfs->private_data;
566         struct smbcli_request *c_req;
567
568         SETUP_PID;
569
570         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
571                 return smb_raw_rename(private->tree, ren);
572         }
573
574         c_req = smb_raw_rename_send(private->tree, ren);
575
576         SIMPLE_ASYNC_TAIL;
577 }
578
579 /*
580   copy a set of files
581 */
582 static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs, 
583                           struct ntvfs_request *req, struct smb_copy *cp)
584 {
585         return NT_STATUS_NOT_SUPPORTED;
586 }
587
588 /*
589   a handler for async read replies
590  */
591 static void async_read(struct smbcli_request *c_req)
592 {
593         struct async_info *async = c_req->async.private;
594         struct ntvfs_request *req = async->req;
595         req->async_states->status = smb_raw_read_recv(c_req, async->parms);
596         talloc_free(async);
597         req->async_states->send_fn(req);
598 }
599
600 /*
601   read from a file
602 */
603 static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs, 
604                           struct ntvfs_request *req, union smb_read *io)
605 {
606         struct cvfs_private *private = ntvfs->private_data;
607         struct smbcli_request *c_req;
608
609         SETUP_PID;
610
611         if (io->generic.level != RAW_READ_GENERIC &&
612             private->map_generic) {
613                 return ntvfs_map_read(ntvfs, req, io);
614         }
615
616         SETUP_FILE;
617
618         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
619                 return smb_raw_read(private->tree, io);
620         }
621
622         c_req = smb_raw_read_send(private->tree, io);
623
624         ASYNC_RECV_TAIL(io, async_read);
625 }
626
627 /*
628   a handler for async write replies
629  */
630 static void async_write(struct smbcli_request *c_req)
631 {
632         struct async_info *async = c_req->async.private;
633         struct ntvfs_request *req = async->req;
634         req->async_states->status = smb_raw_write_recv(c_req, async->parms);
635         talloc_free(async);
636         req->async_states->send_fn(req);
637 }
638
639 /*
640   write to a file
641 */
642 static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs, 
643                            struct ntvfs_request *req, union smb_write *io)
644 {
645         struct cvfs_private *private = ntvfs->private_data;
646         struct smbcli_request *c_req;
647
648         SETUP_PID;
649
650         if (io->generic.level != RAW_WRITE_GENERIC &&
651             private->map_generic) {
652                 return ntvfs_map_write(ntvfs, req, io);
653         }
654         SETUP_FILE;
655
656         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
657                 return smb_raw_write(private->tree, io);
658         }
659
660         c_req = smb_raw_write_send(private->tree, io);
661
662         ASYNC_RECV_TAIL(io, async_write);
663 }
664
665 /*
666   a handler for async seek replies
667  */
668 static void async_seek(struct smbcli_request *c_req)
669 {
670         struct async_info *async = c_req->async.private;
671         struct ntvfs_request *req = async->req;
672         req->async_states->status = smb_raw_seek_recv(c_req, async->parms);
673         talloc_free(async);
674         req->async_states->send_fn(req);
675 }
676
677 /*
678   seek in a file
679 */
680 static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs, 
681                           struct ntvfs_request *req,
682                           union smb_seek *io)
683 {
684         struct cvfs_private *private = ntvfs->private_data;
685         struct smbcli_request *c_req;
686
687         SETUP_PID_AND_FILE;
688
689         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
690                 return smb_raw_seek(private->tree, io);
691         }
692
693         c_req = smb_raw_seek_send(private->tree, io);
694
695         ASYNC_RECV_TAIL(io, async_seek);
696 }
697
698 /*
699   flush a file
700 */
701 static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs, 
702                            struct ntvfs_request *req,
703                            union smb_flush *io)
704 {
705         struct cvfs_private *private = ntvfs->private_data;
706         struct smbcli_request *c_req;
707
708         SETUP_PID;
709         switch (io->generic.level) {
710         case RAW_FLUSH_FLUSH:
711                 SETUP_FILE;
712                 break;
713         case RAW_FLUSH_ALL:
714                 io->generic.in.file.fnum = 0xFFFF;
715                 break;
716         case RAW_FLUSH_SMB2:
717                 return NT_STATUS_INVALID_LEVEL;
718         }
719
720         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
721                 return smb_raw_flush(private->tree, io);
722         }
723
724         c_req = smb_raw_flush_send(private->tree, io);
725
726         SIMPLE_ASYNC_TAIL;
727 }
728
729 /*
730   close a file
731 */
732 static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs, 
733                            struct ntvfs_request *req, union smb_close *io)
734 {
735         struct cvfs_private *private = ntvfs->private_data;
736         struct smbcli_request *c_req;
737
738         SETUP_PID;
739
740         if (io->generic.level != RAW_CLOSE_GENERIC &&
741             private->map_generic) {
742                 return ntvfs_map_close(ntvfs, req, io);
743         }
744         SETUP_FILE;
745
746         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
747                 return smb_raw_close(private->tree, io);
748         }
749
750         c_req = smb_raw_close_send(private->tree, io);
751
752         SIMPLE_ASYNC_TAIL;
753 }
754
755 /*
756   exit - closing files open by the pid
757 */
758 static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs, 
759                           struct ntvfs_request *req)
760 {
761         struct cvfs_private *private = ntvfs->private_data;
762         struct smbcli_request *c_req;
763
764         SETUP_PID;
765
766         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
767                 return smb_raw_exit(private->tree->session);
768         }
769
770         c_req = smb_raw_exit_send(private->tree->session);
771
772         SIMPLE_ASYNC_TAIL;
773 }
774
775 /*
776   logoff - closing files open by the user
777 */
778 static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs, 
779                             struct ntvfs_request *req)
780 {
781         /* we can't do this right in the cifs backend .... */
782         return NT_STATUS_OK;
783 }
784
785 /*
786   setup for an async call - nothing to do yet
787 */
788 static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs, 
789                                  struct ntvfs_request *req, 
790                                  void *private)
791 {
792         return NT_STATUS_OK;
793 }
794
795 /*
796   cancel an async call
797 */
798 static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs, 
799                             struct ntvfs_request *req)
800 {
801         struct cvfs_private *private = ntvfs->private_data;
802         struct async_info *a;
803
804         /* find the matching request */
805         for (a=private->pending;a;a=a->next) {
806                 if (a->req == req) {
807                         break;
808                 }
809         }
810
811         if (a == NULL) {
812                 return NT_STATUS_INVALID_PARAMETER;
813         }
814
815         return smb_raw_ntcancel(a->c_req);
816 }
817
818 /*
819   lock a byte range
820 */
821 static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs, 
822                           struct ntvfs_request *req, union smb_lock *io)
823 {
824         struct cvfs_private *private = ntvfs->private_data;
825         struct smbcli_request *c_req;
826
827         SETUP_PID;
828
829         if (io->generic.level != RAW_LOCK_GENERIC &&
830             private->map_generic) {
831                 return ntvfs_map_lock(ntvfs, req, io);
832         }
833         SETUP_FILE;
834
835         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
836                 return smb_raw_lock(private->tree, io);
837         }
838
839         c_req = smb_raw_lock_send(private->tree, io);
840         SIMPLE_ASYNC_TAIL;
841 }
842
843 /*
844   set info on a open file
845 */
846 static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs, 
847                                  struct ntvfs_request *req, 
848                                  union smb_setfileinfo *io)
849 {
850         struct cvfs_private *private = ntvfs->private_data;
851         struct smbcli_request *c_req;
852
853         SETUP_PID_AND_FILE;
854
855         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
856                 return smb_raw_setfileinfo(private->tree, io);
857         }
858         c_req = smb_raw_setfileinfo_send(private->tree, io);
859
860         SIMPLE_ASYNC_TAIL;
861 }
862
863
864 /*
865   a handler for async fsinfo replies
866  */
867 static void async_fsinfo(struct smbcli_request *c_req)
868 {
869         struct async_info *async = c_req->async.private;
870         struct ntvfs_request *req = async->req;
871         req->async_states->status = smb_raw_fsinfo_recv(c_req, req, async->parms);
872         talloc_free(async);
873         req->async_states->send_fn(req);
874 }
875
876 /*
877   return filesystem space info
878 */
879 static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs, 
880                             struct ntvfs_request *req, union smb_fsinfo *fs)
881 {
882         struct cvfs_private *private = ntvfs->private_data;
883         struct smbcli_request *c_req;
884
885         SETUP_PID;
886
887         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
888                 return smb_raw_fsinfo(private->tree, req, fs);
889         }
890
891         c_req = smb_raw_fsinfo_send(private->tree, req, fs);
892
893         ASYNC_RECV_TAIL(fs, async_fsinfo);
894 }
895
896 /*
897   return print queue info
898 */
899 static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs, 
900                          struct ntvfs_request *req, union smb_lpq *lpq)
901 {
902         return NT_STATUS_NOT_SUPPORTED;
903 }
904
905 /* 
906    list files in a directory matching a wildcard pattern
907 */
908 static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs, 
909                                   struct ntvfs_request *req, union smb_search_first *io, 
910                                   void *search_private, 
911                                   BOOL (*callback)(void *, union smb_search_data *))
912 {
913         struct cvfs_private *private = ntvfs->private_data;
914
915         SETUP_PID;
916
917         return smb_raw_search_first(private->tree, req, io, search_private, callback);
918 }
919
920 /* continue a search */
921 static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs, 
922                                  struct ntvfs_request *req, union smb_search_next *io, 
923                                  void *search_private, 
924                                  BOOL (*callback)(void *, union smb_search_data *))
925 {
926         struct cvfs_private *private = ntvfs->private_data;
927
928         SETUP_PID;
929
930         return smb_raw_search_next(private->tree, req, io, search_private, callback);
931 }
932
933 /* close a search */
934 static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs, 
935                                   struct ntvfs_request *req, union smb_search_close *io)
936 {
937         struct cvfs_private *private = ntvfs->private_data;
938
939         SETUP_PID;
940
941         return smb_raw_search_close(private->tree, io);
942 }
943
944 /*
945   a handler for async trans2 replies
946  */
947 static void async_trans2(struct smbcli_request *c_req)
948 {
949         struct async_info *async = c_req->async.private;
950         struct ntvfs_request *req = async->req;
951         req->async_states->status = smb_raw_trans2_recv(c_req, req, async->parms);
952         talloc_free(async);
953         req->async_states->send_fn(req);
954 }
955
956 /* raw trans2 */
957 static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs, 
958                             struct ntvfs_request *req,
959                             struct smb_trans2 *trans2)
960 {
961         struct cvfs_private *private = ntvfs->private_data;
962         struct smbcli_request *c_req;
963
964         if (private->map_trans2) {
965                 return NT_STATUS_NOT_IMPLEMENTED;
966         }
967
968         SETUP_PID;
969
970         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
971                 return smb_raw_trans2(private->tree, req, trans2);
972         }
973
974         c_req = smb_raw_trans2_send(private->tree, trans2);
975
976         ASYNC_RECV_TAIL(trans2, async_trans2);
977 }
978
979
980 /* SMBtrans - not used on file shares */
981 static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs, 
982                            struct ntvfs_request *req,
983                            struct smb_trans2 *trans2)
984 {
985         return NT_STATUS_ACCESS_DENIED;
986 }
987
988 /*
989   a handler for async change notify replies
990  */
991 static void async_changenotify(struct smbcli_request *c_req)
992 {
993         struct async_info *async = c_req->async.private;
994         struct ntvfs_request *req = async->req;
995         req->async_states->status = smb_raw_changenotify_recv(c_req, req, async->parms);
996         talloc_free(async);
997         req->async_states->send_fn(req);
998 }
999
1000 /* change notify request - always async */
1001 static NTSTATUS cvfs_notify(struct ntvfs_module_context *ntvfs, 
1002                             struct ntvfs_request *req,
1003                             union smb_notify *io)
1004 {
1005         struct cvfs_private *private = ntvfs->private_data;
1006         struct smbcli_request *c_req;
1007         int saved_timeout = private->transport->options.request_timeout;
1008         struct cvfs_file *f;
1009
1010         if (io->nttrans.level != RAW_NOTIFY_NTTRANS) {
1011                 return NT_STATUS_NOT_IMPLEMENTED;
1012         }
1013
1014         SETUP_PID;
1015
1016         f = ntvfs_handle_get_backend_data(io->nttrans.in.file.ntvfs, ntvfs);
1017         if (!f) return NT_STATUS_INVALID_HANDLE;
1018         io->nttrans.in.file.fnum = f->fnum;
1019
1020         /* this request doesn't make sense unless its async */
1021         if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1022                 return NT_STATUS_INVALID_PARAMETER;
1023         }
1024
1025         /* we must not timeout on notify requests - they wait
1026            forever */
1027         private->transport->options.request_timeout = 0;
1028
1029         c_req = smb_raw_changenotify_send(private->tree, io);
1030
1031         private->transport->options.request_timeout = saved_timeout;
1032
1033         ASYNC_RECV_TAIL(io, async_changenotify);
1034 }
1035
1036 /*
1037   initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
1038  */
1039 NTSTATUS ntvfs_cifs_init(void)
1040 {
1041         NTSTATUS ret;
1042         struct ntvfs_ops ops;
1043         NTVFS_CURRENT_CRITICAL_SIZES(vers);
1044
1045         ZERO_STRUCT(ops);
1046
1047         /* fill in the name and type */
1048         ops.name = "cifs";
1049         ops.type = NTVFS_DISK;
1050         
1051         /* fill in all the operations */
1052         ops.connect = cvfs_connect;
1053         ops.disconnect = cvfs_disconnect;
1054         ops.unlink = cvfs_unlink;
1055         ops.chkpath = cvfs_chkpath;
1056         ops.qpathinfo = cvfs_qpathinfo;
1057         ops.setpathinfo = cvfs_setpathinfo;
1058         ops.open = cvfs_open;
1059         ops.mkdir = cvfs_mkdir;
1060         ops.rmdir = cvfs_rmdir;
1061         ops.rename = cvfs_rename;
1062         ops.copy = cvfs_copy;
1063         ops.ioctl = cvfs_ioctl;
1064         ops.read = cvfs_read;
1065         ops.write = cvfs_write;
1066         ops.seek = cvfs_seek;
1067         ops.flush = cvfs_flush; 
1068         ops.close = cvfs_close;
1069         ops.exit = cvfs_exit;
1070         ops.lock = cvfs_lock;
1071         ops.setfileinfo = cvfs_setfileinfo;
1072         ops.qfileinfo = cvfs_qfileinfo;
1073         ops.fsinfo = cvfs_fsinfo;
1074         ops.lpq = cvfs_lpq;
1075         ops.search_first = cvfs_search_first;
1076         ops.search_next = cvfs_search_next;
1077         ops.search_close = cvfs_search_close;
1078         ops.trans = cvfs_trans;
1079         ops.logoff = cvfs_logoff;
1080         ops.async_setup = cvfs_async_setup;
1081         ops.cancel = cvfs_cancel;
1082         ops.notify = cvfs_notify;
1083         ops.trans2 = cvfs_trans2;
1084
1085         /* register ourselves with the NTVFS subsystem. We register
1086            under the name 'cifs'. */
1087         ret = ntvfs_register(&ops, &vers);
1088
1089         if (!NT_STATUS_IS_OK(ret)) {
1090                 DEBUG(0,("Failed to register CIFS backend!\n"));
1091         }
1092         
1093         return ret;
1094 }