vfs: Make function pointer names consistent. They all end in _fn
[Samba/gebeck_regimport.git] / source3 / client / clitar.c
blob594392672a6f876b417ec0390c622684725e2c01
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 char *cmd_ptr;
107 extern bool lowercase;
108 extern int get_total_time_ms;
109 extern int get_total_size;
111 static int blocksize=20;
112 static int tarhandle;
114 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
115 const char *amode, unsigned char ftype);
116 static NTSTATUS do_atar(const char *rname_in, char *lname,
117 struct file_info *finfo1);
118 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
119 const char *dir);
120 static void oct_it(uint64_t value, int ndgs, char *p);
121 static void fixtarname(char *tptr, const char *fp, size_t l);
122 static int dotarbuf(int f, char *b, int n);
123 static void dozerobuf(int f, int n);
124 static void dotareof(int f);
125 static void initarbuf(void);
127 /* restore functions */
128 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix);
129 static long unoct(char *p, int ndgs);
130 static void do_tarput(void);
131 static void unfixtarname(char *tptr, char *fp, int l, bool first);
134 * tar specific utitlities
137 /****************************************************************************
138 Write a tar header to buffer
139 ****************************************************************************/
141 static void writetarheader(int f, const char *aname, uint64_t size, time_t mtime,
142 const char *amode, unsigned char ftype)
144 union hblock hb;
145 int i, chk, l;
146 char *jp;
148 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %.0f, Name = %s\n", ftype, (double)size, aname));
150 memset(hb.dummy, 0, sizeof(hb.dummy));
152 l=strlen(aname);
153 /* We will be prepending a '.' in fixtarheader so use +2 to
154 * take care of the . and terminating zero. JRA.
156 if (l+2 >= NAMSIZ) {
157 /* write a GNU tar style long header */
158 char *b;
159 b = (char *)SMB_MALLOC(l+TBLOCK+100);
160 if (!b) {
161 DEBUG(0,("out of memory\n"));
162 exit(1);
164 writetarheader(f, "/./@LongLink", l+2, 0, " 0 \0", 'L');
165 memset(b, 0, l+TBLOCK+100);
166 fixtarname(b, aname, l+2);
167 i = strlen(b)+1;
168 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b, (int)strlen(b)));
169 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
170 SAFE_FREE(b);
173 fixtarname(hb.dbuf.name, aname, (l+2 >= NAMSIZ) ? NAMSIZ : l + 2);
175 if (lowercase)
176 strlower_m(hb.dbuf.name);
178 /* write out a "standard" tar format header */
180 hb.dbuf.name[NAMSIZ-1]='\0';
181 strlcpy(hb.dbuf.mode, amode ? amode : "", sizeof(hb.dbuf.mode));
182 oct_it((uint64_t)0, 8, hb.dbuf.uid);
183 oct_it((uint64_t)0, 8, hb.dbuf.gid);
184 oct_it((uint64_t) size, 13, hb.dbuf.size);
185 if (size > (uint64_t)077777777777LL) {
186 /* This is a non-POSIX compatible extention to store files
187 greater than 8GB. */
189 memset(hb.dbuf.size, 0, 4);
190 hb.dbuf.size[0]=128;
191 for (i = 8, jp=(char*)&size; i; i--)
192 hb.dbuf.size[i+3] = *(jp++);
194 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
195 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
196 memset(hb.dbuf.linkname, 0, NAMSIZ);
197 hb.dbuf.linkflag=ftype;
199 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
200 chk+=(0xFF & *jp++);
202 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
203 hb.dbuf.chksum[6] = '\0';
205 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
208 /****************************************************************************
209 Read a tar header into a hblock structure, and validate
210 ***************************************************************************/
212 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
214 long chk, fchk;
215 int i;
216 char *jp;
219 * read in a "standard" tar format header - we're not that interested
220 * in that many fields, though
223 /* check the checksum */
224 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
225 chk+=(0xFF & *jp++);
227 if (chk == 0)
228 return chk;
230 /* compensate for blanks in chksum header */
231 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
232 chk-=(0xFF & *jp++);
234 chk += ' ' * sizeof(hb->dbuf.chksum);
236 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
238 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
239 chk, fchk, hb->dbuf.chksum));
241 if (fchk != chk) {
242 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
243 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
244 return -1;
247 if ((finfo->name = SMB_MALLOC(strlen(prefix) + strlen(hb -> dbuf.name) + 4)) == NULL) {
248 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
249 return(-1);
252 strlcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 4);
254 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
255 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
256 strlen(hb->dbuf.name) + 1, True);
258 /* can't handle some links at present */
259 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
260 if (hb->dbuf.linkflag == 0) {
261 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
262 finfo->name));
263 } else {
264 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
265 /* Do nothing here at the moment. do_tarput will handle this
266 as long as the longlink gets back to it, as it has to advance
267 the buffer pointer, etc */
268 } else {
269 DEBUG(0, ("this tar file appears to contain some kind \
270 of link other than a GNUtar Longlink - ignoring\n"));
271 return -2;
276 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
277 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
278 finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
279 } else {
280 finfo->mode=0; /* we don't care about mode at the moment, we'll
281 * just make it a regular file */
285 * Bug fix by richard@sj.co.uk
287 * REC: restore times correctly (as does tar)
288 * We only get the modification time of the file; set the creation time
289 * from the mod. time, and the access time to current time
291 finfo->mtime_ts = finfo->ctime_ts =
292 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
293 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
294 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
296 return True;
299 /****************************************************************************
300 Write out the tar buffer to tape or wherever
301 ****************************************************************************/
303 static int dotarbuf(int f, char *b, int n)
305 int fail=1, writ=n;
307 if (dry_run) {
308 return writ;
310 /* This routine and the next one should be the only ones that do write()s */
311 if (tp + n >= tbufsiz) {
312 int diff;
314 diff=tbufsiz-tp;
315 memcpy(tarbuf + tp, b, diff);
316 fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
317 n-=diff;
318 b+=diff;
319 tp=0;
321 while (n >= tbufsiz) {
322 fail=fail && (1 + sys_write(f, b, tbufsiz));
323 n-=tbufsiz;
324 b+=tbufsiz;
328 if (n>0) {
329 memcpy(tarbuf+tp, b, n);
330 tp+=n;
333 return(fail ? writ : 0);
336 /****************************************************************************
337 Write zeros to buffer / tape
338 ****************************************************************************/
340 static void dozerobuf(int f, int n)
342 /* short routine just to write out n zeros to buffer -
343 * used to round files to nearest block
344 * and to do tar EOFs */
346 if (dry_run)
347 return;
349 if (n+tp >= tbufsiz) {
350 memset(tarbuf+tp, 0, tbufsiz-tp);
351 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
352 DEBUG(0, ("dozerobuf: sys_write fail\n"));
353 return;
355 memset(tarbuf, 0, (tp+=n-tbufsiz));
356 } else {
357 memset(tarbuf+tp, 0, n);
358 tp+=n;
362 /****************************************************************************
363 Malloc tape buffer
364 ****************************************************************************/
366 static void initarbuf(void)
368 /* initialize tar buffer */
369 tbufsiz=blocksize*TBLOCK;
370 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
372 /* reset tar buffer pointer and tar file counter and total dumped */
373 tp=0; ntarf=0; ttarf=0;
376 /****************************************************************************
377 Write two zero blocks at end of file
378 ****************************************************************************/
380 static void dotareof(int f)
382 SMB_STRUCT_STAT stbuf;
383 /* Two zero blocks at end of file, write out full buffer */
385 if (dry_run)
386 return;
388 (void) dozerobuf(f, TBLOCK);
389 (void) dozerobuf(f, TBLOCK);
391 if (sys_fstat(f, &stbuf, false) == -1) {
392 DEBUG(0, ("Couldn't stat file handle\n"));
393 return;
396 /* Could be a pipe, in which case S_ISREG should fail,
397 * and we should write out at full size */
398 if (tp > 0) {
399 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
400 if (sys_write(f, tarbuf, towrite) != towrite) {
401 DEBUG(0,("dotareof: sys_write fail\n"));
406 /****************************************************************************
407 (Un)mangle DOS pathname, make nonabsolute
408 ****************************************************************************/
410 static void fixtarname(char *tptr, const char *fp, size_t l)
412 /* add a '.' to start of file name, convert from ugly dos \'s in path
413 * to lovely unix /'s :-} */
414 *tptr++='.';
415 l--;
417 StrnCpy(tptr, fp, l-1);
418 string_replace(tptr, '\\', '/');
421 /****************************************************************************
422 Convert from decimal to octal string
423 ****************************************************************************/
425 static void oct_it (uint64_t value, int ndgs, char *p)
427 /* Converts long to octal string, pads with leading zeros */
429 /* skip final null, but do final space */
430 --ndgs;
431 p[--ndgs] = ' ';
433 /* Loop does at least one digit */
434 do {
435 p[--ndgs] = '0' + (char) (value & 7);
436 value >>= 3;
437 } while (ndgs > 0 && value != 0);
439 /* Do leading zeros */
440 while (ndgs > 0)
441 p[--ndgs] = '0';
444 /****************************************************************************
445 Convert from octal string to long
446 ***************************************************************************/
448 static long unoct(char *p, int ndgs)
450 long value=0;
451 /* Converts octal string to long, ignoring any non-digit */
453 while (--ndgs) {
454 if (isdigit((int)*p))
455 value = (value << 3) | (long) (*p - '0');
457 p++;
460 return value;
463 /****************************************************************************
464 Compare two strings in a slash insensitive way, allowing s1 to match s2
465 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
466 a file in any subdirectory of s1, declare a match.
467 ***************************************************************************/
469 static int strslashcmp(char *s1, char *s2)
471 char *s1_0=s1;
473 while(*s1 && *s2 && (*s1 == *s2 || tolower_m(*s1) == tolower_m(*s2) ||
474 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
475 s1++; s2++;
478 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
479 string of s2.
481 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
482 return 0;
484 /* ignore trailing slash on s1 */
485 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
486 return 0;
488 /* check for s1 is an "initial" string of s2 */
489 if ((*s2 == '/' || *s2 == '\\') && !*s1)
490 return 0;
492 return *s1-*s2;
495 /****************************************************************************
496 Ensure a remote path exists (make if necessary)
497 ***************************************************************************/
499 static bool ensurepath(const char *fname)
501 /* *must* be called with buffer ready malloc'ed */
502 /* ensures path exists */
504 char *partpath, *ffname;
505 size_t fnamelen = strlen(fname)+1;
506 const char *p=fname;
507 char *basehack;
508 char *saveptr;
509 NTSTATUS status;
511 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
513 partpath = SMB_MALLOC(fnamelen);
514 ffname = SMB_MALLOC(fnamelen);
516 if ((partpath == NULL) || (ffname == NULL)){
517 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
518 SAFE_FREE(partpath);
519 SAFE_FREE(ffname);
520 return(False);
523 *partpath = 0;
525 /* fname copied to ffname so can strtok_r */
527 strlcpy(ffname, fname, fnamelen);
529 /* do a `basename' on ffname, so don't try and make file name directory */
530 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
531 SAFE_FREE(partpath);
532 SAFE_FREE(ffname);
533 return True;
534 } else {
535 *basehack='\0';
538 p=strtok_r(ffname, "\\", &saveptr);
540 while (p) {
541 strlcat(partpath, p, fnamelen);
543 status = cli_chkpath(cli, partpath);
544 if (!NT_STATUS_IS_OK(status)) {
545 status = cli_mkdir(cli, partpath);
546 if (!NT_STATUS_IS_OK(status)) {
547 SAFE_FREE(partpath);
548 SAFE_FREE(ffname);
549 DEBUG(0, ("Error mkdir %s\n", nt_errstr(status)));
550 return False;
551 } else {
552 DEBUG(3, ("mkdirhiering %s\n", partpath));
556 strlcat(partpath, "\\", fnamelen);
557 p = strtok_r(NULL, "/\\", &saveptr);
560 SAFE_FREE(partpath);
561 SAFE_FREE(ffname);
562 return True;
565 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
567 int berr= 0;
568 int bytestowrite;
570 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
571 memset(buf, 0, (size_t)bufsize);
572 while( !berr && padsize > 0 ) {
573 bytestowrite= (int)MIN(bufsize, padsize);
574 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
575 padsize -= bytestowrite;
578 return berr;
581 static void do_setrattr(char *name, uint16 attr, int set)
583 uint16 oldattr;
584 NTSTATUS status;
586 if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
587 return;
590 if (set == ATTRSET) {
591 attr |= oldattr;
592 } else {
593 attr = oldattr & ~attr;
596 status = cli_setatr(cli, name, attr, 0);
597 if (!NT_STATUS_IS_OK(status)) {
598 DEBUG(1, ("setatr failed: %s\n", nt_errstr(status)));
602 /****************************************************************************
603 append one remote file to the tar file
604 ***************************************************************************/
606 static NTSTATUS do_atar(const char *rname_in, char *lname,
607 struct file_info *finfo1)
609 uint16_t fnum = (uint16_t)-1;
610 uint64_t nread=0;
611 char ftype;
612 file_info2 finfo;
613 bool shallitime=True;
614 char *data = NULL;
615 int read_size = 65520;
616 size_t datalen=0;
617 char *rname = NULL;
618 TALLOC_CTX *ctx = talloc_stackframe();
619 NTSTATUS status = NT_STATUS_OK;
620 struct timespec tp_start;
622 clock_gettime_mono(&tp_start);
624 data = SMB_MALLOC_ARRAY(char, read_size);
625 if (!data) {
626 DEBUG(0,("do_atar: out of memory.\n"));
627 status = NT_STATUS_NO_MEMORY;
628 goto cleanup;
631 ftype = '0'; /* An ordinary file ... */
633 ZERO_STRUCT(finfo);
635 finfo.size = finfo1 -> size;
636 finfo.mode = finfo1 -> mode;
637 finfo.uid = finfo1 -> uid;
638 finfo.gid = finfo1 -> gid;
639 finfo.mtime_ts = finfo1 -> mtime_ts;
640 finfo.atime_ts = finfo1 -> atime_ts;
641 finfo.ctime_ts = finfo1 -> ctime_ts;
643 if (dry_run) {
644 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
645 (double)finfo.size));
646 shallitime=0;
647 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
648 ntarf++;
649 goto cleanup;
652 rname = clean_name(ctx, rname_in);
653 if (!rname) {
654 status = NT_STATUS_NO_MEMORY;
655 goto cleanup;
658 status = cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum);
659 if (!NT_STATUS_IS_OK(status)) {
660 DEBUG(0,("%s opening remote file %s (%s)\n",
661 nt_errstr(status),rname, client_get_cur_dir()));
662 goto cleanup;
665 finfo.name = smb_xstrdup(rname);
666 if (finfo.name == NULL) {
667 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
668 status = NT_STATUS_NO_MEMORY;
669 goto cleanup;
672 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
674 if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE)) {
675 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
676 shallitime=0;
677 } else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM)) {
678 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
679 shallitime=0;
680 } else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN)) {
681 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
682 shallitime=0;
683 } else {
684 bool wrote_tar_header = False;
686 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
687 finfo.name, (double)finfo.size, lname));
689 do {
691 DEBUG(3,("nread=%.0f\n",(double)nread));
693 status = cli_read(cli, fnum, data, nread,
694 read_size, &datalen);
695 if (!NT_STATUS_IS_OK(status)) {
696 DEBUG(0,("Error reading file %s : %s\n",
697 rname, nt_errstr(status)));
698 break;
701 nread += datalen;
703 /* Only if the first read succeeds, write out the tar header. */
704 if (!wrote_tar_header) {
705 /* write a tar header, don't bother with mode - just set to 100644 */
706 writetarheader(tarhandle, rname, finfo.size,
707 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
708 wrote_tar_header = True;
711 /* if file size has increased since we made file size query, truncate
712 read so tar header for this file will be correct.
715 if (nread > finfo.size) {
716 datalen -= nread - finfo.size;
717 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
718 finfo.name, (double)finfo.size));
721 /* add received bits of file to buffer - dotarbuf will
722 * write out in 512 byte intervals */
724 if (dotarbuf(tarhandle,data,datalen) != datalen) {
725 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
726 status = map_nt_error_from_unix(errno);
727 break;
730 if ( (datalen == 0) && (finfo.size != 0) ) {
731 status = NT_STATUS_UNSUCCESSFUL;
732 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
733 break;
736 datalen=0;
737 } while ( nread < finfo.size );
739 if (wrote_tar_header) {
740 /* pad tar file with zero's if we couldn't get entire file */
741 if (nread < finfo.size) {
742 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
743 (double)finfo.size, (int)nread));
744 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) {
745 status = map_nt_error_from_unix(errno);
746 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
750 /* round tar file to nearest block */
751 if (finfo.size % TBLOCK)
752 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
754 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
755 ntarf++;
756 } else {
757 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
758 shallitime=0;
759 status = NT_STATUS_UNSUCCESSFUL;
763 cli_close(cli, fnum);
764 fnum = -1;
766 if (shallitime) {
767 struct timespec tp_end;
768 int this_time;
770 /* if shallitime is true then we didn't skip */
771 if (tar_reset && !dry_run)
772 (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
774 clock_gettime_mono(&tp_end);
775 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000;
776 get_total_time_ms += this_time;
777 get_total_size += finfo.size;
779 if (tar_noisy) {
780 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
781 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
782 finfo.name));
785 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
786 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
787 finfo.size / MAX(0.001, (1.024*this_time)),
788 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
791 cleanup:
793 if (fnum != (uint16_t)-1) {
794 cli_close(cli, fnum);
795 fnum = -1;
797 TALLOC_FREE(ctx);
798 SAFE_FREE(data);
799 return status;
802 /****************************************************************************
803 Append single file to tar file (or not)
804 ***************************************************************************/
806 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
807 const char *dir)
809 TALLOC_CTX *ctx = talloc_stackframe();
810 NTSTATUS status = NT_STATUS_OK;
812 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
813 return NT_STATUS_OK;
815 /* Is it on the exclude list ? */
816 if (!tar_excl && clipn) {
817 char *exclaim;
819 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
821 exclaim = talloc_asprintf(ctx,
822 "%s\\%s",
823 client_get_cur_dir(),
824 finfo->name);
825 if (!exclaim) {
826 return NT_STATUS_NO_MEMORY;
829 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
831 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
832 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
833 DEBUG(3,("Skipping file %s\n", exclaim));
834 TALLOC_FREE(exclaim);
835 return NT_STATUS_OK;
837 TALLOC_FREE(exclaim);
840 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
841 char *saved_curdir = NULL;
842 char *new_cd = NULL;
843 char *mtar_mask = NULL;
845 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
846 if (!saved_curdir) {
847 return NT_STATUS_NO_MEMORY;
850 DEBUG(5, ("strlen(cur_dir)=%d, \
851 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
852 (int)strlen(saved_curdir),
853 (int)strlen(finfo->name), finfo->name, saved_curdir));
855 new_cd = talloc_asprintf(ctx,
856 "%s%s\\",
857 client_get_cur_dir(),
858 finfo->name);
859 if (!new_cd) {
860 return NT_STATUS_NO_MEMORY;
862 client_set_cur_dir(new_cd);
864 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
866 /* write a tar directory, don't bother with mode - just
867 * set it to 40755 */
868 writetarheader(tarhandle, client_get_cur_dir(), 0,
869 finfo->mtime_ts.tv_sec, "040755 \0", '5');
870 if (tar_noisy) {
871 DEBUG(0,(" directory %s\n",
872 client_get_cur_dir()));
874 ntarf++; /* Make sure we have a file on there */
875 mtar_mask = talloc_asprintf(ctx,
876 "%s*",
877 client_get_cur_dir());
878 if (!mtar_mask) {
879 return NT_STATUS_NO_MEMORY;
881 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
882 status = do_list(mtar_mask, attribute, do_tar, False, True);
883 client_set_cur_dir(saved_curdir);
884 TALLOC_FREE(saved_curdir);
885 TALLOC_FREE(new_cd);
886 TALLOC_FREE(mtar_mask);
887 } else {
888 char *rname = talloc_asprintf(ctx,
889 "%s%s",
890 client_get_cur_dir(),
891 finfo->name);
892 if (!rname) {
893 return NT_STATUS_NO_MEMORY;
895 status = do_atar(rname,finfo->name,finfo);
896 TALLOC_FREE(rname);
898 return status;
901 /****************************************************************************
902 Convert from UNIX to DOS file names
903 ***************************************************************************/
905 static void unfixtarname(char *tptr, char *fp, int l, bool first)
907 /* remove '.' from start of file name, convert from unix /'s to
908 * dos \'s in path. Kill any absolute path names. But only if first!
911 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
913 if (first) {
914 if (*fp == '.') {
915 fp++;
916 l--;
918 if (*fp == '\\' || *fp == '/') {
919 fp++;
920 l--;
922 if (l <= 0) {
923 return;
927 strlcpy(tptr, fp, l);
928 string_replace(tptr, '/', '\\');
931 /****************************************************************************
932 Move to the next block in the buffer, which may mean read in another set of
933 blocks. FIXME, we should allow more than one block to be skipped.
934 ****************************************************************************/
936 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
938 int bufread, total = 0;
940 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
941 *bufferp += TBLOCK;
942 total = TBLOCK;
944 if (*bufferp >= (ltarbuf + bufsiz)) {
946 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
949 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
950 * Fixes bug where read can return short if coming from
951 * a pipe.
954 bufread = read(tarhandle, ltarbuf, bufsiz);
955 total = bufread;
957 while (total < bufsiz) {
958 if (bufread < 0) { /* An error, return false */
959 return (total > 0 ? -2 : bufread);
961 if (bufread == 0) {
962 if (total <= 0) {
963 return -2;
965 break;
967 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
968 total += bufread;
971 DEBUG(5, ("Total bytes read ... %i\n", total));
973 *bufferp = ltarbuf;
976 return(total);
979 /* Skip a file, even if it includes a long file name? */
980 static int skip_file(int skipsize)
982 int dsize = skipsize;
984 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
986 /* FIXME, we should skip more than one block at a time */
988 while (dsize > 0) {
989 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
990 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
991 return(False);
993 dsize -= TBLOCK;
996 return(True);
999 /*************************************************************
1000 Get a file from the tar file and store it.
1001 When this is called, tarbuf already contains the first
1002 file block. This is a bit broken & needs fixing.
1003 **************************************************************/
1005 static int get_file(file_info2 finfo)
1007 uint16_t fnum = (uint16_t) -1;
1008 int pos = 0, dsize = 0, bpos = 0;
1009 uint64_t rsize = 0;
1010 NTSTATUS status;
1012 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1014 if (!ensurepath(finfo.name)) {
1015 DEBUG(0, ("abandoning restore\n"));
1016 return False;
1019 status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1020 if (!NT_STATUS_IS_OK(status)) {
1021 DEBUG(0, ("abandoning restore\n"));
1022 return False;
1025 /* read the blocks from the tar file and write to the remote file */
1027 rsize = finfo.size; /* This is how much to write */
1029 while (rsize > 0) {
1031 /* We can only write up to the end of the buffer */
1032 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1033 dsize = MIN(dsize, rsize); /* Should be only what is left */
1034 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1036 status = cli_writeall(cli, fnum, 0,
1037 (uint8_t *)(buffer_p + bpos), pos,
1038 dsize, NULL);
1039 if (!NT_STATUS_IS_OK(status)) {
1040 DEBUG(0, ("Error writing remote file: %s\n",
1041 nt_errstr(status)));
1042 return 0;
1045 rsize -= dsize;
1046 pos += dsize;
1048 /* Now figure out how much to move in the buffer */
1050 /* FIXME, we should skip more than one block at a time */
1052 /* First, skip any initial part of the part written that is left over */
1053 /* from the end of the first TBLOCK */
1055 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1056 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1057 bpos = 0;
1059 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1060 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1061 return False;
1066 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1067 * If the file being extracted is an exact multiple of
1068 * TBLOCK bytes then we don't want to extract the next
1069 * block from the tarfile here, as it will be done in
1070 * the caller of get_file().
1073 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1074 ((rsize == 0) && (dsize > TBLOCK))) {
1076 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1077 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1078 return False;
1081 dsize -= TBLOCK;
1083 bpos = dsize;
1086 /* Now close the file ... */
1087 status = cli_close(cli, fnum);
1088 if (!NT_STATUS_IS_OK(status)) {
1089 DEBUG(0, ("Error %s closing remote file\n",
1090 nt_errstr(status)));
1091 return(False);
1094 /* Now we update the creation date ... */
1095 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1097 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1098 if (tar_real_noisy) {
1099 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1100 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1104 ntarf++;
1105 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1106 return(True);
1109 /* Create a directory. We just ensure that the path exists and return as there
1110 is no file associated with a directory
1112 static int get_dir(file_info2 finfo)
1114 DEBUG(0, ("restore directory %s\n", finfo.name));
1116 if (!ensurepath(finfo.name)) {
1117 DEBUG(0, ("Problems creating directory\n"));
1118 return(False);
1120 ntarf++;
1121 return(True);
1124 /* Get a file with a long file name ... first file has file name, next file
1125 has the data. We only want the long file name, as the loop in do_tarput
1126 will deal with the rest.
1128 static char *get_longfilename(file_info2 finfo)
1130 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1131 * header call. */
1132 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1133 char *longname = (char *)SMB_MALLOC(namesize);
1134 int offset = 0, left = finfo.size;
1135 bool first = True;
1137 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1138 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1140 if (longname == NULL) {
1141 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1142 return(NULL);
1145 /* First, add cur_dir to the long file name */
1147 if (strlen(client_get_cur_dir()) > 0) {
1148 strncpy(longname, client_get_cur_dir(), namesize);
1149 offset = strlen(client_get_cur_dir());
1152 /* Loop through the blocks picking up the name */
1154 while (left > 0) {
1155 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1156 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1157 SAFE_FREE(longname);
1158 return(NULL);
1161 unfixtarname(longname + offset, buffer_p,
1162 namesize - offset, first--);
1163 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1165 offset += TBLOCK;
1166 left -= TBLOCK;
1169 return(longname);
1172 static void do_tarput(void)
1174 file_info2 finfo;
1175 struct timespec tp_start;
1176 char *longfilename = NULL, linkflag;
1177 int skip = False;
1179 ZERO_STRUCT(finfo);
1181 clock_gettime_mono(&tp_start);
1182 DEBUG(5, ("RJS do_tarput called ...\n"));
1184 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1186 /* Now read through those files ... */
1187 while (True) {
1188 /* Get us to the next block, or the first block first time around */
1189 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1190 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1191 SAFE_FREE(longfilename);
1192 return;
1195 DEBUG(5, ("Reading the next header ...\n"));
1197 switch (readtarheader((union hblock *) buffer_p,
1198 &finfo, client_get_cur_dir())) {
1199 case -2: /* Hmm, not good, but not fatal */
1200 DEBUG(0, ("Skipping %s...\n", finfo.name));
1201 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1202 DEBUG(0, ("Short file, bailing out...\n"));
1203 SAFE_FREE(longfilename);
1204 return;
1206 break;
1208 case -1:
1209 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1210 SAFE_FREE(longfilename);
1211 return;
1213 case 0: /* chksum is zero - looks like an EOF */
1214 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1215 SAFE_FREE(longfilename);
1216 return; /* Hmmm, bad here ... */
1218 default:
1219 /* No action */
1220 break;
1223 /* Now, do we have a long file name? */
1224 if (longfilename != NULL) {
1225 SAFE_FREE(finfo.name); /* Free the space already allocated */
1226 finfo.name = longfilename;
1227 longfilename = NULL;
1230 /* Well, now we have a header, process the file ... */
1231 /* Should we skip the file? We have the long name as well here */
1232 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1233 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1235 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1236 if (skip) {
1237 skip_file(finfo.size);
1238 continue;
1241 /* We only get this far if we should process the file */
1242 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1243 switch (linkflag) {
1244 case '0': /* Should use symbolic names--FIXME */
1246 * Skip to the next block first, so we can get the file, FIXME, should
1247 * be in get_file ...
1248 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1249 * Fixes bug where file size in tarfile is zero.
1251 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1252 DEBUG(0, ("Short file, bailing out...\n"));
1253 return;
1255 if (!get_file(finfo)) {
1256 DEBUG(0, ("Abandoning restore\n"));
1257 return;
1259 break;
1260 case '5':
1261 if (!get_dir(finfo)) {
1262 DEBUG(0, ("Abandoning restore \n"));
1263 return;
1265 break;
1266 case 'L':
1267 SAFE_FREE(longfilename);
1268 longfilename = get_longfilename(finfo);
1269 if (!longfilename) {
1270 DEBUG(0, ("abandoning restore\n"));
1271 return;
1273 DEBUG(5, ("Long file name: %s\n", longfilename));
1274 break;
1276 default:
1277 skip_file(finfo.size); /* Don't handle these yet */
1278 break;
1284 * samba interactive commands
1287 /****************************************************************************
1288 Blocksize command
1289 ***************************************************************************/
1291 int cmd_block(void)
1293 TALLOC_CTX *ctx = talloc_tos();
1294 char *buf;
1295 int block;
1297 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1298 DEBUG(0, ("blocksize <n>\n"));
1299 return 1;
1302 block=atoi(buf);
1303 if (block < 0 || block > 65535) {
1304 DEBUG(0, ("blocksize out of range"));
1305 return 1;
1308 blocksize=block;
1309 DEBUG(2,("blocksize is now %d\n", blocksize));
1310 return 0;
1313 /****************************************************************************
1314 command to set incremental / reset mode
1315 ***************************************************************************/
1317 int cmd_tarmode(void)
1319 TALLOC_CTX *ctx = talloc_tos();
1320 char *buf;
1322 while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1323 if (strequal(buf, "full"))
1324 tar_inc=False;
1325 else if (strequal(buf, "inc"))
1326 tar_inc=True;
1327 else if (strequal(buf, "reset"))
1328 tar_reset=True;
1329 else if (strequal(buf, "noreset"))
1330 tar_reset=False;
1331 else if (strequal(buf, "system"))
1332 tar_system=True;
1333 else if (strequal(buf, "nosystem"))
1334 tar_system=False;
1335 else if (strequal(buf, "hidden"))
1336 tar_hidden=True;
1337 else if (strequal(buf, "nohidden"))
1338 tar_hidden=False;
1339 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1340 tar_noisy=True;
1341 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1342 tar_noisy=False;
1343 else
1344 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1345 TALLOC_FREE(buf);
1348 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1349 tar_inc ? "incremental" : "full",
1350 tar_system ? "system" : "nosystem",
1351 tar_hidden ? "hidden" : "nohidden",
1352 tar_reset ? "reset" : "noreset",
1353 tar_noisy ? "verbose" : "quiet"));
1354 return 0;
1357 /****************************************************************************
1358 Feeble attrib command
1359 ***************************************************************************/
1361 int cmd_setmode(void)
1363 TALLOC_CTX *ctx = talloc_tos();
1364 char *q;
1365 char *buf;
1366 char *fname = NULL;
1367 uint16 attra[2];
1368 int direct=1;
1370 attra[0] = attra[1] = 0;
1372 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1373 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1374 return 1;
1377 fname = talloc_asprintf(ctx,
1378 "%s%s",
1379 client_get_cur_dir(),
1380 buf);
1381 if (!fname) {
1382 return 1;
1385 while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1386 q=buf;
1388 while(*q) {
1389 switch (*q++) {
1390 case '+':
1391 direct=1;
1392 break;
1393 case '-':
1394 direct=0;
1395 break;
1396 case 'r':
1397 attra[direct]|=FILE_ATTRIBUTE_READONLY;
1398 break;
1399 case 'h':
1400 attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1401 break;
1402 case 's':
1403 attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1404 break;
1405 case 'a':
1406 attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1407 break;
1408 default:
1409 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1410 return 1;
1415 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1416 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1417 return 1;
1420 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1421 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1422 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1423 return 0;
1427 Convert list of tokens to array; dependent on above routine.
1428 Uses the global cmd_ptr from above - bit of a hack.
1431 static char **toktocliplist(int *ctok, const char *sep)
1433 char *s=(char *)cmd_ptr;
1434 int ictok=0;
1435 char **ret, **iret;
1437 if (!sep)
1438 sep = " \t\n\r";
1440 while(*s && strchr_m(sep,*s))
1441 s++;
1443 /* nothing left? */
1444 if (!*s)
1445 return(NULL);
1447 do {
1448 ictok++;
1449 while(*s && (!strchr_m(sep,*s)))
1450 s++;
1451 while(*s && strchr_m(sep,*s))
1452 *s++=0;
1453 } while(*s);
1455 *ctok=ictok;
1456 s=(char *)cmd_ptr;
1458 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1459 return NULL;
1461 while(ictok--) {
1462 *iret++=s;
1463 if (ictok > 0) {
1464 while(*s++)
1466 while(!*s)
1467 s++;
1471 ret[*ctok] = NULL;
1472 return ret;
1475 /****************************************************************************
1476 Principal command for creating / extracting
1477 ***************************************************************************/
1479 int cmd_tar(void)
1481 TALLOC_CTX *ctx = talloc_tos();
1482 char *buf;
1483 char **argl = NULL;
1484 int argcl = 0;
1485 int ret;
1487 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1488 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1489 return 1;
1492 argl=toktocliplist(&argcl, NULL);
1493 if (!tar_parseargs(argcl, argl, buf, 0)) {
1494 SAFE_FREE(argl);
1495 return 1;
1498 ret = process_tar();
1499 SAFE_FREE(argl);
1500 return ret;
1503 /****************************************************************************
1504 Command line (option) version
1505 ***************************************************************************/
1507 int process_tar(void)
1509 TALLOC_CTX *ctx = talloc_tos();
1510 int rc = 0;
1511 initarbuf();
1512 switch(tar_type) {
1513 case 'x':
1515 #if 0
1516 do_tarput2();
1517 #else
1518 do_tarput();
1519 #endif
1520 SAFE_FREE(tarbuf);
1521 close(tarhandle);
1522 break;
1523 case 'r':
1524 case 'c':
1525 if (clipn && tar_excl) {
1526 int i;
1527 char *tarmac = NULL;
1529 for (i=0; i<clipn; i++) {
1530 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1532 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1533 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1536 if (strrchr_m(cliplist[i], '\\')) {
1537 char *p;
1538 char saved_char;
1539 char *saved_dir = talloc_strdup(ctx,
1540 client_get_cur_dir());
1541 if (!saved_dir) {
1542 return 1;
1545 if (*cliplist[i]=='\\') {
1546 tarmac = talloc_strdup(ctx,
1547 cliplist[i]);
1548 } else {
1549 tarmac = talloc_asprintf(ctx,
1550 "%s%s",
1551 client_get_cur_dir(),
1552 cliplist[i]);
1554 if (!tarmac) {
1555 return 1;
1558 * Strip off the last \\xxx
1559 * xxx element of tarmac to set
1560 * it as current directory.
1562 p = strrchr_m(tarmac, '\\');
1563 if (!p) {
1564 return 1;
1566 saved_char = p[1];
1567 p[1] = '\0';
1569 client_set_cur_dir(tarmac);
1572 * Restore the character we
1573 * just replaced to
1574 * put the pathname
1575 * back as it was.
1577 p[1] = saved_char;
1579 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1580 do_list(tarmac,attribute,do_tar, False, True);
1582 client_set_cur_dir(saved_dir);
1584 TALLOC_FREE(saved_dir);
1585 TALLOC_FREE(tarmac);
1586 } else {
1587 tarmac = talloc_asprintf(ctx,
1588 "%s%s",
1589 client_get_cur_dir(),
1590 cliplist[i]);
1591 if (!tarmac) {
1592 return 1;
1594 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1595 do_list(tarmac,attribute,do_tar, False, True);
1596 TALLOC_FREE(tarmac);
1599 } else {
1600 char *mask = talloc_asprintf(ctx,
1601 "%s\\*",
1602 client_get_cur_dir());
1603 if (!mask) {
1604 return 1;
1606 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1607 do_list(mask,attribute,do_tar,False, True);
1608 TALLOC_FREE(mask);
1611 if (ntarf) {
1612 dotareof(tarhandle);
1614 close(tarhandle);
1615 SAFE_FREE(tarbuf);
1617 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1618 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1619 break;
1622 if (must_free_cliplist) {
1623 int i;
1624 for (i = 0; i < clipn; ++i) {
1625 SAFE_FREE(cliplist[i]);
1627 SAFE_FREE(cliplist);
1628 cliplist = NULL;
1629 clipn = 0;
1630 must_free_cliplist = False;
1632 return rc;
1635 /****************************************************************************
1636 Find a token (filename) in a clip list
1637 ***************************************************************************/
1639 static int clipfind(char **aret, int ret, char *tok)
1641 if (aret==NULL)
1642 return 0;
1644 /* ignore leading slashes or dots in token */
1645 while(strchr_m("/\\.", *tok))
1646 tok++;
1648 while(ret--) {
1649 char *pkey=*aret++;
1651 /* ignore leading slashes or dots in list */
1652 while(strchr_m("/\\.", *pkey))
1653 pkey++;
1655 if (!strslashcmp(pkey, tok))
1656 return 1;
1658 return 0;
1661 /****************************************************************************
1662 Read list of files to include from the file and initialize cliplist
1663 accordingly.
1664 ***************************************************************************/
1666 static int read_inclusion_file(char *filename)
1668 XFILE *inclusion = NULL;
1669 char buf[PATH_MAX + 1];
1670 char *inclusion_buffer = NULL;
1671 int inclusion_buffer_size = 0;
1672 int inclusion_buffer_sofar = 0;
1673 char *p;
1674 char *tmpstr;
1675 int i;
1676 int error = 0;
1678 clipn = 0;
1679 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1680 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1681 /* XXX It would be better to include a reason for failure, but without
1682 * autoconf, it's hard to use strerror, sys_errlist, etc.
1684 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1685 return 0;
1688 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1689 if (inclusion_buffer == NULL) {
1690 inclusion_buffer_size = 1024;
1691 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1692 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1693 error = 1;
1694 break;
1698 if (buf[strlen(buf)-1] == '\n') {
1699 buf[strlen(buf)-1] = '\0';
1702 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1703 inclusion_buffer_size *= 2;
1704 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1705 if (!inclusion_buffer) {
1706 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1707 inclusion_buffer_size));
1708 error = 1;
1709 break;
1713 strlcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1714 inclusion_buffer_sofar += strlen(buf) + 1;
1715 clipn++;
1717 x_fclose(inclusion);
1719 if (! error) {
1720 /* Allocate an array of clipn + 1 char*'s for cliplist */
1721 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1722 if (cliplist == NULL) {
1723 DEBUG(0,("failure allocating memory for cliplist\n"));
1724 error = 1;
1725 } else {
1726 cliplist[clipn] = NULL;
1727 p = inclusion_buffer;
1728 for (i = 0; (! error) && (i < clipn); i++) {
1729 /* set current item to NULL so array will be null-terminated even if
1730 * malloc fails below. */
1731 cliplist[i] = NULL;
1732 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1733 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1734 error = 1;
1735 } else {
1736 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1737 cliplist[i] = tmpstr;
1738 if ((p = strchr_m(p, '\000')) == NULL) {
1739 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1740 abort();
1743 ++p;
1745 must_free_cliplist = True;
1749 SAFE_FREE(inclusion_buffer);
1750 if (error) {
1751 if (cliplist) {
1752 char **pp;
1753 /* We know cliplist is always null-terminated */
1754 for (pp = cliplist; *pp; ++pp) {
1755 SAFE_FREE(*pp);
1757 SAFE_FREE(cliplist);
1758 cliplist = NULL;
1759 must_free_cliplist = False;
1761 return 0;
1764 /* cliplist and its elements are freed at the end of process_tar. */
1765 return 1;
1768 /****************************************************************************
1769 Parse tar arguments. Sets tar_type, tar_excl, etc.
1770 ***************************************************************************/
1772 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1774 int newOptind = Optind;
1775 char tar_clipfl='\0';
1777 /* Reset back to defaults - could be from interactive version
1778 * reset mode and archive mode left as they are though
1780 tar_type='\0';
1781 tar_excl=True;
1782 dry_run=False;
1784 while (*Optarg) {
1785 switch(*Optarg++) {
1786 case 'c':
1787 tar_type='c';
1788 break;
1789 case 'x':
1790 if (tar_type=='c') {
1791 printf("Tar must be followed by only one of c or x.\n");
1792 return 0;
1794 tar_type='x';
1795 break;
1796 case 'b':
1797 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1798 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1799 return 0;
1800 } else {
1801 Optind++;
1802 newOptind++;
1804 break;
1805 case 'g':
1806 tar_inc=True;
1807 break;
1808 case 'N':
1809 if (Optind>=argc) {
1810 DEBUG(0,("Option N must be followed by valid file name\n"));
1811 return 0;
1812 } else {
1813 SMB_STRUCT_STAT stbuf;
1815 if (sys_stat(argv[Optind], &stbuf,
1816 false) == 0) {
1817 newer_than = convert_timespec_to_time_t(
1818 stbuf.st_ex_mtime);
1819 DEBUG(1,("Getting files newer than %s",
1820 time_to_asc(newer_than)));
1821 newOptind++;
1822 Optind++;
1823 } else {
1824 DEBUG(0,("Error setting newer-than time\n"));
1825 return 0;
1828 break;
1829 case 'a':
1830 tar_reset=True;
1831 break;
1832 case 'q':
1833 tar_noisy=False;
1834 break;
1835 case 'I':
1836 if (tar_clipfl) {
1837 DEBUG(0,("Only one of I,X,F must be specified\n"));
1838 return 0;
1840 tar_clipfl='I';
1841 break;
1842 case 'X':
1843 if (tar_clipfl) {
1844 DEBUG(0,("Only one of I,X,F must be specified\n"));
1845 return 0;
1847 tar_clipfl='X';
1848 break;
1849 case 'F':
1850 if (tar_clipfl) {
1851 DEBUG(0,("Only one of I,X,F must be specified\n"));
1852 return 0;
1854 tar_clipfl='F';
1855 break;
1856 case 'r':
1857 DEBUG(0, ("tar_re_search set\n"));
1858 tar_re_search = True;
1859 break;
1860 case 'n':
1861 if (tar_type == 'c') {
1862 DEBUG(0, ("dry_run set\n"));
1863 dry_run = True;
1864 } else {
1865 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1866 return 0;
1868 break;
1869 default:
1870 DEBUG(0,("Unknown tar option\n"));
1871 return 0;
1875 if (!tar_type) {
1876 printf("Option T must be followed by one of c or x.\n");
1877 return 0;
1880 /* tar_excl is true if cliplist lists files to be included.
1881 * Both 'I' and 'F' mean include. */
1882 tar_excl=tar_clipfl!='X';
1884 if (tar_clipfl=='F') {
1885 if (argc-Optind-1 != 1) {
1886 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1887 return 0;
1889 newOptind++;
1890 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1891 if (! read_inclusion_file(argv[Optind+1])) {
1892 return 0;
1894 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1895 char *tmpstr;
1896 char **tmplist;
1897 int clipcount;
1899 cliplist=argv+Optind+1;
1900 clipn=argc-Optind-1;
1901 clipcount = clipn;
1903 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1904 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1905 return 0;
1908 for (clipcount = 0; clipcount < clipn; clipcount++) {
1910 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1912 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1913 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1914 SAFE_FREE(tmplist);
1915 return 0;
1918 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1919 tmplist[clipcount] = tmpstr;
1920 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1922 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1925 cliplist = tmplist;
1926 must_free_cliplist = True;
1928 newOptind += clipn;
1931 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1932 /* Doing regular expression seaches not from an inclusion file. */
1933 clipn=argc-Optind-1;
1934 cliplist=argv+Optind+1;
1935 newOptind += clipn;
1938 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1939 /* Sets tar handle to either 0 or 1, as appropriate */
1940 tarhandle=(tar_type=='c');
1942 * Make sure that dbf points to stderr if we are using stdout for
1943 * tar output
1945 if (tarhandle == 1) {
1946 setup_logging("smbclient", DEBUG_STDERR);
1948 if (!argv[Optind]) {
1949 DEBUG(0,("Must specify tar filename\n"));
1950 return 0;
1952 if (!strcmp(argv[Optind], "-")) {
1953 newOptind++;
1956 } else {
1957 if (tar_type=='c' && dry_run) {
1958 tarhandle=-1;
1959 } else if ((tar_type=='x' && (tarhandle = sys_open(argv[Optind], O_RDONLY, 0)) == -1)
1960 || (tar_type=='c' && (tarhandle=sys_creat(argv[Optind], 0644)) < 0)) {
1961 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1962 return(0);
1964 newOptind++;
1967 return newOptind;