source: branches/samba-3.3.x/source/client/clitar.c@ 222

Last change on this file since 222 was 222, checked in by Herwig Bauernfeind, 16 years ago

Update Samba 3.3 branch to 3.3.2

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