source: trunk/server/source3/libsmb/libsmb_dir.c

Last change on this file was 879, checked in by Silvan Scherrer, 10 years ago

Samba Server 3.6: small change for the ndpsmb client

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