2 Unix SMB/CIFS implementation.
4 CIFS-on-CIFS NTVFS filesystem backend
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) James J Myers 2003 <myersjj@samba.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 this implements a CIFS->CIFS NTVFS filesystem backend.
30 /* this is stored in ntvfs_private */
32 struct cli_tree *tree;
33 struct cli_transport *transport;
34 struct tcon_context *conn;
35 const char *map_calls;
39 /* a structure used to pass information to an async handler */
41 struct request_context *req;
46 an idle function to cope with messages from the smbd client while
47 waiting for a reply from the server
48 this function won't be needed once all of the cifs backend
49 and the core of smbd is converted to use async calls
51 static void idle_func(struct cli_transport *transport, void *p_private)
53 struct cvfs_private *private = p_private;
54 if (socket_pending(private->conn->smb->socket.fd)) {
55 smbd_process_async(private->conn->smb);
60 a handler for oplock break events from the server - these need to be passed
63 static BOOL oplock_handler(struct cli_transport *transport, uint16 tid, uint16 fnum, uint8 level, void *p_private)
65 struct cvfs_private *private = p_private;
67 DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
68 return req_send_oplock_break(private->conn, fnum, level);
72 a handler for read events on a connection to a backend server
74 static void cifs_socket_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16 flags)
76 struct tcon_context *conn = fde->private;
77 struct cvfs_private *private = conn->ntvfs_private;
79 DEBUG(5,("cifs_socket_handler event on fd %d\n", fde->fd));
81 if (!cli_request_receive_next(private->transport)) {
82 /* the connection to our server is dead */
88 connect to a share - used when a tree_connect operation comes in.
90 static NTSTATUS cvfs_connect(struct request_context *req, const char *sharename)
92 struct tcon_context *conn = req->conn;
94 struct cvfs_private *private;
97 const char *host, *user, *pass, *domain, *remote_share;
99 /* Here we need to determine which server to connect to.
100 * For now we use parametric options, type cifs.
101 * Later we will use security=server and auth_server.c.
103 host = lp_parm_string(req->conn->service, "cifs", "server");
104 user = lp_parm_string(req->conn->service, "cifs", "user");
105 pass = lp_parm_string(req->conn->service, "cifs", "password");
106 domain = lp_parm_string(req->conn->service, "cifs", "domain");
107 remote_share = lp_parm_string(req->conn->service, "cifs", "share");
109 remote_share = sharename;
112 if (!host || !user || !pass || !domain) {
113 DEBUG(1,("CIFS backend: You must supply server, user, password and domain\n"));
114 return NT_STATUS_INVALID_PARAMETER;
117 private = talloc(req->conn->mem_ctx, sizeof(struct cvfs_private));
119 return NT_STATUS_NO_MEMORY;
121 ZERO_STRUCTP(private);
123 req->conn->ntvfs_private = (void *)private;
125 status = cli_tree_full_connection(&private->tree,
129 remote_share, "?????",
132 if (!NT_STATUS_IS_OK(status)) {
136 private->transport = private->tree->session->transport;
137 private->tree->session->pid = SVAL(req->in.hdr, HDR_PID);
138 private->conn = req->conn;
140 conn->fs_type = talloc_strdup(conn->mem_ctx, "NTFS");
141 conn->dev_type = talloc_strdup(conn->mem_ctx, "A:");
143 map_calls = lp_parm_string(req->conn->service, "cifs", "map calls");
145 private->map_calls = talloc_strdup(conn->mem_ctx, map_calls);
148 /* if we are mapping trans2, then we need to not give a trans2
149 pointer in the operations structure */
150 if (private->map_calls && in_list("trans2", private->map_calls, True)) {
151 conn->ntvfs_ops->trans2 = NULL;
154 /* we need to tell the event loop that we wish to receive read events
155 on our SMB connection to the server */
156 fde.fd = private->transport->socket->fd;
157 fde.flags = EVENT_FD_READ;
158 fde.private = req->conn;
159 fde.handler = cifs_socket_handler;
161 event_add_fd(conn->smb->events, &fde);
163 /* we need to receive oplock break requests from the server */
164 cli_oplock_handler(private->transport, oplock_handler, private);
165 cli_transport_idle_handler(private->transport, idle_func, 100, private);
171 disconnect from a share
173 static NTSTATUS cvfs_disconnect(struct tcon_context *conn)
175 struct cvfs_private *private = conn->ntvfs_private;
177 event_remove_fd_all(conn->smb->events, private->transport->socket->fd);
178 smb_tree_disconnect(private->tree);
179 cli_tree_close(private->tree);
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)
189 static void async_simple(struct cli_request *c_req)
191 struct async_info *async = c_req->async.private;
192 struct request_context *req = async->req;
193 req->async.status = cli_request_simple_recv(c_req);
194 req->async.send_fn(req);
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; \
202 struct async_info *async = c_req->async.private; \
203 async = talloc(req->mem_ctx, sizeof(*async)); \
204 if (!async) return NT_STATUS_NO_MEMORY; \
207 c_req->async.private = async; \
209 c_req->async.fn = async_fn; \
210 req->control_flags |= REQ_CONTROL_ASYNC; \
211 return NT_STATUS_OK; \
214 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
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)
220 static NTSTATUS cvfs_unlink(struct request_context *req, struct smb_unlink *unl)
222 struct cvfs_private *private = req->conn->ntvfs_private;
223 struct cli_request *c_req;
225 /* see if the front end will allow us to perform this
226 function asynchronously. */
227 if (!req->async.send_fn) {
228 return smb_raw_unlink(private->tree, unl);
231 c_req = smb_raw_unlink_send(private->tree, unl);
237 a handler for async ioctl replies
239 static void async_ioctl(struct cli_request *c_req)
241 struct async_info *async = c_req->async.private;
242 struct request_context *req = async->req;
243 req->async.status = smb_raw_ioctl_recv(c_req, req->mem_ctx, async->parms);
244 req->async.send_fn(req);
250 static NTSTATUS cvfs_ioctl(struct request_context *req, struct smb_ioctl *io)
252 struct cvfs_private *private = req->conn->ntvfs_private;
253 struct cli_request *c_req;
255 /* see if the front end will allow us to perform this
256 function asynchronously. */
257 if (!req->async.send_fn) {
258 return smb_raw_ioctl(private->tree, req->mem_ctx, io);
261 c_req = smb_raw_ioctl_send(private->tree, io);
263 ASYNC_RECV_TAIL(io, async_ioctl);
267 check if a directory exists
269 static NTSTATUS cvfs_chkpath(struct request_context *req, struct smb_chkpath *cp)
271 struct cvfs_private *private = req->conn->ntvfs_private;
272 struct cli_request *c_req;
274 if (!req->async.send_fn) {
275 return smb_raw_chkpath(private->tree, cp);
278 c_req = smb_raw_chkpath_send(private->tree, cp);
284 a handler for async qpathinfo replies
286 static void async_qpathinfo(struct cli_request *c_req)
288 struct async_info *async = c_req->async.private;
289 struct request_context *req = async->req;
290 req->async.status = smb_raw_pathinfo_recv(c_req, req->mem_ctx, async->parms);
291 req->async.send_fn(req);
295 return info on a pathname
297 static NTSTATUS cvfs_qpathinfo(struct request_context *req, union smb_fileinfo *info)
299 struct cvfs_private *private = req->conn->ntvfs_private;
300 struct cli_request *c_req;
302 if (!req->async.send_fn) {
303 return smb_raw_pathinfo(private->tree, req->mem_ctx, info);
306 c_req = smb_raw_pathinfo_send(private->tree, info);
308 ASYNC_RECV_TAIL(info, async_qpathinfo);
312 a handler for async qfileinfo replies
314 static void async_qfileinfo(struct cli_request *c_req)
316 struct async_info *async = c_req->async.private;
317 struct request_context *req = async->req;
318 req->async.status = smb_raw_fileinfo_recv(c_req, req->mem_ctx, async->parms);
319 req->async.send_fn(req);
323 query info on a open file
325 static NTSTATUS cvfs_qfileinfo(struct request_context *req, union smb_fileinfo *info)
327 struct cvfs_private *private = req->conn->ntvfs_private;
328 struct cli_request *c_req;
330 if (!req->async.send_fn) {
331 return smb_raw_fileinfo(private->tree, req->mem_ctx, info);
334 c_req = smb_raw_fileinfo_send(private->tree, info);
336 ASYNC_RECV_TAIL(info, async_qfileinfo);
341 set info on a pathname
343 static NTSTATUS cvfs_setpathinfo(struct request_context *req, union smb_setfileinfo *st)
345 struct cvfs_private *private = req->conn->ntvfs_private;
346 struct cli_request *c_req;
348 if (!req->async.send_fn) {
349 return smb_raw_setpathinfo(private->tree, st);
352 c_req = smb_raw_setpathinfo_send(private->tree, st);
359 a handler for async open replies
361 static void async_open(struct cli_request *c_req)
363 struct async_info *async = c_req->async.private;
364 struct request_context *req = async->req;
365 req->async.status = smb_raw_open_recv(c_req, req->mem_ctx, async->parms);
366 req->async.send_fn(req);
372 static NTSTATUS cvfs_open(struct request_context *req, union smb_open *io)
374 struct cvfs_private *private = req->conn->ntvfs_private;
375 struct cli_request *c_req;
377 if (private->map_calls && in_list("open", private->map_calls, True) &&
378 io->generic.level != RAW_OPEN_GENERIC) {
379 return ntvfs_map_open(req, io);
382 if (!req->async.send_fn) {
383 return smb_raw_open(private->tree, req->mem_ctx, io);
386 c_req = smb_raw_open_send(private->tree, io);
388 ASYNC_RECV_TAIL(io, async_open);
394 static NTSTATUS cvfs_mkdir(struct request_context *req, union smb_mkdir *md)
396 struct cvfs_private *private = req->conn->ntvfs_private;
397 struct cli_request *c_req;
399 if (!req->async.send_fn) {
400 return smb_raw_mkdir(private->tree, md);
403 c_req = smb_raw_mkdir_send(private->tree, md);
411 static NTSTATUS cvfs_rmdir(struct request_context *req, struct smb_rmdir *rd)
413 struct cvfs_private *private = req->conn->ntvfs_private;
414 struct cli_request *c_req;
416 if (!req->async.send_fn) {
417 return smb_raw_rmdir(private->tree, rd);
419 c_req = smb_raw_rmdir_send(private->tree, rd);
425 rename a set of files
427 static NTSTATUS cvfs_rename(struct request_context *req, struct smb_rename *ren)
429 struct cvfs_private *private = req->conn->ntvfs_private;
430 struct cli_request *c_req;
432 if (!req->async.send_fn) {
433 return smb_raw_rename(private->tree, ren);
436 c_req = smb_raw_rename_send(private->tree, ren);
444 static NTSTATUS cvfs_copy(struct request_context *req, struct smb_copy *cp)
446 return NT_STATUS_NOT_SUPPORTED;
450 a handler for async read replies
452 static void async_read(struct cli_request *c_req)
454 struct async_info *async = c_req->async.private;
455 struct request_context *req = async->req;
456 req->async.status = smb_raw_read_recv(c_req, async->parms);
457 req->async.send_fn(req);
463 static NTSTATUS cvfs_read(struct request_context *req, union smb_read *rd)
465 struct cvfs_private *private = req->conn->ntvfs_private;
466 struct cli_request *c_req;
468 if (!req->async.send_fn) {
469 return smb_raw_read(private->tree, rd);
472 c_req = smb_raw_read_send(private->tree, rd);
474 ASYNC_RECV_TAIL(rd, async_read);
478 a handler for async write replies
480 static void async_write(struct cli_request *c_req)
482 struct async_info *async = c_req->async.private;
483 struct request_context *req = async->req;
484 req->async.status = smb_raw_write_recv(c_req, async->parms);
485 req->async.send_fn(req);
491 static NTSTATUS cvfs_write(struct request_context *req, union smb_write *wr)
493 struct cvfs_private *private = req->conn->ntvfs_private;
494 struct cli_request *c_req;
496 if (!req->async.send_fn) {
497 return smb_raw_write(private->tree, wr);
500 c_req = smb_raw_write_send(private->tree, wr);
502 ASYNC_RECV_TAIL(wr, async_write);
508 static NTSTATUS cvfs_seek(struct request_context *req, struct smb_seek *io)
510 return NT_STATUS_NOT_SUPPORTED;
516 static NTSTATUS cvfs_flush(struct request_context *req, struct smb_flush *io)
524 static NTSTATUS cvfs_close(struct request_context *req, union smb_close *io)
526 struct cvfs_private *private = req->conn->ntvfs_private;
527 struct cli_request *c_req;
529 if (!req->async.send_fn) {
530 return smb_raw_close(private->tree, io);
533 c_req = smb_raw_close_send(private->tree, io);
539 exit - closing files?
541 static NTSTATUS cvfs_exit(struct request_context *req)
543 return NT_STATUS_NOT_SUPPORTED;
549 static NTSTATUS cvfs_lock(struct request_context *req, union smb_lock *lck)
551 struct cvfs_private *private = req->conn->ntvfs_private;
552 struct cli_request *c_req;
554 if (!req->async.send_fn) {
555 return smb_raw_lock(private->tree, lck);
558 c_req = smb_raw_lock_send(private->tree, lck);
563 set info on a open file
565 static NTSTATUS cvfs_setfileinfo(struct request_context *req,
566 union smb_setfileinfo *info)
568 struct cvfs_private *private = req->conn->ntvfs_private;
569 struct cli_request *c_req;
571 if (!req->async.send_fn) {
572 return smb_raw_setfileinfo(private->tree, info);
574 c_req = smb_raw_setfileinfo_send(private->tree, info);
581 a handler for async fsinfo replies
583 static void async_fsinfo(struct cli_request *c_req)
585 struct async_info *async = c_req->async.private;
586 struct request_context *req = async->req;
587 req->async.status = smb_raw_fsinfo_recv(c_req, req->mem_ctx, async->parms);
588 req->async.send_fn(req);
592 return filesystem space info
594 static NTSTATUS cvfs_fsinfo(struct request_context *req, union smb_fsinfo *fs)
596 struct cvfs_private *private = req->conn->ntvfs_private;
597 struct cli_request *c_req;
599 if (!req->async.send_fn) {
600 return smb_raw_fsinfo(private->tree, req->mem_ctx, fs);
603 c_req = smb_raw_fsinfo_send(private->tree, req->mem_ctx, fs);
605 ASYNC_RECV_TAIL(fs, async_fsinfo);
609 return print queue info
611 static NTSTATUS cvfs_lpq(struct request_context *req, union smb_lpq *lpq)
613 return NT_STATUS_NOT_SUPPORTED;
617 list files in a directory matching a wildcard pattern
619 static NTSTATUS cvfs_search_first(struct request_context *req, union smb_search_first *io,
620 void *search_private,
621 BOOL (*callback)(void *, union smb_search_data *))
623 struct cvfs_private *private = req->conn->ntvfs_private;
625 return smb_raw_search_first(private->tree, req->mem_ctx, io, search_private, callback);
628 /* continue a search */
629 static NTSTATUS cvfs_search_next(struct request_context *req, union smb_search_next *io,
630 void *search_private,
631 BOOL (*callback)(void *, union smb_search_data *))
633 struct cvfs_private *private = req->conn->ntvfs_private;
635 return smb_raw_search_next(private->tree, req->mem_ctx, io, search_private, callback);
639 static NTSTATUS cvfs_search_close(struct request_context *req, union smb_search_close *io)
641 struct cvfs_private *private = req->conn->ntvfs_private;
643 return smb_raw_search_close(private->tree, io);
647 a handler for async trans2 replies
649 static void async_trans2(struct cli_request *c_req)
651 struct async_info *async = c_req->async.private;
652 struct request_context *req = async->req;
653 req->async.status = smb_raw_trans2_recv(c_req, req->mem_ctx, async->parms);
654 req->async.send_fn(req);
658 static NTSTATUS cvfs_trans2(struct request_context *req, struct smb_trans2 *trans2)
660 struct cvfs_private *private = req->conn->ntvfs_private;
661 struct cli_request *c_req;
663 if (!req->async.send_fn) {
664 return smb_raw_trans2(private->tree, req->mem_ctx, trans2);
667 c_req = smb_raw_trans2_send(private->tree, trans2);
669 ASYNC_RECV_TAIL(trans2, async_trans2);
673 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
675 BOOL cifs_vfs_init(void)
678 struct ntvfs_ops ops;
682 /* fill in all the operations */
683 ops.connect = cvfs_connect;
684 ops.disconnect = cvfs_disconnect;
685 ops.unlink = cvfs_unlink;
686 ops.chkpath = cvfs_chkpath;
687 ops.qpathinfo = cvfs_qpathinfo;
688 ops.setpathinfo = cvfs_setpathinfo;
689 ops.open = cvfs_open;
690 ops.mkdir = cvfs_mkdir;
691 ops.rmdir = cvfs_rmdir;
692 ops.rename = cvfs_rename;
693 ops.copy = cvfs_copy;
694 ops.ioctl = cvfs_ioctl;
695 ops.read = cvfs_read;
696 ops.write = cvfs_write;
697 ops.seek = cvfs_seek;
698 ops.flush = cvfs_flush;
699 ops.close = cvfs_close;
700 ops.exit = cvfs_exit;
701 ops.lock = cvfs_lock;
702 ops.setfileinfo = cvfs_setfileinfo;
703 ops.qfileinfo = cvfs_qfileinfo;
704 ops.fsinfo = cvfs_fsinfo;
706 ops.search_first = cvfs_search_first;
707 ops.search_next = cvfs_search_next;
708 ops.search_close = cvfs_search_close;
710 /* only define this one for trans2 testing */
711 ops.trans2 = cvfs_trans2;
713 /* register ourselves with the NTVFS subsystem. We register under the name 'cifs'. */
715 ret = ntvfs_register("cifs", NTVFS_DISK, &ops);
718 DEBUG(0,("Failed to register CIFS backend!\n"));