Tidy up some missing checks for NULL in strlcpy.
[kai/samba.git] / source3 / client / clitar.c
index b01de5b8e705fc4a9c0486e0f7b69b7b3ac65552..80968a64d77ccd9c7b306ddf969603cd36c41d82 100644 (file)
@@ -1,28 +1,27 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
    Tar Extensions
    Copyright (C) Ricky Poulten 1995-1998
    Copyright (C) Richard Sharpe 1998
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 /* The following changes developed by Richard Sharpe for Canon Information
    Systems Research Australia (CISRA)
 
    1. Restore can now restore files with long file names
-   2. Save now saves directory information so that we can restore 
+   2. Save now saves directory information so that we can restore
       directory creation times
    3. tar now accepts both UNIX path names and DOS path names. I prefer
       those lovely /'s to those UGLY \'s :-)
 
 
 #include "includes.h"
+#include "system/filesys.h"
 #include "clitar.h"
-#include "../client/client_proto.h"
+#include "client/client_proto.h"
 
 static int clipfind(char **aret, int ret, char *tok);
 
 typedef struct file_info_struct file_info2;
 
 struct file_info_struct {
-       SMB_BIG_UINT size;
+       SMB_OFF_T size;
        uint16 mode;
        uid_t uid;
        gid_t gid;
        /* These times are normally kept in GMT */
-       time_t mtime;
-       time_t atime;
-       time_t ctime;
-       char *name;     /* This is dynamically allocate */
-
+       struct timespec mtime_ts;
+       struct timespec atime_ts;
+       struct timespec ctime_ts;
+       char *name;     /* This is dynamically allocated */
        file_info2 *next, *prev;  /* Used in the stack ... */
 };
 
@@ -63,6 +62,7 @@ typedef struct {
 } stack;
 
 #define SEPARATORS " \t\n\r"
+extern time_t newer_than;
 extern struct cli_state *cli;
 
 /* These defines are for the do_setrattr routine, to indicate
@@ -70,7 +70,7 @@ extern struct cli_state *cli;
 #define ATTRSET 1
 #define ATTRRESET 0
 
-static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
+static uint16 attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
 
 #ifndef CLIENT_TIMEOUT
 #define CLIENT_TIMEOUT (30*1000)
@@ -80,48 +80,46 @@ static char *tarbuf, *buffer_p;
 static int tp, ntarf, tbufsiz;
 static double ttarf;
 /* Incremental mode */
-static BOOL tar_inc=False;
+static bool tar_inc=False;
 /* Reset archive bit */
-static BOOL tar_reset=False;
+static bool tar_reset=False;
 /* Include / exclude mode (true=include, false=exclude) */
-static BOOL tar_excl=True;
+static bool tar_excl=True;
 /* use regular expressions for search on file names */
-static BOOL tar_re_search=False;
-#ifdef HAVE_REGEX_H
-regex_t *preg;
-#endif
+static bool tar_re_search=False;
 /* Do not dump anything, just calculate sizes */
-static BOOL dry_run=False;
+static bool dry_run=False;
 /* Dump files with System attribute */
-static BOOL tar_system=True;
+static bool tar_system=True;
 /* Dump files with Hidden attribute */
-static BOOL tar_hidden=True;
+static bool tar_hidden=True;
 /* Be noisy - make a catalogue */
-static BOOL tar_noisy=True;
-static BOOL tar_real_noisy=False;  /* Don't want to be really noisy by default */
+static bool tar_noisy=True;
+static bool tar_real_noisy=False;  /* Don't want to be really noisy by default */
 
 char tar_type='\0';
 static char **cliplist=NULL;
 static int clipn=0;
-static BOOL must_free_cliplist = False;
+static bool must_free_cliplist = False;
+extern const char *cmd_ptr;
 
-extern file_info def_finfo;
-extern BOOL lowercase;
+extern bool lowercase;
 extern uint16 cnum;
-extern BOOL readbraw_supported;
+extern bool readbraw_supported;
 extern int max_xmit;
-extern pstring cur_dir;
 extern int get_total_time_ms;
 extern int get_total_size;
 
 static int blocksize=20;
 static int tarhandle;
 
-static void writetarheader(int f,  const char *aname, SMB_BIG_UINT size, time_t mtime,
+static void writetarheader(int f,  const char *aname, uint64_t size, time_t mtime,
                           const char *amode, unsigned char ftype);
-static void do_atar(char *rname,char *lname,file_info *finfo1);
-static void do_tar(file_info *finfo);
-static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
+static NTSTATUS do_atar(const char *rname_in, char *lname,
+                   struct file_info *finfo1);
+static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
+                  const char *dir);
+static void oct_it(uint64_t value, int ndgs, char *p);
 static void fixtarname(char *tptr, const char *fp, size_t l);
 static int dotarbuf(int f, char *b, int n);
 static void dozerobuf(int f, int n);
@@ -129,37 +127,20 @@ static void dotareof(int f);
 static void initarbuf(void);
 
 /* restore functions */
-static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
+static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
 static long unoct(char *p, int ndgs);
 static void do_tarput(void);
-static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
+static void unfixtarname(char *tptr, char *fp, int l, bool first);
 
 /*
  * tar specific utitlities
  */
 
-/*******************************************************************
-Create  a string of size size+1 (for the null)
-*******************************************************************/
-
-static char *string_create_s(int size)
-{
-       char *tmp;
-
-       tmp = (char *)malloc(size+1);
-
-       if (tmp == NULL) {
-               DEBUG(0, ("Out of memory in string_create_s\n"));
-       }
-
-       return(tmp);
-}
-
 /****************************************************************************
 Write a tar header to buffer
 ****************************************************************************/
 
-static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
+static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
                           const char *amode, unsigned char ftype)
 {
        union hblock hb;
@@ -169,7 +150,7 @@ static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t m
        DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
 
        memset(hb.dummy, 0, sizeof(hb.dummy));
-  
+
        l=strlen(aname);
        /* We will be prepending a '.' in fixtarheader so use +2 to
         * take care of the . and terminating zero. JRA.
@@ -177,7 +158,7 @@ static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t m
        if (l+2 >= NAMSIZ) {
                /* write a GNU tar style long header */
                char *b;
-               b = (char *)malloc(l+TBLOCK+100);
+               b = (char *)SMB_MALLOC(l+TBLOCK+100);
                if (!b) {
                        DEBUG(0,("out of memory\n"));
                        exit(1);
@@ -199,12 +180,11 @@ static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t m
        /* write out a "standard" tar format header */
 
        hb.dbuf.name[NAMSIZ-1]='\0';
-       safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
-       oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
-       oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
-       oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
-       if (size > (SMB_BIG_UINT)077777777777LL) {    
-
+       strlcpy(hb.dbuf.mode, amode ? amode : "", sizeof(hb.dbuf.mode));
+       oct_it((uint64_t)0, 8, hb.dbuf.uid);
+       oct_it((uint64_t)0, 8, hb.dbuf.gid);
+       oct_it((uint64_t) size, 13, hb.dbuf.size);
+       if (size > (uint64_t)077777777777LL) {
                /* This is a non-POSIX compatible extention to store files
                        greater than 8GB. */
 
@@ -213,15 +193,15 @@ static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t m
                for (i = 8, jp=(char*)&size; i; i--)
                        hb.dbuf.size[i+3] = *(jp++);
        }
-       oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
+       oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
        memcpy(hb.dbuf.chksum, "        ", sizeof(hb.dbuf.chksum));
        memset(hb.dbuf.linkname, 0, NAMSIZ);
        hb.dbuf.linkflag=ftype;
-  
+
        for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
                chk+=(0xFF & *jp++);
 
-       oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
+       oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
        hb.dbuf.chksum[6] = '\0';
 
        (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
@@ -231,7 +211,7 @@ static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t m
 Read a tar header into a hblock structure, and validate
 ***************************************************************************/
 
-static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
+static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
 {
        long chk, fchk;
        int i;
@@ -262,16 +242,16 @@ static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
 
        if (fchk != chk) {
                DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
-               dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
+               dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
                return -1;
        }
 
-       if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
+       if ((finfo->name = SMB_MALLOC(strlen(prefix) + strlen(hb -> dbuf.name) + 4)) == NULL) {
                DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
                return(-1);
        }
 
-       safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
+       strlcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 4);
 
        /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
        unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
@@ -282,7 +262,7 @@ static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
                if (hb->dbuf.linkflag == 0) {
                        DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
                                finfo->name));
-               } else { 
+               } else {
                        if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
                                /* Do nothing here at the moment. do_tarput will handle this
                                        as long as the longlink gets back to it, as it has to advance 
@@ -294,10 +274,10 @@ of link other than a GNUtar Longlink - ignoring\n"));
                        }
                }
        }
-    
+
        if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
                                (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
-               finfo->mode=aDIR;
+               finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
        } else {
                finfo->mode=0; /* we don't care about mode at the moment, we'll
                                * just make it a regular file */
@@ -310,8 +290,9 @@ of link other than a GNUtar Longlink - ignoring\n"));
         * We only get the modification time of the file; set the creation time
         * from the mod. time, and the access time to current time
         */
-       finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
-       finfo->atime = time(NULL);
+       finfo->mtime_ts = finfo->ctime_ts =
+               convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
+       finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
        finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
 
        return True;
@@ -334,13 +315,13 @@ static int dotarbuf(int f, char *b, int n)
 
                diff=tbufsiz-tp;
                memcpy(tarbuf + tp, b, diff);
-               fail=fail && (1+write(f, tarbuf, tbufsiz));
+               fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
                n-=diff;
                b+=diff;
                tp=0;
 
                while (n >= tbufsiz) {
-                       fail=fail && (1 + write(f, b, tbufsiz));
+                       fail=fail && (1 + sys_write(f, b, tbufsiz));
                        n-=tbufsiz;
                        b+=tbufsiz;
                }
@@ -366,10 +347,13 @@ static void dozerobuf(int f, int n)
 
        if (dry_run)
                return;
-  
+
        if (n+tp >= tbufsiz) {
                memset(tarbuf+tp, 0, tbufsiz-tp);
-               write(f, tarbuf, tbufsiz);
+               if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
+                       DEBUG(0, ("dozerobuf: sys_write fail\n"));
+                       return;
+               }
                memset(tarbuf, 0, (tp+=n-tbufsiz));
        } else {
                memset(tarbuf+tp, 0, n);
@@ -385,7 +369,7 @@ static void initarbuf(void)
 {
        /* initialize tar buffer */
        tbufsiz=blocksize*TBLOCK;
-       tarbuf=malloc(tbufsiz);      /* FIXME: We might not get the buffer */
+       tarbuf=(char *)SMB_MALLOC(tbufsiz);      /* FIXME: We might not get the buffer */
 
        /* reset tar buffer pointer and tar file counter and total dumped */
        tp=0; ntarf=0; ttarf=0;
@@ -406,15 +390,19 @@ static void dotareof(int f)
        (void) dozerobuf(f, TBLOCK);
        (void) dozerobuf(f, TBLOCK);
 
-       if (sys_fstat(f, &stbuf) == -1) {
+       if (sys_fstat(f, &stbuf, false) == -1) {
                DEBUG(0, ("Couldn't stat file handle\n"));
                return;
        }
 
        /* Could be a pipe, in which case S_ISREG should fail,
                * and we should write out at full size */
-       if (tp > 0)
-               write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
+       if (tp > 0) {
+               size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
+               if (sys_write(f, tarbuf, towrite) != towrite) {
+                       DEBUG(0,("dotareof: sys_write fail\n"));
+               }
+       }
 }
 
 /****************************************************************************
@@ -436,20 +424,20 @@ static void fixtarname(char *tptr, const char *fp, size_t l)
 Convert from decimal to octal string
 ****************************************************************************/
 
-static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
+static void oct_it (uint64_t value, int ndgs, char *p)
 {
        /* Converts long to octal string, pads with leading zeros */
 
        /* skip final null, but do final space */
        --ndgs;
        p[--ndgs] = ' ';
+
        /* Loop does at least one digit */
        do {
                p[--ndgs] = '0' + (char) (value & 7);
                value >>= 3;
        } while (ndgs > 0 && value != 0);
+
        /* Do leading zeros */
        while (ndgs > 0)
                p[--ndgs] = '0';
@@ -475,8 +463,8 @@ static long unoct(char *p, int ndgs)
 }
 
 /****************************************************************************
-Compare two strings in a slash insensitive way, allowing s1 to match s2 
-if s1 is an "initial" string (up to directory marker).  Thus, if s2 is 
+Compare two strings in a slash insensitive way, allowing s1 to match s2
+if s1 is an "initial" string (up to directory marker).  Thus, if s2 is
 a file in any subdirectory of s1, declare a match.
 ***************************************************************************/
 
@@ -484,7 +472,7 @@ static int strslashcmp(char *s1, char *s2)
 {
        char *s1_0=s1;
 
-       while(*s1 && *s2 && (*s1 == *s2 || tolower(*s1) == tolower(*s2) ||
+       while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
                                (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
                s1++; s2++;
        }
@@ -510,70 +498,82 @@ static int strslashcmp(char *s1, char *s2)
 Ensure a remote path exists (make if necessary)
 ***************************************************************************/
 
-static BOOL ensurepath(char *fname)
+static bool ensurepath(const char *fname)
 {
        /* *must* be called with buffer ready malloc'ed */
        /* ensures path exists */
 
        char *partpath, *ffname;
-       char *p=fname, *basehack;
+       size_t fnamelen = strlen(fname)+1;
+       const char *p=fname;
+       char *basehack;
+       char *saveptr;
 
        DEBUG(5, ( "Ensurepath called with: %s\n", fname));
 
-       partpath = string_create_s(strlen(fname));
-       ffname = string_create_s(strlen(fname));
+       partpath = SMB_MALLOC(fnamelen);
+       ffname = SMB_MALLOC(fnamelen);
 
        if ((partpath == NULL) || (ffname == NULL)){
                DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
+               SAFE_FREE(partpath);
+               SAFE_FREE(ffname);
                return(False);
        }
 
        *partpath = 0;
 
-       /* fname copied to ffname so can strtok */
+       /* fname copied to ffname so can strtok_r */
 
-       safe_strcpy(ffname, fname, strlen(fname));
+       strlcpy(ffname, fname, fnamelen);
 
        /* do a `basename' on ffname, so don't try and make file name directory */
-       if ((basehack=strrchr_m(ffname, '\\')) == NULL)
+       if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
+               SAFE_FREE(partpath);
+               SAFE_FREE(ffname);
                return True;
-       else
+       } else {
                *basehack='\0';
+       }
 
-       p=strtok(ffname, "\\");
+       p=strtok_r(ffname, "\\", &saveptr);
 
        while (p) {
-               safe_strcat(partpath, p, strlen(fname) + 1);
+               strlcat(partpath, p, fnamelen);
 
-               if (!cli_chkpath(cli, partpath)) {
-                       if (!cli_mkdir(cli, partpath)) {
-                               DEBUG(0, ("Error mkdirhiering\n"));
+               if (!NT_STATUS_IS_OK(cli_chkpath(cli, partpath))) {
+                       if (!NT_STATUS_IS_OK(cli_mkdir(cli, partpath))) {
+                               SAFE_FREE(partpath);
+                               SAFE_FREE(ffname);
+                               DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
                                return False;
                        } else {
                                DEBUG(3, ("mkdirhiering %s\n", partpath));
                        }
                }
 
-               safe_strcat(partpath, "\\", strlen(fname) + 1);
-               p = strtok(NULL,"/\\");
+               strlcat(partpath, "\\", fnamelen);
+               p = strtok_r(NULL, "/\\", &saveptr);
        }
 
+       SAFE_FREE(partpath);
+       SAFE_FREE(ffname);
        return True;
 }
 
-static int padit(char *buf, int bufsize, int padsize)
+static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
 {
        int berr= 0;
        int bytestowrite;
-  
-       DEBUG(5, ("Padding with %d zeros\n", padsize));
-       memset(buf, 0, bufsize);
+
+       DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
+       memset(buf, 0, (size_t)bufsize);
        while( !berr && padsize > 0 ) {
-               bytestowrite= MIN(bufsize, padsize);
+               bytestowrite= (int)MIN(bufsize, padsize);
                berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
                padsize -= bytestowrite;
        }
-  
+
        return berr;
 }
 
@@ -581,7 +581,9 @@ static void do_setrattr(char *name, uint16 attr, int set)
 {
        uint16 oldattr;
 
-       if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
+       if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
+               return;
+       }
 
        if (set == ATTRSET) {
                attr |= oldattr;
@@ -589,7 +591,7 @@ static void do_setrattr(char *name, uint16 attr, int set)
                attr = oldattr & ~attr;
        }
 
-       if (!cli_setatr(cli, name, attr, 0)) {
+       if (!NT_STATUS_IS_OK(cli_setatr(cli, name, attr, 0))) {
                DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
        }
 }
@@ -598,109 +600,111 @@ static void do_setrattr(char *name, uint16 attr, int set)
 append one remote file to the tar file
 ***************************************************************************/
 
-static void do_atar(char *rname,char *lname,file_info *finfo1)
+static NTSTATUS do_atar(const char *rname_in, char *lname,
+                   struct file_info *finfo1)
 {
-       int fnum;
-       SMB_BIG_UINT nread=0;
+       uint16_t fnum = (uint16_t)-1;
+       uint64_t nread=0;
        char ftype;
        file_info2 finfo;
-       BOOL close_done = False;
-       BOOL shallitime=True;
-       char data[65520];
+       bool shallitime=True;
+       char *data = NULL;
        int read_size = 65520;
        int datalen=0;
-
-       struct timeval tp_start;
-
-       GetTimeOfDay(&tp_start);
+       char *rname = NULL;
+       TALLOC_CTX *ctx = talloc_stackframe();
+       NTSTATUS status = NT_STATUS_OK;
+       struct timespec tp_start;
+
+       clock_gettime_mono(&tp_start);
+
+       data = SMB_MALLOC_ARRAY(char, read_size);
+       if (!data) {
+               DEBUG(0,("do_atar: out of memory.\n"));
+               status = NT_STATUS_NO_MEMORY;
+               goto cleanup;
+       }
 
        ftype = '0'; /* An ordinary file ... */
 
-       if (finfo1) {
-               finfo.size  = finfo1 -> size;
-               finfo.mode  = finfo1 -> mode;
-               finfo.uid   = finfo1 -> uid;
-               finfo.gid   = finfo1 -> gid;
-               finfo.mtime = finfo1 -> mtime;
-               finfo.atime = finfo1 -> atime;
-               finfo.ctime = finfo1 -> ctime;
-               finfo.name  = finfo1 -> name;
-       } else {
-               finfo.size  = def_finfo.size;
-               finfo.mode  = def_finfo.mode;
-               finfo.uid   = def_finfo.uid;
-               finfo.gid   = def_finfo.gid;
-               finfo.mtime = def_finfo.mtime;
-               finfo.atime = def_finfo.atime;
-               finfo.ctime = def_finfo.ctime;
-               finfo.name  = def_finfo.name;
-       }
+       ZERO_STRUCT(finfo);
+
+       finfo.size  = finfo1 -> size;
+       finfo.mode  = finfo1 -> mode;
+       finfo.uid   = finfo1 -> uid;
+       finfo.gid   = finfo1 -> gid;
+       finfo.mtime_ts = finfo1 -> mtime_ts;
+       finfo.atime_ts = finfo1 -> atime_ts;
+       finfo.ctime_ts = finfo1 -> ctime_ts;
 
        if (dry_run) {
-               DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
+               DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
                                (double)finfo.size));
                shallitime=0;
                ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
                ntarf++;
-               return;
+               goto cleanup;
        }
 
-       fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
-
-       dos_clean_name(rname);
+       rname = clean_name(ctx, rname_in);
+       if (!rname) {
+               status = NT_STATUS_NO_MEMORY;
+               goto cleanup;
+       }
 
-       if (fnum == -1) {
+       status = cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum);
+       if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("%s opening remote file %s (%s)\n",
-                               cli_errstr(cli),rname, cur_dir));
-               return;
+                               cli_errstr(cli),rname, client_get_cur_dir()));
+               goto cleanup;
        }
 
-       finfo.name = string_create_s(strlen(rname));
+       finfo.name = smb_xstrdup(rname);
        if (finfo.name == NULL) {
                DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
-               return;
-       }
-
-       safe_strcpy(finfo.name,rname, strlen(rname));
-       if (!finfo1) {
-               if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
-                       DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
-                       return;
-               }
-               finfo.ctime = finfo.mtime;
+               status = NT_STATUS_NO_MEMORY;
+               goto cleanup;
        }
 
        DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
 
-       if (tar_inc && !(finfo.mode & aARCH)) {
+       if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE)) {
                DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
                shallitime=0;
-       } else if (!tar_system && (finfo.mode & aSYSTEM)) {
+       } else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM)) {
                DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
                shallitime=0;
-       } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
+       } else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN)) {
                DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
                shallitime=0;
        } else {
+               bool wrote_tar_header = False;
+
                DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
                        finfo.name, (double)finfo.size, lname));
-      
-               /* write a tar header, don't bother with mode - just set to 100644 */
-               writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
 
-               while (nread < finfo.size && !close_done) {
-             
+               do {
+
                        DEBUG(3,("nread=%.0f\n",(double)nread));
-             
+
                        datalen = cli_read(cli, fnum, data, nread, read_size);
-             
+
                        if (datalen == -1) {
                                DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
+                               status = cli_nt_error(cli);
                                break;
                        }
-             
+
                        nread += datalen;
 
+                       /* Only if the first read succeeds, write out the tar header. */
+                       if (!wrote_tar_header) {
+                               /* write a tar header, don't bother with mode - just set to 100644 */
+                               writetarheader(tarhandle, rname, finfo.size,
+                                       finfo.mtime_ts.tv_sec, "100644 \0", ftype);
+                               wrote_tar_header = True;
+                       }
+
                        /* if file size has increased since we made file size query, truncate
                                read so tar header for this file will be correct.
                        */
@@ -716,45 +720,56 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
 
                        if (dotarbuf(tarhandle,data,datalen) != datalen) {
                                DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
+                               status = map_nt_error_from_unix(errno);
                                break;
                        }
-             
-                       if (datalen == 0) {
+
+                       if ( (datalen == 0) && (finfo.size != 0) ) {
+                               status = NT_STATUS_UNSUCCESSFUL;
                                DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
                                break;
                        }
 
                        datalen=0;
-               }
+               } while ( nread < finfo.size );
+
+               if (wrote_tar_header) {
+                       /* pad tar file with zero's if we couldn't get entire file */
+                       if (nread < finfo.size) {
+                               DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
+                                                       (double)finfo.size, (int)nread));
+                               if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) {
+                                       status = map_nt_error_from_unix(errno);
+                                       DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
+                               }
+                       }
 
-               /* pad tar file with zero's if we couldn't get entire file */
-               if (nread < finfo.size) {
-                       DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
-                                               (double)finfo.size, (int)nread));
-                       if (padit(data, sizeof(data), finfo.size - nread))
-                               DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
-               }
+                       /* round tar file to nearest block */
+                       if (finfo.size % TBLOCK)
+                               dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
 
-               /* round tar file to nearest block */
-               if (finfo.size % TBLOCK)
-                       dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
-      
-               ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
-               ntarf++;
+                       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
+                       ntarf++;
+               } else {
+                       DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
+                       shallitime=0;
+                       status = NT_STATUS_UNSUCCESSFUL;
+               }
        }
-  
+
        cli_close(cli, fnum);
+       fnum = -1;
 
        if (shallitime) {
-               struct timeval tp_end;
+               struct timespec tp_end;
                int this_time;
 
                /* if shallitime is true then we didn't skip */
                if (tar_reset && !dry_run)
-                       (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
-      
-               GetTimeOfDay(&tp_end);
-               this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
+                       (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
+
+               clock_gettime_mono(&tp_end);
+               this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000;
                get_total_time_ms += this_time;
                get_total_size += finfo.size;
 
@@ -769,84 +784,122 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
                                finfo.size / MAX(0.001, (1.024*this_time)),
                                get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
        }
+
+  cleanup:
+
+       if (fnum != (uint16_t)-1) {
+               cli_close(cli, fnum);
+               fnum = -1;
+       }
+       TALLOC_FREE(ctx);
+       SAFE_FREE(data);
+       return status;
 }
 
 /****************************************************************************
 Append single file to tar file (or not)
 ***************************************************************************/
 
-static void do_tar(file_info *finfo)
+static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
+                  const char *dir)
 {
-       pstring rname;
+       TALLOC_CTX *ctx = talloc_stackframe();
+       NTSTATUS status = NT_STATUS_OK;
 
        if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
-               return;
+               return NT_STATUS_OK;
 
        /* Is it on the exclude list ? */
        if (!tar_excl && clipn) {
-               pstring exclaim;
-
-               DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
+               char *exclaim;
 
-               pstrcpy(exclaim, cur_dir);
-               *(exclaim+strlen(exclaim)-1)='\0';
+               DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
 
-               pstrcat(exclaim, "\\");
-               pstrcat(exclaim, finfo->name);
+               exclaim = talloc_asprintf(ctx,
+                               "%s\\%s",
+                               client_get_cur_dir(),
+                               finfo->name);
+               if (!exclaim) {
+                       return NT_STATUS_NO_MEMORY;
+               }
 
                DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
 
                if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
-#ifdef HAVE_REGEX_H
-                               (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
-#else
-                               (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
-#endif
+                               (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
                        DEBUG(3,("Skipping file %s\n", exclaim));
-                       return;
+                       TALLOC_FREE(exclaim);
+                       return NT_STATUS_OK;
                }
+               TALLOC_FREE(exclaim);
        }
 
-       if (finfo->mode & aDIR) {
-               pstring saved_curdir;
-               pstring mtar_mask;
+       if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
+               char *saved_curdir = NULL;
+               char *new_cd = NULL;
+               char *mtar_mask = NULL;
 
-               pstrcpy(saved_curdir, cur_dir);
+               saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
+               if (!saved_curdir) {
+                       return NT_STATUS_NO_MEMORY;
+               }
 
-               DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
+               DEBUG(5, ("strlen(cur_dir)=%d, \
 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
-                       (int)sizeof(cur_dir), (int)strlen(cur_dir),
-                       (int)strlen(finfo->name), finfo->name, cur_dir));
-
-               pstrcat(cur_dir,finfo->name);
-               pstrcat(cur_dir,"\\");
+                       (int)strlen(saved_curdir),
+                       (int)strlen(finfo->name), finfo->name, saved_curdir));
+
+               new_cd = talloc_asprintf(ctx,
+                               "%s%s\\",
+                               client_get_cur_dir(),
+                               finfo->name);
+               if (!new_cd) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               client_set_cur_dir(new_cd);
 
-               DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
+               DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
 
-               /* write a tar directory, don't bother with mode - just set it to
-                       * 40755 */
-               writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
+               /* write a tar directory, don't bother with mode - just
+                * set it to 40755 */
+               writetarheader(tarhandle, client_get_cur_dir(), 0,
+                               finfo->mtime_ts.tv_sec, "040755 \0", '5');
                if (tar_noisy) {
-                       DEBUG(0,("                directory %s\n", cur_dir));
+                       DEBUG(0,("                directory %s\n",
+                               client_get_cur_dir()));
                }
                ntarf++;  /* Make sure we have a file on there */
-               pstrcpy(mtar_mask,cur_dir);
-               pstrcat(mtar_mask,"*");
+               mtar_mask = talloc_asprintf(ctx,
+                               "%s*",
+                               client_get_cur_dir());
+               if (!mtar_mask) {
+                       return NT_STATUS_NO_MEMORY;
+               }
                DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
-               do_list(mtar_mask, attribute, do_tar, False, True);
-               pstrcpy(cur_dir,saved_curdir);
+               status = do_list(mtar_mask, attribute, do_tar, False, True);
+               client_set_cur_dir(saved_curdir);
+               TALLOC_FREE(saved_curdir);
+               TALLOC_FREE(new_cd);
+               TALLOC_FREE(mtar_mask);
        } else {
-               pstrcpy(rname,cur_dir);
-               pstrcat(rname,finfo->name);
-               do_atar(rname,finfo->name,finfo);
+               char *rname = talloc_asprintf(ctx,
+                                       "%s%s",
+                                       client_get_cur_dir(),
+                                       finfo->name);
+               if (!rname) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               status = do_atar(rname,finfo->name,finfo);
+               TALLOC_FREE(rname);
        }
+       return status;
 }
 
 /****************************************************************************
 Convert from UNIX to DOS file names
 ***************************************************************************/
 
-static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
+static void unfixtarname(char *tptr, char *fp, int l, bool first)
 {
        /* remove '.' from start of file name, convert from unix /'s to
         * dos \'s in path. Kill any absolute path names. But only if first!
@@ -863,9 +916,12 @@ static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
                        fp++;
                        l--;
                }
+               if (l <= 0) {
+                       return;
+               }
        }
 
-       safe_strcpy(tptr, fp, l);
+       strlcpy(tptr, fp, l);
        string_replace(tptr, '/', '\\');
 }
 
@@ -945,15 +1001,22 @@ static int skip_file(int skipsize)
 
 static int get_file(file_info2 finfo)
 {
-       int fnum = -1, pos = 0, dsize = 0, bpos = 0;
-       SMB_BIG_UINT rsize = 0;
+       uint16_t fnum = (uint16_t) -1;
+       int pos = 0, dsize = 0, bpos = 0;
+       uint64_t rsize = 0;
+       NTSTATUS status;
 
        DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
 
-       if (ensurepath(finfo.name) && 
-                       (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
+       if (!ensurepath(finfo.name)) {
                DEBUG(0, ("abandoning restore\n"));
-               return(False);
+               return False;
+       }
+
+       status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("abandoning restore\n"));
+               return False;
        }
 
        /* read the blocks from the tar file and write to the remote file */
@@ -967,8 +1030,12 @@ static int get_file(file_info2 finfo)
                dsize = MIN(dsize, rsize);  /* Should be only what is left */
                DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
 
-               if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
-                       DEBUG(0, ("Error writing remote file\n"));
+               status = cli_writeall(cli, fnum, 0,
+                                     (uint8_t *)(buffer_p + bpos), pos,
+                                     dsize, NULL);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("Error writing remote file: %s\n",
+                                 nt_errstr(status)));
                        return 0;
                }
 
@@ -1015,15 +1082,16 @@ static int get_file(file_info2 finfo)
 
        /* Now close the file ... */
 
-       if (!cli_close(cli, fnum)) {
-               DEBUG(0, ("Error closing remote file\n"));
+       if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
+               DEBUG(0, ("Error %s closing remote file\n",
+                       cli_errstr(cli)));
                return(False);
        }
 
        /* Now we update the creation date ... */
        DEBUG(5, ("Updating creation date on %s\n", finfo.name));
 
-       if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
+       if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
                if (tar_real_noisy) {
                        DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
                        /*return(False); */ /* Ignore, as Win95 does not allow changes */
@@ -1036,7 +1104,7 @@ static int get_file(file_info2 finfo)
 }
 
 /* Create a directory.  We just ensure that the path exists and return as there
-   is no file associated with a directory 
+   is no file associated with a directory
 */
 static int get_dir(file_info2 finfo)
 {
@@ -1054,12 +1122,14 @@ static int get_dir(file_info2 finfo)
    has the data. We only want the long file name, as the loop in do_tarput
    will deal with the rest.
 */
-static char * get_longfilename(file_info2 finfo)
+static char *get_longfilename(file_info2 finfo)
 {
-       int namesize = strlen(finfo.name) + strlen(cur_dir) + 2;
-       char *longname = malloc(namesize);
+       /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
+        * header call. */
+       int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
+       char *longname = (char *)SMB_MALLOC(namesize);
        int offset = 0, left = finfo.size;
-       BOOL first = True;
+       bool first = True;
 
        DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
        DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
@@ -1071,9 +1141,9 @@ static char * get_longfilename(file_info2 finfo)
 
        /* First, add cur_dir to the long file name */
 
-       if (strlen(cur_dir) > 0) {
-               strncpy(longname, cur_dir, namesize);
-               offset = strlen(cur_dir);
+       if (strlen(client_get_cur_dir()) > 0) {
+               strncpy(longname, client_get_cur_dir(), namesize);
+               offset = strlen(client_get_cur_dir());
        }
 
        /* Loop through the blocks picking up the name */
@@ -1081,10 +1151,12 @@ static char * get_longfilename(file_info2 finfo)
        while (left > 0) {
                if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
                        DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+                       SAFE_FREE(longname);
                        return(NULL);
                }
 
-               unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
+               unfixtarname(longname + offset, buffer_p,
+                       namesize - offset, first--);
                DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
 
                offset += TBLOCK;
@@ -1097,11 +1169,13 @@ static char * get_longfilename(file_info2 finfo)
 static void do_tarput(void)
 {
        file_info2 finfo;
-       struct timeval tp_start;
+       struct timespec tp_start;
        char *longfilename = NULL, linkflag;
        int skip = False;
 
-       GetTimeOfDay(&tp_start);
+       ZERO_STRUCT(finfo);
+
+       clock_gettime_mono(&tp_start);
        DEBUG(5, ("RJS do_tarput called ...\n"));
 
        buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
@@ -1111,26 +1185,31 @@ static void do_tarput(void)
                /* Get us to the next block, or the first block first time around */
                if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
                        DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+                       SAFE_FREE(longfilename);
                        return;
                }
 
                DEBUG(5, ("Reading the next header ...\n"));
 
-               switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
+               switch (readtarheader((union hblock *) buffer_p,
+                                       &finfo, client_get_cur_dir())) {
                        case -2:    /* Hmm, not good, but not fatal */
                                DEBUG(0, ("Skipping %s...\n", finfo.name));
                                if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
                                        DEBUG(0, ("Short file, bailing out...\n"));
+                                       SAFE_FREE(longfilename);
                                        return;
                                }
                                break;
 
                        case -1:
                                DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
+                               SAFE_FREE(longfilename);
                                return;
 
                        case 0: /* chksum is zero - looks like an EOF */
                                DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
+                               SAFE_FREE(longfilename);
                                return;        /* Hmmm, bad here ... */
 
                        default: 
@@ -1148,11 +1227,7 @@ static void do_tarput(void)
                /* Well, now we have a header, process the file ...            */
                /* Should we skip the file? We have the long name as well here */
                skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
-#ifdef HAVE_REGEX_H
-                                       (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
-#else
-                                       (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
-#endif
+                                       (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
 
                DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
                if (skip) {
@@ -1164,7 +1239,7 @@ static void do_tarput(void)
                linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
                switch (linkflag) {
                        case '0':  /* Should use symbolic names--FIXME */
-                               /* 
+                               /*
                                 * Skip to the next block first, so we can get the file, FIXME, should
                                 * be in get_file ...
                                 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
@@ -1186,6 +1261,7 @@ static void do_tarput(void)
                                }
                                break;
                        case 'L':
+                               SAFE_FREE(longfilename);
                                longfilename = get_longfilename(finfo);
                                if (!longfilename) {
                                        DEBUG(0, ("abandoning restore\n"));
@@ -1211,10 +1287,11 @@ Blocksize command
 
 int cmd_block(void)
 {
-       fstring buf;
+       TALLOC_CTX *ctx = talloc_tos();
+       char *buf;
        int block;
 
-       if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+       if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
                DEBUG(0, ("blocksize <n>\n"));
                return 1;
        }
@@ -1227,7 +1304,6 @@ int cmd_block(void)
 
        blocksize=block;
        DEBUG(2,("blocksize is now %d\n", blocksize));
-
        return 0;
 }
 
@@ -1237,9 +1313,10 @@ command to set incremental / reset mode
 
 int cmd_tarmode(void)
 {
-       fstring buf;
+       TALLOC_CTX *ctx = talloc_tos();
+       char *buf;
 
-       while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+       while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
                if (strequal(buf, "full"))
                        tar_inc=False;
                else if (strequal(buf, "inc"))
@@ -1262,6 +1339,7 @@ int cmd_tarmode(void)
                        tar_noisy=False;
                else
                        DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
+               TALLOC_FREE(buf);
        }
 
        DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
@@ -1279,23 +1357,29 @@ Feeble attrib command
 
 int cmd_setmode(void)
 {
+       TALLOC_CTX *ctx = talloc_tos();
        char *q;
-       fstring buf;
-       pstring fname;
+       char *buf;
+       char *fname = NULL;
        uint16 attra[2];
        int direct=1;
 
        attra[0] = attra[1] = 0;
 
-       if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+       if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
                DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
                return 1;
        }
 
-       pstrcpy(fname, cur_dir);
-       pstrcat(fname, buf);
+       fname = talloc_asprintf(ctx,
+                               "%s%s",
+                               client_get_cur_dir(),
+                               buf);
+       if (!fname) {
+               return 1;
+       }
 
-       while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+       while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
                q=buf;
 
                while(*q) {
@@ -1307,16 +1391,16 @@ int cmd_setmode(void)
                                        direct=0;
                                        break;
                                case 'r':
-                                       attra[direct]|=aRONLY;
+                                       attra[direct]|=FILE_ATTRIBUTE_READONLY;
                                        break;
                                case 'h':
-                                       attra[direct]|=aHIDDEN;
+                                       attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
                                        break;
                                case 's':
-                                       attra[direct]|=aSYSTEM;
+                                       attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
                                        break;
                                case 'a':
-                                       attra[direct]|=aARCH;
+                                       attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
                                        break;
                                default:
                                        DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
@@ -1336,28 +1420,81 @@ int cmd_setmode(void)
        return 0;
 }
 
+/**
+ Convert list of tokens to array; dependent on above routine.
+ Uses the global cmd_ptr from above - bit of a hack.
+**/
+
+static char **toktocliplist(int *ctok, const char *sep)
+{
+       char *s=(char *)cmd_ptr;
+       int ictok=0;
+       char **ret, **iret;
+
+       if (!sep)
+               sep = " \t\n\r";
+
+       while(*s && strchr_m(sep,*s))
+               s++;
+
+       /* nothing left? */
+       if (!*s)
+               return(NULL);
+
+       do {
+               ictok++;
+               while(*s && (!strchr_m(sep,*s)))
+                       s++;
+               while(*s && strchr_m(sep,*s))
+                       *s++=0;
+       } while(*s);
+
+       *ctok=ictok;
+       s=(char *)cmd_ptr;
+
+       if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
+               return NULL;
+
+       while(ictok--) {
+               *iret++=s;
+               if (ictok > 0) {
+                       while(*s++)
+                               ;
+                       while(!*s)
+                               s++;
+               }
+       }
+
+       ret[*ctok] = NULL;
+       return ret;
+}
+
 /****************************************************************************
 Principal command for creating / extracting
 ***************************************************************************/
 
 int cmd_tar(void)
 {
-       fstring buf;
-       char **argl;
-       int argcl;
+       TALLOC_CTX *ctx = talloc_tos();
+       char *buf;
+       char **argl = NULL;
+       int argcl = 0;
+       int ret;
 
-       if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
+       if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
                DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
                return 1;
        }
 
        argl=toktocliplist(&argcl, NULL);
-       if (!tar_parseargs(argcl, argl, buf, 0))
+       if (!tar_parseargs(argcl, argl, buf, 0)) {
+               SAFE_FREE(argl);
                return 1;
+       }
 
-       process_tar();
+       ret = process_tar();
        SAFE_FREE(argl);
-       return 0;
+       return ret;
 }
 
 /****************************************************************************
@@ -1366,6 +1503,8 @@ Command line (option) version
 
 int process_tar(void)
 {
+       TALLOC_CTX *ctx = talloc_tos();
+       int rc = 0;
        initarbuf();
        switch(tar_type) {
                case 'x':
@@ -1382,7 +1521,7 @@ int process_tar(void)
                case 'c':
                        if (clipn && tar_excl) {
                                int i;
-                               pstring tarmac;
+                               char *tarmac = NULL;
 
                                for (i=0; i<clipn; i++) {
                                        DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
@@ -1390,44 +1529,88 @@ int process_tar(void)
                                        if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
                                                *(cliplist[i]+strlen(cliplist[i])-1)='\0';
                                        }
-       
+
                                        if (strrchr_m(cliplist[i], '\\')) {
-                                               pstring saved_dir;
-         
-                                               pstrcpy(saved_dir, cur_dir);
-         
+                                               char *p;
+                                               char saved_char;
+                                               char *saved_dir = talloc_strdup(ctx,
+                                                                       client_get_cur_dir());
+                                               if (!saved_dir) {
+                                                       return 1;
+                                               }
+
                                                if (*cliplist[i]=='\\') {
-                                                       pstrcpy(tarmac, cliplist[i]);
+                                                       tarmac = talloc_strdup(ctx,
+                                                                       cliplist[i]);
                                                } else {
-                                                       pstrcpy(tarmac, cur_dir);
-                                                       pstrcat(tarmac, cliplist[i]);
+                                                       tarmac = talloc_asprintf(ctx,
+                                                                       "%s%s",
+                                                                       client_get_cur_dir(),
+                                                                       cliplist[i]);
                                                }
-                                               pstrcpy(cur_dir, tarmac);
-                                               *(strrchr_m(cur_dir, '\\')+1)='\0';
+                                               if (!tarmac) {
+                                                       return 1;
+                                               }
+                                               /*
+                                                * Strip off the last \\xxx
+                                                * xxx element of tarmac to set
+                                                * it as current directory.
+                                                */
+                                               p = strrchr_m(tarmac, '\\');
+                                               if (!p) {
+                                                       return 1;
+                                               }
+                                               saved_char = p[1];
+                                               p[1] = '\0';
+
+                                               client_set_cur_dir(tarmac);
+
+                                               /*
+                                                * Restore the character we
+                                                * just replaced to
+                                                * put the pathname
+                                                * back as it was.
+                                                */
+                                               p[1] = saved_char;
 
                                                DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
                                                do_list(tarmac,attribute,do_tar, False, True);
-                                               pstrcpy(cur_dir,saved_dir);
+
+                                               client_set_cur_dir(saved_dir);
+
+                                               TALLOC_FREE(saved_dir);
+                                               TALLOC_FREE(tarmac);
                                        } else {
-                                               pstrcpy(tarmac, cur_dir);
-                                               pstrcat(tarmac, cliplist[i]);
+                                               tarmac = talloc_asprintf(ctx,
+                                                               "%s%s",
+                                                               client_get_cur_dir(),
+                                                               cliplist[i]);
+                                               if (!tarmac) {
+                                                       return 1;
+                                               }
                                                DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
                                                do_list(tarmac,attribute,do_tar, False, True);
+                                               TALLOC_FREE(tarmac);
                                        }
                                }
                        } else {
-                               pstring mask;
-                               pstrcpy(mask,cur_dir);
+                               char *mask = talloc_asprintf(ctx,
+                                                       "%s\\*",
+                                                       client_get_cur_dir());
+                               if (!mask) {
+                                       return 1;
+                               }
                                DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
-                               pstrcat(mask,"\\*");
                                do_list(mask,attribute,do_tar,False, True);
+                               TALLOC_FREE(mask);
                        }
-    
-                       if (ntarf)
+
+                       if (ntarf) {
                                dotareof(tarhandle);
+                       }
                        close(tarhandle);
                        SAFE_FREE(tarbuf);
-    
+
                        DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
                        DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
                        break;
@@ -1443,7 +1626,7 @@ int process_tar(void)
                clipn = 0;
                must_free_cliplist = False;
        }
-       return(0);
+       return rc;
 }
 
 /****************************************************************************
@@ -1502,32 +1685,29 @@ static int read_inclusion_file(char *filename)
        while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
                if (inclusion_buffer == NULL) {
                        inclusion_buffer_size = 1024;
-                       if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
+                       if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
                                DEBUG(0,("failure allocating buffer to read inclusion file\n"));
                                error = 1;
                                break;
                        }
                }
-    
+
                if (buf[strlen(buf)-1] == '\n') {
                        buf[strlen(buf)-1] = '\0';
                }
-    
+
                if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
-                       char *ib;
                        inclusion_buffer_size *= 2;
-                       ib = Realloc(inclusion_buffer,inclusion_buffer_size);
-                       if (! ib) {
+                       inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
+                       if (!inclusion_buffer) {
                                DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
                                                inclusion_buffer_size));
                                error = 1;
                                break;
-                       } else {
-                               inclusion_buffer = ib;
                        }
                }
-    
-               safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
+
+               strlcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
                inclusion_buffer_sofar += strlen(buf) + 1;
                clipn++;
        }
@@ -1535,7 +1715,7 @@ static int read_inclusion_file(char *filename)
 
        if (! error) {
                /* Allocate an array of clipn + 1 char*'s for cliplist */
-               cliplist = malloc((clipn + 1) * sizeof(char *));
+               cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
                if (cliplist == NULL) {
                        DEBUG(0,("failure allocating memory for cliplist\n"));
                        error = 1;
@@ -1546,7 +1726,7 @@ static int read_inclusion_file(char *filename)
                                /* set current item to NULL so array will be null-terminated even if
                                                * malloc fails below. */
                                cliplist[i] = NULL;
-                               if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
+                               if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
                                        DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
                                        error = 1;
                                } else {
@@ -1577,7 +1757,7 @@ static int read_inclusion_file(char *filename)
                }
                return 0;
        }
-  
+
        /* cliplist and its elements are freed at the end of process_tar. */
        return 1;
 }
@@ -1628,12 +1808,13 @@ int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
                                        return 0;
                                } else {
                                        SMB_STRUCT_STAT stbuf;
-                                       extern time_t newer_than;
-       
-                                       if (sys_stat(argv[Optind], &stbuf) == 0) {
-                                               newer_than = stbuf.st_mtime;
+
+                                       if (sys_stat(argv[Optind], &stbuf,
+                                                    false) == 0) {
+                                               newer_than = convert_timespec_to_time_t(
+                                                       stbuf.st_ex_mtime);
                                                DEBUG(1,("Getting files newer than %s",
-                                                       asctime(LocalTime(&newer_than))));
+                                                       time_to_asc(newer_than)));
                                                newOptind++;
                                                Optind++;
                                        } else {
@@ -1703,8 +1884,8 @@ int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
                        return 0;
                }
                newOptind++;
-               Optind++;
-               if (! read_inclusion_file(argv[Optind])) {
+               /* Optind points at the tar output file, Optind+1 at the inclusion file. */
+               if (! read_inclusion_file(argv[Optind+1])) {
                        return 0;
                }
        } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
@@ -1716,7 +1897,7 @@ int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
                clipn=argc-Optind-1;
                clipcount = clipn;
 
-               if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
+               if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
                        DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
                        return 0;
                }
@@ -1725,8 +1906,9 @@ int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
 
                        DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
 
-                       if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
+                       if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
                                DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
+                               SAFE_FREE(tmplist);
                                return 0;
                        }
 
@@ -1743,26 +1925,8 @@ int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
                newOptind += clipn;
        }
 
-       if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
-#ifdef HAVE_REGEX_H
-               int errcode;
-
-               if ((preg = (regex_t *)malloc(65536)) == NULL) {
-
-                       DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
-                       return;
-               }
-
-               if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
-                       char errstr[1024];
-                       size_t errlen;
-
-                       errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
-                       DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
-                       return;
-               }
-#endif
-
+       if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
+               /* Doing regular expression seaches not from an inclusion file. */
                clipn=argc-Optind-1;
                cliplist=argv+Optind+1;
                newOptind += clipn;
@@ -1776,7 +1940,7 @@ int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
                 * tar output
                 */
                if (tarhandle == 1)  {
-                       dbf = x_stderr;
+                       setup_logging("smbclient", DEBUG_STDERR);
                }
                if (!argv[Optind]) {
                        DEBUG(0,("Must specify tar filename\n"));
@@ -1787,11 +1951,7 @@ int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
                }
 
        } else {
-               if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0)) {
-                       if (!dry_run) {
-                               DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
-                               dry_run = True;
-                       }
+               if (tar_type=='c' && dry_run) {
                        tarhandle=-1;
                } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
                                        || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {