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