Move waf into third_party/.
[Samba.git] / source4 / ntvfs / smb2 / vfs_smb2.c
blobdbb76b3dc12695b5223256cc2db56ddae8bc6ef4
1 /*
2 Unix SMB/CIFS implementation.
4 CIFS-to-SMB2 NTVFS filesystem backend
6 Copyright (C) Andrew Tridgell 2008
8 largely based on vfs_cifs.c which was
9 Copyright (C) Andrew Tridgell 2003
10 Copyright (C) James J Myers 2003 <myersjj@samba.org>
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 this implements a CIFS->CIFS NTVFS filesystem backend.
30 #include "includes.h"
31 #include "libcli/raw/libcliraw.h"
32 #include "libcli/raw/raw_proto.h"
33 #include "libcli/composite/composite.h"
34 #include "libcli/smb_composite/smb_composite.h"
35 #include "auth/auth.h"
36 #include "auth/credentials/credentials.h"
37 #include "ntvfs/ntvfs.h"
38 #include "../lib/util/dlinklist.h"
39 #include "param/param.h"
40 #include "libcli/resolve/resolve.h"
41 #include "libcli/smb2/smb2.h"
42 #include "libcli/smb2/smb2_calls.h"
44 NTSTATUS ntvfs_smb2_init(void);
46 struct cvfs_file {
47 struct cvfs_file *prev, *next;
48 uint16_t fnum;
49 struct ntvfs_handle *h;
52 /* this is stored in ntvfs_private */
53 struct cvfs_private {
54 struct smb2_tree *tree;
55 struct smb2_transport *transport;
56 struct ntvfs_module_context *ntvfs;
57 struct async_info *pending;
58 struct cvfs_file *files;
60 /* a handle on the root of the share */
61 /* TODO: leaving this handle open could prevent other users
62 from opening the share with exclusive access. We probably
63 need to open it on demand */
64 struct smb2_handle roothandle;
68 /* a structure used to pass information to an async handler */
69 struct async_info {
70 struct async_info *next, *prev;
71 struct cvfs_private *cvfs;
72 struct ntvfs_request *req;
73 void *c_req;
74 struct composite_context *c_comp;
75 struct cvfs_file *f;
76 void *parms;
79 #define SETUP_FILE_HERE(f) do { \
80 f = ntvfs_handle_get_backend_data(io->generic.in.file.ntvfs, ntvfs); \
81 if (!f) return NT_STATUS_INVALID_HANDLE; \
82 io->generic.in.file.fnum = f->fnum; \
83 } while (0)
85 #define SETUP_FILE do { \
86 struct cvfs_file *f; \
87 SETUP_FILE_HERE(f); \
88 } while (0)
90 #define SMB2_SERVER "smb2:server"
91 #define SMB2_USER "smb2:user"
92 #define SMB2_PASSWORD "smb2:password"
93 #define SMB2_DOMAIN "smb2:domain"
94 #define SMB2_SHARE "smb2:share"
95 #define SMB2_USE_MACHINE_ACCT "smb2:use-machine-account"
97 #define SMB2_USE_MACHINE_ACCT_DEFAULT false
100 a handler for oplock break events from the server - these need to be passed
101 along to the client
103 #if 0
104 static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *p_private)
106 struct cvfs_private *p = p_private;
107 NTSTATUS status;
108 struct ntvfs_handle *h = NULL;
109 struct cvfs_file *f;
111 for (f=p->files; f; f=f->next) {
112 if (f->fnum != fnum) continue;
113 h = f->h;
114 break;
117 if (!h) {
118 DEBUG(5,("vfs_smb2: ignoring oplock break level %d for fnum %d\n", level, fnum));
119 return true;
122 DEBUG(5,("vfs_smb2: sending oplock break level %d for fnum %d\n", level, fnum));
123 status = ntvfs_send_oplock_break(p->ntvfs, h, level);
124 if (!NT_STATUS_IS_OK(status)) return false;
125 return true;
127 #endif
130 return a handle to the root of the share
132 static NTSTATUS smb2_get_roothandle(struct smb2_tree *tree, struct smb2_handle *handle)
134 struct smb2_create io;
135 NTSTATUS status;
137 ZERO_STRUCT(io);
138 io.in.oplock_level = 0;
139 io.in.desired_access = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST;
140 io.in.file_attributes = 0;
141 io.in.create_disposition = NTCREATEX_DISP_OPEN;
142 io.in.share_access =
143 NTCREATEX_SHARE_ACCESS_READ |
144 NTCREATEX_SHARE_ACCESS_WRITE|
145 NTCREATEX_SHARE_ACCESS_DELETE;
146 io.in.create_options = 0;
147 io.in.fname = NULL;
149 status = smb2_create(tree, tree, &io);
150 NT_STATUS_NOT_OK_RETURN(status);
152 *handle = io.out.file.handle;
154 return NT_STATUS_OK;
158 connect to a share - used when a tree_connect operation comes in.
160 static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs,
161 struct ntvfs_request *req,
162 union smb_tcon* tcon)
164 NTSTATUS status;
165 struct cvfs_private *p;
166 const char *host, *user, *pass, *domain, *remote_share, *sharename;
167 struct share_config *scfg = ntvfs->ctx->config;
168 struct smb2_tree *tree;
169 struct cli_credentials *credentials;
170 bool machine_account;
171 struct smbcli_options options;
172 TALLOC_CTX *tmp_ctx;
174 tmp_ctx = talloc_new(req);
175 if (tmp_ctx == NULL) {
176 return NT_STATUS_NO_MEMORY;
179 switch (tcon->generic.level) {
180 case RAW_TCON_TCON:
181 sharename = tcon->tcon.in.service;
182 break;
183 case RAW_TCON_TCONX:
184 sharename = tcon->tconx.in.path;
185 break;
186 case RAW_TCON_SMB2:
187 sharename = tcon->smb2.in.path;
188 break;
189 default:
190 status = NT_STATUS_INVALID_LEVEL;
191 goto out;
194 if (strncmp(sharename, "\\\\", 2) == 0) {
195 char *str = strchr(sharename+2, '\\');
196 if (str) {
197 sharename = str + 1;
201 /* Here we need to determine which server to connect to.
202 * For now we use parametric options, type cifs.
204 host = share_string_option(tmp_ctx, scfg, SMB2_SERVER, NULL);
205 user = share_string_option(tmp_ctx, scfg, SMB2_USER, NULL);
206 pass = share_string_option(tmp_ctx, scfg, SMB2_PASSWORD, NULL);
207 domain = share_string_option(tmp_ctx, scfg, SMB2_DOMAIN, NULL);
208 remote_share = share_string_option(tmp_ctx, scfg, SMB2_SHARE, NULL);
209 if (!remote_share) {
210 remote_share = sharename;
213 machine_account = share_bool_option(scfg, SMB2_USE_MACHINE_ACCT, SMB2_USE_MACHINE_ACCT_DEFAULT);
215 p = talloc_zero(ntvfs, struct cvfs_private);
216 if (!p) {
217 status = NT_STATUS_NO_MEMORY;
218 goto out;
221 ntvfs->private_data = p;
223 if (!host) {
224 DEBUG(1,("CIFS backend: You must supply server\n"));
225 status = NT_STATUS_INVALID_PARAMETER;
226 goto out;
229 if (user && pass) {
230 DEBUG(5, ("CIFS backend: Using specified password\n"));
231 credentials = cli_credentials_init(p);
232 if (!credentials) {
233 status = NT_STATUS_NO_MEMORY;
234 goto out;
236 cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx);
237 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
238 if (domain) {
239 cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
241 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
242 } else if (machine_account) {
243 DEBUG(5, ("CIFS backend: Using machine account\n"));
244 credentials = cli_credentials_init(p);
245 cli_credentials_set_conf(credentials, ntvfs->ctx->lp_ctx);
246 if (domain) {
247 cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
249 status = cli_credentials_set_machine_account(credentials, ntvfs->ctx->lp_ctx);
250 if (!NT_STATUS_IS_OK(status)) {
251 goto out;
253 } else if (req->session_info->credentials) {
254 DEBUG(5, ("CIFS backend: Using delegated credentials\n"));
255 credentials = req->session_info->credentials;
256 } else {
257 DEBUG(1,("CIFS backend: NO delegated credentials found: You must supply server, user and password or the client must supply delegated credentials\n"));
258 status = NT_STATUS_INVALID_PARAMETER;
259 goto out;
262 lpcfg_smbcli_options(ntvfs->ctx->lp_ctx, &options);
264 status = smb2_connect(p, host,
265 lpcfg_parm_string_list(p, ntvfs->ctx->lp_ctx, NULL, "smb2", "ports", NULL),
266 remote_share,
267 lpcfg_resolve_context(ntvfs->ctx->lp_ctx),
268 credentials,
269 &tree,
270 ntvfs->ctx->event_ctx, &options,
271 lpcfg_socket_options(ntvfs->ctx->lp_ctx),
272 lpcfg_gensec_settings(p, ntvfs->ctx->lp_ctx));
273 if (!NT_STATUS_IS_OK(status)) {
274 goto out;
277 status = smb2_get_roothandle(tree, &p->roothandle);
278 if (!NT_STATUS_IS_OK(status)) {
279 goto out;
282 p->tree = tree;
283 p->transport = p->tree->session->transport;
284 p->ntvfs = ntvfs;
286 ntvfs->ctx->fs_type = talloc_strdup(ntvfs->ctx, "NTFS");
287 if (ntvfs->ctx->fs_type == NULL) {
288 status = NT_STATUS_NO_MEMORY;
289 goto out;
291 ntvfs->ctx->dev_type = talloc_strdup(ntvfs->ctx, "A:");
292 if (ntvfs->ctx->dev_type == NULL) {
293 status = NT_STATUS_NO_MEMORY;
294 goto out;
297 if (tcon->generic.level == RAW_TCON_TCONX) {
298 tcon->tconx.out.fs_type = ntvfs->ctx->fs_type;
299 tcon->tconx.out.dev_type = ntvfs->ctx->dev_type;
302 /* we need to receive oplock break requests from the server */
303 /* TODO: enable oplocks
304 smbcli_oplock_handler(p->transport, oplock_handler, p);
307 status = NT_STATUS_OK;
309 out:
310 TALLOC_FREE(tmp_ctx);
311 return status;
315 disconnect from a share
317 static NTSTATUS cvfs_disconnect(struct ntvfs_module_context *ntvfs)
319 struct cvfs_private *p = ntvfs->private_data;
320 struct async_info *a, *an;
322 /* first cleanup pending requests */
323 for (a=p->pending; a; a = an) {
324 an = a->next;
325 talloc_free(a->c_req);
326 talloc_free(a);
329 talloc_free(p);
330 ntvfs->private_data = NULL;
332 return NT_STATUS_OK;
336 destroy an async info structure
338 static int async_info_destructor(struct async_info *async)
340 DLIST_REMOVE(async->cvfs->pending, async);
341 return 0;
345 a handler for simple async SMB2 replies
346 this handler can only be used for functions that don't return any
347 parameters (those that just return a status code)
349 static void async_simple_smb2(struct smb2_request *c_req)
351 struct async_info *async = c_req->async.private_data;
352 struct ntvfs_request *req = async->req;
354 smb2_request_receive(c_req);
355 req->async_states->status = smb2_request_destroy(c_req);
356 talloc_free(async);
357 req->async_states->send_fn(req);
361 a handler for simple async composite replies
362 this handler can only be used for functions that don't return any
363 parameters (those that just return a status code)
365 static void async_simple_composite(struct composite_context *c_req)
367 struct async_info *async = c_req->async.private_data;
368 struct ntvfs_request *req = async->req;
370 req->async_states->status = composite_wait_free(c_req);
371 talloc_free(async);
372 req->async_states->send_fn(req);
376 /* save some typing for the simple functions */
377 #define ASYNC_RECV_TAIL_F(io, async_fn, file) do { \
378 if (!c_req) return NT_STATUS_UNSUCCESSFUL; \
380 struct async_info *async; \
381 async = talloc(req, struct async_info); \
382 if (!async) return NT_STATUS_NO_MEMORY; \
383 async->parms = io; \
384 async->req = req; \
385 async->f = file; \
386 async->cvfs = p; \
387 async->c_req = c_req; \
388 DLIST_ADD(p->pending, async); \
389 c_req->async.private_data = async; \
390 talloc_set_destructor(async, async_info_destructor); \
392 c_req->async.fn = async_fn; \
393 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; \
394 return NT_STATUS_OK; \
395 } while (0)
397 #define ASYNC_RECV_TAIL(io, async_fn) ASYNC_RECV_TAIL_F(io, async_fn, NULL)
399 #define SIMPLE_ASYNC_TAIL ASYNC_RECV_TAIL(NULL, async_simple_smb2)
400 #define SIMPLE_COMPOSITE_TAIL ASYNC_RECV_TAIL(NULL, async_simple_composite)
402 #define CHECK_ASYNC(req) do { \
403 if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { \
404 DEBUG(0,("SMB2 proxy backend does not support sync operation at %s\n", \
405 __location__)); \
406 return NT_STATUS_NOT_IMPLEMENTED; \
407 }} while (0)
410 delete a file - the dirtype specifies the file types to include in the search.
411 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
413 BUGS:
414 - doesn't handle wildcards
415 - doesn't obey attrib restrictions
417 static NTSTATUS cvfs_unlink(struct ntvfs_module_context *ntvfs,
418 struct ntvfs_request *req, union smb_unlink *unl)
420 struct cvfs_private *p = ntvfs->private_data;
421 struct composite_context *c_req;
423 CHECK_ASYNC(req);
425 c_req = smb2_composite_unlink_send(p->tree, unl);
427 SIMPLE_COMPOSITE_TAIL;
431 ioctl interface
433 static NTSTATUS cvfs_ioctl(struct ntvfs_module_context *ntvfs,
434 struct ntvfs_request *req, union smb_ioctl *io)
436 return NT_STATUS_NOT_IMPLEMENTED;
440 check if a directory exists
442 static NTSTATUS cvfs_chkpath(struct ntvfs_module_context *ntvfs,
443 struct ntvfs_request *req, union smb_chkpath *cp)
445 struct cvfs_private *p = ntvfs->private_data;
446 struct smb2_request *c_req;
447 struct smb2_find f;
449 CHECK_ASYNC(req);
451 /* SMB2 doesn't have a chkpath operation, and also doesn't
452 have a query path info call, so the best seems to be to do a
453 find call, using the roothandle we established at connect
454 time */
455 ZERO_STRUCT(f);
456 f.in.file.handle = p->roothandle;
457 f.in.level = SMB2_FIND_DIRECTORY_INFO;
458 f.in.pattern = cp->chkpath.in.path;
459 /* SMB2 find doesn't accept \ or the empty string - this is the best
460 approximation */
461 if (strcmp(f.in.pattern, "\\") == 0 ||
462 strcmp(f.in.pattern, "") == 0) {
463 f.in.pattern = "?";
465 f.in.continue_flags = SMB2_CONTINUE_FLAG_SINGLE | SMB2_CONTINUE_FLAG_RESTART;
466 f.in.max_response_size = 0x1000;
468 c_req = smb2_find_send(p->tree, &f);
470 SIMPLE_ASYNC_TAIL;
474 return info on a pathname
476 static NTSTATUS cvfs_qpathinfo(struct ntvfs_module_context *ntvfs,
477 struct ntvfs_request *req, union smb_fileinfo *info)
479 return NT_STATUS_NOT_IMPLEMENTED;
483 query info on a open file
485 static NTSTATUS cvfs_qfileinfo(struct ntvfs_module_context *ntvfs,
486 struct ntvfs_request *req, union smb_fileinfo *io)
488 return NT_STATUS_NOT_IMPLEMENTED;
493 set info on a pathname
495 static NTSTATUS cvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
496 struct ntvfs_request *req, union smb_setfileinfo *st)
498 return NT_STATUS_NOT_IMPLEMENTED;
503 open a file
505 static NTSTATUS cvfs_open(struct ntvfs_module_context *ntvfs,
506 struct ntvfs_request *req, union smb_open *io)
508 return NT_STATUS_NOT_IMPLEMENTED;
512 create a directory
514 static NTSTATUS cvfs_mkdir(struct ntvfs_module_context *ntvfs,
515 struct ntvfs_request *req, union smb_mkdir *md)
517 struct cvfs_private *p = ntvfs->private_data;
518 struct composite_context *c_req;
520 CHECK_ASYNC(req);
522 c_req = smb2_composite_mkdir_send(p->tree, md);
524 SIMPLE_COMPOSITE_TAIL;
528 remove a directory
530 static NTSTATUS cvfs_rmdir(struct ntvfs_module_context *ntvfs,
531 struct ntvfs_request *req, struct smb_rmdir *rd)
533 struct cvfs_private *p = ntvfs->private_data;
534 struct composite_context *c_req;
536 CHECK_ASYNC(req);
538 c_req = smb2_composite_rmdir_send(p->tree, rd);
540 SIMPLE_COMPOSITE_TAIL;
544 rename a set of files
546 static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs,
547 struct ntvfs_request *req, union smb_rename *ren)
549 return NT_STATUS_NOT_IMPLEMENTED;
553 copy a set of files
555 static NTSTATUS cvfs_copy(struct ntvfs_module_context *ntvfs,
556 struct ntvfs_request *req, struct smb_copy *cp)
558 return NT_STATUS_NOT_SUPPORTED;
562 read from a file
564 static NTSTATUS cvfs_read(struct ntvfs_module_context *ntvfs,
565 struct ntvfs_request *req, union smb_read *io)
567 return NT_STATUS_NOT_IMPLEMENTED;
571 write to a file
573 static NTSTATUS cvfs_write(struct ntvfs_module_context *ntvfs,
574 struct ntvfs_request *req, union smb_write *io)
576 return NT_STATUS_NOT_IMPLEMENTED;
580 seek in a file
582 static NTSTATUS cvfs_seek(struct ntvfs_module_context *ntvfs,
583 struct ntvfs_request *req,
584 union smb_seek *io)
586 return NT_STATUS_NOT_IMPLEMENTED;
590 flush a file
592 static NTSTATUS cvfs_flush(struct ntvfs_module_context *ntvfs,
593 struct ntvfs_request *req,
594 union smb_flush *io)
596 return NT_STATUS_NOT_IMPLEMENTED;
600 close a file
602 static NTSTATUS cvfs_close(struct ntvfs_module_context *ntvfs,
603 struct ntvfs_request *req, union smb_close *io)
605 return NT_STATUS_NOT_IMPLEMENTED;
609 exit - closing files open by the pid
611 static NTSTATUS cvfs_exit(struct ntvfs_module_context *ntvfs,
612 struct ntvfs_request *req)
614 return NT_STATUS_NOT_IMPLEMENTED;
618 logoff - closing files open by the user
620 static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs,
621 struct ntvfs_request *req)
623 /* we can't do this right in the cifs backend .... */
624 return NT_STATUS_OK;
628 setup for an async call - nothing to do yet
630 static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs,
631 struct ntvfs_request *req,
632 void *private_data)
634 return NT_STATUS_OK;
638 cancel an async call
640 static NTSTATUS cvfs_cancel(struct ntvfs_module_context *ntvfs,
641 struct ntvfs_request *req)
643 return NT_STATUS_NOT_IMPLEMENTED;
647 lock a byte range
649 static NTSTATUS cvfs_lock(struct ntvfs_module_context *ntvfs,
650 struct ntvfs_request *req, union smb_lock *io)
652 return NT_STATUS_NOT_IMPLEMENTED;
656 set info on a open file
658 static NTSTATUS cvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
659 struct ntvfs_request *req,
660 union smb_setfileinfo *io)
662 return NT_STATUS_NOT_IMPLEMENTED;
667 a handler for async fsinfo replies
669 static void async_fsinfo(struct smb2_request *c_req)
671 struct async_info *async = c_req->async.private_data;
672 struct ntvfs_request *req = async->req;
673 req->async_states->status = smb2_getinfo_fs_recv(c_req, req, async->parms);
674 talloc_free(async);
675 req->async_states->send_fn(req);
679 return filesystem space info
681 static NTSTATUS cvfs_fsinfo(struct ntvfs_module_context *ntvfs,
682 struct ntvfs_request *req, union smb_fsinfo *fs)
684 struct cvfs_private *p = ntvfs->private_data;
685 struct smb2_request *c_req;
686 enum smb_fsinfo_level level = fs->generic.level;
688 CHECK_ASYNC(req);
690 switch (level) {
691 /* some levels go straight through */
692 case RAW_QFS_VOLUME_INFORMATION:
693 case RAW_QFS_SIZE_INFORMATION:
694 case RAW_QFS_DEVICE_INFORMATION:
695 case RAW_QFS_ATTRIBUTE_INFORMATION:
696 case RAW_QFS_QUOTA_INFORMATION:
697 case RAW_QFS_FULL_SIZE_INFORMATION:
698 case RAW_QFS_OBJECTID_INFORMATION:
699 break;
701 /* some get mapped */
702 case RAW_QFS_VOLUME_INFO:
703 level = RAW_QFS_VOLUME_INFORMATION;
704 break;
705 case RAW_QFS_SIZE_INFO:
706 level = RAW_QFS_SIZE_INFORMATION;
707 break;
708 case RAW_QFS_DEVICE_INFO:
709 level = RAW_QFS_DEVICE_INFORMATION;
710 break;
711 case RAW_QFS_ATTRIBUTE_INFO:
712 level = RAW_QFS_ATTRIBUTE_INFO;
713 break;
715 default:
716 /* the rest get refused for now */
717 DEBUG(0,("fsinfo level %u not possible on SMB2\n",
718 (unsigned)fs->generic.level));
719 break;
722 fs->generic.level = level;
723 fs->generic.handle = p->roothandle;
725 c_req = smb2_getinfo_fs_send(p->tree, fs);
727 ASYNC_RECV_TAIL(fs, async_fsinfo);
731 return print queue info
733 static NTSTATUS cvfs_lpq(struct ntvfs_module_context *ntvfs,
734 struct ntvfs_request *req, union smb_lpq *lpq)
736 return NT_STATUS_NOT_SUPPORTED;
740 list files in a directory matching a wildcard pattern
742 static NTSTATUS cvfs_search_first(struct ntvfs_module_context *ntvfs,
743 struct ntvfs_request *req, union smb_search_first *io,
744 void *search_private,
745 bool (*callback)(void *, const union smb_search_data *))
747 struct cvfs_private *p = ntvfs->private_data;
748 struct smb2_find f;
749 enum smb_search_data_level smb2_level;
750 unsigned int count, i;
751 union smb_search_data *data;
752 NTSTATUS status;
754 if (io->generic.level != RAW_SEARCH_TRANS2) {
755 DEBUG(0,("We only support trans2 search in smb2 backend\n"));
756 return NT_STATUS_NOT_SUPPORTED;
759 switch (io->generic.data_level) {
760 case RAW_SEARCH_DATA_DIRECTORY_INFO:
761 smb2_level = SMB2_FIND_DIRECTORY_INFO;
762 break;
763 case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
764 smb2_level = SMB2_FIND_FULL_DIRECTORY_INFO;
765 break;
766 case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
767 smb2_level = SMB2_FIND_BOTH_DIRECTORY_INFO;
768 break;
769 case RAW_SEARCH_DATA_NAME_INFO:
770 smb2_level = SMB2_FIND_NAME_INFO;
771 break;
772 case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
773 smb2_level = SMB2_FIND_ID_FULL_DIRECTORY_INFO;
774 break;
775 case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
776 smb2_level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO;
777 break;
778 default:
779 DEBUG(0,("Unsupported search level %u for smb2 backend\n",
780 (unsigned)io->generic.data_level));
781 return NT_STATUS_INVALID_INFO_CLASS;
784 /* we do the search on the roothandle. This only works because
785 search is synchronous, otherwise we'd have no way to
786 distinguish multiple searches happening at once
788 ZERO_STRUCT(f);
789 f.in.file.handle = p->roothandle;
790 f.in.level = smb2_level;
791 f.in.pattern = io->t2ffirst.in.pattern;
792 while (f.in.pattern[0] == '\\') {
793 f.in.pattern++;
795 f.in.continue_flags = 0;
796 f.in.max_response_size = 0x10000;
798 status = smb2_find_level(p->tree, req, &f, &count, &data);
799 NT_STATUS_NOT_OK_RETURN(status);
801 for (i=0;i<count;i++) {
802 if (!callback(search_private, &data[i])) break;
805 io->t2ffirst.out.handle = 0;
806 io->t2ffirst.out.count = i;
807 /* TODO: fix end_of_file */
808 io->t2ffirst.out.end_of_search = 1;
810 talloc_free(data);
812 return NT_STATUS_OK;
815 /* continue a search */
816 static NTSTATUS cvfs_search_next(struct ntvfs_module_context *ntvfs,
817 struct ntvfs_request *req, union smb_search_next *io,
818 void *search_private,
819 bool (*callback)(void *, const union smb_search_data *))
821 return NT_STATUS_NOT_IMPLEMENTED;
824 /* close a search */
825 static NTSTATUS cvfs_search_close(struct ntvfs_module_context *ntvfs,
826 struct ntvfs_request *req, union smb_search_close *io)
828 return NT_STATUS_NOT_IMPLEMENTED;
831 /* SMBtrans - not used on file shares */
832 static NTSTATUS cvfs_trans(struct ntvfs_module_context *ntvfs,
833 struct ntvfs_request *req,
834 struct smb_trans2 *trans2)
836 return NT_STATUS_ACCESS_DENIED;
839 /* change notify request - always async */
840 static NTSTATUS cvfs_notify(struct ntvfs_module_context *ntvfs,
841 struct ntvfs_request *req,
842 union smb_notify *io)
844 return NT_STATUS_NOT_IMPLEMENTED;
848 initialise the CIFS->CIFS backend, registering ourselves with the ntvfs subsystem
850 NTSTATUS ntvfs_smb2_init(void)
852 NTSTATUS ret;
853 struct ntvfs_ops ops;
854 NTVFS_CURRENT_CRITICAL_SIZES(vers);
856 ZERO_STRUCT(ops);
858 /* fill in the name and type */
859 ops.name = "smb2";
860 ops.type = NTVFS_DISK;
862 /* fill in all the operations */
863 ops.connect_fn = cvfs_connect;
864 ops.disconnect_fn = cvfs_disconnect;
865 ops.unlink_fn = cvfs_unlink;
866 ops.chkpath_fn = cvfs_chkpath;
867 ops.qpathinfo_fn = cvfs_qpathinfo;
868 ops.setpathinfo_fn = cvfs_setpathinfo;
869 ops.open_fn = cvfs_open;
870 ops.mkdir_fn = cvfs_mkdir;
871 ops.rmdir_fn = cvfs_rmdir;
872 ops.rename_fn = cvfs_rename;
873 ops.copy_fn = cvfs_copy;
874 ops.ioctl_fn = cvfs_ioctl;
875 ops.read_fn = cvfs_read;
876 ops.write_fn = cvfs_write;
877 ops.seek_fn = cvfs_seek;
878 ops.flush_fn = cvfs_flush;
879 ops.close_fn = cvfs_close;
880 ops.exit_fn = cvfs_exit;
881 ops.lock_fn = cvfs_lock;
882 ops.setfileinfo_fn = cvfs_setfileinfo;
883 ops.qfileinfo_fn = cvfs_qfileinfo;
884 ops.fsinfo_fn = cvfs_fsinfo;
885 ops.lpq_fn = cvfs_lpq;
886 ops.search_first_fn = cvfs_search_first;
887 ops.search_next_fn = cvfs_search_next;
888 ops.search_close_fn = cvfs_search_close;
889 ops.trans_fn = cvfs_trans;
890 ops.logoff_fn = cvfs_logoff;
891 ops.async_setup_fn = cvfs_async_setup;
892 ops.cancel_fn = cvfs_cancel;
893 ops.notify_fn = cvfs_notify;
895 /* register ourselves with the NTVFS subsystem. We register
896 under the name 'smb2'. */
897 ret = ntvfs_register(&ops, &vers);
899 if (!NT_STATUS_IS_OK(ret)) {
900 DEBUG(0,("Failed to register SMB2 backend\n"));
903 return ret;