Small update to clitar.c to omit warnings about servers not
[samba.git] / source / client / clitar.c
index 1f453da492af6c189b177c070a70f74e9bf69ba7..afcd4b9f1d6f875972f5c9f1808df2f4e4f21b0f 100644 (file)
@@ -39,6 +39,8 @@
 #include "includes.h"
 #include "clitar.h"
 
+static int clipfind(char **aret, int ret, char *tok);
+
 typedef struct file_info_struct file_info2;
 
 struct file_info_struct
@@ -83,7 +85,7 @@ static int attribute = aDIR | aSYSTEM | aHIDDEN;
 #define CLIENT_TIMEOUT (30*1000)
 #endif
 
-static char *tarbuf;
+static char *tarbuf, *buffer_p;
 static int tp, ntarf, tbufsiz, ttarf;
 /* Incremental mode */
 BOOL tar_inc=False;
@@ -96,13 +98,15 @@ BOOL tar_re_search=False;
 #ifdef HAVE_REGEX_H
 regex_t *preg;
 #endif
+/* Do not dump anything, just calculate sizes */
+BOOL dry_run=False;
 /* Dump files with System attribute */
 BOOL tar_system=True;
 /* Dump files with Hidden attribute */
 BOOL tar_hidden=True;
 /* Be noisy - make a catalogue */
 BOOL tar_noisy=True;
-BOOL tar_real_noisy=True;
+BOOL tar_real_noisy=False;  /* Don't want to be really noisy by default */
 
 char tar_type='\0';
 static char **cliplist=NULL;
@@ -297,18 +301,13 @@ static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
 
   fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
 
-  DEBUG(5, ("checksum totals chk=%d fchk=%d chksum=%s\n",
+  DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
            chk, fchk, hb->dbuf.chksum));
 
   if (fchk != chk)
     {
-      DEBUG(0, ("checksums don't match %d %d\n", fchk, chk));
-/*      for (i = 0; i < sizeof(hb -> dummy); i++) {
-       fprintf(stdout, "%2X ", hb -> dummy[i]);
-      }
-      fprintf(stdout, "\n");
-      fprintf(stdout, "%s\n", hb -> dummy);
-      fprintf(stdout, "Tarbuf = %X, hb = %X\n", (int)tarbuf, (int)hb);*/
+      DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
+      dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
       return -1;
     }
 
@@ -325,7 +324,7 @@ static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
   unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
               strlen(hb->dbuf.name) + 1, True);
 
-/* can't handle some links at present */
+  /* 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",
@@ -372,6 +371,9 @@ static int dotarbuf(int f, char *b, int n)
 {
   int fail=1, writ=n;
 
+  if (dry_run) {
+    return writ;
+  }
   /* This routine and the next one should be the only ones that do write()s */
   if (tp + n >= tbufsiz)
     {
@@ -408,6 +410,9 @@ static void dozerobuf(int f, int n)
    * used to round files to nearest block
    * and to do tar EOFs */
 
+  if (dry_run)
+    return;
+  
   if (n+tp >= tbufsiz)
     {
       memset(tarbuf+tp, 0, tbufsiz-tp);
@@ -440,13 +445,16 @@ Write two zero blocks at end of file
 ****************************************************************************/
 static void dotareof(int f)
 {
-  struct stat stbuf;
+  SMB_STRUCT_STAT stbuf;
   /* Two zero blocks at end of file, write out full buffer */
 
+  if (dry_run)
+    return;
+
   (void) dozerobuf(f, TBLOCK);
   (void) dozerobuf(f, TBLOCK);
 
-  if (fstat(f, &stbuf) == -1)
+  if (sys_fstat(f, &stbuf) == -1)
     {
       DEBUG(0, ("Couldn't stat file handle\n"));
       return;
@@ -522,7 +530,7 @@ static long unoct(char *p, int ndgs)
 
   while (--ndgs)
     {
-      if (isdigit(*p))
+      if (isdigit((int)*p))
         value = (value << 3) | (long) (*p - '0');
 
       p++;
@@ -840,7 +848,7 @@ static BOOL smbshut(file_info2 finfo, int fnum, char *inbuf, char *outbuf)
   SSVAL(outbuf,smb_vwv0,fnum);
   put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
   
-  DEBUG(3,("Setting date to %s (0x%X)",
+  DEBUG(3,("Setting date to %s (0x%lX)",
           asctime(LocalTime(&finfo.mtime)),
           finfo.mtime));
   
@@ -973,7 +981,7 @@ static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
     return True;
 }
 
-int padit(char *buf, int bufsize, int padsize)
+static int padit(char *buf, int bufsize, int padsize)
 {
   int berr= 0;
   int bytestowrite;
@@ -1032,7 +1040,17 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
     finfo.ctime = def_finfo.ctime;
   }
 
-
+  if (dry_run)
+    {
+      DEBUG(3,("skipping file %s of size %d bytes\n",
+              finfo.name,
+              finfo.size));
+      shallitime=0;
+      ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
+      ntarf++;
+      return;
+    }
+    
   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
 
@@ -1069,7 +1087,7 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
       SSVAL(outbuf,smb_vwv1,PTR_DIFF(p,outbuf) - 4);
       memset(p,0,200);
       p -= smb_wct;
-      SSVAL(p,smb_wct,10);
+      SCVAL(p,smb_wct,10);
       SSVAL(p,smb_vwv0,0xFF);
       SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
       SSVAL(p,smb_vwv9,MIN(0xFFFF,finfo.size));
@@ -1401,7 +1419,8 @@ static void do_atar(char *rname,char *lname,file_info *finfo1)
       int this_time;
 
       /* if shallitime is true then we didn't skip */
-      if (tar_reset) (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
+      if (tar_reset && !dry_run)
+       (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
       
       GetTimeOfDay(&tp_end);
       this_time = 
@@ -1517,7 +1536,7 @@ static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
    * dos \'s in path. Kill any absolute path names. But only if first!
    */
 
-  DEBUG(5, ("firstb=%X, secondb=%X, len=%i\n", tptr, fp, l));
+  DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
 
   if (first) {
     if (*fp == '.') {
@@ -1552,18 +1571,26 @@ static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
   }
 }
 
-#if 0 /* Removed to get around gcc 'defined but not used' error. */
+#ifndef OLD_DOTARPUT 
 
 /****************************************************************************
 Move to the next block in the buffer, which may mean read in another set of
-blocks.
+blocks. FIXME, we should allow more than one block to be skipped.
 ****************************************************************************/
-static int next_block(char *ltarbuf, char *bufferp, int bufsiz)
+static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
 {
   int bufread, total = 0;
 
-  if (bufferp >= (ltarbuf + bufsiz)) {
-    
+  DEBUG(5, ("Advancing to next block: %0x\n", (unsigned int)*bufferp));
+  *bufferp += TBLOCK;
+  total = TBLOCK;
+
+  if (*bufferp >= (ltarbuf + bufsiz)) {
+
+    DEBUG(5, ("Reading more data into ltarbuf ...\n"));
+
+    total = 0;
+
     for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
 
       if (bufread <= 0) { /* An error, return false */
@@ -1572,60 +1599,228 @@ static int next_block(char *ltarbuf, char *bufferp, int bufsiz)
 
     }
 
-    bufferp = ltarbuf;
+    DEBUG(5, ("Total bytes read ... %i\n", total));
 
-  }
-  else {
-
-    bufferp += TBLOCK;
+    *bufferp = ltarbuf;
 
   }
 
-  return(0);
+  return(total);
 
 }
 
-static int skip_file(int skip)
+/* Skip a file, even if it includes a long file name? */
+static int skip_file(int skipsize)
 {
+  int dsize = skipsize;
 
-  return(0);
+  DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
+
+  /* FIXME, we should skip more than one block at a time */
+
+  while (dsize > 0) {
+
+    if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
+
+       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+       return(False);
+
+    }
+
+    dsize -= TBLOCK;
+
+  }
+
+  return(True);
 }
 
-static int get_file(file_info2 finfo)
+/* We get a file from the tar file and store it */
+static int get_file(file_info2 finfo, char * inbuf, char * outbuf)
 {
+  int fsize = finfo.size;
+  int fnum, pos = 0, dsize = 0, rsize = 0, bpos = 0;
 
-  return(0);
+  DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
+
+  if (ensurepath(finfo.name, inbuf, outbuf) &&
+      !smbcreat(finfo, &fnum, inbuf, outbuf))
+    {
+      DEBUG(0, ("abandoning restore\n"));
+      return(False);
+    }
+
+  /* read the blocks from the tar file and write to the remote file */
+
+  rsize = fsize;  /* This is how much to write */
+
+  while (rsize > 0) {
+
+    /* We can only write up to the end of the buffer */
+
+    dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, max_xmit - 50); /* Calculate the size to write */
+    dsize = MIN(dsize, rsize);  /* Should be only what is left */
+    DEBUG(5, ("writing %i bytes, max_xmit = %i, bpos = %i ...\n", dsize, max_xmit, bpos));
+
+    if (!smbwrite(fnum, dsize, pos, 0, fsize - pos, buffer_p + bpos, inbuf, outbuf)) {
+
+      DEBUG(0, ("Error writing remote file\n"));
+      return 0;
+
+    }
+
+    rsize -= dsize;
+    pos += dsize;
+
+    /* Now figure out how much to move in the buffer */
+
+    /* FIXME, we should skip more than one block at a time */
+
+    /* First, skip any initial part of the part written that is left over */
+    /* from the end of the first TBLOCK                                   */
+
+    if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
+
+      dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
+      bpos = 0;
+
+      if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
+       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+       return False;
+
+      }
+
+    }
+
+    while (dsize >= TBLOCK) {
+
+      if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
+
+       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+       return False;
+
+      }
+
+      dsize -= TBLOCK;
+
+    }
+
+    bpos = dsize;
+
+  }
+
+  /* Now close the file ... */
+
+  if (!smbshut(finfo, fnum, inbuf, outbuf)) {
+
+    DEBUG(0, ("Error closing remote file\n"));
+    return(False);
+
+  }
+
+  /* Now we update the creation date ... */
+
+  DEBUG(5, ("Updating creation date on %s\n", finfo.name));
+
+  if (!do_setrtime(finfo.name, finfo.mtime, True)) {
+
+    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 */
+    }
+  }
+
+  ntarf++;
+
+  DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
+  
+  return(True);
 
 }
 
-static int get_dir(file_info2 finfo)
+/* Create a directory.  We just ensure that the path exists and return as there
+   is no file associated with a directory 
+*/
+static int get_dir(file_info2 finfo, char * inbuf, char * outbuf)
 {
 
-  return(0);
+  DEBUG(5, ("Creating directory: %s\n", finfo.name));
 
-}
+  if (!ensurepath(finfo.name, inbuf, outbuf)) {
+
+    DEBUG(0, ("Problems creating directory\n"));
+    return(False);
+
+  }
+  return(True);
 
+}
+/* Get a file with a long file name ... first file has file name, next file 
+   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)
 {
+  int namesize = finfo.size + strlen(cur_dir) + 2;
+  char *longname = malloc(namesize);
+  int offset = 0, left = finfo.size;
+  BOOL first = True;
 
-  return(NULL);
+  DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
+  DEBUG(5, ("Len = %i\n", finfo.size));
 
-}
+  if (longname == NULL) {
+
+    DEBUG(0, ("could not allocate buffer of size %d for longname\n", 
+             finfo.size + strlen(cur_dir) + 2));
+    return(NULL);
+  }
+
+  /* First, add cur_dir to the long file name */
+
+  if (strlen(cur_dir) > 0) {
+    strncpy(longname, cur_dir, namesize);
+    offset = strlen(cur_dir);
+  }
+
+  /* Loop through the blocks picking up the name */
 
-static char * bufferp;
+  while (left > 0) {
 
-static void do_tarput2(void)
+    if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
+
+      DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
+      return(NULL);
+
+    }
+
+    unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
+    DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
+
+    offset += TBLOCK;
+    left -= TBLOCK;
+
+  }
+
+  return(longname);
+
+}
+
+static void do_tarput(void)
 {
-  file_info2 finfo, *finfo2;
+  file_info2 finfo;
   struct timeval tp_start;
-  char *inbuf, *outbuf, *longfilename = NULL;
+  char *inbuf, *outbuf, *longfilename = NULL, linkflag;
   int skip = False;
 
   GetTimeOfDay(&tp_start);
 
-  bufferp = tarbuf + tbufsiz;  /* init this to force first read */
+  DEBUG(5, ("RJS do_tarput called ...\n"));
+
+  buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
 
+#if 0   /* Fix later ... */
   if (push_dir(&dir_stack, &finfo)) {
+    file_info2 *finfo2;
 
     finfo2 = pop_dir(&dir_stack);
     inbuf = top_dir_name(&dir_stack); /* FIXME */
@@ -1635,6 +1830,7 @@ static void do_tarput2(void)
 
     }
   }
+#endif
 
   inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
   outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
@@ -1646,26 +1842,32 @@ static void do_tarput2(void)
 
   }
 
-  if (next_block(tarbuf, bufferp, tbufsiz) <= 0) {
+  /* Now read through those files ... */
+
+  while (True) {
 
-    DEBUG(0, ("Empty file or short tar file: %s\n", strerror(errno)));
+    /* Get us to the next block, or the first block first time around */
 
-  }
+    if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
 
-  /* Now read through those files ... */
+      DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
 
-  while (True) {
+      return;
 
-    switch (readtarheader((union hblock *) bufferp, &finfo, cur_dir)) {
+    }
+
+    DEBUG(5, ("Reading the next header ...\n"));
+
+    switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
 
     case -2:    /* Hmm, not good, but not fatal */
       DEBUG(0, ("Skipping %s...\n", finfo.name));
-      if ((next_block(tarbuf, bufferp, tbufsiz) <= 0) &&
+      if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
           !skip_file(finfo.size)) {
 
        DEBUG(0, ("Short file, bailing out...\n"));
        free(inbuf); free(outbuf);
-       continue;
+       return;
 
       }
 
@@ -1681,7 +1883,9 @@ static void do_tarput2(void)
       free(inbuf); free(outbuf);
       return;        /* Hmmm, bad here ... */
 
-    default:
+    default: 
+      /* No action */
+
       break;
 
     }
@@ -1689,46 +1893,75 @@ static void do_tarput2(void)
     /* Now, do we have a long file name? */
 
     if (longfilename != NULL) {
-      if (strlen(longfilename) < sizeof(finfo.name)) { /* if we have space */
 
-       strncpy(finfo.name, longfilename, sizeof(finfo.name) - 1);
-       free(longfilename);
-       longfilename = NULL;
+      free(finfo.name);   /* Free the space already allocated */
+      finfo.name = longfilename;
+      longfilename = NULL;
 
-      }
-      else {
+    }
 
-       DEBUG(0, ("filename: %s too long, skipping\n", strlen(longfilename)));
-       skip = True;
+    /* Well, now we have a header, process the file ...            */
 
-      }
-    }
+    /* Should we skip the file? We have the long name as well here */
 
-    /* Well, now we have a header, process the file ... */
+    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, False)));
+#endif
 
-    /* Should we skip the file?                         */
+  DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
 
-    if (skip) {
+  if (skip) {
 
-      skip_file(finfo.size);
-      continue;
+    skip_file(finfo.size);
+    continue;
 
-    }
+  }
 
     /* We only get this far if we should process the file */
+  linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
 
-    switch (((union hblock *)bufferp) -> dbuf.linkflag) {
+    switch (linkflag) {
 
     case '0':  /* Should use symbolic names--FIXME */
-      get_file(finfo);
+
+      /* Skip to the next block first, so we can get the file, FIXME, should
+         be in get_file ... */
+
+      if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
+       DEBUG(0, ("Short file, bailing out...\n"));
+       free(inbuf); free(outbuf);
+       return;
+      }
+      if (!get_file(finfo, inbuf, outbuf)) {
+
+       free(inbuf); free(outbuf);
+       DEBUG(0, ("Abandoning restore\n"));
+       return;
+
+      }
       break;
 
     case '5':
-      get_dir(finfo);
+      if (!get_dir(finfo, inbuf, outbuf)) {
+       free(inbuf); free(outbuf);
+       DEBUG(0, ("Abandoning restore \n"));
+       return;
+      }
       break;
 
     case 'L':
       longfilename = get_longfilename(finfo);
+      if (!longfilename) {
+       free(inbuf); free(outbuf);
+       DEBUG(0, ("abandoning restore\n"));
+       return;
+
+      }
+      DEBUG(5, ("Long file name: %s\n", longfilename));
       break;
 
     default:
@@ -1741,7 +1974,8 @@ static void do_tarput2(void)
 
 
 }
-#endif /* Removed to get around gcc 'defined but not used' error. */
+
+#else 
 
 static void do_tarput()
 {
@@ -1772,7 +2006,7 @@ static void do_tarput()
 
   /* These should be the only reads in clitar.c */
   while ((bufread=read(tarhandle, tarbuf, tbufsiz))>0) {
-    char *buffer_p, *endofbuffer;
+    char *endofbuffer;
     int chunk;
 
     /* Code to handle a short read.
@@ -1829,7 +2063,8 @@ static void do_tarput()
              finfo.name = NULL;
 
            }
-           DEBUG(5, ("Tarbuf=%X, buffer=%X, endofbuf=%X\n", tarbuf, buffer_p, endofbuffer));
+           DEBUG(5, ("Tarbuf=%X, buffer=%X, endofbuf=%X\n", 
+                     (int)tarbuf, (int)buffer_p, (int)endofbuffer));
            switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir))
              {
              case -2:             /* something dodgy but not fatal about this */
@@ -1899,7 +2134,8 @@ static void do_tarput()
              cp = longname + strlen(cur_dir);
              file_len = finfo.size;
 
-             DEBUG(5, ("longname=%0X, cp=%0X, file_len=%i\n", longname, cp, file_len));
+             DEBUG(5, ("longname=%0X, cp=%0X, file_len=%i\n", 
+                       (int)longname, (int)cp, file_len));
 
              while (file_len > 0) {
 
@@ -1917,7 +2153,7 @@ static void do_tarput()
                cp = cp + strlen(cp); /* Move to end of string */
                buffer_p += TBLOCK;
                file_len -= TBLOCK;
-               DEBUG(5, ("cp=%0X, file_len=%i\n", cp, file_len));
+               DEBUG(5, ("cp=%0X, file_len=%i\n", (int)cp, file_len));
                next_header = 1;  /* Force read of next header */
 
              }
@@ -2045,7 +2281,7 @@ static void do_tarput()
            }
          if (fsize % TBLOCK) buffer_p+=TBLOCK - (fsize % TBLOCK);
          DEBUG(5, ("buffer_p is now %d (psn=%d)\n",
-                   (long) buffer_p, (long)(buffer_p - tarbuf)));
+                   (int) buffer_p, (int)(buffer_p - tarbuf)));
          ntarf++;
          fsize=0;
 
@@ -2058,6 +2294,7 @@ static void do_tarput()
 
   free(inbuf); free(outbuf);
 }
+#endif
 
 /*
  * samba interactive commands
@@ -2071,7 +2308,7 @@ void cmd_block(char *dum_in, char *dum_out)
   fstring buf;
   int block;
 
-  if (!next_token(NULL,buf,NULL))
+  if (!next_token(NULL,buf,NULL,sizeof(buf)))
     {
       DEBUG(0, ("blocksize <n>\n"));
       return;
@@ -2095,7 +2332,7 @@ void cmd_tarmode(char *dum_in, char *dum_out)
 {
   fstring buf;
 
-  while (next_token(NULL,buf,NULL)) {
+  while (next_token(NULL,buf,NULL,sizeof(buf))) {
     if (strequal(buf, "full"))
       tar_inc=False;
     else if (strequal(buf, "inc"))
@@ -2141,7 +2378,7 @@ void cmd_setmode(char *dum_in, char *dum_out)
 
   attra[0] = attra[1] = 0;
 
-  if (!next_token(NULL,buf,NULL))
+  if (!next_token(NULL,buf,NULL,sizeof(buf)))
     {
       DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
       return;
@@ -2150,7 +2387,7 @@ void cmd_setmode(char *dum_in, char *dum_out)
   safe_strcpy(fname, cur_dir, sizeof(pstring));
   safe_strcat(fname, buf, sizeof(pstring));
 
-  while (next_token(NULL,buf,NULL)) {
+  while (next_token(NULL,buf,NULL,sizeof(buf))) {
     q=buf;
 
     while(*q)
@@ -2192,9 +2429,9 @@ void cmd_tar(char *inbuf, char *outbuf)
   char **argl;
   int argcl;
 
-  if (!next_token(NULL,buf,NULL))
+  if (!next_token(NULL,buf,NULL,sizeof(buf)))
     {
-      DEBUG(0,("tar <c|x>[IXbga] <filename>\n"));
+      DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
       return;
     }
 
@@ -2292,7 +2529,7 @@ int process_tar(char *inbuf, char *outbuf)
 /****************************************************************************
 Find a token (filename) in a clip list
 ***************************************************************************/
-int clipfind(char **aret, int ret, char *tok)
+static int clipfind(char **aret, int ret, char *tok)
 {
   if (aret==NULL) return 0;
 
@@ -2431,6 +2668,7 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
    */
   tar_type='\0';
   tar_excl=True;
+  dry_run=False;
 
   while (*Optarg) 
     switch(*Optarg++) {
@@ -2460,10 +2698,10 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
        DEBUG(0,("Option N must be followed by valid file name\n"));
        return 0;
       } else {
-       struct stat stbuf;
+       SMB_STRUCT_STAT stbuf;
        extern time_t newer_than;
        
-       if (sys_stat(argv[Optind], &stbuf) == 0) {
+       if (dos_stat(argv[Optind], &stbuf) == 0) {
          newer_than = stbuf.st_mtime;
          DEBUG(1,("Getting files newer than %s",
                   asctime(LocalTime(&newer_than))));
@@ -2502,6 +2740,15 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
       DEBUG(0, ("tar_re_search set\n"));
       tar_re_search = True;
       break;
+    case 'n':
+      if (tar_type == 'c') {
+       DEBUG(0, ("dry_run set\n"));
+       dry_run = True;
+      } else {
+       DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
+       return 0;
+      }
+      break;
     default:
       DEBUG(0,("Unknown tar option\n"));
       return 0;
@@ -2592,6 +2839,14 @@ int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
     /* Sets tar handle to either 0 or 1, as appropriate */
     tarhandle=(tar_type=='c');
   } 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"));
+         dry_run = True;
+       }
+       tarhandle=-1;
+      } else
     if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
        || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
       {