s4-dsdb: use DLIST_ADD() not DLIST_ADD_END()
[Samba/aatanasov.git] / source3 / client / clitar.c
blobd9733294274e70fec692d2e98c4fa9eb5545a1a4
1 /*
2 Unix SMB/CIFS implementation.
3 Tar Extensions
4 Copyright (C) Ricky Poulten 1995-1998
5 Copyright (C) Richard Sharpe 1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 /* The following changes developed by Richard Sharpe for Canon Information
21 Systems Research Australia (CISRA)
23 1. Restore can now restore files with long file names
24 2. Save now saves directory information so that we can restore
25 directory creation times
26 3. tar now accepts both UNIX path names and DOS path names. I prefer
27 those lovely /'s to those UGLY \'s :-)
28 4. the files to exclude can be specified as a regular expression by adding
29 an r flag to the other tar flags. Eg:
31 -TcrX file.tar "*.(obj|exe)"
33 will skip all .obj and .exe files
37 #include "includes.h"
38 #include "clitar.h"
39 #include "client/client_proto.h"
41 static int clipfind(char **aret, int ret, char *tok);
43 typedef struct file_info_struct file_info2;
45 struct file_info_struct {
46 SMB_OFF_T size;
47 uint16 mode;
48 uid_t uid;
49 gid_t gid;
50 /* These times are normally kept in GMT */
51 struct timespec mtime_ts;
52 struct timespec atime_ts;
53 struct timespec ctime_ts;
54 char *name; /* This is dynamically allocated */
55 file_info2 *next, *prev; /* Used in the stack ... */
58 typedef struct {
59 file_info2 *top;
60 int items;
61 } stack;
63 #define SEPARATORS " \t\n\r"
64 extern time_t newer_than;
65 extern struct cli_state *cli;
67 /* These defines are for the do_setrattr routine, to indicate
68 * setting and reseting of file attributes in the function call */
69 #define ATTRSET 1
70 #define ATTRRESET 0
72 static uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
74 #ifndef CLIENT_TIMEOUT
75 #define CLIENT_TIMEOUT (30*1000)
76 #endif
78 static char *tarbuf, *buffer_p;
79 static int tp, ntarf, tbufsiz;
80 static double ttarf;
81 /* Incremental mode */
82 static bool tar_inc=False;
83 /* Reset archive bit */
84 static bool tar_reset=False;
85 /* Include / exclude mode (true=include, false=exclude) */
86 static bool tar_excl=True;
87 /* use regular expressions for search on file names */
88 static bool tar_re_search=False;
89 /* Do not dump anything, just calculate sizes */
90 static bool dry_run=False;
91 /* Dump files with System attribute */
92 static bool tar_system=True;
93 /* Dump files with Hidden attribute */
94 static bool tar_hidden=True;
95 /* Be noisy - make a catalogue */
96 static bool tar_noisy=True;
97 static bool tar_real_noisy=False; /* Don't want to be really noisy by default */
99 char tar_type='\0';
100 static char **cliplist=NULL;
101 static int clipn=0;
102 static bool must_free_cliplist = False;
103 extern const char *cmd_ptr;
105 extern bool lowercase;
106 extern uint16 cnum;
107 extern bool readbraw_supported;
108 extern int max_xmit;
109 extern int get_total_time_ms;
110 extern int get_total_size;
112 static int blocksize=20;
113 static int tarhandle;
115 static void writetarheader(int f, const char *aname, uint64_t 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(uint64_t 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, uint64_t 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((uint64_t)0, 8, hb.dbuf.uid);
199 oct_it((uint64_t)0, 8, hb.dbuf.gid);
200 oct_it((uint64_t) size, 13, hb.dbuf.size);
201 if (size > (uint64_t)077777777777LL) {
202 /* This is a non-POSIX compatible extention to store files
203 greater than 8GB. */
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((uint64_t) 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((uint64_t) 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+sys_write(f, tarbuf, tbufsiz));
333 n-=diff;
334 b+=diff;
335 tp=0;
337 while (n >= tbufsiz) {
338 fail=fail && (1 + sys_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 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
368 DEBUG(0, ("dozerobuf: sys_write fail\n"));
369 return;
371 memset(tarbuf, 0, (tp+=n-tbufsiz));
372 } else {
373 memset(tarbuf+tp, 0, n);
374 tp+=n;
378 /****************************************************************************
379 Malloc tape buffer
380 ****************************************************************************/
382 static void initarbuf(void)
384 /* initialize tar buffer */
385 tbufsiz=blocksize*TBLOCK;
386 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
388 /* reset tar buffer pointer and tar file counter and total dumped */
389 tp=0; ntarf=0; ttarf=0;
392 /****************************************************************************
393 Write two zero blocks at end of file
394 ****************************************************************************/
396 static void dotareof(int f)
398 SMB_STRUCT_STAT stbuf;
399 /* Two zero blocks at end of file, write out full buffer */
401 if (dry_run)
402 return;
404 (void) dozerobuf(f, TBLOCK);
405 (void) dozerobuf(f, TBLOCK);
407 if (sys_fstat(f, &stbuf) == -1) {
408 DEBUG(0, ("Couldn't stat file handle\n"));
409 return;
412 /* Could be a pipe, in which case S_ISREG should fail,
413 * and we should write out at full size */
414 if (tp > 0) {
415 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
416 if (sys_write(f, tarbuf, towrite) != towrite) {
417 DEBUG(0,("dotareof: sys_write fail\n"));
422 /****************************************************************************
423 (Un)mangle DOS pathname, make nonabsolute
424 ****************************************************************************/
426 static void fixtarname(char *tptr, const char *fp, size_t l)
428 /* add a '.' to start of file name, convert from ugly dos \'s in path
429 * to lovely unix /'s :-} */
430 *tptr++='.';
431 l--;
433 StrnCpy(tptr, fp, l-1);
434 string_replace(tptr, '\\', '/');
437 /****************************************************************************
438 Convert from decimal to octal string
439 ****************************************************************************/
441 static void oct_it (uint64_t value, int ndgs, char *p)
443 /* Converts long to octal string, pads with leading zeros */
445 /* skip final null, but do final space */
446 --ndgs;
447 p[--ndgs] = ' ';
449 /* Loop does at least one digit */
450 do {
451 p[--ndgs] = '0' + (char) (value & 7);
452 value >>= 3;
453 } while (ndgs > 0 && value != 0);
455 /* Do leading zeros */
456 while (ndgs > 0)
457 p[--ndgs] = '0';
460 /****************************************************************************
461 Convert from octal string to long
462 ***************************************************************************/
464 static long unoct(char *p, int ndgs)
466 long value=0;
467 /* Converts octal string to long, ignoring any non-digit */
469 while (--ndgs) {
470 if (isdigit((int)*p))
471 value = (value << 3) | (long) (*p - '0');
473 p++;
476 return value;
479 /****************************************************************************
480 Compare two strings in a slash insensitive way, allowing s1 to match s2
481 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
482 a file in any subdirectory of s1, declare a match.
483 ***************************************************************************/
485 static int strslashcmp(char *s1, char *s2)
487 char *s1_0=s1;
489 while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
490 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
491 s1++; s2++;
494 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
495 string of s2.
497 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
498 return 0;
500 /* ignore trailing slash on s1 */
501 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
502 return 0;
504 /* check for s1 is an "initial" string of s2 */
505 if ((*s2 == '/' || *s2 == '\\') && !*s1)
506 return 0;
508 return *s1-*s2;
511 /****************************************************************************
512 Ensure a remote path exists (make if necessary)
513 ***************************************************************************/
515 static bool ensurepath(const char *fname)
517 /* *must* be called with buffer ready malloc'ed */
518 /* ensures path exists */
520 char *partpath, *ffname;
521 const char *p=fname;
522 char *basehack;
523 char *saveptr;
525 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
527 partpath = string_create_s(strlen(fname));
528 ffname = string_create_s(strlen(fname));
530 if ((partpath == NULL) || (ffname == NULL)){
531 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
532 SAFE_FREE(partpath);
533 SAFE_FREE(ffname);
534 return(False);
537 *partpath = 0;
539 /* fname copied to ffname so can strtok_r */
541 safe_strcpy(ffname, fname, strlen(fname));
543 /* do a `basename' on ffname, so don't try and make file name directory */
544 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
545 SAFE_FREE(partpath);
546 SAFE_FREE(ffname);
547 return True;
548 } else {
549 *basehack='\0';
552 p=strtok_r(ffname, "\\", &saveptr);
554 while (p) {
555 safe_strcat(partpath, p, strlen(fname) + 1);
557 if (!NT_STATUS_IS_OK(cli_chkpath(cli, partpath))) {
558 if (!NT_STATUS_IS_OK(cli_mkdir(cli, partpath))) {
559 SAFE_FREE(partpath);
560 SAFE_FREE(ffname);
561 DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
562 return False;
563 } else {
564 DEBUG(3, ("mkdirhiering %s\n", partpath));
568 safe_strcat(partpath, "\\", strlen(fname) + 1);
569 p = strtok_r(NULL, "/\\", &saveptr);
572 SAFE_FREE(partpath);
573 SAFE_FREE(ffname);
574 return True;
577 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
579 int berr= 0;
580 int bytestowrite;
582 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
583 memset(buf, 0, (size_t)bufsize);
584 while( !berr && padsize > 0 ) {
585 bytestowrite= (int)MIN(bufsize, padsize);
586 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
587 padsize -= bytestowrite;
590 return berr;
593 static void do_setrattr(char *name, uint16 attr, int set)
595 uint16 oldattr;
597 if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
598 return;
601 if (set == ATTRSET) {
602 attr |= oldattr;
603 } else {
604 attr = oldattr & ~attr;
607 if (!NT_STATUS_IS_OK(cli_setatr(cli, name, attr, 0))) {
608 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
612 /****************************************************************************
613 append one remote file to the tar file
614 ***************************************************************************/
616 static void do_atar(const char *rname_in,char *lname,file_info *finfo1)
618 uint16_t fnum = (uint16_t)-1;
619 uint64_t nread=0;
620 char ftype;
621 file_info2 finfo;
622 bool shallitime=True;
623 char *data = NULL;
624 int read_size = 65520;
625 int datalen=0;
626 char *rname = NULL;
627 TALLOC_CTX *ctx = talloc_stackframe();
629 struct timeval tp_start;
631 GetTimeOfDay(&tp_start);
633 data = SMB_MALLOC_ARRAY(char, read_size);
634 if (!data) {
635 DEBUG(0,("do_atar: out of memory.\n"));
636 goto cleanup;
639 ftype = '0'; /* An ordinary file ... */
641 ZERO_STRUCT(finfo);
643 finfo.size = finfo1 -> size;
644 finfo.mode = finfo1 -> mode;
645 finfo.uid = finfo1 -> uid;
646 finfo.gid = finfo1 -> gid;
647 finfo.mtime_ts = finfo1 -> mtime_ts;
648 finfo.atime_ts = finfo1 -> atime_ts;
649 finfo.ctime_ts = finfo1 -> ctime_ts;
651 if (dry_run) {
652 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
653 (double)finfo.size));
654 shallitime=0;
655 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
656 ntarf++;
657 goto cleanup;
660 rname = clean_name(ctx, rname_in);
661 if (!rname) {
662 goto cleanup;
665 if (!NT_STATUS_IS_OK(cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum))) {
666 DEBUG(0,("%s opening remote file %s (%s)\n",
667 cli_errstr(cli),rname, client_get_cur_dir()));
668 goto cleanup;
671 finfo.name = string_create_s(strlen(rname));
672 if (finfo.name == NULL) {
673 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
674 goto cleanup;
677 safe_strcpy(finfo.name,rname, strlen(rname));
679 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
681 if (tar_inc && !(finfo.mode & aARCH)) {
682 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
683 shallitime=0;
684 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
685 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
686 shallitime=0;
687 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
688 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
689 shallitime=0;
690 } else {
691 bool wrote_tar_header = False;
693 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
694 finfo.name, (double)finfo.size, lname));
696 do {
698 DEBUG(3,("nread=%.0f\n",(double)nread));
700 datalen = cli_read(cli, fnum, data, nread, read_size);
702 if (datalen == -1) {
703 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
704 break;
707 nread += datalen;
709 /* Only if the first read succeeds, write out the tar header. */
710 if (!wrote_tar_header) {
711 /* write a tar header, don't bother with mode - just set to 100644 */
712 writetarheader(tarhandle, rname, finfo.size,
713 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
714 wrote_tar_header = True;
717 /* if file size has increased since we made file size query, truncate
718 read so tar header for this file will be correct.
721 if (nread > finfo.size) {
722 datalen -= nread - finfo.size;
723 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
724 finfo.name, (double)finfo.size));
727 /* add received bits of file to buffer - dotarbuf will
728 * write out in 512 byte intervals */
730 if (dotarbuf(tarhandle,data,datalen) != datalen) {
731 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
732 break;
735 if ( (datalen == 0) && (finfo.size != 0) ) {
736 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
737 break;
740 datalen=0;
741 } while ( nread < finfo.size );
743 if (wrote_tar_header) {
744 /* pad tar file with zero's if we couldn't get entire file */
745 if (nread < finfo.size) {
746 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
747 (double)finfo.size, (int)nread));
748 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread))
749 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
752 /* round tar file to nearest block */
753 if (finfo.size % TBLOCK)
754 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
756 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
757 ntarf++;
758 } else {
759 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
760 shallitime=0;
764 cli_close(cli, fnum);
765 fnum = -1;
767 if (shallitime) {
768 struct timeval tp_end;
769 int this_time;
771 /* if shallitime is true then we didn't skip */
772 if (tar_reset && !dry_run)
773 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
775 GetTimeOfDay(&tp_end);
776 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
777 get_total_time_ms += this_time;
778 get_total_size += finfo.size;
780 if (tar_noisy) {
781 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
782 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
783 finfo.name));
786 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
787 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
788 finfo.size / MAX(0.001, (1.024*this_time)),
789 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
792 cleanup:
794 if (fnum != (uint16_t)-1) {
795 cli_close(cli, fnum);
796 fnum = -1;
798 TALLOC_FREE(ctx);
799 SAFE_FREE(data);
802 /****************************************************************************
803 Append single file to tar file (or not)
804 ***************************************************************************/
806 static void do_tar(file_info *finfo, const char *dir)
808 TALLOC_CTX *ctx = talloc_stackframe();
810 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
811 return;
813 /* Is it on the exclude list ? */
814 if (!tar_excl && clipn) {
815 char *exclaim;
817 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
819 exclaim = talloc_asprintf(ctx,
820 "%s\\%s",
821 client_get_cur_dir(),
822 finfo->name);
823 if (!exclaim) {
824 return;
827 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
829 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
830 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
831 DEBUG(3,("Skipping file %s\n", exclaim));
832 TALLOC_FREE(exclaim);
833 return;
835 TALLOC_FREE(exclaim);
838 if (finfo->mode & aDIR) {
839 char *saved_curdir = NULL;
840 char *new_cd = NULL;
841 char *mtar_mask = NULL;
843 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
844 if (!saved_curdir) {
845 return;
848 DEBUG(5, ("strlen(cur_dir)=%d, \
849 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
850 (int)strlen(saved_curdir),
851 (int)strlen(finfo->name), finfo->name, saved_curdir));
853 new_cd = talloc_asprintf(ctx,
854 "%s%s\\",
855 client_get_cur_dir(),
856 finfo->name);
857 if (!new_cd) {
858 return;
860 client_set_cur_dir(new_cd);
862 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
864 /* write a tar directory, don't bother with mode - just
865 * set it to 40755 */
866 writetarheader(tarhandle, client_get_cur_dir(), 0,
867 finfo->mtime_ts.tv_sec, "040755 \0", '5');
868 if (tar_noisy) {
869 DEBUG(0,(" directory %s\n",
870 client_get_cur_dir()));
872 ntarf++; /* Make sure we have a file on there */
873 mtar_mask = talloc_asprintf(ctx,
874 "%s*",
875 client_get_cur_dir());
876 if (!mtar_mask) {
877 return;
879 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
880 do_list(mtar_mask, attribute, do_tar, False, True);
881 client_set_cur_dir(saved_curdir);
882 TALLOC_FREE(saved_curdir);
883 TALLOC_FREE(new_cd);
884 TALLOC_FREE(mtar_mask);
885 } else {
886 char *rname = talloc_asprintf(ctx,
887 "%s%s",
888 client_get_cur_dir(),
889 finfo->name);
890 if (!rname) {
891 return;
893 do_atar(rname,finfo->name,finfo);
894 TALLOC_FREE(rname);
898 /****************************************************************************
899 Convert from UNIX to DOS file names
900 ***************************************************************************/
902 static void unfixtarname(char *tptr, char *fp, int l, bool first)
904 /* remove '.' from start of file name, convert from unix /'s to
905 * dos \'s in path. Kill any absolute path names. But only if first!
908 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
910 if (first) {
911 if (*fp == '.') {
912 fp++;
913 l--;
915 if (*fp == '\\' || *fp == '/') {
916 fp++;
917 l--;
921 safe_strcpy(tptr, fp, l);
922 string_replace(tptr, '/', '\\');
925 /****************************************************************************
926 Move to the next block in the buffer, which may mean read in another set of
927 blocks. FIXME, we should allow more than one block to be skipped.
928 ****************************************************************************/
930 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
932 int bufread, total = 0;
934 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
935 *bufferp += TBLOCK;
936 total = TBLOCK;
938 if (*bufferp >= (ltarbuf + bufsiz)) {
940 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
943 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
944 * Fixes bug where read can return short if coming from
945 * a pipe.
948 bufread = read(tarhandle, ltarbuf, bufsiz);
949 total = bufread;
951 while (total < bufsiz) {
952 if (bufread < 0) { /* An error, return false */
953 return (total > 0 ? -2 : bufread);
955 if (bufread == 0) {
956 if (total <= 0) {
957 return -2;
959 break;
961 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
962 total += bufread;
965 DEBUG(5, ("Total bytes read ... %i\n", total));
967 *bufferp = ltarbuf;
970 return(total);
973 /* Skip a file, even if it includes a long file name? */
974 static int skip_file(int skipsize)
976 int dsize = skipsize;
978 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
980 /* FIXME, we should skip more than one block at a time */
982 while (dsize > 0) {
983 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
984 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
985 return(False);
987 dsize -= TBLOCK;
990 return(True);
993 /*************************************************************
994 Get a file from the tar file and store it.
995 When this is called, tarbuf already contains the first
996 file block. This is a bit broken & needs fixing.
997 **************************************************************/
999 static int get_file(file_info2 finfo)
1001 uint16_t fnum;
1002 int pos = 0, dsize = 0, bpos = 0;
1003 uint64_t rsize = 0;
1005 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1007 if (ensurepath(finfo.name) &&
1008 (!NT_STATUS_IS_OK(cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE,&fnum)))) {
1009 DEBUG(0, ("abandoning restore\n"));
1010 return(False);
1013 /* read the blocks from the tar file and write to the remote file */
1015 rsize = finfo.size; /* This is how much to write */
1017 while (rsize > 0) {
1019 /* We can only write up to the end of the buffer */
1020 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1021 dsize = MIN(dsize, rsize); /* Should be only what is left */
1022 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1024 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
1025 DEBUG(0, ("Error writing remote file\n"));
1026 return 0;
1029 rsize -= dsize;
1030 pos += dsize;
1032 /* Now figure out how much to move in the buffer */
1034 /* FIXME, we should skip more than one block at a time */
1036 /* First, skip any initial part of the part written that is left over */
1037 /* from the end of the first TBLOCK */
1039 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1040 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1041 bpos = 0;
1043 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1044 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1045 return False;
1050 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1051 * If the file being extracted is an exact multiple of
1052 * TBLOCK bytes then we don't want to extract the next
1053 * block from the tarfile here, as it will be done in
1054 * the caller of get_file().
1057 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1058 ((rsize == 0) && (dsize > TBLOCK))) {
1060 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1061 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1062 return False;
1065 dsize -= TBLOCK;
1067 bpos = dsize;
1070 /* Now close the file ... */
1072 if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
1073 DEBUG(0, ("Error %s closing remote file\n",
1074 cli_errstr(cli)));
1075 return(False);
1078 /* Now we update the creation date ... */
1079 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1081 if (!NT_STATUS_IS_OK(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 SAFE_FREE(argl);
1475 return 1;
1478 ret = process_tar();
1479 SAFE_FREE(argl);
1480 return ret;
1483 /****************************************************************************
1484 Command line (option) version
1485 ***************************************************************************/
1487 int process_tar(void)
1489 TALLOC_CTX *ctx = talloc_tos();
1490 int rc = 0;
1491 initarbuf();
1492 switch(tar_type) {
1493 case 'x':
1495 #if 0
1496 do_tarput2();
1497 #else
1498 do_tarput();
1499 #endif
1500 SAFE_FREE(tarbuf);
1501 close(tarhandle);
1502 break;
1503 case 'r':
1504 case 'c':
1505 if (clipn && tar_excl) {
1506 int i;
1507 char *tarmac = NULL;
1509 for (i=0; i<clipn; i++) {
1510 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1512 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1513 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1516 if (strrchr_m(cliplist[i], '\\')) {
1517 char *p;
1518 char saved_char;
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;
1538 * Strip off the last \\xxx
1539 * xxx element of tarmac to set
1540 * it as current directory.
1542 p = strrchr_m(tarmac, '\\');
1543 if (!p) {
1544 return 1;
1546 saved_char = p[1];
1547 p[1] = '\0';
1549 client_set_cur_dir(tarmac);
1552 * Restore the character we
1553 * just replaced to
1554 * put the pathname
1555 * back as it was.
1557 p[1] = saved_char;
1559 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1560 do_list(tarmac,attribute,do_tar, False, True);
1562 client_set_cur_dir(saved_dir);
1564 TALLOC_FREE(saved_dir);
1565 TALLOC_FREE(tarmac);
1566 } else {
1567 tarmac = talloc_asprintf(ctx,
1568 "%s%s",
1569 client_get_cur_dir(),
1570 cliplist[i]);
1571 if (!tarmac) {
1572 return 1;
1574 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1575 do_list(tarmac,attribute,do_tar, False, True);
1576 TALLOC_FREE(tarmac);
1579 } else {
1580 char *mask = talloc_asprintf(ctx,
1581 "%s\\*",
1582 client_get_cur_dir());
1583 if (!mask) {
1584 return 1;
1586 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1587 do_list(mask,attribute,do_tar,False, True);
1588 TALLOC_FREE(mask);
1591 if (ntarf) {
1592 dotareof(tarhandle);
1594 close(tarhandle);
1595 SAFE_FREE(tarbuf);
1597 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1598 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1599 break;
1602 if (must_free_cliplist) {
1603 int i;
1604 for (i = 0; i < clipn; ++i) {
1605 SAFE_FREE(cliplist[i]);
1607 SAFE_FREE(cliplist);
1608 cliplist = NULL;
1609 clipn = 0;
1610 must_free_cliplist = False;
1612 return rc;
1615 /****************************************************************************
1616 Find a token (filename) in a clip list
1617 ***************************************************************************/
1619 static int clipfind(char **aret, int ret, char *tok)
1621 if (aret==NULL)
1622 return 0;
1624 /* ignore leading slashes or dots in token */
1625 while(strchr_m("/\\.", *tok))
1626 tok++;
1628 while(ret--) {
1629 char *pkey=*aret++;
1631 /* ignore leading slashes or dots in list */
1632 while(strchr_m("/\\.", *pkey))
1633 pkey++;
1635 if (!strslashcmp(pkey, tok))
1636 return 1;
1638 return 0;
1641 /****************************************************************************
1642 Read list of files to include from the file and initialize cliplist
1643 accordingly.
1644 ***************************************************************************/
1646 static int read_inclusion_file(char *filename)
1648 XFILE *inclusion = NULL;
1649 char buf[PATH_MAX + 1];
1650 char *inclusion_buffer = NULL;
1651 int inclusion_buffer_size = 0;
1652 int inclusion_buffer_sofar = 0;
1653 char *p;
1654 char *tmpstr;
1655 int i;
1656 int error = 0;
1658 clipn = 0;
1659 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1660 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1661 /* XXX It would be better to include a reason for failure, but without
1662 * autoconf, it's hard to use strerror, sys_errlist, etc.
1664 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1665 return 0;
1668 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1669 if (inclusion_buffer == NULL) {
1670 inclusion_buffer_size = 1024;
1671 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1672 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1673 error = 1;
1674 break;
1678 if (buf[strlen(buf)-1] == '\n') {
1679 buf[strlen(buf)-1] = '\0';
1682 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1683 inclusion_buffer_size *= 2;
1684 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1685 if (!inclusion_buffer) {
1686 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1687 inclusion_buffer_size));
1688 error = 1;
1689 break;
1693 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1694 inclusion_buffer_sofar += strlen(buf) + 1;
1695 clipn++;
1697 x_fclose(inclusion);
1699 if (! error) {
1700 /* Allocate an array of clipn + 1 char*'s for cliplist */
1701 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1702 if (cliplist == NULL) {
1703 DEBUG(0,("failure allocating memory for cliplist\n"));
1704 error = 1;
1705 } else {
1706 cliplist[clipn] = NULL;
1707 p = inclusion_buffer;
1708 for (i = 0; (! error) && (i < clipn); i++) {
1709 /* set current item to NULL so array will be null-terminated even if
1710 * malloc fails below. */
1711 cliplist[i] = NULL;
1712 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1713 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1714 error = 1;
1715 } else {
1716 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1717 cliplist[i] = tmpstr;
1718 if ((p = strchr_m(p, '\000')) == NULL) {
1719 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1720 abort();
1723 ++p;
1725 must_free_cliplist = True;
1729 SAFE_FREE(inclusion_buffer);
1730 if (error) {
1731 if (cliplist) {
1732 char **pp;
1733 /* We know cliplist is always null-terminated */
1734 for (pp = cliplist; *pp; ++pp) {
1735 SAFE_FREE(*pp);
1737 SAFE_FREE(cliplist);
1738 cliplist = NULL;
1739 must_free_cliplist = False;
1741 return 0;
1744 /* cliplist and its elements are freed at the end of process_tar. */
1745 return 1;
1748 /****************************************************************************
1749 Parse tar arguments. Sets tar_type, tar_excl, etc.
1750 ***************************************************************************/
1752 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1754 int newOptind = Optind;
1755 char tar_clipfl='\0';
1757 /* Reset back to defaults - could be from interactive version
1758 * reset mode and archive mode left as they are though
1760 tar_type='\0';
1761 tar_excl=True;
1762 dry_run=False;
1764 while (*Optarg) {
1765 switch(*Optarg++) {
1766 case 'c':
1767 tar_type='c';
1768 break;
1769 case 'x':
1770 if (tar_type=='c') {
1771 printf("Tar must be followed by only one of c or x.\n");
1772 return 0;
1774 tar_type='x';
1775 break;
1776 case 'b':
1777 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1778 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1779 return 0;
1780 } else {
1781 Optind++;
1782 newOptind++;
1784 break;
1785 case 'g':
1786 tar_inc=True;
1787 break;
1788 case 'N':
1789 if (Optind>=argc) {
1790 DEBUG(0,("Option N must be followed by valid file name\n"));
1791 return 0;
1792 } else {
1793 SMB_STRUCT_STAT stbuf;
1795 if (sys_stat(argv[Optind], &stbuf) == 0) {
1796 newer_than = convert_timespec_to_time_t(
1797 stbuf.st_ex_mtime);
1798 DEBUG(1,("Getting files newer than %s",
1799 time_to_asc(newer_than)));
1800 newOptind++;
1801 Optind++;
1802 } else {
1803 DEBUG(0,("Error setting newer-than time\n"));
1804 return 0;
1807 break;
1808 case 'a':
1809 tar_reset=True;
1810 break;
1811 case 'q':
1812 tar_noisy=False;
1813 break;
1814 case 'I':
1815 if (tar_clipfl) {
1816 DEBUG(0,("Only one of I,X,F must be specified\n"));
1817 return 0;
1819 tar_clipfl='I';
1820 break;
1821 case 'X':
1822 if (tar_clipfl) {
1823 DEBUG(0,("Only one of I,X,F must be specified\n"));
1824 return 0;
1826 tar_clipfl='X';
1827 break;
1828 case 'F':
1829 if (tar_clipfl) {
1830 DEBUG(0,("Only one of I,X,F must be specified\n"));
1831 return 0;
1833 tar_clipfl='F';
1834 break;
1835 case 'r':
1836 DEBUG(0, ("tar_re_search set\n"));
1837 tar_re_search = True;
1838 break;
1839 case 'n':
1840 if (tar_type == 'c') {
1841 DEBUG(0, ("dry_run set\n"));
1842 dry_run = True;
1843 } else {
1844 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1845 return 0;
1847 break;
1848 default:
1849 DEBUG(0,("Unknown tar option\n"));
1850 return 0;
1854 if (!tar_type) {
1855 printf("Option T must be followed by one of c or x.\n");
1856 return 0;
1859 /* tar_excl is true if cliplist lists files to be included.
1860 * Both 'I' and 'F' mean include. */
1861 tar_excl=tar_clipfl!='X';
1863 if (tar_clipfl=='F') {
1864 if (argc-Optind-1 != 1) {
1865 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1866 return 0;
1868 newOptind++;
1869 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1870 if (! read_inclusion_file(argv[Optind+1])) {
1871 return 0;
1873 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1874 char *tmpstr;
1875 char **tmplist;
1876 int clipcount;
1878 cliplist=argv+Optind+1;
1879 clipn=argc-Optind-1;
1880 clipcount = clipn;
1882 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1883 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1884 return 0;
1887 for (clipcount = 0; clipcount < clipn; clipcount++) {
1889 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1891 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1892 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1893 SAFE_FREE(tmplist);
1894 return 0;
1897 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1898 tmplist[clipcount] = tmpstr;
1899 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1901 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1904 cliplist = tmplist;
1905 must_free_cliplist = True;
1907 newOptind += clipn;
1910 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1911 /* Doing regular expression seaches not from an inclusion file. */
1912 clipn=argc-Optind-1;
1913 cliplist=argv+Optind+1;
1914 newOptind += clipn;
1917 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1918 /* Sets tar handle to either 0 or 1, as appropriate */
1919 tarhandle=(tar_type=='c');
1921 * Make sure that dbf points to stderr if we are using stdout for
1922 * tar output
1924 if (tarhandle == 1) {
1925 dbf = x_stderr;
1927 if (!argv[Optind]) {
1928 DEBUG(0,("Must specify tar filename\n"));
1929 return 0;
1931 if (!strcmp(argv[Optind], "-")) {
1932 newOptind++;
1935 } else {
1936 if (tar_type=='c' && dry_run) {
1937 tarhandle=-1;
1938 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1939 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1940 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1941 return(0);
1943 newOptind++;
1946 return newOptind;