source: branches/samba-3.0/source/client/clitar.c@ 104

Last change on this file since 104 was 22, checked in by Yuri Dario, 18 years ago

Source code upgrade to 3.0.25pre2.

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