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

Generated by: LCOV version 1.14