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 "popt_common.h"
27 #include "libsmbclient.h"
28 #include "libsmb_internal.h"
29 #include "rpc_client/cli_pipe.h"
30 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
33 * Routine to open a directory
34 * We accept the URL syntax explained in SMBC_parse_path(), above.
38 remove_dir(SMBCFILE
*dir
)
40 struct smbc_dir_list
*d
,*f
;
52 dir
->dir_list
= dir
->dir_end
= dir
->dir_next
= NULL
;
57 add_dirent(SMBCFILE
*dir
,
62 struct smbc_dirent
*dirent
;
64 int name_length
= (name
== NULL
? 0 : strlen(name
));
65 int comment_len
= (comment
== NULL
? 0 : strlen(comment
));
68 * Allocate space for the dirent, which must be increased by the
69 * size of the name and the comment and 1 each for the null terminator.
72 size
= sizeof(struct smbc_dirent
) + name_length
+ comment_len
+ 2;
74 dirent
= (struct smbc_dirent
*)SMB_MALLOC(size
);
78 dir
->dir_error
= ENOMEM
;
85 if (dir
->dir_list
== NULL
) {
87 dir
->dir_list
= SMB_MALLOC_P(struct smbc_dir_list
);
91 dir
->dir_error
= ENOMEM
;
95 ZERO_STRUCTP(dir
->dir_list
);
97 dir
->dir_end
= dir
->dir_next
= dir
->dir_list
;
101 dir
->dir_end
->next
= SMB_MALLOC_P(struct smbc_dir_list
);
103 if (!dir
->dir_end
->next
) {
106 dir
->dir_error
= ENOMEM
;
110 ZERO_STRUCTP(dir
->dir_end
->next
);
112 dir
->dir_end
= dir
->dir_end
->next
;
115 dir
->dir_end
->next
= NULL
;
116 dir
->dir_end
->dirent
= dirent
;
118 dirent
->smbc_type
= type
;
119 dirent
->namelen
= name_length
;
120 dirent
->commentlen
= comment_len
;
121 dirent
->dirlen
= size
;
124 * dirent->namelen + 1 includes the null (no null termination needed)
125 * Ditto for dirent->commentlen.
126 * The space for the two null bytes was allocated.
128 strncpy(dirent
->name
, (name
?name
:""), dirent
->namelen
+ 1);
129 dirent
->comment
= (char *)(&dirent
->name
+ dirent
->namelen
+ 1);
130 strncpy(dirent
->comment
, (comment
?comment
:""), dirent
->commentlen
+ 1);
137 list_unique_wg_fn(const char *name
,
142 SMBCFILE
*dir
= (SMBCFILE
*)state
;
143 struct smbc_dir_list
*dir_list
;
144 struct smbc_dirent
*dirent
;
148 dirent_type
= dir
->dir_type
;
150 if (add_dirent(dir
, name
, comment
, dirent_type
) < 0) {
151 /* An error occurred, what do we do? */
152 /* FIXME: Add some code here */
153 /* Change cli_NetServerEnum to take a fn
154 returning NTSTATUS... JRA. */
157 /* Point to the one just added */
158 dirent
= dir
->dir_end
->dirent
;
160 /* See if this was a duplicate */
161 for (dir_list
= dir
->dir_list
;
162 dir_list
!= dir
->dir_end
;
163 dir_list
= dir_list
->next
) {
165 strcmp(dir_list
->dirent
->name
, dirent
->name
) == 0) {
166 /* Duplicate. End end of list need to be removed. */
170 if (do_remove
&& dir_list
->next
== dir
->dir_end
) {
171 /* Found the end of the list. Remove it. */
172 dir
->dir_end
= dir_list
;
173 free(dir_list
->next
);
175 dir_list
->next
= NULL
;
182 list_fn(const char *name
,
187 SMBCFILE
*dir
= (SMBCFILE
*)state
;
191 * We need to process the type a little ...
193 * Disk share = 0x00000000
194 * Print share = 0x00000001
195 * Comms share = 0x00000002 (obsolete?)
196 * IPC$ share = 0x00000003
198 * administrative shares:
199 * ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000
202 if (dir
->dir_type
== SMBC_FILE_SHARE
) {
206 dirent_type
= SMBC_FILE_SHARE
;
210 dirent_type
= SMBC_PRINTER_SHARE
;
214 dirent_type
= SMBC_COMMS_SHARE
;
219 dirent_type
= SMBC_IPC_SHARE
;
223 dirent_type
= SMBC_FILE_SHARE
; /* FIXME, error? */
228 dirent_type
= dir
->dir_type
;
231 if (add_dirent(dir
, name
, comment
, dirent_type
) < 0) {
232 /* An error occurred, what do we do? */
233 /* FIXME: Add some code here */
234 /* Change cli_NetServerEnum to take a fn
235 returning NTSTATUS... JRA. */
240 dir_list_fn(const char *mnt
,
241 struct file_info
*finfo
,
246 if (add_dirent((SMBCFILE
*)state
, finfo
->name
, "",
247 (finfo
->mode
&aDIR
?SMBC_DIR
:SMBC_FILE
)) < 0) {
248 SMBCFILE
*dir
= (SMBCFILE
*)state
;
249 return map_nt_error_from_unix(dir
->dir_error
);
255 net_share_enum_rpc(struct cli_state
*cli
,
256 void (*fn
)(const char *name
,
264 uint32 preferred_len
= 0xffffffff;
266 struct srvsvc_NetShareInfoCtr info_ctr
;
267 struct srvsvc_NetShareCtr1 ctr1
;
269 fstring comment
= "";
270 struct rpc_pipe_client
*pipe_hnd
= NULL
;
272 uint32_t resume_handle
= 0;
273 uint32_t total_entries
= 0;
274 struct dcerpc_binding_handle
*b
;
276 /* Open the server service pipe */
277 nt_status
= cli_rpc_pipe_open_noauth(cli
, &ndr_table_srvsvc
.syntax_id
,
279 if (!NT_STATUS_IS_OK(nt_status
)) {
280 DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
284 ZERO_STRUCT(info_ctr
);
288 info_ctr
.ctr
.ctr1
= &ctr1
;
290 b
= pipe_hnd
->binding_handle
;
292 /* Issue the NetShareEnum RPC call and retrieve the response */
293 nt_status
= dcerpc_srvsvc_NetShareEnumAll(b
, talloc_tos(),
301 /* Was it successful? */
302 if (!NT_STATUS_IS_OK(nt_status
)) {
303 /* Nope. Go clean up. */
304 result
= ntstatus_to_werror(nt_status
);
308 if (!W_ERROR_IS_OK(result
)) {
309 /* Nope. Go clean up. */
313 if (total_entries
== 0) {
314 /* Nope. Go clean up. */
315 result
= WERR_GENERAL_FAILURE
;
319 /* For each returned entry... */
320 for (i
= 0; i
< info_ctr
.ctr
.ctr1
->count
; i
++) {
322 /* pull out the share name */
323 fstrcpy(name
, info_ctr
.ctr
.ctr1
->array
[i
].name
);
325 /* pull out the share's comment */
326 fstrcpy(comment
, info_ctr
.ctr
.ctr1
->array
[i
].comment
);
328 /* Get the type value */
329 type
= info_ctr
.ctr
.ctr1
->array
[i
].type
;
331 /* Add this share to the list */
332 (*fn
)(name
, type
, comment
, state
);
336 /* Close the server service pipe */
337 TALLOC_FREE(pipe_hnd
);
339 /* Tell 'em if it worked */
340 return W_ERROR_IS_OK(result
) ? 0 : -1;
345 * Verify that the options specified in a URL are valid
348 SMBC_check_options(char *server
,
353 DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' "
354 "path='%s' options='%s'\n",
355 server
, share
, path
, options
));
357 /* No options at all is always ok */
358 if (! *options
) return 0;
360 /* Currently, we don't support any options. */
366 SMBC_opendir_ctx(SMBCCTX
*context
,
373 char *password
= NULL
;
374 char *options
= NULL
;
375 char *workgroup
= NULL
;
380 SMBCFILE
*dir
= NULL
;
381 struct sockaddr_storage rem_ss
;
382 TALLOC_CTX
*frame
= talloc_stackframe();
384 if (!context
|| !context
->internal
->initialized
) {
385 DEBUG(4, ("no valid context\n"));
387 errno
= EINVAL
+ 8192;
393 DEBUG(4, ("no valid fname\n"));
395 errno
= EINVAL
+ 8193;
399 if (SMBC_parse_path(frame
,
409 DEBUG(4, ("no valid path\n"));
411 errno
= EINVAL
+ 8194;
415 DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
416 "path='%s' options='%s'\n",
417 fname
, server
, share
, path
, options
));
419 /* Ensure the options are valid */
420 if (SMBC_check_options(server
, share
, path
, options
)) {
421 DEBUG(4, ("unacceptable options (%s)\n", options
));
423 errno
= EINVAL
+ 8195;
427 if (!user
|| user
[0] == (char)0) {
428 user
= talloc_strdup(frame
, smbc_getUser(context
));
436 dir
= SMB_MALLOC_P(SMBCFILE
);
447 dir
->fname
= SMB_STRDUP(fname
);
451 dir
->dir_list
= dir
->dir_next
= dir
->dir_end
= NULL
;
453 if (server
[0] == (char)0) {
458 struct ip_service
*ip_list
;
459 struct ip_service server_addr
;
460 struct user_auth_info u_info
;
462 if (share
[0] != (char)0 || path
[0] != (char)0) {
465 SAFE_FREE(dir
->fname
);
469 errno
= EINVAL
+ 8196;
473 /* Determine how many local master browsers to query */
474 max_lmb_count
= (smbc_getOptionBrowseMaxLmbCount(context
) == 0
476 : smbc_getOptionBrowseMaxLmbCount(context
));
478 memset(&u_info
, '\0', sizeof(u_info
));
479 u_info
.username
= talloc_strdup(frame
,user
);
480 u_info
.password
= talloc_strdup(frame
,password
);
481 if (!u_info
.username
|| !u_info
.password
) {
483 SAFE_FREE(dir
->fname
);
491 * We have server and share and path empty but options
492 * requesting that we scan all master browsers for their list
493 * of workgroups/domains. This implies that we must first try
494 * broadcast queries to find all master browsers, and if that
495 * doesn't work, then try our other methods which return only
496 * a single master browser.
500 if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE
, 1, &ip_list
,
506 if (!find_master_ip(workgroup
, &server_addr
.ss
)) {
509 SAFE_FREE(dir
->fname
);
517 ip_list
= (struct ip_service
*)memdup(
518 &server_addr
, sizeof(server_addr
));
519 if (ip_list
== NULL
) {
527 for (i
= 0; i
< count
&& i
< max_lmb_count
; i
++) {
528 char addr
[INET6_ADDRSTRLEN
];
530 struct cli_state
*cli
= NULL
;
532 print_sockaddr(addr
, sizeof(addr
), &ip_list
[i
].ss
);
533 DEBUG(99, ("Found master browser %d of %d: %s\n",
534 i
+1, MAX(count
, max_lmb_count
),
537 cli
= get_ipc_connect_master_ip(talloc_tos(),
541 /* cli == NULL is the master browser refused to talk or
542 could not be found */
547 workgroup
= talloc_strdup(frame
, wg_ptr
);
548 server
= talloc_strdup(frame
, cli
->desthost
);
552 if (!workgroup
|| !server
) {
554 SAFE_FREE(dir
->fname
);
562 DEBUG(4, ("using workgroup %s %s\n",
566 * For each returned master browser IP address, get a
567 * connection to IPC$ on the server if we do not
568 * already have one, and determine the
569 * workgroups/domains that it knows about.
572 srv
= SMBC_server(frame
, context
, True
, server
, "IPC$",
573 &workgroup
, &user
, &password
);
579 dir
->dir_type
= SMBC_WORKGROUP
;
581 /* Now, list the stuff ... */
583 if (!cli_NetServerEnum(srv
->cli
,
595 * Server not an empty string ... Check the rest and see what
598 if (*share
== '\0') {
601 /* Should not have empty share with path */
603 SAFE_FREE(dir
->fname
);
607 errno
= EINVAL
+ 8197;
613 * We don't know if <server> is really a server name
614 * or is a workgroup/domain name. If we already have
615 * a server structure for it, we'll use it.
616 * Otherwise, check to see if <server><1D>,
617 * <server><1B>, or <server><20> translates. We check
618 * to see if <server> is an IP address first.
622 * See if we have an existing server. Do not
623 * establish a connection if one does not already
626 srv
= SMBC_server(frame
, context
, False
,
628 &workgroup
, &user
, &password
);
631 * If no existing server and not an IP addr, look for
635 !is_ipaddress(server
) &&
636 (resolve_name(server
, &rem_ss
, 0x1d, false) || /* LMB */
637 resolve_name(server
, &rem_ss
, 0x1b, false) )) { /* DMB */
639 * "server" is actually a workgroup name,
640 * not a server. Make this clear.
642 char *wgroup
= server
;
645 dir
->dir_type
= SMBC_SERVER
;
648 * Get the backup list ...
650 if (!name_status_find(wgroup
, 0, 0,
651 &rem_ss
, buserver
)) {
652 char addr
[INET6_ADDRSTRLEN
];
654 print_sockaddr(addr
, sizeof(addr
), &rem_ss
);
655 DEBUG(0,("Could not get name of "
656 "local/domain master browser "
657 "for workgroup %s from "
662 SAFE_FREE(dir
->fname
);
672 * Get a connection to IPC$ on the server if
673 * we do not already have one
675 srv
= SMBC_server(frame
, context
, True
,
680 DEBUG(0, ("got no contact to IPC$\n"));
682 SAFE_FREE(dir
->fname
);
692 /* Now, list the servers ... */
693 if (!cli_NetServerEnum(srv
->cli
, wgroup
,
698 SAFE_FREE(dir
->fname
);
705 (resolve_name(server
, &rem_ss
, 0x20, false))) {
708 * If we hadn't found the server, get one now
711 srv
= SMBC_server(frame
, context
, True
,
719 SAFE_FREE(dir
->fname
);
727 dir
->dir_type
= SMBC_FILE_SHARE
;
730 /* List the shares ... */
732 if (net_share_enum_rpc(
741 errno
= cli_errno(srv
->cli
);
743 SAFE_FREE(dir
->fname
);
751 /* Neither the workgroup nor server exists */
752 errno
= ECONNREFUSED
;
754 SAFE_FREE(dir
->fname
);
764 * The server and share are specified ... work from
768 struct cli_state
*targetcli
;
771 /* We connect to the server and list the directory */
772 dir
->dir_type
= SMBC_FILE_SHARE
;
774 srv
= SMBC_server(frame
, context
, True
, server
, share
,
775 &workgroup
, &user
, &password
);
779 SAFE_FREE(dir
->fname
);
788 /* Now, list the files ... */
790 p
= path
+ strlen(path
);
791 path
= talloc_asprintf_append(path
, "\\*");
794 SAFE_FREE(dir
->fname
);
801 if (!cli_resolve_path(frame
, "", context
->internal
->auth_info
,
803 &targetcli
, &targetpath
)) {
804 d_printf("Could not resolve %s\n", path
);
806 SAFE_FREE(dir
->fname
);
813 status
= cli_list(targetcli
, targetpath
,
814 aDIR
| aSYSTEM
| aHIDDEN
,
815 dir_list_fn
, (void *)dir
);
816 if (!NT_STATUS_IS_OK(status
)) {
818 SAFE_FREE(dir
->fname
);
821 saved_errno
= SMBC_errno(context
, targetcli
);
823 if (saved_errno
== EINVAL
) {
825 * See if they asked to opendir
826 * something other than a directory.
827 * If so, the converted error value we
828 * got would have been EINVAL rather
831 *p
= '\0'; /* restore original path */
833 if (SMBC_getatr(context
, srv
, path
,
835 NULL
, NULL
, NULL
, NULL
,
837 ! IS_DOS_DIR(mode
)) {
839 /* It is. Correct the error value */
840 saved_errno
= ENOTDIR
;
845 * If there was an error and the server is no
848 if (cli_is_error(targetcli
) &&
849 smbc_getFunctionCheckServer(context
)(context
, srv
)) {
851 /* ... then remove it. */
852 if (smbc_getFunctionRemoveUnusedServer(context
)(context
,
855 * We could not remove the
856 * server completely, remove
857 * it from the cache so we
858 * will not get it again. It
859 * will be removed when the
860 * last file/dir is closed.
862 smbc_getFunctionRemoveCachedServer(context
)(context
, srv
);
874 DLIST_ADD(context
->internal
->files
, dir
);
881 * Routine to close a directory
885 SMBC_closedir_ctx(SMBCCTX
*context
,
888 TALLOC_CTX
*frame
= talloc_stackframe();
890 if (!context
|| !context
->internal
->initialized
) {
896 if (!dir
|| !SMBC_dlist_contains(context
->internal
->files
, dir
)) {
902 remove_dir(dir
); /* Clean it up */
904 DLIST_REMOVE(context
->internal
->files
, dir
);
908 SAFE_FREE(dir
->fname
);
909 SAFE_FREE(dir
); /* Free the space too */
918 smbc_readdir_internal(SMBCCTX
* context
,
919 struct smbc_dirent
*dest
,
920 struct smbc_dirent
*src
,
923 if (smbc_getOptionUrlEncodeReaddirEntries(context
)) {
925 /* url-encode the name. get back remaining buffer space */
927 smbc_urlencode(dest
->name
, src
->name
, max_namebuf_len
);
929 /* We now know the name length */
930 dest
->namelen
= strlen(dest
->name
);
932 /* Save the pointer to the beginning of the comment */
933 dest
->comment
= dest
->name
+ dest
->namelen
+ 1;
935 /* Copy the comment */
936 strncpy(dest
->comment
, src
->comment
, max_namebuf_len
- 1);
937 dest
->comment
[max_namebuf_len
- 1] = '\0';
939 /* Save other fields */
940 dest
->smbc_type
= src
->smbc_type
;
941 dest
->commentlen
= strlen(dest
->comment
);
942 dest
->dirlen
= ((dest
->comment
+ dest
->commentlen
+ 1) -
946 /* No encoding. Just copy the entry as is. */
947 memcpy(dest
, src
, src
->dirlen
);
948 dest
->comment
= (char *)(&dest
->name
+ src
->namelen
+ 1);
954 * Routine to get a directory entry
958 SMBC_readdir_ctx(SMBCCTX
*context
,
962 struct smbc_dirent
*dirp
, *dirent
;
963 TALLOC_CTX
*frame
= talloc_stackframe();
965 /* Check that all is ok first ... */
967 if (!context
|| !context
->internal
->initialized
) {
970 DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n"));
976 if (!dir
|| !SMBC_dlist_contains(context
->internal
->files
, dir
)) {
979 DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n"));
985 if (dir
->file
!= False
) { /* FIXME, should be dir, perhaps */
988 DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n"));
994 if (!dir
->dir_next
) {
999 dirent
= dir
->dir_next
->dirent
;
1008 dirp
= &context
->internal
->dirent
;
1009 maxlen
= sizeof(context
->internal
->_dirent_name
);
1011 smbc_readdir_internal(context
, dirp
, dirent
, maxlen
);
1013 dir
->dir_next
= dir
->dir_next
->next
;
1020 * Routine to get directory entries
1024 SMBC_getdents_ctx(SMBCCTX
*context
,
1026 struct smbc_dirent
*dirp
,
1032 char *ndir
= (char *)dirp
;
1033 struct smbc_dir_list
*dirlist
;
1034 TALLOC_CTX
*frame
= talloc_stackframe();
1036 /* Check that all is ok first ... */
1038 if (!context
|| !context
->internal
->initialized
) {
1046 if (!dir
|| !SMBC_dlist_contains(context
->internal
->files
, dir
)) {
1054 if (dir
->file
!= False
) { /* FIXME, should be dir, perhaps */
1063 * Now, retrieve the number of entries that will fit in what was passed
1064 * We have to figure out if the info is in the list, or we need to
1065 * send a request to the server to get the info.
1068 while ((dirlist
= dir
->dir_next
)) {
1069 struct smbc_dirent
*dirent
;
1070 struct smbc_dirent
*currentEntry
= (struct smbc_dirent
*)ndir
;
1072 if (!dirlist
->dirent
) {
1074 errno
= ENOENT
; /* Bad error */
1080 /* Do urlencoding of next entry, if so selected */
1081 dirent
= &context
->internal
->dirent
;
1082 maxlen
= sizeof(context
->internal
->_dirent_name
);
1083 smbc_readdir_internal(context
, dirent
,
1084 dirlist
->dirent
, maxlen
);
1086 reqd
= dirent
->dirlen
;
1090 if (rem
< count
) { /* We managed to copy something */
1097 else { /* Nothing copied ... */
1099 errno
= EINVAL
; /* Not enough space ... */
1107 memcpy(currentEntry
, dirent
, reqd
); /* Copy the data in ... */
1109 currentEntry
->comment
= ¤tEntry
->name
[0] +
1110 dirent
->namelen
+ 1;
1115 /* Try and align the struct for the next entry
1116 on a valid pointer boundary by appending zeros */
1117 while((rem
> 0) && ((unsigned long long)ndir
& (sizeof(void*) - 1))) {
1121 currentEntry
->dirlen
++;
1124 dir
->dir_next
= dirlist
= dirlist
-> next
;
1137 * Routine to create a directory ...
1141 SMBC_mkdir_ctx(SMBCCTX
*context
,
1145 SMBCSRV
*srv
= NULL
;
1146 char *server
= NULL
;
1149 char *password
= NULL
;
1150 char *workgroup
= NULL
;
1152 char *targetpath
= NULL
;
1153 struct cli_state
*targetcli
= NULL
;
1154 TALLOC_CTX
*frame
= talloc_stackframe();
1156 if (!context
|| !context
->internal
->initialized
) {
1168 DEBUG(4, ("smbc_mkdir(%s)\n", fname
));
1170 if (SMBC_parse_path(frame
,
1185 if (!user
|| user
[0] == (char)0) {
1186 user
= talloc_strdup(frame
, smbc_getUser(context
));
1194 srv
= SMBC_server(frame
, context
, True
,
1195 server
, share
, &workgroup
, &user
, &password
);
1200 return -1; /* errno set by SMBC_server */
1204 /*d_printf(">>>mkdir: resolving %s\n", path);*/
1205 if (!cli_resolve_path(frame
, "", context
->internal
->auth_info
,
1207 &targetcli
, &targetpath
)) {
1208 d_printf("Could not resolve %s\n", path
);
1213 /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
1215 if (!NT_STATUS_IS_OK(cli_mkdir(targetcli
, targetpath
))) {
1216 errno
= SMBC_errno(context
, targetcli
);
1228 * Our list function simply checks to see if a directory is not empty
1232 rmdir_list_fn(const char *mnt
,
1233 struct file_info
*finfo
,
1237 if (strncmp(finfo
->name
, ".", 1) != 0 &&
1238 strncmp(finfo
->name
, "..", 2) != 0) {
1239 bool *smbc_rmdir_dirempty
= (bool *)state
;
1240 *smbc_rmdir_dirempty
= false;
1242 return NT_STATUS_OK
;
1246 * Routine to remove a directory
1250 SMBC_rmdir_ctx(SMBCCTX
*context
,
1253 SMBCSRV
*srv
= NULL
;
1254 char *server
= NULL
;
1257 char *password
= NULL
;
1258 char *workgroup
= NULL
;
1260 char *targetpath
= NULL
;
1261 struct cli_state
*targetcli
= NULL
;
1262 TALLOC_CTX
*frame
= talloc_stackframe();
1264 if (!context
|| !context
->internal
->initialized
) {
1276 DEBUG(4, ("smbc_rmdir(%s)\n", fname
));
1278 if (SMBC_parse_path(frame
,
1293 if (!user
|| user
[0] == (char)0) {
1294 user
= talloc_strdup(frame
, smbc_getUser(context
));
1302 srv
= SMBC_server(frame
, context
, True
,
1303 server
, share
, &workgroup
, &user
, &password
);
1308 return -1; /* errno set by SMBC_server */
1312 /*d_printf(">>>rmdir: resolving %s\n", path);*/
1313 if (!cli_resolve_path(frame
, "", context
->internal
->auth_info
,
1315 &targetcli
, &targetpath
)) {
1316 d_printf("Could not resolve %s\n", path
);
1321 /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
1323 if (!NT_STATUS_IS_OK(cli_rmdir(targetcli
, targetpath
))) {
1325 errno
= SMBC_errno(context
, targetcli
);
1327 if (errno
== EACCES
) { /* Check if the dir empty or not */
1329 /* Local storage to avoid buffer overflows */
1331 bool smbc_rmdir_dirempty
= true;
1334 lpath
= talloc_asprintf(frame
, "%s\\*",
1342 status
= cli_list(targetcli
, lpath
,
1343 aDIR
| aSYSTEM
| aHIDDEN
,
1345 &smbc_rmdir_dirempty
);
1347 if (!NT_STATUS_IS_OK(status
)) {
1348 /* Fix errno to ignore latest error ... */
1349 DEBUG(5, ("smbc_rmdir: "
1350 "cli_list returned an error: %d\n",
1351 SMBC_errno(context
, targetcli
)));
1356 if (smbc_rmdir_dirempty
)
1374 * Routine to return the current directory position
1378 SMBC_telldir_ctx(SMBCCTX
*context
,
1381 TALLOC_CTX
*frame
= talloc_stackframe();
1383 if (!context
|| !context
->internal
->initialized
) {
1391 if (!dir
|| !SMBC_dlist_contains(context
->internal
->files
, dir
)) {
1399 if (dir
->file
!= False
) { /* FIXME, should be dir, perhaps */
1407 /* See if we're already at the end. */
1408 if (dir
->dir_next
== NULL
) {
1415 * We return the pointer here as the offset
1418 return (off_t
)(long)dir
->dir_next
->dirent
;
1422 * A routine to run down the list and see if the entry is OK
1425 static struct smbc_dir_list
*
1426 check_dir_ent(struct smbc_dir_list
*list
,
1427 struct smbc_dirent
*dirent
)
1430 /* Run down the list looking for what we want */
1434 struct smbc_dir_list
*tmp
= list
;
1438 if (tmp
->dirent
== dirent
)
1447 return NULL
; /* Not found, or an error */
1453 * Routine to seek on a directory
1457 SMBC_lseekdir_ctx(SMBCCTX
*context
,
1461 long int l_offset
= offset
; /* Handle problems of size */
1462 struct smbc_dirent
*dirent
= (struct smbc_dirent
*)l_offset
;
1463 struct smbc_dir_list
*list_ent
= (struct smbc_dir_list
*)NULL
;
1464 TALLOC_CTX
*frame
= talloc_stackframe();
1466 if (!context
|| !context
->internal
->initialized
) {
1474 if (dir
->file
!= False
) { /* FIXME, should be dir, perhaps */
1482 /* Now, check what we were passed and see if it is OK ... */
1484 if (dirent
== NULL
) { /* Seek to the begining of the list */
1486 dir
->dir_next
= dir
->dir_list
;
1492 if (offset
== -1) { /* Seek to the end of the list */
1493 dir
->dir_next
= NULL
;
1498 /* Now, run down the list and make sure that the entry is OK */
1499 /* This may need to be changed if we change the format of the list */
1501 if ((list_ent
= check_dir_ent(dir
->dir_list
, dirent
)) == NULL
) {
1502 errno
= EINVAL
; /* Bad entry */
1507 dir
->dir_next
= list_ent
;
1514 * Routine to fstat a dir
1518 SMBC_fstatdir_ctx(SMBCCTX
*context
,
1523 if (!context
|| !context
->internal
->initialized
) {
1529 /* No code yet ... */
1534 SMBC_chmod_ctx(SMBCCTX
*context
,
1538 SMBCSRV
*srv
= NULL
;
1539 char *server
= NULL
;
1542 char *password
= NULL
;
1543 char *workgroup
= NULL
;
1544 char *targetpath
= NULL
;
1545 struct cli_state
*targetcli
= NULL
;
1548 TALLOC_CTX
*frame
= talloc_stackframe();
1550 if (!context
|| !context
->internal
->initialized
) {
1552 errno
= EINVAL
; /* Best I can think of ... */
1563 DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname
, (unsigned int)newmode
));
1565 if (SMBC_parse_path(frame
,
1580 if (!user
|| user
[0] == (char)0) {
1581 user
= talloc_strdup(frame
, smbc_getUser(context
));
1589 srv
= SMBC_server(frame
, context
, True
,
1590 server
, share
, &workgroup
, &user
, &password
);
1594 return -1; /* errno set by SMBC_server */
1597 /*d_printf(">>>unlink: resolving %s\n", path);*/
1598 if (!cli_resolve_path(frame
, "", context
->internal
->auth_info
,
1600 &targetcli
, &targetpath
)) {
1601 d_printf("Could not resolve %s\n", path
);
1609 if (!(newmode
& (S_IWUSR
| S_IWGRP
| S_IWOTH
))) mode
|= aRONLY
;
1610 if ((newmode
& S_IXUSR
) && lp_map_archive(-1)) mode
|= aARCH
;
1611 if ((newmode
& S_IXGRP
) && lp_map_system(-1)) mode
|= aSYSTEM
;
1612 if ((newmode
& S_IXOTH
) && lp_map_hidden(-1)) mode
|= aHIDDEN
;
1614 if (!NT_STATUS_IS_OK(cli_setatr(targetcli
, targetpath
, mode
, 0))) {
1615 errno
= SMBC_errno(context
, targetcli
);
1625 SMBC_utimes_ctx(SMBCCTX
*context
,
1627 struct timeval
*tbuf
)
1629 SMBCSRV
*srv
= NULL
;
1630 char *server
= NULL
;
1633 char *password
= NULL
;
1634 char *workgroup
= NULL
;
1638 TALLOC_CTX
*frame
= talloc_stackframe();
1640 if (!context
|| !context
->internal
->initialized
) {
1642 errno
= EINVAL
; /* Best I can think of ... */
1654 access_time
= write_time
= time(NULL
);
1656 access_time
= tbuf
[0].tv_sec
;
1657 write_time
= tbuf
[1].tv_sec
;
1665 strncpy(atimebuf
, ctime(&access_time
), sizeof(atimebuf
) - 1);
1666 atimebuf
[sizeof(atimebuf
) - 1] = '\0';
1667 if ((p
= strchr(atimebuf
, '\n')) != NULL
) {
1671 strncpy(mtimebuf
, ctime(&write_time
), sizeof(mtimebuf
) - 1);
1672 mtimebuf
[sizeof(mtimebuf
) - 1] = '\0';
1673 if ((p
= strchr(mtimebuf
, '\n')) != NULL
) {
1677 dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
1678 fname
, atimebuf
, mtimebuf
);
1681 if (SMBC_parse_path(frame
,
1696 if (!user
|| user
[0] == (char)0) {
1697 user
= talloc_strdup(frame
, smbc_getUser(context
));
1705 srv
= SMBC_server(frame
, context
, True
,
1706 server
, share
, &workgroup
, &user
, &password
);
1710 return -1; /* errno set by SMBC_server */
1713 if (!SMBC_setatr(context
, srv
, path
,
1714 0, access_time
, write_time
, 0, 0)) {
1716 return -1; /* errno set by SMBC_setatr */
1724 * Routine to unlink() a file
1728 SMBC_unlink_ctx(SMBCCTX
*context
,
1731 char *server
= NULL
;
1734 char *password
= NULL
;
1735 char *workgroup
= NULL
;
1737 char *targetpath
= NULL
;
1738 struct cli_state
*targetcli
= NULL
;
1739 SMBCSRV
*srv
= NULL
;
1740 TALLOC_CTX
*frame
= talloc_stackframe();
1742 if (!context
|| !context
->internal
->initialized
) {
1744 errno
= EINVAL
; /* Best I can think of ... */
1757 if (SMBC_parse_path(frame
,
1772 if (!user
|| user
[0] == (char)0) {
1773 user
= talloc_strdup(frame
, smbc_getUser(context
));
1781 srv
= SMBC_server(frame
, context
, True
,
1782 server
, share
, &workgroup
, &user
, &password
);
1786 return -1; /* SMBC_server sets errno */
1790 /*d_printf(">>>unlink: resolving %s\n", path);*/
1791 if (!cli_resolve_path(frame
, "", context
->internal
->auth_info
,
1793 &targetcli
, &targetpath
)) {
1794 d_printf("Could not resolve %s\n", path
);
1799 /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
1801 if (!NT_STATUS_IS_OK(cli_unlink(targetcli
, targetpath
, aSYSTEM
| aHIDDEN
))) {
1803 errno
= SMBC_errno(context
, targetcli
);
1805 if (errno
== EACCES
) { /* Check if the file is a directory */
1810 struct timespec write_time_ts
;
1811 struct timespec access_time_ts
;
1812 struct timespec change_time_ts
;
1815 if (!SMBC_getatr(context
, srv
, path
, &mode
, &size
,
1822 /* Hmmm, bad error ... What? */
1824 errno
= SMBC_errno(context
, targetcli
);
1831 if (IS_DOS_DIR(mode
))
1834 errno
= saverr
; /* Restore this */
1845 return 0; /* Success ... */
1850 * Routine to rename() a file
1854 SMBC_rename_ctx(SMBCCTX
*ocontext
,
1859 char *server1
= NULL
;
1860 char *share1
= NULL
;
1861 char *server2
= NULL
;
1862 char *share2
= NULL
;
1865 char *password1
= NULL
;
1866 char *password2
= NULL
;
1867 char *workgroup
= NULL
;
1870 char *targetpath1
= NULL
;
1871 char *targetpath2
= NULL
;
1872 struct cli_state
*targetcli1
= NULL
;
1873 struct cli_state
*targetcli2
= NULL
;
1874 SMBCSRV
*srv
= NULL
;
1875 TALLOC_CTX
*frame
= talloc_stackframe();
1877 if (!ocontext
|| !ncontext
||
1878 !ocontext
->internal
->initialized
||
1879 !ncontext
->internal
->initialized
) {
1881 errno
= EINVAL
; /* Best I can think of ... */
1886 if (!oname
|| !nname
) {
1892 DEBUG(4, ("smbc_rename(%s,%s)\n", oname
, nname
));
1894 if (SMBC_parse_path(frame
,
1909 if (!user1
|| user1
[0] == (char)0) {
1910 user1
= talloc_strdup(frame
, smbc_getUser(ocontext
));
1918 if (SMBC_parse_path(frame
,
1933 if (!user2
|| user2
[0] == (char)0) {
1934 user2
= talloc_strdup(frame
, smbc_getUser(ncontext
));
1942 if (strcmp(server1
, server2
) || strcmp(share1
, share2
) ||
1943 strcmp(user1
, user2
)) {
1944 /* Can't rename across file systems, or users?? */
1950 srv
= SMBC_server(frame
, ocontext
, True
,
1951 server1
, share1
, &workgroup
, &user1
, &password1
);
1958 /* set the credentials to make DFS work */
1959 smbc_set_credentials_with_fallback(ocontext
,
1964 /*d_printf(">>>rename: resolving %s\n", path1);*/
1965 if (!cli_resolve_path(frame
, "", ocontext
->internal
->auth_info
,
1968 &targetcli1
, &targetpath1
)) {
1969 d_printf("Could not resolve %s\n", path1
);
1975 /* set the credentials to make DFS work */
1976 smbc_set_credentials_with_fallback(ncontext
,
1981 /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
1982 /*d_printf(">>>rename: resolving %s\n", path2);*/
1983 if (!cli_resolve_path(frame
, "", ncontext
->internal
->auth_info
,
1986 &targetcli2
, &targetpath2
)) {
1987 d_printf("Could not resolve %s\n", path2
);
1992 /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
1994 if (strcmp(targetcli1
->desthost
, targetcli2
->desthost
) ||
1995 strcmp(targetcli1
->share
, targetcli2
->share
))
1997 /* can't rename across file systems */
2003 if (!NT_STATUS_IS_OK(cli_rename(targetcli1
, targetpath1
, targetpath2
))) {
2004 int eno
= SMBC_errno(ocontext
, targetcli1
);
2006 if (eno
!= EEXIST
||
2007 !NT_STATUS_IS_OK(cli_unlink(targetcli1
, targetpath2
, aSYSTEM
| aHIDDEN
)) ||
2008 !NT_STATUS_IS_OK(cli_rename(targetcli1
, targetpath1
, targetpath2
))) {
2018 return 0; /* Success */