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