2 Unix SMB/Netbios implementation.
5 Copyright (C) Ricky Poulten 1995-1997
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(char *s1
,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
,"/\\");
705 int padit(char *buf
, int bufsize
, int padsize
)
710 DEBUG(0, ("Padding with %d zeros\n", padsize
));
711 memset(buf
, 0, bufsize
);
712 while( !berr
&& padsize
> 0 ) {
713 bytestowrite
= MIN(bufsize
, padsize
);
714 berr
= dotarbuf(tarhandle
, buf
, bytestowrite
) != bytestowrite
;
715 padsize
-= bytestowrite
;
722 * smbclient functions
724 /****************************************************************************
725 append one remote file to the tar file
726 ***************************************************************************/
727 static void do_atar(char *rname
,char *lname
,file_info
*finfo1
)
734 BOOL close_done
= False
;
735 BOOL shallitime
=True
;
736 BOOL ignore_close_error
= False
;
740 struct timeval tp_start
;
741 GetTimeOfDay(&tp_start
);
748 inbuf
= (char *)malloc(BUFFER_SIZE
+ SAFETY_MARGIN
);
749 outbuf
= (char *)malloc(BUFFER_SIZE
+ SAFETY_MARGIN
);
751 if (!inbuf
|| !outbuf
)
753 DEBUG(0,("out of memory\n"));
757 memset(outbuf
,0,smb_size
);
758 set_message(outbuf
,15,1 + strlen(rname
),True
);
760 CVAL(outbuf
,smb_com
) = SMBopenX
;
761 SSVAL(outbuf
,smb_tid
,cnum
);
764 SSVAL(outbuf
,smb_vwv0
,0xFF);
765 SSVAL(outbuf
,smb_vwv2
,1);
766 SSVAL(outbuf
,smb_vwv3
,(DENY_NONE
<<4));
767 SSVAL(outbuf
,smb_vwv4
,aSYSTEM
| aHIDDEN
);
768 SSVAL(outbuf
,smb_vwv5
,aSYSTEM
| aHIDDEN
);
769 SSVAL(outbuf
,smb_vwv8
,1);
773 p
= skip_string(p
,1);
775 dos_clean_name(rname
);
777 /* do a chained openX with a readX? */
780 SSVAL(outbuf
,smb_vwv0
,SMBreadX
);
781 SSVAL(outbuf
,smb_vwv1
,PTR_DIFF(p
,outbuf
) - 4);
785 SSVAL(p
,smb_vwv0
,0xFF);
786 SSVAL(p
,smb_vwv5
,MIN(max_xmit
-500,finfo
.size
));
787 SSVAL(p
,smb_vwv9
,MIN(0xFFFF,finfo
.size
));
788 smb_setlen(outbuf
,smb_len(outbuf
)+11*2+1);
791 send_smb(Client
,outbuf
);
792 receive_smb(Client
,inbuf
,CLIENT_TIMEOUT
);
794 if (CVAL(inbuf
,smb_rcls
) != 0)
796 if (CVAL(inbuf
,smb_rcls
) == ERRSRV
&&
797 SVAL(inbuf
,smb_err
) == ERRnoresource
&&
798 reopen_connection(inbuf
,outbuf
))
800 do_atar(rname
,lname
,finfo1
);
801 free(inbuf
);free(outbuf
);
805 DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf
),rname
));
806 free(inbuf
);free(outbuf
);
810 strcpy(finfo
.name
,rname
);
813 finfo
.mode
= SVAL(inbuf
,smb_vwv3
);
814 finfo
.size
= IVAL(inbuf
,smb_vwv4
);
815 finfo
.mtime
= make_unix_date3(inbuf
+smb_vwv6
);
816 finfo
.atime
= finfo
.ctime
= finfo
.mtime
;
819 DEBUG(3,("file %s attrib 0x%X\n",finfo
.name
,finfo
.mode
));
821 fnum
= SVAL(inbuf
,smb_vwv2
);
823 if (tar_inc
&& !(finfo
.mode
& aARCH
))
825 DEBUG(4, ("skipping %s - archive bit not set\n", finfo
.name
));
830 if (SVAL(inbuf
,smb_vwv0
) == SMBreadX
)
832 p
= (inbuf
+4+SVAL(inbuf
,smb_vwv1
)) - smb_wct
;
833 datalen
= SVAL(p
,smb_vwv5
);
834 dataptr
= inbuf
+ 4 + SVAL(p
,smb_vwv6
);
842 DEBUG(1,("getting file %s of size %d bytes as a tar file %s",
847 /* write a tar header, don't bother with mode - just set to 100644 */
848 writetarheader(tarhandle
, rname
, finfo
.size
, finfo
.mtime
, "100644 \0");
850 while (nread
< finfo
.size
&& !close_done
)
853 static BOOL can_chain_close
=True
;
857 DEBUG(3,("nread=%d\n",nread
));
859 /* 3 possible read types. readbraw if a large block is required.
860 readX + close if not much left and read if neither is supported */
862 /* we might have already read some data from a chained readX */
863 if (dataptr
&& datalen
>0)
866 /* if we can finish now then readX+close */
867 if (method
<0 && can_chain_close
&& (Protocol
>= PROTOCOL_LANMAN1
) &&
868 ((finfo
.size
- nread
) <
869 (max_xmit
- (2*smb_size
+ 13*SIZEOFWORD
+ 300))))
872 /* if we support readraw then use that */
873 if (method
<0 && readbraw_supported
)
876 /* if we can then use readX */
877 if (method
<0 && (Protocol
>= PROTOCOL_LANMAN1
))
889 /* use readX + close */
890 memset(outbuf
,0,smb_size
);
891 set_message(outbuf
,10,0,True
);
892 CVAL(outbuf
,smb_com
) = SMBreadX
;
893 SSVAL(outbuf
,smb_tid
,cnum
);
898 CVAL(outbuf
,smb_vwv0
) = SMBclose
;
899 SSVAL(outbuf
,smb_vwv1
,PTR_DIFF(smb_buf(outbuf
),outbuf
) - 4);
902 CVAL(outbuf
,smb_vwv0
) = 0xFF;
905 SSVAL(outbuf
,smb_vwv2
,fnum
);
906 SIVAL(outbuf
,smb_vwv3
,nread
);
907 SSVAL(outbuf
,smb_vwv5
,MIN(max_xmit
-200,finfo
.size
- nread
));
908 SSVAL(outbuf
,smb_vwv6
,0);
909 SIVAL(outbuf
,smb_vwv7
,0);
910 SSVAL(outbuf
,smb_vwv9
,MIN(0xFFFF,finfo
.size
-nread
));
921 /* now set the total packet length */
922 smb_setlen(outbuf
,smb_len(outbuf
)+9);
925 send_smb(Client
,outbuf
);
926 receive_smb(Client
,inbuf
,CLIENT_TIMEOUT
);
928 if (CVAL(inbuf
,smb_rcls
) != 0)
930 DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf
)));
935 SVAL(inbuf
,smb_vwv0
) != SMBclose
)
937 /* NOTE: WfWg sometimes just ignores the chained
938 command! This seems to break the spec? */
939 DEBUG(3,("Rejected chained close?\n"));
941 can_chain_close
= False
;
942 ignore_close_error
= True
;
945 datalen
= SVAL(inbuf
,smb_vwv5
);
946 dataptr
= inbuf
+ 4 + SVAL(inbuf
,smb_vwv6
);
953 static int readbraw_size
= 0xFFFF;
956 memset(outbuf
,0,smb_size
);
957 set_message(outbuf
,8,0,True
);
958 CVAL(outbuf
,smb_com
) = SMBreadbraw
;
959 SSVAL(outbuf
,smb_tid
,cnum
);
961 SSVAL(outbuf
,smb_vwv0
,fnum
);
962 SIVAL(outbuf
,smb_vwv1
,nread
);
963 SSVAL(outbuf
,smb_vwv3
,MIN(finfo
.size
-nread
,readbraw_size
));
964 SSVAL(outbuf
,smb_vwv4
,0);
965 SIVALS(outbuf
,smb_vwv5
,-1);
966 send_smb(Client
,outbuf
);
968 /* Now read the raw data into the buffer and write it */
969 if(read_smb_length(Client
,inbuf
,0) == -1) {
970 DEBUG(0,("Failed to read length in readbraw\n"));
974 /* Even though this is not an smb message, smb_len
975 returns the generic length of an smb message */
976 datalen
= smb_len(inbuf
);
980 /* we got a readbraw error */
981 DEBUG(4,("readbraw error - reducing size\n"));
982 readbraw_size
= (readbraw_size
* 9) / 10;
984 if (readbraw_size
< max_xmit
)
986 DEBUG(0,("disabling readbraw\n"));
987 readbraw_supported
= False
;
994 if(read_data(Client
,inbuf
,datalen
) != datalen
) {
995 DEBUG(0,("Failed to read data in readbraw\n"));
1003 /* we've already read some data with a chained readX */
1007 /* use plain read */
1008 memset(outbuf
,0,smb_size
);
1009 set_message(outbuf
,5,0,True
);
1010 CVAL(outbuf
,smb_com
) = SMBread
;
1011 SSVAL(outbuf
,smb_tid
,cnum
);
1014 SSVAL(outbuf
,smb_vwv0
,fnum
);
1015 SSVAL(outbuf
,smb_vwv1
,MIN(max_xmit
-200,finfo
.size
- nread
));
1016 SIVAL(outbuf
,smb_vwv2
,nread
);
1017 SSVAL(outbuf
,smb_vwv4
,finfo
.size
- nread
);
1019 send_smb(Client
,outbuf
);
1020 receive_smb(Client
,inbuf
,CLIENT_TIMEOUT
);
1022 if (CVAL(inbuf
,smb_rcls
) != 0)
1024 DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf
)));
1028 datalen
= SVAL(inbuf
,smb_vwv0
);
1029 dataptr
= smb_buf(inbuf
) + 3;
1034 /* add received bits of file to buffer - dotarbuf will
1035 * write out in 512 byte intervals */
1036 if (dotarbuf(tarhandle
,dataptr
,datalen
) != datalen
)
1038 DEBUG(0,("Error writing local file\n"));
1045 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname
));
1053 /* pad tar file with zero's if we couldn't get entire file */
1054 if (nread
< finfo
.size
)
1056 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo
.size
, nread
));
1057 if (padit(inbuf
, BUFFER_SIZE
, finfo
.size
- nread
))
1058 DEBUG(0,("Error writing local file\n"));
1061 /* round tar file to nearest block */
1062 if (finfo
.size
% TBLOCK
)
1063 dozerobuf(tarhandle
, TBLOCK
- (finfo
.size
% TBLOCK
));
1070 memset(outbuf
,0,smb_size
);
1071 set_message(outbuf
,3,0,True
);
1072 CVAL(outbuf
,smb_com
) = SMBclose
;
1073 SSVAL(outbuf
,smb_tid
,cnum
);
1076 SSVAL(outbuf
,smb_vwv0
,fnum
);
1077 SIVALS(outbuf
,smb_vwv1
,-1);
1079 send_smb(Client
,outbuf
);
1080 receive_smb(Client
,inbuf
,CLIENT_TIMEOUT
);
1082 if (!ignore_close_error
&& CVAL(inbuf
,smb_rcls
) != 0)
1084 DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf
)));
1085 free(inbuf
);free(outbuf
);
1092 struct timeval tp_end
;
1095 /* if shallitime is true then we didn't skip */
1096 if (tar_reset
) (void) do_setrattr(finfo
.name
, aARCH
, ATTRRESET
);
1098 GetTimeOfDay(&tp_end
);
1100 (tp_end
.tv_sec
- tp_start
.tv_sec
)*1000 +
1101 (tp_end
.tv_usec
- tp_start
.tv_usec
)/1000;
1102 get_total_time_ms
+= this_time
;
1103 get_total_size
+= finfo
.size
;
1105 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
1106 DEBUG(1,("(%g kb/s) (average %g kb/s)\n",
1107 finfo
.size
/ MAX(0.001, (1.024*this_time
)),
1108 get_total_size
/ MAX(0.001, (1.024*get_total_time_ms
))));
1111 free(inbuf
);free(outbuf
);
1114 /****************************************************************************
1115 Append single file to tar file (or not)
1116 ***************************************************************************/
1117 static void do_tar(file_info
*finfo
)
1121 if (strequal(finfo
->name
,".") || strequal(finfo
->name
,".."))
1124 /* Is it on the exclude list ? */
1125 if (!tar_excl
&& clipn
) {
1128 strcpy(exclaim
, cur_dir
);
1129 *(exclaim
+strlen(exclaim
)-1)='\0';
1131 if (clipfind(cliplist
, clipn
, exclaim
)) {
1132 DEBUG(3,("Skipping directory %s\n", exclaim
));
1136 strcat(exclaim
, "\\");
1137 strcat(exclaim
, finfo
->name
);
1139 if (clipfind(cliplist
, clipn
, exclaim
)) {
1140 DEBUG(3,("Skipping file %s\n", exclaim
));
1145 if (finfo
->mode
& aDIR
)
1147 pstring saved_curdir
;
1149 char *inbuf
,*outbuf
;
1151 inbuf
= (char *)malloc(BUFFER_SIZE
+ SAFETY_MARGIN
);
1152 outbuf
= (char *)malloc(BUFFER_SIZE
+ SAFETY_MARGIN
);
1154 if (!inbuf
|| !outbuf
)
1156 DEBUG(0,("out of memory\n"));
1160 strcpy(saved_curdir
,cur_dir
);
1162 strcat(cur_dir
,finfo
->name
);
1163 strcat(cur_dir
,"\\");
1165 /* write a tar directory, don't bother with mode - just set it to
1167 writetarheader(tarhandle
, cur_dir
, 0, finfo
->mtime
, "040755 \0");
1168 strcpy(mtar_mask
,cur_dir
);
1169 strcat(mtar_mask
,"*");
1171 do_dir((char *)inbuf
,(char *)outbuf
,mtar_mask
,attribute
,do_tar
,recurse
);
1172 strcpy(cur_dir
,saved_curdir
);
1173 free(inbuf
);free(outbuf
);
1177 strcpy(rname
,cur_dir
);
1178 strcat(rname
,finfo
->name
);
1179 do_atar(rname
,finfo
->name
,finfo
);
1183 /****************************************************************************
1184 Convert from UNIX to DOS file names
1185 ***************************************************************************/
1186 static void unfixtarname(char *tptr
, char *fp
, int l
)
1188 /* remove '.' from start of file name, convert from unix /'s to
1189 * dos \'s in path. Kill any absolute path names.
1192 if (*fp
== '.') fp
++;
1193 if (*fp
== '\\' || *fp
== '/') fp
++;
1197 if (is_shift_jis (*fp
)) {
1201 } else if (is_kana (*fp
)) {
1204 } else if (*fp
== '/') {
1214 while (l
--) { *tptr
=(*fp
== '/') ? '\\' : *fp
; tptr
++; fp
++; }
1218 static void do_tarput()
1221 int nread
=0, bufread
;
1222 char *inbuf
,*outbuf
;
1225 struct timeval tp_start
;
1226 BOOL tskip
=False
; /* We'll take each file as it comes */
1228 GetTimeOfDay(&tp_start
);
1230 inbuf
= (char *)malloc(BUFFER_SIZE
+ SAFETY_MARGIN
);
1231 outbuf
= (char *)malloc(BUFFER_SIZE
+ SAFETY_MARGIN
);
1233 if (!inbuf
|| !outbuf
)
1235 DEBUG(0,("out of memory\n"));
1240 * Must read in tbufsiz dollops
1243 /* These should be the only reads in clitar.c */
1244 while ((bufread
=read(tarhandle
, tarbuf
, tbufsiz
))>0) {
1245 char *bufferp
, *endofbuffer
;
1248 /* Code to handle a short read.
1249 * We always need a TBLOCK full of stuff
1251 if (bufread
% TBLOCK
) {
1252 int lchunk
=TBLOCK
-(bufread
% TBLOCK
);
1255 /* It's a shorty - a short read that is */
1256 DEBUG(3, ("Short read, read %d so far (need %d)\n", bufread
, lchunk
));
1258 while ((lread
=read(tarhandle
, tarbuf
+bufread
, lchunk
))>0) {
1260 if (!(lchunk
-=lread
)) break;
1263 /* If we've reached EOF then that must be a short file */
1264 if (lread
<=0) break;
1268 endofbuffer
=tarbuf
+bufread
;
1271 if (fsize
<bufread
) {
1276 if (fsize
==bufread
) tskip
=False
;
1285 switch (readtarheader((union hblock
*) bufferp
, &finfo
, cur_dir
))
1287 case -2: /* something dodgy but not fatal about this */
1288 DEBUG(0, ("skipping %s...\n", finfo
.name
));
1289 bufferp
+=TBLOCK
; /* header - like a link */
1292 DEBUG(0, ("abandoning restore\n"));
1293 free(inbuf
); free(outbuf
);
1295 case 0: /* chksum is zero - we assume that one all zero
1296 *header block will do for eof */
1298 ("total of %d tar files restored to share\n", ntarf
));
1299 free(inbuf
); free(outbuf
);
1306 && (clipfind(cliplist
, clipn
, finfo
.name
) ^ tar_excl
);
1309 if (finfo
.mode
& aDIR
)
1311 else if ((fsize
=finfo
.size
) % TBLOCK
) {
1312 fsize
+=TBLOCK
-(fsize
%TBLOCK
);
1314 if (fsize
<endofbuffer
-bufferp
) {
1319 fsize
-=endofbuffer
-bufferp
;
1324 if (finfo
.mode
& aDIR
)
1326 if (!smbchkpath(finfo
.name
, inbuf
, outbuf
)
1327 && !smbmkdir(finfo
.name
, inbuf
, outbuf
))
1329 DEBUG(0, ("abandoning restore\n"));
1330 free(inbuf
); free(outbuf
);
1342 if (ensurepath(finfo
.name
, inbuf
, outbuf
)
1343 && !smbcreat(finfo
, &fnum
, inbuf
, outbuf
))
1345 DEBUG(0, ("abandoning restore\n"));
1346 free(inbuf
);free(outbuf
);
1350 DEBUG(0,("restore tar file %s of size %d bytes\n",
1351 finfo
.name
,finfo
.size
));
1354 if ((bufferp
+=TBLOCK
) >= endofbuffer
) break;
1357 /* write out the file in chunk sized chunks - don't
1358 * go past end of buffer though */
1359 chunk
=(fsize
-nread
< endofbuffer
- bufferp
)
1360 ? fsize
- nread
: endofbuffer
- bufferp
;
1363 int minichunk
=MIN(chunk
, max_xmit
-200);
1365 if (!smbwrite(fnum
, /* file descriptor */
1367 nread
, /* offset low */
1368 0, /* offset high - not implemented */
1369 fsize
-nread
, /* left - only hint to server */
1374 DEBUG(0, ("Error writing remote file\n"));
1375 free(inbuf
); free(outbuf
);
1378 DEBUG(5, ("chunk writing fname=%s fnum=%d nread=%d minichunk=%d chunk=%d size=%d\n", finfo
.name
, fnum
, nread
, minichunk
, chunk
, fsize
));
1380 bufferp
+=minichunk
; nread
+=minichunk
;
1386 if (!smbshut(finfo
, fnum
, inbuf
, outbuf
))
1388 DEBUG(0, ("Error closing remote file\n"));
1389 free(inbuf
);free(outbuf
);
1392 if (fsize
% TBLOCK
) bufferp
+=TBLOCK
- (fsize
% TBLOCK
);
1393 DEBUG(5, ("bufferp is now %d (psn=%d)\n",
1394 (long) bufferp
, (long)(bufferp
- tarbuf
)));
1398 } while (bufferp
< endofbuffer
);
1401 DEBUG(0, ("premature eof on tar file ?\n"));
1402 DEBUG(0,("total of %d tar files restored to share\n", ntarf
));
1404 free(inbuf
); free(outbuf
);
1408 * samba interactive commands
1411 /****************************************************************************
1413 ***************************************************************************/
1414 void cmd_block(void)
1419 if (!next_token(NULL
,buf
,NULL
))
1421 DEBUG(0, ("blocksize <n>\n"));
1426 if (block
< 0 || block
> 65535)
1428 DEBUG(0, ("blocksize out of range"));
1433 DEBUG(1,("blocksize is now %d\n", blocksize
));
1436 /****************************************************************************
1437 command to set incremental / reset mode
1438 ***************************************************************************/
1439 void cmd_tarmode(void)
1443 while (next_token(NULL
,buf
,NULL
)) {
1444 if (strequal(buf
, "full"))
1446 else if (strequal(buf
, "inc"))
1448 else if (strequal(buf
, "reset"))
1450 else if (strequal(buf
, "noreset"))
1452 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf
));
1455 DEBUG(0, ("tarmode is now %s, %s\n",
1456 tar_inc
? "incremental" : "full",
1457 tar_reset
? "reset" : "noreset"));
1460 /****************************************************************************
1461 Feeble attrib command
1462 ***************************************************************************/
1463 void cmd_setmode(void)
1471 attra
[0] = attra
[1] = 0;
1473 if (!next_token(NULL
,buf
,NULL
))
1475 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1479 strcpy(fname
, cur_dir
);
1482 while (next_token(NULL
,buf
,NULL
)) {
1491 case 'r': attra
[direct
]|=aRONLY
;
1493 case 'h': attra
[direct
]|=aHIDDEN
;
1495 case 's': attra
[direct
]|=aSYSTEM
;
1497 case 'a': attra
[direct
]|=aARCH
;
1499 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1504 if (attra
[ATTRSET
]==0 && attra
[ATTRRESET
]==0)
1506 DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1510 DEBUG(1, ("\nperm set %d %d\n", attra
[ATTRSET
], attra
[ATTRRESET
]));
1511 (void) do_setrattr(fname
, attra
[ATTRSET
], ATTRSET
);
1512 (void) do_setrattr(fname
, attra
[ATTRRESET
], ATTRRESET
);
1515 /****************************************************************************
1516 Principal command for creating / extracting
1517 ***************************************************************************/
1518 void cmd_tar(char *inbuf
, char *outbuf
)
1524 if (!next_token(NULL
,buf
,NULL
))
1526 DEBUG(0,("tar <c|x>[IXbga] <filename>\n"));
1530 argl
=toktocliplist(&argcl
, NULL
);
1531 if (!tar_parseargs(argcl
, argl
, buf
, 0))
1534 process_tar(inbuf
, outbuf
);
1539 /****************************************************************************
1540 Command line (option) version
1541 ***************************************************************************/
1542 int process_tar(char *inbuf
, char *outbuf
)
1553 if (clipn
&& tar_excl
) {
1557 for (i
=0; i
<clipn
; i
++) {
1558 DEBUG(0,("arg %d = %s\n", i
, cliplist
[i
]));
1560 if (*(cliplist
[i
]+strlen(cliplist
[i
])-1)=='\\') {
1561 *(cliplist
[i
]+strlen(cliplist
[i
])-1)='\0';
1564 if (strrchr(cliplist
[i
], '\\')) {
1567 strcpy(saved_dir
, cur_dir
);
1569 if (*cliplist
[i
]=='\\') {
1570 strcpy(tarmac
, cliplist
[i
]);
1572 strcpy(tarmac
, cur_dir
);
1573 strcat(tarmac
, cliplist
[i
]);
1575 strcpy(cur_dir
, tarmac
);
1576 *(strrchr(cur_dir
, '\\')+1)='\0';
1578 do_dir((char *)inbuf
,(char *)outbuf
,tarmac
,attribute
,do_tar
,recurse
);
1579 strcpy(cur_dir
,saved_dir
);
1581 strcpy(tarmac
, cur_dir
);
1582 strcat(tarmac
, cliplist
[i
]);
1583 do_dir((char *)inbuf
,(char *)outbuf
,tarmac
,attribute
,do_tar
,recurse
);
1588 strcpy(mask
,cur_dir
);
1590 do_dir((char *)inbuf
,(char *)outbuf
,mask
,attribute
,do_tar
,recurse
);
1593 if (ntarf
) dotareof(tarhandle
);
1597 DEBUG(0, ("tar: dumped %d tar files\n", ntarf
));
1604 /****************************************************************************
1605 Find a token (filename) in a clip list
1606 ***************************************************************************/
1607 int clipfind(char **aret
, int ret
, char *tok
)
1609 if (aret
==NULL
) return 0;
1611 /* ignore leading slashes or dots in token */
1612 while(strchr("/\\.", *tok
)) tok
++;
1617 /* ignore leading slashes or dots in list */
1618 while(strchr("/\\.", *pkey
)) pkey
++;
1620 if (!strslashcmp(pkey
, tok
)) return 1;
1626 /****************************************************************************
1627 Parse tar arguments. Sets tar_type, tar_excl, etc.
1628 ***************************************************************************/
1629 int tar_parseargs(int argc
, char *argv
[], char *Optarg
, int Optind
)
1631 char tar_clipfl
='\0';
1633 /* Reset back to defaults - could be from interactive version
1634 * reset mode and archive mode left as they are though
1645 if (tar_type
=='c') {
1646 printf("Tar must be followed by only one of c or x.\n");
1652 if (Optind
>=argc
|| !(blocksize
=atoi(argv
[Optind
]))) {
1653 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1664 DEBUG(0,("Option N must be followed by valid file name\n"));
1668 extern time_t newer_than
;
1670 if (sys_stat(argv
[Optind
], &stbuf
) == 0) {
1671 newer_than
= stbuf
.st_mtime
;
1672 DEBUG(1,("Getting files newer than %s",
1673 asctime(LocalTime(&newer_than
))));
1676 DEBUG(0,("Error setting newer-than time\n"));
1686 DEBUG(0,("Only one of I,X must be specified\n"));
1693 DEBUG(0,("Only one of I,X must be specified\n"));
1699 DEBUG(0,("Unknown tar option\n"));
1704 printf("Option T must be followed by one of c or x.\n");
1708 tar_excl
=tar_clipfl
!='X';
1709 if (Optind
+1<argc
) {
1710 cliplist
=argv
+Optind
+1;
1711 clipn
=argc
-Optind
-1;
1713 if (Optind
>=argc
|| !strcmp(argv
[Optind
], "-")) {
1714 /* Sets tar handle to either 0 or 1, as appropriate */
1715 tarhandle
=(tar_type
=='c');
1717 if ((tar_type
=='x' && (tarhandle
= open(argv
[Optind
], O_RDONLY
)) == -1)
1718 || (tar_type
=='c' && (tarhandle
=creat(argv
[Optind
], 0644)) < 0))
1720 DEBUG(0,("Error opening local file %s\n",argv
[Optind
]));