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