2 Unix SMB/Netbios implementation.
5 Copyright (C) Ricky Poulten 1995-1998
6 Copyright (C) Richard Sharpe 1998
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* The following changes developed by Richard Sharpe for Canon Information
23 Systems Research Australia (CISRA)
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 :-)
30 4. the files to exclude can be specified as a regular expression by adding
31 an r flag to the other tar flags. Eg:
33 -TcrX file.tar "*.(obj|exe)"
35 will skip all .obj and .exe files
42 static int clipfind(char **aret
, int ret
, char *tok
);
44 typedef struct file_info_struct file_info2
;
46 struct file_info_struct
52 /* These times are normally kept in GMT */
56 char *name
; /* This is dynamically allocate */
58 file_info2
*next
, *prev
; /* Used in the stack ... */
69 stack dir_stack
= {NULL
, 0}; /* Want an empty stack */
71 #define SEPARATORS " \t\n\r"
72 extern int DEBUGLEVEL
;
73 extern struct cli_state
*cli
;
75 /* These defines are for the do_setrattr routine, to indicate
76 * setting and reseting of file attributes in the function call */
80 static uint16 attribute
= aDIR
| aSYSTEM
| aHIDDEN
;
82 #ifndef CLIENT_TIMEOUT
83 #define CLIENT_TIMEOUT (30*1000)
86 static char *tarbuf
, *buffer_p
;
87 static int tp
, ntarf
, tbufsiz
, ttarf
;
88 /* Incremental mode */
90 /* Reset archive bit */
92 /* Include / exclude mode (true=include, false=exclude) */
94 /* use regular expressions for search on file names */
95 BOOL tar_re_search
=False
;
99 /* Do not dump anything, just calculate sizes */
101 /* Dump files with System attribute */
102 BOOL tar_system
=True
;
103 /* Dump files with Hidden attribute */
104 BOOL tar_hidden
=True
;
105 /* Be noisy - make a catalogue */
107 BOOL tar_real_noisy
=False
; /* Don't want to be really noisy by default */
110 static char **cliplist
=NULL
;
112 static BOOL must_free_cliplist
= False
;
114 extern file_info def_finfo
;
115 extern BOOL lowercase
;
117 extern BOOL readbraw_supported
;
119 extern pstring cur_dir
;
120 extern int get_total_time_ms
;
121 extern int get_total_size
;
127 static void writetarheader(int f
, char *aname
, int size
, time_t mtime
,
128 char *amode
, unsigned char ftype
);
129 static void do_atar(char *rname
,char *lname
,file_info
*finfo1
);
130 static void do_tar(file_info
*finfo
);
131 static void oct_it(long value
, int ndgs
, char *p
);
132 static void fixtarname(char *tptr
, char *fp
, int l
);
133 static int dotarbuf(int f
, char *b
, int n
);
134 static void dozerobuf(int f
, int n
);
135 static void dotareof(int f
);
136 static void initarbuf(void);
138 /* restore functions */
139 static long readtarheader(union hblock
*hb
, file_info2
*finfo
, char *prefix
);
140 static long unoct(char *p
, int ndgs
);
141 static void do_tarput(void);
142 static void unfixtarname(char *tptr
, char *fp
, int l
, BOOL first
);
145 * tar specific utitlities
148 /*******************************************************************
149 Create a string of size size+1 (for the null)
150 *******************************************************************/
151 static char *string_create_s(int size
)
155 tmp
= (char *)malloc(size
+1);
159 DEBUG(0, ("Out of memory in string_create_s\n"));
167 /****************************************************************************
168 Write a tar header to buffer
169 ****************************************************************************/
170 static void writetarheader(int f
, char *aname
, int size
, time_t mtime
,
171 char *amode
, unsigned char ftype
)
177 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype
, size
, aname
));
179 memset(hb
.dummy
, 0, sizeof(hb
.dummy
));
183 /* write a GNU tar style long header */
185 b
= (char *)malloc(l
+TBLOCK
+100);
187 DEBUG(0,("out of memory\n"));
190 writetarheader(f
, "/./@LongLink", l
+1, 0, " 0 \0", 'L');
191 memset(b
, 0, l
+TBLOCK
+100);
192 fixtarname(b
, aname
, l
);
194 DEBUG(5, ("File name in tar file: %s, size=%i, \n", b
, strlen(b
)));
195 dotarbuf(f
, b
, TBLOCK
*(((i
-1)/TBLOCK
)+1));
199 /* use l + 1 to do the null too */
200 fixtarname(hb
.dbuf
.name
, aname
, (l
>= NAMSIZ
) ? NAMSIZ
: l
+ 1);
203 strlower(hb
.dbuf
.name
);
205 /* write out a "standard" tar format header */
207 hb
.dbuf
.name
[NAMSIZ
-1]='\0';
208 safe_strcpy(hb
.dbuf
.mode
, amode
, strlen(amode
));
209 oct_it(0L, 8, hb
.dbuf
.uid
);
210 oct_it(0L, 8, hb
.dbuf
.gid
);
211 oct_it((long) size
, 13, hb
.dbuf
.size
);
212 oct_it((long) mtime
, 13, hb
.dbuf
.mtime
);
213 memcpy(hb
.dbuf
.chksum
, " ", sizeof(hb
.dbuf
.chksum
));
214 memset(hb
.dbuf
.linkname
, 0, NAMSIZ
);
215 hb
.dbuf
.linkflag
=ftype
;
217 for (chk
=0, i
=sizeof(hb
.dummy
), jp
=hb
.dummy
; --i
>=0;) chk
+=(0xFF & *jp
++);
219 oct_it((long) chk
, 8, hb
.dbuf
.chksum
);
220 hb
.dbuf
.chksum
[6] = '\0';
222 (void) dotarbuf(f
, hb
.dummy
, sizeof(hb
.dummy
));
225 /****************************************************************************
226 Read a tar header into a hblock structure, and validate
227 ***************************************************************************/
228 static long readtarheader(union hblock
*hb
, file_info2
*finfo
, char *prefix
)
235 * read in a "standard" tar format header - we're not that interested
236 * in that many fields, though
239 /* check the checksum */
240 for (chk
=0, i
=sizeof(hb
->dummy
), jp
=hb
->dummy
; --i
>=0;) chk
+=(0xFF & *jp
++);
245 /* compensate for blanks in chksum header */
246 for (i
=sizeof(hb
->dbuf
.chksum
), jp
=hb
->dbuf
.chksum
; --i
>=0;)
249 chk
+= ' ' * sizeof(hb
->dbuf
.chksum
);
251 fchk
=unoct(hb
->dbuf
.chksum
, sizeof(hb
->dbuf
.chksum
));
253 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
254 chk
, fchk
, hb
->dbuf
.chksum
));
258 DEBUG(0, ("checksums don't match %ld %ld\n", fchk
, chk
));
259 dump_data(5, (char *)hb
- TBLOCK
, TBLOCK
*3);
263 if ((finfo
->name
= string_create_s(strlen(prefix
) + strlen(hb
-> dbuf
.name
) + 3)) == NULL
) {
265 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb
-> dbuf
.name
));
270 safe_strcpy(finfo
->name
, prefix
, strlen(prefix
) + strlen(hb
-> dbuf
.name
) + 3);
272 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
273 unfixtarname(finfo
->name
+ strlen(prefix
), hb
->dbuf
.name
,
274 strlen(hb
->dbuf
.name
) + 1, True
);
276 /* can't handle some links at present */
277 if ((hb
->dbuf
.linkflag
!= '0') && (hb
-> dbuf
.linkflag
!= '5')) {
278 if (hb
->dbuf
.linkflag
== 0) {
279 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
282 if (hb
-> dbuf
.linkflag
== 'L') { /* We have a longlink */
283 /* Do nothing here at the moment. do_tarput will handle this
284 as long as the longlink gets back to it, as it has to advance
285 the buffer pointer, etc */
288 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
294 if ((unoct(hb
->dbuf
.mode
, sizeof(hb
->dbuf
.mode
)) & S_IFDIR
)
295 || (*(finfo
->name
+strlen(finfo
->name
)-1) == '\\'))
300 finfo
->mode
=0; /* we don't care about mode at the moment, we'll
301 * just make it a regular file */
303 * Bug fix by richard@sj.co.uk
305 * REC: restore times correctly (as does tar)
306 * We only get the modification time of the file; set the creation time
307 * from the mod. time, and the access time to current time
309 finfo
->mtime
= finfo
->ctime
= strtol(hb
->dbuf
.mtime
, NULL
, 8);
310 finfo
->atime
= time(NULL
);
311 finfo
->size
= unoct(hb
->dbuf
.size
, sizeof(hb
->dbuf
.size
));
316 /****************************************************************************
317 Write out the tar buffer to tape or wherever
318 ****************************************************************************/
319 static int dotarbuf(int f
, char *b
, int n
)
326 /* This routine and the next one should be the only ones that do write()s */
327 if (tp
+ n
>= tbufsiz
)
332 memcpy(tarbuf
+ tp
, b
, diff
);
333 fail
=fail
&& (1+write(f
, tarbuf
, tbufsiz
));
340 fail
=fail
&& (1 + write(f
, b
, tbufsiz
));
346 memcpy(tarbuf
+tp
, b
, n
);
350 return(fail
? writ
: 0);
353 /****************************************************************************
354 Write zeros to buffer / tape
355 ****************************************************************************/
356 static void dozerobuf(int f
, int n
)
358 /* short routine just to write out n zeros to buffer -
359 * used to round files to nearest block
360 * and to do tar EOFs */
367 memset(tarbuf
+tp
, 0, tbufsiz
-tp
);
369 write(f
, tarbuf
, tbufsiz
);
370 memset(tarbuf
, 0, (tp
+=n
-tbufsiz
));
374 memset(tarbuf
+tp
, 0, n
);
379 /****************************************************************************
381 ****************************************************************************/
382 static void initarbuf(void)
384 /* initialize tar buffer */
385 tbufsiz
=blocksize
*TBLOCK
;
386 tarbuf
=malloc(tbufsiz
); /* FIXME: We might not get the buffer */
388 /* reset tar buffer pointer and tar file counter and total dumped */
389 tp
=0; ntarf
=0; ttarf
=0;
392 /****************************************************************************
393 Write two zero blocks at end of file
394 ****************************************************************************/
395 static void dotareof(int f
)
397 SMB_STRUCT_STAT stbuf
;
398 /* Two zero blocks at end of file, write out full buffer */
403 (void) dozerobuf(f
, TBLOCK
);
404 (void) dozerobuf(f
, TBLOCK
);
406 if (sys_fstat(f
, &stbuf
) == -1)
408 DEBUG(0, ("Couldn't stat file handle\n"));
412 /* Could be a pipe, in which case S_ISREG should fail,
413 * and we should write out at full size */
414 if (tp
> 0) write(f
, tarbuf
, S_ISREG(stbuf
.st_mode
) ? tp
: tbufsiz
);
417 /****************************************************************************
418 (Un)mangle DOS pathname, make nonabsolute
419 ****************************************************************************/
420 static void fixtarname(char *tptr
, char *fp
, int l
)
422 /* add a '.' to start of file name, convert from ugly dos \'s in path
423 * to lovely unix /'s :-} */
429 if((skip
= skip_multibyte_char( *fp
)) != 0) {
434 } else if (skip
== 1) {
438 } else if (*fp
== '\\') {
449 /****************************************************************************
450 Convert from decimal to octal string
451 ****************************************************************************/
452 static void oct_it (long value
, int ndgs
, char *p
)
454 /* Converts long to octal string, pads with leading zeros */
456 /* skip final null, but do final space */
460 /* Loop does at least one digit */
462 p
[--ndgs
] = '0' + (char) (value
& 7);
465 while (ndgs
> 0 && value
!= 0);
467 /* Do leading zeros */
472 /****************************************************************************
473 Convert from octal string to long
474 ***************************************************************************/
475 static long unoct(char *p
, int ndgs
)
478 /* Converts octal string to long, ignoring any non-digit */
482 if (isdigit((int)*p
))
483 value
= (value
<< 3) | (long) (*p
- '0');
491 /****************************************************************************
492 Compare two strings in a slash insensitive way, allowing s1 to match s2
493 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
494 a file in any subdirectory of s1, declare a match.
495 ***************************************************************************/
496 static int strslashcmp(char *s1
, char *s2
)
502 || tolower(*s1
) == tolower(*s2
)
503 || (*s1
== '\\' && *s2
=='/')
504 || (*s1
== '/' && *s2
=='\\'))) {
508 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
511 if (!*s1
&& s1
!= s1_0
&& (*(s1
-1) == '/' || *(s1
-1) == '\\')) return 0;
513 /* ignore trailing slash on s1 */
514 if (!*s2
&& (*s1
== '/' || *s1
== '\\') && !*(s1
+1)) return 0;
516 /* check for s1 is an "initial" string of s2 */
517 if (*s2
== '/' || *s2
== '\\') return 0;
523 /****************************************************************************
524 Ensure a remote path exists (make if necessary)
525 ***************************************************************************/
526 static BOOL
ensurepath(char *fname
)
528 /* *must* be called with buffer ready malloc'ed */
529 /* ensures path exists */
531 char *partpath
, *ffname
;
532 char *p
=fname
, *basehack
;
534 DEBUG(5, ( "Ensurepath called with: %s\n", fname
));
536 partpath
= string_create_s(strlen(fname
));
537 ffname
= string_create_s(strlen(fname
));
539 if ((partpath
== NULL
) || (ffname
== NULL
)){
541 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname
));
548 /* fname copied to ffname so can strtok */
550 safe_strcpy(ffname
, fname
, strlen(fname
));
552 /* do a `basename' on ffname, so don't try and make file name directory */
553 if ((basehack
=strrchr(ffname
, '\\')) == NULL
)
558 p
=strtok(ffname
, "\\");
562 safe_strcat(partpath
, p
, strlen(fname
) + 1);
564 if (!cli_chkpath(cli
, partpath
)) {
565 if (!cli_mkdir(cli
, partpath
))
567 DEBUG(0, ("Error mkdirhiering\n"));
571 DEBUG(3, ("mkdirhiering %s\n", partpath
));
575 safe_strcat(partpath
, "\\", strlen(fname
) + 1);
576 p
= strtok(NULL
,"/\\");
582 static int padit(char *buf
, int bufsize
, int padsize
)
587 DEBUG(5, ("Padding with %d zeros\n", padsize
));
588 memset(buf
, 0, bufsize
);
589 while( !berr
&& padsize
> 0 ) {
590 bytestowrite
= MIN(bufsize
, padsize
);
591 berr
= dotarbuf(tarhandle
, buf
, bytestowrite
) != bytestowrite
;
592 padsize
-= bytestowrite
;
599 static void do_setrattr(char *name
, uint16 attr
, int set
)
603 if (!cli_getatr(cli
, name
, &oldattr
, NULL
, NULL
)) return;
605 if (set
== ATTRSET
) {
608 attr
= oldattr
& ~attr
;
611 if (!cli_setatr(cli
, name
, attr
, 0)) {
612 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli
)));
617 /****************************************************************************
618 append one remote file to the tar file
619 ***************************************************************************/
620 static void do_atar(char *rname
,char *lname
,file_info
*finfo1
)
626 BOOL close_done
= False
;
627 BOOL shallitime
=True
;
629 int read_size
= 65520;
632 struct timeval tp_start
;
633 GetTimeOfDay(&tp_start
);
635 ftype
= '0'; /* An ordinary file ... */
638 finfo
.size
= finfo1
-> size
;
639 finfo
.mode
= finfo1
-> mode
;
640 finfo
.uid
= finfo1
-> uid
;
641 finfo
.gid
= finfo1
-> gid
;
642 finfo
.mtime
= finfo1
-> mtime
;
643 finfo
.atime
= finfo1
-> atime
;
644 finfo
.ctime
= finfo1
-> ctime
;
647 finfo
.size
= def_finfo
.size
;
648 finfo
.mode
= def_finfo
.mode
;
649 finfo
.uid
= def_finfo
.uid
;
650 finfo
.gid
= def_finfo
.gid
;
651 finfo
.mtime
= def_finfo
.mtime
;
652 finfo
.atime
= def_finfo
.atime
;
653 finfo
.ctime
= def_finfo
.ctime
;
658 DEBUG(3,("skipping file %s of size %d bytes\n",
662 ttarf
+=finfo
.size
+ TBLOCK
- (finfo
.size
% TBLOCK
);
667 fnum
= cli_open(cli
, rname
, O_RDONLY
, DENY_NONE
);
669 dos_clean_name(rname
);
672 DEBUG(0,("%s opening remote file %s (%s)\n",
673 cli_errstr(cli
),rname
, cur_dir
));
677 finfo
.name
= string_create_s(strlen(rname
));
678 if (finfo
.name
== NULL
) {
679 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
683 safe_strcpy(finfo
.name
,rname
, strlen(rname
));
685 if (!cli_getattrE(cli
, fnum
, &finfo
.mode
, &finfo
.size
, NULL
, &finfo
.atime
, &finfo
.mtime
)) {
686 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli
)));
689 finfo
.ctime
= finfo
.mtime
;
692 DEBUG(3,("file %s attrib 0x%X\n",finfo
.name
,finfo
.mode
));
694 if (tar_inc
&& !(finfo
.mode
& aARCH
))
696 DEBUG(4, ("skipping %s - archive bit not set\n", finfo
.name
));
699 else if (!tar_system
&& (finfo
.mode
& aSYSTEM
))
701 DEBUG(4, ("skipping %s - system bit is set\n", finfo
.name
));
704 else if (!tar_hidden
&& (finfo
.mode
& aHIDDEN
))
706 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo
.name
));
711 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
716 /* write a tar header, don't bother with mode - just set to 100644 */
717 writetarheader(tarhandle
, rname
, finfo
.size
, finfo
.mtime
, "100644 \0", ftype
);
719 while (nread
< finfo
.size
&& !close_done
) {
721 DEBUG(3,("nread=%d\n",nread
));
723 datalen
= cli_read(cli
, fnum
, data
, nread
, read_size
);
726 DEBUG(0,("Error reading file %s : %s\n", rname
, cli_errstr(cli
)));
730 /* add received bits of file to buffer - dotarbuf will
731 * write out in 512 byte intervals */
732 if (dotarbuf(tarhandle
,data
,datalen
) != datalen
) {
733 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno
)));
739 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname
));
746 /* pad tar file with zero's if we couldn't get entire file */
747 if (nread
< finfo
.size
) {
748 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", finfo
.size
, nread
));
749 if (padit(data
, sizeof(data
), finfo
.size
- nread
))
750 DEBUG(0,("Error writing tar file - %s\n", strerror(errno
)));
753 /* round tar file to nearest block */
754 if (finfo
.size
% TBLOCK
)
755 dozerobuf(tarhandle
, TBLOCK
- (finfo
.size
% TBLOCK
));
757 ttarf
+=finfo
.size
+ TBLOCK
- (finfo
.size
% TBLOCK
);
761 cli_close(cli
, fnum
);
765 struct timeval tp_end
;
768 /* if shallitime is true then we didn't skip */
769 if (tar_reset
&& !dry_run
)
770 (void) do_setrattr(finfo
.name
, aARCH
, ATTRRESET
);
772 GetTimeOfDay(&tp_end
);
774 (tp_end
.tv_sec
- tp_start
.tv_sec
)*1000 +
775 (tp_end
.tv_usec
- tp_start
.tv_usec
)/1000;
776 get_total_time_ms
+= this_time
;
777 get_total_size
+= finfo
.size
;
781 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
782 finfo
.size
, finfo
.size
/ MAX(0.001, (1.024*this_time
)),
786 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
787 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
788 finfo
.size
/ MAX(0.001, (1.024*this_time
)),
789 get_total_size
/ MAX(0.001, (1.024*get_total_time_ms
))));
793 /****************************************************************************
794 Append single file to tar file (or not)
795 ***************************************************************************/
796 static void do_tar(file_info
*finfo
)
800 if (strequal(finfo
->name
,"..") || strequal(finfo
->name
,"."))
803 /* Is it on the exclude list ? */
804 if (!tar_excl
&& clipn
) {
807 DEBUG(5, ("Excl: strlen(cur_dir) = %i\n", strlen(cur_dir
)));
809 safe_strcpy(exclaim
, cur_dir
, sizeof(pstring
));
810 *(exclaim
+strlen(exclaim
)-1)='\0';
812 safe_strcat(exclaim
, "\\", sizeof(pstring
));
813 safe_strcat(exclaim
, finfo
->name
, sizeof(exclaim
));
815 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search
));
817 if ((!tar_re_search
&& clipfind(cliplist
, clipn
, exclaim
)) ||
819 (tar_re_search
&& !regexec(preg
, exclaim
, 0, NULL
, 0))) {
821 (tar_re_search
&& mask_match(exclaim
, cliplist
[0], True
, False
))) {
823 DEBUG(3,("Skipping file %s\n", exclaim
));
828 if (finfo
->mode
& aDIR
)
830 pstring saved_curdir
;
833 safe_strcpy(saved_curdir
, cur_dir
, sizeof(saved_curdir
));
835 DEBUG(5, ("Sizeof(cur_dir)=%i, strlen(cur_dir)=%i, strlen(finfo->name)=%i\nname=%s,cur_dir=%s\n", sizeof(cur_dir
), strlen(cur_dir
), strlen(finfo
->name
), finfo
->name
, cur_dir
));
837 safe_strcat(cur_dir
,finfo
->name
, sizeof(cur_dir
));
838 safe_strcat(cur_dir
,"\\", sizeof(cur_dir
));
840 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir
));
842 /* write a tar directory, don't bother with mode - just set it to
844 writetarheader(tarhandle
, cur_dir
, 0, finfo
->mtime
, "040755 \0", '5');
846 DEBUG(0,(" directory %s\n", cur_dir
));
848 ntarf
++; /* Make sure we have a file on there */
849 safe_strcpy(mtar_mask
,cur_dir
, sizeof(pstring
));
850 safe_strcat(mtar_mask
,"*", sizeof(pstring
));
851 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask
));
852 do_list(mtar_mask
, attribute
, do_tar
, False
, True
);
853 safe_strcpy(cur_dir
,saved_curdir
, sizeof(pstring
));
857 safe_strcpy(rname
,cur_dir
, sizeof(pstring
));
858 safe_strcat(rname
,finfo
->name
, sizeof(pstring
));
859 do_atar(rname
,finfo
->name
,finfo
);
863 /****************************************************************************
864 Convert from UNIX to DOS file names
865 ***************************************************************************/
866 static void unfixtarname(char *tptr
, char *fp
, int l
, BOOL first
)
868 /* remove '.' from start of file name, convert from unix /'s to
869 * dos \'s in path. Kill any absolute path names. But only if first!
872 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr
, (long)fp
, l
));
879 if (*fp
== '\\' || *fp
== '/') {
887 if(( skip
= skip_multibyte_char( *fp
)) != 0) {
892 } else if (skip
== 1) {
896 } else if (*fp
== '/') {
908 /****************************************************************************
909 Move to the next block in the buffer, which may mean read in another set of
910 blocks. FIXME, we should allow more than one block to be skipped.
911 ****************************************************************************/
912 static int next_block(char *ltarbuf
, char **bufferp
, int bufsiz
)
914 int bufread
, total
= 0;
916 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp
));
920 if (*bufferp
>= (ltarbuf
+ bufsiz
)) {
922 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
926 for (bufread
= read(tarhandle
, ltarbuf
, bufsiz
); total
< bufsiz
; total
+= bufread
) {
928 if (bufread
<= 0) { /* An error, return false */
929 return (total
> 0 ? -2 : bufread
);
934 DEBUG(5, ("Total bytes read ... %i\n", total
));
944 /* Skip a file, even if it includes a long file name? */
945 static int skip_file(int skipsize
)
947 int dsize
= skipsize
;
949 DEBUG(5, ("Skiping file. Size = %i\n", skipsize
));
951 /* FIXME, we should skip more than one block at a time */
955 if (next_block(tarbuf
, &buffer_p
, tbufsiz
) <= 0) {
957 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno
)));
969 /* We get a file from the tar file and store it */
970 static int get_file(file_info2 finfo
)
972 int fsize
= finfo
.size
;
973 int fnum
= -1, pos
= 0, dsize
= 0, rsize
= 0, bpos
= 0;
975 DEBUG(5, ("get_file: file: %s, size %i\n", finfo
.name
, fsize
));
977 if (ensurepath(finfo
.name
) &&
978 (fnum
=cli_open(cli
, finfo
.name
, O_WRONLY
|O_CREAT
|O_TRUNC
, DENY_NONE
)) == -1)
980 DEBUG(0, ("abandoning restore\n"));
984 /* read the blocks from the tar file and write to the remote file */
986 rsize
= fsize
; /* This is how much to write */
990 /* We can only write up to the end of the buffer */
992 dsize
= MIN(tbufsiz
- (buffer_p
- tarbuf
) - bpos
, 65520); /* Calculate the size to write */
993 dsize
= MIN(dsize
, rsize
); /* Should be only what is left */
994 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize
, bpos
));
996 if (cli_write(cli
, fnum
, 0, buffer_p
+ bpos
, pos
, dsize
) != dsize
) {
997 DEBUG(0, ("Error writing remote file\n"));
1004 /* Now figure out how much to move in the buffer */
1006 /* FIXME, we should skip more than one block at a time */
1008 /* First, skip any initial part of the part written that is left over */
1009 /* from the end of the first TBLOCK */
1011 if ((bpos
) && ((bpos
+ dsize
) >= TBLOCK
)) {
1013 dsize
-= (TBLOCK
- bpos
); /* Get rid of the end of the first block */
1016 if (next_block(tarbuf
, &buffer_p
, tbufsiz
) <=0) { /* and skip the block */
1017 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno
)));
1024 while (dsize
>= TBLOCK
) {
1026 if (next_block(tarbuf
, &buffer_p
, tbufsiz
) <=0) {
1028 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno
)));
1041 /* Now close the file ... */
1043 if (!cli_close(cli
, fnum
)) {
1044 DEBUG(0, ("Error closing remote file\n"));
1048 /* Now we update the creation date ... */
1050 DEBUG(5, ("Updating creation date on %s\n", finfo
.name
));
1052 if (!cli_setatr(cli
, finfo
.name
, finfo
.mode
, finfo
.mtime
)) {
1053 if (tar_real_noisy
) {
1054 DEBUG(0, ("Could not set time on file: %s\n", finfo
.name
));
1055 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1061 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo
.name
, finfo
.size
));
1066 /* Create a directory. We just ensure that the path exists and return as there
1067 is no file associated with a directory
1069 static int get_dir(file_info2 finfo
)
1072 DEBUG(5, ("Creating directory: %s\n", finfo
.name
));
1074 if (!ensurepath(finfo
.name
)) {
1076 DEBUG(0, ("Problems creating directory\n"));
1083 /* Get a file with a long file name ... first file has file name, next file
1084 has the data. We only want the long file name, as the loop in do_tarput
1085 will deal with the rest.
1087 static char * get_longfilename(file_info2 finfo
)
1089 int namesize
= finfo
.size
+ strlen(cur_dir
) + 2;
1090 char *longname
= malloc(namesize
);
1091 int offset
= 0, left
= finfo
.size
;
1094 DEBUG(5, ("Restoring a long file name: %s\n", finfo
.name
));
1095 DEBUG(5, ("Len = %i\n", finfo
.size
));
1097 if (longname
== NULL
) {
1099 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1100 finfo
.size
+ strlen(cur_dir
) + 2));
1104 /* First, add cur_dir to the long file name */
1106 if (strlen(cur_dir
) > 0) {
1107 strncpy(longname
, cur_dir
, namesize
);
1108 offset
= strlen(cur_dir
);
1111 /* Loop through the blocks picking up the name */
1115 if (next_block(tarbuf
, &buffer_p
, tbufsiz
) <= 0) {
1117 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno
)));
1122 unfixtarname(longname
+ offset
, buffer_p
, MIN(TBLOCK
, finfo
.size
), first
--);
1123 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname
, buffer_p
));
1134 static void do_tarput(void)
1137 struct timeval tp_start
;
1138 char *longfilename
= NULL
, linkflag
;
1141 GetTimeOfDay(&tp_start
);
1143 DEBUG(5, ("RJS do_tarput called ...\n"));
1145 buffer_p
= tarbuf
+ tbufsiz
; /* init this to force first read */
1147 /* Now read through those files ... */
1151 /* Get us to the next block, or the first block first time around */
1153 if (next_block(tarbuf
, &buffer_p
, tbufsiz
) <= 0) {
1155 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno
)));
1161 DEBUG(5, ("Reading the next header ...\n"));
1163 switch (readtarheader((union hblock
*) buffer_p
, &finfo
, cur_dir
)) {
1165 case -2: /* Hmm, not good, but not fatal */
1166 DEBUG(0, ("Skipping %s...\n", finfo
.name
));
1167 if ((next_block(tarbuf
, &buffer_p
, tbufsiz
) <= 0) &&
1168 !skip_file(finfo
.size
)) {
1170 DEBUG(0, ("Short file, bailing out...\n"));
1178 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1181 case 0: /* chksum is zero - looks like an EOF */
1182 DEBUG(0, ("total of %d tar files restored to share\n", ntarf
));
1183 return; /* Hmmm, bad here ... */
1192 /* Now, do we have a long file name? */
1194 if (longfilename
!= NULL
) {
1196 free(finfo
.name
); /* Free the space already allocated */
1197 finfo
.name
= longfilename
;
1198 longfilename
= NULL
;
1202 /* Well, now we have a header, process the file ... */
1204 /* Should we skip the file? We have the long name as well here */
1207 ((!tar_re_search
&& clipfind(cliplist
, clipn
, finfo
.name
) ^ tar_excl
)
1209 || (tar_re_search
&& !regexec(preg
, finfo
.name
, 0, NULL
, 0)));
1211 || (tar_re_search
&& mask_match(finfo
.name
, cliplist
[0], True
, False
)));
1214 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip
, (cliplist
?cliplist
[0]:NULL
), finfo
.name
));
1218 skip_file(finfo
.size
);
1223 /* We only get this far if we should process the file */
1224 linkflag
= ((union hblock
*)buffer_p
) -> dbuf
.linkflag
;
1228 case '0': /* Should use symbolic names--FIXME */
1230 /* Skip to the next block first, so we can get the file, FIXME, should
1231 be in get_file ... */
1233 if (next_block(tarbuf
, &buffer_p
, tbufsiz
) <=0) {
1234 DEBUG(0, ("Short file, bailing out...\n"));
1237 if (!get_file(finfo
)) {
1238 DEBUG(0, ("Abandoning restore\n"));
1245 if (!get_dir(finfo
)) {
1246 DEBUG(0, ("Abandoning restore \n"));
1252 longfilename
= get_longfilename(finfo
);
1253 if (!longfilename
) {
1254 DEBUG(0, ("abandoning restore\n"));
1258 DEBUG(5, ("Long file name: %s\n", longfilename
));
1262 skip_file(finfo
.size
); /* Don't handle these yet */
1274 * samba interactive commands
1277 /****************************************************************************
1279 ***************************************************************************/
1280 void cmd_block(void)
1285 if (!next_token(NULL
,buf
,NULL
,sizeof(buf
)))
1287 DEBUG(0, ("blocksize <n>\n"));
1292 if (block
< 0 || block
> 65535)
1294 DEBUG(0, ("blocksize out of range"));
1299 DEBUG(2,("blocksize is now %d\n", blocksize
));
1302 /****************************************************************************
1303 command to set incremental / reset mode
1304 ***************************************************************************/
1305 void cmd_tarmode(void)
1309 while (next_token(NULL
,buf
,NULL
,sizeof(buf
))) {
1310 if (strequal(buf
, "full"))
1312 else if (strequal(buf
, "inc"))
1314 else if (strequal(buf
, "reset"))
1316 else if (strequal(buf
, "noreset"))
1318 else if (strequal(buf
, "system"))
1320 else if (strequal(buf
, "nosystem"))
1322 else if (strequal(buf
, "hidden"))
1324 else if (strequal(buf
, "nohidden"))
1326 else if (strequal(buf
, "verbose") || strequal(buf
, "noquiet"))
1328 else if (strequal(buf
, "quiet") || strequal(buf
, "noverbose"))
1330 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf
));
1333 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1334 tar_inc
? "incremental" : "full",
1335 tar_system
? "system" : "nosystem",
1336 tar_hidden
? "hidden" : "nohidden",
1337 tar_reset
? "reset" : "noreset",
1338 tar_noisy
? "verbose" : "quiet"));
1342 /****************************************************************************
1343 Feeble attrib command
1344 ***************************************************************************/
1345 void cmd_setmode(void)
1353 attra
[0] = attra
[1] = 0;
1355 if (!next_token(NULL
,buf
,NULL
,sizeof(buf
)))
1357 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1361 safe_strcpy(fname
, cur_dir
, sizeof(pstring
));
1362 safe_strcat(fname
, buf
, sizeof(pstring
));
1364 while (next_token(NULL
,buf
,NULL
,sizeof(buf
))) {
1373 case 'r': attra
[direct
]|=aRONLY
;
1375 case 'h': attra
[direct
]|=aHIDDEN
;
1377 case 's': attra
[direct
]|=aSYSTEM
;
1379 case 'a': attra
[direct
]|=aARCH
;
1381 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1386 if (attra
[ATTRSET
]==0 && attra
[ATTRRESET
]==0)
1388 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1392 DEBUG(2, ("\nperm set %d %d\n", attra
[ATTRSET
], attra
[ATTRRESET
]));
1393 do_setrattr(fname
, attra
[ATTRSET
], ATTRSET
);
1394 do_setrattr(fname
, attra
[ATTRRESET
], ATTRRESET
);
1397 /****************************************************************************
1398 Principal command for creating / extracting
1399 ***************************************************************************/
1406 if (!next_token(NULL
,buf
,NULL
,sizeof(buf
)))
1408 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1412 argl
=toktocliplist(&argcl
, NULL
);
1413 if (!tar_parseargs(argcl
, argl
, buf
, 0))
1421 /****************************************************************************
1422 Command line (option) version
1423 ***************************************************************************/
1424 int process_tar(void)
1440 if (clipn
&& tar_excl
) {
1444 for (i
=0; i
<clipn
; i
++) {
1445 DEBUG(5,("arg %d = %s\n", i
, cliplist
[i
]));
1447 if (*(cliplist
[i
]+strlen(cliplist
[i
])-1)=='\\') {
1448 *(cliplist
[i
]+strlen(cliplist
[i
])-1)='\0';
1451 if (strrchr(cliplist
[i
], '\\')) {
1454 safe_strcpy(saved_dir
, cur_dir
, sizeof(pstring
));
1456 if (*cliplist
[i
]=='\\') {
1457 safe_strcpy(tarmac
, cliplist
[i
], sizeof(pstring
));
1459 safe_strcpy(tarmac
, cur_dir
, sizeof(pstring
));
1460 safe_strcat(tarmac
, cliplist
[i
], sizeof(pstring
));
1462 safe_strcpy(cur_dir
, tarmac
, sizeof(pstring
));
1463 *(strrchr(cur_dir
, '\\')+1)='\0';
1465 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac
));
1466 do_list(tarmac
,attribute
,do_tar
, False
, True
);
1467 safe_strcpy(cur_dir
,saved_dir
, sizeof(pstring
));
1469 safe_strcpy(tarmac
, cur_dir
, sizeof(pstring
));
1470 safe_strcat(tarmac
, cliplist
[i
], sizeof(pstring
));
1471 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac
));
1472 do_list(tarmac
,attribute
,do_tar
, False
, True
);
1477 safe_strcpy(mask
,cur_dir
, sizeof(pstring
));
1478 DEBUG(5, ("process_tar, do_list with mask: $s\n", mask
));
1479 safe_strcat(mask
,"\\*", sizeof(pstring
));
1480 do_list(mask
,attribute
,do_tar
,False
, True
);
1483 if (ntarf
) dotareof(tarhandle
);
1487 DEBUG(0, ("tar: dumped %d tar files\n", ntarf
));
1488 DEBUG(0, ("Total bytes written: %d\n", ttarf
));
1492 if (must_free_cliplist
) {
1494 for (i
= 0; i
< clipn
; ++i
) {
1500 must_free_cliplist
= False
;
1506 /****************************************************************************
1507 Find a token (filename) in a clip list
1508 ***************************************************************************/
1509 static int clipfind(char **aret
, int ret
, char *tok
)
1511 if (aret
==NULL
) return 0;
1513 /* ignore leading slashes or dots in token */
1514 while(strchr("/\\.", *tok
)) tok
++;
1519 /* ignore leading slashes or dots in list */
1520 while(strchr("/\\.", *pkey
)) pkey
++;
1522 if (!strslashcmp(pkey
, tok
)) return 1;
1528 /****************************************************************************
1529 Read list of files to include from the file and initialize cliplist
1531 ***************************************************************************/
1532 static int read_inclusion_file(char *filename
)
1534 FILE *inclusion
= NULL
;
1535 char buf
[MAXPATHLEN
+ 1];
1536 char *inclusion_buffer
= NULL
;
1537 int inclusion_buffer_size
= 0;
1538 int inclusion_buffer_sofar
= 0;
1545 buf
[MAXPATHLEN
] = '\0'; /* guarantee null-termination */
1546 if ((inclusion
= sys_fopen(filename
, "r")) == NULL
) {
1547 /* XXX It would be better to include a reason for failure, but without
1548 * autoconf, it's hard to use strerror, sys_errlist, etc.
1550 DEBUG(0,("Unable to open inclusion file %s\n", filename
));
1554 while ((! error
) && (fgets(buf
, sizeof(buf
)-1, inclusion
))) {
1555 if (inclusion_buffer
== NULL
) {
1556 inclusion_buffer_size
= 1024;
1557 if ((inclusion_buffer
= malloc(inclusion_buffer_size
)) == NULL
) {
1558 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1564 if (buf
[strlen(buf
)-1] == '\n') {
1565 buf
[strlen(buf
)-1] = '\0';
1568 if ((strlen(buf
) + 1 + inclusion_buffer_sofar
) >= inclusion_buffer_size
) {
1569 inclusion_buffer_size
*= 2;
1570 inclusion_buffer
= Realloc(inclusion_buffer
,inclusion_buffer_size
);
1571 if (! inclusion_buffer
) {
1572 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n",
1573 inclusion_buffer_size
));
1579 safe_strcpy(inclusion_buffer
+ inclusion_buffer_sofar
, buf
, inclusion_buffer_size
- inclusion_buffer_sofar
);
1580 inclusion_buffer_sofar
+= strlen(buf
) + 1;
1586 /* Allocate an array of clipn + 1 char*'s for cliplist */
1587 cliplist
= malloc((clipn
+ 1) * sizeof(char *));
1588 if (cliplist
== NULL
) {
1589 DEBUG(0,("failure allocating memory for cliplist\n"));
1592 cliplist
[clipn
] = NULL
;
1593 p
= inclusion_buffer
;
1594 for (i
= 0; (! error
) && (i
< clipn
); i
++) {
1595 /* set current item to NULL so array will be null-terminated even if
1596 * malloc fails below. */
1598 if ((tmpstr
= (char *)malloc(strlen(p
)+1)) == NULL
) {
1599 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i
));
1602 unfixtarname(tmpstr
, p
, strlen(p
) + 1, True
);
1603 cliplist
[i
] = tmpstr
;
1604 if ((p
= strchr(p
, '\000')) == NULL
) {
1605 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1611 must_free_cliplist
= True
;
1615 if (inclusion_buffer
) {
1616 free(inclusion_buffer
);
1621 /* We know cliplist is always null-terminated */
1622 for (pp
= cliplist
; *pp
; ++pp
) {
1627 must_free_cliplist
= False
;
1632 /* cliplist and its elements are freed at the end of process_tar. */
1636 /****************************************************************************
1637 Parse tar arguments. Sets tar_type, tar_excl, etc.
1638 ***************************************************************************/
1639 int tar_parseargs(int argc
, char *argv
[], char *Optarg
, int Optind
)
1641 char tar_clipfl
='\0';
1643 /* Reset back to defaults - could be from interactive version
1644 * reset mode and archive mode left as they are though
1656 if (tar_type
=='c') {
1657 printf("Tar must be followed by only one of c or x.\n");
1663 if (Optind
>=argc
|| !(blocksize
=atoi(argv
[Optind
]))) {
1664 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1675 DEBUG(0,("Option N must be followed by valid file name\n"));
1678 SMB_STRUCT_STAT stbuf
;
1679 extern time_t newer_than
;
1681 if (dos_stat(argv
[Optind
], &stbuf
) == 0) {
1682 newer_than
= stbuf
.st_mtime
;
1683 DEBUG(1,("Getting files newer than %s",
1684 asctime(LocalTime(&newer_than
))));
1687 DEBUG(0,("Error setting newer-than time\n"));
1700 DEBUG(0,("Only one of I,X,F must be specified\n"));
1707 DEBUG(0,("Only one of I,X,F must be specified\n"));
1714 DEBUG(0,("Only one of I,X,F must be specified\n"));
1720 DEBUG(0, ("tar_re_search set\n"));
1721 tar_re_search
= True
;
1724 if (tar_type
== 'c') {
1725 DEBUG(0, ("dry_run set\n"));
1728 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1733 DEBUG(0,("Unknown tar option\n"));
1738 printf("Option T must be followed by one of c or x.\n");
1742 /* tar_excl is true if cliplist lists files to be included.
1743 * Both 'I' and 'F' mean include. */
1744 tar_excl
=tar_clipfl
!='X';
1746 if (tar_clipfl
=='F') {
1747 if (argc
-Optind
-1 != 1) {
1748 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1751 if (! read_inclusion_file(argv
[Optind
+1])) {
1754 } else if (Optind
+1<argc
&& !tar_re_search
) { /* For backwards compatibility */
1759 cliplist
=argv
+Optind
+1;
1760 clipn
=argc
-Optind
-1;
1763 if ((tmplist
=malloc(clipn
*sizeof(char *))) == NULL
) {
1764 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1770 for (clipcount
= 0; clipcount
< clipn
; clipcount
++) {
1772 DEBUG(5, ("Processing an item, %s\n", cliplist
[clipcount
]));
1774 if ((tmpstr
= (char *)malloc(strlen(cliplist
[clipcount
])+1)) == NULL
) {
1775 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1780 unfixtarname(tmpstr
, cliplist
[clipcount
], strlen(cliplist
[clipcount
]) + 1, True
);
1781 tmplist
[clipcount
] = tmpstr
;
1782 DEBUG(5, ("Processed an item, %s\n", tmpstr
));
1784 DEBUG(5, ("Cliplist is: %s\n", cliplist
[0]));
1787 must_free_cliplist
= True
;
1790 if (Optind
+1<argc
&& tar_re_search
) { /* Doing regular expression seaches */
1794 if ((preg
= (regex_t
*)malloc(65536)) == NULL
) {
1796 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1801 if (errcode
= regcomp(preg
, argv
[Optind
+ 1], REG_EXTENDED
)) {
1805 errlen
= regerror(errcode
, preg
, errstr
, sizeof(errstr
) - 1);
1807 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv
[Optind
+ 1], errstr
));
1813 clipn
=argc
-Optind
-1;
1814 cliplist
=argv
+Optind
+1;
1818 if (Optind
>=argc
|| !strcmp(argv
[Optind
], "-")) {
1819 /* Sets tar handle to either 0 or 1, as appropriate */
1820 tarhandle
=(tar_type
=='c');
1822 if (tar_type
=='c' && (dry_run
|| strcmp(argv
[Optind
], "/dev/null")==0))
1825 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1830 if ((tar_type
=='x' && (tarhandle
= sys_open(argv
[Optind
], O_RDONLY
, 0)) == -1)
1831 || (tar_type
=='c' && (tarhandle
=sys_creat(argv
[Optind
], 0644)) < 0))
1833 DEBUG(0,("Error opening local file %s - %s\n",
1834 argv
[Optind
], strerror(errno
)));