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