I made the curl tool switch from using CURLOPT_IOCTLFUNCTION to now use the

spanking new CURLOPT_SEEKFUNCTION simply to take advantage of the improved
performance for the upload resume cases where you want to upload the last
few bytes of a very large file. To implement this decently, I had to switch
the client code for uploading from fopen()/fread() to plain open()/read() so
that we can use lseek() to do >32bit seeks (as fseek() doesn't allow that)
on systems that offer support for that.
This commit is contained in:
Daniel Stenberg 2008-01-11 14:00:47 +00:00
Родитель 8df7e0bdba
Коммит e2c817731a
3 изменённых файлов: 87 добавлений и 57 удалений

Просмотреть файл

@ -6,6 +6,15 @@
Changelog
Daniel S (11 Jan 2008)
- I made the curl tool switch from using CURLOPT_IOCTLFUNCTION to now use the
spanking new CURLOPT_SEEKFUNCTION simply to take advantage of the improved
performance for the upload resume cases where you want to upload the last
few bytes of a very large file. To implement this decently, I had to switch
the client code for uploading from fopen()/fread() to plain open()/read() so
that we can use lseek() to do >32bit seeks (as fseek() doesn't allow that)
on systems that offer support for that.
Daniel S (10 Jan 2008)
- Michal Marek made curl-config --libs not include /usr/lib64 in the output
(it already before skipped /usr/lib). /usr/lib64 is the default library

Просмотреть файл

@ -5,7 +5,7 @@
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
# Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
@ -1893,6 +1893,7 @@ AC_CHECK_SIZEOF(curl_off_t, ,[
AC_CHECK_SIZEOF(size_t)
AC_CHECK_SIZEOF(long)
AC_CHECK_SIZEOF(time_t)
AC_CHECK_SIZEOF(off_t)
AC_CHECK_TYPE(long long,
[AC_DEFINE(HAVE_LONGLONG, 1, [if your compiler supports long long])]

Просмотреть файл

@ -127,6 +127,12 @@
#define SET_BINMODE(file) ((void)0)
#endif
#ifndef O_BINARY
/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
source code but yet it doesn't ruin anything */
#define O_BINARY 0
#endif
#ifdef MSDOS
#include <dos.h>
@ -201,6 +207,7 @@ typedef enum {
/* Support uploading and resuming of >2GB files
*/
#if defined(WIN32) && (SIZEOF_CURL_OFF_T > 4)
#define lseek(x,y,z) _lseeki64(x, y, z)
#define struct_stat struct _stati64
#define stat(file,st) _stati64(file,st)
#else
@ -605,6 +612,8 @@ struct getout {
static void help(void)
{
int i;
/* A few of these source lines are >80 columns wide, but that's only because
breaking the strings narrower makes this chunk look even worse! */
static const char * const helptext[]={
"Usage: curl [options...] <url>",
"Options: (H) means HTTP/HTTPS only, (F) means FTP only",
@ -1854,7 +1863,8 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
break;
case 'x': /* --krb */
/* kerberos level string */
if(curlinfo->features & (CURL_VERSION_KERBEROS4 | CURL_VERSION_GSSNEGOTIATE))
if(curlinfo->features & (CURL_VERSION_KERBEROS4 |
CURL_VERSION_GSSNEGOTIATE))
GetStr(&config->krblevel, nextarg);
else
return PARAM_LIBCURL_DOESNT_SUPPORT;
@ -3016,41 +3026,56 @@ static size_t my_fwrite(void *buffer, size_t sz, size_t nmemb, void *stream)
}
struct InStruct {
FILE *stream;
int fd;
struct Configurable *config;
};
#if 1
static curlioerr my_ioctl(CURL *handle, curliocmd cmd, void *userp)
{
struct InStruct *in=(struct InStruct *)userp;
(void)handle; /* not used in here */
#define MAX_SEEK 2147483647
switch(cmd) {
case CURLIOCMD_RESTARTREAD:
/* mr libcurl kindly asks as to rewind the read data stream to start */
if(-1 == fseek(in->stream, 0, SEEK_SET))
/* couldn't rewind, the reason is in errno but errno is just not
portable enough and we don't actually care that much why we failed. */
return CURLIOE_FAILRESTART;
break;
default: /* ignore unknown commands */
return CURLIOE_UNKNOWNCMD;
}
return CURLIOE_OK;
}
#else
#ifndef SIZEOF_OFF_T
/* (Jan 11th 2008) this is a reasonably new define in the config.h so there
might be older handicrafted configs that don't define it properly and then
we assume 32bit off_t */
#define SIZEOF_OFF_T 4
#endif
/*
* my_seek() is the CURLOPT_SEEKFUNCTION we use
*/
static int my_seek(void *stream, curl_off_t offset, int whence)
{
struct InStruct *in=(struct InStruct *)stream;
/* We can't use fseek() here since it can't do 64bit seeks on Windows and
possibly elsewhere. We need to switch to the lseek family of tricks. For
that to work, we need to switch from fread() to plain read() etc */
#if (SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(lseek)
/* The sizeof check following here is only interesting if curl_off_t is
larger than off_t, but also not on windows-like systems for which lseek
is a defined macro that works around the 32bit off_t-problem and thus do
64bit seeks correctly anyway */
if(-1 == fseek(in->stream, (off_t)offset, whence))
if(offset > MAX_SEEK) {
/* Some precaution code to work around problems with different data sizes
to allow seeking >32bit even if off_t is 32bit. Should be very rare and
is really valid on weirdo-systems. */
curl_off_t left = offset;
if(whence != SEEK_SET)
/* this code path doesn't support other types */
return 1;
if(-1 == lseek(in->fd, 0, SEEK_SET))
/* couldn't rewind to beginning */
return 1;
while(left) {
long step = (left>MAX_SEEK ? MAX_SEEK : (long)left);
if(-1 == lseek(in->fd, step, SEEK_CUR))
/* couldn't seek forwards the desired amount */
return 1;
left -= step;
}
return 0;
}
#endif
if(-1 == lseek(in->fd, offset, whence))
/* couldn't rewind, the reason is in errno but errno is just not
portable enough and we don't actually care that much why we failed. */
return 1;
@ -3058,15 +3083,16 @@ static int my_seek(void *stream, curl_off_t offset, int whence)
return 0;
}
#endif
static size_t my_fread(void *buffer, size_t sz, size_t nmemb, void *userp)
{
size_t rc;
ssize_t rc;
struct InStruct *in=(struct InStruct *)userp;
rc = fread(buffer, sz, nmemb, in->stream);
return rc;
rc = read(in->fd, buffer, sz*nmemb);
if(rc < 0)
/* since size_t is unsigned we can't return negative values fine */
return 0;
return (size_t)rc;
}
struct ProgressData {
@ -3689,8 +3715,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
int infilenum;
char *uploadfile=NULL; /* a single file, never a glob */
FILE *infd = stdin;
bool infdfopen;
int infd = STDIN_FILENO;
bool infdopen;
FILE *headerfilep = NULL;
curl_off_t uploadfilesize; /* -1 means unknown */
bool stillflags=TRUE;
@ -4112,7 +4138,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
outs.stream = NULL; /* open when needed */
}
}
infdfopen=FALSE;
infdopen=FALSE;
if(uploadfile && !curlx_strequal(uploadfile, "-")) {
/*
* We have specified a file to upload and it isn't "-".
@ -4180,11 +4206,11 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
* to be considered with one appended if implied CC
*/
infd=(FILE *) fopen(uploadfile, "rb");
if (!infd || stat(uploadfile, &fileinfo)) {
infd= open(uploadfile, O_RDONLY | O_BINARY);
if ((infd == -1) || stat(uploadfile, &fileinfo)) {
helpf("Can't open '%s'!\n", uploadfile);
if(infd)
fclose(infd);
if(infd != -1)
close(infd);
/* Free the list of remaining URLs and globbed upload files
* to force curl to exit immediately
@ -4201,13 +4227,13 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
res = CURLE_READ_ERROR;
goto quit_urls;
}
infdfopen=TRUE;
infdopen=TRUE;
uploadfilesize=fileinfo.st_size;
}
else if(uploadfile && curlx_strequal(uploadfile, "-")) {
SET_BINMODE(stdin);
infd = stdin;
infd = STDIN_FILENO;
}
if(uploadfile && config->resume_from_current)
@ -4269,8 +4295,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
config->errors = stderr;
if(!outfile && !(config->conf & CONF_GETTEXT)) {
/* We get the output to stdout and we have not got the ASCII/text flag,
then set stdout to be binary */
/* We get the output to stdout and we have not got the ASCII/text
flag, then set stdout to be binary */
SET_BINMODE(stdout);
}
@ -4283,23 +4309,16 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
my_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
/* for uploads */
input.stream = infd;
input.fd = infd;
input.config = config;
my_setopt(curl, CURLOPT_READDATA, &input);
/* what call to read */
my_setopt(curl, CURLOPT_READFUNCTION, my_fread);
#if 1
/* the ioctl function is at this point only used to rewind files
that are posted when using NTLM etc */
my_setopt(curl, CURLOPT_IOCTLDATA, &input);
my_setopt(curl, CURLOPT_IOCTLFUNCTION, my_ioctl);
#else
/* in 7.18.0, the SEEKFUNCTION/DATA pair is taking over what IOCTL*
previously provided for seeking */
/* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
my_setopt(curl, CURLOPT_SEEKDATA, &input);
my_setopt(curl, CURLOPT_SEEKFUNCTION, my_seek);
#endif
if(config->recvpersecond)
/* tell libcurl to use a smaller sized buffer as it allows us to
@ -4371,7 +4390,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
my_setopt(curl, CURLOPT_SSLKEYTYPE, config->key_type);
my_setopt(curl, CURLOPT_KEYPASSWD, config->key_passwd);
/* SSH private key uses the same command-line option as SSL private key */
/* SSH private key uses the same command-line option as SSL private
key */
my_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
my_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
@ -4780,8 +4800,8 @@ quit_urls:
if(outfile)
free(outfile);
if(infdfopen)
fclose(infd);
if(infdopen)
close(infd);
} /* loop to the next URL */