s3:vlp: fix build on OS X
[Samba.git] / source3 / client / clitar.c
blobc0b6e4e7f194e626e77ec8c540feecc06b645c29
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 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; i; i--) {
192 hb.dbuf.size[i+3] = size & 0xff;
193 size >>= 8;
196 oct_it((uint64_t) mtime, 13, hb.dbuf.mtime);
197 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
198 memset(hb.dbuf.linkname, 0, NAMSIZ);
199 hb.dbuf.linkflag=ftype;
201 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;)
202 chk+=(0xFF & *jp++);
204 oct_it((uint64_t) chk, 8, hb.dbuf.chksum);
205 hb.dbuf.chksum[6] = '\0';
207 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
210 /****************************************************************************
211 Read a tar header into a hblock structure, and validate
212 ***************************************************************************/
214 static long readtarheader(union hblock *hb, file_info2 *finfo, const char *prefix)
216 long chk, fchk;
217 int i;
218 char *jp;
221 * read in a "standard" tar format header - we're not that interested
222 * in that many fields, though
225 /* check the checksum */
226 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;)
227 chk+=(0xFF & *jp++);
229 if (chk == 0)
230 return chk;
232 /* compensate for blanks in chksum header */
233 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
234 chk-=(0xFF & *jp++);
236 chk += ' ' * sizeof(hb->dbuf.chksum);
238 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
240 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
241 chk, fchk, hb->dbuf.chksum));
243 if (fchk != chk) {
244 DEBUG(0, ("checksums don't match %ld %ld\n", fchk, chk));
245 dump_data(5, (uint8 *)hb - TBLOCK, TBLOCK *3);
246 return -1;
249 if ((finfo->name = SMB_MALLOC(strlen(prefix) + strlen(hb -> dbuf.name) + 4)) == NULL) {
250 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb -> dbuf.name));
251 return(-1);
254 strlcpy(finfo->name, prefix, strlen(prefix) + strlen(hb -> dbuf.name) + 4);
256 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
257 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
258 strlen(hb->dbuf.name) + 1, True);
260 /* can't handle some links at present */
261 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
262 if (hb->dbuf.linkflag == 0) {
263 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
264 finfo->name));
265 } else {
266 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
267 /* Do nothing here at the moment. do_tarput will handle this
268 as long as the longlink gets back to it, as it has to advance
269 the buffer pointer, etc */
270 } else {
271 DEBUG(0, ("this tar file appears to contain some kind \
272 of link other than a GNUtar Longlink - ignoring\n"));
273 return -2;
278 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR) ||
279 (*(finfo->name+strlen(finfo->name)-1) == '\\')) {
280 finfo->mode=FILE_ATTRIBUTE_DIRECTORY;
281 } else {
282 finfo->mode=0; /* we don't care about mode at the moment, we'll
283 * just make it a regular file */
287 * Bug fix by richard@sj.co.uk
289 * REC: restore times correctly (as does tar)
290 * We only get the modification time of the file; set the creation time
291 * from the mod. time, and the access time to current time
293 finfo->mtime_ts = finfo->ctime_ts =
294 convert_time_t_to_timespec((time_t)strtol(hb->dbuf.mtime, NULL, 8));
295 finfo->atime_ts = convert_time_t_to_timespec(time(NULL));
296 if ((hb->dbuf.size[0] & 0xff) == 0x80) {
297 /* This is a non-POSIX compatible extention to extract files
298 greater than 8GB. */
299 finfo->size = 0;
300 for (i = 0; i < 8; i++) {
301 finfo->size <<= 8;
302 finfo->size |= hb->dbuf.size[i+4] & 0xff;
304 } else {
305 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
308 return True;
311 /****************************************************************************
312 Write out the tar buffer to tape or wherever
313 ****************************************************************************/
315 static int dotarbuf(int f, char *b, int n)
317 int fail=1, writ=n;
319 if (dry_run) {
320 return writ;
322 /* This routine and the next one should be the only ones that do write()s */
323 if (tp + n >= tbufsiz) {
324 int diff;
326 diff=tbufsiz-tp;
327 memcpy(tarbuf + tp, b, diff);
328 fail=fail && (1+sys_write(f, tarbuf, tbufsiz));
329 n-=diff;
330 b+=diff;
331 tp=0;
333 while (n >= tbufsiz) {
334 fail=fail && (1 + sys_write(f, b, tbufsiz));
335 n-=tbufsiz;
336 b+=tbufsiz;
340 if (n>0) {
341 memcpy(tarbuf+tp, b, n);
342 tp+=n;
345 return(fail ? writ : 0);
348 /****************************************************************************
349 Write zeros to buffer / tape
350 ****************************************************************************/
352 static void dozerobuf(int f, int n)
354 /* short routine just to write out n zeros to buffer -
355 * used to round files to nearest block
356 * and to do tar EOFs */
358 if (dry_run)
359 return;
361 if (n+tp >= tbufsiz) {
362 memset(tarbuf+tp, 0, tbufsiz-tp);
363 if (sys_write(f, tarbuf, tbufsiz) != tbufsiz) {
364 DEBUG(0, ("dozerobuf: sys_write fail\n"));
365 return;
367 memset(tarbuf, 0, (tp+=n-tbufsiz));
368 } else {
369 memset(tarbuf+tp, 0, n);
370 tp+=n;
374 /****************************************************************************
375 Malloc tape buffer
376 ****************************************************************************/
378 static void initarbuf(void)
380 /* initialize tar buffer */
381 tbufsiz=blocksize*TBLOCK;
382 tarbuf=(char *)SMB_MALLOC(tbufsiz); /* FIXME: We might not get the buffer */
384 /* reset tar buffer pointer and tar file counter and total dumped */
385 tp=0; ntarf=0; ttarf=0;
388 /****************************************************************************
389 Write two zero blocks at end of file
390 ****************************************************************************/
392 static void dotareof(int f)
394 SMB_STRUCT_STAT stbuf;
395 /* Two zero blocks at end of file, write out full buffer */
397 if (dry_run)
398 return;
400 (void) dozerobuf(f, TBLOCK);
401 (void) dozerobuf(f, TBLOCK);
403 if (sys_fstat(f, &stbuf, false) == -1) {
404 DEBUG(0, ("Couldn't stat file handle\n"));
405 return;
408 /* Could be a pipe, in which case S_ISREG should fail,
409 * and we should write out at full size */
410 if (tp > 0) {
411 size_t towrite = S_ISREG(stbuf.st_ex_mode) ? tp : tbufsiz;
412 if (sys_write(f, tarbuf, towrite) != towrite) {
413 DEBUG(0,("dotareof: sys_write fail\n"));
418 /****************************************************************************
419 (Un)mangle DOS pathname, make nonabsolute
420 ****************************************************************************/
422 static void fixtarname(char *tptr, const char *fp, size_t l)
424 /* add a '.' to start of file name, convert from ugly dos \'s in path
425 * to lovely unix /'s :-} */
426 *tptr++='.';
427 l--;
429 StrnCpy(tptr, fp, l-1);
430 string_replace(tptr, '\\', '/');
433 /****************************************************************************
434 Convert from decimal to octal string
435 ****************************************************************************/
437 static void oct_it (uint64_t value, int ndgs, char *p)
439 /* Converts long to octal string, pads with leading zeros */
441 /* skip final null, but do final space */
442 --ndgs;
443 p[--ndgs] = ' ';
445 /* Loop does at least one digit */
446 do {
447 p[--ndgs] = '0' + (char) (value & 7);
448 value >>= 3;
449 } while (ndgs > 0 && value != 0);
451 /* Do leading zeros */
452 while (ndgs > 0)
453 p[--ndgs] = '0';
456 /****************************************************************************
457 Convert from octal string to long
458 ***************************************************************************/
460 static long unoct(char *p, int ndgs)
462 long value=0;
463 /* Converts octal string to long, ignoring any non-digit */
465 while (--ndgs) {
466 if (isdigit((int)*p))
467 value = (value << 3) | (long) (*p - '0');
469 p++;
472 return value;
475 /****************************************************************************
476 Compare two strings in a slash insensitive way, allowing s1 to match s2
477 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
478 a file in any subdirectory of s1, declare a match.
479 ***************************************************************************/
481 static int strslashcmp(char *s1, char *s2)
483 char *s1_0=s1;
485 while(*s1 && *s2 && (*s1 == *s2 || tolower_m(*s1) == tolower_m(*s2) ||
486 (*s1 == '\\' && *s2=='/') || (*s1 == '/' && *s2=='\\'))) {
487 s1++; s2++;
490 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
491 string of s2.
493 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\'))
494 return 0;
496 /* ignore trailing slash on s1 */
497 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1))
498 return 0;
500 /* check for s1 is an "initial" string of s2 */
501 if ((*s2 == '/' || *s2 == '\\') && !*s1)
502 return 0;
504 return *s1-*s2;
507 /****************************************************************************
508 Ensure a remote path exists (make if necessary)
509 ***************************************************************************/
511 static bool ensurepath(const char *fname)
513 /* *must* be called with buffer ready malloc'ed */
514 /* ensures path exists */
516 char *partpath, *ffname;
517 size_t fnamelen = strlen(fname)+1;
518 const char *p=fname;
519 char *basehack;
520 char *saveptr;
521 NTSTATUS status;
523 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
525 partpath = SMB_MALLOC(fnamelen);
526 ffname = SMB_MALLOC(fnamelen);
528 if ((partpath == NULL) || (ffname == NULL)){
529 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname));
530 SAFE_FREE(partpath);
531 SAFE_FREE(ffname);
532 return(False);
535 *partpath = 0;
537 /* fname copied to ffname so can strtok_r */
539 strlcpy(ffname, fname, fnamelen);
541 /* do a `basename' on ffname, so don't try and make file name directory */
542 if ((basehack=strrchr_m(ffname, '\\')) == NULL) {
543 SAFE_FREE(partpath);
544 SAFE_FREE(ffname);
545 return True;
546 } else {
547 *basehack='\0';
550 p=strtok_r(ffname, "\\", &saveptr);
552 while (p) {
553 strlcat(partpath, p, fnamelen);
555 status = cli_chkpath(cli, partpath);
556 if (!NT_STATUS_IS_OK(status)) {
557 status = cli_mkdir(cli, partpath);
558 if (!NT_STATUS_IS_OK(status)) {
559 SAFE_FREE(partpath);
560 SAFE_FREE(ffname);
561 DEBUG(0, ("Error mkdir %s\n", nt_errstr(status)));
562 return False;
563 } else {
564 DEBUG(3, ("mkdirhiering %s\n", partpath));
568 strlcat(partpath, "\\", fnamelen);
569 p = strtok_r(NULL, "/\\", &saveptr);
572 SAFE_FREE(partpath);
573 SAFE_FREE(ffname);
574 return True;
577 static int padit(char *buf, uint64_t bufsize, uint64_t padsize)
579 int berr= 0;
580 int bytestowrite;
582 DEBUG(5, ("Padding with %0.f zeros\n", (double)padsize));
583 memset(buf, 0, (size_t)bufsize);
584 while( !berr && padsize > 0 ) {
585 bytestowrite= (int)MIN(bufsize, padsize);
586 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
587 padsize -= bytestowrite;
590 return berr;
593 static void do_setrattr(char *name, uint16 attr, int set)
595 uint16 oldattr;
596 NTSTATUS status;
598 if (!NT_STATUS_IS_OK(cli_getatr(cli, name, &oldattr, NULL, NULL))) {
599 return;
602 if (set == ATTRSET) {
603 attr |= oldattr;
604 } else {
605 attr = oldattr & ~attr;
608 status = cli_setatr(cli, name, attr, 0);
609 if (!NT_STATUS_IS_OK(status)) {
610 DEBUG(1, ("setatr failed: %s\n", nt_errstr(status)));
614 /****************************************************************************
615 append one remote file to the tar file
616 ***************************************************************************/
618 static NTSTATUS do_atar(const char *rname_in, char *lname,
619 struct file_info *finfo1)
621 uint16_t fnum = (uint16_t)-1;
622 uint64_t nread=0;
623 char ftype;
624 file_info2 finfo;
625 bool shallitime=True;
626 char *data = NULL;
627 int read_size = 65520;
628 size_t datalen=0;
629 char *rname = NULL;
630 TALLOC_CTX *ctx = talloc_stackframe();
631 NTSTATUS status = NT_STATUS_OK;
632 struct timespec tp_start;
634 clock_gettime_mono(&tp_start);
636 data = SMB_MALLOC_ARRAY(char, read_size);
637 if (!data) {
638 DEBUG(0,("do_atar: out of memory.\n"));
639 status = NT_STATUS_NO_MEMORY;
640 goto cleanup;
643 ftype = '0'; /* An ordinary file ... */
645 ZERO_STRUCT(finfo);
647 finfo.size = finfo1 -> size;
648 finfo.mode = finfo1 -> mode;
649 finfo.uid = finfo1 -> uid;
650 finfo.gid = finfo1 -> gid;
651 finfo.mtime_ts = finfo1 -> mtime_ts;
652 finfo.atime_ts = finfo1 -> atime_ts;
653 finfo.ctime_ts = finfo1 -> ctime_ts;
655 if (dry_run) {
656 DEBUG(3,("skipping file %s of size %12.0f bytes\n", finfo1->name,
657 (double)finfo.size));
658 shallitime=0;
659 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
660 ntarf++;
661 goto cleanup;
664 rname = clean_name(ctx, rname_in);
665 if (!rname) {
666 status = NT_STATUS_NO_MEMORY;
667 goto cleanup;
670 status = cli_open(cli, rname, O_RDONLY, DENY_NONE, &fnum);
671 if (!NT_STATUS_IS_OK(status)) {
672 DEBUG(0,("%s opening remote file %s (%s)\n",
673 nt_errstr(status),rname, client_get_cur_dir()));
674 goto cleanup;
677 finfo.name = smb_xstrdup(rname);
678 if (finfo.name == NULL) {
679 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
680 status = NT_STATUS_NO_MEMORY;
681 goto cleanup;
684 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
686 if (tar_inc && !(finfo.mode & FILE_ATTRIBUTE_ARCHIVE)) {
687 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
688 shallitime=0;
689 } else if (!tar_system && (finfo.mode & FILE_ATTRIBUTE_SYSTEM)) {
690 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
691 shallitime=0;
692 } else if (!tar_hidden && (finfo.mode & FILE_ATTRIBUTE_HIDDEN)) {
693 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
694 shallitime=0;
695 } else {
696 bool wrote_tar_header = False;
698 DEBUG(3,("getting file %s of size %.0f bytes as a tar file %s",
699 finfo.name, (double)finfo.size, lname));
701 do {
703 DEBUG(3,("nread=%.0f\n",(double)nread));
705 status = cli_read(cli, fnum, data, nread,
706 read_size, &datalen);
707 if (!NT_STATUS_IS_OK(status)) {
708 DEBUG(0,("Error reading file %s : %s\n",
709 rname, nt_errstr(status)));
710 break;
713 nread += datalen;
715 /* Only if the first read succeeds, write out the tar header. */
716 if (!wrote_tar_header) {
717 /* write a tar header, don't bother with mode - just set to 100644 */
718 writetarheader(tarhandle, rname, finfo.size,
719 finfo.mtime_ts.tv_sec, "100644 \0", ftype);
720 wrote_tar_header = True;
723 /* if file size has increased since we made file size query, truncate
724 read so tar header for this file will be correct.
727 if (nread > finfo.size) {
728 datalen -= nread - finfo.size;
729 DEBUG(0,("File size change - truncating %s to %.0f bytes\n",
730 finfo.name, (double)finfo.size));
733 /* add received bits of file to buffer - dotarbuf will
734 * write out in 512 byte intervals */
736 if (dotarbuf(tarhandle,data,datalen) != datalen) {
737 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
738 status = map_nt_error_from_unix(errno);
739 break;
742 if ( (datalen == 0) && (finfo.size != 0) ) {
743 status = NT_STATUS_UNSUCCESSFUL;
744 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
745 break;
748 datalen=0;
749 } while ( nread < finfo.size );
751 if (wrote_tar_header) {
752 /* pad tar file with zero's if we couldn't get entire file */
753 if (nread < finfo.size) {
754 DEBUG(0, ("Didn't get entire file. size=%.0f, nread=%d\n",
755 (double)finfo.size, (int)nread));
756 if (padit(data, (uint64_t)sizeof(data), finfo.size - nread)) {
757 status = map_nt_error_from_unix(errno);
758 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
762 /* round tar file to nearest block */
763 if (finfo.size % TBLOCK)
764 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
766 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
767 ntarf++;
768 } else {
769 DEBUG(4, ("skipping %s - initial read failed (file was locked ?)\n", finfo.name));
770 shallitime=0;
771 status = NT_STATUS_UNSUCCESSFUL;
775 cli_close(cli, fnum);
776 fnum = -1;
778 if (shallitime) {
779 struct timespec tp_end;
780 int this_time;
782 /* if shallitime is true then we didn't skip */
783 if (tar_reset && !dry_run)
784 (void) do_setrattr(finfo.name, FILE_ATTRIBUTE_ARCHIVE, ATTRRESET);
786 clock_gettime_mono(&tp_end);
787 this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_nsec - tp_start.tv_nsec)/1000000;
788 get_total_time_ms += this_time;
789 get_total_size += finfo.size;
791 if (tar_noisy) {
792 DEBUG(0, ("%12.0f (%7.1f kb/s) %s\n",
793 (double)finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
794 finfo.name));
797 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
798 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
799 finfo.size / MAX(0.001, (1.024*this_time)),
800 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
803 cleanup:
805 if (fnum != (uint16_t)-1) {
806 cli_close(cli, fnum);
807 fnum = -1;
809 TALLOC_FREE(ctx);
810 SAFE_FREE(data);
811 return status;
814 /****************************************************************************
815 Append single file to tar file (or not)
816 ***************************************************************************/
818 static NTSTATUS do_tar(struct cli_state *cli_state, struct file_info *finfo,
819 const char *dir)
821 TALLOC_CTX *ctx = talloc_stackframe();
822 NTSTATUS status = NT_STATUS_OK;
824 if (strequal(finfo->name,"..") || strequal(finfo->name,"."))
825 return NT_STATUS_OK;
827 /* Is it on the exclude list ? */
828 if (!tar_excl && clipn) {
829 char *exclaim;
831 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(client_get_cur_dir())));
833 exclaim = talloc_asprintf(ctx,
834 "%s\\%s",
835 client_get_cur_dir(),
836 finfo->name);
837 if (!exclaim) {
838 return NT_STATUS_NO_MEMORY;
841 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search));
843 if ((!tar_re_search && clipfind(cliplist, clipn, exclaim)) ||
844 (tar_re_search && mask_match_list(exclaim, cliplist, clipn, True))) {
845 DEBUG(3,("Skipping file %s\n", exclaim));
846 TALLOC_FREE(exclaim);
847 return NT_STATUS_OK;
849 TALLOC_FREE(exclaim);
852 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
853 char *saved_curdir = NULL;
854 char *new_cd = NULL;
855 char *mtar_mask = NULL;
857 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
858 if (!saved_curdir) {
859 return NT_STATUS_NO_MEMORY;
862 DEBUG(5, ("strlen(cur_dir)=%d, \
863 strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n",
864 (int)strlen(saved_curdir),
865 (int)strlen(finfo->name), finfo->name, saved_curdir));
867 new_cd = talloc_asprintf(ctx,
868 "%s%s\\",
869 client_get_cur_dir(),
870 finfo->name);
871 if (!new_cd) {
872 return NT_STATUS_NO_MEMORY;
874 client_set_cur_dir(new_cd);
876 DEBUG(5, ("Writing a dir, Name = %s\n", client_get_cur_dir()));
878 /* write a tar directory, don't bother with mode - just
879 * set it to 40755 */
880 writetarheader(tarhandle, client_get_cur_dir(), 0,
881 finfo->mtime_ts.tv_sec, "040755 \0", '5');
882 if (tar_noisy) {
883 DEBUG(0,(" directory %s\n",
884 client_get_cur_dir()));
886 ntarf++; /* Make sure we have a file on there */
887 mtar_mask = talloc_asprintf(ctx,
888 "%s*",
889 client_get_cur_dir());
890 if (!mtar_mask) {
891 return NT_STATUS_NO_MEMORY;
893 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask));
894 do_list(mtar_mask, attribute, do_tar, False, True);
895 client_set_cur_dir(saved_curdir);
896 TALLOC_FREE(saved_curdir);
897 TALLOC_FREE(new_cd);
898 TALLOC_FREE(mtar_mask);
899 } else {
900 char *rname = talloc_asprintf(ctx,
901 "%s%s",
902 client_get_cur_dir(),
903 finfo->name);
904 if (!rname) {
905 return NT_STATUS_NO_MEMORY;
907 status = do_atar(rname,finfo->name,finfo);
908 TALLOC_FREE(rname);
910 return status;
913 /****************************************************************************
914 Convert from UNIX to DOS file names
915 ***************************************************************************/
917 static void unfixtarname(char *tptr, char *fp, int l, bool first)
919 /* remove '.' from start of file name, convert from unix /'s to
920 * dos \'s in path. Kill any absolute path names. But only if first!
923 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr, (long)fp, l));
925 if (first) {
926 if (*fp == '.') {
927 fp++;
928 l--;
930 if (*fp == '\\' || *fp == '/') {
931 fp++;
932 l--;
934 if (l <= 0) {
935 return;
939 strlcpy(tptr, fp, l);
940 string_replace(tptr, '/', '\\');
943 /****************************************************************************
944 Move to the next block in the buffer, which may mean read in another set of
945 blocks. FIXME, we should allow more than one block to be skipped.
946 ****************************************************************************/
948 static int next_block(char *ltarbuf, char **bufferp, int bufsiz)
950 int bufread, total = 0;
952 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp));
953 *bufferp += TBLOCK;
954 total = TBLOCK;
956 if (*bufferp >= (ltarbuf + bufsiz)) {
958 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
961 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
962 * Fixes bug where read can return short if coming from
963 * a pipe.
966 bufread = read(tarhandle, ltarbuf, bufsiz);
967 total = bufread;
969 while (total < bufsiz) {
970 if (bufread < 0) { /* An error, return false */
971 return (total > 0 ? -2 : bufread);
973 if (bufread == 0) {
974 if (total <= 0) {
975 return -2;
977 break;
979 bufread = read(tarhandle, &ltarbuf[total], bufsiz - total);
980 total += bufread;
983 DEBUG(5, ("Total bytes read ... %i\n", total));
985 *bufferp = ltarbuf;
988 return(total);
991 /* Skip a file, even if it includes a long file name? */
992 static int skip_file(int skipsize)
994 int dsize = skipsize;
996 DEBUG(5, ("Skiping file. Size = %i\n", skipsize));
998 /* FIXME, we should skip more than one block at a time */
1000 while (dsize > 0) {
1001 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1002 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1003 return(False);
1005 dsize -= TBLOCK;
1008 return(True);
1011 /*************************************************************
1012 Get a file from the tar file and store it.
1013 When this is called, tarbuf already contains the first
1014 file block. This is a bit broken & needs fixing.
1015 **************************************************************/
1017 static int get_file(file_info2 finfo)
1019 uint16_t fnum = (uint16_t) -1;
1020 int dsize = 0, bpos = 0;
1021 uint64_t rsize = 0, pos = 0;
1022 NTSTATUS status;
1024 DEBUG(5, ("get_file: file: %s, size %.0f\n", finfo.name, (double)finfo.size));
1026 if (!ensurepath(finfo.name)) {
1027 DEBUG(0, ("abandoning restore\n"));
1028 return False;
1031 status = cli_open(cli, finfo.name, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1032 if (!NT_STATUS_IS_OK(status)) {
1033 DEBUG(0, ("abandoning restore\n"));
1034 return False;
1037 /* read the blocks from the tar file and write to the remote file */
1039 rsize = finfo.size; /* This is how much to write */
1041 while (rsize > 0) {
1043 /* We can only write up to the end of the buffer */
1044 dsize = MIN(tbufsiz - (buffer_p - tarbuf) - bpos, 65520); /* Calculate the size to write */
1045 dsize = MIN(dsize, rsize); /* Should be only what is left */
1046 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize, bpos));
1048 status = cli_writeall(cli, fnum, 0,
1049 (uint8_t *)(buffer_p + bpos), pos,
1050 dsize, NULL);
1051 if (!NT_STATUS_IS_OK(status)) {
1052 DEBUG(0, ("Error writing remote file: %s\n",
1053 nt_errstr(status)));
1054 return 0;
1057 rsize -= dsize;
1058 pos += dsize;
1060 /* Now figure out how much to move in the buffer */
1062 /* FIXME, we should skip more than one block at a time */
1064 /* First, skip any initial part of the part written that is left over */
1065 /* from the end of the first TBLOCK */
1067 if ((bpos) && ((bpos + dsize) >= TBLOCK)) {
1068 dsize -= (TBLOCK - bpos); /* Get rid of the end of the first block */
1069 bpos = 0;
1071 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) { /* and skip the block */
1072 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1073 return False;
1078 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1079 * If the file being extracted is an exact multiple of
1080 * TBLOCK bytes then we don't want to extract the next
1081 * block from the tarfile here, as it will be done in
1082 * the caller of get_file().
1085 while (((rsize != 0) && (dsize >= TBLOCK)) ||
1086 ((rsize == 0) && (dsize > TBLOCK))) {
1088 if (next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1089 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1090 return False;
1093 dsize -= TBLOCK;
1095 bpos = dsize;
1098 /* Now close the file ... */
1099 status = cli_close(cli, fnum);
1100 if (!NT_STATUS_IS_OK(status)) {
1101 DEBUG(0, ("Error %s closing remote file\n",
1102 nt_errstr(status)));
1103 return(False);
1106 /* Now we update the creation date ... */
1107 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1109 if (!NT_STATUS_IS_OK(cli_setatr(cli, finfo.name, finfo.mode, finfo.mtime_ts.tv_sec))) {
1110 if (tar_real_noisy) {
1111 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1112 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1116 ntarf++;
1117 DEBUG(0, ("restore tar file %s of size %.0f bytes\n", finfo.name, (double)finfo.size));
1118 return(True);
1121 /* Create a directory. We just ensure that the path exists and return as there
1122 is no file associated with a directory
1124 static int get_dir(file_info2 finfo)
1126 DEBUG(0, ("restore directory %s\n", finfo.name));
1128 if (!ensurepath(finfo.name)) {
1129 DEBUG(0, ("Problems creating directory\n"));
1130 return(False);
1132 ntarf++;
1133 return(True);
1136 /* Get a file with a long file name ... first file has file name, next file
1137 has the data. We only want the long file name, as the loop in do_tarput
1138 will deal with the rest.
1140 static char *get_longfilename(file_info2 finfo)
1142 /* finfo.size here is the length of the filename as written by the "/./@LongLink" name
1143 * header call. */
1144 int namesize = finfo.size + strlen(client_get_cur_dir()) + 2;
1145 char *longname = (char *)SMB_MALLOC(namesize);
1146 int offset = 0, left = finfo.size;
1147 bool first = True;
1149 DEBUG(5, ("Restoring a long file name: %s\n", finfo.name));
1150 DEBUG(5, ("Len = %.0f\n", (double)finfo.size));
1152 if (longname == NULL) {
1153 DEBUG(0, ("could not allocate buffer of size %d for longname\n", namesize));
1154 return(NULL);
1157 /* First, add cur_dir to the long file name */
1159 if (strlen(client_get_cur_dir()) > 0) {
1160 strncpy(longname, client_get_cur_dir(), namesize);
1161 offset = strlen(client_get_cur_dir());
1164 /* Loop through the blocks picking up the name */
1166 while (left > 0) {
1167 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1168 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1169 SAFE_FREE(longname);
1170 return(NULL);
1173 unfixtarname(longname + offset, buffer_p,
1174 namesize - offset, first--);
1175 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname, buffer_p));
1177 offset += TBLOCK;
1178 left -= TBLOCK;
1181 return(longname);
1184 static void do_tarput(void)
1186 file_info2 finfo;
1187 struct timespec tp_start;
1188 char *longfilename = NULL, linkflag;
1189 int skip = False;
1191 ZERO_STRUCT(finfo);
1193 clock_gettime_mono(&tp_start);
1194 DEBUG(5, ("RJS do_tarput called ...\n"));
1196 buffer_p = tarbuf + tbufsiz; /* init this to force first read */
1198 /* Now read through those files ... */
1199 while (True) {
1200 /* Get us to the next block, or the first block first time around */
1201 if (next_block(tarbuf, &buffer_p, tbufsiz) <= 0) {
1202 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno)));
1203 SAFE_FREE(longfilename);
1204 return;
1207 DEBUG(5, ("Reading the next header ...\n"));
1209 switch (readtarheader((union hblock *) buffer_p,
1210 &finfo, client_get_cur_dir())) {
1211 case -2: /* Hmm, not good, but not fatal */
1212 DEBUG(0, ("Skipping %s...\n", finfo.name));
1213 if ((next_block(tarbuf, &buffer_p, tbufsiz) <= 0) && !skip_file(finfo.size)) {
1214 DEBUG(0, ("Short file, bailing out...\n"));
1215 SAFE_FREE(longfilename);
1216 return;
1218 break;
1220 case -1:
1221 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1222 SAFE_FREE(longfilename);
1223 return;
1225 case 0: /* chksum is zero - looks like an EOF */
1226 DEBUG(0, ("tar: restored %d files and directories\n", ntarf));
1227 SAFE_FREE(longfilename);
1228 return; /* Hmmm, bad here ... */
1230 default:
1231 /* No action */
1232 break;
1235 /* Now, do we have a long file name? */
1236 if (longfilename != NULL) {
1237 SAFE_FREE(finfo.name); /* Free the space already allocated */
1238 finfo.name = longfilename;
1239 longfilename = NULL;
1242 /* Well, now we have a header, process the file ... */
1243 /* Should we skip the file? We have the long name as well here */
1244 skip = clipn && ((!tar_re_search && clipfind(cliplist, clipn, finfo.name) ^ tar_excl) ||
1245 (tar_re_search && mask_match_list(finfo.name, cliplist, clipn, True)));
1247 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip, (cliplist?cliplist[0]:NULL), finfo.name));
1248 if (skip) {
1249 skip_file(finfo.size);
1250 continue;
1253 /* We only get this far if we should process the file */
1254 linkflag = ((union hblock *)buffer_p) -> dbuf.linkflag;
1255 switch (linkflag) {
1256 case '0': /* Should use symbolic names--FIXME */
1258 * Skip to the next block first, so we can get the file, FIXME, should
1259 * be in get_file ...
1260 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1261 * Fixes bug where file size in tarfile is zero.
1263 if ((finfo.size != 0) && next_block(tarbuf, &buffer_p, tbufsiz) <=0) {
1264 DEBUG(0, ("Short file, bailing out...\n"));
1265 return;
1267 if (!get_file(finfo)) {
1268 DEBUG(0, ("Abandoning restore\n"));
1269 return;
1271 break;
1272 case '5':
1273 if (!get_dir(finfo)) {
1274 DEBUG(0, ("Abandoning restore \n"));
1275 return;
1277 break;
1278 case 'L':
1279 SAFE_FREE(longfilename);
1280 longfilename = get_longfilename(finfo);
1281 if (!longfilename) {
1282 DEBUG(0, ("abandoning restore\n"));
1283 return;
1285 DEBUG(5, ("Long file name: %s\n", longfilename));
1286 break;
1288 default:
1289 skip_file(finfo.size); /* Don't handle these yet */
1290 break;
1296 * samba interactive commands
1299 /****************************************************************************
1300 Blocksize command
1301 ***************************************************************************/
1303 int cmd_block(void)
1305 TALLOC_CTX *ctx = talloc_tos();
1306 char *buf;
1307 int block;
1309 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1310 DEBUG(0, ("blocksize <n>\n"));
1311 return 1;
1314 block=atoi(buf);
1315 if (block < 0 || block > 65535) {
1316 DEBUG(0, ("blocksize out of range"));
1317 return 1;
1320 blocksize=block;
1321 DEBUG(2,("blocksize is now %d\n", blocksize));
1322 return 0;
1325 /****************************************************************************
1326 command to set incremental / reset mode
1327 ***************************************************************************/
1329 int cmd_tarmode(void)
1331 TALLOC_CTX *ctx = talloc_tos();
1332 char *buf;
1334 while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1335 if (strequal(buf, "full"))
1336 tar_inc=False;
1337 else if (strequal(buf, "inc"))
1338 tar_inc=True;
1339 else if (strequal(buf, "reset"))
1340 tar_reset=True;
1341 else if (strequal(buf, "noreset"))
1342 tar_reset=False;
1343 else if (strequal(buf, "system"))
1344 tar_system=True;
1345 else if (strequal(buf, "nosystem"))
1346 tar_system=False;
1347 else if (strequal(buf, "hidden"))
1348 tar_hidden=True;
1349 else if (strequal(buf, "nohidden"))
1350 tar_hidden=False;
1351 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1352 tar_noisy=True;
1353 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1354 tar_noisy=False;
1355 else
1356 DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1357 TALLOC_FREE(buf);
1360 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1361 tar_inc ? "incremental" : "full",
1362 tar_system ? "system" : "nosystem",
1363 tar_hidden ? "hidden" : "nohidden",
1364 tar_reset ? "reset" : "noreset",
1365 tar_noisy ? "verbose" : "quiet"));
1366 return 0;
1369 /****************************************************************************
1370 Feeble attrib command
1371 ***************************************************************************/
1373 int cmd_setmode(void)
1375 TALLOC_CTX *ctx = talloc_tos();
1376 char *q;
1377 char *buf;
1378 char *fname = NULL;
1379 uint16 attra[2];
1380 int direct=1;
1382 attra[0] = attra[1] = 0;
1384 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1385 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1386 return 1;
1389 fname = talloc_asprintf(ctx,
1390 "%s%s",
1391 client_get_cur_dir(),
1392 buf);
1393 if (!fname) {
1394 return 1;
1397 while (next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1398 q=buf;
1400 while(*q) {
1401 switch (*q++) {
1402 case '+':
1403 direct=1;
1404 break;
1405 case '-':
1406 direct=0;
1407 break;
1408 case 'r':
1409 attra[direct]|=FILE_ATTRIBUTE_READONLY;
1410 break;
1411 case 'h':
1412 attra[direct]|=FILE_ATTRIBUTE_HIDDEN;
1413 break;
1414 case 's':
1415 attra[direct]|=FILE_ATTRIBUTE_SYSTEM;
1416 break;
1417 case 'a':
1418 attra[direct]|=FILE_ATTRIBUTE_ARCHIVE;
1419 break;
1420 default:
1421 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1422 return 1;
1427 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0) {
1428 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1429 return 1;
1432 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1433 do_setrattr(fname, attra[ATTRSET], ATTRSET);
1434 do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1435 return 0;
1439 Convert list of tokens to array; dependent on above routine.
1440 Uses the global cmd_ptr from above - bit of a hack.
1443 static char **toktocliplist(int *ctok, const char *sep)
1445 char *s=(char *)cmd_ptr;
1446 int ictok=0;
1447 char **ret, **iret;
1449 if (!sep)
1450 sep = " \t\n\r";
1452 while(*s && strchr_m(sep,*s))
1453 s++;
1455 /* nothing left? */
1456 if (!*s)
1457 return(NULL);
1459 do {
1460 ictok++;
1461 while(*s && (!strchr_m(sep,*s)))
1462 s++;
1463 while(*s && strchr_m(sep,*s))
1464 *s++=0;
1465 } while(*s);
1467 *ctok=ictok;
1468 s=(char *)cmd_ptr;
1470 if (!(ret=iret=SMB_MALLOC_ARRAY(char *,ictok+1)))
1471 return NULL;
1473 while(ictok--) {
1474 *iret++=s;
1475 if (ictok > 0) {
1476 while(*s++)
1478 while(!*s)
1479 s++;
1483 ret[*ctok] = NULL;
1484 return ret;
1487 /****************************************************************************
1488 Principal command for creating / extracting
1489 ***************************************************************************/
1491 int cmd_tar(void)
1493 TALLOC_CTX *ctx = talloc_tos();
1494 char *buf;
1495 char **argl = NULL;
1496 int argcl = 0;
1497 int ret;
1499 if (!next_token_talloc(ctx, (const char **)&cmd_ptr,&buf,NULL)) {
1500 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1501 return 1;
1504 argl=toktocliplist(&argcl, NULL);
1505 if (!tar_parseargs(argcl, argl, buf, 0)) {
1506 SAFE_FREE(argl);
1507 return 1;
1510 ret = process_tar();
1511 SAFE_FREE(argl);
1512 return ret;
1515 /****************************************************************************
1516 Command line (option) version
1517 ***************************************************************************/
1519 int process_tar(void)
1521 TALLOC_CTX *ctx = talloc_tos();
1522 int rc = 0;
1523 initarbuf();
1524 switch(tar_type) {
1525 case 'x':
1527 #if 0
1528 do_tarput2();
1529 #else
1530 do_tarput();
1531 #endif
1532 SAFE_FREE(tarbuf);
1533 close(tarhandle);
1534 break;
1535 case 'r':
1536 case 'c':
1537 if (clipn && tar_excl) {
1538 int i;
1539 char *tarmac = NULL;
1541 for (i=0; i<clipn; i++) {
1542 DEBUG(5,("arg %d = %s\n", i, cliplist[i]));
1544 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1545 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1548 if (strrchr_m(cliplist[i], '\\')) {
1549 char *p;
1550 char saved_char;
1551 char *saved_dir = talloc_strdup(ctx,
1552 client_get_cur_dir());
1553 if (!saved_dir) {
1554 return 1;
1557 if (*cliplist[i]=='\\') {
1558 tarmac = talloc_strdup(ctx,
1559 cliplist[i]);
1560 } else {
1561 tarmac = talloc_asprintf(ctx,
1562 "%s%s",
1563 client_get_cur_dir(),
1564 cliplist[i]);
1566 if (!tarmac) {
1567 return 1;
1570 * Strip off the last \\xxx
1571 * xxx element of tarmac to set
1572 * it as current directory.
1574 p = strrchr_m(tarmac, '\\');
1575 if (!p) {
1576 return 1;
1578 saved_char = p[1];
1579 p[1] = '\0';
1581 client_set_cur_dir(tarmac);
1584 * Restore the character we
1585 * just replaced to
1586 * put the pathname
1587 * back as it was.
1589 p[1] = saved_char;
1591 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1592 do_list(tarmac,attribute,do_tar, False, True);
1594 client_set_cur_dir(saved_dir);
1596 TALLOC_FREE(saved_dir);
1597 TALLOC_FREE(tarmac);
1598 } else {
1599 tarmac = talloc_asprintf(ctx,
1600 "%s%s",
1601 client_get_cur_dir(),
1602 cliplist[i]);
1603 if (!tarmac) {
1604 return 1;
1606 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac));
1607 do_list(tarmac,attribute,do_tar, False, True);
1608 TALLOC_FREE(tarmac);
1611 } else {
1612 char *mask = talloc_asprintf(ctx,
1613 "%s\\*",
1614 client_get_cur_dir());
1615 if (!mask) {
1616 return 1;
1618 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask));
1619 do_list(mask,attribute,do_tar,False, True);
1620 TALLOC_FREE(mask);
1623 if (ntarf) {
1624 dotareof(tarhandle);
1626 close(tarhandle);
1627 SAFE_FREE(tarbuf);
1629 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf));
1630 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf));
1631 break;
1634 if (must_free_cliplist) {
1635 int i;
1636 for (i = 0; i < clipn; ++i) {
1637 SAFE_FREE(cliplist[i]);
1639 SAFE_FREE(cliplist);
1640 cliplist = NULL;
1641 clipn = 0;
1642 must_free_cliplist = False;
1644 return rc;
1647 /****************************************************************************
1648 Find a token (filename) in a clip list
1649 ***************************************************************************/
1651 static int clipfind(char **aret, int ret, char *tok)
1653 if (aret==NULL)
1654 return 0;
1656 /* ignore leading slashes or dots in token */
1657 while(strchr_m("/\\.", *tok))
1658 tok++;
1660 while(ret--) {
1661 char *pkey=*aret++;
1663 /* ignore leading slashes or dots in list */
1664 while(strchr_m("/\\.", *pkey))
1665 pkey++;
1667 if (!strslashcmp(pkey, tok))
1668 return 1;
1670 return 0;
1673 /****************************************************************************
1674 Read list of files to include from the file and initialize cliplist
1675 accordingly.
1676 ***************************************************************************/
1678 static int read_inclusion_file(char *filename)
1680 XFILE *inclusion = NULL;
1681 char buf[PATH_MAX + 1];
1682 char *inclusion_buffer = NULL;
1683 int inclusion_buffer_size = 0;
1684 int inclusion_buffer_sofar = 0;
1685 char *p;
1686 char *tmpstr;
1687 int i;
1688 int error = 0;
1690 clipn = 0;
1691 buf[PATH_MAX] = '\0'; /* guarantee null-termination */
1692 if ((inclusion = x_fopen(filename, O_RDONLY, 0)) == NULL) {
1693 /* XXX It would be better to include a reason for failure, but without
1694 * autoconf, it's hard to use strerror, sys_errlist, etc.
1696 DEBUG(0,("Unable to open inclusion file %s\n", filename));
1697 return 0;
1700 while ((! error) && (x_fgets(buf, sizeof(buf)-1, inclusion))) {
1701 if (inclusion_buffer == NULL) {
1702 inclusion_buffer_size = 1024;
1703 if ((inclusion_buffer = (char *)SMB_MALLOC(inclusion_buffer_size)) == NULL) {
1704 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1705 error = 1;
1706 break;
1710 if (buf[strlen(buf)-1] == '\n') {
1711 buf[strlen(buf)-1] = '\0';
1714 if ((strlen(buf) + 1 + inclusion_buffer_sofar) >= inclusion_buffer_size) {
1715 inclusion_buffer_size *= 2;
1716 inclusion_buffer = (char *)SMB_REALLOC(inclusion_buffer,inclusion_buffer_size);
1717 if (!inclusion_buffer) {
1718 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1719 inclusion_buffer_size));
1720 error = 1;
1721 break;
1725 strlcpy(inclusion_buffer + inclusion_buffer_sofar, buf, inclusion_buffer_size - inclusion_buffer_sofar);
1726 inclusion_buffer_sofar += strlen(buf) + 1;
1727 clipn++;
1729 x_fclose(inclusion);
1731 if (! error) {
1732 /* Allocate an array of clipn + 1 char*'s for cliplist */
1733 cliplist = SMB_MALLOC_ARRAY(char *, clipn + 1);
1734 if (cliplist == NULL) {
1735 DEBUG(0,("failure allocating memory for cliplist\n"));
1736 error = 1;
1737 } else {
1738 cliplist[clipn] = NULL;
1739 p = inclusion_buffer;
1740 for (i = 0; (! error) && (i < clipn); i++) {
1741 /* set current item to NULL so array will be null-terminated even if
1742 * malloc fails below. */
1743 cliplist[i] = NULL;
1744 if ((tmpstr = (char *)SMB_MALLOC(strlen(p)+1)) == NULL) {
1745 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i));
1746 error = 1;
1747 } else {
1748 unfixtarname(tmpstr, p, strlen(p) + 1, True);
1749 cliplist[i] = tmpstr;
1750 if ((p = strchr_m(p, '\000')) == NULL) {
1751 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1752 abort();
1755 ++p;
1757 must_free_cliplist = True;
1761 SAFE_FREE(inclusion_buffer);
1762 if (error) {
1763 if (cliplist) {
1764 char **pp;
1765 /* We know cliplist is always null-terminated */
1766 for (pp = cliplist; *pp; ++pp) {
1767 SAFE_FREE(*pp);
1769 SAFE_FREE(cliplist);
1770 cliplist = NULL;
1771 must_free_cliplist = False;
1773 return 0;
1776 /* cliplist and its elements are freed at the end of process_tar. */
1777 return 1;
1780 /****************************************************************************
1781 Parse tar arguments. Sets tar_type, tar_excl, etc.
1782 ***************************************************************************/
1784 int tar_parseargs(int argc, char *argv[], const char *Optarg, int Optind)
1786 int newOptind = Optind;
1787 char tar_clipfl='\0';
1789 /* Reset back to defaults - could be from interactive version
1790 * reset mode and archive mode left as they are though
1792 tar_type='\0';
1793 tar_excl=True;
1794 dry_run=False;
1796 while (*Optarg) {
1797 switch(*Optarg++) {
1798 case 'c':
1799 tar_type='c';
1800 break;
1801 case 'x':
1802 if (tar_type=='c') {
1803 printf("Tar must be followed by only one of c or x.\n");
1804 return 0;
1806 tar_type='x';
1807 break;
1808 case 'b':
1809 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1810 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1811 return 0;
1812 } else {
1813 Optind++;
1814 newOptind++;
1816 break;
1817 case 'g':
1818 tar_inc=True;
1819 break;
1820 case 'N':
1821 if (Optind>=argc) {
1822 DEBUG(0,("Option N must be followed by valid file name\n"));
1823 return 0;
1824 } else {
1825 SMB_STRUCT_STAT stbuf;
1827 if (sys_stat(argv[Optind], &stbuf,
1828 false) == 0) {
1829 newer_than = convert_timespec_to_time_t(
1830 stbuf.st_ex_mtime);
1831 DEBUG(1,("Getting files newer than %s",
1832 time_to_asc(newer_than)));
1833 newOptind++;
1834 Optind++;
1835 } else {
1836 DEBUG(0,("Error setting newer-than time\n"));
1837 return 0;
1840 break;
1841 case 'a':
1842 tar_reset=True;
1843 break;
1844 case 'q':
1845 tar_noisy=False;
1846 break;
1847 case 'I':
1848 if (tar_clipfl) {
1849 DEBUG(0,("Only one of I,X,F must be specified\n"));
1850 return 0;
1852 tar_clipfl='I';
1853 break;
1854 case 'X':
1855 if (tar_clipfl) {
1856 DEBUG(0,("Only one of I,X,F must be specified\n"));
1857 return 0;
1859 tar_clipfl='X';
1860 break;
1861 case 'F':
1862 if (tar_clipfl) {
1863 DEBUG(0,("Only one of I,X,F must be specified\n"));
1864 return 0;
1866 tar_clipfl='F';
1867 break;
1868 case 'r':
1869 DEBUG(0, ("tar_re_search set\n"));
1870 tar_re_search = True;
1871 break;
1872 case 'n':
1873 if (tar_type == 'c') {
1874 DEBUG(0, ("dry_run set\n"));
1875 dry_run = True;
1876 } else {
1877 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1878 return 0;
1880 break;
1881 default:
1882 DEBUG(0,("Unknown tar option\n"));
1883 return 0;
1887 if (!tar_type) {
1888 printf("Option T must be followed by one of c or x.\n");
1889 return 0;
1892 /* tar_excl is true if cliplist lists files to be included.
1893 * Both 'I' and 'F' mean include. */
1894 tar_excl=tar_clipfl!='X';
1896 if (tar_clipfl=='F') {
1897 if (argc-Optind-1 != 1) {
1898 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1899 return 0;
1901 newOptind++;
1902 /* Optind points at the tar output file, Optind+1 at the inclusion file. */
1903 if (! read_inclusion_file(argv[Optind+1])) {
1904 return 0;
1906 } else if (Optind+1<argc && !tar_re_search) { /* For backwards compatibility */
1907 char *tmpstr;
1908 char **tmplist;
1909 int clipcount;
1911 cliplist=argv+Optind+1;
1912 clipn=argc-Optind-1;
1913 clipcount = clipn;
1915 if ((tmplist=SMB_MALLOC_ARRAY(char *,clipn)) == NULL) {
1916 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n", clipn));
1917 return 0;
1920 for (clipcount = 0; clipcount < clipn; clipcount++) {
1922 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1924 if ((tmpstr = (char *)SMB_MALLOC(strlen(cliplist[clipcount])+1)) == NULL) {
1925 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", clipcount));
1926 SAFE_FREE(tmplist);
1927 return 0;
1930 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1, True);
1931 tmplist[clipcount] = tmpstr;
1932 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1934 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
1937 cliplist = tmplist;
1938 must_free_cliplist = True;
1940 newOptind += clipn;
1943 if (Optind+1<argc && tar_re_search && tar_clipfl != 'F') {
1944 /* Doing regular expression seaches not from an inclusion file. */
1945 clipn=argc-Optind-1;
1946 cliplist=argv+Optind+1;
1947 newOptind += clipn;
1950 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1951 /* Sets tar handle to either 0 or 1, as appropriate */
1952 tarhandle=(tar_type=='c');
1954 * Make sure that dbf points to stderr if we are using stdout for
1955 * tar output
1957 if (tarhandle == 1) {
1958 setup_logging("smbclient", DEBUG_STDERR);
1960 if (!argv[Optind]) {
1961 DEBUG(0,("Must specify tar filename\n"));
1962 return 0;
1964 if (!strcmp(argv[Optind], "-")) {
1965 newOptind++;
1968 } else {
1969 if (tar_type=='c' && dry_run) {
1970 tarhandle=-1;
1971 } else if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY, 0)) == -1)
1972 || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0)) {
1973 DEBUG(0,("Error opening local file %s - %s\n", argv[Optind], strerror(errno)));
1974 return(0);
1976 newOptind++;
1979 return newOptind;