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