Fix IDL for lsa_LookupSids3.
[Samba/gebeck_regimport.git] / source3 / client / clitar.c
blob04cc987889428937047e56e5b9e83baa22f1ec4d
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;
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));
671 if (!finfo1) {
672 time_t atime, mtime;
673 if (!cli_getattrE(cli, fnum, &finfo.mode, &finfo.size, NULL, &atime, &mtime)) {
674 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli)));
675 goto cleanup;
677 finfo.atime_ts = convert_time_t_to_timespec(atime);
678 finfo.mtime_ts = convert_time_t_to_timespec(mtime);
679 finfo.ctime_ts = finfo.mtime_ts;
682 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
684 if (tar_inc && !(finfo.mode & aARCH)) {
685 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
686 shallitime=0;
687 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
688 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
689 shallitime=0;
690 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
691 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
692 shallitime=0;
693 } else {
694 bool wrote_tar_header = False;
696 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
697 finfo.name, (double)finfo.size, lname));
699 do {
701 DEBUG(3,("nread=%.0f\n",(double)nread));
703 datalen = cli_read(cli, fnum, data, nread, read_size);
705 if (datalen == -1) {
706 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
707 break;
710 nread += datalen;
712 /* Only if the first read succeeds, write out the tar header. */
713 if (!wrote_tar_header) {
714 /* write a tar header, don't bother with mode - just set to 100644 */
715 writetarheader(tarhandle, rname, finfo.size,
716 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
717 wrote_tar_header = True;
720 /* if file size has increased since we made file size query, truncate
721 read so tar header for this file will be correct.
724 if (nread > finfo.size) {
725 datalen -= nread - finfo.size;
726 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
727 finfo.name, (double)finfo.size));
730 /* add received bits of file to buffer - dotarbuf will
731 * write out in 512 byte intervals */
733 if (dotarbuf(tarhandle,data,datalen) != datalen) {
734 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
735 break;
738 if ( (datalen == 0) && (finfo.size != 0) ) {
739 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
740 break;
743 datalen=0;
744 } while ( nread < finfo.size );
746 if (wrote_tar_header) {
747 /* pad tar file with zero's if we couldn't get entire file */
748 if (nread < finfo.size) {
749 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
750 (double)finfo.size, (int)nread));
751 if (padit(data, (SMB_BIG_UINT)sizeof(data), finfo.size - nread))
752 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
755 /* round tar file to nearest block */
756 if (finfo.size % TBLOCK)
757 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
759 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
760 ntarf++;
761 } else {
762 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
763 shallitime=0;
767 cli_close(cli, fnum);
768 fnum = -1;
770 if (shallitime) {
771 struct timeval tp_end;
772 int this_time;
774 /* if shallitime is true then we didn't skip */
775 if (tar_reset && !dry_run)
776 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
778 GetTimeOfDay(&tp_end);
779 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
780 get_total_time_ms += this_time;
781 get_total_size += finfo.size;
783 if (tar_noisy) {
784 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
785 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
786 finfo.name));
789 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
790 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
791 finfo.size / MAX(0.001, (1.024*this_time)),
792 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
795 cleanup:
797 if (fnum != -1) {
798 cli_close(cli, fnum);
799 fnum = -1;
801 TALLOC_FREE(ctx);
802 SAFE_FREE(data);
805 /****************************************************************************
806 Append single file to tar file (or not)
807 ***************************************************************************/
809 static void do_tar(file_info *finfo, const char *dir)
811 TALLOC_CTX *ctx = talloc_stackframe();
813 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
814 return;
816 /* Is it on the exclude list ? */
817 if (!tar_excl && clipn) {
818 char *exclaim;
820 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
822 exclaim = talloc_asprintf(ctx,
823 "%s\\%s",
824 client_get_cur_dir(),
825 finfo->name);
826 if (!exclaim) {
827 return;
830 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
832 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
833 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
834 DEBUG(3,("Skipping file %s\n", exclaim));
835 TALLOC_FREE(exclaim);
836 return;
838 TALLOC_FREE(exclaim);
841 if (finfo->mode & aDIR) {
842 char *saved_curdir = NULL;
843 char *new_cd = NULL;
844 char *mtar_mask = NULL;
846 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
847 if (!saved_curdir) {
848 return;
851 DEBUG(5, ("strlen(cur_dir)=%d, \
852 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
853 (int)strlen(saved_curdir),
854 (int)strlen(finfo->name), finfo->name, saved_curdir));
856 new_cd = talloc_asprintf(ctx,
857 "%s%s\\",
858 client_get_cur_dir(),
859 finfo->name);
860 if (!new_cd) {
861 return;
863 client_set_cur_dir(new_cd);
865 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
867 /* write a tar directory, don't bother with mode - just
868 * set it to 40755 */
869 writetarheader(tarhandle, client_get_cur_dir(), 0,
870 finfo->mtime_ts.tv_sec, "040755 \0", '5');
871 if (tar_noisy) {
872 DEBUG(0,(" directory %s\n",
873 client_get_cur_dir()));
875 ntarf++; /* Make sure we have a file on there */
876 mtar_mask = talloc_asprintf(ctx,
877 "%s*",
878 client_get_cur_dir());
879 if (!mtar_mask) {
880 return;
882 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
883 do_list(mtar_mask, attribute, do_tar, False, True);
884 client_set_cur_dir(saved_curdir);
885 TALLOC_FREE(saved_curdir);
886 TALLOC_FREE(new_cd);
887 TALLOC_FREE(mtar_mask);
888 } else {
889 char *rname = talloc_asprintf(ctx,
890 "%s%s",
891 client_get_cur_dir(),
892 finfo->name);
893 if (!rname) {
894 return;
896 do_atar(rname,finfo->name,finfo);
897 TALLOC_FREE(rname);
901 /****************************************************************************
902 Convert from UNIX to DOS file names
903 ***************************************************************************/
905 static void unfixtarname(char *tptr, char *fp, int l, bool first)
907 /* remove '.' from start of file name, convert from unix /'s to
908 * dos \'s in path. Kill any absolute path names. But only if first!
911 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
913 if (first) {
914 if (*fp == '.') {
915 fp++;
916 l--;
918 if (*fp == '\\' || *fp == '/') {
919 fp++;
920 l--;
924 safe_strcpy(tptr, fp, l);
925 string_replace(tptr, '/', '\\');
928 /****************************************************************************
929 Move to the next block in the buffer, which may mean read in another set of
930 blocks. FIXME, we should allow more than one block to be skipped.
931 ****************************************************************************/
933 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
935 int bufread, total = 0;
937 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
938 *bufferp += TBLOCK;
939 total = TBLOCK;
941 if (*bufferp >= (ltarbuf + bufsiz)) {
943 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
946 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
947 * Fixes bug where read can return short if coming from
948 * a pipe.
951 bufread = read(tarhandle, ltarbuf, bufsiz);
952 total = bufread;
954 while (total < bufsiz) {
955 if (bufread < 0) { /* An error, return false */
956 return (total > 0 ? -2 : bufread);
958 if (bufread == 0) {
959 if (total <= 0) {
960 return -2;
962 break;
964 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
965 total += bufread;
968 DEBUG(5, ("Total bytes read ... %i\n", total));
970 *bufferp = ltarbuf;
973 return(total);
976 /* Skip a file, even if it includes a long file name? */
977 static int skip_file(int skipsize)
979 int dsize = skipsize;
981 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
983 /* FIXME, we should skip more than one block at a time */
985 while (dsize > 0) {
986 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
987 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
988 return(False);
990 dsize -= TBLOCK;
993 return(True);
996 /*************************************************************
997 Get a file from the tar file and store it.
998 When this is called, tarbuf already contains the first
999 file block. This is a bit broken & needs fixing.
1000 **************************************************************/
1002 static int get_file(file_info2 finfo)
1004 int fnum = -1, pos = 0, dsize = 0, bpos = 0;
1005 SMB_BIG_UINT rsize = 0;
1007 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1009 if (ensurepath(finfo.name) &&
1010 (fnum=cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) == -1) {
1011 DEBUG(0, ("abandoning restore\n"));
1012 return(False);
1015 /* read the blocks from the tar file and write to the remote file */
1017 rsize = finfo.size; /* This is how much to write */
1019 while (rsize > 0) {
1021 /* We can only write up to the end of the buffer */
1022 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1023 dsize = MIN(dsize, rsize); /* Should be only what is left */
1024 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1026 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
1027 DEBUG(0, ("Error writing remote file\n"));
1028 return 0;
1031 rsize -= dsize;
1032 pos += dsize;
1034 /* Now figure out how much to move in the buffer */
1036 /* FIXME, we should skip more than one block at a time */
1038 /* First, skip any initial part of the part written that is left over */
1039 /* from the end of the first TBLOCK */
1041 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1042 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1043 bpos = 0;
1045 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1046 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1047 return False;
1052 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1053 * If the file being extracted is an exact multiple of
1054 * TBLOCK bytes then we don't want to extract the next
1055 * block from the tarfile here, as it will be done in
1056 * the caller of get_file().
1059 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1060 ((rsize == 0) && (dsize > TBLOCK))) {
1062 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1063 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1064 return False;
1067 dsize -= TBLOCK;
1069 bpos = dsize;
1072 /* Now close the file ... */
1074 if (!cli_close(cli, fnum)) {
1075 DEBUG(0, ("Error closing remote file\n"));
1076 return(False);
1079 /* Now we update the creation date ... */
1080 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1082 if (!cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec)) {
1083 if (tar_real_noisy) {
1084 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1085 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1089 ntarf++;
1090 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1091 return(True);
1094 /* Create a directory. We just ensure that the path exists and return as there
1095 is no file associated with a directory
1097 static int get_dir(file_info2 finfo)
1099 DEBUG(0, ("restore directory %s\n", finfo.name));
1101 if (!ensurepath(finfo.name)) {
1102 DEBUG(0, ("Problems creating directory\n"));
1103 return(False);
1105 ntarf++;
1106 return(True);
1109 /* Get a file with a long file name ... first file has file name, next file
1110 has the data. We only want the long file name, as the loop in do_tarput
1111 will deal with the rest.
1113 static char *get_longfilename(file_info2 finfo)
1115 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1116 * header call. */
1117 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1118 char *longname = (char *)SMB_MALLOC(namesize);
1119 int offset = 0, left = finfo.size;
1120 bool first = True;
1122 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1123 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1125 if (longname == NULL) {
1126 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1127 return(NULL);
1130 /* First, add cur_dir to the long file name */
1132 if (strlen(client_get_cur_dir()) > 0) {
1133 strncpy(longname, client_get_cur_dir(), namesize);
1134 offset = strlen(client_get_cur_dir());
1137 /* Loop through the blocks picking up the name */
1139 while (left > 0) {
1140 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1141 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1142 SAFE_FREE(longname);
1143 return(NULL);
1146 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1147 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1149 offset += TBLOCK;
1150 left -= TBLOCK;
1153 return(longname);
1156 static void do_tarput(void)
1158 file_info2 finfo;
1159 struct timeval tp_start;
1160 char *longfilename = NULL, linkflag;
1161 int skip = False;
1163 ZERO_STRUCT(finfo);
1165 GetTimeOfDay(&tp_start);
1166 DEBUG(5, ("RJS do_tarput called ...\n"));
1168 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1170 /* Now read through those files ... */
1171 while (True) {
1172 /* Get us to the next block, or the first block first time around */
1173 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1174 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1175 SAFE_FREE(longfilename);
1176 return;
1179 DEBUG(5, ("Reading the next header ...\n"));
1181 switch (readtarheader((union hblock *) buffer_p,
1182 &finfo, client_get_cur_dir())) {
1183 case -2: /* Hmm, not good, but not fatal */
1184 DEBUG(0, ("Skipping %s...\n", finfo.name));
1185 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1186 DEBUG(0, ("Short file, bailing out...\n"));
1187 return;
1189 break;
1191 case -1:
1192 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1193 return;
1195 case 0: /* chksum is zero - looks like an EOF */
1196 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1197 return; /* Hmmm, bad here ... */
1199 default:
1200 /* No action */
1201 break;
1204 /* Now, do we have a long file name? */
1205 if (longfilename != NULL) {
1206 SAFE_FREE(finfo.name); /* Free the space already allocated */
1207 finfo.name = longfilename;
1208 longfilename = NULL;
1211 /* Well, now we have a header, process the file ... */
1212 /* Should we skip the file? We have the long name as well here */
1213 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1214 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1216 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1217 if (skip) {
1218 skip_file(finfo.size);
1219 continue;
1222 /* We only get this far if we should process the file */
1223 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1224 switch (linkflag) {
1225 case '0': /* Should use symbolic names--FIXME */
1227 * Skip to the next block first, so we can get the file, FIXME, should
1228 * be in get_file ...
1229 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1230 * Fixes bug where file size in tarfile is zero.
1232 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1233 DEBUG(0, ("Short file, bailing out...\n"));
1234 return;
1236 if (!get_file(finfo)) {
1237 DEBUG(0, ("Abandoning restore\n"));
1238 return;
1240 break;
1241 case '5':
1242 if (!get_dir(finfo)) {
1243 DEBUG(0, ("Abandoning restore \n"));
1244 return;
1246 break;
1247 case 'L':
1248 SAFE_FREE(longfilename);
1249 longfilename = get_longfilename(finfo);
1250 if (!longfilename) {
1251 DEBUG(0, ("abandoning restore\n"));
1252 return;
1254 DEBUG(5, ("Long file name: %s\n", longfilename));
1255 break;
1257 default:
1258 skip_file(finfo.size); /* Don't handle these yet */
1259 break;
1265 * samba interactive commands
1268 /****************************************************************************
1269 Blocksize command
1270 ***************************************************************************/
1272 int cmd_block(void)
1274 TALLOC_CTX *ctx = talloc_tos();
1275 char *buf;
1276 int block;
1278 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1279 DEBUG(0, ("blocksize <n>\n"));
1280 return 1;
1283 block=atoi(buf);
1284 if (block < 0 || block > 65535) {
1285 DEBUG(0, ("blocksize out of range"));
1286 return 1;
1289 blocksize=block;
1290 DEBUG(2,("blocksize is now %d\n", blocksize));
1291 return 0;
1294 /****************************************************************************
1295 command to set incremental / reset mode
1296 ***************************************************************************/
1298 int cmd_tarmode(void)
1300 TALLOC_CTX *ctx = talloc_tos();
1301 char *buf;
1303 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1304 if (strequal(buf, "full"))
1305 tar_inc=False;
1306 else if (strequal(buf, "inc"))
1307 tar_inc=True;
1308 else if (strequal(buf, "reset"))
1309 tar_reset=True;
1310 else if (strequal(buf, "noreset"))
1311 tar_reset=False;
1312 else if (strequal(buf, "system"))
1313 tar_system=True;
1314 else if (strequal(buf, "nosystem"))
1315 tar_system=False;
1316 else if (strequal(buf, "hidden"))
1317 tar_hidden=True;
1318 else if (strequal(buf, "nohidden"))
1319 tar_hidden=False;
1320 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1321 tar_noisy=True;
1322 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1323 tar_noisy=False;
1324 else
1325 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1326 TALLOC_FREE(buf);
1329 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1330 tar_inc ? "incremental" : "full",
1331 tar_system ? "system" : "nosystem",
1332 tar_hidden ? "hidden" : "nohidden",
1333 tar_reset ? "reset" : "noreset",
1334 tar_noisy ? "verbose" : "quiet"));
1335 return 0;
1338 /****************************************************************************
1339 Feeble attrib command
1340 ***************************************************************************/
1342 int cmd_setmode(void)
1344 TALLOC_CTX *ctx = talloc_tos();
1345 char *q;
1346 char *buf;
1347 char *fname = NULL;
1348 uint16 attra[2];
1349 int direct=1;
1351 attra[0] = attra[1] = 0;
1353 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1354 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1355 return 1;
1358 fname = talloc_asprintf(ctx,
1359 "%s%s",
1360 client_get_cur_dir(),
1361 buf);
1362 if (!fname) {
1363 return 1;
1366 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1367 q=buf;
1369 while(*q) {
1370 switch (*q++) {
1371 case '+':
1372 direct=1;
1373 break;
1374 case '-':
1375 direct=0;
1376 break;
1377 case 'r':
1378 attra[direct]|=aRONLY;
1379 break;
1380 case 'h':
1381 attra[direct]|=aHIDDEN;
1382 break;
1383 case 's':
1384 attra[direct]|=aSYSTEM;
1385 break;
1386 case 'a':
1387 attra[direct]|=aARCH;
1388 break;
1389 default:
1390 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1391 return 1;
1396 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1397 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1398 return 1;
1401 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1402 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1403 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1404 return 0;
1408 Convert list of tokens to array; dependent on above routine.
1409 Uses the global cmd_ptr from above - bit of a hack.
1412 static char **toktocliplist(int *ctok, const char *sep)
1414 char *s=(char *)cmd_ptr;
1415 int ictok=0;
1416 char **ret, **iret;
1418 if (!sep)
1419 sep = " \t\n\r";
1421 while(*s && strchr_m(sep,*s))
1422 s++;
1424 /* nothing left? */
1425 if (!*s)
1426 return(NULL);
1428 do {
1429 ictok++;
1430 while(*s && (!strchr_m(sep,*s)))
1431 s++;
1432 while(*s && strchr_m(sep,*s))
1433 *s++=0;
1434 } while(*s);
1436 *ctok=ictok;
1437 s=(char *)cmd_ptr;
1439 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1440 return NULL;
1442 while(ictok--) {
1443 *iret++=s;
1444 if (ictok > 0) {
1445 while(*s++)
1447 while(!*s)
1448 s++;
1452 ret[*ctok] = NULL;
1453 return ret;
1456 /****************************************************************************
1457 Principal command for creating / extracting
1458 ***************************************************************************/
1460 int cmd_tar(void)
1462 TALLOC_CTX *ctx = talloc_tos();
1463 char *buf;
1464 char **argl = NULL;
1465 int argcl = 0;
1466 int ret;
1468 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1469 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1470 return 1;
1473 argl=toktocliplist(&argcl, NULL);
1474 if (!tar_parseargs(argcl, argl, buf, 0)) {
1475 SAFE_FREE(argl);
1476 return 1;
1479 ret = process_tar();
1480 SAFE_FREE(argl);
1481 return ret;
1484 /****************************************************************************
1485 Command line (option) version
1486 ***************************************************************************/
1488 int process_tar(void)
1490 TALLOC_CTX *ctx = talloc_tos();
1491 int rc = 0;
1492 initarbuf();
1493 switch(tar_type) {
1494 case 'x':
1496 #if 0
1497 do_tarput2();
1498 #else
1499 do_tarput();
1500 #endif
1501 SAFE_FREE(tarbuf);
1502 close(tarhandle);
1503 break;
1504 case 'r':
1505 case 'c':
1506 if (clipn && tar_excl) {
1507 int i;
1508 char *tarmac = NULL;
1510 for (i=0; i<clipn; i++) {
1511 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1513 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1514 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1517 if (strrchr_m(cliplist[i], '\\')) {
1518 char *p;
1519 char *saved_dir = talloc_strdup(ctx,
1520 client_get_cur_dir());
1521 if (!saved_dir) {
1522 return 1;
1525 if (*cliplist[i]=='\\') {
1526 tarmac = talloc_strdup(ctx,
1527 cliplist[i]);
1528 } else {
1529 tarmac = talloc_asprintf(ctx,
1530 "%s%s",
1531 client_get_cur_dir(),
1532 cliplist[i]);
1534 if (!tarmac) {
1535 return 1;
1537 p = strrchr_m(tarmac, '\\');
1538 if (!p) {
1539 return 1;
1541 p[1] = '\0';
1542 client_set_cur_dir(tarmac);
1544 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1545 do_list(tarmac,attribute,do_tar, False, True);
1547 client_set_cur_dir(saved_dir);
1549 TALLOC_FREE(saved_dir);
1550 TALLOC_FREE(tarmac);
1551 } else {
1552 tarmac = talloc_asprintf(ctx,
1553 "%s%s",
1554 client_get_cur_dir(),
1555 cliplist[i]);
1556 if (!tarmac) {
1557 return 1;
1559 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1560 do_list(tarmac,attribute,do_tar, False, True);
1561 TALLOC_FREE(tarmac);
1564 } else {
1565 char *mask = talloc_asprintf(ctx,
1566 "%s\\*",
1567 client_get_cur_dir());
1568 if (!mask) {
1569 return 1;
1571 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1572 do_list(mask,attribute,do_tar,False, True);
1573 TALLOC_FREE(mask);
1576 if (ntarf) {
1577 dotareof(tarhandle);
1579 close(tarhandle);
1580 SAFE_FREE(tarbuf);
1582 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1583 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1584 break;
1587 if (must_free_cliplist) {
1588 int i;
1589 for (i = 0; i < clipn; ++i) {
1590 SAFE_FREE(cliplist[i]);
1592 SAFE_FREE(cliplist);
1593 cliplist = NULL;
1594 clipn = 0;
1595 must_free_cliplist = False;
1597 return rc;
1600 /****************************************************************************
1601 Find a token (filename) in a clip list
1602 ***************************************************************************/
1604 static int clipfind(char **aret, int ret, char *tok)
1606 if (aret==NULL)
1607 return 0;
1609 /* ignore leading slashes or dots in token */
1610 while(strchr_m("/\\.", *tok))
1611 tok++;
1613 while(ret--) {
1614 char *pkey=*aret++;
1616 /* ignore leading slashes or dots in list */
1617 while(strchr_m("/\\.", *pkey))
1618 pkey++;
1620 if (!strslashcmp(pkey, tok))
1621 return 1;
1623 return 0;
1626 /****************************************************************************
1627 Read list of files to include from the file and initialize cliplist
1628 accordingly.
1629 ***************************************************************************/
1631 static int read_inclusion_file(char *filename)
1633 XFILE *inclusion = NULL;
1634 char buf[PATH_MAX + 1];
1635 char *inclusion_buffer = NULL;
1636 int inclusion_buffer_size = 0;
1637 int inclusion_buffer_sofar = 0;
1638 char *p;
1639 char *tmpstr;
1640 int i;
1641 int error = 0;
1643 clipn = 0;
1644 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1645 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1646 /* XXX It would be better to include a reason for failure, but without
1647 * autoconf, it's hard to use strerror, sys_errlist, etc.
1649 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1650 return 0;
1653 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1654 if (inclusion_buffer == NULL) {
1655 inclusion_buffer_size = 1024;
1656 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1657 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1658 error = 1;
1659 break;
1663 if (buf[strlen(buf)-1] == '\n') {
1664 buf[strlen(buf)-1] = '\0';
1667 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1668 inclusion_buffer_size *= 2;
1669 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1670 if (!inclusion_buffer) {
1671 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1672 inclusion_buffer_size));
1673 error = 1;
1674 break;
1678 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1679 inclusion_buffer_sofar += strlen(buf) + 1;
1680 clipn++;
1682 x_fclose(inclusion);
1684 if (! error) {
1685 /* Allocate an array of clipn + 1 char*'s for cliplist */
1686 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1687 if (cliplist == NULL) {
1688 DEBUG(0,("failure allocating memory for cliplist\n"));
1689 error = 1;
1690 } else {
1691 cliplist[clipn] = NULL;
1692 p = inclusion_buffer;
1693 for (i = 0; (! error) && (i < clipn); i++) {
1694 /* set current item to NULL so array will be null-terminated even if
1695 * malloc fails below. */
1696 cliplist[i] = NULL;
1697 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1698 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1699 error = 1;
1700 } else {
1701 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1702 cliplist[i] = tmpstr;
1703 if ((p = strchr_m(p, '\000')) == NULL) {
1704 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1705 abort();
1708 ++p;
1710 must_free_cliplist = True;
1714 SAFE_FREE(inclusion_buffer);
1715 if (error) {
1716 if (cliplist) {
1717 char **pp;
1718 /* We know cliplist is always null-terminated */
1719 for (pp = cliplist; *pp; ++pp) {
1720 SAFE_FREE(*pp);
1722 SAFE_FREE(cliplist);
1723 cliplist = NULL;
1724 must_free_cliplist = False;
1726 return 0;
1729 /* cliplist and its elements are freed at the end of process_tar. */
1730 return 1;
1733 /****************************************************************************
1734 Parse tar arguments. Sets tar_type, tar_excl, etc.
1735 ***************************************************************************/
1737 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1739 int newOptind = Optind;
1740 char tar_clipfl='\0';
1742 /* Reset back to defaults - could be from interactive version
1743 * reset mode and archive mode left as they are though
1745 tar_type='\0';
1746 tar_excl=True;
1747 dry_run=False;
1749 while (*Optarg) {
1750 switch(*Optarg++) {
1751 case 'c':
1752 tar_type='c';
1753 break;
1754 case 'x':
1755 if (tar_type=='c') {
1756 printf("Tar must be followed by only one of c or x.\n");
1757 return 0;
1759 tar_type='x';
1760 break;
1761 case 'b':
1762 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1763 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1764 return 0;
1765 } else {
1766 Optind++;
1767 newOptind++;
1769 break;
1770 case 'g':
1771 tar_inc=True;
1772 break;
1773 case 'N':
1774 if (Optind>=argc) {
1775 DEBUG(0,("Option N must be followed by valid file name\n"));
1776 return 0;
1777 } else {
1778 SMB_STRUCT_STAT stbuf;
1780 if (sys_stat(argv[Optind], &stbuf) == 0) {
1781 newer_than = stbuf.st_mtime;
1782 DEBUG(1,("Getting files newer than %s",
1783 time_to_asc(newer_than)));
1784 newOptind++;
1785 Optind++;
1786 } else {
1787 DEBUG(0,("Error setting newer-than time\n"));
1788 return 0;
1791 break;
1792 case 'a':
1793 tar_reset=True;
1794 break;
1795 case 'q':
1796 tar_noisy=False;
1797 break;
1798 case 'I':
1799 if (tar_clipfl) {
1800 DEBUG(0,("Only one of I,X,F must be specified\n"));
1801 return 0;
1803 tar_clipfl='I';
1804 break;
1805 case 'X':
1806 if (tar_clipfl) {
1807 DEBUG(0,("Only one of I,X,F must be specified\n"));
1808 return 0;
1810 tar_clipfl='X';
1811 break;
1812 case 'F':
1813 if (tar_clipfl) {
1814 DEBUG(0,("Only one of I,X,F must be specified\n"));
1815 return 0;
1817 tar_clipfl='F';
1818 break;
1819 case 'r':
1820 DEBUG(0, ("tar_re_search set\n"));
1821 tar_re_search = True;
1822 break;
1823 case 'n':
1824 if (tar_type == 'c') {
1825 DEBUG(0, ("dry_run set\n"));
1826 dry_run = True;
1827 } else {
1828 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1829 return 0;
1831 break;
1832 default:
1833 DEBUG(0,("Unknown tar option\n"));
1834 return 0;
1838 if (!tar_type) {
1839 printf("Option T must be followed by one of c or x.\n");
1840 return 0;
1843 /* tar_excl is true if cliplist lists files to be included.
1844 * Both 'I' and 'F' mean include. */
1845 tar_excl=tar_clipfl!='X';
1847 if (tar_clipfl=='F') {
1848 if (argc-Optind-1 != 1) {
1849 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1850 return 0;
1852 newOptind++;
1853 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1854 if (! read_inclusion_file(argv[Optind+1])) {
1855 return 0;
1857 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1858 char *tmpstr;
1859 char **tmplist;
1860 int clipcount;
1862 cliplist=argv+Optind+1;
1863 clipn=argc-Optind-1;
1864 clipcount = clipn;
1866 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1867 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1868 return 0;
1871 for (clipcount = 0; clipcount < clipn; clipcount++) {
1873 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1875 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1876 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1877 SAFE_FREE(tmplist);
1878 return 0;
1881 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1882 tmplist[clipcount] = tmpstr;
1883 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1885 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1888 cliplist = tmplist;
1889 must_free_cliplist = True;
1891 newOptind += clipn;
1894 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1895 /* Doing regular expression seaches not from an inclusion file. */
1896 clipn=argc-Optind-1;
1897 cliplist=argv+Optind+1;
1898 newOptind += clipn;
1901 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1902 /* Sets tar handle to either 0 or 1, as appropriate */
1903 tarhandle=(tar_type=='c');
1905 * Make sure that dbf points to stderr if we are using stdout for
1906 * tar output
1908 if (tarhandle == 1) {
1909 dbf = x_stderr;
1911 if (!argv[Optind]) {
1912 DEBUG(0,("Must specify tar filename\n"));
1913 return 0;
1915 if (!strcmp(argv[Optind], "-")) {
1916 newOptind++;
1919 } else {
1920 if (tar_type=='c' && dry_run) {
1921 tarhandle=-1;
1922 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1923 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1924 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1925 return(0);
1927 newOptind++;
1930 return newOptind;