WHATSNEW: Update changes.
[Samba.git] / source3 / client / clitar.c
blob030362f14dff63d47328b494338befeb12c6563f
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,
118 struct file_info *finfo1);
119 static void do_tar(struct file_info *finfo, const char *dir);
120 static void oct_it(uint64_t value, int ndgs, char *p);
121 static void fixtarname(char *tptr, const char *fp, size_t l);
122 static int dotarbuf(int f, char *b, int n);
123 static void dozerobuf(int f, int n);
124 static void dotareof(int f);
125 static void initarbuf(void);
127 /* restore functions */
128 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
129 static long unoct(char *p, int ndgs);
130 static void do_tarput(void);
131 static void unfixtarname(char *tptr, char *fp, int l, bool first);
134 * tar specific utitlities
137 /*******************************************************************
138 Create a string of size size+1 (for the null)
139 *******************************************************************/
141 static char *string_create_s(int size)
143 char *tmp;
145 tmp = (char *)SMB_MALLOC(size+1);
147 if (tmp == NULL) {
148 DEBUG(0, ("Out of memory in string_create_s\n"));
151 return(tmp);
154 /****************************************************************************
155 Write a tar header to buffer
156 ****************************************************************************/
158 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
159 const char *amode, unsigned char ftype)
161 union hblock hb;
162 int i, chk, l;
163 char *jp;
165 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
167 memset(hb.dummy, 0, sizeof(hb.dummy));
169 l=strlen(aname);
170 /* We will be prepending a '.' in fixtarheader so use +2 to
171 * take care of the . and terminating zero. JRA.
173 if (l+2 >= NAMSIZ) {
174 /* write a GNU tar style long header */
175 char *b;
176 b = (char *)SMB_MALLOC(l+TBLOCK+100);
177 if (!b) {
178 DEBUG(0,("out of memory\n"));
179 exit(1);
181 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
182 memset(b, 0, l+TBLOCK+100);
183 fixtarname(b, aname, l+2);
184 i = strlen(b)+1;
185 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
186 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
187 SAFE_FREE(b);
190 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
192 if (lowercase)
193 strlower_m(hb.dbuf.name);
195 /* write out a "standard" tar format header */
197 hb.dbuf.name[NAMSIZ-1]='\0';
198 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
199 oct_it((uint64_t)0, 8, hb.dbuf.uid);
200 oct_it((uint64_t)0, 8, hb.dbuf.gid);
201 oct_it((uint64_t) size, 13, hb.dbuf.size);
202 if (size > (uint64_t)077777777777LL) {
203 /* This is a non-POSIX compatible extention to store files
204 greater than 8GB. */
206 memset(hb.dbuf.size, 0, 4);
207 hb.dbuf.size[0]=128;
208 for (i = 8, jp=(char*)&size; i; i--)
209 hb.dbuf.size[i+3] = *(jp++);
211 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
212 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
213 memset(hb.dbuf.linkname, 0, NAMSIZ);
214 hb.dbuf.linkflag=ftype;
216 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
217 chk+=(0xFF & *jp++);
219 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
220 hb.dbuf.chksum[6] = '\0';
222 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
225 /****************************************************************************
226 Read a tar header into a hblock structure, and validate
227 ***************************************************************************/
229 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
231 long chk, fchk;
232 int i;
233 char *jp;
236 * read in a "standard" tar format header - we're not that interested
237 * in that many fields, though
240 /* check the checksum */
241 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
242 chk+=(0xFF & *jp++);
244 if (chk == 0)
245 return chk;
247 /* compensate for blanks in chksum header */
248 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
249 chk-=(0xFF & *jp++);
251 chk += ' ' * sizeof(hb->dbuf.chksum);
253 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
255 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
256 chk, fchk, hb->dbuf.chksum));
258 if (fchk != chk) {
259 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
260 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
261 return -1;
264 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
265 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
266 return(-1);
269 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
271 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
272 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
273 strlen(hb->dbuf.name) + 1, True);
275 /* can't handle some links at present */
276 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
277 if (hb->dbuf.linkflag == 0) {
278 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
279 finfo->name));
280 } else {
281 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
282 /* Do nothing here at the moment. do_tarput will handle this
283 as long as the longlink gets back to it, as it has to advance
284 the buffer pointer, etc */
285 } else {
286 DEBUG(0, ("this tar file appears to contain some kind \
287 of link other than a GNUtar Longlink - ignoring\n"));
288 return -2;
293 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
294 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
295 finfo->mode=aDIR;
296 } else {
297 finfo->mode=0; /* we don't care about mode at the moment, we'll
298 * just make it a regular file */
302 * Bug fix by richard@sj.co.uk
304 * REC: restore times correctly (as does tar)
305 * We only get the modification time of the file; set the creation time
306 * from the mod. time, and the access time to current time
308 finfo->mtime_ts = finfo->ctime_ts =
309 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
310 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
311 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
313 return True;
316 /****************************************************************************
317 Write out the tar buffer to tape or wherever
318 ****************************************************************************/
320 static int dotarbuf(int f, char *b, int n)
322 int fail=1, writ=n;
324 if (dry_run) {
325 return writ;
327 /* This routine and the next one should be the only ones that do write()s */
328 if (tp + n >= tbufsiz) {
329 int diff;
331 diff=tbufsiz-tp;
332 memcpy(tarbuf + tp, b, diff);
333 fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
334 n-=diff;
335 b+=diff;
336 tp=0;
338 while (n >= tbufsiz) {
339 fail=fail && (1 + sys_write(f, b, tbufsiz));
340 n-=tbufsiz;
341 b+=tbufsiz;
345 if (n>0) {
346 memcpy(tarbuf+tp, b, n);
347 tp+=n;
350 return(fail ? writ : 0);
353 /****************************************************************************
354 Write zeros to buffer / tape
355 ****************************************************************************/
357 static void dozerobuf(int f, int n)
359 /* short routine just to write out n zeros to buffer -
360 * used to round files to nearest block
361 * and to do tar EOFs */
363 if (dry_run)
364 return;
366 if (n+tp >= tbufsiz) {
367 memset(tarbuf+tp, 0, tbufsiz-tp);
368 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
369 DEBUG(0, ("dozerobuf: sys_write fail\n"));
370 return;
372 memset(tarbuf, 0, (tp+=n-tbufsiz));
373 } else {
374 memset(tarbuf+tp, 0, n);
375 tp+=n;
379 /****************************************************************************
380 Malloc tape buffer
381 ****************************************************************************/
383 static void initarbuf(void)
385 /* initialize tar buffer */
386 tbufsiz=blocksize*TBLOCK;
387 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
389 /* reset tar buffer pointer and tar file counter and total dumped */
390 tp=0; ntarf=0; ttarf=0;
393 /****************************************************************************
394 Write two zero blocks at end of file
395 ****************************************************************************/
397 static void dotareof(int f)
399 SMB_STRUCT_STAT stbuf;
400 /* Two zero blocks at end of file, write out full buffer */
402 if (dry_run)
403 return;
405 (void) dozerobuf(f, TBLOCK);
406 (void) dozerobuf(f, TBLOCK);
408 if (sys_fstat(f, &stbuf, false) == -1) {
409 DEBUG(0, ("Couldn't stat file handle\n"));
410 return;
413 /* Could be a pipe, in which case S_ISREG should fail,
414 * and we should write out at full size */
415 if (tp > 0) {
416 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
417 if (sys_write(f, tarbuf, towrite) != towrite) {
418 DEBUG(0,("dotareof: sys_write fail\n"));
423 /****************************************************************************
424 (Un)mangle DOS pathname, make nonabsolute
425 ****************************************************************************/
427 static void fixtarname(char *tptr, const char *fp, size_t l)
429 /* add a '.' to start of file name, convert from ugly dos \'s in path
430 * to lovely unix /'s :-} */
431 *tptr++='.';
432 l--;
434 StrnCpy(tptr, fp, l-1);
435 string_replace(tptr, '\\', '/');
438 /****************************************************************************
439 Convert from decimal to octal string
440 ****************************************************************************/
442 static void oct_it (uint64_t value, int ndgs, char *p)
444 /* Converts long to octal string, pads with leading zeros */
446 /* skip final null, but do final space */
447 --ndgs;
448 p[--ndgs] = ' ';
450 /* Loop does at least one digit */
451 do {
452 p[--ndgs] = '0' + (char) (value & 7);
453 value >>= 3;
454 } while (ndgs > 0 && value != 0);
456 /* Do leading zeros */
457 while (ndgs > 0)
458 p[--ndgs] = '0';
461 /****************************************************************************
462 Convert from octal string to long
463 ***************************************************************************/
465 static long unoct(char *p, int ndgs)
467 long value=0;
468 /* Converts octal string to long, ignoring any non-digit */
470 while (--ndgs) {
471 if (isdigit((int)*p))
472 value = (value << 3) | (long) (*p - '0');
474 p++;
477 return value;
480 /****************************************************************************
481 Compare two strings in a slash insensitive way, allowing s1 to match s2
482 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
483 a file in any subdirectory of s1, declare a match.
484 ***************************************************************************/
486 static int strslashcmp(char *s1, char *s2)
488 char *s1_0=s1;
490 while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
491 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
492 s1++; s2++;
495 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
496 string of s2.
498 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
499 return 0;
501 /* ignore trailing slash on s1 */
502 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
503 return 0;
505 /* check for s1 is an "initial" string of s2 */
506 if ((*s2 == '/' || *s2 == '\\') && !*s1)
507 return 0;
509 return *s1-*s2;
512 /****************************************************************************
513 Ensure a remote path exists (make if necessary)
514 ***************************************************************************/
516 static bool ensurepath(const char *fname)
518 /* *must* be called with buffer ready malloc'ed */
519 /* ensures path exists */
521 char *partpath, *ffname;
522 const char *p=fname;
523 char *basehack;
524 char *saveptr;
526 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
528 partpath = string_create_s(strlen(fname));
529 ffname = string_create_s(strlen(fname));
531 if ((partpath == NULL) || (ffname == NULL)){
532 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
533 SAFE_FREE(partpath);
534 SAFE_FREE(ffname);
535 return(False);
538 *partpath = 0;
540 /* fname copied to ffname so can strtok_r */
542 safe_strcpy(ffname, fname, strlen(fname));
544 /* do a `basename' on ffname, so don't try and make file name directory */
545 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
546 SAFE_FREE(partpath);
547 SAFE_FREE(ffname);
548 return True;
549 } else {
550 *basehack='\0';
553 p=strtok_r(ffname, "\\", &saveptr);
555 while (p) {
556 safe_strcat(partpath, p, strlen(fname) + 1);
558 if (!NT_STATUS_IS_OK(cli_chkpath(cli, partpath))) {
559 if (!NT_STATUS_IS_OK(cli_mkdir(cli, partpath))) {
560 SAFE_FREE(partpath);
561 SAFE_FREE(ffname);
562 DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
563 return False;
564 } else {
565 DEBUG(3, ("mkdirhiering %s\n", partpath));
569 safe_strcat(partpath, "\\", strlen(fname) + 1);
570 p = strtok_r(NULL, "/\\", &saveptr);
573 SAFE_FREE(partpath);
574 SAFE_FREE(ffname);
575 return True;
578 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
580 int berr= 0;
581 int bytestowrite;
583 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
584 memset(buf, 0, (size_t)bufsize);
585 while( !berr && padsize > 0 ) {
586 bytestowrite= (int)MIN(bufsize, padsize);
587 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
588 padsize -= bytestowrite;
591 return berr;
594 static void do_setrattr(char *name, uint16 attr, int set)
596 uint16 oldattr;
598 if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
599 return;
602 if (set == ATTRSET) {
603 attr |= oldattr;
604 } else {
605 attr = oldattr & ~attr;
608 if (!NT_STATUS_IS_OK(cli_setatr(cli, name, attr, 0))) {
609 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
613 /****************************************************************************
614 append one remote file to the tar file
615 ***************************************************************************/
617 static void do_atar(const char *rname_in, char *lname,
618 struct file_info *finfo1)
620 uint16_t fnum = (uint16_t)-1;
621 uint64_t nread=0;
622 char ftype;
623 file_info2 finfo;
624 bool shallitime=True;
625 char *data = NULL;
626 int read_size = 65520;
627 int datalen=0;
628 char *rname = NULL;
629 TALLOC_CTX *ctx = talloc_stackframe();
631 struct timeval tp_start;
633 GetTimeOfDay(&tp_start);
635 data = SMB_MALLOC_ARRAY(char, read_size);
636 if (!data) {
637 DEBUG(0,("do_atar: out of memory.\n"));
638 goto cleanup;
641 ftype = '0'; /* An ordinary file ... */
643 ZERO_STRUCT(finfo);
645 finfo.size = finfo1 -> size;
646 finfo.mode = finfo1 -> mode;
647 finfo.uid = finfo1 -> uid;
648 finfo.gid = finfo1 -> gid;
649 finfo.mtime_ts = finfo1 -> mtime_ts;
650 finfo.atime_ts = finfo1 -> atime_ts;
651 finfo.ctime_ts = finfo1 -> ctime_ts;
653 if (dry_run) {
654 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
655 (double)finfo.size));
656 shallitime=0;
657 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
658 ntarf++;
659 goto cleanup;
662 rname = clean_name(ctx, rname_in);
663 if (!rname) {
664 goto cleanup;
667 if (!NT_STATUS_IS_OK(cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum))) {
668 DEBUG(0,("%s opening remote file %s (%s)\n",
669 cli_errstr(cli),rname, client_get_cur_dir()));
670 goto cleanup;
673 finfo.name = string_create_s(strlen(rname));
674 if (finfo.name == NULL) {
675 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
676 goto cleanup;
679 safe_strcpy(finfo.name,rname, strlen(rname));
681 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
683 if (tar_inc && !(finfo.mode & aARCH)) {
684 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
685 shallitime=0;
686 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
687 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
688 shallitime=0;
689 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
690 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
691 shallitime=0;
692 } else {
693 bool wrote_tar_header = False;
695 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
696 finfo.name, (double)finfo.size, lname));
698 do {
700 DEBUG(3,("nread=%.0f\n",(double)nread));
702 datalen = cli_read(cli, fnum, data, nread, read_size);
704 if (datalen == -1) {
705 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
706 break;
709 nread += datalen;
711 /* Only if the first read succeeds, write out the tar header. */
712 if (!wrote_tar_header) {
713 /* write a tar header, don't bother with mode - just set to 100644 */
714 writetarheader(tarhandle, rname, finfo.size,
715 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
716 wrote_tar_header = True;
719 /* if file size has increased since we made file size query, truncate
720 read so tar header for this file will be correct.
723 if (nread > finfo.size) {
724 datalen -= nread - finfo.size;
725 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
726 finfo.name, (double)finfo.size));
729 /* add received bits of file to buffer - dotarbuf will
730 * write out in 512 byte intervals */
732 if (dotarbuf(tarhandle,data,datalen) != datalen) {
733 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
734 break;
737 if ( (datalen == 0) && (finfo.size != 0) ) {
738 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
739 break;
742 datalen=0;
743 } while ( nread < finfo.size );
745 if (wrote_tar_header) {
746 /* pad tar file with zero's if we couldn't get entire file */
747 if (nread < finfo.size) {
748 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
749 (double)finfo.size, (int)nread));
750 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread))
751 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
754 /* round tar file to nearest block */
755 if (finfo.size % TBLOCK)
756 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
758 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
759 ntarf++;
760 } else {
761 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
762 shallitime=0;
766 cli_close(cli, fnum);
767 fnum = -1;
769 if (shallitime) {
770 struct timeval tp_end;
771 int this_time;
773 /* if shallitime is true then we didn't skip */
774 if (tar_reset && !dry_run)
775 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
777 GetTimeOfDay(&tp_end);
778 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000;
779 get_total_time_ms += this_time;
780 get_total_size += finfo.size;
782 if (tar_noisy) {
783 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
784 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
785 finfo.name));
788 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
789 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
790 finfo.size / MAX(0.001, (1.024*this_time)),
791 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
794 cleanup:
796 if (fnum != (uint16_t)-1) {
797 cli_close(cli, fnum);
798 fnum = -1;
800 TALLOC_FREE(ctx);
801 SAFE_FREE(data);
804 /****************************************************************************
805 Append single file to tar file (or not)
806 ***************************************************************************/
808 static void do_tar(struct file_info *finfo, const char *dir)
810 TALLOC_CTX *ctx = talloc_stackframe();
812 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
813 return;
815 /* Is it on the exclude list ? */
816 if (!tar_excl && clipn) {
817 char *exclaim;
819 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
821 exclaim = talloc_asprintf(ctx,
822 "%s\\%s",
823 client_get_cur_dir(),
824 finfo->name);
825 if (!exclaim) {
826 return;
829 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
831 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
832 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
833 DEBUG(3,("Skipping file %s\n", exclaim));
834 TALLOC_FREE(exclaim);
835 return;
837 TALLOC_FREE(exclaim);
840 if (finfo->mode & aDIR) {
841 char *saved_curdir = NULL;
842 char *new_cd = NULL;
843 char *mtar_mask = NULL;
845 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
846 if (!saved_curdir) {
847 return;
850 DEBUG(5, ("strlen(cur_dir)=%d, \
851 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
852 (int)strlen(saved_curdir),
853 (int)strlen(finfo->name), finfo->name, saved_curdir));
855 new_cd = talloc_asprintf(ctx,
856 "%s%s\\",
857 client_get_cur_dir(),
858 finfo->name);
859 if (!new_cd) {
860 return;
862 client_set_cur_dir(new_cd);
864 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
866 /* write a tar directory, don't bother with mode - just
867 * set it to 40755 */
868 writetarheader(tarhandle, client_get_cur_dir(), 0,
869 finfo->mtime_ts.tv_sec, "040755 \0", '5');
870 if (tar_noisy) {
871 DEBUG(0,(" directory %s\n",
872 client_get_cur_dir()));
874 ntarf++; /* Make sure we have a file on there */
875 mtar_mask = talloc_asprintf(ctx,
876 "%s*",
877 client_get_cur_dir());
878 if (!mtar_mask) {
879 return;
881 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
882 do_list(mtar_mask, attribute, do_tar, False, True);
883 client_set_cur_dir(saved_curdir);
884 TALLOC_FREE(saved_curdir);
885 TALLOC_FREE(new_cd);
886 TALLOC_FREE(mtar_mask);
887 } else {
888 char *rname = talloc_asprintf(ctx,
889 "%s%s",
890 client_get_cur_dir(),
891 finfo->name);
892 if (!rname) {
893 return;
895 do_atar(rname,finfo->name,finfo);
896 TALLOC_FREE(rname);
900 /****************************************************************************
901 Convert from UNIX to DOS file names
902 ***************************************************************************/
904 static void unfixtarname(char *tptr, char *fp, int l, bool first)
906 /* remove '.' from start of file name, convert from unix /'s to
907 * dos \'s in path. Kill any absolute path names. But only if first!
910 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
912 if (first) {
913 if (*fp == '.') {
914 fp++;
915 l--;
917 if (*fp == '\\' || *fp == '/') {
918 fp++;
919 l--;
923 safe_strcpy(tptr, fp, l);
924 string_replace(tptr, '/', '\\');
927 /****************************************************************************
928 Move to the next block in the buffer, which may mean read in another set of
929 blocks. FIXME, we should allow more than one block to be skipped.
930 ****************************************************************************/
932 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
934 int bufread, total = 0;
936 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
937 *bufferp += TBLOCK;
938 total = TBLOCK;
940 if (*bufferp >= (ltarbuf + bufsiz)) {
942 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
945 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
946 * Fixes bug where read can return short if coming from
947 * a pipe.
950 bufread = read(tarhandle, ltarbuf, bufsiz);
951 total = bufread;
953 while (total < bufsiz) {
954 if (bufread < 0) { /* An error, return false */
955 return (total > 0 ? -2 : bufread);
957 if (bufread == 0) {
958 if (total <= 0) {
959 return -2;
961 break;
963 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
964 total += bufread;
967 DEBUG(5, ("Total bytes read ... %i\n", total));
969 *bufferp = ltarbuf;
972 return(total);
975 /* Skip a file, even if it includes a long file name? */
976 static int skip_file(int skipsize)
978 int dsize = skipsize;
980 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
982 /* FIXME, we should skip more than one block at a time */
984 while (dsize > 0) {
985 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
986 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
987 return(False);
989 dsize -= TBLOCK;
992 return(True);
995 /*************************************************************
996 Get a file from the tar file and store it.
997 When this is called, tarbuf already contains the first
998 file block. This is a bit broken & needs fixing.
999 **************************************************************/
1001 static int get_file(file_info2 finfo)
1003 uint16_t fnum = (uint16_t) -1;
1004 int pos = 0, dsize = 0, bpos = 0;
1005 uint64_t rsize = 0;
1006 NTSTATUS status;
1008 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1010 if (!ensurepath(finfo.name)) {
1011 DEBUG(0, ("abandoning restore\n"));
1012 return False;
1015 status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1016 if (!NT_STATUS_IS_OK(status)) {
1017 DEBUG(0, ("abandoning restore\n"));
1018 return False;
1021 /* read the blocks from the tar file and write to the remote file */
1023 rsize = finfo.size; /* This is how much to write */
1025 while (rsize > 0) {
1027 /* We can only write up to the end of the buffer */
1028 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1029 dsize = MIN(dsize, rsize); /* Should be only what is left */
1030 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1032 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
1033 DEBUG(0, ("Error writing remote file\n"));
1034 return 0;
1037 rsize -= dsize;
1038 pos += dsize;
1040 /* Now figure out how much to move in the buffer */
1042 /* FIXME, we should skip more than one block at a time */
1044 /* First, skip any initial part of the part written that is left over */
1045 /* from the end of the first TBLOCK */
1047 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1048 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1049 bpos = 0;
1051 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1052 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1053 return False;
1058 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1059 * If the file being extracted is an exact multiple of
1060 * TBLOCK bytes then we don't want to extract the next
1061 * block from the tarfile here, as it will be done in
1062 * the caller of get_file().
1065 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1066 ((rsize == 0) && (dsize > TBLOCK))) {
1068 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1069 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1070 return False;
1073 dsize -= TBLOCK;
1075 bpos = dsize;
1078 /* Now close the file ... */
1080 if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
1081 DEBUG(0, ("Error %s closing remote file\n",
1082 cli_errstr(cli)));
1083 return(False);
1086 /* Now we update the creation date ... */
1087 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1089 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1090 if (tar_real_noisy) {
1091 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1092 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1096 ntarf++;
1097 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1098 return(True);
1101 /* Create a directory. We just ensure that the path exists and return as there
1102 is no file associated with a directory
1104 static int get_dir(file_info2 finfo)
1106 DEBUG(0, ("restore directory %s\n", finfo.name));
1108 if (!ensurepath(finfo.name)) {
1109 DEBUG(0, ("Problems creating directory\n"));
1110 return(False);
1112 ntarf++;
1113 return(True);
1116 /* Get a file with a long file name ... first file has file name, next file
1117 has the data. We only want the long file name, as the loop in do_tarput
1118 will deal with the rest.
1120 static char *get_longfilename(file_info2 finfo)
1122 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1123 * header call. */
1124 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1125 char *longname = (char *)SMB_MALLOC(namesize);
1126 int offset = 0, left = finfo.size;
1127 bool first = True;
1129 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1130 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1132 if (longname == NULL) {
1133 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1134 return(NULL);
1137 /* First, add cur_dir to the long file name */
1139 if (strlen(client_get_cur_dir()) > 0) {
1140 strncpy(longname, client_get_cur_dir(), namesize);
1141 offset = strlen(client_get_cur_dir());
1144 /* Loop through the blocks picking up the name */
1146 while (left > 0) {
1147 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1148 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1149 SAFE_FREE(longname);
1150 return(NULL);
1153 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1154 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1156 offset += TBLOCK;
1157 left -= TBLOCK;
1160 return(longname);
1163 static void do_tarput(void)
1165 file_info2 finfo;
1166 struct timeval tp_start;
1167 char *longfilename = NULL, linkflag;
1168 int skip = False;
1170 ZERO_STRUCT(finfo);
1172 GetTimeOfDay(&tp_start);
1173 DEBUG(5, ("RJS do_tarput called ...\n"));
1175 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1177 /* Now read through those files ... */
1178 while (True) {
1179 /* Get us to the next block, or the first block first time around */
1180 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1181 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1182 SAFE_FREE(longfilename);
1183 return;
1186 DEBUG(5, ("Reading the next header ...\n"));
1188 switch (readtarheader((union hblock *) buffer_p,
1189 &finfo, client_get_cur_dir())) {
1190 case -2: /* Hmm, not good, but not fatal */
1191 DEBUG(0, ("Skipping %s...\n", finfo.name));
1192 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1193 DEBUG(0, ("Short file, bailing out...\n"));
1194 return;
1196 break;
1198 case -1:
1199 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1200 return;
1202 case 0: /* chksum is zero - looks like an EOF */
1203 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1204 return; /* Hmmm, bad here ... */
1206 default:
1207 /* No action */
1208 break;
1211 /* Now, do we have a long file name? */
1212 if (longfilename != NULL) {
1213 SAFE_FREE(finfo.name); /* Free the space already allocated */
1214 finfo.name = longfilename;
1215 longfilename = NULL;
1218 /* Well, now we have a header, process the file ... */
1219 /* Should we skip the file? We have the long name as well here */
1220 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1221 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1223 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1224 if (skip) {
1225 skip_file(finfo.size);
1226 continue;
1229 /* We only get this far if we should process the file */
1230 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1231 switch (linkflag) {
1232 case '0': /* Should use symbolic names--FIXME */
1234 * Skip to the next block first, so we can get the file, FIXME, should
1235 * be in get_file ...
1236 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1237 * Fixes bug where file size in tarfile is zero.
1239 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1240 DEBUG(0, ("Short file, bailing out...\n"));
1241 return;
1243 if (!get_file(finfo)) {
1244 DEBUG(0, ("Abandoning restore\n"));
1245 return;
1247 break;
1248 case '5':
1249 if (!get_dir(finfo)) {
1250 DEBUG(0, ("Abandoning restore \n"));
1251 return;
1253 break;
1254 case 'L':
1255 SAFE_FREE(longfilename);
1256 longfilename = get_longfilename(finfo);
1257 if (!longfilename) {
1258 DEBUG(0, ("abandoning restore\n"));
1259 return;
1261 DEBUG(5, ("Long file name: %s\n", longfilename));
1262 break;
1264 default:
1265 skip_file(finfo.size); /* Don't handle these yet */
1266 break;
1272 * samba interactive commands
1275 /****************************************************************************
1276 Blocksize command
1277 ***************************************************************************/
1279 int cmd_block(void)
1281 TALLOC_CTX *ctx = talloc_tos();
1282 char *buf;
1283 int block;
1285 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1286 DEBUG(0, ("blocksize <n>\n"));
1287 return 1;
1290 block=atoi(buf);
1291 if (block < 0 || block > 65535) {
1292 DEBUG(0, ("blocksize out of range"));
1293 return 1;
1296 blocksize=block;
1297 DEBUG(2,("blocksize is now %d\n", blocksize));
1298 return 0;
1301 /****************************************************************************
1302 command to set incremental / reset mode
1303 ***************************************************************************/
1305 int cmd_tarmode(void)
1307 TALLOC_CTX *ctx = talloc_tos();
1308 char *buf;
1310 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1311 if (strequal(buf, "full"))
1312 tar_inc=False;
1313 else if (strequal(buf, "inc"))
1314 tar_inc=True;
1315 else if (strequal(buf, "reset"))
1316 tar_reset=True;
1317 else if (strequal(buf, "noreset"))
1318 tar_reset=False;
1319 else if (strequal(buf, "system"))
1320 tar_system=True;
1321 else if (strequal(buf, "nosystem"))
1322 tar_system=False;
1323 else if (strequal(buf, "hidden"))
1324 tar_hidden=True;
1325 else if (strequal(buf, "nohidden"))
1326 tar_hidden=False;
1327 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1328 tar_noisy=True;
1329 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1330 tar_noisy=False;
1331 else
1332 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1333 TALLOC_FREE(buf);
1336 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1337 tar_inc ? "incremental" : "full",
1338 tar_system ? "system" : "nosystem",
1339 tar_hidden ? "hidden" : "nohidden",
1340 tar_reset ? "reset" : "noreset",
1341 tar_noisy ? "verbose" : "quiet"));
1342 return 0;
1345 /****************************************************************************
1346 Feeble attrib command
1347 ***************************************************************************/
1349 int cmd_setmode(void)
1351 TALLOC_CTX *ctx = talloc_tos();
1352 char *q;
1353 char *buf;
1354 char *fname = NULL;
1355 uint16 attra[2];
1356 int direct=1;
1358 attra[0] = attra[1] = 0;
1360 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1361 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1362 return 1;
1365 fname = talloc_asprintf(ctx,
1366 "%s%s",
1367 client_get_cur_dir(),
1368 buf);
1369 if (!fname) {
1370 return 1;
1373 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1374 q=buf;
1376 while(*q) {
1377 switch (*q++) {
1378 case '+':
1379 direct=1;
1380 break;
1381 case '-':
1382 direct=0;
1383 break;
1384 case 'r':
1385 attra[direct]|=aRONLY;
1386 break;
1387 case 'h':
1388 attra[direct]|=aHIDDEN;
1389 break;
1390 case 's':
1391 attra[direct]|=aSYSTEM;
1392 break;
1393 case 'a':
1394 attra[direct]|=aARCH;
1395 break;
1396 default:
1397 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1398 return 1;
1403 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1404 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1405 return 1;
1408 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1409 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1410 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1411 return 0;
1415 Convert list of tokens to array; dependent on above routine.
1416 Uses the global cmd_ptr from above - bit of a hack.
1419 static char **toktocliplist(int *ctok, const char *sep)
1421 char *s=(char *)cmd_ptr;
1422 int ictok=0;
1423 char **ret, **iret;
1425 if (!sep)
1426 sep = " \t\n\r";
1428 while(*s && strchr_m(sep,*s))
1429 s++;
1431 /* nothing left? */
1432 if (!*s)
1433 return(NULL);
1435 do {
1436 ictok++;
1437 while(*s && (!strchr_m(sep,*s)))
1438 s++;
1439 while(*s && strchr_m(sep,*s))
1440 *s++=0;
1441 } while(*s);
1443 *ctok=ictok;
1444 s=(char *)cmd_ptr;
1446 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1447 return NULL;
1449 while(ictok--) {
1450 *iret++=s;
1451 if (ictok > 0) {
1452 while(*s++)
1454 while(!*s)
1455 s++;
1459 ret[*ctok] = NULL;
1460 return ret;
1463 /****************************************************************************
1464 Principal command for creating / extracting
1465 ***************************************************************************/
1467 int cmd_tar(void)
1469 TALLOC_CTX *ctx = talloc_tos();
1470 char *buf;
1471 char **argl = NULL;
1472 int argcl = 0;
1473 int ret;
1475 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1476 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1477 return 1;
1480 argl=toktocliplist(&argcl, NULL);
1481 if (!tar_parseargs(argcl, argl, buf, 0)) {
1482 SAFE_FREE(argl);
1483 return 1;
1486 ret = process_tar();
1487 SAFE_FREE(argl);
1488 return ret;
1491 /****************************************************************************
1492 Command line (option) version
1493 ***************************************************************************/
1495 int process_tar(void)
1497 TALLOC_CTX *ctx = talloc_tos();
1498 int rc = 0;
1499 initarbuf();
1500 switch(tar_type) {
1501 case 'x':
1503 #if 0
1504 do_tarput2();
1505 #else
1506 do_tarput();
1507 #endif
1508 SAFE_FREE(tarbuf);
1509 close(tarhandle);
1510 break;
1511 case 'r':
1512 case 'c':
1513 if (clipn && tar_excl) {
1514 int i;
1515 char *tarmac = NULL;
1517 for (i=0; i<clipn; i++) {
1518 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1520 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1521 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1524 if (strrchr_m(cliplist[i], '\\')) {
1525 char *p;
1526 char saved_char;
1527 char *saved_dir = talloc_strdup(ctx,
1528 client_get_cur_dir());
1529 if (!saved_dir) {
1530 return 1;
1533 if (*cliplist[i]=='\\') {
1534 tarmac = talloc_strdup(ctx,
1535 cliplist[i]);
1536 } else {
1537 tarmac = talloc_asprintf(ctx,
1538 "%s%s",
1539 client_get_cur_dir(),
1540 cliplist[i]);
1542 if (!tarmac) {
1543 return 1;
1546 * Strip off the last \\xxx
1547 * xxx element of tarmac to set
1548 * it as current directory.
1550 p = strrchr_m(tarmac, '\\');
1551 if (!p) {
1552 return 1;
1554 saved_char = p[1];
1555 p[1] = '\0';
1557 client_set_cur_dir(tarmac);
1560 * Restore the character we
1561 * just replaced to
1562 * put the pathname
1563 * back as it was.
1565 p[1] = saved_char;
1567 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1568 do_list(tarmac,attribute,do_tar, False, True);
1570 client_set_cur_dir(saved_dir);
1572 TALLOC_FREE(saved_dir);
1573 TALLOC_FREE(tarmac);
1574 } else {
1575 tarmac = talloc_asprintf(ctx,
1576 "%s%s",
1577 client_get_cur_dir(),
1578 cliplist[i]);
1579 if (!tarmac) {
1580 return 1;
1582 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1583 do_list(tarmac,attribute,do_tar, False, True);
1584 TALLOC_FREE(tarmac);
1587 } else {
1588 char *mask = talloc_asprintf(ctx,
1589 "%s\\*",
1590 client_get_cur_dir());
1591 if (!mask) {
1592 return 1;
1594 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1595 do_list(mask,attribute,do_tar,False, True);
1596 TALLOC_FREE(mask);
1599 if (ntarf) {
1600 dotareof(tarhandle);
1602 close(tarhandle);
1603 SAFE_FREE(tarbuf);
1605 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1606 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1607 break;
1610 if (must_free_cliplist) {
1611 int i;
1612 for (i = 0; i < clipn; ++i) {
1613 SAFE_FREE(cliplist[i]);
1615 SAFE_FREE(cliplist);
1616 cliplist = NULL;
1617 clipn = 0;
1618 must_free_cliplist = False;
1620 return rc;
1623 /****************************************************************************
1624 Find a token (filename) in a clip list
1625 ***************************************************************************/
1627 static int clipfind(char **aret, int ret, char *tok)
1629 if (aret==NULL)
1630 return 0;
1632 /* ignore leading slashes or dots in token */
1633 while(strchr_m("/\\.", *tok))
1634 tok++;
1636 while(ret--) {
1637 char *pkey=*aret++;
1639 /* ignore leading slashes or dots in list */
1640 while(strchr_m("/\\.", *pkey))
1641 pkey++;
1643 if (!strslashcmp(pkey, tok))
1644 return 1;
1646 return 0;
1649 /****************************************************************************
1650 Read list of files to include from the file and initialize cliplist
1651 accordingly.
1652 ***************************************************************************/
1654 static int read_inclusion_file(char *filename)
1656 XFILE *inclusion = NULL;
1657 char buf[PATH_MAX + 1];
1658 char *inclusion_buffer = NULL;
1659 int inclusion_buffer_size = 0;
1660 int inclusion_buffer_sofar = 0;
1661 char *p;
1662 char *tmpstr;
1663 int i;
1664 int error = 0;
1666 clipn = 0;
1667 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1668 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1669 /* XXX It would be better to include a reason for failure, but without
1670 * autoconf, it's hard to use strerror, sys_errlist, etc.
1672 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1673 return 0;
1676 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1677 if (inclusion_buffer == NULL) {
1678 inclusion_buffer_size = 1024;
1679 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1680 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1681 error = 1;
1682 break;
1686 if (buf[strlen(buf)-1] == '\n') {
1687 buf[strlen(buf)-1] = '\0';
1690 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1691 inclusion_buffer_size *= 2;
1692 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1693 if (!inclusion_buffer) {
1694 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1695 inclusion_buffer_size));
1696 error = 1;
1697 break;
1701 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1702 inclusion_buffer_sofar += strlen(buf) + 1;
1703 clipn++;
1705 x_fclose(inclusion);
1707 if (! error) {
1708 /* Allocate an array of clipn + 1 char*'s for cliplist */
1709 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1710 if (cliplist == NULL) {
1711 DEBUG(0,("failure allocating memory for cliplist\n"));
1712 error = 1;
1713 } else {
1714 cliplist[clipn] = NULL;
1715 p = inclusion_buffer;
1716 for (i = 0; (! error) && (i < clipn); i++) {
1717 /* set current item to NULL so array will be null-terminated even if
1718 * malloc fails below. */
1719 cliplist[i] = NULL;
1720 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1721 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1722 error = 1;
1723 } else {
1724 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1725 cliplist[i] = tmpstr;
1726 if ((p = strchr_m(p, '\000')) == NULL) {
1727 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1728 abort();
1731 ++p;
1733 must_free_cliplist = True;
1737 SAFE_FREE(inclusion_buffer);
1738 if (error) {
1739 if (cliplist) {
1740 char **pp;
1741 /* We know cliplist is always null-terminated */
1742 for (pp = cliplist; *pp; ++pp) {
1743 SAFE_FREE(*pp);
1745 SAFE_FREE(cliplist);
1746 cliplist = NULL;
1747 must_free_cliplist = False;
1749 return 0;
1752 /* cliplist and its elements are freed at the end of process_tar. */
1753 return 1;
1756 /****************************************************************************
1757 Parse tar arguments. Sets tar_type, tar_excl, etc.
1758 ***************************************************************************/
1760 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1762 int newOptind = Optind;
1763 char tar_clipfl='\0';
1765 /* Reset back to defaults - could be from interactive version
1766 * reset mode and archive mode left as they are though
1768 tar_type='\0';
1769 tar_excl=True;
1770 dry_run=False;
1772 while (*Optarg) {
1773 switch(*Optarg++) {
1774 case 'c':
1775 tar_type='c';
1776 break;
1777 case 'x':
1778 if (tar_type=='c') {
1779 printf("Tar must be followed by only one of c or x.\n");
1780 return 0;
1782 tar_type='x';
1783 break;
1784 case 'b':
1785 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1786 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1787 return 0;
1788 } else {
1789 Optind++;
1790 newOptind++;
1792 break;
1793 case 'g':
1794 tar_inc=True;
1795 break;
1796 case 'N':
1797 if (Optind>=argc) {
1798 DEBUG(0,("Option N must be followed by valid file name\n"));
1799 return 0;
1800 } else {
1801 SMB_STRUCT_STAT stbuf;
1803 if (sys_stat(argv[Optind], &stbuf,
1804 false) == 0) {
1805 newer_than = convert_timespec_to_time_t(
1806 stbuf.st_ex_mtime);
1807 DEBUG(1,("Getting files newer than %s",
1808 time_to_asc(newer_than)));
1809 newOptind++;
1810 Optind++;
1811 } else {
1812 DEBUG(0,("Error setting newer-than time\n"));
1813 return 0;
1816 break;
1817 case 'a':
1818 tar_reset=True;
1819 break;
1820 case 'q':
1821 tar_noisy=False;
1822 break;
1823 case 'I':
1824 if (tar_clipfl) {
1825 DEBUG(0,("Only one of I,X,F must be specified\n"));
1826 return 0;
1828 tar_clipfl='I';
1829 break;
1830 case 'X':
1831 if (tar_clipfl) {
1832 DEBUG(0,("Only one of I,X,F must be specified\n"));
1833 return 0;
1835 tar_clipfl='X';
1836 break;
1837 case 'F':
1838 if (tar_clipfl) {
1839 DEBUG(0,("Only one of I,X,F must be specified\n"));
1840 return 0;
1842 tar_clipfl='F';
1843 break;
1844 case 'r':
1845 DEBUG(0, ("tar_re_search set\n"));
1846 tar_re_search = True;
1847 break;
1848 case 'n':
1849 if (tar_type == 'c') {
1850 DEBUG(0, ("dry_run set\n"));
1851 dry_run = True;
1852 } else {
1853 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1854 return 0;
1856 break;
1857 default:
1858 DEBUG(0,("Unknown tar option\n"));
1859 return 0;
1863 if (!tar_type) {
1864 printf("Option T must be followed by one of c or x.\n");
1865 return 0;
1868 /* tar_excl is true if cliplist lists files to be included.
1869 * Both 'I' and 'F' mean include. */
1870 tar_excl=tar_clipfl!='X';
1872 if (tar_clipfl=='F') {
1873 if (argc-Optind-1 != 1) {
1874 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1875 return 0;
1877 newOptind++;
1878 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1879 if (! read_inclusion_file(argv[Optind+1])) {
1880 return 0;
1882 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1883 char *tmpstr;
1884 char **tmplist;
1885 int clipcount;
1887 cliplist=argv+Optind+1;
1888 clipn=argc-Optind-1;
1889 clipcount = clipn;
1891 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1892 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1893 return 0;
1896 for (clipcount = 0; clipcount < clipn; clipcount++) {
1898 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1900 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1901 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1902 SAFE_FREE(tmplist);
1903 return 0;
1906 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1907 tmplist[clipcount] = tmpstr;
1908 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1910 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1913 cliplist = tmplist;
1914 must_free_cliplist = True;
1916 newOptind += clipn;
1919 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1920 /* Doing regular expression seaches not from an inclusion file. */
1921 clipn=argc-Optind-1;
1922 cliplist=argv+Optind+1;
1923 newOptind += clipn;
1926 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1927 /* Sets tar handle to either 0 or 1, as appropriate */
1928 tarhandle=(tar_type=='c');
1930 * Make sure that dbf points to stderr if we are using stdout for
1931 * tar output
1933 if (tarhandle == 1) {
1934 dbf = x_stderr;
1936 if (!argv[Optind]) {
1937 DEBUG(0,("Must specify tar filename\n"));
1938 return 0;
1940 if (!strcmp(argv[Optind], "-")) {
1941 newOptind++;
1944 } else {
1945 if (tar_type=='c' && dry_run) {
1946 tarhandle=-1;
1947 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1948 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1949 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1950 return(0);
1952 newOptind++;
1955 return newOptind;