1
0
mirror of https://github.com/moparisthebest/curl synced 2025-02-28 17:31:46 -05:00

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
parent 8df7e0bdba
commit e2c817731a
3 changed files with 87 additions and 57 deletions

View File

@ -6,6 +6,15 @@
Changelog 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) Daniel S (10 Jan 2008)
- Michal Marek made curl-config --libs not include /usr/lib64 in the output - 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 (it already before skipped /usr/lib). /usr/lib64 is the default library

View File

@ -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 # This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms # 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(size_t)
AC_CHECK_SIZEOF(long) AC_CHECK_SIZEOF(long)
AC_CHECK_SIZEOF(time_t) AC_CHECK_SIZEOF(time_t)
AC_CHECK_SIZEOF(off_t)
AC_CHECK_TYPE(long long, AC_CHECK_TYPE(long long,
[AC_DEFINE(HAVE_LONGLONG, 1, [if your compiler supports long long])] [AC_DEFINE(HAVE_LONGLONG, 1, [if your compiler supports long long])]

View File

@ -127,6 +127,12 @@
#define SET_BINMODE(file) ((void)0) #define SET_BINMODE(file) ((void)0)
#endif #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 #ifdef MSDOS
#include <dos.h> #include <dos.h>
@ -201,6 +207,7 @@ typedef enum {
/* Support uploading and resuming of >2GB files /* Support uploading and resuming of >2GB files
*/ */
#if defined(WIN32) && (SIZEOF_CURL_OFF_T > 4) #if defined(WIN32) && (SIZEOF_CURL_OFF_T > 4)
#define lseek(x,y,z) _lseeki64(x, y, z)
#define struct_stat struct _stati64 #define struct_stat struct _stati64
#define stat(file,st) _stati64(file,st) #define stat(file,st) _stati64(file,st)
#else #else
@ -605,6 +612,8 @@ struct getout {
static void help(void) static void help(void)
{ {
int i; 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[]={ static const char * const helptext[]={
"Usage: curl [options...] <url>", "Usage: curl [options...] <url>",
"Options: (H) means HTTP/HTTPS only, (F) means FTP only", "Options: (H) means HTTP/HTTPS only, (F) means FTP only",
@ -1854,7 +1863,8 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
break; break;
case 'x': /* --krb */ case 'x': /* --krb */
/* kerberos level string */ /* 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); GetStr(&config->krblevel, nextarg);
else else
return PARAM_LIBCURL_DOESNT_SUPPORT; 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 { struct InStruct {
FILE *stream; int fd;
struct Configurable *config; struct Configurable *config;
}; };
#if 1 #define MAX_SEEK 2147483647
static curlioerr my_ioctl(CURL *handle, curliocmd cmd, void *userp)
{
struct InStruct *in=(struct InStruct *)userp;
(void)handle; /* not used in here */
switch(cmd) { #ifndef SIZEOF_OFF_T
case CURLIOCMD_RESTARTREAD: /* (Jan 11th 2008) this is a reasonably new define in the config.h so there
/* mr libcurl kindly asks as to rewind the read data stream to start */ might be older handicrafted configs that don't define it properly and then
if(-1 == fseek(in->stream, 0, SEEK_SET)) we assume 32bit off_t */
/* couldn't rewind, the reason is in errno but errno is just not #define SIZEOF_OFF_T 4
portable enough and we don't actually care that much why we failed. */ #endif
return CURLIOE_FAILRESTART; /*
* my_seek() is the CURLOPT_SEEKFUNCTION we use
break; */
default: /* ignore unknown commands */
return CURLIOE_UNKNOWNCMD;
}
return CURLIOE_OK;
}
#else
static int my_seek(void *stream, curl_off_t offset, int whence) static int my_seek(void *stream, curl_off_t offset, int whence)
{ {
struct InStruct *in=(struct InStruct *)stream; struct InStruct *in=(struct InStruct *)stream;
/* We can't use fseek() here since it can't do 64bit seeks on Windows and #if (SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(lseek)
possibly elsewhere. We need to switch to the lseek family of tricks. For /* The sizeof check following here is only interesting if curl_off_t is
that to work, we need to switch from fread() to plain read() etc */ 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 /* 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. */ portable enough and we don't actually care that much why we failed. */
return 1; return 1;
@ -3058,15 +3083,16 @@ static int my_seek(void *stream, curl_off_t offset, int whence)
return 0; return 0;
} }
#endif
static size_t my_fread(void *buffer, size_t sz, size_t nmemb, void *userp) 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; struct InStruct *in=(struct InStruct *)userp;
rc = fread(buffer, sz, nmemb, in->stream); rc = read(in->fd, buffer, sz*nmemb);
return rc; if(rc < 0)
/* since size_t is unsigned we can't return negative values fine */
return 0;
return (size_t)rc;
} }
struct ProgressData { struct ProgressData {
@ -3689,8 +3715,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
int infilenum; int infilenum;
char *uploadfile=NULL; /* a single file, never a glob */ char *uploadfile=NULL; /* a single file, never a glob */
FILE *infd = stdin; int infd = STDIN_FILENO;
bool infdfopen; bool infdopen;
FILE *headerfilep = NULL; FILE *headerfilep = NULL;
curl_off_t uploadfilesize; /* -1 means unknown */ curl_off_t uploadfilesize; /* -1 means unknown */
bool stillflags=TRUE; bool stillflags=TRUE;
@ -4112,7 +4138,7 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
outs.stream = NULL; /* open when needed */ outs.stream = NULL; /* open when needed */
} }
} }
infdfopen=FALSE; infdopen=FALSE;
if(uploadfile && !curlx_strequal(uploadfile, "-")) { if(uploadfile && !curlx_strequal(uploadfile, "-")) {
/* /*
* We have specified a file to upload and it isn't "-". * 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 * to be considered with one appended if implied CC
*/ */
infd=(FILE *) fopen(uploadfile, "rb"); infd= open(uploadfile, O_RDONLY | O_BINARY);
if (!infd || stat(uploadfile, &fileinfo)) { if ((infd == -1) || stat(uploadfile, &fileinfo)) {
helpf("Can't open '%s'!\n", uploadfile); helpf("Can't open '%s'!\n", uploadfile);
if(infd) if(infd != -1)
fclose(infd); close(infd);
/* Free the list of remaining URLs and globbed upload files /* Free the list of remaining URLs and globbed upload files
* to force curl to exit immediately * to force curl to exit immediately
@ -4201,13 +4227,13 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
res = CURLE_READ_ERROR; res = CURLE_READ_ERROR;
goto quit_urls; goto quit_urls;
} }
infdfopen=TRUE; infdopen=TRUE;
uploadfilesize=fileinfo.st_size; uploadfilesize=fileinfo.st_size;
} }
else if(uploadfile && curlx_strequal(uploadfile, "-")) { else if(uploadfile && curlx_strequal(uploadfile, "-")) {
SET_BINMODE(stdin); SET_BINMODE(stdin);
infd = stdin; infd = STDIN_FILENO;
} }
if(uploadfile && config->resume_from_current) if(uploadfile && config->resume_from_current)
@ -4269,8 +4295,8 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
config->errors = stderr; config->errors = stderr;
if(!outfile && !(config->conf & CONF_GETTEXT)) { if(!outfile && !(config->conf & CONF_GETTEXT)) {
/* We get the output to stdout and we have not got the ASCII/text flag, /* We get the output to stdout and we have not got the ASCII/text
then set stdout to be binary */ flag, then set stdout to be binary */
SET_BINMODE(stdout); SET_BINMODE(stdout);
} }
@ -4283,23 +4309,16 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
my_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite); my_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
/* for uploads */ /* for uploads */
input.stream = infd; input.fd = infd;
input.config = config; input.config = config;
my_setopt(curl, CURLOPT_READDATA, &input); my_setopt(curl, CURLOPT_READDATA, &input);
/* what call to read */ /* what call to read */
my_setopt(curl, CURLOPT_READFUNCTION, my_fread); my_setopt(curl, CURLOPT_READFUNCTION, my_fread);
#if 1 /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
/* the ioctl function is at this point only used to rewind files CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
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 */
my_setopt(curl, CURLOPT_SEEKDATA, &input); my_setopt(curl, CURLOPT_SEEKDATA, &input);
my_setopt(curl, CURLOPT_SEEKFUNCTION, my_seek); my_setopt(curl, CURLOPT_SEEKFUNCTION, my_seek);
#endif
if(config->recvpersecond) if(config->recvpersecond)
/* tell libcurl to use a smaller sized buffer as it allows us to /* 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_SSLKEYTYPE, config->key_type);
my_setopt(curl, CURLOPT_KEYPASSWD, config->key_passwd); 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_PRIVATE_KEYFILE, config->key);
my_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey); my_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
@ -4780,8 +4800,8 @@ quit_urls:
if(outfile) if(outfile)
free(outfile); free(outfile);
if(infdfopen) if(infdopen)
fclose(infd); close(infd);
} /* loop to the next URL */ } /* loop to the next URL */