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 cvfs_private *private = fde->private;
77 struct tcon_context *conn = private->conn;
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 give a trans2
149 pointer in the operations structure */
150 if (private->map_calls && in_list("trans2", private->map_calls, True)) {
151 struct ntvfs_ops *ops = talloc_memdup(conn->mem_ctx,conn->ntvfs_ops,sizeof(*ops));
152 static NTSTATUS cvfs_trans2(struct request_context *,struct smb_trans2 *);
154 return NT_STATUS_NO_MEMORY;
156 ops->trans2 = cvfs_trans2;
157 conn->ntvfs_ops = ops;
160 /* we need to tell the event loop that we wish to receive read events
161 on our SMB connection to the server */
162 fde.fd = private->transport->socket->fd;
163 fde.flags = EVENT_FD_READ;
164 fde.private = private;
165 fde.handler = cifs_socket_handler;
167 event_add_fd(conn->smb->events, &fde);
169 /* we need to receive oplock break requests from the server */
170 cli_oplock_handler(private->transport, oplock_handler, private);
171 cli_transport_idle_handler(private->transport, idle_func, 100, private);
177 disconnect from a share
179 static NTSTATUS cvfs_disconnect(struct tcon_context *conn)
181 struct cvfs_private *private = conn->ntvfs_private;
183 event_remove_fd_all(conn->smb->events, private->transport->socket->fd);
184 smb_tree_disconnect(private->tree);
185 cli_tree_close(private->tree);
191 a handler for simple async replies
192 this handler can only be used for functions that don't return any
193 parameters (those that just return a status code)
195 static void async_simple(struct cli_request *c_req)
197 struct async_info *async = c_req->async.private;
198 struct request_context *req = async->req;
199 req->async.status = cli_request_simple_recv(c_req);
200 req->async.send_fn(req);
204 /* save some typing for the simple functions */
205 #define ASYNC_RECV_TAIL(io, async_fn) do { \
206 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
208 struct async_info *async; \
209 async = talloc(req->mem_ctx, sizeof(*async)); \
210 if (!async) return NT_STATUS_NO_MEMORY; \
213 c_req->async.private = async; \
215 c_req->async.fn = async_fn; \
216 req->control_flags |= REQ_CONTROL_ASYNC; \
217 return NT_STATUS_OK; \
220 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
223 delete a file - the dirtype specifies the file types to include in the search.
224 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
226 static NTSTATUS cvfs_unlink(struct request_context *req, struct smb_unlink *unl)
228 struct cvfs_private *private = req->conn->ntvfs_private;
229 struct cli_request *c_req;
231 /* see if the front end will allow us to perform this
232 function asynchronously. */
233 if (!req->async.send_fn) {
234 return smb_raw_unlink(private->tree, unl);
237 c_req = smb_raw_unlink_send(private->tree, unl);
243 a handler for async ioctl replies
245 static void async_ioctl(struct cli_request *c_req)
247 struct async_info *async = c_req->async.private;
248 struct request_context *req = async->req;
249 req->async.status = smb_raw_ioctl_recv(c_req, req->mem_ctx, async->parms);
250 req->async.send_fn(req);
256 static NTSTATUS cvfs_ioctl(struct request_context *req, union smb_ioctl *io)
258 struct cvfs_private *private = req->conn->ntvfs_private;
259 struct cli_request *c_req;
261 /* see if the front end will allow us to perform this
262 function asynchronously. */
263 if (!req->async.send_fn) {
264 return smb_raw_ioctl(private->tree, req->mem_ctx, io);
267 c_req = smb_raw_ioctl_send(private->tree, io);
269 ASYNC_RECV_TAIL(io, async_ioctl);
273 check if a directory exists
275 static NTSTATUS cvfs_chkpath(struct request_context *req, struct smb_chkpath *cp)
277 struct cvfs_private *private = req->conn->ntvfs_private;
278 struct cli_request *c_req;
280 if (!req->async.send_fn) {
281 return smb_raw_chkpath(private->tree, cp);
284 c_req = smb_raw_chkpath_send(private->tree, cp);
290 a handler for async qpathinfo replies
292 static void async_qpathinfo(struct cli_request *c_req)
294 struct async_info *async = c_req->async.private;
295 struct request_context *req = async->req;
296 req->async.status = smb_raw_pathinfo_recv(c_req, req->mem_ctx, async->parms);
297 req->async.send_fn(req);
301 return info on a pathname
303 static NTSTATUS cvfs_qpathinfo(struct request_context *req, union smb_fileinfo *info)
305 struct cvfs_private *private = req->conn->ntvfs_private;
306 struct cli_request *c_req;
308 if (!req->async.send_fn) {
309 return smb_raw_pathinfo(private->tree, req->mem_ctx, info);
312 c_req = smb_raw_pathinfo_send(private->tree, info);
314 ASYNC_RECV_TAIL(info, async_qpathinfo);
318 a handler for async qfileinfo replies
320 static void async_qfileinfo(struct cli_request *c_req)
322 struct async_info *async = c_req->async.private;
323 struct request_context *req = async->req;
324 req->async.status = smb_raw_fileinfo_recv(c_req, req->mem_ctx, async->parms);
325 req->async.send_fn(req);
329 query info on a open file
331 static NTSTATUS cvfs_qfileinfo(struct request_context *req, union smb_fileinfo *info)
333 struct cvfs_private *private = req->conn->ntvfs_private;
334 struct cli_request *c_req;
336 if (!req->async.send_fn) {
337 return smb_raw_fileinfo(private->tree, req->mem_ctx, info);
340 c_req = smb_raw_fileinfo_send(private->tree, info);
342 ASYNC_RECV_TAIL(info, async_qfileinfo);
347 set info on a pathname
349 static NTSTATUS cvfs_setpathinfo(struct request_context *req, union smb_setfileinfo *st)
351 struct cvfs_private *private = req->conn->ntvfs_private;
352 struct cli_request *c_req;
354 if (!req->async.send_fn) {
355 return smb_raw_setpathinfo(private->tree, st);
358 c_req = smb_raw_setpathinfo_send(private->tree, st);
365 a handler for async open replies
367 static void async_open(struct cli_request *c_req)
369 struct async_info *async = c_req->async.private;
370 struct request_context *req = async->req;
371 req->async.status = smb_raw_open_recv(c_req, req->mem_ctx, async->parms);
372 req->async.send_fn(req);
378 static NTSTATUS cvfs_open(struct request_context *req, union smb_open *io)
380 struct cvfs_private *private = req->conn->ntvfs_private;
381 struct cli_request *c_req;
383 if (private->map_calls && in_list("open", private->map_calls, True) &&
384 io->generic.level != RAW_OPEN_GENERIC) {
385 return ntvfs_map_open(req, io);
388 if (!req->async.send_fn) {
389 return smb_raw_open(private->tree, req->mem_ctx, io);
392 c_req = smb_raw_open_send(private->tree, io);
394 ASYNC_RECV_TAIL(io, async_open);
400 static NTSTATUS cvfs_mkdir(struct request_context *req, union smb_mkdir *md)
402 struct cvfs_private *private = req->conn->ntvfs_private;
403 struct cli_request *c_req;
405 if (!req->async.send_fn) {
406 return smb_raw_mkdir(private->tree, md);
409 c_req = smb_raw_mkdir_send(private->tree, md);
417 static NTSTATUS cvfs_rmdir(struct request_context *req, struct smb_rmdir *rd)
419 struct cvfs_private *private = req->conn->ntvfs_private;
420 struct cli_request *c_req;
422 if (!req->async.send_fn) {
423 return smb_raw_rmdir(private->tree, rd);
425 c_req = smb_raw_rmdir_send(private->tree, rd);
431 rename a set of files
433 static NTSTATUS cvfs_rename(struct request_context *req, union smb_rename *ren)
435 struct cvfs_private *private = req->conn->ntvfs_private;
436 struct cli_request *c_req;
438 if (!req->async.send_fn) {
439 return smb_raw_rename(private->tree, ren);
442 c_req = smb_raw_rename_send(private->tree, ren);
450 static NTSTATUS cvfs_copy(struct request_context *req, struct smb_copy *cp)
452 return NT_STATUS_NOT_SUPPORTED;
456 a handler for async read replies
458 static void async_read(struct cli_request *c_req)
460 struct async_info *async = c_req->async.private;
461 struct request_context *req = async->req;
462 req->async.status = smb_raw_read_recv(c_req, async->parms);
463 req->async.send_fn(req);
469 static NTSTATUS cvfs_read(struct request_context *req, union smb_read *rd)
471 struct cvfs_private *private = req->conn->ntvfs_private;
472 struct cli_request *c_req;
474 if (!req->async.send_fn) {
475 return smb_raw_read(private->tree, rd);
478 c_req = smb_raw_read_send(private->tree, rd);
480 ASYNC_RECV_TAIL(rd, async_read);
484 a handler for async write replies
486 static void async_write(struct cli_request *c_req)
488 struct async_info *async = c_req->async.private;
489 struct request_context *req = async->req;
490 req->async.status = smb_raw_write_recv(c_req, async->parms);
491 req->async.send_fn(req);
497 static NTSTATUS cvfs_write(struct request_context *req, union smb_write *wr)
499 struct cvfs_private *private = req->conn->ntvfs_private;
500 struct cli_request *c_req;
502 if (!req->async.send_fn) {
503 return smb_raw_write(private->tree, wr);
506 c_req = smb_raw_write_send(private->tree, wr);
508 ASYNC_RECV_TAIL(wr, async_write);
514 static NTSTATUS cvfs_seek(struct request_context *req, struct smb_seek *io)
516 return NT_STATUS_NOT_SUPPORTED;
522 static NTSTATUS cvfs_flush(struct request_context *req, struct smb_flush *io)
530 static NTSTATUS cvfs_close(struct request_context *req, union smb_close *io)
532 struct cvfs_private *private = req->conn->ntvfs_private;
533 struct cli_request *c_req;
535 if (!req->async.send_fn) {
536 return smb_raw_close(private->tree, io);
539 c_req = smb_raw_close_send(private->tree, io);
545 exit - closing files?
547 static NTSTATUS cvfs_exit(struct request_context *req)
549 return NT_STATUS_NOT_SUPPORTED;
555 static NTSTATUS cvfs_lock(struct request_context *req, union smb_lock *lck)
557 struct cvfs_private *private = req->conn->ntvfs_private;
558 struct cli_request *c_req;
560 if (!req->async.send_fn) {
561 return smb_raw_lock(private->tree, lck);
564 c_req = smb_raw_lock_send(private->tree, lck);
569 set info on a open file
571 static NTSTATUS cvfs_setfileinfo(struct request_context *req,
572 union smb_setfileinfo *info)
574 struct cvfs_private *private = req->conn->ntvfs_private;
575 struct cli_request *c_req;
577 if (!req->async.send_fn) {
578 return smb_raw_setfileinfo(private->tree, info);
580 c_req = smb_raw_setfileinfo_send(private->tree, info);
587 a handler for async fsinfo replies
589 static void async_fsinfo(struct cli_request *c_req)
591 struct async_info *async = c_req->async.private;
592 struct request_context *req = async->req;
593 req->async.status = smb_raw_fsinfo_recv(c_req, req->mem_ctx, async->parms);
594 req->async.send_fn(req);
598 return filesystem space info
600 static NTSTATUS cvfs_fsinfo(struct request_context *req, union smb_fsinfo *fs)
602 struct cvfs_private *private = req->conn->ntvfs_private;
603 struct cli_request *c_req;
605 if (!req->async.send_fn) {
606 return smb_raw_fsinfo(private->tree, req->mem_ctx, fs);
609 c_req = smb_raw_fsinfo_send(private->tree, req->mem_ctx, fs);
611 ASYNC_RECV_TAIL(fs, async_fsinfo);
615 return print queue info
617 static NTSTATUS cvfs_lpq(struct request_context *req, union smb_lpq *lpq)
619 return NT_STATUS_NOT_SUPPORTED;
623 list files in a directory matching a wildcard pattern
625 static NTSTATUS cvfs_search_first(struct request_context *req, union smb_search_first *io,
626 void *search_private,
627 BOOL (*callback)(void *, union smb_search_data *))
629 struct cvfs_private *private = req->conn->ntvfs_private;
631 return smb_raw_search_first(private->tree, req->mem_ctx, io, search_private, callback);
634 /* continue a search */
635 static NTSTATUS cvfs_search_next(struct request_context *req, union smb_search_next *io,
636 void *search_private,
637 BOOL (*callback)(void *, union smb_search_data *))
639 struct cvfs_private *private = req->conn->ntvfs_private;
641 return smb_raw_search_next(private->tree, req->mem_ctx, io, search_private, callback);
645 static NTSTATUS cvfs_search_close(struct request_context *req, union smb_search_close *io)
647 struct cvfs_private *private = req->conn->ntvfs_private;
649 return smb_raw_search_close(private->tree, io);
653 a handler for async trans2 replies
655 static void async_trans2(struct cli_request *c_req)
657 struct async_info *async = c_req->async.private;
658 struct request_context *req = async->req;
659 req->async.status = smb_raw_trans2_recv(c_req, req->mem_ctx, async->parms);
660 req->async.send_fn(req);
664 static NTSTATUS cvfs_trans2(struct request_context *req, struct smb_trans2 *trans2)
666 struct cvfs_private *private = req->conn->ntvfs_private;
667 struct cli_request *c_req;
669 if (!req->async.send_fn) {
670 return smb_raw_trans2(private->tree, req->mem_ctx, trans2);
673 c_req = smb_raw_trans2_send(private->tree, trans2);
675 ASYNC_RECV_TAIL(trans2, async_trans2);
679 /* SMBtrans - not used on file shares */
680 static NTSTATUS cvfs_trans(struct request_context *req, struct smb_trans2 *trans2)
682 return NT_STATUS_ACCESS_DENIED;
686 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
688 NTSTATUS ntvfs_cifs_init(void)
691 struct ntvfs_ops ops;
695 /* fill in the name and type */
697 ops.type = NTVFS_DISK;
699 /* fill in all the operations */
700 ops.connect = cvfs_connect;
701 ops.disconnect = cvfs_disconnect;
702 ops.unlink = cvfs_unlink;
703 ops.chkpath = cvfs_chkpath;
704 ops.qpathinfo = cvfs_qpathinfo;
705 ops.setpathinfo = cvfs_setpathinfo;
706 ops.open = cvfs_open;
707 ops.mkdir = cvfs_mkdir;
708 ops.rmdir = cvfs_rmdir;
709 ops.rename = cvfs_rename;
710 ops.copy = cvfs_copy;
711 ops.ioctl = cvfs_ioctl;
712 ops.read = cvfs_read;
713 ops.write = cvfs_write;
714 ops.seek = cvfs_seek;
715 ops.flush = cvfs_flush;
716 ops.close = cvfs_close;
717 ops.exit = cvfs_exit;
718 ops.lock = cvfs_lock;
719 ops.setfileinfo = cvfs_setfileinfo;
720 ops.qfileinfo = cvfs_qfileinfo;
721 ops.fsinfo = cvfs_fsinfo;
723 ops.search_first = cvfs_search_first;
724 ops.search_next = cvfs_search_next;
725 ops.search_close = cvfs_search_close;
726 ops.trans = cvfs_trans;
728 /* only define this one for trans2 testing */
731 /* register ourselves with the NTVFS subsystem. We register
732 under the name 'cifs'. */
733 ret = register_backend("ntvfs", &ops);
735 if (!NT_STATUS_IS_OK(ret)) {
736 DEBUG(0,("Failed to register CIFS backend!\n"));