r13535: Fix #2353 based on a patch by William Jojo.
[Samba/nascimento.git] / source / client / clitar.c
blobcd0ce27eb5fb181e31d7d2f2e01080ef7cda0640
1 /*
2 Unix SMB/CIFS implementation.
3 Tar Extensions
4 Copyright (C) Ricky Poulten 1995-1998
5 Copyright (C) Richard Sharpe 1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* The following changes developed by Richard Sharpe for Canon Information
22 Systems Research Australia (CISRA)
24 1. Restore can now restore files with long file names
25 2. Save now saves directory information so that we can restore
26 directory creation times
27 3. tar now accepts both UNIX path names and DOS path names. I prefer
28 those lovely /'s to those UGLY \'s :-)
29 4. the files to exclude can be specified as a regular expression by adding
30 an r flag to the other tar flags. Eg:
32 -TcrX file.tar "*.(obj|exe)"
34 will skip all .obj and .exe files
38 #include "includes.h"
39 #include "clitar.h"
40 #include "client/client_proto.h"
42 static int clipfind(char **aret, int ret, char *tok);
44 typedef struct file_info_struct file_info2;
46 struct file_info_struct {
47 SMB_OFF_T size;
48 uint16 mode;
49 uid_t uid;
50 gid_t gid;
51 /* These times are normally kept in GMT */
52 time_t mtime;
53 time_t atime;
54 time_t ctime;
55 char *name; /* This is dynamically allocate */
57 file_info2 *next, *prev; /* Used in the stack ... */
60 typedef struct {
61 file_info2 *top;
62 int items;
63 } stack;
65 #define SEPARATORS " \t\n\r"
66 extern time_t newer_than;
67 extern struct cli_state *cli;
69 /* These defines are for the do_setrattr routine, to indicate
70 * setting and reseting of file attributes in the function call */
71 #define ATTRSET 1
72 #define ATTRRESET 0
74 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
76 #ifndef CLIENT_TIMEOUT
77 #define CLIENT_TIMEOUT (30*1000)
78 #endif
80 static char *tarbuf, *buffer_p;
81 static int tp, ntarf, tbufsiz;
82 static double ttarf;
83 /* Incremental mode */
84 static BOOL tar_inc=False;
85 /* Reset archive bit */
86 static BOOL tar_reset=False;
87 /* Include / exclude mode (true=include, false=exclude) */
88 static BOOL tar_excl=True;
89 /* use regular expressions for search on file names */
90 static BOOL tar_re_search=False;
91 /* Do not dump anything, just calculate sizes */
92 static BOOL dry_run=False;
93 /* Dump files with System attribute */
94 static BOOL tar_system=True;
95 /* Dump files with Hidden attribute */
96 static BOOL tar_hidden=True;
97 /* Be noisy - make a catalogue */
98 static BOOL tar_noisy=True;
99 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
101 char tar_type='\0';
102 static char **cliplist=NULL;
103 static int clipn=0;
104 static BOOL must_free_cliplist = False;
106 extern file_info def_finfo;
107 extern BOOL lowercase;
108 extern uint16 cnum;
109 extern BOOL readbraw_supported;
110 extern int max_xmit;
111 extern pstring cur_dir;
112 extern int get_total_time_ms;
113 extern int get_total_size;
115 static int blocksize=20;
116 static int tarhandle;
118 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
119 const char *amode, unsigned char ftype);
120 static void do_atar(char *rname,char *lname,file_info *finfo1);
121 static void do_tar(file_info *finfo);
122 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
123 static void fixtarname(char *tptr, const char *fp, size_t l);
124 static int dotarbuf(int f, char *b, int n);
125 static void dozerobuf(int f, int n);
126 static void dotareof(int f);
127 static void initarbuf(void);
129 /* restore functions */
130 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
131 static long unoct(char *p, int ndgs);
132 static void do_tarput(void);
133 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
136 * tar specific utitlities
139 /*******************************************************************
140 Create a string of size size+1 (for the null)
141 *******************************************************************/
143 static char *string_create_s(int size)
145 char *tmp;
147 tmp = (char *)SMB_MALLOC(size+1);
149 if (tmp == NULL) {
150 DEBUG(0, ("Out of memory in string_create_s\n"));
153 return(tmp);
156 /****************************************************************************
157 Write a tar header to buffer
158 ****************************************************************************/
160 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
161 const char *amode, unsigned char ftype)
163 union hblock hb;
164 int i, chk, l;
165 char *jp;
167 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
169 memset(hb.dummy, 0, sizeof(hb.dummy));
171 l=strlen(aname);
172 /* We will be prepending a '.' in fixtarheader so use +2 to
173 * take care of the . and terminating zero. JRA.
175 if (l+2 >= NAMSIZ) {
176 /* write a GNU tar style long header */
177 char *b;
178 b = (char *)SMB_MALLOC(l+TBLOCK+100);
179 if (!b) {
180 DEBUG(0,("out of memory\n"));
181 exit(1);
183 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
184 memset(b, 0, l+TBLOCK+100);
185 fixtarname(b, aname, l+2);
186 i = strlen(b)+1;
187 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
188 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
189 SAFE_FREE(b);
192 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
194 if (lowercase)
195 strlower_m(hb.dbuf.name);
197 /* write out a "standard" tar format header */
199 hb.dbuf.name[NAMSIZ-1]='\0';
200 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
201 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.uid);
202 oct_it((SMB_BIG_UINT)0, 8, hb.dbuf.gid);
203 oct_it((SMB_BIG_UINT) size, 13, hb.dbuf.size);
204 if (size > (SMB_BIG_UINT)077777777777LL) {
206 /* This is a non-POSIX compatible extention to store files
207 greater than 8GB. */
209 memset(hb.dbuf.size, 0, 4);
210 hb.dbuf.size[0]=128;
211 for (i = 8, jp=(char*)&size; i; i--)
212 hb.dbuf.size[i+3] = *(jp++);
214 oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
215 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
216 memset(hb.dbuf.linkname, 0, NAMSIZ);
217 hb.dbuf.linkflag=ftype;
219 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
220 chk+=(0xFF & *jp++);
222 oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
223 hb.dbuf.chksum[6] = '\0';
225 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
228 /****************************************************************************
229 Read a tar header into a hblock structure, and validate
230 ***************************************************************************/
232 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
234 long chk, fchk;
235 int i;
236 char *jp;
239 * read in a "standard" tar format header - we're not that interested
240 * in that many fields, though
243 /* check the checksum */
244 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
245 chk+=(0xFF & *jp++);
247 if (chk == 0)
248 return chk;
250 /* compensate for blanks in chksum header */
251 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
252 chk-=(0xFF & *jp++);
254 chk += ' ' * sizeof(hb->dbuf.chksum);
256 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
258 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
259 chk, fchk, hb->dbuf.chksum));
261 if (fchk != chk) {
262 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
263 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
264 return -1;
267 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
268 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
269 return(-1);
272 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
274 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
275 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
276 strlen(hb->dbuf.name) + 1, True);
278 /* can't handle some links at present */
279 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
280 if (hb->dbuf.linkflag == 0) {
281 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
282 finfo->name));
283 } else {
284 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
285 /* Do nothing here at the moment. do_tarput will handle this
286 as long as the longlink gets back to it, as it has to advance
287 the buffer pointer, etc */
288 } else {
289 DEBUG(0, ("this tar file appears to contain some kind \
290 of link other than a GNUtar Longlink - ignoring\n"));
291 return -2;
296 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
297 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
298 finfo->mode=aDIR;
299 } else {
300 finfo->mode=0; /* we don't care about mode at the moment, we'll
301 * just make it a regular file */
305 * Bug fix by richard@sj.co.uk
307 * REC: restore times correctly (as does tar)
308 * We only get the modification time of the file; set the creation time
309 * from the mod. time, and the access time to current time
311 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
312 finfo->atime = time(NULL);
313 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
315 return True;
318 /****************************************************************************
319 Write out the tar buffer to tape or wherever
320 ****************************************************************************/
322 static int dotarbuf(int f, char *b, int n)
324 int fail=1, writ=n;
326 if (dry_run) {
327 return writ;
329 /* This routine and the next one should be the only ones that do write()s */
330 if (tp + n >= tbufsiz) {
331 int diff;
333 diff=tbufsiz-tp;
334 memcpy(tarbuf + tp, b, diff);
335 fail=fail && (1+write(f, tarbuf, tbufsiz));
336 n-=diff;
337 b+=diff;
338 tp=0;
340 while (n >= tbufsiz) {
341 fail=fail && (1 + write(f, b, tbufsiz));
342 n-=tbufsiz;
343 b+=tbufsiz;
347 if (n>0) {
348 memcpy(tarbuf+tp, b, n);
349 tp+=n;
352 return(fail ? writ : 0);
355 /****************************************************************************
356 Write zeros to buffer / tape
357 ****************************************************************************/
359 static void dozerobuf(int f, int n)
361 /* short routine just to write out n zeros to buffer -
362 * used to round files to nearest block
363 * and to do tar EOFs */
365 if (dry_run)
366 return;
368 if (n+tp >= tbufsiz) {
369 memset(tarbuf+tp, 0, tbufsiz-tp);
370 write(f, tarbuf, tbufsiz);
371 memset(tarbuf, 0, (tp+=n-tbufsiz));
372 } else {
373 memset(tarbuf+tp, 0, n);
374 tp+=n;
378 /****************************************************************************
379 Malloc tape buffer
380 ****************************************************************************/
382 static void initarbuf(void)
384 /* initialize tar buffer */
385 tbufsiz=blocksize*TBLOCK;
386 tarbuf=SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
388 /* reset tar buffer pointer and tar file counter and total dumped */
389 tp=0; ntarf=0; ttarf=0;
392 /****************************************************************************
393 Write two zero blocks at end of file
394 ****************************************************************************/
396 static void dotareof(int f)
398 SMB_STRUCT_STAT stbuf;
399 /* Two zero blocks at end of file, write out full buffer */
401 if (dry_run)
402 return;
404 (void) dozerobuf(f, TBLOCK);
405 (void) dozerobuf(f, TBLOCK);
407 if (sys_fstat(f, &stbuf) == -1) {
408 DEBUG(0, ("Couldn't stat file handle\n"));
409 return;
412 /* Could be a pipe, in which case S_ISREG should fail,
413 * and we should write out at full size */
414 if (tp > 0)
415 write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
418 /****************************************************************************
419 (Un)mangle DOS pathname, make nonabsolute
420 ****************************************************************************/
422 static void fixtarname(char *tptr, const char *fp, size_t l)
424 /* add a '.' to start of file name, convert from ugly dos \'s in path
425 * to lovely unix /'s :-} */
426 *tptr++='.';
427 l--;
429 StrnCpy(tptr, fp, l-1);
430 string_replace(tptr, '\\', '/');
433 /****************************************************************************
434 Convert from decimal to octal string
435 ****************************************************************************/
437 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
439 /* Converts long to octal string, pads with leading zeros */
441 /* skip final null, but do final space */
442 --ndgs;
443 p[--ndgs] = ' ';
445 /* Loop does at least one digit */
446 do {
447 p[--ndgs] = '0' + (char) (value & 7);
448 value >>= 3;
449 } while (ndgs > 0 && value != 0);
451 /* Do leading zeros */
452 while (ndgs > 0)
453 p[--ndgs] = '0';
456 /****************************************************************************
457 Convert from octal string to long
458 ***************************************************************************/
460 static long unoct(char *p, int ndgs)
462 long value=0;
463 /* Converts octal string to long, ignoring any non-digit */
465 while (--ndgs) {
466 if (isdigit((int)*p))
467 value = (value << 3) | (long) (*p - '0');
469 p++;
472 return value;
475 /****************************************************************************
476 Compare two strings in a slash insensitive way, allowing s1 to match s2
477 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
478 a file in any subdirectory of s1, declare a match.
479 ***************************************************************************/
481 static int strslashcmp(char *s1, char *s2)
483 char *s1_0=s1;
485 while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
486 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
487 s1++; s2++;
490 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
491 string of s2.
493 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
494 return 0;
496 /* ignore trailing slash on s1 */
497 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
498 return 0;
500 /* check for s1 is an "initial" string of s2 */
501 if ((*s2 == '/' || *s2 == '\\') && !*s1)
502 return 0;
504 return *s1-*s2;
507 /****************************************************************************
508 Ensure a remote path exists (make if necessary)
509 ***************************************************************************/
511 static BOOL ensurepath(char *fname)
513 /* *must* be called with buffer ready malloc'ed */
514 /* ensures path exists */
516 char *partpath, *ffname;
517 char *p=fname, *basehack;
519 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
521 partpath = string_create_s(strlen(fname));
522 ffname = string_create_s(strlen(fname));
524 if ((partpath == NULL) || (ffname == NULL)){
525 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
526 return(False);
529 *partpath = 0;
531 /* fname copied to ffname so can strtok */
533 safe_strcpy(ffname, fname, strlen(fname));
535 /* do a `basename' on ffname, so don't try and make file name directory */
536 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
537 return True;
538 else
539 *basehack='\0';
541 p=strtok(ffname, "\\");
543 while (p) {
544 safe_strcat(partpath, p, strlen(fname) + 1);
546 if (!cli_chkpath(cli, partpath)) {
547 if (!cli_mkdir(cli, partpath)) {
548 DEBUG(0, ("Error mkdirhiering\n"));
549 return False;
550 } else {
551 DEBUG(3, ("mkdirhiering %s\n", partpath));
555 safe_strcat(partpath, "\\", strlen(fname) + 1);
556 p = strtok(NULL,"/\\");
559 return True;
562 static int padit(char *buf, int bufsize, int padsize)
564 int berr= 0;
565 int bytestowrite;
567 DEBUG(5, ("Padding with %d zeros\n", padsize));
568 memset(buf, 0, bufsize);
569 while( !berr && padsize > 0 ) {
570 bytestowrite= MIN(bufsize, padsize);
571 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
572 padsize -= bytestowrite;
575 return berr;
578 static void do_setrattr(char *name, uint16 attr, int set)
580 uint16 oldattr;
582 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
584 if (set == ATTRSET) {
585 attr |= oldattr;
586 } else {
587 attr = oldattr & ~attr;
590 if (!cli_setatr(cli, name, attr, 0)) {
591 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
595 /****************************************************************************
596 append one remote file to the tar file
597 ***************************************************************************/
599 static void do_atar(char *rname,char *lname,file_info *finfo1)
601 int fnum;
602 SMB_BIG_UINT nread=0;
603 char ftype;
604 file_info2 finfo;
605 BOOL close_done = False;
606 BOOL shallitime=True;
607 char data[65520];
608 int read_size = 65520;
609 int datalen=0;
611 struct timeval tp_start;
613 GetTimeOfDay(&tp_start);
615 ftype = '0'; /* An ordinary file ... */
617 if (finfo1) {
618 finfo.size = finfo1 -> size;
619 finfo.mode = finfo1 -> mode;
620 finfo.uid = finfo1 -> uid;
621 finfo.gid = finfo1 -> gid;
622 finfo.mtime = finfo1 -> mtime;
623 finfo.atime = finfo1 -> atime;
624 finfo.ctime = finfo1 -> ctime;
625 finfo.name = finfo1 -> name;
626 } else {
627 finfo.size = def_finfo.size;
628 finfo.mode = def_finfo.mode;
629 finfo.uid = def_finfo.uid;
630 finfo.gid = def_finfo.gid;
631 finfo.mtime = def_finfo.mtime;
632 finfo.atime = def_finfo.atime;
633 finfo.ctime = def_finfo.ctime;
634 finfo.name = def_finfo.name;
637 if (dry_run) {
638 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
639 (double)finfo.size));
640 shallitime=0;
641 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
642 ntarf++;
643 return;
646 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
648 dos_clean_name(rname);
650 if (fnum == -1) {
651 DEBUG(0,("%s opening remote file %s (%s)\n",
652 cli_errstr(cli),rname, cur_dir));
653 return;
656 finfo.name = string_create_s(strlen(rname));
657 if (finfo.name == NULL) {
658 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
659 return;
662 safe_strcpy(finfo.name,rname, strlen(rname));
663 if (!finfo1) {
664 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
665 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
666 return;
668 finfo.ctime = finfo.mtime;
671 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
673 if (tar_inc && !(finfo.mode & aARCH)) {
674 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
675 shallitime=0;
676 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
677 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
678 shallitime=0;
679 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
680 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
681 shallitime=0;
682 } else {
683 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
684 finfo.name, (double)finfo.size, lname));
686 /* write a tar header, don't bother with mode - just set to 100644 */
687 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
689 while (nread < finfo.size && !close_done) {
691 DEBUG(3,("nread=%.0f\n",(double)nread));
693 datalen = cli_read(cli, fnum, data, nread, read_size);
695 if (datalen == -1) {
696 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
697 break;
700 nread += datalen;
702 /* if file size has increased since we made file size query, truncate
703 read so tar header for this file will be correct.
706 if (nread > finfo.size) {
707 datalen -= nread - finfo.size;
708 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
709 finfo.name, (double)finfo.size));
712 /* add received bits of file to buffer - dotarbuf will
713 * write out in 512 byte intervals */
715 if (dotarbuf(tarhandle,data,datalen) != datalen) {
716 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
717 break;
720 if (datalen == 0) {
721 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
722 break;
725 datalen=0;
728 /* pad tar file with zero's if we couldn't get entire file */
729 if (nread < finfo.size) {
730 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
731 (double)finfo.size, (int)nread));
732 if (padit(data, sizeof(data), finfo.size - nread))
733 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
736 /* round tar file to nearest block */
737 if (finfo.size % TBLOCK)
738 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
740 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
741 ntarf++;
744 cli_close(cli, fnum);
746 if (shallitime) {
747 struct timeval tp_end;
748 int this_time;
750 /* if shallitime is true then we didn't skip */
751 if (tar_reset && !dry_run)
752 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
754 GetTimeOfDay(&tp_end);
755 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
756 get_total_time_ms += this_time;
757 get_total_size += finfo.size;
759 if (tar_noisy) {
760 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
761 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
762 finfo.name));
765 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
766 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
767 finfo.size / MAX(0.001, (1.024*this_time)),
768 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
772 /****************************************************************************
773 Append single file to tar file (or not)
774 ***************************************************************************/
776 static void do_tar(file_info *finfo)
778 pstring rname;
780 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
781 return;
783 /* Is it on the exclude list ? */
784 if (!tar_excl && clipn) {
785 pstring exclaim;
787 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
789 pstrcpy(exclaim, cur_dir);
790 *(exclaim+strlen(exclaim)-1)='\0';
792 pstrcat(exclaim, "\\");
793 pstrcat(exclaim, finfo->name);
795 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
797 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
798 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
799 DEBUG(3,("Skipping file %s\n", exclaim));
800 return;
804 if (finfo->mode & aDIR) {
805 pstring saved_curdir;
806 pstring mtar_mask;
808 pstrcpy(saved_curdir, cur_dir);
810 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
811 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
812 (int)sizeof(cur_dir), (int)strlen(cur_dir),
813 (int)strlen(finfo->name), finfo->name, cur_dir));
815 pstrcat(cur_dir,finfo->name);
816 pstrcat(cur_dir,"\\");
818 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
820 /* write a tar directory, don't bother with mode - just set it to
821 * 40755 */
822 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
823 if (tar_noisy) {
824 DEBUG(0,(" directory %s\n", cur_dir));
826 ntarf++; /* Make sure we have a file on there */
827 pstrcpy(mtar_mask,cur_dir);
828 pstrcat(mtar_mask,"*");
829 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
830 do_list(mtar_mask, attribute, do_tar, False, True);
831 pstrcpy(cur_dir,saved_curdir);
832 } else {
833 pstrcpy(rname,cur_dir);
834 pstrcat(rname,finfo->name);
835 do_atar(rname,finfo->name,finfo);
839 /****************************************************************************
840 Convert from UNIX to DOS file names
841 ***************************************************************************/
843 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
845 /* remove '.' from start of file name, convert from unix /'s to
846 * dos \'s in path. Kill any absolute path names. But only if first!
849 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
851 if (first) {
852 if (*fp == '.') {
853 fp++;
854 l--;
856 if (*fp == '\\' || *fp == '/') {
857 fp++;
858 l--;
862 safe_strcpy(tptr, fp, l);
863 string_replace(tptr, '/', '\\');
866 /****************************************************************************
867 Move to the next block in the buffer, which may mean read in another set of
868 blocks. FIXME, we should allow more than one block to be skipped.
869 ****************************************************************************/
871 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
873 int bufread, total = 0;
875 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
876 *bufferp += TBLOCK;
877 total = TBLOCK;
879 if (*bufferp >= (ltarbuf + bufsiz)) {
881 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
884 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
885 * Fixes bug where read can return short if coming from
886 * a pipe.
889 bufread = read(tarhandle, ltarbuf, bufsiz);
890 total = bufread;
892 while (total < bufsiz) {
893 if (bufread < 0) { /* An error, return false */
894 return (total > 0 ? -2 : bufread);
896 if (bufread == 0) {
897 if (total <= 0) {
898 return -2;
900 break;
902 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
903 total += bufread;
906 DEBUG(5, ("Total bytes read ... %i\n", total));
908 *bufferp = ltarbuf;
911 return(total);
914 /* Skip a file, even if it includes a long file name? */
915 static int skip_file(int skipsize)
917 int dsize = skipsize;
919 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
921 /* FIXME, we should skip more than one block at a time */
923 while (dsize > 0) {
924 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
925 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
926 return(False);
928 dsize -= TBLOCK;
931 return(True);
934 /*************************************************************
935 Get a file from the tar file and store it.
936 When this is called, tarbuf already contains the first
937 file block. This is a bit broken & needs fixing.
938 **************************************************************/
940 static int get_file(file_info2 finfo)
942 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
943 SMB_BIG_UINT rsize = 0;
945 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
947 if (ensurepath(finfo.name) &&
948 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
949 DEBUG(0, ("abandoning restore\n"));
950 return(False);
953 /* read the blocks from the tar file and write to the remote file */
955 rsize = finfo.size; /* This is how much to write */
957 while (rsize > 0) {
959 /* We can only write up to the end of the buffer */
960 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
961 dsize = MIN(dsize, rsize); /* Should be only what is left */
962 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
964 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
965 DEBUG(0, ("Error writing remote file\n"));
966 return 0;
969 rsize -= dsize;
970 pos += dsize;
972 /* Now figure out how much to move in the buffer */
974 /* FIXME, we should skip more than one block at a time */
976 /* First, skip any initial part of the part written that is left over */
977 /* from the end of the first TBLOCK */
979 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
980 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
981 bpos = 0;
983 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
984 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
985 return False;
990 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
991 * If the file being extracted is an exact multiple of
992 * TBLOCK bytes then we don't want to extract the next
993 * block from the tarfile here, as it will be done in
994 * the caller of get_file().
997 while (((rsize != 0) && (dsize >= TBLOCK)) ||
998 ((rsize == 0) && (dsize > TBLOCK))) {
1000 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1001 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1002 return False;
1005 dsize -= TBLOCK;
1007 bpos = dsize;
1010 /* Now close the file ... */
1012 if (!cli_close(cli, fnum)) {
1013 DEBUG(0, ("Error closing remote file\n"));
1014 return(False);
1017 /* Now we update the creation date ... */
1018 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1020 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1021 if (tar_real_noisy) {
1022 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1023 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1027 ntarf++;
1028 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1029 return(True);
1032 /* Create a directory. We just ensure that the path exists and return as there
1033 is no file associated with a directory
1035 static int get_dir(file_info2 finfo)
1037 DEBUG(0, ("restore directory %s\n", finfo.name));
1039 if (!ensurepath(finfo.name)) {
1040 DEBUG(0, ("Problems creating directory\n"));
1041 return(False);
1043 ntarf++;
1044 return(True);
1047 /* Get a file with a long file name ... first file has file name, next file
1048 has the data. We only want the long file name, as the loop in do_tarput
1049 will deal with the rest.
1051 static char *get_longfilename(file_info2 finfo)
1053 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1054 * header call. */
1055 int namesize = finfo.size + strlen(cur_dir) + 2;
1056 char *longname = SMB_MALLOC(namesize);
1057 int offset = 0, left = finfo.size;
1058 BOOL first = True;
1060 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1061 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1063 if (longname == NULL) {
1064 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1065 return(NULL);
1068 /* First, add cur_dir to the long file name */
1070 if (strlen(cur_dir) > 0) {
1071 strncpy(longname, cur_dir, namesize);
1072 offset = strlen(cur_dir);
1075 /* Loop through the blocks picking up the name */
1077 while (left > 0) {
1078 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1079 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1080 return(NULL);
1083 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1084 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1086 offset += TBLOCK;
1087 left -= TBLOCK;
1090 return(longname);
1093 static void do_tarput(void)
1095 file_info2 finfo;
1096 struct timeval tp_start;
1097 char *longfilename = NULL, linkflag;
1098 int skip = False;
1100 ZERO_STRUCT(finfo);
1102 GetTimeOfDay(&tp_start);
1103 DEBUG(5, ("RJS do_tarput called ...\n"));
1105 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1107 /* Now read through those files ... */
1108 while (True) {
1109 /* Get us to the next block, or the first block first time around */
1110 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1111 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1112 return;
1115 DEBUG(5, ("Reading the next header ...\n"));
1117 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1118 case -2: /* Hmm, not good, but not fatal */
1119 DEBUG(0, ("Skipping %s...\n", finfo.name));
1120 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1121 DEBUG(0, ("Short file, bailing out...\n"));
1122 return;
1124 break;
1126 case -1:
1127 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1128 return;
1130 case 0: /* chksum is zero - looks like an EOF */
1131 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1132 return; /* Hmmm, bad here ... */
1134 default:
1135 /* No action */
1136 break;
1139 /* Now, do we have a long file name? */
1140 if (longfilename != NULL) {
1141 SAFE_FREE(finfo.name); /* Free the space already allocated */
1142 finfo.name = longfilename;
1143 longfilename = NULL;
1146 /* Well, now we have a header, process the file ... */
1147 /* Should we skip the file? We have the long name as well here */
1148 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1149 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1151 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1152 if (skip) {
1153 skip_file(finfo.size);
1154 continue;
1157 /* We only get this far if we should process the file */
1158 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1159 switch (linkflag) {
1160 case '0': /* Should use symbolic names--FIXME */
1162 * Skip to the next block first, so we can get the file, FIXME, should
1163 * be in get_file ...
1164 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1165 * Fixes bug where file size in tarfile is zero.
1167 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1168 DEBUG(0, ("Short file, bailing out...\n"));
1169 return;
1171 if (!get_file(finfo)) {
1172 DEBUG(0, ("Abandoning restore\n"));
1173 return;
1175 break;
1176 case '5':
1177 if (!get_dir(finfo)) {
1178 DEBUG(0, ("Abandoning restore \n"));
1179 return;
1181 break;
1182 case 'L':
1183 longfilename = get_longfilename(finfo);
1184 if (!longfilename) {
1185 DEBUG(0, ("abandoning restore\n"));
1186 return;
1188 DEBUG(5, ("Long file name: %s\n", longfilename));
1189 break;
1191 default:
1192 skip_file(finfo.size); /* Don't handle these yet */
1193 break;
1199 * samba interactive commands
1202 /****************************************************************************
1203 Blocksize command
1204 ***************************************************************************/
1206 int cmd_block(void)
1208 fstring buf;
1209 int block;
1211 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1212 DEBUG(0, ("blocksize <n>\n"));
1213 return 1;
1216 block=atoi(buf);
1217 if (block < 0 || block > 65535) {
1218 DEBUG(0, ("blocksize out of range"));
1219 return 1;
1222 blocksize=block;
1223 DEBUG(2,("blocksize is now %d\n", blocksize));
1225 return 0;
1228 /****************************************************************************
1229 command to set incremental / reset mode
1230 ***************************************************************************/
1232 int cmd_tarmode(void)
1234 fstring buf;
1236 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1237 if (strequal(buf, "full"))
1238 tar_inc=False;
1239 else if (strequal(buf, "inc"))
1240 tar_inc=True;
1241 else if (strequal(buf, "reset"))
1242 tar_reset=True;
1243 else if (strequal(buf, "noreset"))
1244 tar_reset=False;
1245 else if (strequal(buf, "system"))
1246 tar_system=True;
1247 else if (strequal(buf, "nosystem"))
1248 tar_system=False;
1249 else if (strequal(buf, "hidden"))
1250 tar_hidden=True;
1251 else if (strequal(buf, "nohidden"))
1252 tar_hidden=False;
1253 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1254 tar_noisy=True;
1255 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1256 tar_noisy=False;
1257 else
1258 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1261 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1262 tar_inc ? "incremental" : "full",
1263 tar_system ? "system" : "nosystem",
1264 tar_hidden ? "hidden" : "nohidden",
1265 tar_reset ? "reset" : "noreset",
1266 tar_noisy ? "verbose" : "quiet"));
1267 return 0;
1270 /****************************************************************************
1271 Feeble attrib command
1272 ***************************************************************************/
1274 int cmd_setmode(void)
1276 char *q;
1277 fstring buf;
1278 pstring fname;
1279 uint16 attra[2];
1280 int direct=1;
1282 attra[0] = attra[1] = 0;
1284 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1285 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1286 return 1;
1289 pstrcpy(fname, cur_dir);
1290 pstrcat(fname, buf);
1292 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1293 q=buf;
1295 while(*q) {
1296 switch (*q++) {
1297 case '+':
1298 direct=1;
1299 break;
1300 case '-':
1301 direct=0;
1302 break;
1303 case 'r':
1304 attra[direct]|=aRONLY;
1305 break;
1306 case 'h':
1307 attra[direct]|=aHIDDEN;
1308 break;
1309 case 's':
1310 attra[direct]|=aSYSTEM;
1311 break;
1312 case 'a':
1313 attra[direct]|=aARCH;
1314 break;
1315 default:
1316 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1317 return 1;
1322 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1323 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1324 return 1;
1327 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1328 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1329 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1330 return 0;
1333 /****************************************************************************
1334 Principal command for creating / extracting
1335 ***************************************************************************/
1337 int cmd_tar(void)
1339 fstring buf;
1340 char **argl = NULL;
1341 int argcl = 0;
1342 int ret;
1344 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1345 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1346 return 1;
1349 argl=toktocliplist(&argcl, NULL);
1350 if (!tar_parseargs(argcl, argl, buf, 0))
1351 return 1;
1353 ret = process_tar();
1354 SAFE_FREE(argl);
1355 return ret;
1358 /****************************************************************************
1359 Command line (option) version
1360 ***************************************************************************/
1362 int process_tar(void)
1364 int rc = 0;
1365 initarbuf();
1366 switch(tar_type) {
1367 case 'x':
1369 #if 0
1370 do_tarput2();
1371 #else
1372 do_tarput();
1373 #endif
1374 SAFE_FREE(tarbuf);
1375 close(tarhandle);
1376 break;
1377 case 'r':
1378 case 'c':
1379 if (clipn && tar_excl) {
1380 int i;
1381 pstring tarmac;
1383 for (i=0; i<clipn; i++) {
1384 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1386 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1387 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1390 if (strrchr_m(cliplist[i], '\\')) {
1391 pstring saved_dir;
1393 pstrcpy(saved_dir, cur_dir);
1395 if (*cliplist[i]=='\\') {
1396 pstrcpy(tarmac, cliplist[i]);
1397 } else {
1398 pstrcpy(tarmac, cur_dir);
1399 pstrcat(tarmac, cliplist[i]);
1401 pstrcpy(cur_dir, tarmac);
1402 *(strrchr_m(cur_dir, '\\')+1)='\0';
1404 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1405 do_list(tarmac,attribute,do_tar, False, True);
1406 pstrcpy(cur_dir,saved_dir);
1407 } else {
1408 pstrcpy(tarmac, cur_dir);
1409 pstrcat(tarmac, cliplist[i]);
1410 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1411 do_list(tarmac,attribute,do_tar, False, True);
1414 } else {
1415 pstring mask;
1416 pstrcpy(mask,cur_dir);
1417 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1418 pstrcat(mask,"\\*");
1419 do_list(mask,attribute,do_tar,False, True);
1422 if (ntarf)
1423 dotareof(tarhandle);
1424 close(tarhandle);
1425 SAFE_FREE(tarbuf);
1427 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1428 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1429 break;
1432 if (must_free_cliplist) {
1433 int i;
1434 for (i = 0; i < clipn; ++i) {
1435 SAFE_FREE(cliplist[i]);
1437 SAFE_FREE(cliplist);
1438 cliplist = NULL;
1439 clipn = 0;
1440 must_free_cliplist = False;
1442 return rc;
1445 /****************************************************************************
1446 Find a token (filename) in a clip list
1447 ***************************************************************************/
1449 static int clipfind(char **aret, int ret, char *tok)
1451 if (aret==NULL)
1452 return 0;
1454 /* ignore leading slashes or dots in token */
1455 while(strchr_m("/\\.", *tok))
1456 tok++;
1458 while(ret--) {
1459 char *pkey=*aret++;
1461 /* ignore leading slashes or dots in list */
1462 while(strchr_m("/\\.", *pkey))
1463 pkey++;
1465 if (!strslashcmp(pkey, tok))
1466 return 1;
1468 return 0;
1471 /****************************************************************************
1472 Read list of files to include from the file and initialize cliplist
1473 accordingly.
1474 ***************************************************************************/
1476 static int read_inclusion_file(char *filename)
1478 XFILE *inclusion = NULL;
1479 char buf[PATH_MAX + 1];
1480 char *inclusion_buffer = NULL;
1481 int inclusion_buffer_size = 0;
1482 int inclusion_buffer_sofar = 0;
1483 char *p;
1484 char *tmpstr;
1485 int i;
1486 int error = 0;
1488 clipn = 0;
1489 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1490 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1491 /* XXX It would be better to include a reason for failure, but without
1492 * autoconf, it's hard to use strerror, sys_errlist, etc.
1494 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1495 return 0;
1498 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1499 if (inclusion_buffer == NULL) {
1500 inclusion_buffer_size = 1024;
1501 if ((inclusion_buffer = SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1502 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1503 error = 1;
1504 break;
1508 if (buf[strlen(buf)-1] == '\n') {
1509 buf[strlen(buf)-1] = '\0';
1512 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1513 char *ib;
1514 inclusion_buffer_size *= 2;
1515 ib = SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1516 if (! ib) {
1517 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1518 inclusion_buffer_size));
1519 error = 1;
1520 break;
1521 } else {
1522 inclusion_buffer = ib;
1526 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1527 inclusion_buffer_sofar += strlen(buf) + 1;
1528 clipn++;
1530 x_fclose(inclusion);
1532 if (! error) {
1533 /* Allocate an array of clipn + 1 char*'s for cliplist */
1534 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1535 if (cliplist == NULL) {
1536 DEBUG(0,("failure allocating memory for cliplist\n"));
1537 error = 1;
1538 } else {
1539 cliplist[clipn] = NULL;
1540 p = inclusion_buffer;
1541 for (i = 0; (! error) && (i < clipn); i++) {
1542 /* set current item to NULL so array will be null-terminated even if
1543 * malloc fails below. */
1544 cliplist[i] = NULL;
1545 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1546 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1547 error = 1;
1548 } else {
1549 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1550 cliplist[i] = tmpstr;
1551 if ((p = strchr_m(p, '\000')) == NULL) {
1552 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1553 abort();
1556 ++p;
1558 must_free_cliplist = True;
1562 SAFE_FREE(inclusion_buffer);
1563 if (error) {
1564 if (cliplist) {
1565 char **pp;
1566 /* We know cliplist is always null-terminated */
1567 for (pp = cliplist; *pp; ++pp) {
1568 SAFE_FREE(*pp);
1570 SAFE_FREE(cliplist);
1571 cliplist = NULL;
1572 must_free_cliplist = False;
1574 return 0;
1577 /* cliplist and its elements are freed at the end of process_tar. */
1578 return 1;
1581 /****************************************************************************
1582 Parse tar arguments. Sets tar_type, tar_excl, etc.
1583 ***************************************************************************/
1585 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1587 int newOptind = Optind;
1588 char tar_clipfl='\0';
1590 /* Reset back to defaults - could be from interactive version
1591 * reset mode and archive mode left as they are though
1593 tar_type='\0';
1594 tar_excl=True;
1595 dry_run=False;
1597 while (*Optarg) {
1598 switch(*Optarg++) {
1599 case 'c':
1600 tar_type='c';
1601 break;
1602 case 'x':
1603 if (tar_type=='c') {
1604 printf("Tar must be followed by only one of c or x.\n");
1605 return 0;
1607 tar_type='x';
1608 break;
1609 case 'b':
1610 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1611 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1612 return 0;
1613 } else {
1614 Optind++;
1615 newOptind++;
1617 break;
1618 case 'g':
1619 tar_inc=True;
1620 break;
1621 case 'N':
1622 if (Optind>=argc) {
1623 DEBUG(0,("Option N must be followed by valid file name\n"));
1624 return 0;
1625 } else {
1626 SMB_STRUCT_STAT stbuf;
1628 if (sys_stat(argv[Optind], &stbuf) == 0) {
1629 newer_than = stbuf.st_mtime;
1630 DEBUG(1,("Getting files newer than %s",
1631 asctime(localtime(&newer_than))));
1632 newOptind++;
1633 Optind++;
1634 } else {
1635 DEBUG(0,("Error setting newer-than time\n"));
1636 return 0;
1639 break;
1640 case 'a':
1641 tar_reset=True;
1642 break;
1643 case 'q':
1644 tar_noisy=False;
1645 break;
1646 case 'I':
1647 if (tar_clipfl) {
1648 DEBUG(0,("Only one of I,X,F must be specified\n"));
1649 return 0;
1651 tar_clipfl='I';
1652 break;
1653 case 'X':
1654 if (tar_clipfl) {
1655 DEBUG(0,("Only one of I,X,F must be specified\n"));
1656 return 0;
1658 tar_clipfl='X';
1659 break;
1660 case 'F':
1661 if (tar_clipfl) {
1662 DEBUG(0,("Only one of I,X,F must be specified\n"));
1663 return 0;
1665 tar_clipfl='F';
1666 break;
1667 case 'r':
1668 DEBUG(0, ("tar_re_search set\n"));
1669 tar_re_search = True;
1670 break;
1671 case 'n':
1672 if (tar_type == 'c') {
1673 DEBUG(0, ("dry_run set\n"));
1674 dry_run = True;
1675 } else {
1676 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1677 return 0;
1679 break;
1680 default:
1681 DEBUG(0,("Unknown tar option\n"));
1682 return 0;
1686 if (!tar_type) {
1687 printf("Option T must be followed by one of c or x.\n");
1688 return 0;
1691 /* tar_excl is true if cliplist lists files to be included.
1692 * Both 'I' and 'F' mean include. */
1693 tar_excl=tar_clipfl!='X';
1695 if (tar_clipfl=='F') {
1696 if (argc-Optind-1 != 1) {
1697 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1698 return 0;
1700 newOptind++;
1701 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1702 if (! read_inclusion_file(argv[Optind+1])) {
1703 return 0;
1705 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1706 char *tmpstr;
1707 char **tmplist;
1708 int clipcount;
1710 cliplist=argv+Optind+1;
1711 clipn=argc-Optind-1;
1712 clipcount = clipn;
1714 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1715 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1716 return 0;
1719 for (clipcount = 0; clipcount < clipn; clipcount++) {
1721 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1723 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1724 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1725 return 0;
1728 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1729 tmplist[clipcount] = tmpstr;
1730 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1732 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1735 cliplist = tmplist;
1736 must_free_cliplist = True;
1738 newOptind += clipn;
1741 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1742 /* Doing regular expression seaches not from an inclusion file. */
1743 clipn=argc-Optind-1;
1744 cliplist=argv+Optind+1;
1745 newOptind += clipn;
1748 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1749 /* Sets tar handle to either 0 or 1, as appropriate */
1750 tarhandle=(tar_type=='c');
1752 * Make sure that dbf points to stderr if we are using stdout for
1753 * tar output
1755 if (tarhandle == 1) {
1756 dbf = x_stderr;
1758 if (!argv[Optind]) {
1759 DEBUG(0,("Must specify tar filename\n"));
1760 return 0;
1762 if (!strcmp(argv[Optind], "-")) {
1763 newOptind++;
1766 } else {
1767 if (tar_type=='c' && dry_run) {
1768 tarhandle=-1;
1769 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1770 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1771 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1772 return(0);
1774 newOptind++;
1777 return newOptind;