LCOV - code coverage report
Current view: top level - source3/client - clitar.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 563 807 69.8 %
Date: 2024-05-31 13:13:24 Functions: 27 29 93.1 %

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

Generated by: LCOV version 1.14