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