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 struct ntvfs_ops *ops = talloc_memdup(conn->mem_ctx,conn->ntvfs_ops,sizeof(*ops));
153 return NT_STATUS_NO_MEMORY;
156 conn->ntvfs_ops = ops;
159 /* we need to tell the event loop that we wish to receive read events
160 on our SMB connection to the server */
161 fde.fd = private->transport->socket->fd;
162 fde.flags = EVENT_FD_READ;
163 fde.private = req->conn;
164 fde.handler = cifs_socket_handler;
166 event_add_fd(conn->smb->events, &fde);
168 /* we need to receive oplock break requests from the server */
169 cli_oplock_handler(private->transport, oplock_handler, private);
170 cli_transport_idle_handler(private->transport, idle_func, 100, private);
176 disconnect from a share
178 static NTSTATUS cvfs_disconnect(struct tcon_context *conn)
180 struct cvfs_private *private = conn->ntvfs_private;
182 event_remove_fd_all(conn->smb->events, private->transport->socket->fd);
183 smb_tree_disconnect(private->tree);
184 cli_tree_close(private->tree);
190 a handler for simple async replies
191 this handler can only be used for functions that don't return any
192 parameters (those that just return a status code)
194 static void async_simple(struct cli_request *c_req)
196 struct async_info *async = c_req->async.private;
197 struct request_context *req = async->req;
198 req->async.status = cli_request_simple_recv(c_req);
199 req->async.send_fn(req);
203 /* save some typing for the simple functions */
204 #define ASYNC_RECV_TAIL(io, async_fn) do { \
205 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
207 struct async_info *async; \
208 async = talloc(req->mem_ctx, sizeof(*async)); \
209 if (!async) return NT_STATUS_NO_MEMORY; \
212 c_req->async.private = async; \
214 c_req->async.fn = async_fn; \
215 req->control_flags |= REQ_CONTROL_ASYNC; \
216 return NT_STATUS_OK; \
219 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
222 delete a file - the dirtype specifies the file types to include in the search.
223 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
225 static NTSTATUS cvfs_unlink(struct request_context *req, struct smb_unlink *unl)
227 struct cvfs_private *private = req->conn->ntvfs_private;
228 struct cli_request *c_req;
230 /* see if the front end will allow us to perform this
231 function asynchronously. */
232 if (!req->async.send_fn) {
233 return smb_raw_unlink(private->tree, unl);
236 c_req = smb_raw_unlink_send(private->tree, unl);
242 a handler for async ioctl replies
244 static void async_ioctl(struct cli_request *c_req)
246 struct async_info *async = c_req->async.private;
247 struct request_context *req = async->req;
248 req->async.status = smb_raw_ioctl_recv(c_req, req->mem_ctx, async->parms);
249 req->async.send_fn(req);
255 static NTSTATUS cvfs_ioctl(struct request_context *req, union smb_ioctl *io)
257 struct cvfs_private *private = req->conn->ntvfs_private;
258 struct cli_request *c_req;
260 /* see if the front end will allow us to perform this
261 function asynchronously. */
262 if (!req->async.send_fn) {
263 return smb_raw_ioctl(private->tree, req->mem_ctx, io);
266 c_req = smb_raw_ioctl_send(private->tree, io);
268 ASYNC_RECV_TAIL(io, async_ioctl);
272 check if a directory exists
274 static NTSTATUS cvfs_chkpath(struct request_context *req, struct smb_chkpath *cp)
276 struct cvfs_private *private = req->conn->ntvfs_private;
277 struct cli_request *c_req;
279 if (!req->async.send_fn) {
280 return smb_raw_chkpath(private->tree, cp);
283 c_req = smb_raw_chkpath_send(private->tree, cp);
289 a handler for async qpathinfo replies
291 static void async_qpathinfo(struct cli_request *c_req)
293 struct async_info *async = c_req->async.private;
294 struct request_context *req = async->req;
295 req->async.status = smb_raw_pathinfo_recv(c_req, req->mem_ctx, async->parms);
296 req->async.send_fn(req);
300 return info on a pathname
302 static NTSTATUS cvfs_qpathinfo(struct request_context *req, union smb_fileinfo *info)
304 struct cvfs_private *private = req->conn->ntvfs_private;
305 struct cli_request *c_req;
307 if (!req->async.send_fn) {
308 return smb_raw_pathinfo(private->tree, req->mem_ctx, info);
311 c_req = smb_raw_pathinfo_send(private->tree, info);
313 ASYNC_RECV_TAIL(info, async_qpathinfo);
317 a handler for async qfileinfo replies
319 static void async_qfileinfo(struct cli_request *c_req)
321 struct async_info *async = c_req->async.private;
322 struct request_context *req = async->req;
323 req->async.status = smb_raw_fileinfo_recv(c_req, req->mem_ctx, async->parms);
324 req->async.send_fn(req);
328 query info on a open file
330 static NTSTATUS cvfs_qfileinfo(struct request_context *req, union smb_fileinfo *info)
332 struct cvfs_private *private = req->conn->ntvfs_private;
333 struct cli_request *c_req;
335 if (!req->async.send_fn) {
336 return smb_raw_fileinfo(private->tree, req->mem_ctx, info);
339 c_req = smb_raw_fileinfo_send(private->tree, info);
341 ASYNC_RECV_TAIL(info, async_qfileinfo);
346 set info on a pathname
348 static NTSTATUS cvfs_setpathinfo(struct request_context *req, union smb_setfileinfo *st)
350 struct cvfs_private *private = req->conn->ntvfs_private;
351 struct cli_request *c_req;
353 if (!req->async.send_fn) {
354 return smb_raw_setpathinfo(private->tree, st);
357 c_req = smb_raw_setpathinfo_send(private->tree, st);
364 a handler for async open replies
366 static void async_open(struct cli_request *c_req)
368 struct async_info *async = c_req->async.private;
369 struct request_context *req = async->req;
370 req->async.status = smb_raw_open_recv(c_req, req->mem_ctx, async->parms);
371 req->async.send_fn(req);
377 static NTSTATUS cvfs_open(struct request_context *req, union smb_open *io)
379 struct cvfs_private *private = req->conn->ntvfs_private;
380 struct cli_request *c_req;
382 if (private->map_calls && in_list("open", private->map_calls, True) &&
383 io->generic.level != RAW_OPEN_GENERIC) {
384 return ntvfs_map_open(req, io);
387 if (!req->async.send_fn) {
388 return smb_raw_open(private->tree, req->mem_ctx, io);
391 c_req = smb_raw_open_send(private->tree, io);
393 ASYNC_RECV_TAIL(io, async_open);
399 static NTSTATUS cvfs_mkdir(struct request_context *req, union smb_mkdir *md)
401 struct cvfs_private *private = req->conn->ntvfs_private;
402 struct cli_request *c_req;
404 if (!req->async.send_fn) {
405 return smb_raw_mkdir(private->tree, md);
408 c_req = smb_raw_mkdir_send(private->tree, md);
416 static NTSTATUS cvfs_rmdir(struct request_context *req, struct smb_rmdir *rd)
418 struct cvfs_private *private = req->conn->ntvfs_private;
419 struct cli_request *c_req;
421 if (!req->async.send_fn) {
422 return smb_raw_rmdir(private->tree, rd);
424 c_req = smb_raw_rmdir_send(private->tree, rd);
430 rename a set of files
432 static NTSTATUS cvfs_rename(struct request_context *req, union smb_rename *ren)
434 struct cvfs_private *private = req->conn->ntvfs_private;
435 struct cli_request *c_req;
437 if (!req->async.send_fn) {
438 return smb_raw_rename(private->tree, ren);
441 c_req = smb_raw_rename_send(private->tree, ren);
449 static NTSTATUS cvfs_copy(struct request_context *req, struct smb_copy *cp)
451 return NT_STATUS_NOT_SUPPORTED;
455 a handler for async read replies
457 static void async_read(struct cli_request *c_req)
459 struct async_info *async = c_req->async.private;
460 struct request_context *req = async->req;
461 req->async.status = smb_raw_read_recv(c_req, async->parms);
462 req->async.send_fn(req);
468 static NTSTATUS cvfs_read(struct request_context *req, union smb_read *rd)
470 struct cvfs_private *private = req->conn->ntvfs_private;
471 struct cli_request *c_req;
473 if (!req->async.send_fn) {
474 return smb_raw_read(private->tree, rd);
477 c_req = smb_raw_read_send(private->tree, rd);
479 ASYNC_RECV_TAIL(rd, async_read);
483 a handler for async write replies
485 static void async_write(struct cli_request *c_req)
487 struct async_info *async = c_req->async.private;
488 struct request_context *req = async->req;
489 req->async.status = smb_raw_write_recv(c_req, async->parms);
490 req->async.send_fn(req);
496 static NTSTATUS cvfs_write(struct request_context *req, union smb_write *wr)
498 struct cvfs_private *private = req->conn->ntvfs_private;
499 struct cli_request *c_req;
501 if (!req->async.send_fn) {
502 return smb_raw_write(private->tree, wr);
505 c_req = smb_raw_write_send(private->tree, wr);
507 ASYNC_RECV_TAIL(wr, async_write);
513 static NTSTATUS cvfs_seek(struct request_context *req, struct smb_seek *io)
515 return NT_STATUS_NOT_SUPPORTED;
521 static NTSTATUS cvfs_flush(struct request_context *req, struct smb_flush *io)
529 static NTSTATUS cvfs_close(struct request_context *req, union smb_close *io)
531 struct cvfs_private *private = req->conn->ntvfs_private;
532 struct cli_request *c_req;
534 if (!req->async.send_fn) {
535 return smb_raw_close(private->tree, io);
538 c_req = smb_raw_close_send(private->tree, io);
544 exit - closing files?
546 static NTSTATUS cvfs_exit(struct request_context *req)
548 return NT_STATUS_NOT_SUPPORTED;
554 static NTSTATUS cvfs_lock(struct request_context *req, union smb_lock *lck)
556 struct cvfs_private *private = req->conn->ntvfs_private;
557 struct cli_request *c_req;
559 if (!req->async.send_fn) {
560 return smb_raw_lock(private->tree, lck);
563 c_req = smb_raw_lock_send(private->tree, lck);
568 set info on a open file
570 static NTSTATUS cvfs_setfileinfo(struct request_context *req,
571 union smb_setfileinfo *info)
573 struct cvfs_private *private = req->conn->ntvfs_private;
574 struct cli_request *c_req;
576 if (!req->async.send_fn) {
577 return smb_raw_setfileinfo(private->tree, info);
579 c_req = smb_raw_setfileinfo_send(private->tree, info);
586 a handler for async fsinfo replies
588 static void async_fsinfo(struct cli_request *c_req)
590 struct async_info *async = c_req->async.private;
591 struct request_context *req = async->req;
592 req->async.status = smb_raw_fsinfo_recv(c_req, req->mem_ctx, async->parms);
593 req->async.send_fn(req);
597 return filesystem space info
599 static NTSTATUS cvfs_fsinfo(struct request_context *req, union smb_fsinfo *fs)
601 struct cvfs_private *private = req->conn->ntvfs_private;
602 struct cli_request *c_req;
604 if (!req->async.send_fn) {
605 return smb_raw_fsinfo(private->tree, req->mem_ctx, fs);
608 c_req = smb_raw_fsinfo_send(private->tree, req->mem_ctx, fs);
610 ASYNC_RECV_TAIL(fs, async_fsinfo);
614 return print queue info
616 static NTSTATUS cvfs_lpq(struct request_context *req, union smb_lpq *lpq)
618 return NT_STATUS_NOT_SUPPORTED;
622 list files in a directory matching a wildcard pattern
624 static NTSTATUS cvfs_search_first(struct request_context *req, union smb_search_first *io,
625 void *search_private,
626 BOOL (*callback)(void *, union smb_search_data *))
628 struct cvfs_private *private = req->conn->ntvfs_private;
630 return smb_raw_search_first(private->tree, req->mem_ctx, io, search_private, callback);
633 /* continue a search */
634 static NTSTATUS cvfs_search_next(struct request_context *req, union smb_search_next *io,
635 void *search_private,
636 BOOL (*callback)(void *, union smb_search_data *))
638 struct cvfs_private *private = req->conn->ntvfs_private;
640 return smb_raw_search_next(private->tree, req->mem_ctx, io, search_private, callback);
644 static NTSTATUS cvfs_search_close(struct request_context *req, union smb_search_close *io)
646 struct cvfs_private *private = req->conn->ntvfs_private;
648 return smb_raw_search_close(private->tree, io);
652 a handler for async trans2 replies
654 static void async_trans2(struct cli_request *c_req)
656 struct async_info *async = c_req->async.private;
657 struct request_context *req = async->req;
658 req->async.status = smb_raw_trans2_recv(c_req, req->mem_ctx, async->parms);
659 req->async.send_fn(req);
663 static NTSTATUS cvfs_trans2(struct request_context *req, struct smb_trans2 *trans2)
665 struct cvfs_private *private = req->conn->ntvfs_private;
666 struct cli_request *c_req;
668 if (!req->async.send_fn) {
669 return smb_raw_trans2(private->tree, req->mem_ctx, trans2);
672 c_req = smb_raw_trans2_send(private->tree, trans2);
674 ASYNC_RECV_TAIL(trans2, async_trans2);
678 /* SMBtrans - not used on file shares */
679 static NTSTATUS cvfs_trans(struct request_context *req, struct smb_trans2 *trans2)
681 return NT_STATUS_ACCESS_DENIED;
685 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
687 NTSTATUS ntvfs_cifs_init(void)
690 struct ntvfs_ops ops;
694 /* fill in the name and type */
696 ops.type = NTVFS_DISK;
698 /* fill in all the operations */
699 ops.connect = cvfs_connect;
700 ops.disconnect = cvfs_disconnect;
701 ops.unlink = cvfs_unlink;
702 ops.chkpath = cvfs_chkpath;
703 ops.qpathinfo = cvfs_qpathinfo;
704 ops.setpathinfo = cvfs_setpathinfo;
705 ops.open = cvfs_open;
706 ops.mkdir = cvfs_mkdir;
707 ops.rmdir = cvfs_rmdir;
708 ops.rename = cvfs_rename;
709 ops.copy = cvfs_copy;
710 ops.ioctl = cvfs_ioctl;
711 ops.read = cvfs_read;
712 ops.write = cvfs_write;
713 ops.seek = cvfs_seek;
714 ops.flush = cvfs_flush;
715 ops.close = cvfs_close;
716 ops.exit = cvfs_exit;
717 ops.lock = cvfs_lock;
718 ops.setfileinfo = cvfs_setfileinfo;
719 ops.qfileinfo = cvfs_qfileinfo;
720 ops.fsinfo = cvfs_fsinfo;
722 ops.search_first = cvfs_search_first;
723 ops.search_next = cvfs_search_next;
724 ops.search_close = cvfs_search_close;
725 ops.trans = cvfs_trans;
727 /* only define this one for trans2 testing */
728 ops.trans2 = cvfs_trans2;
730 /* register ourselves with the NTVFS subsystem. We register under the name 'cifs'. */
732 ret = register_backend("ntvfs", &ops);
734 if (!NT_STATUS_IS_OK(ret)) {
735 DEBUG(0,("Failed to register CIFS backend!\n"));