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