📄 io.c
字号:
/* io.c
*
* Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft.
* All rights reserved.
*
*/
#include "syshdrs.h"
static int gGotBrokenData = 0;
#if defined(WIN32) || defined(_WINDOWS)
# define ASCII_TRANSLATION 0
#endif
#ifndef ASCII_TRANSLATION
# define ASCII_TRANSLATION 1
#endif
#if !defined(NO_SIGNALS) && (USE_SIO || !defined(SIGALRM) || !defined(SIGPIPE) || !defined(SIGINT))
# define NO_SIGNALS 1
#endif
#ifndef NO_SIGNALS
#ifdef HAVE_SIGSETJMP
static sigjmp_buf gBrokenDataJmp;
#else
static jmp_buf gBrokenDataJmp;
#endif /* HAVE_SIGSETJMP */
static int gCanBrokenDataJmp = 0;
#endif /* NO_SIGNALS */
#ifndef O_BINARY
/* Needed for platforms using different EOLN sequence (i.e. DOS) */
# ifdef _O_BINARY
# define O_BINARY _O_BINARY
# else
# define O_BINARY 0
# endif
#endif
static int WaitForRemoteInput(const FTPCIPtr cip);
static int WaitForRemoteOutput(const FTPCIPtr cip);
#ifndef NO_SIGNALS
static void
BrokenData(int signum)
{
gGotBrokenData = signum;
if (gCanBrokenDataJmp != 0) {
gCanBrokenDataJmp = 0;
#ifdef HAVE_SIGSETJMP
siglongjmp(gBrokenDataJmp, 1);
#else
longjmp(gBrokenDataJmp, 1);
#endif /* HAVE_SIGSETJMP */
}
} /* BrokenData */
#endif /* NO_SIGNALS */
void
FTPInitIOTimer(const FTPCIPtr cip)
{
cip->bytesTransferred = (longest_int) 0;
cip->expectedSize = kSizeUnknown;
cip->mdtm = kModTimeUnknown;
cip->rname = NULL;
cip->lname = NULL;
cip->kBytesPerSec = -1.0;
cip->percentCompleted = -1.0;
cip->sec = -1.0;
cip->secLeft = -1.0;
cip->nextProgressUpdate = 0;
cip->stalled = 0;
cip->dataTimedOut = 0;
cip->useProgressMeter = 1;
(void) gettimeofday(&cip->t0, NULL);
} /* FTPInitIOTimer */
void
FTPStartIOTimer(const FTPCIPtr cip)
{
(void) gettimeofday(&cip->t0, NULL);
if (cip->progress != (FTPProgressMeterProc) 0)
(*cip->progress)(cip, kPrInitMsg);
} /* FTPStartIOTimer */
void
FTPUpdateIOTimer(const FTPCIPtr cip)
{
double sec;
struct timeval *t0, t1;
time_t now;
(void) time(&now);
if (now < cip->nextProgressUpdate)
return;
now += 1;
cip->nextProgressUpdate = now;
(void) gettimeofday(&t1, NULL);
t0 = &cip->t0;
if (t0->tv_usec > t1.tv_usec) {
t1.tv_usec += 1000000;
t1.tv_sec--;
}
sec = ((double) (t1.tv_usec - t0->tv_usec) * 0.000001)
+ (t1.tv_sec - t0->tv_sec);
if (sec > 0.0) {
cip->kBytesPerSec = ((double) cip->bytesTransferred) / (1024.0 * sec);
} else {
cip->kBytesPerSec = -1.0;
}
if (cip->expectedSize == kSizeUnknown) {
cip->percentCompleted = -1.0;
cip->secLeft = -1.0;
} else if (cip->expectedSize <= 0) {
cip->percentCompleted = 100.0;
cip->secLeft = 0.0;
} else {
cip->percentCompleted = ((double) (100.0 * (cip->bytesTransferred + cip->startPoint))) / ((double) cip->expectedSize);
if (cip->percentCompleted >= 100.0) {
cip->percentCompleted = 100.0;
cip->secLeft = 0.0;
} else if (cip->percentCompleted <= 0.0) {
cip->secLeft = 999.0;
}
if (cip->kBytesPerSec > 0.0) {
cip->secLeft = ((cip->expectedSize - cip->bytesTransferred - cip->startPoint) / 1024.0) / cip->kBytesPerSec;
if (cip->secLeft < 0.0)
cip->secLeft = 0.0;
}
}
cip->sec = sec;
if ((cip->progress != (FTPProgressMeterProc) 0) && (cip->useProgressMeter != 0))
(*cip->progress)(cip, kPrUpdateMsg);
} /* FTPUpdateIOTimer */
void
FTPStopIOTimer(const FTPCIPtr cip)
{
cip->nextProgressUpdate = 0; /* force last update */
FTPUpdateIOTimer(cip);
if (cip->progress != (FTPProgressMeterProc) 0)
(*cip->progress)(cip, kPrEndMsg);
} /* FTPStopIOTimer */
/* This isn't too useful -- it mostly serves as an example so you can write
* your own function to do what you need to do with the listing.
*/
int
FTPList(const FTPCIPtr cip, const int outfd, const int longMode, const char *const lsflag)
{
const char *cmd;
char line[512];
char secondaryBuf[768];
#ifndef NO_SIGNALS
char *secBufPtr, *secBufLimit;
int nread;
volatile int result;
#else /* NO_SIGNALS */
SReadlineInfo lsSrl;
int result;
#endif /* NO_SIGNALS */
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
cmd = (longMode != 0) ? "LIST" : "NLST";
if ((lsflag == NULL) || (lsflag[0] == '\0')) {
result = FTPStartDataCmd(cip, kNetReading, kTypeAscii, (longest_int) 0, "%s", cmd);
} else {
result = FTPStartDataCmd(cip, kNetReading, kTypeAscii, (longest_int) 0, "%s %s", cmd, lsflag);
}
#ifdef NO_SIGNALS
if (result == 0) {
if (InitSReadlineInfo(&lsSrl, cip->dataSocket, secondaryBuf, sizeof(secondaryBuf), (int) cip->xferTimeout, 1) < 0) {
/* Not really fdopen, but close in what we're trying to do. */
result = kErrFdopenR;
cip->errNo = kErrFdopenR;
Error(cip, kDoPerror, "Could not fdopen.\n");
return (result);
}
for (;;) {
result = SReadline(&lsSrl, line, sizeof(line) - 2);
if (result == kTimeoutErr) {
/* timeout */
Error(cip, kDontPerror, "Could not directory listing data -- timed out.\n");
cip->errNo = kErrDataTimedOut;
return (cip->errNo);
} else if (result == 0) {
/* end of listing -- done */
cip->numListings++;
break;
} else if (result < 0) {
/* error */
Error(cip, kDoPerror, "Could not read directory listing data");
result = kErrLISTFailed;
cip->errNo = kErrLISTFailed;
break;
}
(void) write(outfd, line, strlen(line));
}
DisposeSReadlineInfo(&lsSrl);
if (FTPEndDataCmd(cip, 1) < 0) {
result = kErrLISTFailed;
cip->errNo = kErrLISTFailed;
}
} else if (result == kErrGeneric) {
result = kErrLISTFailed;
cip->errNo = kErrLISTFailed;
}
#else /* NO_SIGNALS */
if (result == 0) {
/* This line sets the buffer pointer so that the first thing
* BufferGets will do is reset and fill the buffer using
* real I/O.
*/
secBufPtr = secondaryBuf + sizeof(secondaryBuf);
secBufLimit = (char *) 0;
for (;;) {
if (cip->xferTimeout > 0)
(void) alarm(cip->xferTimeout);
nread = BufferGets(line, sizeof(line), cip->dataSocket, secondaryBuf, &secBufPtr, &secBufLimit, sizeof(secondaryBuf));
if (nread <= 0) {
if (nread < 0)
break;
} else {
cip->bytesTransferred += (longest_int) nread;
(void) STRNCAT(line, "\n");
(void) write(outfd, line, strlen(line));
}
}
if (cip->xferTimeout > 0)
(void) alarm(0);
result = FTPEndDataCmd(cip, 1);
if (result < 0) {
result = kErrLISTFailed;
cip->errNo = kErrLISTFailed;
}
result = kNoErr;
cip->numListings++;
} else if (result == kErrGeneric) {
result = kErrLISTFailed;
cip->errNo = kErrLISTFailed;
}
#endif /* NO_SIGNALS */
return (result);
} /* FTPList */
static void
FTPRequestMlsOptions(const FTPCIPtr cip)
{
int f;
char optstr[128];
size_t optstrlen;
if (cip->usedMLS == 0) {
/* First MLSD/MLST ? */
cip->usedMLS = 1;
f = cip->mlsFeatures & kPreferredMlsOpts;
optstr[0] = '\0';
/* TYPE */
if ((f & kMlsOptType) != 0) {
STRNCAT(optstr, "type;");
}
/* SIZE */
if ((f & kMlsOptSize) != 0) {
STRNCAT(optstr, "size;");
}
/* MODTIME */
if ((f & kMlsOptModify) != 0) {
STRNCAT(optstr, "modify;");
}
/* MODE */
if ((f & kMlsOptUNIXmode) != 0) {
STRNCAT(optstr, "UNIX.mode;");
}
/* PERM */
if ((f & kMlsOptPerm) != 0) {
STRNCAT(optstr, "perm;");
}
/* OWNER */
if ((f & kMlsOptUNIXowner) != 0) {
STRNCAT(optstr, "UNIX.owner;");
}
/* UID */
if ((f & kMlsOptUNIXuid) != 0) {
STRNCAT(optstr, "UNIX.uid;");
}
/* GROUP */
if ((f & kMlsOptUNIXgroup) != 0) {
STRNCAT(optstr, "UNIX.group;");
}
/* GID */
if ((f & kMlsOptUNIXgid) != 0) {
STRNCAT(optstr, "UNIX.gid;");
}
/* UNIQUE */
if ((f & kMlsOptUnique) != 0) {
STRNCAT(optstr, "unique;");
}
/* Tell the server what we prefer. */
optstrlen = strlen(optstr);
if (optstrlen > 0) {
if (optstr[optstrlen - 1] == ';')
optstr[optstrlen - 1] = '\0';
(void) FTPCmd(cip, "OPTS MLST %s", optstr);
}
}
} /* FTPRequestMlsOptions */
int
FTPListToMemory2(const FTPCIPtr cip, const char *const pattern, const LineListPtr llines, const char *const lsflags, const int blankLines, int *const tryMLSD)
{
char secondaryBuf[768];
char line[512];
char lsflags1[128];
const char *command = "NLST";
const char *scp;
char *dcp, *lim;
#ifndef NO_SIGNALS
char *secBufPtr, *secBufLimit;
volatile FTPSigProc osigpipe;
volatile FTPCIPtr vcip;
int sj;
int nread;
volatile int result;
#else /* NO_SIGNALS */
SReadlineInfo lsSrl;
int result;
#endif /* NO_SIGNALS */
if (cip == NULL)
return (kErrBadParameter);
if (strcmp(cip->magic, kLibraryMagic))
return (kErrBadMagic);
if ((llines == NULL) || (pattern == NULL) || (lsflags == NULL))
return (kErrBadParameter);
if ((tryMLSD != (int *) 0) && (*tryMLSD != 0) && (cip->hasMLSD == kCommandAvailable)) {
command = "MLSD";
if ((lsflags[0] == '-') && (strchr(lsflags, 'd') != NULL) && (cip->hasMLST == kCommandAvailable))
command = "MLST";
lsflags1[0] = '\0';
FTPRequestMlsOptions(cip);
} else {
/* Not using MLSD. */
if (tryMLSD != (int *) 0)
*tryMLSD = 0;
if (lsflags[0] == '-') {
/* See if we should use LIST instead. */
scp = lsflags + 1;
dcp = lsflags1;
lim = lsflags1 + sizeof(lsflags1) - 2;
for (; *scp != '\0'; scp++) {
if (*scp == 'l') {
/* do not add the 'l' */
command = "LIST";
} else if (dcp < lim) {
if (dcp == lsflags1)
*dcp++ = '-';
*dcp++ = *scp;
}
}
*dcp = '\0';
} else {
(void) STRNCPY(lsflags1, lsflags);
}
}
InitLineList(llines);
result = FTPStartDataCmd(
cip,
kNetReading,
kTypeAscii,
(longest_int) 0,
"%s%s%s%s%s",
command,
(lsflags1[0] == '\0') ? "" : " ",
lsflags1,
(pattern[0] == '\0') ? "" : " ",
pattern
);
#ifdef NO_SIGNALS
if (result == 0) {
if (InitSReadlineInfo(&lsSrl, cip->dataSocket, secondaryBuf, sizeof(secondaryBuf), (int) cip->xferTimeout, 1) < 0) {
/* Not really fdopen, but close in what we're trying to do. */
result = kErrFdopenR;
cip->errNo = kErrFdopenR;
Error(cip, kDoPerror, "Could not fdopen.\n");
return (result);
}
for (;;) {
result = SReadline(&lsSrl, line, sizeof(line) - 1);
if (result == kTimeoutErr) {
/* timeout */
Error(cip, kDontPerror, "Could not directory listing data -- timed out.\n");
cip->errNo = kErrDataTimedOut;
return (cip->errNo);
} else if (result == 0) {
/* end of listing -- done */
cip->numListings++;
break;
} else if (result < 0) {
/* error */
Error(cip, kDoPerror, "Could not read directory listing data");
result = kErrLISTFailed;
cip->errNo = kErrLISTFailed;
break;
}
if (line[result - 1] == '\n')
line[result - 1] = '\0';
if ((blankLines == 0) && (result <= 1))
continue;
/* Valid directory listing line of output */
if ((line[0] == '.') && ((line[1] == '\0') || ((line[1] == '.') && ((line[2] == '\0') || (iscntrl(line[2]))))))
continue; /* Skip . and .. */
(void) AddLine(llines, line);
}
DisposeSReadlineInfo(&lsSrl);
if (FTPEndDataCmd(cip, 1) < 0) {
result = kErrLISTFailed;
cip->errNo = kErrLISTFailed;
}
} else if (result == kErrGeneric) {
result = kErrLISTFailed;
cip->errNo = kErrLISTFailed;
}
#else /* NO_SIGNALS */
vcip = cip;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -