clitar.c: only list <include list> instead of whole share, handle wildcards
[samba.git] / source3 / client / clitar.c
1 /*
2    Unix SMB/CIFS implementation.
3    Tar backup command extension
4    Copyright (C) AurĂ©lien Aptel 2013
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "system/filesys.h"
22 #include "client/client_proto.h"
23 #include "client/clitar_proto.h"
24 #include "libsmb/libsmb.h"
25 #include <archive.h>
26 #include <archive_entry.h>
27
28 #define LEN(x) (sizeof(x)/sizeof((x)[0]))
29 #define DBG(a, b) (DEBUG(a, ("tar:%-4d ", __LINE__)), DEBUG(a, b))
30
31 /**
32  * Maximum value for the blocksize field
33  */
34 #define TAR_MAX_BLOCK_SIZE 0xffff
35
36 /**
37  * Default tar block size in bytes. Hasn't changed since the first
38  * commit in 1996...
39  *
40  * A more adequate size will be used for better performance unless
41  * we're dealing with a tape device with a fixed read/write block
42  * size.
43  *
44  * The actual choice is made by libarchive.
45  */
46 #define TAR_DEFAULT_BLOCK_SIZE 20
47
48 #define TAR_CLI_READ_SIZE 0xff00
49
50 #define TAR_DO_LIST_ATTR (FILE_ATTRIBUTE_DIRECTORY \
51                           | FILE_ATTRIBUTE_SYSTEM  \
52                           | FILE_ATTRIBUTE_HIDDEN)
53
54
55 enum tar_operation {
56     TAR_NO_OPERATION,
57     TAR_CREATE,    /* c flag */
58     TAR_EXTRACT,   /* x flag */
59 };
60
61 enum tar_selection {
62     TAR_NO_SELECTION,
63     TAR_INCLUDE,       /* I and F flag, default */
64     TAR_EXCLUDE,       /* X flag */
65 };
66
67 enum {
68     ATTR_UNSET,
69     ATTR_SET,
70 };
71
72 struct tar {
73     /* in state that needs/can be processed? */
74     bool to_process;
75
76     /* flags */
77     struct tar_mode {
78         enum tar_operation operation; /* create, extract */
79         enum tar_selection selection; /* inc, inc from file, exclude */
80         int blocksize;    /* size in bytes of a block in the tar file */
81         bool hidden;      /* backup hidden file? */
82         bool system;      /* backup system file? */
83         bool incremental; /* backup _only_ archived file? */
84         bool reset;       /* unset archive bit? */
85         bool dry;         /* don't write tar file? */
86         bool regex;       /* XXX: never actually using regex... */
87         bool verbose;
88     } mode;
89
90     /* nb of bytes received */
91     uint64_t total_size;
92
93     /* path to tar archive name */
94     char *tar_path;
95
96     /* list of path to include or exclude */
97     char **path_list;
98     int path_list_size;
99
100     /* archive handle */
101     struct archive *archive;
102 };
103
104 struct tar tar_ctx = {
105     .mode.selection   = TAR_INCLUDE,
106     .mode.blocksize   = TAR_DEFAULT_BLOCK_SIZE,
107     .mode.hidden      = true,
108     .mode.system      = true,
109     .mode.incremental = false,
110     .mode.dry         = false,
111 };
112
113 static char *fix_unix_path (char *path, bool removeprefix)
114 {
115     char *from = path, *to = path;
116
117     if (!path || !*path)
118         return path;
119
120     /* remove prefix:
121      * ./path => path
122      *  /path => path
123      */
124     if (removeprefix) {
125         /* /path */
126         if (path[0] == '/' || path[0] == '\\') {
127             from += 1;
128         }
129
130         /* ./path */
131         if (path[1] && path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
132             from += 2;
133         }
134     }
135
136     /* replace / with \ */
137     while (*from) {
138         if (*from == '/') {
139             *to = '\\';
140         } else {
141             *to = *from;
142         }
143         from++; to++;
144     }
145     *to = 0;
146
147     return path;
148 }
149
150 static char *path_base_name (const char *path)
151 {
152     TALLOC_CTX *ctx = talloc_tos();
153     char *base = NULL;
154     int last = -1;
155     int i;
156
157     for (i = 0; path[i]; i++) {
158         if (path[i] == '\\' || path[i] == '/') {
159             last = i;
160         }
161     }
162
163     if (last >= 0) {
164         base = talloc_strdup(ctx, path);
165         base[last] = 0;
166     }
167
168     return base;
169 }
170
171 #define XSET(v)      [v] = #v
172 #define XTABLE(v, t) DBG(2, ("DUMP:%-20.20s = %s\n", #v, t[v]))
173 #define XBOOL(v)     DBG(2, ("DUMP:%-20.20s = %d\n", #v, v ? 1 : 0))
174 #define XSTR(v)      DBG(2, ("DUMP:%-20.20s = %s\n", #v, v ? v : "NULL"))
175 #define XINT(v)      DBG(2, ("DUMP:%-20.20s = %d\n", #v, v))
176 #define XUINT64(v)   DBG(2, ("DUMP:%-20.20s = %" PRIu64  "\n", #v, v))
177 static void tar_dump(struct tar *t)
178 {
179     int i;
180     const char* op[] = {
181         XSET(TAR_NO_OPERATION),
182         XSET(TAR_CREATE),
183         XSET(TAR_EXTRACT),
184     };
185
186     const char* sel[] = {
187         XSET(TAR_NO_SELECTION),
188         XSET(TAR_INCLUDE),
189         XSET(TAR_EXCLUDE),
190     };
191
192     XBOOL(t->to_process);
193     XTABLE(t->mode.operation, op);
194     XTABLE(t->mode.selection, sel);
195     XINT(t->mode.blocksize);
196     XBOOL(t->mode.hidden);
197     XBOOL(t->mode.system);
198     XBOOL(t->mode.incremental);
199     XBOOL(t->mode.reset);
200     XBOOL(t->mode.dry);
201     XBOOL(t->mode.verbose);
202     XUINT64(t->total_size);
203     XSTR(t->tar_path);
204     XINT(t->path_list_size);
205
206     for (i = 0; t->path_list && t->path_list[i]; i++) {
207         DBG(2, ("DUMP: t->path_list[%2d] = %s\n", i, t->path_list[i]));
208     }
209
210     DBG(2, ("DUMP:t->path_list @ %p (%d elem)\n", t->path_list, i));
211 }
212 #undef XSET
213 #undef XTABLE
214 #undef XBOOL
215 #undef XSTR
216 #undef XINT
217
218 static void tar_add_selection_path(struct tar *t, const char *path)
219 {
220     TALLOC_CTX *ctx = talloc_tos();
221     if (!t->path_list) {
222         t->path_list = str_list_make_empty(ctx);
223         t->path_list_size = 0;
224     }
225
226     t->path_list = str_list_add((const char**)t->path_list, path);
227     t->path_list_size++;
228     fix_unix_path(t->path_list[t->path_list_size - 1], true);
229 }
230
231 static int tar_set_blocksize(struct tar *t, int size)
232 {
233     if (size <= 0 || size > TAR_MAX_BLOCK_SIZE) {
234         return 0;
235     }
236
237     t->mode.blocksize = size;
238
239     return 1;
240 }
241
242 static bool tar_set_newer_than(struct tar *t, const char *filename)
243 {
244     extern time_t newer_than;
245     SMB_STRUCT_STAT stbuf;
246
247     if (sys_stat(filename, &stbuf, false) != 0) {
248         DBG(0, ("Error setting newer-than time\n"));
249         return 0;
250     }
251
252     newer_than = convert_timespec_to_time_t(stbuf.st_ex_mtime);
253     DBG(1, ("Getting files newer than %s\n", time_to_asc(newer_than)));
254     return 1;
255 }
256
257 static bool tar_read_inclusion_file (struct tar *t, const char* filename)
258 {
259     char *line;
260     TALLOC_CTX *ctx = talloc_tos();
261     int fd = open(filename, O_RDONLY);
262
263     if (fd < 0) {
264         DBG(0, ("Can't open inclusion file '%s': %s\n", filename, strerror(errno)));
265         return 0;
266     }
267
268     while ((line = afdgets(fd, ctx, 0))) {
269         tar_add_selection_path(t, line);
270     }
271
272     close(fd);
273     return 1;
274 }
275
276 /* skip leading slashes or dots */
277 static const char* skip_useless_char_in_path(const char *p)
278 {
279     while (p) {
280         if (*p == '/' || *p == '\\') {
281             p++;
282         }
283         else if (p[0] == '.' && (p[1] == '/' || p[1] == '\\')) {
284             p += 2;
285         }
286         else
287             return p;
288     }
289     return p;
290 }
291
292
293 /**
294  * return true if the path @sub is a subpath of @full.
295  *
296  * case-insensitive, true if @sub = @full
297  */
298 static bool is_subpath(const char *sub, const char *full)
299 {
300     const char *full_copy = full;
301
302     while (*full && *sub &&
303            (*full == *sub || tolower_m(*full) == tolower_m(*sub) ||
304             (*full == '\\' && *sub=='/') || (*full == '/' && *sub=='\\'))) {
305         full++; sub++;
306     }
307
308     /* if full has a trailing slash, it compared equal, so full is an "initial"
309        string of sub.
310     */
311     if (!*full && full != full_copy && (*(full-1) == '/' || *(full-1) == '\\'))
312         return true;
313
314     /* ignore trailing slash on full */
315     if (!*sub && (*full == '/' || *full == '\\') && !*(full+1))
316         return true;
317
318     /* check for full is an "initial" string of sub */
319     if ((*sub == '/' || *sub == '\\') && !*full)
320         return true;
321
322     return *full == *sub;
323 }
324
325 static bool tar_path_in_list(struct tar *t, const char *path, bool reverse)
326 {
327     int i;
328     const char *p = path;
329     const char *pattern;
330     bool res;
331
332     if (!p || !p[0])
333         return false;
334
335     p = skip_useless_char_in_path(p);
336
337     for (i = 0; i < t->path_list_size; i++) {
338         pattern = skip_useless_char_in_path(t->path_list[i]);
339         res = is_subpath(p, pattern);
340         if (reverse) {
341             res = res || is_subpath(pattern, p);
342         }
343         if (res) {
344             return true;
345         }
346     }
347
348     return false;
349 }
350
351 static bool tar_extract_skip_path(struct tar *t,
352                                   struct archive_entry *entry)
353 {
354     const bool skip = true;
355     const char *fullpath = archive_entry_pathname(entry);
356     bool in;
357
358     in = t->path_list_size > 0 ? tar_path_in_list(t, fullpath, false) : true;
359
360     if (t->mode.selection == TAR_EXCLUDE) {
361         in = !in;
362     }
363
364     return in ? !skip : skip;
365 }
366
367 static bool tar_create_skip_path(struct tar *t,
368                                  const char *fullpath,
369                                  const struct file_info *finfo)
370 {
371     /* syntaxic sugar */
372     const bool skip = true;
373     const mode_t mode = finfo->mode;
374     const bool isdir = mode & FILE_ATTRIBUTE_DIRECTORY;
375     const bool exclude = t->mode.selection == TAR_EXCLUDE;
376     bool in = true;
377
378     if (!isdir) {
379
380         /* 1. if we dont want X and we have X, skip */
381         if (!t->mode.system && (mode & FILE_ATTRIBUTE_SYSTEM)) {
382             return skip;
383         }
384
385         if (!t->mode.hidden && (mode & FILE_ATTRIBUTE_HIDDEN)) {
386             return skip;
387         }
388
389         /* 2. if we only want archive and it's not, skip */
390
391         if (t->mode.incremental && !(mode & FILE_ATTRIBUTE_ARCHIVE)) {
392             return skip;
393         }
394     }
395
396     /* 3. is it in the selection list? */
397
398     /*
399      * tar_create_from_list() use the include list as a starting
400      * point, no need to check
401      */
402     if (!exclude) {
403         return !skip;
404     }
405
406     /* we are now in exclude mode */
407     if (t->path_list_size > 0) {
408         in = tar_path_in_list(t, fullpath, isdir && !exclude);
409     }
410
411     return in ? skip : !skip;
412 }
413
414 bool tar_to_process (struct tar *t)
415 {
416     return t->to_process;
417 }
418
419 /**
420  * cmd_block - interactive command to change tar blocksize
421  *
422  * Read a size from the client command line and update the current
423  * blocksize.
424  */
425 int cmd_block(void)
426 {
427     /* XXX: from client.c */
428     const extern char *cmd_ptr;
429     char *buf;
430     TALLOC_CTX *ctx = talloc_tos();
431
432     if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
433         DBG(0, ("blocksize <n>\n"));
434         return 1;
435     }
436
437     if (!tar_set_blocksize(&tar_ctx, atoi(buf))) {
438         DBG(0, ("invalid blocksize\n"));
439     }
440
441     DBG(2, ("blocksize is now %d\n", tar_ctx.mode.blocksize));
442
443     return 0;
444 }
445
446 /**
447  * cmd_tarmode - interactive command to change tar behaviour
448  *
449  * Read one or more modes from the client command line and update the
450  * current tar mode.
451  */
452 int cmd_tarmode(void)
453 {
454     const extern char *cmd_ptr;
455     char *buf;
456     int i;
457     TALLOC_CTX *ctx = talloc_tos();
458
459     struct {
460         const char *cmd;
461         bool *p;
462         bool value;
463     } table[] = {
464         {"full",      &tar_ctx.mode.incremental, false},
465         {"inc",       &tar_ctx.mode.incremental, true },
466         {"reset",     &tar_ctx.mode.reset,       true },
467         {"noreset",   &tar_ctx.mode.reset,       false},
468         {"system",    &tar_ctx.mode.system,      true },
469         {"nosystem",  &tar_ctx.mode.system,      false},
470         {"hidden",    &tar_ctx.mode.hidden,      true },
471         {"nohidden",  &tar_ctx.mode.hidden,      false},
472         {"verbose",   &tar_ctx.mode.verbose,     true },
473         {"noquiet",   &tar_ctx.mode.verbose,     true },
474         {"quiet",     &tar_ctx.mode.verbose,     false},
475         {"noverbose", &tar_ctx.mode.verbose,     false},
476     };
477
478     while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
479         for (i = 0; i < LEN(table); i++) {
480             if (strequal(table[i].cmd, buf)) {
481                 *table[i].p = table[i].value;
482                 break;
483             }
484         }
485
486         if (i == LEN(table))
487             DBG(0, ("tarmode: unrecognised option %s\n", buf));
488
489         TALLOC_FREE(buf);
490     }
491
492     DBG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
493               tar_ctx.mode.incremental ? "incremental" : "full",
494               tar_ctx.mode.system      ? "system"      : "nosystem",
495               tar_ctx.mode.hidden      ? "hidden"      : "nohidden",
496               tar_ctx.mode.reset       ? "reset"       : "noreset",
497               tar_ctx.mode.verbose     ? "verbose"     : "quiet"));
498     return 0;
499 }
500
501 /**
502  * set_remote_attr - set DOS attributes of a remote file
503  * @filename: path to the file name
504  * @new_attr: attribute bit mask to use
505  * @mode: one of ATTR_SET or ATTR_UNSET
506  *
507  * Update the file attributes with the one provided.
508  */
509 static void set_remote_attr(const char *filename, uint16 new_attr, int mode)
510 {
511     extern struct cli_state *cli;
512     uint16 old_attr;
513     NTSTATUS status;
514
515     if (!NT_STATUS_IS_OK(cli_getatr(cli, filename, &old_attr, NULL, NULL))) {
516         /* XXX: debug message */
517         return;
518     }
519
520     if (mode == ATTR_SET) {
521         new_attr |= old_attr;
522     } else {
523         new_attr = old_attr & ~new_attr;
524     }
525
526     status = cli_setatr(cli, filename, new_attr, 0);
527     if (!NT_STATUS_IS_OK(status)) {
528         DBG(1, ("setatr failed: %s\n", nt_errstr(status)));
529     }
530 }
531
532 /**
533  * cmd_setmode - interactive command to set DOS attributes
534  *
535  * Read a filename and mode from the client command line and update
536  * the file DOS attributes.
537  */
538 int cmd_setmode(void)
539 {
540     const extern char *cmd_ptr;
541     char *buf;
542     char *fname = NULL;
543     uint16 attr[2] = {0};
544     int mode = ATTR_SET;
545     TALLOC_CTX *ctx = talloc_tos();
546
547
548     if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
549         DBG(0, ("setmode <filename> <[+|-]rsha>\n"));
550         return 1;
551     }
552
553     fname = talloc_asprintf(ctx,
554                             "%s%s",
555                             client_get_cur_dir(),
556                             buf);
557     if (!fname) {
558         return 1;
559     }
560
561     while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
562         const char *s = buf;
563
564         while (*s) {
565             switch (*s++) {
566             case '+':
567                 mode = ATTR_SET;
568                 break;
569             case '-':
570                 mode = ATTR_UNSET;
571                 break;
572             case 'r':
573                 attr[mode] |= FILE_ATTRIBUTE_READONLY;
574                 break;
575             case 'h':
576                 attr[mode] |= FILE_ATTRIBUTE_HIDDEN;
577                 break;
578             case 's':
579                 attr[mode] |= FILE_ATTRIBUTE_SYSTEM;
580                 break;
581             case 'a':
582                 attr[mode] |= FILE_ATTRIBUTE_ARCHIVE;
583                 break;
584             default:
585                 DBG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
586                 return 1;
587             }
588         }
589     }
590
591     if (attr[ATTR_SET] == 0 && attr[ATTR_UNSET] == 0) {
592         DBG(0, ("setmode <filename> <[+|-]rsha>\n"));
593         return 1;
594     }
595
596     DBG(2, ("perm set %d %d\n", attr[ATTR_SET], attr[ATTR_UNSET]));
597     set_remote_attr(fname, attr[ATTR_SET], ATTR_SET);
598     set_remote_attr(fname, attr[ATTR_UNSET], ATTR_UNSET);
599     return 0;
600 }
601
602 static int make_remote_path(const char *full_path)
603 {
604     extern struct cli_state *cli;
605     TALLOC_CTX *ctx = talloc_tos();
606     char *path;
607     char *subpath;
608     char *state;
609     char *last_backslash;
610     char *p;
611     int len;
612     NTSTATUS status;
613     int err = 0;
614
615     subpath = talloc_strdup(ctx, full_path);
616     path = talloc_strdup(ctx, full_path);
617     len = talloc_get_size(path) - 1;
618
619     last_backslash = strrchr_m(path, '\\');
620
621     if (!last_backslash) {
622         goto out;
623     }
624
625     *last_backslash = 0;
626
627     subpath[0] = 0;
628     p = strtok_r(path, "\\", &state);
629
630     while (p) {
631         strlcat(subpath, p, len);
632         status = cli_chkpath(cli, subpath);
633         if (!NT_STATUS_IS_OK(status)) {
634             status = cli_mkdir(cli, subpath);
635             if (!NT_STATUS_IS_OK(status)) {
636                 DBG(0, ("Can't mkdir %s: %s\n", subpath, nt_errstr(status)));
637                 err = 1;
638                 goto out;
639             }
640             DBG(3, ("mkdir %s\n", subpath));
641         }
642
643         strlcat(subpath, "\\", len);
644         p = strtok_r(NULL, "/\\", &state);
645
646     }
647
648  out:
649     return err;
650 }
651
652 static int tar_send_file(struct tar *t, struct archive_entry *entry)
653 {
654     extern struct cli_state *cli;
655     TALLOC_CTX *ctx = talloc_tos();
656     char *dos_path;
657     char *full_path;
658     NTSTATUS status;
659     uint16_t remote_fd = (uint16_t) -1;
660     int err = 0;
661     int flags = O_RDWR | O_CREAT | O_TRUNC;
662     mode_t mode = archive_entry_filetype(entry);
663
664     dos_path = talloc_strdup(ctx, archive_entry_pathname(entry));
665     fix_unix_path(dos_path, true);
666
667     full_path = talloc_strdup(ctx, client_get_cur_dir());
668     full_path = talloc_strdup_append(full_path, dos_path);
669
670     if (mode != AE_IFREG && mode != AE_IFDIR) {
671         DBG(0, ("Skipping non-dir & non-regular file %s\n", full_path));
672         goto out;
673     }
674
675     if (make_remote_path(full_path)) {
676         err = 1;
677         goto out;
678     }
679
680     if (mode == AE_IFDIR) {
681         goto out;
682     }
683
684     status = cli_open(cli, full_path, flags, DENY_NONE, &remote_fd);
685     if (!NT_STATUS_IS_OK(status)) {
686         DBG(0, ("Error opening remote file %s: %s\n",
687                   full_path, nt_errstr(status)));
688         err = 1;
689         goto out;
690     }
691
692     for (;;) {
693         const void *buf;
694         size_t len;
695         off_t off;
696         int r;
697
698         r = archive_read_data_block(t->archive, &buf, &len, &off);
699         if (r == ARCHIVE_EOF) {
700             break;
701         }
702         if (r == ARCHIVE_WARN) {
703             DBG(0, ("Warning: %s\n", archive_error_string(t->archive)));
704         }
705         if (r == ARCHIVE_FATAL) {
706             DBG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
707             err = 1;
708             goto close_out;
709         }
710
711         status = cli_writeall(cli, remote_fd, 0, buf, off, len, NULL);
712         if (!NT_STATUS_IS_OK(status)) {
713             DBG(0, ("Error writing remote file %s: %s\n",
714                       full_path, nt_errstr(status)));
715             err = 1;
716             goto close_out;
717         }
718     }
719
720  close_out:
721     status = cli_close(cli, remote_fd);
722     if (!NT_STATUS_IS_OK(status)) {
723         DBG(0, ("Error losing remote file %s: %s\n",
724                   full_path, nt_errstr(status)));
725         err = 1;
726     }
727
728  out:
729     return err;
730 }
731
732 static int tar_get_file(struct tar *t, const char *full_dos_path,
733                         struct file_info *finfo)
734 {
735     extern struct cli_state *cli;
736     TALLOC_CTX *ctx = talloc_tos();
737     NTSTATUS status;
738     struct archive_entry *entry;
739     char *full_unix_path;
740     char buf[TAR_CLI_READ_SIZE];
741     size_t len;
742     uint64_t off = 0;
743     uint16_t remote_fd = (uint16_t)-1;
744     int err = 0, r;
745     const bool isdir = finfo->mode & FILE_ATTRIBUTE_DIRECTORY;
746
747     DBG(5, ("+++ %s\n", full_dos_path));
748
749     t->total_size += finfo->size;
750
751     if (t->mode.dry) {
752         goto out;
753     }
754
755     if (t->mode.reset) {
756         set_remote_attr(full_dos_path, FILE_ATTRIBUTE_ARCHIVE, ATTR_UNSET);
757     }
758
759     full_unix_path = talloc_asprintf(ctx, ".%s", full_dos_path);
760     string_replace(full_unix_path, '\\', '/');
761     entry = archive_entry_new();
762     archive_entry_copy_pathname(entry, full_unix_path);
763     archive_entry_set_filetype(entry, isdir ? AE_IFDIR : AE_IFREG);
764     archive_entry_set_atime(entry,
765                             finfo->atime_ts.tv_sec,
766                             finfo->atime_ts.tv_nsec);
767     archive_entry_set_mtime(entry,
768                             finfo->mtime_ts.tv_sec,
769                             finfo->mtime_ts.tv_nsec);
770     archive_entry_set_ctime(entry,
771                             finfo->ctime_ts.tv_sec,
772                             finfo->ctime_ts.tv_nsec);
773     archive_entry_set_perm(entry, isdir ? 0755 : 0644);
774     /*
775      * check if we can safely cast unsigned file size to libarchive
776      * signed size. Very unlikely problem (>9 exabyte file)
777      */
778     if (finfo->size > INT64_MAX) {
779         DBG(0, ("Remote file %s too big\n", full_dos_path));
780         goto out_entry;
781     }
782
783     archive_entry_set_size(entry, (int64_t)finfo->size);
784
785     r = archive_write_header(t->archive, entry);
786     if (r != ARCHIVE_OK) {
787         DBG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
788         err = 1;
789         goto out_entry;
790     }
791
792     if (isdir) {
793         DBG(5, ("get_file skip dir %s\n", full_dos_path));
794         goto out_entry;
795     }
796
797     status = cli_open(cli, full_dos_path, O_RDONLY, DENY_NONE, &remote_fd);
798     if (!NT_STATUS_IS_OK(status)) {
799         DBG(0,("%s opening remote file %s\n",
800                  nt_errstr(status), full_dos_path));
801         goto out_entry;
802     }
803
804     do {
805         status = cli_read(cli, remote_fd, buf, off, sizeof(buf), &len);
806         if (!NT_STATUS_IS_OK(status)) {
807             DBG(0,("Error reading file %s : %s\n",
808                      full_dos_path, nt_errstr(status)));
809             err = 1;
810             goto out_close;
811         }
812
813         off += len;
814
815         r = archive_write_data(t->archive, buf, len);
816         if (r < 0) {
817             DBG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
818             err = 1;
819             goto out_close;
820         }
821
822     } while (off < finfo->size);
823
824  out_close:
825     cli_close(cli, remote_fd);
826
827  out_entry:
828     archive_entry_free(entry);
829
830  out:
831     return err;
832 }
833
834 static NTSTATUS get_file_callback(struct cli_state *cli,
835                                   struct file_info *finfo,
836                                   const char *dir)
837 {
838     TALLOC_CTX *ctx = talloc_tos();
839     NTSTATUS err = NT_STATUS_OK;
840     char *remote_name;
841     const char *initial_dir = client_get_cur_dir();
842
843     remote_name = talloc_asprintf(ctx, "%s%s", initial_dir, finfo->name);
844
845     if (strequal(finfo->name, "..") || strequal(finfo->name, ".")) {
846         goto out;
847     }
848
849     if (tar_create_skip_path(&tar_ctx, remote_name, finfo)) {
850         DBG(5, ("--- %s\n", remote_name));
851         goto out;
852     }
853
854     if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
855         char *old_dir;
856         char *new_dir;
857         char *mask;
858
859         old_dir = talloc_strdup(ctx, initial_dir);
860         new_dir = talloc_asprintf(ctx, "%s%s\\", initial_dir, finfo->name);
861         mask = talloc_asprintf(ctx, "%s*", new_dir);
862
863         if (tar_get_file(&tar_ctx, remote_name, finfo)) {
864             err = NT_STATUS_UNSUCCESSFUL;
865             goto out;
866         }
867
868         client_set_cur_dir(new_dir);
869         do_list(mask, TAR_DO_LIST_ATTR, get_file_callback, false, true);
870         client_set_cur_dir(old_dir);
871     }
872
873     else {
874         if (tar_get_file(&tar_ctx, remote_name, finfo)) {
875             err = NT_STATUS_UNSUCCESSFUL;
876             goto out;
877         }
878     }
879
880  out:
881     return err;
882 }
883
884 static int tar_create_from_list(struct tar *t)
885 {
886     TALLOC_CTX *ctx = talloc_tos();
887     int err = 0;
888     NTSTATUS status;
889     const char *path, *mask, *base, *start_dir;
890     int i;
891
892     start_dir = talloc_strdup(ctx, client_get_cur_dir());
893
894     for (i = 0; i < t->path_list_size; i++) {
895         path = t->path_list[i];
896         base = path_base_name(path);
897         mask = talloc_asprintf(ctx, "%s\\%s", client_get_cur_dir(), path);
898
899         DBG(5, ("incl. path='%s', base='%s', mask='%s'\n",
900                 path, base ? base : "NULL", mask));
901
902         if (base) {
903             base = talloc_asprintf(ctx, "%s%s\\",
904                                    client_get_cur_dir(), path_base_name(path));
905             DBG(5, ("cd '%s' before do_list\n", base));
906             client_set_cur_dir(base);
907         }
908         status = do_list(mask, TAR_DO_LIST_ATTR, get_file_callback, false, true);
909         if (base) {
910             client_set_cur_dir(start_dir);
911         }
912         if (!NT_STATUS_IS_OK(status)) {
913             DBG(0, ("do_list failed on %s (%s)\n", path, nt_errstr(status)));
914             err = 1;
915             goto out;
916         }
917     }
918
919  out:
920     return err;
921 }
922
923 static int tar_create(struct tar* t)
924 {
925     TALLOC_CTX *ctx = talloc_tos();
926     int r;
927     int err = 0;
928     NTSTATUS status;
929     const char *mask;
930
931     t->archive = archive_write_new();
932
933     if (!t->mode.dry) {
934         r = archive_write_set_format_pax_restricted(t->archive);
935         if (r != ARCHIVE_OK) {
936             DBG(0, ("Can't open %s: %s\n", t->tar_path,
937                     archive_error_string(t->archive)));
938         }
939
940         if (strequal(t->tar_path, "-")) {
941             r = archive_write_open_fd(t->archive, STDOUT_FILENO);
942         } else {
943             r = archive_write_open_filename(t->archive, t->tar_path);
944         }
945
946         if (r != ARCHIVE_OK) {
947             DBG(0, ("Can't open %s: %s\n", t->tar_path,
948                     archive_error_string(t->archive)));
949             err = 1;
950             goto out_close;
951         }
952     }
953
954     /*
955      * In inclusion mode, iterate on the inclusion list
956      */
957     if (t->mode.selection == TAR_INCLUDE && t->path_list_size > 0) {
958         if (tar_create_from_list(t)) {
959             err = 1;
960             goto out_close;
961         }
962     } else {
963         mask = talloc_asprintf(ctx, "%s\\*", client_get_cur_dir());
964         DBG(5, ("tar_process do_list with mask: %s\n", mask));
965         status = do_list(mask, TAR_DO_LIST_ATTR, get_file_callback, false, true);
966         if (!NT_STATUS_IS_OK(status)) {
967             DBG(0, ("do_list fail %s\n", nt_errstr(status)));
968             err = 1;
969             goto out_close;
970         }
971     }
972
973  out_close:
974     DBG(0, ("Total bytes received: %" PRIu64 "\n", t->total_size));
975
976     if (!t->mode.dry) {
977         r = archive_write_close(t->archive);
978         if (r != ARCHIVE_OK) {
979             DBG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
980             err = 1;
981             goto out;
982         }
983     }
984  out:
985     archive_write_free(t->archive);
986     return err;
987 }
988
989 /**
990  * Return upper limit for the number of token in @str.
991  *
992  * The result is not exact, the actual number of token might be less
993  * than what is returned.
994  */
995 static int max_token (const char *str)
996 {
997     const char *s = str;
998     int nb = 0;
999
1000     if (!str) {
1001         return 0;
1002     }
1003
1004     while (*s) {
1005         if (isspace(*s)) {
1006             nb++;
1007         }
1008         s++;
1009     }
1010
1011     nb++;
1012
1013     return nb;
1014 }
1015
1016 /**
1017  * cmd_tar - interactive command to start a tar backup/restoration
1018  *
1019  * Check presence of argument, parse them and handle the request.
1020  */
1021 int cmd_tar(void)
1022 {
1023     TALLOC_CTX *ctx = talloc_tos();
1024     const extern char *cmd_ptr;
1025     const char *flag;
1026     const char **val;
1027         char *buf;
1028     int maxtok = max_token(cmd_ptr);
1029     int i = 0;
1030     int err = 0;
1031
1032         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1033                 DBG(0, ("tar <c|x>[IXFbganN] [options] <tar file> [path list]\n"));
1034                 return 1;
1035         }
1036
1037     flag = buf;
1038     val = talloc_array(ctx, const char*, maxtok);
1039
1040     while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1041         val[i++] = buf;
1042     }
1043
1044     if (!tar_parse_args(&tar_ctx, flag, val, i)) {
1045         DBG(0, ("parse_args failed\n"));
1046         err = 1;
1047         goto out;
1048     }
1049
1050     if (tar_process(&tar_ctx)) {
1051         DBG(0, ("tar_process failed\n"));
1052         err = 1;
1053         goto out;
1054     }
1055
1056  out:
1057     return err;
1058 }
1059
1060 static int tar_extract(struct tar *t)
1061 {
1062     int err = 0;
1063     int r;
1064     struct archive_entry *entry;
1065
1066     t->archive = archive_read_new();
1067     archive_read_support_format_all(t->archive);
1068     archive_read_support_filter_all(t->archive);
1069
1070     if (strequal(t->tar_path, "-")) {
1071         r = archive_read_open_fd(t->archive, STDIN_FILENO, t->mode.blocksize);
1072     } else {
1073         r = archive_read_open_filename(t->archive, t->tar_path,
1074                                        t->mode.blocksize);
1075     }
1076
1077     if (r != ARCHIVE_OK) {
1078         DBG(0, ("Can't open %s : %s\n", t->tar_path,
1079                   archive_error_string(t->archive)));
1080         err = 1;
1081         goto out;
1082     }
1083
1084     for (;;) {
1085         r = archive_read_next_header(t->archive, &entry);
1086         if (r == ARCHIVE_EOF) {
1087             break;
1088         }
1089         if (r == ARCHIVE_WARN) {
1090             DBG(0, ("Warning: %s\n", archive_error_string(t->archive)));
1091         }
1092         if (r == ARCHIVE_FATAL) {
1093             DBG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
1094             err = 1;
1095             goto out;
1096         }
1097
1098         if (tar_extract_skip_path(t, entry)) {
1099             DBG(5, ("--- %s\n", archive_entry_pathname(entry)));
1100             continue;
1101         }
1102
1103         DBG(5, ("+++ %s\n", archive_entry_pathname(entry)));
1104
1105         if (tar_send_file(t, entry)) {
1106             err = 1;
1107             goto out;
1108         }
1109     }
1110
1111  out:
1112     r = archive_read_free(t->archive);
1113     if (r != ARCHIVE_OK) {
1114         DBG(0, ("Can't close %s : %s\n", t->tar_path,
1115                   archive_error_string(t->archive)));
1116         err = 1;
1117     }
1118     return err;
1119 }
1120
1121 int tar_process(struct tar *t)
1122 {
1123     int rc = 0;
1124
1125     switch(t->mode.operation) {
1126     case TAR_EXTRACT:
1127         rc = tar_extract(t);
1128         break;
1129     case TAR_CREATE:
1130         rc = tar_create(t);
1131         break;
1132     default:
1133         DBG(0, ("Invalid tar state\n"));
1134         rc = 1;
1135     }
1136
1137     DBG(5, ("tar_process done, err = %d\n", rc));
1138     return rc;
1139 }
1140
1141 /**
1142  * tar_parse_args - parse and set tar command line arguments
1143  * @flag: string pointing to tar options
1144  * @val: number of tar arguments
1145  * @valsize: table of arguments after the flags (number of element in val)
1146  *
1147  * tar arguments work in a weird way. For each flag f that takes a
1148  * value v, the user is supposed to type:
1149  *
1150  * on the CLI:
1151  *   -Tf1f2f3 v1 v2 v3 TARFILE PATHS...
1152  *
1153  * in the interactive session:
1154  *   tar f1f2f3 v1 v2 v3 TARFILE PATHS...
1155  *
1156  * opt has only flags (eg. "f1f2f3") and val has the arguments
1157  * (values) following them (eg. ["v1", "v2", "v3", "TARFILE", "PATH1",
1158  * "PATH2"]).
1159  *
1160  * There are only 2 flags that take an arg: b and N. The other flags
1161  * just change the semantic of PATH or TARFILE.
1162  *
1163  * PATH can be a list of included/excluded paths, the path to a file
1164  * containing a list of included/excluded paths to use (F flag). If no
1165  * PATH is provided, the whole share is used (/).
1166  */
1167 int tar_parse_args(struct tar* t, const char *flag,
1168                    const char **val, int valsize)
1169 {
1170     TALLOC_CTX *ctx = talloc_tos();
1171     bool list = false;
1172
1173     /* index of next value to use */
1174     int ival = 0;
1175
1176     /*
1177      * Reset back some options - could be from interactive version
1178      * all other modes are left as they are
1179      */
1180     t->mode.operation = TAR_NO_OPERATION;
1181     t->mode.selection = TAR_NO_SELECTION;
1182     t->mode.dry = false;
1183     t->to_process = false;
1184     t->total_size = 0;
1185
1186     while (*flag) {
1187         switch(*flag++) {
1188         /* operation */
1189         case 'c':
1190             if (t->mode.operation != TAR_NO_OPERATION) {
1191                 printf("Tar must be followed by only one of c or x.\n");
1192                 return 0;
1193             }
1194             t->mode.operation = TAR_CREATE;
1195             break;
1196         case 'x':
1197             if (t->mode.operation != TAR_NO_OPERATION) {
1198                 printf("Tar must be followed by only one of c or x.\n");
1199                 return 0;
1200             }
1201             t->mode.operation = TAR_EXTRACT;
1202             break;
1203
1204         /* selection  */
1205         case 'I':
1206             if (t->mode.selection != TAR_NO_SELECTION) {
1207                 DBG(0,("Only one of I,X,F must be specified\n"));
1208                 return 0;
1209             }
1210             t->mode.selection = TAR_INCLUDE;
1211             break;
1212         case 'X':
1213             if (t->mode.selection != TAR_NO_SELECTION) {
1214                 DBG(0,("Only one of I,X,F must be specified\n"));
1215                 return 0;
1216             }
1217             t->mode.selection = TAR_EXCLUDE;
1218             break;
1219         case 'F':
1220             if (t->mode.selection != TAR_NO_SELECTION) {
1221                 DBG(0,("Only one of I,X,F must be specified\n"));
1222                 return 0;
1223             }
1224             t->mode.selection = TAR_INCLUDE;
1225             list = true;
1226             break;
1227
1228         /* blocksize */
1229         case 'b':
1230             if (ival >= valsize) {
1231                 DBG(0, ("Option b must be followed by a blocksize\n"));
1232                 return 0;
1233             }
1234
1235             if (!tar_set_blocksize(t, atoi(val[ival]))) {
1236                 DBG(0, ("Option b must be followed by a valid blocksize\n"));
1237                 return 0;
1238             }
1239
1240             ival++;
1241             break;
1242
1243          /* incremental mode */
1244         case 'g':
1245             t->mode.incremental = true;
1246             break;
1247
1248         /* newer than */
1249         case 'N':
1250             if (ival >= valsize) {
1251                 DBG(0, ("Option N must be followed by valid file name\n"));
1252                 return 0;
1253             }
1254
1255             if (!tar_set_newer_than(t, val[ival])) {
1256                 DBG(0,("Error setting newer-than time\n"));
1257                 return 0;
1258             }
1259
1260             ival++;
1261             break;
1262
1263         /* reset mode */
1264         case 'a':
1265             t->mode.reset = true;
1266             break;
1267
1268         /* verbose */
1269         case 'q':
1270             t->mode.verbose = true;
1271             break;
1272
1273         /* regex match  */
1274         case 'r':
1275             t->mode.regex = true;
1276             break;
1277
1278         /* dry run mode */
1279         case 'n':
1280             if (t->mode.operation != TAR_CREATE) {
1281                 DBG(0, ("n is only meaningful when creating a tar-file\n"));
1282                 return 0;
1283             }
1284
1285             t->mode.dry = true;
1286             DBG(0, ("dry_run set\n"));
1287             break;
1288
1289         default:
1290             DBG(0,("Unknown tar option\n"));
1291             return 0;
1292         }
1293     }
1294
1295     /* no selection given? default selection is include */
1296     if (t->mode.selection == TAR_NO_SELECTION) {
1297         t->mode.selection = TAR_INCLUDE;
1298     }
1299
1300     if (valsize - ival < 1) {
1301         DBG(0, ("No tar file given.\n"));
1302         return 0;
1303     }
1304
1305     /* handle TARFILE */
1306     t->tar_path = talloc_strdup(ctx, val[ival]);
1307     ival++;
1308
1309     /*
1310      * Make sure that dbf points to stderr if we are using stdout for
1311      * tar output
1312      */
1313     if (t->mode.operation == TAR_CREATE && strequal(t->tar_path, "-")) {
1314         setup_logging("smbclient", DEBUG_STDERR);
1315     }
1316
1317     /* handle PATHs... */
1318
1319     /* flag F -> read file list */
1320     if (list) {
1321         if (valsize - ival != 1) {
1322             DBG(0,("Option F must be followed by exactly one filename.\n"));
1323             return 0;
1324         }
1325
1326         if (!tar_read_inclusion_file(t, val[ival])) {
1327             return 0;
1328         }
1329         ival++;
1330     }
1331
1332     /* otherwise store all the PATHs on the command line */
1333     else {
1334         int i;
1335         for (i = ival; i < valsize; i++) {
1336             tar_add_selection_path(t, val[i]);
1337         }
1338     }
1339
1340     t->to_process = true;
1341     tar_dump(t);
1342     return 1;
1343 }