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