Changes to client.c support the need for directories to be processed by whatever
[Samba/gebeck_regimport.git] / source / client / clitar.c
blob130c5e7a276533440a633c2604b13f3674510927
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Tar Extensions
5 Copyright (C) Ricky Poulten 1995-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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 /* The following changes developed by Richard Sharpe for Canon Information
22 Systems Research Australia (CISRA) are Copyright (C) 1998 by CISRA and are
23 made available under the terms of the GPL as listed above:
25 1. Restore can now restore files with long file names
26 2. Save now saves directory information so that we can restore
27 directory creation times
28 3. tar now accepts both UNIX path names and DOS path names. I prefer
29 those lovely /'s to those UGLY \'s :-)
34 #include "includes.h"
35 #include "clitar.h"
36 #include <regex.h>
38 extern BOOL recurse;
40 #define SEPARATORS " \t\n\r"
41 extern int DEBUGLEVEL;
42 extern int Client;
44 /* These defines are for the do_setrattr routine, to indicate
45 * setting and reseting of file attributes in the function call */
46 #define ATTRSET 1
47 #define ATTRRESET 0
49 static int attribute = aDIR | aSYSTEM | aHIDDEN;
51 #ifndef CLIENT_TIMEOUT
52 #define CLIENT_TIMEOUT (30*1000)
53 #endif
55 static char *tarbuf;
56 static int tp, ntarf, tbufsiz, ttarf;
57 /* Incremental mode */
58 BOOL tar_inc=False;
59 /* Reset archive bit */
60 BOOL tar_reset=False;
61 /* Include / exclude mode (true=include, false=exclude) */
62 BOOL tar_excl=True;
63 /* Dump files with System attribute */
64 BOOL tar_system=False;
65 /* Dump files with Hidden attribute */
66 BOOL tar_hidden=True;
67 /* Be noisy - make a catalogue */
68 BOOL tar_noisy=True;
70 char tar_type='\0';
71 static char **cliplist=NULL;
72 static int clipn=0;
74 extern file_info def_finfo;
75 extern BOOL lowercase;
76 extern int cnum;
77 extern BOOL readbraw_supported;
78 extern int max_xmit;
79 extern pstring cur_dir;
80 extern int get_total_time_ms;
81 extern int get_total_size;
82 extern int Protocol;
84 int blocksize=20;
85 int tarhandle;
87 static void writetarheader(int f, char *aname, int size, time_t mtime,
88 char *amode, unsigned char ftype);
89 static void do_atar();
90 static void do_tar();
91 static void oct_it();
92 static void fixtarname();
93 static int dotarbuf();
94 static void dozerobuf();
95 static void dotareof();
96 static void initarbuf();
97 static int do_setrattr();
99 /* restore functions */
100 static long readtarheader();
101 static long unoct();
102 static void do_tarput();
103 static void unfixtarname();
106 * tar specific utitlities
109 /****************************************************************************
110 Write a tar header to buffer
111 ****************************************************************************/
112 static void writetarheader(int f, char *aname, int size, time_t mtime,
113 char *amode, unsigned char ftype)
115 union hblock hb;
116 int i, chk, l;
117 char *jp;
119 DEBUG(5, ("WriteTarHdr, Type = %c, Name = %s\n", ftype, aname));
121 memset(hb.dummy, 0, sizeof(hb.dummy));
123 l=strlen(aname);
124 if (l >= NAMSIZ) {
125 /* write a GNU tar style long header */
126 char *b;
127 b = (char *)malloc(l+TBLOCK+100);
128 if (!b) {
129 DEBUG(0,("out of memory\n"));
130 exit(1);
132 writetarheader(f, "/./@LongLink", l+1, 0, " 0 \0", 'L');
133 memset(b, 0, l+TBLOCK+100);
134 fixtarname(b, aname, l+1);
135 i = strlen(b)+1;
136 dotarbuf(f, b, TBLOCK*(((i-1)/TBLOCK)+1));
137 free(b);
140 /* use l + 1 to do the null too */
141 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
143 if (lowercase)
144 strlower(hb.dbuf.name);
146 /* write out a "standard" tar format header */
148 hb.dbuf.name[NAMSIZ-1]='\0';
149 strcpy(hb.dbuf.mode, amode);
150 oct_it(0L, 8, hb.dbuf.uid);
151 oct_it(0L, 8, hb.dbuf.gid);
152 oct_it((long) size, 13, hb.dbuf.size);
153 oct_it((long) mtime, 13, hb.dbuf.mtime);
154 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
155 memset(hb.dbuf.linkname, 0, NAMSIZ);
156 hb.dbuf.linkflag=ftype;
158 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
160 oct_it((long) chk, 8, hb.dbuf.chksum);
161 hb.dbuf.chksum[6] = '\0';
163 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
166 /****************************************************************************
167 Read a tar header into a hblock structure, and validate
168 ***************************************************************************/
169 static long readtarheader(union hblock *hb, file_info *finfo, char *prefix)
171 long chk, fchk;
172 int i;
173 char *jp;
176 * read in a "standard" tar format header - we're not that interested
177 * in that many fields, though
180 /* check the checksum */
181 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
183 if (chk == 0)
184 return chk;
186 /* compensate for blanks in chksum header */
187 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
188 chk-=(0xFF & *jp++);
190 chk += ' ' * sizeof(hb->dbuf.chksum);
192 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
194 DEBUG(5, ("checksum totals chk=%d fchk=%d chksum=%s\n",
195 chk, fchk, hb->dbuf.chksum));
197 if (fchk != chk)
199 DEBUG(0, ("checksums don't match %d %d\n", fchk, chk));
200 return -1;
203 strcpy(finfo->name, prefix);
205 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
206 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
207 strlen(hb->dbuf.name) + 1);
209 /* can't handle some links at present */
210 if ((hb->dbuf.linkflag != '0') && (hb -> dbuf.linkflag != '5')) {
211 if (hb->dbuf.linkflag == 0) {
212 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
213 finfo->name));
214 } else {
215 if (hb -> dbuf.linkflag == 'L') { /* We have a longlink */
216 /* Do nothing here at the moment. do_tarput will handle this
217 as long as the longlink gets back to it, as it has to advance
218 the buffer pointer, etc */
220 } else {
221 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
222 return -2;
227 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
228 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
230 finfo->mode=aDIR;
232 else
233 finfo->mode=0; /* we don't care about mode at the moment, we'll
234 * just make it a regular file */
236 * Bug fix by richard@sj.co.uk
238 * REC: restore times correctly (as does tar)
239 * We only get the modification time of the file; set the creation time
240 * from the mod. time, and the access time to current time
242 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
243 finfo->atime = time(NULL);
244 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
246 return True;
249 /****************************************************************************
250 Write out the tar buffer to tape or wherever
251 ****************************************************************************/
252 static int dotarbuf(int f, char *b, int n)
254 int fail=1, writ=n;
256 /* This routine and the next one should be the only ones that do write()s */
257 if (tp + n >= tbufsiz)
259 int diff;
261 diff=tbufsiz-tp;
262 memcpy(tarbuf + tp, b, diff);
263 fail=fail && (1+write(f, tarbuf, tbufsiz));
264 n-=diff;
265 b+=diff;
266 tp=0;
268 while (n >= tbufsiz)
270 fail=fail && (1 + write(f, b, tbufsiz));
271 n-=tbufsiz;
272 b+=tbufsiz;
275 if (n>0) {
276 memcpy(tarbuf+tp, b, n);
277 tp+=n;
280 return(fail ? writ : 0);
283 /****************************************************************************
284 Write zeros to buffer / tape
285 ****************************************************************************/
286 static void dozerobuf(int f, int n)
288 /* short routine just to write out n zeros to buffer -
289 * used to round files to nearest block
290 * and to do tar EOFs */
292 if (n+tp >= tbufsiz)
294 memset(tarbuf+tp, 0, tbufsiz-tp);
296 write(f, tarbuf, tbufsiz);
297 memset(tarbuf, 0, (tp+=n-tbufsiz));
299 else
301 memset(tarbuf+tp, 0, n);
302 tp+=n;
306 /****************************************************************************
307 Malloc tape buffer
308 ****************************************************************************/
309 static void initarbuf()
311 /* initialize tar buffer */
312 tbufsiz=blocksize*TBLOCK;
313 tarbuf=malloc(tbufsiz); /* FIXME: We might not get the buffer */
315 /* reset tar buffer pointer and tar file counter and total dumped */
316 tp=0; ntarf=0; ttarf=0;
319 /****************************************************************************
320 Write two zero blocks at end of file
321 ****************************************************************************/
322 static void dotareof(int f)
324 struct stat stbuf;
325 /* Two zero blocks at end of file, write out full buffer */
327 (void) dozerobuf(f, TBLOCK);
328 (void) dozerobuf(f, TBLOCK);
330 if (fstat(f, &stbuf) == -1)
332 DEBUG(0, ("Couldn't stat file handle\n"));
333 return;
336 /* Could be a pipe, in which case S_ISREG should fail,
337 * and we should write out at full size */
338 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
341 /****************************************************************************
342 (Un)mangle DOS pathname, make nonabsolute
343 ****************************************************************************/
344 static void fixtarname(char *tptr, char *fp, int l)
346 /* add a '.' to start of file name, convert from ugly dos \'s in path
347 * to lovely unix /'s :-} */
349 *tptr++='.';
351 while (l > 0) {
352 int skip;
353 if((skip = skip_multibyte_char( *fp)) != 0) {
354 if (skip == 2) {
355 *tptr++ = *fp++;
356 *tptr++ = *fp++;
357 l -= 2;
358 } else if (skip == 1) {
359 *tptr++ = *fp++;
360 l--;
362 } else if (*fp == '\\') {
363 *tptr++ = '/';
364 fp++;
365 l--;
366 } else {
367 *tptr++ = *fp++;
368 l--;
373 /****************************************************************************
374 Convert from decimal to octal string
375 ****************************************************************************/
376 static void oct_it (register long value, register int ndgs, register char *p)
378 /* Converts long to octal string, pads with leading zeros */
380 /* skip final null, but do final space */
381 --ndgs;
382 p[--ndgs] = ' ';
384 /* Loop does at least one digit */
385 do {
386 p[--ndgs] = '0' + (char) (value & 7);
387 value >>= 3;
389 while (ndgs > 0 && value != 0);
391 /* Do leading zeros */
392 while (ndgs > 0)
393 p[--ndgs] = '0';
396 /****************************************************************************
397 Convert from octal string to long
398 ***************************************************************************/
399 static long unoct(char *p, int ndgs)
401 long value=0;
402 /* Converts octal string to long, ignoring any non-digit */
404 while (--ndgs)
406 if (isdigit(*p))
407 value = (value << 3) | (long) (*p - '0');
409 p++;
412 return value;
415 /****************************************************************************
416 Compare two strings in a slash insensitive way, allowing s1 to match s2
417 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
418 a file in any subdirectory of s1, declare a match.
419 ***************************************************************************/
420 static int strslashcmp(char *s1, char *s2)
422 char *s1_0=s1;
424 while(*s1 && *s2 &&
425 (*s1 == *s2
426 || tolower(*s1) == tolower(*s2)
427 || (*s1 == '\\' && *s2=='/')
428 || (*s1 == '/' && *s2=='\\'))) {
429 s1++; s2++;
432 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
433 string of s2.
435 if (!*s1 && s1 != s1_0 && (*(s1-1) == '/' || *(s1-1) == '\\')) return 0;
437 /* ignore trailing slash on s1 */
438 if (!*s2 && (*s1 == '/' || *s1 == '\\') && !*(s1+1)) return 0;
440 /* check for s1 is an "initial" string of s2 */
441 if (*s2 == '/' || *s2 == '\\') return 0;
443 return *s1-*s2;
447 * general smb utility functions
449 /**********************************************************************
450 do_setrtime, set time on a file or dir ...
451 **********************************************************************/
453 static int do_setrtime(char *fname, int mtime)
455 char *inbuf, *outbuf, *p;
456 char *name;
458 name = (char *)malloc(strlen(fname) + 1 + 1);
459 if (name == NULL) {
461 DEBUG(0, ("Failed to allocate space while setting time on file: %s", fname));
462 return False;
466 strcpy(name, fname);
467 strcpy(fname, "\\");
468 strcat(fname, name);
470 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
471 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
473 if (!inbuf || !outbuf) {
475 DEBUG(0, ("Could not allocate memory for inbuf or outbuf while changing time on: %s\n", fname));
476 return False;
480 memset(outbuf, 0, smb_size);
481 set_message(outbuf, 8, 4 + strlen(fname), True);
482 CVAL(outbuf, smb_com) = SMBsetatr;
483 SSVAL(outbuf, smb_tid, cnum);
484 cli_setup_pkt(outbuf);
486 SSVAL(outbuf, smb_vwv0, 0);
487 put_dos_date3(outbuf, smb_vwv1, mtime);
489 p = smb_buf(outbuf);
490 *p++ = 4;
491 strcpy(p, fname);
492 p+= (strlen(fname)+1);
494 *p++ = 4;
495 *p++ = 0;
497 send_smb(Client, outbuf);
498 client_receive_smb(Client, inbuf, CLIENT_TIMEOUT);
500 if (CVAL(inbuf,smb_rcls) != 0)
502 DEBUG(0,("%s setting attributes on file %s\n",
503 smb_errstr(inbuf), fname));
504 free(inbuf);free(outbuf);
505 return(False);
508 free(inbuf);free(outbuf);
509 return(True);
513 /****************************************************************************
514 Set DOS file attributes
515 ***************************************************************************/
516 static int do_setrattr(char *fname, int attr, int setit)
519 * First get the existing attribs from existing file
521 char *inbuf,*outbuf;
522 char *p;
523 pstring name;
524 int fattr;
526 strcpy(name,fname);
527 strcpy(fname,"\\");
528 strcat(fname,name);
530 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
531 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
533 if (!inbuf || !outbuf)
535 DEBUG(0,("out of memory\n"));
536 return False;
539 /* send an smb getatr message */
541 memset(outbuf,0,smb_size);
542 set_message(outbuf,0,2 + strlen(fname),True);
543 CVAL(outbuf,smb_com) = SMBgetatr;
544 SSVAL(outbuf,smb_tid,cnum);
545 cli_setup_pkt(outbuf);
547 p = smb_buf(outbuf);
548 *p++ = 4;
549 strcpy(p,fname);
550 p += (strlen(fname)+1);
552 *p++ = 4;
553 *p++ = 0;
555 send_smb(Client,outbuf);
556 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
558 if (CVAL(inbuf,smb_rcls) != 0)
559 DEBUG(5,("getatr: %s\n",smb_errstr(inbuf)));
560 else
562 DEBUG(5,("\nattr 0x%X time %d size %d\n",
563 (int)CVAL(inbuf,smb_vwv0),
564 SVAL(inbuf,smb_vwv1),
565 SVAL(inbuf,smb_vwv3)));
568 fattr=CVAL(inbuf,smb_vwv0);
570 /* combine found attributes with bits to be set or reset */
572 attr=setit ? (fattr | attr) : (fattr & ~attr);
574 /* now try and set attributes by sending smb reset message */
576 /* clear out buffer and start again */
577 memset(outbuf,0,smb_size);
578 set_message(outbuf,8,4 + strlen(fname),True);
579 CVAL(outbuf,smb_com) = SMBsetatr;
580 SSVAL(outbuf,smb_tid,cnum);
581 cli_setup_pkt(outbuf);
583 SSVAL(outbuf,smb_vwv0,attr);
585 p = smb_buf(outbuf);
586 *p++ = 4;
587 strcpy(p,fname);
588 p += (strlen(fname)+1);
590 *p++ = 4;
591 *p++ = 0;
593 send_smb(Client,outbuf);
594 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
596 if (CVAL(inbuf,smb_rcls) != 0)
598 DEBUG(0,("%s setting attributes on file %s\n",
599 smb_errstr(inbuf), fname));
600 free(inbuf);free(outbuf);
601 return(False);
604 free(inbuf);free(outbuf);
605 return(True);
608 /****************************************************************************
609 Create a file on a share
610 ***************************************************************************/
611 static BOOL smbcreat(file_info finfo, int *fnum, char *inbuf, char *outbuf)
613 char *p;
614 /* *must* be called with buffer ready malloc'ed */
615 /* open remote file */
617 memset(outbuf,0,smb_size);
618 set_message(outbuf,3,2 + strlen(finfo.name),True);
619 CVAL(outbuf,smb_com) = SMBcreate;
620 SSVAL(outbuf,smb_tid,cnum);
621 cli_setup_pkt(outbuf);
623 SSVAL(outbuf,smb_vwv0,finfo.mode);
624 put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
626 p = smb_buf(outbuf);
627 *p++ = 4;
628 strcpy(p,finfo.name);
630 send_smb(Client,outbuf);
631 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
633 if (CVAL(inbuf,smb_rcls) != 0)
635 DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),
636 finfo.name));
637 return 0;
640 *fnum = SVAL(inbuf,smb_vwv0);
641 return True;
644 /****************************************************************************
645 Write a file to a share
646 ***************************************************************************/
647 static BOOL smbwrite(int fnum, int n, int low, int high, int left,
648 char *bufferp, char *inbuf, char *outbuf)
650 /* *must* be called with buffer ready malloc'ed */
652 memset(outbuf,0,smb_size);
653 set_message(outbuf,5,n + 3,True);
655 memcpy(smb_buf(outbuf)+3, bufferp, n);
657 set_message(outbuf,5,n + 3, False);
658 CVAL(outbuf,smb_com) = SMBwrite;
659 SSVAL(outbuf,smb_tid,cnum);
660 cli_setup_pkt(outbuf);
662 SSVAL(outbuf,smb_vwv0,fnum);
663 SSVAL(outbuf,smb_vwv1,n);
664 SIVAL(outbuf,smb_vwv2,low);
665 SSVAL(outbuf,smb_vwv4,left);
666 CVAL(smb_buf(outbuf),0) = 1;
667 SSVAL(smb_buf(outbuf),1,n);
669 send_smb(Client,outbuf);
670 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
672 if (CVAL(inbuf,smb_rcls) != 0)
674 DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
675 return False;
678 if (n != SVAL(inbuf,smb_vwv0))
680 DEBUG(0,("Error: only wrote %d bytes out of %d\n",
681 SVAL(inbuf,smb_vwv0), n));
682 return False;
685 return True;
688 /****************************************************************************
689 Close a file on a share
690 ***************************************************************************/
691 static BOOL smbshut(file_info finfo, int fnum, char *inbuf, char *outbuf)
693 /* *must* be called with buffer ready malloc'ed */
695 memset(outbuf,0,smb_size);
696 set_message(outbuf,3,0,True);
697 CVAL(outbuf,smb_com) = SMBclose;
698 SSVAL(outbuf,smb_tid,cnum);
699 cli_setup_pkt(outbuf);
701 SSVAL(outbuf,smb_vwv0,fnum);
702 put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
704 DEBUG(3,("Setting date to %s (0x%X)",
705 asctime(LocalTime(&finfo.mtime)),
706 finfo.mtime));
708 send_smb(Client,outbuf);
709 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
711 if (CVAL(inbuf,smb_rcls) != 0)
713 DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),
714 finfo.name));
715 return False;
718 return True;
721 /****************************************************************************
722 Verify existence of path on share
723 ***************************************************************************/
724 static BOOL smbchkpath(char *fname, char *inbuf, char *outbuf)
726 char *p;
728 memset(outbuf,0,smb_size);
729 set_message(outbuf,0,4 + strlen(fname),True);
730 CVAL(outbuf,smb_com) = SMBchkpth;
731 SSVAL(outbuf,smb_tid,cnum);
732 cli_setup_pkt(outbuf);
734 p = smb_buf(outbuf);
735 *p++ = 4;
736 strcpy(p,fname);
738 send_smb(Client,outbuf);
739 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
741 DEBUG(5,("smbchkpath: %s\n",smb_errstr(inbuf)));
743 return(CVAL(inbuf,smb_rcls) == 0);
746 /****************************************************************************
747 Make a directory on share
748 ***************************************************************************/
749 static BOOL smbmkdir(char *fname, char *inbuf, char *outbuf)
751 /* *must* be called with buffer ready malloc'ed */
752 char *p;
754 memset(outbuf,0,smb_size);
755 set_message(outbuf,0,2 + strlen(fname),True);
757 CVAL(outbuf,smb_com) = SMBmkdir;
758 SSVAL(outbuf,smb_tid,cnum);
759 cli_setup_pkt(outbuf);
761 p = smb_buf(outbuf);
762 *p++ = 4;
763 strcpy(p,fname);
765 send_smb(Client,outbuf);
766 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
768 if (CVAL(inbuf,smb_rcls) != 0)
770 DEBUG(0,("%s making remote directory %s\n",
771 smb_errstr(inbuf),fname));
772 return(False);
775 return(True);
778 /****************************************************************************
779 Ensure a remote path exists (make if necessary)
780 ***************************************************************************/
781 static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
783 /* *must* be called with buffer ready malloc'ed */
784 /* ensures path exists */
786 pstring partpath, ffname;
787 char *p=fname, *basehack;
789 DEBUG(5, ( "Ensurepath called with: %s\n", fname));
791 *partpath = 0;
793 /* fname copied to ffname so can strtok */
795 strcpy(ffname, fname);
797 /* do a `basename' on ffname, so don't try and make file name directory */
798 if ((basehack=strrchr(ffname, '\\')) == NULL)
799 return True;
800 else
801 *basehack='\0';
803 p=strtok(ffname, "\\");
805 while (p)
807 strcat(partpath, p);
809 if (!smbchkpath(partpath, inbuf, outbuf)) {
810 if (!smbmkdir(partpath, inbuf, outbuf))
812 DEBUG(0, ("Error mkdirhiering\n"));
813 return False;
815 else
816 DEBUG(3, ("mkdirhiering %s\n", partpath));
820 strcat(partpath, "\\");
821 p = strtok(NULL,"/\\");
824 return True;
827 int padit(char *buf, int bufsize, int padsize)
829 int berr= 0;
830 int bytestowrite;
832 DEBUG(0, ("Padding with %d zeros\n", padsize));
833 memset(buf, 0, bufsize);
834 while( !berr && padsize > 0 ) {
835 bytestowrite= MIN(bufsize, padsize);
836 berr = dotarbuf(tarhandle, buf, bytestowrite) != bytestowrite;
837 padsize -= bytestowrite;
840 return berr;
844 * smbclient functions
846 /****************************************************************************
847 append one remote file to the tar file
848 ***************************************************************************/
849 static void do_atar(char *rname,char *lname,file_info *finfo1)
851 int fnum;
852 uint32 nread=0;
853 char *p, ftype;
854 char *inbuf,*outbuf;
855 file_info finfo;
856 BOOL close_done = False;
857 BOOL shallitime=True;
858 BOOL ignore_close_error = False;
859 char *dataptr=NULL;
860 int datalen=0;
862 struct timeval tp_start;
863 GetTimeOfDay(&tp_start);
865 ftype = '0'; /* An ordinary file ... */
867 if (finfo1)
868 finfo = *finfo1;
869 else
870 finfo = def_finfo;
872 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
873 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
875 if (!inbuf || !outbuf)
877 DEBUG(0,("out of memory\n"));
878 return;
881 memset(outbuf,0,smb_size);
882 set_message(outbuf,15,1 + strlen(rname),True);
884 CVAL(outbuf,smb_com) = SMBopenX;
885 SSVAL(outbuf,smb_tid,cnum);
886 cli_setup_pkt(outbuf);
888 SSVAL(outbuf,smb_vwv0,0xFF);
889 SSVAL(outbuf,smb_vwv2,1);
890 SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
891 SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
892 SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
893 SSVAL(outbuf,smb_vwv8,1);
895 p = smb_buf(outbuf);
896 strcpy(p,rname);
897 p = skip_string(p,1);
899 dos_clean_name(rname);
901 /* do a chained openX with a readX? */
902 if (finfo.size > 0)
904 SSVAL(outbuf,smb_vwv0,SMBreadX);
905 SSVAL(outbuf,smb_vwv1,PTR_DIFF(p,outbuf) - 4);
906 memset(p,0,200);
907 p -= smb_wct;
908 SSVAL(p,smb_wct,10);
909 SSVAL(p,smb_vwv0,0xFF);
910 SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
911 SSVAL(p,smb_vwv9,MIN(0xFFFF,finfo.size));
912 smb_setlen(outbuf,smb_len(outbuf)+11*2+1);
915 send_smb(Client,outbuf);
916 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
918 if (CVAL(inbuf,smb_rcls) != 0)
920 if (CVAL(inbuf,smb_rcls) == ERRSRV &&
921 SVAL(inbuf,smb_err) == ERRnoresource &&
922 cli_reopen_connection(inbuf,outbuf))
924 do_atar(rname,lname,finfo1);
925 free(inbuf);free(outbuf);
926 return;
929 DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),rname));
930 free(inbuf);free(outbuf);
931 return;
934 strcpy(finfo.name,rname);
935 if (!finfo1)
937 finfo.mode = SVAL(inbuf,smb_vwv3);
938 finfo.size = IVAL(inbuf,smb_vwv4);
939 finfo.mtime = make_unix_date3(inbuf+smb_vwv6);
940 finfo.atime = finfo.ctime = finfo.mtime;
943 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
945 fnum = SVAL(inbuf,smb_vwv2);
947 if (tar_inc && !(finfo.mode & aARCH))
949 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
950 shallitime=0;
952 else if (!tar_system && (finfo.mode & aSYSTEM))
954 DEBUG(4, ("skipping %s - system bit is set\n", finfo.name));
955 shallitime=0;
957 else if (!tar_hidden && (finfo.mode & aHIDDEN))
959 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo.name));
960 shallitime=0;
962 else
964 if (SVAL(inbuf,smb_vwv0) == SMBreadX)
966 p = (inbuf+4+SVAL(inbuf,smb_vwv1)) - smb_wct;
967 datalen = SVAL(p,smb_vwv5);
968 dataptr = inbuf + 4 + SVAL(p,smb_vwv6);
970 else
972 dataptr = NULL;
973 datalen = 0;
976 DEBUG(2,("getting file %s of size %d bytes as a tar file %s",
977 finfo.name,
978 finfo.size,
979 lname));
981 /* write a tar header, don't bother with mode - just set to 100644 */
982 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0", ftype);
984 while (nread < finfo.size && !close_done)
986 int method = -1;
987 static BOOL can_chain_close=True;
989 p=NULL;
991 DEBUG(3,("nread=%d\n",nread));
993 /* 3 possible read types. readbraw if a large block is required.
994 readX + close if not much left and read if neither is supported */
996 /* we might have already read some data from a chained readX */
997 if (dataptr && datalen>0)
998 method=3;
1000 /* if we can finish now then readX+close */
1001 if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) &&
1002 ((finfo.size - nread) <
1003 (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
1004 method = 0;
1006 /* if we support readraw then use that */
1007 if (method<0 && readbraw_supported)
1008 method = 1;
1010 /* if we can then use readX */
1011 if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
1012 method = 2;
1015 switch (method)
1017 /* use readX */
1018 case 0:
1019 case 2:
1020 if (method == 0)
1021 close_done = True;
1023 /* use readX + close */
1024 memset(outbuf,0,smb_size);
1025 set_message(outbuf,10,0,True);
1026 CVAL(outbuf,smb_com) = SMBreadX;
1027 SSVAL(outbuf,smb_tid,cnum);
1028 cli_setup_pkt(outbuf);
1030 if (close_done)
1032 CVAL(outbuf,smb_vwv0) = SMBclose;
1033 SSVAL(outbuf,smb_vwv1,PTR_DIFF(smb_buf(outbuf),outbuf) - 4);
1035 else
1036 CVAL(outbuf,smb_vwv0) = 0xFF;
1039 SSVAL(outbuf,smb_vwv2,fnum);
1040 SIVAL(outbuf,smb_vwv3,nread);
1041 SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
1042 SSVAL(outbuf,smb_vwv6,0);
1043 SIVAL(outbuf,smb_vwv7,0);
1044 SSVAL(outbuf,smb_vwv9,MIN(0xFFFF,finfo.size-nread));
1046 if (close_done)
1048 p = smb_buf(outbuf);
1049 memset(p,0,9);
1051 CVAL(p,0) = 3;
1052 SSVAL(p,1,fnum);
1053 SIVALS(p,3,-1);
1055 /* now set the total packet length */
1056 smb_setlen(outbuf,smb_len(outbuf)+9);
1059 send_smb(Client,outbuf);
1060 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1062 if (CVAL(inbuf,smb_rcls) != 0)
1064 DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1065 break;
1068 if (close_done &&
1069 SVAL(inbuf,smb_vwv0) != SMBclose)
1071 /* NOTE: WfWg sometimes just ignores the chained
1072 command! This seems to break the spec? */
1073 DEBUG(3,("Rejected chained close?\n"));
1074 close_done = False;
1075 can_chain_close = False;
1076 ignore_close_error = True;
1079 datalen = SVAL(inbuf,smb_vwv5);
1080 dataptr = inbuf + 4 + SVAL(inbuf,smb_vwv6);
1081 break;
1084 /* use readbraw */
1085 case 1:
1087 static int readbraw_size = 0xFFFF;
1089 extern int Client;
1090 memset(outbuf,0,smb_size);
1091 set_message(outbuf,8,0,True);
1092 CVAL(outbuf,smb_com) = SMBreadbraw;
1093 SSVAL(outbuf,smb_tid,cnum);
1094 cli_setup_pkt(outbuf);
1095 SSVAL(outbuf,smb_vwv0,fnum);
1096 SIVAL(outbuf,smb_vwv1,nread);
1097 SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
1098 SSVAL(outbuf,smb_vwv4,0);
1099 SIVALS(outbuf,smb_vwv5,-1);
1100 send_smb(Client,outbuf);
1102 /* Now read the raw data into the buffer and write it */
1103 if(read_smb_length(Client,inbuf,0) == -1) {
1104 DEBUG(0,("Failed to read length in readbraw\n"));
1105 exit(1);
1108 /* Even though this is not an smb message, smb_len
1109 returns the generic length of an smb message */
1110 datalen = smb_len(inbuf);
1112 if (datalen == 0)
1114 /* we got a readbraw error */
1115 DEBUG(4,("readbraw error - reducing size\n"));
1116 readbraw_size = (readbraw_size * 9) / 10;
1118 if (readbraw_size < max_xmit)
1120 DEBUG(0,("disabling readbraw\n"));
1121 readbraw_supported = False;
1124 dataptr=NULL;
1125 continue;
1128 if(read_data(Client,inbuf,datalen) != datalen) {
1129 DEBUG(0,("Failed to read data in readbraw\n"));
1130 exit(1);
1132 dataptr = inbuf;
1134 break;
1136 case 3:
1137 /* we've already read some data with a chained readX */
1138 break;
1140 default:
1141 /* use plain read */
1142 memset(outbuf,0,smb_size);
1143 set_message(outbuf,5,0,True);
1144 CVAL(outbuf,smb_com) = SMBread;
1145 SSVAL(outbuf,smb_tid,cnum);
1146 cli_setup_pkt(outbuf);
1148 SSVAL(outbuf,smb_vwv0,fnum);
1149 SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
1150 SIVAL(outbuf,smb_vwv2,nread);
1151 SSVAL(outbuf,smb_vwv4,finfo.size - nread);
1153 send_smb(Client,outbuf);
1154 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1156 if (CVAL(inbuf,smb_rcls) != 0)
1158 DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1159 break;
1162 datalen = SVAL(inbuf,smb_vwv0);
1163 dataptr = smb_buf(inbuf) + 3;
1164 break;
1168 /* add received bits of file to buffer - dotarbuf will
1169 * write out in 512 byte intervals */
1170 if (dotarbuf(tarhandle,dataptr,datalen) != datalen)
1172 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno)));
1173 break;
1176 nread += datalen;
1177 if (datalen == 0)
1179 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
1180 break;
1183 dataptr=NULL;
1184 datalen=0;
1187 /* pad tar file with zero's if we couldn't get entire file */
1188 if (nread < finfo.size)
1190 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo.size, nread));
1191 if (padit(inbuf, BUFFER_SIZE, finfo.size - nread))
1192 DEBUG(0,("Error writing tar file - %s\n", strerror(errno)));
1195 /* round tar file to nearest block */
1196 if (finfo.size % TBLOCK)
1197 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
1199 ttarf+=finfo.size + TBLOCK - (finfo.size % TBLOCK);
1200 ntarf++;
1203 if (!close_done)
1205 memset(outbuf,0,smb_size);
1206 set_message(outbuf,3,0,True);
1207 CVAL(outbuf,smb_com) = SMBclose;
1208 SSVAL(outbuf,smb_tid,cnum);
1209 cli_setup_pkt(outbuf);
1211 SSVAL(outbuf,smb_vwv0,fnum);
1212 SIVALS(outbuf,smb_vwv1,-1);
1214 send_smb(Client,outbuf);
1215 client_receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1217 if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
1219 DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
1220 free(inbuf);free(outbuf);
1221 return;
1225 if (shallitime)
1227 struct timeval tp_end;
1228 int this_time;
1230 /* if shallitime is true then we didn't skip */
1231 if (tar_reset) (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
1233 GetTimeOfDay(&tp_end);
1234 this_time =
1235 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1236 (tp_end.tv_usec - tp_start.tv_usec)/1000;
1237 get_total_time_ms += this_time;
1238 get_total_size += finfo.size;
1240 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
1241 DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
1242 finfo.size / MAX(0.001, (1.024*this_time)),
1243 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
1244 if (tar_noisy)
1246 printf("%10d (%7.1f kb/s) %s\n",
1247 finfo.size, finfo.size / MAX(0.001, (1.024*this_time)),
1248 finfo.name);
1253 free(inbuf);free(outbuf);
1256 /****************************************************************************
1257 Append single file to tar file (or not)
1258 ***************************************************************************/
1259 static void do_tar(file_info *finfo)
1261 pstring rname;
1263 if (strequal(finfo->name,".."))
1264 return;
1266 /* Is it on the exclude list ? */
1267 if (!tar_excl && clipn) {
1268 pstring exclaim;
1270 strcpy(exclaim, cur_dir);
1271 *(exclaim+strlen(exclaim)-1)='\0';
1273 strcat(exclaim, "\\");
1274 strcat(exclaim, finfo->name);
1276 if (clipfind(cliplist, clipn, exclaim)) {
1277 DEBUG(3,("Skipping file %s\n", exclaim));
1278 return;
1282 if (finfo->mode & aDIR)
1284 pstring saved_curdir;
1285 pstring mtar_mask;
1286 char *inbuf,*outbuf;
1288 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1289 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1291 if (!inbuf || !outbuf)
1293 DEBUG(0,("out of memory\n"));
1294 return;
1297 strcpy(saved_curdir,cur_dir);
1299 strcat(cur_dir,finfo->name);
1300 strcat(cur_dir,"\\");
1302 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir));
1304 /* write a tar directory, don't bother with mode - just set it to
1305 * 40755 */
1306 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0", '5');
1307 ntarf++; /* Make sure we have a file on there */
1308 strcpy(mtar_mask,cur_dir);
1309 strcat(mtar_mask,"*");
1310 /* do_dir((char *)inbuf,(char *)outbuf,mtar_mask,attribute,do_tar,recurse,True); */
1311 strcpy(cur_dir,saved_curdir);
1312 free(inbuf);free(outbuf);
1314 else
1316 strcpy(rname,cur_dir);
1317 strcat(rname,finfo->name);
1318 do_atar(rname,finfo->name,finfo);
1322 /****************************************************************************
1323 Convert from UNIX to DOS file names
1324 ***************************************************************************/
1325 static void unfixtarname(char *tptr, char *fp, int l)
1327 /* remove '.' from start of file name, convert from unix /'s to
1328 * dos \'s in path. Kill any absolute path names.
1331 if (*fp == '.') fp++;
1332 if (*fp == '\\' || *fp == '/') fp++;
1334 while (l > 0) {
1335 int skip;
1336 if(( skip = skip_multibyte_char( *fp )) != 0) {
1337 if (skip == 2) {
1338 *tptr++ = *fp++;
1339 *tptr++ = *fp++;
1340 l -= 2;
1341 } else if (skip == 1) {
1342 *tptr++ = *fp++;
1343 l--;
1345 } else if (*fp == '/') {
1346 *tptr++ = '\\';
1347 fp++;
1348 l--;
1349 } else {
1350 *tptr++ = *fp++;
1351 l--;
1356 /****************************************************************************
1357 Move to the next block in the buffer, which may mean read in another set of
1358 blocks.
1359 ****************************************************************************/
1360 int next_block(char *tarbuf, char *bufferp, int bufsiz)
1362 int bufread, total = 0;
1364 for (bufread = read(tarhandle, tarbuf, bufsiz); total += bufread; total < bufsiz) {
1370 static void do_tarput()
1372 file_info finfo;
1373 int nread=0, bufread;
1374 char *inbuf,*outbuf, *longname = NULL;
1375 int fsize=0;
1376 int fnum;
1377 struct timeval tp_start;
1378 BOOL tskip=False; /* We'll take each file as it comes */
1380 GetTimeOfDay(&tp_start);
1382 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1383 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1385 if (!inbuf || !outbuf)
1387 DEBUG(0,("out of memory\n"));
1388 return;
1392 * Must read in tbufsiz dollops
1395 /* These should be the only reads in clitar.c */
1396 while ((bufread=read(tarhandle, tarbuf, tbufsiz))>0) {
1397 char *bufferp, *endofbuffer;
1398 int chunk;
1400 /* Code to handle a short read.
1401 * We always need a TBLOCK full of stuff
1403 if (bufread % TBLOCK) {
1404 int lchunk=TBLOCK-(bufread % TBLOCK);
1405 int lread;
1407 /* It's a shorty - a short read that is */
1408 DEBUG(3, ("Short read, read %d so far (need %d)\n", bufread, lchunk));
1410 while ((lread=read(tarhandle, tarbuf+bufread, lchunk))>0) {
1411 bufread+=lread;
1412 if (!(lchunk-=lread)) break;
1415 /* If we've reached EOF then that must be a short file */
1416 if (lread<=0) break;
1419 bufferp=tarbuf;
1420 endofbuffer=tarbuf+bufread;
1422 if (tskip) {
1423 if (fsize<bufread) {
1424 tskip=False;
1425 bufferp+=fsize;
1426 fsize=0;
1427 } else {
1428 if (fsize==bufread) tskip=False;
1429 fsize-=bufread;
1430 continue;
1434 do {
1435 if (!fsize)
1437 int next_header = 1; /* Want at least one header */
1438 while (next_header)
1440 if (bufferp >= endofbuffer) {
1442 bufread = read(tarhandle, tarbuf, tbufsiz);
1443 bufferp = tarbuf;
1446 next_header = 0; /* Don't want the next one ... */
1447 switch (readtarheader((union hblock *) bufferp, &finfo, cur_dir))
1449 case -2: /* something dodgy but not fatal about this */
1450 DEBUG(0, ("skipping %s...\n", finfo.name));
1451 bufferp+=TBLOCK; /* header - like a link */
1452 continue;
1453 case -1:
1454 DEBUG(0, ("abandoning restore, -1 from readtarheader\n"));
1455 free(inbuf); free(outbuf);
1456 return;
1457 case 0: /* chksum is zero - we assume that one all zero
1458 *header block will do for eof */
1459 DEBUG(0,
1460 ("total of %d tar files restored to share\n", ntarf));
1461 free(inbuf); free(outbuf);
1462 return;
1463 default:
1464 break;
1467 /* If we have a longname left from the last time through,
1468 copy it into finfo.name and free it.
1470 The size of a pstring is the limiting factor on filenames
1471 and directory names now. The total pathname length must be
1472 less than sizeof(pstring) - 1, which is currently 1023. */
1474 if (longname != NULL) {
1476 strncpy(finfo.name, longname, sizeof(pstring) - 1);
1477 free(longname);
1478 longname = NULL;
1482 /* Check if a long-link. We do this before the clip checking
1483 because clip-checking should clip on real name - RJS */
1485 if (((union hblock *)bufferp) -> dbuf.linkflag == 'L') {
1487 /* Skip this header, but pick up length, get the name and
1488 fix the name and skip the name. Hmmm, what about end of
1489 buffer??? */
1491 longname = malloc(finfo.size + strlen(cur_dir) + 1);
1492 if (longname == NULL) {
1494 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1495 finfo.size + strlen(cur_dir) + 1)
1497 free(inbuf); free(outbuf);
1498 return;
1501 bufferp += TBLOCK; /* Skip that longlink header */
1503 /* This needs restructuring ... */
1505 if (bufferp >= endofbuffer) {
1507 bufread = read(tarhandle, tarbuf, tbufsiz);
1509 bufferp = tarbuf;
1513 strncpy(longname, cur_dir, strlen(cur_dir));
1514 unfixtarname(longname+strlen(cur_dir), bufferp, finfo.size);
1516 /* Next rounds up to next TBLOCK and takes care of us being right
1517 on a TBLOCK boundary */
1519 bufferp += (((finfo.size - 1)/TBLOCK)+1)*TBLOCK;
1520 next_header = 1; /* Force read of next header */
1524 tskip=clipn
1525 && (clipfind(cliplist, clipn, finfo.name) ^ tar_excl);
1526 if (tskip) {
1527 bufferp+=TBLOCK;
1528 if (finfo.mode & aDIR)
1529 continue;
1530 else if ((fsize=finfo.size) % TBLOCK) {
1531 fsize+=TBLOCK-(fsize%TBLOCK);
1533 if (fsize<endofbuffer-bufferp) {
1534 bufferp+=fsize;
1535 fsize=0;
1536 continue;
1537 } else {
1538 fsize-=endofbuffer-bufferp;
1539 break;
1543 DEBUG(5, ("do_tarput: File is: %s\n", finfo.name));
1545 if (finfo.mode & aDIR)
1547 if (!ensurepath(finfo.name, inbuf, outbuf))
1548 /* if (!smbchkpath(finfo.name, inbuf, outbuf)
1549 && !smbmkdir(finfo.name, inbuf, outbuf))*/
1551 DEBUG(0, ("abandoning restore, problems ensuring path\n"));
1552 free(inbuf); free(outbuf);
1553 return;
1555 else
1557 /* Now we update the creation date ... */
1559 DEBUG(5, ("Updating creation date on %s\n", finfo.name));
1561 if (!do_setrtime(finfo.name, finfo.mtime)) {
1563 DEBUG(0, ("Could not set time on file: %s\n", finfo.name));
1564 return;
1568 ntarf++;
1569 bufferp+=TBLOCK;
1570 continue;
1574 fsize=finfo.size;
1576 if (ensurepath(finfo.name, inbuf, outbuf)
1577 && !smbcreat(finfo, &fnum, inbuf, outbuf))
1579 DEBUG(0, ("abandoning restore\n"));
1580 free(inbuf);free(outbuf);
1581 return;
1584 DEBUG(0 ,("restore tar file %s of size %d bytes\n",
1585 finfo.name,finfo.size));
1587 if (!finfo.size) {
1588 if (!smbshut(finfo, fnum, inbuf, outbuf)){
1589 DEBUG(0, ("Error closing remote file of length 0: %s\n", finfo.name));
1590 free(inbuf);free(outbuf);
1591 return;
1595 nread=0;
1596 if ((bufferp+=TBLOCK) >= endofbuffer) break;
1597 } /* if (!fsize) */
1599 /* write out the file in chunk sized chunks - don't
1600 * go past end of buffer though */
1601 chunk=(fsize-nread < endofbuffer - bufferp)
1602 ? fsize - nread : endofbuffer - bufferp;
1604 while (chunk > 0) {
1605 int minichunk=MIN(chunk, max_xmit-200);
1607 if (!smbwrite(fnum, /* file descriptor */
1608 minichunk, /* n */
1609 nread, /* offset low */
1610 0, /* offset high - not implemented */
1611 fsize-nread, /* left - only hint to server */
1612 bufferp,
1613 inbuf,
1614 outbuf))
1616 DEBUG(0, ("Error writing remote file\n"));
1617 free(inbuf); free(outbuf);
1618 return;
1620 DEBUG(5, ("chunk writing fname=%s fnum=%d nread=%d minichunk=%d chunk=%d size=%d\n", finfo.name, fnum, nread, minichunk, chunk, fsize));
1622 bufferp+=minichunk; nread+=minichunk;
1623 chunk-=minichunk;
1626 if (nread>=fsize)
1628 if (!smbshut(finfo, fnum, inbuf, outbuf))
1630 DEBUG(0, ("Error closing remote file\n"));
1631 free(inbuf);free(outbuf);
1632 return;
1634 if (fsize % TBLOCK) bufferp+=TBLOCK - (fsize % TBLOCK);
1635 DEBUG(5, ("bufferp is now %d (psn=%d)\n",
1636 (long) bufferp, (long)(bufferp - tarbuf)));
1637 ntarf++;
1638 fsize=0;
1640 } while (bufferp < endofbuffer);
1643 DEBUG(0, ("premature eof on tar file ?\n"));
1644 DEBUG(0,("total of %d tar files restored to share\n", ntarf));
1646 free(inbuf); free(outbuf);
1650 * samba interactive commands
1653 /****************************************************************************
1654 Blocksize command
1655 ***************************************************************************/
1656 void cmd_block(void)
1658 fstring buf;
1659 int block;
1661 if (!next_token(NULL,buf,NULL))
1663 DEBUG(0, ("blocksize <n>\n"));
1664 return;
1667 block=atoi(buf);
1668 if (block < 0 || block > 65535)
1670 DEBUG(0, ("blocksize out of range"));
1671 return;
1674 blocksize=block;
1675 DEBUG(2,("blocksize is now %d\n", blocksize));
1678 /****************************************************************************
1679 command to set incremental / reset mode
1680 ***************************************************************************/
1681 void cmd_tarmode(void)
1683 fstring buf;
1685 while (next_token(NULL,buf,NULL)) {
1686 if (strequal(buf, "full"))
1687 tar_inc=False;
1688 else if (strequal(buf, "inc"))
1689 tar_inc=True;
1690 else if (strequal(buf, "reset"))
1691 tar_reset=True;
1692 else if (strequal(buf, "noreset"))
1693 tar_reset=False;
1694 else if (strequal(buf, "system"))
1695 tar_system=True;
1696 else if (strequal(buf, "nosystem"))
1697 tar_system=False;
1698 else if (strequal(buf, "hidden"))
1699 tar_hidden=True;
1700 else if (strequal(buf, "nohidden"))
1701 tar_hidden=False;
1702 else if (strequal(buf, "verbose") || strequal(buf, "noquiet"))
1703 tar_noisy=True;
1704 else if (strequal(buf, "quiet") || strequal(buf, "noverbose"))
1705 tar_noisy=False;
1706 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1709 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1710 tar_inc ? "incremental" : "full",
1711 tar_system ? "system" : "nosystem",
1712 tar_hidden ? "hidden" : "nohidden",
1713 tar_reset ? "reset" : "noreset",
1714 tar_noisy ? "verbose" : "quiet"));
1718 /****************************************************************************
1719 Feeble attrib command
1720 ***************************************************************************/
1721 void cmd_setmode(void)
1723 char *q;
1724 fstring buf;
1725 pstring fname;
1726 int attra[2];
1727 int direct=1;
1729 attra[0] = attra[1] = 0;
1731 if (!next_token(NULL,buf,NULL))
1733 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1734 return;
1737 strcpy(fname, cur_dir);
1738 strcat(fname, buf);
1740 while (next_token(NULL,buf,NULL)) {
1741 q=buf;
1743 while(*q)
1744 switch (*q++) {
1745 case '+': direct=1;
1746 break;
1747 case '-': direct=0;
1748 break;
1749 case 'r': attra[direct]|=aRONLY;
1750 break;
1751 case 'h': attra[direct]|=aHIDDEN;
1752 break;
1753 case 's': attra[direct]|=aSYSTEM;
1754 break;
1755 case 'a': attra[direct]|=aARCH;
1756 break;
1757 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1758 return;
1762 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1764 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1765 return;
1768 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1769 (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
1770 (void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1773 /****************************************************************************
1774 Principal command for creating / extracting
1775 ***************************************************************************/
1776 void cmd_tar(char *inbuf, char *outbuf)
1778 fstring buf;
1779 char **argl;
1780 int argcl;
1782 if (!next_token(NULL,buf,NULL))
1784 DEBUG(0,("tar <c|x>[IXbga] <filename>\n"));
1785 return;
1788 argl=toktocliplist(&argcl, NULL);
1789 if (!tar_parseargs(argcl, argl, buf, 0))
1790 return;
1792 process_tar(inbuf, outbuf);
1794 free(argl);
1797 /****************************************************************************
1798 Command line (option) version
1799 ***************************************************************************/
1800 int process_tar(char *inbuf, char *outbuf)
1802 initarbuf();
1803 switch(tar_type) {
1804 case 'x':
1805 do_tarput();
1806 free(tarbuf);
1807 close(tarhandle);
1808 break;
1809 case 'r':
1810 case 'c':
1811 if (clipn && tar_excl) {
1812 int i;
1813 pstring tarmac;
1815 for (i=0; i<clipn; i++) {
1816 DEBUG(0,("arg %d = %s\n", i, cliplist[i]));
1818 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1819 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1822 if (strrchr(cliplist[i], '\\')) {
1823 pstring saved_dir;
1825 strcpy(saved_dir, cur_dir);
1827 if (*cliplist[i]=='\\') {
1828 strcpy(tarmac, cliplist[i]);
1829 } else {
1830 strcpy(tarmac, cur_dir);
1831 strcat(tarmac, cliplist[i]);
1833 strcpy(cur_dir, tarmac);
1834 *(strrchr(cur_dir, '\\')+1)='\0';
1836 do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True);
1837 strcpy(cur_dir,saved_dir);
1838 } else {
1839 strcpy(tarmac, cur_dir);
1840 strcat(tarmac, cliplist[i]);
1841 do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse, True);
1844 } else {
1845 pstring mask;
1846 strcpy(mask,cur_dir);
1847 strcat(mask,"\\*");
1848 do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_tar,recurse, True);
1851 if (ntarf) dotareof(tarhandle);
1852 close(tarhandle);
1853 free(tarbuf);
1855 DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1856 DEBUG(0, ("Total bytes written: %d\n", ttarf));
1857 break;
1860 return(0);
1863 /****************************************************************************
1864 Find a token (filename) in a clip list
1865 ***************************************************************************/
1866 int clipfind(char **aret, int ret, char *tok)
1868 if (aret==NULL) return 0;
1870 /* ignore leading slashes or dots in token */
1871 while(strchr("/\\.", *tok)) tok++;
1873 while(ret--) {
1874 char *pkey=*aret++;
1876 /* ignore leading slashes or dots in list */
1877 while(strchr("/\\.", *pkey)) pkey++;
1879 if (!strslashcmp(pkey, tok)) return 1;
1882 return 0;
1885 /****************************************************************************
1886 Parse tar arguments. Sets tar_type, tar_excl, etc.
1887 ***************************************************************************/
1888 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1890 char tar_clipfl='\0';
1892 /* Reset back to defaults - could be from interactive version
1893 * reset mode and archive mode left as they are though
1895 tar_type='\0';
1896 tar_excl=True;
1898 while (*Optarg)
1899 switch(*Optarg++) {
1900 case 'c':
1901 tar_type='c';
1902 break;
1903 case 'x':
1904 if (tar_type=='c') {
1905 printf("Tar must be followed by only one of c or x.\n");
1906 return 0;
1908 tar_type='x';
1909 break;
1910 case 'b':
1911 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1912 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1913 return 0;
1914 } else {
1915 Optind++;
1917 break;
1918 case 'g':
1919 tar_inc=True;
1920 break;
1921 case 'N':
1922 if (Optind>=argc) {
1923 DEBUG(0,("Option N must be followed by valid file name\n"));
1924 return 0;
1925 } else {
1926 struct stat stbuf;
1927 extern time_t newer_than;
1929 if (sys_stat(argv[Optind], &stbuf) == 0) {
1930 newer_than = stbuf.st_mtime;
1931 DEBUG(1,("Getting files newer than %s",
1932 asctime(LocalTime(&newer_than))));
1933 Optind++;
1934 } else {
1935 DEBUG(0,("Error setting newer-than time\n"));
1936 return 0;
1939 break;
1940 case 'a':
1941 tar_reset=True;
1942 break;
1943 case 'I':
1944 if (tar_clipfl) {
1945 DEBUG(0,("Only one of I,X must be specified\n"));
1946 return 0;
1948 tar_clipfl='I';
1949 break;
1950 case 'X':
1951 if (tar_clipfl) {
1952 DEBUG(0,("Only one of I,X must be specified\n"));
1953 return 0;
1955 tar_clipfl='X';
1956 break;
1957 default:
1958 DEBUG(0,("Unknown tar option\n"));
1959 return 0;
1962 if (!tar_type) {
1963 printf("Option T must be followed by one of c or x.\n");
1964 return 0;
1967 tar_excl=tar_clipfl!='X';
1968 if (Optind+1<argc) {
1969 char *tmpstr;
1970 char **tmplist;
1971 int clipcount;
1973 cliplist=argv+Optind+1;
1974 clipn=argc-Optind-1;
1975 clipcount = clipn;
1977 if ((tmplist=malloc(clipn*sizeof(char *))) == NULL) {
1978 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1979 clipn)
1981 return 0;
1984 for (clipcount = 0; clipcount < clipn; clipcount++) {
1986 DEBUG(5, ("Processing an item, %s\n", cliplist[clipcount]));
1988 if ((tmpstr = (char *)malloc(strlen(cliplist[clipcount])+1)) == NULL) {
1989 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1990 clipcount)
1992 return 0;
1994 unfixtarname(tmpstr, cliplist[clipcount], strlen(cliplist[clipcount]) + 1);
1995 tmplist[clipcount] = tmpstr;
1996 DEBUG(5, ("Processed an item, %s\n", tmpstr));
1998 DEBUG(5, ("Cliplist is: %s\n", cliplist[0]));
2000 cliplist = tmplist;
2002 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
2003 /* Sets tar handle to either 0 or 1, as appropriate */
2004 tarhandle=(tar_type=='c');
2005 } else {
2006 if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
2007 || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
2009 DEBUG(0,("Error opening local file %s - %s\n",
2010 argv[Optind], strerror(errno)));
2011 return(0);
2015 return 1;