Remove next_token_nr_talloc and its associated global
[kai/samba.git] / source3 / 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
517         DEBUG(5, ( "Ensurepath called with: %s\n", fname));
518
519         partpath = string_create_s(strlen(fname));
520         ffname = string_create_s(strlen(fname));
521
522         if ((partpath == NULL) || (ffname == NULL)){
523                 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
524                 SAFE_FREE(partpath);
525                 SAFE_FREE(ffname);
526                 return(False);
527         }
528
529         *partpath = 0;
530
531         /* fname copied to ffname so can strtok */
532
533         safe_strcpy(ffname, fname, strlen(fname));
534
535         /* do a `basename' on ffname, so don't try and make file name directory */
536         if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
537                 SAFE_FREE(partpath);
538                 SAFE_FREE(ffname);
539                 return True;
540         } else {
541                 *basehack='\0';
542         }
543
544         p=strtok(ffname, "\\");
545
546         while (p) {
547                 safe_strcat(partpath, p, strlen(fname) + 1);
548
549                 if (!cli_chkpath(cli, partpath)) {
550                         if (!cli_mkdir(cli, partpath)) {
551                                 SAFE_FREE(partpath);
552                                 SAFE_FREE(ffname);
553                                 DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
554                                 return False;
555                         } else {
556                                 DEBUG(3, ("mkdirhiering %s\n", partpath));
557                         }
558                 }
559
560                 safe_strcat(partpath, "\\", strlen(fname) + 1);
561                 p = strtok(NULL,"/\\");
562         }
563
564         SAFE_FREE(partpath);
565         SAFE_FREE(ffname);
566         return True;
567 }
568
569 static int padit(char *buf, SMB_BIG_UINT bufsize, SMB_BIG_UINT padsize)
570 {
571         int berr= 0;
572         int bytestowrite;
573
574         DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
575         memset(buf, 0, (size_t)bufsize);
576         while( !berr && padsize > 0 ) {
577                 bytestowrite= (int)MIN(bufsize, padsize);
578                 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
579                 padsize -= bytestowrite;
580         }
581
582         return berr;
583 }
584
585 static void do_setrattr(char *name, uint16 attr, int set)
586 {
587         uint16 oldattr;
588
589         if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
590
591         if (set == ATTRSET) {
592                 attr |= oldattr;
593         } else {
594                 attr = oldattr & ~attr;
595         }
596
597         if (!cli_setatr(cli, name, attr, 0)) {
598                 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
599         }
600 }
601
602 /****************************************************************************
603 append one remote file to the tar file
604 ***************************************************************************/
605
606 static void do_atar(const char *rname_in,char *lname,file_info *finfo1)
607 {
608         int fnum = -1;
609         SMB_BIG_UINT nread=0;
610         char ftype;
611         file_info2 finfo;
612         bool shallitime=True;
613         char *data = NULL;
614         int read_size = 65520;
615         int datalen=0;
616         char *rname = NULL;
617         TALLOC_CTX *ctx = talloc_stackframe();
618
619         struct timeval tp_start;
620
621         GetTimeOfDay(&tp_start);
622
623         data = SMB_MALLOC_ARRAY(char, read_size);
624         if (!data) {
625                 DEBUG(0,("do_atar: out of memory.\n"));
626                 goto cleanup;
627         }
628
629         ftype = '0'; /* An ordinary file ... */
630
631         ZERO_STRUCT(finfo);
632
633         finfo.size  = finfo1 -> size;
634         finfo.mode  = finfo1 -> mode;
635         finfo.uid   = finfo1 -> uid;
636         finfo.gid   = finfo1 -> gid;
637         finfo.mtime_ts = finfo1 -> mtime_ts;
638         finfo.atime_ts = finfo1 -> atime_ts;
639         finfo.ctime_ts = finfo1 -> ctime_ts;
640
641         if (dry_run) {
642                 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
643                                 (double)finfo.size));
644                 shallitime=0;
645                 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
646                 ntarf++;
647                 goto cleanup;
648         }
649
650         rname = clean_name(ctx, rname_in);
651         if (!rname) {
652                 goto cleanup;
653         }
654
655         fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
656
657         if (fnum == -1) {
658                 DEBUG(0,("%s opening remote file %s (%s)\n",
659                                 cli_errstr(cli),rname, client_get_cur_dir()));
660                 goto cleanup;
661         }
662
663         finfo.name = string_create_s(strlen(rname));
664         if (finfo.name == NULL) {
665                 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
666                 goto cleanup;
667         }
668
669         safe_strcpy(finfo.name,rname, strlen(rname));
670         if (!finfo1) {
671                 time_t atime, mtime;
672                 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &atime, &mtime)) {
673                         DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
674                         goto cleanup;
675                 }
676                 finfo.atime_ts = convert_time_t_to_timespec(atime);
677                 finfo.mtime_ts = convert_time_t_to_timespec(mtime);
678                 finfo.ctime_ts = finfo.mtime_ts;
679         }
680
681         DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
682
683         if (tar_inc && !(finfo.mode & aARCH)) {
684                 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
685                 shallitime=0;
686         } else if (!tar_system && (finfo.mode & aSYSTEM)) {
687                 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
688                 shallitime=0;
689         } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
690                 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
691                 shallitime=0;
692         } else {
693                 bool wrote_tar_header = False;
694
695                 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
696                         finfo.name, (double)finfo.size, lname));
697
698                 do {
699
700                         DEBUG(3,("nread=%.0f\n",(double)nread));
701
702                         datalen = cli_read(cli, fnum, data, nread, read_size);
703
704                         if (datalen == -1) {
705                                 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
706                                 break;
707                         }
708
709                         nread += datalen;
710
711                         /* Only if the first read succeeds, write out the tar header. */
712                         if (!wrote_tar_header) {
713                                 /* write a tar header, don't bother with mode - just set to 100644 */
714                                 writetarheader(tarhandle, rname, finfo.size,
715                                         finfo.mtime_ts.tv_sec, "100644 \0", ftype);
716                                 wrote_tar_header = True;
717                         }
718
719                         /* if file size has increased since we made file size query, truncate
720                                 read so tar header for this file will be correct.
721                         */
722
723                         if (nread > finfo.size) {
724                                 datalen -= nread - finfo.size;
725                                 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
726                                                         finfo.name, (double)finfo.size));
727                         }
728
729                         /* add received bits of file to buffer - dotarbuf will
730                         * write out in 512 byte intervals */
731
732                         if (dotarbuf(tarhandle,data,datalen) != datalen) {
733                                 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
734                                 break;
735                         }
736
737                         if ( (datalen == 0) && (finfo.size != 0) ) {
738                                 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
739                                 break;
740                         }
741
742                         datalen=0;
743                 } while ( nread < finfo.size );
744
745                 if (wrote_tar_header) {
746                         /* pad tar file with zero's if we couldn't get entire file */
747                         if (nread < finfo.size) {
748                                 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
749                                                         (double)finfo.size, (int)nread));
750                                 if (padit(data, (SMB_BIG_UINT)sizeof(data), finfo.size - nread))
751                                         DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
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                 } else {
761                         DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
762                         shallitime=0;
763                 }
764         }
765
766         cli_close(cli, fnum);
767         fnum = -1;
768
769         if (shallitime) {
770                 struct timeval tp_end;
771                 int this_time;
772
773                 /* if shallitime is true then we didn't skip */
774                 if (tar_reset && !dry_run)
775                         (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
776
777                 GetTimeOfDay(&tp_end);
778                 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
779                 get_total_time_ms += this_time;
780                 get_total_size += finfo.size;
781
782                 if (tar_noisy) {
783                         DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
784                                 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
785                                 finfo.name));
786                 }
787
788                 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
789                 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
790                                 finfo.size / MAX(0.001, (1.024*this_time)),
791                                 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
792         }
793
794   cleanup:
795
796         if (fnum != -1) {
797                 cli_close(cli, fnum);
798                 fnum = -1;
799         }
800         TALLOC_FREE(ctx);
801         SAFE_FREE(data);
802 }
803
804 /****************************************************************************
805 Append single file to tar file (or not)
806 ***************************************************************************/
807
808 static void do_tar(file_info *finfo, const char *dir)
809 {
810         TALLOC_CTX *ctx = talloc_stackframe();
811
812         if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
813                 return;
814
815         /* Is it on the exclude list ? */
816         if (!tar_excl && clipn) {
817                 char *exclaim;
818
819                 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
820
821                 exclaim = talloc_asprintf(ctx,
822                                 "%s\\%s",
823                                 client_get_cur_dir(),
824                                 finfo->name);
825                 if (!exclaim) {
826                         return;
827                 }
828
829                 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
830
831                 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
832                                 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
833                         DEBUG(3,("Skipping file %s\n", exclaim));
834                         TALLOC_FREE(exclaim);
835                         return;
836                 }
837                 TALLOC_FREE(exclaim);
838         }
839
840         if (finfo->mode & aDIR) {
841                 char *saved_curdir = NULL;
842                 char *new_cd = NULL;
843                 char *mtar_mask = NULL;
844
845                 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
846                 if (!saved_curdir) {
847                         return;
848                 }
849
850                 DEBUG(5, ("strlen(cur_dir)=%d, \
851 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
852                         (int)strlen(saved_curdir),
853                         (int)strlen(finfo->name), finfo->name, saved_curdir));
854
855                 new_cd = talloc_asprintf(ctx,
856                                 "%s%s\\",
857                                 client_get_cur_dir(),
858                                 finfo->name);
859                 if (!new_cd) {
860                         return;
861                 }
862                 client_set_cur_dir(new_cd);
863
864                 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
865
866                 /* write a tar directory, don't bother with mode - just
867                  * set it to 40755 */
868                 writetarheader(tarhandle, client_get_cur_dir(), 0,
869                                 finfo->mtime_ts.tv_sec, "040755 \0", '5');
870                 if (tar_noisy) {
871                         DEBUG(0,("                directory %s\n",
872                                 client_get_cur_dir()));
873                 }
874                 ntarf++;  /* Make sure we have a file on there */
875                 mtar_mask = talloc_asprintf(ctx,
876                                 "%s*",
877                                 client_get_cur_dir());
878                 if (!mtar_mask) {
879                         return;
880                 }
881                 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
882                 do_list(mtar_mask, attribute, do_tar, False, True);
883                 client_set_cur_dir(saved_curdir);
884                 TALLOC_FREE(saved_curdir);
885                 TALLOC_FREE(new_cd);
886                 TALLOC_FREE(mtar_mask);
887         } else {
888                 char *rname = talloc_asprintf(ctx,
889                                         "%s%s",
890                                         client_get_cur_dir(),
891                                         finfo->name);
892                 if (!rname) {
893                         return;
894                 }
895                 do_atar(rname,finfo->name,finfo);
896                 TALLOC_FREE(rname);
897         }
898 }
899
900 /****************************************************************************
901 Convert from UNIX to DOS file names
902 ***************************************************************************/
903
904 static void unfixtarname(char *tptr, char *fp, int l, bool first)
905 {
906         /* remove '.' from start of file name, convert from unix /'s to
907          * dos \'s in path. Kill any absolute path names. But only if first!
908          */
909
910         DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
911
912         if (first) {
913                 if (*fp == '.') {
914                         fp++;
915                         l--;
916                 }
917                 if (*fp == '\\' || *fp == '/') {
918                         fp++;
919                         l--;
920                 }
921         }
922
923         safe_strcpy(tptr, fp, l);
924         string_replace(tptr, '/', '\\');
925 }
926
927 /****************************************************************************
928 Move to the next block in the buffer, which may mean read in another set of
929 blocks. FIXME, we should allow more than one block to be skipped.
930 ****************************************************************************/
931
932 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
933 {
934         int bufread, total = 0;
935
936         DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
937         *bufferp += TBLOCK;
938         total = TBLOCK;
939
940         if (*bufferp >= (ltarbuf + bufsiz)) {
941
942                 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
943
944                 /*
945                  * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
946                  * Fixes bug where read can return short if coming from
947                  * a pipe.
948                  */
949
950                 bufread = read(tarhandle, ltarbuf, bufsiz);
951                 total = bufread;
952
953                 while (total < bufsiz) {
954                         if (bufread < 0) { /* An error, return false */
955                                 return (total > 0 ? -2 : bufread);
956                         }
957                         if (bufread == 0) {
958                                 if (total <= 0) {
959                                         return -2;
960                                 }
961                                 break;
962                         }
963                         bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
964                         total += bufread;
965                 }
966
967                 DEBUG(5, ("Total bytes read ... %i\n", total));
968
969                 *bufferp = ltarbuf;
970         }
971
972         return(total);
973 }
974
975 /* Skip a file, even if it includes a long file name? */
976 static int skip_file(int skipsize)
977 {
978         int dsize = skipsize;
979
980         DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
981
982         /* FIXME, we should skip more than one block at a time */
983
984         while (dsize > 0) {
985                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
986                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
987                         return(False);
988                 }
989                 dsize -= TBLOCK;
990         }
991
992         return(True);
993 }
994
995 /*************************************************************
996  Get a file from the tar file and store it.
997  When this is called, tarbuf already contains the first
998  file block. This is a bit broken & needs fixing.
999 **************************************************************/
1000
1001 static int get_file(file_info2 finfo)
1002 {
1003         int fnum = -1, pos = 0, dsize = 0, bpos = 0;
1004         SMB_BIG_UINT rsize = 0;
1005
1006         DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1007
1008         if (ensurepath(finfo.name) &&
1009                         (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
1010                 DEBUG(0, ("abandoning restore\n"));
1011                 return(False);
1012         }
1013
1014         /* read the blocks from the tar file and write to the remote file */
1015
1016         rsize = finfo.size;  /* This is how much to write */
1017
1018         while (rsize > 0) {
1019
1020                 /* We can only write up to the end of the buffer */
1021                 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1022                 dsize = MIN(dsize, rsize);  /* Should be only what is left */
1023                 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1024
1025                 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
1026                         DEBUG(0, ("Error writing remote file\n"));
1027                         return 0;
1028                 }
1029
1030                 rsize -= dsize;
1031                 pos += dsize;
1032
1033                 /* Now figure out how much to move in the buffer */
1034
1035                 /* FIXME, we should skip more than one block at a time */
1036
1037                 /* First, skip any initial part of the part written that is left over */
1038                 /* from the end of the first TBLOCK                                   */
1039
1040                 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1041                         dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
1042                         bpos = 0;
1043
1044                         if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
1045                                 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1046                                 return False;
1047                         }
1048                 }
1049
1050                 /*
1051                  * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1052                  * If the file being extracted is an exact multiple of
1053                  * TBLOCK bytes then we don't want to extract the next
1054                  * block from the tarfile here, as it will be done in
1055                  * the caller of get_file().
1056                  */
1057
1058                 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1059                                 ((rsize == 0) && (dsize > TBLOCK))) {
1060
1061                         if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1062                                 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1063                                 return False;
1064                         }
1065
1066                         dsize -= TBLOCK;
1067                 }
1068                 bpos = dsize;
1069         }
1070
1071         /* Now close the file ... */
1072
1073         if (!cli_close(cli, fnum)) {
1074                 DEBUG(0, ("Error closing remote file\n"));
1075                 return(False);
1076         }
1077
1078         /* Now we update the creation date ... */
1079         DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1080
1081         if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec)) {
1082                 if (tar_real_noisy) {
1083                         DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1084                         /*return(False); */ /* Ignore, as Win95 does not allow changes */
1085                 }
1086         }
1087
1088         ntarf++;
1089         DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1090         return(True);
1091 }
1092
1093 /* Create a directory.  We just ensure that the path exists and return as there
1094    is no file associated with a directory
1095 */
1096 static int get_dir(file_info2 finfo)
1097 {
1098         DEBUG(0, ("restore directory %s\n", finfo.name));
1099
1100         if (!ensurepath(finfo.name)) {
1101                 DEBUG(0, ("Problems creating directory\n"));
1102                 return(False);
1103         }
1104         ntarf++;
1105         return(True);
1106 }
1107
1108 /* Get a file with a long file name ... first file has file name, next file 
1109    has the data. We only want the long file name, as the loop in do_tarput
1110    will deal with the rest.
1111 */
1112 static char *get_longfilename(file_info2 finfo)
1113 {
1114         /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1115          * header call. */
1116         int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1117         char *longname = (char *)SMB_MALLOC(namesize);
1118         int offset = 0, left = finfo.size;
1119         bool first = True;
1120
1121         DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1122         DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1123
1124         if (longname == NULL) {
1125                 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1126                 return(NULL);
1127         }
1128
1129         /* First, add cur_dir to the long file name */
1130
1131         if (strlen(client_get_cur_dir()) > 0) {
1132                 strncpy(longname, client_get_cur_dir(), namesize);
1133                 offset = strlen(client_get_cur_dir());
1134         }
1135
1136         /* Loop through the blocks picking up the name */
1137
1138         while (left > 0) {
1139                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1140                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1141                         SAFE_FREE(longname);
1142                         return(NULL);
1143                 }
1144
1145                 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1146                 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1147
1148                 offset += TBLOCK;
1149                 left -= TBLOCK;
1150         }
1151
1152         return(longname);
1153 }
1154
1155 static void do_tarput(void)
1156 {
1157         file_info2 finfo;
1158         struct timeval tp_start;
1159         char *longfilename = NULL, linkflag;
1160         int skip = False;
1161
1162         ZERO_STRUCT(finfo);
1163
1164         GetTimeOfDay(&tp_start);
1165         DEBUG(5, ("RJS do_tarput called ...\n"));
1166
1167         buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1168
1169         /* Now read through those files ... */
1170         while (True) {
1171                 /* Get us to the next block, or the first block first time around */
1172                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1173                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1174                         SAFE_FREE(longfilename);
1175                         return;
1176                 }
1177
1178                 DEBUG(5, ("Reading the next header ...\n"));
1179
1180                 switch (readtarheader((union hblock *) buffer_p,
1181                                         &finfo, client_get_cur_dir())) {
1182                         case -2:    /* Hmm, not good, but not fatal */
1183                                 DEBUG(0, ("Skipping %s...\n", finfo.name));
1184                                 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1185                                         DEBUG(0, ("Short file, bailing out...\n"));
1186                                         return;
1187                                 }
1188                                 break;
1189
1190                         case -1:
1191                                 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1192                                 return;
1193
1194                         case 0: /* chksum is zero - looks like an EOF */
1195                                 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1196                                 return;        /* Hmmm, bad here ... */
1197
1198                         default: 
1199                                 /* No action */
1200                                 break;
1201                 }
1202
1203                 /* Now, do we have a long file name? */
1204                 if (longfilename != NULL) {
1205                         SAFE_FREE(finfo.name);   /* Free the space already allocated */
1206                         finfo.name = longfilename;
1207                         longfilename = NULL;
1208                 }
1209
1210                 /* Well, now we have a header, process the file ...            */
1211                 /* Should we skip the file? We have the long name as well here */
1212                 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1213                                         (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1214
1215                 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1216                 if (skip) {
1217                         skip_file(finfo.size);
1218                         continue;
1219                 }
1220
1221                 /* We only get this far if we should process the file */
1222                 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1223                 switch (linkflag) {
1224                         case '0':  /* Should use symbolic names--FIXME */
1225                                 /*
1226                                  * Skip to the next block first, so we can get the file, FIXME, should
1227                                  * be in get_file ...
1228                                  * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1229                                  * Fixes bug where file size in tarfile is zero.
1230                                  */
1231                                 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1232                                         DEBUG(0, ("Short file, bailing out...\n"));
1233                                         return;
1234                                 }
1235                                 if (!get_file(finfo)) {
1236                                         DEBUG(0, ("Abandoning restore\n"));
1237                                         return;
1238                                 }
1239                                 break;
1240                         case '5':
1241                                 if (!get_dir(finfo)) {
1242                                         DEBUG(0, ("Abandoning restore \n"));
1243                                         return;
1244                                 }
1245                                 break;
1246                         case 'L':
1247                                 SAFE_FREE(longfilename);
1248                                 longfilename = get_longfilename(finfo);
1249                                 if (!longfilename) {
1250                                         DEBUG(0, ("abandoning restore\n"));
1251                                         return;
1252                                 }
1253                                 DEBUG(5, ("Long file name: %s\n", longfilename));
1254                                 break;
1255
1256                         default:
1257                                 skip_file(finfo.size);  /* Don't handle these yet */
1258                                 break;
1259                 }
1260         }
1261 }
1262
1263 /*
1264  * samba interactive commands
1265  */
1266
1267 /****************************************************************************
1268 Blocksize command
1269 ***************************************************************************/
1270
1271 int cmd_block(void)
1272 {
1273         TALLOC_CTX *ctx = talloc_tos();
1274         char *buf;
1275         int block;
1276
1277         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1278                 DEBUG(0, ("blocksize <n>\n"));
1279                 return 1;
1280         }
1281
1282         block=atoi(buf);
1283         if (block < 0 || block > 65535) {
1284                 DEBUG(0, ("blocksize out of range"));
1285                 return 1;
1286         }
1287
1288         blocksize=block;
1289         DEBUG(2,("blocksize is now %d\n", blocksize));
1290         return 0;
1291 }
1292
1293 /****************************************************************************
1294 command to set incremental / reset mode
1295 ***************************************************************************/
1296
1297 int cmd_tarmode(void)
1298 {
1299         TALLOC_CTX *ctx = talloc_tos();
1300         char *buf;
1301
1302         while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1303                 if (strequal(buf, "full"))
1304                         tar_inc=False;
1305                 else if (strequal(buf, "inc"))
1306                         tar_inc=True;
1307                 else if (strequal(buf, "reset"))
1308                         tar_reset=True;
1309                 else if (strequal(buf, "noreset"))
1310                         tar_reset=False;
1311                 else if (strequal(buf, "system"))
1312                         tar_system=True;
1313                 else if (strequal(buf, "nosystem"))
1314                         tar_system=False;
1315                 else if (strequal(buf, "hidden"))
1316                         tar_hidden=True;
1317                 else if (strequal(buf, "nohidden"))
1318                         tar_hidden=False;
1319                 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1320                         tar_noisy=True;
1321                 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1322                         tar_noisy=False;
1323                 else
1324                         DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1325                 TALLOC_FREE(buf);
1326         }
1327
1328         DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1329                         tar_inc ? "incremental" : "full",
1330                         tar_system ? "system" : "nosystem",
1331                         tar_hidden ? "hidden" : "nohidden",
1332                         tar_reset ? "reset" : "noreset",
1333                         tar_noisy ? "verbose" : "quiet"));
1334         return 0;
1335 }
1336
1337 /****************************************************************************
1338 Feeble attrib command
1339 ***************************************************************************/
1340
1341 int cmd_setmode(void)
1342 {
1343         TALLOC_CTX *ctx = talloc_tos();
1344         char *q;
1345         char *buf;
1346         char *fname = NULL;
1347         uint16 attra[2];
1348         int direct=1;
1349
1350         attra[0] = attra[1] = 0;
1351
1352         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1353                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1354                 return 1;
1355         }
1356
1357         fname = talloc_asprintf(ctx,
1358                                 "%s%s",
1359                                 client_get_cur_dir(),
1360                                 buf);
1361         if (!fname) {
1362                 return 1;
1363         }
1364
1365         while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1366                 q=buf;
1367
1368                 while(*q) {
1369                         switch (*q++) {
1370                                 case '+':
1371                                         direct=1;
1372                                         break;
1373                                 case '-':
1374                                         direct=0;
1375                                         break;
1376                                 case 'r':
1377                                         attra[direct]|=aRONLY;
1378                                         break;
1379                                 case 'h':
1380                                         attra[direct]|=aHIDDEN;
1381                                         break;
1382                                 case 's':
1383                                         attra[direct]|=aSYSTEM;
1384                                         break;
1385                                 case 'a':
1386                                         attra[direct]|=aARCH;
1387                                         break;
1388                                 default:
1389                                         DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1390                                         return 1;
1391                         }
1392                 }
1393         }
1394
1395         if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1396                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1397                 return 1;
1398         }
1399
1400         DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1401         do_setrattr(fname, attra[ATTRSET], ATTRSET);
1402         do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1403         return 0;
1404 }
1405
1406 /**
1407  Convert list of tokens to array; dependent on above routine.
1408  Uses the global cmd_ptr from above - bit of a hack.
1409 **/
1410
1411 static char **toktocliplist(int *ctok, const char *sep)
1412 {
1413         char *s=(char *)cmd_ptr;
1414         int ictok=0;
1415         char **ret, **iret;
1416
1417         if (!sep)
1418                 sep = " \t\n\r";
1419
1420         while(*s && strchr_m(sep,*s))
1421                 s++;
1422
1423         /* nothing left? */
1424         if (!*s)
1425                 return(NULL);
1426
1427         do {
1428                 ictok++;
1429                 while(*s && (!strchr_m(sep,*s)))
1430                         s++;
1431                 while(*s && strchr_m(sep,*s))
1432                         *s++=0;
1433         } while(*s);
1434
1435         *ctok=ictok;
1436         s=(char *)cmd_ptr;
1437
1438         if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1439                 return NULL;
1440
1441         while(ictok--) {
1442                 *iret++=s;
1443                 if (ictok > 0) {
1444                         while(*s++)
1445                                 ;
1446                         while(!*s)
1447                                 s++;
1448                 }
1449         }
1450
1451         ret[*ctok] = NULL;
1452         return ret;
1453 }
1454
1455 /****************************************************************************
1456 Principal command for creating / extracting
1457 ***************************************************************************/
1458
1459 int cmd_tar(void)
1460 {
1461         TALLOC_CTX *ctx = talloc_tos();
1462         char *buf;
1463         char **argl = NULL;
1464         int argcl = 0;
1465         int ret;
1466
1467         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1468                 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1469                 return 1;
1470         }
1471
1472         argl=toktocliplist(&argcl, NULL);
1473         if (!tar_parseargs(argcl, argl, buf, 0))
1474                 return 1;
1475
1476         ret = process_tar();
1477         SAFE_FREE(argl);
1478         return ret;
1479 }
1480
1481 /****************************************************************************
1482 Command line (option) version
1483 ***************************************************************************/
1484
1485 int process_tar(void)
1486 {
1487         TALLOC_CTX *ctx = talloc_tos();
1488         int rc = 0;
1489         initarbuf();
1490         switch(tar_type) {
1491                 case 'x':
1492
1493 #if 0
1494                         do_tarput2();
1495 #else
1496                         do_tarput();
1497 #endif
1498                         SAFE_FREE(tarbuf);
1499                         close(tarhandle);
1500                         break;
1501                 case 'r':
1502                 case 'c':
1503                         if (clipn && tar_excl) {
1504                                 int i;
1505                                 char *tarmac = NULL;
1506
1507                                 for (i=0; i<clipn; i++) {
1508                                         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1509
1510                                         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1511                                                 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1512                                         }
1513
1514                                         if (strrchr_m(cliplist[i], '\\')) {
1515                                                 char *p;
1516                                                 char *saved_dir = talloc_strdup(ctx,
1517                                                                         client_get_cur_dir());
1518                                                 if (!saved_dir) {
1519                                                         return 1;
1520                                                 }
1521
1522                                                 if (*cliplist[i]=='\\') {
1523                                                         tarmac = talloc_strdup(ctx,
1524                                                                         cliplist[i]);
1525                                                 } else {
1526                                                         tarmac = talloc_asprintf(ctx,
1527                                                                         "%s%s",
1528                                                                         client_get_cur_dir(),
1529                                                                         cliplist[i]);
1530                                                 }
1531                                                 if (!tarmac) {
1532                                                         return 1;
1533                                                 }
1534                                                 p = strrchr_m(tarmac, '\\');
1535                                                 if (!p) {
1536                                                         return 1;
1537                                                 }
1538                                                 p[1] = '\0';
1539                                                 client_set_cur_dir(tarmac);
1540
1541                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1542                                                 do_list(tarmac,attribute,do_tar, False, True);
1543
1544                                                 client_set_cur_dir(saved_dir);
1545
1546                                                 TALLOC_FREE(saved_dir);
1547                                                 TALLOC_FREE(tarmac);
1548                                         } else {
1549                                                 tarmac = talloc_asprintf(ctx,
1550                                                                 "%s%s",
1551                                                                 client_get_cur_dir(),
1552                                                                 cliplist[i]);
1553                                                 if (!tarmac) {
1554                                                         return 1;
1555                                                 }
1556                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1557                                                 do_list(tarmac,attribute,do_tar, False, True);
1558                                                 TALLOC_FREE(tarmac);
1559                                         }
1560                                 }
1561                         } else {
1562                                 char *mask = talloc_asprintf(ctx,
1563                                                         "%s\\*",
1564                                                         client_get_cur_dir());
1565                                 if (!mask) {
1566                                         return 1;
1567                                 }
1568                                 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1569                                 do_list(mask,attribute,do_tar,False, True);
1570                                 TALLOC_FREE(mask);
1571                         }
1572
1573                         if (ntarf) {
1574                                 dotareof(tarhandle);
1575                         }
1576                         close(tarhandle);
1577                         SAFE_FREE(tarbuf);
1578
1579                         DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1580                         DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1581                         break;
1582         }
1583
1584         if (must_free_cliplist) {
1585                 int i;
1586                 for (i = 0; i < clipn; ++i) {
1587                         SAFE_FREE(cliplist[i]);
1588                 }
1589                 SAFE_FREE(cliplist);
1590                 cliplist = NULL;
1591                 clipn = 0;
1592                 must_free_cliplist = False;
1593         }
1594         return rc;
1595 }
1596
1597 /****************************************************************************
1598 Find a token (filename) in a clip list
1599 ***************************************************************************/
1600
1601 static int clipfind(char **aret, int ret, char *tok)
1602 {
1603         if (aret==NULL)
1604                 return 0;
1605
1606         /* ignore leading slashes or dots in token */
1607         while(strchr_m("/\\.", *tok))
1608                 tok++;
1609
1610         while(ret--) {
1611                 char *pkey=*aret++;
1612
1613                 /* ignore leading slashes or dots in list */
1614                 while(strchr_m("/\\.", *pkey))
1615                         pkey++;
1616
1617                 if (!strslashcmp(pkey, tok))
1618                         return 1;
1619         }
1620         return 0;
1621 }
1622
1623 /****************************************************************************
1624 Read list of files to include from the file and initialize cliplist
1625 accordingly.
1626 ***************************************************************************/
1627
1628 static int read_inclusion_file(char *filename)
1629 {
1630         XFILE *inclusion = NULL;
1631         char buf[PATH_MAX + 1];
1632         char *inclusion_buffer = NULL;
1633         int inclusion_buffer_size = 0;
1634         int inclusion_buffer_sofar = 0;
1635         char *p;
1636         char *tmpstr;
1637         int i;
1638         int error = 0;
1639
1640         clipn = 0;
1641         buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1642         if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1643                 /* XXX It would be better to include a reason for failure, but without
1644                  * autoconf, it's hard to use strerror, sys_errlist, etc.
1645                  */
1646                 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1647                 return 0;
1648         }
1649
1650         while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1651                 if (inclusion_buffer == NULL) {
1652                         inclusion_buffer_size = 1024;
1653                         if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1654                                 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1655                                 error = 1;
1656                                 break;
1657                         }
1658                 }
1659
1660                 if (buf[strlen(buf)-1] == '\n') {
1661                         buf[strlen(buf)-1] = '\0';
1662                 }
1663
1664                 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1665                         inclusion_buffer_size *= 2;
1666                         inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1667                         if (!inclusion_buffer) {
1668                                 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1669                                                 inclusion_buffer_size));
1670                                 error = 1;
1671                                 break;
1672                         }
1673                 }
1674
1675                 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1676                 inclusion_buffer_sofar += strlen(buf) + 1;
1677                 clipn++;
1678         }
1679         x_fclose(inclusion);
1680
1681         if (! error) {
1682                 /* Allocate an array of clipn + 1 char*'s for cliplist */
1683                 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1684                 if (cliplist == NULL) {
1685                         DEBUG(0,("failure allocating memory for cliplist\n"));
1686                         error = 1;
1687                 } else {
1688                         cliplist[clipn] = NULL;
1689                         p = inclusion_buffer;
1690                         for (i = 0; (! error) && (i < clipn); i++) {
1691                                 /* set current item to NULL so array will be null-terminated even if
1692                                                 * malloc fails below. */
1693                                 cliplist[i] = NULL;
1694                                 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1695                                         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1696                                         error = 1;
1697                                 } else {
1698                                         unfixtarname(tmpstr, p, strlen(p) + 1, True);
1699                                         cliplist[i] = tmpstr;
1700                                         if ((p = strchr_m(p, '\000')) == NULL) {
1701                                                 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1702                                                 abort();
1703                                         }
1704                                 }
1705                                 ++p;
1706                         }
1707                         must_free_cliplist = True;
1708                 }
1709         }
1710
1711         SAFE_FREE(inclusion_buffer);
1712         if (error) {
1713                 if (cliplist) {
1714                         char **pp;
1715                         /* We know cliplist is always null-terminated */
1716                         for (pp = cliplist; *pp; ++pp) {
1717                                 SAFE_FREE(*pp);
1718                         }
1719                         SAFE_FREE(cliplist);
1720                         cliplist = NULL;
1721                         must_free_cliplist = False;
1722                 }
1723                 return 0;
1724         }
1725
1726         /* cliplist and its elements are freed at the end of process_tar. */
1727         return 1;
1728 }
1729
1730 /****************************************************************************
1731 Parse tar arguments. Sets tar_type, tar_excl, etc.
1732 ***************************************************************************/
1733
1734 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1735 {
1736         int newOptind = Optind;
1737         char tar_clipfl='\0';
1738
1739         /* Reset back to defaults - could be from interactive version 
1740          * reset mode and archive mode left as they are though
1741          */
1742         tar_type='\0';
1743         tar_excl=True;
1744         dry_run=False;
1745
1746         while (*Optarg) {
1747                 switch(*Optarg++) {
1748                         case 'c':
1749                                 tar_type='c';
1750                                 break;
1751                         case 'x':
1752                                 if (tar_type=='c') {
1753                                         printf("Tar must be followed by only one of c or x.\n");
1754                                         return 0;
1755                                 }
1756                                 tar_type='x';
1757                                 break;
1758                         case 'b':
1759                                 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1760                                         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1761                                         return 0;
1762                                 } else {
1763                                         Optind++;
1764                                         newOptind++;
1765                                 }
1766                                 break;
1767                         case 'g':
1768                                 tar_inc=True;
1769                                 break;
1770                         case 'N':
1771                                 if (Optind>=argc) {
1772                                         DEBUG(0,("Option N must be followed by valid file name\n"));
1773                                         return 0;
1774                                 } else {
1775                                         SMB_STRUCT_STAT stbuf;
1776
1777                                         if (sys_stat(argv[Optind], &stbuf) == 0) {
1778                                                 newer_than = stbuf.st_mtime;
1779                                                 DEBUG(1,("Getting files newer than %s",
1780                                                         time_to_asc(newer_than)));
1781                                                 newOptind++;
1782                                                 Optind++;
1783                                         } else {
1784                                                 DEBUG(0,("Error setting newer-than time\n"));
1785                                                 return 0;
1786                                         }
1787                                 }
1788                                 break;
1789                         case 'a':
1790                                 tar_reset=True;
1791                                 break;
1792                         case 'q':
1793                                 tar_noisy=False;
1794                                 break;
1795                         case 'I':
1796                                 if (tar_clipfl) {
1797                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1798                                         return 0;
1799                                 }
1800                                 tar_clipfl='I';
1801                                 break;
1802                         case 'X':
1803                                 if (tar_clipfl) {
1804                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1805                                         return 0;
1806                                 }
1807                                 tar_clipfl='X';
1808                                 break;
1809                         case 'F':
1810                                 if (tar_clipfl) {
1811                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1812                                         return 0;
1813                                 }
1814                                 tar_clipfl='F';
1815                                 break;
1816                         case 'r':
1817                                 DEBUG(0, ("tar_re_search set\n"));
1818                                 tar_re_search = True;
1819                                 break;
1820                         case 'n':
1821                                 if (tar_type == 'c') {
1822                                         DEBUG(0, ("dry_run set\n"));
1823                                         dry_run = True;
1824                                 } else {
1825                                         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1826                                         return 0;
1827                                 }
1828                                 break;
1829                         default:
1830                                 DEBUG(0,("Unknown tar option\n"));
1831                                 return 0;
1832                 }
1833         }
1834
1835         if (!tar_type) {
1836                 printf("Option T must be followed by one of c or x.\n");
1837                 return 0;
1838         }
1839
1840         /* tar_excl is true if cliplist lists files to be included.
1841          * Both 'I' and 'F' mean include. */
1842         tar_excl=tar_clipfl!='X';
1843
1844         if (tar_clipfl=='F') {
1845                 if (argc-Optind-1 != 1) {
1846                         DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1847                         return 0;
1848                 }
1849                 newOptind++;
1850                 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1851                 if (! read_inclusion_file(argv[Optind+1])) {
1852                         return 0;
1853                 }
1854         } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1855                 char *tmpstr;
1856                 char **tmplist;
1857                 int clipcount;
1858
1859                 cliplist=argv+Optind+1;
1860                 clipn=argc-Optind-1;
1861                 clipcount = clipn;
1862
1863                 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1864                         DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1865                         return 0;
1866                 }
1867
1868                 for (clipcount = 0; clipcount < clipn; clipcount++) {
1869
1870                         DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1871
1872                         if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1873                                 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1874                                 SAFE_FREE(tmplist);
1875                                 return 0;
1876                         }
1877
1878                         unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1879                         tmplist[clipcount] = tmpstr;
1880                         DEBUG(5, ("Processed an item, %s\n", tmpstr));
1881
1882                         DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1883                 }
1884
1885                 cliplist = tmplist;
1886                 must_free_cliplist = True;
1887
1888                 newOptind += clipn;
1889         }
1890
1891         if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1892                 /* Doing regular expression seaches not from an inclusion file. */
1893                 clipn=argc-Optind-1;
1894                 cliplist=argv+Optind+1;
1895                 newOptind += clipn;
1896         }
1897
1898         if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1899                 /* Sets tar handle to either 0 or 1, as appropriate */
1900                 tarhandle=(tar_type=='c');
1901                 /*
1902                  * Make sure that dbf points to stderr if we are using stdout for 
1903                  * tar output
1904                  */
1905                 if (tarhandle == 1)  {
1906                         dbf = x_stderr;
1907                 }
1908                 if (!argv[Optind]) {
1909                         DEBUG(0,("Must specify tar filename\n"));
1910                         return 0;
1911                 }
1912                 if (!strcmp(argv[Optind], "-")) {
1913                         newOptind++;
1914                 }
1915
1916         } else {
1917                 if (tar_type=='c' && dry_run) {
1918                         tarhandle=-1;
1919                 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1920                                         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1921                         DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1922                         return(0);
1923                 }
1924                 newOptind++;
1925         }
1926
1927         return newOptind;
1928 }