s3: Move the global variable Protocol to struct smbd_server_connection
[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 extern const char *cmd_ptr;
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, uint64_t 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(uint64_t 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, uint64_t 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((uint64_t)0, 8, hb.dbuf.uid);
199         oct_it((uint64_t)0, 8, hb.dbuf.gid);
200         oct_it((uint64_t) size, 13, hb.dbuf.size);
201         if (size > (uint64_t)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((uint64_t) 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((uint64_t) 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+sys_write(f, tarbuf, tbufsiz));
333                 n-=diff;
334                 b+=diff;
335                 tp=0;
336
337                 while (n >= tbufsiz) {
338                         fail=fail && (1 + sys_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                 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
368                         DEBUG(0, ("dozerobuf: sys_write fail\n"));
369                         return;
370                 }
371                 memset(tarbuf, 0, (tp+=n-tbufsiz));
372         } else {
373                 memset(tarbuf+tp, 0, n);
374                 tp+=n;
375         }
376 }
377
378 /****************************************************************************
379 Malloc tape buffer
380 ****************************************************************************/
381
382 static void initarbuf(void)
383 {
384         /* initialize tar buffer */
385         tbufsiz=blocksize*TBLOCK;
386         tarbuf=(char *)SMB_MALLOC(tbufsiz);      /* FIXME: We might not get the buffer */
387
388         /* reset tar buffer pointer and tar file counter and total dumped */
389         tp=0; ntarf=0; ttarf=0;
390 }
391
392 /****************************************************************************
393 Write two zero blocks at end of file
394 ****************************************************************************/
395
396 static void dotareof(int f)
397 {
398         SMB_STRUCT_STAT stbuf;
399         /* Two zero blocks at end of file, write out full buffer */
400
401         if (dry_run)
402                 return;
403
404         (void) dozerobuf(f, TBLOCK);
405         (void) dozerobuf(f, TBLOCK);
406
407         if (sys_fstat(f, &stbuf) == -1) {
408                 DEBUG(0, ("Couldn't stat file handle\n"));
409                 return;
410         }
411
412         /* Could be a pipe, in which case S_ISREG should fail,
413                 * and we should write out at full size */
414         if (tp > 0) {
415                 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
416                 if (sys_write(f, tarbuf, towrite) != towrite) {
417                         DEBUG(0,("dotareof: sys_write fail\n"));
418                 }
419         }
420 }
421
422 /****************************************************************************
423 (Un)mangle DOS pathname, make nonabsolute
424 ****************************************************************************/
425
426 static void fixtarname(char *tptr, const char *fp, size_t l)
427 {
428         /* add a '.' to start of file name, convert from ugly dos \'s in path
429          * to lovely unix /'s :-} */
430         *tptr++='.';
431         l--;
432
433         StrnCpy(tptr, fp, l-1);
434         string_replace(tptr, '\\', '/');
435 }
436
437 /****************************************************************************
438 Convert from decimal to octal string
439 ****************************************************************************/
440
441 static void oct_it (uint64_t value, int ndgs, char *p)
442 {
443         /* Converts long to octal string, pads with leading zeros */
444
445         /* skip final null, but do final space */
446         --ndgs;
447         p[--ndgs] = ' ';
448
449         /* Loop does at least one digit */
450         do {
451                 p[--ndgs] = '0' + (char) (value & 7);
452                 value >>= 3;
453         } while (ndgs > 0 && value != 0);
454
455         /* Do leading zeros */
456         while (ndgs > 0)
457                 p[--ndgs] = '0';
458 }
459
460 /****************************************************************************
461 Convert from octal string to long
462 ***************************************************************************/
463
464 static long unoct(char *p, int ndgs)
465 {
466         long value=0;
467         /* Converts octal string to long, ignoring any non-digit */
468
469         while (--ndgs) {
470                 if (isdigit((int)*p))
471                         value = (value << 3) | (long) (*p - '0');
472
473                 p++;
474         }
475
476         return value;
477 }
478
479 /****************************************************************************
480 Compare two strings in a slash insensitive way, allowing s1 to match s2
481 if s1 is an "initial" string (up to directory marker).  Thus, if s2 is
482 a file in any subdirectory of s1, declare a match.
483 ***************************************************************************/
484
485 static int strslashcmp(char *s1, char *s2)
486 {
487         char *s1_0=s1;
488
489         while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
490                                 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
491                 s1++; s2++;
492         }
493
494         /* if s1 has a trailing slash, it compared equal, so s1 is an "initial" 
495                 string of s2.
496         */
497         if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
498                 return 0;
499
500         /* ignore trailing slash on s1 */
501         if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
502                 return 0;
503
504         /* check for s1 is an "initial" string of s2 */
505         if ((*s2 == '/' || *s2 == '\\') && !*s1)
506                 return 0;
507
508         return *s1-*s2;
509 }
510
511 /****************************************************************************
512 Ensure a remote path exists (make if necessary)
513 ***************************************************************************/
514
515 static bool ensurepath(const char *fname)
516 {
517         /* *must* be called with buffer ready malloc'ed */
518         /* ensures path exists */
519
520         char *partpath, *ffname;
521         const char *p=fname;
522         char *basehack;
523         char *saveptr;
524
525         DEBUG(5, ( "Ensurepath called with: %s\n", fname));
526
527         partpath = string_create_s(strlen(fname));
528         ffname = string_create_s(strlen(fname));
529
530         if ((partpath == NULL) || (ffname == NULL)){
531                 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
532                 SAFE_FREE(partpath);
533                 SAFE_FREE(ffname);
534                 return(False);
535         }
536
537         *partpath = 0;
538
539         /* fname copied to ffname so can strtok_r */
540
541         safe_strcpy(ffname, fname, strlen(fname));
542
543         /* do a `basename' on ffname, so don't try and make file name directory */
544         if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
545                 SAFE_FREE(partpath);
546                 SAFE_FREE(ffname);
547                 return True;
548         } else {
549                 *basehack='\0';
550         }
551
552         p=strtok_r(ffname, "\\", &saveptr);
553
554         while (p) {
555                 safe_strcat(partpath, p, strlen(fname) + 1);
556
557                 if (!NT_STATUS_IS_OK(cli_chkpath(cli, partpath))) {
558                         if (!NT_STATUS_IS_OK(cli_mkdir(cli, partpath))) {
559                                 SAFE_FREE(partpath);
560                                 SAFE_FREE(ffname);
561                                 DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
562                                 return False;
563                         } else {
564                                 DEBUG(3, ("mkdirhiering %s\n", partpath));
565                         }
566                 }
567
568                 safe_strcat(partpath, "\\", strlen(fname) + 1);
569                 p = strtok_r(NULL, "/\\", &saveptr);
570         }
571
572         SAFE_FREE(partpath);
573         SAFE_FREE(ffname);
574         return True;
575 }
576
577 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
578 {
579         int berr= 0;
580         int bytestowrite;
581
582         DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
583         memset(buf, 0, (size_t)bufsize);
584         while( !berr && padsize > 0 ) {
585                 bytestowrite= (int)MIN(bufsize, padsize);
586                 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
587                 padsize -= bytestowrite;
588         }
589
590         return berr;
591 }
592
593 static void do_setrattr(char *name, uint16 attr, int set)
594 {
595         uint16 oldattr;
596
597         if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
598                 return;
599         }
600
601         if (set == ATTRSET) {
602                 attr |= oldattr;
603         } else {
604                 attr = oldattr & ~attr;
605         }
606
607         if (!NT_STATUS_IS_OK(cli_setatr(cli, name, attr, 0))) {
608                 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
609         }
610 }
611
612 /****************************************************************************
613 append one remote file to the tar file
614 ***************************************************************************/
615
616 static void do_atar(const char *rname_in,char *lname,file_info *finfo1)
617 {
618         uint16_t fnum = (uint16_t)-1;
619         uint64_t nread=0;
620         char ftype;
621         file_info2 finfo;
622         bool shallitime=True;
623         char *data = NULL;
624         int read_size = 65520;
625         int datalen=0;
626         char *rname = NULL;
627         TALLOC_CTX *ctx = talloc_stackframe();
628
629         struct timeval tp_start;
630
631         GetTimeOfDay(&tp_start);
632
633         data = SMB_MALLOC_ARRAY(char, read_size);
634         if (!data) {
635                 DEBUG(0,("do_atar: out of memory.\n"));
636                 goto cleanup;
637         }
638
639         ftype = '0'; /* An ordinary file ... */
640
641         ZERO_STRUCT(finfo);
642
643         finfo.size  = finfo1 -> size;
644         finfo.mode  = finfo1 -> mode;
645         finfo.uid   = finfo1 -> uid;
646         finfo.gid   = finfo1 -> gid;
647         finfo.mtime_ts = finfo1 -> mtime_ts;
648         finfo.atime_ts = finfo1 -> atime_ts;
649         finfo.ctime_ts = finfo1 -> ctime_ts;
650
651         if (dry_run) {
652                 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
653                                 (double)finfo.size));
654                 shallitime=0;
655                 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
656                 ntarf++;
657                 goto cleanup;
658         }
659
660         rname = clean_name(ctx, rname_in);
661         if (!rname) {
662                 goto cleanup;
663         }
664
665         if (!NT_STATUS_IS_OK(cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum))) {
666                 DEBUG(0,("%s opening remote file %s (%s)\n",
667                                 cli_errstr(cli),rname, client_get_cur_dir()));
668                 goto cleanup;
669         }
670
671         finfo.name = string_create_s(strlen(rname));
672         if (finfo.name == NULL) {
673                 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
674                 goto cleanup;
675         }
676
677         safe_strcpy(finfo.name,rname, strlen(rname));
678
679         DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
680
681         if (tar_inc && !(finfo.mode & aARCH)) {
682                 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
683                 shallitime=0;
684         } else if (!tar_system && (finfo.mode & aSYSTEM)) {
685                 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
686                 shallitime=0;
687         } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
688                 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
689                 shallitime=0;
690         } else {
691                 bool wrote_tar_header = False;
692
693                 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
694                         finfo.name, (double)finfo.size, lname));
695
696                 do {
697
698                         DEBUG(3,("nread=%.0f\n",(double)nread));
699
700                         datalen = cli_read(cli, fnum, data, nread, read_size);
701
702                         if (datalen == -1) {
703                                 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
704                                 break;
705                         }
706
707                         nread += datalen;
708
709                         /* Only if the first read succeeds, write out the tar header. */
710                         if (!wrote_tar_header) {
711                                 /* write a tar header, don't bother with mode - just set to 100644 */
712                                 writetarheader(tarhandle, rname, finfo.size,
713                                         finfo.mtime_ts.tv_sec, "100644 \0", ftype);
714                                 wrote_tar_header = True;
715                         }
716
717                         /* if file size has increased since we made file size query, truncate
718                                 read so tar header for this file will be correct.
719                         */
720
721                         if (nread > finfo.size) {
722                                 datalen -= nread - finfo.size;
723                                 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
724                                                         finfo.name, (double)finfo.size));
725                         }
726
727                         /* add received bits of file to buffer - dotarbuf will
728                         * write out in 512 byte intervals */
729
730                         if (dotarbuf(tarhandle,data,datalen) != datalen) {
731                                 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
732                                 break;
733                         }
734
735                         if ( (datalen == 0) && (finfo.size != 0) ) {
736                                 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
737                                 break;
738                         }
739
740                         datalen=0;
741                 } while ( nread < finfo.size );
742
743                 if (wrote_tar_header) {
744                         /* pad tar file with zero's if we couldn't get entire file */
745                         if (nread < finfo.size) {
746                                 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
747                                                         (double)finfo.size, (int)nread));
748                                 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread))
749                                         DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
750                         }
751
752                         /* round tar file to nearest block */
753                         if (finfo.size % TBLOCK)
754                                 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
755
756                         ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
757                         ntarf++;
758                 } else {
759                         DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
760                         shallitime=0;
761                 }
762         }
763
764         cli_close(cli, fnum);
765         fnum = -1;
766
767         if (shallitime) {
768                 struct timeval tp_end;
769                 int this_time;
770
771                 /* if shallitime is true then we didn't skip */
772                 if (tar_reset && !dry_run)
773                         (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
774
775                 GetTimeOfDay(&tp_end);
776                 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
777                 get_total_time_ms += this_time;
778                 get_total_size += finfo.size;
779
780                 if (tar_noisy) {
781                         DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
782                                 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
783                                 finfo.name));
784                 }
785
786                 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
787                 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
788                                 finfo.size / MAX(0.001, (1.024*this_time)),
789                                 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
790         }
791
792   cleanup:
793
794         if (fnum != (uint16_t)-1) {
795                 cli_close(cli, fnum);
796                 fnum = -1;
797         }
798         TALLOC_FREE(ctx);
799         SAFE_FREE(data);
800 }
801
802 /****************************************************************************
803 Append single file to tar file (or not)
804 ***************************************************************************/
805
806 static void do_tar(file_info *finfo, const char *dir)
807 {
808         TALLOC_CTX *ctx = talloc_stackframe();
809
810         if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
811                 return;
812
813         /* Is it on the exclude list ? */
814         if (!tar_excl && clipn) {
815                 char *exclaim;
816
817                 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
818
819                 exclaim = talloc_asprintf(ctx,
820                                 "%s\\%s",
821                                 client_get_cur_dir(),
822                                 finfo->name);
823                 if (!exclaim) {
824                         return;
825                 }
826
827                 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
828
829                 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
830                     (tar_re_search
831                      && mask_match_list(exclaim, cliplist, clipn,
832                                         PROTOCOL_NONE, 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         uint16_t fnum;
1004         int pos = 0, dsize = 0, bpos = 0;
1005         uint64_t rsize = 0;
1006
1007         DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1008
1009         if (ensurepath(finfo.name) &&
1010                         (!NT_STATUS_IS_OK(cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE,&fnum)))) {
1011                 DEBUG(0, ("abandoning restore\n"));
1012                 return(False);
1013         }
1014
1015         /* read the blocks from the tar file and write to the remote file */
1016
1017         rsize = finfo.size;  /* This is how much to write */
1018
1019         while (rsize > 0) {
1020
1021                 /* We can only write up to the end of the buffer */
1022                 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1023                 dsize = MIN(dsize, rsize);  /* Should be only what is left */
1024                 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1025
1026                 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
1027                         DEBUG(0, ("Error writing remote file\n"));
1028                         return 0;
1029                 }
1030
1031                 rsize -= dsize;
1032                 pos += dsize;
1033
1034                 /* Now figure out how much to move in the buffer */
1035
1036                 /* FIXME, we should skip more than one block at a time */
1037
1038                 /* First, skip any initial part of the part written that is left over */
1039                 /* from the end of the first TBLOCK                                   */
1040
1041                 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1042                         dsize -= (TBLOCK - bpos);  /* Get rid of the end of the first block */
1043                         bpos = 0;
1044
1045                         if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {  /* and skip the block */
1046                                 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1047                                 return False;
1048                         }
1049                 }
1050
1051                 /*
1052                  * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1053                  * If the file being extracted is an exact multiple of
1054                  * TBLOCK bytes then we don't want to extract the next
1055                  * block from the tarfile here, as it will be done in
1056                  * the caller of get_file().
1057                  */
1058
1059                 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1060                                 ((rsize == 0) && (dsize > TBLOCK))) {
1061
1062                         if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1063                                 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1064                                 return False;
1065                         }
1066
1067                         dsize -= TBLOCK;
1068                 }
1069                 bpos = dsize;
1070         }
1071
1072         /* Now close the file ... */
1073
1074         if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
1075                 DEBUG(0, ("Error %s closing remote file\n",
1076                         cli_errstr(cli)));
1077                 return(False);
1078         }
1079
1080         /* Now we update the creation date ... */
1081         DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1082
1083         if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1084                 if (tar_real_noisy) {
1085                         DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1086                         /*return(False); */ /* Ignore, as Win95 does not allow changes */
1087                 }
1088         }
1089
1090         ntarf++;
1091         DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1092         return(True);
1093 }
1094
1095 /* Create a directory.  We just ensure that the path exists and return as there
1096    is no file associated with a directory
1097 */
1098 static int get_dir(file_info2 finfo)
1099 {
1100         DEBUG(0, ("restore directory %s\n", finfo.name));
1101
1102         if (!ensurepath(finfo.name)) {
1103                 DEBUG(0, ("Problems creating directory\n"));
1104                 return(False);
1105         }
1106         ntarf++;
1107         return(True);
1108 }
1109
1110 /* Get a file with a long file name ... first file has file name, next file 
1111    has the data. We only want the long file name, as the loop in do_tarput
1112    will deal with the rest.
1113 */
1114 static char *get_longfilename(file_info2 finfo)
1115 {
1116         /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1117          * header call. */
1118         int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1119         char *longname = (char *)SMB_MALLOC(namesize);
1120         int offset = 0, left = finfo.size;
1121         bool first = True;
1122
1123         DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1124         DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1125
1126         if (longname == NULL) {
1127                 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1128                 return(NULL);
1129         }
1130
1131         /* First, add cur_dir to the long file name */
1132
1133         if (strlen(client_get_cur_dir()) > 0) {
1134                 strncpy(longname, client_get_cur_dir(), namesize);
1135                 offset = strlen(client_get_cur_dir());
1136         }
1137
1138         /* Loop through the blocks picking up the name */
1139
1140         while (left > 0) {
1141                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1142                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1143                         SAFE_FREE(longname);
1144                         return(NULL);
1145                 }
1146
1147                 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1148                 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1149
1150                 offset += TBLOCK;
1151                 left -= TBLOCK;
1152         }
1153
1154         return(longname);
1155 }
1156
1157 static void do_tarput(void)
1158 {
1159         file_info2 finfo;
1160         struct timeval tp_start;
1161         char *longfilename = NULL, linkflag;
1162         int skip = False;
1163
1164         ZERO_STRUCT(finfo);
1165
1166         GetTimeOfDay(&tp_start);
1167         DEBUG(5, ("RJS do_tarput called ...\n"));
1168
1169         buffer_p = tarbuf + tbufsiz;  /* init this to force first read */
1170
1171         /* Now read through those files ... */
1172         while (True) {
1173                 /* Get us to the next block, or the first block first time around */
1174                 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1175                         DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1176                         SAFE_FREE(longfilename);
1177                         return;
1178                 }
1179
1180                 DEBUG(5, ("Reading the next header ...\n"));
1181
1182                 switch (readtarheader((union hblock *) buffer_p,
1183                                         &finfo, client_get_cur_dir())) {
1184                         case -2:    /* Hmm, not good, but not fatal */
1185                                 DEBUG(0, ("Skipping %s...\n", finfo.name));
1186                                 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1187                                         DEBUG(0, ("Short file, bailing out...\n"));
1188                                         return;
1189                                 }
1190                                 break;
1191
1192                         case -1:
1193                                 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1194                                 return;
1195
1196                         case 0: /* chksum is zero - looks like an EOF */
1197                                 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1198                                 return;        /* Hmmm, bad here ... */
1199
1200                         default: 
1201                                 /* No action */
1202                                 break;
1203                 }
1204
1205                 /* Now, do we have a long file name? */
1206                 if (longfilename != NULL) {
1207                         SAFE_FREE(finfo.name);   /* Free the space already allocated */
1208                         finfo.name = longfilename;
1209                         longfilename = NULL;
1210                 }
1211
1212                 /* Well, now we have a header, process the file ...            */
1213                 /* Should we skip the file? We have the long name as well here */
1214                 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1215                                  (tar_re_search
1216                                   && mask_match_list(finfo.name, cliplist,
1217                                                      clipn, PROTOCOL_NONE,
1218                                                      True)));
1219
1220                 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1221                 if (skip) {
1222                         skip_file(finfo.size);
1223                         continue;
1224                 }
1225
1226                 /* We only get this far if we should process the file */
1227                 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1228                 switch (linkflag) {
1229                         case '0':  /* Should use symbolic names--FIXME */
1230                                 /*
1231                                  * Skip to the next block first, so we can get the file, FIXME, should
1232                                  * be in get_file ...
1233                                  * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1234                                  * Fixes bug where file size in tarfile is zero.
1235                                  */
1236                                 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1237                                         DEBUG(0, ("Short file, bailing out...\n"));
1238                                         return;
1239                                 }
1240                                 if (!get_file(finfo)) {
1241                                         DEBUG(0, ("Abandoning restore\n"));
1242                                         return;
1243                                 }
1244                                 break;
1245                         case '5':
1246                                 if (!get_dir(finfo)) {
1247                                         DEBUG(0, ("Abandoning restore \n"));
1248                                         return;
1249                                 }
1250                                 break;
1251                         case 'L':
1252                                 SAFE_FREE(longfilename);
1253                                 longfilename = get_longfilename(finfo);
1254                                 if (!longfilename) {
1255                                         DEBUG(0, ("abandoning restore\n"));
1256                                         return;
1257                                 }
1258                                 DEBUG(5, ("Long file name: %s\n", longfilename));
1259                                 break;
1260
1261                         default:
1262                                 skip_file(finfo.size);  /* Don't handle these yet */
1263                                 break;
1264                 }
1265         }
1266 }
1267
1268 /*
1269  * samba interactive commands
1270  */
1271
1272 /****************************************************************************
1273 Blocksize command
1274 ***************************************************************************/
1275
1276 int cmd_block(void)
1277 {
1278         TALLOC_CTX *ctx = talloc_tos();
1279         char *buf;
1280         int block;
1281
1282         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1283                 DEBUG(0, ("blocksize <n>\n"));
1284                 return 1;
1285         }
1286
1287         block=atoi(buf);
1288         if (block < 0 || block > 65535) {
1289                 DEBUG(0, ("blocksize out of range"));
1290                 return 1;
1291         }
1292
1293         blocksize=block;
1294         DEBUG(2,("blocksize is now %d\n", blocksize));
1295         return 0;
1296 }
1297
1298 /****************************************************************************
1299 command to set incremental / reset mode
1300 ***************************************************************************/
1301
1302 int cmd_tarmode(void)
1303 {
1304         TALLOC_CTX *ctx = talloc_tos();
1305         char *buf;
1306
1307         while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1308                 if (strequal(buf, "full"))
1309                         tar_inc=False;
1310                 else if (strequal(buf, "inc"))
1311                         tar_inc=True;
1312                 else if (strequal(buf, "reset"))
1313                         tar_reset=True;
1314                 else if (strequal(buf, "noreset"))
1315                         tar_reset=False;
1316                 else if (strequal(buf, "system"))
1317                         tar_system=True;
1318                 else if (strequal(buf, "nosystem"))
1319                         tar_system=False;
1320                 else if (strequal(buf, "hidden"))
1321                         tar_hidden=True;
1322                 else if (strequal(buf, "nohidden"))
1323                         tar_hidden=False;
1324                 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1325                         tar_noisy=True;
1326                 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1327                         tar_noisy=False;
1328                 else
1329                         DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1330                 TALLOC_FREE(buf);
1331         }
1332
1333         DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1334                         tar_inc ? "incremental" : "full",
1335                         tar_system ? "system" : "nosystem",
1336                         tar_hidden ? "hidden" : "nohidden",
1337                         tar_reset ? "reset" : "noreset",
1338                         tar_noisy ? "verbose" : "quiet"));
1339         return 0;
1340 }
1341
1342 /****************************************************************************
1343 Feeble attrib command
1344 ***************************************************************************/
1345
1346 int cmd_setmode(void)
1347 {
1348         TALLOC_CTX *ctx = talloc_tos();
1349         char *q;
1350         char *buf;
1351         char *fname = NULL;
1352         uint16 attra[2];
1353         int direct=1;
1354
1355         attra[0] = attra[1] = 0;
1356
1357         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1358                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1359                 return 1;
1360         }
1361
1362         fname = talloc_asprintf(ctx,
1363                                 "%s%s",
1364                                 client_get_cur_dir(),
1365                                 buf);
1366         if (!fname) {
1367                 return 1;
1368         }
1369
1370         while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1371                 q=buf;
1372
1373                 while(*q) {
1374                         switch (*q++) {
1375                                 case '+':
1376                                         direct=1;
1377                                         break;
1378                                 case '-':
1379                                         direct=0;
1380                                         break;
1381                                 case 'r':
1382                                         attra[direct]|=aRONLY;
1383                                         break;
1384                                 case 'h':
1385                                         attra[direct]|=aHIDDEN;
1386                                         break;
1387                                 case 's':
1388                                         attra[direct]|=aSYSTEM;
1389                                         break;
1390                                 case 'a':
1391                                         attra[direct]|=aARCH;
1392                                         break;
1393                                 default:
1394                                         DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1395                                         return 1;
1396                         }
1397                 }
1398         }
1399
1400         if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1401                 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1402                 return 1;
1403         }
1404
1405         DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1406         do_setrattr(fname, attra[ATTRSET], ATTRSET);
1407         do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1408         return 0;
1409 }
1410
1411 /**
1412  Convert list of tokens to array; dependent on above routine.
1413  Uses the global cmd_ptr from above - bit of a hack.
1414 **/
1415
1416 static char **toktocliplist(int *ctok, const char *sep)
1417 {
1418         char *s=(char *)cmd_ptr;
1419         int ictok=0;
1420         char **ret, **iret;
1421
1422         if (!sep)
1423                 sep = " \t\n\r";
1424
1425         while(*s && strchr_m(sep,*s))
1426                 s++;
1427
1428         /* nothing left? */
1429         if (!*s)
1430                 return(NULL);
1431
1432         do {
1433                 ictok++;
1434                 while(*s && (!strchr_m(sep,*s)))
1435                         s++;
1436                 while(*s && strchr_m(sep,*s))
1437                         *s++=0;
1438         } while(*s);
1439
1440         *ctok=ictok;
1441         s=(char *)cmd_ptr;
1442
1443         if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1444                 return NULL;
1445
1446         while(ictok--) {
1447                 *iret++=s;
1448                 if (ictok > 0) {
1449                         while(*s++)
1450                                 ;
1451                         while(!*s)
1452                                 s++;
1453                 }
1454         }
1455
1456         ret[*ctok] = NULL;
1457         return ret;
1458 }
1459
1460 /****************************************************************************
1461 Principal command for creating / extracting
1462 ***************************************************************************/
1463
1464 int cmd_tar(void)
1465 {
1466         TALLOC_CTX *ctx = talloc_tos();
1467         char *buf;
1468         char **argl = NULL;
1469         int argcl = 0;
1470         int ret;
1471
1472         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1473                 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1474                 return 1;
1475         }
1476
1477         argl=toktocliplist(&argcl, NULL);
1478         if (!tar_parseargs(argcl, argl, buf, 0)) {
1479                 SAFE_FREE(argl);
1480                 return 1;
1481         }
1482
1483         ret = process_tar();
1484         SAFE_FREE(argl);
1485         return ret;
1486 }
1487
1488 /****************************************************************************
1489 Command line (option) version
1490 ***************************************************************************/
1491
1492 int process_tar(void)
1493 {
1494         TALLOC_CTX *ctx = talloc_tos();
1495         int rc = 0;
1496         initarbuf();
1497         switch(tar_type) {
1498                 case 'x':
1499
1500 #if 0
1501                         do_tarput2();
1502 #else
1503                         do_tarput();
1504 #endif
1505                         SAFE_FREE(tarbuf);
1506                         close(tarhandle);
1507                         break;
1508                 case 'r':
1509                 case 'c':
1510                         if (clipn && tar_excl) {
1511                                 int i;
1512                                 char *tarmac = NULL;
1513
1514                                 for (i=0; i<clipn; i++) {
1515                                         DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1516
1517                                         if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1518                                                 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1519                                         }
1520
1521                                         if (strrchr_m(cliplist[i], '\\')) {
1522                                                 char *p;
1523                                                 char saved_char;
1524                                                 char *saved_dir = talloc_strdup(ctx,
1525                                                                         client_get_cur_dir());
1526                                                 if (!saved_dir) {
1527                                                         return 1;
1528                                                 }
1529
1530                                                 if (*cliplist[i]=='\\') {
1531                                                         tarmac = talloc_strdup(ctx,
1532                                                                         cliplist[i]);
1533                                                 } else {
1534                                                         tarmac = talloc_asprintf(ctx,
1535                                                                         "%s%s",
1536                                                                         client_get_cur_dir(),
1537                                                                         cliplist[i]);
1538                                                 }
1539                                                 if (!tarmac) {
1540                                                         return 1;
1541                                                 }
1542                                                 /*
1543                                                  * Strip off the last \\xxx
1544                                                  * xxx element of tarmac to set
1545                                                  * it as current directory.
1546                                                  */
1547                                                 p = strrchr_m(tarmac, '\\');
1548                                                 if (!p) {
1549                                                         return 1;
1550                                                 }
1551                                                 saved_char = p[1];
1552                                                 p[1] = '\0';
1553
1554                                                 client_set_cur_dir(tarmac);
1555
1556                                                 /*
1557                                                  * Restore the character we
1558                                                  * just replaced to
1559                                                  * put the pathname
1560                                                  * back as it was.
1561                                                  */
1562                                                 p[1] = saved_char;
1563
1564                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1565                                                 do_list(tarmac,attribute,do_tar, False, True);
1566
1567                                                 client_set_cur_dir(saved_dir);
1568
1569                                                 TALLOC_FREE(saved_dir);
1570                                                 TALLOC_FREE(tarmac);
1571                                         } else {
1572                                                 tarmac = talloc_asprintf(ctx,
1573                                                                 "%s%s",
1574                                                                 client_get_cur_dir(),
1575                                                                 cliplist[i]);
1576                                                 if (!tarmac) {
1577                                                         return 1;
1578                                                 }
1579                                                 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1580                                                 do_list(tarmac,attribute,do_tar, False, True);
1581                                                 TALLOC_FREE(tarmac);
1582                                         }
1583                                 }
1584                         } else {
1585                                 char *mask = talloc_asprintf(ctx,
1586                                                         "%s\\*",
1587                                                         client_get_cur_dir());
1588                                 if (!mask) {
1589                                         return 1;
1590                                 }
1591                                 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1592                                 do_list(mask,attribute,do_tar,False, True);
1593                                 TALLOC_FREE(mask);
1594                         }
1595
1596                         if (ntarf) {
1597                                 dotareof(tarhandle);
1598                         }
1599                         close(tarhandle);
1600                         SAFE_FREE(tarbuf);
1601
1602                         DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1603                         DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1604                         break;
1605         }
1606
1607         if (must_free_cliplist) {
1608                 int i;
1609                 for (i = 0; i < clipn; ++i) {
1610                         SAFE_FREE(cliplist[i]);
1611                 }
1612                 SAFE_FREE(cliplist);
1613                 cliplist = NULL;
1614                 clipn = 0;
1615                 must_free_cliplist = False;
1616         }
1617         return rc;
1618 }
1619
1620 /****************************************************************************
1621 Find a token (filename) in a clip list
1622 ***************************************************************************/
1623
1624 static int clipfind(char **aret, int ret, char *tok)
1625 {
1626         if (aret==NULL)
1627                 return 0;
1628
1629         /* ignore leading slashes or dots in token */
1630         while(strchr_m("/\\.", *tok))
1631                 tok++;
1632
1633         while(ret--) {
1634                 char *pkey=*aret++;
1635
1636                 /* ignore leading slashes or dots in list */
1637                 while(strchr_m("/\\.", *pkey))
1638                         pkey++;
1639
1640                 if (!strslashcmp(pkey, tok))
1641                         return 1;
1642         }
1643         return 0;
1644 }
1645
1646 /****************************************************************************
1647 Read list of files to include from the file and initialize cliplist
1648 accordingly.
1649 ***************************************************************************/
1650
1651 static int read_inclusion_file(char *filename)
1652 {
1653         XFILE *inclusion = NULL;
1654         char buf[PATH_MAX + 1];
1655         char *inclusion_buffer = NULL;
1656         int inclusion_buffer_size = 0;
1657         int inclusion_buffer_sofar = 0;
1658         char *p;
1659         char *tmpstr;
1660         int i;
1661         int error = 0;
1662
1663         clipn = 0;
1664         buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1665         if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1666                 /* XXX It would be better to include a reason for failure, but without
1667                  * autoconf, it's hard to use strerror, sys_errlist, etc.
1668                  */
1669                 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1670                 return 0;
1671         }
1672
1673         while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1674                 if (inclusion_buffer == NULL) {
1675                         inclusion_buffer_size = 1024;
1676                         if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1677                                 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1678                                 error = 1;
1679                                 break;
1680                         }
1681                 }
1682
1683                 if (buf[strlen(buf)-1] == '\n') {
1684                         buf[strlen(buf)-1] = '\0';
1685                 }
1686
1687                 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1688                         inclusion_buffer_size *= 2;
1689                         inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1690                         if (!inclusion_buffer) {
1691                                 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1692                                                 inclusion_buffer_size));
1693                                 error = 1;
1694                                 break;
1695                         }
1696                 }
1697
1698                 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1699                 inclusion_buffer_sofar += strlen(buf) + 1;
1700                 clipn++;
1701         }
1702         x_fclose(inclusion);
1703
1704         if (! error) {
1705                 /* Allocate an array of clipn + 1 char*'s for cliplist */
1706                 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1707                 if (cliplist == NULL) {
1708                         DEBUG(0,("failure allocating memory for cliplist\n"));
1709                         error = 1;
1710                 } else {
1711                         cliplist[clipn] = NULL;
1712                         p = inclusion_buffer;
1713                         for (i = 0; (! error) && (i < clipn); i++) {
1714                                 /* set current item to NULL so array will be null-terminated even if
1715                                                 * malloc fails below. */
1716                                 cliplist[i] = NULL;
1717                                 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1718                                         DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1719                                         error = 1;
1720                                 } else {
1721                                         unfixtarname(tmpstr, p, strlen(p) + 1, True);
1722                                         cliplist[i] = tmpstr;
1723                                         if ((p = strchr_m(p, '\000')) == NULL) {
1724                                                 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1725                                                 abort();
1726                                         }
1727                                 }
1728                                 ++p;
1729                         }
1730                         must_free_cliplist = True;
1731                 }
1732         }
1733
1734         SAFE_FREE(inclusion_buffer);
1735         if (error) {
1736                 if (cliplist) {
1737                         char **pp;
1738                         /* We know cliplist is always null-terminated */
1739                         for (pp = cliplist; *pp; ++pp) {
1740                                 SAFE_FREE(*pp);
1741                         }
1742                         SAFE_FREE(cliplist);
1743                         cliplist = NULL;
1744                         must_free_cliplist = False;
1745                 }
1746                 return 0;
1747         }
1748
1749         /* cliplist and its elements are freed at the end of process_tar. */
1750         return 1;
1751 }
1752
1753 /****************************************************************************
1754 Parse tar arguments. Sets tar_type, tar_excl, etc.
1755 ***************************************************************************/
1756
1757 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1758 {
1759         int newOptind = Optind;
1760         char tar_clipfl='\0';
1761
1762         /* Reset back to defaults - could be from interactive version 
1763          * reset mode and archive mode left as they are though
1764          */
1765         tar_type='\0';
1766         tar_excl=True;
1767         dry_run=False;
1768
1769         while (*Optarg) {
1770                 switch(*Optarg++) {
1771                         case 'c':
1772                                 tar_type='c';
1773                                 break;
1774                         case 'x':
1775                                 if (tar_type=='c') {
1776                                         printf("Tar must be followed by only one of c or x.\n");
1777                                         return 0;
1778                                 }
1779                                 tar_type='x';
1780                                 break;
1781                         case 'b':
1782                                 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1783                                         DEBUG(0,("Option b must be followed by valid blocksize\n"));
1784                                         return 0;
1785                                 } else {
1786                                         Optind++;
1787                                         newOptind++;
1788                                 }
1789                                 break;
1790                         case 'g':
1791                                 tar_inc=True;
1792                                 break;
1793                         case 'N':
1794                                 if (Optind>=argc) {
1795                                         DEBUG(0,("Option N must be followed by valid file name\n"));
1796                                         return 0;
1797                                 } else {
1798                                         SMB_STRUCT_STAT stbuf;
1799
1800                                         if (sys_stat(argv[Optind], &stbuf) == 0) {
1801                                                 newer_than = convert_timespec_to_time_t(
1802                                                         stbuf.st_ex_mtime);
1803                                                 DEBUG(1,("Getting files newer than %s",
1804                                                         time_to_asc(newer_than)));
1805                                                 newOptind++;
1806                                                 Optind++;
1807                                         } else {
1808                                                 DEBUG(0,("Error setting newer-than time\n"));
1809                                                 return 0;
1810                                         }
1811                                 }
1812                                 break;
1813                         case 'a':
1814                                 tar_reset=True;
1815                                 break;
1816                         case 'q':
1817                                 tar_noisy=False;
1818                                 break;
1819                         case 'I':
1820                                 if (tar_clipfl) {
1821                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1822                                         return 0;
1823                                 }
1824                                 tar_clipfl='I';
1825                                 break;
1826                         case 'X':
1827                                 if (tar_clipfl) {
1828                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1829                                         return 0;
1830                                 }
1831                                 tar_clipfl='X';
1832                                 break;
1833                         case 'F':
1834                                 if (tar_clipfl) {
1835                                         DEBUG(0,("Only one of I,X,F must be specified\n"));
1836                                         return 0;
1837                                 }
1838                                 tar_clipfl='F';
1839                                 break;
1840                         case 'r':
1841                                 DEBUG(0, ("tar_re_search set\n"));
1842                                 tar_re_search = True;
1843                                 break;
1844                         case 'n':
1845                                 if (tar_type == 'c') {
1846                                         DEBUG(0, ("dry_run set\n"));
1847                                         dry_run = True;
1848                                 } else {
1849                                         DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1850                                         return 0;
1851                                 }
1852                                 break;
1853                         default:
1854                                 DEBUG(0,("Unknown tar option\n"));
1855                                 return 0;
1856                 }
1857         }
1858
1859         if (!tar_type) {
1860                 printf("Option T must be followed by one of c or x.\n");
1861                 return 0;
1862         }
1863
1864         /* tar_excl is true if cliplist lists files to be included.
1865          * Both 'I' and 'F' mean include. */
1866         tar_excl=tar_clipfl!='X';
1867
1868         if (tar_clipfl=='F') {
1869                 if (argc-Optind-1 != 1) {
1870                         DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1871                         return 0;
1872                 }
1873                 newOptind++;
1874                 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1875                 if (! read_inclusion_file(argv[Optind+1])) {
1876                         return 0;
1877                 }
1878         } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1879                 char *tmpstr;
1880                 char **tmplist;
1881                 int clipcount;
1882
1883                 cliplist=argv+Optind+1;
1884                 clipn=argc-Optind-1;
1885                 clipcount = clipn;
1886
1887                 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1888                         DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1889                         return 0;
1890                 }
1891
1892                 for (clipcount = 0; clipcount < clipn; clipcount++) {
1893
1894                         DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1895
1896                         if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1897                                 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1898                                 SAFE_FREE(tmplist);
1899                                 return 0;
1900                         }
1901
1902                         unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1903                         tmplist[clipcount] = tmpstr;
1904                         DEBUG(5, ("Processed an item, %s\n", tmpstr));
1905
1906                         DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1907                 }
1908
1909                 cliplist = tmplist;
1910                 must_free_cliplist = True;
1911
1912                 newOptind += clipn;
1913         }
1914
1915         if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1916                 /* Doing regular expression seaches not from an inclusion file. */
1917                 clipn=argc-Optind-1;
1918                 cliplist=argv+Optind+1;
1919                 newOptind += clipn;
1920         }
1921
1922         if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1923                 /* Sets tar handle to either 0 or 1, as appropriate */
1924                 tarhandle=(tar_type=='c');
1925                 /*
1926                  * Make sure that dbf points to stderr if we are using stdout for 
1927                  * tar output
1928                  */
1929                 if (tarhandle == 1)  {
1930                         dbf = x_stderr;
1931                 }
1932                 if (!argv[Optind]) {
1933                         DEBUG(0,("Must specify tar filename\n"));
1934                         return 0;
1935                 }
1936                 if (!strcmp(argv[Optind], "-")) {
1937                         newOptind++;
1938                 }
1939
1940         } else {
1941                 if (tar_type=='c' && dry_run) {
1942                         tarhandle=-1;
1943                 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1944                                         || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1945                         DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1946                         return(0);
1947                 }
1948                 newOptind++;
1949         }
1950
1951         return newOptind;
1952 }