Add shared pkg.m4 file with convenience macros for using pkg-config.
[kai/samba-autobuild/.git] / source3 / client / client.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB client
4    Copyright (C) Andrew Tridgell          1994-1998
5    Copyright (C) Simo Sorce               2001-2002
6    Copyright (C) Jelmer Vernooij          2003
7    Copyright (C) Gerald (Jerry) Carter    2004
8    Copyright (C) Jeremy Allison           1994-2007
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "client/client_proto.h"
26 #include "include/rpc_client.h"
27 #ifndef REGISTER
28 #define REGISTER 0
29 #endif
30
31 extern int do_smb_browse(void); /* mDNS browsing */
32
33 extern bool AllowDebugChange;
34 extern bool override_logfile;
35 extern char tar_type;
36
37 static int port = 0;
38 static char *service;
39 static char *desthost;
40 static char *calling_name;
41 static bool grepable = false;
42 static char *cmdstr = NULL;
43 const char *cmd_ptr = NULL;
44
45 static int io_bufsize = 524288;
46
47 static int name_type = 0x20;
48 static int max_protocol = PROTOCOL_NT1;
49
50 static int process_tok(char *tok);
51 static int cmd_help(void);
52
53 #define CREATE_ACCESS_READ READ_CONTROL_ACCESS
54
55 /* 30 second timeout on most commands */
56 #define CLIENT_TIMEOUT (30*1000)
57 #define SHORT_TIMEOUT (5*1000)
58
59 /* value for unused fid field in trans2 secondary request */
60 #define FID_UNUSED (0xFFFF)
61
62 time_t newer_than = 0;
63 static int archive_level = 0;
64
65 static bool translation = false;
66 static bool have_ip;
67
68 /* clitar bits insert */
69 extern int blocksize;
70 extern bool tar_inc;
71 extern bool tar_reset;
72 /* clitar bits end */
73
74 static bool prompt = true;
75
76 static bool recurse = false;
77 static bool showacls = false;
78 bool lowercase = false;
79
80 static struct sockaddr_storage dest_ss;
81 static char dest_ss_str[INET6_ADDRSTRLEN];
82
83 #define SEPARATORS " \t\n\r"
84
85 static bool abort_mget = true;
86
87 /* timing globals */
88 uint64_t get_total_size = 0;
89 unsigned int get_total_time_ms = 0;
90 static uint64_t put_total_size = 0;
91 static unsigned int put_total_time_ms = 0;
92
93 /* totals globals */
94 static double dir_total;
95
96 /* encrypted state. */
97 static bool smb_encrypt;
98
99 /* root cli_state connection */
100
101 struct cli_state *cli;
102
103 static char CLI_DIRSEP_CHAR = '\\';
104 static char CLI_DIRSEP_STR[] = { '\\', '\0' };
105
106 /* Accessor functions for directory paths. */
107 static char *fileselection;
108 static const char *client_get_fileselection(void)
109 {
110         if (fileselection) {
111                 return fileselection;
112         }
113         return "";
114 }
115
116 static const char *client_set_fileselection(const char *new_fs)
117 {
118         SAFE_FREE(fileselection);
119         if (new_fs) {
120                 fileselection = SMB_STRDUP(new_fs);
121         }
122         return client_get_fileselection();
123 }
124
125 static char *cwd;
126 static const char *client_get_cwd(void)
127 {
128         if (cwd) {
129                 return cwd;
130         }
131         return CLI_DIRSEP_STR;
132 }
133
134 static const char *client_set_cwd(const char *new_cwd)
135 {
136         SAFE_FREE(cwd);
137         if (new_cwd) {
138                 cwd = SMB_STRDUP(new_cwd);
139         }
140         return client_get_cwd();
141 }
142
143 static char *cur_dir;
144 const char *client_get_cur_dir(void)
145 {
146         if (cur_dir) {
147                 return cur_dir;
148         }
149         return CLI_DIRSEP_STR;
150 }
151
152 const char *client_set_cur_dir(const char *newdir)
153 {
154         SAFE_FREE(cur_dir);
155         if (newdir) {
156                 cur_dir = SMB_STRDUP(newdir);
157         }
158         return client_get_cur_dir();
159 }
160
161 /****************************************************************************
162  Write to a local file with CR/LF->LF translation if appropriate. Return the
163  number taken from the buffer. This may not equal the number written.
164 ****************************************************************************/
165
166 static int writefile(int f, char *b, int n)
167 {
168         int i;
169
170         if (!translation) {
171                 return write(f,b,n);
172         }
173
174         i = 0;
175         while (i < n) {
176                 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
177                         b++;i++;
178                 }
179                 if (write(f, b, 1) != 1) {
180                         break;
181                 }
182                 b++;
183                 i++;
184         }
185
186         return(i);
187 }
188
189 /****************************************************************************
190  Read from a file with LF->CR/LF translation if appropriate. Return the
191  number read. read approx n bytes.
192 ****************************************************************************/
193
194 static int readfile(uint8_t *b, int n, XFILE *f)
195 {
196         int i;
197         int c;
198
199         if (!translation)
200                 return x_fread(b,1,n,f);
201
202         i = 0;
203         while (i < (n - 1) && (i < BUFFER_SIZE)) {
204                 if ((c = x_getc(f)) == EOF) {
205                         break;
206                 }
207
208                 if (c == '\n') { /* change all LFs to CR/LF */
209                         b[i++] = '\r';
210                 }
211
212                 b[i++] = c;
213         }
214
215         return(i);
216 }
217
218 struct push_state {
219         XFILE *f;
220         SMB_OFF_T nread;
221 };
222
223 static size_t push_source(uint8_t *inbuf, size_t n,
224                           const uint8_t **outbuf,
225                           void *priv)
226 {
227         struct push_state *state = (struct push_state *)priv;
228         int result;
229
230         if (x_feof(state->f)) {
231                 return 0;
232         }
233
234         result = readfile(inbuf, n, state->f);
235         state->nread += result;
236         return result;
237 }
238
239 /****************************************************************************
240  Send a message.
241 ****************************************************************************/
242
243 static void send_message(const char *username)
244 {
245         int total_len = 0;
246         int grp_id;
247
248         if (!cli_message_start(cli, desthost, username, &grp_id)) {
249                 d_printf("message start: %s\n", cli_errstr(cli));
250                 return;
251         }
252
253
254         d_printf("Connected. Type your message, ending it with a Control-D\n");
255
256         while (!feof(stdin) && total_len < 1600) {
257                 int maxlen = MIN(1600 - total_len,127);
258                 char msg[1024];
259                 int l=0;
260                 int c;
261
262                 ZERO_ARRAY(msg);
263
264                 for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
265                         if (c == '\n')
266                                 msg[l++] = '\r';
267                         msg[l] = c;
268                 }
269
270                 if ((total_len > 0) && (strlen(msg) == 0)) {
271                         break;
272                 }
273
274                 if (!cli_message_text(cli, msg, l, grp_id)) {
275                         d_printf("SMBsendtxt failed (%s)\n",cli_errstr(cli));
276                         return;
277                 }
278
279                 total_len += l;
280         }
281
282         if (total_len >= 1600)
283                 d_printf("the message was truncated to 1600 bytes\n");
284         else
285                 d_printf("sent %d bytes\n",total_len);
286
287         if (!cli_message_end(cli, grp_id)) {
288                 d_printf("SMBsendend failed (%s)\n",cli_errstr(cli));
289                 return;
290         }
291 }
292
293 /****************************************************************************
294  Check the space on a device.
295 ****************************************************************************/
296
297 static int do_dskattr(void)
298 {
299         int total, bsize, avail;
300         struct cli_state *targetcli = NULL;
301         char *targetpath = NULL;
302         TALLOC_CTX *ctx = talloc_tos();
303
304         if ( !cli_resolve_path(ctx, "", cli, client_get_cur_dir(), &targetcli, &targetpath)) {
305                 d_printf("Error in dskattr: %s\n", cli_errstr(cli));
306                 return 1;
307         }
308
309         if (!cli_dskattr(targetcli, &bsize, &total, &avail)) {
310                 d_printf("Error in dskattr: %s\n",cli_errstr(targetcli));
311                 return 1;
312         }
313
314         d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
315                  total, bsize, avail);
316
317         return 0;
318 }
319
320 /****************************************************************************
321  Show cd/pwd.
322 ****************************************************************************/
323
324 static int cmd_pwd(void)
325 {
326         d_printf("Current directory is %s",service);
327         d_printf("%s\n",client_get_cur_dir());
328         return 0;
329 }
330
331 /****************************************************************************
332  Ensure name has correct directory separators.
333 ****************************************************************************/
334
335 static void normalize_name(char *newdir)
336 {
337         if (!(cli->posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
338                 string_replace(newdir,'/','\\');
339         }
340 }
341
342 /****************************************************************************
343  Change directory - inner section.
344 ****************************************************************************/
345
346 static int do_cd(const char *new_dir)
347 {
348         char *newdir = NULL;
349         char *saved_dir = NULL;
350         char *new_cd = NULL;
351         char *targetpath = NULL;
352         struct cli_state *targetcli = NULL;
353         SMB_STRUCT_STAT sbuf;
354         uint32 attributes;
355         int ret = 1;
356         TALLOC_CTX *ctx = talloc_stackframe();
357
358         newdir = talloc_strdup(ctx, new_dir);
359         if (!newdir) {
360                 TALLOC_FREE(ctx);
361                 return 1;
362         }
363
364         normalize_name(newdir);
365
366         /* Save the current directory in case the new directory is invalid */
367
368         saved_dir = talloc_strdup(ctx, client_get_cur_dir());
369         if (!saved_dir) {
370                 TALLOC_FREE(ctx);
371                 return 1;
372         }
373
374         if (*newdir == CLI_DIRSEP_CHAR) {
375                 client_set_cur_dir(newdir);
376                 new_cd = newdir;
377         } else {
378                 new_cd = talloc_asprintf(ctx, "%s%s",
379                                 client_get_cur_dir(),
380                                 newdir);
381                 if (!new_cd) {
382                         goto out;
383                 }
384         }
385
386         /* Ensure cur_dir ends in a DIRSEP */
387         if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
388                 new_cd = talloc_asprintf_append(new_cd, "%s", CLI_DIRSEP_STR);
389                 if (!new_cd) {
390                         goto out;
391                 }
392         }
393         client_set_cur_dir(new_cd);
394
395         new_cd = clean_name(ctx, new_cd);
396         client_set_cur_dir(new_cd);
397
398         if ( !cli_resolve_path(ctx, "", cli, new_cd, &targetcli, &targetpath)) {
399                 d_printf("cd %s: %s\n", new_cd, cli_errstr(cli));
400                 client_set_cur_dir(saved_dir);
401                 goto out;
402         }
403
404         if (strequal(targetpath,CLI_DIRSEP_STR )) {
405                 TALLOC_FREE(ctx);
406                 return 0;
407         }
408
409         /* Use a trans2_qpathinfo to test directories for modern servers.
410            Except Win9x doesn't support the qpathinfo_basic() call..... */
411
412         if (targetcli->protocol > PROTOCOL_LANMAN2 && !targetcli->win95) {
413                 if (!cli_qpathinfo_basic( targetcli, targetpath, &sbuf, &attributes ) ) {
414                         d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
415                         client_set_cur_dir(saved_dir);
416                         goto out;
417                 }
418
419                 if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
420                         d_printf("cd %s: not a directory\n", new_cd);
421                         client_set_cur_dir(saved_dir);
422                         goto out;
423                 }
424         } else {
425                 targetpath = talloc_asprintf(ctx,
426                                 "%s%s",
427                                 targetpath,
428                                 CLI_DIRSEP_STR );
429                 if (!targetpath) {
430                         client_set_cur_dir(saved_dir);
431                         goto out;
432                 }
433                 targetpath = clean_name(ctx, targetpath);
434                 if (!targetpath) {
435                         client_set_cur_dir(saved_dir);
436                         goto out;
437                 }
438
439                 if (!cli_chkpath(targetcli, targetpath)) {
440                         d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
441                         client_set_cur_dir(saved_dir);
442                         goto out;
443                 }
444         }
445
446         ret = 0;
447
448 out:
449
450         TALLOC_FREE(ctx);
451         return ret;
452 }
453
454 /****************************************************************************
455  Change directory.
456 ****************************************************************************/
457
458 static int cmd_cd(void)
459 {
460         char *buf = NULL;
461         int rc = 0;
462
463         if (next_token_talloc(talloc_tos(), &cmd_ptr, &buf,NULL)) {
464                 rc = do_cd(buf);
465         } else {
466                 d_printf("Current directory is %s\n",client_get_cur_dir());
467         }
468
469         return rc;
470 }
471
472 /****************************************************************************
473  Change directory.
474 ****************************************************************************/
475
476 static int cmd_cd_oneup(void)
477 {
478         return do_cd("..");
479 }
480
481 /*******************************************************************
482  Decide if a file should be operated on.
483 ********************************************************************/
484
485 static bool do_this_one(file_info *finfo)
486 {
487         if (!finfo->name) {
488                 return false;
489         }
490
491         if (finfo->mode & aDIR) {
492                 return true;
493         }
494
495         if (*client_get_fileselection() &&
496             !mask_match(finfo->name,client_get_fileselection(),false)) {
497                 DEBUG(3,("mask_match %s failed\n", finfo->name));
498                 return false;
499         }
500
501         if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
502                 DEBUG(3,("newer_than %s failed\n", finfo->name));
503                 return false;
504         }
505
506         if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
507                 DEBUG(3,("archive %s failed\n", finfo->name));
508                 return false;
509         }
510
511         return true;
512 }
513
514 /****************************************************************************
515  Display info about a file.
516 ****************************************************************************/
517
518 static void display_finfo(file_info *finfo, const char *dir)
519 {
520         time_t t;
521         TALLOC_CTX *ctx = talloc_tos();
522
523         if (!do_this_one(finfo)) {
524                 return;
525         }
526
527         t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
528         if (!showacls) {
529                 d_printf("  %-30s%7.7s %8.0f  %s",
530                          finfo->name,
531                          attrib_string(finfo->mode),
532                         (double)finfo->size,
533                         time_to_asc(t));
534                 dir_total += finfo->size;
535         } else {
536                 char *afname = NULL;
537                 int fnum;
538
539                 /* skip if this is . or .. */
540                 if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
541                         return;
542                 /* create absolute filename for cli_nt_create() FIXME */
543                 afname = talloc_asprintf(ctx,
544                                         "%s%s%s",
545                                         dir,
546                                         CLI_DIRSEP_STR,
547                                         finfo->name);
548                 if (!afname) {
549                         return;
550                 }
551                 /* print file meta date header */
552                 d_printf( "FILENAME:%s\n", finfo->name);
553                 d_printf( "MODE:%s\n", attrib_string(finfo->mode));
554                 d_printf( "SIZE:%.0f\n", (double)finfo->size);
555                 d_printf( "MTIME:%s", time_to_asc(t));
556                 fnum = cli_nt_create(finfo->cli, afname, CREATE_ACCESS_READ);
557                 if (fnum == -1) {
558                         DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
559                                 afname,
560                                 cli_errstr( finfo->cli)));
561                 } else {
562                         SEC_DESC *sd = NULL;
563                         sd = cli_query_secdesc(finfo->cli, fnum, ctx);
564                         if (!sd) {
565                                 DEBUG( 0, ("display_finfo() failed to "
566                                         "get security descriptor: %s",
567                                         cli_errstr( finfo->cli)));
568                         } else {
569                                 display_sec_desc(sd);
570                         }
571                         TALLOC_FREE(sd);
572                 }
573                 TALLOC_FREE(afname);
574         }
575 }
576
577 /****************************************************************************
578  Accumulate size of a file.
579 ****************************************************************************/
580
581 static void do_du(file_info *finfo, const char *dir)
582 {
583         if (do_this_one(finfo)) {
584                 dir_total += finfo->size;
585         }
586 }
587
588 static bool do_list_recurse;
589 static bool do_list_dirs;
590 static char *do_list_queue = 0;
591 static long do_list_queue_size = 0;
592 static long do_list_queue_start = 0;
593 static long do_list_queue_end = 0;
594 static void (*do_list_fn)(file_info *, const char *dir);
595
596 /****************************************************************************
597  Functions for do_list_queue.
598 ****************************************************************************/
599
600 /*
601  * The do_list_queue is a NUL-separated list of strings stored in a
602  * char*.  Since this is a FIFO, we keep track of the beginning and
603  * ending locations of the data in the queue.  When we overflow, we
604  * double the size of the char*.  When the start of the data passes
605  * the midpoint, we move everything back.  This is logically more
606  * complex than a linked list, but easier from a memory management
607  * angle.  In any memory error condition, do_list_queue is reset.
608  * Functions check to ensure that do_list_queue is non-NULL before
609  * accessing it.
610  */
611
612 static void reset_do_list_queue(void)
613 {
614         SAFE_FREE(do_list_queue);
615         do_list_queue_size = 0;
616         do_list_queue_start = 0;
617         do_list_queue_end = 0;
618 }
619
620 static void init_do_list_queue(void)
621 {
622         reset_do_list_queue();
623         do_list_queue_size = 1024;
624         do_list_queue = (char *)SMB_MALLOC(do_list_queue_size);
625         if (do_list_queue == 0) {
626                 d_printf("malloc fail for size %d\n",
627                          (int)do_list_queue_size);
628                 reset_do_list_queue();
629         } else {
630                 memset(do_list_queue, 0, do_list_queue_size);
631         }
632 }
633
634 static void adjust_do_list_queue(void)
635 {
636         /*
637          * If the starting point of the queue is more than half way through,
638          * move everything toward the beginning.
639          */
640
641         if (do_list_queue == NULL) {
642                 DEBUG(4,("do_list_queue is empty\n"));
643                 do_list_queue_start = do_list_queue_end = 0;
644                 return;
645         }
646
647         if (do_list_queue_start == do_list_queue_end) {
648                 DEBUG(4,("do_list_queue is empty\n"));
649                 do_list_queue_start = do_list_queue_end = 0;
650                 *do_list_queue = '\0';
651         } else if (do_list_queue_start > (do_list_queue_size / 2)) {
652                 DEBUG(4,("sliding do_list_queue backward\n"));
653                 memmove(do_list_queue,
654                         do_list_queue + do_list_queue_start,
655                         do_list_queue_end - do_list_queue_start);
656                 do_list_queue_end -= do_list_queue_start;
657                 do_list_queue_start = 0;
658         }
659 }
660
661 static void add_to_do_list_queue(const char *entry)
662 {
663         long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
664         while (new_end > do_list_queue_size) {
665                 do_list_queue_size *= 2;
666                 DEBUG(4,("enlarging do_list_queue to %d\n",
667                          (int)do_list_queue_size));
668                 do_list_queue = (char *)SMB_REALLOC(do_list_queue, do_list_queue_size);
669                 if (! do_list_queue) {
670                         d_printf("failure enlarging do_list_queue to %d bytes\n",
671                                  (int)do_list_queue_size);
672                         reset_do_list_queue();
673                 } else {
674                         memset(do_list_queue + do_list_queue_size / 2,
675                                0, do_list_queue_size / 2);
676                 }
677         }
678         if (do_list_queue) {
679                 safe_strcpy_base(do_list_queue + do_list_queue_end,
680                                  entry, do_list_queue, do_list_queue_size);
681                 do_list_queue_end = new_end;
682                 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
683                          entry, (int)do_list_queue_start, (int)do_list_queue_end));
684         }
685 }
686
687 static char *do_list_queue_head(void)
688 {
689         return do_list_queue + do_list_queue_start;
690 }
691
692 static void remove_do_list_queue_head(void)
693 {
694         if (do_list_queue_end > do_list_queue_start) {
695                 do_list_queue_start += strlen(do_list_queue_head()) + 1;
696                 adjust_do_list_queue();
697                 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
698                          (int)do_list_queue_start, (int)do_list_queue_end));
699         }
700 }
701
702 static int do_list_queue_empty(void)
703 {
704         return (! (do_list_queue && *do_list_queue));
705 }
706
707 /****************************************************************************
708  A helper for do_list.
709 ****************************************************************************/
710
711 static void do_list_helper(const char *mntpoint, file_info *f, const char *mask, void *state)
712 {
713         TALLOC_CTX *ctx = talloc_tos();
714         char *dir = NULL;
715         char *dir_end = NULL;
716
717         /* Work out the directory. */
718         dir = talloc_strdup(ctx, mask);
719         if (!dir) {
720                 return;
721         }
722         if ((dir_end = strrchr(dir, CLI_DIRSEP_CHAR)) != NULL) {
723                 *dir_end = '\0';
724         }
725
726         if (f->mode & aDIR) {
727                 if (do_list_dirs && do_this_one(f)) {
728                         do_list_fn(f, dir);
729                 }
730                 if (do_list_recurse &&
731                     f->name &&
732                     !strequal(f->name,".") &&
733                     !strequal(f->name,"..")) {
734                         char *mask2 = NULL;
735                         char *p = NULL;
736
737                         if (!f->name[0]) {
738                                 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
739                                 TALLOC_FREE(dir);
740                                 return;
741                         }
742
743                         mask2 = talloc_asprintf(ctx,
744                                         "%s%s",
745                                         mntpoint,
746                                         mask);
747                         if (!mask2) {
748                                 TALLOC_FREE(dir);
749                                 return;
750                         }
751                         p = strrchr_m(mask2,CLI_DIRSEP_CHAR);
752                         if (p) {
753                                 p[1] = 0;
754                         } else {
755                                 mask2[0] = '\0';
756                         }
757                         mask2 = talloc_asprintf_append(mask2,
758                                         "%s%s*",
759                                         f->name,
760                                         CLI_DIRSEP_STR);
761                         if (!mask2) {
762                                 TALLOC_FREE(dir);
763                                 return;
764                         }
765                         add_to_do_list_queue(mask2);
766                         TALLOC_FREE(mask2);
767                 }
768                 TALLOC_FREE(dir);
769                 return;
770         }
771
772         if (do_this_one(f)) {
773                 do_list_fn(f,dir);
774         }
775         TALLOC_FREE(dir);
776 }
777
778 /****************************************************************************
779  A wrapper around cli_list that adds recursion.
780 ****************************************************************************/
781
782 void do_list(const char *mask,
783                         uint16 attribute,
784                         void (*fn)(file_info *, const char *dir),
785                         bool rec,
786                         bool dirs)
787 {
788         static int in_do_list = 0;
789         TALLOC_CTX *ctx = talloc_tos();
790         struct cli_state *targetcli = NULL;
791         char *targetpath = NULL;
792
793         if (in_do_list && rec) {
794                 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
795                 exit(1);
796         }
797
798         in_do_list = 1;
799
800         do_list_recurse = rec;
801         do_list_dirs = dirs;
802         do_list_fn = fn;
803
804         if (rec) {
805                 init_do_list_queue();
806                 add_to_do_list_queue(mask);
807
808                 while (!do_list_queue_empty()) {
809                         /*
810                          * Need to copy head so that it doesn't become
811                          * invalid inside the call to cli_list.  This
812                          * would happen if the list were expanded
813                          * during the call.
814                          * Fix from E. Jay Berkenbilt (ejb@ql.org)
815                          */
816                         char *head = talloc_strdup(ctx, do_list_queue_head());
817
818                         if (!head) {
819                                 return;
820                         }
821
822                         /* check for dfs */
823
824                         if ( !cli_resolve_path(ctx, "", cli, head, &targetcli, &targetpath ) ) {
825                                 d_printf("do_list: [%s] %s\n", head, cli_errstr(cli));
826                                 remove_do_list_queue_head();
827                                 continue;
828                         }
829
830                         cli_list(targetcli, targetpath, attribute, do_list_helper, NULL);
831                         remove_do_list_queue_head();
832                         if ((! do_list_queue_empty()) && (fn == display_finfo)) {
833                                 char *next_file = do_list_queue_head();
834                                 char *save_ch = 0;
835                                 if ((strlen(next_file) >= 2) &&
836                                     (next_file[strlen(next_file) - 1] == '*') &&
837                                     (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
838                                         save_ch = next_file +
839                                                 strlen(next_file) - 2;
840                                         *save_ch = '\0';
841                                         if (showacls) {
842                                                 /* cwd is only used if showacls is on */
843                                                 client_set_cwd(next_file);
844                                         }
845                                 }
846                                 if (!showacls) /* don't disturbe the showacls output */
847                                         d_printf("\n%s\n",next_file);
848                                 if (save_ch) {
849                                         *save_ch = CLI_DIRSEP_CHAR;
850                                 }
851                         }
852                         TALLOC_FREE(head);
853                         TALLOC_FREE(targetpath);
854                 }
855         } else {
856                 /* check for dfs */
857                 if (cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetpath)) {
858                         if (cli_list(targetcli, targetpath, attribute, do_list_helper, NULL) == -1) {
859                                 d_printf("%s listing %s\n",
860                                         cli_errstr(targetcli), targetpath);
861                         }
862                         TALLOC_FREE(targetpath);
863                 } else {
864                         d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli));
865                 }
866         }
867
868         in_do_list = 0;
869         reset_do_list_queue();
870 }
871
872 /****************************************************************************
873  Get a directory listing.
874 ****************************************************************************/
875
876 static int cmd_dir(void)
877 {
878         TALLOC_CTX *ctx = talloc_tos();
879         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
880         char *mask = NULL;
881         char *buf = NULL;
882         int rc = 1;
883
884         dir_total = 0;
885         mask = talloc_strdup(ctx, client_get_cur_dir());
886         if (!mask) {
887                 return 1;
888         }
889
890         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
891                 normalize_name(buf);
892                 if (*buf == CLI_DIRSEP_CHAR) {
893                         mask = talloc_strdup(ctx, buf);
894                 } else {
895                         mask = talloc_asprintf_append(mask, "%s", buf);
896                 }
897         } else {
898                 mask = talloc_asprintf_append(mask, "*");
899         }
900         if (!mask) {
901                 return 1;
902         }
903
904         if (showacls) {
905                 /* cwd is only used if showacls is on */
906                 client_set_cwd(client_get_cur_dir());
907         }
908
909         do_list(mask, attribute, display_finfo, recurse, true);
910
911         rc = do_dskattr();
912
913         DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
914
915         return rc;
916 }
917
918 /****************************************************************************
919  Get a directory listing.
920 ****************************************************************************/
921
922 static int cmd_du(void)
923 {
924         TALLOC_CTX *ctx = talloc_tos();
925         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
926         char *mask = NULL;
927         char *buf = NULL;
928         int rc = 1;
929
930         dir_total = 0;
931         mask = talloc_strdup(ctx, client_get_cur_dir());
932         if (!mask) {
933                 return 1;
934         }
935         if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
936                 mask = talloc_asprintf_append(mask, "%s", CLI_DIRSEP_STR);
937                 if (!mask) {
938                         return 1;
939                 }
940         }
941
942         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
943                 normalize_name(buf);
944                 if (*buf == CLI_DIRSEP_CHAR) {
945                         mask = talloc_strdup(ctx, buf);
946                 } else {
947                         mask = talloc_asprintf_append(mask, "%s", buf);
948                 }
949         } else {
950                 mask = talloc_strdup(ctx, "*");
951         }
952
953         do_list(mask, attribute, do_du, recurse, true);
954
955         rc = do_dskattr();
956
957         d_printf("Total number of bytes: %.0f\n", dir_total);
958
959         return rc;
960 }
961
962 static int cmd_echo(void)
963 {
964         TALLOC_CTX *ctx = talloc_tos();
965         char *num;
966         char *data;
967         NTSTATUS status;
968
969         if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
970             || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
971                 d_printf("echo <num> <data>\n");
972                 return 1;
973         }
974
975         status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
976
977         if (!NT_STATUS_IS_OK(status)) {
978                 d_printf("echo failed: %s\n", nt_errstr(status));
979                 return 1;
980         }
981
982         return 0;
983 }
984
985 /****************************************************************************
986  Get a file from rname to lname
987 ****************************************************************************/
988
989 static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
990 {
991         int *pfd = (int *)priv;
992         if (writefile(*pfd, buf, n) == -1) {
993                 return map_nt_error_from_unix(errno);
994         }
995         return NT_STATUS_OK;
996 }
997
998 static int do_get(const char *rname, const char *lname_in, bool reget)
999 {
1000         TALLOC_CTX *ctx = talloc_tos();
1001         int handle = 0, fnum;
1002         bool newhandle = false;
1003         struct timeval tp_start;
1004         uint16 attr;
1005         SMB_OFF_T size;
1006         off_t start = 0;
1007         SMB_OFF_T nread = 0;
1008         int rc = 0;
1009         struct cli_state *targetcli = NULL;
1010         char *targetname = NULL;
1011         char *lname = NULL;
1012         NTSTATUS status;
1013
1014         lname = talloc_strdup(ctx, lname_in);
1015         if (!lname) {
1016                 return 1;
1017         }
1018
1019         if (lowercase) {
1020                 strlower_m(lname);
1021         }
1022
1023         if (!cli_resolve_path(ctx, "", cli, rname, &targetcli, &targetname ) ) {
1024                 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
1025                 return 1;
1026         }
1027
1028         GetTimeOfDay(&tp_start);
1029
1030         fnum = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE);
1031
1032         if (fnum == -1) {
1033                 d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
1034                 return 1;
1035         }
1036
1037         if(!strcmp(lname,"-")) {
1038                 handle = fileno(stdout);
1039         } else {
1040                 if (reget) {
1041                         handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
1042                         if (handle >= 0) {
1043                                 start = sys_lseek(handle, 0, SEEK_END);
1044                                 if (start == -1) {
1045                                         d_printf("Error seeking local file\n");
1046                                         return 1;
1047                                 }
1048                         }
1049                 } else {
1050                         handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1051                 }
1052                 newhandle = true;
1053         }
1054         if (handle < 0) {
1055                 d_printf("Error opening local file %s\n",lname);
1056                 return 1;
1057         }
1058
1059
1060         if (!cli_qfileinfo(targetcli, fnum,
1061                            &attr, &size, NULL, NULL, NULL, NULL, NULL) &&
1062             !cli_getattrE(targetcli, fnum,
1063                           &attr, &size, NULL, NULL, NULL)) {
1064                 d_printf("getattrib: %s\n",cli_errstr(targetcli));
1065                 return 1;
1066         }
1067
1068         DEBUG(1,("getting file %s of size %.0f as %s ",
1069                  rname, (double)size, lname));
1070
1071         status = cli_pull(targetcli, fnum, start, size, io_bufsize,
1072                           writefile_sink, (void *)&handle, &nread);
1073         if (!NT_STATUS_IS_OK(status)) {
1074                 d_fprintf(stderr, "parallel_read returned %s\n",
1075                           nt_errstr(status));
1076                 cli_close(targetcli, fnum);
1077                 return 1;
1078         }
1079
1080         if (!cli_close(targetcli, fnum)) {
1081                 d_printf("Error %s closing remote file\n",cli_errstr(cli));
1082                 rc = 1;
1083         }
1084
1085         if (newhandle) {
1086                 close(handle);
1087         }
1088
1089         if (archive_level >= 2 && (attr & aARCH)) {
1090                 cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
1091         }
1092
1093         {
1094                 struct timeval tp_end;
1095                 int this_time;
1096
1097                 GetTimeOfDay(&tp_end);
1098                 this_time =
1099                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1100                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1101                 get_total_time_ms += this_time;
1102                 get_total_size += nread;
1103
1104                 DEBUG(1,("(%3.1f KiloBytes/sec) (average %3.1f KiloBytes/sec)\n",
1105                          nread / (1.024*this_time + 1.0e-4),
1106                          get_total_size / (1.024*get_total_time_ms)));
1107         }
1108
1109         TALLOC_FREE(targetname);
1110         return rc;
1111 }
1112
1113 /****************************************************************************
1114  Get a file.
1115 ****************************************************************************/
1116
1117 static int cmd_get(void)
1118 {
1119         TALLOC_CTX *ctx = talloc_tos();
1120         char *lname = NULL;
1121         char *rname = NULL;
1122         char *fname = NULL;
1123
1124         rname = talloc_strdup(ctx, client_get_cur_dir());
1125         if (!rname) {
1126                 return 1;
1127         }
1128
1129         if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1130                 d_printf("get <filename> [localname]\n");
1131                 return 1;
1132         }
1133         rname = talloc_asprintf_append(rname, "%s", fname);
1134         if (!rname) {
1135                 return 1;
1136         }
1137         rname = clean_name(ctx, rname);
1138         if (!rname) {
1139                 return 1;
1140         }
1141
1142         next_token_talloc(ctx, &cmd_ptr,&lname,NULL);
1143         if (!lname) {
1144                 lname = fname;
1145         }
1146
1147         return do_get(rname, lname, false);
1148 }
1149
1150 /****************************************************************************
1151  Do an mget operation on one file.
1152 ****************************************************************************/
1153
1154 static void do_mget(file_info *finfo, const char *dir)
1155 {
1156         TALLOC_CTX *ctx = talloc_tos();
1157         char *rname = NULL;
1158         char *quest = NULL;
1159         char *saved_curdir = NULL;
1160         char *mget_mask = NULL;
1161         char *new_cd = NULL;
1162
1163         if (!finfo->name) {
1164                 return;
1165         }
1166
1167         if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1168                 return;
1169
1170         if (abort_mget) {
1171                 d_printf("mget aborted\n");
1172                 return;
1173         }
1174
1175         if (finfo->mode & aDIR) {
1176                 if (asprintf(&quest,
1177                          "Get directory %s? ",finfo->name) < 0) {
1178                         return;
1179                 }
1180         } else {
1181                 if (asprintf(&quest,
1182                          "Get file %s? ",finfo->name) < 0) {
1183                         return;
1184                 }
1185         }
1186
1187         if (prompt && !yesno(quest)) {
1188                 SAFE_FREE(quest);
1189                 return;
1190         }
1191         SAFE_FREE(quest);
1192
1193         if (!(finfo->mode & aDIR)) {
1194                 rname = talloc_asprintf(ctx,
1195                                 "%s%s",
1196                                 client_get_cur_dir(),
1197                                 finfo->name);
1198                 if (!rname) {
1199                         return;
1200                 }
1201                 do_get(rname, finfo->name, false);
1202                 TALLOC_FREE(rname);
1203                 return;
1204         }
1205
1206         /* handle directories */
1207         saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
1208         if (!saved_curdir) {
1209                 return;
1210         }
1211
1212         new_cd = talloc_asprintf(ctx,
1213                                 "%s%s%s",
1214                                 client_get_cur_dir(),
1215                                 finfo->name,
1216                                 CLI_DIRSEP_STR);
1217         if (!new_cd) {
1218                 return;
1219         }
1220         client_set_cur_dir(new_cd);
1221
1222         string_replace(finfo->name,'\\','/');
1223         if (lowercase) {
1224                 strlower_m(finfo->name);
1225         }
1226
1227         if (!directory_exist(finfo->name) &&
1228             mkdir(finfo->name,0777) != 0) {
1229                 d_printf("failed to create directory %s\n",finfo->name);
1230                 client_set_cur_dir(saved_curdir);
1231                 return;
1232         }
1233
1234         if (chdir(finfo->name) != 0) {
1235                 d_printf("failed to chdir to directory %s\n",finfo->name);
1236                 client_set_cur_dir(saved_curdir);
1237                 return;
1238         }
1239
1240         mget_mask = talloc_asprintf(ctx,
1241                         "%s*",
1242                         client_get_cur_dir());
1243
1244         if (!mget_mask) {
1245                 return;
1246         }
1247
1248         do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,false, true);
1249         if (chdir("..") == -1) {
1250                 d_printf("do_mget: failed to chdir to .. (error %s)\n",
1251                         strerror(errno) );
1252         }
1253         client_set_cur_dir(saved_curdir);
1254         TALLOC_FREE(mget_mask);
1255         TALLOC_FREE(saved_curdir);
1256         TALLOC_FREE(new_cd);
1257 }
1258
1259 /****************************************************************************
1260  View the file using the pager.
1261 ****************************************************************************/
1262
1263 static int cmd_more(void)
1264 {
1265         TALLOC_CTX *ctx = talloc_tos();
1266         char *rname = NULL;
1267         char *fname = NULL;
1268         char *lname = NULL;
1269         char *pager_cmd = NULL;
1270         const char *pager;
1271         int fd;
1272         int rc = 0;
1273
1274         rname = talloc_strdup(ctx, client_get_cur_dir());
1275         if (!rname) {
1276                 return 1;
1277         }
1278
1279         lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
1280         if (!lname) {
1281                 return 1;
1282         }
1283         fd = smb_mkstemp(lname);
1284         if (fd == -1) {
1285                 d_printf("failed to create temporary file for more\n");
1286                 return 1;
1287         }
1288         close(fd);
1289
1290         if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1291                 d_printf("more <filename>\n");
1292                 unlink(lname);
1293                 return 1;
1294         }
1295         rname = talloc_asprintf_append(rname, "%s", fname);
1296         if (!rname) {
1297                 return 1;
1298         }
1299         rname = clean_name(ctx,rname);
1300         if (!rname) {
1301                 return 1;
1302         }
1303
1304         rc = do_get(rname, lname, false);
1305
1306         pager=getenv("PAGER");
1307
1308         pager_cmd = talloc_asprintf(ctx,
1309                                 "%s %s",
1310                                 (pager? pager:PAGER),
1311                                 lname);
1312         if (!pager_cmd) {
1313                 return 1;
1314         }
1315         if (system(pager_cmd) == -1) {
1316                 d_printf("system command '%s' returned -1\n",
1317                         pager_cmd);
1318         }
1319         unlink(lname);
1320
1321         return rc;
1322 }
1323
1324 /****************************************************************************
1325  Do a mget command.
1326 ****************************************************************************/
1327
1328 static int cmd_mget(void)
1329 {
1330         TALLOC_CTX *ctx = talloc_tos();
1331         uint16 attribute = aSYSTEM | aHIDDEN;
1332         char *mget_mask = NULL;
1333         char *buf = NULL;
1334
1335         if (recurse) {
1336                 attribute |= aDIR;
1337         }
1338
1339         abort_mget = false;
1340
1341         while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1342                 mget_mask = talloc_strdup(ctx, client_get_cur_dir());
1343                 if (!mget_mask) {
1344                         return 1;
1345                 }
1346                 if (*buf == CLI_DIRSEP_CHAR) {
1347                         mget_mask = talloc_strdup(ctx, buf);
1348                 } else {
1349                         mget_mask = talloc_asprintf_append(mget_mask,
1350                                                         "%s", buf);
1351                 }
1352                 if (!mget_mask) {
1353                         return 1;
1354                 }
1355                 do_list(mget_mask, attribute, do_mget, false, true);
1356         }
1357
1358         if (mget_mask == NULL) {
1359                 d_printf("nothing to mget\n");
1360                 return 0;
1361         }
1362
1363         if (!*mget_mask) {
1364                 mget_mask = talloc_asprintf(ctx,
1365                                         "%s*",
1366                                         client_get_cur_dir());
1367                 if (!mget_mask) {
1368                         return 1;
1369                 }
1370                 do_list(mget_mask, attribute, do_mget, false, true);
1371         }
1372
1373         return 0;
1374 }
1375
1376 /****************************************************************************
1377  Make a directory of name "name".
1378 ****************************************************************************/
1379
1380 static bool do_mkdir(const char *name)
1381 {
1382         TALLOC_CTX *ctx = talloc_tos();
1383         struct cli_state *targetcli;
1384         char *targetname = NULL;
1385
1386         if (!cli_resolve_path(ctx, "", cli, name, &targetcli, &targetname)) {
1387                 d_printf("mkdir %s: %s\n", name, cli_errstr(cli));
1388                 return false;
1389         }
1390
1391         if (!cli_mkdir(targetcli, targetname)) {
1392                 d_printf("%s making remote directory %s\n",
1393                          cli_errstr(targetcli),name);
1394                 return false;
1395         }
1396
1397         return true;
1398 }
1399
1400 /****************************************************************************
1401  Show 8.3 name of a file.
1402 ****************************************************************************/
1403
1404 static bool do_altname(const char *name)
1405 {
1406         fstring altname;
1407
1408         if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
1409                 d_printf("%s getting alt name for %s\n",
1410                          cli_errstr(cli),name);
1411                 return false;
1412         }
1413         d_printf("%s\n", altname);
1414
1415         return true;
1416 }
1417
1418 /****************************************************************************
1419  Exit client.
1420 ****************************************************************************/
1421
1422 static int cmd_quit(void)
1423 {
1424         cli_cm_shutdown();
1425         exit(0);
1426         /* NOTREACHED */
1427         return 0;
1428 }
1429
1430 /****************************************************************************
1431  Make a directory.
1432 ****************************************************************************/
1433
1434 static int cmd_mkdir(void)
1435 {
1436         TALLOC_CTX *ctx = talloc_tos();
1437         char *mask = NULL;
1438         char *buf = NULL;
1439
1440         mask = talloc_strdup(ctx, client_get_cur_dir());
1441         if (!mask) {
1442                 return 1;
1443         }
1444
1445         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1446                 if (!recurse) {
1447                         d_printf("mkdir <dirname>\n");
1448                 }
1449                 return 1;
1450         }
1451         mask = talloc_asprintf_append(mask, "%s", buf);
1452         if (!mask) {
1453                 return 1;
1454         }
1455
1456         if (recurse) {
1457                 char *ddir = NULL;
1458                 char *ddir2 = NULL;
1459                 struct cli_state *targetcli;
1460                 char *targetname = NULL;
1461                 char *p = NULL;
1462                 char *saveptr;
1463
1464                 ddir2 = talloc_strdup(ctx, "");
1465                 if (!ddir2) {
1466                         return 1;
1467                 }
1468
1469                 if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
1470                         return 1;
1471                 }
1472
1473                 ddir = talloc_strdup(ctx, targetname);
1474                 if (!ddir) {
1475                         return 1;
1476                 }
1477                 trim_char(ddir,'.','\0');
1478                 p = strtok_r(ddir, "/\\", &saveptr);
1479                 while (p) {
1480                         ddir2 = talloc_asprintf_append(ddir2, "%s", p);
1481                         if (!ddir2) {
1482                                 return 1;
1483                         }
1484                         if (!cli_chkpath(targetcli, ddir2)) {
1485                                 do_mkdir(ddir2);
1486                         }
1487                         ddir2 = talloc_asprintf_append(ddir2, "%s", CLI_DIRSEP_STR);
1488                         if (!ddir2) {
1489                                 return 1;
1490                         }
1491                         p = strtok_r(NULL, "/\\", &saveptr);
1492                 }
1493         } else {
1494                 do_mkdir(mask);
1495         }
1496
1497         return 0;
1498 }
1499
1500 /****************************************************************************
1501  Show alt name.
1502 ****************************************************************************/
1503
1504 static int cmd_altname(void)
1505 {
1506         TALLOC_CTX *ctx = talloc_tos();
1507         char *name;
1508         char *buf;
1509
1510         name = talloc_strdup(ctx, client_get_cur_dir());
1511         if (!name) {
1512                 return 1;
1513         }
1514
1515         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1516                 d_printf("altname <file>\n");
1517                 return 1;
1518         }
1519         name = talloc_asprintf_append(name, "%s", buf);
1520         if (!name) {
1521                 return 1;
1522         }
1523         do_altname(name);
1524         return 0;
1525 }
1526
1527 /****************************************************************************
1528  Show all info we can get
1529 ****************************************************************************/
1530
1531 static int do_allinfo(const char *name)
1532 {
1533         fstring altname;
1534         struct timespec b_time, a_time, m_time, c_time;
1535         SMB_OFF_T size;
1536         uint16_t mode;
1537         SMB_INO_T ino;
1538         NTTIME tmp;
1539         unsigned int num_streams;
1540         struct stream_struct *streams;
1541         unsigned int i;
1542
1543         if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
1544                 d_printf("%s getting alt name for %s\n",
1545                          cli_errstr(cli),name);
1546                 return false;
1547         }
1548         d_printf("altname: %s\n", altname);
1549
1550         if (!cli_qpathinfo2(cli, name, &b_time, &a_time, &m_time, &c_time,
1551                             &size, &mode, &ino)) {
1552                 d_printf("%s getting pathinfo for %s\n",
1553                          cli_errstr(cli),name);
1554                 return false;
1555         }
1556
1557         unix_timespec_to_nt_time(&tmp, b_time);
1558         d_printf("create_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1559
1560         unix_timespec_to_nt_time(&tmp, a_time);
1561         d_printf("access_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1562
1563         unix_timespec_to_nt_time(&tmp, m_time);
1564         d_printf("write_time:     %s\n", nt_time_string(talloc_tos(), tmp));
1565
1566         unix_timespec_to_nt_time(&tmp, c_time);
1567         d_printf("change_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1568
1569         if (!cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
1570                                    &streams)) {
1571                 d_printf("%s getting streams for %s\n",
1572                          cli_errstr(cli),name);
1573                 return false;
1574         }
1575
1576         for (i=0; i<num_streams; i++) {
1577                 d_printf("stream: [%s], %lld bytes\n", streams[i].name,
1578                          (unsigned long long)streams[i].size);
1579         }
1580
1581         return 0;
1582 }
1583
1584 /****************************************************************************
1585  Show all info we can get
1586 ****************************************************************************/
1587
1588 static int cmd_allinfo(void)
1589 {
1590         TALLOC_CTX *ctx = talloc_tos();
1591         char *name;
1592         char *buf;
1593
1594         name = talloc_strdup(ctx, client_get_cur_dir());
1595         if (!name) {
1596                 return 1;
1597         }
1598
1599         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1600                 d_printf("allinfo <file>\n");
1601                 return 1;
1602         }
1603         name = talloc_asprintf_append(name, "%s", buf);
1604         if (!name) {
1605                 return 1;
1606         }
1607
1608         do_allinfo(name);
1609
1610         return 0;
1611 }
1612
1613 /****************************************************************************
1614  Put a single file.
1615 ****************************************************************************/
1616
1617 static int do_put(const char *rname, const char *lname, bool reput)
1618 {
1619         TALLOC_CTX *ctx = talloc_tos();
1620         int fnum;
1621         XFILE *f;
1622         SMB_OFF_T start = 0;
1623         int rc = 0;
1624         struct timeval tp_start;
1625         struct cli_state *targetcli;
1626         char *targetname = NULL;
1627         struct push_state state;
1628         NTSTATUS status;
1629
1630         if (!cli_resolve_path(ctx, "", cli, rname, &targetcli, &targetname)) {
1631                 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
1632                 return 1;
1633         }
1634
1635         GetTimeOfDay(&tp_start);
1636
1637         if (reput) {
1638                 fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE);
1639                 if (fnum >= 0) {
1640                         if (!cli_qfileinfo(targetcli, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL) &&
1641                             !cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL)) {
1642                                 d_printf("getattrib: %s\n",cli_errstr(cli));
1643                                 return 1;
1644                         }
1645                 }
1646         } else {
1647                 fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
1648         }
1649
1650         if (fnum == -1) {
1651                 d_printf("%s opening remote file %s\n",cli_errstr(targetcli),rname);
1652                 return 1;
1653         }
1654
1655         /* allow files to be piped into smbclient
1656            jdblair 24.jun.98
1657
1658            Note that in this case this function will exit(0) rather
1659            than returning. */
1660         if (!strcmp(lname, "-")) {
1661                 f = x_stdin;
1662                 /* size of file is not known */
1663         } else {
1664                 f = x_fopen(lname,O_RDONLY, 0);
1665                 if (f && reput) {
1666                         if (x_tseek(f, start, SEEK_SET) == -1) {
1667                                 d_printf("Error seeking local file\n");
1668                                 return 1;
1669                         }
1670                 }
1671         }
1672
1673         if (!f) {
1674                 d_printf("Error opening local file %s\n",lname);
1675                 return 1;
1676         }
1677
1678         DEBUG(1,("putting file %s as %s ",lname,
1679                  rname));
1680
1681         x_setvbuf(f, NULL, X_IOFBF, io_bufsize);
1682
1683         state.f = f;
1684         state.nread = 0;
1685
1686         status = cli_push(targetcli, fnum, 0, 0, io_bufsize,
1687                           false, push_source, &state);
1688         if (!NT_STATUS_IS_OK(status)) {
1689                 d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
1690         }
1691
1692         if (!cli_close(targetcli, fnum)) {
1693                 d_printf("%s closing remote file %s\n",cli_errstr(cli),rname);
1694                 x_fclose(f);
1695                 return 1;
1696         }
1697
1698         if (f != x_stdin) {
1699                 x_fclose(f);
1700         }
1701
1702         {
1703                 struct timeval tp_end;
1704                 int this_time;
1705
1706                 GetTimeOfDay(&tp_end);
1707                 this_time =
1708                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1709                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1710                 put_total_time_ms += this_time;
1711                 put_total_size += state.nread;
1712
1713                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1714                          state.nread / (1.024*this_time + 1.0e-4),
1715                          put_total_size / (1.024*put_total_time_ms)));
1716         }
1717
1718         if (f == x_stdin) {
1719                 cli_cm_shutdown();
1720                 exit(0);
1721         }
1722
1723         return rc;
1724 }
1725
1726 /****************************************************************************
1727  Put a file.
1728 ****************************************************************************/
1729
1730 static int cmd_put(void)
1731 {
1732         TALLOC_CTX *ctx = talloc_tos();
1733         char *lname;
1734         char *rname;
1735         char *buf;
1736
1737         rname = talloc_strdup(ctx, client_get_cur_dir());
1738         if (!rname) {
1739                 return 1;
1740         }
1741
1742         if (!next_token_talloc(ctx, &cmd_ptr,&lname,NULL)) {
1743                 d_printf("put <filename>\n");
1744                 return 1;
1745         }
1746
1747         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1748                 rname = talloc_asprintf_append(rname, "%s", buf);
1749         } else {
1750                 rname = talloc_asprintf_append(rname, "%s", lname);
1751         }
1752         if (!rname) {
1753                 return 1;
1754         }
1755
1756         rname = clean_name(ctx, rname);
1757         if (!rname) {
1758                 return 1;
1759         }
1760
1761         {
1762                 SMB_STRUCT_STAT st;
1763                 /* allow '-' to represent stdin
1764                    jdblair, 24.jun.98 */
1765                 if (!file_exist_stat(lname,&st) &&
1766                     (strcmp(lname,"-"))) {
1767                         d_printf("%s does not exist\n",lname);
1768                         return 1;
1769                 }
1770         }
1771
1772         return do_put(rname, lname, false);
1773 }
1774
1775 /*************************************
1776  File list structure.
1777 *************************************/
1778
1779 static struct file_list {
1780         struct file_list *prev, *next;
1781         char *file_path;
1782         bool isdir;
1783 } *file_list;
1784
1785 /****************************************************************************
1786  Free a file_list structure.
1787 ****************************************************************************/
1788
1789 static void free_file_list (struct file_list *l_head)
1790 {
1791         struct file_list *list, *next;
1792
1793         for (list = l_head; list; list = next) {
1794                 next = list->next;
1795                 DLIST_REMOVE(l_head, list);
1796                 SAFE_FREE(list->file_path);
1797                 SAFE_FREE(list);
1798         }
1799 }
1800
1801 /****************************************************************************
1802  Seek in a directory/file list until you get something that doesn't start with
1803  the specified name.
1804 ****************************************************************************/
1805
1806 static bool seek_list(struct file_list *list, char *name)
1807 {
1808         while (list) {
1809                 trim_string(list->file_path,"./","\n");
1810                 if (strncmp(list->file_path, name, strlen(name)) != 0) {
1811                         return true;
1812                 }
1813                 list = list->next;
1814         }
1815
1816         return false;
1817 }
1818
1819 /****************************************************************************
1820  Set the file selection mask.
1821 ****************************************************************************/
1822
1823 static int cmd_select(void)
1824 {
1825         TALLOC_CTX *ctx = talloc_tos();
1826         char *new_fs = NULL;
1827         next_token_talloc(ctx, &cmd_ptr,&new_fs,NULL)
1828                 ;
1829         if (new_fs) {
1830                 client_set_fileselection(new_fs);
1831         } else {
1832                 client_set_fileselection("");
1833         }
1834         return 0;
1835 }
1836
1837 /****************************************************************************
1838   Recursive file matching function act as find
1839   match must be always set to true when calling this function
1840 ****************************************************************************/
1841
1842 static int file_find(struct file_list **list, const char *directory,
1843                       const char *expression, bool match)
1844 {
1845         SMB_STRUCT_DIR *dir;
1846         struct file_list *entry;
1847         struct stat statbuf;
1848         int ret;
1849         char *path;
1850         bool isdir;
1851         const char *dname;
1852
1853         dir = sys_opendir(directory);
1854         if (!dir)
1855                 return -1;
1856
1857         while ((dname = readdirname(dir))) {
1858                 if (!strcmp("..", dname))
1859                         continue;
1860                 if (!strcmp(".", dname))
1861                         continue;
1862
1863                 if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
1864                         continue;
1865                 }
1866
1867                 isdir = false;
1868                 if (!match || !gen_fnmatch(expression, dname)) {
1869                         if (recurse) {
1870                                 ret = stat(path, &statbuf);
1871                                 if (ret == 0) {
1872                                         if (S_ISDIR(statbuf.st_mode)) {
1873                                                 isdir = true;
1874                                                 ret = file_find(list, path, expression, false);
1875                                         }
1876                                 } else {
1877                                         d_printf("file_find: cannot stat file %s\n", path);
1878                                 }
1879
1880                                 if (ret == -1) {
1881                                         SAFE_FREE(path);
1882                                         sys_closedir(dir);
1883                                         return -1;
1884                                 }
1885                         }
1886                         entry = SMB_MALLOC_P(struct file_list);
1887                         if (!entry) {
1888                                 d_printf("Out of memory in file_find\n");
1889                                 sys_closedir(dir);
1890                                 return -1;
1891                         }
1892                         entry->file_path = path;
1893                         entry->isdir = isdir;
1894                         DLIST_ADD(*list, entry);
1895                 } else {
1896                         SAFE_FREE(path);
1897                 }
1898         }
1899
1900         sys_closedir(dir);
1901         return 0;
1902 }
1903
1904 /****************************************************************************
1905  mput some files.
1906 ****************************************************************************/
1907
1908 static int cmd_mput(void)
1909 {
1910         TALLOC_CTX *ctx = talloc_tos();
1911         char *p = NULL;
1912
1913         while (next_token_talloc(ctx, &cmd_ptr,&p,NULL)) {
1914                 int ret;
1915                 struct file_list *temp_list;
1916                 char *quest, *lname, *rname;
1917
1918                 file_list = NULL;
1919
1920                 ret = file_find(&file_list, ".", p, true);
1921                 if (ret) {
1922                         free_file_list(file_list);
1923                         continue;
1924                 }
1925
1926                 quest = NULL;
1927                 lname = NULL;
1928                 rname = NULL;
1929
1930                 for (temp_list = file_list; temp_list;
1931                      temp_list = temp_list->next) {
1932
1933                         SAFE_FREE(lname);
1934                         if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) {
1935                                 continue;
1936                         }
1937                         trim_string(lname, "./", "/");
1938
1939                         /* check if it's a directory */
1940                         if (temp_list->isdir) {
1941                                 /* if (!recurse) continue; */
1942
1943                                 SAFE_FREE(quest);
1944                                 if (asprintf(&quest, "Put directory %s? ", lname) < 0) {
1945                                         break;
1946                                 }
1947                                 if (prompt && !yesno(quest)) { /* No */
1948                                         /* Skip the directory */
1949                                         lname[strlen(lname)-1] = '/';
1950                                         if (!seek_list(temp_list, lname))
1951                                                 break;
1952                                 } else { /* Yes */
1953                                         SAFE_FREE(rname);
1954                                         if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
1955                                                 break;
1956                                         }
1957                                         normalize_name(rname);
1958                                         if (!cli_chkpath(cli, rname) &&
1959                                             !do_mkdir(rname)) {
1960                                                 DEBUG (0, ("Unable to make dir, skipping..."));
1961                                                 /* Skip the directory */
1962                                                 lname[strlen(lname)-1] = '/';
1963                                                 if (!seek_list(temp_list, lname)) {
1964                                                         break;
1965                                                 }
1966                                         }
1967                                 }
1968                                 continue;
1969                         } else {
1970                                 SAFE_FREE(quest);
1971                                 if (asprintf(&quest,"Put file %s? ", lname) < 0) {
1972                                         break;
1973                                 }
1974                                 if (prompt && !yesno(quest)) {
1975                                         /* No */
1976                                         continue;
1977                                 }
1978
1979                                 /* Yes */
1980                                 SAFE_FREE(rname);
1981                                 if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
1982                                         break;
1983                                 }
1984                         }
1985
1986                         normalize_name(rname);
1987
1988                         do_put(rname, lname, false);
1989                 }
1990                 free_file_list(file_list);
1991                 SAFE_FREE(quest);
1992                 SAFE_FREE(lname);
1993                 SAFE_FREE(rname);
1994         }
1995
1996         return 0;
1997 }
1998
1999 /****************************************************************************
2000  Cancel a print job.
2001 ****************************************************************************/
2002
2003 static int do_cancel(int job)
2004 {
2005         if (cli_printjob_del(cli, job)) {
2006                 d_printf("Job %d cancelled\n",job);
2007                 return 0;
2008         } else {
2009                 d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
2010                 return 1;
2011         }
2012 }
2013
2014 /****************************************************************************
2015  Cancel a print job.
2016 ****************************************************************************/
2017
2018 static int cmd_cancel(void)
2019 {
2020         TALLOC_CTX *ctx = talloc_tos();
2021         char *buf = NULL;
2022         int job;
2023
2024         if (!next_token_talloc(ctx, &cmd_ptr, &buf,NULL)) {
2025                 d_printf("cancel <jobid> ...\n");
2026                 return 1;
2027         }
2028         do {
2029                 job = atoi(buf);
2030                 do_cancel(job);
2031         } while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL));
2032
2033         return 0;
2034 }
2035
2036 /****************************************************************************
2037  Print a file.
2038 ****************************************************************************/
2039
2040 static int cmd_print(void)
2041 {
2042         TALLOC_CTX *ctx = talloc_tos();
2043         char *lname = NULL;
2044         char *rname = NULL;
2045         char *p = NULL;
2046
2047         if (!next_token_talloc(ctx, &cmd_ptr, &lname,NULL)) {
2048                 d_printf("print <filename>\n");
2049                 return 1;
2050         }
2051
2052         rname = talloc_strdup(ctx, lname);
2053         if (!rname) {
2054                 return 1;
2055         }
2056         p = strrchr_m(rname,'/');
2057         if (p) {
2058                 rname = talloc_asprintf(ctx,
2059                                         "%s-%d",
2060                                         p+1,
2061                                         (int)sys_getpid());
2062         }
2063         if (strequal(lname,"-")) {
2064                 rname = talloc_asprintf(ctx,
2065                                 "stdin-%d",
2066                                 (int)sys_getpid());
2067         }
2068         if (!rname) {
2069                 return 1;
2070         }
2071
2072         return do_put(rname, lname, false);
2073 }
2074
2075 /****************************************************************************
2076  Show a print queue entry.
2077 ****************************************************************************/
2078
2079 static void queue_fn(struct print_job_info *p)
2080 {
2081         d_printf("%-6d   %-9d    %s\n", (int)p->id, (int)p->size, p->name);
2082 }
2083
2084 /****************************************************************************
2085  Show a print queue.
2086 ****************************************************************************/
2087
2088 static int cmd_queue(void)
2089 {
2090         cli_print_queue(cli, queue_fn);
2091         return 0;
2092 }
2093
2094 /****************************************************************************
2095  Delete some files.
2096 ****************************************************************************/
2097
2098 static void do_del(file_info *finfo, const char *dir)
2099 {
2100         TALLOC_CTX *ctx = talloc_tos();
2101         char *mask = NULL;
2102
2103         mask = talloc_asprintf(ctx,
2104                                 "%s%c%s",
2105                                 dir,
2106                                 CLI_DIRSEP_CHAR,
2107                                 finfo->name);
2108         if (!mask) {
2109                 return;
2110         }
2111
2112         if (finfo->mode & aDIR) {
2113                 TALLOC_FREE(mask);
2114                 return;
2115         }
2116
2117         if (!cli_unlink(finfo->cli, mask)) {
2118                 d_printf("%s deleting remote file %s\n",
2119                                 cli_errstr(finfo->cli),mask);
2120         }
2121         TALLOC_FREE(mask);
2122 }
2123
2124 /****************************************************************************
2125  Delete some files.
2126 ****************************************************************************/
2127
2128 static int cmd_del(void)
2129 {
2130         TALLOC_CTX *ctx = talloc_tos();
2131         char *mask = NULL;
2132         char *buf = NULL;
2133         uint16 attribute = aSYSTEM | aHIDDEN;
2134
2135         if (recurse) {
2136                 attribute |= aDIR;
2137         }
2138
2139         mask = talloc_strdup(ctx, client_get_cur_dir());
2140         if (!mask) {
2141                 return 1;
2142         }
2143         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2144                 d_printf("del <filename>\n");
2145                 return 1;
2146         }
2147         mask = talloc_asprintf_append(mask, "%s", buf);
2148         if (!mask) {
2149                 return 1;
2150         }
2151
2152         do_list(mask,attribute,do_del,false,false);
2153         return 0;
2154 }
2155
2156 /****************************************************************************
2157  Wildcard delete some files.
2158 ****************************************************************************/
2159
2160 static int cmd_wdel(void)
2161 {
2162         TALLOC_CTX *ctx = talloc_tos();
2163         char *mask = NULL;
2164         char *buf = NULL;
2165         uint16 attribute;
2166         struct cli_state *targetcli;
2167         char *targetname = NULL;
2168
2169         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2170                 d_printf("wdel 0x<attrib> <wcard>\n");
2171                 return 1;
2172         }
2173
2174         attribute = (uint16)strtol(buf, (char **)NULL, 16);
2175
2176         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2177                 d_printf("wdel 0x<attrib> <wcard>\n");
2178                 return 1;
2179         }
2180
2181         mask = talloc_asprintf(ctx, "%s%s",
2182                         client_get_cur_dir(),
2183                         buf);
2184         if (!mask) {
2185                 return 1;
2186         }
2187
2188         if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
2189                 d_printf("cmd_wdel %s: %s\n", mask, cli_errstr(cli));
2190                 return 1;
2191         }
2192
2193         if (!cli_unlink_full(targetcli, targetname, attribute)) {
2194                 d_printf("%s deleting remote files %s\n",cli_errstr(targetcli),targetname);
2195         }
2196         return 0;
2197 }
2198
2199 /****************************************************************************
2200 ****************************************************************************/
2201
2202 static int cmd_open(void)
2203 {
2204         TALLOC_CTX *ctx = talloc_tos();
2205         char *mask = NULL;
2206         char *buf = NULL;
2207         char *targetname = NULL;
2208         struct cli_state *targetcli;
2209         int fnum;
2210
2211         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2212                 d_printf("open <filename>\n");
2213                 return 1;
2214         }
2215         mask = talloc_asprintf(ctx,
2216                         "%s%s",
2217                         client_get_cur_dir(),
2218                         buf);
2219         if (!mask) {
2220                 return 1;
2221         }
2222
2223         if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
2224                 d_printf("open %s: %s\n", mask, cli_errstr(cli));
2225                 return 1;
2226         }
2227
2228         fnum = cli_nt_create(targetcli, targetname, FILE_READ_DATA|FILE_WRITE_DATA);
2229         if (fnum == -1) {
2230                 fnum = cli_nt_create(targetcli, targetname, FILE_READ_DATA);
2231                 if (fnum != -1) {
2232                         d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2233                 } else {
2234                         d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
2235                 }
2236         } else {
2237                 d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2238         }
2239         return 0;
2240 }
2241
2242 static int cmd_posix_encrypt(void)
2243 {
2244         TALLOC_CTX *ctx = talloc_tos();
2245         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2246
2247         if (cli->use_kerberos) {
2248                 status = cli_gss_smb_encryption_start(cli);
2249         } else {
2250                 char *domain = NULL;
2251                 char *user = NULL;
2252                 char *password = NULL;
2253
2254                 if (!next_token_talloc(ctx, &cmd_ptr,&domain,NULL)) {
2255                         d_printf("posix_encrypt domain user password\n");
2256                         return 1;
2257                 }
2258
2259                 if (!next_token_talloc(ctx, &cmd_ptr,&user,NULL)) {
2260                         d_printf("posix_encrypt domain user password\n");
2261                         return 1;
2262                 }
2263
2264                 if (!next_token_talloc(ctx, &cmd_ptr,&password,NULL)) {
2265                         d_printf("posix_encrypt domain user password\n");
2266                         return 1;
2267                 }
2268
2269                 status = cli_raw_ntlm_smb_encryption_start(cli,
2270                                                         user,
2271                                                         password,
2272                                                         domain);
2273         }
2274
2275         if (!NT_STATUS_IS_OK(status)) {
2276                 d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
2277         } else {
2278                 d_printf("encryption on\n");
2279                 smb_encrypt = true;
2280         }
2281
2282         return 0;
2283 }
2284
2285 /****************************************************************************
2286 ****************************************************************************/
2287
2288 static int cmd_posix_open(void)
2289 {
2290         TALLOC_CTX *ctx = talloc_tos();
2291         char *mask = NULL;
2292         char *buf = NULL;
2293         char *targetname = NULL;
2294         struct cli_state *targetcli;
2295         mode_t mode;
2296         int fnum;
2297
2298         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2299                 d_printf("posix_open <filename> 0<mode>\n");
2300                 return 1;
2301         }
2302         mask = talloc_asprintf(ctx,
2303                         "%s%s",
2304                         client_get_cur_dir(),
2305                         buf);
2306         if (!mask) {
2307                 return 1;
2308         }
2309
2310         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2311                 d_printf("posix_open <filename> 0<mode>\n");
2312                 return 1;
2313         }
2314         mode = (mode_t)strtol(buf, (char **)NULL, 8);
2315
2316         if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
2317                 d_printf("posix_open %s: %s\n", mask, cli_errstr(cli));
2318                 return 1;
2319         }
2320
2321         fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode);
2322         if (fnum == -1) {
2323                 fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode);
2324                 if (fnum != -1) {
2325                         d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
2326                 } else {
2327                         d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
2328                 }
2329         } else {
2330                 d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
2331         }
2332
2333         return 0;
2334 }
2335
2336 static int cmd_posix_mkdir(void)
2337 {
2338         TALLOC_CTX *ctx = talloc_tos();
2339         char *mask = NULL;
2340         char *buf = NULL;
2341         char *targetname = NULL;
2342         struct cli_state *targetcli;
2343         mode_t mode;
2344         int fnum;
2345
2346         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2347                 d_printf("posix_mkdir <filename> 0<mode>\n");
2348                 return 1;
2349         }
2350         mask = talloc_asprintf(ctx,
2351                         "%s%s",
2352                         client_get_cur_dir(),
2353                         buf);
2354         if (!mask) {
2355                 return 1;
2356         }
2357
2358         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2359                 d_printf("posix_mkdir <filename> 0<mode>\n");
2360                 return 1;
2361         }
2362         mode = (mode_t)strtol(buf, (char **)NULL, 8);
2363
2364         if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
2365                 d_printf("posix_mkdir %s: %s\n", mask, cli_errstr(cli));
2366                 return 1;
2367         }
2368
2369         fnum = cli_posix_mkdir(targetcli, targetname, mode);
2370         if (fnum == -1) {
2371                 d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
2372         } else {
2373                 d_printf("posix_mkdir created directory %s\n", targetname);
2374         }
2375         return 0;
2376 }
2377
2378 static int cmd_posix_unlink(void)
2379 {
2380         TALLOC_CTX *ctx = talloc_tos();
2381         char *mask = NULL;
2382         char *buf = NULL;
2383         char *targetname = NULL;
2384         struct cli_state *targetcli;
2385
2386         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2387                 d_printf("posix_unlink <filename>\n");
2388                 return 1;
2389         }
2390         mask = talloc_asprintf(ctx,
2391                         "%s%s",
2392                         client_get_cur_dir(),
2393                         buf);
2394         if (!mask) {
2395                 return 1;
2396         }
2397
2398         if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
2399                 d_printf("posix_unlink %s: %s\n", mask, cli_errstr(cli));
2400                 return 1;
2401         }
2402
2403         if (!cli_posix_unlink(targetcli, targetname)) {
2404                 d_printf("Failed to unlink file %s. %s\n", targetname, cli_errstr(cli));
2405         } else {
2406                 d_printf("posix_unlink deleted file %s\n", targetname);
2407         }
2408
2409         return 0;
2410 }
2411
2412 static int cmd_posix_rmdir(void)
2413 {
2414         TALLOC_CTX *ctx = talloc_tos();
2415         char *mask = NULL;
2416         char *buf = NULL;
2417         char *targetname = NULL;
2418         struct cli_state *targetcli;
2419
2420         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2421                 d_printf("posix_rmdir <filename>\n");
2422                 return 1;
2423         }
2424         mask = talloc_asprintf(ctx,
2425                         "%s%s",
2426                         client_get_cur_dir(),
2427                         buf);
2428         if (!mask) {
2429                 return 1;
2430         }
2431
2432         if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
2433                 d_printf("posix_rmdir %s: %s\n", mask, cli_errstr(cli));
2434                 return 1;
2435         }
2436
2437         if (!cli_posix_rmdir(targetcli, targetname)) {
2438                 d_printf("Failed to unlink directory %s. %s\n", targetname, cli_errstr(cli));
2439         } else {
2440                 d_printf("posix_rmdir deleted directory %s\n", targetname);
2441         }
2442
2443         return 0;
2444 }
2445
2446 static int cmd_close(void)
2447 {
2448         TALLOC_CTX *ctx = talloc_tos();
2449         char *buf = NULL;
2450         int fnum;
2451
2452         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2453                 d_printf("close <fnum>\n");
2454                 return 1;
2455         }
2456
2457         fnum = atoi(buf);
2458         /* We really should use the targetcli here.... */
2459         if (!cli_close(cli, fnum)) {
2460                 d_printf("close %d: %s\n", fnum, cli_errstr(cli));
2461                 return 1;
2462         }
2463         return 0;
2464 }
2465
2466 static int cmd_posix(void)
2467 {
2468         TALLOC_CTX *ctx = talloc_tos();
2469         uint16 major, minor;
2470         uint32 caplow, caphigh;
2471         char *caps;
2472
2473         if (!SERVER_HAS_UNIX_CIFS(cli)) {
2474                 d_printf("Server doesn't support UNIX CIFS extensions.\n");
2475                 return 1;
2476         }
2477
2478         if (!cli_unix_extensions_version(cli, &major, &minor, &caplow, &caphigh)) {
2479                 d_printf("Can't get UNIX CIFS extensions version from server.\n");
2480                 return 1;
2481         }
2482
2483         d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
2484
2485         caps = talloc_strdup(ctx, "");
2486         if (!caps) {
2487                 return 1;
2488         }
2489         if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
2490                 caps = talloc_asprintf_append(caps, "locks ");
2491                 if (!caps) {
2492                         return 1;
2493                 }
2494         }
2495         if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
2496                 caps = talloc_asprintf_append(caps, "acls ");
2497                 if (!caps) {
2498                         return 1;
2499                 }
2500         }
2501         if (caplow & CIFS_UNIX_XATTTR_CAP) {
2502                 caps = talloc_asprintf_append(caps, "eas ");
2503                 if (!caps) {
2504                         return 1;
2505                 }
2506         }
2507         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2508                 caps = talloc_asprintf_append(caps, "pathnames ");
2509                 if (!caps) {
2510                         return 1;
2511                 }
2512         }
2513         if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
2514                 caps = talloc_asprintf_append(caps, "posix_path_operations ");
2515                 if (!caps) {
2516                         return 1;
2517                 }
2518         }
2519         if (caplow & CIFS_UNIX_LARGE_READ_CAP) {
2520                 caps = talloc_asprintf_append(caps, "large_read ");
2521                 if (!caps) {
2522                         return 1;
2523                 }
2524         }
2525         if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) {
2526                 caps = talloc_asprintf_append(caps, "large_write ");
2527                 if (!caps) {
2528                         return 1;
2529                 }
2530         }
2531         if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) {
2532                 caps = talloc_asprintf_append(caps, "posix_encrypt ");
2533                 if (!caps) {
2534                         return 1;
2535                 }
2536         }
2537         if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) {
2538                 caps = talloc_asprintf_append(caps, "mandatory_posix_encrypt ");
2539                 if (!caps) {
2540                         return 1;
2541                 }
2542         }
2543
2544         if (*caps && caps[strlen(caps)-1] == ' ') {
2545                 caps[strlen(caps)-1] = '\0';
2546         }
2547
2548         d_printf("Server supports CIFS capabilities %s\n", caps);
2549
2550         if (!cli_set_unix_extensions_capabilities(cli, major, minor, caplow, caphigh)) {
2551                 d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n", cli_errstr(cli));
2552                 return 1;
2553         }
2554
2555         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2556                 CLI_DIRSEP_CHAR = '/';
2557                 *CLI_DIRSEP_STR = '/';
2558                 client_set_cur_dir(CLI_DIRSEP_STR);
2559         }
2560
2561         return 0;
2562 }
2563
2564 static int cmd_lock(void)
2565 {
2566         TALLOC_CTX *ctx = talloc_tos();
2567         char *buf = NULL;
2568         uint64_t start, len;
2569         enum brl_type lock_type;
2570         int fnum;
2571
2572         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2573                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2574                 return 1;
2575         }
2576         fnum = atoi(buf);
2577
2578         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2579                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2580                 return 1;
2581         }
2582
2583         if (*buf == 'r' || *buf == 'R') {
2584                 lock_type = READ_LOCK;
2585         } else if (*buf == 'w' || *buf == 'W') {
2586                 lock_type = WRITE_LOCK;
2587         } else {
2588                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2589                 return 1;
2590         }
2591
2592         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2593                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2594                 return 1;
2595         }
2596
2597         start = (uint64_t)strtol(buf, (char **)NULL, 16);
2598
2599         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2600                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2601                 return 1;
2602         }
2603
2604         len = (uint64_t)strtol(buf, (char **)NULL, 16);
2605
2606         if (!cli_posix_lock(cli, fnum, start, len, true, lock_type)) {
2607                 d_printf("lock failed %d: %s\n", fnum, cli_errstr(cli));
2608         }
2609
2610         return 0;
2611 }
2612
2613 static int cmd_unlock(void)
2614 {
2615         TALLOC_CTX *ctx = talloc_tos();
2616         char *buf = NULL;
2617         uint64_t start, len;
2618         int fnum;
2619
2620         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2621                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2622                 return 1;
2623         }
2624         fnum = atoi(buf);
2625
2626         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2627                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2628                 return 1;
2629         }
2630
2631         start = (uint64_t)strtol(buf, (char **)NULL, 16);
2632
2633         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2634                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2635                 return 1;
2636         }
2637
2638         len = (uint64_t)strtol(buf, (char **)NULL, 16);
2639
2640         if (!cli_posix_unlock(cli, fnum, start, len)) {
2641                 d_printf("unlock failed %d: %s\n", fnum, cli_errstr(cli));
2642         }
2643
2644         return 0;
2645 }
2646
2647
2648 /****************************************************************************
2649  Remove a directory.
2650 ****************************************************************************/
2651
2652 static int cmd_rmdir(void)
2653 {
2654         TALLOC_CTX *ctx = talloc_tos();
2655         char *mask = NULL;
2656         char *buf = NULL;
2657         char *targetname = NULL;
2658         struct cli_state *targetcli;
2659
2660         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2661                 d_printf("rmdir <dirname>\n");
2662                 return 1;
2663         }
2664         mask = talloc_asprintf(ctx,
2665                         "%s%s",
2666                         client_get_cur_dir(),
2667                         buf);
2668         if (!mask) {
2669                 return 1;
2670         }
2671
2672         if (!cli_resolve_path(ctx, "", cli, mask, &targetcli, &targetname)) {
2673                 d_printf("rmdir %s: %s\n", mask, cli_errstr(cli));
2674                 return 1;
2675         }
2676
2677         if (!cli_rmdir(targetcli, targetname)) {
2678                 d_printf("%s removing remote directory file %s\n",
2679                          cli_errstr(targetcli),mask);
2680         }
2681
2682         return 0;
2683 }
2684
2685 /****************************************************************************
2686  UNIX hardlink.
2687 ****************************************************************************/
2688
2689 static int cmd_link(void)
2690 {
2691         TALLOC_CTX *ctx = talloc_tos();
2692         char *oldname = NULL;
2693         char *newname = NULL;
2694         char *buf = NULL;
2695         char *buf2 = NULL;
2696         char *targetname = NULL;
2697         struct cli_state *targetcli;
2698
2699         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
2700             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
2701                 d_printf("link <oldname> <newname>\n");
2702                 return 1;
2703         }
2704         oldname = talloc_asprintf(ctx,
2705                         "%s%s",
2706                         client_get_cur_dir(),
2707                         buf);
2708         if (!oldname) {
2709                 return 1;
2710         }
2711         newname = talloc_asprintf(ctx,
2712                         "%s%s",
2713                         client_get_cur_dir(),
2714                         buf2);
2715         if (!newname) {
2716                 return 1;
2717         }
2718
2719         if (!cli_resolve_path(ctx, "", cli, oldname, &targetcli, &targetname)) {
2720                 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
2721                 return 1;
2722         }
2723
2724         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2725                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2726                 return 1;
2727         }
2728
2729         if (!cli_unix_hardlink(targetcli, targetname, newname)) {
2730                 d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
2731                 return 1;
2732         }
2733         return 0;
2734 }
2735
2736 /****************************************************************************
2737  UNIX symlink.
2738 ****************************************************************************/
2739
2740 static int cmd_symlink(void)
2741 {
2742         TALLOC_CTX *ctx = talloc_tos();
2743         char *oldname = NULL;
2744         char *newname = NULL;
2745         char *buf = NULL;
2746         char *buf2 = NULL;
2747         char *targetname = NULL;
2748         struct cli_state *targetcli;
2749
2750         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
2751             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
2752                 d_printf("symlink <oldname> <newname>\n");
2753                 return 1;
2754         }
2755         oldname = talloc_asprintf(ctx,
2756                         "%s%s",
2757                         client_get_cur_dir(),
2758                         buf);
2759         if (!oldname) {
2760                 return 1;
2761         }
2762         newname = talloc_asprintf(ctx,
2763                         "%s%s",
2764                         client_get_cur_dir(),
2765                         buf2);
2766         if (!newname) {
2767                 return 1;
2768         }
2769
2770         if (!cli_resolve_path(ctx, "", cli, oldname, &targetcli, &targetname)) {
2771                 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
2772                 return 1;
2773         }
2774
2775         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2776                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2777                 return 1;
2778         }
2779
2780         if (!cli_unix_symlink(targetcli, targetname, newname)) {
2781                 d_printf("%s symlinking files (%s -> %s)\n",
2782                         cli_errstr(targetcli), newname, targetname);
2783                 return 1;
2784         }
2785
2786         return 0;
2787 }
2788
2789 /****************************************************************************
2790  UNIX chmod.
2791 ****************************************************************************/
2792
2793 static int cmd_chmod(void)
2794 {
2795         TALLOC_CTX *ctx = talloc_tos();
2796         char *src = NULL;
2797         char *buf = NULL;
2798         char *buf2 = NULL;
2799         char *targetname = NULL;
2800         struct cli_state *targetcli;
2801         mode_t mode;
2802
2803         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
2804             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
2805                 d_printf("chmod mode file\n");
2806                 return 1;
2807         }
2808         src = talloc_asprintf(ctx,
2809                         "%s%s",
2810                         client_get_cur_dir(),
2811                         buf2);
2812         if (!src) {
2813                 return 1;
2814         }
2815
2816         mode = (mode_t)strtol(buf, NULL, 8);
2817
2818         if (!cli_resolve_path(ctx, "", cli, src, &targetcli, &targetname)) {
2819                 d_printf("chmod %s: %s\n", src, cli_errstr(cli));
2820                 return 1;
2821         }
2822
2823         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2824                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2825                 return 1;
2826         }
2827
2828         if (!cli_unix_chmod(targetcli, targetname, mode)) {
2829                 d_printf("%s chmod file %s 0%o\n",
2830                         cli_errstr(targetcli), src, (unsigned int)mode);
2831                 return 1;
2832         }
2833
2834         return 0;
2835 }
2836
2837 static const char *filetype_to_str(mode_t mode)
2838 {
2839         if (S_ISREG(mode)) {
2840                 return "regular file";
2841         } else if (S_ISDIR(mode)) {
2842                 return "directory";
2843         } else
2844 #ifdef S_ISCHR
2845         if (S_ISCHR(mode)) {
2846                 return "character device";
2847         } else
2848 #endif
2849 #ifdef S_ISBLK
2850         if (S_ISBLK(mode)) {
2851                 return "block device";
2852         } else
2853 #endif
2854 #ifdef S_ISFIFO
2855         if (S_ISFIFO(mode)) {
2856                 return "fifo";
2857         } else
2858 #endif
2859 #ifdef S_ISLNK
2860         if (S_ISLNK(mode)) {
2861                 return "symbolic link";
2862         } else
2863 #endif
2864 #ifdef S_ISSOCK
2865         if (S_ISSOCK(mode)) {
2866                 return "socket";
2867         } else
2868 #endif
2869         return "";
2870 }
2871
2872 static char rwx_to_str(mode_t m, mode_t bt, char ret)
2873 {
2874         if (m & bt) {
2875                 return ret;
2876         } else {
2877                 return '-';
2878         }
2879 }
2880
2881 static char *unix_mode_to_str(char *s, mode_t m)
2882 {
2883         char *p = s;
2884         const char *str = filetype_to_str(m);
2885
2886         switch(str[0]) {
2887                 case 'd':
2888                         *p++ = 'd';
2889                         break;
2890                 case 'c':
2891                         *p++ = 'c';
2892                         break;
2893                 case 'b':
2894                         *p++ = 'b';
2895                         break;
2896                 case 'f':
2897                         *p++ = 'p';
2898                         break;
2899                 case 's':
2900                         *p++ = str[1] == 'y' ? 'l' : 's';
2901                         break;
2902                 case 'r':
2903                 default:
2904                         *p++ = '-';
2905                         break;
2906         }
2907         *p++ = rwx_to_str(m, S_IRUSR, 'r');
2908         *p++ = rwx_to_str(m, S_IWUSR, 'w');
2909         *p++ = rwx_to_str(m, S_IXUSR, 'x');
2910         *p++ = rwx_to_str(m, S_IRGRP, 'r');
2911         *p++ = rwx_to_str(m, S_IWGRP, 'w');
2912         *p++ = rwx_to_str(m, S_IXGRP, 'x');
2913         *p++ = rwx_to_str(m, S_IROTH, 'r');
2914         *p++ = rwx_to_str(m, S_IWOTH, 'w');
2915         *p++ = rwx_to_str(m, S_IXOTH, 'x');
2916         *p++ = '\0';
2917         return s;
2918 }
2919
2920 /****************************************************************************
2921  Utility function for UNIX getfacl.
2922 ****************************************************************************/
2923
2924 static char *perms_to_string(fstring permstr, unsigned char perms)
2925 {
2926         fstrcpy(permstr, "---");
2927         if (perms & SMB_POSIX_ACL_READ) {
2928                 permstr[0] = 'r';
2929         }
2930         if (perms & SMB_POSIX_ACL_WRITE) {
2931                 permstr[1] = 'w';
2932         }
2933         if (perms & SMB_POSIX_ACL_EXECUTE) {
2934                 permstr[2] = 'x';
2935         }
2936         return permstr;
2937 }
2938
2939 /****************************************************************************
2940  UNIX getfacl.
2941 ****************************************************************************/
2942
2943 static int cmd_getfacl(void)
2944 {
2945         TALLOC_CTX *ctx = talloc_tos();
2946         char *src = NULL;
2947         char *name = NULL;
2948         char *targetname = NULL;
2949         struct cli_state *targetcli;
2950         uint16 major, minor;
2951         uint32 caplow, caphigh;
2952         char *retbuf = NULL;
2953         size_t rb_size = 0;
2954         SMB_STRUCT_STAT sbuf;
2955         uint16 num_file_acls = 0;
2956         uint16 num_dir_acls = 0;
2957         uint16 i;
2958
2959         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
2960                 d_printf("getfacl filename\n");
2961                 return 1;
2962         }
2963         src = talloc_asprintf(ctx,
2964                         "%s%s",
2965                         client_get_cur_dir(),
2966                         name);
2967         if (!src) {
2968                 return 1;
2969         }
2970
2971         if (!cli_resolve_path(ctx, "", cli, src, &targetcli, &targetname)) {
2972                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
2973                 return 1;
2974         }
2975
2976         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2977                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2978                 return 1;
2979         }
2980
2981         if (!cli_unix_extensions_version(targetcli, &major, &minor,
2982                                 &caplow, &caphigh)) {
2983                 d_printf("Can't get UNIX CIFS version from server.\n");
2984                 return 1;
2985         }
2986
2987         if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
2988                 d_printf("This server supports UNIX extensions "
2989                         "but doesn't support POSIX ACLs.\n");
2990                 return 1;
2991         }
2992
2993         if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
2994                 d_printf("%s getfacl doing a stat on file %s\n",
2995                         cli_errstr(targetcli), src);
2996                 return 1;
2997         }
2998
2999         if (!cli_unix_getfacl(targetcli, targetname, &rb_size, &retbuf)) {
3000                 d_printf("%s getfacl file %s\n",
3001                         cli_errstr(targetcli), src);
3002                 return 1;
3003         }
3004
3005         /* ToDo : Print out the ACL values. */
3006         if (SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION || rb_size < 6) {
3007                 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
3008                         src, (unsigned int)CVAL(retbuf,0) );
3009                 SAFE_FREE(retbuf);
3010                 return 1;
3011         }
3012
3013         num_file_acls = SVAL(retbuf,2);
3014         num_dir_acls = SVAL(retbuf,4);
3015         if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
3016                 d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
3017                         src,
3018                         (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
3019                         (unsigned int)rb_size);
3020
3021                 SAFE_FREE(retbuf);
3022                 return 1;
3023         }
3024
3025         d_printf("# file: %s\n", src);
3026         d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_uid, (unsigned int)sbuf.st_gid);
3027
3028         if (num_file_acls == 0 && num_dir_acls == 0) {
3029                 d_printf("No acls found.\n");
3030         }
3031
3032         for (i = 0; i < num_file_acls; i++) {
3033                 uint32 uorg;
3034                 fstring permstring;
3035                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
3036                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3037
3038                 switch(tagtype) {
3039                         case SMB_POSIX_ACL_USER_OBJ:
3040                                 d_printf("user::");
3041                                 break;
3042                         case SMB_POSIX_ACL_USER:
3043                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3044                                 d_printf("user:%u:", uorg);
3045                                 break;
3046                         case SMB_POSIX_ACL_GROUP_OBJ:
3047                                 d_printf("group::");
3048                                 break;
3049                         case SMB_POSIX_ACL_GROUP:
3050                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3051                                 d_printf("group:%u:", uorg);
3052                                 break;
3053                         case SMB_POSIX_ACL_MASK:
3054                                 d_printf("mask::");
3055                                 break;
3056                         case SMB_POSIX_ACL_OTHER:
3057                                 d_printf("other::");
3058                                 break;
3059                         default:
3060                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3061                                         src, (unsigned int)tagtype );
3062                                 SAFE_FREE(retbuf);
3063                                 return 1;
3064                 }
3065
3066                 d_printf("%s\n", perms_to_string(permstring, perms));
3067         }
3068
3069         for (i = 0; i < num_dir_acls; i++) {
3070                 uint32 uorg;
3071                 fstring permstring;
3072                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
3073                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3074
3075                 switch(tagtype) {
3076                         case SMB_POSIX_ACL_USER_OBJ:
3077                                 d_printf("default:user::");
3078                                 break;
3079                         case SMB_POSIX_ACL_USER:
3080                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3081                                 d_printf("default:user:%u:", uorg);
3082                                 break;
3083                         case SMB_POSIX_ACL_GROUP_OBJ:
3084                                 d_printf("default:group::");
3085                                 break;
3086                         case SMB_POSIX_ACL_GROUP:
3087                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3088                                 d_printf("default:group:%u:", uorg);
3089                                 break;
3090                         case SMB_POSIX_ACL_MASK:
3091                                 d_printf("default:mask::");
3092                                 break;
3093                         case SMB_POSIX_ACL_OTHER:
3094                                 d_printf("default:other::");
3095                                 break;
3096                         default:
3097                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3098                                         src, (unsigned int)tagtype );
3099                                 SAFE_FREE(retbuf);
3100                                 return 1;
3101                 }
3102
3103                 d_printf("%s\n", perms_to_string(permstring, perms));
3104         }
3105
3106         SAFE_FREE(retbuf);
3107         return 0;
3108 }
3109
3110 /****************************************************************************
3111  UNIX stat.
3112 ****************************************************************************/
3113
3114 static int cmd_stat(void)
3115 {
3116         TALLOC_CTX *ctx = talloc_tos();
3117         char *src = NULL;
3118         char *name = NULL;
3119         char *targetname = NULL;
3120         struct cli_state *targetcli;
3121         fstring mode_str;
3122         SMB_STRUCT_STAT sbuf;
3123         struct tm *lt;
3124
3125         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3126                 d_printf("stat file\n");
3127                 return 1;
3128         }
3129         src = talloc_asprintf(ctx,
3130                         "%s%s",
3131                         client_get_cur_dir(),
3132                         name);
3133         if (!src) {
3134                 return 1;
3135         }
3136
3137         if (!cli_resolve_path(ctx, "", cli, src, &targetcli, &targetname)) {
3138                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
3139                 return 1;
3140         }
3141
3142         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3143                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3144                 return 1;
3145         }
3146
3147         if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
3148                 d_printf("%s stat file %s\n",
3149                         cli_errstr(targetcli), src);
3150                 return 1;
3151         }
3152
3153         /* Print out the stat values. */
3154         d_printf("File: %s\n", src);
3155         d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
3156                 (double)sbuf.st_size,
3157                 (unsigned int)sbuf.st_blocks,
3158                 filetype_to_str(sbuf.st_mode));
3159
3160 #if defined(S_ISCHR) && defined(S_ISBLK)
3161         if (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode)) {
3162                 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
3163                         (double)sbuf.st_ino,
3164                         (unsigned int)sbuf.st_nlink,
3165                         unix_dev_major(sbuf.st_rdev),
3166                         unix_dev_minor(sbuf.st_rdev));
3167         } else
3168 #endif
3169                 d_printf("Inode: %.0f\tLinks: %u\n",
3170                         (double)sbuf.st_ino,
3171                         (unsigned int)sbuf.st_nlink);
3172
3173         d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
3174                 ((int)sbuf.st_mode & 0777),
3175                 unix_mode_to_str(mode_str, sbuf.st_mode),
3176                 (unsigned int)sbuf.st_uid,
3177                 (unsigned int)sbuf.st_gid);
3178
3179         lt = localtime(&sbuf.st_atime);
3180         if (lt) {
3181                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
3182         } else {
3183                 fstrcpy(mode_str, "unknown");
3184         }
3185         d_printf("Access: %s\n", mode_str);
3186
3187         lt = localtime(&sbuf.st_mtime);
3188         if (lt) {
3189                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
3190         } else {
3191                 fstrcpy(mode_str, "unknown");
3192         }
3193         d_printf("Modify: %s\n", mode_str);
3194
3195         lt = localtime(&sbuf.st_ctime);
3196         if (lt) {
3197                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
3198         } else {
3199                 fstrcpy(mode_str, "unknown");
3200         }
3201         d_printf("Change: %s\n", mode_str);
3202
3203         return 0;