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"
37 #include "lib/util/time_basic.h"
40 * Routine to open a directory
41 * We accept the URL syntax explained in SMBC_parse_path(), above.
44 static void remove_dirplus(SMBCFILE *dir)
46 struct smbc_dirplus_list *d = NULL;
48 d = dir->dirplus_list;
50 struct smbc_dirplus_list *f = d;
53 SAFE_FREE(f->smb_finfo->short_name);
54 SAFE_FREE(f->smb_finfo->name);
55 SAFE_FREE(f->smb_finfo);
59 dir->dirplus_list = NULL;
60 dir->dirplus_end = NULL;
61 dir->dirplus_next = NULL;
65 remove_dir(SMBCFILE *dir)
67 struct smbc_dir_list *d,*f;
79 dir->dir_list = dir->dir_end = dir->dir_next = NULL;
84 add_dirent(SMBCFILE *dir,
89 struct smbc_dirent *dirent;
91 int name_length = (name == NULL ? 0 : strlen(name));
92 int comment_len = (comment == NULL ? 0 : strlen(comment));
95 * Allocate space for the dirent, which must be increased by the
96 * size of the name and the comment and 1 each for the null terminator.
99 size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
101 dirent = (struct smbc_dirent *)SMB_MALLOC(size);
105 dir->dir_error = ENOMEM;
110 ZERO_STRUCTP(dirent);
112 if (dir->dir_list == NULL) {
114 dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
115 if (!dir->dir_list) {
118 dir->dir_error = ENOMEM;
122 ZERO_STRUCTP(dir->dir_list);
124 dir->dir_end = dir->dir_next = dir->dir_list;
128 dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
130 if (!dir->dir_end->next) {
133 dir->dir_error = ENOMEM;
137 ZERO_STRUCTP(dir->dir_end->next);
139 dir->dir_end = dir->dir_end->next;
142 dir->dir_end->next = NULL;
143 dir->dir_end->dirent = dirent;
145 dirent->smbc_type = type;
146 dirent->namelen = name_length;
147 dirent->commentlen = comment_len;
148 dirent->dirlen = size;
151 * dirent->namelen + 1 includes the null (no null termination needed)
152 * Ditto for dirent->commentlen.
153 * The space for the two null bytes was allocated.
155 strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
156 dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
157 strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
163 static int add_dirplus(SMBCFILE *dir, struct file_info *finfo)
165 struct smbc_dirplus_list *new_entry = NULL;
166 struct libsmb_file_info *info = NULL;
168 new_entry = SMB_MALLOC_P(struct smbc_dirplus_list);
169 if (new_entry == NULL) {
170 dir->dir_error = ENOMEM;
173 ZERO_STRUCTP(new_entry);
174 new_entry->ino = finfo->ino;
176 info = SMB_MALLOC_P(struct libsmb_file_info);
178 SAFE_FREE(new_entry);
179 dir->dir_error = ENOMEM;
185 info->btime_ts = finfo->btime_ts;
186 info->atime_ts = finfo->atime_ts;
187 info->ctime_ts = finfo->ctime_ts;
188 info->mtime_ts = finfo->mtime_ts;
189 info->gid = finfo->gid;
190 info->attrs = finfo->mode;
191 info->size = finfo->size;
192 info->uid = finfo->uid;
193 info->name = SMB_STRDUP(finfo->name);
194 if (info->name == NULL) {
196 SAFE_FREE(new_entry);
197 dir->dir_error = ENOMEM;
201 if (finfo->short_name) {
202 info->short_name = SMB_STRDUP(finfo->short_name);
204 info->short_name = SMB_STRDUP("");
207 if (info->short_name == NULL) {
208 SAFE_FREE(info->name);
210 SAFE_FREE(new_entry);
211 dir->dir_error = ENOMEM;
214 new_entry->smb_finfo = info;
216 /* Now add to the list. */
217 if (dir->dirplus_list == NULL) {
218 /* Empty list - point everything at new_entry. */
219 dir->dirplus_list = new_entry;
220 dir->dirplus_end = new_entry;
221 dir->dirplus_next = new_entry;
223 /* Append to list but leave the ->next cursor alone. */
224 dir->dirplus_end->next = new_entry;
225 dir->dirplus_end = new_entry;
232 list_unique_wg_fn(const char *name,
237 SMBCFILE *dir = (SMBCFILE *)state;
238 struct smbc_dir_list *dir_list;
239 struct smbc_dirent *dirent;
243 dirent_type = dir->dir_type;
245 if (add_dirent(dir, name, comment, dirent_type) < 0) {
246 /* An error occurred, what do we do? */
247 /* FIXME: Add some code here */
248 /* Change cli_NetServerEnum to take a fn
249 returning NTSTATUS... JRA. */
252 /* Point to the one just added */
253 dirent = dir->dir_end->dirent;
255 /* See if this was a duplicate */
256 for (dir_list = dir->dir_list;
257 dir_list != dir->dir_end;
258 dir_list = dir_list->next) {
260 strcmp(dir_list->dirent->name, dirent->name) == 0) {
261 /* Duplicate. End end of list need to be removed. */
265 if (do_remove && dir_list->next == dir->dir_end) {
266 /* Found the end of the list. Remove it. */
267 dir->dir_end = dir_list;
268 free(dir_list->next);
270 dir_list->next = NULL;
277 list_fn(const char *name,
282 SMBCFILE *dir = (SMBCFILE *)state;
286 * We need to process the type a little ...
288 * Disk share = 0x00000000
289 * Print share = 0x00000001
290 * Comms share = 0x00000002 (obsolete?)
291 * IPC$ share = 0x00000003
293 * administrative shares:
294 * ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000
297 if (dir->dir_type == SMBC_FILE_SHARE) {
301 dirent_type = SMBC_FILE_SHARE;
305 dirent_type = SMBC_PRINTER_SHARE;
309 dirent_type = SMBC_COMMS_SHARE;
314 dirent_type = SMBC_IPC_SHARE;
318 dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
323 dirent_type = dir->dir_type;
326 if (add_dirent(dir, name, comment, dirent_type) < 0) {
327 /* An error occurred, what do we do? */
328 /* FIXME: Add some code here */
329 /* Change cli_NetServerEnum to take a fn
330 returning NTSTATUS... JRA. */
335 dir_list_fn(const char *mnt,
336 struct file_info *finfo,
340 SMBCFILE *dirp = (SMBCFILE *)state;
343 if (add_dirent((SMBCFILE *)state, finfo->name, "",
344 (finfo->mode&FILE_ATTRIBUTE_DIRECTORY?SMBC_DIR:SMBC_FILE)) < 0) {
345 SMBCFILE *dir = (SMBCFILE *)state;
346 return map_nt_error_from_unix(dir->dir_error);
348 ret = add_dirplus(dirp, finfo);
350 return map_nt_error_from_unix(dirp->dir_error);
356 net_share_enum_rpc(struct cli_state *cli,
357 void (*fn)(const char *name,
365 uint32_t preferred_len = 0xffffffff;
367 struct srvsvc_NetShareInfoCtr info_ctr;
368 struct srvsvc_NetShareCtr1 ctr1;
370 fstring comment = "";
371 struct rpc_pipe_client *pipe_hnd = NULL;
373 uint32_t resume_handle = 0;
374 uint32_t total_entries = 0;
375 struct dcerpc_binding_handle *b;
377 /* Open the server service pipe */
378 nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc,
380 if (!NT_STATUS_IS_OK(nt_status)) {
381 DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
385 ZERO_STRUCT(info_ctr);
389 info_ctr.ctr.ctr1 = &ctr1;
391 b = pipe_hnd->binding_handle;
393 /* Issue the NetShareEnum RPC call and retrieve the response */
394 nt_status = dcerpc_srvsvc_NetShareEnumAll(b, talloc_tos(),
402 /* Was it successful? */
403 if (!NT_STATUS_IS_OK(nt_status)) {
404 /* Nope. Go clean up. */
408 if (!W_ERROR_IS_OK(result)) {
409 /* Nope. Go clean up. */
410 nt_status = werror_to_ntstatus(result);
414 if (total_entries == 0) {
415 /* Nope. Go clean up. */
416 nt_status = NT_STATUS_NOT_FOUND;
420 /* For each returned entry... */
421 for (i = 0; i < info_ctr.ctr.ctr1->count; i++) {
423 /* pull out the share name */
424 fstrcpy(name, info_ctr.ctr.ctr1->array[i].name);
426 /* pull out the share's comment */
427 fstrcpy(comment, info_ctr.ctr.ctr1->array[i].comment);
429 /* Get the type value */
430 type = info_ctr.ctr.ctr1->array[i].type;
432 /* Add this share to the list */
433 (*fn)(name, type, comment, state);
437 /* Close the server service pipe */
438 TALLOC_FREE(pipe_hnd);
440 /* Tell 'em if it worked */
446 * Verify that the options specified in a URL are valid
449 SMBC_check_options(char *server,
454 DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' "
455 "path='%s' options='%s'\n",
456 server, share, path, options));
458 /* No options at all is always ok */
459 if (! *options) return 0;
461 /* Currently, we don't support any options. */
467 SMBC_opendir_ctx(SMBCCTX *context,
474 char *password = NULL;
475 char *options = NULL;
476 char *workgroup = NULL;
481 SMBCFILE *dir = NULL;
482 struct sockaddr_storage rem_ss;
483 TALLOC_CTX *frame = talloc_stackframe();
485 if (!context || !context->internal->initialized) {
486 DEBUG(4, ("no valid context\n"));
488 errno = EINVAL + 8192;
494 DEBUG(4, ("no valid fname\n"));
496 errno = EINVAL + 8193;
500 if (SMBC_parse_path(frame,
511 DEBUG(4, ("no valid path\n"));
513 errno = EINVAL + 8194;
517 DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
518 "path='%s' options='%s'\n",
519 fname, server, share, path, options));
521 /* Ensure the options are valid */
522 if (SMBC_check_options(server, share, path, options)) {
523 DEBUG(4, ("unacceptable options (%s)\n", options));
525 errno = EINVAL + 8195;
529 if (!user || user[0] == (char)0) {
530 user = talloc_strdup(frame, smbc_getUser(context));
538 dir = SMB_MALLOC_P(SMBCFILE);
549 dir->fname = SMB_STRDUP(fname);
553 dir->dir_list = dir->dir_next = dir->dir_end = NULL;
555 if (server[0] == (char)0) {
560 struct sockaddr_storage *ip_list;
561 struct sockaddr_storage server_addr;
562 struct user_auth_info *u_info;
565 if (share[0] != (char)0 || path[0] != (char)0) {
568 SAFE_FREE(dir->fname);
572 errno = EINVAL + 8196;
576 /* Determine how many local master browsers to query */
577 max_lmb_count = (smbc_getOptionBrowseMaxLmbCount(context) == 0
579 : smbc_getOptionBrowseMaxLmbCount(context));
581 u_info = user_auth_info_init(frame);
582 if (u_info == NULL) {
584 SAFE_FREE(dir->fname);
591 set_cmdline_auth_info_username(u_info, user);
592 set_cmdline_auth_info_password(u_info, password);
595 * We have server and share and path empty but options
596 * requesting that we scan all master browsers for their list
597 * of workgroups/domains. This implies that we must first try
598 * broadcast queries to find all master browsers, and if that
599 * doesn't work, then try our other methods which return only
600 * a single master browser.
604 status = name_resolve_bcast(MSBROWSE, 1, talloc_tos(),
606 if (!NT_STATUS_IS_OK(status))
609 TALLOC_FREE(ip_list);
611 if (!find_master_ip(workgroup, &server_addr)) {
614 SAFE_FREE(dir->fname);
622 ip_list = (struct sockaddr_storage *)talloc_memdup(
623 talloc_tos(), &server_addr,
624 sizeof(server_addr));
625 if (ip_list == NULL) {
627 SAFE_FREE(dir->fname);
637 for (i = 0; i < count && i < max_lmb_count; i++) {
638 char addr[INET6_ADDRSTRLEN];
640 struct cli_state *cli = NULL;
642 print_sockaddr(addr, sizeof(addr), &ip_list[i]);
643 DEBUG(99, ("Found master browser %d of %d: %s\n",
644 i+1, MAX(count, max_lmb_count),
647 cli = get_ipc_connect_master_ip(talloc_tos(),
651 /* cli == NULL is the master browser refused to talk or
652 could not be found */
657 workgroup = talloc_strdup(frame, wg_ptr);
658 server = talloc_strdup(frame, smbXcli_conn_remote_name(cli->conn));
662 if (!workgroup || !server) {
664 SAFE_FREE(dir->fname);
672 DEBUG(4, ("using workgroup %s %s\n",
676 * For each returned master browser IP address, get a
677 * connection to IPC$ on the server if we do not
678 * already have one, and determine the
679 * workgroups/domains that it knows about.
682 srv = SMBC_server(frame, context, True, server, port, "IPC$",
683 &workgroup, &user, &password);
688 if (smbXcli_conn_protocol(srv->cli->conn) > PROTOCOL_NT1) {
693 dir->dir_type = SMBC_WORKGROUP;
695 /* Now, list the stuff ... */
697 if (!cli_NetServerEnum(srv->cli,
706 TALLOC_FREE(ip_list);
709 * Server not an empty string ... Check the rest and see what
712 if (*share == '\0') {
715 /* Should not have empty share with path */
717 SAFE_FREE(dir->fname);
721 errno = EINVAL + 8197;
727 * We don't know if <server> is really a server name
728 * or is a workgroup/domain name. If we already have
729 * a server structure for it, we'll use it.
730 * Otherwise, check to see if <server><1D>,
731 * <server><1B>, or <server><20> translates. We check
732 * to see if <server> is an IP address first.
736 * See if we have an existing server. Do not
737 * establish a connection if one does not already
740 srv = SMBC_server(frame, context, False,
741 server, port, "IPC$",
742 &workgroup, &user, &password);
745 * If no existing server and not an IP addr, look for
749 !is_ipaddress(server) &&
750 (resolve_name(server, &rem_ss, 0x1d, false) || /* LMB */
751 resolve_name(server, &rem_ss, 0x1b, false) )) { /* DMB */
753 * "server" is actually a workgroup name,
754 * not a server. Make this clear.
756 char *wgroup = server;
759 dir->dir_type = SMBC_SERVER;
762 * Get the backup list ...
764 if (!name_status_find(wgroup, 0, 0,
765 &rem_ss, buserver)) {
766 char addr[INET6_ADDRSTRLEN];
768 print_sockaddr(addr, sizeof(addr), &rem_ss);
769 DEBUG(0,("Could not get name of "
770 "local/domain master browser "
771 "for workgroup %s from "
776 SAFE_FREE(dir->fname);
786 * Get a connection to IPC$ on the server if
787 * we do not already have one
789 srv = SMBC_server(frame, context, True,
790 buserver, port, "IPC$",
794 DEBUG(0, ("got no contact to IPC$\n"));
796 SAFE_FREE(dir->fname);
806 if (smbXcli_conn_protocol(srv->cli->conn) > PROTOCOL_NT1) {
808 SAFE_FREE(dir->fname);
815 /* Now, list the servers ... */
816 if (!cli_NetServerEnum(srv->cli, wgroup,
821 SAFE_FREE(dir->fname);
828 (resolve_name(server, &rem_ss, 0x20, false))) {
832 * If we hadn't found the server, get one now
835 srv = SMBC_server(frame, context, True,
836 server, port, "IPC$",
843 SAFE_FREE(dir->fname);
851 dir->dir_type = SMBC_FILE_SHARE;
854 /* List the shares ... */
856 status = net_share_enum_rpc(srv->cli,
859 if (!NT_STATUS_IS_OK(status) &&
860 smbXcli_conn_protocol(srv->cli->conn) <=
863 * Only call cli_RNetShareEnum()
864 * on SMB1 connections, not SMB2+.
866 int rc = cli_RNetShareEnum(srv->cli,
870 status = cli_nt_error(srv->cli);
872 status = NT_STATUS_OK;
875 if (!NT_STATUS_IS_OK(status)) {
877 * Set cli->raw_status so SMBC_errno()
878 * will correctly return the error.
880 srv->cli->raw_status = status;
882 SAFE_FREE(dir->fname);
886 errno = map_errno_from_nt_status(
891 /* Neither the workgroup nor server exists */
892 errno = ECONNREFUSED;
894 SAFE_FREE(dir->fname);
904 * The server and share are specified ... work from
908 struct cli_state *targetcli;
911 /* We connect to the server and list the directory */
912 dir->dir_type = SMBC_FILE_SHARE;
914 srv = SMBC_server(frame, context, True, server, port, share,
915 &workgroup, &user, &password);
919 SAFE_FREE(dir->fname);
928 /* Now, list the files ... */
930 path_len = strlen(path);
931 path = talloc_asprintf_append(path, "\\*");
934 SAFE_FREE(dir->fname);
941 status = cli_resolve_path(
942 frame, "", context->internal->auth_info,
943 srv->cli, path, &targetcli, &targetpath);
944 if (!NT_STATUS_IS_OK(status)) {
945 d_printf("Could not resolve %s\n", path);
947 SAFE_FREE(dir->fname);
954 status = cli_list(targetcli, targetpath,
955 FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
956 dir_list_fn, (void *)dir);
957 if (!NT_STATUS_IS_OK(status)) {
959 SAFE_FREE(dir->fname);
962 saved_errno = SMBC_errno(context, targetcli);
964 if (saved_errno == EINVAL) {
965 struct stat sb = {0};
967 * See if they asked to opendir
968 * something other than a directory.
969 * If so, the converted error value we
970 * got would have been EINVAL rather
973 path[path_len] = '\0'; /* restore original path */
975 if (SMBC_getatr(context,
979 !S_ISDIR(sb.st_mode)) {
981 /* It is. Correct the error value */
982 saved_errno = ENOTDIR;
987 * If there was an error and the server is no
990 if (cli_is_error(targetcli) &&
991 smbc_getFunctionCheckServer(context)(context, srv)) {
993 /* ... then remove it. */
994 if (smbc_getFunctionRemoveUnusedServer(context)(context,
997 * We could not remove the
998 * server completely, remove
999 * it from the cache so we
1000 * will not get it again. It
1001 * will be removed when the
1002 * last file/dir is closed.
1004 smbc_getFunctionRemoveCachedServer(context)(context, srv);
1009 errno = saved_errno;
1016 DLIST_ADD(context->internal->files, dir);
1023 * Routine to close a directory
1027 SMBC_closedir_ctx(SMBCCTX *context,
1030 TALLOC_CTX *frame = talloc_stackframe();
1032 if (!context || !context->internal->initialized) {
1038 if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
1044 remove_dir(dir); /* Clean it up */
1045 remove_dirplus(dir);
1047 DLIST_REMOVE(context->internal->files, dir);
1051 SAFE_FREE(dir->fname);
1052 SAFE_FREE(dir); /* Free the space too */
1061 smbc_readdir_internal(SMBCCTX * context,
1062 struct smbc_dirent *dest,
1063 struct smbc_dirent *src,
1064 int max_namebuf_len)
1066 if (smbc_getOptionUrlEncodeReaddirEntries(context)) {
1069 /* url-encode the name. get back remaining buffer space */
1071 smbc_urlencode(dest->name, src->name, max_namebuf_len);
1073 /* -1 means no null termination. */
1074 if (remaining_len < 0) {
1078 /* We now know the name length */
1079 dest->namelen = strlen(dest->name);
1081 if (dest->namelen + 1 < 1) {
1086 if (dest->namelen + 1 >= max_namebuf_len) {
1087 /* Out of space for comment. */
1091 /* Save the pointer to the beginning of the comment */
1092 dest->comment = dest->name + dest->namelen + 1;
1094 if (remaining_len < 1) {
1095 /* No room for comment null termination. */
1099 /* Copy the comment */
1100 strlcpy(dest->comment, src->comment, remaining_len);
1102 /* Save other fields */
1103 dest->smbc_type = src->smbc_type;
1104 dest->commentlen = strlen(dest->comment);
1105 dest->dirlen = ((dest->comment + dest->commentlen + 1) -
1109 /* No encoding. Just copy the entry as is. */
1110 if (src->dirlen > max_namebuf_len) {
1113 memcpy(dest, src, src->dirlen);
1114 if (src->namelen + 1 < 1) {
1118 if (src->namelen + 1 >= max_namebuf_len) {
1119 /* Comment off the end. */
1122 dest->comment = (char *)(&dest->name + src->namelen + 1);
1128 * Routine to get a directory entry
1131 struct smbc_dirent *
1132 SMBC_readdir_ctx(SMBCCTX *context,
1137 struct smbc_dirent *dirp, *dirent;
1138 TALLOC_CTX *frame = talloc_stackframe();
1140 /* Check that all is ok first ... */
1142 if (!context || !context->internal->initialized) {
1145 DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n"));
1151 if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
1154 DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n"));
1160 if (dir->file != False) { /* FIXME, should be dir, perhaps */
1163 DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n"));
1169 if (!dir->dir_next) {
1174 dirent = dir->dir_next->dirent;
1183 dirp = &context->internal->dirent;
1184 maxlen = sizeof(context->internal->_dirent_name);
1186 ret = smbc_readdir_internal(context, dirp, dirent, maxlen);
1193 dir->dir_next = dir->dir_next->next;
1196 * If we are returning file entries, we
1197 * have a duplicate list in dirplus.
1199 * Update dirplus_next also so readdir and
1200 * readdirplus are kept in sync.
1202 if (dir->dirplus_list != NULL) {
1203 dir->dirplus_next = dir->dirplus_next->next;
1211 * Routine to get a directory entry with all attributes
1214 const struct libsmb_file_info *
1215 SMBC_readdirplus_ctx(SMBCCTX *context,
1218 struct libsmb_file_info *smb_finfo = NULL;
1219 TALLOC_CTX *frame = talloc_stackframe();
1221 /* Check that all is ok first ... */
1223 if (context == NULL || !context->internal->initialized) {
1224 DBG_ERR("Invalid context in SMBC_readdirplus_ctx()\n");
1231 SMBC_dlist_contains(context->internal->files,
1233 DBG_ERR("Invalid dir in SMBC_readdirplus_ctx()\n");
1239 if (dir->dirplus_next == NULL) {
1244 smb_finfo = dir->dirplus_next->smb_finfo;
1245 if (smb_finfo == NULL) {
1250 dir->dirplus_next = dir->dirplus_next->next;
1253 * If we are returning file entries, we
1254 * have a duplicate list in dir_list
1256 * Update dir_next also so readdir and
1257 * readdirplus are kept in sync.
1259 if (dir->dir_list) {
1260 dir->dir_next = dir->dir_next->next;
1268 * Routine to get a directory entry plus a filled in stat structure if
1272 const struct libsmb_file_info *SMBC_readdirplus2_ctx(SMBCCTX *context,
1276 struct libsmb_file_info *smb_finfo = NULL;
1277 struct smbc_dirplus_list *dp_list = NULL;
1279 char *full_pathname = NULL;
1280 char *workgroup = NULL;
1281 char *server = NULL;
1286 char *password = NULL;
1287 char *options = NULL;
1289 TALLOC_CTX *frame = NULL;
1292 * Allow caller to pass in NULL for stat pointer if
1293 * required. This makes this call identical to
1294 * smbc_readdirplus().
1298 return SMBC_readdirplus_ctx(context, dir);
1301 frame = talloc_stackframe();
1303 /* Check that all is ok first ... */
1304 if (context == NULL || !context->internal->initialized) {
1305 DBG_ERR("Invalid context in SMBC_readdirplus2_ctx()\n");
1312 SMBC_dlist_contains(context->internal->files,
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 (!dir || !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 (!dir || !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;
2051 struct timespec access_time, write_time;
2053 TALLOC_CTX *frame = talloc_stackframe();
2056 if (!context || !context->internal->initialized) {
2058 errno = EINVAL; /* Best I can think of ... */
2070 access_time = write_time = timespec_current();
2072 access_time = convert_timeval_to_timespec(tbuf[0]);
2073 write_time = convert_timeval_to_timespec(tbuf[1]);
2077 struct timeval_buf abuf, wbuf;
2079 dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
2081 timespec_string_buf(&access_time, false, &abuf),
2082 timespec_string_buf(&write_time, false, &wbuf));
2085 if (SMBC_parse_path(frame,
2101 if (!user || user[0] == (char)0) {
2102 user = talloc_strdup(frame, smbc_getUser(context));
2110 srv = SMBC_server(frame, context, True,
2111 server, port, share, &workgroup, &user, &password);
2115 return -1; /* errno set by SMBC_server */
2122 (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT },
2125 (struct timespec) { .tv_nsec = SAMBA_UTIME_OMIT },
2129 return -1; /* errno set by SMBC_setatr */
2137 * Routine to unlink() a file
2141 SMBC_unlink_ctx(SMBCCTX *context,
2144 char *server = NULL;
2147 char *password = NULL;
2148 char *workgroup = NULL;
2150 char *targetpath = NULL;
2152 struct cli_state *targetcli = NULL;
2153 SMBCSRV *srv = NULL;
2154 TALLOC_CTX *frame = talloc_stackframe();
2157 if (!context || !context->internal->initialized) {
2159 errno = EINVAL; /* Best I can think of ... */
2172 if (SMBC_parse_path(frame,
2188 if (!user || user[0] == (char)0) {
2189 user = talloc_strdup(frame, smbc_getUser(context));
2197 srv = SMBC_server(frame, context, True,
2198 server, port, share, &workgroup, &user, &password);
2202 return -1; /* SMBC_server sets errno */
2206 /*d_printf(">>>unlink: resolving %s\n", path);*/
2207 status = cli_resolve_path(frame, "", context->internal->auth_info,
2208 srv->cli, path, &targetcli, &targetpath);
2209 if (!NT_STATUS_IS_OK(status)) {
2210 d_printf("Could not resolve %s\n", path);
2215 /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
2217 if (!NT_STATUS_IS_OK(cli_unlink(targetcli, targetpath, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))) {
2219 errno = SMBC_errno(context, targetcli);
2221 if (errno == EACCES) { /* Check if the file is a directory */
2224 struct stat sb = {0};
2227 ok = SMBC_getatr(context, srv, path, &sb);
2229 /* Hmmm, bad error ... What? */
2231 errno = SMBC_errno(context, targetcli);
2238 if (S_ISDIR(sb.st_mode))
2241 errno = saverr; /* Restore this */
2252 return 0; /* Success ... */
2257 * Routine to rename() a file
2261 SMBC_rename_ctx(SMBCCTX *ocontext,
2266 char *server1 = NULL;
2267 char *share1 = NULL;
2268 char *server2 = NULL;
2269 char *share2 = NULL;
2272 char *password1 = NULL;
2273 char *password2 = NULL;
2274 char *workgroup = NULL;
2277 char *targetpath1 = NULL;
2278 char *targetpath2 = NULL;
2279 struct cli_state *targetcli1 = NULL;
2280 struct cli_state *targetcli2 = NULL;
2281 SMBCSRV *srv = NULL;
2284 TALLOC_CTX *frame = talloc_stackframe();
2287 if (!ocontext || !ncontext ||
2288 !ocontext->internal->initialized ||
2289 !ncontext->internal->initialized) {
2291 errno = EINVAL; /* Best I can think of ... */
2296 if (!oname || !nname) {
2302 DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
2304 if (SMBC_parse_path(frame,
2320 if (!user1 || user1[0] == (char)0) {
2321 user1 = talloc_strdup(frame, smbc_getUser(ocontext));
2329 if (SMBC_parse_path(frame,
2345 if (!user2 || user2[0] == (char)0) {
2346 user2 = talloc_strdup(frame, smbc_getUser(ncontext));
2354 if (strcmp(server1, server2) || strcmp(share1, share2) ||
2355 strcmp(user1, user2)) {
2356 /* Can't rename across file systems, or users?? */
2362 srv = SMBC_server(frame, ocontext, True,
2363 server1, port1, share1, &workgroup, &user1, &password1);
2370 /* set the credentials to make DFS work */
2371 smbc_set_credentials_with_fallback(ocontext,
2376 /*d_printf(">>>rename: resolving %s\n", path1);*/
2377 status = cli_resolve_path(frame, "", ocontext->internal->auth_info,
2378 srv->cli, path1, &targetcli1, &targetpath1);
2379 if (!NT_STATUS_IS_OK(status)) {
2380 d_printf("Could not resolve %s\n", path1);
2386 /* set the credentials to make DFS work */
2387 smbc_set_credentials_with_fallback(ncontext,
2392 /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
2393 /*d_printf(">>>rename: resolving %s\n", path2);*/
2394 status = cli_resolve_path(frame, "", ncontext->internal->auth_info,
2395 srv->cli, path2, &targetcli2, &targetpath2);
2396 if (!NT_STATUS_IS_OK(status)) {
2397 d_printf("Could not resolve %s\n", path2);
2402 /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
2404 if (strcmp(smbXcli_conn_remote_name(targetcli1->conn), smbXcli_conn_remote_name(targetcli2->conn)) ||
2405 strcmp(targetcli1->share, targetcli2->share))
2407 /* can't rename across file systems */
2413 if (!NT_STATUS_IS_OK(
2414 cli_rename(targetcli1, targetpath1, targetpath2, false))) {
2415 int eno = SMBC_errno(ocontext, targetcli1);
2417 if (eno != EEXIST ||
2418 !NT_STATUS_IS_OK(cli_unlink(targetcli1, targetpath2,
2419 FILE_ATTRIBUTE_SYSTEM |
2420 FILE_ATTRIBUTE_HIDDEN)) ||
2421 !NT_STATUS_IS_OK(cli_rename(targetcli1, targetpath1,
2422 targetpath2, false))) {
2432 return 0; /* Success */
2435 struct smbc_notify_cb_state {
2436 struct tevent_context *ev;
2437 struct cli_state *cli;
2440 uint32_t completion_filter;
2441 unsigned callback_timeout_ms;
2442 smbc_notify_callback_fn cb;
2446 static void smbc_notify_cb_got_changes(struct tevent_req *subreq);
2447 static void smbc_notify_cb_timedout(struct tevent_req *subreq);
2449 static struct tevent_req *smbc_notify_cb_send(
2450 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
2451 uint16_t fnum, bool recursive, uint32_t completion_filter,
2452 unsigned callback_timeout_ms,
2453 smbc_notify_callback_fn cb, void *private_data)
2455 struct tevent_req *req, *subreq;
2456 struct smbc_notify_cb_state *state;
2458 req = tevent_req_create(mem_ctx, &state, struct smbc_notify_cb_state);
2465 state->recursive = recursive;
2466 state->completion_filter = completion_filter;
2467 state->callback_timeout_ms = callback_timeout_ms;
2469 state->private_data = private_data;
2471 subreq = cli_notify_send(
2472 state, state->ev, state->cli, state->fnum, 1000,
2473 state->completion_filter, state->recursive);
2474 if (tevent_req_nomem(subreq, req)) {
2475 return tevent_req_post(req, ev);
2477 tevent_req_set_callback(subreq, smbc_notify_cb_got_changes, req);
2479 if (state->callback_timeout_ms == 0) {
2483 subreq = tevent_wakeup_send(
2485 tevent_timeval_current_ofs(state->callback_timeout_ms/1000,
2486 state->callback_timeout_ms*1000));
2487 if (tevent_req_nomem(subreq, req)) {
2488 return tevent_req_post(req, ev);
2490 tevent_req_set_callback(subreq, smbc_notify_cb_timedout, req);
2495 static void smbc_notify_cb_got_changes(struct tevent_req *subreq)
2497 struct tevent_req *req = tevent_req_callback_data(
2498 subreq, struct tevent_req);
2499 struct smbc_notify_cb_state *state = tevent_req_data(
2500 req, struct smbc_notify_cb_state);
2501 uint32_t num_changes;
2502 struct notify_change *changes;
2506 status = cli_notify_recv(subreq, state, &num_changes, &changes);
2507 TALLOC_FREE(subreq);
2508 if (tevent_req_nterror(req, status)) {
2513 struct smbc_notify_callback_action actions[num_changes];
2516 for (i=0; i<num_changes; i++) {
2517 actions[i].action = changes[i].action;
2518 actions[i].filename = changes[i].name;
2521 cb_ret = state->cb(actions, num_changes, state->private_data);
2524 TALLOC_FREE(changes);
2527 tevent_req_done(req);
2531 subreq = cli_notify_send(
2532 state, state->ev, state->cli, state->fnum, 1000,
2533 state->completion_filter, state->recursive);
2534 if (tevent_req_nomem(subreq, req)) {
2537 tevent_req_set_callback(subreq, smbc_notify_cb_got_changes, req);
2540 static void smbc_notify_cb_timedout(struct tevent_req *subreq)
2542 struct tevent_req *req = tevent_req_callback_data(
2543 subreq, struct tevent_req);
2544 struct smbc_notify_cb_state *state = tevent_req_data(
2545 req, struct smbc_notify_cb_state);
2549 ok = tevent_wakeup_recv(subreq);
2550 TALLOC_FREE(subreq);
2552 tevent_req_oom(req);
2556 cb_ret = state->cb(NULL, 0, state->private_data);
2558 tevent_req_done(req);
2562 subreq = tevent_wakeup_send(
2564 tevent_timeval_current_ofs(state->callback_timeout_ms/1000,
2565 state->callback_timeout_ms*1000));
2566 if (tevent_req_nomem(subreq, req)) {
2569 tevent_req_set_callback(subreq, smbc_notify_cb_timedout, req);
2572 static NTSTATUS smbc_notify_cb_recv(struct tevent_req *req)
2574 return tevent_req_simple_recv_ntstatus(req);
2577 static NTSTATUS smbc_notify_cb(struct cli_state *cli, uint16_t fnum,
2578 bool recursive, uint32_t completion_filter,
2579 unsigned callback_timeout_ms,
2580 smbc_notify_callback_fn cb, void *private_data)
2582 TALLOC_CTX *frame = talloc_stackframe();
2583 struct tevent_context *ev;
2584 struct tevent_req *req;
2585 NTSTATUS status = NT_STATUS_NO_MEMORY;
2587 ev = samba_tevent_context_init(frame);
2591 req = smbc_notify_cb_send(frame, ev, cli, fnum, recursive,
2593 callback_timeout_ms, cb, private_data);
2597 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2600 status = smbc_notify_cb_recv(req);
2608 SMBC_notify_ctx(SMBCCTX *context, SMBCFILE *dir, smbc_bool recursive,
2609 uint32_t completion_filter, unsigned callback_timeout_ms,
2610 smbc_notify_callback_fn cb, void *private_data)
2612 TALLOC_CTX *frame = talloc_stackframe();
2613 struct cli_state *cli;
2614 char *server = NULL;
2617 char *password = NULL;
2618 char *options = NULL;
2619 char *workgroup = NULL;
2625 if ((context == NULL) || !context->internal->initialized) {
2630 if ((dir == NULL) ||
2631 !SMBC_dlist_contains(context->internal->files, dir)) {
2637 if (SMBC_parse_path(frame,
2648 DEBUG(4, ("no valid path\n"));
2650 errno = EINVAL + 8194;
2654 DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
2655 "path='%s' options='%s'\n",
2656 dir->fname, server, share, path, options));
2658 DEBUG(4, ("%s(%p, %d, %"PRIu32")\n", __func__, dir,
2659 (int)recursive, completion_filter));
2661 cli = dir->srv->cli;
2662 status = cli_ntcreate(
2663 cli, path, 0, FILE_READ_DATA, 0,
2664 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
2665 FILE_OPEN, 0, 0, &fnum, NULL);
2666 if (!NT_STATUS_IS_OK(status)) {
2667 int err = SMBC_errno(context, cli);
2673 status = smbc_notify_cb(cli, fnum, recursive != 0, completion_filter,
2674 callback_timeout_ms, cb, private_data);
2675 if (!NT_STATUS_IS_OK(status)) {
2676 int err = SMBC_errno(context, cli);
2677 cli_close(cli, fnum);
2683 cli_close(cli, fnum);