Add comment explaining the previous fix.
[Samba.git] / source / client / clitar.c
blobbe0bc320bb48a956bdeaee307df137c6db20ac6c
1 /*
2 Unix SMB/CIFS implementation.
3 Tar Extensions
4 Copyright (C) Ricky Poulten 1995-1998
5 Copyright (C) Richard Sharpe 1998
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.
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.
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/>.
20 /* The following changes developed by Richard Sharpe for Canon Information
21 Systems Research Australia (CISRA)
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:
31 -TcrX file.tar "*.(obj|exe)"
33 will skip all .obj and .exe files
37 #include "includes.h"
38 #include "clitar.h"
39 #include "client/client_proto.h"
41 static int clipfind(char **aret, int ret, char *tok);
43 typedef struct file_info_struct file_info2;
45 struct 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 ... */
58 typedef struct {
59 file_info2 *top;
60 int items;
61 } stack;
63 #define SEPARATORS " \t\n\r"
64 extern time_t newer_than;
65 extern struct cli_state *cli;
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
72 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
74 #ifndef CLIENT_TIMEOUT
75 #define CLIENT_TIMEOUT (30*1000)
76 #endif
78 static char *tarbuf, *buffer_p;
79 static int tp, ntarf, tbufsiz;
80 static double ttarf;
81 /* Incremental mode */
82 static bool tar_inc=False;
83 /* Reset archive bit */
84 static bool tar_reset=False;
85 /* Include / exclude mode (true=include, false=exclude) */
86 static bool tar_excl=True;
87 /* use regular expressions for search on file names */
88 static bool tar_re_search=False;
89 /* Do not dump anything, just calculate sizes */
90 static bool dry_run=False;
91 /* Dump files with System attribute */
92 static bool tar_system=True;
93 /* Dump files with Hidden attribute */
94 static bool tar_hidden=True;
95 /* Be noisy - make a catalogue */
96 static bool tar_noisy=True;
97 static bool tar_real_noisy=False; /* Don't want to be really noisy by default */
99 char tar_type='\0';
100 static char **cliplist=NULL;
101 static int clipn=0;
102 static bool must_free_cliplist = False;
103 extern const char *cmd_ptr;
105 extern bool lowercase;
106 extern uint16 cnum;
107 extern bool readbraw_supported;
108 extern int max_xmit;
109 extern int get_total_time_ms;
110 extern int get_total_size;
112 static int blocksize=20;
113 static int tarhandle;
115 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
116 const char *amode, unsigned char ftype);
117 static void do_atar(const char *rname_in,char *lname,file_info *finfo1);
118 static void do_tar(file_info *finfo, const char *dir);
119 static void oct_it(SMB_BIG_UINT value, int ndgs, char *p);
120 static void fixtarname(char *tptr, const char *fp, size_t l);
121 static int dotarbuf(int f, char *b, int n);
122 static void dozerobuf(int f, int n);
123 static void dotareof(int f);
124 static void initarbuf(void);
126 /* restore functions */
127 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
128 static long unoct(char *p, int ndgs);
129 static void do_tarput(void);
130 static void unfixtarname(char *tptr, char *fp, int l, bool first);
133 * tar specific utitlities
136 /*******************************************************************
137 Create a string of size size+1 (for the null)
138 *******************************************************************/
140 static char *string_create_s(int size)
142 char *tmp;
144 tmp = (char *)SMB_MALLOC(size+1);
146 if (tmp == NULL) {
147 DEBUG(0, ("Out of memory in string_create_s\n"));
150 return(tmp);
153 /****************************************************************************
154 Write a tar header to buffer
155 ****************************************************************************/
157 static void writetarheader(int f, const char *aname, SMB_BIG_UINT size, time_t mtime,
158 const char *amode, unsigned char ftype)
160 union hblock hb;
161 int i, chk, l;
162 char *jp;
164 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
166 memset(hb.dummy, 0, sizeof(hb.dummy));
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.
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);
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);
189 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
191 if (lowercase)
192 strlower_m(hb.dbuf.name);
194 /* write out a "standard" tar format header */
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. */
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++);
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;
215 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
216 chk+=(0xFF & *jp++);
218 oct_it((SMB_BIG_UINT) chk, 8, hb.dbuf.chksum);
219 hb.dbuf.chksum[6] = '\0';
221 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
224 /****************************************************************************
225 Read a tar header into a hblock structure, and validate
226 ***************************************************************************/
228 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
230 long chk, fchk;
231 int i;
232 char *jp;
235 * read in a "standard" tar format header - we're not that interested
236 * in that many fields, though
239 /* check the checksum */
240 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
241 chk+=(0xFF & *jp++);
243 if (chk == 0)
244 return chk;
246 /* compensate for blanks in chksum header */
247 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
248 chk-=(0xFF & *jp++);
250 chk += ' ' * sizeof(hb->dbuf.chksum);
252 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
254 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
255 chk, fchk, hb->dbuf.chksum));
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;
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);
268 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
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);
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 \
286 of link other than a GNUtar Longlink - ignoring\n"));
287 return -2;
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 */
301 * Bug fix by richard@sj.co.uk
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
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));
312 return True;
315 /****************************************************************************
316 Write out the tar buffer to tape or wherever
317 ****************************************************************************/
319 static int dotarbuf(int f, char *b, int n)
321 int fail=1, writ=n;
323 if (dry_run) {
324 return writ;
326 /* This routine and the next one should be the only ones that do write()s */
327 if (tp + n >= tbufsiz) {
328 int diff;
330 diff=tbufsiz-tp;
331 memcpy(tarbuf + tp, b, diff);
332 fail=fail && (1+write(f, tarbuf, tbufsiz));
333 n-=diff;
334 b+=diff;
335 tp=0;
337 while (n >= tbufsiz) {
338 fail=fail && (1 + write(f, b, tbufsiz));
339 n-=tbufsiz;
340 b+=tbufsiz;
344 if (n>0) {
345 memcpy(tarbuf+tp, b, n);
346 tp+=n;
349 return(fail ? writ : 0);
352 /****************************************************************************
353 Write zeros to buffer / tape
354 ****************************************************************************/
356 static void dozerobuf(int f, int n)
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 */
362 if (dry_run)
363 return;
365 if (n+tp >= tbufsiz) {
366 memset(tarbuf+tp, 0, tbufsiz-tp);
367 write(f, tarbuf, tbufsiz);
368 memset(tarbuf, 0, (tp+=n-tbufsiz));
369 } else {
370 memset(tarbuf+tp, 0, n);
371 tp+=n;
375 /****************************************************************************
376 Malloc tape buffer
377 ****************************************************************************/
379 static void initarbuf(void)
381 /* initialize tar buffer */
382 tbufsiz=blocksize*TBLOCK;
383 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
385 /* reset tar buffer pointer and tar file counter and total dumped */
386 tp=0; ntarf=0; ttarf=0;
389 /****************************************************************************
390 Write two zero blocks at end of file
391 ****************************************************************************/
393 static void dotareof(int f)
395 SMB_STRUCT_STAT stbuf;
396 /* Two zero blocks at end of file, write out full buffer */
398 if (dry_run)
399 return;
401 (void) dozerobuf(f, TBLOCK);
402 (void) dozerobuf(f, TBLOCK);
404 if (sys_fstat(f, &stbuf) == -1) {
405 DEBUG(0, ("Couldn't stat file handle\n"));
406 return;
409 /* Could be a pipe, in which case S_ISREG should fail,
410 * and we should write out at full size */
411 if (tp > 0)
412 write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
415 /****************************************************************************
416 (Un)mangle DOS pathname, make nonabsolute
417 ****************************************************************************/
419 static void fixtarname(char *tptr, const char *fp, size_t l)
421 /* add a '.' to start of file name, convert from ugly dos \'s in path
422 * to lovely unix /'s :-} */
423 *tptr++='.';
424 l--;
426 StrnCpy(tptr, fp, l-1);
427 string_replace(tptr, '\\', '/');
430 /****************************************************************************
431 Convert from decimal to octal string
432 ****************************************************************************/
434 static void oct_it (SMB_BIG_UINT value, int ndgs, char *p)
436 /* Converts long to octal string, pads with leading zeros */
438 /* skip final null, but do final space */
439 --ndgs;
440 p[--ndgs] = ' ';
442 /* Loop does at least one digit */
443 do {
444 p[--ndgs] = '0' + (char) (value & 7);
445 value >>= 3;
446 } while (ndgs > 0 && value != 0);
448 /* Do leading zeros */
449 while (ndgs > 0)
450 p[--ndgs] = '0';
453 /****************************************************************************
454 Convert from octal string to long
455 ***************************************************************************/
457 static long unoct(char *p, int ndgs)
459 long value=0;
460 /* Converts octal string to long, ignoring any non-digit */
462 while (--ndgs) {
463 if (isdigit((int)*p))
464 value = (value << 3) | (long) (*p - '0');
466 p++;
469 return value;
472 /****************************************************************************
473 Compare two strings in a slash insensitive way, allowing s1 to match s2
474 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
475 a file in any subdirectory of s1, declare a match.
476 ***************************************************************************/
478 static int strslashcmp(char *s1, char *s2)
480 char *s1_0=s1;
482 while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
483 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
484 s1++; s2++;
487 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
488 string of s2.
490 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
491 return 0;
493 /* ignore trailing slash on s1 */
494 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
495 return 0;
497 /* check for s1 is an "initial" string of s2 */
498 if ((*s2 == '/' || *s2 == '\\') && !*s1)
499 return 0;
501 return *s1-*s2;
504 /****************************************************************************
505 Ensure a remote path exists (make if necessary)
506 ***************************************************************************/
508 static bool ensurepath(const char *fname)
510 /* *must* be called with buffer ready malloc'ed */
511 /* ensures path exists */
513 char *partpath, *ffname;
514 const char *p=fname;
515 char *basehack;
516 char *saveptr;
518 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
520 partpath = string_create_s(strlen(fname));
521 ffname = string_create_s(strlen(fname));
523 if ((partpath == NULL) || (ffname == NULL)){
524 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
525 SAFE_FREE(partpath);
526 SAFE_FREE(ffname);
527 return(False);
530 *partpath = 0;
532 /* fname copied to ffname so can strtok_r */
534 safe_strcpy(ffname, fname, strlen(fname));
536 /* do a `basename' on ffname, so don't try and make file name directory */
537 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
538 SAFE_FREE(partpath);
539 SAFE_FREE(ffname);
540 return True;
541 } else {
542 *basehack='\0';
545 p=strtok_r(ffname, "\\", &saveptr);
547 while (p) {
548 safe_strcat(partpath, p, strlen(fname) + 1);
550 if (!cli_chkpath(cli, partpath)) {
551 if (!cli_mkdir(cli, partpath)) {
552 SAFE_FREE(partpath);
553 SAFE_FREE(ffname);
554 DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
555 return False;
556 } else {
557 DEBUG(3, ("mkdirhiering %s\n", partpath));
561 safe_strcat(partpath, "\\", strlen(fname) + 1);
562 p = strtok_r(NULL, "/\\", &saveptr);
565 SAFE_FREE(partpath);
566 SAFE_FREE(ffname);
567 return True;
570 static int padit(char *buf, SMB_BIG_UINT bufsize, SMB_BIG_UINT padsize)
572 int berr= 0;
573 int bytestowrite;
575 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
576 memset(buf, 0, (size_t)bufsize);
577 while( !berr && padsize > 0 ) {
578 bytestowrite= (int)MIN(bufsize, padsize);
579 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
580 padsize -= bytestowrite;
583 return berr;
586 static void do_setrattr(char *name, uint16 attr, int set)
588 uint16 oldattr;
590 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
592 if (set == ATTRSET) {
593 attr |= oldattr;
594 } else {
595 attr = oldattr & ~attr;
598 if (!cli_setatr(cli, name, attr, 0)) {
599 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
603 /****************************************************************************
604 append one remote file to the tar file
605 ***************************************************************************/
607 static void do_atar(const char *rname_in,char *lname,file_info *finfo1)
609 int fnum = -1;
610 SMB_BIG_UINT nread=0;
611 char ftype;
612 file_info2 finfo;
613 bool shallitime=True;
614 char *data = NULL;
615 int read_size = 65520;
616 int datalen=0;
617 char *rname = NULL;
618 TALLOC_CTX *ctx = talloc_stackframe();
620 struct timeval tp_start;
622 GetTimeOfDay(&tp_start);
624 data = SMB_MALLOC_ARRAY(char, read_size);
625 if (!data) {
626 DEBUG(0,("do_atar: out of memory.\n"));
627 goto cleanup;
630 ftype = '0'; /* An ordinary file ... */
632 ZERO_STRUCT(finfo);
634 finfo.size = finfo1 -> size;
635 finfo.mode = finfo1 -> mode;
636 finfo.uid = finfo1 -> uid;
637 finfo.gid = finfo1 -> gid;
638 finfo.mtime_ts = finfo1 -> mtime_ts;
639 finfo.atime_ts = finfo1 -> atime_ts;
640 finfo.ctime_ts = finfo1 -> ctime_ts;
642 if (dry_run) {
643 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
644 (double)finfo.size));
645 shallitime=0;
646 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
647 ntarf++;
648 goto cleanup;
651 rname = clean_name(ctx, rname_in);
652 if (!rname) {
653 goto cleanup;
656 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
658 if (fnum == -1) {
659 DEBUG(0,("%s opening remote file %s (%s)\n",
660 cli_errstr(cli),rname, client_get_cur_dir()));
661 goto cleanup;
664 finfo.name = string_create_s(strlen(rname));
665 if (finfo.name == NULL) {
666 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
667 goto cleanup;
670 safe_strcpy(finfo.name,rname, strlen(rname));
672 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
674 if (tar_inc && !(finfo.mode & aARCH)) {
675 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
676 shallitime=0;
677 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
678 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
679 shallitime=0;
680 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
681 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
682 shallitime=0;
683 } else {
684 bool wrote_tar_header = False;
686 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
687 finfo.name, (double)finfo.size, lname));
689 do {
691 DEBUG(3,("nread=%.0f\n",(double)nread));
693 datalen = cli_read(cli, fnum, data, nread, read_size);
695 if (datalen == -1) {
696 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
697 break;
700 nread += datalen;
702 /* Only if the first read succeeds, write out the tar header. */
703 if (!wrote_tar_header) {
704 /* write a tar header, don't bother with mode - just set to 100644 */
705 writetarheader(tarhandle, rname, finfo.size,
706 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
707 wrote_tar_header = True;
710 /* if file size has increased since we made file size query, truncate
711 read so tar header for this file will be correct.
714 if (nread > finfo.size) {
715 datalen -= nread - finfo.size;
716 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
717 finfo.name, (double)finfo.size));
720 /* add received bits of file to buffer - dotarbuf will
721 * write out in 512 byte intervals */
723 if (dotarbuf(tarhandle,data,datalen) != datalen) {
724 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
725 break;
728 if ( (datalen == 0) && (finfo.size != 0) ) {
729 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
730 break;
733 datalen=0;
734 } while ( nread < finfo.size );
736 if (wrote_tar_header) {
737 /* pad tar file with zero's if we couldn't get entire file */
738 if (nread < finfo.size) {
739 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
740 (double)finfo.size, (int)nread));
741 if (padit(data, (SMB_BIG_UINT)sizeof(data), finfo.size - nread))
742 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
745 /* round tar file to nearest block */
746 if (finfo.size % TBLOCK)
747 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
749 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
750 ntarf++;
751 } else {
752 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
753 shallitime=0;
757 cli_close(cli, fnum);
758 fnum = -1;
760 if (shallitime) {
761 struct timeval tp_end;
762 int this_time;
764 /* if shallitime is true then we didn't skip */
765 if (tar_reset && !dry_run)
766 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
768 GetTimeOfDay(&tp_end);
769 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
770 get_total_time_ms += this_time;
771 get_total_size += finfo.size;
773 if (tar_noisy) {
774 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
775 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
776 finfo.name));
779 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
780 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
781 finfo.size / MAX(0.001, (1.024*this_time)),
782 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
785 cleanup:
787 if (fnum != -1) {
788 cli_close(cli, fnum);
789 fnum = -1;
791 TALLOC_FREE(ctx);
792 SAFE_FREE(data);
795 /****************************************************************************
796 Append single file to tar file (or not)
797 ***************************************************************************/
799 static void do_tar(file_info *finfo, const char *dir)
801 TALLOC_CTX *ctx = talloc_stackframe();
803 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
804 return;
806 /* Is it on the exclude list ? */
807 if (!tar_excl && clipn) {
808 char *exclaim;
810 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
812 exclaim = talloc_asprintf(ctx,
813 "%s\\%s",
814 client_get_cur_dir(),
815 finfo->name);
816 if (!exclaim) {
817 return;
820 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
822 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
823 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
824 DEBUG(3,("Skipping file %s\n", exclaim));
825 TALLOC_FREE(exclaim);
826 return;
828 TALLOC_FREE(exclaim);
831 if (finfo->mode & aDIR) {
832 char *saved_curdir = NULL;
833 char *new_cd = NULL;
834 char *mtar_mask = NULL;
836 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
837 if (!saved_curdir) {
838 return;
841 DEBUG(5, ("strlen(cur_dir)=%d, \
842 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
843 (int)strlen(saved_curdir),
844 (int)strlen(finfo->name), finfo->name, saved_curdir));
846 new_cd = talloc_asprintf(ctx,
847 "%s%s\\",
848 client_get_cur_dir(),
849 finfo->name);
850 if (!new_cd) {
851 return;
853 client_set_cur_dir(new_cd);
855 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
857 /* write a tar directory, don't bother with mode - just
858 * set it to 40755 */
859 writetarheader(tarhandle, client_get_cur_dir(), 0,
860 finfo->mtime_ts.tv_sec, "040755 \0", '5');
861 if (tar_noisy) {
862 DEBUG(0,(" directory %s\n",
863 client_get_cur_dir()));
865 ntarf++; /* Make sure we have a file on there */
866 mtar_mask = talloc_asprintf(ctx,
867 "%s*",
868 client_get_cur_dir());
869 if (!mtar_mask) {
870 return;
872 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
873 do_list(mtar_mask, attribute, do_tar, False, True);
874 client_set_cur_dir(saved_curdir);
875 TALLOC_FREE(saved_curdir);
876 TALLOC_FREE(new_cd);
877 TALLOC_FREE(mtar_mask);
878 } else {
879 char *rname = talloc_asprintf(ctx,
880 "%s%s",
881 client_get_cur_dir(),
882 finfo->name);
883 if (!rname) {
884 return;
886 do_atar(rname,finfo->name,finfo);
887 TALLOC_FREE(rname);
891 /****************************************************************************
892 Convert from UNIX to DOS file names
893 ***************************************************************************/
895 static void unfixtarname(char *tptr, char *fp, int l, bool first)
897 /* remove '.' from start of file name, convert from unix /'s to
898 * dos \'s in path. Kill any absolute path names. But only if first!
901 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
903 if (first) {
904 if (*fp == '.') {
905 fp++;
906 l--;
908 if (*fp == '\\' || *fp == '/') {
909 fp++;
910 l--;
914 safe_strcpy(tptr, fp, l);
915 string_replace(tptr, '/', '\\');
918 /****************************************************************************
919 Move to the next block in the buffer, which may mean read in another set of
920 blocks. FIXME, we should allow more than one block to be skipped.
921 ****************************************************************************/
923 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
925 int bufread, total = 0;
927 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
928 *bufferp += TBLOCK;
929 total = TBLOCK;
931 if (*bufferp >= (ltarbuf + bufsiz)) {
933 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
936 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
937 * Fixes bug where read can return short if coming from
938 * a pipe.
941 bufread = read(tarhandle, ltarbuf, bufsiz);
942 total = bufread;
944 while (total < bufsiz) {
945 if (bufread < 0) { /* An error, return false */
946 return (total > 0 ? -2 : bufread);
948 if (bufread == 0) {
949 if (total <= 0) {
950 return -2;
952 break;
954 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
955 total += bufread;
958 DEBUG(5, ("Total bytes read ... %i\n", total));
960 *bufferp = ltarbuf;
963 return(total);
966 /* Skip a file, even if it includes a long file name? */
967 static int skip_file(int skipsize)
969 int dsize = skipsize;
971 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
973 /* FIXME, we should skip more than one block at a time */
975 while (dsize > 0) {
976 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
977 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
978 return(False);
980 dsize -= TBLOCK;
983 return(True);
986 /*************************************************************
987 Get a file from the tar file and store it.
988 When this is called, tarbuf already contains the first
989 file block. This is a bit broken & needs fixing.
990 **************************************************************/
992 static int get_file(file_info2 finfo)
994 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
995 SMB_BIG_UINT rsize = 0;
997 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
999 if (ensurepath(finfo.name) &&
1000 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
1001 DEBUG(0, ("abandoning restore\n"));
1002 return(False);
1005 /* read the blocks from the tar file and write to the remote file */
1007 rsize = finfo.size; /* This is how much to write */
1009 while (rsize > 0) {
1011 /* We can only write up to the end of the buffer */
1012 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1013 dsize = MIN(dsize, rsize); /* Should be only what is left */
1014 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1016 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
1017 DEBUG(0, ("Error writing remote file\n"));
1018 return 0;
1021 rsize -= dsize;
1022 pos += dsize;
1024 /* Now figure out how much to move in the buffer */
1026 /* FIXME, we should skip more than one block at a time */
1028 /* First, skip any initial part of the part written that is left over */
1029 /* from the end of the first TBLOCK */
1031 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1032 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1033 bpos = 0;
1035 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1036 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1037 return False;
1042 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1043 * If the file being extracted is an exact multiple of
1044 * TBLOCK bytes then we don't want to extract the next
1045 * block from the tarfile here, as it will be done in
1046 * the caller of get_file().
1049 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1050 ((rsize == 0) && (dsize > TBLOCK))) {
1052 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1053 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1054 return False;
1057 dsize -= TBLOCK;
1059 bpos = dsize;
1062 /* Now close the file ... */
1064 if (!cli_close(cli, fnum)) {
1065 DEBUG(0, ("Error closing remote file\n"));
1066 return(False);
1069 /* Now we update the creation date ... */
1070 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1072 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec)) {
1073 if (tar_real_noisy) {
1074 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1075 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1079 ntarf++;
1080 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1081 return(True);
1084 /* Create a directory. We just ensure that the path exists and return as there
1085 is no file associated with a directory
1087 static int get_dir(file_info2 finfo)
1089 DEBUG(0, ("restore directory %s\n", finfo.name));
1091 if (!ensurepath(finfo.name)) {
1092 DEBUG(0, ("Problems creating directory\n"));
1093 return(False);
1095 ntarf++;
1096 return(True);
1099 /* Get a file with a long file name ... first file has file name, next file
1100 has the data. We only want the long file name, as the loop in do_tarput
1101 will deal with the rest.
1103 static char *get_longfilename(file_info2 finfo)
1105 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1106 * header call. */
1107 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1108 char *longname = (char *)SMB_MALLOC(namesize);
1109 int offset = 0, left = finfo.size;
1110 bool first = True;
1112 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1113 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1115 if (longname == NULL) {
1116 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1117 return(NULL);
1120 /* First, add cur_dir to the long file name */
1122 if (strlen(client_get_cur_dir()) > 0) {
1123 strncpy(longname, client_get_cur_dir(), namesize);
1124 offset = strlen(client_get_cur_dir());
1127 /* Loop through the blocks picking up the name */
1129 while (left > 0) {
1130 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1131 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1132 SAFE_FREE(longname);
1133 return(NULL);
1136 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1137 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1139 offset += TBLOCK;
1140 left -= TBLOCK;
1143 return(longname);
1146 static void do_tarput(void)
1148 file_info2 finfo;
1149 struct timeval tp_start;
1150 char *longfilename = NULL, linkflag;
1151 int skip = False;
1153 ZERO_STRUCT(finfo);
1155 GetTimeOfDay(&tp_start);
1156 DEBUG(5, ("RJS do_tarput called ...\n"));
1158 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1160 /* Now read through those files ... */
1161 while (True) {
1162 /* Get us to the next block, or the first block first time around */
1163 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1164 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1165 SAFE_FREE(longfilename);
1166 return;
1169 DEBUG(5, ("Reading the next header ...\n"));
1171 switch (readtarheader((union hblock *) buffer_p,
1172 &finfo, client_get_cur_dir())) {
1173 case -2: /* Hmm, not good, but not fatal */
1174 DEBUG(0, ("Skipping %s...\n", finfo.name));
1175 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1176 DEBUG(0, ("Short file, bailing out...\n"));
1177 return;
1179 break;
1181 case -1:
1182 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1183 return;
1185 case 0: /* chksum is zero - looks like an EOF */
1186 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1187 return; /* Hmmm, bad here ... */
1189 default:
1190 /* No action */
1191 break;
1194 /* Now, do we have a long file name? */
1195 if (longfilename != NULL) {
1196 SAFE_FREE(finfo.name); /* Free the space already allocated */
1197 finfo.name = longfilename;
1198 longfilename = NULL;
1201 /* Well, now we have a header, process the file ... */
1202 /* Should we skip the file? We have the long name as well here */
1203 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1204 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1206 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1207 if (skip) {
1208 skip_file(finfo.size);
1209 continue;
1212 /* We only get this far if we should process the file */
1213 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1214 switch (linkflag) {
1215 case '0': /* Should use symbolic names--FIXME */
1217 * Skip to the next block first, so we can get the file, FIXME, should
1218 * be in get_file ...
1219 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1220 * Fixes bug where file size in tarfile is zero.
1222 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1223 DEBUG(0, ("Short file, bailing out...\n"));
1224 return;
1226 if (!get_file(finfo)) {
1227 DEBUG(0, ("Abandoning restore\n"));
1228 return;
1230 break;
1231 case '5':
1232 if (!get_dir(finfo)) {
1233 DEBUG(0, ("Abandoning restore \n"));
1234 return;
1236 break;
1237 case 'L':
1238 SAFE_FREE(longfilename);
1239 longfilename = get_longfilename(finfo);
1240 if (!longfilename) {
1241 DEBUG(0, ("abandoning restore\n"));
1242 return;
1244 DEBUG(5, ("Long file name: %s\n", longfilename));
1245 break;
1247 default:
1248 skip_file(finfo.size); /* Don't handle these yet */
1249 break;
1255 * samba interactive commands
1258 /****************************************************************************
1259 Blocksize command
1260 ***************************************************************************/
1262 int cmd_block(void)
1264 TALLOC_CTX *ctx = talloc_tos();
1265 char *buf;
1266 int block;
1268 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1269 DEBUG(0, ("blocksize <n>\n"));
1270 return 1;
1273 block=atoi(buf);
1274 if (block < 0 || block > 65535) {
1275 DEBUG(0, ("blocksize out of range"));
1276 return 1;
1279 blocksize=block;
1280 DEBUG(2,("blocksize is now %d\n", blocksize));
1281 return 0;
1284 /****************************************************************************
1285 command to set incremental / reset mode
1286 ***************************************************************************/
1288 int cmd_tarmode(void)
1290 TALLOC_CTX *ctx = talloc_tos();
1291 char *buf;
1293 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1294 if (strequal(buf, "full"))
1295 tar_inc=False;
1296 else if (strequal(buf, "inc"))
1297 tar_inc=True;
1298 else if (strequal(buf, "reset"))
1299 tar_reset=True;
1300 else if (strequal(buf, "noreset"))
1301 tar_reset=False;
1302 else if (strequal(buf, "system"))
1303 tar_system=True;
1304 else if (strequal(buf, "nosystem"))
1305 tar_system=False;
1306 else if (strequal(buf, "hidden"))
1307 tar_hidden=True;
1308 else if (strequal(buf, "nohidden"))
1309 tar_hidden=False;
1310 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1311 tar_noisy=True;
1312 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1313 tar_noisy=False;
1314 else
1315 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1316 TALLOC_FREE(buf);
1319 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1320 tar_inc ? "incremental" : "full",
1321 tar_system ? "system" : "nosystem",
1322 tar_hidden ? "hidden" : "nohidden",
1323 tar_reset ? "reset" : "noreset",
1324 tar_noisy ? "verbose" : "quiet"));
1325 return 0;
1328 /****************************************************************************
1329 Feeble attrib command
1330 ***************************************************************************/
1332 int cmd_setmode(void)
1334 TALLOC_CTX *ctx = talloc_tos();
1335 char *q;
1336 char *buf;
1337 char *fname = NULL;
1338 uint16 attra[2];
1339 int direct=1;
1341 attra[0] = attra[1] = 0;
1343 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1344 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1345 return 1;
1348 fname = talloc_asprintf(ctx,
1349 "%s%s",
1350 client_get_cur_dir(),
1351 buf);
1352 if (!fname) {
1353 return 1;
1356 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1357 q=buf;
1359 while(*q) {
1360 switch (*q++) {
1361 case '+':
1362 direct=1;
1363 break;
1364 case '-':
1365 direct=0;
1366 break;
1367 case 'r':
1368 attra[direct]|=aRONLY;
1369 break;
1370 case 'h':
1371 attra[direct]|=aHIDDEN;
1372 break;
1373 case 's':
1374 attra[direct]|=aSYSTEM;
1375 break;
1376 case 'a':
1377 attra[direct]|=aARCH;
1378 break;
1379 default:
1380 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1381 return 1;
1386 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1387 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1388 return 1;
1391 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1392 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1393 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1394 return 0;
1398 Convert list of tokens to array; dependent on above routine.
1399 Uses the global cmd_ptr from above - bit of a hack.
1402 static char **toktocliplist(int *ctok, const char *sep)
1404 char *s=(char *)cmd_ptr;
1405 int ictok=0;
1406 char **ret, **iret;
1408 if (!sep)
1409 sep = " \t\n\r";
1411 while(*s && strchr_m(sep,*s))
1412 s++;
1414 /* nothing left? */
1415 if (!*s)
1416 return(NULL);
1418 do {
1419 ictok++;
1420 while(*s && (!strchr_m(sep,*s)))
1421 s++;
1422 while(*s && strchr_m(sep,*s))
1423 *s++=0;
1424 } while(*s);
1426 *ctok=ictok;
1427 s=(char *)cmd_ptr;
1429 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1430 return NULL;
1432 while(ictok--) {
1433 *iret++=s;
1434 if (ictok > 0) {
1435 while(*s++)
1437 while(!*s)
1438 s++;
1442 ret[*ctok] = NULL;
1443 return ret;
1446 /****************************************************************************
1447 Principal command for creating / extracting
1448 ***************************************************************************/
1450 int cmd_tar(void)
1452 TALLOC_CTX *ctx = talloc_tos();
1453 char *buf;
1454 char **argl = NULL;
1455 int argcl = 0;
1456 int ret;
1458 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1459 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1460 return 1;
1463 argl=toktocliplist(&argcl, NULL);
1464 if (!tar_parseargs(argcl, argl, buf, 0)) {
1465 SAFE_FREE(argl);
1466 return 1;
1469 ret = process_tar();
1470 SAFE_FREE(argl);
1471 return ret;
1474 /****************************************************************************
1475 Command line (option) version
1476 ***************************************************************************/
1478 int process_tar(void)
1480 TALLOC_CTX *ctx = talloc_tos();
1481 int rc = 0;
1482 initarbuf();
1483 switch(tar_type) {
1484 case 'x':
1486 #if 0
1487 do_tarput2();
1488 #else
1489 do_tarput();
1490 #endif
1491 SAFE_FREE(tarbuf);
1492 close(tarhandle);
1493 break;
1494 case 'r':
1495 case 'c':
1496 if (clipn && tar_excl) {
1497 int i;
1498 char *tarmac = NULL;
1500 for (i=0; i<clipn; i++) {
1501 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1503 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1504 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1507 if (strrchr_m(cliplist[i], '\\')) {
1508 char *p;
1509 char saved_char;
1510 char *saved_dir = talloc_strdup(ctx,
1511 client_get_cur_dir());
1512 if (!saved_dir) {
1513 return 1;
1516 if (*cliplist[i]=='\\') {
1517 tarmac = talloc_strdup(ctx,
1518 cliplist[i]);
1519 } else {
1520 tarmac = talloc_asprintf(ctx,
1521 "%s%s",
1522 client_get_cur_dir(),
1523 cliplist[i]);
1525 if (!tarmac) {
1526 return 1;
1529 * Strip off the last \\xxx
1530 * xxx element of tarmac to set
1531 * it as current directory.
1533 p = strrchr_m(tarmac, '\\');
1534 if (!p) {
1535 return 1;
1537 saved_char = p[1];
1538 p[1] = '\0';
1540 client_set_cur_dir(tarmac);
1543 * Restore the character we
1544 * just replaced to
1545 * put the pathname
1546 * back as it was.
1548 p[1] = saved_char;
1550 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1551 do_list(tarmac,attribute,do_tar, False, True);
1553 client_set_cur_dir(saved_dir);
1555 TALLOC_FREE(saved_dir);
1556 TALLOC_FREE(tarmac);
1557 } else {
1558 tarmac = talloc_asprintf(ctx,
1559 "%s%s",
1560 client_get_cur_dir(),
1561 cliplist[i]);
1562 if (!tarmac) {
1563 return 1;
1565 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1566 do_list(tarmac,attribute,do_tar, False, True);
1567 TALLOC_FREE(tarmac);
1570 } else {
1571 char *mask = talloc_asprintf(ctx,
1572 "%s\\*",
1573 client_get_cur_dir());
1574 if (!mask) {
1575 return 1;
1577 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1578 do_list(mask,attribute,do_tar,False, True);
1579 TALLOC_FREE(mask);
1582 if (ntarf) {
1583 dotareof(tarhandle);
1585 close(tarhandle);
1586 SAFE_FREE(tarbuf);
1588 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1589 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1590 break;
1593 if (must_free_cliplist) {
1594 int i;
1595 for (i = 0; i < clipn; ++i) {
1596 SAFE_FREE(cliplist[i]);
1598 SAFE_FREE(cliplist);
1599 cliplist = NULL;
1600 clipn = 0;
1601 must_free_cliplist = False;
1603 return rc;
1606 /****************************************************************************
1607 Find a token (filename) in a clip list
1608 ***************************************************************************/
1610 static int clipfind(char **aret, int ret, char *tok)
1612 if (aret==NULL)
1613 return 0;
1615 /* ignore leading slashes or dots in token */
1616 while(strchr_m("/\\.", *tok))
1617 tok++;
1619 while(ret--) {
1620 char *pkey=*aret++;
1622 /* ignore leading slashes or dots in list */
1623 while(strchr_m("/\\.", *pkey))
1624 pkey++;
1626 if (!strslashcmp(pkey, tok))
1627 return 1;
1629 return 0;
1632 /****************************************************************************
1633 Read list of files to include from the file and initialize cliplist
1634 accordingly.
1635 ***************************************************************************/
1637 static int read_inclusion_file(char *filename)
1639 XFILE *inclusion = NULL;
1640 char buf[PATH_MAX + 1];
1641 char *inclusion_buffer = NULL;
1642 int inclusion_buffer_size = 0;
1643 int inclusion_buffer_sofar = 0;
1644 char *p;
1645 char *tmpstr;
1646 int i;
1647 int error = 0;
1649 clipn = 0;
1650 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1651 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1652 /* XXX It would be better to include a reason for failure, but without
1653 * autoconf, it's hard to use strerror, sys_errlist, etc.
1655 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1656 return 0;
1659 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1660 if (inclusion_buffer == NULL) {
1661 inclusion_buffer_size = 1024;
1662 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1663 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1664 error = 1;
1665 break;
1669 if (buf[strlen(buf)-1] == '\n') {
1670 buf[strlen(buf)-1] = '\0';
1673 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1674 inclusion_buffer_size *= 2;
1675 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1676 if (!inclusion_buffer) {
1677 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1678 inclusion_buffer_size));
1679 error = 1;
1680 break;
1684 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1685 inclusion_buffer_sofar += strlen(buf) + 1;
1686 clipn++;
1688 x_fclose(inclusion);
1690 if (! error) {
1691 /* Allocate an array of clipn + 1 char*'s for cliplist */
1692 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1693 if (cliplist == NULL) {
1694 DEBUG(0,("failure allocating memory for cliplist\n"));
1695 error = 1;
1696 } else {
1697 cliplist[clipn] = NULL;
1698 p = inclusion_buffer;
1699 for (i = 0; (! error) && (i < clipn); i++) {
1700 /* set current item to NULL so array will be null-terminated even if
1701 * malloc fails below. */
1702 cliplist[i] = NULL;
1703 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1704 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1705 error = 1;
1706 } else {
1707 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1708 cliplist[i] = tmpstr;
1709 if ((p = strchr_m(p, '\000')) == NULL) {
1710 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1711 abort();
1714 ++p;
1716 must_free_cliplist = True;
1720 SAFE_FREE(inclusion_buffer);
1721 if (error) {
1722 if (cliplist) {
1723 char **pp;
1724 /* We know cliplist is always null-terminated */
1725 for (pp = cliplist; *pp; ++pp) {
1726 SAFE_FREE(*pp);
1728 SAFE_FREE(cliplist);
1729 cliplist = NULL;
1730 must_free_cliplist = False;
1732 return 0;
1735 /* cliplist and its elements are freed at the end of process_tar. */
1736 return 1;
1739 /****************************************************************************
1740 Parse tar arguments. Sets tar_type, tar_excl, etc.
1741 ***************************************************************************/
1743 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1745 int newOptind = Optind;
1746 char tar_clipfl='\0';
1748 /* Reset back to defaults - could be from interactive version
1749 * reset mode and archive mode left as they are though
1751 tar_type='\0';
1752 tar_excl=True;
1753 dry_run=False;
1755 while (*Optarg) {
1756 switch(*Optarg++) {
1757 case 'c':
1758 tar_type='c';
1759 break;
1760 case 'x':
1761 if (tar_type=='c') {
1762 printf("Tar must be followed by only one of c or x.\n");
1763 return 0;
1765 tar_type='x';
1766 break;
1767 case 'b':
1768 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1769 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1770 return 0;
1771 } else {
1772 Optind++;
1773 newOptind++;
1775 break;
1776 case 'g':
1777 tar_inc=True;
1778 break;
1779 case 'N':
1780 if (Optind>=argc) {
1781 DEBUG(0,("Option N must be followed by valid file name\n"));
1782 return 0;
1783 } else {
1784 SMB_STRUCT_STAT stbuf;
1786 if (sys_stat(argv[Optind], &stbuf) == 0) {
1787 newer_than = stbuf.st_mtime;
1788 DEBUG(1,("Getting files newer than %s",
1789 time_to_asc(newer_than)));
1790 newOptind++;
1791 Optind++;
1792 } else {
1793 DEBUG(0,("Error setting newer-than time\n"));
1794 return 0;
1797 break;
1798 case 'a':
1799 tar_reset=True;
1800 break;
1801 case 'q':
1802 tar_noisy=False;
1803 break;
1804 case 'I':
1805 if (tar_clipfl) {
1806 DEBUG(0,("Only one of I,X,F must be specified\n"));
1807 return 0;
1809 tar_clipfl='I';
1810 break;
1811 case 'X':
1812 if (tar_clipfl) {
1813 DEBUG(0,("Only one of I,X,F must be specified\n"));
1814 return 0;
1816 tar_clipfl='X';
1817 break;
1818 case 'F':
1819 if (tar_clipfl) {
1820 DEBUG(0,("Only one of I,X,F must be specified\n"));
1821 return 0;
1823 tar_clipfl='F';
1824 break;
1825 case 'r':
1826 DEBUG(0, ("tar_re_search set\n"));
1827 tar_re_search = True;
1828 break;
1829 case 'n':
1830 if (tar_type == 'c') {
1831 DEBUG(0, ("dry_run set\n"));
1832 dry_run = True;
1833 } else {
1834 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1835 return 0;
1837 break;
1838 default:
1839 DEBUG(0,("Unknown tar option\n"));
1840 return 0;
1844 if (!tar_type) {
1845 printf("Option T must be followed by one of c or x.\n");
1846 return 0;
1849 /* tar_excl is true if cliplist lists files to be included.
1850 * Both 'I' and 'F' mean include. */
1851 tar_excl=tar_clipfl!='X';
1853 if (tar_clipfl=='F') {
1854 if (argc-Optind-1 != 1) {
1855 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1856 return 0;
1858 newOptind++;
1859 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1860 if (! read_inclusion_file(argv[Optind+1])) {
1861 return 0;
1863 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1864 char *tmpstr;
1865 char **tmplist;
1866 int clipcount;
1868 cliplist=argv+Optind+1;
1869 clipn=argc-Optind-1;
1870 clipcount = clipn;
1872 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1873 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1874 return 0;
1877 for (clipcount = 0; clipcount < clipn; clipcount++) {
1879 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1881 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1882 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1883 SAFE_FREE(tmplist);
1884 return 0;
1887 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1888 tmplist[clipcount] = tmpstr;
1889 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1891 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1894 cliplist = tmplist;
1895 must_free_cliplist = True;
1897 newOptind += clipn;
1900 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1901 /* Doing regular expression seaches not from an inclusion file. */
1902 clipn=argc-Optind-1;
1903 cliplist=argv+Optind+1;
1904 newOptind += clipn;
1907 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1908 /* Sets tar handle to either 0 or 1, as appropriate */
1909 tarhandle=(tar_type=='c');
1911 * Make sure that dbf points to stderr if we are using stdout for
1912 * tar output
1914 if (tarhandle == 1) {
1915 dbf = x_stderr;
1917 if (!argv[Optind]) {
1918 DEBUG(0,("Must specify tar filename\n"));
1919 return 0;
1921 if (!strcmp(argv[Optind], "-")) {
1922 newOptind++;
1925 } else {
1926 if (tar_type=='c' && dry_run) {
1927 tarhandle=-1;
1928 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1929 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1930 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1931 return(0);
1933 newOptind++;
1936 return newOptind;