WHATSNEW: Start release notes for Samba 3.6.4.
[Samba.git] / source3 / client / clitar.c
blob3c08734e92f0172197ae1a3549f932fa13a59776
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"
41 #include "libsmb/libsmb.h"
43 static int clipfind(char **aret, int ret, char *tok);
45 typedef struct file_info_struct file_info2;
47 struct file_info_struct {
48 SMB_OFF_T size;
49 uint16 mode;
50 uid_t uid;
51 gid_t gid;
52 /* These times are normally kept in GMT */
53 struct timespec mtime_ts;
54 struct timespec atime_ts;
55 struct timespec ctime_ts;
56 char *name; /* This is dynamically allocated */
57 file_info2 *next, *prev; /* Used in the stack ... */
60 typedef struct {
61 file_info2 *top;
62 int items;
63 } stack;
65 #define SEPARATORS " \t\n\r"
66 extern time_t newer_than;
67 extern struct cli_state *cli;
69 /* These defines are for the do_setrattr routine, to indicate
70 * setting and reseting of file attributes in the function call */
71 #define ATTRSET 1
72 #define ATTRRESET 0
74 static uint16 attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
76 #ifndef CLIENT_TIMEOUT
77 #define CLIENT_TIMEOUT (30*1000)
78 #endif
80 static char *tarbuf, *buffer_p;
81 static int tp, ntarf, tbufsiz;
82 static double ttarf;
83 /* Incremental mode */
84 static bool tar_inc=False;
85 /* Reset archive bit */
86 static bool tar_reset=False;
87 /* Include / exclude mode (true=include, false=exclude) */
88 static bool tar_excl=True;
89 /* use regular expressions for search on file names */
90 static bool tar_re_search=False;
91 /* Do not dump anything, just calculate sizes */
92 static bool dry_run=False;
93 /* Dump files with System attribute */
94 static bool tar_system=True;
95 /* Dump files with Hidden attribute */
96 static bool tar_hidden=True;
97 /* Be noisy - make a catalogue */
98 static bool tar_noisy=True;
99 static bool tar_real_noisy=False; /* Don't want to be really noisy by default */
101 char tar_type='\0';
102 static char **cliplist=NULL;
103 static int clipn=0;
104 static bool must_free_cliplist = False;
105 extern const char *cmd_ptr;
107 extern bool lowercase;
108 extern uint16 cnum;
109 extern bool readbraw_supported;
110 extern int max_xmit;
111 extern int get_total_time_ms;
112 extern int get_total_size;
114 static int blocksize=20;
115 static int tarhandle;
117 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
118 const char *amode, unsigned char ftype);
119 static NTSTATUS do_atar(const char *rname_in, char *lname,
120 struct file_info *finfo1);
121 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
122 const char *dir);
123 static void oct_it(uint64_t value, int ndgs, char *p);
124 static void fixtarname(char *tptr, const char *fp, size_t l);
125 static int dotarbuf(int f, char *b, int n);
126 static void dozerobuf(int f, int n);
127 static void dotareof(int f);
128 static void initarbuf(void);
130 /* restore functions */
131 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
132 static long unoct(char *p, int ndgs);
133 static void do_tarput(void);
134 static void unfixtarname(char *tptr, char *fp, int l, bool first);
137 * tar specific utitlities
140 /*******************************************************************
141 Create a string of size size+1 (for the null)
142 *******************************************************************/
144 static char *string_create_s(int size)
146 char *tmp;
148 tmp = (char *)SMB_MALLOC(size+1);
150 if (tmp == NULL) {
151 DEBUG(0, ("Out of memory in string_create_s\n"));
154 return(tmp);
157 /****************************************************************************
158 Write a tar header to buffer
159 ****************************************************************************/
161 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
162 const char *amode, unsigned char ftype)
164 union hblock hb;
165 int i, chk, l;
166 char *jp;
168 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
170 memset(hb.dummy, 0, sizeof(hb.dummy));
172 l=strlen(aname);
173 /* We will be prepending a '.' in fixtarheader so use +2 to
174 * take care of the . and terminating zero. JRA.
176 if (l+2 >= NAMSIZ) {
177 /* write a GNU tar style long header */
178 char *b;
179 b = (char *)SMB_MALLOC(l+TBLOCK+100);
180 if (!b) {
181 DEBUG(0,("out of memory\n"));
182 exit(1);
184 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
185 memset(b, 0, l+TBLOCK+100);
186 fixtarname(b, aname, l+2);
187 i = strlen(b)+1;
188 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
189 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
190 SAFE_FREE(b);
193 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
195 if (lowercase)
196 strlower_m(hb.dbuf.name);
198 /* write out a "standard" tar format header */
200 hb.dbuf.name[NAMSIZ-1]='\0';
201 safe_strcpy(hb.dbuf.mode, amode, sizeof(hb.dbuf.mode)-1);
202 oct_it((uint64_t)0, 8, hb.dbuf.uid);
203 oct_it((uint64_t)0, 8, hb.dbuf.gid);
204 oct_it((uint64_t) size, 13, hb.dbuf.size);
205 if (size > (uint64_t)077777777777LL) {
206 /* This is a non-POSIX compatible extention to store files
207 greater than 8GB. */
209 memset(hb.dbuf.size, 0, 4);
210 hb.dbuf.size[0]=128;
211 for (i = 8; i; i--) {
212 hb.dbuf.size[i+3] = size & 0xff;
213 size >>= 8;
216 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
217 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
218 memset(hb.dbuf.linkname, 0, NAMSIZ);
219 hb.dbuf.linkflag=ftype;
221 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
222 chk+=(0xFF & *jp++);
224 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
225 hb.dbuf.chksum[6] = '\0';
227 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
230 /****************************************************************************
231 Read a tar header into a hblock structure, and validate
232 ***************************************************************************/
234 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
236 long chk, fchk;
237 int i;
238 char *jp;
241 * read in a "standard" tar format header - we're not that interested
242 * in that many fields, though
245 /* check the checksum */
246 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
247 chk+=(0xFF & *jp++);
249 if (chk == 0)
250 return chk;
252 /* compensate for blanks in chksum header */
253 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
254 chk-=(0xFF & *jp++);
256 chk += ' ' * sizeof(hb->dbuf.chksum);
258 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
260 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
261 chk, fchk, hb->dbuf.chksum));
263 if (fchk != chk) {
264 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
265 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
266 return -1;
269 if ((finfo->name = string_create_s(strlen(prefix) + strlen(hb -> dbuf.name) + 3)) == NULL) {
270 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
271 return(-1);
274 safe_strcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 3);
276 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
277 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
278 strlen(hb->dbuf.name) + 1, True);
280 /* can't handle some links at present */
281 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
282 if (hb->dbuf.linkflag == 0) {
283 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
284 finfo->name));
285 } else {
286 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
287 /* Do nothing here at the moment. do_tarput will handle this
288 as long as the longlink gets back to it, as it has to advance
289 the buffer pointer, etc */
290 } else {
291 DEBUG(0, ("this tar file appears to contain some kind \
292 of link other than a GNUtar Longlink - ignoring\n"));
293 return -2;
298 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
299 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
300 finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
301 } else {
302 finfo->mode=0; /* we don't care about mode at the moment, we'll
303 * just make it a regular file */
307 * Bug fix by richard@sj.co.uk
309 * REC: restore times correctly (as does tar)
310 * We only get the modification time of the file; set the creation time
311 * from the mod. time, and the access time to current time
313 finfo->mtime_ts = finfo->ctime_ts =
314 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
315 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
316 if ((hb->dbuf.size[0] & 0xff) == 0x80) {
317 /* This is a non-POSIX compatible extention to extract files
318 greater than 8GB. */
319 finfo->size = 0;
320 for (i = 0; i < 8; i++) {
321 finfo->size <<= 8;
322 finfo->size |= hb->dbuf.size[i+4] & 0xff;
324 } else {
325 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
328 return True;
331 /****************************************************************************
332 Write out the tar buffer to tape or wherever
333 ****************************************************************************/
335 static int dotarbuf(int f, char *b, int n)
337 int fail=1, writ=n;
339 if (dry_run) {
340 return writ;
342 /* This routine and the next one should be the only ones that do write()s */
343 if (tp + n >= tbufsiz) {
344 int diff;
346 diff=tbufsiz-tp;
347 memcpy(tarbuf + tp, b, diff);
348 fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
349 n-=diff;
350 b+=diff;
351 tp=0;
353 while (n >= tbufsiz) {
354 fail=fail && (1 + sys_write(f, b, tbufsiz));
355 n-=tbufsiz;
356 b+=tbufsiz;
360 if (n>0) {
361 memcpy(tarbuf+tp, b, n);
362 tp+=n;
365 return(fail ? writ : 0);
368 /****************************************************************************
369 Write zeros to buffer / tape
370 ****************************************************************************/
372 static void dozerobuf(int f, int n)
374 /* short routine just to write out n zeros to buffer -
375 * used to round files to nearest block
376 * and to do tar EOFs */
378 if (dry_run)
379 return;
381 if (n+tp >= tbufsiz) {
382 memset(tarbuf+tp, 0, tbufsiz-tp);
383 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
384 DEBUG(0, ("dozerobuf: sys_write fail\n"));
385 return;
387 memset(tarbuf, 0, (tp+=n-tbufsiz));
388 } else {
389 memset(tarbuf+tp, 0, n);
390 tp+=n;
394 /****************************************************************************
395 Malloc tape buffer
396 ****************************************************************************/
398 static void initarbuf(void)
400 /* initialize tar buffer */
401 tbufsiz=blocksize*TBLOCK;
402 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
404 /* reset tar buffer pointer and tar file counter and total dumped */
405 tp=0; ntarf=0; ttarf=0;
408 /****************************************************************************
409 Write two zero blocks at end of file
410 ****************************************************************************/
412 static void dotareof(int f)
414 SMB_STRUCT_STAT stbuf;
415 /* Two zero blocks at end of file, write out full buffer */
417 if (dry_run)
418 return;
420 (void) dozerobuf(f, TBLOCK);
421 (void) dozerobuf(f, TBLOCK);
423 if (sys_fstat(f, &stbuf, false) == -1) {
424 DEBUG(0, ("Couldn't stat file handle\n"));
425 return;
428 /* Could be a pipe, in which case S_ISREG should fail,
429 * and we should write out at full size */
430 if (tp > 0) {
431 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
432 if (sys_write(f, tarbuf, towrite) != towrite) {
433 DEBUG(0,("dotareof: sys_write fail\n"));
438 /****************************************************************************
439 (Un)mangle DOS pathname, make nonabsolute
440 ****************************************************************************/
442 static void fixtarname(char *tptr, const char *fp, size_t l)
444 /* add a '.' to start of file name, convert from ugly dos \'s in path
445 * to lovely unix /'s :-} */
446 *tptr++='.';
447 l--;
449 StrnCpy(tptr, fp, l-1);
450 string_replace(tptr, '\\', '/');
453 /****************************************************************************
454 Convert from decimal to octal string
455 ****************************************************************************/
457 static void oct_it (uint64_t value, int ndgs, char *p)
459 /* Converts long to octal string, pads with leading zeros */
461 /* skip final null, but do final space */
462 --ndgs;
463 p[--ndgs] = ' ';
465 /* Loop does at least one digit */
466 do {
467 p[--ndgs] = '0' + (char) (value & 7);
468 value >>= 3;
469 } while (ndgs > 0 && value != 0);
471 /* Do leading zeros */
472 while (ndgs > 0)
473 p[--ndgs] = '0';
476 /****************************************************************************
477 Convert from octal string to long
478 ***************************************************************************/
480 static long unoct(char *p, int ndgs)
482 long value=0;
483 /* Converts octal string to long, ignoring any non-digit */
485 while (--ndgs) {
486 if (isdigit((int)*p))
487 value = (value << 3) | (long) (*p - '0');
489 p++;
492 return value;
495 /****************************************************************************
496 Compare two strings in a slash insensitive way, allowing s1 to match s2
497 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
498 a file in any subdirectory of s1, declare a match.
499 ***************************************************************************/
501 static int strslashcmp(char *s1, char *s2)
503 char *s1_0=s1;
505 while(*s1 && *s2 && (*s1 == *s2 || tolower_m(*s1) == tolower_m(*s2) ||
506 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
507 s1++; s2++;
510 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
511 string of s2.
513 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
514 return 0;
516 /* ignore trailing slash on s1 */
517 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
518 return 0;
520 /* check for s1 is an "initial" string of s2 */
521 if ((*s2 == '/' || *s2 == '\\') && !*s1)
522 return 0;
524 return *s1-*s2;
527 /****************************************************************************
528 Ensure a remote path exists (make if necessary)
529 ***************************************************************************/
531 static bool ensurepath(const char *fname)
533 /* *must* be called with buffer ready malloc'ed */
534 /* ensures path exists */
536 char *partpath, *ffname;
537 const char *p=fname;
538 char *basehack;
539 char *saveptr;
541 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
543 partpath = string_create_s(strlen(fname));
544 ffname = string_create_s(strlen(fname));
546 if ((partpath == NULL) || (ffname == NULL)){
547 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
548 SAFE_FREE(partpath);
549 SAFE_FREE(ffname);
550 return(False);
553 *partpath = 0;
555 /* fname copied to ffname so can strtok_r */
557 safe_strcpy(ffname, fname, strlen(fname));
559 /* do a `basename' on ffname, so don't try and make file name directory */
560 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
561 SAFE_FREE(partpath);
562 SAFE_FREE(ffname);
563 return True;
564 } else {
565 *basehack='\0';
568 p=strtok_r(ffname, "\\", &saveptr);
570 while (p) {
571 safe_strcat(partpath, p, strlen(fname) + 1);
573 if (!NT_STATUS_IS_OK(cli_chkpath(cli, partpath))) {
574 if (!NT_STATUS_IS_OK(cli_mkdir(cli, partpath))) {
575 SAFE_FREE(partpath);
576 SAFE_FREE(ffname);
577 DEBUG(0, ("Error mkdir %s\n", cli_errstr(cli)));
578 return False;
579 } else {
580 DEBUG(3, ("mkdirhiering %s\n", partpath));
584 safe_strcat(partpath, "\\", strlen(fname) + 1);
585 p = strtok_r(NULL, "/\\", &saveptr);
588 SAFE_FREE(partpath);
589 SAFE_FREE(ffname);
590 return True;
593 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
595 int berr= 0;
596 int bytestowrite;
598 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
599 memset(buf, 0, (size_t)bufsize);
600 while( !berr && padsize > 0 ) {
601 bytestowrite= (int)MIN(bufsize, padsize);
602 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
603 padsize -= bytestowrite;
606 return berr;
609 static void do_setrattr(char *name, uint16 attr, int set)
611 uint16 oldattr;
613 if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
614 return;
617 if (set == ATTRSET) {
618 attr |= oldattr;
619 } else {
620 attr = oldattr & ~attr;
623 if (!NT_STATUS_IS_OK(cli_setatr(cli, name, attr, 0))) {
624 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli)));
628 /****************************************************************************
629 append one remote file to the tar file
630 ***************************************************************************/
632 static NTSTATUS do_atar(const char *rname_in, char *lname,
633 struct file_info *finfo1)
635 uint16_t fnum = (uint16_t)-1;
636 uint64_t nread=0;
637 char ftype;
638 file_info2 finfo;
639 bool shallitime=True;
640 char *data = NULL;
641 int read_size = 65520;
642 int datalen=0;
643 char *rname = NULL;
644 TALLOC_CTX *ctx = talloc_stackframe();
645 NTSTATUS status = NT_STATUS_OK;
646 struct timespec tp_start;
648 clock_gettime_mono(&tp_start);
650 data = SMB_MALLOC_ARRAY(char, read_size);
651 if (!data) {
652 DEBUG(0,("do_atar: out of memory.\n"));
653 status = NT_STATUS_NO_MEMORY;
654 goto cleanup;
657 ftype = '0'; /* An ordinary file ... */
659 ZERO_STRUCT(finfo);
661 finfo.size = finfo1 -> size;
662 finfo.mode = finfo1 -> mode;
663 finfo.uid = finfo1 -> uid;
664 finfo.gid = finfo1 -> gid;
665 finfo.mtime_ts = finfo1 -> mtime_ts;
666 finfo.atime_ts = finfo1 -> atime_ts;
667 finfo.ctime_ts = finfo1 -> ctime_ts;
669 if (dry_run) {
670 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
671 (double)finfo.size));
672 shallitime=0;
673 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
674 ntarf++;
675 goto cleanup;
678 rname = clean_name(ctx, rname_in);
679 if (!rname) {
680 status = NT_STATUS_NO_MEMORY;
681 goto cleanup;
684 status = cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum);
685 if (!NT_STATUS_IS_OK(status)) {
686 DEBUG(0,("%s opening remote file %s (%s)\n",
687 cli_errstr(cli),rname, client_get_cur_dir()));
688 goto cleanup;
691 finfo.name = string_create_s(strlen(rname));
692 if (finfo.name == NULL) {
693 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
694 status = NT_STATUS_NO_MEMORY;
695 goto cleanup;
698 safe_strcpy(finfo.name,rname, strlen(rname));
700 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
702 if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE)) {
703 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
704 shallitime=0;
705 } else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM)) {
706 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
707 shallitime=0;
708 } else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN)) {
709 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
710 shallitime=0;
711 } else {
712 bool wrote_tar_header = False;
714 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
715 finfo.name, (double)finfo.size, lname));
717 do {
719 DEBUG(3,("nread=%.0f\n",(double)nread));
721 datalen = cli_read(cli, fnum, data, nread, read_size);
723 if (datalen == -1) {
724 DEBUG(0,("Error reading file %s : %s\n", rname, cli_errstr(cli)));
725 status = cli_nt_error(cli);
726 break;
729 nread += datalen;
731 /* Only if the first read succeeds, write out the tar header. */
732 if (!wrote_tar_header) {
733 /* write a tar header, don't bother with mode - just set to 100644 */
734 writetarheader(tarhandle, rname, finfo.size,
735 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
736 wrote_tar_header = True;
739 /* if file size has increased since we made file size query, truncate
740 read so tar header for this file will be correct.
743 if (nread > finfo.size) {
744 datalen -= nread - finfo.size;
745 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
746 finfo.name, (double)finfo.size));
749 /* add received bits of file to buffer - dotarbuf will
750 * write out in 512 byte intervals */
752 if (dotarbuf(tarhandle,data,datalen) != datalen) {
753 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
754 status = map_nt_error_from_unix(errno);
755 break;
758 if ( (datalen == 0) && (finfo.size != 0) ) {
759 status = NT_STATUS_UNSUCCESSFUL;
760 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
761 break;
764 datalen=0;
765 } while ( nread < finfo.size );
767 if (wrote_tar_header) {
768 /* pad tar file with zero's if we couldn't get entire file */
769 if (nread < finfo.size) {
770 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
771 (double)finfo.size, (int)nread));
772 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) {
773 status = map_nt_error_from_unix(errno);
774 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
778 /* round tar file to nearest block */
779 if (finfo.size % TBLOCK)
780 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
782 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
783 ntarf++;
784 } else {
785 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
786 shallitime=0;
787 status = NT_STATUS_UNSUCCESSFUL;
791 cli_close(cli, fnum);
792 fnum = -1;
794 if (shallitime) {
795 struct timespec tp_end;
796 int this_time;
798 /* if shallitime is true then we didn't skip */
799 if (tar_reset && !dry_run)
800 (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
802 clock_gettime_mono(&tp_end);
803 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000;
804 get_total_time_ms += this_time;
805 get_total_size += finfo.size;
807 if (tar_noisy) {
808 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
809 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
810 finfo.name));
813 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
814 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
815 finfo.size / MAX(0.001, (1.024*this_time)),
816 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
819 cleanup:
821 if (fnum != (uint16_t)-1) {
822 cli_close(cli, fnum);
823 fnum = -1;
825 TALLOC_FREE(ctx);
826 SAFE_FREE(data);
827 return status;
830 /****************************************************************************
831 Append single file to tar file (or not)
832 ***************************************************************************/
834 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
835 const char *dir)
837 TALLOC_CTX *ctx = talloc_stackframe();
838 NTSTATUS status = NT_STATUS_OK;
840 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
841 return NT_STATUS_OK;
843 /* Is it on the exclude list ? */
844 if (!tar_excl && clipn) {
845 char *exclaim;
847 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
849 exclaim = talloc_asprintf(ctx,
850 "%s\\%s",
851 client_get_cur_dir(),
852 finfo->name);
853 if (!exclaim) {
854 return NT_STATUS_NO_MEMORY;
857 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
859 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
860 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
861 DEBUG(3,("Skipping file %s\n", exclaim));
862 TALLOC_FREE(exclaim);
863 return NT_STATUS_OK;
865 TALLOC_FREE(exclaim);
868 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
869 char *saved_curdir = NULL;
870 char *new_cd = NULL;
871 char *mtar_mask = NULL;
873 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
874 if (!saved_curdir) {
875 return NT_STATUS_NO_MEMORY;
878 DEBUG(5, ("strlen(cur_dir)=%d, \
879 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
880 (int)strlen(saved_curdir),
881 (int)strlen(finfo->name), finfo->name, saved_curdir));
883 new_cd = talloc_asprintf(ctx,
884 "%s%s\\",
885 client_get_cur_dir(),
886 finfo->name);
887 if (!new_cd) {
888 return NT_STATUS_NO_MEMORY;
890 client_set_cur_dir(new_cd);
892 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
894 /* write a tar directory, don't bother with mode - just
895 * set it to 40755 */
896 writetarheader(tarhandle, client_get_cur_dir(), 0,
897 finfo->mtime_ts.tv_sec, "040755 \0", '5');
898 if (tar_noisy) {
899 DEBUG(0,(" directory %s\n",
900 client_get_cur_dir()));
902 ntarf++; /* Make sure we have a file on there */
903 mtar_mask = talloc_asprintf(ctx,
904 "%s*",
905 client_get_cur_dir());
906 if (!mtar_mask) {
907 return NT_STATUS_NO_MEMORY;
909 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
910 status = do_list(mtar_mask, attribute, do_tar, False, True);
911 client_set_cur_dir(saved_curdir);
912 TALLOC_FREE(saved_curdir);
913 TALLOC_FREE(new_cd);
914 TALLOC_FREE(mtar_mask);
915 } else {
916 char *rname = talloc_asprintf(ctx,
917 "%s%s",
918 client_get_cur_dir(),
919 finfo->name);
920 if (!rname) {
921 return NT_STATUS_NO_MEMORY;
923 status = do_atar(rname,finfo->name,finfo);
924 TALLOC_FREE(rname);
926 return status;
929 /****************************************************************************
930 Convert from UNIX to DOS file names
931 ***************************************************************************/
933 static void unfixtarname(char *tptr, char *fp, int l, bool first)
935 /* remove '.' from start of file name, convert from unix /'s to
936 * dos \'s in path. Kill any absolute path names. But only if first!
939 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
941 if (first) {
942 if (*fp == '.') {
943 fp++;
944 l--;
946 if (*fp == '\\' || *fp == '/') {
947 fp++;
948 l--;
952 safe_strcpy(tptr, fp, l);
953 string_replace(tptr, '/', '\\');
956 /****************************************************************************
957 Move to the next block in the buffer, which may mean read in another set of
958 blocks. FIXME, we should allow more than one block to be skipped.
959 ****************************************************************************/
961 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
963 int bufread, total = 0;
965 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
966 *bufferp += TBLOCK;
967 total = TBLOCK;
969 if (*bufferp >= (ltarbuf + bufsiz)) {
971 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
974 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
975 * Fixes bug where read can return short if coming from
976 * a pipe.
979 bufread = read(tarhandle, ltarbuf, bufsiz);
980 total = bufread;
982 while (total < bufsiz) {
983 if (bufread < 0) { /* An error, return false */
984 return (total > 0 ? -2 : bufread);
986 if (bufread == 0) {
987 if (total <= 0) {
988 return -2;
990 break;
992 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
993 total += bufread;
996 DEBUG(5, ("Total bytes read ... %i\n", total));
998 *bufferp = ltarbuf;
1001 return(total);
1004 /* Skip a file, even if it includes a long file name? */
1005 static int skip_file(int skipsize)
1007 int dsize = skipsize;
1009 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
1011 /* FIXME, we should skip more than one block at a time */
1013 while (dsize > 0) {
1014 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1015 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1016 return(False);
1018 dsize -= TBLOCK;
1021 return(True);
1024 /*************************************************************
1025 Get a file from the tar file and store it.
1026 When this is called, tarbuf already contains the first
1027 file block. This is a bit broken & needs fixing.
1028 **************************************************************/
1030 static int get_file(file_info2 finfo)
1032 uint16_t fnum = (uint16_t) -1;
1033 int dsize = 0, bpos = 0;
1034 uint64_t rsize = 0, pos = 0;
1035 NTSTATUS status;
1037 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1039 if (!ensurepath(finfo.name)) {
1040 DEBUG(0, ("abandoning restore\n"));
1041 return False;
1044 status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1045 if (!NT_STATUS_IS_OK(status)) {
1046 DEBUG(0, ("abandoning restore\n"));
1047 return False;
1050 /* read the blocks from the tar file and write to the remote file */
1052 rsize = finfo.size; /* This is how much to write */
1054 while (rsize > 0) {
1056 /* We can only write up to the end of the buffer */
1057 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1058 dsize = MIN(dsize, rsize); /* Should be only what is left */
1059 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1061 status = cli_writeall(cli, fnum, 0,
1062 (uint8_t *)(buffer_p + bpos), pos,
1063 dsize, NULL);
1064 if (!NT_STATUS_IS_OK(status)) {
1065 DEBUG(0, ("Error writing remote file: %s\n",
1066 nt_errstr(status)));
1067 return 0;
1070 rsize -= dsize;
1071 pos += dsize;
1073 /* Now figure out how much to move in the buffer */
1075 /* FIXME, we should skip more than one block at a time */
1077 /* First, skip any initial part of the part written that is left over */
1078 /* from the end of the first TBLOCK */
1080 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1081 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1082 bpos = 0;
1084 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1085 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1086 return False;
1091 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1092 * If the file being extracted is an exact multiple of
1093 * TBLOCK bytes then we don't want to extract the next
1094 * block from the tarfile here, as it will be done in
1095 * the caller of get_file().
1098 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1099 ((rsize == 0) && (dsize > TBLOCK))) {
1101 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1102 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1103 return False;
1106 dsize -= TBLOCK;
1108 bpos = dsize;
1111 /* Now close the file ... */
1113 if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
1114 DEBUG(0, ("Error %s closing remote file\n",
1115 cli_errstr(cli)));
1116 return(False);
1119 /* Now we update the creation date ... */
1120 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1122 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1123 if (tar_real_noisy) {
1124 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1125 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1129 ntarf++;
1130 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1131 return(True);
1134 /* Create a directory. We just ensure that the path exists and return as there
1135 is no file associated with a directory
1137 static int get_dir(file_info2 finfo)
1139 DEBUG(0, ("restore directory %s\n", finfo.name));
1141 if (!ensurepath(finfo.name)) {
1142 DEBUG(0, ("Problems creating directory\n"));
1143 return(False);
1145 ntarf++;
1146 return(True);
1149 /* Get a file with a long file name ... first file has file name, next file
1150 has the data. We only want the long file name, as the loop in do_tarput
1151 will deal with the rest.
1153 static char *get_longfilename(file_info2 finfo)
1155 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1156 * header call. */
1157 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1158 char *longname = (char *)SMB_MALLOC(namesize);
1159 int offset = 0, left = finfo.size;
1160 bool first = True;
1162 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1163 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1165 if (longname == NULL) {
1166 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1167 return(NULL);
1170 /* First, add cur_dir to the long file name */
1172 if (strlen(client_get_cur_dir()) > 0) {
1173 strncpy(longname, client_get_cur_dir(), namesize);
1174 offset = strlen(client_get_cur_dir());
1177 /* Loop through the blocks picking up the name */
1179 while (left > 0) {
1180 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1181 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1182 SAFE_FREE(longname);
1183 return(NULL);
1186 unfixtarname(longname + offset, buffer_p, MIN(TBLOCK, finfo.size), first--);
1187 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1189 offset += TBLOCK;
1190 left -= TBLOCK;
1193 return(longname);
1196 static void do_tarput(void)
1198 file_info2 finfo;
1199 struct timespec tp_start;
1200 char *longfilename = NULL, linkflag;
1201 int skip = False;
1203 ZERO_STRUCT(finfo);
1205 clock_gettime_mono(&tp_start);
1206 DEBUG(5, ("RJS do_tarput called ...\n"));
1208 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1210 /* Now read through those files ... */
1211 while (True) {
1212 /* Get us to the next block, or the first block first time around */
1213 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1214 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1215 SAFE_FREE(longfilename);
1216 return;
1219 DEBUG(5, ("Reading the next header ...\n"));
1221 switch (readtarheader((union hblock *) buffer_p,
1222 &finfo, client_get_cur_dir())) {
1223 case -2: /* Hmm, not good, but not fatal */
1224 DEBUG(0, ("Skipping %s...\n", finfo.name));
1225 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1226 DEBUG(0, ("Short file, bailing out...\n"));
1227 SAFE_FREE(longfilename);
1228 return;
1230 break;
1232 case -1:
1233 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1234 SAFE_FREE(longfilename);
1235 return;
1237 case 0: /* chksum is zero - looks like an EOF */
1238 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1239 SAFE_FREE(longfilename);
1240 return; /* Hmmm, bad here ... */
1242 default:
1243 /* No action */
1244 break;
1247 /* Now, do we have a long file name? */
1248 if (longfilename != NULL) {
1249 SAFE_FREE(finfo.name); /* Free the space already allocated */
1250 finfo.name = longfilename;
1251 longfilename = NULL;
1254 /* Well, now we have a header, process the file ... */
1255 /* Should we skip the file? We have the long name as well here */
1256 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1257 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1259 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1260 if (skip) {
1261 skip_file(finfo.size);
1262 continue;
1265 /* We only get this far if we should process the file */
1266 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1267 switch (linkflag) {
1268 case '0': /* Should use symbolic names--FIXME */
1270 * Skip to the next block first, so we can get the file, FIXME, should
1271 * be in get_file ...
1272 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1273 * Fixes bug where file size in tarfile is zero.
1275 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1276 DEBUG(0, ("Short file, bailing out...\n"));
1277 return;
1279 if (!get_file(finfo)) {
1280 DEBUG(0, ("Abandoning restore\n"));
1281 return;
1283 break;
1284 case '5':
1285 if (!get_dir(finfo)) {
1286 DEBUG(0, ("Abandoning restore \n"));
1287 return;
1289 break;
1290 case 'L':
1291 SAFE_FREE(longfilename);
1292 longfilename = get_longfilename(finfo);
1293 if (!longfilename) {
1294 DEBUG(0, ("abandoning restore\n"));
1295 return;
1297 DEBUG(5, ("Long file name: %s\n", longfilename));
1298 break;
1300 default:
1301 skip_file(finfo.size); /* Don't handle these yet */
1302 break;
1308 * samba interactive commands
1311 /****************************************************************************
1312 Blocksize command
1313 ***************************************************************************/
1315 int cmd_block(void)
1317 TALLOC_CTX *ctx = talloc_tos();
1318 char *buf;
1319 int block;
1321 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1322 DEBUG(0, ("blocksize <n>\n"));
1323 return 1;
1326 block=atoi(buf);
1327 if (block < 0 || block > 65535) {
1328 DEBUG(0, ("blocksize out of range"));
1329 return 1;
1332 blocksize=block;
1333 DEBUG(2,("blocksize is now %d\n", blocksize));
1334 return 0;
1337 /****************************************************************************
1338 command to set incremental / reset mode
1339 ***************************************************************************/
1341 int cmd_tarmode(void)
1343 TALLOC_CTX *ctx = talloc_tos();
1344 char *buf;
1346 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1347 if (strequal(buf, "full"))
1348 tar_inc=False;
1349 else if (strequal(buf, "inc"))
1350 tar_inc=True;
1351 else if (strequal(buf, "reset"))
1352 tar_reset=True;
1353 else if (strequal(buf, "noreset"))
1354 tar_reset=False;
1355 else if (strequal(buf, "system"))
1356 tar_system=True;
1357 else if (strequal(buf, "nosystem"))
1358 tar_system=False;
1359 else if (strequal(buf, "hidden"))
1360 tar_hidden=True;
1361 else if (strequal(buf, "nohidden"))
1362 tar_hidden=False;
1363 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1364 tar_noisy=True;
1365 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1366 tar_noisy=False;
1367 else
1368 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1369 TALLOC_FREE(buf);
1372 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1373 tar_inc ? "incremental" : "full",
1374 tar_system ? "system" : "nosystem",
1375 tar_hidden ? "hidden" : "nohidden",
1376 tar_reset ? "reset" : "noreset",
1377 tar_noisy ? "verbose" : "quiet"));
1378 return 0;
1381 /****************************************************************************
1382 Feeble attrib command
1383 ***************************************************************************/
1385 int cmd_setmode(void)
1387 TALLOC_CTX *ctx = talloc_tos();
1388 char *q;
1389 char *buf;
1390 char *fname = NULL;
1391 uint16 attra[2];
1392 int direct=1;
1394 attra[0] = attra[1] = 0;
1396 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1397 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1398 return 1;
1401 fname = talloc_asprintf(ctx,
1402 "%s%s",
1403 client_get_cur_dir(),
1404 buf);
1405 if (!fname) {
1406 return 1;
1409 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1410 q=buf;
1412 while(*q) {
1413 switch (*q++) {
1414 case '+':
1415 direct=1;
1416 break;
1417 case '-':
1418 direct=0;
1419 break;
1420 case 'r':
1421 attra[direct]|=FILE_ATTRIBUTE_READONLY;
1422 break;
1423 case 'h':
1424 attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1425 break;
1426 case 's':
1427 attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1428 break;
1429 case 'a':
1430 attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1431 break;
1432 default:
1433 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1434 return 1;
1439 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1440 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1441 return 1;
1444 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1445 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1446 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1447 return 0;
1451 Convert list of tokens to array; dependent on above routine.
1452 Uses the global cmd_ptr from above - bit of a hack.
1455 static char **toktocliplist(int *ctok, const char *sep)
1457 char *s=(char *)cmd_ptr;
1458 int ictok=0;
1459 char **ret, **iret;
1461 if (!sep)
1462 sep = " \t\n\r";
1464 while(*s && strchr_m(sep,*s))
1465 s++;
1467 /* nothing left? */
1468 if (!*s)
1469 return(NULL);
1471 do {
1472 ictok++;
1473 while(*s && (!strchr_m(sep,*s)))
1474 s++;
1475 while(*s && strchr_m(sep,*s))
1476 *s++=0;
1477 } while(*s);
1479 *ctok=ictok;
1480 s=(char *)cmd_ptr;
1482 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1483 return NULL;
1485 while(ictok--) {
1486 *iret++=s;
1487 if (ictok > 0) {
1488 while(*s++)
1490 while(!*s)
1491 s++;
1495 ret[*ctok] = NULL;
1496 return ret;
1499 /****************************************************************************
1500 Principal command for creating / extracting
1501 ***************************************************************************/
1503 int cmd_tar(void)
1505 TALLOC_CTX *ctx = talloc_tos();
1506 char *buf;
1507 char **argl = NULL;
1508 int argcl = 0;
1509 int ret;
1511 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1512 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1513 return 1;
1516 argl=toktocliplist(&argcl, NULL);
1517 if (!tar_parseargs(argcl, argl, buf, 0)) {
1518 SAFE_FREE(argl);
1519 return 1;
1522 ret = process_tar();
1523 SAFE_FREE(argl);
1524 return ret;
1527 /****************************************************************************
1528 Command line (option) version
1529 ***************************************************************************/
1531 int process_tar(void)
1533 TALLOC_CTX *ctx = talloc_tos();
1534 int rc = 0;
1535 initarbuf();
1536 switch(tar_type) {
1537 case 'x':
1539 #if 0
1540 do_tarput2();
1541 #else
1542 do_tarput();
1543 #endif
1544 SAFE_FREE(tarbuf);
1545 close(tarhandle);
1546 break;
1547 case 'r':
1548 case 'c':
1549 if (clipn && tar_excl) {
1550 int i;
1551 char *tarmac = NULL;
1553 for (i=0; i<clipn; i++) {
1554 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1556 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1557 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1560 if (strrchr_m(cliplist[i], '\\')) {
1561 char *p;
1562 char saved_char;
1563 char *saved_dir = talloc_strdup(ctx,
1564 client_get_cur_dir());
1565 if (!saved_dir) {
1566 return 1;
1569 if (*cliplist[i]=='\\') {
1570 tarmac = talloc_strdup(ctx,
1571 cliplist[i]);
1572 } else {
1573 tarmac = talloc_asprintf(ctx,
1574 "%s%s",
1575 client_get_cur_dir(),
1576 cliplist[i]);
1578 if (!tarmac) {
1579 return 1;
1582 * Strip off the last \\xxx
1583 * xxx element of tarmac to set
1584 * it as current directory.
1586 p = strrchr_m(tarmac, '\\');
1587 if (!p) {
1588 return 1;
1590 saved_char = p[1];
1591 p[1] = '\0';
1593 client_set_cur_dir(tarmac);
1596 * Restore the character we
1597 * just replaced to
1598 * put the pathname
1599 * back as it was.
1601 p[1] = saved_char;
1603 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1604 do_list(tarmac,attribute,do_tar, False, True);
1606 client_set_cur_dir(saved_dir);
1608 TALLOC_FREE(saved_dir);
1609 TALLOC_FREE(tarmac);
1610 } else {
1611 tarmac = talloc_asprintf(ctx,
1612 "%s%s",
1613 client_get_cur_dir(),
1614 cliplist[i]);
1615 if (!tarmac) {
1616 return 1;
1618 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1619 do_list(tarmac,attribute,do_tar, False, True);
1620 TALLOC_FREE(tarmac);
1623 } else {
1624 char *mask = talloc_asprintf(ctx,
1625 "%s\\*",
1626 client_get_cur_dir());
1627 if (!mask) {
1628 return 1;
1630 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1631 do_list(mask,attribute,do_tar,False, True);
1632 TALLOC_FREE(mask);
1635 if (ntarf) {
1636 dotareof(tarhandle);
1638 close(tarhandle);
1639 SAFE_FREE(tarbuf);
1641 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1642 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1643 break;
1646 if (must_free_cliplist) {
1647 int i;
1648 for (i = 0; i < clipn; ++i) {
1649 SAFE_FREE(cliplist[i]);
1651 SAFE_FREE(cliplist);
1652 cliplist = NULL;
1653 clipn = 0;
1654 must_free_cliplist = False;
1656 return rc;
1659 /****************************************************************************
1660 Find a token (filename) in a clip list
1661 ***************************************************************************/
1663 static int clipfind(char **aret, int ret, char *tok)
1665 if (aret==NULL)
1666 return 0;
1668 /* ignore leading slashes or dots in token */
1669 while(strchr_m("/\\.", *tok))
1670 tok++;
1672 while(ret--) {
1673 char *pkey=*aret++;
1675 /* ignore leading slashes or dots in list */
1676 while(strchr_m("/\\.", *pkey))
1677 pkey++;
1679 if (!strslashcmp(pkey, tok))
1680 return 1;
1682 return 0;
1685 /****************************************************************************
1686 Read list of files to include from the file and initialize cliplist
1687 accordingly.
1688 ***************************************************************************/
1690 static int read_inclusion_file(char *filename)
1692 XFILE *inclusion = NULL;
1693 char buf[PATH_MAX + 1];
1694 char *inclusion_buffer = NULL;
1695 int inclusion_buffer_size = 0;
1696 int inclusion_buffer_sofar = 0;
1697 char *p;
1698 char *tmpstr;
1699 int i;
1700 int error = 0;
1702 clipn = 0;
1703 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1704 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1705 /* XXX It would be better to include a reason for failure, but without
1706 * autoconf, it's hard to use strerror, sys_errlist, etc.
1708 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1709 return 0;
1712 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1713 if (inclusion_buffer == NULL) {
1714 inclusion_buffer_size = 1024;
1715 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1716 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1717 error = 1;
1718 break;
1722 if (buf[strlen(buf)-1] == '\n') {
1723 buf[strlen(buf)-1] = '\0';
1726 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1727 inclusion_buffer_size *= 2;
1728 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1729 if (!inclusion_buffer) {
1730 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1731 inclusion_buffer_size));
1732 error = 1;
1733 break;
1737 safe_strcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1738 inclusion_buffer_sofar += strlen(buf) + 1;
1739 clipn++;
1741 x_fclose(inclusion);
1743 if (! error) {
1744 /* Allocate an array of clipn + 1 char*'s for cliplist */
1745 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1746 if (cliplist == NULL) {
1747 DEBUG(0,("failure allocating memory for cliplist\n"));
1748 error = 1;
1749 } else {
1750 cliplist[clipn] = NULL;
1751 p = inclusion_buffer;
1752 for (i = 0; (! error) && (i < clipn); i++) {
1753 /* set current item to NULL so array will be null-terminated even if
1754 * malloc fails below. */
1755 cliplist[i] = NULL;
1756 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1757 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1758 error = 1;
1759 } else {
1760 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1761 cliplist[i] = tmpstr;
1762 if ((p = strchr_m(p, '\000')) == NULL) {
1763 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1764 abort();
1767 ++p;
1769 must_free_cliplist = True;
1773 SAFE_FREE(inclusion_buffer);
1774 if (error) {
1775 if (cliplist) {
1776 char **pp;
1777 /* We know cliplist is always null-terminated */
1778 for (pp = cliplist; *pp; ++pp) {
1779 SAFE_FREE(*pp);
1781 SAFE_FREE(cliplist);
1782 cliplist = NULL;
1783 must_free_cliplist = False;
1785 return 0;
1788 /* cliplist and its elements are freed at the end of process_tar. */
1789 return 1;
1792 /****************************************************************************
1793 Parse tar arguments. Sets tar_type, tar_excl, etc.
1794 ***************************************************************************/
1796 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1798 int newOptind = Optind;
1799 char tar_clipfl='\0';
1801 /* Reset back to defaults - could be from interactive version
1802 * reset mode and archive mode left as they are though
1804 tar_type='\0';
1805 tar_excl=True;
1806 dry_run=False;
1808 while (*Optarg) {
1809 switch(*Optarg++) {
1810 case 'c':
1811 tar_type='c';
1812 break;
1813 case 'x':
1814 if (tar_type=='c') {
1815 printf("Tar must be followed by only one of c or x.\n");
1816 return 0;
1818 tar_type='x';
1819 break;
1820 case 'b':
1821 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1822 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1823 return 0;
1824 } else {
1825 Optind++;
1826 newOptind++;
1828 break;
1829 case 'g':
1830 tar_inc=True;
1831 break;
1832 case 'N':
1833 if (Optind>=argc) {
1834 DEBUG(0,("Option N must be followed by valid file name\n"));
1835 return 0;
1836 } else {
1837 SMB_STRUCT_STAT stbuf;
1839 if (sys_stat(argv[Optind], &stbuf,
1840 false) == 0) {
1841 newer_than = convert_timespec_to_time_t(
1842 stbuf.st_ex_mtime);
1843 DEBUG(1,("Getting files newer than %s",
1844 time_to_asc(newer_than)));
1845 newOptind++;
1846 Optind++;
1847 } else {
1848 DEBUG(0,("Error setting newer-than time\n"));
1849 return 0;
1852 break;
1853 case 'a':
1854 tar_reset=True;
1855 break;
1856 case 'q':
1857 tar_noisy=False;
1858 break;
1859 case 'I':
1860 if (tar_clipfl) {
1861 DEBUG(0,("Only one of I,X,F must be specified\n"));
1862 return 0;
1864 tar_clipfl='I';
1865 break;
1866 case 'X':
1867 if (tar_clipfl) {
1868 DEBUG(0,("Only one of I,X,F must be specified\n"));
1869 return 0;
1871 tar_clipfl='X';
1872 break;
1873 case 'F':
1874 if (tar_clipfl) {
1875 DEBUG(0,("Only one of I,X,F must be specified\n"));
1876 return 0;
1878 tar_clipfl='F';
1879 break;
1880 case 'r':
1881 DEBUG(0, ("tar_re_search set\n"));
1882 tar_re_search = True;
1883 break;
1884 case 'n':
1885 if (tar_type == 'c') {
1886 DEBUG(0, ("dry_run set\n"));
1887 dry_run = True;
1888 } else {
1889 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1890 return 0;
1892 break;
1893 default:
1894 DEBUG(0,("Unknown tar option\n"));
1895 return 0;
1899 if (!tar_type) {
1900 printf("Option T must be followed by one of c or x.\n");
1901 return 0;
1904 /* tar_excl is true if cliplist lists files to be included.
1905 * Both 'I' and 'F' mean include. */
1906 tar_excl=tar_clipfl!='X';
1908 if (tar_clipfl=='F') {
1909 if (argc-Optind-1 != 1) {
1910 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1911 return 0;
1913 newOptind++;
1914 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1915 if (! read_inclusion_file(argv[Optind+1])) {
1916 return 0;
1918 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1919 char *tmpstr;
1920 char **tmplist;
1921 int clipcount;
1923 cliplist=argv+Optind+1;
1924 clipn=argc-Optind-1;
1925 clipcount = clipn;
1927 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1928 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1929 return 0;
1932 for (clipcount = 0; clipcount < clipn; clipcount++) {
1934 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1936 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1937 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1938 SAFE_FREE(tmplist);
1939 return 0;
1942 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1943 tmplist[clipcount] = tmpstr;
1944 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1946 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1949 cliplist = tmplist;
1950 must_free_cliplist = True;
1952 newOptind += clipn;
1955 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1956 /* Doing regular expression seaches not from an inclusion file. */
1957 clipn=argc-Optind-1;
1958 cliplist=argv+Optind+1;
1959 newOptind += clipn;
1962 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1963 /* Sets tar handle to either 0 or 1, as appropriate */
1964 tarhandle=(tar_type=='c');
1966 * Make sure that dbf points to stderr if we are using stdout for
1967 * tar output
1969 if (tarhandle == 1) {
1970 setup_logging("smbclient", DEBUG_STDERR);
1972 if (!argv[Optind]) {
1973 DEBUG(0,("Must specify tar filename\n"));
1974 return 0;
1976 if (!strcmp(argv[Optind], "-")) {
1977 newOptind++;
1980 } else {
1981 if (tar_type=='c' && dry_run) {
1982 tarhandle=-1;
1983 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1984 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1985 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1986 return(0);
1988 newOptind++;
1991 return newOptind;