Rolling clitar.c back to the previous rev 1.22 as the current one
[samba.git] / source / client / clitar.c
index d5bca8c5bbb6e13687e5a73c109c72df2d28ee03..32731200b0d2a6f2e64e9ff14e04c4eb5dcefe92 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Tar Extensions
-   Copyright (C) Ricky Poulten 1995-1997
+   Copyright (C) Ricky Poulten 1995-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
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
+/* The following changes developed by Richard Sharpe for Canon Information
+   Systems Research Australia (CISRA) are Copyright (C) 1998 by CISRA and are 
+   made available under the terms of the GPL as listed above:
+
+   1. Restore can now restore files with long file names
+   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 "clitar.h"
+#include <regex.h>
 
 extern BOOL recurse;
 
@@ -48,6 +60,13 @@ BOOL tar_inc=False;
 BOOL tar_reset=False;
 /* Include / exclude mode (true=include, false=exclude) */
 BOOL tar_excl=True;
+/* Dump files with System attribute */
+BOOL tar_system=False;
+/* Dump files with Hidden attribute */
+BOOL tar_hidden=True;
+/* Be noisy - make a catalogue */
+BOOL tar_noisy=True;
+
 char tar_type='\0';
 static char **cliplist=NULL;
 static int clipn=0;
@@ -65,22 +84,15 @@ extern int Protocol;
 int blocksize=20;
 int tarhandle;
 
-static void writetarheader();
-static void do_atar();
-static void do_tar();
-static void oct_it();
-static void fixtarname();
-static int dotarbuf();
-static void dozerobuf();
-static void dotareof();
-static void initarbuf();
-static int do_setrattr();
-
-/* restore functions */
-static long readtarheader();
-static long unoct();
-static void do_tarput();
-static void unfixtarname();
+static void writetarheader(int f,  char *aname, int size, time_t mtime,
+                          char *amode, unsigned char ftype);
+
+/* Forward references. */
+static void fixtarname(char *tptr, char *fp, int l);
+static int dotarbuf(int f, char *b, int n);
+static void oct_it (long value, int ndgs, char *p);
+static long unoct(char *p, int ndgs);
+static void unfixtarname(char *tptr, char *fp, int l);
 
 /*
  * tar specific utitlities
@@ -90,19 +102,32 @@ static void unfixtarname();
 Write a tar header to buffer
 ****************************************************************************/
 static void writetarheader(int f,  char *aname, int size, time_t mtime,
-                   char *amode)
+                          char *amode, unsigned char ftype)
 {
   union hblock hb;
   int i, chk, l;
   char *jp;
 
+  DEBUG(5, ("WriteTarHdr, Type = %c, Name = %s\n", ftype, aname));
+
   memset(hb.dummy, 0, sizeof(hb.dummy));
   
   l=strlen(aname);
-  if (l >= NAMSIZ)
-    {
-      DEBUG(0, ("tar file %s name length exceeds NAMSIZ\n", aname));
-    }
+  if (l >= NAMSIZ) {
+         /* write a GNU tar style long header */
+         char *b;
+         b = (char *)malloc(l+TBLOCK+100);
+         if (!b) {
+                 DEBUG(0,("out of memory\n"));
+                 exit(1);
+         }
+         writetarheader(f, "/./@LongLink", l+1, 0, "     0 \0", 'L');
+         memset(b, 0, l+TBLOCK+100);
+         fixtarname(b, aname, l+1);
+         i = strlen(b)+1;
+         dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
+         free(b);
+  }
 
   /* use l + 1 to do the null too */
   fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
@@ -119,8 +144,8 @@ static void writetarheader(int f,  char *aname, int size, time_t mtime,
   oct_it((long) size, 13, hb.dbuf.size);
   oct_it((long) mtime, 13, hb.dbuf.mtime);
   memcpy(hb.dbuf.chksum, "        ", sizeof(hb.dbuf.chksum));
-  hb.dbuf.linkflag='0';
   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++);
 
@@ -173,14 +198,21 @@ static long readtarheader(union hblock *hb, file_info *finfo, char *prefix)
   unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
               strlen(hb->dbuf.name) + 1);
 
-/* can't handle links at present */
-  if (hb->dbuf.linkflag != '0') {
+/* can't handle some links at present */
+  if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
     if (hb->dbuf.linkflag == 0) {
       DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
                finfo->name));
     } else { 
-      DEBUG(0, ("this tar file appears to contain some kind of link - ignoring\n"));
-      return -2;
+      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 
+            the buffer pointer, etc */
+
+      } else {
+        DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
+        return -2;
+      }
     }
   }
     
@@ -241,7 +273,7 @@ static int dotarbuf(int f, char *b, int n)
 }
 
 /****************************************************************************
-Write zeros to buffer / tape
+Write zeros to buffer / tape
 ****************************************************************************/
 static void dozerobuf(int f, int n)
 {
@@ -252,6 +284,7 @@ static void dozerobuf(int f, int n)
   if (n+tp >= tbufsiz)
     {
       memset(tarbuf+tp, 0, tbufsiz-tp);
+
       write(f, tarbuf, tbufsiz);
       memset(tarbuf, 0, (tp+=n-tbufsiz));
     }
@@ -265,11 +298,11 @@ static void dozerobuf(int f, int n)
 /****************************************************************************
 Malloc tape buffer
 ****************************************************************************/
-static void initarbuf()
+static void initarbuf(void)
 {
   /* initialize tar buffer */
   tbufsiz=blocksize*TBLOCK;
-  tarbuf=malloc(tbufsiz);
+  tarbuf=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;
@@ -306,15 +339,18 @@ static void fixtarname(char *tptr, char *fp, int l)
    * to lovely unix /'s :-} */
 
   *tptr++='.';
-#ifdef KANJI
+
   while (l > 0) {
-    if (is_shift_jis (*fp)) {
-      *tptr++ = *fp++;
-      *tptr++ = *fp++;
-      l -= 2;
-    } else if (is_kana (*fp)) {
-      *tptr++ = *fp++;
-      l--;
+    int skip;
+    if((skip = skip_multibyte_char( *fp)) != 0) {
+      if (skip == 2) {
+        *tptr++ = *fp++;
+        *tptr++ = *fp++;
+        l -= 2;
+      } else if (skip == 1) {
+        *tptr++ = *fp++;
+        l--;
+      }
     } else if (*fp == '\\') {
       *tptr++ = '/';
       fp++;
@@ -324,15 +360,12 @@ static void fixtarname(char *tptr, char *fp, int l)
       l--;
     }
   }
-#else
-  while (l--) { *tptr=(*fp == '\\') ? '/' : *fp; tptr++; fp++; }
-#endif
 }
 
 /****************************************************************************
 Convert from decimal to octal string
 ****************************************************************************/
-static void oct_it (register long value, register int ndgs, register char *p)
+static void oct_it (long value, int ndgs, char *p)
 {
   /* Converts long to octal string, pads with leading zeros */
 
@@ -405,6 +438,70 @@ static int strslashcmp(char *s1, char *s2)
 /*
  * general smb utility functions
  */
+/**********************************************************************
+do_setrtime, set time on a file or dir ...
+**********************************************************************/
+
+static int do_setrtime(char *fname, int mtime)
+{
+  char *inbuf, *outbuf, *p;
+  char *name;
+
+  name = (char *)malloc(strlen(fname) + 1 + 1);
+  if (name == NULL) {
+
+     DEBUG(0, ("Failed to allocate space while setting time on file: %s", fname));
+     return False;
+
+  }
+
+  strcpy(name, fname);
+  strcpy(fname, "\\");
+  strcat(fname, name);
+
+  inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+  outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
+
+  if (!inbuf || !outbuf) {
+
+    DEBUG(0, ("Could not allocate memory for inbuf or outbuf while changing time on: %s\n", fname));
+    return False;
+
+  }
+
+  memset(outbuf, 0, smb_size);
+  set_message(outbuf, 8, 4 + strlen(fname), True);
+  CVAL(outbuf, smb_com) = SMBsetatr;
+  SSVAL(outbuf, smb_tid, cnum);
+  cli_setup_pkt(outbuf);
+
+  SSVAL(outbuf, smb_vwv0, 0);
+  put_dos_date3(outbuf, smb_vwv1, mtime);
+
+  p = smb_buf(outbuf);
+  *p++ = 4;
+  strcpy(p, fname);
+  p+= (strlen(fname)+1);
+
+  *p++ = 4;
+  *p++ = 0;
+
+  send_smb(Client, outbuf);
+  client_receive_smb(Client, inbuf, CLIENT_TIMEOUT);
+
+  if (CVAL(inbuf,smb_rcls) != 0)
+    {
+      DEBUG(0,("%s setting attributes on file %s\n",
+           smb_errstr(inbuf), fname));
+      free(inbuf);free(outbuf);
+      return(False);
+    }
+
+  free(inbuf);free(outbuf);
+  return(True);
+
+}
+
 /****************************************************************************
 Set DOS file attributes
 ***************************************************************************/
@@ -437,7 +534,7 @@ static int do_setrattr(char *fname, int attr, int setit)
   set_message(outbuf,0,2 + strlen(fname),True);
   CVAL(outbuf,smb_com) = SMBgetatr;
   SSVAL(outbuf,smb_tid,cnum);
-  setup_pkt(outbuf);
+  cli_setup_pkt(outbuf);
 
   p = smb_buf(outbuf);
   *p++ = 4;
@@ -448,7 +545,7 @@ static int do_setrattr(char *fname, int attr, int setit)
   *p++ = 0;
 
   send_smb(Client,outbuf);
-  receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+  client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
 
   if (CVAL(inbuf,smb_rcls) != 0)
     DEBUG(5,("getatr: %s\n",smb_errstr(inbuf)));
@@ -473,10 +570,10 @@ static int do_setrattr(char *fname, int attr, int setit)
   set_message(outbuf,8,4 + strlen(fname),True);
   CVAL(outbuf,smb_com) = SMBsetatr;
   SSVAL(outbuf,smb_tid,cnum);
-  setup_pkt(outbuf);
+  cli_setup_pkt(outbuf);
 
   SSVAL(outbuf,smb_vwv0,attr);
-
+  
   p = smb_buf(outbuf);
   *p++ = 4;      
   strcpy(p,fname);
@@ -486,7 +583,7 @@ static int do_setrattr(char *fname, int attr, int setit)
   *p++ = 0;
 
   send_smb(Client,outbuf);
-  receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+  client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
   
   if (CVAL(inbuf,smb_rcls) != 0)
     {
@@ -508,12 +605,12 @@ static BOOL smbcreat(file_info finfo, int *fnum, char *inbuf, char *outbuf)
   char *p;
   /* *must* be called with buffer ready malloc'ed */
   /* open remote file */
-  
+
   memset(outbuf,0,smb_size);
   set_message(outbuf,3,2 + strlen(finfo.name),True);
   CVAL(outbuf,smb_com) = SMBcreate;
   SSVAL(outbuf,smb_tid,cnum);
-  setup_pkt(outbuf);
+  cli_setup_pkt(outbuf);
   
   SSVAL(outbuf,smb_vwv0,finfo.mode);
   put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
@@ -523,7 +620,7 @@ static BOOL smbcreat(file_info finfo, int *fnum, char *inbuf, char *outbuf)
   strcpy(p,finfo.name);
   
   send_smb(Client,outbuf);
-  receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+  client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
   
   if (CVAL(inbuf,smb_rcls) != 0)
     {
@@ -552,7 +649,7 @@ static BOOL smbwrite(int fnum, int n, int low, int high, int left,
   set_message(outbuf,5,n + 3, False);
   CVAL(outbuf,smb_com) = SMBwrite;
   SSVAL(outbuf,smb_tid,cnum);
-  setup_pkt(outbuf);
+  cli_setup_pkt(outbuf);
   
   SSVAL(outbuf,smb_vwv0,fnum);
   SSVAL(outbuf,smb_vwv1,n);
@@ -562,7 +659,7 @@ static BOOL smbwrite(int fnum, int n, int low, int high, int left,
   SSVAL(smb_buf(outbuf),1,n);
 
   send_smb(Client,outbuf); 
-  receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+  client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
   
   if (CVAL(inbuf,smb_rcls) != 0)
     {
@@ -591,7 +688,7 @@ static BOOL smbshut(file_info finfo, int fnum, char *inbuf, char *outbuf)
   set_message(outbuf,3,0,True);
   CVAL(outbuf,smb_com) = SMBclose;
   SSVAL(outbuf,smb_tid,cnum);
-  setup_pkt(outbuf);
+  cli_setup_pkt(outbuf);
   
   SSVAL(outbuf,smb_vwv0,fnum);
   put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
@@ -601,7 +698,7 @@ static BOOL smbshut(file_info finfo, int fnum, char *inbuf, char *outbuf)
           finfo.mtime));
   
   send_smb(Client,outbuf);
-  receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+  client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
   
   if (CVAL(inbuf,smb_rcls) != 0)
     {
@@ -624,14 +721,14 @@ static BOOL smbchkpath(char *fname, char *inbuf, char *outbuf)
   set_message(outbuf,0,4 + strlen(fname),True);
   CVAL(outbuf,smb_com) = SMBchkpth;
   SSVAL(outbuf,smb_tid,cnum);
-  setup_pkt(outbuf);
+  cli_setup_pkt(outbuf);
 
   p = smb_buf(outbuf);
   *p++ = 4;
   strcpy(p,fname);
 
   send_smb(Client,outbuf);
-  receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+  client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
 
   DEBUG(5,("smbchkpath: %s\n",smb_errstr(inbuf)));
 
@@ -651,14 +748,14 @@ static BOOL smbmkdir(char *fname, char *inbuf, char *outbuf)
   
   CVAL(outbuf,smb_com) = SMBmkdir;
   SSVAL(outbuf,smb_tid,cnum);
-  setup_pkt(outbuf);
+  cli_setup_pkt(outbuf);
   
   p = smb_buf(outbuf);
   *p++ = 4;      
   strcpy(p,fname);
   
   send_smb(Client,outbuf);
-  receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+  client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
   
   if (CVAL(inbuf,smb_rcls) != 0)
     {
@@ -681,6 +778,8 @@ static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
   pstring partpath, ffname;
   char *p=fname, *basehack;
 
+  DEBUG(5, ( "Ensurepath called with: %s\n", fname));
+
   *partpath = 0;
 
   /* fname copied to ffname so can strtok */
@@ -743,7 +842,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
 {
   int fnum;
   uint32 nread=0;
-  char *p;
+  char *p, ftype;
   char *inbuf,*outbuf;
   file_info finfo;
   BOOL close_done = False;
@@ -755,6 +854,8 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
   struct timeval tp_start;
   GetTimeOfDay(&tp_start);
 
+  ftype = '0'; /* An ordinary file ... */
+
   if (finfo1) 
     finfo = *finfo1;
   else
@@ -774,7 +875,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
 
   CVAL(outbuf,smb_com) = SMBopenX;
   SSVAL(outbuf,smb_tid,cnum);
-  setup_pkt(outbuf);
+  cli_setup_pkt(outbuf);
 
   SSVAL(outbuf,smb_vwv0,0xFF);
   SSVAL(outbuf,smb_vwv2,1);
@@ -804,13 +905,13 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
     }
   
   send_smb(Client,outbuf);
-  receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+  client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
 
   if (CVAL(inbuf,smb_rcls) != 0)
     {
       if (CVAL(inbuf,smb_rcls) == ERRSRV &&
          SVAL(inbuf,smb_err) == ERRnoresource &&
-         reopen_connection(inbuf,outbuf))
+         cli_reopen_connection(inbuf,outbuf))
        {
          do_atar(rname,lname,finfo1);
          free(inbuf);free(outbuf);
@@ -840,6 +941,16 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
       DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
       shallitime=0;
     }
+  else if (!tar_system && (finfo.mode & aSYSTEM))
+    {
+      DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
+      shallitime=0;
+    }
+  else if (!tar_hidden && (finfo.mode & aHIDDEN))
+    {
+      DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
+      shallitime=0;
+    }
   else
     {
       if (SVAL(inbuf,smb_vwv0) == SMBreadX)
@@ -854,13 +965,13 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
          datalen = 0;
        }
 
-      DEBUG(1,("getting file %s of size %d bytes as a tar file %s",
+      DEBUG(2,("getting file %s of size %d bytes as a tar file %s",
               finfo.name,
               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");
+      writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
       
       while (nread < finfo.size && !close_done)
        {
@@ -906,7 +1017,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
              set_message(outbuf,10,0,True);
              CVAL(outbuf,smb_com) = SMBreadX;
              SSVAL(outbuf,smb_tid,cnum);
-             setup_pkt(outbuf);
+             cli_setup_pkt(outbuf);
              
              if (close_done)
                {
@@ -938,7 +1049,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
                }
              
              send_smb(Client,outbuf);
-             receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+             client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
              
              if (CVAL(inbuf,smb_rcls) != 0)
                {
@@ -972,7 +1083,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
                set_message(outbuf,8,0,True);
                CVAL(outbuf,smb_com) = SMBreadbraw;
                SSVAL(outbuf,smb_tid,cnum);
-               setup_pkt(outbuf);
+               cli_setup_pkt(outbuf);
                SSVAL(outbuf,smb_vwv0,fnum);
                SIVAL(outbuf,smb_vwv1,nread);
                SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
@@ -1024,7 +1135,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
              set_message(outbuf,5,0,True);
              CVAL(outbuf,smb_com) = SMBread;
              SSVAL(outbuf,smb_tid,cnum);
-             setup_pkt(outbuf);
+             cli_setup_pkt(outbuf);
              
              SSVAL(outbuf,smb_vwv0,fnum);
              SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
@@ -1032,7 +1143,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
              SSVAL(outbuf,smb_vwv4,finfo.size - nread);
              
              send_smb(Client,outbuf);
-             receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+             client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
              
              if (CVAL(inbuf,smb_rcls) != 0)
                {
@@ -1050,7 +1161,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
           * write out in 512 byte intervals */
          if (dotarbuf(tarhandle,dataptr,datalen) != datalen)
            {
-             DEBUG(0,("Error writing local file\n"));
+             DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
              break;
            }
          
@@ -1070,7 +1181,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
         {
           DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
           if (padit(inbuf, BUFFER_SIZE, finfo.size - nread))
-              DEBUG(0,("Error writing local file\n"));
+              DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
         }
 
       /* round tar file to nearest block */
@@ -1087,13 +1198,13 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
       set_message(outbuf,3,0,True);
       CVAL(outbuf,smb_com) = SMBclose;
       SSVAL(outbuf,smb_tid,cnum);
-      setup_pkt(outbuf);
+      cli_setup_pkt(outbuf);
       
       SSVAL(outbuf,smb_vwv0,fnum);
       SIVALS(outbuf,smb_vwv1,-1);
       
       send_smb(Client,outbuf);
-      receive_smb(Client,inbuf,CLIENT_TIMEOUT);
+      client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
       
       if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
        {
@@ -1119,9 +1230,16 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
       get_total_size += finfo.size;
 
       /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
-      DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
+      DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
               finfo.size / MAX(0.001, (1.024*this_time)),
               get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
+      if (tar_noisy)
+       {
+         printf("%10d (%7.1f kb/s) %s\n",
+              finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
+               finfo.name);
+       }
+
     }
   
   free(inbuf);free(outbuf);
@@ -1134,7 +1252,7 @@ static void do_tar(file_info *finfo)
 {
   pstring rname;
 
-  if (strequal(finfo->name,".") || strequal(finfo->name,".."))
+  if (strequal(finfo->name,".."))
     return;
 
   /* Is it on the exclude list ? */
@@ -1173,14 +1291,16 @@ static void do_tar(file_info *finfo)
       strcat(cur_dir,finfo->name);
       strcat(cur_dir,"\\");
 
+      DEBUG(5, ("Writing a dir, Name = %s\n", 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");
+      writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
+      ntarf++;  /* Make sure we have a file on there */
       strcpy(mtar_mask,cur_dir);
       strcat(mtar_mask,"*");
-      
-      do_dir((char *)inbuf,(char *)outbuf,mtar_mask,attribute,do_tar,recurse);
-      strcpy(cur_dir,saved_curdir);
+      /*      do_dir((char *)inbuf,(char *)outbuf,mtar_mask,attribute,do_tar,recurse,True); */
+             strcpy(cur_dir,saved_curdir);
       free(inbuf);free(outbuf);
     }
   else
@@ -1203,15 +1323,17 @@ static void unfixtarname(char *tptr, char *fp, int l)
   if (*fp == '.') fp++;
   if (*fp == '\\' || *fp == '/') fp++;
 
-#ifdef KANJI
   while (l > 0) {
-    if (is_shift_jis (*fp)) {
-      *tptr++ = *fp++;
-      *tptr++ = *fp++;
-      l -= 2;
-    } else if (is_kana (*fp)) {
-      *tptr++ = *fp++;
-      l--;
+    int skip;
+    if(( skip = skip_multibyte_char( *fp )) != 0) {
+      if (skip == 2) {
+        *tptr++ = *fp++;
+        *tptr++ = *fp++;
+        l -= 2;
+      } else if (skip == 1) {
+        *tptr++ = *fp++;
+        l--;
+      }
     } else if (*fp == '/') {
       *tptr++ = '\\';
       fp++;
@@ -1221,16 +1343,13 @@ static void unfixtarname(char *tptr, char *fp, int l)
       l--;
     }
   }
-#else
-  while (l--) { *tptr=(*fp == '/') ? '\\' : *fp; tptr++; fp++; }
-#endif
 }
 
-static void do_tarput()
+static void do_tarput(void)
 {
   file_info finfo;
   int nread=0, bufread;
-  char *inbuf,*outbuf; 
+  char *inbuf,*outbuf, *longname = NULL
   int fsize=0;
   int fnum;
   struct timeval tp_start;
@@ -1293,26 +1412,93 @@ static void do_tarput()
     do {
       if (!fsize)
        {
-         switch (readtarheader((union hblock *) bufferp, &finfo, cur_dir))
-           {
-           case -2:             /* something dodgy but not fatal about this */
-             DEBUG(0, ("skipping %s...\n", finfo.name));
-             bufferp+=TBLOCK;   /* header - like a link */
-             continue;
-           case -1:
-             DEBUG(0, ("abandoning restore\n"));
-             free(inbuf); free(outbuf);
-             return;
-           case 0: /* chksum is zero - we assume that one all zero
-                    *header block will do for eof */
-             DEBUG(0,
-                   ("total of %d tar files restored to share\n", ntarf));
-             free(inbuf); free(outbuf);
-             return;
-           default:
-             break;
-           }
+          int next_header = 1;  /* Want at least one header */
+          while (next_header) 
+            {  
+            if (bufferp >= endofbuffer) {
+
+              bufread = read(tarhandle, tarbuf, tbufsiz);
+              bufferp = tarbuf;
+
+            }
+            next_header = 0;    /* Don't want the next one ... */
+           switch (readtarheader((union hblock *) bufferp, &finfo, cur_dir))
+             {
+             case -2:             /* something dodgy but not fatal about this */
+               DEBUG(0, ("skipping %s...\n", finfo.name));
+               bufferp+=TBLOCK;   /* header - like a link */
+               continue;
+             case -1:
+               DEBUG(0, ("abandoning restore, -1 from readtarheader\n"));
+               free(inbuf); free(outbuf);
+               return;
+             case 0: /* chksum is zero - we assume that one all zero
+                      *header block will do for eof */
+               DEBUG(0,
+                     ("total of %d tar files restored to share\n", ntarf));
+               free(inbuf); free(outbuf);
+               return;
+             default:
+               break;
+             }
+
+            /* If we have a longname left from the last time through, 
+               copy it into finfo.name and free it.
+
+               The size of a pstring is the limiting factor on filenames
+               and directory names now. The total pathname length must be
+               less than sizeof(pstring) - 1, which is currently 1023. */
+
+            if (longname != NULL) {
+
+              strncpy(finfo.name, longname, sizeof(pstring) - 1);
+              free(longname);
+              longname = NULL;
+
+            }
+
+            /* Check if a long-link. We do this before the clip checking
+               because clip-checking should clip on real name - RJS */
+
+            if (((union hblock *)bufferp) -> dbuf.linkflag == 'L') {
 
+              /* Skip this header, but pick up length, get the name and 
+                 fix the name and skip the name. Hmmm, what about end of
+                 buffer??? */
+
+              longname = malloc(finfo.size + strlen(cur_dir) + 1);
+              if (longname == NULL) {
+
+                 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
+                          finfo.size + strlen(cur_dir) + 1)
+                      );
+                 free(inbuf); free(outbuf);
+                 return;
+              }
+
+              bufferp += TBLOCK;   /* Skip that longlink header */
+
+              /* This needs restructuring ... */
+
+             if (bufferp >= endofbuffer) {
+
+               bufread = read(tarhandle, tarbuf, tbufsiz);
+
+               bufferp = tarbuf;
+
+              }
+
+              strncpy(longname, cur_dir, strlen(cur_dir)); 
+              unfixtarname(longname+strlen(cur_dir), bufferp, finfo.size);
+
+              /* Next rounds up to next TBLOCK and takes care of us being right
+                 on a TBLOCK boundary */
+
+              bufferp += (((finfo.size - 1)/TBLOCK)+1)*TBLOCK;
+              next_header = 1;  /* Force read of next header */
+
+            }
+          }
          tskip=clipn
            && (clipfind(cliplist, clipn, finfo.name) ^ tar_excl);
          if (tskip) {
@@ -1332,17 +1518,32 @@ static void do_tarput()
            }
          }
 
+         DEBUG(5, ("do_tarput: File is: %s\n", finfo.name));
+
          if (finfo.mode & aDIR)
            {
-             if (!smbchkpath(finfo.name, inbuf, outbuf)
-                 && !smbmkdir(finfo.name, inbuf, outbuf))
+             if (!ensurepath(finfo.name, inbuf, outbuf))
+/*           if (!smbchkpath(finfo.name, inbuf, outbuf)
+                 && !smbmkdir(finfo.name, inbuf, outbuf))*/
                {
-                 DEBUG(0, ("abandoning restore\n"));
+                 DEBUG(0, ("abandoning restore, problems ensuring path\n"));
                  free(inbuf); free(outbuf);
                  return;
              }
              else
                {
+                 /* Now we update the creation date ... */
+
+                 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
+
+                 if (!do_setrtime(finfo.name, finfo.mtime)) {
+
+                    DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
+                    return;
+
+                  }
+
+                 ntarf++;
                  bufferp+=TBLOCK;
                  continue;
                }
@@ -1358,9 +1559,17 @@ static void do_tarput()
              return;
            }
 
-         DEBUG(0,("restore tar file %s of size %d bytes\n",
+         DEBUG(0 ,("restore tar file %s of size %d bytes\n",
                   finfo.name,finfo.size));
 
+          if (!finfo.size) {
+           if (!smbshut(finfo, fnum, inbuf, outbuf)){
+              DEBUG(0, ("Error closing remote file of length 0: %s\n", finfo.name));
+             free(inbuf);free(outbuf);
+              return;
+            }
+         }
+
          nread=0;
          if ((bufferp+=TBLOCK) >= endofbuffer) break;    
        } /* if (!fsize) */
@@ -1391,7 +1600,7 @@ static void do_tarput()
        bufferp+=minichunk; nread+=minichunk;
        chunk-=minichunk;
       }
-      
+
       if (nread>=fsize)
        {
          if (!smbshut(finfo, fnum, inbuf, outbuf))
@@ -1422,7 +1631,7 @@ static void do_tarput()
 /****************************************************************************
 Blocksize command
 ***************************************************************************/
-void cmd_block(void)
+void cmd_block(char *dum_in, char *dum_out)
 {
   fstring buf;
   int block;
@@ -1441,13 +1650,13 @@ void cmd_block(void)
     }
 
   blocksize=block;
-  DEBUG(1,("blocksize is now %d\n", blocksize));
+  DEBUG(2,("blocksize is now %d\n", blocksize));
 }
 
 /****************************************************************************
 command to set incremental / reset mode
 ***************************************************************************/
-void cmd_tarmode(void)
+void cmd_tarmode(char *dum_in, char *dum_out)
 {
   fstring buf;
 
@@ -1460,18 +1669,34 @@ void cmd_tarmode(void)
       tar_reset=True;
     else if (strequal(buf, "noreset"))
       tar_reset=False;
+    else if (strequal(buf, "system"))
+      tar_system=True;
+    else if (strequal(buf, "nosystem"))
+      tar_system=False;
+    else if (strequal(buf, "hidden"))
+      tar_hidden=True;
+    else if (strequal(buf, "nohidden"))
+      tar_hidden=False;
+    else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
+      tar_noisy=True;
+    else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
+      tar_noisy=False;
     else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
   }
 
-  DEBUG(0, ("tarmode is now %s, %s\n",
+  DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
            tar_inc ? "incremental" : "full",
-           tar_reset ? "reset" : "noreset"));
+           tar_system ? "system" : "nosystem",
+           tar_hidden ? "hidden" : "nohidden",
+           tar_reset ? "reset" : "noreset",
+           tar_noisy ? "verbose" : "quiet"));
+
 }
 
 /****************************************************************************
 Feeble attrib command
 ***************************************************************************/
-void cmd_setmode(void)
+void cmd_setmode(char *dum_in, char *dum_out)
 {
   char *q;
   fstring buf;
@@ -1518,7 +1743,7 @@ void cmd_setmode(void)
       return;
     }
 
-  DEBUG(1, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
+  DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
   (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
   (void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
 }
@@ -1586,19 +1811,19 @@ int process_tar(char *inbuf, char *outbuf)
          strcpy(cur_dir, tarmac);
          *(strrchr(cur_dir, '\\')+1)='\0';
 
-         do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse);
+         do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True);
          strcpy(cur_dir,saved_dir);
        } else {
          strcpy(tarmac, cur_dir);
          strcat(tarmac, cliplist[i]);
-         do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse);
+         do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True);
        }
       }
     } else {
       pstring mask;
       strcpy(mask,cur_dir);
       strcat(mask,"\\*");
-      do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_tar,recurse);
+      do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_tar,recurse, True);
     }
     
     if (ntarf) dotareof(tarhandle);
@@ -1719,8 +1944,38 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
 
   tar_excl=tar_clipfl!='X';
   if (Optind+1<argc) {
+    char *tmpstr;
+    char **tmplist;
+    int clipcount;
+
     cliplist=argv+Optind+1;
     clipn=argc-Optind-1;
+    clipcount = clipn;
+
+    if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
+      DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 
+               clipn)
+           );
+      return 0;
+    }
+
+    for (clipcount = 0; clipcount < clipn; clipcount++) {
+
+      DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
+
+      if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
+        DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
+                 clipcount)
+             );
+        return 0;
+      }
+      unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1);
+      tmplist[clipcount] = tmpstr;
+      DEBUG(5, ("Processed an item, %s\n", tmpstr));
+
+      DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
+    }
+    cliplist = tmplist;
   }
   if (Optind>=argc || !strcmp(argv[Optind], "-")) {
     /* Sets tar handle to either 0 or 1, as appropriate */
@@ -1729,7 +1984,8 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
     if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
        || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
       {
-       DEBUG(0,("Error opening local file %s\n",argv[Optind]));
+       DEBUG(0,("Error opening local file %s - %s\n",
+                argv[Optind], strerror(errno)));
        return(0);
       }
   }