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