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