76596067f2d8949f0780de447f57413bd705fe26
[bbaumbach/samba-autobuild/.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 /**
21  * # General overview of the tar extension
22  *
23  * All tar_xxx() functions work on a `struct tar` which store most of
24  * the context of the backup process.
25  *
26  * The current tar context can be accessed via the global variable
27  * `tar_ctx`. It's publicly exported as an opaque handle via
28  * tar_get_ctx().
29  *
30  * A tar context is first configured through tar_parse_args() which
31  * can be called from either the CLI (in client.c) or the interactive
32  * session (via the cmd_tar() callback).
33  *
34  * Once the configuration is done (successfully), the context is ready
35  * for processing and tar_to_process() returns true.
36  *
37  * The next step is to call tar_process() which dispatch the
38  * processing to either tar_create() or tar_extract(), depending on
39  * the context.
40  *
41  * ## Archive creation
42  *
43  * tar_create() creates an archive using the libarchive API then
44  *
45  * - iterates on the requested paths if the context is in inclusion
46  *   mode with tar_create_from_list()
47  *
48  * - or iterates on the whole share (starting from the current dir) if
49  *   in exclusion mode or if no specific path were requested
50  *
51  * The do_list() function from client.c is used to list recursively
52  * the share. In particular it takes a DOS path mask (eg. \mydir\*)
53  * and a callback function which will be called with each file name
54  * and attributes. The tar callback function is get_file_callback().
55  *
56  * The callback function checks whether the file should be skipped
57  * according the the configuration via tar_create_skip_path(). If it's
58  * not skipped it's downloaded and written to the archive in
59  * tar_get_file().
60  *
61  * ## Archive extraction
62  *
63  * tar_extract() opens the archive and iterates on each file in
64  * it. For each file tar_extract_skip_path() checks whether it should
65  * be skipped according to the config. If it's not skipped it's
66  * uploaded on the server in tar_send_file().
67  */
68
69 #include "includes.h"
70 #include "system/filesys.h"
71 #include "client/client_proto.h"
72 #include "client/clitar_proto.h"
73 #include "libsmb/libsmb.h"
74
75 #ifdef HAVE_LIBARCHIVE
76
77 #include <archive.h>
78 #include <archive_entry.h>
79
80 /* prepend module name and line number to debug messages */
81 #define DBG(a, b) (DEBUG(a, ("tar:%-4d ", __LINE__)), DEBUG(a, b))
82
83 /* preprocessor magic to stringify __LINE__ (int) */
84 #define STR1(x) #x
85 #define STR2(x) STR1(x)
86
87 /**
88  * Number of byte in a block unit.
89  */
90 #define TAR_BLOCK_UNIT 512
91
92 /**
93  * Default tar block size in TAR_BLOCK_UNIT.
94  */
95 #define TAR_DEFAULT_BLOCK_SIZE 20
96
97 /**
98  * Maximum value for the blocksize field
99  */
100 #define TAR_MAX_BLOCK_SIZE 0xffff
101
102 /**
103  * Size of the buffer used when downloading a file
104  */
105 #define TAR_CLI_READ_SIZE 0xff00
106
107 #define TAR_DO_LIST_ATTR (FILE_ATTRIBUTE_DIRECTORY \
108                           | FILE_ATTRIBUTE_SYSTEM  \
109                           | FILE_ATTRIBUTE_HIDDEN)
110
111
112 enum tar_operation {
113         TAR_NO_OPERATION,
114         TAR_CREATE,    /* c flag */
115         TAR_EXTRACT,   /* x flag */
116 };
117
118 enum tar_selection {
119         TAR_NO_SELECTION,
120         TAR_INCLUDE,       /* I and F flag, default */
121         TAR_EXCLUDE,       /* X flag */
122 };
123
124 struct tar {
125         TALLOC_CTX *talloc_ctx;
126
127         /* in state that needs/can be processed? */
128         bool to_process;
129
130         /* flags */
131         struct tar_mode {
132                 enum tar_operation operation; /* create, extract */
133                 enum tar_selection selection; /* include, exclude */
134                 int blocksize;    /* size in TAR_BLOCK_UNIT of a tar file block */
135                 bool hidden;      /* backup hidden file? */
136                 bool system;      /* backup system file? */
137                 bool incremental; /* backup _only_ archived file? */
138                 bool reset;       /* unset archive bit? */
139                 bool dry;         /* don't write tar file? */
140                 bool regex;       /* XXX: never actually using regex... */
141                 bool verbose;     /* XXX: ignored */
142         } mode;
143
144         /* nb of bytes received */
145         uint64_t total_size;
146
147         /* path to tar archive name */
148         char *tar_path;
149
150         /* list of path to include or exclude */
151         char **path_list;
152         int path_list_size;
153
154         /* archive handle */
155         struct archive *archive;
156
157         /* counters */
158         uint64_t numdir;
159         uint64_t numfile;
160 };
161
162 /**
163  * Global context imported in client.c when needed.
164  *
165  * Default options.
166  */
167 struct tar tar_ctx = {
168         .mode.selection   = TAR_INCLUDE,
169         .mode.blocksize   = TAR_DEFAULT_BLOCK_SIZE,
170         .mode.hidden      = true,
171         .mode.system      = true,
172         .mode.incremental = false,
173         .mode.reset       = false,
174         .mode.dry         = false,
175         .mode.regex       = false,
176         .mode.verbose     = false,
177 };
178
179 /* tar, local function */
180 static int tar_create(struct tar* t);
181 static int tar_create_from_list(struct tar *t);
182 static int tar_extract(struct tar *t);
183 static int tar_read_inclusion_file(struct tar *t, const char* filename);
184 static int tar_send_file(struct tar *t, struct archive_entry *entry);
185 static int tar_set_blocksize(struct tar *t, int size);
186 static int tar_set_newer_than(struct tar *t, const char *filename);
187 static NTSTATUS tar_add_selection_path(struct tar *t, const char *path);
188 static void tar_dump(struct tar *t);
189 static NTSTATUS tar_extract_skip_path(struct tar *t,
190                                       struct archive_entry *entry,
191                                       bool *_skip);
192 static TALLOC_CTX *tar_reset_mem_context(struct tar *t);
193 static void tar_free_mem_context(struct tar *t);
194 static NTSTATUS tar_create_skip_path(struct tar *t,
195                                      const char *fullpath,
196                                      const struct file_info *finfo,
197                                      bool *_skip);
198
199 static NTSTATUS tar_path_in_list(struct tar *t, const char *path,
200                                  bool reverse, bool *_is_in_list);
201
202 static int tar_get_file(struct tar *t,
203                         const char *full_dos_path,
204                         struct file_info *finfo);
205
206 static NTSTATUS get_file_callback(struct cli_state *cli,
207                                   struct file_info *finfo,
208                                   const char *dir);
209
210 /* utilities */
211 static char *fix_unix_path(char *path, bool removeprefix);
212 static NTSTATUS path_base_name(TALLOC_CTX *ctx, const char *path, char **_base);
213 static const char* skip_useless_char_in_path(const char *p);
214 static int make_remote_path(const char *full_path);
215 static int max_token (const char *str);
216 static NTSTATUS is_subpath(const char *sub, const char *full,
217                            bool *_subpath_match);
218  /*
219  * tar_get_ctx - retrieve global tar context handle
220  */
221 struct tar *tar_get_ctx()
222 {
223         return &tar_ctx;
224 }
225
226 /**
227  * cmd_block - interactive command to change tar blocksize
228  *
229  * Read a size from the client command line and update the current
230  * blocksize.
231  */
232 int cmd_block(void)
233 {
234         /* XXX: from client.c */
235         const extern char *cmd_ptr;
236         char *buf;
237         int err = 0;
238         bool ok;
239         TALLOC_CTX *ctx = talloc_new(NULL);
240         if (ctx == NULL) {
241                 return 1;
242         }
243
244         ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
245         if (!ok) {
246                 DBG(0, ("blocksize <n>\n"));
247                 err = 1;
248                 goto out;
249         }
250
251         ok = tar_set_blocksize(&tar_ctx, atoi(buf));
252         if (ok) {
253                 DBG(0, ("invalid blocksize\n"));
254                 err = 1;
255                 goto out;
256         }
257
258         DBG(2, ("blocksize is now %d\n", tar_ctx.mode.blocksize));
259
260 out:
261         talloc_free(ctx);
262         return err;
263 }
264
265 /**
266  * cmd_tarmode - interactive command to change tar behaviour
267  *
268  * Read one or more modes from the client command line and update the
269  * current tar mode.
270  */
271 int cmd_tarmode(void)
272 {
273         const extern char *cmd_ptr;
274         char *buf;
275         int i;
276         TALLOC_CTX *ctx;
277
278         struct {
279                 const char *cmd;
280                 bool *p;
281                 bool value;
282         } table[] = {
283                 {"full",      &tar_ctx.mode.incremental, false},
284                 {"inc",       &tar_ctx.mode.incremental, true },
285                 {"reset",     &tar_ctx.mode.reset,       true },
286                 {"noreset",   &tar_ctx.mode.reset,       false},
287                 {"system",    &tar_ctx.mode.system,      true },
288                 {"nosystem",  &tar_ctx.mode.system,      false},
289                 {"hidden",    &tar_ctx.mode.hidden,      true },
290                 {"nohidden",  &tar_ctx.mode.hidden,      false},
291                 {"verbose",   &tar_ctx.mode.verbose,     false},
292                 {"noverbose", &tar_ctx.mode.verbose,     true },
293         };
294
295         ctx = talloc_new(NULL);
296         if (ctx == NULL) {
297                 return 1;
298         }
299
300         while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
301                 for (i = 0; i < ARRAY_SIZE(table); i++) {
302                         if (strequal(table[i].cmd, buf)) {
303                                 *table[i].p = table[i].value;
304                                 break;
305                         }
306                 }
307
308                 if (i == ARRAY_SIZE(table))
309                         d_printf("tarmode: unrecognised option %s\n", buf);
310         }
311
312         d_printf("tarmode is now %s, %s, %s, %s, %s\n",
313                                 tar_ctx.mode.incremental ? "incremental" : "full",
314                                 tar_ctx.mode.system      ? "system"      : "nosystem",
315                                 tar_ctx.mode.hidden      ? "hidden"      : "nohidden",
316                                 tar_ctx.mode.reset       ? "reset"       : "noreset",
317                                 tar_ctx.mode.verbose     ? "verbose"     : "noverbose");
318
319         talloc_free(ctx);
320         return 0;
321 }
322
323 /**
324  * cmd_tar - interactive command to start a tar backup/restoration
325  *
326  * Check presence of argument, parse them and handle the request.
327  */
328 int cmd_tar(void)
329 {
330         const extern char *cmd_ptr;
331         const char *flag;
332         const char **val;
333         char *buf;
334         int maxtok = max_token(cmd_ptr);
335         int i = 0;
336         int err = 0;
337         bool ok;
338         int rc;
339         TALLOC_CTX *ctx = talloc_new(NULL);
340         if (ctx == NULL) {
341                 return 1;
342         }
343
344         ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
345         if (!ok) {
346                 d_printf("tar <c|x>[IXFbgvanN] [options] <tar file> [path list]\n");
347                 err = 1;
348                 goto out;
349         }
350
351         flag = buf;
352         val = talloc_array(ctx, const char *, maxtok);
353         if (val == NULL) {
354                 err = 1;
355                 goto out;
356         }
357
358         while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
359                 val[i++] = buf;
360         }
361
362         rc = tar_parse_args(&tar_ctx, flag, val, i);
363         if (rc != 0) {
364                 d_printf("parse_args failed\n");
365                 err = 1;
366                 goto out;
367         }
368
369         rc = tar_process(&tar_ctx);
370         if (rc != 0) {
371                 d_printf("tar_process failed\n");
372                 err = 1;
373                 goto out;
374         }
375
376 out:
377         talloc_free(ctx);
378         return err;
379 }
380
381
382 /**
383  * tar_parse_args - parse and set tar command line arguments
384  * @flag: string pointing to tar options
385  * @val: number of tar arguments
386  * @valsize: table of arguments after the flags (number of element in val)
387  *
388  * tar arguments work in a weird way. For each flag f that takes a
389  * value v, the user is supposed to type:
390  *
391  * on the CLI:
392  *   -Tf1f2f3 v1 v2 v3 TARFILE PATHS...
393  *
394  * in the interactive session:
395  *   tar f1f2f3 v1 v2 v3 TARFILE PATHS...
396  *
397  * @flag has only flags (eg. "f1f2f3") and @val has the arguments
398  * (values) following them (eg. ["v1", "v2", "v3", "TARFILE", "PATH1",
399  * "PATH2"]).
400  *
401  * There are only 2 flags that take an arg: b and N. The other flags
402  * just change the semantic of PATH or TARFILE.
403  *
404  * PATH can be a list of included/excluded paths, the path to a file
405  * containing a list of included/excluded paths to use (F flag). If no
406  * PATH is provided, the whole share is used (/).
407  */
408 int tar_parse_args(struct tar* t,
409                    const char *flag,
410                    const char **val,
411                    int valsize)
412 {
413         TALLOC_CTX *ctx;
414         bool do_read_list = false;
415         /* index of next value to use */
416         int ival = 0;
417         int rc;
418
419         if (t == NULL) {
420                 DBG_WARNING("Invalid tar context\n");
421                 return 1;
422         }
423
424         ctx = tar_reset_mem_context(t);
425         if (ctx == NULL) {
426                 return 1;
427         }
428         /*
429          * Reset back some options - could be from interactive version
430          * all other modes are left as they are
431          */
432         t->mode.operation = TAR_NO_OPERATION;
433         t->mode.selection = TAR_NO_SELECTION;
434         t->mode.dry = false;
435         t->to_process = false;
436         t->total_size = 0;
437
438         while (flag[0] != '\0') {
439                 switch(flag[0]) {
440                 /* operation */
441                 case 'c':
442                         if (t->mode.operation != TAR_NO_OPERATION) {
443                                 d_printf("Tar must be followed by only one of c or x.\n");
444                                 return 1;
445                         }
446                         t->mode.operation = TAR_CREATE;
447                         break;
448                 case 'x':
449                         if (t->mode.operation != TAR_NO_OPERATION) {
450                                 d_printf("Tar must be followed by only one of c or x.\n");
451                                 return 1;
452                         }
453                         t->mode.operation = TAR_EXTRACT;
454                         break;
455
456                         /* selection  */
457                 case 'I':
458                         if (t->mode.selection != TAR_NO_SELECTION) {
459                                 d_printf("Only one of I,X,F must be specified\n");
460                                 return 1;
461                         }
462                         t->mode.selection = TAR_INCLUDE;
463                         break;
464                 case 'X':
465                         if (t->mode.selection != TAR_NO_SELECTION) {
466                                 d_printf("Only one of I,X,F must be specified\n");
467                                 return 1;
468                         }
469                         t->mode.selection = TAR_EXCLUDE;
470                         break;
471                 case 'F':
472                         if (t->mode.selection != TAR_NO_SELECTION) {
473                                 d_printf("Only one of I,X,F must be specified\n");
474                                 return 1;
475                         }
476                         t->mode.selection = TAR_INCLUDE;
477                         do_read_list = true;
478                         break;
479
480                         /* blocksize */
481                 case 'b':
482                         if (ival >= valsize) {
483                                 d_printf("Option b must be followed by a blocksize\n");
484                                 return 1;
485                         }
486
487                         if (tar_set_blocksize(t, atoi(val[ival]))) {
488                                 d_printf("Option b must be followed by a valid blocksize\n");
489                                 return 1;
490                         }
491
492                         ival++;
493                         break;
494
495                         /* incremental mode */
496                 case 'g':
497                         t->mode.incremental = true;
498                         break;
499
500                         /* newer than */
501                 case 'N':
502                         if (ival >= valsize) {
503                                 d_printf("Option N must be followed by valid file name\n");
504                                 return 1;
505                         }
506
507                         if (tar_set_newer_than(t, val[ival])) {
508                                 d_printf("Error setting newer-than time\n");
509                                 return 1;
510                         }
511
512                         ival++;
513                         break;
514
515                         /* reset mode */
516                 case 'a':
517                         t->mode.reset = true;
518                         break;
519
520                         /* verbose */
521                 case 'v':
522                         t->mode.verbose = true;
523                         break;
524
525                         /* regex match  */
526                 case 'r':
527                         t->mode.regex = true;
528                         break;
529
530                         /* dry run mode */
531                 case 'n':
532                         if (t->mode.operation != TAR_CREATE) {
533                                 d_printf("n is only meaningful when creating a tar-file\n");
534                                 return 1;
535                         }
536
537                         t->mode.dry = true;
538                         d_printf("dry_run set\n");
539                         break;
540
541                 default:
542                         d_printf("Unknown tar option\n");
543                         return 1;
544                 }
545
546                 flag++;
547         }
548
549         /* no selection given? default selection is include */
550         if (t->mode.selection == TAR_NO_SELECTION) {
551                 t->mode.selection = TAR_INCLUDE;
552         }
553
554         if (valsize - ival < 1) {
555                 d_printf("No tar file given.\n");
556                 return 1;
557         }
558
559         /* handle TARFILE */
560         t->tar_path = talloc_strdup(ctx, val[ival]);
561         if (t->tar_path == NULL) {
562                 return 1;
563         }
564         ival++;
565
566         /*
567          * Make sure that dbf points to stderr if we are using stdout for
568          * tar output
569          */
570         if (t->mode.operation == TAR_CREATE && strequal(t->tar_path, "-")) {
571                 setup_logging("smbclient", DEBUG_STDERR);
572         }
573
574         /* handle PATHs... */
575
576         /* flag F -> read file list */
577         if (do_read_list) {
578                 if (valsize - ival != 1) {
579                         d_printf("Option F must be followed by exactly one filename.\n");
580                         return 1;
581                 }
582
583                 rc = tar_read_inclusion_file(t, val[ival]);
584                 if (rc != 0) {
585                         return 1;
586                 }
587                 ival++;
588         /* otherwise store all the PATHs on the command line */
589         } else {
590                 int i;
591                 for (i = ival; i < valsize; i++) {
592                         NTSTATUS status;
593                         status = tar_add_selection_path(t, val[i]);
594                         if (!NT_STATUS_IS_OK(status)) {
595                                 return 1;
596                         }
597                 }
598         }
599
600         t->to_process = true;
601         tar_dump(t);
602         return 0;
603 }
604
605 /**
606  * tar_process - start processing archive
607  *
608  * The talloc context of the fields is freed at the end of the call.
609  */
610 int tar_process(struct tar *t)
611 {
612         int rc = 0;
613
614         if (t == NULL) {
615                 DBG_WARNING("Invalid tar context\n");
616                 return 1;
617         }
618
619         switch(t->mode.operation) {
620         case TAR_EXTRACT:
621                 rc = tar_extract(t);
622                 break;
623         case TAR_CREATE:
624                 rc = tar_create(t);
625                 break;
626         default:
627                 DBG_WARNING("Invalid tar state\n");
628                 rc = 1;
629         }
630
631         t->to_process = false;
632         tar_free_mem_context(t);
633         DBG(5, ("tar_process done, err = %d\n", rc));
634         return rc;
635 }
636
637 /**
638  * tar_create - create archive and fetch files
639  */
640 static int tar_create(struct tar* t)
641 {
642         int r;
643         int err = 0;
644         NTSTATUS status;
645         const char *mask;
646         struct timespec tp_start, tp_end;
647         TALLOC_CTX *ctx = talloc_new(NULL);
648         if (ctx == NULL) {
649                 return 1;
650         }
651
652         clock_gettime_mono(&tp_start);
653
654         t->numfile = 0;
655         t->numdir = 0;
656         t->archive = archive_write_new();
657
658         if (!t->mode.dry) {
659                 const int bsize = t->mode.blocksize * TAR_BLOCK_UNIT;
660                 r = archive_write_set_bytes_per_block(t->archive, bsize);
661                 if (r != ARCHIVE_OK) {
662                         d_printf("Can't use a block size of %d bytes", bsize);
663                         err = 1;
664                         goto out;
665                 }
666
667                 /*
668                  * Use PAX restricted format which is not the most
669                  * conservative choice but has useful extensions and is widely
670                  * supported
671                  */
672                 r = archive_write_set_format_pax_restricted(t->archive);
673                 if (r != ARCHIVE_OK) {
674                         d_printf("Can't use pax restricted format: %s\n",
675                                                 archive_error_string(t->archive));
676                         err = 1;
677                         goto out;
678                 }
679
680                 if (strequal(t->tar_path, "-")) {
681                         r = archive_write_open_fd(t->archive, STDOUT_FILENO);
682                 } else {
683                         r = archive_write_open_filename(t->archive, t->tar_path);
684                 }
685
686                 if (r != ARCHIVE_OK) {
687                         d_printf("Can't open %s: %s\n", t->tar_path,
688                                                 archive_error_string(t->archive));
689                         err = 1;
690                         goto out_close;
691                 }
692         }
693
694         /*
695          * In inclusion mode, iterate on the inclusion list
696          */
697         if (t->mode.selection == TAR_INCLUDE && t->path_list_size > 0) {
698                 if (tar_create_from_list(t)) {
699                         err = 1;
700                         goto out_close;
701                 }
702         } else {
703                 mask = talloc_asprintf(ctx, "%s\\*", client_get_cur_dir());
704                 if (mask == NULL) {
705                         err = 1;
706                         goto out_close;
707                 }
708                 mask = client_clean_name(ctx, mask);
709                 if (mask == NULL) {
710                         err = 1;
711                         goto out_close;
712                 }
713                 DBG(5, ("tar_process do_list with mask: %s\n", mask));
714                 status = do_list(mask, TAR_DO_LIST_ATTR, get_file_callback, false, true);
715                 if (!NT_STATUS_IS_OK(status)) {
716                         DBG(0, ("do_list fail %s\n", nt_errstr(status)));
717                         err = 1;
718                         goto out_close;
719                 }
720         }
721
722         clock_gettime_mono(&tp_end);
723         d_printf("tar: dumped %"PRIu64" files and %"PRIu64" directories\n",
724                  t->numfile, t->numdir);
725         d_printf("Total bytes written: %"PRIu64" (%.1f MiB/s)\n",
726                 t->total_size,
727                 t->total_size/timespec_elapsed2(&tp_start, &tp_end)/1024/1024);
728
729 out_close:
730
731         if (!t->mode.dry) {
732                 r = archive_write_close(t->archive);
733                 if (r != ARCHIVE_OK) {
734                         d_printf("Fatal: %s\n", archive_error_string(t->archive));
735                         err = 1;
736                         goto out;
737                 }
738         }
739 out:
740 #ifdef HAVE_ARCHIVE_READ_FREE
741         archive_write_free(t->archive);
742 #else
743         archive_write_finish(t->archive);
744 #endif
745         talloc_free(ctx);
746         return err;
747 }
748
749 /**
750  * tar_create_from_list - fetch from path list in include mode
751  */
752 static int tar_create_from_list(struct tar *t)
753 {
754         int err = 0;
755         NTSTATUS status;
756         char *base;
757         const char *path, *mask, *start_dir;
758         int i;
759         TALLOC_CTX *ctx = talloc_new(NULL);
760         if (ctx == NULL) {
761                 return 1;
762         }
763
764         start_dir = talloc_strdup(ctx, client_get_cur_dir());
765         if (start_dir == NULL) {
766                 err = 1;
767                 goto out;
768         }
769
770         for (i = 0; i < t->path_list_size; i++) {
771                 path = t->path_list[i];
772                 base = NULL;
773                 status = path_base_name(ctx, path, &base);
774                 if (!NT_STATUS_IS_OK(status)) {
775                         err = 1;
776                         goto out;
777                 }
778                 mask = talloc_asprintf(ctx, "%s\\%s",
779                                        client_get_cur_dir(), path);
780                 if (mask == NULL) {
781                         err = 1;
782                         goto out;
783                 }
784                 mask = client_clean_name(ctx, mask);
785                 if (mask == NULL) {
786                         err = 1;
787                         goto out;
788                 }
789
790                 DBG(5, ("incl. path='%s', base='%s', mask='%s'\n",
791                                         path, base ? base : "NULL", mask));
792
793                 if (base != NULL) {
794                         base = talloc_asprintf(ctx, "%s%s\\",
795                                                client_get_cur_dir(), base);
796                         if (base == NULL) {
797                                 err = 1;
798                                 goto out;
799                         }
800                         base = client_clean_name(ctx, base);
801                         if (base == NULL) {
802                                 err = 1;
803                                 goto out;
804                         }
805
806                         DBG(5, ("cd '%s' before do_list\n", base));
807                         client_set_cur_dir(base);
808                 }
809                 status = do_list(mask, TAR_DO_LIST_ATTR, get_file_callback, false, true);
810                 if (base != NULL) {
811                         client_set_cur_dir(start_dir);
812                 }
813                 if (!NT_STATUS_IS_OK(status)) {
814                         DBG(0, ("do_list failed on %s (%s)\n", path, nt_errstr(status)));
815                         err = 1;
816                         goto out;
817                 }
818         }
819
820 out:
821         talloc_free(ctx);
822         return err;
823 }
824
825 /**
826  * get_file_callback - do_list callback
827  *
828  * Callback for client.c do_list(). Called for each file found on the
829  * share matching do_list mask. Recursively call do_list() with itself
830  * as callback when the current file is a directory.
831  */
832 static NTSTATUS get_file_callback(struct cli_state *cli,
833                                   struct file_info *finfo,
834                                   const char *dir)
835 {
836         NTSTATUS status = NT_STATUS_OK;
837         char *remote_name;
838         char *old_dir = NULL;
839         char *new_dir = NULL;
840         const char *initial_dir = client_get_cur_dir();
841         bool skip = false;
842         bool isdir;
843         int rc;
844         TALLOC_CTX *ctx = talloc_new(NULL);
845         if (ctx == NULL) {
846                 return NT_STATUS_NO_MEMORY;
847         }
848
849         remote_name = talloc_asprintf(ctx, "%s%s", initial_dir, finfo->name);
850         if (remote_name == NULL) {
851                 status = NT_STATUS_NO_MEMORY;
852                 goto out;
853         }
854         remote_name = client_clean_name(ctx, remote_name);
855         if (remote_name == NULL) {
856                 status = NT_STATUS_NO_MEMORY;
857                 goto out;
858         }
859
860         if (strequal(finfo->name, "..") || strequal(finfo->name, ".")) {
861                 goto out;
862         }
863
864         isdir = finfo->mode & FILE_ATTRIBUTE_DIRECTORY;
865         if (isdir) {
866                 old_dir = talloc_strdup(ctx, initial_dir);
867                 new_dir = talloc_asprintf(ctx, "%s\\", remote_name);
868                 if ((old_dir == NULL) || (new_dir == NULL)) {
869                         status = NT_STATUS_NO_MEMORY;
870                         goto out;
871                 }
872         }
873
874         status = tar_create_skip_path(&tar_ctx,
875                                       isdir ? new_dir : remote_name,
876                                       finfo, &skip);
877         if (!NT_STATUS_IS_OK(status)) {
878                 goto out;
879         }
880
881         if (skip) {
882                 DBG(5, ("--- %s\n", remote_name));
883                 status = NT_STATUS_OK;
884                 goto out;
885         }
886
887         if (isdir) {
888                 char *mask;
889                 mask = talloc_asprintf(ctx, "%s*", new_dir);
890                 if (mask == NULL) {
891                         status = NT_STATUS_NO_MEMORY;
892                         goto out;
893                 }
894                 mask = client_clean_name(ctx, mask);
895                 if (mask == NULL) {
896                         status = NT_STATUS_NO_MEMORY;
897                         goto out;
898                 }
899
900                 rc = tar_get_file(&tar_ctx, remote_name, finfo);
901                 if (rc != 0) {
902                         status = NT_STATUS_UNSUCCESSFUL;
903                         goto out;
904                 }
905
906                 client_set_cur_dir(new_dir);
907                 do_list(mask, TAR_DO_LIST_ATTR, get_file_callback, false, true);
908                 client_set_cur_dir(old_dir);
909                 tar_ctx.numdir++;
910         } else {
911                 rc = tar_get_file(&tar_ctx, remote_name, finfo);
912                 if (rc != 0) {
913                         status = NT_STATUS_UNSUCCESSFUL;
914                         goto out;
915                 }
916         }
917
918 out:
919         talloc_free(ctx);
920         return status;
921 }
922
923 /**
924  * tar_get_file - fetch a remote file to the local archive
925  * @full_dos_path: path to the file to fetch
926  * @finfo: attributes of the file to fetch
927  */
928 static int tar_get_file(struct tar *t,
929                         const char *full_dos_path,
930                         struct file_info *finfo)
931 {
932         extern struct cli_state *cli;
933         NTSTATUS status;
934         struct archive_entry *entry;
935         char *full_unix_path;
936         char buf[TAR_CLI_READ_SIZE];
937         size_t len;
938         uint64_t off = 0;
939         uint16_t remote_fd = (uint16_t)-1;
940         int err = 0, r;
941         const bool isdir = finfo->mode & FILE_ATTRIBUTE_DIRECTORY;
942         TALLOC_CTX *ctx = talloc_new(NULL);
943
944         if (ctx == NULL) {
945                 return 1;
946         }
947
948         DBG(5, ("+++ %s\n", full_dos_path));
949
950         t->total_size += finfo->size;
951
952         if (t->mode.dry) {
953                 goto out;
954         }
955
956         if (t->mode.reset) {
957                 /* ignore return value: server might not store DOS attributes */
958                 set_remote_attr(full_dos_path, FILE_ATTRIBUTE_ARCHIVE, ATTR_UNSET);
959         }
960
961         full_unix_path = talloc_asprintf(ctx, ".%s", full_dos_path);
962         if (full_unix_path == NULL) {
963                 err = 1;
964                 goto out;
965         }
966         string_replace(full_unix_path, '\\', '/');
967         entry = archive_entry_new();
968         archive_entry_copy_pathname(entry, full_unix_path);
969         archive_entry_set_filetype(entry, isdir ? AE_IFDIR : AE_IFREG);
970         archive_entry_set_atime(entry,
971                         finfo->atime_ts.tv_sec,
972                         finfo->atime_ts.tv_nsec);
973         archive_entry_set_mtime(entry,
974                         finfo->mtime_ts.tv_sec,
975                         finfo->mtime_ts.tv_nsec);
976         archive_entry_set_ctime(entry,
977                         finfo->ctime_ts.tv_sec,
978                         finfo->ctime_ts.tv_nsec);
979         archive_entry_set_perm(entry, isdir ? 0755 : 0644);
980         /*
981          * check if we can safely cast unsigned file size to libarchive
982          * signed size. Very unlikely problem (>9 exabyte file)
983          */
984         if (finfo->size > INT64_MAX) {
985                 d_printf("Remote file %s too big\n", full_dos_path);
986                 goto out_entry;
987         }
988
989         archive_entry_set_size(entry, (int64_t)finfo->size);
990
991         if (isdir) {
992                 /* It's a directory just write a header */
993                 r = archive_write_header(t->archive, entry);
994                 if (r != ARCHIVE_OK) {
995                         d_printf("Fatal: %s\n", archive_error_string(t->archive));
996                         err = 1;
997                 }
998                 if (t->mode.verbose) {
999                         d_printf("a %s\\\n", full_dos_path);
1000                 }
1001                 DBG(5, ("get_file skip dir %s\n", full_dos_path));
1002                 goto out_entry;
1003         }
1004
1005         status = cli_open(cli, full_dos_path, O_RDONLY, DENY_NONE, &remote_fd);
1006         if (!NT_STATUS_IS_OK(status)) {
1007                 d_printf("%s opening remote file %s\n",
1008                                         nt_errstr(status), full_dos_path);
1009                 goto out_entry;
1010         }
1011
1012         /* don't make tar file entry until after the file is open */
1013         r = archive_write_header(t->archive, entry);
1014         if (r != ARCHIVE_OK) {
1015                 d_printf("Fatal: %s\n", archive_error_string(t->archive));
1016                 err = 1;
1017                 goto out_entry;
1018         }
1019
1020         if (t->mode.verbose) {
1021                 d_printf("a %s\n", full_dos_path);
1022         }
1023
1024         do {
1025                 status = cli_read(cli, remote_fd, buf, off, sizeof(buf), &len);
1026                 if (!NT_STATUS_IS_OK(status)) {
1027                         d_printf("Error reading file %s : %s\n",
1028                                                 full_dos_path, nt_errstr(status));
1029                         err = 1;
1030                         goto out_close;
1031                 }
1032
1033                 off += len;
1034
1035                 r = archive_write_data(t->archive, buf, len);
1036                 if (r < 0) {
1037                         d_printf("Fatal: %s\n", archive_error_string(t->archive));
1038                         err = 1;
1039                         goto out_close;
1040                 }
1041
1042         } while (off < finfo->size);
1043         t->numfile++;
1044
1045 out_close:
1046         cli_close(cli, remote_fd);
1047
1048 out_entry:
1049         archive_entry_free(entry);
1050
1051 out:
1052         talloc_free(ctx);
1053         return err;
1054 }
1055
1056 /**
1057  * tar_extract - open archive and send files.
1058  */
1059 static int tar_extract(struct tar *t)
1060 {
1061         int err = 0;
1062         int r;
1063         struct archive_entry *entry;
1064         const size_t bsize = t->mode.blocksize * TAR_BLOCK_UNIT;
1065         int rc;
1066
1067         t->archive = archive_read_new();
1068         archive_read_support_format_all(t->archive);
1069 #ifdef HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL
1070         archive_read_support_filter_all(t->archive);
1071 #endif
1072
1073         if (strequal(t->tar_path, "-")) {
1074                 r = archive_read_open_fd(t->archive, STDIN_FILENO, bsize);
1075         } else {
1076                 r = archive_read_open_filename(t->archive, t->tar_path, bsize);
1077         }
1078
1079         if (r != ARCHIVE_OK) {
1080                 d_printf("Can't open %s : %s\n", t->tar_path,
1081                                         archive_error_string(t->archive));
1082                 err = 1;
1083                 goto out;
1084         }
1085
1086         for (;;) {
1087                 NTSTATUS status;
1088                 bool skip = false;
1089                 r = archive_read_next_header(t->archive, &entry);
1090                 if (r == ARCHIVE_EOF) {
1091                         break;
1092                 }
1093                 if (r == ARCHIVE_WARN) {
1094                         d_printf("Warning: %s\n", archive_error_string(t->archive));
1095                 }
1096                 if (r == ARCHIVE_FATAL) {
1097                         d_printf("Fatal: %s\n", archive_error_string(t->archive));
1098                         err = 1;
1099                         goto out;
1100                 }
1101
1102                 status = tar_extract_skip_path(t, entry, &skip);
1103                 if (!NT_STATUS_IS_OK(status)) {
1104                         err = 1;
1105                         goto out;
1106                 }
1107                 if (skip) {
1108                         DBG(5, ("--- %s\n", archive_entry_pathname(entry)));
1109                         continue;
1110                 }
1111                 DBG(5, ("+++ %s\n", archive_entry_pathname(entry)));
1112
1113                 if (t->mode.verbose) {
1114                         d_printf("x %s\n", archive_entry_pathname(entry));
1115                 }
1116
1117                 rc = tar_send_file(t, entry);
1118                 if (rc != 0) {
1119                         err = 1;
1120                         goto out;
1121                 }
1122         }
1123
1124 out:
1125 #ifdef HAVE_ARCHIVE_READ_FREE
1126         r = archive_read_free(t->archive);
1127 #else
1128         r = archive_read_finish(t->archive);
1129 #endif
1130         if (r != ARCHIVE_OK) {
1131                 d_printf("Can't close %s : %s\n", t->tar_path,
1132                                         archive_error_string(t->archive));
1133                 err = 1;
1134         }
1135         return err;
1136 }
1137
1138 /**
1139  * tar_send_file - send @entry to the remote server
1140  * @entry: current archive entry
1141  *
1142  * Handle the creation of the parent directories and transfer the
1143  * entry to a new remote file.
1144  */
1145 static int tar_send_file(struct tar *t, struct archive_entry *entry)
1146 {
1147         extern struct cli_state *cli;
1148         char *dos_path;
1149         char *full_path;
1150         NTSTATUS status;
1151         uint16_t remote_fd = (uint16_t) -1;
1152         int err = 0;
1153         int flags = O_RDWR | O_CREAT | O_TRUNC;
1154         mode_t mode = archive_entry_filetype(entry);
1155         int rc;
1156         TALLOC_CTX *ctx = talloc_new(NULL);
1157         if (ctx == NULL) {
1158                 return 1;
1159         }
1160
1161         dos_path = talloc_strdup(ctx, archive_entry_pathname(entry));
1162         if (dos_path == NULL) {
1163                 err = 1;
1164                 goto out;
1165         }
1166         fix_unix_path(dos_path, true);
1167
1168         full_path = talloc_strdup(ctx, client_get_cur_dir());
1169         if (full_path == NULL) {
1170                 err = 1;
1171                 goto out;
1172         }
1173         full_path = talloc_strdup_append(full_path, dos_path);
1174         if (full_path == NULL) {
1175                 err = 1;
1176                 goto out;
1177         }
1178         full_path = client_clean_name(ctx, full_path);
1179         if (full_path == NULL) {
1180                 err = 1;
1181                 goto out;
1182         }
1183
1184         if (mode != AE_IFREG && mode != AE_IFDIR) {
1185                 d_printf("Skipping non-dir & non-regular file %s\n", full_path);
1186                 goto out;
1187         }
1188
1189         rc = make_remote_path(full_path);
1190         if (rc != 0) {
1191                 err = 1;
1192                 goto out;
1193         }
1194
1195         if (mode == AE_IFDIR) {
1196                 goto out;
1197         }
1198
1199         status = cli_open(cli, full_path, flags, DENY_NONE, &remote_fd);
1200         if (!NT_STATUS_IS_OK(status)) {
1201                 d_printf("Error opening remote file %s: %s\n",
1202                                         full_path, nt_errstr(status));
1203                 err = 1;
1204                 goto out;
1205         }
1206
1207         for (;;) {
1208                 const void *buf;
1209                 size_t len;
1210                 off_t off;
1211                 int r;
1212
1213                 r = archive_read_data_block(t->archive, &buf, &len, &off);
1214                 if (r == ARCHIVE_EOF) {
1215                         break;
1216                 }
1217                 if (r == ARCHIVE_WARN) {
1218                         d_printf("Warning: %s\n", archive_error_string(t->archive));
1219                 }
1220                 if (r == ARCHIVE_FATAL) {
1221                         d_printf("Fatal: %s\n", archive_error_string(t->archive));
1222                         err = 1;
1223                         goto close_out;
1224                 }
1225
1226                 status = cli_writeall(cli, remote_fd, 0, buf, off, len, NULL);
1227                 if (!NT_STATUS_IS_OK(status)) {
1228                         d_printf("Error writing remote file %s: %s\n",
1229                                                 full_path, nt_errstr(status));
1230                         err = 1;
1231                         goto close_out;
1232                 }
1233         }
1234
1235 close_out:
1236         status = cli_close(cli, remote_fd);
1237         if (!NT_STATUS_IS_OK(status)) {
1238                 d_printf("Error closing remote file %s: %s\n",
1239                                         full_path, nt_errstr(status));
1240                 err = 1;
1241         }
1242
1243 out:
1244         talloc_free(ctx);
1245         return err;
1246 }
1247
1248 /**
1249  * tar_add_selection_path - add a path to the path list
1250  * @path: path to add
1251  */
1252 static NTSTATUS tar_add_selection_path(struct tar *t, const char *path)
1253 {
1254         const char **list;
1255         TALLOC_CTX *ctx = t->talloc_ctx;
1256         if (!t->path_list) {
1257                 t->path_list = str_list_make_empty(ctx);
1258                 if (t->path_list == NULL) {
1259                         return NT_STATUS_NO_MEMORY;
1260                 }
1261                 t->path_list_size = 0;
1262         }
1263
1264         /* cast to silence gcc const-qual warning */
1265         list = str_list_add((void *)t->path_list, path);
1266         if (list == NULL) {
1267                 return NT_STATUS_NO_MEMORY;
1268         }
1269         t->path_list = discard_const_p(char *, list);
1270         t->path_list_size++;
1271         fix_unix_path(t->path_list[t->path_list_size - 1], true);
1272
1273         return NT_STATUS_OK;
1274 }
1275
1276 /**
1277  * tar_set_blocksize - set block size in TAR_BLOCK_UNIT
1278  */
1279 static int tar_set_blocksize(struct tar *t, int size)
1280 {
1281         if (size <= 0 || size > TAR_MAX_BLOCK_SIZE) {
1282                 return 1;
1283         }
1284
1285         t->mode.blocksize = size;
1286
1287         return 0;
1288 }
1289
1290 /**
1291  * tar_set_newer_than - set date threshold of saved files
1292  * @filename: local path to a file
1293  *
1294  * Only files newer than the modification time of @filename will be
1295  * saved.
1296  *
1297  * Note: this function set the global variable newer_than from
1298  * client.c. Thus the time is not a field of the tar structure. See
1299  * cmd_newer() to change its value from an interactive session.
1300  */
1301 static int tar_set_newer_than(struct tar *t, const char *filename)
1302 {
1303         extern time_t newer_than;
1304         SMB_STRUCT_STAT stbuf;
1305         int rc;
1306
1307         rc = sys_stat(filename, &stbuf, false);
1308         if (rc != 0) {
1309                 d_printf("Error setting newer-than time\n");
1310                 return 1;
1311         }
1312
1313         newer_than = convert_timespec_to_time_t(stbuf.st_ex_mtime);
1314         DBG(1, ("Getting files newer than %s\n", time_to_asc(newer_than)));
1315         return 0;
1316 }
1317
1318 /**
1319  * tar_read_inclusion_file - set path list from file
1320  * @filename: path to the list file
1321  *
1322  * Read and add each line of @filename to the path list.
1323  */
1324 static int tar_read_inclusion_file(struct tar *t, const char* filename)
1325 {
1326         char *line;
1327         int err = 0;
1328         int fd = -1;
1329         TALLOC_CTX *ctx = talloc_new(NULL);
1330         if (ctx == NULL) {
1331                 return 1;
1332         }
1333
1334         fd = open(filename, O_RDONLY);
1335         if (fd < 0) {
1336                 d_printf("Can't open inclusion file '%s': %s\n", filename, strerror(errno));
1337                 err = 1;
1338                 goto out;
1339         }
1340
1341         for (line = afdgets(fd, ctx, 0);
1342                         line != NULL;
1343                         line = afdgets(fd, ctx, 0)) {
1344                 NTSTATUS status;
1345                 status = tar_add_selection_path(t, line);
1346                 if (!NT_STATUS_IS_OK(status)) {
1347                         err = 1;
1348                         goto out;
1349                 }
1350         }
1351
1352 out:
1353         if (fd != -1) {
1354                 close(fd);
1355         }
1356         talloc_free(ctx);
1357         return err;
1358 }
1359
1360 /**
1361  * tar_path_in_list - check whether @path is in the path list
1362  * @path: path to find
1363  * @reverse: when true also try to find path list element in @path
1364  * @_is_in_list: set if @path is in the path list
1365  *
1366  * Look at each path of the path list and set @_is_in_list if @path is a
1367  * subpath of one of them.
1368  *
1369  * If you want /path to be in the path list (path/a/, path/b/) set
1370  * @reverse to true to try to match the other way around.
1371  */
1372 static NTSTATUS tar_path_in_list(struct tar *t, const char *path,
1373                                  bool reverse, bool *_is_in_list)
1374 {
1375         int i;
1376         const char *p;
1377         const char *pattern;
1378
1379         if (path == NULL || path[0] == '\0') {
1380                 *_is_in_list = false;
1381                 return NT_STATUS_OK;
1382         }
1383
1384         p = skip_useless_char_in_path(path);
1385
1386         for (i = 0; i < t->path_list_size; i++) {
1387                 bool is_in_list;
1388                 NTSTATUS status;
1389
1390                 pattern = skip_useless_char_in_path(t->path_list[i]);
1391                 status = is_subpath(p, pattern, &is_in_list);
1392                 if (!NT_STATUS_IS_OK(status)) {
1393                         return status;
1394                 }
1395                 if (reverse && !is_in_list) {
1396                         status = is_subpath(pattern, p, &is_in_list);
1397                         if (!NT_STATUS_IS_OK(status)) {
1398                                 return status;
1399                         }
1400                 }
1401                 if (is_in_list) {
1402                         *_is_in_list = true;
1403                         return NT_STATUS_OK;
1404                 }
1405         }
1406
1407         *_is_in_list = false;
1408         return NT_STATUS_OK;
1409 }
1410
1411 /**
1412  * tar_extract_skip_path - check if @entry should be skipped
1413  * @entry: current tar entry
1414  * @_skip: set true if path should be skipped, otherwise false
1415  *
1416  * Skip predicate for tar extraction (archive to server) only.
1417  */
1418 static NTSTATUS tar_extract_skip_path(struct tar *t,
1419                                       struct archive_entry *entry,
1420                                       bool *_skip)
1421 {
1422         const char *fullpath = archive_entry_pathname(entry);
1423         bool in = true;
1424
1425         if (t->path_list_size <= 0) {
1426                 *_skip = false;
1427                 return NT_STATUS_OK;
1428         }
1429
1430         if (t->mode.regex) {
1431                 in = mask_match_list(fullpath, t->path_list, t->path_list_size, true);
1432         } else {
1433                 NTSTATUS status = tar_path_in_list(t, fullpath, false, &in);
1434                 if (!NT_STATUS_IS_OK(status)) {
1435                         return status;
1436                 }
1437         }
1438
1439         if (t->mode.selection == TAR_EXCLUDE) {
1440                 *_skip = in;
1441         } else {
1442                 *_skip = !in;
1443         }
1444
1445         return NT_STATUS_OK;
1446 }
1447
1448 /**
1449  * tar_create_skip_path - check if @fullpath shoud be skipped
1450  * @fullpath: full remote path of the current file
1451  * @finfo: remote file attributes
1452  * @_skip: returned skip not
1453  *
1454  * Skip predicate for tar creation (server to archive) only.
1455  */
1456 static NTSTATUS tar_create_skip_path(struct tar *t,
1457                                      const char *fullpath,
1458                                      const struct file_info *finfo,
1459                                      bool *_skip)
1460 {
1461         /* syntaxic sugar */
1462         const mode_t mode = finfo->mode;
1463         const bool isdir = mode & FILE_ATTRIBUTE_DIRECTORY;
1464         const bool exclude = t->mode.selection == TAR_EXCLUDE;
1465         bool in = true;
1466
1467         if (!isdir) {
1468
1469                 /* 1. if we don't want X and we have X, skip */
1470                 if (!t->mode.system && (mode & FILE_ATTRIBUTE_SYSTEM)) {
1471                         *_skip = true;
1472                         return NT_STATUS_OK;
1473                 }
1474
1475                 if (!t->mode.hidden && (mode & FILE_ATTRIBUTE_HIDDEN)) {
1476                         *_skip = true;
1477                         return NT_STATUS_OK;
1478                 }
1479
1480                 /* 2. if we only want archive and it's not, skip */
1481
1482                 if (t->mode.incremental && !(mode & FILE_ATTRIBUTE_ARCHIVE)) {
1483                         *_skip = true;
1484                         return NT_STATUS_OK;
1485                 }
1486         }
1487
1488         /* 3. is it in the selection list? */
1489
1490         /*
1491          * tar_create_from_list() use the include list as a starting
1492          * point, no need to check
1493          */
1494         if (!exclude) {
1495                 *_skip = false;
1496                 return NT_STATUS_OK;
1497         }
1498
1499         /* we are now in exclude mode */
1500
1501         /* no matter the selection, no list => include everything */
1502         if (t->path_list_size <= 0) {
1503                 *_skip = false;
1504                 return NT_STATUS_OK;
1505         }
1506
1507         if (t->mode.regex) {
1508                 in = mask_match_list(fullpath, t->path_list, t->path_list_size, true);
1509         } else {
1510                 bool reverse = isdir && !exclude;
1511                 NTSTATUS status = tar_path_in_list(t, fullpath, reverse, &in);
1512                 if (!NT_STATUS_IS_OK(status)) {
1513                         return status;
1514                 }
1515         }
1516         *_skip = in;
1517
1518         return NT_STATUS_OK;
1519 }
1520
1521 /**
1522  * tar_to_process - return true if @t is ready to be processed
1523  *
1524  * @t is ready if it properly parsed command line arguments.
1525  */
1526 bool tar_to_process(struct tar *t)
1527 {
1528         if (t == NULL) {
1529                 DBG_WARNING("Invalid tar context\n");
1530                 return false;
1531         }
1532         return t->to_process;
1533 }
1534
1535 /**
1536  * skip_useless_char_in_path - skip leading slashes/dots
1537  *
1538  * Skip leading slashes, backslashes and dot-slashes.
1539  */
1540 static const char* skip_useless_char_in_path(const char *p)
1541 {
1542         while (p) {
1543                 if (*p == '/' || *p == '\\') {
1544                         p++;
1545                 }
1546                 else if (p[0] == '.' && (p[1] == '/' || p[1] == '\\')) {
1547                         p += 2;
1548                 }
1549                 else
1550                         return p;
1551         }
1552         return p;
1553 }
1554
1555 /**
1556  * is_subpath - check if the path @sub is a subpath of @full.
1557  * @sub: path to test
1558  * @full: container path
1559  * @_subpath_match: set true if @sub is a subpath of @full, otherwise false
1560  *
1561  * String comparaison is case-insensitive.
1562  */
1563 static NTSTATUS is_subpath(const char *sub, const char *full,
1564                            bool *_subpath_match)
1565 {
1566         NTSTATUS status = NT_STATUS_OK;
1567         int len = 0;
1568         char *f, *s;
1569         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
1570         if (tmp_ctx == NULL) {
1571                 status = NT_STATUS_NO_MEMORY;
1572                 goto out;
1573         }
1574
1575         f = strlower_talloc(tmp_ctx, full);
1576         if (f == NULL) {
1577                 status = NT_STATUS_NO_MEMORY;
1578                 goto out_ctx_free;
1579         }
1580         string_replace(f, '\\', '/');
1581         s = strlower_talloc(tmp_ctx, sub);
1582         if (s == NULL) {
1583                 status = NT_STATUS_NO_MEMORY;
1584                 goto out_ctx_free;
1585         }
1586         string_replace(s, '\\', '/');
1587
1588         /* find the point where sub and full diverge */
1589         while ((*f != '\0') && (*s != '\0') && (*f == *s)) {
1590                 f++;
1591                 s++;
1592                 len++;
1593         }
1594
1595         if ((*f == '\0') && (*s == '\0')) {
1596                 *_subpath_match = true; /* sub and full match */
1597                 goto out_ctx_free;
1598         }
1599
1600         if ((*f == '\0') && (len > 0) && (*(f - 1) == '/')) {
1601                 /* sub diverges from full at path separator */
1602                 *_subpath_match = true;
1603                 goto out_ctx_free;
1604         }
1605
1606         if ((*s == '\0') && (strcmp(f, "/") == 0)) {
1607                 /* full diverges from sub with trailing slash only */
1608                 *_subpath_match = true;
1609                 goto out_ctx_free;
1610         }
1611
1612         if ((*s == '/') && (*f == '\0')) {
1613                 /* sub diverges from full with extra path component */
1614                 *_subpath_match = true;
1615                 goto out_ctx_free;
1616         }
1617         *_subpath_match = false;
1618
1619 out_ctx_free:
1620         talloc_free(tmp_ctx);
1621 out:
1622         return status;
1623 }
1624
1625
1626 /**
1627  * make_remote_path - recursively make remote dirs
1628  * @full_path: full hierarchy to create
1629  *
1630  * Create @full_path and each parent directories as needed.
1631  */
1632 static int make_remote_path(const char *full_path)
1633 {
1634         extern struct cli_state *cli;
1635         char *path;
1636         char *subpath;
1637         char *state;
1638         char *last_backslash;
1639         char *p;
1640         int len;
1641         NTSTATUS status;
1642         int err = 0;
1643         TALLOC_CTX *ctx = talloc_new(NULL);
1644         if (ctx == NULL) {
1645                 return 1;
1646         }
1647
1648         subpath = talloc_strdup(ctx, full_path);
1649         if (subpath == NULL) {
1650                 err = 1;
1651                 goto out;
1652         }
1653         path = talloc_strdup(ctx, full_path);
1654         if (path == NULL) {
1655                 err = 1;
1656                 goto out;
1657         }
1658         len = talloc_get_size(path) - 1;
1659
1660         last_backslash = strrchr_m(path, '\\');
1661         if (last_backslash == NULL) {
1662                 goto out;
1663         }
1664
1665         *last_backslash = 0;
1666
1667         subpath[0] = 0;
1668         p = strtok_r(path, "\\", &state);
1669
1670         while (p != NULL) {
1671                 strlcat(subpath, p, len);
1672                 status = cli_chkpath(cli, subpath);
1673                 if (!NT_STATUS_IS_OK(status)) {
1674                         status = cli_mkdir(cli, subpath);
1675                         if (!NT_STATUS_IS_OK(status)) {
1676                                 d_printf("Can't mkdir %s: %s\n", subpath, nt_errstr(status));
1677                                 err = 1;
1678                                 goto out;
1679                         }
1680                         DBG(3, ("mkdir %s\n", subpath));
1681                 }
1682
1683                 strlcat(subpath, "\\", len);
1684                 p = strtok_r(NULL, "/\\", &state);
1685
1686         }
1687
1688 out:
1689         talloc_free(ctx);
1690         return err;
1691 }
1692
1693 /**
1694  * tar_reset_mem_context - reset talloc context associated with @t
1695  *
1696  * At the start of the program the context is NULL so a new one is
1697  * allocated. On the following runs (interactive session only), simply
1698  * free the children.
1699  */
1700 static TALLOC_CTX *tar_reset_mem_context(struct tar *t)
1701 {
1702         tar_free_mem_context(t);
1703         t->talloc_ctx = talloc_new(NULL);
1704         return t->talloc_ctx;
1705 }
1706
1707 /**
1708  * tar_free_mem_context - free talloc context associated with @t
1709  */
1710 static void tar_free_mem_context(struct tar *t)
1711 {
1712         if (t->talloc_ctx) {
1713                 talloc_free(t->talloc_ctx);
1714                 t->talloc_ctx = NULL;
1715                 t->path_list_size = 0;
1716                 t->path_list = NULL;
1717                 t->tar_path = NULL;
1718         }
1719 }
1720
1721 #define XSET(v)      [v] = #v
1722 #define XTABLE(v, t) DBG(2, ("DUMP:%-20.20s = %s\n", #v, t[v]))
1723 #define XBOOL(v)     DBG(2, ("DUMP:%-20.20s = %d\n", #v, v ? 1 : 0))
1724 #define XSTR(v)      DBG(2, ("DUMP:%-20.20s = %s\n", #v, v ? v : "NULL"))
1725 #define XINT(v)      DBG(2, ("DUMP:%-20.20s = %d\n", #v, v))
1726 #define XUINT64(v)   DBG(2, ("DUMP:%-20.20s = %" PRIu64  "\n", #v, v))
1727
1728 /**
1729  * tar_dump - dump tar structure on stdout
1730  */
1731 static void tar_dump(struct tar *t)
1732 {
1733         int i;
1734         const char* op[] = {
1735                 XSET(TAR_NO_OPERATION),
1736                 XSET(TAR_CREATE),
1737                 XSET(TAR_EXTRACT),
1738         };
1739
1740         const char* sel[] = {
1741                 XSET(TAR_NO_SELECTION),
1742                 XSET(TAR_INCLUDE),
1743                 XSET(TAR_EXCLUDE),
1744         };
1745
1746         XBOOL(t->to_process);
1747         XTABLE(t->mode.operation, op);
1748         XTABLE(t->mode.selection, sel);
1749         XINT(t->mode.blocksize);
1750         XBOOL(t->mode.hidden);
1751         XBOOL(t->mode.system);
1752         XBOOL(t->mode.incremental);
1753         XBOOL(t->mode.reset);
1754         XBOOL(t->mode.dry);
1755         XBOOL(t->mode.verbose);
1756         XUINT64(t->total_size);
1757         XSTR(t->tar_path);
1758         XINT(t->path_list_size);
1759
1760         for (i = 0; t->path_list && t->path_list[i]; i++) {
1761                 DBG(2, ("DUMP: t->path_list[%2d] = %s\n", i, t->path_list[i]));
1762         }
1763
1764         DBG(2, ("DUMP:t->path_list @ %p (%d elem)\n", t->path_list, i));
1765 }
1766 #undef XSET
1767 #undef XTABLE
1768 #undef XBOOL
1769 #undef XSTR
1770 #undef XINT
1771
1772 /**
1773  * max_token - return upper limit for the number of token in @str
1774  *
1775  * The result is not exact, the actual number of token might be less
1776  * than what is returned.
1777  */
1778 static int max_token(const char *str)
1779 {
1780         const char *s;
1781         int nb = 0;
1782
1783         if (str == NULL) {
1784                 return 0;
1785         }
1786
1787         s = str;
1788         while (s[0] != '\0') {
1789                 if (isspace((int)s[0])) {
1790                         nb++;
1791                 }
1792                 s++;
1793         }
1794
1795         nb++;
1796
1797         return nb;
1798 }
1799
1800 /**
1801  * fix_unix_path - convert @path to a DOS path
1802  * @path: path to convert
1803  * @removeprefix: if true, remove leading ./ or /.
1804  */
1805 static char *fix_unix_path(char *path, bool do_remove_prefix)
1806 {
1807         char *from = path, *to = path;
1808
1809         if (path == NULL || path[0] == '\0') {
1810                 return path;
1811         }
1812
1813         /* remove prefix:
1814          * ./path => path
1815          *  /path => path
1816          */
1817         if (do_remove_prefix) {
1818                 /* /path */
1819                 if (path[0] == '/' || path[0] == '\\') {
1820                         from += 1;
1821                 }
1822
1823                 /* ./path */
1824                 if (path[1] != '\0' && path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
1825                         from += 2;
1826                 }
1827         }
1828
1829         /* replace / with \ */
1830         while (from[0] != '\0') {
1831                 if (from[0] == '/') {
1832                         to[0] = '\\';
1833                 } else {
1834                         to[0] = from[0];
1835                 }
1836
1837                 from++;
1838                 to++;
1839         }
1840         to[0] = '\0';
1841
1842         return path;
1843 }
1844
1845 /**
1846  * path_base_name - return @path basename
1847  *
1848  * If @path doesn't contain any directory separator return NULL.
1849  */
1850 static NTSTATUS path_base_name(TALLOC_CTX *ctx, const char *path, char **_base)
1851 {
1852         char *base = NULL;
1853         int last = -1;
1854         int i;
1855
1856         for (i = 0; path[i]; i++) {
1857                 if (path[i] == '\\' || path[i] == '/') {
1858                         last = i;
1859                 }
1860         }
1861
1862         if (last >= 0) {
1863                 base = talloc_strdup(ctx, path);
1864                 if (base == NULL) {
1865                         return NT_STATUS_NO_MEMORY;
1866                 }
1867
1868                 base[last] = 0;
1869         }
1870
1871         *_base = base;
1872         return NT_STATUS_OK;
1873 }
1874
1875 #else
1876
1877 #define NOT_IMPLEMENTED DEBUG(0, ("tar mode not compiled. build used --without-libarchive\n"))
1878
1879 int cmd_block(void)
1880 {
1881         NOT_IMPLEMENTED;
1882         return 1;
1883 }
1884
1885 int cmd_tarmode(void)
1886 {
1887         NOT_IMPLEMENTED;
1888         return 1;
1889 }
1890
1891 int cmd_tar(void)
1892 {
1893         NOT_IMPLEMENTED;
1894         return 1;
1895 }
1896
1897 int tar_process(struct tar* tar)
1898 {
1899         NOT_IMPLEMENTED;
1900         return 1;
1901 }
1902
1903 int tar_parse_args(struct tar *tar, const char *flag, const char **val, int valsize)
1904 {
1905         NOT_IMPLEMENTED;
1906         return 1;
1907 }
1908
1909 bool tar_to_process(struct tar *tar)
1910 {
1911         return false;
1912 }
1913
1914 struct tar *tar_get_ctx()
1915 {
1916         return NULL;
1917 }
1918
1919 #endif