diff --git a/CHANGES b/CHANGES index a9b86d674..032aac0a0 100644 --- a/CHANGES +++ b/CHANGES @@ -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 diff --git a/configure.ac b/configure.ac index c8a4ed3c4..58a3a9a78 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2008, Daniel Stenberg, , 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])] diff --git a/src/main.c b/src/main.c index 2b6cf4ab8..7801c345f 100644 --- a/src/main.c +++ b/src/main.c @@ -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 @@ -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...] ", "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 */