Line data Source code
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 3 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, see <http://www.gnu.org/licenses/>.
21 : */
22 : /*
23 : this implements a CIFS->CIFS NTVFS filesystem backend.
24 :
25 : */
26 :
27 : #include "includes.h"
28 : #include "libcli/raw/libcliraw.h"
29 : #include "libcli/raw/raw_proto.h"
30 : #include "libcli/smb_composite/smb_composite.h"
31 : #include "auth/auth.h"
32 : #include "auth/credentials/credentials.h"
33 : #include "ntvfs/ntvfs.h"
34 : #include "../lib/util/dlinklist.h"
35 : #include "param/param.h"
36 : #include "libcli/resolve/resolve.h"
37 : #include "../libcli/smb/smbXcli_base.h"
38 :
39 : struct cvfs_file {
40 : struct cvfs_file *prev, *next;
41 : uint16_t fnum;
42 : struct ntvfs_handle *h;
43 : };
44 :
45 : /* this is stored in ntvfs_private */
46 : struct cvfs_private {
47 : struct smbcli_tree *tree;
48 : struct smbcli_transport *transport;
49 : struct ntvfs_module_context *ntvfs;
50 : struct async_info *pending;
51 : struct cvfs_file *files;
52 : bool map_generic;
53 : bool map_trans2;
54 : };
55 :
56 :
57 : /* a structure used to pass information to an async handler */
58 : struct async_info {
59 : struct async_info *next, *prev;
60 : struct cvfs_private *cvfs;
61 : struct ntvfs_request *req;
62 : struct smbcli_request *c_req;
63 : struct cvfs_file *f;
64 : void *parms;
65 : };
66 :
67 : NTSTATUS ntvfs_cifs_init(TALLOC_CTX *);
68 :
69 : #define CHECK_UPSTREAM_OPEN do { \
70 : if (!smbXcli_conn_is_connected(p->transport->conn)) { \
71 : req->async_states->state|=NTVFS_ASYNC_STATE_CLOSE; \
72 : return NT_STATUS_CONNECTION_DISCONNECTED; \
73 : } \
74 : } while(0)
75 :
76 : #define SETUP_PID do { \
77 : p->tree->session->pid = req->smbpid; \
78 : CHECK_UPSTREAM_OPEN; \
79 : } while(0)
80 :
81 : #define SETUP_FILE_HERE(f) do { \
82 : f = ntvfs_handle_get_backend_data(io->generic.in.file.ntvfs, ntvfs); \
83 : if (!f) return NT_STATUS_INVALID_HANDLE; \
84 : io->generic.in.file.fnum = f->fnum; \
85 : } while (0)
86 :
87 : #define SETUP_FILE do { \
88 : struct cvfs_file *f; \
89 : SETUP_FILE_HERE(f); \
90 : } while (0)
91 :
92 : #define SETUP_PID_AND_FILE do { \
93 : SETUP_PID; \
94 : SETUP_FILE; \
95 : } while (0)
96 :
97 : #define CIFS_SERVER "cifs:server"
98 : #define CIFS_USER "cifs:user"
99 : #define CIFS_PASSWORD "cifs:password"
100 : #define CIFS_DOMAIN "cifs:domain"
101 : #define CIFS_SHARE "cifs:share"
102 : #define CIFS_USE_MACHINE_ACCT "cifs:use-machine-account"
103 : #define CIFS_USE_S4U2PROXY "cifs:use-s4u2proxy"
104 : #define CIFS_MAP_GENERIC "cifs:map-generic"
105 : #define CIFS_MAP_TRANS2 "cifs:map-trans2"
106 :
107 : #define CIFS_USE_MACHINE_ACCT_DEFAULT false
108 : #define CIFS_USE_S4U2PROXY_DEFAULT false
109 : #define CIFS_MAP_GENERIC_DEFAULT false
110 : #define CIFS_MAP_TRANS2_DEFAULT true
111 :
112 : /*
113 : a handler for oplock break events from the server - these need to be passed
114 : along to the client
115 : */
116 0 : static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
117 : {
118 0 : struct cvfs_private *p = p_private;
119 0 : NTSTATUS status;
120 0 : struct ntvfs_handle *h = NULL;
121 0 : struct cvfs_file *f;
122 :
123 0 : for (f=p->files; f; f=f->next) {
124 0 : if (f->fnum != fnum) continue;
125 0 : h = f->h;
126 0 : break;
127 : }
128 :
129 0 : if (!h) {
130 0 : DEBUG(5,("vfs_cifs: ignoring oplock break level %d for fnum %d\n", level, fnum));
131 0 : return true;
132 : }
133 :
134 0 : DEBUG(5,("vfs_cifs: sending oplock break level %d for fnum %d\n", level, fnum));
135 0 : status = ntvfs_send_oplock_break(p->ntvfs, h, level);
136 0 : if (!NT_STATUS_IS_OK(status)) return false;
137 0 : return true;
138 : }
139 :
140 : /*
141 : connect to a share - used when a tree_connect operation comes in.
142 : */
143 156 : static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
144 : struct ntvfs_request *req,
145 : union smb_tcon *tcon)
146 : {
147 0 : NTSTATUS status;
148 0 : struct cvfs_private *p;
149 0 : const char *host, *user, *pass, *domain, *remote_share;
150 0 : struct smb_composite_connect io;
151 0 : struct composite_context *creq;
152 156 : struct share_config *scfg = ntvfs->ctx->config;
153 :
154 0 : struct cli_credentials *credentials;
155 0 : bool machine_account;
156 0 : bool s4u2proxy;
157 0 : const char* sharename;
158 0 : TALLOC_CTX *tmp_ctx;
159 :
160 156 : tmp_ctx = talloc_new(req);
161 156 : if (tmp_ctx == NULL) {
162 0 : return NT_STATUS_NO_MEMORY;
163 : }
164 :
165 156 : switch (tcon->generic.level) {
166 0 : case RAW_TCON_TCON:
167 0 : sharename = tcon->tcon.in.service;
168 0 : break;
169 156 : case RAW_TCON_TCONX:
170 156 : sharename = tcon->tconx.in.path;
171 156 : break;
172 0 : case RAW_TCON_SMB2:
173 0 : sharename = tcon->smb2.in.path;
174 0 : break;
175 0 : default:
176 0 : status = NT_STATUS_INVALID_LEVEL;
177 0 : goto out;
178 : }
179 :
180 156 : if (strncmp(sharename, "\\\\", 2) == 0) {
181 153 : char *str = strchr(sharename+2, '\\');
182 153 : if (str) {
183 153 : sharename = str + 1;
184 : }
185 : }
186 :
187 : /* Here we need to determine which server to connect to.
188 : * For now we use parametric options, type cifs.
189 : */
190 156 : host = share_string_option(tmp_ctx, scfg, CIFS_SERVER, NULL);
191 156 : user = share_string_option(tmp_ctx, scfg, CIFS_USER, NULL);
192 156 : pass = share_string_option(tmp_ctx, scfg, CIFS_PASSWORD, NULL);
193 156 : domain = share_string_option(tmp_ctx, scfg, CIFS_DOMAIN, NULL);
194 156 : remote_share = share_string_option(tmp_ctx, scfg, CIFS_SHARE, NULL);
195 156 : if (!remote_share) {
196 0 : remote_share = sharename;
197 : }
198 :
199 156 : machine_account = share_bool_option(scfg, CIFS_USE_MACHINE_ACCT, CIFS_USE_MACHINE_ACCT_DEFAULT);
200 156 : s4u2proxy = share_bool_option(scfg, CIFS_USE_S4U2PROXY, CIFS_USE_S4U2PROXY_DEFAULT);
201 :
202 156 : p = talloc_zero(ntvfs, struct cvfs_private);
203 156 : if (!p) {
204 0 : status = NT_STATUS_NO_MEMORY;
205 0 : goto out;
206 : }
207 :
208 156 : ntvfs->private_data = p;
209 :
210 156 : if (!host) {
211 0 : DEBUG(1,("CIFS backend: You must supply server\n"));
212 0 : status = NT_STATUS_INVALID_PARAMETER;
213 0 : goto out;
214 : }
215 :
216 156 : if (user && pass) {
217 0 : DEBUG(5, ("CIFS backend: Using specified password\n"));
218 0 : credentials = cli_credentials_init(p);
219 0 : if (!credentials) {
220 0 : status = NT_STATUS_NO_MEMORY;
221 0 : goto out;
222 : }
223 0 : cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx);
224 0 : cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
225 0 : if (domain) {
226 0 : cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
227 : }
228 0 : cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
229 156 : } else if (machine_account) {
230 0 : DEBUG(5, ("CIFS backend: Using machine account\n"));
231 0 : credentials = cli_credentials_init_server(p,
232 0 : ntvfs->ctx->lp_ctx);
233 0 : if (credentials == NULL) {
234 0 : status = NT_STATUS_NO_MEMORY;
235 0 : goto out;
236 : }
237 156 : } else if (req->session_info->credentials) {
238 151 : DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
239 151 : credentials = req->session_info->credentials;
240 5 : } else if (s4u2proxy) {
241 5 : struct ccache_container *ccc = NULL;
242 5 : const char *err_str = NULL;
243 0 : int ret;
244 0 : char *impersonate_principal;
245 0 : char *self_service;
246 0 : char *target_service;
247 :
248 5 : impersonate_principal = talloc_asprintf(req, "%s@%s",
249 5 : req->session_info->info->account_name,
250 5 : req->session_info->info->domain_name);
251 :
252 5 : self_service = talloc_asprintf(req, "cifs/%s",
253 5 : lpcfg_netbios_name(ntvfs->ctx->lp_ctx));
254 :
255 5 : target_service = talloc_asprintf(req, "cifs/%s", host);
256 :
257 5 : DEBUG(5, ("CIFS backend: Using S4U2Proxy credentials\n"));
258 :
259 5 : credentials = cli_credentials_init_server(p,
260 5 : ntvfs->ctx->lp_ctx);
261 5 : if (credentials == NULL) {
262 0 : status = NT_STATUS_NO_MEMORY;
263 0 : goto out;
264 : }
265 5 : cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED);
266 5 : cli_credentials_set_impersonate_principal(credentials,
267 : impersonate_principal,
268 : self_service);
269 5 : cli_credentials_set_target_service(credentials, target_service);
270 5 : ret = cli_credentials_get_ccache(credentials,
271 5 : ntvfs->ctx->event_ctx,
272 5 : ntvfs->ctx->lp_ctx,
273 : &ccc,
274 : &err_str);
275 5 : if (ret != 0) {
276 0 : status = NT_STATUS_CROSSREALM_DELEGATION_FAILURE;
277 0 : DEBUG(1,("S4U2Proxy: cli_credentials_get_ccache() gave: ret[%d] str[%s] - %s\n",
278 : ret, err_str, nt_errstr(status)));
279 0 : goto out;
280 : }
281 :
282 : } else {
283 0 : DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
284 0 : status = NT_STATUS_INTERNAL_ERROR;
285 0 : goto out;
286 : }
287 :
288 : /* connect to the server, using the smbd event context */
289 156 : io.in.dest_host = host;
290 156 : io.in.dest_ports = lpcfg_smb_ports(ntvfs->ctx->lp_ctx);
291 156 : io.in.socket_options = lpcfg_socket_options(ntvfs->ctx->lp_ctx);
292 156 : io.in.called_name = host;
293 156 : io.in.existing_conn = NULL;
294 156 : io.in.credentials = credentials;
295 156 : io.in.fallback_to_anonymous = false;
296 156 : io.in.workgroup = lpcfg_workgroup(ntvfs->ctx->lp_ctx);
297 156 : io.in.service = remote_share;
298 156 : io.in.service_type = "?????";
299 156 : io.in.gensec_settings = lpcfg_gensec_settings(p, ntvfs->ctx->lp_ctx);
300 156 : lpcfg_smbcli_options(ntvfs->ctx->lp_ctx, &io.in.options);
301 156 : lpcfg_smbcli_session_options(ntvfs->ctx->lp_ctx, &io.in.session_options);
302 :
303 156 : if (!(ntvfs->ctx->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS)) {
304 0 : io.in.options.use_level2_oplocks = false;
305 : }
306 :
307 156 : creq = smb_composite_connect_send(&io, p,
308 156 : lpcfg_resolve_context(ntvfs->ctx->lp_ctx),
309 156 : ntvfs->ctx->event_ctx);
310 156 : status = smb_composite_connect_recv(creq, p);
311 156 : if (!NT_STATUS_IS_OK(status)) {
312 0 : goto out;
313 : }
314 :
315 156 : p->tree = io.out.tree;
316 :
317 156 : p->transport = p->tree->session->transport;
318 156 : SETUP_PID;
319 156 : p->ntvfs = ntvfs;
320 :
321 156 : ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
322 156 : if (ntvfs->ctx->fs_type == NULL) {
323 0 : status = NT_STATUS_NO_MEMORY;
324 0 : goto out;
325 : }
326 156 : ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
327 156 : if (ntvfs->ctx->dev_type == NULL) {
328 0 : status = NT_STATUS_NO_MEMORY;
329 0 : goto out;
330 : }
331 :
332 156 : if (tcon->generic.level == RAW_TCON_TCONX) {
333 156 : tcon->tconx.out.fs_type = ntvfs->ctx->fs_type;
334 156 : tcon->tconx.out.dev_type = ntvfs->ctx->dev_type;
335 : }
336 :
337 : /* we need to receive oplock break requests from the server */
338 156 : smbcli_oplock_handler(p->transport, oplock_handler, p);
339 :
340 156 : p->map_generic = share_bool_option(scfg, CIFS_MAP_GENERIC, CIFS_MAP_GENERIC_DEFAULT);
341 :
342 156 : p->map_trans2 = share_bool_option(scfg, CIFS_MAP_TRANS2, CIFS_MAP_TRANS2_DEFAULT);
343 :
344 156 : status = NT_STATUS_OK;
345 :
346 156 : out:
347 156 : TALLOC_FREE(tmp_ctx);
348 156 : return status;
349 : }
350 :
351 : /*
352 : disconnect from a share
353 : */
354 156 : static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs)
355 : {
356 156 : struct cvfs_private *p = ntvfs->private_data;
357 0 : struct async_info *a, *an;
358 :
359 : /* first cleanup pending requests */
360 186 : for (a=p->pending; a; a = an) {
361 30 : an = a->next;
362 30 : smbcli_request_destroy(a->c_req);
363 30 : talloc_free(a);
364 : }
365 :
366 156 : talloc_free(p);
367 156 : ntvfs->private_data = NULL;
368 :
369 156 : return NT_STATUS_OK;
370 : }
371 :
372 : /*
373 : destroy an async info structure
374 : */
375 66981 : static int async_info_destructor(struct async_info *async)
376 : {
377 66981 : DLIST_REMOVE(async->cvfs->pending, async);
378 66981 : return 0;
379 : }
380 :
381 : /*
382 : a handler for simple async replies
383 : this handler can only be used for functions that don't return any
384 : parameters (those that just return a status code)
385 : */
386 21425 : static void async_simple(struct smbcli_request *c_req)
387 : {
388 21425 : struct async_info *async = c_req->async.private_data;
389 21425 : struct ntvfs_request *req = async->req;
390 21425 : req->async_states->status = smbcli_request_simple_recv(c_req);
391 21425 : talloc_free(async);
392 21425 : req->async_states->send_fn(req);
393 21425 : }
394 :
395 :
396 : /* save some typing for the simple functions */
397 : #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
398 : if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
399 : { \
400 : struct async_info *async; \
401 : async = talloc(req, struct async_info); \
402 : if (!async) return NT_STATUS_NO_MEMORY; \
403 : async->parms = io; \
404 : async->req = req; \
405 : async->f = file; \
406 : async->cvfs = p; \
407 : async->c_req = c_req; \
408 : DLIST_ADD(p->pending, async); \
409 : c_req->async.private_data = async; \
410 : talloc_set_destructor(async, async_info_destructor); \
411 : } \
412 : c_req->async.fn = async_fn; \
413 : req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
414 : return NT_STATUS_OK; \
415 : } while (0)
416 :
417 : #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
418 :
419 : #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple)
420 :
421 : /*
422 : delete a file - the dirtype specifies the file types to include in the search.
423 : The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
424 : */
425 6923 : static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs,
426 : struct ntvfs_request *req, union smb_unlink *unl)
427 : {
428 6923 : struct cvfs_private *p = ntvfs->private_data;
429 0 : struct smbcli_request *c_req;
430 :
431 6923 : SETUP_PID;
432 :
433 : /* see if the front end will allow us to perform this
434 : function asynchronously. */
435 6923 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
436 0 : return smb_raw_unlink(p->tree, unl);
437 : }
438 :
439 6923 : c_req = smb_raw_unlink_send(p->tree, unl);
440 :
441 6923 : SIMPLE_ASYNC_TAIL;
442 : }
443 :
444 : /*
445 : a handler for async ioctl replies
446 : */
447 0 : static void async_ioctl(struct smbcli_request *c_req)
448 : {
449 0 : struct async_info *async = c_req->async.private_data;
450 0 : struct ntvfs_request *req = async->req;
451 0 : req->async_states->status = smb_raw_ioctl_recv(c_req, req, async->parms);
452 0 : talloc_free(async);
453 0 : req->async_states->send_fn(req);
454 0 : }
455 :
456 : /*
457 : ioctl interface
458 : */
459 0 : static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs,
460 : struct ntvfs_request *req, union smb_ioctl *io)
461 : {
462 0 : struct cvfs_private *p = ntvfs->private_data;
463 0 : struct smbcli_request *c_req;
464 :
465 0 : SETUP_PID_AND_FILE;
466 :
467 : /* see if the front end will allow us to perform this
468 : function asynchronously. */
469 0 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
470 0 : return smb_raw_ioctl(p->tree, req, io);
471 : }
472 :
473 0 : c_req = smb_raw_ioctl_send(p->tree, io);
474 :
475 0 : ASYNC_RECV_TAIL(io, async_ioctl);
476 : }
477 :
478 : /*
479 : check if a directory exists
480 : */
481 25 : static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs,
482 : struct ntvfs_request *req, union smb_chkpath *cp)
483 : {
484 25 : struct cvfs_private *p = ntvfs->private_data;
485 0 : struct smbcli_request *c_req;
486 :
487 25 : SETUP_PID;
488 :
489 25 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
490 0 : return smb_raw_chkpath(p->tree, cp);
491 : }
492 :
493 25 : c_req = smb_raw_chkpath_send(p->tree, cp);
494 :
495 25 : SIMPLE_ASYNC_TAIL;
496 : }
497 :
498 : /*
499 : a handler for async qpathinfo replies
500 : */
501 2373 : static void async_qpathinfo(struct smbcli_request *c_req)
502 : {
503 2373 : struct async_info *async = c_req->async.private_data;
504 2373 : struct ntvfs_request *req = async->req;
505 2373 : req->async_states->status = smb_raw_pathinfo_recv(c_req, req, async->parms);
506 2373 : talloc_free(async);
507 2373 : req->async_states->send_fn(req);
508 2373 : }
509 :
510 : /*
511 : return info on a pathname
512 : */
513 2373 : static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs,
514 : struct ntvfs_request *req, union smb_fileinfo *info)
515 : {
516 2373 : struct cvfs_private *p = ntvfs->private_data;
517 0 : struct smbcli_request *c_req;
518 :
519 2373 : SETUP_PID;
520 :
521 2373 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
522 0 : return smb_raw_pathinfo(p->tree, req, info);
523 : }
524 :
525 2373 : c_req = smb_raw_pathinfo_send(p->tree, info);
526 :
527 2373 : ASYNC_RECV_TAIL(info, async_qpathinfo);
528 : }
529 :
530 : /*
531 : a handler for async qfileinfo replies
532 : */
533 2157 : static void async_qfileinfo(struct smbcli_request *c_req)
534 : {
535 2157 : struct async_info *async = c_req->async.private_data;
536 2157 : struct ntvfs_request *req = async->req;
537 2157 : req->async_states->status = smb_raw_fileinfo_recv(c_req, req, async->parms);
538 2157 : talloc_free(async);
539 2157 : req->async_states->send_fn(req);
540 2157 : }
541 :
542 : /*
543 : query info on a open file
544 : */
545 2157 : static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
546 : struct ntvfs_request *req, union smb_fileinfo *io)
547 : {
548 2157 : struct cvfs_private *p = ntvfs->private_data;
549 0 : struct smbcli_request *c_req;
550 :
551 2157 : SETUP_PID_AND_FILE;
552 :
553 2157 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
554 0 : return smb_raw_fileinfo(p->tree, req, io);
555 : }
556 :
557 2157 : c_req = smb_raw_fileinfo_send(p->tree, io);
558 :
559 2157 : ASYNC_RECV_TAIL(io, async_qfileinfo);
560 : }
561 :
562 :
563 : /*
564 : set info on a pathname
565 : */
566 146 : static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
567 : struct ntvfs_request *req, union smb_setfileinfo *st)
568 : {
569 146 : struct cvfs_private *p = ntvfs->private_data;
570 0 : struct smbcli_request *c_req;
571 :
572 146 : SETUP_PID;
573 :
574 146 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
575 0 : return smb_raw_setpathinfo(p->tree, st);
576 : }
577 :
578 146 : c_req = smb_raw_setpathinfo_send(p->tree, st);
579 :
580 146 : SIMPLE_ASYNC_TAIL;
581 : }
582 :
583 :
584 : /*
585 : a handler for async open replies
586 : */
587 13380 : static void async_open(struct smbcli_request *c_req)
588 : {
589 13380 : struct async_info *async = c_req->async.private_data;
590 13380 : struct cvfs_private *cvfs = async->cvfs;
591 13380 : struct ntvfs_request *req = async->req;
592 13380 : struct cvfs_file *f = async->f;
593 13380 : union smb_open *io = async->parms;
594 0 : union smb_handle *file;
595 13380 : if (f == NULL) {
596 0 : goto failed;
597 : }
598 13380 : talloc_free(async);
599 13380 : req->async_states->status = smb_raw_open_recv(c_req, req, io);
600 13380 : SMB_OPEN_OUT_FILE(io, file);
601 13380 : if (file == NULL) {
602 0 : goto failed;
603 : }
604 13380 : f->fnum = file->fnum;
605 13380 : file->ntvfs = NULL;
606 13380 : if (!NT_STATUS_IS_OK(req->async_states->status)) goto failed;
607 11789 : req->async_states->status = ntvfs_handle_set_backend_data(f->h, cvfs->ntvfs, f);
608 11789 : if (!NT_STATUS_IS_OK(req->async_states->status)) goto failed;
609 11789 : file->ntvfs = f->h;
610 11789 : DLIST_ADD(cvfs->files, f);
611 13380 : failed:
612 13380 : req->async_states->send_fn(req);
613 13380 : }
614 :
615 : /*
616 : open a file
617 : */
618 13400 : static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs,
619 : struct ntvfs_request *req, union smb_open *io)
620 : {
621 13400 : struct cvfs_private *p = ntvfs->private_data;
622 0 : struct smbcli_request *c_req;
623 0 : struct ntvfs_handle *h;
624 0 : struct cvfs_file *f;
625 0 : NTSTATUS status;
626 :
627 13400 : SETUP_PID;
628 :
629 13400 : if (io->generic.level != RAW_OPEN_GENERIC &&
630 2726 : p->map_generic) {
631 0 : return ntvfs_map_open(ntvfs, req, io);
632 : }
633 :
634 13400 : status = ntvfs_handle_new(ntvfs, req, &h);
635 13400 : NT_STATUS_NOT_OK_RETURN(status);
636 :
637 13400 : f = talloc_zero(h, struct cvfs_file);
638 13400 : NT_STATUS_HAVE_NO_MEMORY(f);
639 13400 : f->h = h;
640 :
641 13400 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
642 0 : union smb_handle *file;
643 :
644 0 : status = smb_raw_open(p->tree, req, io);
645 0 : NT_STATUS_NOT_OK_RETURN(status);
646 :
647 0 : SMB_OPEN_OUT_FILE(io, file);
648 0 : if (file == NULL) {
649 0 : return NT_STATUS_INVALID_PARAMETER;
650 : }
651 0 : f->fnum = file->fnum;
652 0 : file->ntvfs = NULL;
653 0 : status = ntvfs_handle_set_backend_data(f->h, p->ntvfs, f);
654 0 : NT_STATUS_NOT_OK_RETURN(status);
655 0 : file->ntvfs = f->h;
656 0 : DLIST_ADD(p->files, f);
657 :
658 0 : return NT_STATUS_OK;
659 : }
660 :
661 13400 : c_req = smb_raw_open_send(p->tree, io);
662 :
663 13400 : ASYNC_RECV_TAIL_F(io, async_open, f);
664 : }
665 :
666 : /*
667 : create a directory
668 : */
669 1125 : static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs,
670 : struct ntvfs_request *req, union smb_mkdir *md)
671 : {
672 1125 : struct cvfs_private *p = ntvfs->private_data;
673 0 : struct smbcli_request *c_req;
674 :
675 1125 : SETUP_PID;
676 :
677 1125 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
678 0 : return smb_raw_mkdir(p->tree, md);
679 : }
680 :
681 1125 : c_req = smb_raw_mkdir_send(p->tree, md);
682 :
683 1125 : SIMPLE_ASYNC_TAIL;
684 : }
685 :
686 : /*
687 : remove a directory
688 : */
689 1230 : static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs,
690 : struct ntvfs_request *req, struct smb_rmdir *rd)
691 : {
692 1230 : struct cvfs_private *p = ntvfs->private_data;
693 0 : struct smbcli_request *c_req;
694 :
695 1230 : SETUP_PID;
696 :
697 1230 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
698 0 : return smb_raw_rmdir(p->tree, rd);
699 : }
700 1230 : c_req = smb_raw_rmdir_send(p->tree, rd);
701 :
702 1230 : SIMPLE_ASYNC_TAIL;
703 : }
704 :
705 : /*
706 : rename a set of files
707 : */
708 4 : static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs,
709 : struct ntvfs_request *req, union smb_rename *ren)
710 : {
711 4 : struct cvfs_private *p = ntvfs->private_data;
712 0 : struct smbcli_request *c_req;
713 :
714 4 : SETUP_PID;
715 :
716 4 : if (ren->nttrans.level == RAW_RENAME_NTTRANS) {
717 0 : struct cvfs_file *f;
718 0 : f = ntvfs_handle_get_backend_data(ren->nttrans.in.file.ntvfs, ntvfs);
719 0 : if (!f) return NT_STATUS_INVALID_HANDLE;
720 0 : ren->nttrans.in.file.fnum = f->fnum;
721 : }
722 :
723 4 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
724 0 : return smb_raw_rename(p->tree, ren);
725 : }
726 :
727 4 : c_req = smb_raw_rename_send(p->tree, ren);
728 :
729 4 : SIMPLE_ASYNC_TAIL;
730 : }
731 :
732 : /*
733 : copy a set of files
734 : */
735 0 : static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs,
736 : struct ntvfs_request *req, struct smb_copy *cp)
737 : {
738 0 : return NT_STATUS_NOT_SUPPORTED;
739 : }
740 :
741 : /*
742 : a handler for async read replies
743 : */
744 16958 : static void async_read(struct smbcli_request *c_req)
745 : {
746 16958 : struct async_info *async = c_req->async.private_data;
747 16958 : struct ntvfs_request *req = async->req;
748 16958 : req->async_states->status = smb_raw_read_recv(c_req, async->parms);
749 16958 : talloc_free(async);
750 16958 : req->async_states->send_fn(req);
751 16958 : }
752 :
753 : /*
754 : read from a file
755 : */
756 16958 : static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs,
757 : struct ntvfs_request *req, union smb_read *io)
758 : {
759 16958 : struct cvfs_private *p = ntvfs->private_data;
760 0 : struct smbcli_request *c_req;
761 :
762 16958 : SETUP_PID;
763 :
764 16958 : if (io->generic.level != RAW_READ_GENERIC &&
765 0 : p->map_generic) {
766 0 : return ntvfs_map_read(ntvfs, req, io);
767 : }
768 :
769 16958 : SETUP_FILE;
770 :
771 16958 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
772 0 : return smb_raw_read(p->tree, io);
773 : }
774 :
775 16958 : c_req = smb_raw_read_send(p->tree, io);
776 :
777 16958 : ASYNC_RECV_TAIL(io, async_read);
778 : }
779 :
780 : /*
781 : a handler for async write replies
782 : */
783 8657 : static void async_write(struct smbcli_request *c_req)
784 : {
785 8657 : struct async_info *async = c_req->async.private_data;
786 8657 : struct ntvfs_request *req = async->req;
787 8657 : req->async_states->status = smb_raw_write_recv(c_req, async->parms);
788 8657 : talloc_free(async);
789 8657 : req->async_states->send_fn(req);
790 8657 : }
791 :
792 : /*
793 : write to a file
794 : */
795 8657 : static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs,
796 : struct ntvfs_request *req, union smb_write *io)
797 : {
798 8657 : struct cvfs_private *p = ntvfs->private_data;
799 0 : struct smbcli_request *c_req;
800 :
801 8657 : SETUP_PID;
802 :
803 8657 : if (io->generic.level != RAW_WRITE_GENERIC &&
804 0 : p->map_generic) {
805 0 : return ntvfs_map_write(ntvfs, req, io);
806 : }
807 8657 : SETUP_FILE;
808 :
809 8657 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
810 0 : return smb_raw_write(p->tree, io);
811 : }
812 :
813 8657 : c_req = smb_raw_write_send(p->tree, io);
814 :
815 8657 : ASYNC_RECV_TAIL(io, async_write);
816 : }
817 :
818 : /*
819 : a handler for async seek replies
820 : */
821 0 : static void async_seek(struct smbcli_request *c_req)
822 : {
823 0 : struct async_info *async = c_req->async.private_data;
824 0 : struct ntvfs_request *req = async->req;
825 0 : req->async_states->status = smb_raw_seek_recv(c_req, async->parms);
826 0 : talloc_free(async);
827 0 : req->async_states->send_fn(req);
828 0 : }
829 :
830 : /*
831 : seek in a file
832 : */
833 0 : static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs,
834 : struct ntvfs_request *req,
835 : union smb_seek *io)
836 : {
837 0 : struct cvfs_private *p = ntvfs->private_data;
838 0 : struct smbcli_request *c_req;
839 :
840 0 : SETUP_PID_AND_FILE;
841 :
842 0 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
843 0 : return smb_raw_seek(p->tree, io);
844 : }
845 :
846 0 : c_req = smb_raw_seek_send(p->tree, io);
847 :
848 0 : ASYNC_RECV_TAIL(io, async_seek);
849 : }
850 :
851 : /*
852 : flush a file
853 : */
854 0 : static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs,
855 : struct ntvfs_request *req,
856 : union smb_flush *io)
857 : {
858 0 : struct cvfs_private *p = ntvfs->private_data;
859 0 : struct smbcli_request *c_req;
860 :
861 0 : SETUP_PID;
862 0 : switch (io->generic.level) {
863 0 : case RAW_FLUSH_FLUSH:
864 0 : SETUP_FILE;
865 0 : break;
866 0 : case RAW_FLUSH_ALL:
867 0 : io->generic.in.file.fnum = 0xFFFF;
868 0 : break;
869 0 : case RAW_FLUSH_SMB2:
870 0 : return NT_STATUS_INVALID_LEVEL;
871 : }
872 :
873 0 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
874 0 : return smb_raw_flush(p->tree, io);
875 : }
876 :
877 0 : c_req = smb_raw_flush_send(p->tree, io);
878 :
879 0 : SIMPLE_ASYNC_TAIL;
880 : }
881 :
882 : /*
883 : close a file
884 : */
885 11754 : static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs,
886 : struct ntvfs_request *req, union smb_close *io)
887 : {
888 11754 : struct cvfs_private *p = ntvfs->private_data;
889 0 : struct smbcli_request *c_req;
890 0 : struct cvfs_file *f;
891 0 : union smb_close io2;
892 :
893 11754 : SETUP_PID;
894 :
895 11754 : if (io->generic.level != RAW_CLOSE_GENERIC &&
896 11754 : p->map_generic) {
897 0 : return ntvfs_map_close(ntvfs, req, io);
898 : }
899 :
900 11754 : if (io->generic.level == RAW_CLOSE_GENERIC) {
901 0 : ZERO_STRUCT(io2);
902 0 : io2.close.level = RAW_CLOSE_CLOSE;
903 0 : io2.close.in.file = io->generic.in.file;
904 0 : io2.close.in.write_time = io->generic.in.write_time;
905 0 : io = &io2;
906 : }
907 :
908 11754 : SETUP_FILE_HERE(f);
909 : /* Note, we aren't free-ing f, or it's h here. Should we?
910 : even if file-close fails, we'll remove it from the list,
911 : what else would we do? Maybe we should not remove until
912 : after the proxied call completes? */
913 11754 : DLIST_REMOVE(p->files, f);
914 :
915 11754 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
916 0 : return smb_raw_close(p->tree, io);
917 : }
918 :
919 11754 : c_req = smb_raw_close_send(p->tree, io);
920 :
921 11754 : SIMPLE_ASYNC_TAIL;
922 : }
923 :
924 : /*
925 : exit - closing files open by the pid
926 : */
927 91 : static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs,
928 : struct ntvfs_request *req)
929 : {
930 91 : struct cvfs_private *p = ntvfs->private_data;
931 0 : struct smbcli_request *c_req;
932 :
933 91 : SETUP_PID;
934 :
935 91 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
936 91 : return smb_raw_exit(p->tree->session);
937 : }
938 :
939 0 : c_req = smb_raw_exit_send(p->tree->session);
940 :
941 0 : SIMPLE_ASYNC_TAIL;
942 : }
943 :
944 : /*
945 : logoff - closing files open by the user
946 : */
947 0 : static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs,
948 : struct ntvfs_request *req)
949 : {
950 : /* we can't do this right in the cifs backend .... */
951 0 : return NT_STATUS_OK;
952 : }
953 :
954 : /*
955 : setup for an async call - nothing to do yet
956 : */
957 0 : static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs,
958 : struct ntvfs_request *req,
959 : void *private_data)
960 : {
961 0 : return NT_STATUS_OK;
962 : }
963 :
964 : /*
965 : cancel an async call
966 : */
967 0 : static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs,
968 : struct ntvfs_request *req)
969 : {
970 0 : struct cvfs_private *p = ntvfs->private_data;
971 0 : struct async_info *a;
972 :
973 : /* find the matching request */
974 0 : for (a=p->pending;a;a=a->next) {
975 0 : if (a->req == req) {
976 0 : break;
977 : }
978 : }
979 :
980 0 : if (a == NULL) {
981 0 : return NT_STATUS_INVALID_PARAMETER;
982 : }
983 :
984 0 : return smb_raw_ntcancel(a->c_req);
985 : }
986 :
987 : /*
988 : lock a byte range
989 : */
990 190 : static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs,
991 : struct ntvfs_request *req, union smb_lock *io)
992 : {
993 190 : struct cvfs_private *p = ntvfs->private_data;
994 0 : struct smbcli_request *c_req;
995 :
996 190 : SETUP_PID;
997 :
998 190 : if (io->generic.level != RAW_LOCK_GENERIC &&
999 0 : p->map_generic) {
1000 0 : return ntvfs_map_lock(ntvfs, req, io);
1001 : }
1002 190 : SETUP_FILE;
1003 :
1004 190 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1005 0 : return smb_raw_lock(p->tree, io);
1006 : }
1007 :
1008 190 : c_req = smb_raw_lock_send(p->tree, io);
1009 190 : SIMPLE_ASYNC_TAIL;
1010 : }
1011 :
1012 : /*
1013 : set info on a open file
1014 : */
1015 38 : static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
1016 : struct ntvfs_request *req,
1017 : union smb_setfileinfo *io)
1018 : {
1019 38 : struct cvfs_private *p = ntvfs->private_data;
1020 0 : struct smbcli_request *c_req;
1021 :
1022 38 : SETUP_PID_AND_FILE;
1023 :
1024 38 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1025 0 : return smb_raw_setfileinfo(p->tree, io);
1026 : }
1027 38 : c_req = smb_raw_setfileinfo_send(p->tree, io);
1028 :
1029 38 : SIMPLE_ASYNC_TAIL;
1030 : }
1031 :
1032 :
1033 : /*
1034 : a handler for async fsinfo replies
1035 : */
1036 2001 : static void async_fsinfo(struct smbcli_request *c_req)
1037 : {
1038 2001 : struct async_info *async = c_req->async.private_data;
1039 2001 : struct ntvfs_request *req = async->req;
1040 2001 : req->async_states->status = smb_raw_fsinfo_recv(c_req, req, async->parms);
1041 2001 : talloc_free(async);
1042 2001 : req->async_states->send_fn(req);
1043 2001 : }
1044 :
1045 : /*
1046 : return filesystem space info
1047 : */
1048 2001 : static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs,
1049 : struct ntvfs_request *req, union smb_fsinfo *fs)
1050 : {
1051 2001 : struct cvfs_private *p = ntvfs->private_data;
1052 0 : struct smbcli_request *c_req;
1053 :
1054 2001 : SETUP_PID;
1055 :
1056 2001 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1057 0 : return smb_raw_fsinfo(p->tree, req, fs);
1058 : }
1059 :
1060 2001 : c_req = smb_raw_fsinfo_send(p->tree, req, fs);
1061 :
1062 2001 : ASYNC_RECV_TAIL(fs, async_fsinfo);
1063 : }
1064 :
1065 : /*
1066 : return print queue info
1067 : */
1068 0 : static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs,
1069 : struct ntvfs_request *req, union smb_lpq *lpq)
1070 : {
1071 0 : return NT_STATUS_NOT_SUPPORTED;
1072 : }
1073 :
1074 : /*
1075 : list files in a directory matching a wildcard pattern
1076 : */
1077 3127 : static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs,
1078 : struct ntvfs_request *req, union smb_search_first *io,
1079 : void *search_private,
1080 : bool (*callback)(void *, const union smb_search_data *))
1081 : {
1082 3127 : struct cvfs_private *p = ntvfs->private_data;
1083 :
1084 3127 : SETUP_PID;
1085 :
1086 3127 : return smb_raw_search_first(p->tree, req, io, search_private, callback);
1087 : }
1088 :
1089 : /* continue a search */
1090 12 : static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs,
1091 : struct ntvfs_request *req, union smb_search_next *io,
1092 : void *search_private,
1093 : bool (*callback)(void *, const union smb_search_data *))
1094 : {
1095 12 : struct cvfs_private *p = ntvfs->private_data;
1096 :
1097 12 : SETUP_PID;
1098 :
1099 12 : return smb_raw_search_next(p->tree, req, io, search_private, callback);
1100 : }
1101 :
1102 : /* close a search */
1103 0 : static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs,
1104 : struct ntvfs_request *req, union smb_search_close *io)
1105 : {
1106 0 : struct cvfs_private *p = ntvfs->private_data;
1107 :
1108 0 : SETUP_PID;
1109 :
1110 0 : return smb_raw_search_close(p->tree, io);
1111 : }
1112 :
1113 : /*
1114 : a handler for async trans2 replies
1115 : */
1116 0 : static void async_trans2(struct smbcli_request *c_req)
1117 : {
1118 0 : struct async_info *async = c_req->async.private_data;
1119 0 : struct ntvfs_request *req = async->req;
1120 0 : req->async_states->status = smb_raw_trans2_recv(c_req, req, async->parms);
1121 0 : talloc_free(async);
1122 0 : req->async_states->send_fn(req);
1123 0 : }
1124 :
1125 : /* raw trans2 */
1126 11624 : static NTSTATUS cvfs_trans2(struct ntvfs_module_context *ntvfs,
1127 : struct ntvfs_request *req,
1128 : struct smb_trans2 *trans2)
1129 : {
1130 11624 : struct cvfs_private *p = ntvfs->private_data;
1131 0 : struct smbcli_request *c_req;
1132 :
1133 11624 : if (p->map_trans2) {
1134 11624 : return NT_STATUS_NOT_IMPLEMENTED;
1135 : }
1136 :
1137 0 : SETUP_PID;
1138 :
1139 0 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1140 0 : return smb_raw_trans2(p->tree, req, trans2);
1141 : }
1142 :
1143 0 : c_req = smb_raw_trans2_send(p->tree, trans2);
1144 :
1145 0 : ASYNC_RECV_TAIL(trans2, async_trans2);
1146 : }
1147 :
1148 :
1149 : /* SMBtrans - not used on file shares */
1150 0 : static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs,
1151 : struct ntvfs_request *req,
1152 : struct smb_trans2 *trans2)
1153 : {
1154 0 : return NT_STATUS_ACCESS_DENIED;
1155 : }
1156 :
1157 : /*
1158 : a handler for async change notify replies
1159 : */
1160 0 : static void async_changenotify(struct smbcli_request *c_req)
1161 : {
1162 0 : struct async_info *async = c_req->async.private_data;
1163 0 : struct ntvfs_request *req = async->req;
1164 0 : req->async_states->status = smb_raw_changenotify_recv(c_req, req, async->parms);
1165 0 : talloc_free(async);
1166 0 : req->async_states->send_fn(req);
1167 0 : }
1168 :
1169 : /* change notify request - always async */
1170 0 : static NTSTATUS cvfs_notify(struct ntvfs_module_context *ntvfs,
1171 : struct ntvfs_request *req,
1172 : union smb_notify *io)
1173 : {
1174 0 : struct cvfs_private *p = ntvfs->private_data;
1175 0 : struct smbcli_request *c_req;
1176 0 : int saved_timeout = p->transport->options.request_timeout;
1177 0 : struct cvfs_file *f;
1178 :
1179 0 : if (io->nttrans.level != RAW_NOTIFY_NTTRANS) {
1180 0 : return NT_STATUS_NOT_IMPLEMENTED;
1181 : }
1182 :
1183 0 : SETUP_PID;
1184 :
1185 0 : f = ntvfs_handle_get_backend_data(io->nttrans.in.file.ntvfs, ntvfs);
1186 0 : if (!f) return NT_STATUS_INVALID_HANDLE;
1187 0 : io->nttrans.in.file.fnum = f->fnum;
1188 :
1189 : /* this request doesn't make sense unless its async */
1190 0 : if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1191 0 : return NT_STATUS_INVALID_PARAMETER;
1192 : }
1193 :
1194 : /* we must not timeout on notify requests - they wait
1195 : forever */
1196 0 : p->transport->options.request_timeout = 0;
1197 :
1198 0 : c_req = smb_raw_changenotify_send(p->tree, io);
1199 :
1200 0 : p->transport->options.request_timeout = saved_timeout;
1201 :
1202 0 : ASYNC_RECV_TAIL(io, async_changenotify);
1203 : }
1204 :
1205 : /*
1206 : initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
1207 : */
1208 68 : NTSTATUS ntvfs_cifs_init(TALLOC_CTX *ctx)
1209 : {
1210 3 : NTSTATUS ret;
1211 3 : struct ntvfs_ops ops;
1212 68 : NTVFS_CURRENT_CRITICAL_SIZES(vers);
1213 :
1214 68 : ZERO_STRUCT(ops);
1215 :
1216 : /* fill in the name and type */
1217 68 : ops.name = "cifs";
1218 68 : ops.type = NTVFS_DISK;
1219 :
1220 : /* fill in all the operations */
1221 68 : ops.connect_fn = cvfs_connect;
1222 68 : ops.disconnect_fn = cvfs_disconnect;
1223 68 : ops.unlink_fn = cvfs_unlink;
1224 68 : ops.chkpath_fn = cvfs_chkpath;
1225 68 : ops.qpathinfo_fn = cvfs_qpathinfo;
1226 68 : ops.setpathinfo_fn = cvfs_setpathinfo;
1227 68 : ops.open_fn = cvfs_open;
1228 68 : ops.mkdir_fn = cvfs_mkdir;
1229 68 : ops.rmdir_fn = cvfs_rmdir;
1230 68 : ops.rename_fn = cvfs_rename;
1231 68 : ops.copy_fn = cvfs_copy;
1232 68 : ops.ioctl_fn = cvfs_ioctl;
1233 68 : ops.read_fn = cvfs_read;
1234 68 : ops.write_fn = cvfs_write;
1235 68 : ops.seek_fn = cvfs_seek;
1236 68 : ops.flush_fn = cvfs_flush;
1237 68 : ops.close_fn = cvfs_close;
1238 68 : ops.exit_fn = cvfs_exit;
1239 68 : ops.lock_fn = cvfs_lock;
1240 68 : ops.setfileinfo_fn = cvfs_setfileinfo;
1241 68 : ops.qfileinfo_fn = cvfs_qfileinfo;
1242 68 : ops.fsinfo_fn = cvfs_fsinfo;
1243 68 : ops.lpq_fn = cvfs_lpq;
1244 68 : ops.search_first_fn = cvfs_search_first;
1245 68 : ops.search_next_fn = cvfs_search_next;
1246 68 : ops.search_close_fn = cvfs_search_close;
1247 68 : ops.trans_fn = cvfs_trans;
1248 68 : ops.logoff_fn = cvfs_logoff;
1249 68 : ops.async_setup_fn = cvfs_async_setup;
1250 68 : ops.cancel_fn = cvfs_cancel;
1251 68 : ops.notify_fn = cvfs_notify;
1252 68 : ops.trans2_fn = cvfs_trans2;
1253 :
1254 : /* register ourselves with the NTVFS subsystem. We register
1255 : under the name 'cifs'. */
1256 68 : ret = ntvfs_register(&ops, &vers);
1257 :
1258 68 : if (!NT_STATUS_IS_OK(ret)) {
1259 0 : DEBUG(0,("Failed to register CIFS backend!\n"));
1260 : }
1261 :
1262 68 : return ret;
1263 : }
|