source: branches/samba-3.2.x/source/libsmb/libsmb_dir.c

Last change on this file was 233, checked in by Herwig Bauernfeind, 16 years ago

Update 3.2 branch to 3.2.9

File size: 50.6 KB
Line 
1/*
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
10
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.
15
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.
20
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/>.
23*/
24
25#include "includes.h"
26#include "libsmbclient.h"
27#include "libsmb_internal.h"
28
29
30/*
31 * Routine to open a directory
32 * We accept the URL syntax explained in SMBC_parse_path(), above.
33 */
34
35static void
36remove_dir(SMBCFILE *dir)
37{
38 struct smbc_dir_list *d,*f;
39
40 d = dir->dir_list;
41 while (d) {
42
43 f = d; d = d->next;
44
45 SAFE_FREE(f->dirent);
46 SAFE_FREE(f);
47
48 }
49
50 dir->dir_list = dir->dir_end = dir->dir_next = NULL;
51
52}
53
54static int
55add_dirent(SMBCFILE *dir,
56 const char *name,
57 const char *comment,
58 uint32 type)
59{
60 struct smbc_dirent *dirent;
61 int size;
62 int name_length = (name == NULL ? 0 : strlen(name));
63 int comment_len = (comment == NULL ? 0 : strlen(comment));
64
65 /*
66 * Allocate space for the dirent, which must be increased by the
67 * size of the name and the comment and 1 each for the null terminator.
68 */
69
70 size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
71
72 dirent = (struct smbc_dirent *)SMB_MALLOC(size);
73
74 if (!dirent) {
75
76 dir->dir_error = ENOMEM;
77 return -1;
78
79 }
80
81 ZERO_STRUCTP(dirent);
82
83 if (dir->dir_list == NULL) {
84
85 dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
86 if (!dir->dir_list) {
87
88 SAFE_FREE(dirent);
89 dir->dir_error = ENOMEM;
90 return -1;
91
92 }
93 ZERO_STRUCTP(dir->dir_list);
94
95 dir->dir_end = dir->dir_next = dir->dir_list;
96 }
97 else {
98
99 dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
100
101 if (!dir->dir_end->next) {
102
103 SAFE_FREE(dirent);
104 dir->dir_error = ENOMEM;
105 return -1;
106
107 }
108 ZERO_STRUCTP(dir->dir_end->next);
109
110 dir->dir_end = dir->dir_end->next;
111 }
112
113 dir->dir_end->next = NULL;
114 dir->dir_end->dirent = dirent;
115
116 dirent->smbc_type = type;
117 dirent->namelen = name_length;
118 dirent->commentlen = comment_len;
119 dirent->dirlen = size;
120
121 /*
122 * dirent->namelen + 1 includes the null (no null termination needed)
123 * Ditto for dirent->commentlen.
124 * The space for the two null bytes was allocated.
125 */
126 strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
127 dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
128 strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
129
130 return 0;
131
132}
133
134static void
135list_unique_wg_fn(const char *name,
136 uint32 type,
137 const char *comment,
138 void *state)
139{
140 SMBCFILE *dir = (SMBCFILE *)state;
141 struct smbc_dir_list *dir_list;
142 struct smbc_dirent *dirent;
143 int dirent_type;
144 int do_remove = 0;
145
146 dirent_type = dir->dir_type;
147
148 if (add_dirent(dir, name, comment, dirent_type) < 0) {
149
150 /* An error occurred, what do we do? */
151 /* FIXME: Add some code here */
152 }
153
154 /* Point to the one just added */
155 dirent = dir->dir_end->dirent;
156
157 /* See if this was a duplicate */
158 for (dir_list = dir->dir_list;
159 dir_list != dir->dir_end;
160 dir_list = dir_list->next) {
161 if (! do_remove &&
162 strcmp(dir_list->dirent->name, dirent->name) == 0) {
163 /* Duplicate. End end of list need to be removed. */
164 do_remove = 1;
165 }
166
167 if (do_remove && dir_list->next == dir->dir_end) {
168 /* Found the end of the list. Remove it. */
169 dir->dir_end = dir_list;
170 free(dir_list->next);
171 free(dirent);
172 dir_list->next = NULL;
173 break;
174 }
175 }
176}
177
178static void
179list_fn(const char *name,
180 uint32 type,
181 const char *comment,
182 void *state)
183{
184 SMBCFILE *dir = (SMBCFILE *)state;
185 int dirent_type;
186
187 /*
188 * We need to process the type a little ...
189 *
190 * Disk share = 0x00000000
191 * Print share = 0x00000001
192 * Comms share = 0x00000002 (obsolete?)
193 * IPC$ share = 0x00000003
194 *
195 * administrative shares:
196 * ADMIN$, IPC$, C$, D$, E$ ... are type |= 0x80000000
197 */
198
199 if (dir->dir_type == SMBC_FILE_SHARE) {
200 switch (type) {
201 case 0 | 0x80000000:
202 case 0:
203 dirent_type = SMBC_FILE_SHARE;
204 break;
205
206 case 1:
207 dirent_type = SMBC_PRINTER_SHARE;
208 break;
209
210 case 2:
211 dirent_type = SMBC_COMMS_SHARE;
212 break;
213
214 case 3 | 0x80000000:
215 case 3:
216 dirent_type = SMBC_IPC_SHARE;
217 break;
218
219 default:
220 dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
221 break;
222 }
223 }
224 else {
225 dirent_type = dir->dir_type;
226 }
227
228 if (add_dirent(dir, name, comment, dirent_type) < 0) {
229
230 /* An error occurred, what do we do? */
231 /* FIXME: Add some code here */
232
233 }
234}
235
236static void
237dir_list_fn(const char *mnt,
238 file_info *finfo,
239 const char *mask,
240 void *state)
241{
242
243 if (add_dirent((SMBCFILE *)state, finfo->name, "",
244 (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
245
246 /* Handle an error ... */
247
248 /* FIXME: Add some code ... */
249
250 }
251
252}
253
254static int
255net_share_enum_rpc(struct cli_state *cli,
256 void (*fn)(const char *name,
257 uint32 type,
258 const char *comment,
259 void *state),
260 void *state)
261{
262 int i;
263 WERROR result;
264 uint32 preferred_len = 0xffffffff;
265 uint32 type;
266 struct srvsvc_NetShareInfoCtr info_ctr;
267 struct srvsvc_NetShareCtr1 ctr1;
268 fstring name = "";
269 fstring comment = "";
270 struct rpc_pipe_client *pipe_hnd;
271 NTSTATUS nt_status;
272 uint32_t resume_handle = 0;
273 uint32_t total_entries = 0;
274
275 /* Open the server service pipe */
276 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &nt_status);
277 if (!pipe_hnd) {
278 DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
279 return -1;
280 }
281
282 ZERO_STRUCT(info_ctr);
283 ZERO_STRUCT(ctr1);
284
285 info_ctr.level = 1;
286 info_ctr.ctr.ctr1 = &ctr1;
287
288 /* Issue the NetShareEnum RPC call and retrieve the response */
289 nt_status = rpccli_srvsvc_NetShareEnumAll(pipe_hnd, talloc_tos(),
290 pipe_hnd->cli->desthost,
291 &info_ctr,
292 preferred_len,
293 &total_entries,
294 &resume_handle,
295 &result);
296
297 /* Was it successful? */
298 if (!NT_STATUS_IS_OK(nt_status) || !W_ERROR_IS_OK(result) ||
299 total_entries == 0) {
300 /* Nope. Go clean up. */
301 goto done;
302 }
303
304 /* For each returned entry... */
305 for (i = 0; i < total_entries; i++) {
306
307 /* pull out the share name */
308 fstrcpy(name, info_ctr.ctr.ctr1->array[i].name);
309
310 /* pull out the share's comment */
311 fstrcpy(comment, info_ctr.ctr.ctr1->array[i].comment);
312
313 /* Get the type value */
314 type = info_ctr.ctr.ctr1->array[i].type;
315
316 /* Add this share to the list */
317 (*fn)(name, type, comment, state);
318 }
319
320done:
321 /* Close the server service pipe */
322 cli_rpc_pipe_close(pipe_hnd);
323
324 /* Tell 'em if it worked */
325 return W_ERROR_IS_OK(result) ? 0 : -1;
326}
327
328
329/*
330 * Verify that the options specified in a URL are valid
331 */
332int
333SMBC_check_options(char *server,
334 char *share,
335 char *path,
336 char *options)
337{
338 DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' "
339 "path='%s' options='%s'\n",
340 server, share, path, options));
341
342 /* No options at all is always ok */
343 if (! *options) return 0;
344
345 /* Currently, we don't support any options. */
346 return -1;
347}
348
349
350SMBCFILE *
351SMBC_opendir_ctx(SMBCCTX *context,
352 const char *fname)
353{
354 int saved_errno;
355 char *server = NULL;
356 char *share = NULL;
357 char *user = NULL;
358 char *password = NULL;
359 char *options = NULL;
360 char *workgroup = NULL;
361 char *path = NULL;
362 uint16 mode;
363 char *p = NULL;
364 SMBCSRV *srv = NULL;
365 SMBCFILE *dir = NULL;
366 struct sockaddr_storage rem_ss;
367 TALLOC_CTX *frame = talloc_stackframe();
368
369 if (!context || !context->internal->initialized) {
370 DEBUG(4, ("no valid context\n"));
371 errno = EINVAL + 8192;
372 TALLOC_FREE(frame);
373 return NULL;
374
375 }
376
377 if (!fname) {
378 DEBUG(4, ("no valid fname\n"));
379 errno = EINVAL + 8193;
380 TALLOC_FREE(frame);
381 return NULL;
382 }
383
384 if (SMBC_parse_path(frame,
385 context,
386 fname,
387 &workgroup,
388 &server,
389 &share,
390 &path,
391 &user,
392 &password,
393 &options)) {
394 DEBUG(4, ("no valid path\n"));
395 errno = EINVAL + 8194;
396 TALLOC_FREE(frame);
397 return NULL;
398 }
399
400 DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
401 "path='%s' options='%s'\n",
402 fname, server, share, path, options));
403
404 /* Ensure the options are valid */
405 if (SMBC_check_options(server, share, path, options)) {
406 DEBUG(4, ("unacceptable options (%s)\n", options));
407 errno = EINVAL + 8195;
408 TALLOC_FREE(frame);
409 return NULL;
410 }
411
412 if (!user || user[0] == (char)0) {
413 user = talloc_strdup(frame, smbc_getUser(context));
414 if (!user) {
415 errno = ENOMEM;
416 TALLOC_FREE(frame);
417 return NULL;
418 }
419 }
420
421 dir = SMB_MALLOC_P(SMBCFILE);
422
423 if (!dir) {
424 errno = ENOMEM;
425 TALLOC_FREE(frame);
426 return NULL;
427 }
428
429 ZERO_STRUCTP(dir);
430
431 dir->cli_fd = 0;
432 dir->fname = SMB_STRDUP(fname);
433 dir->srv = NULL;
434 dir->offset = 0;
435 dir->file = False;
436 dir->dir_list = dir->dir_next = dir->dir_end = NULL;
437
438 if (server[0] == (char)0) {
439
440 int i;
441 int count;
442 int max_lmb_count;
443 struct ip_service *ip_list;
444 struct ip_service server_addr;
445 struct user_auth_info u_info;
446
447 if (share[0] != (char)0 || path[0] != (char)0) {
448
449 errno = EINVAL + 8196;
450 if (dir) {
451 SAFE_FREE(dir->fname);
452 SAFE_FREE(dir);
453 }
454 TALLOC_FREE(frame);
455 return NULL;
456 }
457
458 /* Determine how many local master browsers to query */
459 max_lmb_count = (smbc_getOptionBrowseMaxLmbCount(context) == 0
460 ? INT_MAX
461 : smbc_getOptionBrowseMaxLmbCount(context));
462
463 memset(&u_info, '\0', sizeof(u_info));
464 u_info.username = talloc_strdup(frame,user);
465 u_info.password = talloc_strdup(frame,password);
466 if (!u_info.username || !u_info.password) {
467 if (dir) {
468 SAFE_FREE(dir->fname);
469 SAFE_FREE(dir);
470 }
471 TALLOC_FREE(frame);
472 return NULL;
473 }
474
475 /*
476 * We have server and share and path empty but options
477 * requesting that we scan all master browsers for their list
478 * of workgroups/domains. This implies that we must first try
479 * broadcast queries to find all master browsers, and if that
480 * doesn't work, then try our other methods which return only
481 * a single master browser.
482 */
483
484 ip_list = NULL;
485 if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
486 &count)))
487 {
488
489 SAFE_FREE(ip_list);
490
491 if (!find_master_ip(workgroup, &server_addr.ss)) {
492
493 if (dir) {
494 SAFE_FREE(dir->fname);
495 SAFE_FREE(dir);
496 }
497 errno = ENOENT;
498 TALLOC_FREE(frame);
499 return NULL;
500 }
501
502 ip_list = (struct ip_service *)memdup(
503 &server_addr, sizeof(server_addr));
504 if (ip_list == NULL) {
505 errno = ENOMEM;
506 TALLOC_FREE(frame);
507 return NULL;
508 }
509 count = 1;
510 }
511
512 for (i = 0; i < count && i < max_lmb_count; i++) {
513 char addr[INET6_ADDRSTRLEN];
514 char *wg_ptr = NULL;
515 struct cli_state *cli = NULL;
516
517 print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
518 DEBUG(99, ("Found master browser %d of %d: %s\n",
519 i+1, MAX(count, max_lmb_count),
520 addr));
521
522 cli = get_ipc_connect_master_ip(talloc_tos(),
523 &ip_list[i],
524 &u_info,
525 &wg_ptr);
526 /* cli == NULL is the master browser refused to talk or
527 could not be found */
528 if (!cli) {
529 continue;
530 }
531
532 workgroup = talloc_strdup(frame, wg_ptr);
533 server = talloc_strdup(frame, cli->desthost);
534
535 cli_shutdown(cli);
536
537 if (!workgroup || !server) {
538 errno = ENOMEM;
539 TALLOC_FREE(frame);
540 return NULL;
541 }
542
543 DEBUG(4, ("using workgroup %s %s\n",
544 workgroup, server));
545
546 /*
547 * For each returned master browser IP address, get a
548 * connection to IPC$ on the server if we do not
549 * already have one, and determine the
550 * workgroups/domains that it knows about.
551 */
552
553 srv = SMBC_server(frame, context, True, server, "IPC$",
554 &workgroup, &user, &password);
555 if (!srv) {
556 continue;
557 }
558
559 dir->srv = srv;
560 dir->dir_type = SMBC_WORKGROUP;
561
562 /* Now, list the stuff ... */
563
564 if (!cli_NetServerEnum(srv->cli,
565 workgroup,
566 SV_TYPE_DOMAIN_ENUM,
567 list_unique_wg_fn,
568 (void *)dir)) {
569 continue;
570 }
571 }
572
573 SAFE_FREE(ip_list);
574 } else {
575 /*
576 * Server not an empty string ... Check the rest and see what
577 * gives
578 */
579 if (*share == '\0') {
580 if (*path != '\0') {
581
582 /* Should not have empty share with path */
583 errno = EINVAL + 8197;
584 if (dir) {
585 SAFE_FREE(dir->fname);
586 SAFE_FREE(dir);
587 }
588 TALLOC_FREE(frame);
589 return NULL;
590
591 }
592
593 /*
594 * We don't know if <server> is really a server name
595 * or is a workgroup/domain name. If we already have
596 * a server structure for it, we'll use it.
597 * Otherwise, check to see if <server><1D>,
598 * <server><1B>, or <server><20> translates. We check
599 * to see if <server> is an IP address first.
600 */
601
602 /*
603 * See if we have an existing server. Do not
604 * establish a connection if one does not already
605 * exist.
606 */
607 srv = SMBC_server(frame, context, False,
608 server, "IPC$",
609 &workgroup, &user, &password);
610
611 /*
612 * If no existing server and not an IP addr, look for
613 * LMB or DMB
614 */
615 if (!srv &&
616 !is_ipaddress(server) &&
617 (resolve_name(server, &rem_ss, 0x1d) || /* LMB */
618 resolve_name(server, &rem_ss, 0x1b) )) { /* DMB */
619
620 fstring buserver;
621
622 dir->dir_type = SMBC_SERVER;
623
624 /*
625 * Get the backup list ...
626 */
627 if (!name_status_find(server, 0, 0,
628 &rem_ss, buserver)) {
629
630 DEBUG(0,("Could not get name of "
631 "local/domain master browser "
632 "for server %s\n", server));
633 if (dir) {
634 SAFE_FREE(dir->fname);
635 SAFE_FREE(dir);
636 }
637 errno = EPERM;
638 TALLOC_FREE(frame);
639 return NULL;
640
641 }
642
643 /*
644 * Get a connection to IPC$ on the server if
645 * we do not already have one
646 */
647 srv = SMBC_server(frame, context, True,
648 buserver, "IPC$",
649 &workgroup,
650 &user, &password);
651 if (!srv) {
652 DEBUG(0, ("got no contact to IPC$\n"));
653 if (dir) {
654 SAFE_FREE(dir->fname);
655 SAFE_FREE(dir);
656 }
657 TALLOC_FREE(frame);
658 return NULL;
659
660 }
661
662 dir->srv = srv;
663
664 /* Now, list the servers ... */
665 if (!cli_NetServerEnum(srv->cli, server,
666 0x0000FFFE, list_fn,
667 (void *)dir)) {
668
669 if (dir) {
670 SAFE_FREE(dir->fname);
671 SAFE_FREE(dir);
672 }
673 TALLOC_FREE(frame);
674 return NULL;
675 }
676 } else if (srv ||
677 (resolve_name(server, &rem_ss, 0x20))) {
678
679 /*
680 * If we hadn't found the server, get one now
681 */
682 if (!srv) {
683 srv = SMBC_server(frame, context, True,
684 server, "IPC$",
685 &workgroup,
686 &user, &password);
687 }
688
689 if (!srv) {
690 if (dir) {
691 SAFE_FREE(dir->fname);
692 SAFE_FREE(dir);
693 }
694 TALLOC_FREE(frame);
695 return NULL;
696
697 }
698
699 dir->dir_type = SMBC_FILE_SHARE;
700 dir->srv = srv;
701
702 /* List the shares ... */
703
704 if (net_share_enum_rpc(
705 srv->cli,
706 list_fn,
707 (void *) dir) < 0 &&
708 cli_RNetShareEnum(
709 srv->cli,
710 list_fn,
711 (void *)dir) < 0) {
712
713 errno = cli_errno(srv->cli);
714 if (dir) {
715 SAFE_FREE(dir->fname);
716 SAFE_FREE(dir);
717 }
718 TALLOC_FREE(frame);
719 return NULL;
720
721 }
722 } else {
723 /* Neither the workgroup nor server exists */
724 errno = ECONNREFUSED;
725 if (dir) {
726 SAFE_FREE(dir->fname);
727 SAFE_FREE(dir);
728 }
729 TALLOC_FREE(frame);
730 return NULL;
731 }
732
733 }
734 else {
735 /*
736 * The server and share are specified ... work from
737 * there ...
738 */
739 char *targetpath;
740 struct cli_state *targetcli;
741
742 /* We connect to the server and list the directory */
743 dir->dir_type = SMBC_FILE_SHARE;
744
745 srv = SMBC_server(frame, context, True, server, share,
746 &workgroup, &user, &password);
747
748 if (!srv) {
749 if (dir) {
750 SAFE_FREE(dir->fname);
751 SAFE_FREE(dir);
752 }
753 TALLOC_FREE(frame);
754 return NULL;
755 }
756
757 dir->srv = srv;
758
759 /* Now, list the files ... */
760
761 p = path + strlen(path);
762 path = talloc_asprintf_append(path, "\\*");
763 if (!path) {
764 if (dir) {
765 SAFE_FREE(dir->fname);
766 SAFE_FREE(dir);
767 }
768 TALLOC_FREE(frame);
769 return NULL;
770 }
771
772 if (!cli_resolve_path(frame, "", srv->cli, path,
773 &targetcli, &targetpath)) {
774 d_printf("Could not resolve %s\n", path);
775 if (dir) {
776 SAFE_FREE(dir->fname);
777 SAFE_FREE(dir);
778 }
779 TALLOC_FREE(frame);
780 return NULL;
781 }
782
783 if (cli_list(targetcli, targetpath,
784 aDIR | aSYSTEM | aHIDDEN,
785 dir_list_fn, (void *)dir) < 0) {
786
787 if (dir) {
788 SAFE_FREE(dir->fname);
789 SAFE_FREE(dir);
790 }
791 saved_errno = SMBC_errno(context, targetcli);
792
793 if (saved_errno == EINVAL) {
794 /*
795 * See if they asked to opendir
796 * something other than a directory.
797 * If so, the converted error value we
798 * got would have been EINVAL rather
799 * than ENOTDIR.
800 */
801 *p = '\0'; /* restore original path */
802
803 if (SMBC_getatr(context, srv, path,
804 &mode, NULL,
805 NULL, NULL, NULL, NULL,
806 NULL) &&
807 ! IS_DOS_DIR(mode)) {
808
809 /* It is. Correct the error value */
810 DEBUG( 0, ( "PS - ENOTDIR5\n" ) );
811 saved_errno = ENOTDIR;
812 }
813 }
814
815 /*
816 * If there was an error and the server is no
817 * good any more...
818 */
819 if (cli_is_error(targetcli) &&
820 smbc_getFunctionCheckServer(context)(context, srv)) {
821
822 /* ... then remove it. */
823 if (smbc_getFunctionRemoveUnusedServer(context)(context,
824 srv)) {
825 /*
826 * We could not remove the
827 * server completely, remove
828 * it from the cache so we
829 * will not get it again. It
830 * will be removed when the
831 * last file/dir is closed.
832 */
833 smbc_getFunctionRemoveCachedServer(context)(context, srv);
834 }
835 }
836
837 errno = saved_errno;
838 TALLOC_FREE(frame);
839 return NULL;
840 }
841 }
842
843 }
844
845 DLIST_ADD(context->internal->files, dir);
846 TALLOC_FREE(frame);
847 return dir;
848
849}
850
851/*
852 * Routine to close a directory
853 */
854
855int
856SMBC_closedir_ctx(SMBCCTX *context,
857 SMBCFILE *dir)
858{
859 TALLOC_CTX *frame = talloc_stackframe();
860
861 if (!context || !context->internal->initialized) {
862 errno = EINVAL;
863 TALLOC_FREE(frame);
864 return -1;
865 }
866
867 if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
868 errno = EBADF;
869 TALLOC_FREE(frame);
870 return -1;
871 }
872
873 remove_dir(dir); /* Clean it up */
874
875 DLIST_REMOVE(context->internal->files, dir);
876
877 if (dir) {
878
879 SAFE_FREE(dir->fname);
880 SAFE_FREE(dir); /* Free the space too */
881 }
882
883 TALLOC_FREE(frame);
884 return 0;
885
886}
887
888static void
889smbc_readdir_internal(SMBCCTX * context,
890 struct smbc_dirent *dest,
891 struct smbc_dirent *src,
892 int max_namebuf_len)
893{
894 if (smbc_getOptionUrlEncodeReaddirEntries(context)) {
895
896 /* url-encode the name. get back remaining buffer space */
897 max_namebuf_len =
898 smbc_urlencode(dest->name, src->name, max_namebuf_len);
899
900 /* We now know the name length */
901 dest->namelen = strlen(dest->name);
902
903 /* Save the pointer to the beginning of the comment */
904 dest->comment = dest->name + dest->namelen + 1;
905
906 /* Copy the comment */
907 strncpy(dest->comment, src->comment, max_namebuf_len - 1);
908 dest->comment[max_namebuf_len - 1] = '\0';
909
910 /* Save other fields */
911 dest->smbc_type = src->smbc_type;
912 dest->commentlen = strlen(dest->comment);
913 dest->dirlen = ((dest->comment + dest->commentlen + 1) -
914 (char *) dest);
915 } else {
916
917 /* No encoding. Just copy the entry as is. */
918 memcpy(dest, src, src->dirlen);
919 dest->comment = (char *)(&dest->name + src->namelen + 1);
920 }
921
922}
923
924/*
925 * Routine to get a directory entry
926 */
927
928struct smbc_dirent *
929SMBC_readdir_ctx(SMBCCTX *context,
930 SMBCFILE *dir)
931{
932 int maxlen;
933 struct smbc_dirent *dirp, *dirent;
934 TALLOC_CTX *frame = talloc_stackframe();
935
936 /* Check that all is ok first ... */
937
938 if (!context || !context->internal->initialized) {
939
940 errno = EINVAL;
941 DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n"));
942 TALLOC_FREE(frame);
943 return NULL;
944
945 }
946
947 if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
948
949 errno = EBADF;
950 DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n"));
951 TALLOC_FREE(frame);
952 return NULL;
953
954 }
955
956 if (dir->file != False) { /* FIXME, should be dir, perhaps */
957
958 DEBUG( 0, ( "PS - ENOTDIR6\n" ) );
959 errno = ENOTDIR;
960 DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n"));
961 TALLOC_FREE(frame);
962 return NULL;
963
964 }
965
966 if (!dir->dir_next) {
967 TALLOC_FREE(frame);
968 return NULL;
969 }
970
971 dirent = dir->dir_next->dirent;
972 if (!dirent) {
973
974 errno = ENOENT;
975 TALLOC_FREE(frame);
976 return NULL;
977
978 }
979
980 dirp = &context->internal->dirent;
981 maxlen = sizeof(context->internal->_dirent_name);
982
983 smbc_readdir_internal(context, dirp, dirent, maxlen);
984
985 dir->dir_next = dir->dir_next->next;
986
987 TALLOC_FREE(frame);
988 return dirp;
989}
990
991/*
992 * Routine to get directory entries
993 */
994
995int
996SMBC_getdents_ctx(SMBCCTX *context,
997 SMBCFILE *dir,
998 struct smbc_dirent *dirp,
999 int count)
1000{
1001 int rem = count;
1002 int reqd;
1003 int maxlen;
1004 char *ndir = (char *)dirp;
1005 struct smbc_dir_list *dirlist;
1006 TALLOC_CTX *frame = talloc_stackframe();
1007
1008 /* Check that all is ok first ... */
1009
1010 if (!context || !context->internal->initialized) {
1011
1012 errno = EINVAL;
1013 TALLOC_FREE(frame);
1014 return -1;
1015
1016 }
1017
1018 if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
1019
1020 errno = EBADF;
1021 TALLOC_FREE(frame);
1022 return -1;
1023
1024 }
1025
1026 if (dir->file != False) { /* FIXME, should be dir, perhaps */
1027
1028 DEBUG( 0, ( "PS - ENOTDIR7\n" ) );
1029 errno = ENOTDIR;
1030 TALLOC_FREE(frame);
1031 return -1;
1032
1033 }
1034
1035 /*
1036 * Now, retrieve the number of entries that will fit in what was passed
1037 * We have to figure out if the info is in the list, or we need to
1038 * send a request to the server to get the info.
1039 */
1040
1041 while ((dirlist = dir->dir_next)) {
1042 struct smbc_dirent *dirent;
1043
1044 if (!dirlist->dirent) {
1045
1046 errno = ENOENT; /* Bad error */
1047 TALLOC_FREE(frame);
1048 return -1;
1049
1050 }
1051
1052 /* Do urlencoding of next entry, if so selected */
1053 dirent = &context->internal->dirent;
1054 maxlen = sizeof(context->internal->_dirent_name);
1055 smbc_readdir_internal(context, dirent,
1056 dirlist->dirent, maxlen);
1057
1058 reqd = dirent->dirlen;
1059
1060 if (rem < reqd) {
1061
1062 if (rem < count) { /* We managed to copy something */
1063
1064 errno = 0;
1065 TALLOC_FREE(frame);
1066 return count - rem;
1067
1068 }
1069 else { /* Nothing copied ... */
1070
1071 errno = EINVAL; /* Not enough space ... */
1072 TALLOC_FREE(frame);
1073 return -1;
1074
1075 }
1076
1077 }
1078
1079 memcpy(ndir, dirent, reqd); /* Copy the data in ... */
1080
1081 ((struct smbc_dirent *)ndir)->comment =
1082 (char *)(&((struct smbc_dirent *)ndir)->name +
1083 dirent->namelen +
1084 1);
1085
1086 ndir += reqd;
1087
1088 rem -= reqd;
1089
1090 dir->dir_next = dirlist = dirlist -> next;
1091 }
1092
1093 TALLOC_FREE(frame);
1094
1095 if (rem == count)
1096 return 0;
1097 else
1098 return count - rem;
1099
1100}
1101
1102/*
1103 * Routine to create a directory ...
1104 */
1105
1106int
1107SMBC_mkdir_ctx(SMBCCTX *context,
1108 const char *fname,
1109 mode_t mode)
1110{
1111 SMBCSRV *srv = NULL;
1112 char *server = NULL;
1113 char *share = NULL;
1114 char *user = NULL;
1115 char *password = NULL;
1116 char *workgroup = NULL;
1117 char *path = NULL;
1118 char *targetpath = NULL;
1119 struct cli_state *targetcli = NULL;
1120 TALLOC_CTX *frame = talloc_stackframe();
1121
1122 if (!context || !context->internal->initialized) {
1123 errno = EINVAL;
1124 TALLOC_FREE(frame);
1125 return -1;
1126 }
1127
1128 if (!fname) {
1129 errno = EINVAL;
1130 TALLOC_FREE(frame);
1131 return -1;
1132 }
1133
1134 DEBUG(4, ("smbc_mkdir(%s)\n", fname));
1135
1136 if (SMBC_parse_path(frame,
1137 context,
1138 fname,
1139 &workgroup,
1140 &server,
1141 &share,
1142 &path,
1143 &user,
1144 &password,
1145 NULL)) {
1146 errno = EINVAL;
1147 TALLOC_FREE(frame);
1148 return -1;
1149 }
1150
1151 if (!user || user[0] == (char)0) {
1152 user = talloc_strdup(frame, smbc_getUser(context));
1153 if (!user) {
1154 errno = ENOMEM;
1155 TALLOC_FREE(frame);
1156 return -1;
1157 }
1158 }
1159
1160 srv = SMBC_server(frame, context, True,
1161 server, share, &workgroup, &user, &password);
1162
1163 if (!srv) {
1164
1165 TALLOC_FREE(frame);
1166 return -1; /* errno set by SMBC_server */
1167
1168 }
1169
1170 /*d_printf(">>>mkdir: resolving %s\n", path);*/
1171 if (!cli_resolve_path(frame, "", srv->cli, path,
1172 &targetcli, &targetpath)) {
1173 d_printf("Could not resolve %s\n", path);
1174 errno = ENOENT;
1175 TALLOC_FREE(frame);
1176 return -1;
1177 }
1178 /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
1179
1180 if (!cli_mkdir(targetcli, targetpath)) {
1181
1182 errno = SMBC_errno(context, targetcli);
1183 TALLOC_FREE(frame);
1184 return -1;
1185
1186 }
1187
1188 TALLOC_FREE(frame);
1189 return 0;
1190
1191}
1192
1193/*
1194 * Our list function simply checks to see if a directory is not empty
1195 */
1196
1197static int smbc_rmdir_dirempty = True;
1198
1199static void
1200rmdir_list_fn(const char *mnt,
1201 file_info *finfo,
1202 const char *mask,
1203 void *state)
1204{
1205 if (strncmp(finfo->name, ".", 1) != 0 &&
1206 strncmp(finfo->name, "..", 2) != 0) {
1207 smbc_rmdir_dirempty = False;
1208 }
1209}
1210
1211/*
1212 * Routine to remove a directory
1213 */
1214
1215int
1216SMBC_rmdir_ctx(SMBCCTX *context,
1217 const char *fname)
1218{
1219 SMBCSRV *srv = NULL;
1220 char *server = NULL;
1221 char *share = NULL;
1222 char *user = NULL;
1223 char *password = NULL;
1224 char *workgroup = NULL;
1225 char *path = NULL;
1226 char *targetpath = NULL;
1227 struct cli_state *targetcli = NULL;
1228 TALLOC_CTX *frame = talloc_stackframe();
1229
1230 if (!context || !context->internal->initialized) {
1231 errno = EINVAL;
1232 TALLOC_FREE(frame);
1233 return -1;
1234 }
1235
1236 if (!fname) {
1237 errno = EINVAL;
1238 TALLOC_FREE(frame);
1239 return -1;
1240 }
1241
1242 DEBUG(4, ("smbc_rmdir(%s)\n", fname));
1243
1244 if (SMBC_parse_path(frame,
1245 context,
1246 fname,
1247 &workgroup,
1248 &server,
1249 &share,
1250 &path,
1251 &user,
1252 &password,
1253 NULL)) {
1254 errno = EINVAL;
1255 TALLOC_FREE(frame);
1256 return -1;
1257 }
1258
1259 if (!user || user[0] == (char)0) {
1260 user = talloc_strdup(frame, smbc_getUser(context));
1261 if (!user) {
1262 errno = ENOMEM;
1263 TALLOC_FREE(frame);
1264 return -1;
1265 }
1266 }
1267
1268 srv = SMBC_server(frame, context, True,
1269 server, share, &workgroup, &user, &password);
1270
1271 if (!srv) {
1272
1273 TALLOC_FREE(frame);
1274 return -1; /* errno set by SMBC_server */
1275
1276 }
1277
1278 /*d_printf(">>>rmdir: resolving %s\n", path);*/
1279 if (!cli_resolve_path(frame, "", srv->cli, path,
1280 &targetcli, &targetpath)) {
1281 d_printf("Could not resolve %s\n", path);
1282 errno = ENOENT;
1283 TALLOC_FREE(frame);
1284 return -1;
1285 }
1286 /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
1287
1288
1289 if (!cli_rmdir(targetcli, targetpath)) {
1290
1291 errno = SMBC_errno(context, targetcli);
1292
1293 if (errno == EACCES) { /* Check if the dir empty or not */
1294
1295 /* Local storage to avoid buffer overflows */
1296 char *lpath;
1297
1298 smbc_rmdir_dirempty = True; /* Make this so ... */
1299
1300 lpath = talloc_asprintf(frame, "%s\\*",
1301 targetpath);
1302 if (!lpath) {
1303 errno = ENOMEM;
1304 TALLOC_FREE(frame);
1305 return -1;
1306 }
1307
1308 if (cli_list(targetcli, lpath,
1309 aDIR | aSYSTEM | aHIDDEN,
1310 rmdir_list_fn, NULL) < 0) {
1311
1312 /* Fix errno to ignore latest error ... */
1313 DEBUG(5, ("smbc_rmdir: "
1314 "cli_list returned an error: %d\n",
1315 SMBC_errno(context, targetcli)));
1316 errno = EACCES;
1317
1318 }
1319
1320 if (smbc_rmdir_dirempty)
1321 errno = EACCES;
1322 else
1323 errno = ENOTEMPTY;
1324
1325 }
1326
1327 TALLOC_FREE(frame);
1328 return -1;
1329
1330 }
1331
1332 TALLOC_FREE(frame);
1333 return 0;
1334
1335}
1336
1337/*
1338 * Routine to return the current directory position
1339 */
1340
1341off_t
1342SMBC_telldir_ctx(SMBCCTX *context,
1343 SMBCFILE *dir)
1344{
1345 TALLOC_CTX *frame = talloc_stackframe();
1346
1347 if (!context || !context->internal->initialized) {
1348
1349 errno = EINVAL;
1350 TALLOC_FREE(frame);
1351 return -1;
1352
1353 }
1354
1355 if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
1356
1357 errno = EBADF;
1358 TALLOC_FREE(frame);
1359 return -1;
1360
1361 }
1362
1363 if (dir->file != False) { /* FIXME, should be dir, perhaps */
1364
1365 DEBUG( 0, ( "PS - ENOTDIR8\n" ) );
1366 errno = ENOTDIR;
1367 TALLOC_FREE(frame);
1368 return -1;
1369
1370 }
1371
1372 /* See if we're already at the end. */
1373 if (dir->dir_next == NULL) {
1374 /* We are. */
1375 TALLOC_FREE(frame);
1376 return -1;
1377 }
1378
1379 /*
1380 * We return the pointer here as the offset
1381 */
1382 TALLOC_FREE(frame);
1383 return (off_t)(long)dir->dir_next->dirent;
1384}
1385
1386/*
1387 * A routine to run down the list and see if the entry is OK
1388 */
1389
1390static struct smbc_dir_list *
1391check_dir_ent(struct smbc_dir_list *list,
1392 struct smbc_dirent *dirent)
1393{
1394
1395 /* Run down the list looking for what we want */
1396
1397 if (dirent) {
1398
1399 struct smbc_dir_list *tmp = list;
1400
1401 while (tmp) {
1402
1403 if (tmp->dirent == dirent)
1404 return tmp;
1405
1406 tmp = tmp->next;
1407
1408 }
1409
1410 }
1411
1412 return NULL; /* Not found, or an error */
1413
1414}
1415
1416
1417/*
1418 * Routine to seek on a directory
1419 */
1420
1421int
1422SMBC_lseekdir_ctx(SMBCCTX *context,
1423 SMBCFILE *dir,
1424 off_t offset)
1425{
1426 long int l_offset = offset; /* Handle problems of size */
1427 struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
1428 struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL;
1429 TALLOC_CTX *frame = talloc_stackframe();
1430
1431 if (!context || !context->internal->initialized) {
1432
1433 errno = EINVAL;
1434 TALLOC_FREE(frame);
1435 return -1;
1436
1437 }
1438
1439 if (dir->file != False) { /* FIXME, should be dir, perhaps */
1440
1441 DEBUG( 0, ( "PS - ENOTDIR9\n" ) );
1442 errno = ENOTDIR;
1443 TALLOC_FREE(frame);
1444 return -1;
1445
1446 }
1447
1448 /* Now, check what we were passed and see if it is OK ... */
1449
1450 if (dirent == NULL) { /* Seek to the begining of the list */
1451
1452 dir->dir_next = dir->dir_list;
1453 TALLOC_FREE(frame);
1454 return 0;
1455
1456 }
1457
1458 if (offset == -1) { /* Seek to the end of the list */
1459 dir->dir_next = NULL;
1460 TALLOC_FREE(frame);
1461 return 0;
1462 }
1463
1464 /* Now, run down the list and make sure that the entry is OK */
1465 /* This may need to be changed if we change the format of the list */
1466
1467 if ((list_ent = check_dir_ent(dir->dir_list, dirent)) == NULL) {
1468 errno = EINVAL; /* Bad entry */
1469 TALLOC_FREE(frame);
1470 return -1;
1471 }
1472
1473 dir->dir_next = list_ent;
1474
1475 TALLOC_FREE(frame);
1476 return 0;
1477}
1478
1479/*
1480 * Routine to fstat a dir
1481 */
1482
1483int
1484SMBC_fstatdir_ctx(SMBCCTX *context,
1485 SMBCFILE *dir,
1486 struct stat *st)
1487{
1488
1489 if (!context || !context->internal->initialized) {
1490
1491 errno = EINVAL;
1492 return -1;
1493 }
1494
1495 /* No code yet ... */
1496 return 0;
1497}
1498
1499int
1500SMBC_chmod_ctx(SMBCCTX *context,
1501 const char *fname,
1502 mode_t newmode)
1503{
1504 SMBCSRV *srv = NULL;
1505 char *server = NULL;
1506 char *share = NULL;
1507 char *user = NULL;
1508 char *password = NULL;
1509 char *workgroup = NULL;
1510 char *path = NULL;
1511 uint16 mode;
1512 TALLOC_CTX *frame = talloc_stackframe();
1513
1514 if (!context || !context->internal->initialized) {
1515
1516 errno = EINVAL; /* Best I can think of ... */
1517 TALLOC_FREE(frame);
1518 return -1;
1519 }
1520
1521 if (!fname) {
1522 errno = EINVAL;
1523 TALLOC_FREE(frame);
1524 return -1;
1525 }
1526
1527 DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode));
1528
1529 if (SMBC_parse_path(frame,
1530 context,
1531 fname,
1532 &workgroup,
1533 &server,
1534 &share,
1535 &path,
1536 &user,
1537 &password,
1538 NULL)) {
1539 errno = EINVAL;
1540 TALLOC_FREE(frame);
1541 return -1;
1542 }
1543
1544 if (!user || user[0] == (char)0) {
1545 user = talloc_strdup(frame, smbc_getUser(context));
1546 if (!user) {
1547 errno = ENOMEM;
1548 TALLOC_FREE(frame);
1549 return -1;
1550 }
1551 }
1552
1553 srv = SMBC_server(frame, context, True,
1554 server, share, &workgroup, &user, &password);
1555
1556 if (!srv) {
1557 TALLOC_FREE(frame);
1558 return -1; /* errno set by SMBC_server */
1559 }
1560
1561 mode = 0;
1562
1563 if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
1564 if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
1565 if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
1566 if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
1567
1568 if (!cli_setatr(srv->cli, path, mode, 0)) {
1569 errno = SMBC_errno(context, srv->cli);
1570 TALLOC_FREE(frame);
1571 return -1;
1572 }
1573
1574 TALLOC_FREE(frame);
1575 return 0;
1576}
1577
1578int
1579SMBC_utimes_ctx(SMBCCTX *context,
1580 const char *fname,
1581 struct timeval *tbuf)
1582{
1583 SMBCSRV *srv = NULL;
1584 char *server = NULL;
1585 char *share = NULL;
1586 char *user = NULL;
1587 char *password = NULL;
1588 char *workgroup = NULL;
1589 char *path = NULL;
1590 time_t access_time;
1591 time_t write_time;
1592 TALLOC_CTX *frame = talloc_stackframe();
1593
1594 if (!context || !context->internal->initialized) {
1595
1596 errno = EINVAL; /* Best I can think of ... */
1597 TALLOC_FREE(frame);
1598 return -1;
1599 }
1600
1601 if (!fname) {
1602 errno = EINVAL;
1603 TALLOC_FREE(frame);
1604 return -1;
1605 }
1606
1607 if (tbuf == NULL) {
1608 access_time = write_time = time(NULL);
1609 } else {
1610 access_time = tbuf[0].tv_sec;
1611 write_time = tbuf[1].tv_sec;
1612 }
1613
1614 if (DEBUGLVL(4)) {
1615 char *p;
1616 char atimebuf[32];
1617 char mtimebuf[32];
1618
1619 strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1);
1620 atimebuf[sizeof(atimebuf) - 1] = '\0';
1621 if ((p = strchr(atimebuf, '\n')) != NULL) {
1622 *p = '\0';
1623 }
1624
1625 strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1);
1626 mtimebuf[sizeof(mtimebuf) - 1] = '\0';
1627 if ((p = strchr(mtimebuf, '\n')) != NULL) {
1628 *p = '\0';
1629 }
1630
1631 dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
1632 fname, atimebuf, mtimebuf);
1633 }
1634
1635 if (SMBC_parse_path(frame,
1636 context,
1637 fname,
1638 &workgroup,
1639 &server,
1640 &share,
1641 &path,
1642 &user,
1643 &password,
1644 NULL)) {
1645 errno = EINVAL;
1646 TALLOC_FREE(frame);
1647 return -1;
1648 }
1649
1650 if (!user || user[0] == (char)0) {
1651 user = talloc_strdup(frame, smbc_getUser(context));
1652 if (!user) {
1653 errno = ENOMEM;
1654 TALLOC_FREE(frame);
1655 return -1;
1656 }
1657 }
1658
1659 srv = SMBC_server(frame, context, True,
1660 server, share, &workgroup, &user, &password);
1661
1662 if (!srv) {
1663 TALLOC_FREE(frame);
1664 return -1; /* errno set by SMBC_server */
1665 }
1666
1667 if (!SMBC_setatr(context, srv, path,
1668 0, access_time, write_time, 0, 0)) {
1669 TALLOC_FREE(frame);
1670 return -1; /* errno set by SMBC_setatr */
1671 }
1672
1673 TALLOC_FREE(frame);
1674 return 0;
1675}
1676
1677/*
1678 * Routine to unlink() a file
1679 */
1680
1681int
1682SMBC_unlink_ctx(SMBCCTX *context,
1683 const char *fname)
1684{
1685 char *server = NULL;
1686 char *share = NULL;
1687 char *user = NULL;
1688 char *password = NULL;
1689 char *workgroup = NULL;
1690 char *path = NULL;
1691 char *targetpath = NULL;
1692 struct cli_state *targetcli = NULL;
1693 SMBCSRV *srv = NULL;
1694 TALLOC_CTX *frame = talloc_stackframe();
1695
1696 if (!context || !context->internal->initialized) {
1697
1698 errno = EINVAL; /* Best I can think of ... */
1699 TALLOC_FREE(frame);
1700 return -1;
1701
1702 }
1703
1704 if (!fname) {
1705 errno = EINVAL;
1706 TALLOC_FREE(frame);
1707 return -1;
1708
1709 }
1710
1711 if (SMBC_parse_path(frame,
1712 context,
1713 fname,
1714 &workgroup,
1715 &server,
1716 &share,
1717 &path,
1718 &user,
1719 &password,
1720 NULL)) {
1721 errno = EINVAL;
1722 TALLOC_FREE(frame);
1723 return -1;
1724 }
1725
1726 if (!user || user[0] == (char)0) {
1727 user = talloc_strdup(frame, smbc_getUser(context));
1728 if (!user) {
1729 errno = ENOMEM;
1730 TALLOC_FREE(frame);
1731 return -1;
1732 }
1733 }
1734
1735 srv = SMBC_server(frame, context, True,
1736 server, share, &workgroup, &user, &password);
1737
1738 if (!srv) {
1739 TALLOC_FREE(frame);
1740 return -1; /* SMBC_server sets errno */
1741
1742 }
1743
1744 /*d_printf(">>>unlink: resolving %s\n", path);*/
1745 if (!cli_resolve_path(frame, "", srv->cli, path,
1746 &targetcli, &targetpath)) {
1747 d_printf("Could not resolve %s\n", path);
1748 errno = ENOENT;
1749 errno = ENOENT;
1750 TALLOC_FREE(frame);
1751 return -1;
1752 }
1753 /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
1754
1755 if (!cli_unlink(targetcli, targetpath)) {
1756
1757 errno = SMBC_errno(context, targetcli);
1758
1759 if (errno == EACCES) { /* Check if the file is a directory */
1760
1761 int saverr = errno;
1762 SMB_OFF_T size = 0;
1763 uint16 mode = 0;
1764 struct timespec write_time_ts;
1765 struct timespec access_time_ts;
1766 struct timespec change_time_ts;
1767 SMB_INO_T ino = 0;
1768
1769 if (!SMBC_getatr(context, srv, path, &mode, &size,
1770 NULL,
1771 &access_time_ts,
1772 &write_time_ts,
1773 &change_time_ts,
1774 &ino)) {
1775
1776 /* Hmmm, bad error ... What? */
1777
1778 errno = SMBC_errno(context, targetcli);
1779 TALLOC_FREE(frame);
1780 return -1;
1781
1782 }
1783 else {
1784
1785 if (IS_DOS_DIR(mode))
1786 errno = EISDIR;
1787 else
1788 errno = saverr; /* Restore this */
1789
1790 }
1791 }
1792
1793 TALLOC_FREE(frame);
1794 return -1;
1795
1796 }
1797
1798 TALLOC_FREE(frame);
1799 return 0; /* Success ... */
1800
1801}
1802
1803/*
1804 * Routine to rename() a file
1805 */
1806
1807int
1808SMBC_rename_ctx(SMBCCTX *ocontext,
1809 const char *oname,
1810 SMBCCTX *ncontext,
1811 const char *nname)
1812{
1813 char *server1 = NULL;
1814 char *share1 = NULL;
1815 char *server2 = NULL;
1816 char *share2 = NULL;
1817 char *user1 = NULL;
1818 char *user2 = NULL;
1819 char *password1 = NULL;
1820 char *password2 = NULL;
1821 char *workgroup = NULL;
1822 char *path1 = NULL;
1823 char *path2 = NULL;
1824 char *targetpath1 = NULL;
1825 char *targetpath2 = NULL;
1826 struct cli_state *targetcli1 = NULL;
1827 struct cli_state *targetcli2 = NULL;
1828 SMBCSRV *srv = NULL;
1829 TALLOC_CTX *frame = talloc_stackframe();
1830
1831 if (!ocontext || !ncontext ||
1832 !ocontext->internal->initialized ||
1833 !ncontext->internal->initialized) {
1834
1835 errno = EINVAL; /* Best I can think of ... */
1836 TALLOC_FREE(frame);
1837 return -1;
1838 }
1839
1840 if (!oname || !nname) {
1841 errno = EINVAL;
1842 TALLOC_FREE(frame);
1843 return -1;
1844 }
1845
1846 DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
1847
1848 if (SMBC_parse_path(frame,
1849 ocontext,
1850 oname,
1851 &workgroup,
1852 &server1,
1853 &share1,
1854 &path1,
1855 &user1,
1856 &password1,
1857 NULL)) {
1858 errno = EINVAL;
1859 TALLOC_FREE(frame);
1860 return -1;
1861 }
1862
1863 if (!user1 || user1[0] == (char)0) {
1864 user1 = talloc_strdup(frame, smbc_getUser(ocontext));
1865 if (!user1) {
1866 errno = ENOMEM;
1867 TALLOC_FREE(frame);
1868 return -1;
1869 }
1870 }
1871
1872 if (SMBC_parse_path(frame,
1873 ncontext,
1874 nname,
1875 NULL,
1876 &server2,
1877 &share2,
1878 &path2,
1879 &user2,
1880 &password2,
1881 NULL)) {
1882 errno = EINVAL;
1883 TALLOC_FREE(frame);
1884 return -1;
1885 }
1886
1887 if (!user2 || user2[0] == (char)0) {
1888 user2 = talloc_strdup(frame, smbc_getUser(ncontext));
1889 if (!user2) {
1890 errno = ENOMEM;
1891 TALLOC_FREE(frame);
1892 return -1;
1893 }
1894 }
1895
1896 if (strcmp(server1, server2) || strcmp(share1, share2) ||
1897 strcmp(user1, user2)) {
1898 /* Can't rename across file systems, or users?? */
1899 errno = EXDEV;
1900 TALLOC_FREE(frame);
1901 return -1;
1902 }
1903
1904 srv = SMBC_server(frame, ocontext, True,
1905 server1, share1, &workgroup, &user1, &password1);
1906 if (!srv) {
1907 TALLOC_FREE(frame);
1908 return -1;
1909
1910 }
1911
1912 /*d_printf(">>>rename: resolving %s\n", path1);*/
1913 if (!cli_resolve_path(frame, "", srv->cli, path1,
1914 &targetcli1, &targetpath1)) {
1915 d_printf("Could not resolve %s\n", path1);
1916 errno = ENOENT;
1917 TALLOC_FREE(frame);
1918 return -1;
1919 }
1920 /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
1921 /*d_printf(">>>rename: resolving %s\n", path2);*/
1922 if (!cli_resolve_path(frame, "", srv->cli, path2,
1923 &targetcli2, &targetpath2)) {
1924 d_printf("Could not resolve %s\n", path2);
1925 errno = ENOENT;
1926 TALLOC_FREE(frame);
1927 return -1;
1928 }
1929 /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
1930
1931 if (strcmp(targetcli1->desthost, targetcli2->desthost) ||
1932 strcmp(targetcli1->share, targetcli2->share))
1933 {
1934 /* can't rename across file systems */
1935 errno = EXDEV;
1936 TALLOC_FREE(frame);
1937 return -1;
1938 }
1939
1940 if (!cli_rename(targetcli1, targetpath1, targetpath2)) {
1941 int eno = SMBC_errno(ocontext, targetcli1);
1942
1943 if (eno != EEXIST ||
1944 !cli_unlink(targetcli1, targetpath2) ||
1945 !cli_rename(targetcli1, targetpath1, targetpath2)) {
1946
1947 errno = eno;
1948 TALLOC_FREE(frame);
1949 return -1;
1950
1951 }
1952 }
1953
1954 TALLOC_FREE(frame);
1955 return 0; /* Success */
1956}
1957
Note: See TracBrowser for help on using the repository browser.