s3: Fix Coverity ID 83: RESOURCE_LEAK
[Samba.git] / source3 / client / clitar.c
blobac891aa7e8c613be530af33348f0bfafd290d31d
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 NTSTATUS do_atar(const char *rname_in, char *lname,
118 struct file_info *finfo1);
119 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
120 const char *dir);
121 static void oct_it(uint64_t value, int ndgs, char *p);
122 static void fixtarname(char *tptr, const char *fp, size_t l);
123 static int dotarbuf(int f, char *b, int n);
124 static void dozerobuf(int f, int n);
125 static void dotareof(int f);
126 static void initarbuf(void);
128 /* restore functions */
129 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
130 static long unoct(char *p, int ndgs);
131 static void do_tarput(void);
132 static void unfixtarname(char *tptr, char *fp, int l, bool first);
135 * tar specific utitlities
138 /*******************************************************************
139 Create a string of size size+1 (for the null)
140 *******************************************************************/
142 static char *string_create_s(int size)
144 char *tmp;
146 tmp = (char *)SMB_MALLOC(size+1);
148 if (tmp == NULL) {
149 DEBUG(0, ("Out of memory in string_create_s\n"));
152 return(tmp);
155 /****************************************************************************
156 Write a tar header to buffer
157 ****************************************************************************/
159 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
160 const char *amode, unsigned char ftype)
162 union hblock hb;
163 int i, chk, l;
164 char *jp;
166 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
168 memset(hb.dummy, 0, sizeof(hb.dummy));
170 l=strlen(aname);
171 /* We will be prepending a '.' in fixtarheader so use +2 to
172 * take care of the . and terminating zero. JRA.
174 if (l+2 >= NAMSIZ) {
175 /* write a GNU tar style long header */
176 char *b;
177 b = (char *)SMB_MALLOC(l+TBLOCK+100);
178 if (!b) {
179 DEBUG(0,("out of memory\n"));
180 exit(1);
182 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
183 memset(b, 0, l+TBLOCK+100);
184 fixtarname(b, aname, l+2);
185 i = strlen(b)+1;
186 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
187 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
188 SAFE_FREE(b);
191 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
193 if (lowercase)
194 strlower_m(hb.dbuf.name);
196 /* write out a "standard" tar format header */
198 hb.dbuf.name[NAMSIZ-1]='\0';
199 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
200 oct_it((uint64_t)0, 8, hb.dbuf.uid);
201 oct_it((uint64_t)0, 8, hb.dbuf.gid);
202 oct_it((uint64_t) size, 13, hb.dbuf.size);
203 if (size > (uint64_t)077777777777LL) {
204 /* This is a non-POSIX compatible extention to store files
205 greater than 8GB. */
207 memset(hb.dbuf.size, 0, 4);
208 hb.dbuf.size[0]=128;
209 for (i = 8, jp=(char*)&size; i; i--)
210 hb.dbuf.size[i+3] = *(jp++);
212 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
213 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
214 memset(hb.dbuf.linkname, 0, NAMSIZ);
215 hb.dbuf.linkflag=ftype;
217 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
218 chk+=(0xFF & *jp++);
220 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
221 hb.dbuf.chksum[6] = '\0';
223 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
226 /****************************************************************************
227 Read a tar header into a hblock structure, and validate
228 ***************************************************************************/
230 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
232 long chk, fchk;
233 int i;
234 char *jp;
237 * read in a "standard" tar format header - we're not that interested
238 * in that many fields, though
241 /* check the checksum */
242 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
243 chk+=(0xFF & *jp++);
245 if (chk == 0)
246 return chk;
248 /* compensate for blanks in chksum header */
249 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
250 chk-=(0xFF & *jp++);
252 chk += ' ' * sizeof(hb->dbuf.chksum);
254 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
256 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
257 chk, fchk, hb->dbuf.chksum));
259 if (fchk != chk) {
260 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
261 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
262 return -1;
265 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
266 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
267 return(-1);
270 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
272 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
273 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
274 strlen(hb->dbuf.name) + 1, True);
276 /* can't handle some links at present */
277 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
278 if (hb->dbuf.linkflag == 0) {
279 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
280 finfo->name));
281 } else {
282 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
283 /* Do nothing here at the moment. do_tarput will handle this
284 as long as the longlink gets back to it, as it has to advance
285 the buffer pointer, etc */
286 } else {
287 DEBUG(0, ("this tar file appears to contain some kind \
288 of link other than a GNUtar Longlink - ignoring\n"));
289 return -2;
294 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
295 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
296 finfo->mode=aDIR;
297 } else {
298 finfo->mode=0; /* we don't care about mode at the moment, we'll
299 * just make it a regular file */
303 * Bug fix by richard@sj.co.uk
305 * REC: restore times correctly (as does tar)
306 * We only get the modification time of the file; set the creation time
307 * from the mod. time, and the access time to current time
309 finfo->mtime_ts = finfo->ctime_ts =
310 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
311 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
312 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
314 return True;
317 /****************************************************************************
318 Write out the tar buffer to tape or wherever
319 ****************************************************************************/
321 static int dotarbuf(int f, char *b, int n)
323 int fail=1, writ=n;
325 if (dry_run) {
326 return writ;
328 /* This routine and the next one should be the only ones that do write()s */
329 if (tp + n >= tbufsiz) {
330 int diff;
332 diff=tbufsiz-tp;
333 memcpy(tarbuf + tp, b, diff);
334 fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
335 n-=diff;
336 b+=diff;
337 tp=0;
339 while (n >= tbufsiz) {
340 fail=fail && (1 + sys_write(f, b, tbufsiz));
341 n-=tbufsiz;
342 b+=tbufsiz;
346 if (n>0) {
347 memcpy(tarbuf+tp, b, n);
348 tp+=n;
351 return(fail ? writ : 0);
354 /****************************************************************************
355 Write zeros to buffer / tape
356 ****************************************************************************/
358 static void dozerobuf(int f, int n)
360 /* short routine just to write out n zeros to buffer -
361 * used to round files to nearest block
362 * and to do tar EOFs */
364 if (dry_run)
365 return;
367 if (n+tp >= tbufsiz) {
368 memset(tarbuf+tp, 0, tbufsiz-tp);
369 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
370 DEBUG(0, ("dozerobuf: sys_write fail\n"));
371 return;
373 memset(tarbuf, 0, (tp+=n-tbufsiz));
374 } else {
375 memset(tarbuf+tp, 0, n);
376 tp+=n;
380 /****************************************************************************
381 Malloc tape buffer
382 ****************************************************************************/
384 static void initarbuf(void)
386 /* initialize tar buffer */
387 tbufsiz=blocksize*TBLOCK;
388 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
390 /* reset tar buffer pointer and tar file counter and total dumped */
391 tp=0; ntarf=0; ttarf=0;
394 /****************************************************************************
395 Write two zero blocks at end of file
396 ****************************************************************************/
398 static void dotareof(int f)
400 SMB_STRUCT_STAT stbuf;
401 /* Two zero blocks at end of file, write out full buffer */
403 if (dry_run)
404 return;
406 (void) dozerobuf(f, TBLOCK);
407 (void) dozerobuf(f, TBLOCK);
409 if (sys_fstat(f, &stbuf, false) == -1) {
410 DEBUG(0, ("Couldn't stat file handle\n"));
411 return;
414 /* Could be a pipe, in which case S_ISREG should fail,
415 * and we should write out at full size */
416 if (tp > 0) {
417 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
418 if (sys_write(f, tarbuf, towrite) != towrite) {
419 DEBUG(0,("dotareof: sys_write fail\n"));
424 /****************************************************************************
425 (Un)mangle DOS pathname, make nonabsolute
426 ****************************************************************************/
428 static void fixtarname(char *tptr, const char *fp, size_t l)
430 /* add a '.' to start of file name, convert from ugly dos \'s in path
431 * to lovely unix /'s :-} */
432 *tptr++='.';
433 l--;
435 StrnCpy(tptr, fp, l-1);
436 string_replace(tptr, '\\', '/');
439 /****************************************************************************
440 Convert from decimal to octal string
441 ****************************************************************************/
443 static void oct_it (uint64_t value, int ndgs, char *p)
445 /* Converts long to octal string, pads with leading zeros */
447 /* skip final null, but do final space */
448 --ndgs;
449 p[--ndgs] = ' ';
451 /* Loop does at least one digit */
452 do {
453 p[--ndgs] = '0' + (char) (value & 7);
454 value >>= 3;
455 } while (ndgs > 0 && value != 0);
457 /* Do leading zeros */
458 while (ndgs > 0)
459 p[--ndgs] = '0';
462 /****************************************************************************
463 Convert from octal string to long
464 ***************************************************************************/
466 static long unoct(char *p, int ndgs)
468 long value=0;
469 /* Converts octal string to long, ignoring any non-digit */
471 while (--ndgs) {
472 if (isdigit((int)*p))
473 value = (value << 3) | (long) (*p - '0');
475 p++;
478 return value;
481 /****************************************************************************
482 Compare two strings in a slash insensitive way, allowing s1 to match s2
483 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
484 a file in any subdirectory of s1, declare a match.
485 ***************************************************************************/
487 static int strslashcmp(char *s1, char *s2)
489 char *s1_0=s1;
491 while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
492 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
493 s1++; s2++;
496 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
497 string of s2.
499 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
500 return 0;
502 /* ignore trailing slash on s1 */
503 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
504 return 0;
506 /* check for s1 is an "initial" string of s2 */
507 if ((*s2 == '/' || *s2 == '\\') && !*s1)
508 return 0;
510 return *s1-*s2;
513 /****************************************************************************
514 Ensure a remote path exists (make if necessary)
515 ***************************************************************************/
517 static bool ensurepath(const char *fname)
519 /* *must* be called with buffer ready malloc'ed */
520 /* ensures path exists */
522 char *partpath, *ffname;
523 const char *p=fname;
524 char *basehack;
525 char *saveptr;
527 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
529 partpath = string_create_s(strlen(fname));
530 ffname = string_create_s(strlen(fname));
532 if ((partpath == NULL) || (ffname == NULL)){
533 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
534 SAFE_FREE(partpath);
535 SAFE_FREE(ffname);
536 return(False);
539 *partpath = 0;
541 /* fname copied to ffname so can strtok_r */
543 safe_strcpy(ffname, fname, strlen(fname));
545 /* do a `basename' on ffname, so don't try and make file name directory */
546 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
547 SAFE_FREE(partpath);
548 SAFE_FREE(ffname);
549 return True;
550 } else {
551 *basehack='\0';
554 p=strtok_r(ffname, "\\", &saveptr);
556 while (p) {
557 safe_strcat(partpath, p, strlen(fname) + 1);
559 if (!NT_STATUS_IS_OK(cli_chkpath(cli, partpath))) {
560 if (!NT_STATUS_IS_OK(cli_mkdir(cli, partpath))) {
561 SAFE_FREE(partpath);
562 SAFE_FREE(ffname);
563 DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
564 return False;
565 } else {
566 DEBUG(3, ("mkdirhiering %s\n", partpath));
570 safe_strcat(partpath, "\\", strlen(fname) + 1);
571 p = strtok_r(NULL, "/\\", &saveptr);
574 SAFE_FREE(partpath);
575 SAFE_FREE(ffname);
576 return True;
579 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
581 int berr= 0;
582 int bytestowrite;
584 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
585 memset(buf, 0, (size_t)bufsize);
586 while( !berr && padsize > 0 ) {
587 bytestowrite= (int)MIN(bufsize, padsize);
588 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
589 padsize -= bytestowrite;
592 return berr;
595 static void do_setrattr(char *name, uint16 attr, int set)
597 uint16 oldattr;
599 if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
600 return;
603 if (set == ATTRSET) {
604 attr |= oldattr;
605 } else {
606 attr = oldattr & ~attr;
609 if (!NT_STATUS_IS_OK(cli_setatr(cli, name, attr, 0))) {
610 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
614 /****************************************************************************
615 append one remote file to the tar file
616 ***************************************************************************/
618 static NTSTATUS do_atar(const char *rname_in, char *lname,
619 struct file_info *finfo1)
621 uint16_t fnum = (uint16_t)-1;
622 uint64_t nread=0;
623 char ftype;
624 file_info2 finfo;
625 bool shallitime=True;
626 char *data = NULL;
627 int read_size = 65520;
628 int datalen=0;
629 char *rname = NULL;
630 TALLOC_CTX *ctx = talloc_stackframe();
631 NTSTATUS status = NT_STATUS_OK;
632 struct timespec tp_start;
634 clock_gettime_mono(&tp_start);
636 data = SMB_MALLOC_ARRAY(char, read_size);
637 if (!data) {
638 DEBUG(0,("do_atar: out of memory.\n"));
639 status = NT_STATUS_NO_MEMORY;
640 goto cleanup;
643 ftype = '0'; /* An ordinary file ... */
645 ZERO_STRUCT(finfo);
647 finfo.size = finfo1 -> size;
648 finfo.mode = finfo1 -> mode;
649 finfo.uid = finfo1 -> uid;
650 finfo.gid = finfo1 -> gid;
651 finfo.mtime_ts = finfo1 -> mtime_ts;
652 finfo.atime_ts = finfo1 -> atime_ts;
653 finfo.ctime_ts = finfo1 -> ctime_ts;
655 if (dry_run) {
656 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
657 (double)finfo.size));
658 shallitime=0;
659 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
660 ntarf++;
661 goto cleanup;
664 rname = clean_name(ctx, rname_in);
665 if (!rname) {
666 status = NT_STATUS_NO_MEMORY;
667 goto cleanup;
670 status = cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum);
671 if (!NT_STATUS_IS_OK(status)) {
672 DEBUG(0,("%s opening remote file %s (%s)\n",
673 cli_errstr(cli),rname, client_get_cur_dir()));
674 goto cleanup;
677 finfo.name = string_create_s(strlen(rname));
678 if (finfo.name == NULL) {
679 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
680 status = NT_STATUS_NO_MEMORY;
681 goto cleanup;
684 safe_strcpy(finfo.name,rname, strlen(rname));
686 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
688 if (tar_inc && !(finfo.mode & aARCH)) {
689 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
690 shallitime=0;
691 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
692 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
693 shallitime=0;
694 } else if (!tar_hidden && (finfo.mode & aHIDDEN)) {
695 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
696 shallitime=0;
697 } else {
698 bool wrote_tar_header = False;
700 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
701 finfo.name, (double)finfo.size, lname));
703 do {
705 DEBUG(3,("nread=%.0f\n",(double)nread));
707 datalen = cli_read(cli, fnum, data, nread, read_size);
709 if (datalen == -1) {
710 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
711 status = cli_nt_error(cli);
712 break;
715 nread += datalen;
717 /* Only if the first read succeeds, write out the tar header. */
718 if (!wrote_tar_header) {
719 /* write a tar header, don't bother with mode - just set to 100644 */
720 writetarheader(tarhandle, rname, finfo.size,
721 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
722 wrote_tar_header = True;
725 /* if file size has increased since we made file size query, truncate
726 read so tar header for this file will be correct.
729 if (nread > finfo.size) {
730 datalen -= nread - finfo.size;
731 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
732 finfo.name, (double)finfo.size));
735 /* add received bits of file to buffer - dotarbuf will
736 * write out in 512 byte intervals */
738 if (dotarbuf(tarhandle,data,datalen) != datalen) {
739 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
740 status = map_nt_error_from_unix(errno);
741 break;
744 if ( (datalen == 0) && (finfo.size != 0) ) {
745 status = NT_STATUS_UNSUCCESSFUL;
746 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
747 break;
750 datalen=0;
751 } while ( nread < finfo.size );
753 if (wrote_tar_header) {
754 /* pad tar file with zero's if we couldn't get entire file */
755 if (nread < finfo.size) {
756 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
757 (double)finfo.size, (int)nread));
758 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) {
759 status = map_nt_error_from_unix(errno);
760 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
764 /* round tar file to nearest block */
765 if (finfo.size % TBLOCK)
766 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
768 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
769 ntarf++;
770 } else {
771 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
772 shallitime=0;
773 status = NT_STATUS_UNSUCCESSFUL;
777 cli_close(cli, fnum);
778 fnum = -1;
780 if (shallitime) {
781 struct timespec tp_end;
782 int this_time;
784 /* if shallitime is true then we didn't skip */
785 if (tar_reset && !dry_run)
786 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
788 clock_gettime_mono(&tp_end);
789 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000;
790 get_total_time_ms += this_time;
791 get_total_size += finfo.size;
793 if (tar_noisy) {
794 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
795 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
796 finfo.name));
799 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
800 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
801 finfo.size / MAX(0.001, (1.024*this_time)),
802 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
805 cleanup:
807 if (fnum != (uint16_t)-1) {
808 cli_close(cli, fnum);
809 fnum = -1;
811 TALLOC_FREE(ctx);
812 SAFE_FREE(data);
813 return status;
816 /****************************************************************************
817 Append single file to tar file (or not)
818 ***************************************************************************/
820 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
821 const char *dir)
823 TALLOC_CTX *ctx = talloc_stackframe();
824 NTSTATUS status = NT_STATUS_OK;
826 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
827 return NT_STATUS_OK;
829 /* Is it on the exclude list ? */
830 if (!tar_excl && clipn) {
831 char *exclaim;
833 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
835 exclaim = talloc_asprintf(ctx,
836 "%s\\%s",
837 client_get_cur_dir(),
838 finfo->name);
839 if (!exclaim) {
840 return NT_STATUS_NO_MEMORY;
843 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
845 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
846 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
847 DEBUG(3,("Skipping file %s\n", exclaim));
848 TALLOC_FREE(exclaim);
849 return NT_STATUS_OK;
851 TALLOC_FREE(exclaim);
854 if (finfo->mode & aDIR) {
855 char *saved_curdir = NULL;
856 char *new_cd = NULL;
857 char *mtar_mask = NULL;
859 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
860 if (!saved_curdir) {
861 return NT_STATUS_NO_MEMORY;
864 DEBUG(5, ("strlen(cur_dir)=%d, \
865 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
866 (int)strlen(saved_curdir),
867 (int)strlen(finfo->name), finfo->name, saved_curdir));
869 new_cd = talloc_asprintf(ctx,
870 "%s%s\\",
871 client_get_cur_dir(),
872 finfo->name);
873 if (!new_cd) {
874 return NT_STATUS_NO_MEMORY;
876 client_set_cur_dir(new_cd);
878 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
880 /* write a tar directory, don't bother with mode - just
881 * set it to 40755 */
882 writetarheader(tarhandle, client_get_cur_dir(), 0,
883 finfo->mtime_ts.tv_sec, "040755 \0", '5');
884 if (tar_noisy) {
885 DEBUG(0,(" directory %s\n",
886 client_get_cur_dir()));
888 ntarf++; /* Make sure we have a file on there */
889 mtar_mask = talloc_asprintf(ctx,
890 "%s*",
891 client_get_cur_dir());
892 if (!mtar_mask) {
893 return NT_STATUS_NO_MEMORY;
895 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
896 status = do_list(mtar_mask, attribute, do_tar, False, True);
897 client_set_cur_dir(saved_curdir);
898 TALLOC_FREE(saved_curdir);
899 TALLOC_FREE(new_cd);
900 TALLOC_FREE(mtar_mask);
901 } else {
902 char *rname = talloc_asprintf(ctx,
903 "%s%s",
904 client_get_cur_dir(),
905 finfo->name);
906 if (!rname) {
907 return NT_STATUS_NO_MEMORY;
909 status = do_atar(rname,finfo->name,finfo);
910 TALLOC_FREE(rname);
912 return status;
915 /****************************************************************************
916 Convert from UNIX to DOS file names
917 ***************************************************************************/
919 static void unfixtarname(char *tptr, char *fp, int l, bool first)
921 /* remove '.' from start of file name, convert from unix /'s to
922 * dos \'s in path. Kill any absolute path names. But only if first!
925 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
927 if (first) {
928 if (*fp == '.') {
929 fp++;
930 l--;
932 if (*fp == '\\' || *fp == '/') {
933 fp++;
934 l--;
938 safe_strcpy(tptr, fp, l);
939 string_replace(tptr, '/', '\\');
942 /****************************************************************************
943 Move to the next block in the buffer, which may mean read in another set of
944 blocks. FIXME, we should allow more than one block to be skipped.
945 ****************************************************************************/
947 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
949 int bufread, total = 0;
951 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
952 *bufferp += TBLOCK;
953 total = TBLOCK;
955 if (*bufferp >= (ltarbuf + bufsiz)) {
957 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
960 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
961 * Fixes bug where read can return short if coming from
962 * a pipe.
965 bufread = read(tarhandle, ltarbuf, bufsiz);
966 total = bufread;
968 while (total < bufsiz) {
969 if (bufread < 0) { /* An error, return false */
970 return (total > 0 ? -2 : bufread);
972 if (bufread == 0) {
973 if (total <= 0) {
974 return -2;
976 break;
978 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
979 total += bufread;
982 DEBUG(5, ("Total bytes read ... %i\n", total));
984 *bufferp = ltarbuf;
987 return(total);
990 /* Skip a file, even if it includes a long file name? */
991 static int skip_file(int skipsize)
993 int dsize = skipsize;
995 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
997 /* FIXME, we should skip more than one block at a time */
999 while (dsize > 0) {
1000 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1001 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1002 return(False);
1004 dsize -= TBLOCK;
1007 return(True);
1010 /*************************************************************
1011 Get a file from the tar file and store it.
1012 When this is called, tarbuf already contains the first
1013 file block. This is a bit broken & needs fixing.
1014 **************************************************************/
1016 static int get_file(file_info2 finfo)
1018 uint16_t fnum = (uint16_t) -1;
1019 int pos = 0, dsize = 0, bpos = 0;
1020 uint64_t rsize = 0;
1021 NTSTATUS status;
1023 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1025 if (!ensurepath(finfo.name)) {
1026 DEBUG(0, ("abandoning restore\n"));
1027 return False;
1030 status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1031 if (!NT_STATUS_IS_OK(status)) {
1032 DEBUG(0, ("abandoning restore\n"));
1033 return False;
1036 /* read the blocks from the tar file and write to the remote file */
1038 rsize = finfo.size; /* This is how much to write */
1040 while (rsize > 0) {
1042 /* We can only write up to the end of the buffer */
1043 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1044 dsize = MIN(dsize, rsize); /* Should be only what is left */
1045 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1047 if (cli_write(cli, fnum, 0, buffer_p + bpos, pos, dsize) != dsize) {
1048 DEBUG(0, ("Error writing remote file\n"));
1049 return 0;
1052 rsize -= dsize;
1053 pos += dsize;
1055 /* Now figure out how much to move in the buffer */
1057 /* FIXME, we should skip more than one block at a time */
1059 /* First, skip any initial part of the part written that is left over */
1060 /* from the end of the first TBLOCK */
1062 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1063 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1064 bpos = 0;
1066 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1067 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1068 return False;
1073 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1074 * If the file being extracted is an exact multiple of
1075 * TBLOCK bytes then we don't want to extract the next
1076 * block from the tarfile here, as it will be done in
1077 * the caller of get_file().
1080 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1081 ((rsize == 0) && (dsize > TBLOCK))) {
1083 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1084 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1085 return False;
1088 dsize -= TBLOCK;
1090 bpos = dsize;
1093 /* Now close the file ... */
1095 if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
1096 DEBUG(0, ("Error %s closing remote file\n",
1097 cli_errstr(cli)));
1098 return(False);
1101 /* Now we update the creation date ... */
1102 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1104 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1105 if (tar_real_noisy) {
1106 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1107 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1111 ntarf++;
1112 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1113 return(True);
1116 /* Create a directory. We just ensure that the path exists and return as there
1117 is no file associated with a directory
1119 static int get_dir(file_info2 finfo)
1121 DEBUG(0, ("restore directory %s\n", finfo.name));
1123 if (!ensurepath(finfo.name)) {
1124 DEBUG(0, ("Problems creating directory\n"));
1125 return(False);
1127 ntarf++;
1128 return(True);
1131 /* Get a file with a long file name ... first file has file name, next file
1132 has the data. We only want the long file name, as the loop in do_tarput
1133 will deal with the rest.
1135 static char *get_longfilename(file_info2 finfo)
1137 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1138 * header call. */
1139 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1140 char *longname = (char *)SMB_MALLOC(namesize);
1141 int offset = 0, left = finfo.size;
1142 bool first = True;
1144 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1145 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1147 if (longname == NULL) {
1148 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1149 return(NULL);
1152 /* First, add cur_dir to the long file name */
1154 if (strlen(client_get_cur_dir()) > 0) {
1155 strncpy(longname, client_get_cur_dir(), namesize);
1156 offset = strlen(client_get_cur_dir());
1159 /* Loop through the blocks picking up the name */
1161 while (left > 0) {
1162 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1163 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1164 SAFE_FREE(longname);
1165 return(NULL);
1168 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1169 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1171 offset += TBLOCK;
1172 left -= TBLOCK;
1175 return(longname);
1178 static void do_tarput(void)
1180 file_info2 finfo;
1181 struct timespec tp_start;
1182 char *longfilename = NULL, linkflag;
1183 int skip = False;
1185 ZERO_STRUCT(finfo);
1187 clock_gettime_mono(&tp_start);
1188 DEBUG(5, ("RJS do_tarput called ...\n"));
1190 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1192 /* Now read through those files ... */
1193 while (True) {
1194 /* Get us to the next block, or the first block first time around */
1195 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1196 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1197 SAFE_FREE(longfilename);
1198 return;
1201 DEBUG(5, ("Reading the next header ...\n"));
1203 switch (readtarheader((union hblock *) buffer_p,
1204 &finfo, client_get_cur_dir())) {
1205 case -2: /* Hmm, not good, but not fatal */
1206 DEBUG(0, ("Skipping %s...\n", finfo.name));
1207 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1208 DEBUG(0, ("Short file, bailing out...\n"));
1209 SAFE_FREE(longfilename);
1210 return;
1212 break;
1214 case -1:
1215 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1216 SAFE_FREE(longfilename);
1217 return;
1219 case 0: /* chksum is zero - looks like an EOF */
1220 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1221 SAFE_FREE(longfilename);
1222 return; /* Hmmm, bad here ... */
1224 default:
1225 /* No action */
1226 break;
1229 /* Now, do we have a long file name? */
1230 if (longfilename != NULL) {
1231 SAFE_FREE(finfo.name); /* Free the space already allocated */
1232 finfo.name = longfilename;
1233 longfilename = NULL;
1236 /* Well, now we have a header, process the file ... */
1237 /* Should we skip the file? We have the long name as well here */
1238 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1239 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1241 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1242 if (skip) {
1243 skip_file(finfo.size);
1244 continue;
1247 /* We only get this far if we should process the file */
1248 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1249 switch (linkflag) {
1250 case '0': /* Should use symbolic names--FIXME */
1252 * Skip to the next block first, so we can get the file, FIXME, should
1253 * be in get_file ...
1254 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1255 * Fixes bug where file size in tarfile is zero.
1257 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1258 DEBUG(0, ("Short file, bailing out...\n"));
1259 return;
1261 if (!get_file(finfo)) {
1262 DEBUG(0, ("Abandoning restore\n"));
1263 return;
1265 break;
1266 case '5':
1267 if (!get_dir(finfo)) {
1268 DEBUG(0, ("Abandoning restore \n"));
1269 return;
1271 break;
1272 case 'L':
1273 SAFE_FREE(longfilename);
1274 longfilename = get_longfilename(finfo);
1275 if (!longfilename) {
1276 DEBUG(0, ("abandoning restore\n"));
1277 return;
1279 DEBUG(5, ("Long file name: %s\n", longfilename));
1280 break;
1282 default:
1283 skip_file(finfo.size); /* Don't handle these yet */
1284 break;
1290 * samba interactive commands
1293 /****************************************************************************
1294 Blocksize command
1295 ***************************************************************************/
1297 int cmd_block(void)
1299 TALLOC_CTX *ctx = talloc_tos();
1300 char *buf;
1301 int block;
1303 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1304 DEBUG(0, ("blocksize <n>\n"));
1305 return 1;
1308 block=atoi(buf);
1309 if (block < 0 || block > 65535) {
1310 DEBUG(0, ("blocksize out of range"));
1311 return 1;
1314 blocksize=block;
1315 DEBUG(2,("blocksize is now %d\n", blocksize));
1316 return 0;
1319 /****************************************************************************
1320 command to set incremental / reset mode
1321 ***************************************************************************/
1323 int cmd_tarmode(void)
1325 TALLOC_CTX *ctx = talloc_tos();
1326 char *buf;
1328 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1329 if (strequal(buf, "full"))
1330 tar_inc=False;
1331 else if (strequal(buf, "inc"))
1332 tar_inc=True;
1333 else if (strequal(buf, "reset"))
1334 tar_reset=True;
1335 else if (strequal(buf, "noreset"))
1336 tar_reset=False;
1337 else if (strequal(buf, "system"))
1338 tar_system=True;
1339 else if (strequal(buf, "nosystem"))
1340 tar_system=False;
1341 else if (strequal(buf, "hidden"))
1342 tar_hidden=True;
1343 else if (strequal(buf, "nohidden"))
1344 tar_hidden=False;
1345 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1346 tar_noisy=True;
1347 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1348 tar_noisy=False;
1349 else
1350 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1351 TALLOC_FREE(buf);
1354 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1355 tar_inc ? "incremental" : "full",
1356 tar_system ? "system" : "nosystem",
1357 tar_hidden ? "hidden" : "nohidden",
1358 tar_reset ? "reset" : "noreset",
1359 tar_noisy ? "verbose" : "quiet"));
1360 return 0;
1363 /****************************************************************************
1364 Feeble attrib command
1365 ***************************************************************************/
1367 int cmd_setmode(void)
1369 TALLOC_CTX *ctx = talloc_tos();
1370 char *q;
1371 char *buf;
1372 char *fname = NULL;
1373 uint16 attra[2];
1374 int direct=1;
1376 attra[0] = attra[1] = 0;
1378 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1379 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1380 return 1;
1383 fname = talloc_asprintf(ctx,
1384 "%s%s",
1385 client_get_cur_dir(),
1386 buf);
1387 if (!fname) {
1388 return 1;
1391 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1392 q=buf;
1394 while(*q) {
1395 switch (*q++) {
1396 case '+':
1397 direct=1;
1398 break;
1399 case '-':
1400 direct=0;
1401 break;
1402 case 'r':
1403 attra[direct]|=aRONLY;
1404 break;
1405 case 'h':
1406 attra[direct]|=aHIDDEN;
1407 break;
1408 case 's':
1409 attra[direct]|=aSYSTEM;
1410 break;
1411 case 'a':
1412 attra[direct]|=aARCH;
1413 break;
1414 default:
1415 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1416 return 1;
1421 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1422 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1423 return 1;
1426 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1427 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1428 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1429 return 0;
1433 Convert list of tokens to array; dependent on above routine.
1434 Uses the global cmd_ptr from above - bit of a hack.
1437 static char **toktocliplist(int *ctok, const char *sep)
1439 char *s=(char *)cmd_ptr;
1440 int ictok=0;
1441 char **ret, **iret;
1443 if (!sep)
1444 sep = " \t\n\r";
1446 while(*s && strchr_m(sep,*s))
1447 s++;
1449 /* nothing left? */
1450 if (!*s)
1451 return(NULL);
1453 do {
1454 ictok++;
1455 while(*s && (!strchr_m(sep,*s)))
1456 s++;
1457 while(*s && strchr_m(sep,*s))
1458 *s++=0;
1459 } while(*s);
1461 *ctok=ictok;
1462 s=(char *)cmd_ptr;
1464 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1465 return NULL;
1467 while(ictok--) {
1468 *iret++=s;
1469 if (ictok > 0) {
1470 while(*s++)
1472 while(!*s)
1473 s++;
1477 ret[*ctok] = NULL;
1478 return ret;
1481 /****************************************************************************
1482 Principal command for creating / extracting
1483 ***************************************************************************/
1485 int cmd_tar(void)
1487 TALLOC_CTX *ctx = talloc_tos();
1488 char *buf;
1489 char **argl = NULL;
1490 int argcl = 0;
1491 int ret;
1493 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1494 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1495 return 1;
1498 argl=toktocliplist(&argcl, NULL);
1499 if (!tar_parseargs(argcl, argl, buf, 0)) {
1500 SAFE_FREE(argl);
1501 return 1;
1504 ret = process_tar();
1505 SAFE_FREE(argl);
1506 return ret;
1509 /****************************************************************************
1510 Command line (option) version
1511 ***************************************************************************/
1513 int process_tar(void)
1515 TALLOC_CTX *ctx = talloc_tos();
1516 int rc = 0;
1517 initarbuf();
1518 switch(tar_type) {
1519 case 'x':
1521 #if 0
1522 do_tarput2();
1523 #else
1524 do_tarput();
1525 #endif
1526 SAFE_FREE(tarbuf);
1527 close(tarhandle);
1528 break;
1529 case 'r':
1530 case 'c':
1531 if (clipn && tar_excl) {
1532 int i;
1533 char *tarmac = NULL;
1535 for (i=0; i<clipn; i++) {
1536 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1538 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1539 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1542 if (strrchr_m(cliplist[i], '\\')) {
1543 char *p;
1544 char saved_char;
1545 char *saved_dir = talloc_strdup(ctx,
1546 client_get_cur_dir());
1547 if (!saved_dir) {
1548 return 1;
1551 if (*cliplist[i]=='\\') {
1552 tarmac = talloc_strdup(ctx,
1553 cliplist[i]);
1554 } else {
1555 tarmac = talloc_asprintf(ctx,
1556 "%s%s",
1557 client_get_cur_dir(),
1558 cliplist[i]);
1560 if (!tarmac) {
1561 return 1;
1564 * Strip off the last \\xxx
1565 * xxx element of tarmac to set
1566 * it as current directory.
1568 p = strrchr_m(tarmac, '\\');
1569 if (!p) {
1570 return 1;
1572 saved_char = p[1];
1573 p[1] = '\0';
1575 client_set_cur_dir(tarmac);
1578 * Restore the character we
1579 * just replaced to
1580 * put the pathname
1581 * back as it was.
1583 p[1] = saved_char;
1585 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1586 do_list(tarmac,attribute,do_tar, False, True);
1588 client_set_cur_dir(saved_dir);
1590 TALLOC_FREE(saved_dir);
1591 TALLOC_FREE(tarmac);
1592 } else {
1593 tarmac = talloc_asprintf(ctx,
1594 "%s%s",
1595 client_get_cur_dir(),
1596 cliplist[i]);
1597 if (!tarmac) {
1598 return 1;
1600 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1601 do_list(tarmac,attribute,do_tar, False, True);
1602 TALLOC_FREE(tarmac);
1605 } else {
1606 char *mask = talloc_asprintf(ctx,
1607 "%s\\*",
1608 client_get_cur_dir());
1609 if (!mask) {
1610 return 1;
1612 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1613 do_list(mask,attribute,do_tar,False, True);
1614 TALLOC_FREE(mask);
1617 if (ntarf) {
1618 dotareof(tarhandle);
1620 close(tarhandle);
1621 SAFE_FREE(tarbuf);
1623 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1624 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1625 break;
1628 if (must_free_cliplist) {
1629 int i;
1630 for (i = 0; i < clipn; ++i) {
1631 SAFE_FREE(cliplist[i]);
1633 SAFE_FREE(cliplist);
1634 cliplist = NULL;
1635 clipn = 0;
1636 must_free_cliplist = False;
1638 return rc;
1641 /****************************************************************************
1642 Find a token (filename) in a clip list
1643 ***************************************************************************/
1645 static int clipfind(char **aret, int ret, char *tok)
1647 if (aret==NULL)
1648 return 0;
1650 /* ignore leading slashes or dots in token */
1651 while(strchr_m("/\\.", *tok))
1652 tok++;
1654 while(ret--) {
1655 char *pkey=*aret++;
1657 /* ignore leading slashes or dots in list */
1658 while(strchr_m("/\\.", *pkey))
1659 pkey++;
1661 if (!strslashcmp(pkey, tok))
1662 return 1;
1664 return 0;
1667 /****************************************************************************
1668 Read list of files to include from the file and initialize cliplist
1669 accordingly.
1670 ***************************************************************************/
1672 static int read_inclusion_file(char *filename)
1674 XFILE *inclusion = NULL;
1675 char buf[PATH_MAX + 1];
1676 char *inclusion_buffer = NULL;
1677 int inclusion_buffer_size = 0;
1678 int inclusion_buffer_sofar = 0;
1679 char *p;
1680 char *tmpstr;
1681 int i;
1682 int error = 0;
1684 clipn = 0;
1685 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1686 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1687 /* XXX It would be better to include a reason for failure, but without
1688 * autoconf, it's hard to use strerror, sys_errlist, etc.
1690 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1691 return 0;
1694 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1695 if (inclusion_buffer == NULL) {
1696 inclusion_buffer_size = 1024;
1697 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1698 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1699 error = 1;
1700 break;
1704 if (buf[strlen(buf)-1] == '\n') {
1705 buf[strlen(buf)-1] = '\0';
1708 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1709 inclusion_buffer_size *= 2;
1710 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1711 if (!inclusion_buffer) {
1712 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1713 inclusion_buffer_size));
1714 error = 1;
1715 break;
1719 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1720 inclusion_buffer_sofar += strlen(buf) + 1;
1721 clipn++;
1723 x_fclose(inclusion);
1725 if (! error) {
1726 /* Allocate an array of clipn + 1 char*'s for cliplist */
1727 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1728 if (cliplist == NULL) {
1729 DEBUG(0,("failure allocating memory for cliplist\n"));
1730 error = 1;
1731 } else {
1732 cliplist[clipn] = NULL;
1733 p = inclusion_buffer;
1734 for (i = 0; (! error) && (i < clipn); i++) {
1735 /* set current item to NULL so array will be null-terminated even if
1736 * malloc fails below. */
1737 cliplist[i] = NULL;
1738 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1739 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1740 error = 1;
1741 } else {
1742 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1743 cliplist[i] = tmpstr;
1744 if ((p = strchr_m(p, '\000')) == NULL) {
1745 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1746 abort();
1749 ++p;
1751 must_free_cliplist = True;
1755 SAFE_FREE(inclusion_buffer);
1756 if (error) {
1757 if (cliplist) {
1758 char **pp;
1759 /* We know cliplist is always null-terminated */
1760 for (pp = cliplist; *pp; ++pp) {
1761 SAFE_FREE(*pp);
1763 SAFE_FREE(cliplist);
1764 cliplist = NULL;
1765 must_free_cliplist = False;
1767 return 0;
1770 /* cliplist and its elements are freed at the end of process_tar. */
1771 return 1;
1774 /****************************************************************************
1775 Parse tar arguments. Sets tar_type, tar_excl, etc.
1776 ***************************************************************************/
1778 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1780 int newOptind = Optind;
1781 char tar_clipfl='\0';
1783 /* Reset back to defaults - could be from interactive version
1784 * reset mode and archive mode left as they are though
1786 tar_type='\0';
1787 tar_excl=True;
1788 dry_run=False;
1790 while (*Optarg) {
1791 switch(*Optarg++) {
1792 case 'c':
1793 tar_type='c';
1794 break;
1795 case 'x':
1796 if (tar_type=='c') {
1797 printf("Tar must be followed by only one of c or x.\n");
1798 return 0;
1800 tar_type='x';
1801 break;
1802 case 'b':
1803 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1804 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1805 return 0;
1806 } else {
1807 Optind++;
1808 newOptind++;
1810 break;
1811 case 'g':
1812 tar_inc=True;
1813 break;
1814 case 'N':
1815 if (Optind>=argc) {
1816 DEBUG(0,("Option N must be followed by valid file name\n"));
1817 return 0;
1818 } else {
1819 SMB_STRUCT_STAT stbuf;
1821 if (sys_stat(argv[Optind], &stbuf,
1822 false) == 0) {
1823 newer_than = convert_timespec_to_time_t(
1824 stbuf.st_ex_mtime);
1825 DEBUG(1,("Getting files newer than %s",
1826 time_to_asc(newer_than)));
1827 newOptind++;
1828 Optind++;
1829 } else {
1830 DEBUG(0,("Error setting newer-than time\n"));
1831 return 0;
1834 break;
1835 case 'a':
1836 tar_reset=True;
1837 break;
1838 case 'q':
1839 tar_noisy=False;
1840 break;
1841 case 'I':
1842 if (tar_clipfl) {
1843 DEBUG(0,("Only one of I,X,F must be specified\n"));
1844 return 0;
1846 tar_clipfl='I';
1847 break;
1848 case 'X':
1849 if (tar_clipfl) {
1850 DEBUG(0,("Only one of I,X,F must be specified\n"));
1851 return 0;
1853 tar_clipfl='X';
1854 break;
1855 case 'F':
1856 if (tar_clipfl) {
1857 DEBUG(0,("Only one of I,X,F must be specified\n"));
1858 return 0;
1860 tar_clipfl='F';
1861 break;
1862 case 'r':
1863 DEBUG(0, ("tar_re_search set\n"));
1864 tar_re_search = True;
1865 break;
1866 case 'n':
1867 if (tar_type == 'c') {
1868 DEBUG(0, ("dry_run set\n"));
1869 dry_run = True;
1870 } else {
1871 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1872 return 0;
1874 break;
1875 default:
1876 DEBUG(0,("Unknown tar option\n"));
1877 return 0;
1881 if (!tar_type) {
1882 printf("Option T must be followed by one of c or x.\n");
1883 return 0;
1886 /* tar_excl is true if cliplist lists files to be included.
1887 * Both 'I' and 'F' mean include. */
1888 tar_excl=tar_clipfl!='X';
1890 if (tar_clipfl=='F') {
1891 if (argc-Optind-1 != 1) {
1892 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1893 return 0;
1895 newOptind++;
1896 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1897 if (! read_inclusion_file(argv[Optind+1])) {
1898 return 0;
1900 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1901 char *tmpstr;
1902 char **tmplist;
1903 int clipcount;
1905 cliplist=argv+Optind+1;
1906 clipn=argc-Optind-1;
1907 clipcount = clipn;
1909 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1910 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1911 return 0;
1914 for (clipcount = 0; clipcount < clipn; clipcount++) {
1916 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1918 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1919 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1920 SAFE_FREE(tmplist);
1921 return 0;
1924 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1925 tmplist[clipcount] = tmpstr;
1926 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1928 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1931 cliplist = tmplist;
1932 must_free_cliplist = True;
1934 newOptind += clipn;
1937 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1938 /* Doing regular expression seaches not from an inclusion file. */
1939 clipn=argc-Optind-1;
1940 cliplist=argv+Optind+1;
1941 newOptind += clipn;
1944 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1945 /* Sets tar handle to either 0 or 1, as appropriate */
1946 tarhandle=(tar_type=='c');
1948 * Make sure that dbf points to stderr if we are using stdout for
1949 * tar output
1951 if (tarhandle == 1) {
1952 setup_logging("smbclient", DEBUG_STDERR);
1954 if (!argv[Optind]) {
1955 DEBUG(0,("Must specify tar filename\n"));
1956 return 0;
1958 if (!strcmp(argv[Optind], "-")) {
1959 newOptind++;
1962 } else {
1963 if (tar_type=='c' && dry_run) {
1964 tarhandle=-1;
1965 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1966 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1967 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1968 return(0);
1970 newOptind++;
1973 return newOptind;