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 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
;
89 /* Incremental mode */
91 /* Reset archive bit */
93 /* Include / exclude mode (true=include, false=exclude) */
95 /* use regular expressions for search on file names */
96 BOOL tar_re_search
=False
;
100 /* Do not dump anything, just calculate sizes */
102 /* Dump files with System attribute */
103 BOOL tar_system
=True
;
104 /* Dump files with Hidden attribute */
105 BOOL tar_hidden
=True
;
106 /* Be noisy - make a catalogue */
108 BOOL tar_real_noisy
=False
; /* Don't want to be really noisy by default */
111 static char **cliplist
=NULL
;
113 static BOOL must_free_cliplist
= False
;
115 extern file_info def_finfo
;
116 extern BOOL lowercase
;
118 extern BOOL readbraw_supported
;
120 extern pstring cur_dir
;
121 extern int get_total_time_ms
;
122 extern int get_total_size
;
128 static void writetarheader(int f
, char *aname
, int size
, time_t mtime
,
129 char *amode
, unsigned char ftype
);
130 static void do_atar(char *rname
,char *lname
,file_info
*finfo1
);
131 static void do_tar(file_info
*finfo
);
132 static void oct_it(long value
, int ndgs
, char *p
);
133 static void fixtarname(char *tptr
, char *fp
, int l
);
134 static int dotarbuf(int f
, char *b
, int n
);
135 static void dozerobuf(int f
, int n
);
136 static void dotareof(int f
);
137 static void initarbuf(void);
139 /* restore functions */
140 static long readtarheader(union hblock
*hb
, file_info2
*finfo
, char *prefix
);
141 static long unoct(char *p
, int ndgs
);
142 static void do_tarput(void);
143 static void unfixtarname(char *tptr
, char *fp
, int l
, BOOL first
);
146 * tar specific utitlities
149 /*******************************************************************
150 Create a string of size size+1 (for the null)
151 *******************************************************************/
152 static char *string_create_s(int size
)
156 tmp
= (char *)malloc(size
+1);
160 DEBUG(0, ("Out of memory in string_create_s\n"));
168 /****************************************************************************
169 Write a tar header to buffer
170 ****************************************************************************/
171 static void writetarheader(int f
, char *aname
, int size
, time_t mtime
,
172 char *amode
, unsigned char ftype
)
178 DEBUG(5, ("WriteTarHdr, Type = %c, Size= %i, Name = %s\n", ftype
, size
, aname
));
180 memset(hb
.dummy
, 0, sizeof(hb
.dummy
));
183 if (l
>= NAMSIZ
- 1) {
184 /* write a GNU tar style long header */
186 b
= (char *)malloc(l
+TBLOCK
+100);
188 DEBUG(0,("out of memory\n"));
191 writetarheader(f
, "/./@LongLink", l
+2, 0, " 0 \0", 'L');
192 memset(b
, 0, l
+TBLOCK
+100);
193 fixtarname(b
, aname
, l
);
195 DEBUG(5, ("File name in tar file: %s, size=%d, \n", b
, (int)strlen(b
)));
196 dotarbuf(f
, b
, TBLOCK
*(((i
-1)/TBLOCK
)+1));
200 /* use l + 1 to do the null too */
201 fixtarname(hb
.dbuf
.name
, aname
, (l
>= NAMSIZ
) ? NAMSIZ
: l
+ 1);
204 strlower(hb
.dbuf
.name
);
206 /* write out a "standard" tar format header */
208 hb
.dbuf
.name
[NAMSIZ
-1]='\0';
209 safe_strcpy(hb
.dbuf
.mode
, amode
, strlen(amode
));
210 oct_it(0L, 8, hb
.dbuf
.uid
);
211 oct_it(0L, 8, hb
.dbuf
.gid
);
212 oct_it((long) size
, 13, hb
.dbuf
.size
);
213 oct_it((long) mtime
, 13, hb
.dbuf
.mtime
);
214 memcpy(hb
.dbuf
.chksum
, " ", sizeof(hb
.dbuf
.chksum
));
215 memset(hb
.dbuf
.linkname
, 0, NAMSIZ
);
216 hb
.dbuf
.linkflag
=ftype
;
218 for (chk
=0, i
=sizeof(hb
.dummy
), jp
=hb
.dummy
; --i
>=0;) chk
+=(0xFF & *jp
++);
220 oct_it((long) chk
, 8, hb
.dbuf
.chksum
);
221 hb
.dbuf
.chksum
[6] = '\0';
223 (void) dotarbuf(f
, hb
.dummy
, sizeof(hb
.dummy
));
226 /****************************************************************************
227 Read a tar header into a hblock structure, and validate
228 ***************************************************************************/
229 static long readtarheader(union hblock
*hb
, file_info2
*finfo
, char *prefix
)
236 * read in a "standard" tar format header - we're not that interested
237 * in that many fields, though
240 /* check the checksum */
241 for (chk
=0, i
=sizeof(hb
->dummy
), jp
=hb
->dummy
; --i
>=0;) chk
+=(0xFF & *jp
++);
246 /* compensate for blanks in chksum header */
247 for (i
=sizeof(hb
->dbuf
.chksum
), jp
=hb
->dbuf
.chksum
; --i
>=0;)
250 chk
+= ' ' * sizeof(hb
->dbuf
.chksum
);
252 fchk
=unoct(hb
->dbuf
.chksum
, sizeof(hb
->dbuf
.chksum
));
254 DEBUG(5, ("checksum totals chk=%ld fchk=%ld chksum=%s\n",
255 chk
, fchk
, hb
->dbuf
.chksum
));
259 DEBUG(0, ("checksums don't match %ld %ld\n", fchk
, chk
));
260 dump_data(5, (char *)hb
- TBLOCK
, TBLOCK
*3);
264 if ((finfo
->name
= string_create_s(strlen(prefix
) + strlen(hb
-> dbuf
.name
) + 3)) == NULL
) {
266 DEBUG(0, ("Out of space creating file_info2 for %s\n", hb
-> dbuf
.name
));
271 safe_strcpy(finfo
->name
, prefix
, strlen(prefix
) + strlen(hb
-> dbuf
.name
) + 3);
273 /* use l + 1 to do the null too; do prefix - prefcnt to zap leading slash */
274 unfixtarname(finfo
->name
+ strlen(prefix
), hb
->dbuf
.name
,
275 strlen(hb
->dbuf
.name
) + 1, True
);
277 /* can't handle some links at present */
278 if ((hb
->dbuf
.linkflag
!= '0') && (hb
-> dbuf
.linkflag
!= '5')) {
279 if (hb
->dbuf
.linkflag
== 0) {
280 DEBUG(6, ("Warning: NULL link flag (gnu tar archive ?) %s\n",
283 if (hb
-> dbuf
.linkflag
== 'L') { /* We have a longlink */
284 /* Do nothing here at the moment. do_tarput will handle this
285 as long as the longlink gets back to it, as it has to advance
286 the buffer pointer, etc */
289 DEBUG(0, ("this tar file appears to contain some kind of link other than a GNUtar Longlink - ignoring\n"));
295 if ((unoct(hb
->dbuf
.mode
, sizeof(hb
->dbuf
.mode
)) & S_IFDIR
)
296 || (*(finfo
->name
+strlen(finfo
->name
)-1) == '\\'))
301 finfo
->mode
=0; /* we don't care about mode at the moment, we'll
302 * just make it a regular file */
304 * Bug fix by richard@sj.co.uk
306 * REC: restore times correctly (as does tar)
307 * We only get the modification time of the file; set the creation time
308 * from the mod. time, and the access time to current time
310 finfo
->mtime
= finfo
->ctime
= strtol(hb
->dbuf
.mtime
, NULL
, 8);
311 finfo
->atime
= time(NULL
);
312 finfo
->size
= unoct(hb
->dbuf
.size
, sizeof(hb
->dbuf
.size
));
317 /****************************************************************************
318 Write out the tar buffer to tape or wherever
319 ****************************************************************************/
320 static int dotarbuf(int f
, char *b
, int n
)
327 /* This routine and the next one should be the only ones that do write()s */
328 if (tp
+ n
>= tbufsiz
)
333 memcpy(tarbuf
+ tp
, b
, diff
);
334 fail
=fail
&& (1+write(f
, tarbuf
, tbufsiz
));
341 fail
=fail
&& (1 + write(f
, b
, tbufsiz
));
347 memcpy(tarbuf
+tp
, b
, n
);
351 return(fail
? writ
: 0);
354 /****************************************************************************
355 Write zeros to buffer / tape
356 ****************************************************************************/
357 static void dozerobuf(int f
, int n
)
359 /* short routine just to write out n zeros to buffer -
360 * used to round files to nearest block
361 * and to do tar EOFs */
368 memset(tarbuf
+tp
, 0, tbufsiz
-tp
);
370 write(f
, tarbuf
, tbufsiz
);
371 memset(tarbuf
, 0, (tp
+=n
-tbufsiz
));
375 memset(tarbuf
+tp
, 0, n
);
380 /****************************************************************************
382 ****************************************************************************/
383 static void initarbuf(void)
385 /* initialize tar buffer */
386 tbufsiz
=blocksize
*TBLOCK
;
387 tarbuf
=malloc(tbufsiz
); /* FIXME: We might not get the buffer */
389 /* reset tar buffer pointer and tar file counter and total dumped */
390 tp
=0; ntarf
=0; ttarf
=0;
393 /****************************************************************************
394 Write two zero blocks at end of file
395 ****************************************************************************/
396 static void dotareof(int f
)
398 SMB_STRUCT_STAT stbuf
;
399 /* Two zero blocks at end of file, write out full buffer */
404 (void) dozerobuf(f
, TBLOCK
);
405 (void) dozerobuf(f
, TBLOCK
);
407 if (sys_fstat(f
, &stbuf
) == -1)
409 DEBUG(0, ("Couldn't stat file handle\n"));
413 /* Could be a pipe, in which case S_ISREG should fail,
414 * and we should write out at full size */
415 if (tp
> 0) write(f
, tarbuf
, S_ISREG(stbuf
.st_mode
) ? tp
: tbufsiz
);
418 /****************************************************************************
419 (Un)mangle DOS pathname, make nonabsolute
420 ****************************************************************************/
421 static void fixtarname(char *tptr
, char *fp
, int l
)
423 /* add a '.' to start of file name, convert from ugly dos \'s in path
424 * to lovely unix /'s :-} */
429 int skip
= get_character_len(*fp
);
435 } else if (skip
== 1) {
439 } else if (*fp
== '\\') {
450 /****************************************************************************
451 Convert from decimal to octal string
452 ****************************************************************************/
453 static void oct_it (long value
, int ndgs
, char *p
)
455 /* Converts long to octal string, pads with leading zeros */
457 /* skip final null, but do final space */
461 /* Loop does at least one digit */
463 p
[--ndgs
] = '0' + (char) (value
& 7);
466 while (ndgs
> 0 && value
!= 0);
468 /* Do leading zeros */
473 /****************************************************************************
474 Convert from octal string to long
475 ***************************************************************************/
476 static long unoct(char *p
, int ndgs
)
479 /* Converts octal string to long, ignoring any non-digit */
483 if (isdigit((int)*p
))
484 value
= (value
<< 3) | (long) (*p
- '0');
492 /****************************************************************************
493 Compare two strings in a slash insensitive way, allowing s1 to match s2
494 if s1 is an "initial" string (up to directory marker). Thus, if s2 is
495 a file in any subdirectory of s1, declare a match.
496 ***************************************************************************/
497 static int strslashcmp(char *s1
, char *s2
)
503 || tolower(*s1
) == tolower(*s2
)
504 || (*s1
== '\\' && *s2
=='/')
505 || (*s1
== '/' && *s2
=='\\'))) {
509 /* if s1 has a trailing slash, it compared equal, so s1 is an "initial"
512 if (!*s1
&& s1
!= s1_0
&& (*(s1
-1) == '/' || *(s1
-1) == '\\')) return 0;
514 /* ignore trailing slash on s1 */
515 if (!*s2
&& (*s1
== '/' || *s1
== '\\') && !*(s1
+1)) return 0;
517 /* check for s1 is an "initial" string of s2 */
518 if (*s2
== '/' || *s2
== '\\') return 0;
524 /****************************************************************************
525 Ensure a remote path exists (make if necessary)
526 ***************************************************************************/
527 static BOOL
ensurepath(char *fname
)
529 /* *must* be called with buffer ready malloc'ed */
530 /* ensures path exists */
532 char *partpath
, *ffname
;
533 char *p
=fname
, *basehack
;
535 DEBUG(5, ( "Ensurepath called with: %s\n", fname
));
537 partpath
= string_create_s(strlen(fname
));
538 ffname
= string_create_s(strlen(fname
));
540 if ((partpath
== NULL
) || (ffname
== NULL
)){
542 DEBUG(0, ("Out of memory in ensurepath: %s\n", fname
));
549 /* fname copied to ffname so can strtok */
551 safe_strcpy(ffname
, fname
, strlen(fname
));
553 /* do a `basename' on ffname, so don't try and make file name directory */
554 if ((basehack
=strrchr(ffname
, '\\')) == NULL
)
559 p
=strtok(ffname
, "\\");
563 safe_strcat(partpath
, p
, strlen(fname
) + 1);
565 if (!cli_chkpath(cli
, partpath
)) {
566 if (!cli_mkdir(cli
, partpath
))
568 DEBUG(0, ("Error mkdirhiering\n"));
572 DEBUG(3, ("mkdirhiering %s\n", partpath
));
576 safe_strcat(partpath
, "\\", strlen(fname
) + 1);
577 p
= strtok(NULL
,"/\\");
583 static int padit(char *buf
, int bufsize
, int padsize
)
588 DEBUG(5, ("Padding with %d zeros\n", padsize
));
589 memset(buf
, 0, bufsize
);
590 while( !berr
&& padsize
> 0 ) {
591 bytestowrite
= MIN(bufsize
, padsize
);
592 berr
= dotarbuf(tarhandle
, buf
, bytestowrite
) != bytestowrite
;
593 padsize
-= bytestowrite
;
600 static void do_setrattr(char *name
, uint16 attr
, int set
)
604 if (!cli_getatr(cli
, name
, &oldattr
, NULL
, NULL
)) return;
606 if (set
== ATTRSET
) {
609 attr
= oldattr
& ~attr
;
612 if (!cli_setatr(cli
, name
, attr
, 0)) {
613 DEBUG(1,("setatr failed: %s\n", cli_errstr(cli
)));
618 /****************************************************************************
619 append one remote file to the tar file
620 ***************************************************************************/
621 static void do_atar(char *rname
,char *lname
,file_info
*finfo1
)
627 BOOL close_done
= False
;
628 BOOL shallitime
=True
;
630 int read_size
= 65520;
633 struct timeval tp_start
;
634 GetTimeOfDay(&tp_start
);
636 ftype
= '0'; /* An ordinary file ... */
639 finfo
.size
= finfo1
-> size
;
640 finfo
.mode
= finfo1
-> mode
;
641 finfo
.uid
= finfo1
-> uid
;
642 finfo
.gid
= finfo1
-> gid
;
643 finfo
.mtime
= finfo1
-> mtime
;
644 finfo
.atime
= finfo1
-> atime
;
645 finfo
.ctime
= finfo1
-> ctime
;
648 finfo
.size
= def_finfo
.size
;
649 finfo
.mode
= def_finfo
.mode
;
650 finfo
.uid
= def_finfo
.uid
;
651 finfo
.gid
= def_finfo
.gid
;
652 finfo
.mtime
= def_finfo
.mtime
;
653 finfo
.atime
= def_finfo
.atime
;
654 finfo
.ctime
= def_finfo
.ctime
;
659 DEBUG(3,("skipping file %s of size %d bytes\n",
663 ttarf
+=finfo
.size
+ TBLOCK
- (finfo
.size
% TBLOCK
);
668 fnum
= cli_open(cli
, rname
, O_RDONLY
, DENY_NONE
);
670 dos_clean_name(rname
);
673 DEBUG(0,("%s opening remote file %s (%s)\n",
674 cli_errstr(cli
),rname
, cur_dir
));
678 finfo
.name
= string_create_s(strlen(rname
));
679 if (finfo
.name
== NULL
) {
680 DEBUG(0, ("Unable to allocate space for finfo.name in do_atar\n"));
684 safe_strcpy(finfo
.name
,rname
, strlen(rname
));
686 if (!cli_getattrE(cli
, fnum
, &finfo
.mode
, &finfo
.size
, NULL
, &finfo
.atime
, &finfo
.mtime
)) {
687 DEBUG(0, ("getattrE: %s\n", cli_errstr(cli
)));
690 finfo
.ctime
= finfo
.mtime
;
693 DEBUG(3,("file %s attrib 0x%X\n",finfo
.name
,finfo
.mode
));
695 if (tar_inc
&& !(finfo
.mode
& aARCH
))
697 DEBUG(4, ("skipping %s - archive bit not set\n", finfo
.name
));
700 else if (!tar_system
&& (finfo
.mode
& aSYSTEM
))
702 DEBUG(4, ("skipping %s - system bit is set\n", finfo
.name
));
705 else if (!tar_hidden
&& (finfo
.mode
& aHIDDEN
))
707 DEBUG(4, ("skipping %s - hidden bit is set\n", finfo
.name
));
712 DEBUG(3,("getting file %s of size %d bytes as a tar file %s",
717 /* write a tar header, don't bother with mode - just set to 100644 */
718 writetarheader(tarhandle
, rname
, finfo
.size
, finfo
.mtime
, "100644 \0", ftype
);
720 while (nread
< finfo
.size
&& !close_done
) {
722 DEBUG(3,("nread=%d\n",nread
));
724 datalen
= cli_read(cli
, fnum
, data
, nread
, read_size
);
727 DEBUG(0,("Error reading file %s : %s\n", rname
, cli_errstr(cli
)));
733 /* if file size has increased since we made file size query, truncate
734 read so tar header for this file will be correct.
737 if (nread
> finfo
.size
) {
738 datalen
-= nread
- finfo
.size
;
739 DEBUG(0,("File size change - truncating %s to %d bytes\n", finfo
.name
, (int)finfo
.size
));
742 /* add received bits of file to buffer - dotarbuf will
743 * write out in 512 byte intervals */
744 if (dotarbuf(tarhandle
,data
,datalen
) != datalen
) {
745 DEBUG(0,("Error writing to tar file - %s\n", strerror(errno
)));
750 DEBUG(0,("Error reading file %s. Got 0 bytes\n", rname
));
757 /* pad tar file with zero's if we couldn't get entire file */
758 if (nread
< finfo
.size
) {
759 DEBUG(0, ("Didn't get entire file. size=%d, nread=%d\n", (int)finfo
.size
, (int)nread
));
760 if (padit(data
, sizeof(data
), finfo
.size
- nread
))
761 DEBUG(0,("Error writing tar file - %s\n", strerror(errno
)));
764 /* round tar file to nearest block */
765 if (finfo
.size
% TBLOCK
)
766 dozerobuf(tarhandle
, TBLOCK
- (finfo
.size
% TBLOCK
));
768 ttarf
+=finfo
.size
+ TBLOCK
- (finfo
.size
% TBLOCK
);
772 cli_close(cli
, fnum
);
776 struct timeval tp_end
;
779 /* if shallitime is true then we didn't skip */
780 if (tar_reset
&& !dry_run
)
781 (void) do_setrattr(finfo
.name
, aARCH
, ATTRRESET
);
783 GetTimeOfDay(&tp_end
);
785 (tp_end
.tv_sec
- tp_start
.tv_sec
)*1000 +
786 (tp_end
.tv_usec
- tp_start
.tv_usec
)/1000;
787 get_total_time_ms
+= this_time
;
788 get_total_size
+= finfo
.size
;
792 DEBUG(0, ("%10d (%7.1f kb/s) %s\n",
793 (int)finfo
.size
, finfo
.size
/ MAX(0.001, (1.024*this_time
)),
797 /* Thanks to Carel-Jan Engel (ease@mail.wirehub.nl) for this one */
798 DEBUG(3,("(%g kb/s) (average %g kb/s)\n",
799 finfo
.size
/ MAX(0.001, (1.024*this_time
)),
800 get_total_size
/ MAX(0.001, (1.024*get_total_time_ms
))));
804 /****************************************************************************
805 Append single file to tar file (or not)
806 ***************************************************************************/
807 static void do_tar(file_info
*finfo
)
811 if (strequal(finfo
->name
,"..") || strequal(finfo
->name
,"."))
814 /* Is it on the exclude list ? */
815 if (!tar_excl
&& clipn
) {
818 DEBUG(5, ("Excl: strlen(cur_dir) = %d\n", (int)strlen(cur_dir
)));
820 safe_strcpy(exclaim
, cur_dir
, sizeof(pstring
));
821 *(exclaim
+strlen(exclaim
)-1)='\0';
823 safe_strcat(exclaim
, "\\", sizeof(pstring
));
824 safe_strcat(exclaim
, finfo
->name
, sizeof(exclaim
));
826 DEBUG(5, ("...tar_re_search: %d\n", tar_re_search
));
828 if ((!tar_re_search
&& clipfind(cliplist
, clipn
, exclaim
)) ||
830 (tar_re_search
&& !regexec(preg
, exclaim
, 0, NULL
, 0))) {
832 (tar_re_search
&& mask_match(exclaim
, cliplist
[0], True
))) {
834 DEBUG(3,("Skipping file %s\n", exclaim
));
839 if (finfo
->mode
& aDIR
)
841 pstring saved_curdir
;
844 safe_strcpy(saved_curdir
, cur_dir
, sizeof(saved_curdir
));
846 DEBUG(5, ("Sizeof(cur_dir)=%d, strlen(cur_dir)=%d, strlen(finfo->name)=%d\nname=%s,cur_dir=%s\n", (int)sizeof(cur_dir
), (int)strlen(cur_dir
), (int)strlen(finfo
->name
), finfo
->name
, cur_dir
));
848 safe_strcat(cur_dir
,finfo
->name
, sizeof(cur_dir
));
849 safe_strcat(cur_dir
,"\\", sizeof(cur_dir
));
851 DEBUG(5, ("Writing a dir, Name = %s\n", cur_dir
));
853 /* write a tar directory, don't bother with mode - just set it to
855 writetarheader(tarhandle
, cur_dir
, 0, finfo
->mtime
, "040755 \0", '5');
857 DEBUG(0,(" directory %s\n", cur_dir
));
859 ntarf
++; /* Make sure we have a file on there */
860 safe_strcpy(mtar_mask
,cur_dir
, sizeof(pstring
));
861 safe_strcat(mtar_mask
,"*", sizeof(pstring
));
862 DEBUG(5, ("Doing list with mtar_mask: %s\n", mtar_mask
));
863 do_list(mtar_mask
, attribute
, do_tar
, False
, True
);
864 safe_strcpy(cur_dir
,saved_curdir
, sizeof(pstring
));
868 safe_strcpy(rname
,cur_dir
, sizeof(pstring
));
869 safe_strcat(rname
,finfo
->name
, sizeof(pstring
));
870 do_atar(rname
,finfo
->name
,finfo
);
874 /****************************************************************************
875 Convert from UNIX to DOS file names
876 ***************************************************************************/
877 static void unfixtarname(char *tptr
, char *fp
, int l
, BOOL first
)
879 /* remove '.' from start of file name, convert from unix /'s to
880 * dos \'s in path. Kill any absolute path names. But only if first!
883 DEBUG(5, ("firstb=%lX, secondb=%lX, len=%i\n", (long)tptr
, (long)fp
, l
));
890 if (*fp
== '\\' || *fp
== '/') {
897 int skip
= get_character_len(*fp
);
903 } else if (skip
== 1) {
907 } else if (*fp
== '/') {
919 /****************************************************************************
920 Move to the next block in the buffer, which may mean read in another set of
921 blocks. FIXME, we should allow more than one block to be skipped.
922 ****************************************************************************/
923 static int next_block(char *ltarbuf
, char **bufferp
, int bufsiz
)
925 int bufread
, total
= 0;
927 DEBUG(5, ("Advancing to next block: %0lx\n", (unsigned long)*bufferp
));
931 if (*bufferp
>= (ltarbuf
+ bufsiz
)) {
933 DEBUG(5, ("Reading more data into ltarbuf ...\n"));
936 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>
937 * Fixes bug where read can return short if coming from
941 bufread
= read(tarhandle
, ltarbuf
, bufsiz
);
944 while (total
< bufsiz
) {
945 if (bufread
< 0) { /* An error, return false */
946 return (total
> 0 ? -2 : bufread
);
954 bufread
= read(tarhandle
, <arbuf
[total
], bufsiz
- total
);
958 DEBUG(5, ("Total bytes read ... %i\n", total
));
968 /* Skip a file, even if it includes a long file name? */
969 static int skip_file(int skipsize
)
971 int dsize
= skipsize
;
973 DEBUG(5, ("Skiping file. Size = %i\n", skipsize
));
975 /* FIXME, we should skip more than one block at a time */
979 if (next_block(tarbuf
, &buffer_p
, tbufsiz
) <= 0) {
981 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno
)));
993 /*************************************************************
994 Get a file from the tar file and store it.
995 When this is called, tarbuf already contains the first
996 file block. This is a bit broken & needs fixing.
997 **************************************************************/
999 static int get_file(file_info2 finfo
)
1001 int fnum
= -1, pos
= 0, dsize
= 0, rsize
= 0, bpos
= 0;
1003 DEBUG(5, ("get_file: file: %s, size %i\n", finfo
.name
, (int)finfo
.size
));
1005 if (ensurepath(finfo
.name
) &&
1006 (fnum
=cli_open(cli
, finfo
.name
, O_RDWR
|O_CREAT
|O_TRUNC
, DENY_NONE
)) == -1) {
1007 DEBUG(0, ("abandoning restore\n"));
1011 /* read the blocks from the tar file and write to the remote file */
1013 rsize
= finfo
.size
; /* This is how much to write */
1017 /* We can only write up to the end of the buffer */
1019 dsize
= MIN(tbufsiz
- (buffer_p
- tarbuf
) - bpos
, 65520); /* Calculate the size to write */
1020 dsize
= MIN(dsize
, rsize
); /* Should be only what is left */
1021 DEBUG(5, ("writing %i bytes, bpos = %i ...\n", dsize
, bpos
));
1023 if (cli_write(cli
, fnum
, 0, buffer_p
+ bpos
, pos
, dsize
) != dsize
) {
1024 DEBUG(0, ("Error writing remote file\n"));
1031 /* Now figure out how much to move in the buffer */
1033 /* FIXME, we should skip more than one block at a time */
1035 /* First, skip any initial part of the part written that is left over */
1036 /* from the end of the first TBLOCK */
1038 if ((bpos
) && ((bpos
+ dsize
) >= TBLOCK
)) {
1040 dsize
-= (TBLOCK
- bpos
); /* Get rid of the end of the first block */
1043 if (next_block(tarbuf
, &buffer_p
, tbufsiz
) <=0) { /* and skip the block */
1044 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno
)));
1052 * Bugfix from Bob Boehmer <boehmer@worldnet.att.net>.
1053 * If the file being extracted is an exact multiple of
1054 * TBLOCK bytes then we don't want to extract the next
1055 * block from the tarfile here, as it will be done in
1056 * the caller of get_file().
1059 while (((rsize
!= 0) && (dsize
>= TBLOCK
)) ||
1060 ((rsize
== 0) && (dsize
> TBLOCK
))) {
1062 if (next_block(tarbuf
, &buffer_p
, tbufsiz
) <=0) {
1063 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno
)));
1074 /* Now close the file ... */
1076 if (!cli_close(cli
, fnum
)) {
1077 DEBUG(0, ("Error closing remote file\n"));
1081 /* Now we update the creation date ... */
1083 DEBUG(5, ("Updating creation date on %s\n", finfo
.name
));
1085 if (!cli_setatr(cli
, finfo
.name
, finfo
.mode
, finfo
.mtime
)) {
1086 if (tar_real_noisy
) {
1087 DEBUG(0, ("Could not set time on file: %s\n", finfo
.name
));
1088 /*return(False); */ /* Ignore, as Win95 does not allow changes */
1094 DEBUG(0, ("restore tar file %s of size %d bytes\n", finfo
.name
, (int)finfo
.size
));
1099 /* Create a directory. We just ensure that the path exists and return as there
1100 is no file associated with a directory
1102 static int get_dir(file_info2 finfo
)
1105 DEBUG(0, ("restore directory %s\n", finfo
.name
));
1107 if (!ensurepath(finfo
.name
)) {
1109 DEBUG(0, ("Problems creating directory\n"));
1118 /* Get a file with a long file name ... first file has file name, next file
1119 has the data. We only want the long file name, as the loop in do_tarput
1120 will deal with the rest.
1122 static char * get_longfilename(file_info2 finfo
)
1124 int namesize
= finfo
.size
+ strlen(cur_dir
) + 2;
1125 char *longname
= malloc(namesize
);
1126 int offset
= 0, left
= finfo
.size
;
1129 DEBUG(5, ("Restoring a long file name: %s\n", finfo
.name
));
1130 DEBUG(5, ("Len = %d\n", (int)finfo
.size
));
1132 if (longname
== NULL
) {
1134 DEBUG(0, ("could not allocate buffer of size %d for longname\n",
1135 (int)(finfo
.size
+ strlen(cur_dir
) + 2)));
1139 /* First, add cur_dir to the long file name */
1141 if (strlen(cur_dir
) > 0) {
1142 strncpy(longname
, cur_dir
, namesize
);
1143 offset
= strlen(cur_dir
);
1146 /* Loop through the blocks picking up the name */
1150 if (next_block(tarbuf
, &buffer_p
, tbufsiz
) <= 0) {
1152 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno
)));
1157 unfixtarname(longname
+ offset
, buffer_p
, MIN(TBLOCK
, finfo
.size
), first
--);
1158 DEBUG(5, ("UnfixedName: %s, buffer: %s\n", longname
, buffer_p
));
1169 static void do_tarput(void)
1172 struct timeval tp_start
;
1173 char *longfilename
= NULL
, linkflag
;
1176 GetTimeOfDay(&tp_start
);
1178 DEBUG(5, ("RJS do_tarput called ...\n"));
1180 buffer_p
= tarbuf
+ tbufsiz
; /* init this to force first read */
1182 /* Now read through those files ... */
1186 /* Get us to the next block, or the first block first time around */
1188 if (next_block(tarbuf
, &buffer_p
, tbufsiz
) <= 0) {
1190 DEBUG(0, ("Empty file, short tar file, or read error: %s\n", strerror(errno
)));
1196 DEBUG(5, ("Reading the next header ...\n"));
1198 switch (readtarheader((union hblock
*) buffer_p
, &finfo
, cur_dir
)) {
1200 case -2: /* Hmm, not good, but not fatal */
1201 DEBUG(0, ("Skipping %s...\n", finfo
.name
));
1202 if ((next_block(tarbuf
, &buffer_p
, tbufsiz
) <= 0) &&
1203 !skip_file(finfo
.size
)) {
1205 DEBUG(0, ("Short file, bailing out...\n"));
1213 DEBUG(0, ("abandoning restore, -1 from read tar header\n"));
1216 case 0: /* chksum is zero - looks like an EOF */
1217 DEBUG(0, ("tar: restored %d files and directories\n", ntarf
));
1218 return; /* Hmmm, bad here ... */
1227 /* Now, do we have a long file name? */
1229 if (longfilename
!= NULL
) {
1231 SAFE_FREE(finfo
.name
); /* Free the space already allocated */
1232 finfo
.name
= longfilename
;
1233 longfilename
= NULL
;
1237 /* Well, now we have a header, process the file ... */
1239 /* Should we skip the file? We have the long name as well here */
1242 ((!tar_re_search
&& clipfind(cliplist
, clipn
, finfo
.name
) ^ tar_excl
)
1244 || (tar_re_search
&& !regexec(preg
, finfo
.name
, 0, NULL
, 0)));
1246 || (tar_re_search
&& mask_match(finfo
.name
, cliplist
[0], True
)));
1249 DEBUG(5, ("Skip = %i, cliplist=%s, file=%s\n", skip
, (cliplist
?cliplist
[0]:NULL
), finfo
.name
));
1253 skip_file(finfo
.size
);
1258 /* We only get this far if we should process the file */
1259 linkflag
= ((union hblock
*)buffer_p
) -> dbuf
.linkflag
;
1263 case '0': /* Should use symbolic names--FIXME */
1266 * Skip to the next block first, so we can get the file, FIXME, should
1267 * be in get_file ...
1268 * The 'finfo.size != 0' fix is from Bob Boehmer <boehmer@worldnet.att.net>
1269 * Fixes bug where file size in tarfile is zero.
1272 if ((finfo
.size
!= 0) && next_block(tarbuf
, &buffer_p
, tbufsiz
) <=0) {
1273 DEBUG(0, ("Short file, bailing out...\n"));
1276 if (!get_file(finfo
)) {
1277 DEBUG(0, ("Abandoning restore\n"));
1284 if (!get_dir(finfo
)) {
1285 DEBUG(0, ("Abandoning restore \n"));
1291 longfilename
= get_longfilename(finfo
);
1292 if (!longfilename
) {
1293 DEBUG(0, ("abandoning restore\n"));
1297 DEBUG(5, ("Long file name: %s\n", longfilename
));
1301 skip_file(finfo
.size
); /* Don't handle these yet */
1313 * samba interactive commands
1316 /****************************************************************************
1318 ***************************************************************************/
1319 void cmd_block(void)
1324 if (!next_token(NULL
,buf
,NULL
,sizeof(buf
)))
1326 DEBUG(0, ("blocksize <n>\n"));
1331 if (block
< 0 || block
> 65535)
1333 DEBUG(0, ("blocksize out of range"));
1338 DEBUG(2,("blocksize is now %d\n", blocksize
));
1341 /****************************************************************************
1342 command to set incremental / reset mode
1343 ***************************************************************************/
1344 void cmd_tarmode(void)
1348 while (next_token(NULL
,buf
,NULL
,sizeof(buf
))) {
1349 if (strequal(buf
, "full"))
1351 else if (strequal(buf
, "inc"))
1353 else if (strequal(buf
, "reset"))
1355 else if (strequal(buf
, "noreset"))
1357 else if (strequal(buf
, "system"))
1359 else if (strequal(buf
, "nosystem"))
1361 else if (strequal(buf
, "hidden"))
1363 else if (strequal(buf
, "nohidden"))
1365 else if (strequal(buf
, "verbose") || strequal(buf
, "noquiet"))
1367 else if (strequal(buf
, "quiet") || strequal(buf
, "noverbose"))
1369 else DEBUG(0, ("tarmode: unrecognised option %s\n", buf
));
1372 DEBUG(0, ("tarmode is now %s, %s, %s, %s, %s\n",
1373 tar_inc
? "incremental" : "full",
1374 tar_system
? "system" : "nosystem",
1375 tar_hidden
? "hidden" : "nohidden",
1376 tar_reset
? "reset" : "noreset",
1377 tar_noisy
? "verbose" : "quiet"));
1381 /****************************************************************************
1382 Feeble attrib command
1383 ***************************************************************************/
1384 void cmd_setmode(void)
1392 attra
[0] = attra
[1] = 0;
1394 if (!next_token(NULL
,buf
,NULL
,sizeof(buf
)))
1396 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1400 safe_strcpy(fname
, cur_dir
, sizeof(pstring
));
1401 safe_strcat(fname
, buf
, sizeof(pstring
));
1403 while (next_token(NULL
,buf
,NULL
,sizeof(buf
))) {
1412 case 'r': attra
[direct
]|=aRONLY
;
1414 case 'h': attra
[direct
]|=aHIDDEN
;
1416 case 's': attra
[direct
]|=aSYSTEM
;
1418 case 'a': attra
[direct
]|=aARCH
;
1420 default: DEBUG(0, ("setmode <filename> <perm=[+|-]rsha>\n"));
1425 if (attra
[ATTRSET
]==0 && attra
[ATTRRESET
]==0)
1427 DEBUG(0, ("setmode <filename> <[+|-]rsha>\n"));
1431 DEBUG(2, ("\nperm set %d %d\n", attra
[ATTRSET
], attra
[ATTRRESET
]));
1432 do_setrattr(fname
, attra
[ATTRSET
], ATTRSET
);
1433 do_setrattr(fname
, attra
[ATTRRESET
], ATTRRESET
);
1436 /****************************************************************************
1437 Principal command for creating / extracting
1438 ***************************************************************************/
1445 if (!next_token(NULL
,buf
,NULL
,sizeof(buf
)))
1447 DEBUG(0,("tar <c|x>[IXbgan] <filename>\n"));
1451 argl
=toktocliplist(&argcl
, NULL
);
1452 if (!tar_parseargs(argcl
, argl
, buf
, 0))
1460 /****************************************************************************
1461 Command line (option) version
1462 ***************************************************************************/
1463 int process_tar(void)
1479 if (clipn
&& tar_excl
) {
1483 for (i
=0; i
<clipn
; i
++) {
1484 DEBUG(5,("arg %d = %s\n", i
, cliplist
[i
]));
1486 if (*(cliplist
[i
]+strlen(cliplist
[i
])-1)=='\\') {
1487 *(cliplist
[i
]+strlen(cliplist
[i
])-1)='\0';
1490 if (strrchr(cliplist
[i
], '\\')) {
1493 safe_strcpy(saved_dir
, cur_dir
, sizeof(pstring
));
1495 if (*cliplist
[i
]=='\\') {
1496 safe_strcpy(tarmac
, cliplist
[i
], sizeof(pstring
));
1498 safe_strcpy(tarmac
, cur_dir
, sizeof(pstring
));
1499 safe_strcat(tarmac
, cliplist
[i
], sizeof(pstring
));
1501 safe_strcpy(cur_dir
, tarmac
, sizeof(pstring
));
1502 *(strrchr(cur_dir
, '\\')+1)='\0';
1504 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac
));
1505 do_list(tarmac
,attribute
,do_tar
, False
, True
);
1506 safe_strcpy(cur_dir
,saved_dir
, sizeof(pstring
));
1508 safe_strcpy(tarmac
, cur_dir
, sizeof(pstring
));
1509 safe_strcat(tarmac
, cliplist
[i
], sizeof(pstring
));
1510 DEBUG(5, ("process_tar, do_list with tarmac: %s\n", tarmac
));
1511 do_list(tarmac
,attribute
,do_tar
, False
, True
);
1516 safe_strcpy(mask
,cur_dir
, sizeof(pstring
));
1517 DEBUG(5, ("process_tar, do_list with mask: %s\n", mask
));
1518 safe_strcat(mask
,"\\*", sizeof(pstring
));
1519 do_list(mask
,attribute
,do_tar
,False
, True
);
1522 if (ntarf
) dotareof(tarhandle
);
1526 DEBUG(0, ("tar: dumped %d files and directories\n", ntarf
));
1527 DEBUG(0, ("Total bytes written: %.0f\n", (double)ttarf
));
1531 if (must_free_cliplist
) {
1533 for (i
= 0; i
< clipn
; ++i
) {
1534 SAFE_FREE(cliplist
[i
]);
1536 SAFE_FREE(cliplist
);
1539 must_free_cliplist
= False
;
1545 /****************************************************************************
1546 Find a token (filename) in a clip list
1547 ***************************************************************************/
1548 static int clipfind(char **aret
, int ret
, char *tok
)
1550 if (aret
==NULL
) return 0;
1552 /* ignore leading slashes or dots in token */
1553 while(strchr("/\\.", *tok
)) tok
++;
1558 /* ignore leading slashes or dots in list */
1559 while(strchr("/\\.", *pkey
)) pkey
++;
1561 if (!strslashcmp(pkey
, tok
)) return 1;
1567 /****************************************************************************
1568 Read list of files to include from the file and initialize cliplist
1570 ***************************************************************************/
1571 static int read_inclusion_file(char *filename
)
1573 FILE *inclusion
= NULL
;
1574 char buf
[MAXPATHLEN
+ 1];
1575 char *inclusion_buffer
= NULL
;
1576 int inclusion_buffer_size
= 0;
1577 int inclusion_buffer_sofar
= 0;
1584 buf
[MAXPATHLEN
] = '\0'; /* guarantee null-termination */
1585 if ((inclusion
= sys_fopen(filename
, "r")) == NULL
) {
1586 /* XXX It would be better to include a reason for failure, but without
1587 * autoconf, it's hard to use strerror, sys_errlist, etc.
1589 DEBUG(0,("Unable to open inclusion file %s\n", filename
));
1593 while ((! error
) && (fgets(buf
, sizeof(buf
)-1, inclusion
))) {
1594 if (inclusion_buffer
== NULL
) {
1595 inclusion_buffer_size
= 1024;
1596 if ((inclusion_buffer
= malloc(inclusion_buffer_size
)) == NULL
) {
1597 DEBUG(0,("failure allocating buffer to read inclusion file\n"));
1603 if (buf
[strlen(buf
)-1] == '\n') {
1604 buf
[strlen(buf
)-1] = '\0';
1607 if ((strlen(buf
) + 1 + inclusion_buffer_sofar
) >= inclusion_buffer_size
) {
1609 inclusion_buffer_size
*= 2;
1610 ib
= Realloc(inclusion_buffer
,inclusion_buffer_size
);
1612 DEBUG(0,("failure enlarging inclusion buffer to %d bytes\n", inclusion_buffer_size
));
1616 inclusion_buffer
= ib
;
1619 safe_strcpy(inclusion_buffer
+ inclusion_buffer_sofar
, buf
, inclusion_buffer_size
- inclusion_buffer_sofar
);
1620 inclusion_buffer_sofar
+= strlen(buf
) + 1;
1626 /* Allocate an array of clipn + 1 char*'s for cliplist */
1627 cliplist
= malloc((clipn
+ 1) * sizeof(char *));
1628 if (cliplist
== NULL
) {
1629 DEBUG(0,("failure allocating memory for cliplist\n"));
1632 cliplist
[clipn
] = NULL
;
1633 p
= inclusion_buffer
;
1634 for (i
= 0; (! error
) && (i
< clipn
); i
++) {
1635 /* set current item to NULL so array will be null-terminated even if
1636 * malloc fails below. */
1638 if ((tmpstr
= (char *)malloc(strlen(p
)+1)) == NULL
) {
1639 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n", i
));
1642 unfixtarname(tmpstr
, p
, strlen(p
) + 1, True
);
1643 cliplist
[i
] = tmpstr
;
1644 if ((p
= strchr(p
, '\000')) == NULL
) {
1645 DEBUG(0,("INTERNAL ERROR: inclusion_buffer is of unexpected contents.\n"));
1651 must_free_cliplist
= True
;
1655 if (inclusion_buffer
) {
1656 SAFE_FREE(inclusion_buffer
);
1661 /* We know cliplist is always null-terminated */
1662 for (pp
= cliplist
; *pp
; ++pp
) {
1665 SAFE_FREE(cliplist
);
1667 must_free_cliplist
= False
;
1672 /* cliplist and its elements are freed at the end of process_tar. */
1676 /****************************************************************************
1677 Parse tar arguments. Sets tar_type, tar_excl, etc.
1678 ***************************************************************************/
1679 int tar_parseargs(int argc
, char *argv
[], char *Optarg
, int Optind
)
1681 char tar_clipfl
='\0';
1683 /* Reset back to defaults - could be from interactive version
1684 * reset mode and archive mode left as they are though
1696 if (tar_type
=='c') {
1697 printf("Tar must be followed by only one of c or x.\n");
1703 if (Optind
>=argc
|| !(blocksize
=atoi(argv
[Optind
]))) {
1704 DEBUG(0,("Option b must be followed by valid blocksize\n"));
1715 DEBUG(0,("Option N must be followed by valid file name\n"));
1718 SMB_STRUCT_STAT stbuf
;
1719 extern time_t newer_than
;
1721 if (sys_stat(dos_to_unix_static(argv
[Optind
]), &stbuf
) == 0) {
1722 newer_than
= stbuf
.st_mtime
;
1723 DEBUG(1,("Getting files newer than %s",
1724 asctime(LocalTime(&newer_than
))));
1727 DEBUG(0,("Error setting newer-than time\n"));
1740 DEBUG(0,("Only one of I,X,F must be specified\n"));
1747 DEBUG(0,("Only one of I,X,F must be specified\n"));
1754 DEBUG(0,("Only one of I,X,F must be specified\n"));
1760 DEBUG(0, ("tar_re_search set\n"));
1761 tar_re_search
= True
;
1764 if (tar_type
== 'c') {
1765 DEBUG(0, ("dry_run set\n"));
1768 DEBUG(0, ("n is only meaningful when creating a tar-file\n"));
1773 DEBUG(0,("Unknown tar option\n"));
1778 printf("Option T must be followed by one of c or x.\n");
1782 /* tar_excl is true if cliplist lists files to be included.
1783 * Both 'I' and 'F' mean include. */
1784 tar_excl
=tar_clipfl
!='X';
1786 if (tar_clipfl
=='F') {
1787 if (argc
-Optind
-1 != 1) {
1788 DEBUG(0,("Option F must be followed by exactly one filename.\n"));
1791 if (! read_inclusion_file(argv
[Optind
+1])) {
1794 } else if (Optind
+1<argc
&& !tar_re_search
) { /* For backwards compatibility */
1799 cliplist
=argv
+Optind
+1;
1800 clipn
=argc
-Optind
-1;
1803 if ((tmplist
=malloc(clipn
*sizeof(char *))) == NULL
) {
1804 DEBUG(0, ("Could not allocate space to process cliplist, count = %i\n",
1810 for (clipcount
= 0; clipcount
< clipn
; clipcount
++) {
1812 DEBUG(5, ("Processing an item, %s\n", cliplist
[clipcount
]));
1814 if ((tmpstr
= (char *)malloc(strlen(cliplist
[clipcount
])+1)) == NULL
) {
1815 DEBUG(0, ("Could not allocate space for a cliplist item, # %i\n",
1820 unfixtarname(tmpstr
, cliplist
[clipcount
], strlen(cliplist
[clipcount
]) + 1, True
);
1821 tmplist
[clipcount
] = tmpstr
;
1822 DEBUG(5, ("Processed an item, %s\n", tmpstr
));
1824 DEBUG(5, ("Cliplist is: %s\n", cliplist
[0]));
1827 must_free_cliplist
= True
;
1830 if (Optind
+1<argc
&& tar_re_search
) { /* Doing regular expression seaches */
1834 if ((preg
= (regex_t
*)malloc(65536)) == NULL
) {
1836 DEBUG(0, ("Could not allocate buffer for regular expression search\n"));
1841 if (errcode
= regcomp(preg
, argv
[Optind
+ 1], REG_EXTENDED
)) {
1845 errlen
= regerror(errcode
, preg
, errstr
, sizeof(errstr
) - 1);
1847 DEBUG(0, ("Could not compile pattern buffer for re search: %s\n%s\n", argv
[Optind
+ 1], errstr
));
1853 clipn
=argc
-Optind
-1;
1854 cliplist
=argv
+Optind
+1;
1858 if (Optind
>=argc
|| !strcmp(argv
[Optind
], "-")) {
1859 /* Sets tar handle to either 0 or 1, as appropriate */
1860 tarhandle
=(tar_type
=='c');
1862 * Make sure that dbf points to stderr if we are using stdout for
1868 if (tar_type
=='c' && (dry_run
|| strcmp(argv
[Optind
], "/dev/null")==0))
1871 DEBUG(0,("Output is /dev/null, assuming dry_run"));
1876 if ((tar_type
=='x' && (tarhandle
= sys_open(argv
[Optind
], O_RDONLY
, 0)) == -1)
1877 || (tar_type
=='c' && (tarhandle
=sys_creat(argv
[Optind
], 0644)) < 0))
1879 DEBUG(0,("Error opening local file %s - %s\n",
1880 argv
[Optind
], strerror(errno
)));