1 /* G U N I X I O -- UNIX i/o module for gkermit */
4 UNIX i/o functions for gkermit.
11 New York NY 10025-7799 USA
12 http://www.columbia.edu/kermit/
16 The Trustees of Columbia University in the City of New York.
18 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation; either version 2 of the License, or
21 (at your option) any later version.
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
42 ttpkt - Put in packet mode
43 ttres - Restore normal mode
44 ttinl - Input a raw packet
46 ttchk - Check if input ready
47 ttflui - Flush input buffer
50 zchki - See if file can be opened for input
51 zopeni - Open input file
52 zopeno - Open output file
53 zclosi - Close input file
54 zcloso - Close output file
55 zrtol - Remote-to-Local filename conversion
56 zltor - Local-to-Remote filename conversion
57 zgetc - Get character from input file
60 #include <stdio.h> /* Standard input/output */
65 #include <termios.h> /* Terminal modes */
74 #include <ctype.h> /* Character types */
75 #include <sys/types.h> /* Needed e.g. by <stat.h> */
76 #include <signal.h> /* Interrupts */
77 #include <setjmp.h> /* Longjumps */
78 #include <sys/stat.h> /* File exist, file size */
79 #include <errno.h> /* Error symbols */
80 #include "gkermit.h" /* gkermit definitions */
82 /* All versions of HP-UX need Xon/Xoff */
84 #ifdef hpux /* HP-UX Pre-7.00 */
90 #ifdef __hpux /* HP-UX 7.00 and later */
93 #endif /* SETXONXOFF */
96 #ifdef NOXONXOFF /* -DNOXONXOFF overrides */
99 #endif /* SETXONXOFF */
100 #endif /* NOXONXOFF */
102 #ifndef TINBUFSIZ /* read() inpbut buffer */
104 #define TINBUFSIZ 0 /* getchar() has its own */
107 #define TINBUFSIZ 240
109 #define TINBUFSIZ 4080
111 #endif /* USE_GETCHAR */
112 #endif /* TINBUFSIZ */
116 #ifndef NOFCNTL_H /* For nonblocking buffered read() */
118 #include <sys/fcntl.h>
123 #define O_NDELAY O_NONBLOCK
124 #endif /* O_NONBLOCK */
125 #endif /* O_NDELAY */
126 #endif /* SYS_FCNTL_H */
127 #endif /* NOFCNTL_H */
128 #endif /* USE_GETCHAR */
131 #ifdef O_NDELAY /* For System V R3 and earlier */
134 #define EWOULDBLOCK EAGAIN
136 #endif /* EWOULDBLOCK */
137 #endif /* O_NDELAY */
139 #ifndef DUMBIO /* To force single-char read/write */
143 #endif /* O_NDELAY */
144 #endif /* USE_GETCHAR */
147 /* Header file deficiencies section... */
161 #define _IFMT 0170000
166 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
169 /* External variables */
171 extern int literal
; /* Literal filenames */
172 extern int quiet
; /* No messages */
173 extern int keep
; /* Keep incomplete files */
174 extern int streamok
; /* OK to offer streaming */
175 extern int nomodes
; /* Don't get/set tty modes */
176 extern int xonxoff
; /* Set Xon/Xoff */
177 extern int noxonxoff
; /* Don't set Xon/Xoff */
178 extern FILE * db
; /* Debug log file */
180 /* Exported variables */
182 FILE *ifp
, *ofp
; /* Input and output file pointers */
183 char zinbuf
[MAXRECORD
+1]; /* File input buffer */
184 int zincnt
= 0; /* count */
185 char * zinptr
= NULL
; /* and pointer. */
187 /* Private global variables */
189 static int havemodes
= 0; /* Have obtained terminal modes */
190 static int ttflags
= -1; /* Terminal flags */
191 static int nonblock
= 0; /* Nonblocking i/o enabled */
192 static char tinbuf
[TINBUFSIZ
+16]; /* Communications input buffer */
193 static char * tinptr
= NULL
; /* Pointer to current item */
194 static int tincnt
= 0; /* Buffer count */
195 static int tlast
= 0; /* Last item in buffer */
196 static int xparity
= 0; /* Parity in use, 0 = none */
197 static int raw
= 0; /* Terminal rawmode flag */
198 static char work
[MAXPATHLEN
+1]; /* Filename conversion buffer */
200 /* Terminal mode structs */
202 #ifdef POSIX /* POSIX */
203 static struct termios ttold
, ttraw
;
205 #ifdef SYSV /* System V */
206 static struct termio ttold
= {0};
207 static struct termio ttraw
= {0};
209 #ifdef BSD /* 4.2 BSD or UNIX V7 */
210 static struct sgttyb ttold
, ttraw
;
215 static jmp_buf jbuf
; /* Longjump buffer for timeouts */
220 doexit(x
) int x
; { /* Exit routine */
221 if (x
) /* If failure */
222 ttflui(); /* flush pending junk we won't read */
223 ttres(); /* Reset the communication device */
225 if (ttflags
> -1) /* Restore its flags */
226 fcntl(0,F_SETFL
,ttflags
);
229 fprintf(db
,"exit %d\n",x
);
236 sysinit() { /* To be run first thing */
238 ttflags
= fcntl(0,F_GETFL
,0); /* Get and save stdin flags */
241 signal(SIGINT
,SIG_IGN
); /* Ignore interrupts */
244 signal(SIGTSTP
,SIG_IGN
);
247 signal(SIGQUIT
,SIG_IGN
);
249 signal(SIGHUP
,doexit
); /* Go here on hangup */
252 /* Console Functions */
254 #ifdef COMMENT /* (not used) */
256 tmsg(s
) char *s
; { /* tmsg() */
258 fprintf(stderr
,"%s",s
); /* Type message on the screen. */
263 tmsgl(s
) char *s
; { /* tmsgl() */
266 fprintf(stderr
,"%s\r\n",s
); /* Type message with CRLF */
268 fprintf(stderr
,"%s\n",s
);
272 /* Debugging functions */
275 logerr(s
) char * s
; { /* Log text and errno */
278 if (db
) fprintf(db
,"%s: errno = %d\n",s
,errno
);
281 /* Parity function */
288 #endif /* __STDC__ */
291 if (!xparity
) return(ch
); else ch
&= 0177;
293 case 'm': return(ch
| 128); /* Mark */
294 case 's': return(ch
& 127); /* Space */
295 case 'o': /* Odd (fall thru) */
297 a
= (ch
& 15) ^ ((ch
>> 4) & 15);
298 a
= (a
& 3) ^ ((a
>> 2) & 3);
299 a
= (a
& 1) ^ ((a
>> 1) & 1);
300 if (xparity
== 'o') a
= 1 - a
; /* Switch sense for odd */
301 return(ch
| (a
<< 7));
306 /* Communication functions */
309 ttopen(ttname
) char *ttname
; { /* "Open" the communication device */
310 if (debug
) { /* Vital statistics for debug log */
312 fprintf(db
,"ttopen __STDC__\n");
313 #endif /* __STDC__ */
315 fprintf(db
,"ttopen SIG_V\n");
318 fprintf(db
,"ttopen SIG_I\n");
322 fprintf(db
,"ttopen getchar/putchar\n");
324 fprintf(db
,"ttopen BUFSIZ = %d\n", BUFSIZ
);
328 fprintf(db
,"ttopen single-byte read/write\n");
330 fprintf(db
,"ttopen nonblocking read/write\n");
332 #endif /* USE_GETCHAR */
333 fprintf(db
,"ttopen TINBUFSIZ = %d\n", TINBUFSIZ
);
335 fprintf(db
,"ttopen __hpux\n");
338 fprintf(db
,"ttopen pdp11\n");
341 fprintf(db
,"ttopen SETXONXOFF\n");
342 #endif /* SETXONXOFF */
343 fprintf(db
,"ttopen xonxoff = %d\n",xonxoff
);
344 fprintf(db
,"ttopen noxonxoff = %d\n",noxonxoff
);
345 fprintf(db
,"ttopen ttflags %d\n",ttflags
);
346 fprintf(db
,"ttopen nomodes %d\n",nomodes
);
348 if (nomodes
) { /* If external protocol */
349 #ifdef SIGINT /* exit on interrupts */
350 signal(SIGINT
,doexit
);
353 signal(SIGTSTP
,doexit
);
356 signal(SIGQUIT
,doexit
);
365 if (ttflags
!= -1) { /* Set nonbocking i/o on stdin */
367 if (fcntl(0, F_SETFL
,ttflags
|O_NDELAY
) == -1)
368 logerr("ttopen fcntl(0,F_SETFL,O_NDELAY)");
373 #endif /* O_NDELAY */
374 #endif /* USE_GETCHAR */
376 if (!nonblock
) /* No streaming without */
377 streamok
= -1; /* nonblocking reads */
380 fprintf(db
,"ttopen nonblock = %d\n", nonblock
);
382 tcgetattr(0,&ttold
); /* Get stdin device attributes */
386 ioctl(0,TCGETA
,&ttold
);
387 ioctl(0,TCGETA
,&ttraw
);
400 ttpkt(parity
) int parity
; { /* Put comm device in packet mode */
404 xparity
= parity
; /* Make local copy of parity */
408 #ifdef SVORPOSIX /* System V or POSIX section... */
409 ttraw
.c_iflag
|= IGNPAR
;
410 ttraw
.c_lflag
&= ~(ICANON
|ECHO
);
411 ttraw
.c_lflag
&= ~ISIG
;
412 ttraw
.c_lflag
|= NOFLSH
;
415 ttraw
.c_iflag
|= (IXON
|IXOFF
);
416 if (debug
) fprintf(db
,"ttpkt SVORPOSIX Xon/Xoff\n");
420 if (debug
) fprintf(db
,"ttpkt SVORPOSIX Xon/Xoff\n");
421 ttraw
.c_iflag
|= (IXON
|IXOFF
);
423 #endif /* SETXONXOFF */
425 ttraw
.c_lflag
&= ~IEXTEN
;
428 ttraw
.c_iflag
&= ~(IGNBRK
|INLCR
|IGNCR
|ICRNL
|INPCK
|ISTRIP
);
430 ttraw
.c_iflag
&= ~(IGNBRK
|INLCR
|IGNCR
|ICRNL
|INPCK
|ISTRIP
|IXANY
);
432 ttraw
.c_oflag
&= ~OPOST
;
433 ttraw
.c_cflag
&= ~(CSIZE
);
434 ttraw
.c_cflag
|= (CS8
|CREAD
|HUPCL
);
435 ttraw
.c_cflag
&= ~(PARENB
);
441 ttraw
.c_cc
[VMIN
] = 1;
449 ttraw
.c_cc
[VTIME
] = 0;
454 ttraw
.c_cc
[VINTR
] = 0;
458 if (tcsetattr(0,TCSADRAIN
,&ttraw
) < 0)
461 if (ioctl(0,TCSETAW
,&ttraw
) < 0)
467 #else /* Not SVORPOSIX */
470 ttraw
.sg_flags
|= RAW
; /* BSD/V7 raw (binary) mode */
473 ttraw
.sg_flags
|= TANDEM
;
474 if (debug
) fprintf(db
,"ttpkt BSD Xon/Xoff\n");
478 ttraw
.sg_flags
|= TANDEM
;
479 if (debug
) fprintf(db
,"ttpkt BSD Xon/Xoff\n");
481 #endif /* SETXONXOFF */
482 ttraw
.sg_flags
&= ~(ECHO
|CRMOD
); /* No echo, etc */
483 if (stty(0,&ttraw
) < 0) return(-1); /* Set modes */
485 system("stty raw -echo");
487 #endif /* SVORPOSIX */
488 raw
= 1; /* Flag we're now in raw mode */
493 ttres() { /* Reset terminal */
495 if (havemodes
) { /* Restore old modes */
497 x
= tcsetattr(0,TCSADRAIN
,&ttold
);
500 sleep(1); /* Let output finish */
501 x
= ioctl(0,TCSETAW
,&ttold
);
504 sleep(1); /* Let output finish */
507 x
= system("stty -raw echo");
512 write(1,"\015\012",2);
518 ttchk() { /* Check if input ready */
520 if (nonblock
) { /* Try to read */
522 x
= read(0,&tinbuf
[tlast
],TINBUFSIZ
-tlast
);
524 fprintf(db
,"ttchk read %d errno = %d\n",x
,errno
);
525 #endif /* EXTRADEBUG */
527 if (x
< 0 && errno
== EWOULDBLOCK
) /* Nothing to read */
529 #endif /* EWOULDBLOCK */
530 if (x
< 0) /* Fatal i/o error */
533 tincnt
+= x
; /* Buffer bookkeeping */
535 return(x
+ tincnt
); /* How much is waiting to be read */
539 ttflui() { /* Flush comm device input buffer */
541 long n
= 1; /* Specify read queue */
544 tincnt
= 0; /* Our own buffer */
549 x
= tcflush(0,TCIFLUSH
); /* kernel/driver buffers */
552 x
= ioctl(0,TCFLSH
,0);
555 x
= ioctl(0,TIOCFLUSH
,&n
);
559 if (debug
) fprintf(db
,"ttflui = %d, errno = %d\n",x
,errno
);
564 timerh(dummy
) int dummy
; { /* Timeout handler */
570 ttinl() - Read a raw packet.
573 dest - where to put it
575 timo - timeout (seconds, 0 = none)
576 eol - packet terminator
577 turn - half-duplex line turnaround character to wait for, 0 = none
579 Returns length obtained, or -1 if error or timeout, -2 on disconnection.
583 #endif /* DEBUGWRAP */
587 ttinl(char * dest
, int max
, int timo
, char eol
, char soh
, int turn
)
589 ttinl(dest
,max
,timo
,eol
,soh
,turn
) int max
, timo
, turn
; char eol
, soh
, *dest
;
590 #endif /* __STDC__ */
592 int n
= 0, x
= 0, flag
= 0, rc
= 0, ccn
= 0; /* Local variables */
594 int havelen
= 0, pktlen
= 0, lplen
= 0;
597 if (debug
) fprintf(db
,"ttinl getchar timo = %d\n",timo
);
599 if (debug
) fprintf(db
,"ttinl read timo = %d\n",timo
);
600 #endif /* USE_GETCHAR */
601 *dest
= NUL
; /* Clear destination buffer */
603 signal(SIGALRM
,timerh
); /* Enable timer interrupt */
604 alarm(timo
); /* Set it. */
606 if (setjmp(jbuf
)) { /* Timer went off? */
607 if (debug
) fprintf(db
,"ttinl timeout\n");
608 rc
= -1; /* Yes, set this return code. */
609 } else { /* Otherwise... */
610 while (1) { /* Read until we have a packet */
612 x
= read(0,&c
,1); /* Dumb blocking read byte loop */
614 logerr("ttinl XX read 1");
620 x
= getchar(); /* Buffered read with getchar() */
624 logerr("ttinl getchar");
628 #else /* USE_GETCHAR */
630 if (nonblock
) { /* Buffered nonblocking read() */
632 if (tincnt
< 1) { /* Need to fill our buffer */
634 tincnt
= read(0,tinbuf
,TINBUFSIZ
);
635 if (tincnt
> -1) tlast
= tincnt
;
637 fprintf(db
,"ttinl nonblock tincnt=%d errno=%d\n",
639 if (tincnt
== 0 || errno
== EWOULDBLOCK
) {
641 /* Go back to blocking and wait for 1 char */
644 x
= fcntl(0, F_SETFL
, ttflags
& ~O_NDELAY
);
645 if (x
== -1 || errno
)
646 logerr("ttinl fcntl O_NDELAY off");
648 tincnt
= read(0,tinbuf
,1);
649 if (tincnt
< 1 || errno
)
650 logerr("ttinl BL read");
652 fcntl(0, F_SETFL
, ttflags
| O_NDELAY
);
653 if (x
== -1 || errno
)
654 logerr("ttinl fcntl O_NDELAY on");
656 if (tincnt
== 0) { /* Check results */
659 if (tincnt
< 0) { /* I/O error */
664 fprintf(db
,"ttinl blocking read %d\n",tincnt
);
666 /* No other form of sleeping is portable */
670 } else if (tincnt
< 0) {
679 #endif /* O_NDELAY */
680 x
= read(0,&c
,1); /* Dumb read byte loop */
682 logerr("ttinl XX read 1");
687 #endif /* O_NDELAY */
688 #endif /* USE_GETCHAR */
692 if (xparity
) /* Strip parity */
695 /* Only uncomment in emergencies */
697 fprintf(db
,"ttinl char=%c flag=%d tincnt=%d\n",c
,flag
,tincnt
);
699 if (c
== '\03') { /* Got ^C, count it. */
700 if (++ccn
> 2) { /* If more than 2, let them out */
701 fprintf(stderr
,"^C...");
703 if (debug
) fprintf(db
,"ttinl interrupted\n");
708 } else /* Not ^C so reset counter*/
711 if (!flag
&& (c
!= soh
)) /* Look for SOH */
712 continue; /* Skip stuff between packets */
713 flag
= 1; /* Have SOH */
716 if (debug
) fprintf(db
,"ttinl overflow\n");
720 dest
[n
++] = c
; /* Store the character */
722 /* Use EOL to determine end of packet */
728 /* Use length field for framing */
731 pktlen
= xunchar(dest
[1] & 0x7f);
733 if (debug
) fprintf(db
,"ttinl length = %d\n",pktlen
);
736 } else if (n
== 5 && pktlen
== 0) {
737 lplen
= xunchar(dest
[4] & 0x7f);
738 } else if (n
== 6 && pktlen
== 0) {
739 pktlen
= lplen
* 95 + xunchar(dest
[5] & 0x7f) + 5;
740 if (debug
) fprintf(db
,"ttinl length = %d\n",pktlen
);
744 if (havelen
&& (n
> pktlen
+1)) {
745 if (turn
&& c
!= turn
) /* Wait for turnaround char */
747 dest
[n
] = NUL
; /* Null-terminate whatever we got */
753 xttinl
: /* Common exit point */
755 alarm(0); /* Turn off the alarm */
756 signal(SIGALRM
,SIG_IGN
); /* and associated interrupt */
758 if (debug
&& n
> 0) { /* Log packet */
760 if (n
> DEBUGWRAP
) { /* Truncate if it would wrap */
761 dest
[n
] = NUL
; /* in case of interruption */
763 dest
[DEBUGWRAP
] = NUL
;
764 fprintf(db
,"PKT<-[^A%s...](%d) rc=%d\n",&dest
[1],n
,rc
);
768 #endif /* FULLPACKETS */
769 fprintf(db
,"PKT<-[^A%s](%d) rc=%d\n",&dest
[1],n
,rc
);
771 if (rc
== -9) /* Interrupted by user */
775 return(rc
); /* Return length, or failure. */
779 ttol(s
,len
) int len
; char *s
; { /* Output string s of given length */
780 register int i
= 0, n
= 0, m
= 0;
785 if (debug
) fprintf(db
,"ttol len = %d\n",n
);
788 if (xparity
) { /* Add parity if requested */
789 for (i
= 0; i
< n
; i
++)
792 if (debug
) { /* Log the packet if requested */
798 fprintf(db
,"PKT->[^A%s...](%d)\n",&s
[1],n
);
801 #endif /* FULLPACKETS */
804 fprintf(db
,"PKT->[^A%s](%d)\n",&s
[1],n
);
808 #endif /* FULLPACKETS */
811 { /* Send the packet with putchar() */
812 register CHAR c
; register int i
;
813 for (i
= 0; i
< n
; i
++) {
815 if (putchar(c
) == EOF
) {
816 logerr("ttol putchar");
821 fflush(stdout
); /* Push it out */
824 while (n
> 0) { /* Send the packet with write() */
825 i
= write(1,&s
[m
],n
); /* Allowing for partial results */
827 if (errno
== EWOULDBLOCK
) /* and even no results at all.. */
829 logerr("ttol write");
836 if (debug
) fprintf(db
,"ttol partial write %d (%d/%d)\n",i
,m
,len
);
841 if (debug
) fprintf(db
,"ttol partial write %d (%d/%d)\n",i
,m
,len
);
843 if (debug
) fprintf(db
,"ttol foulup %d != %d\n",m
,len
);
848 #endif /* USE_GETCHAR */
853 char ofile
[MAXPATHLEN
]; /* Output filename */
854 long filelength
= -1L;
857 zchki(fn
) char * fn
; { /* Check if file is readable */
860 if (stat(fn
,&buf
) < 0)
863 if (access(fn
,R_OK
) < 0) {
865 fprintf(db
,"zchki access %s errno = %d\n",fn
,errno
);
868 if (!S_ISREG(buf
.st_mode
)) {
870 fprintf(db
,"zchki %s is a directory",fn
);
877 zchko(fn
) char *fn
; { /* Check write access */
881 if (!fn
) /* Defend against empty name */
885 if (!strcmp(fn
,"/dev/null")) /* Null device is OK. */
887 if ((x
= zchki(fn
)) == -2) /* An existing directory? */
890 if (x
< 0) { /* If file does not exist */
891 strncpy(work
,fn
,MAXPATHLEN
);
892 work
[MAXPATHLEN
] = NUL
;
894 for (i
= (int)strlen(s
); i
> 0; i
--) { /* Strip filename from right */
895 if (s
[i
-1] == '/') { /* and check its directory */
904 x
= access(s
,W_OK
); /* Check access of path. */
905 if (debug
) fprintf(db
,"zchko(%s) x = %d errno = %d\n",s
,x
,errno
);
906 return((x
< 0) ? -1 : 0); /* and return. */
910 zopeni(name
) char *name
; { /* Open existing file for input */
911 ifp
= fopen(name
,"r");
912 if (debug
) fprintf(db
,"zopeni %s: %d\n",name
, ifp
? 0 : errno
);
913 filelength
= zchki(name
);
915 return((int)filelength
);
918 return((ifp
== NULL
) ? -1 : 0);
922 zopeno(name
) char *name
; { /* Open new file for output */
924 ofp
= fopen(name
,"w");
925 if (debug
) fprintf(db
,"zopeno %s: %d\n",name
, ofp
? 0 : errno
);
927 strncpy(ofile
,name
,MAXPATHLEN
);
928 ofile
[MAXPATHLEN
-1] = NUL
;
934 VOID
/* Local to remote file name */
935 zltor(lclnam
,pktnam
,maxlen
) char *lclnam
, *pktnam
; int maxlen
; {
936 char *p
, *np
= NULL
, *cp
, *pp
, c
;
942 fprintf(db
,"zltor %s: maxlen = %d, literal = %d\n",
943 lclnam
,maxlen
,literal
);
948 if (*p
== '/') dirp
= p
+1;
951 strncpy(pktnam
,dirp
,maxlen
);
953 for (p
= lclnam
; *p
; p
++) { /* Point to name part */
959 if (!*np
) np
= lclnam
;
964 fprintf(db
,"zltor np %s\n",np
);
966 pp
= work
; /* Output buffer */
967 for (cp
= np
, n
= 0; *cp
&& n
< maxlen
; cp
++,n
++) {
969 if (islower(c
)) /* Uppercase letters */
970 *pp
++ = toupper(c
); /* Change tilde to hyphen */
973 else if (c
== '#') /* Change number sign to 'X' */
975 else if (c
== '*' || c
== '?') /* Change wildcard chars to 'X' */
977 else if (c
== ' ') /* Change space to underscore */
979 else if (c
< ' ') /* Change space and controls to 'X' */
981 else if (c
== '.') { /* Change dot to underscore */
982 dotp
= pp
; /* Remember where we last did this */
990 *pp
= NUL
; /* Tie it off. */
991 if (dotp
> dirp
) *dotp
= '.'; /* Restore last dot in file name */
992 cp
= pktnam
; /* If nothing before dot, */
993 if (*work
== '.') *cp
++ = 'X'; /* insert 'X' */
994 strncpy(cp
,work
,maxlen
);
998 fprintf(db
,"zltor result: %s\n",pktnam
);
1002 zbackup(fn
) char * fn
; { /* Back up existing file */
1004 int i
, j
, k
, x
, state
, flag
;
1005 char *p
, newname
[MAXPATHLEN
+12];
1007 if (!fn
) /* Watch out for null pointers. */
1009 if (!*fn
) /* And empty names. */
1011 if (stat(fn
,&buf
) < 0) /* If file doesn't exist */
1012 return(0); /* no need to back it up. */
1014 i
= strlen(fn
); /* Get length */
1015 if (i
> MAXPATHLEN
) /* Guard buffer */
1018 fprintf(db
,"zbackup A %s: %d\n", fn
, i
);
1020 strncpy(work
,fn
,MAXPATHLEN
); /* Make pokeable copy of name */
1021 work
[MAXPATHLEN
] = NUL
;
1022 p
= work
; /* Strip any backup prefix */
1025 for (flag
= state
= 0; (!flag
&& (i
> 0)); i
--) {
1027 case 0: /* State 0 - final char */
1028 if (p
[i
] == '~') /* Is tilde */
1029 state
= 1; /* Switch to next state */
1030 else /* Otherwise */
1031 flag
= 1; /* Quit - no backup suffix. */
1033 case 1: /* State 1 - digits */
1034 if (p
[i
] == '~' && p
[i
-1] == '.') { /* Have suffix */
1035 p
[i
-1] = NUL
; /* Trim it */
1036 flag
= 1; /* done */
1037 } else if (p
[i
] >= '0' && p
[i
] <= '9') { /* In number part */
1038 continue; /* Keep going */
1039 } else { /* Something else */
1040 flag
= 1; /* Not a backup suffix - quit. */
1046 fprintf(db
,"zbackup B %s\n", p
);
1050 strncpy(newname
,p
,MAXPATHLEN
);
1051 for (i
= 1; i
< 1000; i
++) { /* Search from 1 to 999 */
1052 if (i
< 10) /* Length of numeric part of suffix */
1058 x
= j
; /* Where to write suffix */
1059 if ((x
+ k
+ 3) > MAXPATHLEN
)
1060 x
= MAXPATHLEN
- k
- 3;
1061 sprintf(&newname
[x
],".~%d~",i
); /* Make a backup name */
1062 if (stat(newname
,&buf
) < 0) { /* If it doesn't exist */
1064 if (link(fn
,newname
) < 0) { /* Rename old file to backup name */
1066 fprintf(db
,"zbackup failed: link(%s): %d\n",newname
,errno
);
1068 } else if (unlink(fn
) < 0) {
1070 fprintf(db
,"zbackup failed: unlink(%s): %d\n",fn
,errno
);
1074 fprintf(db
,"zbackup %s: OK\n",newname
);
1080 fprintf(db
,"zbackup failed: all numbers used\n");
1084 int /* Remote to local filename */
1085 zrtol(pktnam
,lclnam
,warn
,maxlen
) char *pktnam
, *lclnam
; int warn
, maxlen
; {
1086 int acase
= 0, flag
= 0, n
= 0;
1090 strncpy(lclnam
,pktnam
,maxlen
);
1092 for (p
= lclnam
; *pktnam
!= '\0' && n
< maxlen
; pktnam
++) {
1093 if (*pktnam
> SP
) flag
= 1; /* Strip leading blanks and controls */
1094 if (flag
== 0 && *pktnam
< '!')
1096 if (isupper(*pktnam
)) /* Check for mixed case */
1098 else if (islower(*pktnam
))
1103 *p
-- = NUL
; /* Terminate */
1104 while (*p
< '!' && p
> lclnam
) /* Strip trailing blanks & controls */
1107 if (!*lclnam
) { /* Nothing left? */
1108 strncpy(lclnam
,"NONAME",maxlen
); /* do this... */
1109 } else if (acase
== 1) { /* All uppercase? */
1110 p
= lclnam
; /* So convert all letters to lower */
1119 if (zbackup(lclnam
) < 0)
1126 zclosi() { /* Close input file */
1128 rc
= (fclose(ifp
) == EOF
) ? -1 : 0;
1134 zcloso(cx
) int cx
; { /* Close output file */
1136 rc
= (fclose(ofp
) == EOF
) ? -1 : 0;
1137 if (debug
) fprintf(db
,"zcloso(%s) cx = %d keep = %d\n", ofile
, cx
, keep
);
1138 if (cx
&& !keep
) unlink(ofile
); /* Delete if incomplete */
1144 zfillbuf(text
) int text
; { /* Refill input file buffer */
1145 if (zincnt
< 1) { /* Nothing in buffer - must refill */
1146 if (text
) { /* Text mode needs LF/CRLF handling */
1147 int c
; /* Current character */
1148 for (zincnt
= 0; /* Read a line */
1149 zincnt
< MAXRECORD
- 1 && (c
= getc(ifp
)) != EOF
&& c
!= '\n';
1154 if (c
== '\n') { /* Have newline. */
1155 zinbuf
[zincnt
++] = '\r'; /* Substitute CRLF */
1156 zinbuf
[zincnt
++] = c
;
1158 } else { /* Binary - just read raw buffers */
1159 zincnt
= fread(zinbuf
, sizeof(char), MAXRECORD
, ifp
);
1161 zinbuf
[zincnt
] = NUL
; /* Terminate. */
1162 if (zincnt
== 0) /* Check for EOF */
1164 zinptr
= zinbuf
; /* Not EOF - reset pointer */
1166 #ifdef EXTRADEBUG /* Voluminous debugging */
1167 if (debug
) fprintf(db
,"zfillbuf (%s) zincnt = %d\n",
1168 text
? "text" : "binary",
1171 #endif /* EXTRADEBUG */
1172 zincnt
--; /* Return first byte. */
1173 return(*zinptr
++ & 0xff);