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