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