s3-smb Use FILE_ATTRIBUTE_HIDDEN intead of aHIDDEN
[Samba.git] / source3 / client / clitar.c
blobeba9915e2a56d455e495770e00bf32c511b1b579
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 "system/filesys.h"
39 #include "clitar.h"
40 #include "client/client_proto.h"
42 static int clipfind(char **aret, int ret, char *tok);
44 typedef struct file_info_struct file_info2;
46 struct file_info_struct {
47 SMB_OFF_T size;
48 uint16 mode;
49 uid_t uid;
50 gid_t gid;
51 /* These times are normally kept in GMT */
52 struct timespec mtime_ts;
53 struct timespec atime_ts;
54 struct timespec ctime_ts;
55 char *name; /* This is dynamically allocated */
56 file_info2 *next, *prev; /* Used in the stack ... */
59 typedef struct {
60 file_info2 *top;
61 int items;
62 } stack;
64 #define SEPARATORS " \t\n\r"
65 extern time_t newer_than;
66 extern struct cli_state *cli;
68 /* These defines are for the do_setrattr routine, to indicate
69 * setting and reseting of file attributes in the function call */
70 #define ATTRSET 1
71 #define ATTRRESET 0
73 static uint16 attribute = aDIR | aSYSTEM | FILE_ATTRIBUTE_HIDDEN;
75 #ifndef CLIENT_TIMEOUT
76 #define CLIENT_TIMEOUT (30*1000)
77 #endif
79 static char *tarbuf, *buffer_p;
80 static int tp, ntarf, tbufsiz;
81 static double ttarf;
82 /* Incremental mode */
83 static bool tar_inc=False;
84 /* Reset archive bit */
85 static bool tar_reset=False;
86 /* Include / exclude mode (true=include, false=exclude) */
87 static bool tar_excl=True;
88 /* use regular expressions for search on file names */
89 static bool tar_re_search=False;
90 /* Do not dump anything, just calculate sizes */
91 static bool dry_run=False;
92 /* Dump files with System attribute */
93 static bool tar_system=True;
94 /* Dump files with Hidden attribute */
95 static bool tar_hidden=True;
96 /* Be noisy - make a catalogue */
97 static bool tar_noisy=True;
98 static bool tar_real_noisy=False; /* Don't want to be really noisy by default */
100 char tar_type='\0';
101 static char **cliplist=NULL;
102 static int clipn=0;
103 static bool must_free_cliplist = False;
104 extern const char *cmd_ptr;
106 extern bool lowercase;
107 extern uint16 cnum;
108 extern bool readbraw_supported;
109 extern int max_xmit;
110 extern int get_total_time_ms;
111 extern int get_total_size;
113 static int blocksize=20;
114 static int tarhandle;
116 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
117 const char *amode, unsigned char ftype);
118 static NTSTATUS do_atar(const char *rname_in, char *lname,
119 struct file_info *finfo1);
120 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
121 const char *dir);
122 static void oct_it(uint64_t value, int ndgs, char *p);
123 static void fixtarname(char *tptr, const char *fp, size_t l);
124 static int dotarbuf(int f, char *b, int n);
125 static void dozerobuf(int f, int n);
126 static void dotareof(int f);
127 static void initarbuf(void);
129 /* restore functions */
130 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
131 static long unoct(char *p, int ndgs);
132 static void do_tarput(void);
133 static void unfixtarname(char *tptr, char *fp, int l, bool first);
136 * tar specific utitlities
139 /*******************************************************************
140 Create a string of size size+1 (for the null)
141 *******************************************************************/
143 static char *string_create_s(int size)
145 char *tmp;
147 tmp = (char *)SMB_MALLOC(size+1);
149 if (tmp == NULL) {
150 DEBUG(0, ("Out of memory in string_create_s\n"));
153 return(tmp);
156 /****************************************************************************
157 Write a tar header to buffer
158 ****************************************************************************/
160 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
161 const char *amode, unsigned char ftype)
163 union hblock hb;
164 int i, chk, l;
165 char *jp;
167 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
169 memset(hb.dummy, 0, sizeof(hb.dummy));
171 l=strlen(aname);
172 /* We will be prepending a '.' in fixtarheader so use +2 to
173 * take care of the . and terminating zero. JRA.
175 if (l+2 >= NAMSIZ) {
176 /* write a GNU tar style long header */
177 char *b;
178 b = (char *)SMB_MALLOC(l+TBLOCK+100);
179 if (!b) {
180 DEBUG(0,("out of memory\n"));
181 exit(1);
183 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
184 memset(b, 0, l+TBLOCK+100);
185 fixtarname(b, aname, l+2);
186 i = strlen(b)+1;
187 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
188 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
189 SAFE_FREE(b);
192 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
194 if (lowercase)
195 strlower_m(hb.dbuf.name);
197 /* write out a "standard" tar format header */
199 hb.dbuf.name[NAMSIZ-1]='\0';
200 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
201 oct_it((uint64_t)0, 8, hb.dbuf.uid);
202 oct_it((uint64_t)0, 8, hb.dbuf.gid);
203 oct_it((uint64_t) size, 13, hb.dbuf.size);
204 if (size > (uint64_t)077777777777LL) {
205 /* This is a non-POSIX compatible extention to store files
206 greater than 8GB. */
208 memset(hb.dbuf.size, 0, 4);
209 hb.dbuf.size[0]=128;
210 for (i = 8, jp=(char*)&size; i; i--)
211 hb.dbuf.size[i+3] = *(jp++);
213 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
214 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
215 memset(hb.dbuf.linkname, 0, NAMSIZ);
216 hb.dbuf.linkflag=ftype;
218 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
219 chk+=(0xFF & *jp++);
221 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
222 hb.dbuf.chksum[6] = '\0';
224 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
227 /****************************************************************************
228 Read a tar header into a hblock structure, and validate
229 ***************************************************************************/
231 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
233 long chk, fchk;
234 int i;
235 char *jp;
238 * read in a "standard" tar format header - we're not that interested
239 * in that many fields, though
242 /* check the checksum */
243 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
244 chk+=(0xFF & *jp++);
246 if (chk == 0)
247 return chk;
249 /* compensate for blanks in chksum header */
250 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
251 chk-=(0xFF & *jp++);
253 chk += ' ' * sizeof(hb->dbuf.chksum);
255 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
257 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
258 chk, fchk, hb->dbuf.chksum));
260 if (fchk != chk) {
261 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
262 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
263 return -1;
266 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
267 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
268 return(-1);
271 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
273 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
274 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
275 strlen(hb->dbuf.name) + 1, True);
277 /* can't handle some links at present */
278 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
279 if (hb->dbuf.linkflag == 0) {
280 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
281 finfo->name));
282 } else {
283 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
284 /* Do nothing here at the moment. do_tarput will handle this
285 as long as the longlink gets back to it, as it has to advance
286 the buffer pointer, etc */
287 } else {
288 DEBUG(0, ("this tar file appears to contain some kind \
289 of link other than a GNUtar Longlink - ignoring\n"));
290 return -2;
295 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
296 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
297 finfo->mode=aDIR;
298 } else {
299 finfo->mode=0; /* we don't care about mode at the moment, we'll
300 * just make it a regular file */
304 * Bug fix by richard@sj.co.uk
306 * REC: restore times correctly (as does tar)
307 * We only get the modification time of the file; set the creation time
308 * from the mod. time, and the access time to current time
310 finfo->mtime_ts = finfo->ctime_ts =
311 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
312 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
313 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
315 return True;
318 /****************************************************************************
319 Write out the tar buffer to tape or wherever
320 ****************************************************************************/
322 static int dotarbuf(int f, char *b, int n)
324 int fail=1, writ=n;
326 if (dry_run) {
327 return writ;
329 /* This routine and the next one should be the only ones that do write()s */
330 if (tp + n >= tbufsiz) {
331 int diff;
333 diff=tbufsiz-tp;
334 memcpy(tarbuf + tp, b, diff);
335 fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
336 n-=diff;
337 b+=diff;
338 tp=0;
340 while (n >= tbufsiz) {
341 fail=fail && (1 + sys_write(f, b, tbufsiz));
342 n-=tbufsiz;
343 b+=tbufsiz;
347 if (n>0) {
348 memcpy(tarbuf+tp, b, n);
349 tp+=n;
352 return(fail ? writ : 0);
355 /****************************************************************************
356 Write zeros to buffer / tape
357 ****************************************************************************/
359 static void dozerobuf(int f, int n)
361 /* short routine just to write out n zeros to buffer -
362 * used to round files to nearest block
363 * and to do tar EOFs */
365 if (dry_run)
366 return;
368 if (n+tp >= tbufsiz) {
369 memset(tarbuf+tp, 0, tbufsiz-tp);
370 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
371 DEBUG(0, ("dozerobuf: sys_write fail\n"));
372 return;
374 memset(tarbuf, 0, (tp+=n-tbufsiz));
375 } else {
376 memset(tarbuf+tp, 0, n);
377 tp+=n;
381 /****************************************************************************
382 Malloc tape buffer
383 ****************************************************************************/
385 static void initarbuf(void)
387 /* initialize tar buffer */
388 tbufsiz=blocksize*TBLOCK;
389 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
391 /* reset tar buffer pointer and tar file counter and total dumped */
392 tp=0; ntarf=0; ttarf=0;
395 /****************************************************************************
396 Write two zero blocks at end of file
397 ****************************************************************************/
399 static void dotareof(int f)
401 SMB_STRUCT_STAT stbuf;
402 /* Two zero blocks at end of file, write out full buffer */
404 if (dry_run)
405 return;
407 (void) dozerobuf(f, TBLOCK);
408 (void) dozerobuf(f, TBLOCK);
410 if (sys_fstat(f, &stbuf, false) == -1) {
411 DEBUG(0, ("Couldn't stat file handle\n"));
412 return;
415 /* Could be a pipe, in which case S_ISREG should fail,
416 * and we should write out at full size */
417 if (tp > 0) {
418 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
419 if (sys_write(f, tarbuf, towrite) != towrite) {
420 DEBUG(0,("dotareof: sys_write fail\n"));
425 /****************************************************************************
426 (Un)mangle DOS pathname, make nonabsolute
427 ****************************************************************************/
429 static void fixtarname(char *tptr, const char *fp, size_t l)
431 /* add a '.' to start of file name, convert from ugly dos \'s in path
432 * to lovely unix /'s :-} */
433 *tptr++='.';
434 l--;
436 StrnCpy(tptr, fp, l-1);
437 string_replace(tptr, '\\', '/');
440 /****************************************************************************
441 Convert from decimal to octal string
442 ****************************************************************************/
444 static void oct_it (uint64_t value, int ndgs, char *p)
446 /* Converts long to octal string, pads with leading zeros */
448 /* skip final null, but do final space */
449 --ndgs;
450 p[--ndgs] = ' ';
452 /* Loop does at least one digit */
453 do {
454 p[--ndgs] = '0' + (char) (value & 7);
455 value >>= 3;
456 } while (ndgs > 0 && value != 0);
458 /* Do leading zeros */
459 while (ndgs > 0)
460 p[--ndgs] = '0';
463 /****************************************************************************
464 Convert from octal string to long
465 ***************************************************************************/
467 static long unoct(char *p, int ndgs)
469 long value=0;
470 /* Converts octal string to long, ignoring any non-digit */
472 while (--ndgs) {
473 if (isdigit((int)*p))
474 value = (value << 3) | (long) (*p - '0');
476 p++;
479 return value;
482 /****************************************************************************
483 Compare two strings in a slash insensitive way, allowing s1 to match s2
484 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
485 a file in any subdirectory of s1, declare a match.
486 ***************************************************************************/
488 static int strslashcmp(char *s1, char *s2)
490 char *s1_0=s1;
492 while(*s1 && *s2 && (*s1 == *s2 || tolower_ascii(*s1) == tolower_ascii(*s2) ||
493 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
494 s1++; s2++;
497 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
498 string of s2.
500 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
501 return 0;
503 /* ignore trailing slash on s1 */
504 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
505 return 0;
507 /* check for s1 is an "initial" string of s2 */
508 if ((*s2 == '/' || *s2 == '\\') && !*s1)
509 return 0;
511 return *s1-*s2;
514 /****************************************************************************
515 Ensure a remote path exists (make if necessary)
516 ***************************************************************************/
518 static bool ensurepath(const char *fname)
520 /* *must* be called with buffer ready malloc'ed */
521 /* ensures path exists */
523 char *partpath, *ffname;
524 const char *p=fname;
525 char *basehack;
526 char *saveptr;
528 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
530 partpath = string_create_s(strlen(fname));
531 ffname = string_create_s(strlen(fname));
533 if ((partpath == NULL) || (ffname == NULL)){
534 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
535 SAFE_FREE(partpath);
536 SAFE_FREE(ffname);
537 return(False);
540 *partpath = 0;
542 /* fname copied to ffname so can strtok_r */
544 safe_strcpy(ffname, fname, strlen(fname));
546 /* do a `basename' on ffname, so don't try and make file name directory */
547 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
548 SAFE_FREE(partpath);
549 SAFE_FREE(ffname);
550 return True;
551 } else {
552 *basehack='\0';
555 p=strtok_r(ffname, "\\", &saveptr);
557 while (p) {
558 safe_strcat(partpath, p, strlen(fname) + 1);
560 if (!NT_STATUS_IS_OK(cli_chkpath(cli, partpath))) {
561 if (!NT_STATUS_IS_OK(cli_mkdir(cli, partpath))) {
562 SAFE_FREE(partpath);
563 SAFE_FREE(ffname);
564 DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
565 return False;
566 } else {
567 DEBUG(3, ("mkdirhiering %s\n", partpath));
571 safe_strcat(partpath, "\\", strlen(fname) + 1);
572 p = strtok_r(NULL, "/\\", &saveptr);
575 SAFE_FREE(partpath);
576 SAFE_FREE(ffname);
577 return True;
580 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
582 int berr= 0;
583 int bytestowrite;
585 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
586 memset(buf, 0, (size_t)bufsize);
587 while( !berr && padsize > 0 ) {
588 bytestowrite= (int)MIN(bufsize, padsize);
589 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
590 padsize -= bytestowrite;
593 return berr;
596 static void do_setrattr(char *name, uint16 attr, int set)
598 uint16 oldattr;
600 if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
601 return;
604 if (set == ATTRSET) {
605 attr |= oldattr;
606 } else {
607 attr = oldattr & ~attr;
610 if (!NT_STATUS_IS_OK(cli_setatr(cli, name, attr, 0))) {
611 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
615 /****************************************************************************
616 append one remote file to the tar file
617 ***************************************************************************/
619 static NTSTATUS do_atar(const char *rname_in, char *lname,
620 struct file_info *finfo1)
622 uint16_t fnum = (uint16_t)-1;
623 uint64_t nread=0;
624 char ftype;
625 file_info2 finfo;
626 bool shallitime=True;
627 char *data = NULL;
628 int read_size = 65520;
629 int datalen=0;
630 char *rname = NULL;
631 TALLOC_CTX *ctx = talloc_stackframe();
632 NTSTATUS status = NT_STATUS_OK;
633 struct timespec tp_start;
635 clock_gettime_mono(&tp_start);
637 data = SMB_MALLOC_ARRAY(char, read_size);
638 if (!data) {
639 DEBUG(0,("do_atar: out of memory.\n"));
640 status = NT_STATUS_NO_MEMORY;
641 goto cleanup;
644 ftype = '0'; /* An ordinary file ... */
646 ZERO_STRUCT(finfo);
648 finfo.size = finfo1 -> size;
649 finfo.mode = finfo1 -> mode;
650 finfo.uid = finfo1 -> uid;
651 finfo.gid = finfo1 -> gid;
652 finfo.mtime_ts = finfo1 -> mtime_ts;
653 finfo.atime_ts = finfo1 -> atime_ts;
654 finfo.ctime_ts = finfo1 -> ctime_ts;
656 if (dry_run) {
657 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
658 (double)finfo.size));
659 shallitime=0;
660 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
661 ntarf++;
662 goto cleanup;
665 rname = clean_name(ctx, rname_in);
666 if (!rname) {
667 status = NT_STATUS_NO_MEMORY;
668 goto cleanup;
671 status = cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum);
672 if (!NT_STATUS_IS_OK(status)) {
673 DEBUG(0,("%s opening remote file %s (%s)\n",
674 cli_errstr(cli),rname, client_get_cur_dir()));
675 goto cleanup;
678 finfo.name = string_create_s(strlen(rname));
679 if (finfo.name == NULL) {
680 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
681 status = NT_STATUS_NO_MEMORY;
682 goto cleanup;
685 safe_strcpy(finfo.name,rname, strlen(rname));
687 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
689 if (tar_inc && !(finfo.mode & aARCH)) {
690 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
691 shallitime=0;
692 } else if (!tar_system && (finfo.mode & aSYSTEM)) {
693 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
694 shallitime=0;
695 } else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN)) {
696 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
697 shallitime=0;
698 } else {
699 bool wrote_tar_header = False;
701 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
702 finfo.name, (double)finfo.size, lname));
704 do {
706 DEBUG(3,("nread=%.0f\n",(double)nread));
708 datalen = cli_read(cli, fnum, data, nread, read_size);
710 if (datalen == -1) {
711 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
712 status = cli_nt_error(cli);
713 break;
716 nread += datalen;
718 /* Only if the first read succeeds, write out the tar header. */
719 if (!wrote_tar_header) {
720 /* write a tar header, don't bother with mode - just set to 100644 */
721 writetarheader(tarhandle, rname, finfo.size,
722 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
723 wrote_tar_header = True;
726 /* if file size has increased since we made file size query, truncate
727 read so tar header for this file will be correct.
730 if (nread > finfo.size) {
731 datalen -= nread - finfo.size;
732 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
733 finfo.name, (double)finfo.size));
736 /* add received bits of file to buffer - dotarbuf will
737 * write out in 512 byte intervals */
739 if (dotarbuf(tarhandle,data,datalen) != datalen) {
740 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
741 status = map_nt_error_from_unix(errno);
742 break;
745 if ( (datalen == 0) && (finfo.size != 0) ) {
746 status = NT_STATUS_UNSUCCESSFUL;
747 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
748 break;
751 datalen=0;
752 } while ( nread < finfo.size );
754 if (wrote_tar_header) {
755 /* pad tar file with zero's if we couldn't get entire file */
756 if (nread < finfo.size) {
757 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
758 (double)finfo.size, (int)nread));
759 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) {
760 status = map_nt_error_from_unix(errno);
761 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
765 /* round tar file to nearest block */
766 if (finfo.size % TBLOCK)
767 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
769 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
770 ntarf++;
771 } else {
772 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
773 shallitime=0;
774 status = NT_STATUS_UNSUCCESSFUL;
778 cli_close(cli, fnum);
779 fnum = -1;
781 if (shallitime) {
782 struct timespec tp_end;
783 int this_time;
785 /* if shallitime is true then we didn't skip */
786 if (tar_reset && !dry_run)
787 (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
789 clock_gettime_mono(&tp_end);
790 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000;
791 get_total_time_ms += this_time;
792 get_total_size += finfo.size;
794 if (tar_noisy) {
795 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
796 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
797 finfo.name));
800 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
801 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
802 finfo.size / MAX(0.001, (1.024*this_time)),
803 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
806 cleanup:
808 if (fnum != (uint16_t)-1) {
809 cli_close(cli, fnum);
810 fnum = -1;
812 TALLOC_FREE(ctx);
813 SAFE_FREE(data);
814 return status;
817 /****************************************************************************
818 Append single file to tar file (or not)
819 ***************************************************************************/
821 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
822 const char *dir)
824 TALLOC_CTX *ctx = talloc_stackframe();
825 NTSTATUS status = NT_STATUS_OK;
827 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
828 return NT_STATUS_OK;
830 /* Is it on the exclude list ? */
831 if (!tar_excl && clipn) {
832 char *exclaim;
834 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
836 exclaim = talloc_asprintf(ctx,
837 "%s\\%s",
838 client_get_cur_dir(),
839 finfo->name);
840 if (!exclaim) {
841 return NT_STATUS_NO_MEMORY;
844 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
846 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
847 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
848 DEBUG(3,("Skipping file %s\n", exclaim));
849 TALLOC_FREE(exclaim);
850 return NT_STATUS_OK;
852 TALLOC_FREE(exclaim);
855 if (finfo->mode & aDIR) {
856 char *saved_curdir = NULL;
857 char *new_cd = NULL;
858 char *mtar_mask = NULL;
860 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
861 if (!saved_curdir) {
862 return NT_STATUS_NO_MEMORY;
865 DEBUG(5, ("strlen(cur_dir)=%d, \
866 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
867 (int)strlen(saved_curdir),
868 (int)strlen(finfo->name), finfo->name, saved_curdir));
870 new_cd = talloc_asprintf(ctx,
871 "%s%s\\",
872 client_get_cur_dir(),
873 finfo->name);
874 if (!new_cd) {
875 return NT_STATUS_NO_MEMORY;
877 client_set_cur_dir(new_cd);
879 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
881 /* write a tar directory, don't bother with mode - just
882 * set it to 40755 */
883 writetarheader(tarhandle, client_get_cur_dir(), 0,
884 finfo->mtime_ts.tv_sec, "040755 \0", '5');
885 if (tar_noisy) {
886 DEBUG(0,(" directory %s\n",
887 client_get_cur_dir()));
889 ntarf++; /* Make sure we have a file on there */
890 mtar_mask = talloc_asprintf(ctx,
891 "%s*",
892 client_get_cur_dir());
893 if (!mtar_mask) {
894 return NT_STATUS_NO_MEMORY;
896 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
897 status = do_list(mtar_mask, attribute, do_tar, False, True);
898 client_set_cur_dir(saved_curdir);
899 TALLOC_FREE(saved_curdir);
900 TALLOC_FREE(new_cd);
901 TALLOC_FREE(mtar_mask);
902 } else {
903 char *rname = talloc_asprintf(ctx,
904 "%s%s",
905 client_get_cur_dir(),
906 finfo->name);
907 if (!rname) {
908 return NT_STATUS_NO_MEMORY;
910 status = do_atar(rname,finfo->name,finfo);
911 TALLOC_FREE(rname);
913 return status;
916 /****************************************************************************
917 Convert from UNIX to DOS file names
918 ***************************************************************************/
920 static void unfixtarname(char *tptr, char *fp, int l, bool first)
922 /* remove '.' from start of file name, convert from unix /'s to
923 * dos \'s in path. Kill any absolute path names. But only if first!
926 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
928 if (first) {
929 if (*fp == '.') {
930 fp++;
931 l--;
933 if (*fp == '\\' || *fp == '/') {
934 fp++;
935 l--;
939 safe_strcpy(tptr, fp, l);
940 string_replace(tptr, '/', '\\');
943 /****************************************************************************
944 Move to the next block in the buffer, which may mean read in another set of
945 blocks. FIXME, we should allow more than one block to be skipped.
946 ****************************************************************************/
948 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
950 int bufread, total = 0;
952 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
953 *bufferp += TBLOCK;
954 total = TBLOCK;
956 if (*bufferp >= (ltarbuf + bufsiz)) {
958 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
961 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
962 * Fixes bug where read can return short if coming from
963 * a pipe.
966 bufread = read(tarhandle, ltarbuf, bufsiz);
967 total = bufread;
969 while (total < bufsiz) {
970 if (bufread < 0) { /* An error, return false */
971 return (total > 0 ? -2 : bufread);
973 if (bufread == 0) {
974 if (total <= 0) {
975 return -2;
977 break;
979 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
980 total += bufread;
983 DEBUG(5, ("Total bytes read ... %i\n", total));
985 *bufferp = ltarbuf;
988 return(total);
991 /* Skip a file, even if it includes a long file name? */
992 static int skip_file(int skipsize)
994 int dsize = skipsize;
996 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
998 /* FIXME, we should skip more than one block at a time */
1000 while (dsize > 0) {
1001 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1002 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1003 return(False);
1005 dsize -= TBLOCK;
1008 return(True);
1011 /*************************************************************
1012 Get a file from the tar file and store it.
1013 When this is called, tarbuf already contains the first
1014 file block. This is a bit broken & needs fixing.
1015 **************************************************************/
1017 static int get_file(file_info2 finfo)
1019 uint16_t fnum = (uint16_t) -1;
1020 int pos = 0, dsize = 0, bpos = 0;
1021 uint64_t rsize = 0;
1022 NTSTATUS status;
1024 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1026 if (!ensurepath(finfo.name)) {
1027 DEBUG(0, ("abandoning restore\n"));
1028 return False;
1031 status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1032 if (!NT_STATUS_IS_OK(status)) {
1033 DEBUG(0, ("abandoning restore\n"));
1034 return False;
1037 /* read the blocks from the tar file and write to the remote file */
1039 rsize = finfo.size; /* This is how much to write */
1041 while (rsize > 0) {
1043 /* We can only write up to the end of the buffer */
1044 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1045 dsize = MIN(dsize, rsize); /* Should be only what is left */
1046 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1048 status = cli_writeall(cli, fnum, 0,
1049 (uint8_t *)(buffer_p + bpos), pos,
1050 dsize, NULL);
1051 if (!NT_STATUS_IS_OK(status)) {
1052 DEBUG(0, ("Error writing remote file: %s\n",
1053 nt_errstr(status)));
1054 return 0;
1057 rsize -= dsize;
1058 pos += dsize;
1060 /* Now figure out how much to move in the buffer */
1062 /* FIXME, we should skip more than one block at a time */
1064 /* First, skip any initial part of the part written that is left over */
1065 /* from the end of the first TBLOCK */
1067 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1068 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1069 bpos = 0;
1071 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1072 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1073 return False;
1078 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1079 * If the file being extracted is an exact multiple of
1080 * TBLOCK bytes then we don't want to extract the next
1081 * block from the tarfile here, as it will be done in
1082 * the caller of get_file().
1085 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1086 ((rsize == 0) && (dsize > TBLOCK))) {
1088 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1089 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1090 return False;
1093 dsize -= TBLOCK;
1095 bpos = dsize;
1098 /* Now close the file ... */
1100 if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
1101 DEBUG(0, ("Error %s closing remote file\n",
1102 cli_errstr(cli)));
1103 return(False);
1106 /* Now we update the creation date ... */
1107 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1109 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1110 if (tar_real_noisy) {
1111 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1112 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1116 ntarf++;
1117 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1118 return(True);
1121 /* Create a directory. We just ensure that the path exists and return as there
1122 is no file associated with a directory
1124 static int get_dir(file_info2 finfo)
1126 DEBUG(0, ("restore directory %s\n", finfo.name));
1128 if (!ensurepath(finfo.name)) {
1129 DEBUG(0, ("Problems creating directory\n"));
1130 return(False);
1132 ntarf++;
1133 return(True);
1136 /* Get a file with a long file name ... first file has file name, next file
1137 has the data. We only want the long file name, as the loop in do_tarput
1138 will deal with the rest.
1140 static char *get_longfilename(file_info2 finfo)
1142 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1143 * header call. */
1144 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1145 char *longname = (char *)SMB_MALLOC(namesize);
1146 int offset = 0, left = finfo.size;
1147 bool first = True;
1149 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1150 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1152 if (longname == NULL) {
1153 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1154 return(NULL);
1157 /* First, add cur_dir to the long file name */
1159 if (strlen(client_get_cur_dir()) > 0) {
1160 strncpy(longname, client_get_cur_dir(), namesize);
1161 offset = strlen(client_get_cur_dir());
1164 /* Loop through the blocks picking up the name */
1166 while (left > 0) {
1167 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1168 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1169 SAFE_FREE(longname);
1170 return(NULL);
1173 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1174 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1176 offset += TBLOCK;
1177 left -= TBLOCK;
1180 return(longname);
1183 static void do_tarput(void)
1185 file_info2 finfo;
1186 struct timespec tp_start;
1187 char *longfilename = NULL, linkflag;
1188 int skip = False;
1190 ZERO_STRUCT(finfo);
1192 clock_gettime_mono(&tp_start);
1193 DEBUG(5, ("RJS do_tarput called ...\n"));
1195 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1197 /* Now read through those files ... */
1198 while (True) {
1199 /* Get us to the next block, or the first block first time around */
1200 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1201 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1202 SAFE_FREE(longfilename);
1203 return;
1206 DEBUG(5, ("Reading the next header ...\n"));
1208 switch (readtarheader((union hblock *) buffer_p,
1209 &finfo, client_get_cur_dir())) {
1210 case -2: /* Hmm, not good, but not fatal */
1211 DEBUG(0, ("Skipping %s...\n", finfo.name));
1212 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1213 DEBUG(0, ("Short file, bailing out...\n"));
1214 SAFE_FREE(longfilename);
1215 return;
1217 break;
1219 case -1:
1220 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1221 SAFE_FREE(longfilename);
1222 return;
1224 case 0: /* chksum is zero - looks like an EOF */
1225 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1226 SAFE_FREE(longfilename);
1227 return; /* Hmmm, bad here ... */
1229 default:
1230 /* No action */
1231 break;
1234 /* Now, do we have a long file name? */
1235 if (longfilename != NULL) {
1236 SAFE_FREE(finfo.name); /* Free the space already allocated */
1237 finfo.name = longfilename;
1238 longfilename = NULL;
1241 /* Well, now we have a header, process the file ... */
1242 /* Should we skip the file? We have the long name as well here */
1243 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1244 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1246 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1247 if (skip) {
1248 skip_file(finfo.size);
1249 continue;
1252 /* We only get this far if we should process the file */
1253 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1254 switch (linkflag) {
1255 case '0': /* Should use symbolic names--FIXME */
1257 * Skip to the next block first, so we can get the file, FIXME, should
1258 * be in get_file ...
1259 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1260 * Fixes bug where file size in tarfile is zero.
1262 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1263 DEBUG(0, ("Short file, bailing out...\n"));
1264 return;
1266 if (!get_file(finfo)) {
1267 DEBUG(0, ("Abandoning restore\n"));
1268 return;
1270 break;
1271 case '5':
1272 if (!get_dir(finfo)) {
1273 DEBUG(0, ("Abandoning restore \n"));
1274 return;
1276 break;
1277 case 'L':
1278 SAFE_FREE(longfilename);
1279 longfilename = get_longfilename(finfo);
1280 if (!longfilename) {
1281 DEBUG(0, ("abandoning restore\n"));
1282 return;
1284 DEBUG(5, ("Long file name: %s\n", longfilename));
1285 break;
1287 default:
1288 skip_file(finfo.size); /* Don't handle these yet */
1289 break;
1295 * samba interactive commands
1298 /****************************************************************************
1299 Blocksize command
1300 ***************************************************************************/
1302 int cmd_block(void)
1304 TALLOC_CTX *ctx = talloc_tos();
1305 char *buf;
1306 int block;
1308 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1309 DEBUG(0, ("blocksize <n>\n"));
1310 return 1;
1313 block=atoi(buf);
1314 if (block < 0 || block > 65535) {
1315 DEBUG(0, ("blocksize out of range"));
1316 return 1;
1319 blocksize=block;
1320 DEBUG(2,("blocksize is now %d\n", blocksize));
1321 return 0;
1324 /****************************************************************************
1325 command to set incremental / reset mode
1326 ***************************************************************************/
1328 int cmd_tarmode(void)
1330 TALLOC_CTX *ctx = talloc_tos();
1331 char *buf;
1333 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1334 if (strequal(buf, "full"))
1335 tar_inc=False;
1336 else if (strequal(buf, "inc"))
1337 tar_inc=True;
1338 else if (strequal(buf, "reset"))
1339 tar_reset=True;
1340 else if (strequal(buf, "noreset"))
1341 tar_reset=False;
1342 else if (strequal(buf, "system"))
1343 tar_system=True;
1344 else if (strequal(buf, "nosystem"))
1345 tar_system=False;
1346 else if (strequal(buf, "hidden"))
1347 tar_hidden=True;
1348 else if (strequal(buf, "nohidden"))
1349 tar_hidden=False;
1350 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1351 tar_noisy=True;
1352 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1353 tar_noisy=False;
1354 else
1355 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1356 TALLOC_FREE(buf);
1359 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1360 tar_inc ? "incremental" : "full",
1361 tar_system ? "system" : "nosystem",
1362 tar_hidden ? "hidden" : "nohidden",
1363 tar_reset ? "reset" : "noreset",
1364 tar_noisy ? "verbose" : "quiet"));
1365 return 0;
1368 /****************************************************************************
1369 Feeble attrib command
1370 ***************************************************************************/
1372 int cmd_setmode(void)
1374 TALLOC_CTX *ctx = talloc_tos();
1375 char *q;
1376 char *buf;
1377 char *fname = NULL;
1378 uint16 attra[2];
1379 int direct=1;
1381 attra[0] = attra[1] = 0;
1383 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1384 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1385 return 1;
1388 fname = talloc_asprintf(ctx,
1389 "%s%s",
1390 client_get_cur_dir(),
1391 buf);
1392 if (!fname) {
1393 return 1;
1396 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1397 q=buf;
1399 while(*q) {
1400 switch (*q++) {
1401 case '+':
1402 direct=1;
1403 break;
1404 case '-':
1405 direct=0;
1406 break;
1407 case 'r':
1408 attra[direct]|=FILE_ATTRIBUTE_READONLY;
1409 break;
1410 case 'h':
1411 attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1412 break;
1413 case 's':
1414 attra[direct]|=aSYSTEM;
1415 break;
1416 case 'a':
1417 attra[direct]|=aARCH;
1418 break;
1419 default:
1420 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1421 return 1;
1426 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1427 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1428 return 1;
1431 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1432 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1433 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1434 return 0;
1438 Convert list of tokens to array; dependent on above routine.
1439 Uses the global cmd_ptr from above - bit of a hack.
1442 static char **toktocliplist(int *ctok, const char *sep)
1444 char *s=(char *)cmd_ptr;
1445 int ictok=0;
1446 char **ret, **iret;
1448 if (!sep)
1449 sep = " \t\n\r";
1451 while(*s && strchr_m(sep,*s))
1452 s++;
1454 /* nothing left? */
1455 if (!*s)
1456 return(NULL);
1458 do {
1459 ictok++;
1460 while(*s && (!strchr_m(sep,*s)))
1461 s++;
1462 while(*s && strchr_m(sep,*s))
1463 *s++=0;
1464 } while(*s);
1466 *ctok=ictok;
1467 s=(char *)cmd_ptr;
1469 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1470 return NULL;
1472 while(ictok--) {
1473 *iret++=s;
1474 if (ictok > 0) {
1475 while(*s++)
1477 while(!*s)
1478 s++;
1482 ret[*ctok] = NULL;
1483 return ret;
1486 /****************************************************************************
1487 Principal command for creating / extracting
1488 ***************************************************************************/
1490 int cmd_tar(void)
1492 TALLOC_CTX *ctx = talloc_tos();
1493 char *buf;
1494 char **argl = NULL;
1495 int argcl = 0;
1496 int ret;
1498 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1499 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1500 return 1;
1503 argl=toktocliplist(&argcl, NULL);
1504 if (!tar_parseargs(argcl, argl, buf, 0)) {
1505 SAFE_FREE(argl);
1506 return 1;
1509 ret = process_tar();
1510 SAFE_FREE(argl);
1511 return ret;
1514 /****************************************************************************
1515 Command line (option) version
1516 ***************************************************************************/
1518 int process_tar(void)
1520 TALLOC_CTX *ctx = talloc_tos();
1521 int rc = 0;
1522 initarbuf();
1523 switch(tar_type) {
1524 case 'x':
1526 #if 0
1527 do_tarput2();
1528 #else
1529 do_tarput();
1530 #endif
1531 SAFE_FREE(tarbuf);
1532 close(tarhandle);
1533 break;
1534 case 'r':
1535 case 'c':
1536 if (clipn && tar_excl) {
1537 int i;
1538 char *tarmac = NULL;
1540 for (i=0; i<clipn; i++) {
1541 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1543 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1544 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1547 if (strrchr_m(cliplist[i], '\\')) {
1548 char *p;
1549 char saved_char;
1550 char *saved_dir = talloc_strdup(ctx,
1551 client_get_cur_dir());
1552 if (!saved_dir) {
1553 return 1;
1556 if (*cliplist[i]=='\\') {
1557 tarmac = talloc_strdup(ctx,
1558 cliplist[i]);
1559 } else {
1560 tarmac = talloc_asprintf(ctx,
1561 "%s%s",
1562 client_get_cur_dir(),
1563 cliplist[i]);
1565 if (!tarmac) {
1566 return 1;
1569 * Strip off the last \\xxx
1570 * xxx element of tarmac to set
1571 * it as current directory.
1573 p = strrchr_m(tarmac, '\\');
1574 if (!p) {
1575 return 1;
1577 saved_char = p[1];
1578 p[1] = '\0';
1580 client_set_cur_dir(tarmac);
1583 * Restore the character we
1584 * just replaced to
1585 * put the pathname
1586 * back as it was.
1588 p[1] = saved_char;
1590 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1591 do_list(tarmac,attribute,do_tar, False, True);
1593 client_set_cur_dir(saved_dir);
1595 TALLOC_FREE(saved_dir);
1596 TALLOC_FREE(tarmac);
1597 } else {
1598 tarmac = talloc_asprintf(ctx,
1599 "%s%s",
1600 client_get_cur_dir(),
1601 cliplist[i]);
1602 if (!tarmac) {
1603 return 1;
1605 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1606 do_list(tarmac,attribute,do_tar, False, True);
1607 TALLOC_FREE(tarmac);
1610 } else {
1611 char *mask = talloc_asprintf(ctx,
1612 "%s\\*",
1613 client_get_cur_dir());
1614 if (!mask) {
1615 return 1;
1617 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1618 do_list(mask,attribute,do_tar,False, True);
1619 TALLOC_FREE(mask);
1622 if (ntarf) {
1623 dotareof(tarhandle);
1625 close(tarhandle);
1626 SAFE_FREE(tarbuf);
1628 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1629 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1630 break;
1633 if (must_free_cliplist) {
1634 int i;
1635 for (i = 0; i < clipn; ++i) {
1636 SAFE_FREE(cliplist[i]);
1638 SAFE_FREE(cliplist);
1639 cliplist = NULL;
1640 clipn = 0;
1641 must_free_cliplist = False;
1643 return rc;
1646 /****************************************************************************
1647 Find a token (filename) in a clip list
1648 ***************************************************************************/
1650 static int clipfind(char **aret, int ret, char *tok)
1652 if (aret==NULL)
1653 return 0;
1655 /* ignore leading slashes or dots in token */
1656 while(strchr_m("/\\.", *tok))
1657 tok++;
1659 while(ret--) {
1660 char *pkey=*aret++;
1662 /* ignore leading slashes or dots in list */
1663 while(strchr_m("/\\.", *pkey))
1664 pkey++;
1666 if (!strslashcmp(pkey, tok))
1667 return 1;
1669 return 0;
1672 /****************************************************************************
1673 Read list of files to include from the file and initialize cliplist
1674 accordingly.
1675 ***************************************************************************/
1677 static int read_inclusion_file(char *filename)
1679 XFILE *inclusion = NULL;
1680 char buf[PATH_MAX + 1];
1681 char *inclusion_buffer = NULL;
1682 int inclusion_buffer_size = 0;
1683 int inclusion_buffer_sofar = 0;
1684 char *p;
1685 char *tmpstr;
1686 int i;
1687 int error = 0;
1689 clipn = 0;
1690 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1691 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1692 /* XXX It would be better to include a reason for failure, but without
1693 * autoconf, it's hard to use strerror, sys_errlist, etc.
1695 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1696 return 0;
1699 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1700 if (inclusion_buffer == NULL) {
1701 inclusion_buffer_size = 1024;
1702 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1703 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1704 error = 1;
1705 break;
1709 if (buf[strlen(buf)-1] == '\n') {
1710 buf[strlen(buf)-1] = '\0';
1713 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1714 inclusion_buffer_size *= 2;
1715 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1716 if (!inclusion_buffer) {
1717 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1718 inclusion_buffer_size));
1719 error = 1;
1720 break;
1724 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1725 inclusion_buffer_sofar += strlen(buf) + 1;
1726 clipn++;
1728 x_fclose(inclusion);
1730 if (! error) {
1731 /* Allocate an array of clipn + 1 char*'s for cliplist */
1732 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1733 if (cliplist == NULL) {
1734 DEBUG(0,("failure allocating memory for cliplist\n"));
1735 error = 1;
1736 } else {
1737 cliplist[clipn] = NULL;
1738 p = inclusion_buffer;
1739 for (i = 0; (! error) && (i < clipn); i++) {
1740 /* set current item to NULL so array will be null-terminated even if
1741 * malloc fails below. */
1742 cliplist[i] = NULL;
1743 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1744 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1745 error = 1;
1746 } else {
1747 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1748 cliplist[i] = tmpstr;
1749 if ((p = strchr_m(p, '\000')) == NULL) {
1750 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1751 abort();
1754 ++p;
1756 must_free_cliplist = True;
1760 SAFE_FREE(inclusion_buffer);
1761 if (error) {
1762 if (cliplist) {
1763 char **pp;
1764 /* We know cliplist is always null-terminated */
1765 for (pp = cliplist; *pp; ++pp) {
1766 SAFE_FREE(*pp);
1768 SAFE_FREE(cliplist);
1769 cliplist = NULL;
1770 must_free_cliplist = False;
1772 return 0;
1775 /* cliplist and its elements are freed at the end of process_tar. */
1776 return 1;
1779 /****************************************************************************
1780 Parse tar arguments. Sets tar_type, tar_excl, etc.
1781 ***************************************************************************/
1783 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1785 int newOptind = Optind;
1786 char tar_clipfl='\0';
1788 /* Reset back to defaults - could be from interactive version
1789 * reset mode and archive mode left as they are though
1791 tar_type='\0';
1792 tar_excl=True;
1793 dry_run=False;
1795 while (*Optarg) {
1796 switch(*Optarg++) {
1797 case 'c':
1798 tar_type='c';
1799 break;
1800 case 'x':
1801 if (tar_type=='c') {
1802 printf("Tar must be followed by only one of c or x.\n");
1803 return 0;
1805 tar_type='x';
1806 break;
1807 case 'b':
1808 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1809 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1810 return 0;
1811 } else {
1812 Optind++;
1813 newOptind++;
1815 break;
1816 case 'g':
1817 tar_inc=True;
1818 break;
1819 case 'N':
1820 if (Optind>=argc) {
1821 DEBUG(0,("Option N must be followed by valid file name\n"));
1822 return 0;
1823 } else {
1824 SMB_STRUCT_STAT stbuf;
1826 if (sys_stat(argv[Optind], &stbuf,
1827 false) == 0) {
1828 newer_than = convert_timespec_to_time_t(
1829 stbuf.st_ex_mtime);
1830 DEBUG(1,("Getting files newer than %s",
1831 time_to_asc(newer_than)));
1832 newOptind++;
1833 Optind++;
1834 } else {
1835 DEBUG(0,("Error setting newer-than time\n"));
1836 return 0;
1839 break;
1840 case 'a':
1841 tar_reset=True;
1842 break;
1843 case 'q':
1844 tar_noisy=False;
1845 break;
1846 case 'I':
1847 if (tar_clipfl) {
1848 DEBUG(0,("Only one of I,X,F must be specified\n"));
1849 return 0;
1851 tar_clipfl='I';
1852 break;
1853 case 'X':
1854 if (tar_clipfl) {
1855 DEBUG(0,("Only one of I,X,F must be specified\n"));
1856 return 0;
1858 tar_clipfl='X';
1859 break;
1860 case 'F':
1861 if (tar_clipfl) {
1862 DEBUG(0,("Only one of I,X,F must be specified\n"));
1863 return 0;
1865 tar_clipfl='F';
1866 break;
1867 case 'r':
1868 DEBUG(0, ("tar_re_search set\n"));
1869 tar_re_search = True;
1870 break;
1871 case 'n':
1872 if (tar_type == 'c') {
1873 DEBUG(0, ("dry_run set\n"));
1874 dry_run = True;
1875 } else {
1876 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1877 return 0;
1879 break;
1880 default:
1881 DEBUG(0,("Unknown tar option\n"));
1882 return 0;
1886 if (!tar_type) {
1887 printf("Option T must be followed by one of c or x.\n");
1888 return 0;
1891 /* tar_excl is true if cliplist lists files to be included.
1892 * Both 'I' and 'F' mean include. */
1893 tar_excl=tar_clipfl!='X';
1895 if (tar_clipfl=='F') {
1896 if (argc-Optind-1 != 1) {
1897 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1898 return 0;
1900 newOptind++;
1901 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1902 if (! read_inclusion_file(argv[Optind+1])) {
1903 return 0;
1905 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1906 char *tmpstr;
1907 char **tmplist;
1908 int clipcount;
1910 cliplist=argv+Optind+1;
1911 clipn=argc-Optind-1;
1912 clipcount = clipn;
1914 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1915 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1916 return 0;
1919 for (clipcount = 0; clipcount < clipn; clipcount++) {
1921 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1923 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1924 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1925 SAFE_FREE(tmplist);
1926 return 0;
1929 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1930 tmplist[clipcount] = tmpstr;
1931 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1933 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1936 cliplist = tmplist;
1937 must_free_cliplist = True;
1939 newOptind += clipn;
1942 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1943 /* Doing regular expression seaches not from an inclusion file. */
1944 clipn=argc-Optind-1;
1945 cliplist=argv+Optind+1;
1946 newOptind += clipn;
1949 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1950 /* Sets tar handle to either 0 or 1, as appropriate */
1951 tarhandle=(tar_type=='c');
1953 * Make sure that dbf points to stderr if we are using stdout for
1954 * tar output
1956 if (tarhandle == 1) {
1957 setup_logging("smbclient", DEBUG_STDERR);
1959 if (!argv[Optind]) {
1960 DEBUG(0,("Must specify tar filename\n"));
1961 return 0;
1963 if (!strcmp(argv[Optind], "-")) {
1964 newOptind++;
1967 } else {
1968 if (tar_type=='c' && dry_run) {
1969 tarhandle=-1;
1970 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1971 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1972 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1973 return(0);
1975 newOptind++;
1978 return newOptind;