Properly destroy the pdb search object
[Samba.git] / source / client / clitar.c
blob135815c3cd7d11a848f13d1725ce0f5ae051483f
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 static const char *cmd_ptr = NULL;
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;
517 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
519 partpath = string_create_s(strlen(fname));
520 ffname = string_create_s(strlen(fname));
522 if ((partpath == NULL) || (ffname == NULL)){
523 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
524 SAFE_FREE(partpath);
525 SAFE_FREE(ffname);
526 return(False);
529 *partpath = 0;
531 /* fname copied to ffname so can strtok */
533 safe_strcpy(ffname, fname, strlen(fname));
535 /* do a `basename' on ffname, so don't try and make file name directory */
536 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
537 SAFE_FREE(partpath);
538 SAFE_FREE(ffname);
539 return True;
540 } else {
541 *basehack='\0';
544 p=strtok(ffname, "\\");
546 while (p) {
547 safe_strcat(partpath, p, strlen(fname) + 1);
549 if (!cli_chkpath(cli, partpath)) {
550 if (!cli_mkdir(cli, partpath)) {
551 SAFE_FREE(partpath);
552 SAFE_FREE(ffname);
553 DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
554 return False;
555 } else {
556 DEBUG(3, ("mkdirhiering %s\n", partpath));
560 safe_strcat(partpath, "\\", strlen(fname) + 1);
561 p = strtok(NULL,"/\\");
564 SAFE_FREE(partpath);
565 SAFE_FREE(ffname);
566 return True;
569 static int padit(char *buf, SMB_BIG_UINT bufsize, SMB_BIG_UINT padsize)
571 int berr= 0;
572 int bytestowrite;
574 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
575 memset(buf, 0, (size_t)bufsize);
576 while( !berr && padsize > 0 ) {
577 bytestowrite= (int)MIN(bufsize, padsize);
578 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
579 padsize -= bytestowrite;
582 return berr;
585 static void do_setrattr(char *name, uint16 attr, int set)
587 uint16 oldattr;
589 if (!cli_getatr(cli, name, &oldattr, NULL, NULL)) return;
591 if (set == ATTRSET) {
592 attr |= oldattr;
593 } else {
594 attr = oldattr & ~attr;
597 if (!cli_setatr(cli, name, attr, 0)) {
598 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
602 /****************************************************************************
603 append one remote file to the tar file
604 ***************************************************************************/
606 static void do_atar(const char *rname_in,char *lname,file_info *finfo1)
608 int fnum = -1;
609 SMB_BIG_UINT nread=0;
610 char ftype;
611 file_info2 finfo;
612 bool shallitime=True;
613 char *data = NULL;
614 int read_size = 65520;
615 int datalen=0;
616 char *rname = NULL;
617 TALLOC_CTX *ctx = talloc_stackframe();
619 struct timeval tp_start;
621 GetTimeOfDay(&tp_start);
623 data = SMB_MALLOC_ARRAY(char, read_size);
624 if (!data) {
625 DEBUG(0,("do_atar: out of memory.\n"));
626 goto cleanup;
629 ftype = '0'; /* An ordinary file ... */
631 ZERO_STRUCT(finfo);
633 finfo.size = finfo1 -> size;
634 finfo.mode = finfo1 -> mode;
635 finfo.uid = finfo1 -> uid;
636 finfo.gid = finfo1 -> gid;
637 finfo.mtime_ts = finfo1 -> mtime_ts;
638 finfo.atime_ts = finfo1 -> atime_ts;
639 finfo.ctime_ts = finfo1 -> ctime_ts;
641 if (dry_run) {
642 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
643 (double)finfo.size));
644 shallitime=0;
645 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
646 ntarf++;
647 goto cleanup;
650 rname = clean_name(ctx, rname_in);
651 if (!rname) {
652 goto cleanup;
655 fnum = cli_open(cli, rname, O_RDONLY, DENY_NONE);
657 if (fnum == -1) {
658 DEBUG(0,("%s opening remote file %s (%s)\n",
659 cli_errstr(cli),rname, client_get_cur_dir()));
660 goto cleanup;
663 finfo.name = string_create_s(strlen(rname));
664 if (finfo.name == NULL) {
665 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
666 goto cleanup;
669 safe_strcpy(finfo.name,rname, strlen(rname));
670 if (!finfo1) {
671 time_t atime, mtime;
672 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &atime, &mtime)) {
673 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
674 goto cleanup;
676 finfo.atime_ts = convert_time_t_to_timespec(atime);
677 finfo.mtime_ts = convert_time_t_to_timespec(mtime);
678 finfo.ctime_ts = finfo.mtime_ts;
681 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
683 if (tar_inc && !(finfo.mode & aARCH)) {
684 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
685 shallitime=0;
686 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
687 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
688 shallitime=0;
689 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
690 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
691 shallitime=0;
692 } else {
693 bool wrote_tar_header = False;
695 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
696 finfo.name, (double)finfo.size, lname));
698 do {
700 DEBUG(3,("nread=%.0f\n",(double)nread));
702 datalen = cli_read(cli, fnum, data, nread, read_size);
704 if (datalen == -1) {
705 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
706 break;
709 nread += datalen;
711 /* Only if the first read succeeds, write out the tar header. */
712 if (!wrote_tar_header) {
713 /* write a tar header, don't bother with mode - just set to 100644 */
714 writetarheader(tarhandle, rname, finfo.size,
715 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
716 wrote_tar_header = True;
719 /* if file size has increased since we made file size query, truncate
720 read so tar header for this file will be correct.
723 if (nread > finfo.size) {
724 datalen -= nread - finfo.size;
725 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
726 finfo.name, (double)finfo.size));
729 /* add received bits of file to buffer - dotarbuf will
730 * write out in 512 byte intervals */
732 if (dotarbuf(tarhandle,data,datalen) != datalen) {
733 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
734 break;
737 if ( (datalen == 0) && (finfo.size != 0) ) {
738 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
739 break;
742 datalen=0;
743 } while ( nread < finfo.size );
745 if (wrote_tar_header) {
746 /* pad tar file with zero's if we couldn't get entire file */
747 if (nread < finfo.size) {
748 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
749 (double)finfo.size, (int)nread));
750 if (padit(data, (SMB_BIG_UINT)sizeof(data), finfo.size - nread))
751 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
754 /* round tar file to nearest block */
755 if (finfo.size % TBLOCK)
756 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
758 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
759 ntarf++;
760 } else {
761 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
762 shallitime=0;
766 cli_close(cli, fnum);
767 fnum = -1;
769 if (shallitime) {
770 struct timeval tp_end;
771 int this_time;
773 /* if shallitime is true then we didn't skip */
774 if (tar_reset && !dry_run)
775 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
777 GetTimeOfDay(&tp_end);
778 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
779 get_total_time_ms += this_time;
780 get_total_size += finfo.size;
782 if (tar_noisy) {
783 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
784 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
785 finfo.name));
788 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
789 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
790 finfo.size / MAX(0.001, (1.024*this_time)),
791 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
794 cleanup:
796 if (fnum != -1) {
797 cli_close(cli, fnum);
798 fnum = -1;
800 TALLOC_FREE(ctx);
801 SAFE_FREE(data);
804 /****************************************************************************
805 Append single file to tar file (or not)
806 ***************************************************************************/
808 static void do_tar(file_info *finfo, const char *dir)
810 TALLOC_CTX *ctx = talloc_stackframe();
812 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
813 return;
815 /* Is it on the exclude list ? */
816 if (!tar_excl && clipn) {
817 char *exclaim;
819 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
821 exclaim = talloc_asprintf(ctx,
822 "%s\\%s",
823 client_get_cur_dir(),
824 finfo->name);
825 if (!exclaim) {
826 return;
829 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
831 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
832 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
833 DEBUG(3,("Skipping file %s\n", exclaim));
834 TALLOC_FREE(exclaim);
835 return;
837 TALLOC_FREE(exclaim);
840 if (finfo->mode & aDIR) {
841 char *saved_curdir = NULL;
842 char *new_cd = NULL;
843 char *mtar_mask = NULL;
845 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
846 if (!saved_curdir) {
847 return;
850 DEBUG(5, ("strlen(cur_dir)=%d, \
851 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
852 (int)strlen(saved_curdir),
853 (int)strlen(finfo->name), finfo->name, saved_curdir));
855 new_cd = talloc_asprintf(ctx,
856 "%s%s\\",
857 client_get_cur_dir(),
858 finfo->name);
859 if (!new_cd) {
860 return;
862 client_set_cur_dir(new_cd);
864 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
866 /* write a tar directory, don't bother with mode - just
867 * set it to 40755 */
868 writetarheader(tarhandle, client_get_cur_dir(), 0,
869 finfo->mtime_ts.tv_sec, "040755 \0", '5');
870 if (tar_noisy) {
871 DEBUG(0,(" directory %s\n",
872 client_get_cur_dir()));
874 ntarf++; /* Make sure we have a file on there */
875 mtar_mask = talloc_asprintf(ctx,
876 "%s*",
877 client_get_cur_dir());
878 if (!mtar_mask) {
879 return;
881 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
882 do_list(mtar_mask, attribute, do_tar, False, True);
883 client_set_cur_dir(saved_curdir);
884 TALLOC_FREE(saved_curdir);
885 TALLOC_FREE(new_cd);
886 TALLOC_FREE(mtar_mask);
887 } else {
888 char *rname = talloc_asprintf(ctx,
889 "%s%s",
890 client_get_cur_dir(),
891 finfo->name);
892 if (!rname) {
893 return;
895 do_atar(rname,finfo->name,finfo);
896 TALLOC_FREE(rname);
900 /****************************************************************************
901 Convert from UNIX to DOS file names
902 ***************************************************************************/
904 static void unfixtarname(char *tptr, char *fp, int l, bool first)
906 /* remove '.' from start of file name, convert from unix /'s to
907 * dos \'s in path. Kill any absolute path names. But only if first!
910 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
912 if (first) {
913 if (*fp == '.') {
914 fp++;
915 l--;
917 if (*fp == '\\' || *fp == '/') {
918 fp++;
919 l--;
923 safe_strcpy(tptr, fp, l);
924 string_replace(tptr, '/', '\\');
927 /****************************************************************************
928 Move to the next block in the buffer, which may mean read in another set of
929 blocks. FIXME, we should allow more than one block to be skipped.
930 ****************************************************************************/
932 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
934 int bufread, total = 0;
936 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
937 *bufferp += TBLOCK;
938 total = TBLOCK;
940 if (*bufferp >= (ltarbuf + bufsiz)) {
942 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
945 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
946 * Fixes bug where read can return short if coming from
947 * a pipe.
950 bufread = read(tarhandle, ltarbuf, bufsiz);
951 total = bufread;
953 while (total < bufsiz) {
954 if (bufread < 0) { /* An error, return false */
955 return (total > 0 ? -2 : bufread);
957 if (bufread == 0) {
958 if (total <= 0) {
959 return -2;
961 break;
963 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
964 total += bufread;
967 DEBUG(5, ("Total bytes read ... %i\n", total));
969 *bufferp = ltarbuf;
972 return(total);
975 /* Skip a file, even if it includes a long file name? */
976 static int skip_file(int skipsize)
978 int dsize = skipsize;
980 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
982 /* FIXME, we should skip more than one block at a time */
984 while (dsize > 0) {
985 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
986 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
987 return(False);
989 dsize -= TBLOCK;
992 return(True);
995 /*************************************************************
996 Get a file from the tar file and store it.
997 When this is called, tarbuf already contains the first
998 file block. This is a bit broken & needs fixing.
999 **************************************************************/
1001 static int get_file(file_info2 finfo)
1003 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
1004 SMB_BIG_UINT rsize = 0;
1006 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1008 if (ensurepath(finfo.name) &&
1009 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
1010 DEBUG(0, ("abandoning restore\n"));
1011 return(False);
1014 /* read the blocks from the tar file and write to the remote file */
1016 rsize = finfo.size; /* This is how much to write */
1018 while (rsize > 0) {
1020 /* We can only write up to the end of the buffer */
1021 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1022 dsize = MIN(dsize, rsize); /* Should be only what is left */
1023 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1025 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
1026 DEBUG(0, ("Error writing remote file\n"));
1027 return 0;
1030 rsize -= dsize;
1031 pos += dsize;
1033 /* Now figure out how much to move in the buffer */
1035 /* FIXME, we should skip more than one block at a time */
1037 /* First, skip any initial part of the part written that is left over */
1038 /* from the end of the first TBLOCK */
1040 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1041 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1042 bpos = 0;
1044 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1045 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1046 return False;
1051 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1052 * If the file being extracted is an exact multiple of
1053 * TBLOCK bytes then we don't want to extract the next
1054 * block from the tarfile here, as it will be done in
1055 * the caller of get_file().
1058 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1059 ((rsize == 0) && (dsize > TBLOCK))) {
1061 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1062 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1063 return False;
1066 dsize -= TBLOCK;
1068 bpos = dsize;
1071 /* Now close the file ... */
1073 if (!cli_close(cli, fnum)) {
1074 DEBUG(0, ("Error closing remote file\n"));
1075 return(False);
1078 /* Now we update the creation date ... */
1079 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1081 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec)) {
1082 if (tar_real_noisy) {
1083 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1084 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1088 ntarf++;
1089 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1090 return(True);
1093 /* Create a directory. We just ensure that the path exists and return as there
1094 is no file associated with a directory
1096 static int get_dir(file_info2 finfo)
1098 DEBUG(0, ("restore directory %s\n", finfo.name));
1100 if (!ensurepath(finfo.name)) {
1101 DEBUG(0, ("Problems creating directory\n"));
1102 return(False);
1104 ntarf++;
1105 return(True);
1108 /* Get a file with a long file name ... first file has file name, next file
1109 has the data. We only want the long file name, as the loop in do_tarput
1110 will deal with the rest.
1112 static char *get_longfilename(file_info2 finfo)
1114 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1115 * header call. */
1116 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1117 char *longname = (char *)SMB_MALLOC(namesize);
1118 int offset = 0, left = finfo.size;
1119 bool first = True;
1121 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1122 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1124 if (longname == NULL) {
1125 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1126 return(NULL);
1129 /* First, add cur_dir to the long file name */
1131 if (strlen(client_get_cur_dir()) > 0) {
1132 strncpy(longname, client_get_cur_dir(), namesize);
1133 offset = strlen(client_get_cur_dir());
1136 /* Loop through the blocks picking up the name */
1138 while (left > 0) {
1139 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1140 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1141 SAFE_FREE(longname);
1142 return(NULL);
1145 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1146 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1148 offset += TBLOCK;
1149 left -= TBLOCK;
1152 return(longname);
1155 static void do_tarput(void)
1157 file_info2 finfo;
1158 struct timeval tp_start;
1159 char *longfilename = NULL, linkflag;
1160 int skip = False;
1162 ZERO_STRUCT(finfo);
1164 GetTimeOfDay(&tp_start);
1165 DEBUG(5, ("RJS do_tarput called ...\n"));
1167 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1169 /* Now read through those files ... */
1170 while (True) {
1171 /* Get us to the next block, or the first block first time around */
1172 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1173 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1174 SAFE_FREE(longfilename);
1175 return;
1178 DEBUG(5, ("Reading the next header ...\n"));
1180 switch (readtarheader((union hblock *) buffer_p,
1181 &finfo, client_get_cur_dir())) {
1182 case -2: /* Hmm, not good, but not fatal */
1183 DEBUG(0, ("Skipping %s...\n", finfo.name));
1184 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1185 DEBUG(0, ("Short file, bailing out...\n"));
1186 return;
1188 break;
1190 case -1:
1191 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1192 return;
1194 case 0: /* chksum is zero - looks like an EOF */
1195 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1196 return; /* Hmmm, bad here ... */
1198 default:
1199 /* No action */
1200 break;
1203 /* Now, do we have a long file name? */
1204 if (longfilename != NULL) {
1205 SAFE_FREE(finfo.name); /* Free the space already allocated */
1206 finfo.name = longfilename;
1207 longfilename = NULL;
1210 /* Well, now we have a header, process the file ... */
1211 /* Should we skip the file? We have the long name as well here */
1212 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1213 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1215 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1216 if (skip) {
1217 skip_file(finfo.size);
1218 continue;
1221 /* We only get this far if we should process the file */
1222 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1223 switch (linkflag) {
1224 case '0': /* Should use symbolic names--FIXME */
1226 * Skip to the next block first, so we can get the file, FIXME, should
1227 * be in get_file ...
1228 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1229 * Fixes bug where file size in tarfile is zero.
1231 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1232 DEBUG(0, ("Short file, bailing out...\n"));
1233 return;
1235 if (!get_file(finfo)) {
1236 DEBUG(0, ("Abandoning restore\n"));
1237 return;
1239 break;
1240 case '5':
1241 if (!get_dir(finfo)) {
1242 DEBUG(0, ("Abandoning restore \n"));
1243 return;
1245 break;
1246 case 'L':
1247 SAFE_FREE(longfilename);
1248 longfilename = get_longfilename(finfo);
1249 if (!longfilename) {
1250 DEBUG(0, ("abandoning restore\n"));
1251 return;
1253 DEBUG(5, ("Long file name: %s\n", longfilename));
1254 break;
1256 default:
1257 skip_file(finfo.size); /* Don't handle these yet */
1258 break;
1264 * samba interactive commands
1267 /****************************************************************************
1268 Blocksize command
1269 ***************************************************************************/
1271 int cmd_block(void)
1273 TALLOC_CTX *ctx = talloc_tos();
1274 char *buf;
1275 int block;
1277 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1278 DEBUG(0, ("blocksize <n>\n"));
1279 return 1;
1282 block=atoi(buf);
1283 if (block < 0 || block > 65535) {
1284 DEBUG(0, ("blocksize out of range"));
1285 return 1;
1288 blocksize=block;
1289 DEBUG(2,("blocksize is now %d\n", blocksize));
1290 return 0;
1293 /****************************************************************************
1294 command to set incremental / reset mode
1295 ***************************************************************************/
1297 int cmd_tarmode(void)
1299 TALLOC_CTX *ctx = talloc_tos();
1300 char *buf;
1302 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1303 if (strequal(buf, "full"))
1304 tar_inc=False;
1305 else if (strequal(buf, "inc"))
1306 tar_inc=True;
1307 else if (strequal(buf, "reset"))
1308 tar_reset=True;
1309 else if (strequal(buf, "noreset"))
1310 tar_reset=False;
1311 else if (strequal(buf, "system"))
1312 tar_system=True;
1313 else if (strequal(buf, "nosystem"))
1314 tar_system=False;
1315 else if (strequal(buf, "hidden"))
1316 tar_hidden=True;
1317 else if (strequal(buf, "nohidden"))
1318 tar_hidden=False;
1319 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1320 tar_noisy=True;
1321 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1322 tar_noisy=False;
1323 else
1324 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1325 TALLOC_FREE(buf);
1328 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1329 tar_inc ? "incremental" : "full",
1330 tar_system ? "system" : "nosystem",
1331 tar_hidden ? "hidden" : "nohidden",
1332 tar_reset ? "reset" : "noreset",
1333 tar_noisy ? "verbose" : "quiet"));
1334 return 0;
1337 /****************************************************************************
1338 Feeble attrib command
1339 ***************************************************************************/
1341 int cmd_setmode(void)
1343 TALLOC_CTX *ctx = talloc_tos();
1344 char *q;
1345 char *buf;
1346 char *fname = NULL;
1347 uint16 attra[2];
1348 int direct=1;
1350 attra[0] = attra[1] = 0;
1352 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1353 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1354 return 1;
1357 fname = talloc_asprintf(ctx,
1358 "%s%s",
1359 client_get_cur_dir(),
1360 buf);
1361 if (!fname) {
1362 return 1;
1365 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1366 q=buf;
1368 while(*q) {
1369 switch (*q++) {
1370 case '+':
1371 direct=1;
1372 break;
1373 case '-':
1374 direct=0;
1375 break;
1376 case 'r':
1377 attra[direct]|=aRONLY;
1378 break;
1379 case 'h':
1380 attra[direct]|=aHIDDEN;
1381 break;
1382 case 's':
1383 attra[direct]|=aSYSTEM;
1384 break;
1385 case 'a':
1386 attra[direct]|=aARCH;
1387 break;
1388 default:
1389 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1390 return 1;
1395 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1396 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1397 return 1;
1400 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1401 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1402 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1403 return 0;
1407 Convert list of tokens to array; dependent on above routine.
1408 Uses the global cmd_ptr from above - bit of a hack.
1411 static char **toktocliplist(int *ctok, const char *sep)
1413 char *s=(char *)cmd_ptr;
1414 int ictok=0;
1415 char **ret, **iret;
1417 if (!sep)
1418 sep = " \t\n\r";
1420 while(*s && strchr_m(sep,*s))
1421 s++;
1423 /* nothing left? */
1424 if (!*s)
1425 return(NULL);
1427 do {
1428 ictok++;
1429 while(*s && (!strchr_m(sep,*s)))
1430 s++;
1431 while(*s && strchr_m(sep,*s))
1432 *s++=0;
1433 } while(*s);
1435 *ctok=ictok;
1436 s=(char *)cmd_ptr;
1438 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1439 return NULL;
1441 while(ictok--) {
1442 *iret++=s;
1443 if (ictok > 0) {
1444 while(*s++)
1446 while(!*s)
1447 s++;
1451 ret[*ctok] = NULL;
1452 return ret;
1455 /****************************************************************************
1456 Principal command for creating / extracting
1457 ***************************************************************************/
1459 int cmd_tar(void)
1461 TALLOC_CTX *ctx = talloc_tos();
1462 char *buf;
1463 char **argl = NULL;
1464 int argcl = 0;
1465 int ret;
1467 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1468 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1469 return 1;
1472 argl=toktocliplist(&argcl, NULL);
1473 if (!tar_parseargs(argcl, argl, buf, 0))
1474 return 1;
1476 ret = process_tar();
1477 SAFE_FREE(argl);
1478 return ret;
1481 /****************************************************************************
1482 Command line (option) version
1483 ***************************************************************************/
1485 int process_tar(void)
1487 TALLOC_CTX *ctx = talloc_tos();
1488 int rc = 0;
1489 initarbuf();
1490 switch(tar_type) {
1491 case 'x':
1493 #if 0
1494 do_tarput2();
1495 #else
1496 do_tarput();
1497 #endif
1498 SAFE_FREE(tarbuf);
1499 close(tarhandle);
1500 break;
1501 case 'r':
1502 case 'c':
1503 if (clipn && tar_excl) {
1504 int i;
1505 char *tarmac = NULL;
1507 for (i=0; i<clipn; i++) {
1508 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1510 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1511 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1514 if (strrchr_m(cliplist[i], '\\')) {
1515 char *p;
1516 char *saved_dir = talloc_strdup(ctx,
1517 client_get_cur_dir());
1518 if (!saved_dir) {
1519 return 1;
1522 if (*cliplist[i]=='\\') {
1523 tarmac = talloc_strdup(ctx,
1524 cliplist[i]);
1525 } else {
1526 tarmac = talloc_asprintf(ctx,
1527 "%s%s",
1528 client_get_cur_dir(),
1529 cliplist[i]);
1531 if (!tarmac) {
1532 return 1;
1534 p = strrchr_m(tarmac, '\\');
1535 if (!p) {
1536 return 1;
1538 p[1] = '\0';
1539 client_set_cur_dir(tarmac);
1541 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1542 do_list(tarmac,attribute,do_tar, False, True);
1544 client_set_cur_dir(saved_dir);
1546 TALLOC_FREE(saved_dir);
1547 TALLOC_FREE(tarmac);
1548 } else {
1549 tarmac = talloc_asprintf(ctx,
1550 "%s%s",
1551 client_get_cur_dir(),
1552 cliplist[i]);
1553 if (!tarmac) {
1554 return 1;
1556 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1557 do_list(tarmac,attribute,do_tar, False, True);
1558 TALLOC_FREE(tarmac);
1561 } else {
1562 char *mask = talloc_asprintf(ctx,
1563 "%s\\*",
1564 client_get_cur_dir());
1565 if (!mask) {
1566 return 1;
1568 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1569 do_list(mask,attribute,do_tar,False, True);
1570 TALLOC_FREE(mask);
1573 if (ntarf) {
1574 dotareof(tarhandle);
1576 close(tarhandle);
1577 SAFE_FREE(tarbuf);
1579 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1580 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1581 break;
1584 if (must_free_cliplist) {
1585 int i;
1586 for (i = 0; i < clipn; ++i) {
1587 SAFE_FREE(cliplist[i]);
1589 SAFE_FREE(cliplist);
1590 cliplist = NULL;
1591 clipn = 0;
1592 must_free_cliplist = False;
1594 return rc;
1597 /****************************************************************************
1598 Find a token (filename) in a clip list
1599 ***************************************************************************/
1601 static int clipfind(char **aret, int ret, char *tok)
1603 if (aret==NULL)
1604 return 0;
1606 /* ignore leading slashes or dots in token */
1607 while(strchr_m("/\\.", *tok))
1608 tok++;
1610 while(ret--) {
1611 char *pkey=*aret++;
1613 /* ignore leading slashes or dots in list */
1614 while(strchr_m("/\\.", *pkey))
1615 pkey++;
1617 if (!strslashcmp(pkey, tok))
1618 return 1;
1620 return 0;
1623 /****************************************************************************
1624 Read list of files to include from the file and initialize cliplist
1625 accordingly.
1626 ***************************************************************************/
1628 static int read_inclusion_file(char *filename)
1630 XFILE *inclusion = NULL;
1631 char buf[PATH_MAX + 1];
1632 char *inclusion_buffer = NULL;
1633 int inclusion_buffer_size = 0;
1634 int inclusion_buffer_sofar = 0;
1635 char *p;
1636 char *tmpstr;
1637 int i;
1638 int error = 0;
1640 clipn = 0;
1641 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1642 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1643 /* XXX It would be better to include a reason for failure, but without
1644 * autoconf, it's hard to use strerror, sys_errlist, etc.
1646 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1647 return 0;
1650 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1651 if (inclusion_buffer == NULL) {
1652 inclusion_buffer_size = 1024;
1653 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1654 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1655 error = 1;
1656 break;
1660 if (buf[strlen(buf)-1] == '\n') {
1661 buf[strlen(buf)-1] = '\0';
1664 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1665 inclusion_buffer_size *= 2;
1666 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1667 if (!inclusion_buffer) {
1668 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1669 inclusion_buffer_size));
1670 error = 1;
1671 break;
1675 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1676 inclusion_buffer_sofar += strlen(buf) + 1;
1677 clipn++;
1679 x_fclose(inclusion);
1681 if (! error) {
1682 /* Allocate an array of clipn + 1 char*'s for cliplist */
1683 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1684 if (cliplist == NULL) {
1685 DEBUG(0,("failure allocating memory for cliplist\n"));
1686 error = 1;
1687 } else {
1688 cliplist[clipn] = NULL;
1689 p = inclusion_buffer;
1690 for (i = 0; (! error) && (i < clipn); i++) {
1691 /* set current item to NULL so array will be null-terminated even if
1692 * malloc fails below. */
1693 cliplist[i] = NULL;
1694 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1695 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1696 error = 1;
1697 } else {
1698 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1699 cliplist[i] = tmpstr;
1700 if ((p = strchr_m(p, '\000')) == NULL) {
1701 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1702 abort();
1705 ++p;
1707 must_free_cliplist = True;
1711 SAFE_FREE(inclusion_buffer);
1712 if (error) {
1713 if (cliplist) {
1714 char **pp;
1715 /* We know cliplist is always null-terminated */
1716 for (pp = cliplist; *pp; ++pp) {
1717 SAFE_FREE(*pp);
1719 SAFE_FREE(cliplist);
1720 cliplist = NULL;
1721 must_free_cliplist = False;
1723 return 0;
1726 /* cliplist and its elements are freed at the end of process_tar. */
1727 return 1;
1730 /****************************************************************************
1731 Parse tar arguments. Sets tar_type, tar_excl, etc.
1732 ***************************************************************************/
1734 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1736 int newOptind = Optind;
1737 char tar_clipfl='\0';
1739 /* Reset back to defaults - could be from interactive version
1740 * reset mode and archive mode left as they are though
1742 tar_type='\0';
1743 tar_excl=True;
1744 dry_run=False;
1746 while (*Optarg) {
1747 switch(*Optarg++) {
1748 case 'c':
1749 tar_type='c';
1750 break;
1751 case 'x':
1752 if (tar_type=='c') {
1753 printf("Tar must be followed by only one of c or x.\n");
1754 return 0;
1756 tar_type='x';
1757 break;
1758 case 'b':
1759 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1760 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1761 return 0;
1762 } else {
1763 Optind++;
1764 newOptind++;
1766 break;
1767 case 'g':
1768 tar_inc=True;
1769 break;
1770 case 'N':
1771 if (Optind>=argc) {
1772 DEBUG(0,("Option N must be followed by valid file name\n"));
1773 return 0;
1774 } else {
1775 SMB_STRUCT_STAT stbuf;
1777 if (sys_stat(argv[Optind], &stbuf) == 0) {
1778 newer_than = stbuf.st_mtime;
1779 DEBUG(1,("Getting files newer than %s",
1780 time_to_asc(newer_than)));
1781 newOptind++;
1782 Optind++;
1783 } else {
1784 DEBUG(0,("Error setting newer-than time\n"));
1785 return 0;
1788 break;
1789 case 'a':
1790 tar_reset=True;
1791 break;
1792 case 'q':
1793 tar_noisy=False;
1794 break;
1795 case 'I':
1796 if (tar_clipfl) {
1797 DEBUG(0,("Only one of I,X,F must be specified\n"));
1798 return 0;
1800 tar_clipfl='I';
1801 break;
1802 case 'X':
1803 if (tar_clipfl) {
1804 DEBUG(0,("Only one of I,X,F must be specified\n"));
1805 return 0;
1807 tar_clipfl='X';
1808 break;
1809 case 'F':
1810 if (tar_clipfl) {
1811 DEBUG(0,("Only one of I,X,F must be specified\n"));
1812 return 0;
1814 tar_clipfl='F';
1815 break;
1816 case 'r':
1817 DEBUG(0, ("tar_re_search set\n"));
1818 tar_re_search = True;
1819 break;
1820 case 'n':
1821 if (tar_type == 'c') {
1822 DEBUG(0, ("dry_run set\n"));
1823 dry_run = True;
1824 } else {
1825 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1826 return 0;
1828 break;
1829 default:
1830 DEBUG(0,("Unknown tar option\n"));
1831 return 0;
1835 if (!tar_type) {
1836 printf("Option T must be followed by one of c or x.\n");
1837 return 0;
1840 /* tar_excl is true if cliplist lists files to be included.
1841 * Both 'I' and 'F' mean include. */
1842 tar_excl=tar_clipfl!='X';
1844 if (tar_clipfl=='F') {
1845 if (argc-Optind-1 != 1) {
1846 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1847 return 0;
1849 newOptind++;
1850 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1851 if (! read_inclusion_file(argv[Optind+1])) {
1852 return 0;
1854 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1855 char *tmpstr;
1856 char **tmplist;
1857 int clipcount;
1859 cliplist=argv+Optind+1;
1860 clipn=argc-Optind-1;
1861 clipcount = clipn;
1863 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1864 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1865 return 0;
1868 for (clipcount = 0; clipcount < clipn; clipcount++) {
1870 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1872 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1873 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1874 SAFE_FREE(tmplist);
1875 return 0;
1878 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1879 tmplist[clipcount] = tmpstr;
1880 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1882 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1885 cliplist = tmplist;
1886 must_free_cliplist = True;
1888 newOptind += clipn;
1891 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1892 /* Doing regular expression seaches not from an inclusion file. */
1893 clipn=argc-Optind-1;
1894 cliplist=argv+Optind+1;
1895 newOptind += clipn;
1898 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1899 /* Sets tar handle to either 0 or 1, as appropriate */
1900 tarhandle=(tar_type=='c');
1902 * Make sure that dbf points to stderr if we are using stdout for
1903 * tar output
1905 if (tarhandle == 1) {
1906 dbf = x_stderr;
1908 if (!argv[Optind]) {
1909 DEBUG(0,("Must specify tar filename\n"));
1910 return 0;
1912 if (!strcmp(argv[Optind], "-")) {
1913 newOptind++;
1916 } else {
1917 if (tar_type=='c' && dry_run) {
1918 tarhandle=-1;
1919 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1920 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1921 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1922 return(0);
1924 newOptind++;
1927 return newOptind;