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