[GLUE] Rsync SAMBA_3_0 SVN r25598 in order to create the v3-0-test branch.
[Samba.git] / source / client / clitar.c
blob7bbb9fc58bf68554bf7ec637f57ed38b164da6f0
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 struct timespec mtime_ts;
53 struct timespec atime_ts;
54 struct timespec ctime_ts;
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 #ifdef HAVE_LONGLONG
205 if (size > (SMB_BIG_UINT)077777777777LL) {
206 #else
207 if (size > (SMB_BIG_UINT)077777777777) {
208 #endif
210 /* This is a non-POSIX compatible extention to store files
211 greater than 8GB. */
213 memset(hb.dbuf.size, 0, 4);
214 hb.dbuf.size[0]=128;
215 for (i = 8, jp=(char*)&size; i; i--)
216 hb.dbuf.size[i+3] = *(jp++);
218 oct_it((SMB_BIG_UINT) mtime, 13, hb.dbuf.mtime);
219 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
220 memset(hb.dbuf.linkname, 0, NAMSIZ);
221 hb.dbuf.linkflag=ftype;
223 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
224 chk+=(0xFF & *jp++);
226 oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
227 hb.dbuf.chksum[6] = '\0';
229 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
232 /****************************************************************************
233 Read a tar header into a hblock structure, and validate
234 ***************************************************************************/
236 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
238 long chk, fchk;
239 int i;
240 char *jp;
243 * read in a "standard" tar format header - we're not that interested
244 * in that many fields, though
247 /* check the checksum */
248 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
249 chk+=(0xFF & *jp++);
251 if (chk == 0)
252 return chk;
254 /* compensate for blanks in chksum header */
255 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
256 chk-=(0xFF & *jp++);
258 chk += ' ' * sizeof(hb->dbuf.chksum);
260 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
262 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
263 chk, fchk, hb->dbuf.chksum));
265 if (fchk != chk) {
266 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
267 dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
268 return -1;
271 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
272 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
273 return(-1);
276 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
278 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
279 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
280 strlen(hb->dbuf.name) + 1, True);
282 /* can't handle some links at present */
283 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
284 if (hb->dbuf.linkflag == 0) {
285 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
286 finfo->name));
287 } else {
288 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
289 /* Do nothing here at the moment. do_tarput will handle this
290 as long as the longlink gets back to it, as it has to advance
291 the buffer pointer, etc */
292 } else {
293 DEBUG(0, ("this tar file appears to contain some kind \
294 of link other than a GNUtar Longlink - ignoring\n"));
295 return -2;
300 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
301 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
302 finfo->mode=aDIR;
303 } else {
304 finfo->mode=0; /* we don't care about mode at the moment, we'll
305 * just make it a regular file */
309 * Bug fix by richard@sj.co.uk
311 * REC: restore times correctly (as does tar)
312 * We only get the modification time of the file; set the creation time
313 * from the mod. time, and the access time to current time
315 finfo->mtime_ts = finfo->ctime_ts =
316 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
317 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
318 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
320 return True;
323 /****************************************************************************
324 Write out the tar buffer to tape or wherever
325 ****************************************************************************/
327 static int dotarbuf(int f, char *b, int n)
329 int fail=1, writ=n;
331 if (dry_run) {
332 return writ;
334 /* This routine and the next one should be the only ones that do write()s */
335 if (tp + n >= tbufsiz) {
336 int diff;
338 diff=tbufsiz-tp;
339 memcpy(tarbuf + tp, b, diff);
340 fail=fail && (1+write(f, tarbuf, tbufsiz));
341 n-=diff;
342 b+=diff;
343 tp=0;
345 while (n >= tbufsiz) {
346 fail=fail && (1 + write(f, b, tbufsiz));
347 n-=tbufsiz;
348 b+=tbufsiz;
352 if (n>0) {
353 memcpy(tarbuf+tp, b, n);
354 tp+=n;
357 return(fail ? writ : 0);
360 /****************************************************************************
361 Write zeros to buffer / tape
362 ****************************************************************************/
364 static void dozerobuf(int f, int n)
366 /* short routine just to write out n zeros to buffer -
367 * used to round files to nearest block
368 * and to do tar EOFs */
370 if (dry_run)
371 return;
373 if (n+tp >= tbufsiz) {
374 memset(tarbuf+tp, 0, tbufsiz-tp);
375 write(f, tarbuf, tbufsiz);
376 memset(tarbuf, 0, (tp+=n-tbufsiz));
377 } else {
378 memset(tarbuf+tp, 0, n);
379 tp+=n;
383 /****************************************************************************
384 Malloc tape buffer
385 ****************************************************************************/
387 static void initarbuf(void)
389 /* initialize tar buffer */
390 tbufsiz=blocksize*TBLOCK;
391 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
393 /* reset tar buffer pointer and tar file counter and total dumped */
394 tp=0; ntarf=0; ttarf=0;
397 /****************************************************************************
398 Write two zero blocks at end of file
399 ****************************************************************************/
401 static void dotareof(int f)
403 SMB_STRUCT_STAT stbuf;
404 /* Two zero blocks at end of file, write out full buffer */
406 if (dry_run)
407 return;
409 (void) dozerobuf(f, TBLOCK);
410 (void) dozerobuf(f, TBLOCK);
412 if (sys_fstat(f, &stbuf) == -1) {
413 DEBUG(0, ("Couldn't stat file handle\n"));
414 return;
417 /* Could be a pipe, in which case S_ISREG should fail,
418 * and we should write out at full size */
419 if (tp > 0)
420 write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
423 /****************************************************************************
424 (Un)mangle DOS pathname, make nonabsolute
425 ****************************************************************************/
427 static void fixtarname(char *tptr, const char *fp, size_t l)
429 /* add a '.' to start of file name, convert from ugly dos \'s in path
430 * to lovely unix /'s :-} */
431 *tptr++='.';
432 l--;
434 StrnCpy(tptr, fp, l-1);
435 string_replace(tptr, '\\', '/');
438 /****************************************************************************
439 Convert from decimal to octal string
440 ****************************************************************************/
442 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
444 /* Converts long to octal string, pads with leading zeros */
446 /* skip final null, but do final space */
447 --ndgs;
448 p[--ndgs] = ' ';
450 /* Loop does at least one digit */
451 do {
452 p[--ndgs] = '0' + (char) (value & 7);
453 value >>= 3;
454 } while (ndgs > 0 && value != 0);
456 /* Do leading zeros */
457 while (ndgs > 0)
458 p[--ndgs] = '0';
461 /****************************************************************************
462 Convert from octal string to long
463 ***************************************************************************/
465 static long unoct(char *p, int ndgs)
467 long value=0;
468 /* Converts octal string to long, ignoring any non-digit */
470 while (--ndgs) {
471 if (isdigit((int)*p))
472 value = (value << 3) | (long) (*p - '0');
474 p++;
477 return value;
480 /****************************************************************************
481 Compare two strings in a slash insensitive way, allowing s1 to match s2
482 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
483 a file in any subdirectory of s1, declare a match.
484 ***************************************************************************/
486 static int strslashcmp(char *s1, char *s2)
488 char *s1_0=s1;
490 while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
491 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
492 s1++; s2++;
495 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
496 string of s2.
498 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
499 return 0;
501 /* ignore trailing slash on s1 */
502 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
503 return 0;
505 /* check for s1 is an "initial" string of s2 */
506 if ((*s2 == '/' || *s2 == '\\') && !*s1)
507 return 0;
509 return *s1-*s2;
512 /****************************************************************************
513 Ensure a remote path exists (make if necessary)
514 ***************************************************************************/
516 static BOOL ensurepath(char *fname)
518 /* *must* be called with buffer ready malloc'ed */
519 /* ensures path exists */
521 char *partpath, *ffname;
522 char *p=fname, *basehack;
524 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
526 partpath = string_create_s(strlen(fname));
527 ffname = string_create_s(strlen(fname));
529 if ((partpath == NULL) || (ffname == NULL)){
530 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
531 SAFE_FREE(partpath);
532 SAFE_FREE(ffname);
533 return(False);
536 *partpath = 0;
538 /* fname copied to ffname so can strtok */
540 safe_strcpy(ffname, fname, strlen(fname));
542 /* do a `basename' on ffname, so don't try and make file name directory */
543 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
544 return True;
545 else
546 *basehack='\0';
548 p=strtok(ffname, "\\");
550 while (p) {
551 safe_strcat(partpath, p, strlen(fname) + 1);
553 if (!cli_chkpath(cli, partpath)) {
554 if (!cli_mkdir(cli, partpath)) {
555 DEBUG(0, ("Error mkdirhiering\n"));
556 return False;
557 } else {
558 DEBUG(3, ("mkdirhiering %s\n", partpath));
562 safe_strcat(partpath, "\\", strlen(fname) + 1);
563 p = strtok(NULL,"/\\");
566 return True;
569 static int padit(char *buf, SMB_BIG_UINT bufsize, SMB_BIG_UINT padsize)
571 int berr= 0;
572 int bytestowrite;
574 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
575 memset(buf, 0, (size_t)bufsize);
576 while( !berr && padsize > 0 ) {
577 bytestowrite= (int)MIN(bufsize, padsize);
578 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
579 padsize -= bytestowrite;
582 return berr;
585 static void do_setrattr(char *name, uint16 attr, int set)
587 uint16 oldattr;
589 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
591 if (set == ATTRSET) {
592 attr |= oldattr;
593 } else {
594 attr = oldattr & ~attr;
597 if (!cli_setatr(cli, name, attr, 0)) {
598 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
602 /****************************************************************************
603 append one remote file to the tar file
604 ***************************************************************************/
606 static void do_atar(char *rname,char *lname,file_info *finfo1)
608 int fnum;
609 SMB_BIG_UINT nread=0;
610 char ftype;
611 file_info2 finfo;
612 BOOL close_done = False;
613 BOOL shallitime=True;
614 char data[65520];
615 int read_size = 65520;
616 int datalen=0;
618 struct timeval tp_start;
620 GetTimeOfDay(&tp_start);
622 ftype = '0'; /* An ordinary file ... */
624 if (finfo1) {
625 finfo.size = finfo1 -> size;
626 finfo.mode = finfo1 -> mode;
627 finfo.uid = finfo1 -> uid;
628 finfo.gid = finfo1 -> gid;
629 finfo.mtime_ts = finfo1 -> mtime_ts;
630 finfo.atime_ts = finfo1 -> atime_ts;
631 finfo.ctime_ts = finfo1 -> ctime_ts;
632 finfo.name = finfo1 -> name;
633 } else {
634 finfo.size = def_finfo.size;
635 finfo.mode = def_finfo.mode;
636 finfo.uid = def_finfo.uid;
637 finfo.gid = def_finfo.gid;
638 finfo.mtime_ts = def_finfo.mtime_ts;
639 finfo.atime_ts = def_finfo.atime_ts;
640 finfo.ctime_ts = def_finfo.ctime_ts;
641 finfo.name = def_finfo.name;
644 if (dry_run) {
645 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
646 (double)finfo.size));
647 shallitime=0;
648 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
649 ntarf++;
650 return;
653 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
655 clean_name(rname);
657 if (fnum == -1) {
658 DEBUG(0,("%s opening remote file %s (%s)\n",
659 cli_errstr(cli),rname, cur_dir));
660 return;
663 finfo.name = string_create_s(strlen(rname));
664 if (finfo.name == NULL) {
665 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
666 return;
669 safe_strcpy(finfo.name,rname, strlen(rname));
670 if (!finfo1) {
671 time_t atime, mtime;
672 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &atime, &mtime)) {
673 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
674 return;
676 finfo.atime_ts = convert_time_t_to_timespec(atime);
677 finfo.mtime_ts = convert_time_t_to_timespec(mtime);
678 finfo.ctime_ts = finfo.mtime_ts;
681 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
683 if (tar_inc && !(finfo.mode & aARCH)) {
684 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
685 shallitime=0;
686 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
687 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
688 shallitime=0;
689 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
690 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
691 shallitime=0;
692 } else {
693 BOOL wrote_tar_header = False;
695 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
696 finfo.name, (double)finfo.size, lname));
698 while (nread < finfo.size && !close_done) {
700 DEBUG(3,("nread=%.0f\n",(double)nread));
702 datalen = cli_read(cli, fnum, data, nread, read_size);
704 if (datalen == -1) {
705 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
706 break;
709 nread += datalen;
711 /* Only if the first read succeeds, write out the tar header. */
712 if (!wrote_tar_header) {
713 /* write a tar header, don't bother with mode - just set to 100644 */
714 writetarheader(tarhandle, rname, finfo.size,
715 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
716 wrote_tar_header = True;
719 /* if file size has increased since we made file size query, truncate
720 read so tar header for this file will be correct.
723 if (nread > finfo.size) {
724 datalen -= nread - finfo.size;
725 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
726 finfo.name, (double)finfo.size));
729 /* add received bits of file to buffer - dotarbuf will
730 * write out in 512 byte intervals */
732 if (dotarbuf(tarhandle,data,datalen) != datalen) {
733 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
734 break;
737 if (datalen == 0) {
738 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
739 break;
742 datalen=0;
745 if (wrote_tar_header) {
746 /* pad tar file with zero's if we couldn't get entire file */
747 if (nread < finfo.size) {
748 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
749 (double)finfo.size, (int)nread));
750 if (padit(data, (SMB_BIG_UINT)sizeof(data), finfo.size - nread))
751 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
754 /* round tar file to nearest block */
755 if (finfo.size % TBLOCK)
756 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
758 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
759 ntarf++;
760 } else {
761 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
762 shallitime=0;
766 cli_close(cli, fnum);
768 if (shallitime) {
769 struct timeval tp_end;
770 int this_time;
772 /* if shallitime is true then we didn't skip */
773 if (tar_reset && !dry_run)
774 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
776 GetTimeOfDay(&tp_end);
777 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
778 get_total_time_ms += this_time;
779 get_total_size += finfo.size;
781 if (tar_noisy) {
782 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
783 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
784 finfo.name));
787 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
788 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
789 finfo.size / MAX(0.001, (1.024*this_time)),
790 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
794 /****************************************************************************
795 Append single file to tar file (or not)
796 ***************************************************************************/
798 static void do_tar(file_info *finfo)
800 pstring rname;
802 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
803 return;
805 /* Is it on the exclude list ? */
806 if (!tar_excl && clipn) {
807 pstring exclaim;
809 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
811 pstrcpy(exclaim, cur_dir);
812 *(exclaim+strlen(exclaim)-1)='\0';
814 pstrcat(exclaim, "\\");
815 pstrcat(exclaim, finfo->name);
817 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
819 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
820 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
821 DEBUG(3,("Skipping file %s\n", exclaim));
822 return;
826 if (finfo->mode & aDIR) {
827 pstring saved_curdir;
828 pstring mtar_mask;
830 pstrcpy(saved_curdir, cur_dir);
832 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
833 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
834 (int)sizeof(cur_dir), (int)strlen(cur_dir),
835 (int)strlen(finfo->name), finfo->name, cur_dir));
837 pstrcat(cur_dir,finfo->name);
838 pstrcat(cur_dir,"\\");
840 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
842 /* write a tar directory, don't bother with mode - just set it to
843 * 40755 */
844 writetarheader(tarhandle, cur_dir, 0, finfo->mtime_ts.tv_sec, "040755 \0", '5');
845 if (tar_noisy) {
846 DEBUG(0,(" directory %s\n", cur_dir));
848 ntarf++; /* Make sure we have a file on there */
849 pstrcpy(mtar_mask,cur_dir);
850 pstrcat(mtar_mask,"*");
851 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
852 do_list(mtar_mask, attribute, do_tar, False, True);
853 pstrcpy(cur_dir,saved_curdir);
854 } else {
855 pstrcpy(rname,cur_dir);
856 pstrcat(rname,finfo->name);
857 do_atar(rname,finfo->name,finfo);
861 /****************************************************************************
862 Convert from UNIX to DOS file names
863 ***************************************************************************/
865 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
867 /* remove '.' from start of file name, convert from unix /'s to
868 * dos \'s in path. Kill any absolute path names. But only if first!
871 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
873 if (first) {
874 if (*fp == '.') {
875 fp++;
876 l--;
878 if (*fp == '\\' || *fp == '/') {
879 fp++;
880 l--;
884 safe_strcpy(tptr, fp, l);
885 string_replace(tptr, '/', '\\');
888 /****************************************************************************
889 Move to the next block in the buffer, which may mean read in another set of
890 blocks. FIXME, we should allow more than one block to be skipped.
891 ****************************************************************************/
893 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
895 int bufread, total = 0;
897 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
898 *bufferp += TBLOCK;
899 total = TBLOCK;
901 if (*bufferp >= (ltarbuf + bufsiz)) {
903 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
906 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
907 * Fixes bug where read can return short if coming from
908 * a pipe.
911 bufread = read(tarhandle, ltarbuf, bufsiz);
912 total = bufread;
914 while (total < bufsiz) {
915 if (bufread < 0) { /* An error, return false */
916 return (total > 0 ? -2 : bufread);
918 if (bufread == 0) {
919 if (total <= 0) {
920 return -2;
922 break;
924 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
925 total += bufread;
928 DEBUG(5, ("Total bytes read ... %i\n", total));
930 *bufferp = ltarbuf;
933 return(total);
936 /* Skip a file, even if it includes a long file name? */
937 static int skip_file(int skipsize)
939 int dsize = skipsize;
941 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
943 /* FIXME, we should skip more than one block at a time */
945 while (dsize > 0) {
946 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
947 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
948 return(False);
950 dsize -= TBLOCK;
953 return(True);
956 /*************************************************************
957 Get a file from the tar file and store it.
958 When this is called, tarbuf already contains the first
959 file block. This is a bit broken & needs fixing.
960 **************************************************************/
962 static int get_file(file_info2 finfo)
964 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
965 SMB_BIG_UINT rsize = 0;
967 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
969 if (ensurepath(finfo.name) &&
970 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
971 DEBUG(0, ("abandoning restore\n"));
972 return(False);
975 /* read the blocks from the tar file and write to the remote file */
977 rsize = finfo.size; /* This is how much to write */
979 while (rsize > 0) {
981 /* We can only write up to the end of the buffer */
982 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
983 dsize = MIN(dsize, rsize); /* Should be only what is left */
984 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
986 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
987 DEBUG(0, ("Error writing remote file\n"));
988 return 0;
991 rsize -= dsize;
992 pos += dsize;
994 /* Now figure out how much to move in the buffer */
996 /* FIXME, we should skip more than one block at a time */
998 /* First, skip any initial part of the part written that is left over */
999 /* from the end of the first TBLOCK */
1001 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1002 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1003 bpos = 0;
1005 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1006 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1007 return False;
1012 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1013 * If the file being extracted is an exact multiple of
1014 * TBLOCK bytes then we don't want to extract the next
1015 * block from the tarfile here, as it will be done in
1016 * the caller of get_file().
1019 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1020 ((rsize == 0) && (dsize > TBLOCK))) {
1022 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1023 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1024 return False;
1027 dsize -= TBLOCK;
1029 bpos = dsize;
1032 /* Now close the file ... */
1034 if (!cli_close(cli, fnum)) {
1035 DEBUG(0, ("Error closing remote file\n"));
1036 return(False);
1039 /* Now we update the creation date ... */
1040 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1042 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec)) {
1043 if (tar_real_noisy) {
1044 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1045 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1049 ntarf++;
1050 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1051 return(True);
1054 /* Create a directory. We just ensure that the path exists and return as there
1055 is no file associated with a directory
1057 static int get_dir(file_info2 finfo)
1059 DEBUG(0, ("restore directory %s\n", finfo.name));
1061 if (!ensurepath(finfo.name)) {
1062 DEBUG(0, ("Problems creating directory\n"));
1063 return(False);
1065 ntarf++;
1066 return(True);
1069 /* Get a file with a long file name ... first file has file name, next file
1070 has the data. We only want the long file name, as the loop in do_tarput
1071 will deal with the rest.
1073 static char *get_longfilename(file_info2 finfo)
1075 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1076 * header call. */
1077 int namesize = finfo.size + strlen(cur_dir) + 2;
1078 char *longname = (char *)SMB_MALLOC(namesize);
1079 int offset = 0, left = finfo.size;
1080 BOOL first = True;
1082 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1083 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1085 if (longname == NULL) {
1086 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1087 return(NULL);
1090 /* First, add cur_dir to the long file name */
1092 if (strlen(cur_dir) > 0) {
1093 strncpy(longname, cur_dir, namesize);
1094 offset = strlen(cur_dir);
1097 /* Loop through the blocks picking up the name */
1099 while (left > 0) {
1100 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1101 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1102 SAFE_FREE(longname);
1103 return(NULL);
1106 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1107 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1109 offset += TBLOCK;
1110 left -= TBLOCK;
1113 return(longname);
1116 static void do_tarput(void)
1118 file_info2 finfo;
1119 struct timeval tp_start;
1120 char *longfilename = NULL, linkflag;
1121 int skip = False;
1123 ZERO_STRUCT(finfo);
1125 GetTimeOfDay(&tp_start);
1126 DEBUG(5, ("RJS do_tarput called ...\n"));
1128 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1130 /* Now read through those files ... */
1131 while (True) {
1132 /* Get us to the next block, or the first block first time around */
1133 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1134 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1135 SAFE_FREE(longfilename);
1136 return;
1139 DEBUG(5, ("Reading the next header ...\n"));
1141 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1142 case -2: /* Hmm, not good, but not fatal */
1143 DEBUG(0, ("Skipping %s...\n", finfo.name));
1144 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1145 DEBUG(0, ("Short file, bailing out...\n"));
1146 return;
1148 break;
1150 case -1:
1151 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1152 return;
1154 case 0: /* chksum is zero - looks like an EOF */
1155 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1156 return; /* Hmmm, bad here ... */
1158 default:
1159 /* No action */
1160 break;
1163 /* Now, do we have a long file name? */
1164 if (longfilename != NULL) {
1165 SAFE_FREE(finfo.name); /* Free the space already allocated */
1166 finfo.name = longfilename;
1167 longfilename = NULL;
1170 /* Well, now we have a header, process the file ... */
1171 /* Should we skip the file? We have the long name as well here */
1172 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1173 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1175 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1176 if (skip) {
1177 skip_file(finfo.size);
1178 continue;
1181 /* We only get this far if we should process the file */
1182 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1183 switch (linkflag) {
1184 case '0': /* Should use symbolic names--FIXME */
1186 * Skip to the next block first, so we can get the file, FIXME, should
1187 * be in get_file ...
1188 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1189 * Fixes bug where file size in tarfile is zero.
1191 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1192 DEBUG(0, ("Short file, bailing out...\n"));
1193 return;
1195 if (!get_file(finfo)) {
1196 DEBUG(0, ("Abandoning restore\n"));
1197 return;
1199 break;
1200 case '5':
1201 if (!get_dir(finfo)) {
1202 DEBUG(0, ("Abandoning restore \n"));
1203 return;
1205 break;
1206 case 'L':
1207 SAFE_FREE(longfilename);
1208 longfilename = get_longfilename(finfo);
1209 if (!longfilename) {
1210 DEBUG(0, ("abandoning restore\n"));
1211 return;
1213 DEBUG(5, ("Long file name: %s\n", longfilename));
1214 break;
1216 default:
1217 skip_file(finfo.size); /* Don't handle these yet */
1218 break;
1224 * samba interactive commands
1227 /****************************************************************************
1228 Blocksize command
1229 ***************************************************************************/
1231 int cmd_block(void)
1233 fstring buf;
1234 int block;
1236 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1237 DEBUG(0, ("blocksize <n>\n"));
1238 return 1;
1241 block=atoi(buf);
1242 if (block < 0 || block > 65535) {
1243 DEBUG(0, ("blocksize out of range"));
1244 return 1;
1247 blocksize=block;
1248 DEBUG(2,("blocksize is now %d\n", blocksize));
1250 return 0;
1253 /****************************************************************************
1254 command to set incremental / reset mode
1255 ***************************************************************************/
1257 int cmd_tarmode(void)
1259 fstring buf;
1261 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1262 if (strequal(buf, "full"))
1263 tar_inc=False;
1264 else if (strequal(buf, "inc"))
1265 tar_inc=True;
1266 else if (strequal(buf, "reset"))
1267 tar_reset=True;
1268 else if (strequal(buf, "noreset"))
1269 tar_reset=False;
1270 else if (strequal(buf, "system"))
1271 tar_system=True;
1272 else if (strequal(buf, "nosystem"))
1273 tar_system=False;
1274 else if (strequal(buf, "hidden"))
1275 tar_hidden=True;
1276 else if (strequal(buf, "nohidden"))
1277 tar_hidden=False;
1278 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1279 tar_noisy=True;
1280 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1281 tar_noisy=False;
1282 else
1283 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1286 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1287 tar_inc ? "incremental" : "full",
1288 tar_system ? "system" : "nosystem",
1289 tar_hidden ? "hidden" : "nohidden",
1290 tar_reset ? "reset" : "noreset",
1291 tar_noisy ? "verbose" : "quiet"));
1292 return 0;
1295 /****************************************************************************
1296 Feeble attrib command
1297 ***************************************************************************/
1299 int cmd_setmode(void)
1301 char *q;
1302 fstring buf;
1303 pstring fname;
1304 uint16 attra[2];
1305 int direct=1;
1307 attra[0] = attra[1] = 0;
1309 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1310 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1311 return 1;
1314 pstrcpy(fname, cur_dir);
1315 pstrcat(fname, buf);
1317 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1318 q=buf;
1320 while(*q) {
1321 switch (*q++) {
1322 case '+':
1323 direct=1;
1324 break;
1325 case '-':
1326 direct=0;
1327 break;
1328 case 'r':
1329 attra[direct]|=aRONLY;
1330 break;
1331 case 'h':
1332 attra[direct]|=aHIDDEN;
1333 break;
1334 case 's':
1335 attra[direct]|=aSYSTEM;
1336 break;
1337 case 'a':
1338 attra[direct]|=aARCH;
1339 break;
1340 default:
1341 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1342 return 1;
1347 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1348 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1349 return 1;
1352 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1353 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1354 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1355 return 0;
1358 /****************************************************************************
1359 Principal command for creating / extracting
1360 ***************************************************************************/
1362 int cmd_tar(void)
1364 fstring buf;
1365 char **argl = NULL;
1366 int argcl = 0;
1367 int ret;
1369 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1370 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1371 return 1;
1374 argl=toktocliplist(&argcl, NULL);
1375 if (!tar_parseargs(argcl, argl, buf, 0))
1376 return 1;
1378 ret = process_tar();
1379 SAFE_FREE(argl);
1380 return ret;
1383 /****************************************************************************
1384 Command line (option) version
1385 ***************************************************************************/
1387 int process_tar(void)
1389 int rc = 0;
1390 initarbuf();
1391 switch(tar_type) {
1392 case 'x':
1394 #if 0
1395 do_tarput2();
1396 #else
1397 do_tarput();
1398 #endif
1399 SAFE_FREE(tarbuf);
1400 close(tarhandle);
1401 break;
1402 case 'r':
1403 case 'c':
1404 if (clipn && tar_excl) {
1405 int i;
1406 pstring tarmac;
1408 for (i=0; i<clipn; i++) {
1409 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1411 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1412 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1415 if (strrchr_m(cliplist[i], '\\')) {
1416 pstring saved_dir;
1418 pstrcpy(saved_dir, cur_dir);
1420 if (*cliplist[i]=='\\') {
1421 pstrcpy(tarmac, cliplist[i]);
1422 } else {
1423 pstrcpy(tarmac, cur_dir);
1424 pstrcat(tarmac, cliplist[i]);
1426 pstrcpy(cur_dir, tarmac);
1427 *(strrchr_m(cur_dir, '\\')+1)='\0';
1429 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1430 do_list(tarmac,attribute,do_tar, False, True);
1431 pstrcpy(cur_dir,saved_dir);
1432 } else {
1433 pstrcpy(tarmac, cur_dir);
1434 pstrcat(tarmac, cliplist[i]);
1435 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1436 do_list(tarmac,attribute,do_tar, False, True);
1439 } else {
1440 pstring mask;
1441 pstrcpy(mask,cur_dir);
1442 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1443 pstrcat(mask,"\\*");
1444 do_list(mask,attribute,do_tar,False, True);
1447 if (ntarf)
1448 dotareof(tarhandle);
1449 close(tarhandle);
1450 SAFE_FREE(tarbuf);
1452 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1453 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1454 break;
1457 if (must_free_cliplist) {
1458 int i;
1459 for (i = 0; i < clipn; ++i) {
1460 SAFE_FREE(cliplist[i]);
1462 SAFE_FREE(cliplist);
1463 cliplist = NULL;
1464 clipn = 0;
1465 must_free_cliplist = False;
1467 return rc;
1470 /****************************************************************************
1471 Find a token (filename) in a clip list
1472 ***************************************************************************/
1474 static int clipfind(char **aret, int ret, char *tok)
1476 if (aret==NULL)
1477 return 0;
1479 /* ignore leading slashes or dots in token */
1480 while(strchr_m("/\\.", *tok))
1481 tok++;
1483 while(ret--) {
1484 char *pkey=*aret++;
1486 /* ignore leading slashes or dots in list */
1487 while(strchr_m("/\\.", *pkey))
1488 pkey++;
1490 if (!strslashcmp(pkey, tok))
1491 return 1;
1493 return 0;
1496 /****************************************************************************
1497 Read list of files to include from the file and initialize cliplist
1498 accordingly.
1499 ***************************************************************************/
1501 static int read_inclusion_file(char *filename)
1503 XFILE *inclusion = NULL;
1504 char buf[PATH_MAX + 1];
1505 char *inclusion_buffer = NULL;
1506 int inclusion_buffer_size = 0;
1507 int inclusion_buffer_sofar = 0;
1508 char *p;
1509 char *tmpstr;
1510 int i;
1511 int error = 0;
1513 clipn = 0;
1514 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1515 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1516 /* XXX It would be better to include a reason for failure, but without
1517 * autoconf, it's hard to use strerror, sys_errlist, etc.
1519 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1520 return 0;
1523 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1524 if (inclusion_buffer == NULL) {
1525 inclusion_buffer_size = 1024;
1526 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1527 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1528 error = 1;
1529 break;
1533 if (buf[strlen(buf)-1] == '\n') {
1534 buf[strlen(buf)-1] = '\0';
1537 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1538 inclusion_buffer_size *= 2;
1539 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1540 if (!inclusion_buffer) {
1541 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1542 inclusion_buffer_size));
1543 error = 1;
1544 break;
1548 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1549 inclusion_buffer_sofar += strlen(buf) + 1;
1550 clipn++;
1552 x_fclose(inclusion);
1554 if (! error) {
1555 /* Allocate an array of clipn + 1 char*'s for cliplist */
1556 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1557 if (cliplist == NULL) {
1558 DEBUG(0,("failure allocating memory for cliplist\n"));
1559 error = 1;
1560 } else {
1561 cliplist[clipn] = NULL;
1562 p = inclusion_buffer;
1563 for (i = 0; (! error) && (i < clipn); i++) {
1564 /* set current item to NULL so array will be null-terminated even if
1565 * malloc fails below. */
1566 cliplist[i] = NULL;
1567 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1568 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1569 error = 1;
1570 } else {
1571 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1572 cliplist[i] = tmpstr;
1573 if ((p = strchr_m(p, '\000')) == NULL) {
1574 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1575 abort();
1578 ++p;
1580 must_free_cliplist = True;
1584 SAFE_FREE(inclusion_buffer);
1585 if (error) {
1586 if (cliplist) {
1587 char **pp;
1588 /* We know cliplist is always null-terminated */
1589 for (pp = cliplist; *pp; ++pp) {
1590 SAFE_FREE(*pp);
1592 SAFE_FREE(cliplist);
1593 cliplist = NULL;
1594 must_free_cliplist = False;
1596 return 0;
1599 /* cliplist and its elements are freed at the end of process_tar. */
1600 return 1;
1603 /****************************************************************************
1604 Parse tar arguments. Sets tar_type, tar_excl, etc.
1605 ***************************************************************************/
1607 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1609 int newOptind = Optind;
1610 char tar_clipfl='\0';
1612 /* Reset back to defaults - could be from interactive version
1613 * reset mode and archive mode left as they are though
1615 tar_type='\0';
1616 tar_excl=True;
1617 dry_run=False;
1619 while (*Optarg) {
1620 switch(*Optarg++) {
1621 case 'c':
1622 tar_type='c';
1623 break;
1624 case 'x':
1625 if (tar_type=='c') {
1626 printf("Tar must be followed by only one of c or x.\n");
1627 return 0;
1629 tar_type='x';
1630 break;
1631 case 'b':
1632 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1633 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1634 return 0;
1635 } else {
1636 Optind++;
1637 newOptind++;
1639 break;
1640 case 'g':
1641 tar_inc=True;
1642 break;
1643 case 'N':
1644 if (Optind>=argc) {
1645 DEBUG(0,("Option N must be followed by valid file name\n"));
1646 return 0;
1647 } else {
1648 SMB_STRUCT_STAT stbuf;
1650 if (sys_stat(argv[Optind], &stbuf) == 0) {
1651 newer_than = stbuf.st_mtime;
1652 DEBUG(1,("Getting files newer than %s",
1653 time_to_asc(newer_than)));
1654 newOptind++;
1655 Optind++;
1656 } else {
1657 DEBUG(0,("Error setting newer-than time\n"));
1658 return 0;
1661 break;
1662 case 'a':
1663 tar_reset=True;
1664 break;
1665 case 'q':
1666 tar_noisy=False;
1667 break;
1668 case 'I':
1669 if (tar_clipfl) {
1670 DEBUG(0,("Only one of I,X,F must be specified\n"));
1671 return 0;
1673 tar_clipfl='I';
1674 break;
1675 case 'X':
1676 if (tar_clipfl) {
1677 DEBUG(0,("Only one of I,X,F must be specified\n"));
1678 return 0;
1680 tar_clipfl='X';
1681 break;
1682 case 'F':
1683 if (tar_clipfl) {
1684 DEBUG(0,("Only one of I,X,F must be specified\n"));
1685 return 0;
1687 tar_clipfl='F';
1688 break;
1689 case 'r':
1690 DEBUG(0, ("tar_re_search set\n"));
1691 tar_re_search = True;
1692 break;
1693 case 'n':
1694 if (tar_type == 'c') {
1695 DEBUG(0, ("dry_run set\n"));
1696 dry_run = True;
1697 } else {
1698 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1699 return 0;
1701 break;
1702 default:
1703 DEBUG(0,("Unknown tar option\n"));
1704 return 0;
1708 if (!tar_type) {
1709 printf("Option T must be followed by one of c or x.\n");
1710 return 0;
1713 /* tar_excl is true if cliplist lists files to be included.
1714 * Both 'I' and 'F' mean include. */
1715 tar_excl=tar_clipfl!='X';
1717 if (tar_clipfl=='F') {
1718 if (argc-Optind-1 != 1) {
1719 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1720 return 0;
1722 newOptind++;
1723 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1724 if (! read_inclusion_file(argv[Optind+1])) {
1725 return 0;
1727 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1728 char *tmpstr;
1729 char **tmplist;
1730 int clipcount;
1732 cliplist=argv+Optind+1;
1733 clipn=argc-Optind-1;
1734 clipcount = clipn;
1736 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1737 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1738 return 0;
1741 for (clipcount = 0; clipcount < clipn; clipcount++) {
1743 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1745 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1746 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1747 SAFE_FREE(tmplist);
1748 return 0;
1751 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1752 tmplist[clipcount] = tmpstr;
1753 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1755 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1758 cliplist = tmplist;
1759 must_free_cliplist = True;
1761 newOptind += clipn;
1764 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1765 /* Doing regular expression seaches not from an inclusion file. */
1766 clipn=argc-Optind-1;
1767 cliplist=argv+Optind+1;
1768 newOptind += clipn;
1771 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1772 /* Sets tar handle to either 0 or 1, as appropriate */
1773 tarhandle=(tar_type=='c');
1775 * Make sure that dbf points to stderr if we are using stdout for
1776 * tar output
1778 if (tarhandle == 1) {
1779 dbf = x_stderr;
1781 if (!argv[Optind]) {
1782 DEBUG(0,("Must specify tar filename\n"));
1783 return 0;
1785 if (!strcmp(argv[Optind], "-")) {
1786 newOptind++;
1789 } else {
1790 if (tar_type=='c' && dry_run) {
1791 tarhandle=-1;
1792 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1793 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1794 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1795 return(0);
1797 newOptind++;
1800 return newOptind;