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