Apply a little const
[Samba/gebeck_regimport.git] / source / client / clitar.c
blob5e20c3e11bbfb4b91f6b1e148f2c254ed4739b04
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_BIG_UINT 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 struct cli_state *cli;
68 /* These defines are for the do_setrattr routine, to indicate
69 * setting and reseting of file attributes in the function call */
70 #define ATTRSET 1
71 #define ATTRRESET 0
73 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
75 #ifndef CLIENT_TIMEOUT
76 #define CLIENT_TIMEOUT (30*1000)
77 #endif
79 static char *tarbuf, *buffer_p;
80 static int tp, ntarf, tbufsiz;
81 static double ttarf;
82 /* Incremental mode */
83 static BOOL tar_inc=False;
84 /* Reset archive bit */
85 static BOOL tar_reset=False;
86 /* Include / exclude mode (true=include, false=exclude) */
87 static BOOL tar_excl=True;
88 /* use regular expressions for search on file names */
89 static BOOL tar_re_search=False;
90 #ifdef HAVE_REGEX_H
91 regex_t *preg;
92 #endif
93 /* Do not dump anything, just calculate sizes */
94 static BOOL dry_run=False;
95 /* Dump files with System attribute */
96 static BOOL tar_system=True;
97 /* Dump files with Hidden attribute */
98 static BOOL tar_hidden=True;
99 /* Be noisy - make a catalogue */
100 static BOOL tar_noisy=True;
101 static BOOL tar_real_noisy=False; /* Don't want to be really noisy by default */
103 char tar_type='\0';
104 static char **cliplist=NULL;
105 static int clipn=0;
106 static BOOL must_free_cliplist = False;
108 extern file_info def_finfo;
109 extern BOOL lowercase;
110 extern uint16 cnum;
111 extern BOOL readbraw_supported;
112 extern int max_xmit;
113 extern pstring cur_dir;
114 extern int get_total_time_ms;
115 extern int get_total_size;
117 static int blocksize=20;
118 static int tarhandle;
120 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
121 const char *amode, unsigned char ftype);
122 static void do_atar(char *rname,char *lname,file_info *finfo1);
123 static void do_tar(file_info *finfo);
124 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
125 static void fixtarname(char *tptr, const char *fp, int l);
126 static int dotarbuf(int f, char *b, int n);
127 static void dozerobuf(int f, int n);
128 static void dotareof(int f);
129 static void initarbuf(void);
131 /* restore functions */
132 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
133 static long unoct(char *p, int ndgs);
134 static void do_tarput(void);
135 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
138 * tar specific utitlities
141 /*******************************************************************
142 Create a string of size size+1 (for the null)
143 *******************************************************************/
145 static char *string_create_s(int size)
147 char *tmp;
149 tmp = (char *)malloc(size+1);
151 if (tmp == NULL) {
152 DEBUG(0, ("Out of memory in string_create_s\n"));
155 return(tmp);
158 /****************************************************************************
159 Write a tar header to buffer
160 ****************************************************************************/
162 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
163 const char *amode, unsigned char ftype)
165 union hblock hb;
166 int i, chk, l;
167 char *jp;
169 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
171 memset(hb.dummy, 0, sizeof(hb.dummy));
173 l=strlen(aname);
174 if (l >= NAMSIZ - 1) {
175 /* write a GNU tar style long header */
176 char *b;
177 b = (char *)malloc(l+TBLOCK+100);
178 if (!b) {
179 DEBUG(0,("out of memory\n"));
180 exit(1);
182 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
183 memset(b, 0, l+TBLOCK+100);
184 fixtarname(b, aname, l);
185 i = strlen(b)+1;
186 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
187 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
188 SAFE_FREE(b);
191 /* use l + 1 to do the null too */
192 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
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=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, int l)
424 /* add a '.' to start of file name, convert from ugly dos \'s in path
425 * to lovely unix /'s :-} */
426 *tptr++='.';
428 safe_strcpy(tptr, fp, l);
429 string_replace(tptr, '\\', '/');
432 /****************************************************************************
433 Convert from decimal to octal string
434 ****************************************************************************/
436 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
438 /* Converts long to octal string, pads with leading zeros */
440 /* skip final null, but do final space */
441 --ndgs;
442 p[--ndgs] = ' ';
444 /* Loop does at least one digit */
445 do {
446 p[--ndgs] = '0' + (char) (value & 7);
447 value >>= 3;
448 } while (ndgs > 0 && value != 0);
450 /* Do leading zeros */
451 while (ndgs > 0)
452 p[--ndgs] = '0';
455 /****************************************************************************
456 Convert from octal string to long
457 ***************************************************************************/
459 static long unoct(char *p, int ndgs)
461 long value=0;
462 /* Converts octal string to long, ignoring any non-digit */
464 while (--ndgs) {
465 if (isdigit((int)*p))
466 value = (value << 3) | (long) (*p - '0');
468 p++;
471 return value;
474 /****************************************************************************
475 Compare two strings in a slash insensitive way, allowing s1 to match s2
476 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
477 a file in any subdirectory of s1, declare a match.
478 ***************************************************************************/
480 static int strslashcmp(char *s1, char *s2)
482 char *s1_0=s1;
484 while(*s1 && *s2 && (*s1 == *s2 || tolower(*s1) == tolower(*s2) ||
485 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
486 s1++; s2++;
489 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
490 string of s2.
492 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
493 return 0;
495 /* ignore trailing slash on s1 */
496 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
497 return 0;
499 /* check for s1 is an "initial" string of s2 */
500 if ((*s2 == '/' || *s2 == '\\') && !*s1)
501 return 0;
503 return *s1-*s2;
506 /****************************************************************************
507 Ensure a remote path exists (make if necessary)
508 ***************************************************************************/
510 static BOOL ensurepath(char *fname)
512 /* *must* be called with buffer ready malloc'ed */
513 /* ensures path exists */
515 char *partpath, *ffname;
516 char *p=fname, *basehack;
518 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
520 partpath = string_create_s(strlen(fname));
521 ffname = string_create_s(strlen(fname));
523 if ((partpath == NULL) || (ffname == NULL)){
524 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
525 return(False);
528 *partpath = 0;
530 /* fname copied to ffname so can strtok */
532 safe_strcpy(ffname, fname, strlen(fname));
534 /* do a `basename' on ffname, so don't try and make file name directory */
535 if ((basehack=strrchr_m(ffname, '\\')) == NULL)
536 return True;
537 else
538 *basehack='\0';
540 p=strtok(ffname, "\\");
542 while (p) {
543 safe_strcat(partpath, p, strlen(fname) + 1);
545 if (!cli_chkpath(cli, partpath)) {
546 if (!cli_mkdir(cli, partpath)) {
547 DEBUG(0, ("Error mkdirhiering\n"));
548 return False;
549 } else {
550 DEBUG(3, ("mkdirhiering %s\n", partpath));
554 safe_strcat(partpath, "\\", strlen(fname) + 1);
555 p = strtok(NULL,"/\\");
558 return True;
561 static int padit(char *buf, int bufsize, int padsize)
563 int berr= 0;
564 int bytestowrite;
566 DEBUG(5, ("Padding with %d zeros\n", padsize));
567 memset(buf, 0, bufsize);
568 while( !berr && padsize > 0 ) {
569 bytestowrite= MIN(bufsize, padsize);
570 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
571 padsize -= bytestowrite;
574 return berr;
577 static void do_setrattr(char *name, uint16 attr, int set)
579 uint16 oldattr;
581 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
583 if (set == ATTRSET) {
584 attr |= oldattr;
585 } else {
586 attr = oldattr & ~attr;
589 if (!cli_setatr(cli, name, attr, 0)) {
590 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
594 /****************************************************************************
595 append one remote file to the tar file
596 ***************************************************************************/
598 static void do_atar(char *rname,char *lname,file_info *finfo1)
600 int fnum;
601 SMB_BIG_UINT nread=0;
602 char ftype;
603 file_info2 finfo;
604 BOOL close_done = False;
605 BOOL shallitime=True;
606 char data[65520];
607 int read_size = 65520;
608 int datalen=0;
610 struct timeval tp_start;
612 GetTimeOfDay(&tp_start);
614 ftype = '0'; /* An ordinary file ... */
616 if (finfo1) {
617 finfo.size = finfo1 -> size;
618 finfo.mode = finfo1 -> mode;
619 finfo.uid = finfo1 -> uid;
620 finfo.gid = finfo1 -> gid;
621 finfo.mtime = finfo1 -> mtime;
622 finfo.atime = finfo1 -> atime;
623 finfo.ctime = finfo1 -> ctime;
624 finfo.name = finfo1 -> name;
625 } else {
626 finfo.size = def_finfo.size;
627 finfo.mode = def_finfo.mode;
628 finfo.uid = def_finfo.uid;
629 finfo.gid = def_finfo.gid;
630 finfo.mtime = def_finfo.mtime;
631 finfo.atime = def_finfo.atime;
632 finfo.ctime = def_finfo.ctime;
633 finfo.name = def_finfo.name;
636 if (dry_run) {
637 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
638 (double)finfo.size));
639 shallitime=0;
640 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
641 ntarf++;
642 return;
645 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
647 dos_clean_name(rname);
649 if (fnum == -1) {
650 DEBUG(0,("%s opening remote file %s (%s)\n",
651 cli_errstr(cli),rname, cur_dir));
652 return;
655 finfo.name = string_create_s(strlen(rname));
656 if (finfo.name == NULL) {
657 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
658 return;
661 safe_strcpy(finfo.name,rname, strlen(rname));
662 if (!finfo1) {
663 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
664 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
665 return;
667 finfo.ctime = finfo.mtime;
670 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
672 if (tar_inc && !(finfo.mode & aARCH)) {
673 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
674 shallitime=0;
675 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
676 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
677 shallitime=0;
678 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
679 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
680 shallitime=0;
681 } else {
682 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
683 finfo.name, (double)finfo.size, lname));
685 /* write a tar header, don't bother with mode - just set to 100644 */
686 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
688 while (nread < finfo.size && !close_done) {
690 DEBUG(3,("nread=%.0f\n",(double)nread));
692 datalen = cli_read(cli, fnum, data, nread, read_size);
694 if (datalen == -1) {
695 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
696 break;
699 nread += datalen;
701 /* if file size has increased since we made file size query, truncate
702 read so tar header for this file will be correct.
705 if (nread > finfo.size) {
706 datalen -= nread - finfo.size;
707 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
708 finfo.name, (double)finfo.size));
711 /* add received bits of file to buffer - dotarbuf will
712 * write out in 512 byte intervals */
714 if (dotarbuf(tarhandle,data,datalen) != datalen) {
715 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
716 break;
719 if (datalen == 0) {
720 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
721 break;
724 datalen=0;
727 /* pad tar file with zero's if we couldn't get entire file */
728 if (nread < finfo.size) {
729 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
730 (double)finfo.size, (int)nread));
731 if (padit(data, sizeof(data), finfo.size - nread))
732 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
735 /* round tar file to nearest block */
736 if (finfo.size % TBLOCK)
737 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
739 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
740 ntarf++;
743 cli_close(cli, fnum);
745 if (shallitime) {
746 struct timeval tp_end;
747 int this_time;
749 /* if shallitime is true then we didn't skip */
750 if (tar_reset && !dry_run)
751 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
753 GetTimeOfDay(&tp_end);
754 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
755 get_total_time_ms += this_time;
756 get_total_size += finfo.size;
758 if (tar_noisy) {
759 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
760 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
761 finfo.name));
764 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
765 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
766 finfo.size / MAX(0.001, (1.024*this_time)),
767 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
771 /****************************************************************************
772 Append single file to tar file (or not)
773 ***************************************************************************/
775 static void do_tar(file_info *finfo)
777 pstring rname;
779 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
780 return;
782 /* Is it on the exclude list ? */
783 if (!tar_excl && clipn) {
784 pstring exclaim;
786 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
788 pstrcpy(exclaim, cur_dir);
789 *(exclaim+strlen(exclaim)-1)='\0';
791 pstrcat(exclaim, "\\");
792 pstrcat(exclaim, finfo->name);
794 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
796 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
797 #ifdef HAVE_REGEX_H
798 (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
799 #else
800 (tar_re_search && mask_match(exclaim, cliplist[0], True))) {
801 #endif
802 DEBUG(3,("Skipping file %s\n", exclaim));
803 return;
807 if (finfo->mode & aDIR) {
808 pstring saved_curdir;
809 pstring mtar_mask;
811 pstrcpy(saved_curdir, cur_dir);
813 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
814 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
815 (int)sizeof(cur_dir), (int)strlen(cur_dir),
816 (int)strlen(finfo->name), finfo->name, cur_dir));
818 pstrcat(cur_dir,finfo->name);
819 pstrcat(cur_dir,"\\");
821 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
823 /* write a tar directory, don't bother with mode - just set it to
824 * 40755 */
825 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
826 if (tar_noisy) {
827 DEBUG(0,(" directory %s\n", cur_dir));
829 ntarf++; /* Make sure we have a file on there */
830 pstrcpy(mtar_mask,cur_dir);
831 pstrcat(mtar_mask,"*");
832 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
833 do_list(mtar_mask, attribute, do_tar, False, True);
834 pstrcpy(cur_dir,saved_curdir);
835 } else {
836 pstrcpy(rname,cur_dir);
837 pstrcat(rname,finfo->name);
838 do_atar(rname,finfo->name,finfo);
842 /****************************************************************************
843 Convert from UNIX to DOS file names
844 ***************************************************************************/
846 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
848 /* remove '.' from start of file name, convert from unix /'s to
849 * dos \'s in path. Kill any absolute path names. But only if first!
852 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
854 if (first) {
855 if (*fp == '.') {
856 fp++;
857 l--;
859 if (*fp == '\\' || *fp == '/') {
860 fp++;
861 l--;
865 safe_strcpy(tptr, fp, l);
866 string_replace(tptr, '/', '\\');
869 /****************************************************************************
870 Move to the next block in the buffer, which may mean read in another set of
871 blocks. FIXME, we should allow more than one block to be skipped.
872 ****************************************************************************/
874 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
876 int bufread, total = 0;
878 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
879 *bufferp += TBLOCK;
880 total = TBLOCK;
882 if (*bufferp >= (ltarbuf + bufsiz)) {
884 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
887 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
888 * Fixes bug where read can return short if coming from
889 * a pipe.
892 bufread = read(tarhandle, ltarbuf, bufsiz);
893 total = bufread;
895 while (total < bufsiz) {
896 if (bufread < 0) { /* An error, return false */
897 return (total > 0 ? -2 : bufread);
899 if (bufread == 0) {
900 if (total <= 0) {
901 return -2;
903 break;
905 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
906 total += bufread;
909 DEBUG(5, ("Total bytes read ... %i\n", total));
911 *bufferp = ltarbuf;
914 return(total);
917 /* Skip a file, even if it includes a long file name? */
918 static int skip_file(int skipsize)
920 int dsize = skipsize;
922 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
924 /* FIXME, we should skip more than one block at a time */
926 while (dsize > 0) {
927 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
928 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
929 return(False);
931 dsize -= TBLOCK;
934 return(True);
937 /*************************************************************
938 Get a file from the tar file and store it.
939 When this is called, tarbuf already contains the first
940 file block. This is a bit broken & needs fixing.
941 **************************************************************/
943 static int get_file(file_info2 finfo)
945 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
946 SMB_BIG_UINT rsize = 0;
948 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
950 if (ensurepath(finfo.name) &&
951 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
952 DEBUG(0, ("abandoning restore\n"));
953 return(False);
956 /* read the blocks from the tar file and write to the remote file */
958 rsize = finfo.size; /* This is how much to write */
960 while (rsize > 0) {
962 /* We can only write up to the end of the buffer */
963 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
964 dsize = MIN(dsize, rsize); /* Should be only what is left */
965 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
967 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
968 DEBUG(0, ("Error writing remote file\n"));
969 return 0;
972 rsize -= dsize;
973 pos += dsize;
975 /* Now figure out how much to move in the buffer */
977 /* FIXME, we should skip more than one block at a time */
979 /* First, skip any initial part of the part written that is left over */
980 /* from the end of the first TBLOCK */
982 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
983 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
984 bpos = 0;
986 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
987 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
988 return False;
993 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
994 * If the file being extracted is an exact multiple of
995 * TBLOCK bytes then we don't want to extract the next
996 * block from the tarfile here, as it will be done in
997 * the caller of get_file().
1000 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1001 ((rsize == 0) && (dsize > TBLOCK))) {
1003 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1004 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1005 return False;
1008 dsize -= TBLOCK;
1010 bpos = dsize;
1013 /* Now close the file ... */
1015 if (!cli_close(cli, fnum)) {
1016 DEBUG(0, ("Error closing remote file\n"));
1017 return(False);
1020 /* Now we update the creation date ... */
1021 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1023 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1024 if (tar_real_noisy) {
1025 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1026 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1030 ntarf++;
1031 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1032 return(True);
1035 /* Create a directory. We just ensure that the path exists and return as there
1036 is no file associated with a directory
1038 static int get_dir(file_info2 finfo)
1040 DEBUG(0, ("restore directory %s\n", finfo.name));
1042 if (!ensurepath(finfo.name)) {
1043 DEBUG(0, ("Problems creating directory\n"));
1044 return(False);
1046 ntarf++;
1047 return(True);
1050 /* Get a file with a long file name ... first file has file name, next file
1051 has the data. We only want the long file name, as the loop in do_tarput
1052 will deal with the rest.
1054 static char * get_longfilename(file_info2 finfo)
1056 int namesize = strlen(finfo.name) + strlen(cur_dir) + 2;
1057 char *longname = malloc(namesize);
1058 int offset = 0, left = finfo.size;
1059 BOOL first = True;
1061 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1062 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1064 if (longname == NULL) {
1065 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1066 return(NULL);
1069 /* First, add cur_dir to the long file name */
1071 if (strlen(cur_dir) > 0) {
1072 strncpy(longname, cur_dir, namesize);
1073 offset = strlen(cur_dir);
1076 /* Loop through the blocks picking up the name */
1078 while (left > 0) {
1079 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1080 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1081 return(NULL);
1084 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1085 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1087 offset += TBLOCK;
1088 left -= TBLOCK;
1091 return(longname);
1094 static void do_tarput(void)
1096 file_info2 finfo;
1097 struct timeval tp_start;
1098 char *longfilename = NULL, linkflag;
1099 int skip = False;
1101 GetTimeOfDay(&tp_start);
1102 DEBUG(5, ("RJS do_tarput called ...\n"));
1104 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1106 /* Now read through those files ... */
1107 while (True) {
1108 /* Get us to the next block, or the first block first time around */
1109 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1110 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1111 return;
1114 DEBUG(5, ("Reading the next header ...\n"));
1116 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1117 case -2: /* Hmm, not good, but not fatal */
1118 DEBUG(0, ("Skipping %s...\n", finfo.name));
1119 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1120 DEBUG(0, ("Short file, bailing out...\n"));
1121 return;
1123 break;
1125 case -1:
1126 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1127 return;
1129 case 0: /* chksum is zero - looks like an EOF */
1130 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1131 return; /* Hmmm, bad here ... */
1133 default:
1134 /* No action */
1135 break;
1138 /* Now, do we have a long file name? */
1139 if (longfilename != NULL) {
1140 SAFE_FREE(finfo.name); /* Free the space already allocated */
1141 finfo.name = longfilename;
1142 longfilename = NULL;
1145 /* Well, now we have a header, process the file ... */
1146 /* Should we skip the file? We have the long name as well here */
1147 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1148 #ifdef HAVE_REGEX_H
1149 (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1150 #else
1151 (tar_re_search && mask_match(finfo.name, cliplist[0], True)));
1152 #endif
1154 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1155 if (skip) {
1156 skip_file(finfo.size);
1157 continue;
1160 /* We only get this far if we should process the file */
1161 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1162 switch (linkflag) {
1163 case '0': /* Should use symbolic names--FIXME */
1165 * Skip to the next block first, so we can get the file, FIXME, should
1166 * be in get_file ...
1167 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1168 * Fixes bug where file size in tarfile is zero.
1170 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1171 DEBUG(0, ("Short file, bailing out...\n"));
1172 return;
1174 if (!get_file(finfo)) {
1175 DEBUG(0, ("Abandoning restore\n"));
1176 return;
1178 break;
1179 case '5':
1180 if (!get_dir(finfo)) {
1181 DEBUG(0, ("Abandoning restore \n"));
1182 return;
1184 break;
1185 case 'L':
1186 longfilename = get_longfilename(finfo);
1187 if (!longfilename) {
1188 DEBUG(0, ("abandoning restore\n"));
1189 return;
1191 DEBUG(5, ("Long file name: %s\n", longfilename));
1192 break;
1194 default:
1195 skip_file(finfo.size); /* Don't handle these yet */
1196 break;
1202 * samba interactive commands
1205 /****************************************************************************
1206 Blocksize command
1207 ***************************************************************************/
1209 int cmd_block(void)
1211 fstring buf;
1212 int block;
1214 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1215 DEBUG(0, ("blocksize <n>\n"));
1216 return 1;
1219 block=atoi(buf);
1220 if (block < 0 || block > 65535) {
1221 DEBUG(0, ("blocksize out of range"));
1222 return 1;
1225 blocksize=block;
1226 DEBUG(2,("blocksize is now %d\n", blocksize));
1228 return 0;
1231 /****************************************************************************
1232 command to set incremental / reset mode
1233 ***************************************************************************/
1235 int cmd_tarmode(void)
1237 fstring buf;
1239 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1240 if (strequal(buf, "full"))
1241 tar_inc=False;
1242 else if (strequal(buf, "inc"))
1243 tar_inc=True;
1244 else if (strequal(buf, "reset"))
1245 tar_reset=True;
1246 else if (strequal(buf, "noreset"))
1247 tar_reset=False;
1248 else if (strequal(buf, "system"))
1249 tar_system=True;
1250 else if (strequal(buf, "nosystem"))
1251 tar_system=False;
1252 else if (strequal(buf, "hidden"))
1253 tar_hidden=True;
1254 else if (strequal(buf, "nohidden"))
1255 tar_hidden=False;
1256 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1257 tar_noisy=True;
1258 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1259 tar_noisy=False;
1260 else
1261 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1264 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1265 tar_inc ? "incremental" : "full",
1266 tar_system ? "system" : "nosystem",
1267 tar_hidden ? "hidden" : "nohidden",
1268 tar_reset ? "reset" : "noreset",
1269 tar_noisy ? "verbose" : "quiet"));
1270 return 0;
1273 /****************************************************************************
1274 Feeble attrib command
1275 ***************************************************************************/
1277 int cmd_setmode(void)
1279 char *q;
1280 fstring buf;
1281 pstring fname;
1282 uint16 attra[2];
1283 int direct=1;
1285 attra[0] = attra[1] = 0;
1287 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1288 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1289 return 1;
1292 pstrcpy(fname, cur_dir);
1293 pstrcat(fname, buf);
1295 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1296 q=buf;
1298 while(*q) {
1299 switch (*q++) {
1300 case '+':
1301 direct=1;
1302 break;
1303 case '-':
1304 direct=0;
1305 break;
1306 case 'r':
1307 attra[direct]|=aRONLY;
1308 break;
1309 case 'h':
1310 attra[direct]|=aHIDDEN;
1311 break;
1312 case 's':
1313 attra[direct]|=aSYSTEM;
1314 break;
1315 case 'a':
1316 attra[direct]|=aARCH;
1317 break;
1318 default:
1319 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1320 return 1;
1325 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1326 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1327 return 1;
1330 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1331 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1332 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1333 return 0;
1336 /****************************************************************************
1337 Principal command for creating / extracting
1338 ***************************************************************************/
1340 int cmd_tar(void)
1342 fstring buf;
1343 char **argl;
1344 int argcl;
1346 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1347 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1348 return 1;
1351 argl=toktocliplist(&argcl, NULL);
1352 if (!tar_parseargs(argcl, argl, buf, 0))
1353 return 1;
1355 process_tar();
1356 SAFE_FREE(argl);
1357 return 0;
1360 /****************************************************************************
1361 Command line (option) version
1362 ***************************************************************************/
1364 int process_tar(void)
1366 initarbuf();
1367 switch(tar_type) {
1368 case 'x':
1370 #if 0
1371 do_tarput2();
1372 #else
1373 do_tarput();
1374 #endif
1375 SAFE_FREE(tarbuf);
1376 close(tarhandle);
1377 break;
1378 case 'r':
1379 case 'c':
1380 if (clipn && tar_excl) {
1381 int i;
1382 pstring tarmac;
1384 for (i=0; i<clipn; i++) {
1385 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1387 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1388 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1391 if (strrchr_m(cliplist[i], '\\')) {
1392 pstring saved_dir;
1394 pstrcpy(saved_dir, cur_dir);
1396 if (*cliplist[i]=='\\') {
1397 pstrcpy(tarmac, cliplist[i]);
1398 } else {
1399 pstrcpy(tarmac, cur_dir);
1400 pstrcat(tarmac, cliplist[i]);
1402 pstrcpy(cur_dir, tarmac);
1403 *(strrchr_m(cur_dir, '\\')+1)='\0';
1405 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1406 do_list(tarmac,attribute,do_tar, False, True);
1407 pstrcpy(cur_dir,saved_dir);
1408 } else {
1409 pstrcpy(tarmac, cur_dir);
1410 pstrcat(tarmac, cliplist[i]);
1411 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1412 do_list(tarmac,attribute,do_tar, False, True);
1415 } else {
1416 pstring mask;
1417 pstrcpy(mask,cur_dir);
1418 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1419 pstrcat(mask,"\\*");
1420 do_list(mask,attribute,do_tar,False, True);
1423 if (ntarf)
1424 dotareof(tarhandle);
1425 close(tarhandle);
1426 SAFE_FREE(tarbuf);
1428 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1429 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1430 break;
1433 if (must_free_cliplist) {
1434 int i;
1435 for (i = 0; i < clipn; ++i) {
1436 SAFE_FREE(cliplist[i]);
1438 SAFE_FREE(cliplist);
1439 cliplist = NULL;
1440 clipn = 0;
1441 must_free_cliplist = False;
1443 return(0);
1446 /****************************************************************************
1447 Find a token (filename) in a clip list
1448 ***************************************************************************/
1450 static int clipfind(char **aret, int ret, char *tok)
1452 if (aret==NULL)
1453 return 0;
1455 /* ignore leading slashes or dots in token */
1456 while(strchr_m("/\\.", *tok))
1457 tok++;
1459 while(ret--) {
1460 char *pkey=*aret++;
1462 /* ignore leading slashes or dots in list */
1463 while(strchr_m("/\\.", *pkey))
1464 pkey++;
1466 if (!strslashcmp(pkey, tok))
1467 return 1;
1469 return 0;
1472 /****************************************************************************
1473 Read list of files to include from the file and initialize cliplist
1474 accordingly.
1475 ***************************************************************************/
1477 static int read_inclusion_file(char *filename)
1479 XFILE *inclusion = NULL;
1480 char buf[PATH_MAX + 1];
1481 char *inclusion_buffer = NULL;
1482 int inclusion_buffer_size = 0;
1483 int inclusion_buffer_sofar = 0;
1484 char *p;
1485 char *tmpstr;
1486 int i;
1487 int error = 0;
1489 clipn = 0;
1490 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1491 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1492 /* XXX It would be better to include a reason for failure, but without
1493 * autoconf, it's hard to use strerror, sys_errlist, etc.
1495 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1496 return 0;
1499 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1500 if (inclusion_buffer == NULL) {
1501 inclusion_buffer_size = 1024;
1502 if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1503 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1504 error = 1;
1505 break;
1509 if (buf[strlen(buf)-1] == '\n') {
1510 buf[strlen(buf)-1] = '\0';
1513 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1514 char *ib;
1515 inclusion_buffer_size *= 2;
1516 ib = Realloc(inclusion_buffer,inclusion_buffer_size);
1517 if (! ib) {
1518 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1519 inclusion_buffer_size));
1520 error = 1;
1521 break;
1522 } else {
1523 inclusion_buffer = ib;
1527 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1528 inclusion_buffer_sofar += strlen(buf) + 1;
1529 clipn++;
1531 x_fclose(inclusion);
1533 if (! error) {
1534 /* Allocate an array of clipn + 1 char*'s for cliplist */
1535 cliplist = malloc((clipn + 1) * sizeof(char *));
1536 if (cliplist == NULL) {
1537 DEBUG(0,("failure allocating memory for cliplist\n"));
1538 error = 1;
1539 } else {
1540 cliplist[clipn] = NULL;
1541 p = inclusion_buffer;
1542 for (i = 0; (! error) && (i < clipn); i++) {
1543 /* set current item to NULL so array will be null-terminated even if
1544 * malloc fails below. */
1545 cliplist[i] = NULL;
1546 if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1547 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1548 error = 1;
1549 } else {
1550 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1551 cliplist[i] = tmpstr;
1552 if ((p = strchr_m(p, '\000')) == NULL) {
1553 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1554 abort();
1557 ++p;
1559 must_free_cliplist = True;
1563 SAFE_FREE(inclusion_buffer);
1564 if (error) {
1565 if (cliplist) {
1566 char **pp;
1567 /* We know cliplist is always null-terminated */
1568 for (pp = cliplist; *pp; ++pp) {
1569 SAFE_FREE(*pp);
1571 SAFE_FREE(cliplist);
1572 cliplist = NULL;
1573 must_free_cliplist = False;
1575 return 0;
1578 /* cliplist and its elements are freed at the end of process_tar. */
1579 return 1;
1582 /****************************************************************************
1583 Parse tar arguments. Sets tar_type, tar_excl, etc.
1584 ***************************************************************************/
1586 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1588 int newOptind = Optind;
1589 char tar_clipfl='\0';
1591 /* Reset back to defaults - could be from interactive version
1592 * reset mode and archive mode left as they are though
1594 tar_type='\0';
1595 tar_excl=True;
1596 dry_run=False;
1598 while (*Optarg) {
1599 switch(*Optarg++) {
1600 case 'c':
1601 tar_type='c';
1602 break;
1603 case 'x':
1604 if (tar_type=='c') {
1605 printf("Tar must be followed by only one of c or x.\n");
1606 return 0;
1608 tar_type='x';
1609 break;
1610 case 'b':
1611 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1612 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1613 return 0;
1614 } else {
1615 Optind++;
1616 newOptind++;
1618 break;
1619 case 'g':
1620 tar_inc=True;
1621 break;
1622 case 'N':
1623 if (Optind>=argc) {
1624 DEBUG(0,("Option N must be followed by valid file name\n"));
1625 return 0;
1626 } else {
1627 SMB_STRUCT_STAT stbuf;
1628 extern time_t newer_than;
1630 if (sys_stat(argv[Optind], &stbuf) == 0) {
1631 newer_than = stbuf.st_mtime;
1632 DEBUG(1,("Getting files newer than %s",
1633 asctime(LocalTime(&newer_than))));
1634 newOptind++;
1635 Optind++;
1636 } else {
1637 DEBUG(0,("Error setting newer-than time\n"));
1638 return 0;
1641 break;
1642 case 'a':
1643 tar_reset=True;
1644 break;
1645 case 'q':
1646 tar_noisy=False;
1647 break;
1648 case 'I':
1649 if (tar_clipfl) {
1650 DEBUG(0,("Only one of I,X,F must be specified\n"));
1651 return 0;
1653 tar_clipfl='I';
1654 break;
1655 case 'X':
1656 if (tar_clipfl) {
1657 DEBUG(0,("Only one of I,X,F must be specified\n"));
1658 return 0;
1660 tar_clipfl='X';
1661 break;
1662 case 'F':
1663 if (tar_clipfl) {
1664 DEBUG(0,("Only one of I,X,F must be specified\n"));
1665 return 0;
1667 tar_clipfl='F';
1668 break;
1669 case 'r':
1670 DEBUG(0, ("tar_re_search set\n"));
1671 tar_re_search = True;
1672 break;
1673 case 'n':
1674 if (tar_type == 'c') {
1675 DEBUG(0, ("dry_run set\n"));
1676 dry_run = True;
1677 } else {
1678 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1679 return 0;
1681 break;
1682 default:
1683 DEBUG(0,("Unknown tar option\n"));
1684 return 0;
1688 if (!tar_type) {
1689 printf("Option T must be followed by one of c or x.\n");
1690 return 0;
1693 /* tar_excl is true if cliplist lists files to be included.
1694 * Both 'I' and 'F' mean include. */
1695 tar_excl=tar_clipfl!='X';
1697 if (tar_clipfl=='F') {
1698 if (argc-Optind-1 != 1) {
1699 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1700 return 0;
1702 newOptind++;
1703 Optind++;
1704 if (! read_inclusion_file(argv[Optind])) {
1705 return 0;
1707 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1708 char *tmpstr;
1709 char **tmplist;
1710 int clipcount;
1712 cliplist=argv+Optind+1;
1713 clipn=argc-Optind-1;
1714 clipcount = clipn;
1716 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1717 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1718 return 0;
1721 for (clipcount = 0; clipcount < clipn; clipcount++) {
1723 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1725 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1726 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1727 return 0;
1730 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1731 tmplist[clipcount] = tmpstr;
1732 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1734 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1737 cliplist = tmplist;
1738 must_free_cliplist = True;
1740 newOptind += clipn;
1743 if (Optind+1<argc && tar_re_search) { /* Doing regular expression seaches */
1744 #ifdef HAVE_REGEX_H
1745 int errcode;
1747 if ((preg = (regex_t *)malloc(65536)) == NULL) {
1749 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1750 return;
1753 if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1754 char errstr[1024];
1755 size_t errlen;
1757 errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1758 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1759 return;
1761 #endif
1763 clipn=argc-Optind-1;
1764 cliplist=argv+Optind+1;
1765 newOptind += clipn;
1768 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1769 /* Sets tar handle to either 0 or 1, as appropriate */
1770 tarhandle=(tar_type=='c');
1772 * Make sure that dbf points to stderr if we are using stdout for
1773 * tar output
1775 if (tarhandle == 1) {
1776 dbf = x_stderr;
1778 if (!strcmp(argv[Optind], "-")) {
1779 newOptind++;
1782 } else {
1783 if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0)) {
1784 if (!dry_run) {
1785 DEBUG(0,("Output is /dev/null, assuming dry_run\n"));
1786 dry_run = True;
1788 tarhandle=-1;
1789 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1790 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1791 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1792 return(0);
1794 newOptind++;
1797 return newOptind;