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