Ignore:
Timestamp:
Nov 24, 2016, 1:14:11 PM (9 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: update vendor to version 4.4.3

File:
1 edited

Legend:

Unmodified
Added
Removed
  • vendor/current/source3/client/clitar.c

    r746 r988  
    11/*
    22   Unix SMB/CIFS implementation.
    3    Tar Extensions
    4    Copyright (C) Ricky Poulten 1995-1998
    5    Copyright (C) Richard Sharpe 1998
     3   Tar backup command extension
     4   Copyright (C) Aurélien Aptel 2013
    65
    76   This program is free software; you can redistribute it and/or modify
     
    1817   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    1918*/
    20 /* The following changes developed by Richard Sharpe for Canon Information
    21    Systems Research Australia (CISRA)
    22 
    23    1. Restore can now restore files with long file names
    24    2. Save now saves directory information so that we can restore
    25       directory creation times
    26    3. tar now accepts both UNIX path names and DOS path names. I prefer
    27       those lovely /'s to those UGLY \'s :-)
    28    4. the files to exclude can be specified as a regular expression by adding
    29       an r flag to the other tar flags. Eg:
    30 
    31          -TcrX file.tar "*.(obj|exe)"
    32 
    33       will skip all .obj and .exe files
    34 */
    35 
     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 */
    3668
    3769#include "includes.h"
    3870#include "system/filesys.h"
    39 #include "clitar.h"
    4071#include "client/client_proto.h"
     72#include "client/clitar_proto.h"
    4173#include "libsmb/libsmb.h"
    4274
    43 static int clipfind(char **aret, int ret, char *tok);
    44 
    45 typedef struct file_info_struct file_info2;
    46 
    47 struct file_info_struct {
    48         SMB_OFF_T size;
    49         uint16 mode;
    50         uid_t uid;
    51         gid_t gid;
    52         /* These times are normally kept in GMT */
    53         struct timespec mtime_ts;
    54         struct timespec atime_ts;
    55         struct timespec ctime_ts;
    56         char *name;     /* This is dynamically allocated */
    57         file_info2 *next, *prev;  /* Used in the stack ... */
     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
     112enum tar_operation {
     113        TAR_NO_OPERATION,
     114        TAR_CREATE,    /* c flag */
     115        TAR_EXTRACT,   /* x flag */
    58116};
    59117
    60 typedef struct {
    61         file_info2 *top;
    62         int items;
    63 } stack;
    64 
    65 #define SEPARATORS " \t\n\r"
    66 extern time_t newer_than;
    67 extern struct cli_state *cli;
    68 
    69 /* These defines are for the do_setrattr routine, to indicate
    70  * setting and reseting of file attributes in the function call */
    71 #define ATTRSET 1
    72 #define ATTRRESET 0
    73 
    74 static uint16 attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
    75 
    76 #ifndef CLIENT_TIMEOUT
    77 #define CLIENT_TIMEOUT (30*1000)
    78 #endif
    79 
    80 static char *tarbuf, *buffer_p;
    81 static int tp, ntarf, tbufsiz;
    82 static double ttarf;
    83 /* Incremental mode */
    84 static bool tar_inc=False;
    85 /* Reset archive bit */
    86 static bool tar_reset=False;
    87 /* Include / exclude mode (true=include, false=exclude) */
    88 static bool tar_excl=True;
    89 /* use regular expressions for search on file names */
    90 static bool tar_re_search=False;
    91 /* Do not dump anything, just calculate sizes */
    92 static bool dry_run=False;
    93 /* Dump files with System attribute */
    94 static bool tar_system=True;
    95 /* Dump files with Hidden attribute */
    96 static bool tar_hidden=True;
    97 /* Be noisy - make a catalogue */
    98 static bool tar_noisy=True;
    99 static bool tar_real_noisy=False;  /* Don't want to be really noisy by default */
    100 
    101 char tar_type='\0';
    102 static char **cliplist=NULL;
    103 static int clipn=0;
    104 static bool must_free_cliplist = False;
    105 extern const char *cmd_ptr;
    106 
    107 extern bool lowercase;
    108 extern uint16 cnum;
    109 extern bool readbraw_supported;
    110 extern int max_xmit;
    111 extern int get_total_time_ms;
    112 extern int get_total_size;
    113 
    114 static int blocksize=20;
    115 static int tarhandle;
    116 
    117 static void writetarheader(int f,  const char *aname, uint64_t size, time_t mtime,
    118                            const char *amode, unsigned char ftype);
    119 static NTSTATUS do_atar(const char *rname_in, char *lname,
    120                     struct file_info *finfo1);
    121 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
    122                    const char *dir);
    123 static void oct_it(uint64_t value, int ndgs, char *p);
    124 static void fixtarname(char *tptr, const char *fp, size_t l);
    125 static int dotarbuf(int f, char *b, int n);
    126 static void dozerobuf(int f, int n);
    127 static void dotareof(int f);
    128 static void initarbuf(void);
    129 
    130 /* restore functions */
    131 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
    132 static long unoct(char *p, int ndgs);
    133 static void do_tarput(void);
    134 static void unfixtarname(char *tptr, char *fp, int l, bool first);
    135 
    136 /*
    137  * tar specific utitlities
    138  */
    139 
    140 /*******************************************************************
    141 Create  a string of size size+1 (for the null)
    142 *******************************************************************/
    143 
    144 static char *string_create_s(int size)
    145 {
    146         char *tmp;
    147 
    148         tmp = (char *)SMB_MALLOC(size+1);
    149 
    150         if (tmp == NULL) {
    151                 DEBUG(0, ("Out of memory in string_create_s\n"));
    152         }
    153 
    154         return(tmp);
    155 }
    156 
    157 /****************************************************************************
    158 Write a tar header to buffer
    159 ****************************************************************************/
    160 
    161 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
    162                            const char *amode, unsigned char ftype)
    163 {
    164         union hblock hb;
    165         int i, chk, l;
    166         char *jp;
    167 
    168         DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
    169 
    170         memset(hb.dummy, 0, sizeof(hb.dummy));
    171 
    172         l=strlen(aname);
    173         /* We will be prepending a '.' in fixtarheader so use +2 to
    174          * take care of the . and terminating zero. JRA.
    175          */
    176         if (l+2 >= NAMSIZ) {
    177                 /* write a GNU tar style long header */
    178                 char *b;
    179                 b = (char *)SMB_MALLOC(l+TBLOCK+100);
    180                 if (!b) {
    181                         DEBUG(0,("out of memory\n"));
    182                         exit(1);
    183                 }
    184                 writetarheader(f, "/./@LongLink", l+2, 0, "     0 \0", 'L');
    185                 memset(b, 0, l+TBLOCK+100);
    186                 fixtarname(b, aname, l+2);
    187                 i = strlen(b)+1;
    188                 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
    189                 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
    190                 SAFE_FREE(b);
    191         }
    192 
    193         fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
    194 
    195         if (lowercase)
    196                 strlower_m(hb.dbuf.name);
    197 
    198         /* write out a "standard" tar format header */
    199 
    200         hb.dbuf.name[NAMSIZ-1]='\0';
    201         safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
    202         oct_it((uint64_t)0, 8, hb.dbuf.uid);
    203         oct_it((uint64_t)0, 8, hb.dbuf.gid);
    204         oct_it((uint64_t) size, 13, hb.dbuf.size);
    205         if (size > (uint64_t)077777777777LL) {
    206                 /* This is a non-POSIX compatible extention to store files
    207                         greater than 8GB. */
    208 
    209                 memset(hb.dbuf.size, 0, 4);
    210                 hb.dbuf.size[0]=128;
    211                 for (i = 8; i; i--) {
    212                         hb.dbuf.size[i+3] = size & 0xff;
    213                         size >>= 8;
    214                 }
    215         }
    216         oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
    217         memcpy(hb.dbuf.chksum, "        ", sizeof(hb.dbuf.chksum));
    218         memset(hb.dbuf.linkname, 0, NAMSIZ);
    219         hb.dbuf.linkflag=ftype;
    220 
    221         for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
    222                 chk+=(0xFF & *jp++);
    223 
    224         oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
    225         hb.dbuf.chksum[6] = '\0';
    226 
    227         (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
    228 }
    229 
    230 /****************************************************************************
    231 Read a tar header into a hblock structure, and validate
    232 ***************************************************************************/
    233 
    234 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
    235 {
    236         long chk, fchk;
     118enum tar_selection {
     119        TAR_NO_SELECTION,
     120        TAR_INCLUDE,       /* I and F flag, default */
     121        TAR_EXCLUDE,       /* X flag */
     122};
     123
     124struct tar {
     125        TALLOC_CTX *talloc_ctx;
     126
     127        /* in state that needs/can be processed? */
     128        bool to_process;
     129
     130        /* flags */
     131        struct tar_mode {
     132                enum tar_operation operation; /* create, extract */
     133                enum tar_selection selection; /* include, exclude */
     134                int blocksize;    /* size in TAR_BLOCK_UNIT of a tar file block */
     135                bool hidden;      /* backup hidden file? */
     136                bool system;      /* backup system file? */
     137                bool incremental; /* backup _only_ archived file? */
     138                bool reset;       /* unset archive bit? */
     139                bool dry;         /* don't write tar file? */
     140                bool regex;       /* XXX: never actually using regex... */
     141                bool verbose;     /* XXX: ignored */
     142        } mode;
     143
     144        /* nb of bytes received */
     145        uint64_t total_size;
     146
     147        /* path to tar archive name */
     148        char *tar_path;
     149
     150        /* list of path to include or exclude */
     151        char **path_list;
     152        int path_list_size;
     153
     154        /* archive handle */
     155        struct archive *archive;
     156};
     157
     158/**
     159 * Global context imported in client.c when needed.
     160 *
     161 * Default options.
     162 */
     163struct tar tar_ctx = {
     164        .mode.selection   = TAR_INCLUDE,
     165        .mode.blocksize   = TAR_DEFAULT_BLOCK_SIZE,
     166        .mode.hidden      = true,
     167        .mode.system      = true,
     168        .mode.incremental = false,
     169        .mode.reset       = false,
     170        .mode.dry         = false,
     171        .mode.regex       = false,
     172        .mode.verbose     = false,
     173};
     174
     175/* tar, local function */
     176static int tar_create(struct tar* t);
     177static int tar_create_from_list(struct tar *t);
     178static int tar_extract(struct tar *t);
     179static int tar_read_inclusion_file(struct tar *t, const char* filename);
     180static int tar_send_file(struct tar *t, struct archive_entry *entry);
     181static int tar_set_blocksize(struct tar *t, int size);
     182static int tar_set_newer_than(struct tar *t, const char *filename);
     183static NTSTATUS tar_add_selection_path(struct tar *t, const char *path);
     184static void tar_dump(struct tar *t);
     185static NTSTATUS tar_extract_skip_path(struct tar *t,
     186                                      struct archive_entry *entry,
     187                                      bool *_skip);
     188static TALLOC_CTX *tar_reset_mem_context(struct tar *t);
     189static void tar_free_mem_context(struct tar *t);
     190static NTSTATUS tar_create_skip_path(struct tar *t,
     191                                     const char *fullpath,
     192                                     const struct file_info *finfo,
     193                                     bool *_skip);
     194
     195static NTSTATUS tar_path_in_list(struct tar *t, const char *path,
     196                                 bool reverse, bool *_is_in_list);
     197
     198static int tar_get_file(struct tar *t,
     199                        const char *full_dos_path,
     200                        struct file_info *finfo);
     201
     202static NTSTATUS get_file_callback(struct cli_state *cli,
     203                                  struct file_info *finfo,
     204                                  const char *dir);
     205
     206/* utilities */
     207static char *fix_unix_path(char *path, bool removeprefix);
     208static NTSTATUS path_base_name(TALLOC_CTX *ctx, const char *path, char **_base);
     209static const char* skip_useless_char_in_path(const char *p);
     210static int make_remote_path(const char *full_path);
     211static int max_token (const char *str);
     212static NTSTATUS is_subpath(const char *sub, const char *full,
     213                           bool *_subpath_match);
     214
     215/**
     216 * tar_get_ctx - retrieve global tar context handle
     217 */
     218struct tar *tar_get_ctx()
     219{
     220        return &tar_ctx;
     221}
     222
     223/**
     224 * cmd_block - interactive command to change tar blocksize
     225 *
     226 * Read a size from the client command line and update the current
     227 * blocksize.
     228 */
     229int cmd_block(void)
     230{
     231        /* XXX: from client.c */
     232        const extern char *cmd_ptr;
     233        char *buf;
     234        int err = 0;
     235        bool ok;
     236        TALLOC_CTX *ctx = talloc_new(NULL);
     237        if (ctx == NULL) {
     238                return 1;
     239        }
     240
     241        ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
     242        if (!ok) {
     243                DBG(0, ("blocksize <n>\n"));
     244                err = 1;
     245                goto out;
     246        }
     247
     248        ok = tar_set_blocksize(&tar_ctx, atoi(buf));
     249        if (ok) {
     250                DBG(0, ("invalid blocksize\n"));
     251                err = 1;
     252                goto out;
     253        }
     254
     255        DBG(2, ("blocksize is now %d\n", tar_ctx.mode.blocksize));
     256
     257out:
     258        talloc_free(ctx);
     259        return err;
     260}
     261
     262/**
     263 * cmd_tarmode - interactive command to change tar behaviour
     264 *
     265 * Read one or more modes from the client command line and update the
     266 * current tar mode.
     267 */
     268int cmd_tarmode(void)
     269{
     270        const extern char *cmd_ptr;
     271        char *buf;
    237272        int i;
    238         char *jp;
    239 
    240         /*
    241          * read in a "standard" tar format header - we're not that interested
    242          * in that many fields, though
    243          */
    244 
    245         /* check the checksum */
    246         for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
    247                 chk+=(0xFF & *jp++);
    248 
    249         if (chk == 0)
    250                 return chk;
    251 
    252         /* compensate for blanks in chksum header */
    253         for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
    254                 chk-=(0xFF & *jp++);
    255 
    256         chk += ' ' * sizeof(hb->dbuf.chksum);
    257 
    258         fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
    259 
    260         DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
    261                         chk, fchk, hb->dbuf.chksum));
    262 
    263         if (fchk != chk) {
    264                 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
    265                 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
    266                 return -1;
    267         }
    268 
    269         if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
    270                 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
    271                 return(-1);
    272         }
    273 
    274         safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
    275 
    276         /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
    277         unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
    278                 strlen(hb->dbuf.name) + 1, True);
    279 
    280         /* can't handle some links at present */
    281         if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
    282                 if (hb->dbuf.linkflag == 0) {
    283                         DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
    284                                 finfo->name));
    285                 } else {
    286                         if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
    287                                 /* Do nothing here at the moment. do_tarput will handle this
    288                                         as long as the longlink gets back to it, as it has to advance
    289                                         the buffer pointer, etc */
    290                         } else {
    291                                 DEBUG(0, ("this tar file appears to contain some kind \
    292 of link other than a GNUtar Longlink - ignoring\n"));
    293                                 return -2;
    294                         }
    295                 }
    296         }
    297 
    298         if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
    299                                 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
    300                 finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
    301         } else {
    302                 finfo->mode=0; /* we don't care about mode at the moment, we'll
    303                                 * just make it a regular file */
    304         }
    305 
    306         /*
    307          * Bug fix by richard@sj.co.uk
    308          *
    309          * REC: restore times correctly (as does tar)
    310          * We only get the modification time of the file; set the creation time
    311          * from the mod. time, and the access time to current time
    312          */
    313         finfo->mtime_ts = finfo->ctime_ts =
    314                 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
    315         finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
    316         if ((hb->dbuf.size[0] & 0xff) == 0x80) {
    317                 /* This is a non-POSIX compatible extention to extract files
    318                         greater than 8GB. */
    319                 finfo->size = 0;
    320                 for (i = 0; i < 8; i++) {
    321                         finfo->size <<= 8;
    322                         finfo->size |= hb->dbuf.size[i+4] & 0xff;
    323                 }
    324         } else {
    325                 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
    326         }
    327 
    328         return True;
    329 }
    330 
    331 /****************************************************************************
    332 Write out the tar buffer to tape or wherever
    333 ****************************************************************************/
    334 
    335 static int dotarbuf(int f, char *b, int n)
    336 {
    337         int fail=1, writ=n;
    338 
    339         if (dry_run) {
    340                 return writ;
    341         }
    342         /* This routine and the next one should be the only ones that do write()s */
    343         if (tp + n >= tbufsiz) {
    344                 int diff;
    345 
    346                 diff=tbufsiz-tp;
    347                 memcpy(tarbuf + tp, b, diff);
    348                 fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
    349                 n-=diff;
    350                 b+=diff;
    351                 tp=0;
    352 
    353                 while (n >= tbufsiz) {
    354                         fail=fail && (1 + sys_write(f, b, tbufsiz));
    355                         n-=tbufsiz;
    356                         b+=tbufsiz;
    357                 }
    358         }
    359 
    360         if (n>0) {
    361                 memcpy(tarbuf+tp, b, n);
    362                 tp+=n;
    363         }
    364 
    365         return(fail ? writ : 0);
    366 }
    367 
    368 /****************************************************************************
    369 Write zeros to buffer / tape
    370 ****************************************************************************/
    371 
    372 static void dozerobuf(int f, int n)
    373 {
    374         /* short routine just to write out n zeros to buffer -
    375          * used to round files to nearest block
    376          * and to do tar EOFs */
    377 
    378         if (dry_run)
    379                 return;
    380 
    381         if (n+tp >= tbufsiz) {
    382                 memset(tarbuf+tp, 0, tbufsiz-tp);
    383                 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
    384                         DEBUG(0, ("dozerobuf: sys_write fail\n"));
    385                         return;
    386                 }
    387                 memset(tarbuf, 0, (tp+=n-tbufsiz));
    388         } else {
    389                 memset(tarbuf+tp, 0, n);
    390                 tp+=n;
    391         }
    392 }
    393 
    394 /****************************************************************************
    395 Malloc tape buffer
    396 ****************************************************************************/
    397 
    398 static void initarbuf(void)
    399 {
    400         /* initialize tar buffer */
    401         tbufsiz=blocksize*TBLOCK;
    402         tarbuf=(char *)SMB_MALLOC(tbufsiz);      /* FIXME: We might not get the buffer */
    403 
    404         /* reset tar buffer pointer and tar file counter and total dumped */
    405         tp=0; ntarf=0; ttarf=0;
    406 }
    407 
    408 /****************************************************************************
    409 Write two zero blocks at end of file
    410 ****************************************************************************/
    411 
    412 static void dotareof(int f)
    413 {
    414         SMB_STRUCT_STAT stbuf;
    415         /* Two zero blocks at end of file, write out full buffer */
    416 
    417         if (dry_run)
    418                 return;
    419 
    420         (void) dozerobuf(f, TBLOCK);
    421         (void) dozerobuf(f, TBLOCK);
    422 
    423         if (sys_fstat(f, &stbuf, false) == -1) {
    424                 DEBUG(0, ("Couldn't stat file handle\n"));
    425                 return;
    426         }
    427 
    428         /* Could be a pipe, in which case S_ISREG should fail,
    429                 * and we should write out at full size */
    430         if (tp > 0) {
    431                 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
    432                 if (sys_write(f, tarbuf, towrite) != towrite) {
    433                         DEBUG(0,("dotareof: sys_write fail\n"));
    434                 }
    435         }
    436 }
    437 
    438 /****************************************************************************
    439 (Un)mangle DOS pathname, make nonabsolute
    440 ****************************************************************************/
    441 
    442 static void fixtarname(char *tptr, const char *fp, size_t l)
    443 {
    444         /* add a '.' to start of file name, convert from ugly dos \'s in path
    445          * to lovely unix /'s :-} */
    446         *tptr++='.';
    447         l--;
    448 
    449         StrnCpy(tptr, fp, l-1);
    450         string_replace(tptr, '\\', '/');
    451 }
    452 
    453 /****************************************************************************
    454 Convert from decimal to octal string
    455 ****************************************************************************/
    456 
    457 static void oct_it (uint64_t value, int ndgs, char *p)
    458 {
    459         /* Converts long to octal string, pads with leading zeros */
    460 
    461         /* skip final null, but do final space */
    462         --ndgs;
    463         p[--ndgs] = ' ';
    464 
    465         /* Loop does at least one digit */
    466         do {
    467                 p[--ndgs] = '0' + (char) (value & 7);
    468                 value >>= 3;
    469         } while (ndgs > 0 && value != 0);
    470 
    471         /* Do leading zeros */
    472         while (ndgs > 0)
    473                 p[--ndgs] = '0';
    474 }
    475 
    476 /****************************************************************************
    477 Convert from octal string to long
    478 ***************************************************************************/
    479 
    480 static long unoct(char *p, int ndgs)
    481 {
    482         long value=0;
    483         /* Converts octal string to long, ignoring any non-digit */
    484 
    485         while (--ndgs) {
    486                 if (isdigit((int)*p))
    487                         value = (value << 3) | (long) (*p - '0');
    488 
    489                 p++;
    490         }
    491 
    492         return value;
    493 }
    494 
    495 /****************************************************************************
    496 Compare two strings in a slash insensitive way, allowing s1 to match s2
    497 if s1 is an "initial" string (up to directory marker).  Thus, if s2 is
    498 a file in any subdirectory of s1, declare a match.
    499 ***************************************************************************/
    500 
    501 static int strslashcmp(char *s1, char *s2)
    502 {
    503         char *s1_0=s1;
    504 
    505         while(*s1 && *s2 && (*s1 == *s2 || tolower_m(*s1) == tolower_m(*s2) ||
    506                                 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
    507                 s1++; s2++;
    508         }
    509 
    510         /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
    511                 string of s2.
    512         */
    513         if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
    514                 return 0;
    515 
    516         /* ignore trailing slash on s1 */
    517         if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
    518                 return 0;
    519 
    520         /* check for s1 is an "initial" string of s2 */
    521         if ((*s2 == '/' || *s2 == '\\') && !*s1)
    522                 return 0;
    523 
    524         return *s1-*s2;
    525 }
    526 
    527 /****************************************************************************
    528 Ensure a remote path exists (make if necessary)
    529 ***************************************************************************/
    530 
    531 static bool ensurepath(const char *fname)
    532 {
    533         /* *must* be called with buffer ready malloc'ed */
    534         /* ensures path exists */
    535 
    536         char *partpath, *ffname;
    537         const char *p=fname;
    538         char *basehack;
    539         char *saveptr;
    540 
    541         DEBUG(5, ( "Ensurepath called with: %s\n", fname));
    542 
    543         partpath = string_create_s(strlen(fname));
    544         ffname = string_create_s(strlen(fname));
    545 
    546         if ((partpath == NULL) || (ffname == NULL)){
    547                 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
    548                 SAFE_FREE(partpath);
    549                 SAFE_FREE(ffname);
    550                 return(False);
    551         }
    552 
    553         *partpath = 0;
    554 
    555         /* fname copied to ffname so can strtok_r */
    556 
    557         safe_strcpy(ffname, fname, strlen(fname));
    558 
    559         /* do a `basename' on ffname, so don't try and make file name directory */
    560         if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
    561                 SAFE_FREE(partpath);
    562                 SAFE_FREE(ffname);
    563                 return True;
    564         } else {
    565                 *basehack='\0';
    566         }
    567 
    568         p=strtok_r(ffname, "\\", &saveptr);
    569 
    570         while (p) {
    571                 safe_strcat(partpath, p, strlen(fname) + 1);
    572 
    573                 if (!NT_STATUS_IS_OK(cli_chkpath(cli, partpath))) {
    574                         if (!NT_STATUS_IS_OK(cli_mkdir(cli, partpath))) {
    575                                 SAFE_FREE(partpath);
    576                                 SAFE_FREE(ffname);
    577                                 DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
    578                                 return False;
    579                         } else {
    580                                 DEBUG(3, ("mkdirhiering %s\n", partpath));
    581                         }
    582                 }
    583 
    584                 safe_strcat(partpath, "\\", strlen(fname) + 1);
    585                 p = strtok_r(NULL, "/\\", &saveptr);
    586         }
    587 
    588         SAFE_FREE(partpath);
    589         SAFE_FREE(ffname);
    590         return True;
    591 }
    592 
    593 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
    594 {
    595         int berr= 0;
    596         int bytestowrite;
    597 
    598         DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
    599         memset(buf, 0, (size_t)bufsize);
    600         while( !berr && padsize > 0 ) {
    601                 bytestowrite= (int)MIN(bufsize, padsize);
    602                 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
    603                 padsize -= bytestowrite;
    604         }
    605 
    606         return berr;
    607 }
    608 
    609 static void do_setrattr(char *name, uint16 attr, int set)
    610 {
    611         uint16 oldattr;
    612 
    613         if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
    614                 return;
    615         }
    616 
    617         if (set == ATTRSET) {
    618                 attr |= oldattr;
    619         } else {
    620                 attr = oldattr & ~attr;
    621         }
    622 
    623         if (!NT_STATUS_IS_OK(cli_setatr(cli, name, attr, 0))) {
    624                 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
    625         }
    626 }
    627 
    628 /****************************************************************************
    629 append one remote file to the tar file
    630 ***************************************************************************/
    631 
    632 static NTSTATUS do_atar(const char *rname_in, char *lname,
    633                     struct file_info *finfo1)
    634 {
    635         uint16_t fnum = (uint16_t)-1;
    636         uint64_t nread=0;
    637         char ftype;
    638         file_info2 finfo;
    639         bool shallitime=True;
    640         char *data = NULL;
    641         int read_size = 65520;
    642         int datalen=0;
    643         char *rname = NULL;
    644         TALLOC_CTX *ctx = talloc_stackframe();
    645         NTSTATUS status = NT_STATUS_OK;
    646         struct timespec tp_start;
    647 
    648         clock_gettime_mono(&tp_start);
    649 
    650         data = SMB_MALLOC_ARRAY(char, read_size);
    651         if (!data) {
    652                 DEBUG(0,("do_atar: out of memory.\n"));
    653                 status = NT_STATUS_NO_MEMORY;
    654                 goto cleanup;
    655         }
    656 
    657         ftype = '0'; /* An ordinary file ... */
    658 
    659         ZERO_STRUCT(finfo);
    660 
    661         finfo.size  = finfo1 -> size;
    662         finfo.mode  = finfo1 -> mode;
    663         finfo.uid   = finfo1 -> uid;
    664         finfo.gid   = finfo1 -> gid;
    665         finfo.mtime_ts = finfo1 -> mtime_ts;
    666         finfo.atime_ts = finfo1 -> atime_ts;
    667         finfo.ctime_ts = finfo1 -> ctime_ts;
    668 
    669         if (dry_run) {
    670                 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
    671                                 (double)finfo.size));
    672                 shallitime=0;
    673                 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
    674                 ntarf++;
    675                 goto cleanup;
    676         }
    677 
    678         rname = clean_name(ctx, rname_in);
    679         if (!rname) {
    680                 status = NT_STATUS_NO_MEMORY;
    681                 goto cleanup;
    682         }
    683 
    684         status = cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum);
    685         if (!NT_STATUS_IS_OK(status)) {
    686                 DEBUG(0,("%s opening remote file %s (%s)\n",
    687                                 cli_errstr(cli),rname, client_get_cur_dir()));
    688                 goto cleanup;
    689         }
    690 
    691         finfo.name = string_create_s(strlen(rname));
    692         if (finfo.name == NULL) {
    693                 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
    694                 status = NT_STATUS_NO_MEMORY;
    695                 goto cleanup;
    696         }
    697 
    698         safe_strcpy(finfo.name,rname, strlen(rname));
    699 
    700         DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
    701 
    702         if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE)) {
    703                 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
    704                 shallitime=0;
    705         } else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM)) {
    706                 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
    707                 shallitime=0;
    708         } else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN)) {
    709                 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
    710                 shallitime=0;
    711         } else {
    712                 bool wrote_tar_header = False;
    713 
    714                 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
    715                         finfo.name, (double)finfo.size, lname));
    716 
    717                 do {
    718 
    719                         DEBUG(3,("nread=%.0f\n",(double)nread));
    720 
    721                         datalen = cli_read(cli, fnum, data, nread, read_size);
    722 
    723                         if (datalen == -1) {
    724                                 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
    725                                 status = cli_nt_error(cli);
     273        TALLOC_CTX *ctx;
     274
     275        struct {
     276                const char *cmd;
     277                bool *p;
     278                bool value;
     279        } table[] = {
     280                {"full",      &tar_ctx.mode.incremental, false},
     281                {"inc",       &tar_ctx.mode.incremental, true },
     282                {"reset",     &tar_ctx.mode.reset,       true },
     283                {"noreset",   &tar_ctx.mode.reset,       false},
     284                {"system",    &tar_ctx.mode.system,      true },
     285                {"nosystem",  &tar_ctx.mode.system,      false},
     286                {"hidden",    &tar_ctx.mode.hidden,      true },
     287                {"nohidden",  &tar_ctx.mode.hidden,      false},
     288                {"verbose",   &tar_ctx.mode.verbose,     true },
     289                {"noquiet",   &tar_ctx.mode.verbose,     true },
     290                {"quiet",     &tar_ctx.mode.verbose,     false},
     291                {"noverbose", &tar_ctx.mode.verbose,     false},
     292        };
     293
     294        ctx = talloc_new(NULL);
     295        if (ctx == NULL) {
     296                return 1;
     297        }
     298
     299        while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
     300                for (i = 0; i < ARRAY_SIZE(table); i++) {
     301                        if (strequal(table[i].cmd, buf)) {
     302                                *table[i].p = table[i].value;
    726303                                break;
    727304                        }
    728 
    729                         nread += datalen;
    730 
    731                         /* Only if the first read succeeds, write out the tar header. */
    732                         if (!wrote_tar_header) {
    733                                 /* write a tar header, don't bother with mode - just set to 100644 */
    734                                 writetarheader(tarhandle, rname, finfo.size,
    735                                         finfo.mtime_ts.tv_sec, "100644 \0", ftype);
    736                                 wrote_tar_header = True;
     305                }
     306
     307                if (i == ARRAY_SIZE(table))
     308                        DBG(0, ("tarmode: unrecognised option %s\n", buf));
     309        }
     310
     311        DBG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
     312                                tar_ctx.mode.incremental ? "incremental" : "full",
     313                                tar_ctx.mode.system      ? "system"      : "nosystem",
     314                                tar_ctx.mode.hidden      ? "hidden"      : "nohidden",
     315                                tar_ctx.mode.reset       ? "reset"       : "noreset",
     316                                tar_ctx.mode.verbose     ? "verbose"     : "quiet"));
     317
     318        talloc_free(ctx);
     319        return 0;
     320}
     321
     322/**
     323 * cmd_tar - interactive command to start a tar backup/restoration
     324 *
     325 * Check presence of argument, parse them and handle the request.
     326 */
     327int cmd_tar(void)
     328{
     329        const extern char *cmd_ptr;
     330        const char *flag;
     331        const char **val;
     332        char *buf;
     333        int maxtok = max_token(cmd_ptr);
     334        int i = 0;
     335        int err = 0;
     336        bool ok;
     337        int rc;
     338        TALLOC_CTX *ctx = talloc_new(NULL);
     339        if (ctx == NULL) {
     340                return 1;
     341        }
     342
     343        ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
     344        if (!ok) {
     345                DBG(0, ("tar <c|x>[IXFbganN] [options] <tar file> [path list]\n"));
     346                err = 1;
     347                goto out;
     348        }
     349
     350        flag = buf;
     351        val = talloc_array(ctx, const char *, maxtok);
     352        if (val == NULL) {
     353                err = 1;
     354                goto out;
     355        }
     356
     357        while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
     358                val[i++] = buf;
     359        }
     360
     361        rc = tar_parse_args(&tar_ctx, flag, val, i);
     362        if (rc != 0) {
     363                DBG(0, ("parse_args failed\n"));
     364                err = 1;
     365                goto out;
     366        }
     367
     368        rc = tar_process(&tar_ctx);
     369        if (rc != 0) {
     370                DBG(0, ("tar_process failed\n"));
     371                err = 1;
     372                goto out;
     373        }
     374
     375out:
     376        talloc_free(ctx);
     377        return err;
     378}
     379
     380
     381/**
     382 * tar_parse_args - parse and set tar command line arguments
     383 * @flag: string pointing to tar options
     384 * @val: number of tar arguments
     385 * @valsize: table of arguments after the flags (number of element in val)
     386 *
     387 * tar arguments work in a weird way. For each flag f that takes a
     388 * value v, the user is supposed to type:
     389 *
     390 * on the CLI:
     391 *   -Tf1f2f3 v1 v2 v3 TARFILE PATHS...
     392 *
     393 * in the interactive session:
     394 *   tar f1f2f3 v1 v2 v3 TARFILE PATHS...
     395 *
     396 * @flag has only flags (eg. "f1f2f3") and @val has the arguments
     397 * (values) following them (eg. ["v1", "v2", "v3", "TARFILE", "PATH1",
     398 * "PATH2"]).
     399 *
     400 * There are only 2 flags that take an arg: b and N. The other flags
     401 * just change the semantic of PATH or TARFILE.
     402 *
     403 * PATH can be a list of included/excluded paths, the path to a file
     404 * containing a list of included/excluded paths to use (F flag). If no
     405 * PATH is provided, the whole share is used (/).
     406 */
     407int tar_parse_args(struct tar* t,
     408                   const char *flag,
     409                   const char **val,
     410                   int valsize)
     411{
     412        TALLOC_CTX *ctx;
     413        bool do_read_list = false;
     414        /* index of next value to use */
     415        int ival = 0;
     416        int rc;
     417
     418        if (t == NULL) {
     419                DBG(0, ("Invalid tar context\n"));
     420                return 1;
     421        }
     422
     423        ctx = tar_reset_mem_context(t);
     424        if (ctx == NULL) {
     425                return 1;
     426        }
     427        /*
     428         * Reset back some options - could be from interactive version
     429         * all other modes are left as they are
     430         */
     431        t->mode.operation = TAR_NO_OPERATION;
     432        t->mode.selection = TAR_NO_SELECTION;
     433        t->mode.dry = false;
     434        t->to_process = false;
     435        t->total_size = 0;
     436
     437        while (flag[0] != '\0') {
     438                switch(flag[0]) {
     439                /* operation */
     440                case 'c':
     441                        if (t->mode.operation != TAR_NO_OPERATION) {
     442                                printf("Tar must be followed by only one of c or x.\n");
     443                                return 1;
    737444                        }
    738 
    739                         /* if file size has increased since we made file size query, truncate
    740                                 read so tar header for this file will be correct.
    741                         */
    742 
    743                         if (nread > finfo.size) {
    744                                 datalen -= nread - finfo.size;
    745                                 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
    746                                                         finfo.name, (double)finfo.size));
     445                        t->mode.operation = TAR_CREATE;
     446                        break;
     447                case 'x':
     448                        if (t->mode.operation != TAR_NO_OPERATION) {
     449                                printf("Tar must be followed by only one of c or x.\n");
     450                                return 1;
    747451                        }
    748 
    749                         /* add received bits of file to buffer - dotarbuf will
    750                         * write out in 512 byte intervals */
    751 
    752                         if (dotarbuf(tarhandle,data,datalen) != datalen) {
    753                                 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
    754                                 status = map_nt_error_from_unix(errno);
    755                                 break;
     452                        t->mode.operation = TAR_EXTRACT;
     453                        break;
     454
     455                        /* selection  */
     456                case 'I':
     457                        if (t->mode.selection != TAR_NO_SELECTION) {
     458                                DBG(0,("Only one of I,X,F must be specified\n"));
     459                                return 1;
    756460                        }
    757 
    758                         if ( (datalen == 0) && (finfo.size != 0) ) {
    759                                 status = NT_STATUS_UNSUCCESSFUL;
    760                                 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
    761                                 break;
     461                        t->mode.selection = TAR_INCLUDE;
     462                        break;
     463                case 'X':
     464                        if (t->mode.selection != TAR_NO_SELECTION) {
     465                                DBG(0,("Only one of I,X,F must be specified\n"));
     466                                return 1;
    762467                        }
    763 
    764                         datalen=0;
    765                 } while ( nread < finfo.size );
    766 
    767                 if (wrote_tar_header) {
    768                         /* pad tar file with zero's if we couldn't get entire file */
    769                         if (nread < finfo.size) {
    770                                 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
    771                                                         (double)finfo.size, (int)nread));
    772                                 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) {
    773                                         status = map_nt_error_from_unix(errno);
    774                                         DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
    775                                 }
     468                        t->mode.selection = TAR_EXCLUDE;
     469                        break;
     470                case 'F':
     471                        if (t->mode.selection != TAR_NO_SELECTION) {
     472                                DBG(0,("Only one of I,X,F must be specified\n"));
     473                                return 1;
    776474                        }
    777 
    778                         /* round tar file to nearest block */
    779                         if (finfo.size % TBLOCK)
    780                                 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
    781 
    782                         ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
    783                         ntarf++;
     475                        t->mode.selection = TAR_INCLUDE;
     476                        do_read_list = true;
     477                        break;
     478
     479                        /* blocksize */
     480                case 'b':
     481                        if (ival >= valsize) {
     482                                DBG(0, ("Option b must be followed by a blocksize\n"));
     483                                return 1;
     484                        }
     485
     486                        if (tar_set_blocksize(t, atoi(val[ival]))) {
     487                                DBG(0, ("Option b must be followed by a valid blocksize\n"));
     488                                return 1;
     489                        }
     490
     491                        ival++;
     492                        break;
     493
     494                        /* incremental mode */
     495                case 'g':
     496                        t->mode.incremental = true;
     497                        break;
     498
     499                        /* newer than */
     500                case 'N':
     501                        if (ival >= valsize) {
     502                                DBG(0, ("Option N must be followed by valid file name\n"));
     503                                return 1;
     504                        }
     505
     506                        if (tar_set_newer_than(t, val[ival])) {
     507                                DBG(0,("Error setting newer-than time\n"));
     508                                return 1;
     509                        }
     510
     511                        ival++;
     512                        break;
     513
     514                        /* reset mode */
     515                case 'a':
     516                        t->mode.reset = true;
     517                        break;
     518
     519                        /* verbose */
     520                case 'q':
     521                        t->mode.verbose = true;
     522                        break;
     523
     524                        /* regex match  */
     525                case 'r':
     526                        t->mode.regex = true;
     527                        break;
     528
     529                        /* dry run mode */
     530                case 'n':
     531                        if (t->mode.operation != TAR_CREATE) {
     532                                DBG(0, ("n is only meaningful when creating a tar-file\n"));
     533                                return 1;
     534                        }
     535
     536                        t->mode.dry = true;
     537                        DBG(0, ("dry_run set\n"));
     538                        break;
     539
     540                default:
     541                        DBG(0,("Unknown tar option\n"));
     542                        return 1;
     543                }
     544
     545                flag++;
     546        }
     547
     548        /* no selection given? default selection is include */
     549        if (t->mode.selection == TAR_NO_SELECTION) {
     550                t->mode.selection = TAR_INCLUDE;
     551        }
     552
     553        if (valsize - ival < 1) {
     554                DBG(0, ("No tar file given.\n"));
     555                return 1;
     556        }
     557
     558        /* handle TARFILE */
     559        t->tar_path = talloc_strdup(ctx, val[ival]);
     560        if (t->tar_path == NULL) {
     561                return 1;
     562        }
     563        ival++;
     564
     565        /*
     566         * Make sure that dbf points to stderr if we are using stdout for
     567         * tar output
     568         */
     569        if (t->mode.operation == TAR_CREATE && strequal(t->tar_path, "-")) {
     570                setup_logging("smbclient", DEBUG_STDERR);
     571        }
     572
     573        /* handle PATHs... */
     574
     575        /* flag F -> read file list */
     576        if (do_read_list) {
     577                if (valsize - ival != 1) {
     578                        DBG(0,("Option F must be followed by exactly one filename.\n"));
     579                        return 1;
     580                }
     581
     582                rc = tar_read_inclusion_file(t, val[ival]);
     583                if (rc != 0) {
     584                        return 1;
     585                }
     586                ival++;
     587        /* otherwise store all the PATHs on the command line */
     588        } else {
     589                int i;
     590                for (i = ival; i < valsize; i++) {
     591                        NTSTATUS status;
     592                        status = tar_add_selection_path(t, val[i]);
     593                        if (!NT_STATUS_IS_OK(status)) {
     594                                return 1;
     595                        }
     596                }
     597        }
     598
     599        t->to_process = true;
     600        tar_dump(t);
     601        return 0;
     602}
     603
     604/**
     605 * tar_process - start processing archive
     606 *
     607 * The talloc context of the fields is freed at the end of the call.
     608 */
     609int tar_process(struct tar *t)
     610{
     611        int rc = 0;
     612
     613        if (t == NULL) {
     614                DBG(0, ("Invalid tar context\n"));
     615                return 1;
     616        }
     617
     618        switch(t->mode.operation) {
     619        case TAR_EXTRACT:
     620                rc = tar_extract(t);
     621                break;
     622        case TAR_CREATE:
     623                rc = tar_create(t);
     624                break;
     625        default:
     626                DBG(0, ("Invalid tar state\n"));
     627                rc = 1;
     628        }
     629
     630        t->to_process = false;
     631        tar_free_mem_context(t);
     632        DBG(5, ("tar_process done, err = %d\n", rc));
     633        return rc;
     634}
     635
     636/**
     637 * tar_create - create archive and fetch files
     638 */
     639static int tar_create(struct tar* t)
     640{
     641        int r;
     642        int err = 0;
     643        NTSTATUS status;
     644        const char *mask;
     645        TALLOC_CTX *ctx = talloc_new(NULL);
     646        if (ctx == NULL) {
     647                return 1;
     648        }
     649
     650        t->archive = archive_write_new();
     651
     652        if (!t->mode.dry) {
     653                const int bsize = t->mode.blocksize * TAR_BLOCK_UNIT;
     654                r = archive_write_set_bytes_per_block(t->archive, bsize);
     655                if (r != ARCHIVE_OK) {
     656                        DBG(0, ("Can't use a block size of %d bytes", bsize));
     657                        err = 1;
     658                        goto out;
     659                }
     660
     661                /*
     662                 * Use PAX restricted format which is not the most
     663                 * conservative choice but has useful extensions and is widely
     664                 * supported
     665                 */
     666                r = archive_write_set_format_pax_restricted(t->archive);
     667                if (r != ARCHIVE_OK) {
     668                        DBG(0, ("Can't use pax restricted format: %s\n",
     669                                                archive_error_string(t->archive)));
     670                        err = 1;
     671                        goto out;
     672                }
     673
     674                if (strequal(t->tar_path, "-")) {
     675                        r = archive_write_open_fd(t->archive, STDOUT_FILENO);
    784676                } else {
    785                         DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
    786                         shallitime=0;
     677                        r = archive_write_open_filename(t->archive, t->tar_path);
     678                }
     679
     680                if (r != ARCHIVE_OK) {
     681                        DBG(0, ("Can't open %s: %s\n", t->tar_path,
     682                                                archive_error_string(t->archive)));
     683                        err = 1;
     684                        goto out_close;
     685                }
     686        }
     687
     688        /*
     689         * In inclusion mode, iterate on the inclusion list
     690         */
     691        if (t->mode.selection == TAR_INCLUDE && t->path_list_size > 0) {
     692                if (tar_create_from_list(t)) {
     693                        err = 1;
     694                        goto out_close;
     695                }
     696        } else {
     697                mask = talloc_asprintf(ctx, "%s\\*", client_get_cur_dir());
     698                if (mask == NULL) {
     699                        err = 1;
     700                        goto out_close;
     701                }
     702                DBG(5, ("tar_process do_list with mask: %s\n", mask));
     703                status = do_list(mask, TAR_DO_LIST_ATTR, get_file_callback, false, true);
     704                if (!NT_STATUS_IS_OK(status)) {
     705                        DBG(0, ("do_list fail %s\n", nt_errstr(status)));
     706                        err = 1;
     707                        goto out_close;
     708                }
     709        }
     710
     711out_close:
     712        DBG(0, ("Total bytes received: %" PRIu64 "\n", t->total_size));
     713
     714        if (!t->mode.dry) {
     715                r = archive_write_close(t->archive);
     716                if (r != ARCHIVE_OK) {
     717                        DBG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
     718                        err = 1;
     719                        goto out;
     720                }
     721        }
     722out:
     723#ifdef HAVE_ARCHIVE_READ_FREE
     724        archive_write_free(t->archive);
     725#else
     726        archive_write_finish(t->archive);
     727#endif
     728        talloc_free(ctx);
     729        return err;
     730}
     731
     732/**
     733 * tar_create_from_list - fetch from path list in include mode
     734 */
     735static int tar_create_from_list(struct tar *t)
     736{
     737        int err = 0;
     738        NTSTATUS status;
     739        char *base;
     740        const char *path, *mask, *start_dir;
     741        int i;
     742        TALLOC_CTX *ctx = talloc_new(NULL);
     743        if (ctx == NULL) {
     744                return 1;
     745        }
     746
     747        start_dir = talloc_strdup(ctx, client_get_cur_dir());
     748        if (start_dir == NULL) {
     749                err = 1;
     750                goto out;
     751        }
     752
     753        for (i = 0; i < t->path_list_size; i++) {
     754                path = t->path_list[i];
     755                base = NULL;
     756                status = path_base_name(ctx, path, &base);
     757                if (!NT_STATUS_IS_OK(status)) {
     758                        err = 1;
     759                        goto out;
     760                }
     761                mask = talloc_asprintf(ctx, "%s\\%s",
     762                                       client_get_cur_dir(), path);
     763                if (mask == NULL) {
     764                        err = 1;
     765                        goto out;
     766                }
     767
     768                DBG(5, ("incl. path='%s', base='%s', mask='%s'\n",
     769                                        path, base ? base : "NULL", mask));
     770
     771                if (base != NULL) {
     772                        base = talloc_asprintf(ctx, "%s%s\\",
     773                                               client_get_cur_dir(), base);
     774                        if (base == NULL) {
     775                                err = 1;
     776                                goto out;
     777                        }
     778                        DBG(5, ("cd '%s' before do_list\n", base));
     779                        client_set_cur_dir(base);
     780                }
     781                status = do_list(mask, TAR_DO_LIST_ATTR, get_file_callback, false, true);
     782                if (base != NULL) {
     783                        client_set_cur_dir(start_dir);
     784                }
     785                if (!NT_STATUS_IS_OK(status)) {
     786                        DBG(0, ("do_list failed on %s (%s)\n", path, nt_errstr(status)));
     787                        err = 1;
     788                        goto out;
     789                }
     790        }
     791
     792out:
     793        talloc_free(ctx);
     794        return err;
     795}
     796
     797/**
     798 * get_file_callback - do_list callback
     799 *
     800 * Callback for client.c do_list(). Called for each file found on the
     801 * share matching do_list mask. Recursively call do_list() with itself
     802 * as callback when the current file is a directory.
     803 */
     804static NTSTATUS get_file_callback(struct cli_state *cli,
     805                                  struct file_info *finfo,
     806                                  const char *dir)
     807{
     808        NTSTATUS status = NT_STATUS_OK;
     809        char *remote_name;
     810        const char *initial_dir = client_get_cur_dir();
     811        bool skip = false;
     812        int rc;
     813        TALLOC_CTX *ctx = talloc_new(NULL);
     814        if (ctx == NULL) {
     815                return NT_STATUS_NO_MEMORY;
     816        }
     817
     818        remote_name = talloc_asprintf(ctx, "%s%s", initial_dir, finfo->name);
     819        if (remote_name == NULL) {
     820                status = NT_STATUS_NO_MEMORY;
     821                goto out;
     822        }
     823
     824        if (strequal(finfo->name, "..") || strequal(finfo->name, ".")) {
     825                goto out;
     826        }
     827
     828        status = tar_create_skip_path(&tar_ctx, remote_name, finfo, &skip);
     829        if (!NT_STATUS_IS_OK(status)) {
     830                goto out;
     831        }
     832
     833        if (skip) {
     834                DBG(5, ("--- %s\n", remote_name));
     835                status = NT_STATUS_OK;
     836                goto out;
     837        }
     838
     839        if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
     840                char *old_dir;
     841                char *new_dir;
     842                char *mask;
     843
     844                old_dir = talloc_strdup(ctx, initial_dir);
     845                new_dir = talloc_asprintf(ctx, "%s%s\\",
     846                                          initial_dir, finfo->name);
     847                if ((old_dir == NULL) || (new_dir == NULL)) {
     848                        status = NT_STATUS_NO_MEMORY;
     849                        goto out;
     850                }
     851                mask = talloc_asprintf(ctx, "%s*", new_dir);
     852                if (mask == NULL) {
     853                        status = NT_STATUS_NO_MEMORY;
     854                        goto out;
     855                }
     856
     857                rc = tar_get_file(&tar_ctx, remote_name, finfo);
     858                if (rc != 0) {
    787859                        status = NT_STATUS_UNSUCCESSFUL;
    788                 }
    789         }
    790 
    791         cli_close(cli, fnum);
    792         fnum = -1;
    793 
    794         if (shallitime) {
    795                 struct timespec tp_end;
    796                 int this_time;
    797 
    798                 /* if shallitime is true then we didn't skip */
    799                 if (tar_reset && !dry_run)
    800                         (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
    801 
    802                 clock_gettime_mono(&tp_end);
    803                 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000;
    804                 get_total_time_ms += this_time;
    805                 get_total_size += finfo.size;
    806 
    807                 if (tar_noisy) {
    808                         DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
    809                                 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
    810                                 finfo.name));
    811                 }
    812 
    813                 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
    814                 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
    815                                 finfo.size / MAX(0.001, (1.024*this_time)),
    816                                 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
    817         }
    818 
    819   cleanup:
    820 
    821         if (fnum != (uint16_t)-1) {
    822                 cli_close(cli, fnum);
    823                 fnum = -1;
    824         }
    825         TALLOC_FREE(ctx);
    826         SAFE_FREE(data);
     860                        goto out;
     861                }
     862
     863                client_set_cur_dir(new_dir);
     864                do_list(mask, TAR_DO_LIST_ATTR, get_file_callback, false, true);
     865                client_set_cur_dir(old_dir);
     866        } else {
     867                rc = tar_get_file(&tar_ctx, remote_name, finfo);
     868                if (rc != 0) {
     869                        status = NT_STATUS_UNSUCCESSFUL;
     870                        goto out;
     871                }
     872        }
     873
     874out:
     875        talloc_free(ctx);
    827876        return status;
    828877}
    829878
    830 /****************************************************************************
    831 Append single file to tar file (or not)
    832 ***************************************************************************/
    833 
    834 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
    835                    const char *dir)
    836 {
    837         TALLOC_CTX *ctx = talloc_stackframe();
     879/**
     880 * tar_get_file - fetch a remote file to the local archive
     881 * @full_dos_path: path to the file to fetch
     882 * @finfo: attributes of the file to fetch
     883 */
     884static int tar_get_file(struct tar *t,
     885                        const char *full_dos_path,
     886                        struct file_info *finfo)
     887{
     888        extern struct cli_state *cli;
     889        NTSTATUS status;
     890        struct archive_entry *entry;
     891        char *full_unix_path;
     892        char buf[TAR_CLI_READ_SIZE];
     893        size_t len;
     894        uint64_t off = 0;
     895        uint16_t remote_fd = (uint16_t)-1;
     896        int err = 0, r;
     897        const bool isdir = finfo->mode & FILE_ATTRIBUTE_DIRECTORY;
     898        TALLOC_CTX *ctx = talloc_new(NULL);
     899        if (ctx == NULL) {
     900                return 1;
     901        }
     902
     903        DBG(5, ("+++ %s\n", full_dos_path));
     904
     905        t->total_size += finfo->size;
     906
     907        if (t->mode.dry) {
     908                goto out;
     909        }
     910
     911        if (t->mode.reset) {
     912                /* ignore return value: server might not store DOS attributes */
     913                set_remote_attr(full_dos_path, FILE_ATTRIBUTE_ARCHIVE, ATTR_UNSET);
     914        }
     915
     916        full_unix_path = talloc_asprintf(ctx, ".%s", full_dos_path);
     917        if (full_unix_path == NULL) {
     918                err = 1;
     919                goto out;
     920        }
     921        string_replace(full_unix_path, '\\', '/');
     922        entry = archive_entry_new();
     923        archive_entry_copy_pathname(entry, full_unix_path);
     924        archive_entry_set_filetype(entry, isdir ? AE_IFDIR : AE_IFREG);
     925        archive_entry_set_atime(entry,
     926                        finfo->atime_ts.tv_sec,
     927                        finfo->atime_ts.tv_nsec);
     928        archive_entry_set_mtime(entry,
     929                        finfo->mtime_ts.tv_sec,
     930                        finfo->mtime_ts.tv_nsec);
     931        archive_entry_set_ctime(entry,
     932                        finfo->ctime_ts.tv_sec,
     933                        finfo->ctime_ts.tv_nsec);
     934        archive_entry_set_perm(entry, isdir ? 0755 : 0644);
     935        /*
     936         * check if we can safely cast unsigned file size to libarchive
     937         * signed size. Very unlikely problem (>9 exabyte file)
     938         */
     939        if (finfo->size > INT64_MAX) {
     940                DBG(0, ("Remote file %s too big\n", full_dos_path));
     941                goto out_entry;
     942        }
     943
     944        archive_entry_set_size(entry, (int64_t)finfo->size);
     945
     946        r = archive_write_header(t->archive, entry);
     947        if (r != ARCHIVE_OK) {
     948                DBG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
     949                err = 1;
     950                goto out_entry;
     951        }
     952
     953        if (isdir) {
     954                DBG(5, ("get_file skip dir %s\n", full_dos_path));
     955                goto out_entry;
     956        }
     957
     958        status = cli_open(cli, full_dos_path, O_RDONLY, DENY_NONE, &remote_fd);
     959        if (!NT_STATUS_IS_OK(status)) {
     960                DBG(0,("%s opening remote file %s\n",
     961                                        nt_errstr(status), full_dos_path));
     962                goto out_entry;
     963        }
     964
     965        do {
     966                status = cli_read(cli, remote_fd, buf, off, sizeof(buf), &len);
     967                if (!NT_STATUS_IS_OK(status)) {
     968                        DBG(0,("Error reading file %s : %s\n",
     969                                                full_dos_path, nt_errstr(status)));
     970                        err = 1;
     971                        goto out_close;
     972                }
     973
     974                off += len;
     975
     976                r = archive_write_data(t->archive, buf, len);
     977                if (r < 0) {
     978                        DBG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
     979                        err = 1;
     980                        goto out_close;
     981                }
     982
     983        } while (off < finfo->size);
     984
     985out_close:
     986        cli_close(cli, remote_fd);
     987
     988out_entry:
     989        archive_entry_free(entry);
     990
     991out:
     992        talloc_free(ctx);
     993        return err;
     994}
     995
     996/**
     997 * tar_extract - open archive and send files.
     998 */
     999static int tar_extract(struct tar *t)
     1000{
     1001        int err = 0;
     1002        int r;
     1003        struct archive_entry *entry;
     1004        const size_t bsize = t->mode.blocksize * TAR_BLOCK_UNIT;
     1005        int rc;
     1006
     1007        t->archive = archive_read_new();
     1008        archive_read_support_format_all(t->archive);
     1009#ifdef HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL
     1010        archive_read_support_filter_all(t->archive);
     1011#endif
     1012
     1013        if (strequal(t->tar_path, "-")) {
     1014                r = archive_read_open_fd(t->archive, STDIN_FILENO, bsize);
     1015        } else {
     1016                r = archive_read_open_filename(t->archive, t->tar_path, bsize);
     1017        }
     1018
     1019        if (r != ARCHIVE_OK) {
     1020                DBG(0, ("Can't open %s : %s\n", t->tar_path,
     1021                                        archive_error_string(t->archive)));
     1022                err = 1;
     1023                goto out;
     1024        }
     1025
     1026        for (;;) {
     1027                NTSTATUS status;
     1028                bool skip;
     1029                r = archive_read_next_header(t->archive, &entry);
     1030                if (r == ARCHIVE_EOF) {
     1031                        break;
     1032                }
     1033                if (r == ARCHIVE_WARN) {
     1034                        DBG(0, ("Warning: %s\n", archive_error_string(t->archive)));
     1035                }
     1036                if (r == ARCHIVE_FATAL) {
     1037                        DBG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
     1038                        err = 1;
     1039                        goto out;
     1040                }
     1041
     1042                status = tar_extract_skip_path(t, entry, &skip);
     1043                if (!NT_STATUS_IS_OK(status)) {
     1044                        err = 1;
     1045                        goto out;
     1046                }
     1047                if (skip) {
     1048                        DBG(5, ("--- %s\n", archive_entry_pathname(entry)));
     1049                        continue;
     1050                }
     1051
     1052                DBG(5, ("+++ %s\n", archive_entry_pathname(entry)));
     1053
     1054                rc = tar_send_file(t, entry);
     1055                if (rc != 0) {
     1056                        err = 1;
     1057                        goto out;
     1058                }
     1059        }
     1060
     1061out:
     1062#ifdef HAVE_ARCHIVE_READ_FREE
     1063        r = archive_read_free(t->archive);
     1064#else
     1065        r = archive_read_finish(t->archive);
     1066#endif
     1067        if (r != ARCHIVE_OK) {
     1068                DBG(0, ("Can't close %s : %s\n", t->tar_path,
     1069                                        archive_error_string(t->archive)));
     1070                err = 1;
     1071        }
     1072        return err;
     1073}
     1074
     1075/**
     1076 * tar_send_file - send @entry to the remote server
     1077 * @entry: current archive entry
     1078 *
     1079 * Handle the creation of the parent directories and transfer the
     1080 * entry to a new remote file.
     1081 */
     1082static int tar_send_file(struct tar *t, struct archive_entry *entry)
     1083{
     1084        extern struct cli_state *cli;
     1085        char *dos_path;
     1086        char *full_path;
     1087        NTSTATUS status;
     1088        uint16_t remote_fd = (uint16_t) -1;
     1089        int err = 0;
     1090        int flags = O_RDWR | O_CREAT | O_TRUNC;
     1091        mode_t mode = archive_entry_filetype(entry);
     1092        int rc;
     1093        TALLOC_CTX *ctx = talloc_new(NULL);
     1094        if (ctx == NULL) {
     1095                return 1;
     1096        }
     1097
     1098        dos_path = talloc_strdup(ctx, archive_entry_pathname(entry));
     1099        if (dos_path == NULL) {
     1100                err = 1;
     1101                goto out;
     1102        }
     1103        fix_unix_path(dos_path, true);
     1104
     1105        full_path = talloc_strdup(ctx, client_get_cur_dir());
     1106        if (full_path == NULL) {
     1107                err = 1;
     1108                goto out;
     1109        }
     1110        full_path = talloc_strdup_append(full_path, dos_path);
     1111        if (full_path == NULL) {
     1112                err = 1;
     1113                goto out;
     1114        }
     1115
     1116        if (mode != AE_IFREG && mode != AE_IFDIR) {
     1117                DBG(0, ("Skipping non-dir & non-regular file %s\n", full_path));
     1118                goto out;
     1119        }
     1120
     1121        rc = make_remote_path(full_path);
     1122        if (rc != 0) {
     1123                err = 1;
     1124                goto out;
     1125        }
     1126
     1127        if (mode == AE_IFDIR) {
     1128                goto out;
     1129        }
     1130
     1131        status = cli_open(cli, full_path, flags, DENY_NONE, &remote_fd);
     1132        if (!NT_STATUS_IS_OK(status)) {
     1133                DBG(0, ("Error opening remote file %s: %s\n",
     1134                                        full_path, nt_errstr(status)));
     1135                err = 1;
     1136                goto out;
     1137        }
     1138
     1139        for (;;) {
     1140                const void *buf;
     1141                size_t len;
     1142                off_t off;
     1143                int r;
     1144
     1145                r = archive_read_data_block(t->archive, &buf, &len, &off);
     1146                if (r == ARCHIVE_EOF) {
     1147                        break;
     1148                }
     1149                if (r == ARCHIVE_WARN) {
     1150                        DBG(0, ("Warning: %s\n", archive_error_string(t->archive)));
     1151                }
     1152                if (r == ARCHIVE_FATAL) {
     1153                        DBG(0, ("Fatal: %s\n", archive_error_string(t->archive)));
     1154                        err = 1;
     1155                        goto close_out;
     1156                }
     1157
     1158                status = cli_writeall(cli, remote_fd, 0, buf, off, len, NULL);
     1159                if (!NT_STATUS_IS_OK(status)) {
     1160                        DBG(0, ("Error writing remote file %s: %s\n",
     1161                                                full_path, nt_errstr(status)));
     1162                        err = 1;
     1163                        goto close_out;
     1164                }
     1165        }
     1166
     1167close_out:
     1168        status = cli_close(cli, remote_fd);
     1169        if (!NT_STATUS_IS_OK(status)) {
     1170                DBG(0, ("Error losing remote file %s: %s\n",
     1171                                        full_path, nt_errstr(status)));
     1172                err = 1;
     1173        }
     1174
     1175out:
     1176        talloc_free(ctx);
     1177        return err;
     1178}
     1179
     1180/**
     1181 * tar_add_selection_path - add a path to the path list
     1182 * @path: path to add
     1183 */
     1184static NTSTATUS tar_add_selection_path(struct tar *t, const char *path)
     1185{
     1186        const char **list;
     1187        TALLOC_CTX *ctx = t->talloc_ctx;
     1188        if (!t->path_list) {
     1189                t->path_list = str_list_make_empty(ctx);
     1190                if (t->path_list == NULL) {
     1191                        return NT_STATUS_NO_MEMORY;
     1192                }
     1193                t->path_list_size = 0;
     1194        }
     1195
     1196        /* cast to silence gcc const-qual warning */
     1197        list = str_list_add((void *)t->path_list, path);
     1198        if (list == NULL) {
     1199                return NT_STATUS_NO_MEMORY;
     1200        }
     1201        t->path_list = discard_const_p(char *, list);
     1202        t->path_list_size++;
     1203        fix_unix_path(t->path_list[t->path_list_size - 1], true);
     1204
     1205        return NT_STATUS_OK;
     1206}
     1207
     1208/**
     1209 * tar_set_blocksize - set block size in TAR_BLOCK_UNIT
     1210 */
     1211static int tar_set_blocksize(struct tar *t, int size)
     1212{
     1213        if (size <= 0 || size > TAR_MAX_BLOCK_SIZE) {
     1214                return 1;
     1215        }
     1216
     1217        t->mode.blocksize = size;
     1218
     1219        return 0;
     1220}
     1221
     1222/**
     1223 * tar_set_newer_than - set date threshold of saved files
     1224 * @filename: local path to a file
     1225 *
     1226 * Only files newer than the modification time of @filename will be
     1227 * saved.
     1228 *
     1229 * Note: this function set the global variable newer_than from
     1230 * client.c. Thus the time is not a field of the tar structure. See
     1231 * cmd_newer() to change its value from an interactive session.
     1232 */
     1233static int tar_set_newer_than(struct tar *t, const char *filename)
     1234{
     1235        extern time_t newer_than;
     1236        SMB_STRUCT_STAT stbuf;
     1237        int rc;
     1238
     1239        rc = sys_stat(filename, &stbuf, false);
     1240        if (rc != 0) {
     1241                DBG(0, ("Error setting newer-than time\n"));
     1242                return 1;
     1243        }
     1244
     1245        newer_than = convert_timespec_to_time_t(stbuf.st_ex_mtime);
     1246        DBG(1, ("Getting files newer than %s\n", time_to_asc(newer_than)));
     1247        return 0;
     1248}
     1249
     1250/**
     1251 * tar_read_inclusion_file - set path list from file
     1252 * @filename: path to the list file
     1253 *
     1254 * Read and add each line of @filename to the path list.
     1255 */
     1256static int tar_read_inclusion_file(struct tar *t, const char* filename)
     1257{
     1258        char *line;
     1259        int err = 0;
     1260        int fd;
     1261        TALLOC_CTX *ctx = talloc_new(NULL);
     1262        if (ctx == NULL) {
     1263                return 1;
     1264        }
     1265
     1266        fd = open(filename, O_RDONLY);
     1267        if (fd < 0) {
     1268                DBG(0, ("Can't open inclusion file '%s': %s\n", filename, strerror(errno)));
     1269                err = 1;
     1270                goto out;
     1271        }
     1272
     1273        for (line = afdgets(fd, ctx, 0);
     1274                        line != NULL;
     1275                        line = afdgets(fd, ctx, 0)) {
     1276                NTSTATUS status;
     1277                status = tar_add_selection_path(t, line);
     1278                if (!NT_STATUS_IS_OK(status)) {
     1279                        err = 1;
     1280                        goto out;
     1281                }
     1282        }
     1283
     1284        close(fd);
     1285
     1286out:
     1287        talloc_free(ctx);
     1288        return err;
     1289}
     1290
     1291/**
     1292 * tar_path_in_list - check whether @path is in the path list
     1293 * @path: path to find
     1294 * @reverse: when true also try to find path list element in @path
     1295 * @_is_in_list: set if @path is in the path list
     1296 *
     1297 * Look at each path of the path list and set @_is_in_list if @path is a
     1298 * subpath of one of them.
     1299 *
     1300 * If you want /path to be in the path list (path/a/, path/b/) set
     1301 * @reverse to true to try to match the other way around.
     1302 */
     1303static NTSTATUS tar_path_in_list(struct tar *t, const char *path,
     1304                                 bool reverse, bool *_is_in_list)
     1305{
     1306        int i;
     1307        const char *p;
     1308        const char *pattern;
     1309
     1310        if (path == NULL || path[0] == '\0') {
     1311                *_is_in_list = false;
     1312                return NT_STATUS_OK;
     1313        }
     1314
     1315        p = skip_useless_char_in_path(path);
     1316
     1317        for (i = 0; i < t->path_list_size; i++) {
     1318                bool is_in_list;
     1319                NTSTATUS status;
     1320
     1321                pattern = skip_useless_char_in_path(t->path_list[i]);
     1322                status = is_subpath(p, pattern, &is_in_list);
     1323                if (!NT_STATUS_IS_OK(status)) {
     1324                        return status;
     1325                }
     1326                if (reverse && !is_in_list) {
     1327                        status = is_subpath(pattern, p, &is_in_list);
     1328                        if (!NT_STATUS_IS_OK(status)) {
     1329                                return status;
     1330                        }
     1331                }
     1332                if (is_in_list) {
     1333                        *_is_in_list = true;
     1334                        return NT_STATUS_OK;
     1335                }
     1336        }
     1337
     1338        *_is_in_list = false;
     1339        return NT_STATUS_OK;
     1340}
     1341
     1342/**
     1343 * tar_extract_skip_path - check if @entry should be skipped
     1344 * @entry: current tar entry
     1345 * @_skip: set true if path should be skipped, otherwise false
     1346 *
     1347 * Skip predicate for tar extraction (archive to server) only.
     1348 */
     1349static NTSTATUS tar_extract_skip_path(struct tar *t,
     1350                                      struct archive_entry *entry,
     1351                                      bool *_skip)
     1352{
     1353        const char *fullpath = archive_entry_pathname(entry);
     1354        bool in = true;
     1355
     1356        if (t->path_list_size <= 0) {
     1357                *_skip = false;
     1358                return NT_STATUS_OK;
     1359        }
     1360
     1361        if (t->mode.regex) {
     1362                in = mask_match_list(fullpath, t->path_list, t->path_list_size, true);
     1363        } else {
     1364                NTSTATUS status = tar_path_in_list(t, fullpath, false, &in);
     1365                if (!NT_STATUS_IS_OK(status)) {
     1366                        return status;
     1367                }
     1368        }
     1369
     1370        if (t->mode.selection == TAR_EXCLUDE) {
     1371                *_skip = in;
     1372        } else {
     1373                *_skip = !in;
     1374        }
     1375
     1376        return NT_STATUS_OK;
     1377}
     1378
     1379/**
     1380 * tar_create_skip_path - check if @fullpath shoud be skipped
     1381 * @fullpath: full remote path of the current file
     1382 * @finfo: remote file attributes
     1383 * @_skip: returned skip not
     1384 *
     1385 * Skip predicate for tar creation (server to archive) only.
     1386 */
     1387static NTSTATUS tar_create_skip_path(struct tar *t,
     1388                                     const char *fullpath,
     1389                                     const struct file_info *finfo,
     1390                                     bool *_skip)
     1391{
     1392        /* syntaxic sugar */
     1393        const mode_t mode = finfo->mode;
     1394        const bool isdir = mode & FILE_ATTRIBUTE_DIRECTORY;
     1395        const bool exclude = t->mode.selection == TAR_EXCLUDE;
     1396        bool in = true;
     1397
     1398        if (!isdir) {
     1399
     1400                /* 1. if we don't want X and we have X, skip */
     1401                if (!t->mode.system && (mode & FILE_ATTRIBUTE_SYSTEM)) {
     1402                        *_skip = true;
     1403                        return NT_STATUS_OK;
     1404                }
     1405
     1406                if (!t->mode.hidden && (mode & FILE_ATTRIBUTE_HIDDEN)) {
     1407                        *_skip = true;
     1408                        return NT_STATUS_OK;
     1409                }
     1410
     1411                /* 2. if we only want archive and it's not, skip */
     1412
     1413                if (t->mode.incremental && !(mode & FILE_ATTRIBUTE_ARCHIVE)) {
     1414                        *_skip = true;
     1415                        return NT_STATUS_OK;
     1416                }
     1417        }
     1418
     1419        /* 3. is it in the selection list? */
     1420
     1421        /*
     1422         * tar_create_from_list() use the include list as a starting
     1423         * point, no need to check
     1424         */
     1425        if (!exclude) {
     1426                *_skip = false;
     1427                return NT_STATUS_OK;
     1428        }
     1429
     1430        /* we are now in exclude mode */
     1431
     1432        /* no matter the selection, no list => include everything */
     1433        if (t->path_list_size <= 0) {
     1434                *_skip = false;
     1435                return NT_STATUS_OK;
     1436        }
     1437
     1438        if (t->mode.regex) {
     1439                in = mask_match_list(fullpath, t->path_list, t->path_list_size, true);
     1440        } else {
     1441                bool reverse = isdir && !exclude;
     1442                NTSTATUS status = tar_path_in_list(t, fullpath, reverse, &in);
     1443                if (!NT_STATUS_IS_OK(status)) {
     1444                        return status;
     1445                }
     1446        }
     1447        *_skip = in;
     1448
     1449        return NT_STATUS_OK;
     1450}
     1451
     1452/**
     1453 * tar_to_process - return true if @t is ready to be processed
     1454 *
     1455 * @t is ready if it properly parsed command line arguments.
     1456 */
     1457bool tar_to_process(struct tar *t)
     1458{
     1459        if (t == NULL) {
     1460                DBG(0, ("Invalid tar context\n"));
     1461                return false;
     1462        }
     1463        return t->to_process;
     1464}
     1465
     1466/**
     1467 * skip_useless_char_in_path - skip leading slashes/dots
     1468 *
     1469 * Skip leading slashes, backslashes and dot-slashes.
     1470 */
     1471static const char* skip_useless_char_in_path(const char *p)
     1472{
     1473        while (p) {
     1474                if (*p == '/' || *p == '\\') {
     1475                        p++;
     1476                }
     1477                else if (p[0] == '.' && (p[1] == '/' || p[1] == '\\')) {
     1478                        p += 2;
     1479                }
     1480                else
     1481                        return p;
     1482        }
     1483        return p;
     1484}
     1485
     1486/**
     1487 * is_subpath - check if the path @sub is a subpath of @full.
     1488 * @sub: path to test
     1489 * @full: container path
     1490 * @_subpath_match: set true if @sub is a subpath of @full, otherwise false
     1491 *
     1492 * String comparaison is case-insensitive.
     1493 */
     1494static NTSTATUS is_subpath(const char *sub, const char *full,
     1495                           bool *_subpath_match)
     1496{
    8381497        NTSTATUS status = NT_STATUS_OK;
    839 
    840         if (strequal(finfo->name,"..") || strequal(finfo->name,".")) {
    841                 status = NT_STATUS_OK;
    842                 goto cleanup;
    843         }
    844 
    845         /* Is it on the exclude list ? */
    846         if (!tar_excl && clipn) {
    847                 char *exclaim;
    848 
    849                 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
    850 
    851                 exclaim = talloc_asprintf(ctx,
    852                                 "%s\\%s",
    853                                 client_get_cur_dir(),
    854                                 finfo->name);
    855                 if (!exclaim) {
    856                         status = NT_STATUS_NO_MEMORY;
    857                         goto cleanup;
    858                 }
    859 
    860                 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
    861 
    862                 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
    863                                 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
    864                         DEBUG(3,("Skipping file %s\n", exclaim));
    865                         TALLOC_FREE(exclaim);
    866                         status = NT_STATUS_OK;
    867                         goto cleanup;
    868                 }
    869                 TALLOC_FREE(exclaim);
    870         }
    871 
    872         if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
    873                 char *saved_curdir = NULL;
    874                 char *new_cd = NULL;
    875                 char *mtar_mask = NULL;
    876 
    877                 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
    878                 if (!saved_curdir) {
    879                         status = NT_STATUS_NO_MEMORY;
    880                         goto cleanup;
    881                 }
    882 
    883                 DEBUG(5, ("strlen(cur_dir)=%d, \
    884 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
    885                         (int)strlen(saved_curdir),
    886                         (int)strlen(finfo->name), finfo->name, saved_curdir));
    887 
    888                 new_cd = talloc_asprintf(ctx,
    889                                 "%s%s\\",
    890                                 client_get_cur_dir(),
    891                                 finfo->name);
    892                 if (!new_cd) {
    893                         status = NT_STATUS_NO_MEMORY;
    894                         goto cleanup;
    895                 }
    896                 client_set_cur_dir(new_cd);
    897 
    898                 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
    899 
    900                 /* write a tar directory, don't bother with mode - just
    901                  * set it to 40755 */
    902                 writetarheader(tarhandle, client_get_cur_dir(), 0,
    903                                 finfo->mtime_ts.tv_sec, "040755 \0", '5');
    904                 if (tar_noisy) {
    905                         DEBUG(0,("                directory %s\n",
    906                                 client_get_cur_dir()));
    907                 }
    908                 ntarf++;  /* Make sure we have a file on there */
    909                 mtar_mask = talloc_asprintf(ctx,
    910                                 "%s*",
    911                                 client_get_cur_dir());
    912                 if (!mtar_mask) {
    913                         status = NT_STATUS_NO_MEMORY;
    914                         goto cleanup;
    915                 }
    916                 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
    917                 do_list(mtar_mask, attribute, do_tar, False, True);
    918                 client_set_cur_dir(saved_curdir);
    919                 TALLOC_FREE(saved_curdir);
    920                 TALLOC_FREE(new_cd);
    921                 TALLOC_FREE(mtar_mask);
    922         } else {
    923                 char *rname = talloc_asprintf(ctx,
    924                                         "%s%s",
    925                                         client_get_cur_dir(),
    926                                         finfo->name);
    927                 if (!rname) {
    928                         status = NT_STATUS_NO_MEMORY;
    929                         goto cleanup;
    930                 }
    931                 status = do_atar(rname,finfo->name,finfo);
    932                 TALLOC_FREE(rname);
    933         }
    934 
    935   cleanup:
    936         TALLOC_FREE(ctx);
     1498        int len = 0;
     1499        char *f, *s;
     1500        TALLOC_CTX *tmp_ctx = talloc_new(NULL);
     1501        if (tmp_ctx == NULL) {
     1502                status = NT_STATUS_NO_MEMORY;
     1503                goto out;
     1504        }
     1505
     1506        f = strlower_talloc(tmp_ctx, full);
     1507        if (f == NULL) {
     1508                status = NT_STATUS_NO_MEMORY;
     1509                goto out_ctx_free;
     1510        }
     1511        string_replace(f, '\\', '/');
     1512        s = strlower_talloc(tmp_ctx, sub);
     1513        if (f == NULL) {
     1514                status = NT_STATUS_NO_MEMORY;
     1515                goto out_ctx_free;
     1516        }
     1517        string_replace(s, '\\', '/');
     1518
     1519        /* find the point where sub and full diverge */
     1520        while ((*f != '\0') && (*s != '\0') && (*f == *s)) {
     1521                f++;
     1522                s++;
     1523                len++;
     1524        }
     1525
     1526        if ((*f == '\0') && (*s == '\0')) {
     1527                *_subpath_match = true; /* sub and full match */
     1528                goto out_ctx_free;
     1529        }
     1530
     1531        if ((*f == '\0') && (len > 0) && (*(f - 1) == '/')) {
     1532                /* sub diverges from full at path separator */
     1533                *_subpath_match = true;
     1534                goto out_ctx_free;
     1535        }
     1536
     1537        if ((*s == '\0') && (strcmp(f, "/") == 0)) {
     1538                /* full diverges from sub with trailing slash only */
     1539                *_subpath_match = true;
     1540                goto out_ctx_free;
     1541        }
     1542
     1543        if ((*s == '/') && (*f == '\0')) {
     1544                /* sub diverges from full with extra path component */
     1545                *_subpath_match = true;
     1546                goto out_ctx_free;
     1547        }
     1548        *_subpath_match = false;
     1549
     1550out_ctx_free:
     1551        talloc_free(tmp_ctx);
     1552out:
    9371553        return status;
    9381554}
    9391555
    940 /****************************************************************************
    941 Convert from UNIX to DOS file names
    942 ***************************************************************************/
    943 
    944 static void unfixtarname(char *tptr, char *fp, int l, bool first)
    945 {
    946         /* remove '.' from start of file name, convert from unix /'s to
    947          * dos \'s in path. Kill any absolute path names. But only if first!
     1556
     1557/**
     1558 * make_remote_path - recursively make remote dirs
     1559 * @full_path: full hierarchy to create
     1560 *
     1561 * Create @full_path and each parent directories as needed.
     1562 */
     1563static int make_remote_path(const char *full_path)
     1564{
     1565        extern struct cli_state *cli;
     1566        char *path;
     1567        char *subpath;
     1568        char *state;
     1569        char *last_backslash;
     1570        char *p;
     1571        int len;
     1572        NTSTATUS status;
     1573        int err = 0;
     1574        TALLOC_CTX *ctx = talloc_new(NULL);
     1575        if (ctx == NULL) {
     1576                return 1;
     1577        }
     1578
     1579        subpath = talloc_strdup(ctx, full_path);
     1580        if (subpath == NULL) {
     1581                err = 1;
     1582                goto out;
     1583        }
     1584        path = talloc_strdup(ctx, full_path);
     1585        if (path == NULL) {
     1586                err = 1;
     1587                goto out;
     1588        }
     1589        len = talloc_get_size(path) - 1;
     1590
     1591        last_backslash = strrchr_m(path, '\\');
     1592        if (last_backslash == NULL) {
     1593                goto out;
     1594        }
     1595
     1596        *last_backslash = 0;
     1597
     1598        subpath[0] = 0;
     1599        p = strtok_r(path, "\\", &state);
     1600
     1601        while (p != NULL) {
     1602                strlcat(subpath, p, len);
     1603                status = cli_chkpath(cli, subpath);
     1604                if (!NT_STATUS_IS_OK(status)) {
     1605                        status = cli_mkdir(cli, subpath);
     1606                        if (!NT_STATUS_IS_OK(status)) {
     1607                                DBG(0, ("Can't mkdir %s: %s\n", subpath, nt_errstr(status)));
     1608                                err = 1;
     1609                                goto out;
     1610                        }
     1611                        DBG(3, ("mkdir %s\n", subpath));
     1612                }
     1613
     1614                strlcat(subpath, "\\", len);
     1615                p = strtok_r(NULL, "/\\", &state);
     1616
     1617        }
     1618
     1619out:
     1620        talloc_free(ctx);
     1621        return err;
     1622}
     1623
     1624/**
     1625 * tar_reset_mem_context - reset talloc context associated with @t
     1626 *
     1627 * At the start of the program the context is NULL so a new one is
     1628 * allocated. On the following runs (interactive session only), simply
     1629 * free the children.
     1630 */
     1631static TALLOC_CTX *tar_reset_mem_context(struct tar *t)
     1632{
     1633        tar_free_mem_context(t);
     1634        t->talloc_ctx = talloc_new(NULL);
     1635        return t->talloc_ctx;
     1636}
     1637
     1638/**
     1639 * tar_free_mem_context - free talloc context associated with @t
     1640 */
     1641static void tar_free_mem_context(struct tar *t)
     1642{
     1643        if (t->talloc_ctx) {
     1644                talloc_free(t->talloc_ctx);
     1645                t->talloc_ctx = NULL;
     1646                t->path_list_size = 0;
     1647                t->path_list = NULL;
     1648                t->tar_path = NULL;
     1649        }
     1650}
     1651
     1652#define XSET(v)      [v] = #v
     1653#define XTABLE(v, t) DBG(2, ("DUMP:%-20.20s = %s\n", #v, t[v]))
     1654#define XBOOL(v)     DBG(2, ("DUMP:%-20.20s = %d\n", #v, v ? 1 : 0))
     1655#define XSTR(v)      DBG(2, ("DUMP:%-20.20s = %s\n", #v, v ? v : "NULL"))
     1656#define XINT(v)      DBG(2, ("DUMP:%-20.20s = %d\n", #v, v))
     1657#define XUINT64(v)   DBG(2, ("DUMP:%-20.20s = %" PRIu64  "\n", #v, v))
     1658
     1659/**
     1660 * tar_dump - dump tar structure on stdout
     1661 */
     1662static void tar_dump(struct tar *t)
     1663{
     1664        int i;
     1665        const char* op[] = {
     1666                XSET(TAR_NO_OPERATION),
     1667                XSET(TAR_CREATE),
     1668                XSET(TAR_EXTRACT),
     1669        };
     1670
     1671        const char* sel[] = {
     1672                XSET(TAR_NO_SELECTION),
     1673                XSET(TAR_INCLUDE),
     1674                XSET(TAR_EXCLUDE),
     1675        };
     1676
     1677        XBOOL(t->to_process);
     1678        XTABLE(t->mode.operation, op);
     1679        XTABLE(t->mode.selection, sel);
     1680        XINT(t->mode.blocksize);
     1681        XBOOL(t->mode.hidden);
     1682        XBOOL(t->mode.system);
     1683        XBOOL(t->mode.incremental);
     1684        XBOOL(t->mode.reset);
     1685        XBOOL(t->mode.dry);
     1686        XBOOL(t->mode.verbose);
     1687        XUINT64(t->total_size);
     1688        XSTR(t->tar_path);
     1689        XINT(t->path_list_size);
     1690
     1691        for (i = 0; t->path_list && t->path_list[i]; i++) {
     1692                DBG(2, ("DUMP: t->path_list[%2d] = %s\n", i, t->path_list[i]));
     1693        }
     1694
     1695        DBG(2, ("DUMP:t->path_list @ %p (%d elem)\n", t->path_list, i));
     1696}
     1697#undef XSET
     1698#undef XTABLE
     1699#undef XBOOL
     1700#undef XSTR
     1701#undef XINT
     1702
     1703/**
     1704 * max_token - return upper limit for the number of token in @str
     1705 *
     1706 * The result is not exact, the actual number of token might be less
     1707 * than what is returned.
     1708 */
     1709static int max_token(const char *str)
     1710{
     1711        const char *s;
     1712        int nb = 0;
     1713
     1714        if (str == NULL) {
     1715                return 0;
     1716        }
     1717
     1718        s = str;
     1719        while (s[0] != '\0') {
     1720                if (isspace((int)s[0])) {
     1721                        nb++;
     1722                }
     1723                s++;
     1724        }
     1725
     1726        nb++;
     1727
     1728        return nb;
     1729}
     1730
     1731/**
     1732 * fix_unix_path - convert @path to a DOS path
     1733 * @path: path to convert
     1734 * @removeprefix: if true, remove leading ./ or /.
     1735 */
     1736static char *fix_unix_path(char *path, bool do_remove_prefix)
     1737{
     1738        char *from = path, *to = path;
     1739
     1740        if (path == NULL || path[0] == '\0') {
     1741                return path;
     1742        }
     1743
     1744        /* remove prefix:
     1745         * ./path => path
     1746         *  /path => path
    9481747         */
    949 
    950         DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
    951 
    952         if (first) {
    953                 if (*fp == '.') {
    954                         fp++;
    955                         l--;
    956                 }
    957                 if (*fp == '\\' || *fp == '/') {
    958                         fp++;
    959                         l--;
    960                 }
    961         }
    962 
    963         safe_strcpy(tptr, fp, l);
    964         string_replace(tptr, '/', '\\');
    965 }
    966 
    967 /****************************************************************************
    968 Move to the next block in the buffer, which may mean read in another set of
    969 blocks. FIXME, we should allow more than one block to be skipped.
    970 ****************************************************************************/
    971 
    972 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
    973 {
    974         int bufread, total = 0;
    975 
    976         DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
    977         *bufferp += TBLOCK;
    978         total = TBLOCK;
    979 
    980         if (*bufferp >= (ltarbuf + bufsiz)) {
    981 
    982                 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
    983 
    984                 /*
    985                  * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
    986                  * Fixes bug where read can return short if coming from
    987                  * a pipe.
    988                  */
    989 
    990                 bufread = read(tarhandle, ltarbuf, bufsiz);
    991                 total = bufread;
    992 
    993                 while (total < bufsiz) {
    994                         if (bufread < 0) { /* An error, return false */
    995                                 return (total > 0 ? -2 : bufread);
    996                         }
    997                         if (bufread == 0) {
    998                                 if (total <= 0) {
    999                                         return -2;
    1000                                 }
    1001                                 break;
    1002                         }
    1003                         bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
    1004                         total += bufread;
    1005                 }
    1006 
    1007                 DEBUG(5, ("Total bytes read ... %i\n", total));
    1008 
    1009                 *bufferp = ltarbuf;
    1010         }
    1011 
    1012         return(total);
    1013 }
    1014 
    1015 /* Skip a file, even if it includes a long file name? */
    1016 static int skip_file(int skipsize)
    1017 {
    1018         int dsize = skipsize;
    1019 
    1020         DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
    1021 
    1022         /* FIXME, we should skip more than one block at a time */
    1023 
    1024         while (dsize > 0) {
    1025                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
    1026                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
    1027                         return(False);
    1028                 }
    1029                 dsize -= TBLOCK;
    1030         }
    1031 
    1032         return(True);
    1033 }
    1034 
    1035 /*************************************************************
    1036  Get a file from the tar file and store it.
    1037  When this is called, tarbuf already contains the first
    1038  file block. This is a bit broken & needs fixing.
    1039 **************************************************************/
    1040 
    1041 static int get_file(file_info2 finfo)
    1042 {
    1043         uint16_t fnum = (uint16_t) -1;
    1044         int dsize = 0, bpos = 0;
    1045         uint64_t rsize = 0, pos = 0;
    1046         NTSTATUS status;
    1047 
    1048         DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
    1049 
    1050         if (!ensurepath(finfo.name)) {
    1051                 DEBUG(0, ("abandoning restore\n"));
    1052                 return False;
    1053         }
    1054 
    1055         status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
    1056         if (!NT_STATUS_IS_OK(status)) {
    1057                 DEBUG(0, ("abandoning restore\n"));
    1058                 return False;
    1059         }
    1060 
    1061         /* read the blocks from the tar file and write to the remote file */
    1062 
    1063         rsize = finfo.size;  /* This is how much to write */
    1064 
    1065         while (rsize > 0) {
    1066 
    1067                 /* We can only write up to the end of the buffer */
    1068                 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
    1069                 dsize = MIN(dsize, rsize);  /* Should be only what is left */
    1070                 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
    1071 
    1072                 status = cli_writeall(cli, fnum, 0,
    1073                                       (uint8_t *)(buffer_p + bpos), pos,
    1074                                       dsize, NULL);
    1075                 if (!NT_STATUS_IS_OK(status)) {
    1076                         DEBUG(0, ("Error writing remote file: %s\n",
    1077                                   nt_errstr(status)));
    1078                         return 0;
    1079                 }
    1080 
    1081                 rsize -= dsize;
    1082                 pos += dsize;
    1083 
    1084                 /* Now figure out how much to move in the buffer */
    1085 
    1086                 /* FIXME, we should skip more than one block at a time */
    1087 
    1088                 /* First, skip any initial part of the part written that is left over */
    1089                 /* from the end of the first TBLOCK                                   */
    1090 
    1091                 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
    1092                         dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
    1093                         bpos = 0;
    1094 
    1095                         if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
    1096                                 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
    1097                                 return False;
    1098                         }
    1099                 }
    1100 
    1101                 /*
    1102                  * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
    1103                  * If the file being extracted is an exact multiple of
    1104                  * TBLOCK bytes then we don't want to extract the next
    1105                  * block from the tarfile here, as it will be done in
    1106                  * the caller of get_file().
    1107                  */
    1108 
    1109                 while (((rsize != 0) && (dsize >= TBLOCK)) ||
    1110                                 ((rsize == 0) && (dsize > TBLOCK))) {
    1111 
    1112                         if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
    1113                                 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
    1114                                 return False;
    1115                         }
    1116 
    1117                         dsize -= TBLOCK;
    1118                 }
    1119                 bpos = dsize;
    1120         }
    1121 
    1122         /* Now close the file ... */
    1123 
    1124         if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
    1125                 DEBUG(0, ("Error %s closing remote file\n",
    1126                         cli_errstr(cli)));
    1127                 return(False);
    1128         }
    1129 
    1130         /* Now we update the creation date ... */
    1131         DEBUG(5, ("Updating creation date on %s\n", finfo.name));
    1132 
    1133         if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
    1134                 if (tar_real_noisy) {
    1135                         DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
    1136                         /*return(False); */ /* Ignore, as Win95 does not allow changes */
    1137                 }
    1138         }
    1139 
    1140         ntarf++;
    1141         DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
    1142         return(True);
    1143 }
    1144 
    1145 /* Create a directory.  We just ensure that the path exists and return as there
    1146    is no file associated with a directory
    1147 */
    1148 static int get_dir(file_info2 finfo)
    1149 {
    1150         DEBUG(0, ("restore directory %s\n", finfo.name));
    1151 
    1152         if (!ensurepath(finfo.name)) {
    1153                 DEBUG(0, ("Problems creating directory\n"));
    1154                 return(False);
    1155         }
    1156         ntarf++;
    1157         return(True);
    1158 }
    1159 
    1160 /* Get a file with a long file name ... first file has file name, next file
    1161    has the data. We only want the long file name, as the loop in do_tarput
    1162    will deal with the rest.
    1163 */
    1164 static char *get_longfilename(file_info2 finfo)
    1165 {
    1166         /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
    1167          * header call. */
    1168         int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
    1169         char *longname = (char *)SMB_MALLOC(namesize);
    1170         int offset = 0, left = finfo.size;
    1171         bool first = True;
    1172 
    1173         DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
    1174         DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
    1175 
    1176         if (longname == NULL) {
    1177                 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
    1178                 return(NULL);
    1179         }
    1180 
    1181         /* First, add cur_dir to the long file name */
    1182 
    1183         if (strlen(client_get_cur_dir()) > 0) {
    1184                 strncpy(longname, client_get_cur_dir(), namesize);
    1185                 offset = strlen(client_get_cur_dir());
    1186         }
    1187 
    1188         /* Loop through the blocks picking up the name */
    1189 
    1190         while (left > 0) {
    1191                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
    1192                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
    1193                         SAFE_FREE(longname);
    1194                         return(NULL);
    1195                 }
    1196 
    1197                 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
    1198                 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
    1199 
    1200                 offset += TBLOCK;
    1201                 left -= TBLOCK;
    1202         }
    1203 
    1204         return(longname);
    1205 }
    1206 
    1207 static void do_tarput(void)
    1208 {
    1209         file_info2 finfo;
    1210         struct timespec tp_start;
    1211         char *longfilename = NULL, linkflag;
    1212         int skip = False;
    1213 
    1214         ZERO_STRUCT(finfo);
    1215 
    1216         clock_gettime_mono(&tp_start);
    1217         DEBUG(5, ("RJS do_tarput called ...\n"));
    1218 
    1219         buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
    1220 
    1221         /* Now read through those files ... */
    1222         while (True) {
    1223                 /* Get us to the next block, or the first block first time around */
    1224                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
    1225                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
    1226                         SAFE_FREE(longfilename);
    1227                         return;
    1228                 }
    1229 
    1230                 DEBUG(5, ("Reading the next header ...\n"));
    1231 
    1232                 switch (readtarheader((union hblock *) buffer_p,
    1233                                         &finfo, client_get_cur_dir())) {
    1234                         case -2:    /* Hmm, not good, but not fatal */
    1235                                 DEBUG(0, ("Skipping %s...\n", finfo.name));
    1236                                 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
    1237                                         DEBUG(0, ("Short file, bailing out...\n"));
    1238                                         SAFE_FREE(longfilename);
    1239                                         return;
    1240                                 }
    1241                                 break;
    1242 
    1243                         case -1:
    1244                                 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
    1245                                 SAFE_FREE(longfilename);
    1246                                 return;
    1247 
    1248                         case 0: /* chksum is zero - looks like an EOF */
    1249                                 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
    1250                                 SAFE_FREE(longfilename);
    1251                                 return;        /* Hmmm, bad here ... */
    1252 
    1253                         default:
    1254                                 /* No action */
    1255                                 break;
    1256                 }
    1257 
    1258                 /* Now, do we have a long file name? */
    1259                 if (longfilename != NULL) {
    1260                         SAFE_FREE(finfo.name);   /* Free the space already allocated */
    1261                         finfo.name = longfilename;
    1262                         longfilename = NULL;
    1263                 }
    1264 
    1265                 /* Well, now we have a header, process the file ...            */
    1266                 /* Should we skip the file? We have the long name as well here */
    1267                 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
    1268                                         (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
    1269 
    1270                 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
    1271                 if (skip) {
    1272                         skip_file(finfo.size);
    1273                         continue;
    1274                 }
    1275 
    1276                 /* We only get this far if we should process the file */
    1277                 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
    1278                 switch (linkflag) {
    1279                         case '0':  /* Should use symbolic names--FIXME */
    1280                                 /*
    1281                                  * Skip to the next block first, so we can get the file, FIXME, should
    1282                                  * be in get_file ...
    1283                                  * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
    1284                                  * Fixes bug where file size in tarfile is zero.
    1285                                  */
    1286                                 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
    1287                                         DEBUG(0, ("Short file, bailing out...\n"));
    1288                                         return;
    1289                                 }
    1290                                 if (!get_file(finfo)) {
    1291                                         DEBUG(0, ("Abandoning restore\n"));
    1292                                         return;
    1293                                 }
    1294                                 break;
    1295                         case '5':
    1296                                 if (!get_dir(finfo)) {
    1297                                         DEBUG(0, ("Abandoning restore \n"));
    1298                                         return;
    1299                                 }
    1300                                 break;
    1301                         case 'L':
    1302                                 SAFE_FREE(longfilename);
    1303                                 longfilename = get_longfilename(finfo);
    1304                                 if (!longfilename) {
    1305                                         DEBUG(0, ("abandoning restore\n"));
    1306                                         return;
    1307                                 }
    1308                                 DEBUG(5, ("Long file name: %s\n", longfilename));
    1309                                 break;
    1310 
    1311                         default:
    1312                                 skip_file(finfo.size);  /* Don't handle these yet */
    1313                                 break;
    1314                 }
    1315         }
    1316 }
    1317 
    1318 /*
    1319  * samba interactive commands
    1320  */
    1321 
    1322 /****************************************************************************
    1323 Blocksize command
    1324 ***************************************************************************/
     1748        if (do_remove_prefix) {
     1749                /* /path */
     1750                if (path[0] == '/' || path[0] == '\\') {
     1751                        from += 1;
     1752                }
     1753
     1754                /* ./path */
     1755                if (path[1] != '\0' && path[0] == '.' && (path[1] == '/' || path[1] == '\\')) {
     1756                        from += 2;
     1757                }
     1758        }
     1759
     1760        /* replace / with \ */
     1761        while (from[0] != '\0') {
     1762                if (from[0] == '/') {
     1763                        to[0] = '\\';
     1764                } else {
     1765                        to[0] = from[0];
     1766                }
     1767
     1768                from++;
     1769                to++;
     1770        }
     1771        to[0] = '\0';
     1772
     1773        return path;
     1774}
     1775
     1776/**
     1777 * path_base_name - return @path basename
     1778 *
     1779 * If @path doesn't contain any directory separator return NULL.
     1780 */
     1781static NTSTATUS path_base_name(TALLOC_CTX *ctx, const char *path, char **_base)
     1782{
     1783        char *base = NULL;
     1784        int last = -1;
     1785        int i;
     1786
     1787        for (i = 0; path[i]; i++) {
     1788                if (path[i] == '\\' || path[i] == '/') {
     1789                        last = i;
     1790                }
     1791        }
     1792
     1793        if (last >= 0) {
     1794                base = talloc_strdup(ctx, path);
     1795                if (base == NULL) {
     1796                        return NT_STATUS_NO_MEMORY;
     1797                }
     1798
     1799                base[last] = 0;
     1800        }
     1801
     1802        *_base = base;
     1803        return NT_STATUS_OK;
     1804}
     1805
     1806#else
     1807
     1808#define NOT_IMPLEMENTED DEBUG(0, ("tar mode not compiled. build with --with-libarchive\n"))
    13251809
    13261810int cmd_block(void)
    13271811{
    1328         TALLOC_CTX *ctx = talloc_tos();
    1329         char *buf;
    1330         int block;
    1331 
    1332         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
    1333                 DEBUG(0, ("blocksize <n>\n"));
    1334                 return 1;
    1335         }
    1336 
    1337         block=atoi(buf);
    1338         if (block < 0 || block > 65535) {
    1339                 DEBUG(0, ("blocksize out of range"));
    1340                 return 1;
    1341         }
    1342 
    1343         blocksize=block;
    1344         DEBUG(2,("blocksize is now %d\n", blocksize));
    1345         return 0;
    1346 }
    1347 
    1348 /****************************************************************************
    1349 command to set incremental / reset mode
    1350 ***************************************************************************/
     1812        NOT_IMPLEMENTED;
     1813        return 1;
     1814}
    13511815
    13521816int cmd_tarmode(void)
    13531817{
    1354         TALLOC_CTX *ctx = talloc_tos();
    1355         char *buf;
    1356 
    1357         while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
    1358                 if (strequal(buf, "full"))
    1359                         tar_inc=False;
    1360                 else if (strequal(buf, "inc"))
    1361                         tar_inc=True;
    1362                 else if (strequal(buf, "reset"))
    1363                         tar_reset=True;
    1364                 else if (strequal(buf, "noreset"))
    1365                         tar_reset=False;
    1366                 else if (strequal(buf, "system"))
    1367                         tar_system=True;
    1368                 else if (strequal(buf, "nosystem"))
    1369                         tar_system=False;
    1370                 else if (strequal(buf, "hidden"))
    1371                         tar_hidden=True;
    1372                 else if (strequal(buf, "nohidden"))
    1373                         tar_hidden=False;
    1374                 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
    1375                         tar_noisy=True;
    1376                 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
    1377                         tar_noisy=False;
    1378                 else
    1379                         DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
    1380                 TALLOC_FREE(buf);
    1381         }
    1382 
    1383         DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
    1384                         tar_inc ? "incremental" : "full",
    1385                         tar_system ? "system" : "nosystem",
    1386                         tar_hidden ? "hidden" : "nohidden",
    1387                         tar_reset ? "reset" : "noreset",
    1388                         tar_noisy ? "verbose" : "quiet"));
    1389         return 0;
    1390 }
    1391 
    1392 /****************************************************************************
    1393 Feeble attrib command
    1394 ***************************************************************************/
    1395 
    1396 int cmd_setmode(void)
    1397 {
    1398         TALLOC_CTX *ctx = talloc_tos();
    1399         char *q;
    1400         char *buf;
    1401         char *fname = NULL;
    1402         uint16 attra[2];
    1403         int direct=1;
    1404 
    1405         attra[0] = attra[1] = 0;
    1406 
    1407         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
    1408                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
    1409                 return 1;
    1410         }
    1411 
    1412         fname = talloc_asprintf(ctx,
    1413                                 "%s%s",
    1414                                 client_get_cur_dir(),
    1415                                 buf);
    1416         if (!fname) {
    1417                 return 1;
    1418         }
    1419 
    1420         while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
    1421                 q=buf;
    1422 
    1423                 while(*q) {
    1424                         switch (*q++) {
    1425                                 case '+':
    1426                                         direct=1;
    1427                                         break;
    1428                                 case '-':
    1429                                         direct=0;
    1430                                         break;
    1431                                 case 'r':
    1432                                         attra[direct]|=FILE_ATTRIBUTE_READONLY;
    1433                                         break;
    1434                                 case 'h':
    1435                                         attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
    1436                                         break;
    1437                                 case 's':
    1438                                         attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
    1439                                         break;
    1440                                 case 'a':
    1441                                         attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
    1442                                         break;
    1443                                 default:
    1444                                         DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
    1445                                         return 1;
    1446                         }
    1447                 }
    1448         }
    1449 
    1450         if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
    1451                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
    1452                 return 1;
    1453         }
    1454 
    1455         DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
    1456         do_setrattr(fname, attra[ATTRSET], ATTRSET);
    1457         do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
    1458         return 0;
    1459 }
    1460 
    1461 /**
    1462  Convert list of tokens to array; dependent on above routine.
    1463  Uses the global cmd_ptr from above - bit of a hack.
    1464 **/
    1465 
    1466 static char **toktocliplist(int *ctok, const char *sep)
    1467 {
    1468         char *s=(char *)cmd_ptr;
    1469         int ictok=0;
    1470         char **ret, **iret;
    1471 
    1472         if (!sep)
    1473                 sep = " \t\n\r";
    1474 
    1475         while(*s && strchr_m(sep,*s))
    1476                 s++;
    1477 
    1478         /* nothing left? */
    1479         if (!*s)
    1480                 return(NULL);
    1481 
    1482         do {
    1483                 ictok++;
    1484                 while(*s && (!strchr_m(sep,*s)))
    1485                         s++;
    1486                 while(*s && strchr_m(sep,*s))
    1487                         *s++=0;
    1488         } while(*s);
    1489 
    1490         *ctok=ictok;
    1491         s=(char *)cmd_ptr;
    1492 
    1493         if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
    1494                 return NULL;
    1495 
    1496         while(ictok--) {
    1497                 *iret++=s;
    1498                 if (ictok > 0) {
    1499                         while(*s++)
    1500                                 ;
    1501                         while(!*s)
    1502                                 s++;
    1503                 }
    1504         }
    1505 
    1506         ret[*ctok] = NULL;
    1507         return ret;
    1508 }
    1509 
    1510 /****************************************************************************
    1511 Principal command for creating / extracting
    1512 ***************************************************************************/
     1818        NOT_IMPLEMENTED;
     1819        return 1;
     1820}
    15131821
    15141822int cmd_tar(void)
    15151823{
    1516         TALLOC_CTX *ctx = talloc_tos();
    1517         char *buf;
    1518         char **argl = NULL;
    1519         int argcl = 0;
    1520         int ret;
    1521 
    1522         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
    1523                 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
    1524                 return 1;
    1525         }
    1526 
    1527         argl=toktocliplist(&argcl, NULL);
    1528         if (!tar_parseargs(argcl, argl, buf, 0)) {
    1529                 SAFE_FREE(argl);
    1530                 return 1;
    1531         }
    1532 
    1533         ret = process_tar();
    1534         SAFE_FREE(argl);
    1535         return ret;
    1536 }
    1537 
    1538 /****************************************************************************
    1539 Command line (option) version
    1540 ***************************************************************************/
    1541 
    1542 int process_tar(void)
    1543 {
    1544         TALLOC_CTX *ctx = talloc_tos();
    1545         int rc = 0;
    1546         initarbuf();
    1547         switch(tar_type) {
    1548                 case 'x':
    1549 
    1550 #if 0
    1551                         do_tarput2();
    1552 #else
    1553                         do_tarput();
     1824        NOT_IMPLEMENTED;
     1825        return 1;
     1826}
     1827
     1828int tar_process(struct tar* tar)
     1829{
     1830        NOT_IMPLEMENTED;
     1831        return 1;
     1832}
     1833
     1834int tar_parse_args(struct tar *tar, const char *flag, const char **val, int valsize)
     1835{
     1836        NOT_IMPLEMENTED;
     1837        return 1;
     1838}
     1839
     1840bool tar_to_process(struct tar *tar)
     1841{
     1842        return false;
     1843}
     1844
     1845struct tar *tar_get_ctx()
     1846{
     1847        return NULL;
     1848}
     1849
    15541850#endif
    1555                         SAFE_FREE(tarbuf);
    1556                         close(tarhandle);
    1557                         break;
    1558                 case 'r':
    1559                 case 'c':
    1560                         if (clipn && tar_excl) {
    1561                                 int i;
    1562                                 char *tarmac = NULL;
    1563 
    1564                                 for (i=0; i<clipn; i++) {
    1565                                         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
    1566 
    1567                                         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
    1568                                                 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
    1569                                         }
    1570 
    1571                                         if (strrchr_m(cliplist[i], '\\')) {
    1572                                                 char *p;
    1573                                                 char saved_char;
    1574                                                 char *saved_dir = talloc_strdup(ctx,
    1575                                                                         client_get_cur_dir());
    1576                                                 if (!saved_dir) {
    1577                                                         return 1;
    1578                                                 }
    1579 
    1580                                                 if (*cliplist[i]=='\\') {
    1581                                                         tarmac = talloc_strdup(ctx,
    1582                                                                         cliplist[i]);
    1583                                                 } else {
    1584                                                         tarmac = talloc_asprintf(ctx,
    1585                                                                         "%s%s",
    1586                                                                         client_get_cur_dir(),
    1587                                                                         cliplist[i]);
    1588                                                 }
    1589                                                 if (!tarmac) {
    1590                                                         return 1;
    1591                                                 }
    1592                                                 /*
    1593                                                  * Strip off the last \\xxx
    1594                                                  * xxx element of tarmac to set
    1595                                                  * it as current directory.
    1596                                                  */
    1597                                                 p = strrchr_m(tarmac, '\\');
    1598                                                 if (!p) {
    1599                                                         return 1;
    1600                                                 }
    1601                                                 saved_char = p[1];
    1602                                                 p[1] = '\0';
    1603 
    1604                                                 client_set_cur_dir(tarmac);
    1605 
    1606                                                 /*
    1607                                                  * Restore the character we
    1608                                                  * just replaced to
    1609                                                  * put the pathname
    1610                                                  * back as it was.
    1611                                                  */
    1612                                                 p[1] = saved_char;
    1613 
    1614                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
    1615                                                 do_list(tarmac,attribute,do_tar, False, True);
    1616 
    1617                                                 client_set_cur_dir(saved_dir);
    1618 
    1619                                                 TALLOC_FREE(saved_dir);
    1620                                                 TALLOC_FREE(tarmac);
    1621                                         } else {
    1622                                                 tarmac = talloc_asprintf(ctx,
    1623                                                                 "%s%s",
    1624                                                                 client_get_cur_dir(),
    1625                                                                 cliplist[i]);
    1626                                                 if (!tarmac) {
    1627                                                         return 1;
    1628                                                 }
    1629                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
    1630                                                 do_list(tarmac,attribute,do_tar, False, True);
    1631                                                 TALLOC_FREE(tarmac);
    1632                                         }
    1633                                 }
    1634                         } else {
    1635                                 char *mask = talloc_asprintf(ctx,
    1636                                                         "%s\\*",
    1637                                                         client_get_cur_dir());
    1638                                 if (!mask) {
    1639                                         return 1;
    1640                                 }
    1641                                 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
    1642                                 do_list(mask,attribute,do_tar,False, True);
    1643                                 TALLOC_FREE(mask);
    1644                         }
    1645 
    1646                         if (ntarf) {
    1647                                 dotareof(tarhandle);
    1648                         }
    1649                         close(tarhandle);
    1650                         SAFE_FREE(tarbuf);
    1651 
    1652                         DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
    1653                         DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
    1654                         break;
    1655         }
    1656 
    1657         if (must_free_cliplist) {
    1658                 int i;
    1659                 for (i = 0; i < clipn; ++i) {
    1660                         SAFE_FREE(cliplist[i]);
    1661                 }
    1662                 SAFE_FREE(cliplist);
    1663                 cliplist = NULL;
    1664                 clipn = 0;
    1665                 must_free_cliplist = False;
    1666         }
    1667         return rc;
    1668 }
    1669 
    1670 /****************************************************************************
    1671 Find a token (filename) in a clip list
    1672 ***************************************************************************/
    1673 
    1674 static int clipfind(char **aret, int ret, char *tok)
    1675 {
    1676         if (aret==NULL)
    1677                 return 0;
    1678 
    1679         /* ignore leading slashes or dots in token */
    1680         while(strchr_m("/\\.", *tok))
    1681                 tok++;
    1682 
    1683         while(ret--) {
    1684                 char *pkey=*aret++;
    1685 
    1686                 /* ignore leading slashes or dots in list */
    1687                 while(strchr_m("/\\.", *pkey))
    1688                         pkey++;
    1689 
    1690                 if (!strslashcmp(pkey, tok))
    1691                         return 1;
    1692         }
    1693         return 0;
    1694 }
    1695 
    1696 /****************************************************************************
    1697 Read list of files to include from the file and initialize cliplist
    1698 accordingly.
    1699 ***************************************************************************/
    1700 
    1701 static int read_inclusion_file(char *filename)
    1702 {
    1703         XFILE *inclusion = NULL;
    1704         char buf[PATH_MAX + 1];
    1705         char *inclusion_buffer = NULL;
    1706         int inclusion_buffer_size = 0;
    1707         int inclusion_buffer_sofar = 0;
    1708         char *p;
    1709         char *tmpstr;
    1710         int i;
    1711         int error = 0;
    1712 
    1713         clipn = 0;
    1714         buf[PATH_MAX] = '\0'; /* guarantee null-termination */
    1715         if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
    1716                 /* XXX It would be better to include a reason for failure, but without
    1717                  * autoconf, it's hard to use strerror, sys_errlist, etc.
    1718                  */
    1719                 DEBUG(0,("Unable to open inclusion file %s\n", filename));
    1720                 return 0;
    1721         }
    1722 
    1723         while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
    1724                 if (inclusion_buffer == NULL) {
    1725                         inclusion_buffer_size = 1024;
    1726                         if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
    1727                                 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
    1728                                 error = 1;
    1729                                 break;
    1730                         }
    1731                 }
    1732 
    1733                 if (buf[strlen(buf)-1] == '\n') {
    1734                         buf[strlen(buf)-1] = '\0';
    1735                 }
    1736 
    1737                 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
    1738                         inclusion_buffer_size *= 2;
    1739                         inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
    1740                         if (!inclusion_buffer) {
    1741                                 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
    1742                                                 inclusion_buffer_size));
    1743                                 error = 1;
    1744                                 break;
    1745                         }
    1746                 }
    1747 
    1748                 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
    1749                 inclusion_buffer_sofar += strlen(buf) + 1;
    1750                 clipn++;
    1751         }
    1752         x_fclose(inclusion);
    1753 
    1754         if (! error) {
    1755                 /* Allocate an array of clipn + 1 char*'s for cliplist */
    1756                 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
    1757                 if (cliplist == NULL) {
    1758                         DEBUG(0,("failure allocating memory for cliplist\n"));
    1759                         error = 1;
    1760                 } else {
    1761                         cliplist[clipn] = NULL;
    1762                         p = inclusion_buffer;
    1763                         for (i = 0; (! error) && (i < clipn); i++) {
    1764                                 /* set current item to NULL so array will be null-terminated even if
    1765                                                 * malloc fails below. */
    1766                                 cliplist[i] = NULL;
    1767                                 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
    1768                                         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
    1769                                         error = 1;
    1770                                 } else {
    1771                                         unfixtarname(tmpstr, p, strlen(p) + 1, True);
    1772                                         cliplist[i] = tmpstr;
    1773                                         if ((p = strchr_m(p, '\000')) == NULL) {
    1774                                                 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
    1775                                                 abort();
    1776                                         }
    1777                                 }
    1778                                 ++p;
    1779                         }
    1780                         must_free_cliplist = True;
    1781                 }
    1782         }
    1783 
    1784         SAFE_FREE(inclusion_buffer);
    1785         if (error) {
    1786                 if (cliplist) {
    1787                         char **pp;
    1788                         /* We know cliplist is always null-terminated */
    1789                         for (pp = cliplist; *pp; ++pp) {
    1790                                 SAFE_FREE(*pp);
    1791                         }
    1792                         SAFE_FREE(cliplist);
    1793                         cliplist = NULL;
    1794                         must_free_cliplist = False;
    1795                 }
    1796                 return 0;
    1797         }
    1798 
    1799         /* cliplist and its elements are freed at the end of process_tar. */
    1800         return 1;
    1801 }
    1802 
    1803 /****************************************************************************
    1804 Parse tar arguments. Sets tar_type, tar_excl, etc.
    1805 ***************************************************************************/
    1806 
    1807 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
    1808 {
    1809         int newOptind = Optind;
    1810         char tar_clipfl='\0';
    1811 
    1812         /* Reset back to defaults - could be from interactive version
    1813          * reset mode and archive mode left as they are though
    1814          */
    1815         tar_type='\0';
    1816         tar_excl=True;
    1817         dry_run=False;
    1818 
    1819         while (*Optarg) {
    1820                 switch(*Optarg++) {
    1821                         case 'c':
    1822                                 tar_type='c';
    1823                                 break;
    1824                         case 'x':
    1825                                 if (tar_type=='c') {
    1826                                         printf("Tar must be followed by only one of c or x.\n");
    1827                                         return 0;
    1828                                 }
    1829                                 tar_type='x';
    1830                                 break;
    1831                         case 'b':
    1832                                 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
    1833                                         DEBUG(0,("Option b must be followed by valid blocksize\n"));
    1834                                         return 0;
    1835                                 } else {
    1836                                         Optind++;
    1837                                         newOptind++;
    1838                                 }
    1839                                 break;
    1840                         case 'g':
    1841                                 tar_inc=True;
    1842                                 break;
    1843                         case 'N':
    1844                                 if (Optind>=argc) {
    1845                                         DEBUG(0,("Option N must be followed by valid file name\n"));
    1846                                         return 0;
    1847                                 } else {
    1848                                         SMB_STRUCT_STAT stbuf;
    1849 
    1850                                         if (sys_stat(argv[Optind], &stbuf,
    1851                                                      false) == 0) {
    1852                                                 newer_than = convert_timespec_to_time_t(
    1853                                                         stbuf.st_ex_mtime);
    1854                                                 DEBUG(1,("Getting files newer than %s",
    1855                                                         time_to_asc(newer_than)));
    1856                                                 newOptind++;
    1857                                                 Optind++;
    1858                                         } else {
    1859                                                 DEBUG(0,("Error setting newer-than time\n"));
    1860                                                 return 0;
    1861                                         }
    1862                                 }
    1863                                 break;
    1864                         case 'a':
    1865                                 tar_reset=True;
    1866                                 break;
    1867                         case 'q':
    1868                                 tar_noisy=False;
    1869                                 break;
    1870                         case 'I':
    1871                                 if (tar_clipfl) {
    1872                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
    1873                                         return 0;
    1874                                 }
    1875                                 tar_clipfl='I';
    1876                                 break;
    1877                         case 'X':
    1878                                 if (tar_clipfl) {
    1879                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
    1880                                         return 0;
    1881                                 }
    1882                                 tar_clipfl='X';
    1883                                 break;
    1884                         case 'F':
    1885                                 if (tar_clipfl) {
    1886                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
    1887                                         return 0;
    1888                                 }
    1889                                 tar_clipfl='F';
    1890                                 break;
    1891                         case 'r':
    1892                                 DEBUG(0, ("tar_re_search set\n"));
    1893                                 tar_re_search = True;
    1894                                 break;
    1895                         case 'n':
    1896                                 if (tar_type == 'c') {
    1897                                         DEBUG(0, ("dry_run set\n"));
    1898                                         dry_run = True;
    1899                                 } else {
    1900                                         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
    1901                                         return 0;
    1902                                 }
    1903                                 break;
    1904                         default:
    1905                                 DEBUG(0,("Unknown tar option\n"));
    1906                                 return 0;
    1907                 }
    1908         }
    1909 
    1910         if (!tar_type) {
    1911                 printf("Option T must be followed by one of c or x.\n");
    1912                 return 0;
    1913         }
    1914 
    1915         /* tar_excl is true if cliplist lists files to be included.
    1916          * Both 'I' and 'F' mean include. */
    1917         tar_excl=tar_clipfl!='X';
    1918 
    1919         if (tar_clipfl=='F') {
    1920                 if (argc-Optind-1 != 1) {
    1921                         DEBUG(0,("Option F must be followed by exactly one filename.\n"));
    1922                         return 0;
    1923                 }
    1924                 newOptind++;
    1925                 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
    1926                 if (! read_inclusion_file(argv[Optind+1])) {
    1927                         return 0;
    1928                 }
    1929         } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
    1930                 char *tmpstr;
    1931                 char **tmplist;
    1932                 int clipcount;
    1933 
    1934                 cliplist=argv+Optind+1;
    1935                 clipn=argc-Optind-1;
    1936                 clipcount = clipn;
    1937 
    1938                 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
    1939                         DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
    1940                         return 0;
    1941                 }
    1942 
    1943                 for (clipcount = 0; clipcount < clipn; clipcount++) {
    1944 
    1945                         DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
    1946 
    1947                         if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
    1948                                 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
    1949                                 SAFE_FREE(tmplist);
    1950                                 return 0;
    1951                         }
    1952 
    1953                         unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
    1954                         tmplist[clipcount] = tmpstr;
    1955                         DEBUG(5, ("Processed an item, %s\n", tmpstr));
    1956 
    1957                         DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
    1958                 }
    1959 
    1960                 cliplist = tmplist;
    1961                 must_free_cliplist = True;
    1962 
    1963                 newOptind += clipn;
    1964         }
    1965 
    1966         if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
    1967                 /* Doing regular expression seaches not from an inclusion file. */
    1968                 clipn=argc-Optind-1;
    1969                 cliplist=argv+Optind+1;
    1970                 newOptind += clipn;
    1971         }
    1972 
    1973         if (Optind>=argc || !strcmp(argv[Optind], "-")) {
    1974                 /* Sets tar handle to either 0 or 1, as appropriate */
    1975                 tarhandle=(tar_type=='c');
    1976                 /*
    1977                  * Make sure that dbf points to stderr if we are using stdout for
    1978                  * tar output
    1979                  */
    1980                 if (tarhandle == 1)  {
    1981                         setup_logging("smbclient", DEBUG_STDERR);
    1982                 }
    1983                 if (!argv[Optind]) {
    1984                         DEBUG(0,("Must specify tar filename\n"));
    1985                         return 0;
    1986                 }
    1987                 if (!strcmp(argv[Optind], "-")) {
    1988                         newOptind++;
    1989                 }
    1990 
    1991         } else {
    1992                 if (tar_type=='c' && dry_run) {
    1993                         tarhandle=-1;
    1994                 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
    1995                                         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
    1996                         DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
    1997                         return(0);
    1998                 }
    1999                 newOptind++;
    2000         }
    2001 
    2002         return newOptind;
    2003 }
Note: See TracChangeset for help on using the changeset viewer.