Makefile.in: Removed rpc_server/srv_ldap_helpers.c per J.F.'s instructions.
[samba.git] / source3 / client / clitar.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Tar Extensions
5    Copyright (C) Ricky Poulten 1995-1998
6    Copyright (C) Richard Sharpe 1998
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 /* The following changes developed by Richard Sharpe for Canon Information
23    Systems Research Australia (CISRA)
24
25    1. Restore can now restore files with long file names
26    2. Save now saves directory information so that we can restore 
27       directory creation times
28    3. tar now accepts both UNIX path names and DOS path names. I prefer
29       those lovely /'s to those UGLY \'s :-)
30    4. the files to exclude can be specified as a regular expression by adding
31       an r flag to the other tar flags. Eg:
32
33          -TcrX file.tar "*.(obj|exe)"
34
35       will skip all .obj and .exe files
36 */
37
38
39 #include "includes.h"
40 #include "clitar.h"
41
42 static int clipfind(char **aret, int ret, char *tok);
43
44 typedef struct file_info_struct file_info2;
45
46 struct file_info_struct
47 {
48   size_t size;
49   uint16 mode;
50   int uid;
51   int gid;
52   /* These times are normally kept in GMT */
53   time_t mtime;
54   time_t atime;
55   time_t ctime;
56   char *name;     /* This is dynamically allocate */
57
58   file_info2 *next, *prev;  /* Used in the stack ... */
59
60 };
61
62 typedef struct
63 {
64   file_info2 *top;
65   int items;
66
67 } stack;
68
69 stack dir_stack = {NULL, 0}; /* Want an empty stack */
70
71 #define SEPARATORS " \t\n\r"
72 extern int DEBUGLEVEL;
73 extern struct cli_state *cli;
74
75 /* These defines are for the do_setrattr routine, to indicate
76  * setting and reseting of file attributes in the function call */
77 #define ATTRSET 1
78 #define ATTRRESET 0
79
80 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
81
82 #ifndef CLIENT_TIMEOUT
83 #define CLIENT_TIMEOUT (30*1000)
84 #endif
85
86 static char *tarbuf, *buffer_p;
87 static int tp, ntarf, tbufsiz, ttarf;
88 /* Incremental mode */
89 BOOL tar_inc=False;
90 /* Reset archive bit */
91 BOOL tar_reset=False;
92 /* Include / exclude mode (true=include, false=exclude) */
93 BOOL tar_excl=True;
94 /* use regular expressions for search on file names */
95 BOOL tar_re_search=False;
96 #ifdef HAVE_REGEX_H
97 regex_t *preg;
98 #endif
99 /* Do not dump anything, just calculate sizes */
100 BOOL dry_run=False;
101 /* Dump files with System attribute */
102 BOOL tar_system=True;
103 /* Dump files with Hidden attribute */
104 BOOL tar_hidden=True;
105 /* Be noisy - make a catalogue */
106 BOOL tar_noisy=True;
107 BOOL tar_real_noisy=False;  /* Don't want to be really noisy by default */
108
109 char tar_type='\0';
110 static char **cliplist=NULL;
111 static int clipn=0;
112 static BOOL must_free_cliplist = False;
113
114 extern file_info def_finfo;
115 extern BOOL lowercase;
116 extern uint16 cnum;
117 extern BOOL readbraw_supported;
118 extern int max_xmit;
119 extern pstring cur_dir;
120 extern int get_total_time_ms;
121 extern int get_total_size;
122 extern int Protocol;
123
124 int blocksize=20;
125 int tarhandle;
126
127 static void writetarheader(int f,  char *aname, int size, time_t mtime,
128                            char *amode, unsigned char ftype);
129 static void do_atar(char *rname,char *lname,file_info *finfo1);
130 static void do_tar(file_info *finfo);
131 static void oct_it(long value, int ndgs, char *p);
132 static void fixtarname(char *tptr, char *fp, int l);
133 static int dotarbuf(int f, char *b, int n);
134 static void dozerobuf(int f, int n);
135 static void dotareof(int f);
136 static void initarbuf(void);
137
138 /* restore functions */
139 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix);
140 static long unoct(char *p, int ndgs);
141 static void do_tarput(void);
142 static void unfixtarname(char *tptr, char *fp, int l, BOOL first);
143
144 /*
145  * tar specific utitlities
146  */
147
148 /*******************************************************************
149 Create  a string of size size+1 (for the null)
150 *******************************************************************/
151 static char *string_create_s(int size)
152 {
153   char *tmp;
154
155   tmp = (char *)malloc(size+1);
156
157   if (tmp == NULL) {
158
159     DEBUG(0, ("Out of memory in string_create_s\n"));
160
161   }
162
163   return(tmp);
164
165 }
166
167 /****************************************************************************
168 Write a tar header to buffer
169 ****************************************************************************/
170 static void writetarheader(int f,  char *aname, int size, time_t mtime,
171                            char *amode, unsigned char ftype)
172 {
173   union hblock hb;
174   int i, chk, l;
175   char *jp;
176
177   DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype, size, aname));
178
179   memset(hb.dummy, 0, sizeof(hb.dummy));
180   
181   l=strlen(aname);
182   if (l >= NAMSIZ) {
183           /* write a GNU tar style long header */
184           char *b;
185           b = (char *)malloc(l+TBLOCK+100);
186           if (!b) {
187                   DEBUG(0,("out of memory\n"));
188                   exit(1);
189           }
190           writetarheader(f, "/./@LongLink", l+1, 0, "     0 \0", 'L');
191           memset(b, 0, l+TBLOCK+100);
192           fixtarname(b, aname, l);
193           i = strlen(b)+1;
194           DEBUG(5, ("File name in tar file: %s, size=%i, \n", b, strlen(b)));
195           dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
196           free(b);
197   }
198
199   /* use l + 1 to do the null too */
200   fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
201
202   if (lowercase)
203     strlower(hb.dbuf.name);
204
205   /* write out a "standard" tar format header */
206
207   hb.dbuf.name[NAMSIZ-1]='\0';
208   safe_strcpy(hb.dbuf.mode, amode, strlen(amode));
209   oct_it(0L, 8, hb.dbuf.uid);
210   oct_it(0L, 8, hb.dbuf.gid);
211   oct_it((long) size, 13, hb.dbuf.size);
212   oct_it((long) mtime, 13, hb.dbuf.mtime);
213   memcpy(hb.dbuf.chksum, "        ", sizeof(hb.dbuf.chksum));
214   memset(hb.dbuf.linkname, 0, NAMSIZ);
215   hb.dbuf.linkflag=ftype;
216   
217   for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
218
219   oct_it((long) chk, 8, hb.dbuf.chksum);
220   hb.dbuf.chksum[6] = '\0';
221
222   (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
223 }
224
225 /****************************************************************************
226 Read a tar header into a hblock structure, and validate
227 ***************************************************************************/
228 static long readtarheader(union hblock *hb, file_info2 *finfo, char *prefix)
229 {
230   long chk, fchk;
231   int i;
232   char *jp;
233
234   /*
235    * read in a "standard" tar format header - we're not that interested
236    * in that many fields, though
237    */
238
239   /* check the checksum */
240   for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
241
242   if (chk == 0)
243     return chk;
244
245   /* compensate for blanks in chksum header */
246   for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
247     chk-=(0xFF & *jp++);
248
249   chk += ' ' * sizeof(hb->dbuf.chksum);
250
251   fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
252
253   DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
254             chk, fchk, hb->dbuf.chksum));
255
256   if (fchk != chk)
257     {
258       DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
259       dump_data(5, (char *)hb - TBLOCK, TBLOCK *3);
260       return -1;
261     }
262
263   if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
264
265     DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
266     return(-1);
267
268   }
269
270   safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
271
272   /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
273   unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
274                strlen(hb->dbuf.name) + 1, True);
275
276   /* can't handle some links at present */
277   if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
278     if (hb->dbuf.linkflag == 0) {
279       DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
280                 finfo->name));
281     } else { 
282       if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
283          /* Do nothing here at the moment. do_tarput will handle this
284             as long as the longlink gets back to it, as it has to advance 
285             the buffer pointer, etc */
286
287       } else {
288         DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
289         return -2;
290       }
291     }
292   }
293     
294   if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
295     || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
296     {
297       finfo->mode=aDIR;
298     }
299   else
300     finfo->mode=0; /* we don't care about mode at the moment, we'll
301                     * just make it a regular file */
302   /*
303    * Bug fix by richard@sj.co.uk
304    *
305    * REC: restore times correctly (as does tar)
306    * We only get the modification time of the file; set the creation time
307    * from the mod. time, and the access time to current time
308    */
309   finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
310   finfo->atime = time(NULL);
311   finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
312
313   return True;
314 }
315
316 /****************************************************************************
317 Write out the tar buffer to tape or wherever
318 ****************************************************************************/
319 static int dotarbuf(int f, char *b, int n)
320 {
321   int fail=1, writ=n;
322
323   if (dry_run) {
324     return writ;
325   }
326   /* This routine and the next one should be the only ones that do write()s */
327   if (tp + n >= tbufsiz)
328     {
329       int diff;
330
331       diff=tbufsiz-tp;
332       memcpy(tarbuf + tp, b, diff);
333       fail=fail && (1+write(f, tarbuf, tbufsiz));
334       n-=diff;
335       b+=diff;
336       tp=0;
337
338       while (n >= tbufsiz)
339         {
340           fail=fail && (1 + write(f, b, tbufsiz));
341           n-=tbufsiz;
342           b+=tbufsiz;
343         }
344     }
345   if (n>0) {
346     memcpy(tarbuf+tp, b, n);
347     tp+=n;
348   }
349
350   return(fail ? writ : 0);
351 }
352
353 /****************************************************************************
354 Write zeros to buffer / tape
355 ****************************************************************************/
356 static void dozerobuf(int f, int n)
357 {
358   /* short routine just to write out n zeros to buffer -
359    * used to round files to nearest block
360    * and to do tar EOFs */
361
362   if (dry_run)
363     return;
364   
365   if (n+tp >= tbufsiz)
366     {
367       memset(tarbuf+tp, 0, tbufsiz-tp);
368
369       write(f, tarbuf, tbufsiz);
370       memset(tarbuf, 0, (tp+=n-tbufsiz));
371     }
372   else
373     {
374       memset(tarbuf+tp, 0, n);
375       tp+=n;
376     }
377 }
378
379 /****************************************************************************
380 Malloc tape buffer
381 ****************************************************************************/
382 static void initarbuf(void)
383 {
384   /* initialize tar buffer */
385   tbufsiz=blocksize*TBLOCK;
386   tarbuf=malloc(tbufsiz);      /* FIXME: We might not get the buffer */
387
388   /* reset tar buffer pointer and tar file counter and total dumped */
389   tp=0; ntarf=0; ttarf=0;
390 }
391
392 /****************************************************************************
393 Write two zero blocks at end of file
394 ****************************************************************************/
395 static void dotareof(int f)
396 {
397   SMB_STRUCT_STAT stbuf;
398   /* Two zero blocks at end of file, write out full buffer */
399
400   if (dry_run)
401     return;
402
403   (void) dozerobuf(f, TBLOCK);
404   (void) dozerobuf(f, TBLOCK);
405
406   if (sys_fstat(f, &stbuf) == -1)
407     {
408       DEBUG(0, ("Couldn't stat file handle\n"));
409       return;
410     }
411
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) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
415 }
416
417 /****************************************************************************
418 (Un)mangle DOS pathname, make nonabsolute
419 ****************************************************************************/
420 static void fixtarname(char *tptr, char *fp, int l)
421 {
422   /* add a '.' to start of file name, convert from ugly dos \'s in path
423    * to lovely unix /'s :-} */
424
425   *tptr++='.';
426
427   while (l > 0) {
428     int skip;
429     if((skip = skip_multibyte_char( *fp)) != 0) {
430       if (skip == 2) {
431         *tptr++ = *fp++;
432         *tptr++ = *fp++;
433         l -= 2;
434       } else if (skip == 1) {
435         *tptr++ = *fp++;
436         l--;
437       }
438     } else if (*fp == '\\') {
439       *tptr++ = '/';
440       fp++;
441       l--;
442     } else {
443       *tptr++ = *fp++;
444       l--;
445     }
446   }
447 }
448
449 /****************************************************************************
450 Convert from decimal to octal string
451 ****************************************************************************/
452 static void oct_it (long value, int ndgs, char *p)
453 {
454   /* Converts long to octal string, pads with leading zeros */
455
456   /* skip final null, but do final space */
457   --ndgs;
458   p[--ndgs] = ' ';
459  
460   /* Loop does at least one digit */
461   do {
462       p[--ndgs] = '0' + (char) (value & 7);
463       value >>= 3;
464     }
465   while (ndgs > 0 && value != 0);
466  
467   /* Do leading zeros */
468   while (ndgs > 0)
469     p[--ndgs] = '0';
470 }
471
472 /****************************************************************************
473 Convert from octal string to long
474 ***************************************************************************/
475 static long unoct(char *p, int ndgs)
476 {
477   long value=0;
478   /* Converts octal string to long, ignoring any non-digit */
479
480   while (--ndgs)
481     {
482       if (isdigit((int)*p))
483         value = (value << 3) | (long) (*p - '0');
484
485       p++;
486     }
487
488   return value;
489 }
490
491 /****************************************************************************
492 Compare two strings in a slash insensitive way, allowing s1 to match s2 
493 if s1 is an "initial" string (up to directory marker).  Thus, if s2 is 
494 a file in any subdirectory of s1, declare a match.
495 ***************************************************************************/
496 static int strslashcmp(char *s1, char *s2)
497 {
498   char *s1_0=s1;
499
500   while(*s1 && *s2 &&
501         (*s1 == *s2
502          || tolower(*s1) == tolower(*s2)
503          || (*s1 == '\\' && *s2=='/')
504          || (*s1 == '/' && *s2=='\\'))) {
505           s1++; s2++;
506   }
507
508   /* if s1 has a trailing slash, it compared equal, so s1 is an "initial" 
509      string of s2.
510    */
511   if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
512
513   /* ignore trailing slash on s1 */
514   if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
515
516   /* check for s1 is an "initial" string of s2 */
517   if (*s2 == '/' || *s2 == '\\') return 0;
518
519   return *s1-*s2;
520 }
521
522
523 /****************************************************************************
524 Ensure a remote path exists (make if necessary)
525 ***************************************************************************/
526 static BOOL ensurepath(char *fname)
527 {
528   /* *must* be called with buffer ready malloc'ed */
529   /* ensures path exists */
530
531   char *partpath, *ffname;
532   char *p=fname, *basehack;
533
534   DEBUG(5, ( "Ensurepath called with: %s\n", fname));
535
536   partpath = string_create_s(strlen(fname));
537   ffname = string_create_s(strlen(fname));
538
539   if ((partpath == NULL) || (ffname == NULL)){
540
541     DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
542     return(False);
543
544   }
545
546   *partpath = 0;
547
548   /* fname copied to ffname so can strtok */
549
550   safe_strcpy(ffname, fname, strlen(fname));
551
552   /* do a `basename' on ffname, so don't try and make file name directory */
553   if ((basehack=strrchr(ffname, '\\')) == NULL)
554     return True;
555   else
556     *basehack='\0';
557
558   p=strtok(ffname, "\\");
559
560   while (p)
561     {
562       safe_strcat(partpath, p, strlen(fname) + 1);
563
564       if (!cli_chkpath(cli, partpath)) {
565         if (!cli_mkdir(cli, partpath))
566           {
567             DEBUG(0, ("Error mkdirhiering\n"));
568             return False;
569           }
570         else
571           DEBUG(3, ("mkdirhiering %s\n", partpath));
572
573       }
574
575       safe_strcat(partpath, "\\", strlen(fname) + 1);
576       p = strtok(NULL,"/\\");
577     }
578
579     return True;
580 }
581
582 static int padit(char *buf, int bufsize, int padsize)
583 {
584         int berr= 0;
585         int bytestowrite;
586   
587         DEBUG(5, ("Padding with %d zeros\n", padsize));
588         memset(buf, 0, bufsize);
589         while( !berr && padsize > 0 ) {
590                 bytestowrite= MIN(bufsize, padsize);
591                 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
592                 padsize -= bytestowrite;
593         }
594   
595         return berr;
596 }
597
598
599 static void do_setrattr(char *name, uint16 attr, int set)
600 {
601         uint16 oldattr;
602         time_t t;
603
604         if (!cli_getatr(cli, name, &oldattr, NULL, &t)) return;
605
606         if (set == ATTRSET) {
607                 attr |= oldattr;
608         } else {
609                 attr = oldattr & ~attr;
610         }
611
612         if (!cli_setatr(cli, name, attr, t)) {
613                 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
614         }
615 }
616
617
618 /****************************************************************************
619 append one remote file to the tar file
620 ***************************************************************************/
621 static void do_atar(char *rname,char *lname,file_info *finfo1)
622 {
623   int fnum;
624   uint32 nread=0;
625   char ftype;
626   file_info2 finfo;
627   BOOL close_done = False;
628   BOOL shallitime=True;
629   char data[65520];
630   int read_size = 65520;
631   int datalen=0;
632
633   struct timeval tp_start;
634   GetTimeOfDay(&tp_start);
635
636   ftype = '0'; /* An ordinary file ... */
637
638   if (finfo1) {
639     finfo.size  = finfo1 -> size;
640     finfo.mode  = finfo1 -> mode;
641     finfo.uid   = finfo1 -> uid;
642     finfo.gid   = finfo1 -> gid;
643     finfo.mtime = finfo1 -> mtime;
644     finfo.atime = finfo1 -> atime;
645     finfo.ctime = finfo1 -> ctime;
646   }
647   else {
648     finfo.size  = def_finfo.size;
649     finfo.mode  = def_finfo.mode;
650     finfo.uid   = def_finfo.uid;
651     finfo.gid   = def_finfo.gid;
652     finfo.mtime = def_finfo.mtime;
653     finfo.atime = def_finfo.atime;
654     finfo.ctime = def_finfo.ctime;
655   }
656
657   if (dry_run)
658     {
659       DEBUG(3,("skipping file %s of size %d bytes\n",
660                finfo.name,
661                finfo.size));
662       shallitime=0;
663       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
664       ntarf++;
665       return;
666     }
667
668   fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
669
670   dos_clean_name(rname);
671
672   if (fnum == -1) {
673           DEBUG(0,("%s opening remote file %s (%s)\n",
674                    cli_errstr(cli),rname, cur_dir));
675           return;
676   }
677
678   finfo.name = string_create_s(strlen(rname));
679   if (finfo.name == NULL) {
680           DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
681           return;
682   }
683
684   safe_strcpy(finfo.name,rname, strlen(rname));
685   if (!finfo1) {
686           if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &finfo.atime, &finfo.mtime)) {
687                   DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
688                   return;
689           }
690           finfo.ctime = finfo.mtime;
691   }
692
693   DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
694
695   if (tar_inc && !(finfo.mode & aARCH))
696     {
697       DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
698       shallitime=0;
699     }
700   else if (!tar_system && (finfo.mode & aSYSTEM))
701     {
702       DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
703       shallitime=0;
704     }
705   else if (!tar_hidden && (finfo.mode & aHIDDEN))
706     {
707       DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
708       shallitime=0;
709     }
710   else
711     {
712       DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
713                finfo.name,
714                finfo.size,
715                lname));
716       
717       /* write a tar header, don't bother with mode - just set to 100644 */
718       writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
719
720       while (nread < finfo.size && !close_done) {
721               
722               DEBUG(3,("nread=%d\n",nread));
723               
724               datalen = cli_read(cli, fnum, data, nread, read_size);
725               
726               if (datalen == -1) {
727                       DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
728                       break;
729               }
730               
731               /* add received bits of file to buffer - dotarbuf will
732                * write out in 512 byte intervals */
733               if (dotarbuf(tarhandle,data,datalen) != datalen) {
734                       DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
735                       break;
736               }
737               
738               nread += datalen;
739               if (datalen == 0) {
740                       DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
741                       break;
742               }
743
744               datalen=0;
745       }
746
747       /* pad tar file with zero's if we couldn't get entire file */
748       if (nread < finfo.size) {
749               DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
750               if (padit(data, sizeof(data), finfo.size - nread))
751                       DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
752       }
753
754       /* round tar file to nearest block */
755       if (finfo.size % TBLOCK)
756         dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
757       
758       ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
759       ntarf++;
760     }
761   
762   cli_close(cli, fnum);
763
764   if (shallitime)
765     {
766       struct timeval tp_end;
767       int this_time;
768
769       /* if shallitime is true then we didn't skip */
770       if (tar_reset && !dry_run)
771         (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
772       
773       GetTimeOfDay(&tp_end);
774       this_time = 
775         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
776           (tp_end.tv_usec - tp_start.tv_usec)/1000;
777       get_total_time_ms += this_time;
778       get_total_size += finfo.size;
779
780       if (tar_noisy)
781         {
782           DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
783                finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
784                finfo.name));
785         }
786
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))));
791     }
792 }
793
794 /****************************************************************************
795 Append single file to tar file (or not)
796 ***************************************************************************/
797 static void do_tar(file_info *finfo)
798 {
799   pstring rname;
800
801   if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
802     return;
803
804   /* Is it on the exclude list ? */
805   if (!tar_excl && clipn) {
806     pstring exclaim;
807
808     DEBUG(5, ("Excl: strlen(cur_dir) = %i\n", strlen(cur_dir)));
809
810     safe_strcpy(exclaim, cur_dir, sizeof(pstring));
811     *(exclaim+strlen(exclaim)-1)='\0';
812
813     safe_strcat(exclaim, "\\", sizeof(pstring));
814     safe_strcat(exclaim, finfo->name, sizeof(exclaim));
815
816     DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
817
818     if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
819 #ifdef HAVE_REGEX_H
820         (tar_re_search && !regexec(preg, exclaim, 0, NULL, 0))) {
821 #else
822         (tar_re_search && mask_match(exclaim, cliplist[0], True, False))) {
823 #endif
824       DEBUG(3,("Skipping file %s\n", exclaim));
825       return;
826     }
827   }
828
829   if (finfo->mode & aDIR)
830     {
831       pstring saved_curdir;
832       pstring mtar_mask;
833
834       safe_strcpy(saved_curdir, cur_dir, sizeof(saved_curdir));
835
836       DEBUG(5, ("Sizeof(cur_dir)=%i, strlen(cur_dir)=%i, strlen(finfo->name)=%i\nname=%s,cur_dir=%s\n", sizeof(cur_dir), strlen(cur_dir), strlen(finfo->name), finfo->name, cur_dir));
837
838       safe_strcat(cur_dir,finfo->name, sizeof(cur_dir));
839       safe_strcat(cur_dir,"\\", sizeof(cur_dir));
840
841       DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
842
843       /* write a tar directory, don't bother with mode - just set it to
844        * 40755 */
845       writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
846       if (tar_noisy) {
847           DEBUG(0,("                directory %s\n", cur_dir));
848       }
849       ntarf++;  /* Make sure we have a file on there */
850       safe_strcpy(mtar_mask,cur_dir, sizeof(pstring));
851       safe_strcat(mtar_mask,"*.*", sizeof(pstring));
852       do_list(mtar_mask, attribute, do_tar, False, True);
853       safe_strcpy(cur_dir,saved_curdir, sizeof(pstring));
854     }
855   else
856     {
857       safe_strcpy(rname,cur_dir, sizeof(pstring));
858       safe_strcat(rname,finfo->name, sizeof(pstring));
859       do_atar(rname,finfo->name,finfo);
860     }
861 }
862
863 /****************************************************************************
864 Convert from UNIX to DOS file names
865 ***************************************************************************/
866 static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
867 {
868   /* remove '.' from start of file name, convert from unix /'s to
869    * dos \'s in path. Kill any absolute path names. But only if first!
870    */
871
872   DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
873
874   if (first) {
875     if (*fp == '.') {
876       fp++;
877       l--;
878     }
879     if (*fp == '\\' || *fp == '/') {
880       fp++;
881       l--;
882     }
883   }
884
885   while (l > 0) {
886     int skip;
887     if(( skip = skip_multibyte_char( *fp )) != 0) {
888       if (skip == 2) {
889         *tptr++ = *fp++;
890         *tptr++ = *fp++;
891         l -= 2;
892       } else if (skip == 1) {
893         *tptr++ = *fp++;
894         l--;
895       }
896     } else if (*fp == '/') {
897       *tptr++ = '\\';
898       fp++;
899       l--;
900     } else {
901       *tptr++ = *fp++;
902       l--;
903     }
904   }
905 }
906
907
908 /****************************************************************************
909 Move to the next block in the buffer, which may mean read in another set of
910 blocks. FIXME, we should allow more than one block to be skipped.
911 ****************************************************************************/
912 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
913 {
914   int bufread, total = 0;
915
916   DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
917   *bufferp += TBLOCK;
918   total = TBLOCK;
919
920   if (*bufferp >= (ltarbuf + bufsiz)) {
921
922     DEBUG(5, ("Reading more data into ltarbuf ...\n"));
923
924     total = 0;
925
926     for (bufread = read(tarhandle, ltarbuf, bufsiz); total < bufsiz; total += bufread) {
927
928       if (bufread <= 0) { /* An error, return false */
929         return (total > 0 ? -2 : bufread);
930       }
931
932     }
933
934     DEBUG(5, ("Total bytes read ... %i\n", total));
935
936     *bufferp = ltarbuf;
937
938   }
939
940   return(total);
941
942 }
943
944 /* Skip a file, even if it includes a long file name? */
945 static int skip_file(int skipsize)
946 {
947   int dsize = skipsize;
948
949   DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
950
951   /* FIXME, we should skip more than one block at a time */
952
953   while (dsize > 0) {
954
955     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
956
957         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
958         return(False);
959
960     }
961
962     dsize -= TBLOCK;
963
964   }
965
966   return(True);
967 }
968
969 /* We get a file from the tar file and store it */
970 static int get_file(file_info2 finfo)
971 {
972   int fsize = finfo.size;
973   int fnum, pos = 0, dsize = 0, rsize = 0, bpos = 0;
974
975   DEBUG(5, ("get_file: file: %s, size %i\n", finfo.name, fsize));
976
977   if (ensurepath(finfo.name) && 
978       (fnum=cli_open(cli, finfo.name, O_WRONLY|O_CREAT|O_TRUNC, DENY_NONE)) == -1)
979     {
980       DEBUG(0, ("abandoning restore\n"));
981       return(False);
982     }
983
984   /* read the blocks from the tar file and write to the remote file */
985
986   rsize = fsize;  /* This is how much to write */
987
988   while (rsize > 0) {
989
990     /* We can only write up to the end of the buffer */
991
992     dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
993     dsize = MIN(dsize, rsize);  /* Should be only what is left */
994     DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
995
996     if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
997             DEBUG(0, ("Error writing remote file\n"));
998             return 0;
999     }
1000
1001     rsize -= dsize;
1002     pos += dsize;
1003
1004     /* Now figure out how much to move in the buffer */
1005
1006     /* FIXME, we should skip more than one block at a time */
1007
1008     /* First, skip any initial part of the part written that is left over */
1009     /* from the end of the first TBLOCK                                   */
1010
1011     if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1012
1013       dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
1014       bpos = 0;
1015
1016       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
1017         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1018         return False;
1019
1020       }
1021
1022     }
1023
1024     while (dsize >= TBLOCK) {
1025
1026       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1027
1028         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1029         return False;
1030
1031       }
1032
1033       dsize -= TBLOCK;
1034
1035     }
1036
1037     bpos = dsize;
1038
1039   }
1040
1041   /* Now close the file ... */
1042
1043   if (!cli_close(cli, fnum)) {
1044           DEBUG(0, ("Error closing remote file\n"));
1045           return(False);
1046   }
1047
1048   /* Now we update the creation date ... */
1049
1050   DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1051
1052   if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime)) {
1053           if (tar_real_noisy) {
1054                   DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1055                   /*return(False); */ /* Ignore, as Win95 does not allow changes */
1056           }
1057   }
1058
1059   ntarf++;
1060
1061   DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo.name, finfo.size));
1062   
1063   return(True);
1064 }
1065
1066 /* Create a directory.  We just ensure that the path exists and return as there
1067    is no file associated with a directory 
1068 */
1069 static int get_dir(file_info2 finfo)
1070 {
1071
1072   DEBUG(5, ("Creating directory: %s\n", finfo.name));
1073
1074   if (!ensurepath(finfo.name)) {
1075
1076     DEBUG(0, ("Problems creating directory\n"));
1077     return(False);
1078
1079   }
1080   return(True);
1081
1082 }
1083 /* Get a file with a long file name ... first file has file name, next file 
1084    has the data. We only want the long file name, as the loop in do_tarput
1085    will deal with the rest.
1086 */
1087 static char * get_longfilename(file_info2 finfo)
1088 {
1089   int namesize = finfo.size + strlen(cur_dir) + 2;
1090   char *longname = malloc(namesize);
1091   int offset = 0, left = finfo.size;
1092   BOOL first = True;
1093
1094   DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1095   DEBUG(5, ("Len = %i\n", finfo.size));
1096
1097   if (longname == NULL) {
1098
1099     DEBUG(0, ("could not allocate buffer of size %d for longname\n", 
1100               finfo.size + strlen(cur_dir) + 2));
1101     return(NULL);
1102   }
1103
1104   /* First, add cur_dir to the long file name */
1105
1106   if (strlen(cur_dir) > 0) {
1107     strncpy(longname, cur_dir, namesize);
1108     offset = strlen(cur_dir);
1109   }
1110
1111   /* Loop through the blocks picking up the name */
1112
1113   while (left > 0) {
1114
1115     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1116
1117       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1118       return(NULL);
1119
1120     }
1121
1122     unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1123     DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1124
1125     offset += TBLOCK;
1126     left -= TBLOCK;
1127
1128   }
1129
1130   return(longname);
1131
1132 }
1133
1134 static void do_tarput(void)
1135 {
1136   file_info2 finfo;
1137   struct timeval tp_start;
1138   char *longfilename = NULL, linkflag;
1139   int skip = False;
1140
1141   GetTimeOfDay(&tp_start);
1142
1143   DEBUG(5, ("RJS do_tarput called ...\n"));
1144
1145   buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1146
1147   /* Now read through those files ... */
1148
1149   while (True) {
1150
1151     /* Get us to the next block, or the first block first time around */
1152
1153     if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1154
1155       DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1156
1157       return;
1158
1159     }
1160
1161     DEBUG(5, ("Reading the next header ...\n"));
1162
1163     switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1164
1165     case -2:    /* Hmm, not good, but not fatal */
1166       DEBUG(0, ("Skipping %s...\n", finfo.name));
1167       if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) &&
1168           !skip_file(finfo.size)) {
1169
1170         DEBUG(0, ("Short file, bailing out...\n"));
1171         return;
1172
1173       }
1174
1175       break;
1176
1177     case -1:
1178       DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1179       return;
1180
1181     case 0: /* chksum is zero - looks like an EOF */
1182       DEBUG(0, ("total of %d tar files restored to share\n", ntarf));
1183       return;        /* Hmmm, bad here ... */
1184
1185     default: 
1186       /* No action */
1187
1188       break;
1189
1190     }
1191
1192     /* Now, do we have a long file name? */
1193
1194     if (longfilename != NULL) {
1195
1196       free(finfo.name);   /* Free the space already allocated */
1197       finfo.name = longfilename;
1198       longfilename = NULL;
1199
1200     }
1201
1202     /* Well, now we have a header, process the file ...            */
1203
1204     /* Should we skip the file? We have the long name as well here */
1205
1206     skip = clipn &&
1207       ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl)
1208 #ifdef HAVE_REGEX_H
1209       || (tar_re_search && !regexec(preg, finfo.name, 0, NULL, 0)));
1210 #else
1211       || (tar_re_search && mask_match(finfo.name, cliplist[0], True, False)));
1212 #endif
1213
1214   DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1215
1216   if (skip) {
1217
1218     skip_file(finfo.size);
1219     continue;
1220
1221   }
1222
1223     /* We only get this far if we should process the file */
1224   linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1225
1226     switch (linkflag) {
1227
1228     case '0':  /* Should use symbolic names--FIXME */
1229
1230       /* Skip to the next block first, so we can get the file, FIXME, should
1231          be in get_file ... */
1232
1233       if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1234         DEBUG(0, ("Short file, bailing out...\n"));
1235         return;
1236       }
1237       if (!get_file(finfo)) {
1238         DEBUG(0, ("Abandoning restore\n"));
1239         return;
1240
1241       }
1242       break;
1243
1244     case '5':
1245       if (!get_dir(finfo)) {
1246         DEBUG(0, ("Abandoning restore \n"));
1247         return;
1248       }
1249       break;
1250
1251     case 'L':
1252       longfilename = get_longfilename(finfo);
1253       if (!longfilename) {
1254         DEBUG(0, ("abandoning restore\n"));
1255         return;
1256
1257       }
1258       DEBUG(5, ("Long file name: %s\n", longfilename));
1259       break;
1260
1261     default:
1262       skip_file(finfo.size);  /* Don't handle these yet */
1263       break;
1264
1265     }
1266
1267   }
1268
1269
1270 }
1271
1272
1273 /*
1274  * samba interactive commands
1275  */
1276
1277 /****************************************************************************
1278 Blocksize command
1279 ***************************************************************************/
1280 void cmd_block(void)
1281 {
1282   fstring buf;
1283   int block;
1284
1285   if (!next_token(NULL,buf,NULL,sizeof(buf)))
1286     {
1287       DEBUG(0, ("blocksize <n>\n"));
1288       return;
1289     }
1290
1291   block=atoi(buf);
1292   if (block < 0 || block > 65535)
1293     {
1294       DEBUG(0, ("blocksize out of range"));
1295       return;
1296     }
1297
1298   blocksize=block;
1299   DEBUG(2,("blocksize is now %d\n", blocksize));
1300 }
1301
1302 /****************************************************************************
1303 command to set incremental / reset mode
1304 ***************************************************************************/
1305 void cmd_tarmode(void)
1306 {
1307   fstring buf;
1308
1309   while (next_token(NULL,buf,NULL,sizeof(buf))) {
1310     if (strequal(buf, "full"))
1311       tar_inc=False;
1312     else if (strequal(buf, "inc"))
1313       tar_inc=True;
1314     else if (strequal(buf, "reset"))
1315       tar_reset=True;
1316     else if (strequal(buf, "noreset"))
1317       tar_reset=False;
1318     else if (strequal(buf, "system"))
1319       tar_system=True;
1320     else if (strequal(buf, "nosystem"))
1321       tar_system=False;
1322     else if (strequal(buf, "hidden"))
1323       tar_hidden=True;
1324     else if (strequal(buf, "nohidden"))
1325       tar_hidden=False;
1326     else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1327       tar_noisy=True;
1328     else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1329       tar_noisy=False;
1330     else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1331   }
1332
1333   DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1334             tar_inc ? "incremental" : "full",
1335             tar_system ? "system" : "nosystem",
1336             tar_hidden ? "hidden" : "nohidden",
1337             tar_reset ? "reset" : "noreset",
1338             tar_noisy ? "verbose" : "quiet"));
1339
1340 }
1341
1342 /****************************************************************************
1343 Feeble attrib command
1344 ***************************************************************************/
1345 void cmd_setmode(void)
1346 {
1347   char *q;
1348   fstring buf;
1349   pstring fname;
1350   uint16 attra[2];
1351   int direct=1;
1352
1353   attra[0] = attra[1] = 0;
1354
1355   if (!next_token(NULL,buf,NULL,sizeof(buf)))
1356     {
1357       DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1358       return;
1359     }
1360
1361   safe_strcpy(fname, cur_dir, sizeof(pstring));
1362   safe_strcat(fname, buf, sizeof(pstring));
1363
1364   while (next_token(NULL,buf,NULL,sizeof(buf))) {
1365     q=buf;
1366
1367     while(*q)
1368       switch (*q++) {
1369       case '+': direct=1;
1370         break;
1371       case '-': direct=0;
1372         break;
1373       case 'r': attra[direct]|=aRONLY;
1374         break;
1375       case 'h': attra[direct]|=aHIDDEN;
1376         break;
1377       case 's': attra[direct]|=aSYSTEM;
1378         break;
1379       case 'a': attra[direct]|=aARCH;
1380         break;
1381       default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1382         return;
1383       }
1384   }
1385
1386   if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1387     {
1388       DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1389       return;
1390     }
1391
1392   DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1393   (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
1394   (void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1395 }
1396
1397 /****************************************************************************
1398 Principal command for creating / extracting
1399 ***************************************************************************/
1400 void cmd_tar(void)
1401 {
1402   fstring buf;
1403   char **argl;
1404   int argcl;
1405
1406   if (!next_token(NULL,buf,NULL,sizeof(buf)))
1407     {
1408       DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1409       return;
1410     }
1411
1412   argl=toktocliplist(&argcl, NULL);
1413   if (!tar_parseargs(argcl, argl, buf, 0))
1414     return;
1415
1416   process_tar();
1417
1418   free(argl);
1419 }
1420
1421 /****************************************************************************
1422 Command line (option) version
1423 ***************************************************************************/
1424 int process_tar(void)
1425 {
1426   initarbuf();
1427   switch(tar_type) {
1428   case 'x':
1429
1430 #if 0
1431     do_tarput2();
1432 #else
1433     do_tarput();
1434 #endif
1435     free(tarbuf);
1436     close(tarhandle);
1437     break;
1438   case 'r':
1439   case 'c':
1440     if (clipn && tar_excl) {
1441       int i;
1442       pstring tarmac;
1443
1444       for (i=0; i<clipn; i++) {
1445         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1446
1447         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1448           *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1449         }
1450         
1451         if (strrchr(cliplist[i], '\\')) {
1452           pstring saved_dir;
1453           
1454           safe_strcpy(saved_dir, cur_dir, sizeof(pstring));
1455           
1456           if (*cliplist[i]=='\\') {
1457             safe_strcpy(tarmac, cliplist[i], sizeof(pstring));
1458           } else {
1459             safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1460             safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1461           }
1462           safe_strcpy(cur_dir, tarmac, sizeof(pstring));
1463           *(strrchr(cur_dir, '\\')+1)='\0';
1464
1465           do_list(tarmac,attribute,do_tar, False, True);
1466           safe_strcpy(cur_dir,saved_dir, sizeof(pstring));
1467         } else {
1468           safe_strcpy(tarmac, cur_dir, sizeof(pstring));
1469           safe_strcat(tarmac, cliplist[i], sizeof(pstring));
1470           do_list(tarmac,attribute,do_tar, False, True);
1471         }
1472       }
1473     } else {
1474       pstring mask;
1475       safe_strcpy(mask,cur_dir, sizeof(pstring));
1476       safe_strcat(mask,"\\*.*", sizeof(pstring));
1477       do_list(mask,attribute,do_tar,False, True);
1478     }
1479     
1480     if (ntarf) dotareof(tarhandle);
1481     close(tarhandle);
1482     free(tarbuf);
1483     
1484     DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1485     DEBUG(0, ("Total bytes written: %d\n", ttarf));
1486     break;
1487   }
1488
1489   if (must_free_cliplist) {
1490     int i;
1491     for (i = 0; i < clipn; ++i) {
1492       free(cliplist[i]);
1493     }
1494     free(cliplist);
1495     cliplist = NULL;
1496     clipn = 0;
1497     must_free_cliplist = False;
1498   }
1499
1500   return(0);
1501 }
1502
1503 /****************************************************************************
1504 Find a token (filename) in a clip list
1505 ***************************************************************************/
1506 static int clipfind(char **aret, int ret, char *tok)
1507 {
1508   if (aret==NULL) return 0;
1509
1510   /* ignore leading slashes or dots in token */
1511   while(strchr("/\\.", *tok)) tok++;
1512
1513   while(ret--) {
1514     char *pkey=*aret++;
1515
1516     /* ignore leading slashes or dots in list */
1517     while(strchr("/\\.", *pkey)) pkey++;
1518
1519     if (!strslashcmp(pkey, tok)) return 1;
1520   }
1521
1522   return 0;
1523 }
1524
1525 /****************************************************************************
1526 Read list of files to include from the file and initialize cliplist
1527 accordingly.
1528 ***************************************************************************/
1529 static int read_inclusion_file(char *filename)
1530 {
1531   FILE *inclusion = NULL;
1532   char buf[MAXPATHLEN + 1];
1533   char *inclusion_buffer = NULL;
1534   int inclusion_buffer_size = 0;
1535   int inclusion_buffer_sofar = 0;
1536   char *p;
1537   char *tmpstr;
1538   int i;
1539   int error = 0;
1540
1541   clipn = 0;
1542   buf[MAXPATHLEN] = '\0'; /* guarantee null-termination */
1543   if ((inclusion = fopen(filename, "r")) == NULL) {
1544     /* XXX It would be better to include a reason for failure, but without
1545      * autoconf, it's hard to use strerror, sys_errlist, etc.
1546      */
1547     DEBUG(0,("Unable to open inclusion file %s\n", filename));
1548     return 0;
1549   }
1550
1551   while ((! error) && (fgets(buf, sizeof(buf)-1, inclusion))) {
1552     if (inclusion_buffer == NULL) {
1553       inclusion_buffer_size = 1024;
1554       if ((inclusion_buffer = malloc(inclusion_buffer_size)) == NULL) {
1555         DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1556         error = 1;
1557         break;
1558       }
1559     }
1560     
1561     if (buf[strlen(buf)-1] == '\n') {
1562       buf[strlen(buf)-1] = '\0';
1563     }
1564     
1565     if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1566       inclusion_buffer_size *= 2;
1567       inclusion_buffer = Realloc(inclusion_buffer,inclusion_buffer_size);
1568       if (! inclusion_buffer) {
1569         DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1570                  inclusion_buffer_size));
1571         error = 1;
1572         break;
1573       }
1574     }
1575     
1576     safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1577     inclusion_buffer_sofar += strlen(buf) + 1;
1578     clipn++;
1579   }
1580   fclose(inclusion);
1581
1582   if (! error) {
1583     /* Allocate an array of clipn + 1 char*'s for cliplist */
1584     cliplist = malloc((clipn + 1) * sizeof(char *));
1585     if (cliplist == NULL) {
1586       DEBUG(0,("failure allocating memory for cliplist\n"));
1587       error = 1;
1588     } else {
1589       cliplist[clipn] = NULL;
1590       p = inclusion_buffer;
1591       for (i = 0; (! error) && (i < clipn); i++) {
1592         /* set current item to NULL so array will be null-terminated even if
1593          * malloc fails below. */
1594         cliplist[i] = NULL;
1595         if ((tmpstr = (char *)malloc(strlen(p)+1)) == NULL) {
1596           DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1597           error = 1;
1598         } else {
1599           unfixtarname(tmpstr, p, strlen(p) + 1, True);
1600           cliplist[i] = tmpstr;
1601           if ((p = strchr(p, '\000')) == NULL) {
1602             DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1603             abort();
1604           }
1605         }
1606         ++p;
1607       }
1608       must_free_cliplist = True;
1609     }
1610   }
1611
1612   if (inclusion_buffer) {
1613     free(inclusion_buffer);
1614   }
1615   if (error) {
1616     if (cliplist) {
1617       char **pp;
1618       /* We know cliplist is always null-terminated */
1619       for (pp = cliplist; *pp; ++pp) {
1620         free(*pp);
1621       }
1622       free(cliplist);
1623       cliplist = NULL;
1624       must_free_cliplist = False;
1625     }
1626     return 0;
1627   }
1628   
1629   /* cliplist and its elements are freed at the end of process_tar. */
1630   return 1;
1631 }
1632
1633 /****************************************************************************
1634 Parse tar arguments. Sets tar_type, tar_excl, etc.
1635 ***************************************************************************/
1636 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1637 {
1638   char tar_clipfl='\0';
1639
1640   /* Reset back to defaults - could be from interactive version 
1641    * reset mode and archive mode left as they are though
1642    */
1643   tar_type='\0';
1644   tar_excl=True;
1645   dry_run=False;
1646
1647   while (*Optarg) 
1648     switch(*Optarg++) {
1649     case 'c':
1650       tar_type='c';
1651       break;
1652     case 'x':
1653       if (tar_type=='c') {
1654         printf("Tar must be followed by only one of c or x.\n");
1655         return 0;
1656       }
1657       tar_type='x';
1658       break;
1659     case 'b':
1660       if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1661         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1662         return 0;
1663       } else {
1664         Optind++;
1665       }
1666       break;
1667     case 'g':
1668       tar_inc=True;
1669       break;
1670     case 'N':
1671       if (Optind>=argc) {
1672         DEBUG(0,("Option N must be followed by valid file name\n"));
1673         return 0;
1674       } else {
1675         SMB_STRUCT_STAT stbuf;
1676         extern time_t newer_than;
1677         
1678         if (dos_stat(argv[Optind], &stbuf) == 0) {
1679           newer_than = stbuf.st_mtime;
1680           DEBUG(1,("Getting files newer than %s",
1681                    asctime(LocalTime(&newer_than))));
1682           Optind++;
1683         } else {
1684           DEBUG(0,("Error setting newer-than time\n"));
1685           return 0;
1686         }
1687       }
1688       break;
1689     case 'a':
1690       tar_reset=True;
1691       break;
1692     case 'q':
1693       tar_noisy=False;
1694       break;
1695     case 'I':
1696       if (tar_clipfl) {
1697         DEBUG(0,("Only one of I,X,F must be specified\n"));
1698         return 0;
1699       }
1700       tar_clipfl='I';
1701       break;
1702     case 'X':
1703       if (tar_clipfl) {
1704         DEBUG(0,("Only one of I,X,F must be specified\n"));
1705         return 0;
1706       }
1707       tar_clipfl='X';
1708       break;
1709     case 'F':
1710       if (tar_clipfl) {
1711         DEBUG(0,("Only one of I,X,F must be specified\n"));
1712         return 0;
1713       }
1714       tar_clipfl='F';
1715       break;
1716     case 'r':
1717       DEBUG(0, ("tar_re_search set\n"));
1718       tar_re_search = True;
1719       break;
1720     case 'n':
1721       if (tar_type == 'c') {
1722         DEBUG(0, ("dry_run set\n"));
1723         dry_run = True;
1724       } else {
1725         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1726         return 0;
1727       }
1728       break;
1729     default:
1730       DEBUG(0,("Unknown tar option\n"));
1731       return 0;
1732     }
1733
1734   if (!tar_type) {
1735     printf("Option T must be followed by one of c or x.\n");
1736     return 0;
1737   }
1738
1739   /* tar_excl is true if cliplist lists files to be included.
1740    * Both 'I' and 'F' mean include. */
1741   tar_excl=tar_clipfl!='X';
1742
1743   if (tar_clipfl=='F') {
1744     if (argc-Optind-1 != 1) {
1745       DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1746       return 0;
1747     }
1748     if (! read_inclusion_file(argv[Optind+1])) {
1749       return 0;
1750     }
1751   } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1752     char *tmpstr;
1753     char **tmplist;
1754     int clipcount;
1755
1756     cliplist=argv+Optind+1;
1757     clipn=argc-Optind-1;
1758     clipcount = clipn;
1759
1760     if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1761       DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", 
1762                clipn)
1763            );
1764       return 0;
1765     }
1766
1767     for (clipcount = 0; clipcount < clipn; clipcount++) {
1768
1769       DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1770
1771       if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1772         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1773                  clipcount)
1774              );
1775         return 0;
1776       }
1777       unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1778       tmplist[clipcount] = tmpstr;
1779       DEBUG(5, ("Processed an item, %s\n", tmpstr));
1780
1781       DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1782     }
1783     cliplist = tmplist;
1784     must_free_cliplist = True;
1785   }
1786
1787   if (Optind+1<argc && tar_re_search) {  /* Doing regular expression seaches */
1788 #ifdef HAVE_REGEX_H
1789     int errcode;
1790
1791     if ((preg = (regex_t *)malloc(65536)) == NULL) {
1792
1793       DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1794       return;
1795
1796     }
1797
1798     if (errcode = regcomp(preg, argv[Optind + 1], REG_EXTENDED)) {
1799       char errstr[1024];
1800       size_t errlen;
1801
1802       errlen = regerror(errcode, preg, errstr, sizeof(errstr) - 1);
1803       
1804       DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv[Optind + 1], errstr));
1805       return;
1806
1807     }
1808 #endif
1809
1810     clipn=argc-Optind-1;
1811     cliplist=argv+Optind+1;
1812
1813   }
1814
1815   if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1816     /* Sets tar handle to either 0 or 1, as appropriate */
1817     tarhandle=(tar_type=='c');
1818   } else {
1819     if (tar_type=='c' && (dry_run || strcmp(argv[Optind], "/dev/null")==0))
1820       {
1821         if (!dry_run) {
1822           DEBUG(0,("Output is /dev/null, assuming dry_run"));
1823           dry_run = True;
1824         }
1825         tarhandle=-1;
1826       } else
1827     if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
1828         || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
1829       {
1830         DEBUG(0,("Error opening local file %s - %s\n",
1831                  argv[Optind], strerror(errno)));
1832         return(0);
1833       }
1834   }
1835
1836   return 1;
1837 }