2 Unix SMB/Netbios implementation.
5 Copyright (C) Ricky Poulten 1995
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.
28 #define SEPARATORS " \t\n\r"
29 extern int DEBUGLEVEL;
32 /* These defines are for the do_setrattr routine, to indicate
33 * setting and reseting of file attributes in the function call */
37 static int attribute = aDIR | aSYSTEM | aHIDDEN;
39 #ifndef CLIENT_TIMEOUT
40 #define CLIENT_TIMEOUT (30*1000)
44 static int tp, ntarf, tbufsiz;
45 /* Incremental mode */
47 /* Reset archive bit */
49 /* Include / exclude mode (true=include, false=exclude) */
52 static char **cliplist=NULL;
55 extern file_info def_finfo;
56 extern BOOL lowercase;
58 extern BOOL readbraw_supported;
60 extern pstring cur_dir;
61 extern int get_total_time_ms;
62 extern int get_total_size;
68 static void writetarheader();
69 static void do_atar();
72 static void fixtarname();
73 static int dotarbuf();
74 static void dozerobuf();
75 static void dotareof();
76 static void initarbuf();
77 static int do_setrattr();
79 /* restore functions */
80 static long readtarheader();
82 static void do_tarput();
83 static void unfixtarname();
86 * tar specific utitlities
89 /****************************************************************************
90 Write a tar header to buffer
91 ****************************************************************************/
92 static void writetarheader(int f, char *aname, int size, time_t mtime,
99 memset(hb.dummy, 0, sizeof(hb.dummy));
104 DEBUG(0, ("tar file %s name length exceeds NAMSIZ\n", aname));
107 /* use l + 1 to do the null too */
108 fixtarname(hb.dbuf.name, aname, (l >= NAMSIZ) ? NAMSIZ : l + 1);
111 strlower(hb.dbuf.name);
113 /* write out a "standard" tar format header */
115 hb.dbuf.name[NAMSIZ-1]='\0';
116 strcpy(hb.dbuf.mode, amode);
117 oct_it(0L, 8, hb.dbuf.uid);
118 oct_it(0L, 8, hb.dbuf.gid);
119 oct_it((long) size, 13, hb.dbuf.size);
120 oct_it((long) mtime, 13, hb.dbuf.mtime);
121 memcpy(hb.dbuf.chksum, " ", sizeof(hb.dbuf.chksum));
122 hb.dbuf.linkflag='0';
123 memset(hb.dbuf.linkname, 0, NAMSIZ);
125 for (chk=0, i=sizeof(hb.dummy), jp=hb.dummy; --i>=0;) chk+=(0xFF & *jp++);
127 oct_it((long) chk, 8, hb.dbuf.chksum);
128 hb.dbuf.chksum[6] = '\0';
130 (void) dotarbuf(f, hb.dummy, sizeof(hb.dummy));
133 /****************************************************************************
134 Read a tar header into a hblock structure, and validate
135 ***************************************************************************/
136 static long readtarheader(union hblock *hb, file_info *finfo, char *prefix)
143 * read in a "standard" tar format header - we're not that interested
144 * in that many fields, though
147 /* check the checksum */
148 for (chk=0, i=sizeof(hb->dummy), jp=hb->dummy; --i>=0;) chk+=(0xFF & *jp++);
153 /* compensate for blanks in chksum header */
154 for (i=sizeof(hb->dbuf.chksum), jp=hb->dbuf.chksum; --i>=0;)
157 chk += ' ' * sizeof(hb->dbuf.chksum);
159 fchk=unoct(hb->dbuf.chksum, sizeof(hb->dbuf.chksum));
161 DEBUG(5, ("checksum totals chk=%d fchk=%d chksum=%s\n",
162 chk, fchk, hb->dbuf.chksum));
166 DEBUG(0, ("checksums don't match %d %d\n", fchk, chk));
170 strcpy(finfo->name, prefix);
172 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
173 unfixtarname(finfo->name + strlen(prefix), hb->dbuf.name,
174 strlen(hb->dbuf.name) + 1);
176 /* can't handle links at present */
177 if (hb->dbuf.linkflag != '0') {
178 if (hb->dbuf.linkflag == 0) {
179 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
182 DEBUG(0, ("this tar file appears to contain some kind of link - ignoring\n"));
187 if ((unoct(hb->dbuf.mode, sizeof(hb->dbuf.mode)) & S_IFDIR)
188 || (*(finfo->name+strlen(finfo->name)-1) == '\\'))
193 finfo->mode=0; /* we don't care about mode at the moment, we'll
194 * just make it a regular file */
196 * Bug fix by richard@sj.co.uk
198 * REC: restore times correctly (as does tar)
199 * We only get the modification time of the file; set the creation time
200 * from the mod. time, and the access time to current time
202 finfo->mtime = finfo->ctime = strtol(hb->dbuf.mtime, NULL, 8);
203 finfo->atime = time(NULL);
204 finfo->size = unoct(hb->dbuf.size, sizeof(hb->dbuf.size));
209 /****************************************************************************
210 Write out the tar buffer to tape or wherever
211 ****************************************************************************/
212 static int dotarbuf(int f, char *b, int n)
216 /* This routine and the next one should be the only ones that do write()s */
217 if (tp + n >= tbufsiz)
222 memcpy(tarbuf + tp, b, diff);
223 fail=fail && (1+write(f, tarbuf, tbufsiz));
230 fail=fail && (1 + write(f, b, tbufsiz));
236 memcpy(tarbuf+tp, b, n);
240 return(fail ? writ : 0);
243 /****************************************************************************
244 Write a zeros to buffer / tape
245 ****************************************************************************/
246 static void dozerobuf(int f, int n)
248 /* short routine just to write out n zeros to buffer -
249 * used to round files to nearest block
250 * and to do tar EOFs */
254 memset(tarbuf+tp, 0, tbufsiz-tp);
255 write(f, tarbuf, tbufsiz);
256 memset(tarbuf, 0, (tp+=n-tbufsiz));
260 memset(tarbuf+tp, 0, n);
265 /****************************************************************************
267 ****************************************************************************/
268 static void initarbuf()
270 /* initialize tar buffer */
271 tbufsiz=blocksize*TBLOCK;
272 tarbuf=malloc(tbufsiz);
274 /* reset tar buffer pointer and tar file counter */
278 /****************************************************************************
279 Write two zero blocks at end of file
280 ****************************************************************************/
281 static void dotareof(int f)
284 /* Two zero blocks at end of file, write out full buffer */
286 (void) dozerobuf(f, TBLOCK);
287 (void) dozerobuf(f, TBLOCK);
289 if (fstat(f, &stbuf) == -1)
291 DEBUG(0, ("Couldn't stat file handle\n"));
295 /* Could be a pipe, in which case S_ISREG should fail,
296 * and we should write out at full size */
297 if (tp > 0) write(f, tarbuf, S_ISREG(stbuf.st_mode) ? tp : tbufsiz);
300 /****************************************************************************
301 (Un)mangle DOS pathname, make nonabsolute
302 ****************************************************************************/
303 static void fixtarname(char *tptr, char *fp, int l)
305 /* add a '.' to start of file name, convert from ugly dos \'s in path
306 * to lovely unix /'s :-} */
311 if (is_shift_jis (*fp)) {
315 } else if (is_kana (*fp)) {
318 } else if (*fp == '\\') {
328 while (l--) { *tptr=(*fp == '\\') ? '/' : *fp; tptr++; fp++; }
332 /****************************************************************************
333 Convert from decimal to octal string
334 ****************************************************************************/
335 static void oct_it (register long value, register int ndgs, register char *p)
337 /* Converts long to octal string, pads with leading zeros */
339 /* skip final null, but do final space */
343 /* Loop does at least one digit */
345 p[--ndgs] = '0' + (char) (value & 7);
348 while (ndgs > 0 && value != 0);
350 /* Do leading zeros */
355 /****************************************************************************
356 Convert from octal string to long
357 ***************************************************************************/
358 static long unoct(char *p, int ndgs)
361 /* Converts octal string to long, ignoring any non-digit */
366 value = (value << 3) | (long) (*p - '0');
374 /****************************************************************************
375 Compare two strings in a slash insensitive way
376 ***************************************************************************/
377 int strslashcmp(const char *s1, const char *s2)
381 || tolower(*s1) == tolower(*s2)
382 || (*s1 == '\\' && *s2=='/')
383 || (*s1 == '/' && *s2=='\\'))) {
391 * general smb utility functions
393 /****************************************************************************
394 Set DOS file attributes
395 ***************************************************************************/
396 static int do_setrattr(char *fname, int attr, int setit)
399 * First get the existing attribs from existing file
410 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
411 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
413 if (!inbuf || !outbuf)
415 DEBUG(0,("out of memory\n"));
419 /* send an smb getatr message */
421 memset(outbuf,0,smb_size);
422 set_message(outbuf,0,2 + strlen(fname),True);
423 CVAL(outbuf,smb_com) = SMBgetatr;
424 SSVAL(outbuf,smb_tid,cnum);
430 p += (strlen(fname)+1);
435 send_smb(Client,outbuf);
436 receive_smb(Client,inbuf,CLIENT_TIMEOUT);
438 if (CVAL(inbuf,smb_rcls) != 0)
439 DEBUG(5,("getatr: %s\n",smb_errstr(inbuf)));
442 DEBUG(5,("\nattr 0x%X time %d size %d\n",
443 (int)CVAL(inbuf,smb_vwv0),
444 SVAL(inbuf,smb_vwv1),
445 SVAL(inbuf,smb_vwv3)));
448 fattr=CVAL(inbuf,smb_vwv0);
450 /* combine found attributes with bits to be set or reset */
452 attr=setit ? (fattr | attr) : (fattr & ~attr);
454 /* now try and set attributes by sending smb reset message */
456 /* clear out buffer and start again */
457 memset(outbuf,0,smb_size);
458 set_message(outbuf,8,4 + strlen(fname),True);
459 CVAL(outbuf,smb_com) = SMBsetatr;
460 SSVAL(outbuf,smb_tid,cnum);
463 SSVAL(outbuf,smb_vwv0,attr);
468 p += (strlen(fname)+1);
473 send_smb(Client,outbuf);
474 receive_smb(Client,inbuf,CLIENT_TIMEOUT);
476 if (CVAL(inbuf,smb_rcls) != 0)
478 DEBUG(0,("%s setting attributes on file %s\n",
479 smb_errstr(inbuf), fname));
480 free(inbuf);free(outbuf);
484 free(inbuf);free(outbuf);
488 /****************************************************************************
489 Create a file on a share
490 ***************************************************************************/
491 static BOOL smbcreat(file_info finfo, int *fnum, char *inbuf, char *outbuf)
494 /* *must* be called with buffer ready malloc'ed */
495 /* open remote file */
497 memset(outbuf,0,smb_size);
498 set_message(outbuf,3,2 + strlen(finfo.name),True);
499 CVAL(outbuf,smb_com) = SMBcreate;
500 SSVAL(outbuf,smb_tid,cnum);
503 SSVAL(outbuf,smb_vwv0,finfo.mode);
504 put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
508 strcpy(p,finfo.name);
510 send_smb(Client,outbuf);
511 receive_smb(Client,inbuf,CLIENT_TIMEOUT);
513 if (CVAL(inbuf,smb_rcls) != 0)
515 DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),
520 *fnum = SVAL(inbuf,smb_vwv0);
524 /****************************************************************************
525 Write a file to a share
526 ***************************************************************************/
527 static BOOL smbwrite(int fnum, int n, int low, int high, int left,
528 char *bufferp, char *inbuf, char *outbuf)
530 /* *must* be called with buffer ready malloc'ed */
532 memset(outbuf,0,smb_size);
533 set_message(outbuf,5,n + 3,True);
535 memcpy(smb_buf(outbuf)+3, bufferp, n);
537 set_message(outbuf,5,n + 3, False);
538 CVAL(outbuf,smb_com) = SMBwrite;
539 SSVAL(outbuf,smb_tid,cnum);
542 SSVAL(outbuf,smb_vwv0,fnum);
543 SSVAL(outbuf,smb_vwv1,n);
544 SIVAL(outbuf,smb_vwv2,low);
545 SSVAL(outbuf,smb_vwv4,left);
546 CVAL(smb_buf(outbuf),0) = 1;
547 SSVAL(smb_buf(outbuf),1,n);
549 send_smb(Client,outbuf);
550 receive_smb(Client,inbuf,CLIENT_TIMEOUT);
552 if (CVAL(inbuf,smb_rcls) != 0)
554 DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf)));
558 if (n != SVAL(inbuf,smb_vwv0))
560 DEBUG(0,("Error: only wrote %d bytes out of %d\n",
561 SVAL(inbuf,smb_vwv0), n));
568 /****************************************************************************
569 Close a file on a share
570 ***************************************************************************/
571 static BOOL smbshut(file_info finfo, int fnum, char *inbuf, char *outbuf)
573 /* *must* be called with buffer ready malloc'ed */
575 memset(outbuf,0,smb_size);
576 set_message(outbuf,3,0,True);
577 CVAL(outbuf,smb_com) = SMBclose;
578 SSVAL(outbuf,smb_tid,cnum);
581 SSVAL(outbuf,smb_vwv0,fnum);
582 put_dos_date3(outbuf,smb_vwv1,finfo.mtime);
584 DEBUG(3,("Setting date to %s (0x%X)",
585 asctime(LocalTime(&finfo.mtime)),
588 send_smb(Client,outbuf);
589 receive_smb(Client,inbuf,CLIENT_TIMEOUT);
591 if (CVAL(inbuf,smb_rcls) != 0)
593 DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),
601 /****************************************************************************
602 Verify existence of path on share
603 ***************************************************************************/
604 static BOOL smbchkpath(char *fname, char *inbuf, char *outbuf)
608 memset(outbuf,0,smb_size);
609 set_message(outbuf,0,4 + strlen(fname),True);
610 CVAL(outbuf,smb_com) = SMBchkpth;
611 SSVAL(outbuf,smb_tid,cnum);
618 send_smb(Client,outbuf);
619 receive_smb(Client,inbuf,CLIENT_TIMEOUT);
621 DEBUG(5,("smbchkpath: %s\n",smb_errstr(inbuf)));
623 return(CVAL(inbuf,smb_rcls) == 0);
626 /****************************************************************************
627 Make a directory on share
628 ***************************************************************************/
629 static BOOL smbmkdir(char *fname, char *inbuf, char *outbuf)
631 /* *must* be called with buffer ready malloc'ed */
634 memset(outbuf,0,smb_size);
635 set_message(outbuf,0,2 + strlen(fname),True);
637 CVAL(outbuf,smb_com) = SMBmkdir;
638 SSVAL(outbuf,smb_tid,cnum);
645 send_smb(Client,outbuf);
646 receive_smb(Client,inbuf,CLIENT_TIMEOUT);
648 if (CVAL(inbuf,smb_rcls) != 0)
650 DEBUG(0,("%s making remote directory %s\n",
651 smb_errstr(inbuf),fname));
658 /****************************************************************************
659 Ensure a remote path exists (make if necessary)
660 ***************************************************************************/
661 static BOOL ensurepath(char *fname, char *inbuf, char *outbuf)
663 /* *must* be called with buffer ready malloc'ed */
664 /* ensures path exists */
666 pstring partpath, ffname;
667 char *p=fname, *basehack;
671 /* fname copied to ffname so can strtok */
673 strcpy(ffname, fname);
675 /* do a `basename' on ffname, so don't try and make file name directory */
676 if ((basehack=strrchr(ffname, '\\')) == NULL)
681 p=strtok(ffname, "\\");
687 if (!smbchkpath(partpath, inbuf, outbuf)) {
688 if (!smbmkdir(partpath, inbuf, outbuf))
690 DEBUG(0, ("Error mkdirhiering\n"));
694 DEBUG(3, ("mkdirhiering %s\n", partpath));
698 strcat(partpath, "\\");
699 p = strtok(NULL,"/\\");
706 * smbclient functions
708 /****************************************************************************
709 append one remote file to the tar file
710 ***************************************************************************/
711 static void do_atar(char *rname,char *lname,file_info *finfo1)
718 BOOL close_done = False;
719 BOOL shallitime=True;
720 BOOL ignore_close_error = False;
724 struct timeval tp_start;
725 GetTimeOfDay(&tp_start);
732 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
733 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
735 if (!inbuf || !outbuf)
737 DEBUG(0,("out of memory\n"));
741 memset(outbuf,0,smb_size);
742 set_message(outbuf,15,1 + strlen(rname),True);
744 CVAL(outbuf,smb_com) = SMBopenX;
745 SSVAL(outbuf,smb_tid,cnum);
748 SSVAL(outbuf,smb_vwv0,0xFF);
749 SSVAL(outbuf,smb_vwv2,1);
750 SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
751 SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
752 SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
753 SSVAL(outbuf,smb_vwv8,1);
757 p = skip_string(p,1);
759 dos_clean_name(rname);
761 /* do a chained openX with a readX? */
764 SSVAL(outbuf,smb_vwv0,SMBreadX);
765 SSVAL(outbuf,smb_vwv1,PTR_DIFF(p,outbuf) - 4);
769 SSVAL(p,smb_vwv0,0xFF);
770 SSVAL(p,smb_vwv5,MIN(max_xmit-500,finfo.size));
771 SSVAL(p,smb_vwv9,MIN(0xFFFF,finfo.size));
772 smb_setlen(outbuf,smb_len(outbuf)+11*2+1);
775 send_smb(Client,outbuf);
776 receive_smb(Client,inbuf,CLIENT_TIMEOUT);
778 if (CVAL(inbuf,smb_rcls) != 0)
780 if (CVAL(inbuf,smb_rcls) == ERRSRV &&
781 SVAL(inbuf,smb_err) == ERRnoresource &&
782 reopen_connection(inbuf,outbuf))
784 do_atar(rname,lname,finfo1);
785 free(inbuf);free(outbuf);
789 DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),rname));
790 free(inbuf);free(outbuf);
794 strcpy(finfo.name,rname);
797 finfo.mode = SVAL(inbuf,smb_vwv3);
798 finfo.size = IVAL(inbuf,smb_vwv4);
799 finfo.mtime = make_unix_date3(inbuf+smb_vwv6);
800 finfo.atime = finfo.ctime = finfo.mtime;
803 DEBUG(3,("file %s attrib 0x%X\n",finfo.name,finfo.mode));
805 fnum = SVAL(inbuf,smb_vwv2);
807 if (tar_inc && !(finfo.mode & aARCH))
809 DEBUG(4, ("skipping %s - archive bit not set\n", finfo.name));
814 if (SVAL(inbuf,smb_vwv0) == SMBreadX)
816 p = (inbuf+4+SVAL(inbuf,smb_vwv1)) - smb_wct;
817 datalen = SVAL(p,smb_vwv5);
818 dataptr = inbuf + 4 + SVAL(p,smb_vwv6);
826 DEBUG(2,("getting file %s of size %d bytes as a tar file %s",
831 /* write a tar header, don't bother with mode - just set to 100644 */
832 writetarheader(tarhandle, rname, finfo.size, finfo.mtime, "100644 \0");
834 while (nread < finfo.size && !close_done)
837 static BOOL can_chain_close=True;
841 DEBUG(3,("nread=%d\n",nread));
843 /* 3 possible read types. readbraw if a large block is required.
844 readX + close if not much left and read if neither is supported */
846 /* we might have already read some data from a chained readX */
847 if (dataptr && datalen>0)
850 /* if we can finish now then readX+close */
851 if (method<0 && can_chain_close && (Protocol >= PROTOCOL_LANMAN1) &&
852 ((finfo.size - nread) <
853 (max_xmit - (2*smb_size + 13*SIZEOFWORD + 300))))
856 /* if we support readraw then use that */
857 if (method<0 && readbraw_supported)
860 /* if we can then use readX */
861 if (method<0 && (Protocol >= PROTOCOL_LANMAN1))
873 /* use readX + close */
874 memset(outbuf,0,smb_size);
875 set_message(outbuf,10,0,True);
876 CVAL(outbuf,smb_com) = SMBreadX;
877 SSVAL(outbuf,smb_tid,cnum);
882 CVAL(outbuf,smb_vwv0) = SMBclose;
883 SSVAL(outbuf,smb_vwv1,PTR_DIFF(smb_buf(outbuf),outbuf) - 4);
886 CVAL(outbuf,smb_vwv0) = 0xFF;
889 SSVAL(outbuf,smb_vwv2,fnum);
890 SIVAL(outbuf,smb_vwv3,nread);
891 SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread));
892 SSVAL(outbuf,smb_vwv6,0);
893 SIVAL(outbuf,smb_vwv7,0);
894 SSVAL(outbuf,smb_vwv9,MIN(0xFFFF,finfo.size-nread));
905 /* now set the total packet length */
906 smb_setlen(outbuf,smb_len(outbuf)+9);
909 send_smb(Client,outbuf);
910 receive_smb(Client,inbuf,CLIENT_TIMEOUT);
912 if (CVAL(inbuf,smb_rcls) != 0)
914 DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
919 SVAL(inbuf,smb_vwv0) != SMBclose)
921 /* NOTE: WfWg sometimes just ignores the chained
922 command! This seems to break the spec? */
923 DEBUG(3,("Rejected chained close?\n"));
925 can_chain_close = False;
926 ignore_close_error = True;
929 datalen = SVAL(inbuf,smb_vwv5);
930 dataptr = inbuf + 4 + SVAL(inbuf,smb_vwv6);
937 static int readbraw_size = 0xFFFF;
940 memset(outbuf,0,smb_size);
941 set_message(outbuf,8,0,True);
942 CVAL(outbuf,smb_com) = SMBreadbraw;
943 SSVAL(outbuf,smb_tid,cnum);
945 SSVAL(outbuf,smb_vwv0,fnum);
946 SIVAL(outbuf,smb_vwv1,nread);
947 SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size));
948 SSVAL(outbuf,smb_vwv4,0);
949 SIVALS(outbuf,smb_vwv5,-1);
950 send_smb(Client,outbuf);
952 /* Now read the raw data into the buffer and write it */
953 if(read_smb_length(Client,inbuf,0) == -1) {
954 DEBUG(0,("Failed to read length in readbraw\n"));
958 /* Even though this is not an smb message, smb_len
959 returns the generic length of an smb message */
960 datalen = smb_len(inbuf);
964 /* we got a readbraw error */
965 DEBUG(4,("readbraw error - reducing size\n"));
966 readbraw_size = (readbraw_size * 9) / 10;
968 if (readbraw_size < max_xmit)
970 DEBUG(0,("disabling readbraw\n"));
971 readbraw_supported = False;
978 if(read_data(Client,inbuf,datalen) != datalen) {
979 DEBUG(0,("Failed to read data in readbraw\n"));
987 /* we've already read some data with a chained readX */
992 memset(outbuf,0,smb_size);
993 set_message(outbuf,5,0,True);
994 CVAL(outbuf,smb_com) = SMBread;
995 SSVAL(outbuf,smb_tid,cnum);
998 SSVAL(outbuf,smb_vwv0,fnum);
999 SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread));
1000 SIVAL(outbuf,smb_vwv2,nread);
1001 SSVAL(outbuf,smb_vwv4,finfo.size - nread);
1003 send_smb(Client,outbuf);
1004 receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1006 if (CVAL(inbuf,smb_rcls) != 0)
1008 DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf)));
1012 datalen = SVAL(inbuf,smb_vwv0);
1013 dataptr = smb_buf(inbuf) + 3;
1018 /* add received bits of file to buffer - dotarbuf will
1019 * write out in 512 byte intervals */
1020 if (dotarbuf(tarhandle,dataptr,datalen) != datalen)
1022 DEBUG(0,("Error writing local file\n"));
1029 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname));
1037 /* round tar file to nearest block */
1038 if (finfo.size % TBLOCK)
1039 dozerobuf(tarhandle, TBLOCK - (finfo.size % TBLOCK));
1046 memset(outbuf,0,smb_size);
1047 set_message(outbuf,3,0,True);
1048 CVAL(outbuf,smb_com) = SMBclose;
1049 SSVAL(outbuf,smb_tid,cnum);
1052 SSVAL(outbuf,smb_vwv0,fnum);
1053 SIVALS(outbuf,smb_vwv1,-1);
1055 send_smb(Client,outbuf);
1056 receive_smb(Client,inbuf,CLIENT_TIMEOUT);
1058 if (!ignore_close_error && CVAL(inbuf,smb_rcls) != 0)
1060 DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf)));
1061 free(inbuf);free(outbuf);
1068 struct timeval tp_end;
1071 /* if shallitime is true then we didn't skip */
1072 if (tar_reset) (void) do_setrattr(finfo.name, aARCH, ATTRRESET);
1074 GetTimeOfDay(&tp_end);
1076 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1077 (tp_end.tv_usec - tp_start.tv_usec)/1000;
1078 get_total_time_ms += this_time;
1079 get_total_size += finfo.size;
1081 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
1082 DEBUG(2,("(%g kb/s) (average %g kb/s)\n",
1083 finfo.size / MAX(0.001, (1.024*this_time)),
1084 get_total_size / MAX(0.001, (1.024*get_total_time_ms))));
1087 free(inbuf);free(outbuf);
1090 /****************************************************************************
1091 Append single file to tar file (or not)
1092 ***************************************************************************/
1093 static void do_tar(file_info *finfo)
1097 if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1100 /* Is it on the exclude list ? */
1101 if (!tar_excl && clipn) {
1104 strcpy(exclaim, cur_dir);
1105 *(exclaim+strlen(exclaim)-1)='\0';
1107 if (clipfind(cliplist, clipn, exclaim)) {
1108 DEBUG(3,("Skipping directory %s\n", exclaim));
1112 strcat(exclaim, "\\");
1113 strcat(exclaim, finfo->name);
1115 if (clipfind(cliplist, clipn, exclaim)) {
1116 DEBUG(3,("Skipping file %s\n", exclaim));
1121 if (finfo->mode & aDIR)
1123 pstring saved_curdir;
1125 char *inbuf,*outbuf;
1127 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1128 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1130 if (!inbuf || !outbuf)
1132 DEBUG(0,("out of memory\n"));
1136 strcpy(saved_curdir,cur_dir);
1138 strcat(cur_dir,finfo->name);
1139 strcat(cur_dir,"\\");
1141 /* write a tar directory, don't bother with mode - just set it to
1143 writetarheader(tarhandle, cur_dir, 0, finfo->mtime, "040755 \0");
1144 strcpy(mtar_mask,cur_dir);
1145 strcat(mtar_mask,"*");
1147 do_dir((char *)inbuf,(char *)outbuf,mtar_mask,attribute,do_tar,recurse);
1148 strcpy(cur_dir,saved_curdir);
1149 free(inbuf);free(outbuf);
1153 strcpy(rname,cur_dir);
1154 strcat(rname,finfo->name);
1155 do_atar(rname,finfo->name,finfo);
1159 /****************************************************************************
1160 Convert from UNIX to DOS file names
1161 ***************************************************************************/
1162 static void unfixtarname(char *tptr, char *fp, int l)
1164 /* remove '.' from start of file name, convert from unix /'s to
1165 * dos \'s in path. Kill any absolute path names.
1168 if (*fp == '.') fp++;
1169 if (*fp == '\\' || *fp == '/') fp++;
1173 if (is_shift_jis (*fp)) {
1177 } else if (is_kana (*fp)) {
1180 } else if (*fp == '/') {
1190 while (l--) { *tptr=(*fp == '/') ? '\\' : *fp; tptr++; fp++; }
1194 static void do_tarput()
1197 int nread=0, bufread;
1198 char *inbuf,*outbuf;
1201 struct timeval tp_start;
1202 BOOL tskip=False; /* We'll take each file as it comes */
1204 GetTimeOfDay(&tp_start);
1206 inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1207 outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
1209 if (!inbuf || !outbuf)
1211 DEBUG(0,("out of memory\n"));
1216 * Must read in tbufsiz dollops
1219 /* These should be the only reads in clitar.c */
1220 while ((bufread=read(tarhandle, tarbuf, tbufsiz))>0) {
1221 char *bufferp, *endofbuffer;
1224 /* Code to handle a short read.
1225 * We always need a TBLOCK full of stuff
1227 if (bufread % TBLOCK) {
1228 int lchunk=TBLOCK-(bufread % TBLOCK);
1231 /* It's a shorty - a short read that is */
1232 DEBUG(3, ("Short read, read %d so far (need %d)\n", bufread, lchunk));
1234 while ((lread=read(tarhandle, tarbuf+bufread, lchunk))>0) {
1236 if (!(lchunk-=lread)) break;
1239 /* If we've reached EOF then that must be a short file */
1240 if (lread<=0) break;
1244 endofbuffer=tarbuf+bufread;
1247 if (fsize<bufread) {
1252 if (fsize==bufread) tskip=False;
1261 switch (readtarheader((union hblock *) bufferp, &finfo, cur_dir))
1263 case -2: /* something dodgy but not fatal about this */
1264 DEBUG(0, ("skipping %s...\n", finfo.name));
1265 bufferp+=TBLOCK; /* header - like a link */
1268 DEBUG(0, ("abandoning restore\n"));
1269 free(inbuf); free(outbuf);
1271 case 0: /* chksum is zero - we assume that one all zero
1272 *header block will do for eof */
1274 ("total of %d tar files restored to share\n", ntarf));
1275 free(inbuf); free(outbuf);
1282 && (clipfind(cliplist, clipn, finfo.name) ^ tar_excl);
1285 if (finfo.mode & aDIR)
1287 else if ((fsize=finfo.size) % TBLOCK) {
1288 fsize+=TBLOCK-(fsize%TBLOCK);
1290 if (fsize<endofbuffer-bufferp) {
1295 fsize-=endofbuffer-bufferp;
1300 if (finfo.mode & aDIR)
1302 if (!smbchkpath(finfo.name, inbuf, outbuf)
1303 && !smbmkdir(finfo.name, inbuf, outbuf))
1305 DEBUG(0, ("abandoning restore\n"));
1306 free(inbuf); free(outbuf);
1318 if (ensurepath(finfo.name, inbuf, outbuf)
1319 && !smbcreat(finfo, &fnum, inbuf, outbuf))
1321 DEBUG(0, ("abandoning restore\n"));
1322 free(inbuf);free(outbuf);
1326 DEBUG(0,("restore tar file %s of size %d bytes\n",
1327 finfo.name,finfo.size));
1330 if ((bufferp+=TBLOCK) >= endofbuffer) break;
1333 /* write out the file in chunk sized chunks - don't
1334 * go past end of buffer though */
1335 chunk=(fsize-nread < endofbuffer - bufferp)
1336 ? fsize - nread : endofbuffer - bufferp;
1339 int minichunk=MIN(chunk, max_xmit-200);
1341 if (!smbwrite(fnum, /* file descriptor */
1343 nread, /* offset low */
1344 0, /* offset high - not implemented */
1345 fsize-nread, /* left - only hint to server */
1350 DEBUG(0, ("Error writing remote file\n"));
1351 free(inbuf); free(outbuf);
1354 DEBUG(5, ("chunk writing fname=%s fnum=%d nread=%d minichunk=%d chunk=%d size=%d\n", finfo.name, fnum, nread, minichunk, chunk, fsize));
1356 bufferp+=minichunk; nread+=minichunk;
1362 if (!smbshut(finfo, fnum, inbuf, outbuf))
1364 DEBUG(0, ("Error closing remote file\n"));
1365 free(inbuf);free(outbuf);
1368 if (fsize % TBLOCK) bufferp+=TBLOCK - (fsize % TBLOCK);
1369 DEBUG(5, ("bufferp is now %d (psn=%d)\n",
1370 (long) bufferp, (long)(bufferp - tarbuf)));
1374 } while (bufferp < endofbuffer);
1377 DEBUG(0, ("premature eof on tar file ?\n"));
1378 DEBUG(0,("total of %d tar files restored to share\n", ntarf));
1380 free(inbuf); free(outbuf);
1384 * samba interactive commands
1387 /****************************************************************************
1389 ***************************************************************************/
1390 void cmd_block(void)
1395 if (!next_token(NULL,buf,NULL))
1397 DEBUG(0, ("blocksize <n>\n"));
1402 if (block < 0 || block > 65535)
1404 DEBUG(0, ("blocksize out of range"));
1409 DEBUG(2,("blocksize is now %d\n", blocksize));
1412 /****************************************************************************
1413 command to set incremental / reset mode
1414 ***************************************************************************/
1415 void cmd_tarmode(void)
1419 while (next_token(NULL,buf,NULL)) {
1420 if (strequal(buf, "full"))
1422 else if (strequal(buf, "inc"))
1424 else if (strequal(buf, "reset"))
1426 else if (strequal(buf, "noreset"))
1428 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf));
1431 DEBUG(0, ("tarmode is now %s, %s\n",
1432 tar_inc ? "incremental" : "full",
1433 tar_reset ? "reset" : "noreset"));
1436 /****************************************************************************
1437 Feeble attrib command
1438 ***************************************************************************/
1439 void cmd_setmode(void)
1447 attra[0] = attra[1] = 0;
1449 if (!next_token(NULL,buf,NULL))
1451 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1455 strcpy(fname, cur_dir);
1458 while (next_token(NULL,buf,NULL)) {
1467 case 'r': attra[direct]|=aRONLY;
1469 case 'h': attra[direct]|=aHIDDEN;
1471 case 's': attra[direct]|=aSYSTEM;
1473 case 'a': attra[direct]|=aARCH;
1475 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1480 if (attra[ATTRSET]==0 && attra[ATTRRESET]==0)
1482 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1486 DEBUG(2, ("\nperm set %d %d\n", attra[ATTRSET], attra[ATTRRESET]));
1487 (void) do_setrattr(fname, attra[ATTRSET], ATTRSET);
1488 (void) do_setrattr(fname, attra[ATTRRESET], ATTRRESET);
1491 /****************************************************************************
1492 Principal command for creating / extracting
1493 ***************************************************************************/
1494 void cmd_tar(char *inbuf, char *outbuf)
1500 if (!next_token(NULL,buf,NULL))
1502 DEBUG(0,("tar <c|x>[IXbga] <filename>\n"));
1506 argl=toktocliplist(&argcl, NULL);
1507 if (!tar_parseargs(argcl, argl, buf, 0))
1510 process_tar(inbuf, outbuf);
1515 /****************************************************************************
1516 Command line (option) version
1517 ***************************************************************************/
1518 int process_tar(char *inbuf, char *outbuf)
1529 if (clipn && tar_excl) {
1533 for (i=0; i<clipn; i++) {
1534 DEBUG(0,("arg %d = %s\n", i, cliplist[i]));
1536 if (*(cliplist[i]+strlen(cliplist[i])-1)=='\\') {
1537 *(cliplist[i]+strlen(cliplist[i])-1)='\0';
1540 if (strrchr(cliplist[i], '\\')) {
1543 strcpy(saved_dir, cur_dir);
1545 if (*cliplist[i]=='\\') {
1546 strcpy(tarmac, cliplist[i]);
1548 strcpy(tarmac, cur_dir);
1549 strcat(tarmac, cliplist[i]);
1551 strcpy(cur_dir, tarmac);
1552 *(strrchr(cur_dir, '\\')+1)='\0';
1554 do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse);
1555 strcpy(cur_dir,saved_dir);
1557 strcpy(tarmac, cur_dir);
1558 strcat(tarmac, cliplist[i]);
1559 do_dir((char *)inbuf,(char *)outbuf,tarmac,attribute,do_tar,recurse);
1564 strcpy(mask,cur_dir);
1566 do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_tar,recurse);
1569 if (ntarf) dotareof(tarhandle);
1573 DEBUG(0, ("tar: dumped %d tar files\n", ntarf));
1580 /****************************************************************************
1581 Find a token (filename) in a clip list
1582 ***************************************************************************/
1583 int clipfind(char **aret, int ret, char *tok)
1585 if (aret==NULL) return 0;
1587 /* ignore leading slashes or dots in token */
1588 while(strchr("/\\.", *tok)) tok++;
1593 /* ignore leading slashes or dots in list */
1594 while(strchr("/\\.", *pkey)) pkey++;
1596 if (!strslashcmp(pkey, tok)) return 1;
1602 /****************************************************************************
1603 Parse tar arguments. Sets tar_type, tar_excl, etc.
1604 ***************************************************************************/
1605 int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind)
1607 char tar_clipfl='\0';
1609 /* Reset back to defaults - could be from interactive version
1610 * reset mode and archive mode left as they are though
1621 if (tar_type=='c') {
1622 printf("Tar must be followed by only one of c or x.\n");
1628 if (Optind>=argc || !(blocksize=atoi(argv[Optind]))) {
1629 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1640 DEBUG(0,("Option N must be followed by valid file name\n"));
1644 extern time_t newer_than;
1646 if (sys_stat(argv[Optind], &stbuf) == 0) {
1647 newer_than = stbuf.st_mtime;
1648 DEBUG(1,("Getting files newer than %s",
1649 asctime(LocalTime(&newer_than))));
1652 DEBUG(0,("Error setting newer-than time\n"));
1662 DEBUG(0,("Only one of I,X must be specified\n"));
1669 DEBUG(0,("Only one of I,X must be specified\n"));
1675 DEBUG(0,("Unknown tar option\n"));
1680 printf("Option T must be followed by one of c or x.\n");
1684 if (Optind>=argc || !strcmp(argv[Optind], "-")) {
1685 /* Sets tar handle to either 0 or 1, as appropriate */
1686 tarhandle=(tar_type=='c');
1688 tar_excl=tar_clipfl!='X';
1690 if (Optind+1<argc) {
1691 cliplist=argv+Optind+1;
1692 clipn=argc-Optind-1;
1695 if ((tar_type=='x' && (tarhandle = open(argv[Optind], O_RDONLY)) == -1)
1696 || (tar_type=='c' && (tarhandle=creat(argv[Optind], 0644)) < 0))
1698 DEBUG(0,("Error opening local file %s\n",argv[Optind]));