/*
- Unix SMB/Netbios implementation.
- Version 1.9.
+ Unix SMB/CIFS implementation.
Tar Extensions
Copyright (C) Ricky Poulten 1995-1998
Copyright (C) Richard Sharpe 1998
#include "includes.h"
#include "clitar.h"
+#include "../client/client_proto.h"
static int clipfind(char **aret, int ret, char *tok);
} stack;
-stack dir_stack = {NULL, 0}; /* Want an empty stack */
-
#define SEPARATORS " \t\n\r"
-extern int DEBUGLEVEL;
extern struct cli_state *cli;
-extern FILE *dbf;
/* These defines are for the do_setrattr routine, to indicate
* setting and reseting of file attributes in the function call */
#endif
static char *tarbuf, *buffer_p;
-static int tp, ntarf, tbufsiz, ttarf;
+static int tp, ntarf, tbufsiz;
+static double ttarf;
/* Incremental mode */
-BOOL tar_inc=False;
+static BOOL tar_inc=False;
/* Reset archive bit */
-BOOL tar_reset=False;
+static BOOL tar_reset=False;
/* Include / exclude mode (true=include, false=exclude) */
-BOOL tar_excl=True;
+static BOOL tar_excl=True;
/* use regular expressions for search on file names */
-BOOL tar_re_search=False;
+static BOOL tar_re_search=False;
#ifdef HAVE_REGEX_H
regex_t *preg;
#endif
/* Do not dump anything, just calculate sizes */
-BOOL dry_run=False;
+static BOOL dry_run=False;
/* Dump files with System attribute */
-BOOL tar_system=True;
+static BOOL tar_system=True;
/* Dump files with Hidden attribute */
-BOOL tar_hidden=True;
+static BOOL tar_hidden=True;
/* Be noisy - make a catalogue */
-BOOL tar_noisy=True;
-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;
extern pstring cur_dir;
extern int get_total_time_ms;
extern int get_total_size;
-extern int Protocol;
-int blocksize=20;
-int tarhandle;
+static int blocksize=20;
+static int tarhandle;
static void writetarheader(int f, char *aname, int size, time_t mtime,
char *amode, unsigned char ftype);
memset(hb.dummy, 0, sizeof(hb.dummy));
l=strlen(aname);
- if (l >= NAMSIZ) {
+ if (l >= NAMSIZ - 1) {
/* write a GNU tar style long header */
char *b;
b = (char *)malloc(l+TBLOCK+100);
DEBUG(0,("out of memory\n"));
exit(1);
}
- writetarheader(f, "/./@LongLink", l+1, 0, " 0 \0", 'L');
+ writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
memset(b, 0, l+TBLOCK+100);
fixtarname(b, aname, l);
i = strlen(b)+1;
- DEBUG(5, ("File name in tar file: %s, size=%i, \n", b, strlen(b)));
+ DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
- free(b);
+ SAFE_FREE(b);
}
/* use l + 1 to do the null too */
****************************************************************************/
static void fixtarname(char *tptr, char *fp, int l)
{
- /* add a '.' to start of file name, convert from ugly dos \'s in path
- * to lovely unix /'s :-} */
-
- *tptr++='.';
-
- while (l > 0) {
- 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++;
- l--;
- } else {
- *tptr++ = *fp++;
- l--;
- }
- }
+ /* add a '.' to start of file name, convert from ugly dos \'s in path
+ * to lovely unix /'s :-} */
+ *tptr++='.';
+
+ safe_strcpy(tptr, fp, l);
+ string_replace(tptr, '\\', '/');
}
/****************************************************************************
safe_strcpy(ffname, fname, strlen(fname));
/* do a `basename' on ffname, so don't try and make file name directory */
- if ((basehack=strrchr(ffname, '\\')) == NULL)
+ if ((basehack=strrchr_m(ffname, '\\')) == NULL)
return True;
else
*basehack='\0';
{
DEBUG(3,("skipping file %s of size %d bytes\n",
finfo.name,
- finfo.size));
+ (int)finfo.size));
shallitime=0;
ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
ntarf++;
{
DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
finfo.name,
- finfo.size,
+ (int)finfo.size,
lname));
/* write a tar header, don't bother with mode - just set to 100644 */
break;
}
+ nread += datalen;
+
+ /* if file size has increased since we made file size query, truncate
+ read so tar header for this file will be correct.
+ */
+
+ if (nread > finfo.size) {
+ datalen -= nread - finfo.size;
+ DEBUG(0,("File size change - truncating %s to %d bytes\n", finfo.name, (int)finfo.size));
+ }
+
/* add received bits of file to buffer - dotarbuf will
* write out in 512 byte intervals */
if (dotarbuf(tarhandle,data,datalen) != datalen) {
break;
}
- nread += datalen;
if (datalen == 0) {
DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
break;
/* 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=%d, nread=%d\n", finfo.size, nread));
+ DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", (int)finfo.size, (int)nread));
if (padit(data, sizeof(data), finfo.size - nread))
DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
}
if (tar_noisy)
{
DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
- finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
+ (int)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
finfo.name));
}
if (!tar_excl && clipn) {
pstring exclaim;
- DEBUG(5, ("Excl: strlen(cur_dir) = %i\n", strlen(cur_dir)));
+ DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
safe_strcpy(exclaim, cur_dir, sizeof(pstring));
*(exclaim+strlen(exclaim)-1)='\0';
#ifdef HAVE_REGEX_H
(tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
#else
- (tar_re_search && mask_match(exclaim, cliplist[0], True, False))) {
+ (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
#endif
DEBUG(3,("Skipping file %s\n", exclaim));
return;
safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
- DEBUG(5, ("Sizeof(cur_dir)=%i, strlen(cur_dir)=%i, strlen(finfo->name)=%i\nname=%s,cur_dir=%s\n", sizeof(cur_dir), strlen(cur_dir), strlen(finfo->name), finfo->name, cur_dir));
+ DEBUG(5, ("Sizeof(cur_dir)=%d, 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));
safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
safe_strcat(cur_dir,"\\", sizeof(cur_dir));
***************************************************************************/
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!
- */
-
- DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
-
- if (first) {
- if (*fp == '.') {
- fp++;
- l--;
- }
- if (*fp == '\\' || *fp == '/') {
- fp++;
- l--;
- }
- }
+ /* remove '.' from start of file name, convert from unix /'s to
+ * dos \'s in path. Kill any absolute path names. But only if first!
+ */
+
+ DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
+
+ if (first) {
+ if (*fp == '.') {
+ fp++;
+ l--;
+ }
+ if (*fp == '\\' || *fp == '/') {
+ fp++;
+ l--;
+ }
+ }
- while (l > 0) {
- 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++;
- l--;
- } else {
- *tptr++ = *fp++;
- l--;
- }
- }
+ safe_strcpy(tptr, fp, l);
+ string_replace(tptr, '/', '\\');
}
DEBUG(5, ("Reading more data into ltarbuf ...\n"));
- total = 0;
+ /*
+ * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
+ * Fixes bug where read can return short if coming from
+ * a pipe.
+ */
- for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
+ bufread = read(tarhandle, ltarbuf, bufsiz);
+ total = bufread;
- if (bufread <= 0) { /* An error, return false */
- return (total > 0 ? -2 : bufread);
+ while (total < bufsiz) {
+ if (bufread < 0) { /* An error, return false */
+ return (total > 0 ? -2 : bufread);
}
-
+ if (bufread == 0) {
+ if (total <= 0) {
+ return -2;
+ }
+ break;
+ }
+ bufread = read(tarhandle, <arbuf[total], bufsiz - total);
+ total += bufread;
}
DEBUG(5, ("Total bytes read ... %i\n", total));
return(True);
}
-/* We get a file from the tar file and store it */
+/*************************************************************
+ Get a file from the tar file and store it.
+ When this is called, tarbuf already contains the first
+ file block. This is a bit broken & needs fixing.
+**************************************************************/
+
static int get_file(file_info2 finfo)
{
- int fsize = finfo.size;
int fnum = -1, pos = 0, dsize = 0, rsize = 0, bpos = 0;
- DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
+ DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, (int)finfo.size));
if (ensurepath(finfo.name) &&
- (fnum=cli_open(cli, finfo.name, O_WRONLY|O_CREAT|O_TRUNC, DENY_NONE)) == -1)
- {
+ (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
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 */
+ rsize = finfo.size; /* This is how much to write */
while (rsize > 0) {
}
- while (dsize >= TBLOCK) {
+ /*
+ * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
+ * If the file being extracted is an exact multiple of
+ * TBLOCK bytes then we don't want to extract the next
+ * block from the tarfile here, as it will be done in
+ * the caller of get_file().
+ */
- if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
+ while (((rsize != 0) && (dsize >= TBLOCK)) ||
+ ((rsize == 0) && (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;
ntarf++;
- DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
+ DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, (int)finfo.size));
return(True);
}
static int get_dir(file_info2 finfo)
{
- DEBUG(5, ("Creating directory: %s\n", finfo.name));
+ DEBUG(0, ("restore directory %s\n", finfo.name));
if (!ensurepath(finfo.name)) {
return(False);
}
+
+ ntarf++;
return(True);
}
BOOL first = True;
DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
- DEBUG(5, ("Len = %i\n", finfo.size));
+ DEBUG(5, ("Len = %d\n", (int)finfo.size));
if (longname == NULL) {
DEBUG(0, ("could not allocate buffer of size %d for longname\n",
- finfo.size + strlen(cur_dir) + 2));
+ (int)(finfo.size + strlen(cur_dir) + 2)));
return(NULL);
}
return;
case 0: /* chksum is zero - looks like an EOF */
- DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
+ DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
return; /* Hmmm, bad here ... */
default:
if (longfilename != NULL) {
- free(finfo.name); /* Free the space already allocated */
+ SAFE_FREE(finfo.name); /* Free the space already allocated */
finfo.name = longfilename;
longfilename = NULL;
#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)));
+ || (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
#endif
DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
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 ... */
+ /*
+ * 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>
+ * Fixes bug where file size in tarfile is zero.
+ */
- if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
+ if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
DEBUG(0, ("Short file, bailing out...\n"));
return;
}
/****************************************************************************
Blocksize command
***************************************************************************/
-void cmd_block(void)
+int cmd_block(void)
{
fstring buf;
int block;
- if (!next_token(NULL,buf,NULL,sizeof(buf)))
+ if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
{
DEBUG(0, ("blocksize <n>\n"));
- return;
+ return 1;
}
block=atoi(buf);
if (block < 0 || block > 65535)
{
DEBUG(0, ("blocksize out of range"));
- return;
+ return 1;
}
blocksize=block;
DEBUG(2,("blocksize is now %d\n", blocksize));
+
+ return 0;
}
/****************************************************************************
command to set incremental / reset mode
***************************************************************************/
-void cmd_tarmode(void)
+int cmd_tarmode(void)
{
fstring buf;
- while (next_token(NULL,buf,NULL,sizeof(buf))) {
+ while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
if (strequal(buf, "full"))
tar_inc=False;
else if (strequal(buf, "inc"))
tar_reset ? "reset" : "noreset",
tar_noisy ? "verbose" : "quiet"));
+ return 0;
}
/****************************************************************************
Feeble attrib command
***************************************************************************/
-void cmd_setmode(void)
+int cmd_setmode(void)
{
char *q;
fstring buf;
attra[0] = attra[1] = 0;
- if (!next_token(NULL,buf,NULL,sizeof(buf)))
+ if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
{
DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
- return;
+ return 1;
}
safe_strcpy(fname, cur_dir, sizeof(pstring));
safe_strcat(fname, buf, sizeof(pstring));
- while (next_token(NULL,buf,NULL,sizeof(buf))) {
+ while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
q=buf;
while(*q)
case 'a': attra[direct]|=aARCH;
break;
default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
- return;
+ return 1;
}
}
if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
{
DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
- return;
+ return 1;
}
DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
do_setrattr(fname, attra[ATTRSET], ATTRSET);
do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
+
+ return 0;
}
/****************************************************************************
Principal command for creating / extracting
***************************************************************************/
-void cmd_tar(void)
+int cmd_tar(void)
{
fstring buf;
char **argl;
int argcl;
- if (!next_token(NULL,buf,NULL,sizeof(buf)))
+ if (!next_token_nr(NULL,buf,NULL,sizeof(buf)))
{
DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
- return;
+ return 1;
}
argl=toktocliplist(&argcl, NULL);
if (!tar_parseargs(argcl, argl, buf, 0))
- return;
+ return 1;
process_tar();
- free(argl);
+ SAFE_FREE(argl);
+
+ return 0;
}
/****************************************************************************
#else
do_tarput();
#endif
- free(tarbuf);
+ SAFE_FREE(tarbuf);
close(tarhandle);
break;
case 'r':
*(cliplist[i]+strlen(cliplist[i])-1)='\0';
}
- if (strrchr(cliplist[i], '\\')) {
+ if (strrchr_m(cliplist[i], '\\')) {
pstring saved_dir;
safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
safe_strcat(tarmac, cliplist[i], sizeof(pstring));
}
safe_strcpy(cur_dir, tarmac, sizeof(pstring));
- *(strrchr(cur_dir, '\\')+1)='\0';
+ *(strrchr_m(cur_dir, '\\')+1)='\0';
DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
do_list(tarmac,attribute,do_tar, False, True);
} else {
pstring mask;
safe_strcpy(mask,cur_dir, sizeof(pstring));
- DEBUG(5, ("process_tar, do_list with mask: $s\n", mask));
+ DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
safe_strcat(mask,"\\*", sizeof(pstring));
do_list(mask,attribute,do_tar,False, True);
}
if (ntarf) dotareof(tarhandle);
close(tarhandle);
- free(tarbuf);
+ SAFE_FREE(tarbuf);
- DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
- DEBUG(0, ("Total bytes written: %d\n", ttarf));
+ DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
+ DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
break;
}
if (must_free_cliplist) {
int i;
for (i = 0; i < clipn; ++i) {
- free(cliplist[i]);
+ SAFE_FREE(cliplist[i]);
}
- free(cliplist);
+ SAFE_FREE(cliplist);
cliplist = NULL;
clipn = 0;
must_free_cliplist = False;
if (aret==NULL) return 0;
/* ignore leading slashes or dots in token */
- while(strchr("/\\.", *tok)) tok++;
+ while(strchr_m("/\\.", *tok)) tok++;
while(ret--) {
char *pkey=*aret++;
/* ignore leading slashes or dots in list */
- while(strchr("/\\.", *pkey)) pkey++;
+ while(strchr_m("/\\.", *pkey)) pkey++;
if (!strslashcmp(pkey, tok)) return 1;
}
***************************************************************************/
static int read_inclusion_file(char *filename)
{
- FILE *inclusion = NULL;
+ XFILE *inclusion = NULL;
char buf[MAXPATHLEN + 1];
char *inclusion_buffer = NULL;
int inclusion_buffer_size = 0;
clipn = 0;
buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
- if ((inclusion = sys_fopen(filename, "r")) == NULL) {
+ if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
/* XXX It would be better to include a reason for failure, but without
* autoconf, it's hard to use strerror, sys_errlist, etc.
*/
return 0;
}
- while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
+ 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 ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
+ char *ib;
inclusion_buffer_size *= 2;
- inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
- if (! inclusion_buffer) {
+ ib = Realloc(inclusion_buffer,inclusion_buffer_size);
+ if (! ib) {
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);
inclusion_buffer_sofar += strlen(buf) + 1;
clipn++;
}
- fclose(inclusion);
+ x_fclose(inclusion);
if (! error) {
/* Allocate an array of clipn + 1 char*'s for cliplist */
} else {
unfixtarname(tmpstr, p, strlen(p) + 1, True);
cliplist[i] = tmpstr;
- if ((p = strchr(p, '\000')) == NULL) {
+ if ((p = strchr_m(p, '\000')) == NULL) {
DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
abort();
}
}
}
- if (inclusion_buffer) {
- free(inclusion_buffer);
- }
+ SAFE_FREE(inclusion_buffer);
if (error) {
if (cliplist) {
char **pp;
/* We know cliplist is always null-terminated */
for (pp = cliplist; *pp; ++pp) {
- free(*pp);
+ SAFE_FREE(*pp);
}
- free(cliplist);
+ SAFE_FREE(cliplist);
cliplist = NULL;
must_free_cliplist = False;
}
SMB_STRUCT_STAT stbuf;
extern time_t newer_than;
- if (dos_stat(argv[Optind], &stbuf) == 0) {
+ if (sys_stat(argv[Optind], &stbuf) == 0) {
newer_than = stbuf.st_mtime;
DEBUG(1,("Getting files newer than %s",
asctime(LocalTime(&newer_than))));
* tar output
*/
if (tarhandle == 1)
- dbf = stderr;
+ dbf = x_stderr;
} else {
if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
{