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

Last change on this file since 431 was 105, checked in by Paul Smedley, 18 years ago

Update source to 3.0.27a

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 shallitime=True;
613 char data[65520];
614 int read_size = 65520;
615 int datalen=0;
616
617 struct timeval tp_start;
618
619 GetTimeOfDay(&tp_start);
620
621 ftype = '0'; /* An ordinary file ... */
622
623 if (finfo1) {
624 finfo.size = finfo1 -> size;
625 finfo.mode = finfo1 -> mode;
626 finfo.uid = finfo1 -> uid;
627 finfo.gid = finfo1 -> gid;
628 finfo.mtime_ts = finfo1 -> mtime_ts;
629 finfo.atime_ts = finfo1 -> atime_ts;
630 finfo.ctime_ts = finfo1 -> ctime_ts;
631 finfo.name = finfo1 -> name;
632 } else {
633 finfo.size = def_finfo.size;
634 finfo.mode = def_finfo.mode;
635 finfo.uid = def_finfo.uid;
636 finfo.gid = def_finfo.gid;
637 finfo.mtime_ts = def_finfo.mtime_ts;
638 finfo.atime_ts = def_finfo.atime_ts;
639 finfo.ctime_ts = def_finfo.ctime_ts;
640 finfo.name = def_finfo.name;
641 }
642
643 if (dry_run) {
644 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo.name,
645 (double)finfo.size));
646 shallitime=0;
647 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
648 ntarf++;
649 return;
650 }
651
652 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
653
654 clean_name(rname);
655
656 if (fnum == -1) {
657 DEBUG(0,("%s opening remote file %s (%s)\n",
658 cli_errstr(cli),rname, cur_dir));
659 return;
660 }
661
662 finfo.name = string_create_s(strlen(rname));
663 if (finfo.name == NULL) {
664 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
665 return;
666 }
667
668 safe_strcpy(finfo.name,rname, strlen(rname));
669 if (!finfo1) {
670 time_t atime, mtime;
671 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &atime, &mtime)) {
672 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
673 return;
674 }
675 finfo.atime_ts = convert_time_t_to_timespec(atime);
676 finfo.mtime_ts = convert_time_t_to_timespec(mtime);
677 finfo.ctime_ts = finfo.mtime_ts;
678 }
679
680 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
681
682 if (tar_inc && !(finfo.mode & aARCH)) {
683 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
684 shallitime=0;
685 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
686 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
687 shallitime=0;
688 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
689 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
690 shallitime=0;
691 } else {
692 BOOL wrote_tar_header = False;
693
694 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
695 finfo.name, (double)finfo.size, lname));
696
697 do {
698
699 DEBUG(3,("nread=%.0f\n",(double)nread));
700
701 datalen = cli_read(cli, fnum, data, nread, read_size);
702
703 if (datalen == -1) {
704 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
705 break;
706 }
707
708 nread += datalen;
709
710 /* Only if the first read succeeds, write out the tar header. */
711 if (!wrote_tar_header) {
712 /* write a tar header, don't bother with mode - just set to 100644 */
713 writetarheader(tarhandle, rname, finfo.size,
714 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
715 wrote_tar_header = True;
716 }
717
718 /* if file size has increased since we made file size query, truncate
719 read so tar header for this file will be correct.
720 */
721
722 if (nread > finfo.size) {
723 datalen -= nread - finfo.size;
724 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
725 finfo.name, (double)finfo.size));
726 }
727
728 /* add received bits of file to buffer - dotarbuf will
729 * write out in 512 byte intervals */
730
731 if (dotarbuf(tarhandle,data,datalen) != datalen) {
732 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
733 break;
734 }
735
736 if ( (datalen == 0) && (finfo.size != 0) ) {
737 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
738 break;
739 }
740
741 datalen=0;
742 } while ( nread < finfo.size );
743
744 if (wrote_tar_header) {
745 /* pad tar file with zero's if we couldn't get entire file */
746 if (nread < finfo.size) {
747 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
748 (double)finfo.size, (int)nread));
749 if (padit(data, (SMB_BIG_UINT)sizeof(data), finfo.size - nread))
750 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
751 }
752
753 /* round tar file to nearest block */
754 if (finfo.size % TBLOCK)
755 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
756
757 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
758 ntarf++;
759 } else {
760 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
761 shallitime=0;
762 }
763 }
764
765 cli_close(cli, fnum);
766
767 if (shallitime) {
768 struct timeval tp_end;
769 int this_time;
770
771 /* if shallitime is true then we didn't skip */
772 if (tar_reset && !dry_run)
773 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
774
775 GetTimeOfDay(&tp_end);
776 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
777 get_total_time_ms += this_time;
778 get_total_size += finfo.size;
779
780 if (tar_noisy) {
781 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
782 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
783 finfo.name));
784 }
785
786 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
787 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
788 finfo.size / MAX(0.001, (1.024*this_time)),
789 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
790 }
791}
792
793/****************************************************************************
794Append single file to tar file (or not)
795***************************************************************************/
796
797static void do_tar(file_info *finfo)
798{
799 pstring rname;
800
801 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
802 return;
803
804 /* Is it on the exclude list ? */
805 if (!tar_excl && clipn) {
806 pstring exclaim;
807
808 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir)));
809
810 pstrcpy(exclaim, cur_dir);
811 *(exclaim+strlen(exclaim)-1)='\0';
812
813 pstrcat(exclaim, "\\");
814 pstrcat(exclaim, finfo->name);
815
816 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
817
818 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
819 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
820 DEBUG(3,("Skipping file %s\n", exclaim));
821 return;
822 }
823 }
824
825 if (finfo->mode & aDIR) {
826 pstring saved_curdir;
827 pstring mtar_mask;
828
829 pstrcpy(saved_curdir, cur_dir);
830
831 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, \
832strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
833 (int)sizeof(cur_dir), (int)strlen(cur_dir),
834 (int)strlen(finfo->name), finfo->name, cur_dir));
835
836 pstrcat(cur_dir,finfo->name);
837 pstrcat(cur_dir,"\\");
838
839 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
840
841 /* write a tar directory, don't bother with mode - just set it to
842 * 40755 */
843 writetarheader(tarhandle, cur_dir, 0, finfo->mtime_ts.tv_sec, "040755 \0", '5');
844 if (tar_noisy) {
845 DEBUG(0,(" directory %s\n", cur_dir));
846 }
847 ntarf++; /* Make sure we have a file on there */
848 pstrcpy(mtar_mask,cur_dir);
849 pstrcat(mtar_mask,"*");
850 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
851 do_list(mtar_mask, attribute, do_tar, False, True);
852 pstrcpy(cur_dir,saved_curdir);
853 } else {
854 pstrcpy(rname,cur_dir);
855 pstrcat(rname,finfo->name);
856 do_atar(rname,finfo->name,finfo);
857 }
858}
859
860/****************************************************************************
861Convert from UNIX to DOS file names
862***************************************************************************/
863
864static void unfixtarname(char *tptr, char *fp, int l, BOOL first)
865{
866 /* remove '.' from start of file name, convert from unix /'s to
867 * dos \'s in path. Kill any absolute path names. But only if first!
868 */
869
870 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
871
872 if (first) {
873 if (*fp == '.') {
874 fp++;
875 l--;
876 }
877 if (*fp == '\\' || *fp == '/') {
878 fp++;
879 l--;
880 }
881 }
882
883 safe_strcpy(tptr, fp, l);
884 string_replace(tptr, '/', '\\');
885}
886
887/****************************************************************************
888Move to the next block in the buffer, which may mean read in another set of
889blocks. FIXME, we should allow more than one block to be skipped.
890****************************************************************************/
891
892static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
893{
894 int bufread, total = 0;
895
896 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
897 *bufferp += TBLOCK;
898 total = TBLOCK;
899
900 if (*bufferp >= (ltarbuf + bufsiz)) {
901
902 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
903
904 /*
905 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
906 * Fixes bug where read can return short if coming from
907 * a pipe.
908 */
909
910 bufread = read(tarhandle, ltarbuf, bufsiz);
911 total = bufread;
912
913 while (total < bufsiz) {
914 if (bufread < 0) { /* An error, return false */
915 return (total > 0 ? -2 : bufread);
916 }
917 if (bufread == 0) {
918 if (total <= 0) {
919 return -2;
920 }
921 break;
922 }
923 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
924 total += bufread;
925 }
926
927 DEBUG(5, ("Total bytes read ... %i\n", total));
928
929 *bufferp = ltarbuf;
930 }
931
932 return(total);
933}
934
935/* Skip a file, even if it includes a long file name? */
936static int skip_file(int skipsize)
937{
938 int dsize = skipsize;
939
940 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
941
942 /* FIXME, we should skip more than one block at a time */
943
944 while (dsize > 0) {
945 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
946 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
947 return(False);
948 }
949 dsize -= TBLOCK;
950 }
951
952 return(True);
953}
954
955/*************************************************************
956 Get a file from the tar file and store it.
957 When this is called, tarbuf already contains the first
958 file block. This is a bit broken & needs fixing.
959**************************************************************/
960
961static int get_file(file_info2 finfo)
962{
963 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
964 SMB_BIG_UINT rsize = 0;
965
966 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
967
968 if (ensurepath(finfo.name) &&
969 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
970 DEBUG(0, ("abandoning restore\n"));
971 return(False);
972 }
973
974 /* read the blocks from the tar file and write to the remote file */
975
976 rsize = finfo.size; /* This is how much to write */
977
978 while (rsize > 0) {
979
980 /* We can only write up to the end of the buffer */
981 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
982 dsize = MIN(dsize, rsize); /* Should be only what is left */
983 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
984
985 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
986 DEBUG(0, ("Error writing remote file\n"));
987 return 0;
988 }
989
990 rsize -= dsize;
991 pos += dsize;
992
993 /* Now figure out how much to move in the buffer */
994
995 /* FIXME, we should skip more than one block at a time */
996
997 /* First, skip any initial part of the part written that is left over */
998 /* from the end of the first TBLOCK */
999
1000 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1001 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1002 bpos = 0;
1003
1004 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1005 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1006 return False;
1007 }
1008 }
1009
1010 /*
1011 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1012 * If the file being extracted is an exact multiple of
1013 * TBLOCK bytes then we don't want to extract the next
1014 * block from the tarfile here, as it will be done in
1015 * the caller of get_file().
1016 */
1017
1018 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1019 ((rsize == 0) && (dsize > TBLOCK))) {
1020
1021 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1022 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1023 return False;
1024 }
1025
1026 dsize -= TBLOCK;
1027 }
1028 bpos = dsize;
1029 }
1030
1031 /* Now close the file ... */
1032
1033 if (!cli_close(cli, fnum)) {
1034 DEBUG(0, ("Error closing remote file\n"));
1035 return(False);
1036 }
1037
1038 /* Now we update the creation date ... */
1039 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1040
1041 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec)) {
1042 if (tar_real_noisy) {
1043 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1044 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1045 }
1046 }
1047
1048 ntarf++;
1049 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1050 return(True);
1051}
1052
1053/* Create a directory. We just ensure that the path exists and return as there
1054 is no file associated with a directory
1055*/
1056static int get_dir(file_info2 finfo)
1057{
1058 DEBUG(0, ("restore directory %s\n", finfo.name));
1059
1060 if (!ensurepath(finfo.name)) {
1061 DEBUG(0, ("Problems creating directory\n"));
1062 return(False);
1063 }
1064 ntarf++;
1065 return(True);
1066}
1067
1068/* Get a file with a long file name ... first file has file name, next file
1069 has the data. We only want the long file name, as the loop in do_tarput
1070 will deal with the rest.
1071*/
1072static char *get_longfilename(file_info2 finfo)
1073{
1074 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1075 * header call. */
1076 int namesize = finfo.size + strlen(cur_dir) + 2;
1077 char *longname = (char *)SMB_MALLOC(namesize);
1078 int offset = 0, left = finfo.size;
1079 BOOL first = True;
1080
1081 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1082 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1083
1084 if (longname == NULL) {
1085 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1086 return(NULL);
1087 }
1088
1089 /* First, add cur_dir to the long file name */
1090
1091 if (strlen(cur_dir) > 0) {
1092 strncpy(longname, cur_dir, namesize);
1093 offset = strlen(cur_dir);
1094 }
1095
1096 /* Loop through the blocks picking up the name */
1097
1098 while (left > 0) {
1099 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1100 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1101 SAFE_FREE(longname);
1102 return(NULL);
1103 }
1104
1105 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1106 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1107
1108 offset += TBLOCK;
1109 left -= TBLOCK;
1110 }
1111
1112 return(longname);
1113}
1114
1115static void do_tarput(void)
1116{
1117 file_info2 finfo;
1118 struct timeval tp_start;
1119 char *longfilename = NULL, linkflag;
1120 int skip = False;
1121
1122 ZERO_STRUCT(finfo);
1123
1124 GetTimeOfDay(&tp_start);
1125 DEBUG(5, ("RJS do_tarput called ...\n"));
1126
1127 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1128
1129 /* Now read through those files ... */
1130 while (True) {
1131 /* Get us to the next block, or the first block first time around */
1132 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1133 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1134 SAFE_FREE(longfilename);
1135 return;
1136 }
1137
1138 DEBUG(5, ("Reading the next header ...\n"));
1139
1140 switch (readtarheader((union hblock *) buffer_p, &finfo, cur_dir)) {
1141 case -2: /* Hmm, not good, but not fatal */
1142 DEBUG(0, ("Skipping %s...\n", finfo.name));
1143 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1144 DEBUG(0, ("Short file, bailing out...\n"));
1145 return;
1146 }
1147 break;
1148
1149 case -1:
1150 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1151 return;
1152
1153 case 0: /* chksum is zero - looks like an EOF */
1154 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1155 return; /* Hmmm, bad here ... */
1156
1157 default:
1158 /* No action */
1159 break;
1160 }
1161
1162 /* Now, do we have a long file name? */
1163 if (longfilename != NULL) {
1164 SAFE_FREE(finfo.name); /* Free the space already allocated */
1165 finfo.name = longfilename;
1166 longfilename = NULL;
1167 }
1168
1169 /* Well, now we have a header, process the file ... */
1170 /* Should we skip the file? We have the long name as well here */
1171 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1172 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1173
1174 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1175 if (skip) {
1176 skip_file(finfo.size);
1177 continue;
1178 }
1179
1180 /* We only get this far if we should process the file */
1181 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1182 switch (linkflag) {
1183 case '0': /* Should use symbolic names--FIXME */
1184 /*
1185 * Skip to the next block first, so we can get the file, FIXME, should
1186 * be in get_file ...
1187 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1188 * Fixes bug where file size in tarfile is zero.
1189 */
1190 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1191 DEBUG(0, ("Short file, bailing out...\n"));
1192 return;
1193 }
1194 if (!get_file(finfo)) {
1195 DEBUG(0, ("Abandoning restore\n"));
1196 return;
1197 }
1198 break;
1199 case '5':
1200 if (!get_dir(finfo)) {
1201 DEBUG(0, ("Abandoning restore \n"));
1202 return;
1203 }
1204 break;
1205 case 'L':
1206 SAFE_FREE(longfilename);
1207 longfilename = get_longfilename(finfo);
1208 if (!longfilename) {
1209 DEBUG(0, ("abandoning restore\n"));
1210 return;
1211 }
1212 DEBUG(5, ("Long file name: %s\n", longfilename));
1213 break;
1214
1215 default:
1216 skip_file(finfo.size); /* Don't handle these yet */
1217 break;
1218 }
1219 }
1220}
1221
1222/*
1223 * samba interactive commands
1224 */
1225
1226/****************************************************************************
1227Blocksize command
1228***************************************************************************/
1229
1230int cmd_block(void)
1231{
1232 fstring buf;
1233 int block;
1234
1235 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1236 DEBUG(0, ("blocksize <n>\n"));
1237 return 1;
1238 }
1239
1240 block=atoi(buf);
1241 if (block < 0 || block > 65535) {
1242 DEBUG(0, ("blocksize out of range"));
1243 return 1;
1244 }
1245
1246 blocksize=block;
1247 DEBUG(2,("blocksize is now %d\n", blocksize));
1248
1249 return 0;
1250}
1251
1252/****************************************************************************
1253command to set incremental / reset mode
1254***************************************************************************/
1255
1256int cmd_tarmode(void)
1257{
1258 fstring buf;
1259
1260 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1261 if (strequal(buf, "full"))
1262 tar_inc=False;
1263 else if (strequal(buf, "inc"))
1264 tar_inc=True;
1265 else if (strequal(buf, "reset"))
1266 tar_reset=True;
1267 else if (strequal(buf, "noreset"))
1268 tar_reset=False;
1269 else if (strequal(buf, "system"))
1270 tar_system=True;
1271 else if (strequal(buf, "nosystem"))
1272 tar_system=False;
1273 else if (strequal(buf, "hidden"))
1274 tar_hidden=True;
1275 else if (strequal(buf, "nohidden"))
1276 tar_hidden=False;
1277 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1278 tar_noisy=True;
1279 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1280 tar_noisy=False;
1281 else
1282 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1283 }
1284
1285 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1286 tar_inc ? "incremental" : "full",
1287 tar_system ? "system" : "nosystem",
1288 tar_hidden ? "hidden" : "nohidden",
1289 tar_reset ? "reset" : "noreset",
1290 tar_noisy ? "verbose" : "quiet"));
1291 return 0;
1292}
1293
1294/****************************************************************************
1295Feeble attrib command
1296***************************************************************************/
1297
1298int cmd_setmode(void)
1299{
1300 char *q;
1301 fstring buf;
1302 pstring fname;
1303 uint16 attra[2];
1304 int direct=1;
1305
1306 attra[0] = attra[1] = 0;
1307
1308 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1309 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1310 return 1;
1311 }
1312
1313 pstrcpy(fname, cur_dir);
1314 pstrcat(fname, buf);
1315
1316 while (next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1317 q=buf;
1318
1319 while(*q) {
1320 switch (*q++) {
1321 case '+':
1322 direct=1;
1323 break;
1324 case '-':
1325 direct=0;
1326 break;
1327 case 'r':
1328 attra[direct]|=aRONLY;
1329 break;
1330 case 'h':
1331 attra[direct]|=aHIDDEN;
1332 break;
1333 case 's':
1334 attra[direct]|=aSYSTEM;
1335 break;
1336 case 'a':
1337 attra[direct]|=aARCH;
1338 break;
1339 default:
1340 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1341 return 1;
1342 }
1343 }
1344 }
1345
1346 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1347 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1348 return 1;
1349 }
1350
1351 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1352 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1353 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1354 return 0;
1355}
1356
1357/****************************************************************************
1358Principal command for creating / extracting
1359***************************************************************************/
1360
1361int cmd_tar(void)
1362{
1363 fstring buf;
1364 char **argl = NULL;
1365 int argcl = 0;
1366 int ret;
1367
1368 if (!next_token_nr(NULL,buf,NULL,sizeof(buf))) {
1369 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1370 return 1;
1371 }
1372
1373 argl=toktocliplist(&argcl, NULL);
1374 if (!tar_parseargs(argcl, argl, buf, 0))
1375 return 1;
1376
1377 ret = process_tar();
1378 SAFE_FREE(argl);
1379 return ret;
1380}
1381
1382/****************************************************************************
1383Command line (option) version
1384***************************************************************************/
1385
1386int process_tar(void)
1387{
1388 int rc = 0;
1389 initarbuf();
1390 switch(tar_type) {
1391 case 'x':
1392
1393#if 0
1394 do_tarput2();
1395#else
1396 do_tarput();
1397#endif
1398 SAFE_FREE(tarbuf);
1399 close(tarhandle);
1400 break;
1401 case 'r':
1402 case 'c':
1403 if (clipn && tar_excl) {
1404 int i;
1405 pstring tarmac;
1406
1407 for (i=0; i<clipn; i++) {
1408 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1409
1410 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1411 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1412 }
1413
1414 if (strrchr_m(cliplist[i], '\\')) {
1415 pstring saved_dir;
1416
1417 pstrcpy(saved_dir, cur_dir);
1418
1419 if (*cliplist[i]=='\\') {
1420 pstrcpy(tarmac, cliplist[i]);
1421 } else {
1422 pstrcpy(tarmac, cur_dir);
1423 pstrcat(tarmac, cliplist[i]);
1424 }
1425 pstrcpy(cur_dir, tarmac);
1426 *(strrchr_m(cur_dir, '\\')+1)='\0';
1427
1428 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1429 do_list(tarmac,attribute,do_tar, False, True);
1430 pstrcpy(cur_dir,saved_dir);
1431 } else {
1432 pstrcpy(tarmac, cur_dir);
1433 pstrcat(tarmac, cliplist[i]);
1434 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1435 do_list(tarmac,attribute,do_tar, False, True);
1436 }
1437 }
1438 } else {
1439 pstring mask;
1440 pstrcpy(mask,cur_dir);
1441 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1442 pstrcat(mask,"\\*");
1443 do_list(mask,attribute,do_tar,False, True);
1444 }
1445
1446 if (ntarf)
1447 dotareof(tarhandle);
1448 close(tarhandle);
1449 SAFE_FREE(tarbuf);
1450
1451 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1452 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1453 break;
1454 }
1455
1456 if (must_free_cliplist) {
1457 int i;
1458 for (i = 0; i < clipn; ++i) {
1459 SAFE_FREE(cliplist[i]);
1460 }
1461 SAFE_FREE(cliplist);
1462 cliplist = NULL;
1463 clipn = 0;
1464 must_free_cliplist = False;
1465 }
1466 return rc;
1467}
1468
1469/****************************************************************************
1470Find a token (filename) in a clip list
1471***************************************************************************/
1472
1473static int clipfind(char **aret, int ret, char *tok)
1474{
1475 if (aret==NULL)
1476 return 0;
1477
1478 /* ignore leading slashes or dots in token */
1479 while(strchr_m("/\\.", *tok))
1480 tok++;
1481
1482 while(ret--) {
1483 char *pkey=*aret++;
1484
1485 /* ignore leading slashes or dots in list */
1486 while(strchr_m("/\\.", *pkey))
1487 pkey++;
1488
1489 if (!strslashcmp(pkey, tok))
1490 return 1;
1491 }
1492 return 0;
1493}
1494
1495/****************************************************************************
1496Read list of files to include from the file and initialize cliplist
1497accordingly.
1498***************************************************************************/
1499
1500static int read_inclusion_file(char *filename)
1501{
1502 XFILE *inclusion = NULL;
1503 char buf[PATH_MAX + 1];
1504 char *inclusion_buffer = NULL;
1505 int inclusion_buffer_size = 0;
1506 int inclusion_buffer_sofar = 0;
1507 char *p;
1508 char *tmpstr;
1509 int i;
1510 int error = 0;
1511
1512 clipn = 0;
1513 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1514 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1515 /* XXX It would be better to include a reason for failure, but without
1516 * autoconf, it's hard to use strerror, sys_errlist, etc.
1517 */
1518 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1519 return 0;
1520 }
1521
1522 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1523 if (inclusion_buffer == NULL) {
1524 inclusion_buffer_size = 1024;
1525 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1526 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1527 error = 1;
1528 break;
1529 }
1530 }
1531
1532 if (buf[strlen(buf)-1] == '\n') {
1533 buf[strlen(buf)-1] = '\0';
1534 }
1535
1536 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1537 inclusion_buffer_size *= 2;
1538 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1539 if (!inclusion_buffer) {
1540 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1541 inclusion_buffer_size));
1542 error = 1;
1543 break;
1544 }
1545 }
1546
1547 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1548 inclusion_buffer_sofar += strlen(buf) + 1;
1549 clipn++;
1550 }
1551 x_fclose(inclusion);
1552
1553 if (! error) {
1554 /* Allocate an array of clipn + 1 char*'s for cliplist */
1555 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1556 if (cliplist == NULL) {
1557 DEBUG(0,("failure allocating memory for cliplist\n"));
1558 error = 1;
1559 } else {
1560 cliplist[clipn] = NULL;
1561 p = inclusion_buffer;
1562 for (i = 0; (! error) && (i < clipn); i++) {
1563 /* set current item to NULL so array will be null-terminated even if
1564 * malloc fails below. */
1565 cliplist[i] = NULL;
1566 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1567 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1568 error = 1;
1569 } else {
1570 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1571 cliplist[i] = tmpstr;
1572 if ((p = strchr_m(p, '\000')) == NULL) {
1573 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1574 abort();
1575 }
1576 }
1577 ++p;
1578 }
1579 must_free_cliplist = True;
1580 }
1581 }
1582
1583 SAFE_FREE(inclusion_buffer);
1584 if (error) {
1585 if (cliplist) {
1586 char **pp;
1587 /* We know cliplist is always null-terminated */
1588 for (pp = cliplist; *pp; ++pp) {
1589 SAFE_FREE(*pp);
1590 }
1591 SAFE_FREE(cliplist);
1592 cliplist = NULL;
1593 must_free_cliplist = False;
1594 }
1595 return 0;
1596 }
1597
1598 /* cliplist and its elements are freed at the end of process_tar. */
1599 return 1;
1600}
1601
1602/****************************************************************************
1603Parse tar arguments. Sets tar_type, tar_excl, etc.
1604***************************************************************************/
1605
1606int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1607{
1608 int newOptind = Optind;
1609 char tar_clipfl='\0';
1610
1611 /* Reset back to defaults - could be from interactive version
1612 * reset mode and archive mode left as they are though
1613 */
1614 tar_type='\0';
1615 tar_excl=True;
1616 dry_run=False;
1617
1618 while (*Optarg) {
1619 switch(*Optarg++) {
1620 case 'c':
1621 tar_type='c';
1622 break;
1623 case 'x':
1624 if (tar_type=='c') {
1625 printf("Tar must be followed by only one of c or x.\n");
1626 return 0;
1627 }
1628 tar_type='x';
1629 break;
1630 case 'b':
1631 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1632 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1633 return 0;
1634 } else {
1635 Optind++;
1636 newOptind++;
1637 }
1638 break;
1639 case 'g':
1640 tar_inc=True;
1641 break;
1642 case 'N':
1643 if (Optind>=argc) {
1644 DEBUG(0,("Option N must be followed by valid file name\n"));
1645 return 0;
1646 } else {
1647 SMB_STRUCT_STAT stbuf;
1648
1649 if (sys_stat(argv[Optind], &stbuf) == 0) {
1650 newer_than = stbuf.st_mtime;
1651 DEBUG(1,("Getting files newer than %s",
1652 time_to_asc(newer_than)));
1653 newOptind++;
1654 Optind++;
1655 } else {
1656 DEBUG(0,("Error setting newer-than time\n"));
1657 return 0;
1658 }
1659 }
1660 break;
1661 case 'a':
1662 tar_reset=True;
1663 break;
1664 case 'q':
1665 tar_noisy=False;
1666 break;
1667 case 'I':
1668 if (tar_clipfl) {
1669 DEBUG(0,("Only one of I,X,F must be specified\n"));
1670 return 0;
1671 }
1672 tar_clipfl='I';
1673 break;
1674 case 'X':
1675 if (tar_clipfl) {
1676 DEBUG(0,("Only one of I,X,F must be specified\n"));
1677 return 0;
1678 }
1679 tar_clipfl='X';
1680 break;
1681 case 'F':
1682 if (tar_clipfl) {
1683 DEBUG(0,("Only one of I,X,F must be specified\n"));
1684 return 0;
1685 }
1686 tar_clipfl='F';
1687 break;
1688 case 'r':
1689 DEBUG(0, ("tar_re_search set\n"));
1690 tar_re_search = True;
1691 break;
1692 case 'n':
1693 if (tar_type == 'c') {
1694 DEBUG(0, ("dry_run set\n"));
1695 dry_run = True;
1696 } else {
1697 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1698 return 0;
1699 }
1700 break;
1701 default:
1702 DEBUG(0,("Unknown tar option\n"));
1703 return 0;
1704 }
1705 }
1706
1707 if (!tar_type) {
1708 printf("Option T must be followed by one of c or x.\n");
1709 return 0;
1710 }
1711
1712 /* tar_excl is true if cliplist lists files to be included.
1713 * Both 'I' and 'F' mean include. */
1714 tar_excl=tar_clipfl!='X';
1715
1716 if (tar_clipfl=='F') {
1717 if (argc-Optind-1 != 1) {
1718 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1719 return 0;
1720 }
1721 newOptind++;
1722 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1723 if (! read_inclusion_file(argv[Optind+1])) {
1724 return 0;
1725 }
1726 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1727 char *tmpstr;
1728 char **tmplist;
1729 int clipcount;
1730
1731 cliplist=argv+Optind+1;
1732 clipn=argc-Optind-1;
1733 clipcount = clipn;
1734
1735 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1736 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1737 return 0;
1738 }
1739
1740 for (clipcount = 0; clipcount < clipn; clipcount++) {
1741
1742 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1743
1744 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1745 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1746 SAFE_FREE(tmplist);
1747 return 0;
1748 }
1749
1750 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1751 tmplist[clipcount] = tmpstr;
1752 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1753
1754 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1755 }
1756
1757 cliplist = tmplist;
1758 must_free_cliplist = True;
1759
1760 newOptind += clipn;
1761 }
1762
1763 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1764 /* Doing regular expression seaches not from an inclusion file. */
1765 clipn=argc-Optind-1;
1766 cliplist=argv+Optind+1;
1767 newOptind += clipn;
1768 }
1769
1770 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1771 /* Sets tar handle to either 0 or 1, as appropriate */
1772 tarhandle=(tar_type=='c');
1773 /*
1774 * Make sure that dbf points to stderr if we are using stdout for
1775 * tar output
1776 */
1777 if (tarhandle == 1) {
1778 dbf = x_stderr;
1779 }
1780 if (!argv[Optind]) {
1781 DEBUG(0,("Must specify tar filename\n"));
1782 return 0;
1783 }
1784 if (!strcmp(argv[Optind], "-")) {
1785 newOptind++;
1786 }
1787
1788 } else {
1789 if (tar_type=='c' && dry_run) {
1790 tarhandle=-1;
1791 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1792 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1793 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1794 return(0);
1795 }
1796 newOptind++;
1797 }
1798
1799 return newOptind;
1800}
Note: See TracBrowser for help on using the repository browser.