2 Unix SMB/Netbios implementation.
3 SMB client library implementation
4 Copyright (C) Andrew Tridgell 1998
5 Copyright (C) Richard Sharpe 2000, 2002
6 Copyright (C) John Terpstra 2000
7 Copyright (C) Tom Jansen (Ninja ISD) 2002
8 Copyright (C) Derrell Lipman 2003-2008
9 Copyright (C) Jeremy Allison 2007, 2008
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "libsmb/namequery.h"
27 #include "libsmb/libsmb.h"
28 #include "auth_info.h"
29 #include "libsmbclient.h"
30 #include "libsmb_internal.h"
31 #include "rpc_client/cli_pipe.h"
32 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
33 #include "libsmb/nmblib.h"
34 #include "../libcli/smb/smbXcli_base.h"
35 #include "../libcli/security/security.h"
36 #include "lib/util/tevent_ntstatus.h"
39 * Routine to open a directory
40 * We accept the URL syntax explained in SMBC_parse_path(), above.
43 static void remove_dirplus(SMBCFILE *dir)
45 struct smbc_dirplus_list *d = NULL;
47 d = dir->dirplus_list;
49 struct smbc_dirplus_list *f = d;
52 SAFE_FREE(f->smb_finfo->short_name);
53 SAFE_FREE(f->smb_finfo->name);
54 SAFE_FREE(f->smb_finfo);
58 dir->dirplus_list = NULL;
59 dir->dirplus_end = NULL;
60 dir->dirplus_next = NULL;
64 remove_dir(SMBCFILE *dir)
66 struct smbc_dir_list *d,*f;
78 dir->dir_list = dir->dir_end = dir->dir_next = NULL;
83 add_dirent(SMBCFILE *dir,
88 struct smbc_dirent *dirent;
90 int name_length = (name == NULL ? 0 : strlen(name));
91 int comment_len = (comment == NULL ? 0 : strlen(comment));
94 * Allocate space for the dirent, which must be increased by the
95 * size of the name and the comment and 1 each for the null terminator.
98 size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
100 dirent = (struct smbc_dirent *)SMB_MALLOC(size);
104 dir->dir_error = ENOMEM;
109 ZERO_STRUCTP(dirent);
111 if (dir->dir_list == NULL) {
113 dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
114 if (!dir->dir_list) {
117 dir->dir_error = ENOMEM;
121 ZERO_STRUCTP(dir->dir_list);
123 dir->dir_end = dir->dir_next = dir->dir_list;
127 dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
129 if (!dir->dir_end->next) {
132 dir->dir_error = ENOMEM;
136 ZERO_STRUCTP(dir->dir_end->next);
138 dir->dir_end = dir->dir_end->next;
141 dir->dir_end->next = NULL;
142 dir->dir_end->dirent = dirent;
144 dirent->smbc_type = type;
145 dirent->namelen = name_length;
146 dirent->commentlen = comment_len;
147 dirent->dirlen = size;
150 * dirent->namelen + 1 includes the null (no null termination needed)
151 * Ditto for dirent->commentlen.
152 * The space for the two null bytes was allocated.
154 strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
155 dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
156 strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
162 static int add_dirplus(SMBCFILE *dir, struct file_info *finfo)
164 struct smbc_dirplus_list *new_entry = NULL;
165 struct libsmb_file_info *info = NULL;
167 new_entry = SMB_MALLOC_P(struct smbc_dirplus_list);
168 if (new_entry == NULL) {
169 dir->dir_error = ENOMEM;
172 ZERO_STRUCTP(new_entry);
173 new_entry->ino = finfo->ino;
175 info = SMB_MALLOC_P(struct libsmb_file_info);
177 SAFE_FREE(new_entry);
178 dir->dir_error = ENOMEM;
184 info->btime_ts = finfo->btime_ts;
185 info->atime_ts = finfo->atime_ts;
186 info->ctime_ts = finfo->ctime_ts;
187 info->mtime_ts = finfo->mtime_ts;
188 info->gid = finfo->gid;
189 info->attrs = finfo->mode;
190 info->size = finfo->size;
191 info->uid = finfo->uid;
192 info->name = SMB_STRDUP(finfo->name);
193 if (info->name == NULL) {
195 SAFE_FREE(new_entry);
196 dir->dir_error = ENOMEM;
200 if (finfo->short_name) {
201 info->short_name = SMB_STRDUP(finfo->short_name);
203 info->short_name = SMB_STRDUP("");
206 if (info->short_name == NULL) {
207 SAFE_FREE(info->name);
209 SAFE_FREE(new_entry);
210 dir->dir_error = ENOMEM;
213 new_entry->smb_finfo = info;
215 /* Now add to the list. */
216 if (dir->dirplus_list == NULL) {
217 /* Empty list - point everything at new_entry. */
218 dir->dirplus_list = new_entry;
219 dir->dirplus_end = new_entry;
220 dir->dirplus_next = new_entry;
222 /* Append to list but leave the ->next cursor alone. */
223 dir->dirplus_end->next = new_entry;
224 dir->dirplus_end = new_entry;
231 list_unique_wg_fn(const char *name,
236 SMBCFILE *dir = (SMBCFILE *)state;
237 struct smbc_dir_list *dir_list;
238 struct smbc_dirent *dirent;
242 dirent_type = dir->dir_type;
244 if (add_dirent(dir, name, comment, dirent_type) < 0) {
245 /* An error occurred, what do we do? */
246 /* FIXME: Add some code here */
247 /* Change cli_NetServerEnum to take a fn
248 returning NTSTATUS... JRA. */
251 /* Point to the one just added */
252 dirent = dir->dir_end->dirent;
254 /* See if this was a duplicate */
255 for (dir_list = dir->dir_list;
256 dir_list != dir->dir_end;
257 dir_list = dir_list->next) {
259 strcmp(dir_list->dirent->name, dirent->name) == 0) {
260 /* Duplicate. End end of list need to be removed. */
264 if (do_remove && dir_list->next == dir->dir_end) {
265 /* Found the end of the list. Remove it. */
266 dir->dir_end = dir_list;
267 free(dir_list->next);
269 dir_list->next = NULL;
276 list_fn(const char *name,
281 SMBCFILE *dir = (SMBCFILE *)state;
285 * We need to process the type a little ...
287 * Disk share = 0x00000000
288 * Print share = 0x00000001
289 * Comms share = 0x00000002 (obsolete?)
290 * IPC$ share = 0x00000003
292 * administrative shares:
293 * ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000
296 if (dir->dir_type == SMBC_FILE_SHARE) {
300 dirent_type = SMBC_FILE_SHARE;
304 dirent_type = SMBC_PRINTER_SHARE;
308 dirent_type = SMBC_COMMS_SHARE;
313 dirent_type = SMBC_IPC_SHARE;
317 dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
322 dirent_type = dir->dir_type;
325 if (add_dirent(dir, name, comment, dirent_type) < 0) {
326 /* An error occurred, what do we do? */
327 /* FIXME: Add some code here */
328 /* Change cli_NetServerEnum to take a fn
329 returning NTSTATUS... JRA. */
334 dir_list_fn(const char *mnt,
335 struct file_info *finfo,
339 SMBCFILE *dirp = (SMBCFILE *)state;
342 if (add_dirent((SMBCFILE *)state, finfo->name, "",
343 (finfo->mode&FILE_ATTRIBUTE_DIRECTORY?SMBC_DIR:SMBC_FILE)) < 0) {
344 SMBCFILE *dir = (SMBCFILE *)state;
345 return map_nt_error_from_unix(dir->dir_error);
347 ret = add_dirplus(dirp, finfo);
349 return map_nt_error_from_unix(dirp->dir_error);
355 net_share_enum_rpc(struct cli_state *cli,
356 void (*fn)(const char *name,
364 uint32_t preferred_len = 0xffffffff;
366 struct srvsvc_NetShareInfoCtr info_ctr;
367 struct srvsvc_NetShareCtr1 ctr1;
369 fstring comment = "";
370 struct rpc_pipe_client *pipe_hnd = NULL;
372 uint32_t resume_handle = 0;
373 uint32_t total_entries = 0;
374 struct dcerpc_binding_handle *b;
376 /* Open the server service pipe */
377 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc,
379 if (!NT_STATUS_IS_OK(nt_status)) {
380 DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
384 ZERO_STRUCT(info_ctr);
388 info_ctr.ctr.ctr1 = &ctr1;
390 b = pipe_hnd->binding_handle;
392 /* Issue the NetShareEnum RPC call and retrieve the response */
393 nt_status = dcerpc_srvsvc_NetShareEnumAll(b, talloc_tos(),
401 /* Was it successful? */
402 if (!NT_STATUS_IS_OK(nt_status)) {
403 /* Nope. Go clean up. */
407 if (!W_ERROR_IS_OK(result)) {
408 /* Nope. Go clean up. */
409 nt_status = werror_to_ntstatus(result);
413 if (total_entries == 0) {
414 /* Nope. Go clean up. */
415 nt_status = NT_STATUS_NOT_FOUND;
419 /* For each returned entry... */
420 for (i = 0; i < info_ctr.ctr.ctr1->count; i++) {
422 /* pull out the share name */
423 fstrcpy(name, info_ctr.ctr.ctr1->array[i].name);
425 /* pull out the share's comment */
426 fstrcpy(comment, info_ctr.ctr.ctr1->array[i].comment);
428 /* Get the type value */
429 type = info_ctr.ctr.ctr1->array[i].type;
431 /* Add this share to the list */
432 (*fn)(name, type, comment, state);
436 /* Close the server service pipe */
437 TALLOC_FREE(pipe_hnd);
439 /* Tell 'em if it worked */
445 * Verify that the options specified in a URL are valid
448 SMBC_check_options(char *server,
453 DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' "
454 "path='%s' options='%s'\n",
455 server, share, path, options));
457 /* No options at all is always ok */
458 if (! *options) return 0;
460 /* Currently, we don't support any options. */
466 SMBC_opendir_ctx(SMBCCTX *context,
473 char *password = NULL;
474 char *options = NULL;
475 char *workgroup = NULL;
480 SMBCFILE *dir = NULL;
481 struct sockaddr_storage rem_ss;
482 TALLOC_CTX *frame = talloc_stackframe();
484 if (!context || !context->internal->initialized) {
485 DEBUG(4, ("no valid context\n"));
487 errno = EINVAL + 8192;
493 DEBUG(4, ("no valid fname\n"));
495 errno = EINVAL + 8193;
499 if (SMBC_parse_path(frame,
510 DEBUG(4, ("no valid path\n"));
512 errno = EINVAL + 8194;
516 DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
517 "path='%s' options='%s'\n",
518 fname, server, share, path, options));
520 /* Ensure the options are valid */
521 if (SMBC_check_options(server, share, path, options)) {
522 DEBUG(4, ("unacceptable options (%s)\n", options));
524 errno = EINVAL + 8195;
528 if (!user || user[0] == (char)0) {
529 user = talloc_strdup(frame, smbc_getUser(context));
537 dir = SMB_MALLOC_P(SMBCFILE);
548 dir->fname = SMB_STRDUP(fname);
549 if (dir->fname == NULL) {
558 dir->dir_list = dir->dir_next = dir->dir_end = NULL;
560 if (server[0] == (char)0) {
565 struct sockaddr_storage *ip_list;
566 struct sockaddr_storage server_addr;
567 struct user_auth_info *u_info;
570 if (share[0] != (char)0 || path[0] != (char)0) {
573 SAFE_FREE(dir->fname);
577 errno = EINVAL + 8196;
581 /* Determine how many local master browsers to query */
582 max_lmb_count = (smbc_getOptionBrowseMaxLmbCount(context) == 0
584 : smbc_getOptionBrowseMaxLmbCount(context));
586 u_info = user_auth_info_init(frame);
587 if (u_info == NULL) {
589 SAFE_FREE(dir->fname);
596 set_cmdline_auth_info_username(u_info, user);
597 set_cmdline_auth_info_password(u_info, password);
600 * We have server and share and path empty but options
601 * requesting that we scan all master browsers for their list
602 * of workgroups/domains. This implies that we must first try
603 * broadcast queries to find all master browsers, and if that
604 * doesn't work, then try our other methods which return only
605 * a single master browser.
609 status = name_resolve_bcast(MSBROWSE, 1, talloc_tos(),
611 if (!NT_STATUS_IS_OK(status))
614 TALLOC_FREE(ip_list);
616 if (!find_master_ip(workgroup, &server_addr)) {
619 SAFE_FREE(dir->fname);
627 ip_list = (struct sockaddr_storage *)talloc_memdup(
628 talloc_tos(), &server_addr,
629 sizeof(server_addr));
630 if (ip_list == NULL) {
632 SAFE_FREE(dir->fname);
642 for (i = 0; i < count && i < max_lmb_count; i++) {
643 char addr[INET6_ADDRSTRLEN];
645 struct cli_state *cli = NULL;
647 print_sockaddr(addr, sizeof(addr), &ip_list[i]);
648 DEBUG(99, ("Found master browser %d of %d: %s\n",
649 i+1, MAX(count, max_lmb_count),
652 cli = get_ipc_connect_master_ip(talloc_tos(),
656 /* cli == NULL is the master browser refused to talk or
657 could not be found */
662 workgroup = talloc_strdup(frame, wg_ptr);
663 server = talloc_strdup(frame, smbXcli_conn_remote_name(cli->conn));
667 if (!workgroup || !server) {
669 SAFE_FREE(dir->fname);
677 DEBUG(4, ("using workgroup %s %s\n",
681 * For each returned master browser IP address, get a
682 * connection to IPC$ on the server if we do not
683 * already have one, and determine the
684 * workgroups/domains that it knows about.
687 srv = SMBC_server(frame, context, True, server, port, "IPC$",
688 &workgroup, &user, &password);
693 if (smbXcli_conn_protocol(srv->cli->conn) > PROTOCOL_NT1) {
698 dir->dir_type = SMBC_WORKGROUP;
700 /* Now, list the stuff ... */
702 if (!cli_NetServerEnum(srv->cli,
711 TALLOC_FREE(ip_list);
714 * Server not an empty string ... Check the rest and see what
717 if (*share == '\0') {
720 /* Should not have empty share with path */
722 SAFE_FREE(dir->fname);
726 errno = EINVAL + 8197;
732 * We don't know if <server> is really a server name
733 * or is a workgroup/domain name. If we already have
734 * a server structure for it, we'll use it.
735 * Otherwise, check to see if <server><1D>,
736 * <server><1B>, or <server><20> translates. We check
737 * to see if <server> is an IP address first.
741 * See if we have an existing server. Do not
742 * establish a connection if one does not already
745 srv = SMBC_server(frame, context, False,
746 server, port, "IPC$",
747 &workgroup, &user, &password);
750 * If no existing server and not an IP addr, look for
754 !is_ipaddress(server) &&
755 (resolve_name(server, &rem_ss, 0x1d, false) || /* LMB */
756 resolve_name(server, &rem_ss, 0x1b, false) )) { /* DMB */
758 * "server" is actually a workgroup name,
759 * not a server. Make this clear.
761 char *wgroup = server;
764 dir->dir_type = SMBC_SERVER;
767 * Get the backup list ...
769 if (!name_status_find(wgroup, 0, 0,
770 &rem_ss, buserver)) {
771 char addr[INET6_ADDRSTRLEN];
773 print_sockaddr(addr, sizeof(addr), &rem_ss);
774 DEBUG(0,("Could not get name of "
775 "local/domain master browser "
776 "for workgroup %s from "
781 SAFE_FREE(dir->fname);
791 * Get a connection to IPC$ on the server if
792 * we do not already have one
794 srv = SMBC_server(frame, context, True,
795 buserver, port, "IPC$",
799 DEBUG(0, ("got no contact to IPC$\n"));
801 SAFE_FREE(dir->fname);
811 if (smbXcli_conn_protocol(srv->cli->conn) > PROTOCOL_NT1) {
813 SAFE_FREE(dir->fname);
820 /* Now, list the servers ... */
821 if (!cli_NetServerEnum(srv->cli, wgroup,
826 SAFE_FREE(dir->fname);
833 (resolve_name(server, &rem_ss, 0x20, false))) {
837 * If we hadn't found the server, get one now
840 srv = SMBC_server(frame, context, True,
841 server, port, "IPC$",
848 SAFE_FREE(dir->fname);
856 dir->dir_type = SMBC_FILE_SHARE;
859 /* List the shares ... */
861 status = net_share_enum_rpc(srv->cli,
864 if (!NT_STATUS_IS_OK(status) &&
865 smbXcli_conn_protocol(srv->cli->conn) <=
868 * Only call cli_RNetShareEnum()
869 * on SMB1 connections, not SMB2+.
871 int rc = cli_RNetShareEnum(srv->cli,
875 status = cli_nt_error(srv->cli);
877 status = NT_STATUS_OK;
880 if (!NT_STATUS_IS_OK(status)) {
882 * Set cli->raw_status so SMBC_errno()
883 * will correctly return the error.
885 srv->cli->raw_status = status;
887 SAFE_FREE(dir->fname);
891 errno = map_errno_from_nt_status(
896 /* Neither the workgroup nor server exists */
897 errno = ECONNREFUSED;
899 SAFE_FREE(dir->fname);
909 * The server and share are specified ... work from
913 struct cli_state *targetcli;
916 /* We connect to the server and list the directory */
917 dir->dir_type = SMBC_FILE_SHARE;
919 srv = SMBC_server(frame, context, True, server, port, share,
920 &workgroup, &user, &password);
924 SAFE_FREE(dir->fname);
933 /* Now, list the files ... */
935 path_len = strlen(path);
936 path = talloc_asprintf_append(path, "\\*");
939 SAFE_FREE(dir->fname);
946 status = cli_resolve_path(
947 frame, "", context->internal->auth_info,
948 srv->cli, path, &targetcli, &targetpath);
949 if (!NT_STATUS_IS_OK(status)) {
950 d_printf("Could not resolve %s\n", path);
952 SAFE_FREE(dir->fname);
959 status = cli_list(targetcli, targetpath,
960 FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
961 dir_list_fn, (void *)dir);
962 if (!NT_STATUS_IS_OK(status)) {
964 SAFE_FREE(dir->fname);
967 saved_errno = SMBC_errno(context, targetcli);
969 if (saved_errno == EINVAL) {
970 struct stat sb = {0};
972 * See if they asked to opendir
973 * something other than a directory.
974 * If so, the converted error value we
975 * got would have been EINVAL rather
978 path[path_len] = '\0'; /* restore original path */
980 if (SMBC_getatr(context,
984 !S_ISDIR(sb.st_mode)) {
986 /* It is. Correct the error value */
987 saved_errno = ENOTDIR;
992 * If there was an error and the server is no
995 if (cli_is_error(targetcli) &&
996 smbc_getFunctionCheckServer(context)(context, srv)) {
998 /* ... then remove it. */
999 if (smbc_getFunctionRemoveUnusedServer(context)(context,
1002 * We could not remove the
1003 * server completely, remove
1004 * it from the cache so we
1005 * will not get it again. It
1006 * will be removed when the
1007 * last file/dir is closed.
1009 smbc_getFunctionRemoveCachedServer(context)(context, srv);
1014 errno = saved_errno;
1021 DLIST_ADD(context->internal->files, dir);
1028 * Routine to close a directory
1032 SMBC_closedir_ctx(SMBCCTX *context,
1035 TALLOC_CTX *frame = talloc_stackframe();
1037 if (!context || !context->internal->initialized) {
1043 if (!SMBC_dlist_contains(context->internal->files, dir)) {
1049 remove_dir(dir); /* Clean it up */
1050 remove_dirplus(dir);
1052 DLIST_REMOVE(context->internal->files, dir);
1056 SAFE_FREE(dir->fname);
1057 SAFE_FREE(dir); /* Free the space too */
1066 smbc_readdir_internal(SMBCCTX * context,
1067 struct smbc_dirent *dest,
1068 struct smbc_dirent *src,
1069 int max_namebuf_len)
1071 if (smbc_getOptionUrlEncodeReaddirEntries(context)) {
1074 /* url-encode the name. get back remaining buffer space */
1076 smbc_urlencode(dest->name, src->name, max_namebuf_len);
1078 /* -1 means no null termination. */
1079 if (remaining_len < 0) {
1083 /* We now know the name length */
1084 dest->namelen = strlen(dest->name);
1086 if (dest->namelen + 1 < 1) {
1091 if (dest->namelen + 1 >= max_namebuf_len) {
1092 /* Out of space for comment. */
1096 /* Save the pointer to the beginning of the comment */
1097 dest->comment = dest->name + dest->namelen + 1;
1099 if (remaining_len < 1) {
1100 /* No room for comment null termination. */
1104 /* Copy the comment */
1105 strlcpy(dest->comment, src->comment, remaining_len);
1107 /* Save other fields */
1108 dest->smbc_type = src->smbc_type;
1109 dest->commentlen = strlen(dest->comment);
1110 dest->dirlen = ((dest->comment + dest->commentlen + 1) -
1114 /* No encoding. Just copy the entry as is. */
1115 if (src->dirlen > max_namebuf_len) {
1118 memcpy(dest, src, src->dirlen);
1119 if (src->namelen + 1 < 1) {
1123 if (src->namelen + 1 >= max_namebuf_len) {
1124 /* Comment off the end. */
1127 dest->comment = (char *)(&dest->name + src->namelen + 1);
1133 * Routine to get a directory entry
1136 struct smbc_dirent *
1137 SMBC_readdir_ctx(SMBCCTX *context,
1142 struct smbc_dirent *dirp, *dirent;
1143 TALLOC_CTX *frame = talloc_stackframe();
1145 /* Check that all is ok first ... */
1147 if (!context || !context->internal->initialized) {
1150 DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n"));
1156 if (!SMBC_dlist_contains(context->internal->files, dir)) {
1159 DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n"));
1165 if (dir->file != False) { /* FIXME, should be dir, perhaps */
1168 DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n"));
1174 if (!dir->dir_next) {
1179 dirent = dir->dir_next->dirent;
1188 dirp = &context->internal->dirent;
1189 maxlen = sizeof(context->internal->_dirent_name);
1191 ret = smbc_readdir_internal(context, dirp, dirent, maxlen);
1198 dir->dir_next = dir->dir_next->next;
1201 * If we are returning file entries, we
1202 * have a duplicate list in dirplus.
1204 * Update dirplus_next also so readdir and
1205 * readdirplus are kept in sync.
1207 if (dir->dirplus_list != NULL) {
1208 dir->dirplus_next = dir->dirplus_next->next;
1216 * Routine to get a directory entry with all attributes
1219 const struct libsmb_file_info *
1220 SMBC_readdirplus_ctx(SMBCCTX *context,
1223 struct libsmb_file_info *smb_finfo = NULL;
1224 TALLOC_CTX *frame = talloc_stackframe();
1226 /* Check that all is ok first ... */
1228 if (context == NULL || !context->internal->initialized) {
1229 DBG_ERR("Invalid context in SMBC_readdirplus_ctx()\n");
1235 if (!SMBC_dlist_contains(context->internal->files, dir)) {
1236 DBG_ERR("Invalid dir in SMBC_readdirplus_ctx()\n");
1242 if (dir->dirplus_next == NULL) {
1247 smb_finfo = dir->dirplus_next->smb_finfo;
1248 if (smb_finfo == NULL) {
1253 dir->dirplus_next = dir->dirplus_next->next;
1256 * If we are returning file entries, we
1257 * have a duplicate list in dir_list
1259 * Update dir_next also so readdir and
1260 * readdirplus are kept in sync.
1262 if (dir->dir_list) {
1263 dir->dir_next = dir->dir_next->next;
1271 * Routine to get a directory entry plus a filled in stat structure if
1275 const struct libsmb_file_info *SMBC_readdirplus2_ctx(SMBCCTX *context,
1279 struct libsmb_file_info *smb_finfo = NULL;
1280 struct smbc_dirplus_list *dp_list = NULL;
1282 char *full_pathname = NULL;
1283 char *workgroup = NULL;
1284 char *server = NULL;
1289 char *password = NULL;
1290 char *options = NULL;
1292 TALLOC_CTX *frame = NULL;
1295 * Allow caller to pass in NULL for stat pointer if
1296 * required. This makes this call identical to
1297 * smbc_readdirplus().
1301 return SMBC_readdirplus_ctx(context, dir);
1304 frame = talloc_stackframe();
1306 /* Check that all is ok first ... */
1307 if (context == NULL || !context->internal->initialized) {
1308 DBG_ERR("Invalid context in SMBC_readdirplus2_ctx()\n");
1314 if (!SMBC_dlist_contains(context->internal->files, dir)) {
1315 DBG_ERR("Invalid dir in SMBC_readdirplus2_ctx()\n");
1321 dp_list = dir->dirplus_next;
1322 if (dp_list == NULL) {
1327 ino = (ino_t)dp_list->ino;
1329 smb_finfo = dp_list->smb_finfo;
1330 if (smb_finfo == NULL) {
1336 full_pathname = talloc_asprintf(frame,
1340 if (full_pathname == NULL) {
1346 rc = SMBC_parse_path(frame,
1369 smb_finfo->atime_ts,
1370 smb_finfo->ctime_ts,
1371 smb_finfo->mtime_ts);
1373 TALLOC_FREE(full_pathname);
1375 dir->dirplus_next = dir->dirplus_next->next;
1378 * If we are returning file entries, we
1379 * have a duplicate list in dir_list
1381 * Update dir_next also so readdir and
1382 * readdirplus are kept in sync.
1384 if (dir->dir_list) {
1385 dir->dir_next = dir->dir_next->next;
1393 * Routine to get directory entries
1397 SMBC_getdents_ctx(SMBCCTX *context,
1399 struct smbc_dirent *dirp,
1405 char *ndir = (char *)dirp;
1406 struct smbc_dir_list *dirlist;
1407 TALLOC_CTX *frame = talloc_stackframe();
1409 /* Check that all is ok first ... */
1411 if (!context || !context->internal->initialized) {
1419 if (!SMBC_dlist_contains(context->internal->files, dir)) {
1427 if (dir->file != False) { /* FIXME, should be dir, perhaps */
1436 * Now, retrieve the number of entries that will fit in what was passed
1437 * We have to figure out if the info is in the list, or we need to
1438 * send a request to the server to get the info.
1441 while ((dirlist = dir->dir_next)) {
1443 struct smbc_dirent *dirent;
1444 struct smbc_dirent *currentEntry = (struct smbc_dirent *)ndir;
1446 if (!dirlist->dirent) {
1448 errno = ENOENT; /* Bad error */
1454 /* Do urlencoding of next entry, if so selected */
1455 dirent = &context->internal->dirent;
1456 maxlen = sizeof(context->internal->_dirent_name);
1457 ret = smbc_readdir_internal(context, dirent,
1458 dirlist->dirent, maxlen);
1465 reqd = dirent->dirlen;
1469 if (rem < count) { /* We managed to copy something */
1476 else { /* Nothing copied ... */
1478 errno = EINVAL; /* Not enough space ... */
1486 memcpy(currentEntry, dirent, reqd); /* Copy the data in ... */
1488 currentEntry->comment = ¤tEntry->name[0] +
1489 dirent->namelen + 1;
1494 /* Try and align the struct for the next entry
1495 on a valid pointer boundary by appending zeros */
1496 while((rem > 0) && ((uintptr_t)ndir & (sizeof(void*) - 1))) {
1500 currentEntry->dirlen++;
1503 dir->dir_next = dirlist = dirlist -> next;
1506 * If we are returning file entries, we
1507 * have a duplicate list in dirplus.
1509 * Update dirplus_next also so readdir and
1510 * readdirplus are kept in sync.
1512 if (dir->dirplus_list != NULL) {
1513 dir->dirplus_next = dir->dirplus_next->next;
1527 * Routine to create a directory ...
1531 SMBC_mkdir_ctx(SMBCCTX *context,
1535 SMBCSRV *srv = NULL;
1536 char *server = NULL;
1539 char *password = NULL;
1540 char *workgroup = NULL;
1542 char *targetpath = NULL;
1544 struct cli_state *targetcli = NULL;
1545 TALLOC_CTX *frame = talloc_stackframe();
1548 if (!context || !context->internal->initialized) {
1560 DEBUG(4, ("smbc_mkdir(%s)\n", fname));
1562 if (SMBC_parse_path(frame,
1578 if (!user || user[0] == (char)0) {
1579 user = talloc_strdup(frame, smbc_getUser(context));
1587 srv = SMBC_server(frame, context, True,
1588 server, port, share, &workgroup, &user, &password);
1593 return -1; /* errno set by SMBC_server */
1597 /*d_printf(">>>mkdir: resolving %s\n", path);*/
1598 status = cli_resolve_path(frame, "", context->internal->auth_info,
1599 srv->cli, path, &targetcli, &targetpath);
1600 if (!NT_STATUS_IS_OK(status)) {
1601 d_printf("Could not resolve %s\n", path);
1606 /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
1608 if (!NT_STATUS_IS_OK(cli_mkdir(targetcli, targetpath))) {
1609 errno = SMBC_errno(context, targetcli);
1621 * Our list function simply checks to see if a directory is not empty
1625 rmdir_list_fn(const char *mnt,
1626 struct file_info *finfo,
1630 if (strncmp(finfo->name, ".", 1) != 0 &&
1631 strncmp(finfo->name, "..", 2) != 0) {
1632 bool *smbc_rmdir_dirempty = (bool *)state;
1633 *smbc_rmdir_dirempty = false;
1635 return NT_STATUS_OK;
1639 * Routine to remove a directory
1643 SMBC_rmdir_ctx(SMBCCTX *context,
1646 SMBCSRV *srv = NULL;
1647 char *server = NULL;
1650 char *password = NULL;
1651 char *workgroup = NULL;
1653 char *targetpath = NULL;
1655 struct cli_state *targetcli = NULL;
1656 TALLOC_CTX *frame = talloc_stackframe();
1659 if (!context || !context->internal->initialized) {
1671 DEBUG(4, ("smbc_rmdir(%s)\n", fname));
1673 if (SMBC_parse_path(frame,
1689 if (!user || user[0] == (char)0) {
1690 user = talloc_strdup(frame, smbc_getUser(context));
1698 srv = SMBC_server(frame, context, True,
1699 server, port, share, &workgroup, &user, &password);
1704 return -1; /* errno set by SMBC_server */
1708 /*d_printf(">>>rmdir: resolving %s\n", path);*/
1709 status = cli_resolve_path(frame, "", context->internal->auth_info,
1710 srv->cli, path, &targetcli, &targetpath);
1711 if (!NT_STATUS_IS_OK(status)) {
1712 d_printf("Could not resolve %s\n", path);
1717 /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
1719 if (!NT_STATUS_IS_OK(cli_rmdir(targetcli, targetpath))) {
1721 errno = SMBC_errno(context, targetcli);
1723 if (errno == EACCES) { /* Check if the dir empty or not */
1725 /* Local storage to avoid buffer overflows */
1727 bool smbc_rmdir_dirempty = true;
1729 lpath = talloc_asprintf(frame, "%s\\*",
1737 status = cli_list(targetcli, lpath,
1738 FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
1740 &smbc_rmdir_dirempty);
1742 if (!NT_STATUS_IS_OK(status)) {
1743 /* Fix errno to ignore latest error ... */
1744 DEBUG(5, ("smbc_rmdir: "
1745 "cli_list returned an error: %d\n",
1746 SMBC_errno(context, targetcli)));
1751 if (smbc_rmdir_dirempty)
1769 * Routine to return the current directory position
1773 SMBC_telldir_ctx(SMBCCTX *context,
1776 TALLOC_CTX *frame = talloc_stackframe();
1778 if (!context || !context->internal->initialized) {
1786 if (!SMBC_dlist_contains(context->internal->files, dir)) {
1794 if (dir->file != False) { /* FIXME, should be dir, perhaps */
1802 /* See if we're already at the end. */
1803 if (dir->dir_next == NULL) {
1810 * We return the pointer here as the offset
1813 return (off_t)(long)dir->dir_next->dirent;
1817 * A routine to run down the list and see if the entry is OK
1818 * Modifies the dir list and the dirplus list (if it exists)
1819 * to point at the correct next entry on success.
1822 static bool update_dir_ents(SMBCFILE *dir, struct smbc_dirent *dirent)
1824 struct smbc_dir_list *tmp_dir = dir->dir_list;
1825 struct smbc_dirplus_list *tmp_dirplus = dir->dirplus_list;
1828 * Run down the list looking for what we want.
1829 * If we're enumerating files both dir_list
1830 * and dirplus_list contain the same entry
1831 * list, as they were seeded from the same
1832 * cli_list callback.
1834 * If we're enumerating servers then
1835 * dirplus_list will be NULL, so don't
1836 * update in that case.
1839 while (tmp_dir != NULL) {
1840 if (tmp_dir->dirent == dirent) {
1841 dir->dir_next = tmp_dir;
1842 if (tmp_dirplus != NULL) {
1843 dir->dirplus_next = tmp_dirplus;
1847 tmp_dir = tmp_dir->next;
1848 if (tmp_dirplus != NULL) {
1849 tmp_dirplus = tmp_dirplus->next;
1856 * Routine to seek on a directory
1860 SMBC_lseekdir_ctx(SMBCCTX *context,
1864 long int l_offset = offset; /* Handle problems of size */
1865 struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
1866 TALLOC_CTX *frame = talloc_stackframe();
1869 if (!context || !context->internal->initialized) {
1877 if (dir->file != False) { /* FIXME, should be dir, perhaps */
1885 /* Now, check what we were passed and see if it is OK ... */
1887 if (dirent == NULL) { /* Seek to the begining of the list */
1889 dir->dir_next = dir->dir_list;
1891 /* Do the same for dirplus. */
1892 dir->dirplus_next = dir->dirplus_list;
1899 if (offset == -1) { /* Seek to the end of the list */
1900 dir->dir_next = NULL;
1902 /* Do the same for dirplus. */
1903 dir->dirplus_next = NULL;
1910 * Run down the list and make sure that the entry is OK.
1911 * Update the position of both dir and dirplus lists.
1914 ok = update_dir_ents(dir, dirent);
1916 errno = EINVAL; /* Bad entry */
1926 * Routine to fstat a dir
1930 SMBC_fstatdir_ctx(SMBCCTX *context,
1935 if (!context || !context->internal->initialized) {
1941 /* No code yet ... */
1946 SMBC_chmod_ctx(SMBCCTX *context,
1950 SMBCSRV *srv = NULL;
1951 char *server = NULL;
1954 char *password = NULL;
1955 char *workgroup = NULL;
1956 char *targetpath = NULL;
1957 struct cli_state *targetcli = NULL;
1961 TALLOC_CTX *frame = talloc_stackframe();
1964 if (!context || !context->internal->initialized) {
1966 errno = EINVAL; /* Best I can think of ... */
1977 DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, (unsigned int)newmode));
1979 if (SMBC_parse_path(frame,
1995 if (!user || user[0] == (char)0) {
1996 user = talloc_strdup(frame, smbc_getUser(context));
2004 srv = SMBC_server(frame, context, True,
2005 server, port, share, &workgroup, &user, &password);
2009 return -1; /* errno set by SMBC_server */
2012 /*d_printf(">>>unlink: resolving %s\n", path);*/
2013 status = cli_resolve_path(frame, "", context->internal->auth_info,
2014 srv->cli, path, &targetcli, &targetpath);
2015 if (!NT_STATUS_IS_OK(status)) {
2016 d_printf("Could not resolve %s\n", path);
2024 if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= FILE_ATTRIBUTE_READONLY;
2025 if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= FILE_ATTRIBUTE_ARCHIVE;
2026 if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= FILE_ATTRIBUTE_SYSTEM;
2027 if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= FILE_ATTRIBUTE_HIDDEN;
2029 if (!NT_STATUS_IS_OK(cli_setatr(targetcli, targetpath, mode, 0))) {
2030 errno = SMBC_errno(context, targetcli);
2040 SMBC_utimes_ctx(SMBCCTX *context,
2042 struct timeval *tbuf)
2044 SMBCSRV *srv = NULL;
2045 char *server = NULL;
2048 char *password = NULL;
2049 char *workgroup = NULL;
2054 TALLOC_CTX *frame = talloc_stackframe();
2056 if (!context || !context->internal->initialized) {
2058 errno = EINVAL; /* Best I can think of ... */
2070 access_time = write_time = time(NULL);
2072 access_time = tbuf[0].tv_sec;
2073 write_time = tbuf[1].tv_sec;
2081 strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1);
2082 atimebuf[sizeof(atimebuf) - 1] = '\0';
2083 if ((p = strchr(atimebuf, '\n')) != NULL) {
2087 strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1);
2088 mtimebuf[sizeof(mtimebuf) - 1] = '\0';
2089 if ((p = strchr(mtimebuf, '\n')) != NULL) {
2093 dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
2094 fname, atimebuf, mtimebuf);
2097 if (SMBC_parse_path(frame,
2113 if (!user || user[0] == (char)0) {
2114 user = talloc_strdup(frame, smbc_getUser(context));
2122 srv = SMBC_server(frame, context, True,
2123 server, port, share, &workgroup, &user, &password);
2127 return -1; /* errno set by SMBC_server */
2130 if (!SMBC_setatr(context, srv, path,
2131 0, access_time, write_time, 0, 0)) {
2133 return -1; /* errno set by SMBC_setatr */
2141 * Routine to unlink() a file
2145 SMBC_unlink_ctx(SMBCCTX *context,
2148 char *server = NULL;
2151 char *password = NULL;
2152 char *workgroup = NULL;
2154 char *targetpath = NULL;
2156 struct cli_state *targetcli = NULL;
2157 SMBCSRV *srv = NULL;
2158 TALLOC_CTX *frame = talloc_stackframe();
2161 if (!context || !context->internal->initialized) {
2163 errno = EINVAL; /* Best I can think of ... */
2176 if (SMBC_parse_path(frame,
2192 if (!user || user[0] == (char)0) {
2193 user = talloc_strdup(frame, smbc_getUser(context));
2201 srv = SMBC_server(frame, context, True,
2202 server, port, share, &workgroup, &user, &password);
2206 return -1; /* SMBC_server sets errno */
2210 /*d_printf(">>>unlink: resolving %s\n", path);*/
2211 status = cli_resolve_path(frame, "", context->internal->auth_info,
2212 srv->cli, path, &targetcli, &targetpath);
2213 if (!NT_STATUS_IS_OK(status)) {
2214 d_printf("Could not resolve %s\n", path);
2219 /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
2221 if (!NT_STATUS_IS_OK(cli_unlink(targetcli, targetpath, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))) {
2223 errno = SMBC_errno(context, targetcli);
2225 if (errno == EACCES) { /* Check if the file is a directory */
2228 struct stat sb = {0};
2231 ok = SMBC_getatr(context, srv, path, &sb);
2233 /* Hmmm, bad error ... What? */
2235 errno = SMBC_errno(context, targetcli);
2242 if (S_ISDIR(sb.st_mode))
2245 errno = saverr; /* Restore this */
2256 return 0; /* Success ... */
2261 * Routine to rename() a file
2265 SMBC_rename_ctx(SMBCCTX *ocontext,
2270 char *server1 = NULL;
2271 char *share1 = NULL;
2272 char *server2 = NULL;
2273 char *share2 = NULL;
2276 char *password1 = NULL;
2277 char *password2 = NULL;
2278 char *workgroup = NULL;
2281 char *targetpath1 = NULL;
2282 char *targetpath2 = NULL;
2283 struct cli_state *targetcli1 = NULL;
2284 struct cli_state *targetcli2 = NULL;
2285 SMBCSRV *srv = NULL;
2288 TALLOC_CTX *frame = talloc_stackframe();
2291 if (!ocontext || !ncontext ||
2292 !ocontext->internal->initialized ||
2293 !ncontext->internal->initialized) {
2295 errno = EINVAL; /* Best I can think of ... */
2300 if (!oname || !nname) {
2306 DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
2308 if (SMBC_parse_path(frame,
2324 if (!user1 || user1[0] == (char)0) {
2325 user1 = talloc_strdup(frame, smbc_getUser(ocontext));
2333 if (SMBC_parse_path(frame,
2349 if (!user2 || user2[0] == (char)0) {
2350 user2 = talloc_strdup(frame, smbc_getUser(ncontext));
2358 if (strcmp(server1, server2) || strcmp(share1, share2) ||
2359 strcmp(user1, user2)) {
2360 /* Can't rename across file systems, or users?? */
2366 srv = SMBC_server(frame, ocontext, True,
2367 server1, port1, share1, &workgroup, &user1, &password1);
2374 /* set the credentials to make DFS work */
2375 smbc_set_credentials_with_fallback(ocontext,
2380 /*d_printf(">>>rename: resolving %s\n", path1);*/
2381 status = cli_resolve_path(frame, "", ocontext->internal->auth_info,
2382 srv->cli, path1, &targetcli1, &targetpath1);
2383 if (!NT_STATUS_IS_OK(status)) {
2384 d_printf("Could not resolve %s\n", path1);
2390 /* set the credentials to make DFS work */
2391 smbc_set_credentials_with_fallback(ncontext,
2396 /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
2397 /*d_printf(">>>rename: resolving %s\n", path2);*/
2398 status = cli_resolve_path(frame, "", ncontext->internal->auth_info,
2399 srv->cli, path2, &targetcli2, &targetpath2);
2400 if (!NT_STATUS_IS_OK(status)) {
2401 d_printf("Could not resolve %s\n", path2);
2406 /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
2408 if (strcmp(smbXcli_conn_remote_name(targetcli1->conn), smbXcli_conn_remote_name(targetcli2->conn)) ||
2409 strcmp(targetcli1->share, targetcli2->share))
2411 /* can't rename across file systems */
2417 if (!NT_STATUS_IS_OK(
2418 cli_rename(targetcli1, targetpath1, targetpath2, false))) {
2419 int eno = SMBC_errno(ocontext, targetcli1);
2421 if (eno != EEXIST ||
2422 !NT_STATUS_IS_OK(cli_unlink(targetcli1, targetpath2,
2423 FILE_ATTRIBUTE_SYSTEM |
2424 FILE_ATTRIBUTE_HIDDEN)) ||
2425 !NT_STATUS_IS_OK(cli_rename(targetcli1, targetpath1,
2426 targetpath2, false))) {
2436 return 0; /* Success */
2439 struct smbc_notify_cb_state {
2440 struct tevent_context *ev;
2441 struct cli_state *cli;
2444 uint32_t completion_filter;
2445 unsigned callback_timeout_ms;
2446 smbc_notify_callback_fn cb;
2450 static void smbc_notify_cb_got_changes(struct tevent_req *subreq);
2451 static void smbc_notify_cb_timedout(struct tevent_req *subreq);
2453 static struct tevent_req *smbc_notify_cb_send(
2454 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
2455 uint16_t fnum, bool recursive, uint32_t completion_filter,
2456 unsigned callback_timeout_ms,
2457 smbc_notify_callback_fn cb, void *private_data)
2459 struct tevent_req *req, *subreq;
2460 struct smbc_notify_cb_state *state;
2462 req = tevent_req_create(mem_ctx, &state, struct smbc_notify_cb_state);
2469 state->recursive = recursive;
2470 state->completion_filter = completion_filter;
2471 state->callback_timeout_ms = callback_timeout_ms;
2473 state->private_data = private_data;
2475 subreq = cli_notify_send(
2476 state, state->ev, state->cli, state->fnum, 1000,
2477 state->completion_filter, state->recursive);
2478 if (tevent_req_nomem(subreq, req)) {
2479 return tevent_req_post(req, ev);
2481 tevent_req_set_callback(subreq, smbc_notify_cb_got_changes, req);
2483 if (state->callback_timeout_ms == 0) {
2487 subreq = tevent_wakeup_send(
2489 tevent_timeval_current_ofs(state->callback_timeout_ms/1000,
2490 state->callback_timeout_ms*1000));
2491 if (tevent_req_nomem(subreq, req)) {
2492 return tevent_req_post(req, ev);
2494 tevent_req_set_callback(subreq, smbc_notify_cb_timedout, req);
2499 static void smbc_notify_cb_got_changes(struct tevent_req *subreq)
2501 struct tevent_req *req = tevent_req_callback_data(
2502 subreq, struct tevent_req);
2503 struct smbc_notify_cb_state *state = tevent_req_data(
2504 req, struct smbc_notify_cb_state);
2505 uint32_t num_changes;
2506 struct notify_change *changes;
2510 status = cli_notify_recv(subreq, state, &num_changes, &changes);
2511 TALLOC_FREE(subreq);
2512 if (tevent_req_nterror(req, status)) {
2517 struct smbc_notify_callback_action actions[num_changes];
2520 for (i=0; i<num_changes; i++) {
2521 actions[i].action = changes[i].action;
2522 actions[i].filename = changes[i].name;
2525 cb_ret = state->cb(actions, num_changes, state->private_data);
2528 TALLOC_FREE(changes);
2531 tevent_req_done(req);
2535 subreq = cli_notify_send(
2536 state, state->ev, state->cli, state->fnum, 1000,
2537 state->completion_filter, state->recursive);
2538 if (tevent_req_nomem(subreq, req)) {
2541 tevent_req_set_callback(subreq, smbc_notify_cb_got_changes, req);
2544 static void smbc_notify_cb_timedout(struct tevent_req *subreq)
2546 struct tevent_req *req = tevent_req_callback_data(
2547 subreq, struct tevent_req);
2548 struct smbc_notify_cb_state *state = tevent_req_data(
2549 req, struct smbc_notify_cb_state);
2553 ok = tevent_wakeup_recv(subreq);
2554 TALLOC_FREE(subreq);
2556 tevent_req_oom(req);
2560 cb_ret = state->cb(NULL, 0, state->private_data);
2562 tevent_req_done(req);
2566 subreq = tevent_wakeup_send(
2568 tevent_timeval_current_ofs(state->callback_timeout_ms/1000,
2569 state->callback_timeout_ms*1000));
2570 if (tevent_req_nomem(subreq, req)) {
2573 tevent_req_set_callback(subreq, smbc_notify_cb_timedout, req);
2576 static NTSTATUS smbc_notify_cb_recv(struct tevent_req *req)
2578 return tevent_req_simple_recv_ntstatus(req);
2581 static NTSTATUS smbc_notify_cb(struct cli_state *cli, uint16_t fnum,
2582 bool recursive, uint32_t completion_filter,
2583 unsigned callback_timeout_ms,
2584 smbc_notify_callback_fn cb, void *private_data)
2586 TALLOC_CTX *frame = talloc_stackframe();
2587 struct tevent_context *ev;
2588 struct tevent_req *req;
2589 NTSTATUS status = NT_STATUS_NO_MEMORY;
2591 ev = samba_tevent_context_init(frame);
2595 req = smbc_notify_cb_send(frame, ev, cli, fnum, recursive,
2597 callback_timeout_ms, cb, private_data);
2601 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2604 status = smbc_notify_cb_recv(req);
2612 SMBC_notify_ctx(SMBCCTX *context, SMBCFILE *dir, smbc_bool recursive,
2613 uint32_t completion_filter, unsigned callback_timeout_ms,
2614 smbc_notify_callback_fn cb, void *private_data)
2616 TALLOC_CTX *frame = talloc_stackframe();
2617 struct cli_state *cli;
2618 char *server = NULL;
2621 char *password = NULL;
2622 char *options = NULL;
2623 char *workgroup = NULL;
2629 if ((context == NULL) || !context->internal->initialized) {
2634 if (!SMBC_dlist_contains(context->internal->files, dir)) {
2640 if (SMBC_parse_path(frame,
2651 DEBUG(4, ("no valid path\n"));
2653 errno = EINVAL + 8194;
2657 DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
2658 "path='%s' options='%s'\n",
2659 dir->fname, server, share, path, options));
2661 DEBUG(4, ("%s(%p, %d, %"PRIu32")\n", __func__, dir,
2662 (int)recursive, completion_filter));
2664 cli = dir->srv->cli;
2665 status = cli_ntcreate(
2666 cli, path, 0, FILE_READ_DATA, 0,
2667 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
2668 FILE_OPEN, 0, 0, &fnum, NULL);
2669 if (!NT_STATUS_IS_OK(status)) {
2670 int err = SMBC_errno(context, cli);
2676 status = smbc_notify_cb(cli, fnum, recursive != 0, completion_filter,
2677 callback_timeout_ms, cb, private_data);
2678 if (!NT_STATUS_IS_OK(status)) {
2679 int err = SMBC_errno(context, cli);
2680 cli_close(cli, fnum);
2686 cli_close(cli, fnum);