source: branches/samba-3.5.x/source3/client/clitar.c@ 1075

Last change on this file since 1075 was 733, checked in by Silvan Scherrer, 13 years ago

Samba Server 3.5: update branche to 3.5.13

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