612a8772c0efdb6a93882bb4c890a1450b1cbb2d
[kai/samba.git] / source3 / libsmb / libsmb_dir.c
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
35 static void
36 remove_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
54 static int
55 add_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
134 static void
135 list_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
178 static void
179 list_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
236 static void
237 dir_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
254 static int
255 net_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->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
320 done:
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  */
332 int
333 SMBC_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
350 SMBCFILE *
351 SMBC_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                                                 saved_errno = ENOTDIR;
811                                         }
812                                 }
813
814                                 /*
815                                  * If there was an error and the server is no
816                                  * good any more...
817                                  */
818                                 if (cli_is_error(targetcli) &&
819                                     smbc_getFunctionCheckServer(context)(context, srv)) {
820
821                                         /* ... then remove it. */
822                                         if (smbc_getFunctionRemoveUnusedServer(context)(context,
823                                                                                         srv)) {
824                                                 /*
825                                                  * We could not remove the
826                                                  * server completely, remove
827                                                  * it from the cache so we
828                                                  * will not get it again. It
829                                                  * will be removed when the
830                                                  * last file/dir is closed.
831                                                  */
832                                                 smbc_getFunctionRemoveCachedServer(context)(context, srv);
833                                         }
834                                 }
835
836                                 errno = saved_errno;
837                                 TALLOC_FREE(frame);
838                                 return NULL;
839                         }
840                 }
841
842         }
843
844         DLIST_ADD(context->internal->files, dir);
845         TALLOC_FREE(frame);
846         return dir;
847
848 }
849
850 /*
851  * Routine to close a directory
852  */
853
854 int
855 SMBC_closedir_ctx(SMBCCTX *context,
856                   SMBCFILE *dir)
857 {
858         TALLOC_CTX *frame = talloc_stackframe();
859
860         if (!context || !context->internal->initialized) {
861                 errno = EINVAL;
862                 TALLOC_FREE(frame);
863                 return -1;
864         }
865
866         if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
867                 errno = EBADF;
868                 TALLOC_FREE(frame);
869                 return -1;
870         }
871
872         remove_dir(dir); /* Clean it up */
873
874         DLIST_REMOVE(context->internal->files, dir);
875
876         if (dir) {
877
878                 SAFE_FREE(dir->fname);
879                 SAFE_FREE(dir);    /* Free the space too */
880         }
881
882         TALLOC_FREE(frame);
883         return 0;
884
885 }
886
887 static void
888 smbc_readdir_internal(SMBCCTX * context,
889                       struct smbc_dirent *dest,
890                       struct smbc_dirent *src,
891                       int max_namebuf_len)
892 {
893         if (smbc_getOptionUrlEncodeReaddirEntries(context)) {
894
895                 /* url-encode the name.  get back remaining buffer space */
896                 max_namebuf_len =
897                         SMBC_urlencode(dest->name, src->name, max_namebuf_len);
898
899                 /* We now know the name length */
900                 dest->namelen = strlen(dest->name);
901
902                 /* Save the pointer to the beginning of the comment */
903                 dest->comment = dest->name + dest->namelen + 1;
904
905                 /* Copy the comment */
906                 strncpy(dest->comment, src->comment, max_namebuf_len - 1);
907                 dest->comment[max_namebuf_len - 1] = '\0';
908
909                 /* Save other fields */
910                 dest->smbc_type = src->smbc_type;
911                 dest->commentlen = strlen(dest->comment);
912                 dest->dirlen = ((dest->comment + dest->commentlen + 1) -
913                                 (char *) dest);
914         } else {
915
916                 /* No encoding.  Just copy the entry as is. */
917                 memcpy(dest, src, src->dirlen);
918                 dest->comment = (char *)(&dest->name + src->namelen + 1);
919         }
920
921 }
922
923 /*
924  * Routine to get a directory entry
925  */
926
927 struct smbc_dirent *
928 SMBC_readdir_ctx(SMBCCTX *context,
929                  SMBCFILE *dir)
930 {
931         int maxlen;
932         struct smbc_dirent *dirp, *dirent;
933         TALLOC_CTX *frame = talloc_stackframe();
934
935         /* Check that all is ok first ... */
936
937         if (!context || !context->internal->initialized) {
938
939                 errno = EINVAL;
940                 DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n"));
941                 TALLOC_FREE(frame);
942                 return NULL;
943
944         }
945
946         if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
947
948                 errno = EBADF;
949                 DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n"));
950                 TALLOC_FREE(frame);
951                 return NULL;
952
953         }
954
955         if (dir->file != False) { /* FIXME, should be dir, perhaps */
956
957                 errno = ENOTDIR;
958                 DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n"));
959                 TALLOC_FREE(frame);
960                 return NULL;
961
962         }
963
964         if (!dir->dir_next) {
965                 TALLOC_FREE(frame);
966                 return NULL;
967         }
968
969         dirent = dir->dir_next->dirent;
970         if (!dirent) {
971
972                 errno = ENOENT;
973                 TALLOC_FREE(frame);
974                 return NULL;
975
976         }
977
978         dirp = (struct smbc_dirent *)context->internal->dirent;
979         maxlen = (sizeof(context->internal->dirent) -
980                   sizeof(struct smbc_dirent));
981
982         smbc_readdir_internal(context, dirp, dirent, maxlen);
983
984         dir->dir_next = dir->dir_next->next;
985
986         TALLOC_FREE(frame);
987         return dirp;
988 }
989
990 /*
991  * Routine to get directory entries
992  */
993
994 int
995 SMBC_getdents_ctx(SMBCCTX *context,
996                   SMBCFILE *dir,
997                   struct smbc_dirent *dirp,
998                   int count)
999 {
1000         int rem = count;
1001         int reqd;
1002         int maxlen;
1003         char *ndir = (char *)dirp;
1004         struct smbc_dir_list *dirlist;
1005         TALLOC_CTX *frame = talloc_stackframe();
1006
1007         /* Check that all is ok first ... */
1008
1009         if (!context || !context->internal->initialized) {
1010
1011                 errno = EINVAL;
1012                 TALLOC_FREE(frame);
1013                 return -1;
1014
1015         }
1016
1017         if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
1018
1019                 errno = EBADF;
1020                 TALLOC_FREE(frame);
1021                 return -1;
1022
1023         }
1024
1025         if (dir->file != False) { /* FIXME, should be dir, perhaps */
1026
1027                 errno = ENOTDIR;
1028                 TALLOC_FREE(frame);
1029                 return -1;
1030
1031         }
1032
1033         /*
1034          * Now, retrieve the number of entries that will fit in what was passed
1035          * We have to figure out if the info is in the list, or we need to
1036          * send a request to the server to get the info.
1037          */
1038
1039         while ((dirlist = dir->dir_next)) {
1040                 struct smbc_dirent *dirent;
1041
1042                 if (!dirlist->dirent) {
1043
1044                         errno = ENOENT;  /* Bad error */
1045                         TALLOC_FREE(frame);
1046                         return -1;
1047
1048                 }
1049
1050                 /* Do urlencoding of next entry, if so selected */
1051                 dirent = (struct smbc_dirent *)context->internal->dirent;
1052                 maxlen = (sizeof(context->internal->dirent) -
1053                           sizeof(struct smbc_dirent));
1054                 smbc_readdir_internal(context, dirent,
1055                                       dirlist->dirent, maxlen);
1056
1057                 reqd = dirent->dirlen;
1058
1059                 if (rem < reqd) {
1060
1061                         if (rem < count) { /* We managed to copy something */
1062
1063                                 errno = 0;
1064                                 TALLOC_FREE(frame);
1065                                 return count - rem;
1066
1067                         }
1068                         else { /* Nothing copied ... */
1069
1070                                 errno = EINVAL;  /* Not enough space ... */
1071                                 TALLOC_FREE(frame);
1072                                 return -1;
1073
1074                         }
1075
1076                 }
1077
1078                 memcpy(ndir, dirent, reqd); /* Copy the data in ... */
1079
1080                 ((struct smbc_dirent *)ndir)->comment =
1081                         (char *)(&((struct smbc_dirent *)ndir)->name +
1082                                  dirent->namelen +
1083                                  1);
1084
1085                 ndir += reqd;
1086
1087                 rem -= reqd;
1088
1089                 dir->dir_next = dirlist = dirlist -> next;
1090         }
1091
1092         TALLOC_FREE(frame);
1093
1094         if (rem == count)
1095                 return 0;
1096         else
1097                 return count - rem;
1098
1099 }
1100
1101 /*
1102  * Routine to create a directory ...
1103  */
1104
1105 int
1106 SMBC_mkdir_ctx(SMBCCTX *context,
1107                const char *fname,
1108                mode_t mode)
1109 {
1110         SMBCSRV *srv = NULL;
1111         char *server = NULL;
1112         char *share = NULL;
1113         char *user = NULL;
1114         char *password = NULL;
1115         char *workgroup = NULL;
1116         char *path = NULL;
1117         char *targetpath = NULL;
1118         struct cli_state *targetcli = NULL;
1119         TALLOC_CTX *frame = talloc_stackframe();
1120
1121         if (!context || !context->internal->initialized) {
1122                 errno = EINVAL;
1123                 TALLOC_FREE(frame);
1124                 return -1;
1125         }
1126
1127         if (!fname) {
1128                 errno = EINVAL;
1129                 TALLOC_FREE(frame);
1130                 return -1;
1131         }
1132
1133         DEBUG(4, ("smbc_mkdir(%s)\n", fname));
1134
1135         if (SMBC_parse_path(frame,
1136                             context,
1137                             fname,
1138                             &workgroup,
1139                             &server,
1140                             &share,
1141                             &path,
1142                             &user,
1143                             &password,
1144                             NULL)) {
1145                 errno = EINVAL;
1146                 TALLOC_FREE(frame);
1147                 return -1;
1148         }
1149
1150         if (!user || user[0] == (char)0) {
1151                 user = talloc_strdup(frame, smbc_getUser(context));
1152                 if (!user) {
1153                         errno = ENOMEM;
1154                         TALLOC_FREE(frame);
1155                         return -1;
1156                 }
1157         }
1158
1159         srv = SMBC_server(frame, context, True,
1160                           server, share, &workgroup, &user, &password);
1161
1162         if (!srv) {
1163
1164                 TALLOC_FREE(frame);
1165                 return -1;  /* errno set by SMBC_server */
1166
1167         }
1168
1169         /*d_printf(">>>mkdir: resolving %s\n", path);*/
1170         if (!cli_resolve_path(frame, "", srv->cli, path,
1171                               &targetcli, &targetpath)) {
1172                 d_printf("Could not resolve %s\n", path);
1173                 TALLOC_FREE(frame);
1174                 return -1;
1175         }
1176         /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
1177
1178         if (!cli_mkdir(targetcli, targetpath)) {
1179
1180                 errno = SMBC_errno(context, targetcli);
1181                 TALLOC_FREE(frame);
1182                 return -1;
1183
1184         }
1185
1186         TALLOC_FREE(frame);
1187         return 0;
1188
1189 }
1190
1191 /*
1192  * Our list function simply checks to see if a directory is not empty
1193  */
1194
1195 static int smbc_rmdir_dirempty = True;
1196
1197 static void
1198 rmdir_list_fn(const char *mnt,
1199               file_info *finfo,
1200               const char *mask,
1201               void *state)
1202 {
1203         if (strncmp(finfo->name, ".", 1) != 0 &&
1204             strncmp(finfo->name, "..", 2) != 0) {
1205                 smbc_rmdir_dirempty = False;
1206         }
1207 }
1208
1209 /*
1210  * Routine to remove a directory
1211  */
1212
1213 int
1214 SMBC_rmdir_ctx(SMBCCTX *context,
1215                const char *fname)
1216 {
1217         SMBCSRV *srv = NULL;
1218         char *server = NULL;
1219         char *share = NULL;
1220         char *user = NULL;
1221         char *password = NULL;
1222         char *workgroup = NULL;
1223         char *path = NULL;
1224         char *targetpath = NULL;
1225         struct cli_state *targetcli = NULL;
1226         TALLOC_CTX *frame = talloc_stackframe();
1227
1228         if (!context || !context->internal->initialized) {
1229                 errno = EINVAL;
1230                 TALLOC_FREE(frame);
1231                 return -1;
1232         }
1233
1234         if (!fname) {
1235                 errno = EINVAL;
1236                 TALLOC_FREE(frame);
1237                 return -1;
1238         }
1239
1240         DEBUG(4, ("smbc_rmdir(%s)\n", fname));
1241
1242         if (SMBC_parse_path(frame,
1243                             context,
1244                             fname,
1245                             &workgroup,
1246                             &server,
1247                             &share,
1248                             &path,
1249                             &user,
1250                             &password,
1251                             NULL)) {
1252                 errno = EINVAL;
1253                 TALLOC_FREE(frame);
1254                 return -1;
1255         }
1256
1257         if (!user || user[0] == (char)0) {
1258                 user = talloc_strdup(frame, smbc_getUser(context));
1259                 if (!user) {
1260                         errno = ENOMEM;
1261                         TALLOC_FREE(frame);
1262                         return -1;
1263                 }
1264         }
1265
1266         srv = SMBC_server(frame, context, True,
1267                           server, share, &workgroup, &user, &password);
1268
1269         if (!srv) {
1270
1271                 TALLOC_FREE(frame);
1272                 return -1;  /* errno set by SMBC_server */
1273
1274         }
1275
1276         /*d_printf(">>>rmdir: resolving %s\n", path);*/
1277         if (!cli_resolve_path(frame, "", srv->cli, path,
1278                               &targetcli, &targetpath)) {
1279                 d_printf("Could not resolve %s\n", path);
1280                 TALLOC_FREE(frame);
1281                 return -1;
1282         }
1283         /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
1284
1285
1286         if (!cli_rmdir(targetcli, targetpath)) {
1287
1288                 errno = SMBC_errno(context, targetcli);
1289
1290                 if (errno == EACCES) {  /* Check if the dir empty or not */
1291
1292                         /* Local storage to avoid buffer overflows */
1293                         char *lpath;
1294
1295                         smbc_rmdir_dirempty = True;  /* Make this so ... */
1296
1297                         lpath = talloc_asprintf(frame, "%s\\*",
1298                                                 targetpath);
1299                         if (!lpath) {
1300                                 errno = ENOMEM;
1301                                 TALLOC_FREE(frame);
1302                                 return -1;
1303                         }
1304
1305                         if (cli_list(targetcli, lpath,
1306                                      aDIR | aSYSTEM | aHIDDEN,
1307                                      rmdir_list_fn, NULL) < 0) {
1308
1309                                 /* Fix errno to ignore latest error ... */
1310                                 DEBUG(5, ("smbc_rmdir: "
1311                                           "cli_list returned an error: %d\n",
1312                                           SMBC_errno(context, targetcli)));
1313                                 errno = EACCES;
1314
1315                         }
1316
1317                         if (smbc_rmdir_dirempty)
1318                                 errno = EACCES;
1319                         else
1320                                 errno = ENOTEMPTY;
1321
1322                 }
1323
1324                 TALLOC_FREE(frame);
1325                 return -1;
1326
1327         }
1328
1329         TALLOC_FREE(frame);
1330         return 0;
1331
1332 }
1333
1334 /*
1335  * Routine to return the current directory position
1336  */
1337
1338 off_t
1339 SMBC_telldir_ctx(SMBCCTX *context,
1340                  SMBCFILE *dir)
1341 {
1342         TALLOC_CTX *frame = talloc_stackframe();
1343
1344         if (!context || !context->internal->initialized) {
1345
1346                 errno = EINVAL;
1347                 TALLOC_FREE(frame);
1348                 return -1;
1349
1350         }
1351
1352         if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
1353
1354                 errno = EBADF;
1355                 TALLOC_FREE(frame);
1356                 return -1;
1357
1358         }
1359
1360         if (dir->file != False) { /* FIXME, should be dir, perhaps */
1361
1362                 errno = ENOTDIR;
1363                 TALLOC_FREE(frame);
1364                 return -1;
1365
1366         }
1367
1368         /* See if we're already at the end. */
1369         if (dir->dir_next == NULL) {
1370                 /* We are. */
1371                 TALLOC_FREE(frame);
1372                 return -1;
1373         }
1374
1375         /*
1376          * We return the pointer here as the offset
1377          */
1378         TALLOC_FREE(frame);
1379         return (off_t)(long)dir->dir_next->dirent;
1380 }
1381
1382 /*
1383  * A routine to run down the list and see if the entry is OK
1384  */
1385
1386 static struct smbc_dir_list *
1387 check_dir_ent(struct smbc_dir_list *list,
1388               struct smbc_dirent *dirent)
1389 {
1390
1391         /* Run down the list looking for what we want */
1392
1393         if (dirent) {
1394
1395                 struct smbc_dir_list *tmp = list;
1396
1397                 while (tmp) {
1398
1399                         if (tmp->dirent == dirent)
1400                                 return tmp;
1401
1402                         tmp = tmp->next;
1403
1404                 }
1405
1406         }
1407
1408         return NULL;  /* Not found, or an error */
1409
1410 }
1411
1412
1413 /*
1414  * Routine to seek on a directory
1415  */
1416
1417 int
1418 SMBC_lseekdir_ctx(SMBCCTX *context,
1419                   SMBCFILE *dir,
1420                   off_t offset)
1421 {
1422         long int l_offset = offset;  /* Handle problems of size */
1423         struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
1424         struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL;
1425         TALLOC_CTX *frame = talloc_stackframe();
1426
1427         if (!context || !context->internal->initialized) {
1428
1429                 errno = EINVAL;
1430                 TALLOC_FREE(frame);
1431                 return -1;
1432
1433         }
1434
1435         if (dir->file != False) { /* FIXME, should be dir, perhaps */
1436
1437                 errno = ENOTDIR;
1438                 TALLOC_FREE(frame);
1439                 return -1;
1440
1441         }
1442
1443         /* Now, check what we were passed and see if it is OK ... */
1444
1445         if (dirent == NULL) {  /* Seek to the begining of the list */
1446
1447                 dir->dir_next = dir->dir_list;
1448                 TALLOC_FREE(frame);
1449                 return 0;
1450
1451         }
1452
1453         if (offset == -1) {     /* Seek to the end of the list */
1454                 dir->dir_next = NULL;
1455                 TALLOC_FREE(frame);
1456                 return 0;
1457         }
1458
1459         /* Now, run down the list and make sure that the entry is OK       */
1460         /* This may need to be changed if we change the format of the list */
1461
1462         if ((list_ent = check_dir_ent(dir->dir_list, dirent)) == NULL) {
1463                 errno = EINVAL;   /* Bad entry */
1464                 TALLOC_FREE(frame);
1465                 return -1;
1466         }
1467
1468         dir->dir_next = list_ent;
1469
1470         TALLOC_FREE(frame);
1471         return 0;
1472 }
1473
1474 /*
1475  * Routine to fstat a dir
1476  */
1477
1478 int
1479 SMBC_fstatdir_ctx(SMBCCTX *context,
1480                   SMBCFILE *dir,
1481                   struct stat *st)
1482 {
1483
1484         if (!context || !context->internal->initialized) {
1485
1486                 errno = EINVAL;
1487                 return -1;
1488         }
1489
1490         /* No code yet ... */
1491         return 0;
1492 }
1493
1494 int
1495 SMBC_chmod_ctx(SMBCCTX *context,
1496                const char *fname,
1497                mode_t newmode)
1498 {
1499         SMBCSRV *srv = NULL;
1500         char *server = NULL;
1501         char *share = NULL;
1502         char *user = NULL;
1503         char *password = NULL;
1504         char *workgroup = NULL;
1505         char *path = NULL;
1506         uint16 mode;
1507         TALLOC_CTX *frame = talloc_stackframe();
1508
1509         if (!context || !context->internal->initialized) {
1510
1511                 errno = EINVAL;  /* Best I can think of ... */
1512                 TALLOC_FREE(frame);
1513                 return -1;
1514         }
1515
1516         if (!fname) {
1517                 errno = EINVAL;
1518                 TALLOC_FREE(frame);
1519                 return -1;
1520         }
1521
1522         DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode));
1523
1524         if (SMBC_parse_path(frame,
1525                             context,
1526                             fname,
1527                             &workgroup,
1528                             &server,
1529                             &share,
1530                             &path,
1531                             &user,
1532                             &password,
1533                             NULL)) {
1534                 errno = EINVAL;
1535                 TALLOC_FREE(frame);
1536                 return -1;
1537         }
1538
1539         if (!user || user[0] == (char)0) {
1540                 user = talloc_strdup(frame, smbc_getUser(context));
1541                 if (!user) {
1542                         errno = ENOMEM;
1543                         TALLOC_FREE(frame);
1544                         return -1;
1545                 }
1546         }
1547
1548         srv = SMBC_server(frame, context, True,
1549                           server, share, &workgroup, &user, &password);
1550
1551         if (!srv) {
1552                 TALLOC_FREE(frame);
1553                 return -1;  /* errno set by SMBC_server */
1554         }
1555
1556         mode = 0;
1557
1558         if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
1559         if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
1560         if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
1561         if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
1562
1563         if (!cli_setatr(srv->cli, path, mode, 0)) {
1564                 errno = SMBC_errno(context, srv->cli);
1565                 TALLOC_FREE(frame);
1566                 return -1;
1567         }
1568
1569         TALLOC_FREE(frame);
1570         return 0;
1571 }
1572
1573 int
1574 SMBC_utimes_ctx(SMBCCTX *context,
1575                 const char *fname,
1576                 struct timeval *tbuf)
1577 {
1578         SMBCSRV *srv = NULL;
1579         char *server = NULL;
1580         char *share = NULL;
1581         char *user = NULL;
1582         char *password = NULL;
1583         char *workgroup = NULL;
1584         char *path = NULL;
1585         time_t access_time;
1586         time_t write_time;
1587         TALLOC_CTX *frame = talloc_stackframe();
1588
1589         if (!context || !context->internal->initialized) {
1590
1591                 errno = EINVAL;  /* Best I can think of ... */
1592                 TALLOC_FREE(frame);
1593                 return -1;
1594         }
1595
1596         if (!fname) {
1597                 errno = EINVAL;
1598                 TALLOC_FREE(frame);
1599                 return -1;
1600         }
1601
1602         if (tbuf == NULL) {
1603                 access_time = write_time = time(NULL);
1604         } else {
1605                 access_time = tbuf[0].tv_sec;
1606                 write_time = tbuf[1].tv_sec;
1607         }
1608
1609         if (DEBUGLVL(4)) {
1610                 char *p;
1611                 char atimebuf[32];
1612                 char mtimebuf[32];
1613
1614                 strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1);
1615                 atimebuf[sizeof(atimebuf) - 1] = '\0';
1616                 if ((p = strchr(atimebuf, '\n')) != NULL) {
1617                         *p = '\0';
1618                 }
1619
1620                 strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1);
1621                 mtimebuf[sizeof(mtimebuf) - 1] = '\0';
1622                 if ((p = strchr(mtimebuf, '\n')) != NULL) {
1623                         *p = '\0';
1624                 }
1625
1626                 dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
1627                         fname, atimebuf, mtimebuf);
1628         }
1629
1630         if (SMBC_parse_path(frame,
1631                             context,
1632                             fname,
1633                             &workgroup,
1634                             &server,
1635                             &share,
1636                             &path,
1637                             &user,
1638                             &password,
1639                             NULL)) {
1640                 errno = EINVAL;
1641                 TALLOC_FREE(frame);
1642                 return -1;
1643         }
1644
1645         if (!user || user[0] == (char)0) {
1646                 user = talloc_strdup(frame, smbc_getUser(context));
1647                 if (!user) {
1648                         errno = ENOMEM;
1649                         TALLOC_FREE(frame);
1650                         return -1;
1651                 }
1652         }
1653
1654         srv = SMBC_server(frame, context, True,
1655                           server, share, &workgroup, &user, &password);
1656
1657         if (!srv) {
1658                 TALLOC_FREE(frame);
1659                 return -1;      /* errno set by SMBC_server */
1660         }
1661
1662         if (!SMBC_setatr(context, srv, path,
1663                          0, access_time, write_time, 0, 0)) {
1664                 TALLOC_FREE(frame);
1665                 return -1;      /* errno set by SMBC_setatr */
1666         }
1667
1668         TALLOC_FREE(frame);
1669         return 0;
1670 }
1671
1672 /*
1673  * Routine to unlink() a file
1674  */
1675
1676 int
1677 SMBC_unlink_ctx(SMBCCTX *context,
1678                 const char *fname)
1679 {
1680         char *server = NULL;
1681         char *share = NULL;
1682         char *user = NULL;
1683         char *password = NULL;
1684         char *workgroup = NULL;
1685         char *path = NULL;
1686         char *targetpath = NULL;
1687         struct cli_state *targetcli = NULL;
1688         SMBCSRV *srv = NULL;
1689         TALLOC_CTX *frame = talloc_stackframe();
1690
1691         if (!context || !context->internal->initialized) {
1692
1693                 errno = EINVAL;  /* Best I can think of ... */
1694                 TALLOC_FREE(frame);
1695                 return -1;
1696
1697         }
1698
1699         if (!fname) {
1700                 errno = EINVAL;
1701                 TALLOC_FREE(frame);
1702                 return -1;
1703
1704         }
1705
1706         if (SMBC_parse_path(frame,
1707                             context,
1708                             fname,
1709                             &workgroup,
1710                             &server,
1711                             &share,
1712                             &path,
1713                             &user,
1714                             &password,
1715                             NULL)) {
1716                 errno = EINVAL;
1717                 TALLOC_FREE(frame);
1718                 return -1;
1719         }
1720
1721         if (!user || user[0] == (char)0) {
1722                 user = talloc_strdup(frame, smbc_getUser(context));
1723                 if (!user) {
1724                         errno = ENOMEM;
1725                         TALLOC_FREE(frame);
1726                         return -1;
1727                 }
1728         }
1729
1730         srv = SMBC_server(frame, context, True,
1731                           server, share, &workgroup, &user, &password);
1732
1733         if (!srv) {
1734                 TALLOC_FREE(frame);
1735                 return -1;  /* SMBC_server sets errno */
1736
1737         }
1738
1739         /*d_printf(">>>unlink: resolving %s\n", path);*/
1740         if (!cli_resolve_path(frame, "", srv->cli, path,
1741                               &targetcli, &targetpath)) {
1742                 d_printf("Could not resolve %s\n", path);
1743                 TALLOC_FREE(frame);
1744                 return -1;
1745         }
1746         /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
1747
1748         if (!cli_unlink(targetcli, targetpath)) {
1749
1750                 errno = SMBC_errno(context, targetcli);
1751
1752                 if (errno == EACCES) { /* Check if the file is a directory */
1753
1754                         int saverr = errno;
1755                         SMB_OFF_T size = 0;
1756                         uint16 mode = 0;
1757                         struct timespec write_time_ts;
1758                         struct timespec access_time_ts;
1759                         struct timespec change_time_ts;
1760                         SMB_INO_T ino = 0;
1761
1762                         if (!SMBC_getatr(context, srv, path, &mode, &size,
1763                                          NULL,
1764                                          &access_time_ts,
1765                                          &write_time_ts,
1766                                          &change_time_ts,
1767                                          &ino)) {
1768
1769                                 /* Hmmm, bad error ... What? */
1770
1771                                 errno = SMBC_errno(context, targetcli);
1772                                 TALLOC_FREE(frame);
1773                                 return -1;
1774
1775                         }
1776                         else {
1777
1778                                 if (IS_DOS_DIR(mode))
1779                                         errno = EISDIR;
1780                                 else
1781                                         errno = saverr;  /* Restore this */
1782
1783                         }
1784                 }
1785
1786                 TALLOC_FREE(frame);
1787                 return -1;
1788
1789         }
1790
1791         TALLOC_FREE(frame);
1792         return 0;  /* Success ... */
1793
1794 }
1795
1796 /*
1797  * Routine to rename() a file
1798  */
1799
1800 int
1801 SMBC_rename_ctx(SMBCCTX *ocontext,
1802                 const char *oname,
1803                 SMBCCTX *ncontext,
1804                 const char *nname)
1805 {
1806         char *server1 = NULL;
1807         char *share1 = NULL;
1808         char *server2 = NULL;
1809         char *share2 = NULL;
1810         char *user1 = NULL;
1811         char *user2 = NULL;
1812         char *password1 = NULL;
1813         char *password2 = NULL;
1814         char *workgroup = NULL;
1815         char *path1 = NULL;
1816         char *path2 = NULL;
1817         char *targetpath1 = NULL;
1818         char *targetpath2 = NULL;
1819         struct cli_state *targetcli1 = NULL;
1820         struct cli_state *targetcli2 = NULL;
1821         SMBCSRV *srv = NULL;
1822         TALLOC_CTX *frame = talloc_stackframe();
1823
1824         if (!ocontext || !ncontext ||
1825             !ocontext->internal->initialized ||
1826             !ncontext->internal->initialized) {
1827
1828                 errno = EINVAL;  /* Best I can think of ... */
1829                 TALLOC_FREE(frame);
1830                 return -1;
1831         }
1832
1833         if (!oname || !nname) {
1834                 errno = EINVAL;
1835                 TALLOC_FREE(frame);
1836                 return -1;
1837         }
1838
1839         DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
1840
1841         if (SMBC_parse_path(frame,
1842                             ocontext,
1843                             oname,
1844                             &workgroup,
1845                             &server1,
1846                             &share1,
1847                             &path1,
1848                             &user1,
1849                             &password1,
1850                             NULL)) {
1851                 errno = EINVAL;
1852                 TALLOC_FREE(frame);
1853                 return -1;
1854         }
1855
1856         if (!user1 || user1[0] == (char)0) {
1857                 user1 = talloc_strdup(frame, smbc_getUser(ocontext));
1858                 if (!user1) {
1859                         errno = ENOMEM;
1860                         TALLOC_FREE(frame);
1861                         return -1;
1862                 }
1863         }
1864
1865         if (SMBC_parse_path(frame,
1866                             ncontext,
1867                             nname,
1868                             NULL,
1869                             &server2,
1870                             &share2,
1871                             &path2,
1872                             &user2,
1873                             &password2,
1874                             NULL)) {
1875                 errno = EINVAL;
1876                 TALLOC_FREE(frame);
1877                 return -1;
1878         }
1879
1880         if (!user2 || user2[0] == (char)0) {
1881                 user2 = talloc_strdup(frame, smbc_getUser(ncontext));
1882                 if (!user2) {
1883                         errno = ENOMEM;
1884                         TALLOC_FREE(frame);
1885                         return -1;
1886                 }
1887         }
1888
1889         if (strcmp(server1, server2) || strcmp(share1, share2) ||
1890             strcmp(user1, user2)) {
1891                 /* Can't rename across file systems, or users?? */
1892                 errno = EXDEV;
1893                 TALLOC_FREE(frame);
1894                 return -1;
1895         }
1896
1897         srv = SMBC_server(frame, ocontext, True,
1898                           server1, share1, &workgroup, &user1, &password1);
1899         if (!srv) {
1900                 TALLOC_FREE(frame);
1901                 return -1;
1902
1903         }
1904
1905         /*d_printf(">>>rename: resolving %s\n", path1);*/
1906         if (!cli_resolve_path(frame, "", srv->cli, path1,
1907                               &targetcli1, &targetpath1)) {
1908                 d_printf("Could not resolve %s\n", path1);
1909                 TALLOC_FREE(frame);
1910                 return -1;
1911         }
1912         /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
1913         /*d_printf(">>>rename: resolving %s\n", path2);*/
1914         if (!cli_resolve_path(frame, "", srv->cli, path2,
1915                               &targetcli2, &targetpath2)) {
1916                 d_printf("Could not resolve %s\n", path2);
1917                 TALLOC_FREE(frame);
1918                 return -1;
1919         }
1920         /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
1921
1922         if (strcmp(targetcli1->desthost, targetcli2->desthost) ||
1923             strcmp(targetcli1->share, targetcli2->share))
1924         {
1925                 /* can't rename across file systems */
1926                 errno = EXDEV;
1927                 TALLOC_FREE(frame);
1928                 return -1;
1929         }
1930
1931         if (!cli_rename(targetcli1, targetpath1, targetpath2)) {
1932                 int eno = SMBC_errno(ocontext, targetcli1);
1933
1934                 if (eno != EEXIST ||
1935                     !cli_unlink(targetcli1, targetpath2) ||
1936                     !cli_rename(targetcli1, targetpath1, targetpath2)) {
1937
1938                         errno = eno;
1939                         TALLOC_FREE(frame);
1940                         return -1;
1941
1942                 }
1943         }
1944
1945         TALLOC_FREE(frame);
1946         return 0; /* Success */
1947 }
1948