curl-library
Re: FTP large file support patch
Date: Sun, 21 Dec 2003 11:44:36 -0500
As for the name, I would suggest something more descriptive like
appending _64BIT rather than _BIG or _NEW. Sometime in the future there
will be another _BIG or _NEW.
Dave Meyer wrote:
>>Here's where I would like to chime in! I would rather have new options that
>>...
>>
>> CURLOPT_RESUME_FROM
>> CURLOPT_INFILESIZE
>> CURLOPT_MAXFILESIZE
>> CURLOPT_PROGRESSFUNCTION (the new version of this would take a function
>> pointer to a function that accepts off_t arguments for the sizes).
>>
>>Perhaps appending "_BIG" is fine? Or "_NEW"?
>>
>>I would also like to see the 'off_t' handling get its own CURLOPTTYPE in the
>>curl.h file (similar to how CURLOPTTYPE_OBJECTPOINT is used etc) so that it
>>...
>>
>>
>
>Here's the new patch.
>
>I've changed the original CURLOPT_xxx values back to using longs, and
>added new CURLOPT_xxx_BIG versions which take off_t's. Internally, the
>library always uses off_t's, since those can hold longs without any
>difficulty (unless there's some system out there that has smaller than
>4-byte file offsets...). I've updated the documentation for the originals
>back to what they were, and added documentation for the new values. I
>didn't document anything about the originals being deprecated, though -- I
>don't know whether you were just speculating or not when you mentioned
>that.
>
>I also added the CURLOPTTYPE_OFF_T, and added the _BIG options in as that
>type. This allowed me to clean up my changes to easy.c, so they match the
>existing checks for parameter type.
>
>The one thing I did *not* do was the changes for CURLOPT_PROGRESSFUNCTION.
>The current progress function takes doubles (or, rather, that's how its
>prototype is written), which are already large enough to hold 64-bit
>integer values (with some slight loss of precision, of course). Thus, I
>didn't add a new one that took off_t's, since it looked like the current
>function would work properly with off_t's to begin with.
>
>Perhaps I misunderstood your reasoning for having a new progress function,
>or maybe I misread; if so, please let me know, and I can address that. :)
>
>Thanks,
>
>Dave
>
>
>------------------------------------------------------------------------
>
>diff -ur curl-7.10.8.orig/docs/examples/ftpupload.c curl-7.10.8.large_ftp/docs/examples/ftpupload.c
>--- curl-7.10.8.orig/docs/examples/ftpupload.c Mon Mar 17 04:38:08 2003
>+++ curl-7.10.8.large_ftp/docs/examples/ftpupload.c Wed Dec 10 10:43:03 2003
>@@ -73,7 +73,7 @@
> curl_easy_setopt(curl, CURLOPT_INFILE, hd_src);
>
> /* and give the size of the upload (optional) */
>- curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_info.st_size);
>+ curl_easy_setopt(curl, CURLOPT_INFILESIZE_BIG, file_info.st_size);
>
> /* Now run off and do what you've been told! */
> res = curl_easy_perform(curl);
>diff -ur curl-7.10.8.orig/docs/examples/httpput.c curl-7.10.8.large_ftp/docs/examples/httpput.c
>--- curl-7.10.8.orig/docs/examples/httpput.c Tue Sep 3 04:43:32 2002
>+++ curl-7.10.8.large_ftp/docs/examples/httpput.c Wed Dec 10 10:43:18 2003
>@@ -85,7 +85,7 @@
> curl_easy_setopt(curl, CURLOPT_INFILE, hd_src);
>
> /* and give the size of the upload (optional) */
>- curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_info.st_size);
>+ curl_easy_setopt(curl, CURLOPT_INFILESIZE_BIG, file_info.st_size);
>
> /* Now run off and do what you've been told! */
> res = curl_easy_perform(curl);
>diff -ur curl-7.10.8.orig/docs/libcurl/curl_easy_setopt.3 curl-7.10.8.large_ftp/docs/libcurl/curl_easy_setopt.3
>--- curl-7.10.8.orig/docs/libcurl/curl_easy_setopt.3 Sat Oct 18 04:54:19 2003
>+++ curl-7.10.8.large_ftp/docs/libcurl/curl_easy_setopt.3 Wed Dec 10 13:00:29 2003
>@@ -425,7 +425,7 @@
> .TP
> .B CURLOPT_PUT
> A non-zero parameter tells the library to use HTTP PUT to transfer data. The
>-data should be set with CURLOPT_READDATA and CURLOPT_INFILESIZE.
>+data should be set with CURLOPT_READDATA and CURLOPT_INFILESIZE_BIG.
> .TP
> .B CURLOPT_POST
> A non-zero parameter tells the library to do a regular HTTP post. This is a
>@@ -682,7 +682,11 @@
> techniques).
> .TP
> .B CURLOPT_RESUME_FROM
>-Pass a long as parameter. It contains the offset in number of bytes that you
>+Pass a long as a parameter. It contains the offset in number of bytes that you
>+want the transfer to start from.
>+.TP
>+.B CURLOPT_RESUME_FROM_BIG
>+Pass an off_t as a parameter. It contains the offset in number of bytes that you
> want the transfer to start from.
> .TP
> .B CURLOPT_CUSTOMREQUEST
>@@ -714,14 +718,29 @@
> .TP
> .B CURLOPT_INFILESIZE
> When uploading a file to a remote site, this option should be used to tell
>-libcurl what the expected size of the infile is.
>+libcurl what the expected size of the infile is. This value should be
>+passed as a long.
>+.TP
>+.B CURLOPT_INFILESIZE_BIG
>+When uploading a file to a remote site, this option should be used to tell
>+libcurl what the expected size of the infile is. This value should be
>+passed as an off_t.
> .TP
> .B CURLOPT_UPLOAD
> A non-zero parameter tells the library to prepare for an upload. The
>-CURLOPT_READDATA and CURLOPT_INFILESIZE are also interesting for uploads.
>+CURLOPT_READDATA and CURLOPT_INFILESIZE_BIG are also interesting for uploads.
> .TP
> .B CURLOPT_MAXFILESIZE
>-Pass a long as parameter. This allows you to specify the maximum size (in
>+Pass a long as a parameter. This allows you to specify the maximum size (in
>+bytes) of a file to download. If the file requested is larger than this value,
>+the transfer will not start and CURLE_FILESIZE_EXCEEDED will be returned.
>+
>+NOTE: The file size is not always known prior to download, and for such files
>+this option has no effect even if the file transfer ends up being larger than
>+this given limit. This concerns both FTP and HTTP transfers.
>+.TP
>+.B CURLOPT_MAXFILESIZE_BIG
>+Pass an off_t as a parameter. This allows you to specify the maximum size (in
> bytes) of a file to download. If the file requested is larger than this value,
> the transfer will not start and CURLE_FILESIZE_EXCEEDED will be returned.
>
>diff -ur curl-7.10.8.orig/docs/libcurl/curl_easy_setopt.html curl-7.10.8.large_ftp/docs/libcurl/curl_easy_setopt.html
>--- curl-7.10.8.orig/docs/libcurl/curl_easy_setopt.html Sat Oct 18 05:01:53 2003
>+++ curl-7.10.8.large_ftp/docs/libcurl/curl_easy_setopt.html Wed Dec 10 12:58:47 2003
>@@ -505,7 +505,7 @@
> <B>CURLOPT_PUT</B>
> A non-zero parameter tells the library to use HTTP PUT
> to transfer data. The data should be set with CUR-
>- LOPT_READDATA and CURLOPT_INFILESIZE.
>+ LOPT_READDATA and CURLOPT_INFILESIZE_BIG.
>
> <B>CURLOPT_POST</B>
> A non-zero parameter tells the library to do a regular
>@@ -803,7 +803,12 @@
> techniques).
>
> <B>CURLOPT_RESUME_FROM</B>
>- Pass a long as parameter. It contains the offset in
>+ Pass a long as a parameter. It contains the offset in
>+ number of bytes that you want the transfer to start
>+ from.
>+
>+ <B>CURLOPT_RESUME_FROM_BIG</B>
>+ Pass an off_t as a parameter. It contains the offset in
> number of bytes that you want the transfer to start
> from.
>
>@@ -846,11 +851,17 @@
> <B>CURLOPT_INFILESIZE</B>
> When uploading a file to a remote site, this option
> should be used to tell libcurl what the expected size
>- of the infile is.
>+ of the infile is. The size should be passed as a long.
>+
>+ <B>CURLOPT_INFILESIZE_BIG</B>
>+ When uploading a file to a remote site, this option
>+ should be used to tell libcurl what the expected size
>+ of the infile is. The size should be passed as an
>+ off_t.
>
> <B>CURLOPT_UPLOAD</B>
> A non-zero parameter tells the library to prepare for
>- an upload. The CURLOPT_READDATA and CURLOPT_INFILESIZE
>+ an upload. The CURLOPT_READDATA and CURLOPT_INFILESIZE_BIG
> are also interesting for uploads.
> Pass a long as parameter. This allows you to specify
> the maximum size (in bytes) of a file to download. If
>diff -ur curl-7.10.8.orig/docs/libcurl-the-guide curl-7.10.8.large_ftp/docs/libcurl-the-guide
>--- curl-7.10.8.orig/docs/libcurl-the-guide Thu Dec 19 07:22:36 2002
>+++ curl-7.10.8.large_ftp/docs/libcurl-the-guide Wed Dec 10 12:54:52 2003
>@@ -298,9 +298,9 @@
>
> A few protocols won't behave properly when uploads are done without any prior
> knowledge of the expected file size. So, set the upload file size using the
>- CURLOPT_INFILESIZE for all known file sizes like this[1]:
>+ CURLOPT_INFILESIZE_BIG for all known file sizes like this[1]:
>
>- curl_easy_setopt(easyhandle, CURLOPT_INFILESIZE, file_size);
>+ curl_easy_setopt(easyhandle, CURLOPT_INFILESIZE_BIG, file_size);
>
> When you call curl_easy_perform() this time, it'll perform all the necessary
> operations and when it has invoked the upload it'll call your supplied
>diff -ur curl-7.10.8.orig/include/curl/curl.h curl-7.10.8.large_ftp/include/curl/curl.h
>--- curl-7.10.8.orig/include/curl/curl.h Sat Nov 1 03:25:51 2003
>+++ curl-7.10.8.large_ftp/include/curl/curl.h Wed Dec 10 10:35:53 2003
>@@ -262,6 +262,7 @@
> #define CURLOPTTYPE_LONG 0
> #define CURLOPTTYPE_OBJECTPOINT 10000
> #define CURLOPTTYPE_FUNCTIONPOINT 20000
>+#define CURLOPTTYPE_OFF_T 30000
>
> /* name is uppercase CURLOPT_<name>,
> type is one of the defined CURLOPTTYPE_<type>
>@@ -292,6 +293,7 @@
> #define LONG CURLOPTTYPE_LONG
> #define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT
> #define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
>+#define OFF_T CURLOPTTYPE_OFF_T
> #define CINIT(name,type,number) CURLOPT_/**/name = type + number
> #endif
>
>@@ -348,7 +350,12 @@
> /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about
> * how large the file being sent really is. That allows better error
> * checking and better verifies that the upload was succcessful. -1 means
>- * unknown size. */
>+ * unknown size.
>+ *
>+ * For large file support, there is also a _BIG version of the key
>+ * which takes an off_t type, allowing platforms with larger off_t
>+ * sizes to handle larger files. See below for INFILESIZE_BIG.
>+ */
> CINIT(INFILESIZE, LONG, 14),
>
> /* POST input fields. */
>@@ -376,7 +383,12 @@
> /* Set the "low speed time" */
> CINIT(LOW_SPEED_TIME, LONG, 20),
>
>- /* Set the continuation offset */
>+ /* Set the continuation offset.
>+ *
>+ * Note there is also a _BIG version of this key which uses
>+ * off_t types, allowing for large file offsets on platforms which
>+ * use larger-than-32-bit off_t's. Look below for RESUME_FROM_BIG.
>+ */
> CINIT(RESUME_FROM, LONG, 21),
>
> /* Set cookie in request: */
>@@ -691,8 +703,26 @@
> CINIT(IPRESOLVE, LONG, 113),
>
> /* Set this option to limit the size of a file that will be downloaded from
>- an HTTP or FTP server. */
>+ an HTTP or FTP server.
>+
>+ Note there is also _BIG version which adds large file support for
>+ platforms which have larger off_t sizes. See MAXFILESIZE_BIG below. */
> CINIT(MAXFILESIZE, LONG, 114),
>+
>+ /* See the comment for INFILESIZE above, but in short, specifies
>+ * the size of the file being uploaded. -1 means unknown.
>+ */
>+ CINIT(INFILESIZE_BIG, OFF_T, 115),
>+
>+ /* Sets the continuation offset. There is also a LONG version of this;
>+ * look above for RESUME_FROM.
>+ */
>+ CINIT(RESUME_FROM_BIG, OFF_T, 116),
>+
>+ /* Sets the maximum size of data that will be downloaded from
>+ * an HTTP or FTP server. See MAXFILESIZE above for the LONG version.
>+ */
>+ CINIT(MAXFILESIZE_BIG, OFF_T, 117),
>
> CURLOPT_LASTENTRY /* the last unused */
> } CURLoption;
>diff -ur curl-7.10.8.orig/lib/dict.c curl-7.10.8.large_ftp/lib/dict.c
>--- curl-7.10.8.orig/lib/dict.c Wed Oct 15 13:35:34 2003
>+++ curl-7.10.8.large_ftp/lib/dict.c Wed Dec 10 09:49:23 2003
>@@ -91,7 +91,7 @@
> struct SessionHandle *data=conn->data;
>
> char *path = conn->path;
>- long *bytecount = &conn->bytecount;
>+ off_t *bytecount = &conn->bytecount;
>
> if(conn->bits.user_passwd) {
> /* AUTH is missing */
>diff -ur curl-7.10.8.orig/lib/easy.c curl-7.10.8.large_ftp/lib/easy.c
>--- curl-7.10.8.orig/lib/easy.c Wed Oct 15 13:35:34 2003
>+++ curl-7.10.8.large_ftp/lib/easy.c Wed Dec 10 10:41:04 2003
>@@ -202,6 +202,7 @@
> func_T param_func = (func_T)0;
> long param_long = 0;
> void *param_obj = NULL;
>+ off_t param_offset = 0;
> struct SessionHandle *data = curl;
> CURLcode ret=CURLE_FAILED_INIT;
>
>@@ -224,9 +225,14 @@
> param_obj = va_arg(arg, void *);
> ret = Curl_setopt(data, tag, param_obj);
> }
>- else {
>+ else if(tag < CURLOPTTYPE_OFF_T) {
>+ /* This is a function pointer type */
> param_func = va_arg(arg, func_T );
> ret = Curl_setopt(data, tag, param_func);
>+ } else {
>+ /* This is an off_t type */
>+ param_offset = va_arg(arg, off_t);
>+ ret = Curl_setopt(data, tag, param_offset);
> }
>
> va_end(arg);
>diff -ur curl-7.10.8.orig/lib/file.c curl-7.10.8.large_ftp/lib/file.c
>--- curl-7.10.8.orig/lib/file.c Fri Oct 31 13:18:01 2003
>+++ curl-7.10.8.large_ftp/lib/file.c Wed Dec 10 09:49:23 2003
>@@ -163,12 +163,12 @@
> */
> CURLcode res = CURLE_OK;
> struct stat statbuf;
>- unsigned long expected_size=0;
>+ off_t expected_size=0;
> bool fstated=FALSE;
> ssize_t nread;
> struct SessionHandle *data = conn->data;
> char *buf = data->state.buffer;
>- int bytecount = 0;
>+ off_t bytecount = 0;
> struct timeval start = Curl_tvnow();
> struct timeval now = start;
> int fd;
>@@ -188,7 +188,7 @@
> date. */
> if(data->set.no_body && data->set.include_header && fstated) {
> CURLcode result;
>- sprintf(buf, "Content-Length: %lu\r\n", expected_size);
>+ sprintf(buf, "Content-Length: %lld\r\n", expected_size);
> result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
> if(result)
> return result;
>@@ -217,7 +217,7 @@
> }
>
> /* Added by Dolbneff A.V & Spiridonoff A.V */
>- if (conn->resume_from <= (long)expected_size)
>+ if (conn->resume_from <= expected_size)
> expected_size -= conn->resume_from;
> else
> /* Is this error code suitable in such situation? */
>diff -ur curl-7.10.8.orig/lib/ftp.c curl-7.10.8.large_ftp/lib/ftp.c
>--- curl-7.10.8.orig/lib/ftp.c Fri Oct 31 13:36:43 2003
>+++ curl-7.10.8.large_ftp/lib/ftp.c Wed Dec 10 13:06:06 2003
>@@ -283,9 +283,16 @@
> */
> if(ftp->cache) {
> /* we had data in the "cache", copy that instead of doing an actual
>- read */
>- memcpy(ptr, ftp->cache, ftp->cache_size);
>- gotbytes = ftp->cache_size;
>+ * read
>+ *
>+ * Dave Meyer, December 2003:
>+ * ftp->cache_size is cast to int here. This should be safe,
>+ * because it would have been populated with something of size
>+ * int to begin with, even though its datatype may be larger
>+ * than an int.
>+ */
>+ memcpy(ptr, ftp->cache, (int)ftp->cache_size);
>+ gotbytes = (int)ftp->cache_size;
> free(ftp->cache); /* free the cache */
> ftp->cache = NULL; /* clear the pointer */
> ftp->cache_size = 0; /* zero the size just in case */
>@@ -363,9 +370,9 @@
> already! Cleverly figured out by Eric Lavigne in December
> 2001. */
> ftp->cache_size = gotbytes - i;
>- ftp->cache = (char *)malloc(ftp->cache_size);
>+ ftp->cache = (char *)malloc((int)ftp->cache_size);
> if(ftp->cache)
>- memcpy(ftp->cache, line_start, ftp->cache_size);
>+ memcpy(ftp->cache, line_start, (int)ftp->cache_size);
> else
> return CURLE_OUT_OF_MEMORY; /**BANG**/
> }
>@@ -635,7 +642,7 @@
> if((-1 != data->set.infilesize) &&
> (data->set.infilesize != *ftp->bytecountp) &&
> !data->set.crlf) {
>- failf(data, "Uploaded unaligned file size (%d out of %d bytes)",
>+ failf(data, "Uploaded unaligned file size (%lld out of %lld bytes)",
> *ftp->bytecountp, data->set.infilesize);
> return CURLE_PARTIAL_FILE;
> }
>@@ -643,7 +650,8 @@
> else {
> if((-1 != conn->size) && (conn->size != *ftp->bytecountp) &&
> (conn->maxdownload != *ftp->bytecountp)) {
>- failf(data, "Received only partial file: %d bytes", *ftp->bytecountp);
>+ failf(data, "Received only partial file: %lld bytes",
>+ *ftp->bytecountp);
> return CURLE_PARTIAL_FILE;
> }
> else if(!ftp->dont_check &&
>@@ -831,7 +839,7 @@
>
> static
> CURLcode ftp_getsize(struct connectdata *conn, char *file,
>- ssize_t *size)
>+ off_t *size)
> {
> struct SessionHandle *data = conn->data;
> int ftpcode;
>@@ -846,7 +854,7 @@
>
> if(ftpcode == 213) {
> /* get the size from the ascii string: */
>- *size = atoi(buf+4);
>+ *size = strtoll(buf+4, NULL, 0);
> }
> else
> return CURLE_FTP_COULDNT_GET_SIZE;
>@@ -1569,7 +1577,7 @@
>
> /* the ftp struct is already inited in Curl_ftp_connect() */
> struct FTP *ftp = conn->proto.ftp;
>- long *bytecountp = ftp->bytecountp;
>+ off_t *bytecountp = ftp->bytecountp;
>
> if(data->set.upload) {
>
>@@ -1601,7 +1609,7 @@
> if(conn->resume_from < 0 ) {
> /* we could've got a specified offset from the command line,
> but now we know we didn't */
>- ssize_t gottensize;
>+ off_t gottensize;
>
> if(CURLE_OK != ftp_getsize(conn, ftp->file, &gottensize)) {
> failf(data, "Couldn't get remote file size");
>@@ -1612,7 +1620,7 @@
>
> if(conn->resume_from) {
> /* do we still game? */
>- int passed=0;
>+ off_t passed=0;
> /* enable append instead */
> data->set.ftp_append = 1;
>
>@@ -1620,19 +1628,19 @@
> input. If we knew it was a proper file we could've just
> fseek()ed but we only have a stream here */
> do {
>- int readthisamountnow = (conn->resume_from - passed);
>- int actuallyread;
>+ off_t readthisamountnow = (conn->resume_from - passed);
>+ off_t actuallyread;
>
> if(readthisamountnow > BUFSIZE)
> readthisamountnow = BUFSIZE;
>
> actuallyread =
>- conn->fread(data->state.buffer, 1, readthisamountnow,
>+ conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
> conn->fread_in);
>
> passed += actuallyread;
> if(actuallyread != readthisamountnow) {
>- failf(data, "Could only read %d bytes from the input", passed);
>+ failf(data, "Could only read %lld bytes from the input", passed);
> return CURLE_FTP_COULDNT_USE_REST;
> }
> }
>@@ -1690,7 +1698,7 @@
> /* When we know we're uploading a specified file, we can get the file
> size prior to the actual upload. */
>
>- Curl_pgrsSetUploadSize(data, data->set.infilesize);
>+ Curl_pgrsSetUploadSize(data, (double)data->set.infilesize);
>
> result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
> conn->secondarysocket, bytecountp);
>@@ -1701,18 +1709,18 @@
> else if(!data->set.no_body) {
> /* Retrieve file or directory */
> bool dirlist=FALSE;
>- long downloadsize=-1;
>+ off_t downloadsize=-1;
>
> if(conn->bits.use_range && conn->range) {
>- long from, to;
>- int totalsize=-1;
>+ off_t from, to;
>+ off_t totalsize=-1;
> char *ptr;
> char *ptr2;
>
>- from=strtol(conn->range, &ptr, 0);
>+ from=strtoll(conn->range, &ptr, 0);
> while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
> ptr++;
>- to=strtol(ptr, &ptr2, 0);
>+ to=strtoll(ptr, &ptr2, 0);
> if(ptr == ptr2) {
> /* we didn't get any digit */
> to=-1;
>@@ -1720,24 +1728,24 @@
> if((-1 == to) && (from>=0)) {
> /* X - */
> conn->resume_from = from;
>- infof(data, "FTP RANGE %d to end of file\n", from);
>+ infof(data, "FTP RANGE %lld to end of file\n", from);
> }
> else if(from < 0) {
> /* -Y */
> totalsize = -from;
> conn->maxdownload = -from;
> conn->resume_from = from;
>- infof(data, "FTP RANGE the last %d bytes\n", totalsize);
>+ infof(data, "FTP RANGE the last %lld bytes\n", totalsize);
> }
> else {
> /* X-Y */
> totalsize = to-from;
> conn->maxdownload = totalsize+1; /* include the last mentioned byte */
> conn->resume_from = from;
>- infof(data, "FTP RANGE from %d getting %d bytes\n", from,
>+ infof(data, "FTP RANGE from %lld getting %lld bytes\n", from,
> conn->maxdownload);
> }
>- infof(data, "range-download from %d to %d, totally %d bytes\n",
>+ infof(data, "range-download from %lld to %lld, totally %lld bytes\n",
> from, to, totalsize);
> ftp->dont_check = TRUE; /* dont check for successful transfer */
> }
>@@ -1762,7 +1770,7 @@
> (data->set.ftp_list_only?"NLST":"LIST"));
> }
> else {
>- ssize_t foundsize;
>+ off_t foundsize;
>
> /* Set type to binary (unless specified ASCII) */
> result = ftp_transfertype(conn, data->set.ftp_ascii);
>@@ -1812,7 +1820,7 @@
> if(conn->resume_from< 0) {
> /* We're supposed to download the last abs(from) bytes */
> if(foundsize < -conn->resume_from) {
>- failf(data, "Offset (%d) was beyond file size (%d)",
>+ failf(data, "Offset (%lld) was beyond file size (%lld)",
> conn->resume_from, foundsize);
> return CURLE_FTP_BAD_DOWNLOAD_RESUME;
> }
>@@ -1823,7 +1831,7 @@
> }
> else {
> if(foundsize < conn->resume_from) {
>- failf(data, "Offset (%d) was beyond file size (%d)",
>+ failf(data, "Offset (%lld) was beyond file size (%lld)",
> conn->resume_from, foundsize);
> return CURLE_FTP_BAD_DOWNLOAD_RESUME;
> }
>@@ -1844,10 +1852,10 @@
> }
>
> /* Set resume file transfer offset */
>- infof(data, "Instructs server to resume from offset %d\n",
>+ infof(data, "Instructs server to resume from offset %lld\n",
> conn->resume_from);
>
>- FTPSENDF(conn, "REST %d", conn->resume_from);
>+ FTPSENDF(conn, "REST %lld", conn->resume_from);
>
> result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
> if(result)
>@@ -1885,7 +1893,7 @@
> E:
> 125 Data connection already open; Transfer starting. */
>
>- int size=-1; /* default unknown size */
>+ off_t size=-1; /* default unknown size */
>
>
> /*
>@@ -1927,7 +1935,7 @@
> /* only if we have nothing but digits: */
> if(bytes++) {
> /* get the number! */
>- size = atoi(bytes);
>+ size = strtoll(bytes, NULL, 0);
> }
>
> }
>@@ -1941,7 +1949,7 @@
> return result;
> }
>
>- infof(data, "Getting file with size: %d\n", size);
>+ infof(data, "Getting file with size: %lld\n", size);
>
> /* FTP download: */
> result=Curl_Transfer(conn, conn->secondarysocket, size, FALSE,
>@@ -2057,7 +2065,7 @@
> /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
> may not support it! It is however the only way we have to get a file's
> size! */
>- ssize_t filesize;
>+ off_t filesize;
> ssize_t nread;
> int ftpcode;
>
>@@ -2073,7 +2081,7 @@
> result = ftp_getsize(conn, ftp->file, &filesize);
>
> if(CURLE_OK == result) {
>- sprintf(buf, "Content-Length: %d\r\n", filesize);
>+ sprintf(buf, "Content-Length: %lld\r\n", filesize);
> result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
> if(result)
> return result;
>diff -ur curl-7.10.8.orig/lib/http.c curl-7.10.8.large_ftp/lib/http.c
>--- curl-7.10.8.orig/lib/http.c Fri Oct 31 13:43:22 2003
>+++ curl-7.10.8.large_ftp/lib/http.c Wed Dec 10 09:49:23 2003
>@@ -1219,25 +1219,25 @@
>
> if(conn->resume_from) {
> /* do we still game? */
>- int passed=0;
>+ off_t passed=0;
>
> /* Now, let's read off the proper amount of bytes from the
> input. If we knew it was a proper file we could've just
> fseek()ed but we only have a stream here */
> do {
>- int readthisamountnow = (conn->resume_from - passed);
>- int actuallyread;
>+ off_t readthisamountnow = (conn->resume_from - passed);
>+ off_t actuallyread;
>
> if(readthisamountnow > BUFSIZE)
> readthisamountnow = BUFSIZE;
>
> actuallyread =
>- data->set.fread(data->state.buffer, 1, readthisamountnow,
>+ data->set.fread(data->state.buffer, 1, (size_t)readthisamountnow,
> data->set.in);
>
> passed += actuallyread;
> if(actuallyread != readthisamountnow) {
>- failf(data, "Could only read %d bytes from the input",
>+ failf(data, "Could only read %lld bytes from the input",
> passed);
> return CURLE_READ_ERROR;
> }
>@@ -1273,15 +1273,16 @@
>
> if(conn->resume_from) {
> /* This is because "resume" was selected */
>- long total_expected_size= conn->resume_from + data->set.infilesize;
>- conn->allocptr.rangeline = aprintf("Content-Range: bytes %s%ld/%ld\r\n",
>- conn->range, total_expected_size-1,
>- total_expected_size);
>+ off_t total_expected_size= conn->resume_from + data->set.infilesize;
>+ conn->allocptr.rangeline =
>+ aprintf("Content-Range: bytes %s%lld/%lld\r\n",
>+ conn->range, total_expected_size-1,
>+ total_expected_size);
> }
> else {
> /* Range was selected and then we just pass the incoming range and
> append total size */
>- conn->allocptr.rangeline = aprintf("Content-Range: bytes %s/%d\r\n",
>+ conn->allocptr.rangeline = aprintf("Content-Range: bytes %s/%lld\r\n",
> conn->range, data->set.infilesize);
> }
> }
>@@ -1511,13 +1512,13 @@
> if((data->set.infilesize>0) && !conn->bits.upload_chunky)
> /* only add Content-Length if not uploading chunked */
> add_bufferf(req_buffer,
>- "Content-Length: %d\r\n", /* file size */
>+ "Content-Length: %lld\r\n", /* file size */
> data->set.infilesize );
>
> add_bufferf(req_buffer, "\r\n");
>
> /* set the upload size to the progress meter */
>- Curl_pgrsSetUploadSize(data, data->set.infilesize);
>+ Curl_pgrsSetUploadSize(data, (double)data->set.infilesize);
>
> /* this sends the buffer and frees all the buffer resources */
> result = add_buffer_send(req_buffer, conn->firstsocket, conn,
>@@ -1594,7 +1595,7 @@
> }
> else {
> /* set the upload size to the progress meter */
>- Curl_pgrsSetUploadSize(data, data->set.infilesize);
>+ Curl_pgrsSetUploadSize(data, (double)data->set.infilesize);
>
> /* set the pointer to mark that we will send the post body using
> the read callback */
>diff -ur curl-7.10.8.orig/lib/progress.c curl-7.10.8.large_ftp/lib/progress.c
>--- curl-7.10.8.orig/lib/progress.c Wed Oct 15 13:35:34 2003
>+++ curl-7.10.8.large_ftp/lib/progress.c Wed Dec 10 09:49:23 2003
>@@ -228,7 +228,8 @@
> else if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
> if (!data->progress.callback) {
> if(conn->resume_from)
>- fprintf(data->set.err, "** Resuming transfer from byte position %d\n",
>+ fprintf(data->set.err,
>+ "** Resuming transfer from byte position %lld\n",
> conn->resume_from);
> fprintf(data->set.err,
> " %% Total %% Received %% Xferd Average Speed Time Curr.\n"
>diff -ur curl-7.10.8.orig/lib/transfer.c curl-7.10.8.large_ftp/lib/transfer.c
>--- curl-7.10.8.orig/lib/transfer.c Fri Oct 24 14:54:34 2003
>+++ curl-7.10.8.large_ftp/lib/transfer.c Wed Dec 10 09:49:23 2003
>@@ -590,14 +590,14 @@
> info about the true size of the document we didn't get now. */
> if ((k->httpcode != 416) &&
> checkprefix("Content-Length:", k->p) &&
>- sscanf (k->p+15, " %ld", &k->contentlength)) {
>+ sscanf (k->p+15, " %lld", &k->contentlength)) {
> if (data->set.max_filesize && k->contentlength >
> data->set.max_filesize) {
> failf(data, "Maximum file size exceeded");
> return CURLE_FILESIZE_EXCEEDED;
> }
> conn->size = k->contentlength;
>- Curl_pgrsSetDownloadSize(data, k->contentlength);
>+ Curl_pgrsSetDownloadSize(data, (double)k->contentlength);
> }
> /* check for Content-Type: header lines to get the mime-type */
> else if (checkprefix("Content-Type:", k->p)) {
>@@ -710,8 +710,8 @@
> k->content_encoding = COMPRESS;
> }
> else if (checkprefix("Content-Range:", k->p)) {
>- if (sscanf (k->p+14, " bytes %d-", &k->offset) ||
>- sscanf (k->p+14, " bytes: %d-", &k->offset)) {
>+ if (sscanf (k->p+14, " bytes %lld-", &k->offset) ||
>+ sscanf (k->p+14, " bytes: %lld-", &k->offset)) {
> /* This second format was added August 1st 2000 by Igor
> Khristophorov since Sun's webserver JavaWebServer/1.1.1
> obviously sends the header this way! :-( */
>@@ -938,7 +938,7 @@
>
> if((-1 != conn->maxdownload) &&
> (k->bytecount + nread >= conn->maxdownload)) {
>- nread = conn->maxdownload - k->bytecount;
>+ nread = (ssize_t) (conn->maxdownload - k->bytecount);
> if(nread < 0 ) /* this should be unusual */
> nread = 0;
>
>@@ -1204,7 +1204,7 @@
>
> if (data->set.timeout &&
> ((Curl_tvdiff(k->now, k->start)/1000) >= data->set.timeout)) {
>- failf (data, "Operation timed out with %d out of %d bytes received",
>+ failf (data, "Operation timed out with %lld out of %lld bytes received",
> k->bytecount, conn->size);
> return CURLE_OPERATION_TIMEOUTED;
> }
>@@ -1218,7 +1218,7 @@
> if(!(data->set.no_body) && k->contentlength &&
> (k->bytecount != k->contentlength) &&
> !conn->newurl) {
>- failf(data, "transfer closed with %d bytes remaining to read",
>+ failf(data, "transfer closed with %lld bytes remaining to read",
> k->contentlength-k->bytecount);
> return CURLE_PARTIAL_FILE;
> }
>@@ -1268,7 +1268,7 @@
> if (!conn->bits.getheader) {
> k->header = FALSE;
> if(conn->size > 0)
>- Curl_pgrsSetDownloadSize(data, conn->size);
>+ Curl_pgrsSetDownloadSize(data, (double)conn->size);
> }
> /* we want header and/or body, if neither then don't do this! */
> if(conn->bits.getheader || !data->set.no_body) {
>@@ -1937,12 +1937,12 @@
> CURLcode
> Curl_Transfer(struct connectdata *c_conn, /* connection data */
> int sockfd, /* socket to read from or -1 */
>- int size, /* -1 if unknown at this point */
>+ off_t size, /* -1 if unknown at this point */
> bool getheader, /* TRUE if header parsing is wanted */
>- long *bytecountp, /* return number of bytes read or NULL */
>+ off_t *bytecountp, /* return number of bytes read or NULL */
> int writesockfd, /* socket to write to, it may very well be
> the same we read from. -1 disables */
>- long *writebytecountp /* return number of bytes written or
>+ off_t *writebytecountp /* return number of bytes written or
> NULL */
> )
> {
>diff -ur curl-7.10.8.orig/lib/transfer.h curl-7.10.8.large_ftp/lib/transfer.h
>--- curl-7.10.8.orig/lib/transfer.h Thu Jan 16 13:08:13 2003
>+++ curl-7.10.8.large_ftp/lib/transfer.h Wed Dec 10 09:49:23 2003
>@@ -38,11 +38,11 @@
> CURLcode
> Curl_Transfer (struct connectdata *data,
> int sockfd, /* socket to read from or -1 */
>- int size, /* -1 if unknown at this point */
>+ off_t size, /* -1 if unknown at this point */
> bool getheader, /* TRUE if header parsing is wanted */
>- long *bytecountp, /* return number of bytes read */
>+ off_t *bytecountp, /* return number of bytes read */
> int writesockfd, /* socket to write to, it may very well be
> the same we read from. -1 disables */
>- long *writebytecountp /* return number of bytes written */
>+ off_t *writebytecountp /* return number of bytes written */
> );
> #endif
>diff -ur curl-7.10.8.orig/lib/url.c curl-7.10.8.large_ftp/lib/url.c
>--- curl-7.10.8.orig/lib/url.c Fri Oct 31 13:18:01 2003
>+++ curl-7.10.8.large_ftp/lib/url.c Wed Dec 10 12:52:44 2003
>@@ -705,6 +705,13 @@
> */
> data->set.infilesize = va_arg(param, long);
> break;
>+ case CURLOPT_INFILESIZE_BIG:
>+ /*
>+ * If known, this should inform curl about the file size of the
>+ * to-be-uploaded file.
>+ */
>+ data->set.infilesize = va_arg(param, off_t);
>+ break;
> case CURLOPT_LOW_SPEED_LIMIT:
> /*
> * The low speed limit that if transfers are below this for
>@@ -949,6 +956,12 @@
> */
> data->set.set_resume_from = va_arg(param, long);
> break;
>+ case CURLOPT_RESUME_FROM_BIG:
>+ /*
>+ * Resume transfer at the give file position
>+ */
>+ data->set.set_resume_from = va_arg(param, off_t);
>+ break;
> case CURLOPT_DEBUGFUNCTION:
> /*
> * stderr write callback.
>@@ -1245,6 +1258,13 @@
> data->set.max_filesize = va_arg(param, long);
> break;
>
>+ case CURLOPT_MAXFILESIZE_BIG:
>+ /*
>+ * Set the maximum size of a file to download.
>+ */
>+ data->set.max_filesize = va_arg(param, off_t);
>+ break;
>+
> default:
> /* unknown tag and its companion, just ignore: */
> return CURLE_FAILED_INIT; /* correct this */
>@@ -2337,7 +2357,7 @@
> if(conn->resume_from) {
> if(!conn->bits.use_range) {
> /* if it already was in use, we just skip this */
>- snprintf(resumerange, sizeof(resumerange), "%d-", conn->resume_from);
>+ snprintf(resumerange, sizeof(resumerange), "%lld-", conn->resume_from);
> conn->range=strdup(resumerange); /* tell ourselves to fetch this range */
> conn->bits.rangestringalloc = TRUE; /* mark as allocated */
> conn->bits.use_range = 1; /* switch on range usage */
>@@ -2853,7 +2873,7 @@
> */
> conn->resume_from = data->set.set_resume_from;
> if (conn->resume_from) {
>- snprintf(resumerange, sizeof(resumerange), "%d-", conn->resume_from);
>+ snprintf(resumerange, sizeof(resumerange), "%lld-", conn->resume_from);
> if (conn->bits.rangestringalloc == TRUE)
> free(conn->range);
>
>diff -ur curl-7.10.8.orig/lib/urldata.h curl-7.10.8.large_ftp/lib/urldata.h
>--- curl-7.10.8.orig/lib/urldata.h Sat Oct 18 13:14:33 2003
>+++ curl-7.10.8.large_ftp/lib/urldata.h Wed Dec 10 09:49:23 2003
>@@ -210,8 +210,8 @@
>
> const char *p_pragma; /* Pragma: string */
> const char *p_accept; /* Accept: string */
>- long readbytecount;
>- long writebytecount;
>+ off_t readbytecount;
>+ off_t writebytecount;
>
> /* For FORM posting */
> struct Form form;
>@@ -239,7 +239,7 @@
> * FTP unique setup
> ***************************************************************************/
> struct FTP {
>- long *bytecountp;
>+ off_t *bytecountp;
> char *user; /* user name string */
> char *passwd; /* password string */
> char *urlpath; /* the originally given path part of the URL */
>@@ -249,7 +249,7 @@
> char *entrypath; /* the PWD reply when we logged on */
>
> char *cache; /* data cache between getresponse()-calls */
>- size_t cache_size; /* size of cache in bytes */
>+ off_t cache_size; /* size of cache in bytes */
> bool dont_check; /* Set to TRUE to prevent the final (post-transfer)
> file size and 226/250 status check. It should still
> read the line, just ignore the result. */
>@@ -304,9 +304,9 @@
> */
>
> struct Curl_transfer_keeper {
>- int bytecount; /* total number of bytes read */
>+ off_t bytecount; /* total number of bytes read */
> int writebytecount; /* number of bytes written */
>- long contentlength; /* size of incoming data */
>+ off_t contentlength; /* size of incoming data */
> struct timeval start; /* transfer started at this time */
> struct timeval now; /* current time */
> bool header; /* incoming data has HTTP header */
>@@ -326,7 +326,7 @@
> char *end_ptr; /* within buf */
> char *p; /* within headerbuff */
> bool content_range; /* set TRUE if Content-Range: was found */
>- int offset; /* possible resume offset read from the
>+ off_t offset; /* possible resume offset read from the
> Content-Range: header */
> int httpcode; /* error code from the 'HTTP/1.? XXX' line */
> int httpversion; /* the HTTP version*10 */
>@@ -425,12 +425,12 @@
> unsigned short remote_port; /* what remote port to connect to,
> not the proxy port! */
> char *ppath;
>- long bytecount;
>+ off_t bytecount;
> long headerbytecount; /* only count received headers */
>
> char *range; /* range, if used. See README for detailed specification on
> this syntax. */
>- ssize_t resume_from; /* continue [ftp] transfer from here */
>+ off_t resume_from; /* continue [ftp] transfer from here */
>
> char *proxyhost; /* name of the http proxy host */
>
>@@ -444,7 +444,7 @@
> struct timeval created; /* creation time */
> int firstsocket; /* the main socket to use */
> int secondarysocket; /* for i.e ftp transfers */
>- long maxdownload; /* in bytes, the maximum amount of data to fetch, 0
>+ off_t maxdownload; /* in bytes, the maximum amount of data to fetch, 0
> means unlimited */
>
> struct ssl_connect_data ssl; /* this is for ssl-stuff */
>@@ -482,13 +482,13 @@
>
> /* READ stuff */
> int sockfd; /* socket to read from or -1 */
>- int size; /* -1 if unknown at this point */
>- long *bytecountp; /* return number of bytes read or NULL */
>+ off_t size; /* -1 if unknown at this point */
>+ off_t *bytecountp; /* return number of bytes read or NULL */
>
> /* WRITE stuff */
> int writesockfd; /* socket to write to, it may very well be
> the same we read from. -1 disables */
>- long *writebytecountp; /* return number of bytes written or NULL */
>+ off_t *writebytecountp; /* return number of bytes written or NULL */
>
> /** Dynamicly allocated strings, may need to be freed before this **/
> /** struct is killed. **/
>@@ -784,10 +784,10 @@
> long timeout; /* in seconds, 0 means no timeout */
> long connecttimeout; /* in seconds, 0 means no timeout */
> long ftp_response_timeout; /* in seconds, 0 means no timeout */
>- long infilesize; /* size of file to upload, -1 means unknown */
>+ off_t infilesize; /* size of file to upload, -1 means unknown */
> long low_speed_limit; /* bytes/second */
> long low_speed_time; /* number of seconds */
>- int set_resume_from; /* continue [ftp] transfer from here */
>+ off_t set_resume_from; /* continue [ftp] transfer from here */
> char *cookie; /* HTTP cookie string to send */
> struct curl_slist *headers; /* linked list of extra headers */
> struct HttpPost *httppost; /* linked list of POST data */
>@@ -829,7 +829,7 @@
>
> int ip_version;
>
>- long max_filesize; /* Maximum file size to download */
>+ off_t max_filesize; /* Maximum file size to download */
>
> /* Here follows boolean settings that define how to behave during
> this session. They are STATIC, set by libcurl users or at least initially
>diff -ur curl-7.10.8.orig/src/main.c curl-7.10.8.large_ftp/src/main.c
>--- curl-7.10.8.orig/src/main.c Fri Oct 31 13:18:01 2003
>+++ curl-7.10.8.large_ftp/src/main.c Wed Dec 10 12:51:22 2003
>@@ -500,14 +500,14 @@
> bool resume_from_current;
> bool disable_epsv;
> bool disable_eprt;
>- long resume_from;
>+ off_t resume_from;
> char *postfields;
> long postfieldsize;
> char *referer;
> long timeout;
> long connecttimeout;
> long maxredirs;
>- long max_filesize;
>+ off_t max_filesize;
> char *headerfile;
> char *ftpport;
> char *iface;
>@@ -1070,6 +1070,39 @@
> return retcode;
> }
>
>+/**
>+ * Parses the given string looking for an offset (which may be
>+ * a larger-than-integer value).
>+ *
>+ * @param val the offset to populate
>+ * @param str the buffer containing the offset
>+ * @return zero if successful, non-zero if failure.
>+ */
>+static int str2offset(off_t *val, char *str) {
>+ if (sizeof(off_t) == 8) {
>+ /* Ugly, but without going through a bunch of rigamarole,
>+ * we don't have the definitions for LLONG_{MIN,MAX} or
>+ * LONG_LONG_{MIN,MAX}.
>+ */
>+#ifndef LLONG_MAX
>+#define LLONG_MAX 0x7FFFFFFFFFFFFFFF
>+#define LLONG_MIN 0x8000000000000000
>+#endif
>+
>+ *val = strtoll(str, NULL, 0);
>+ if ((*val == LLONG_MAX || *val == LLONG_MIN) && errno == ERANGE) {
>+ return 1;
>+ }
>+ } else {
>+ *val = strtol(str, NULL, 0);
>+ if ((*val == LONG_MIN || *val == LONG_MAX) && errno == ERANGE) {
>+ return 1;
>+ }
>+ }
>+
>+ return 0;
>+}
>+
> static void checkpasswd(const char *kind, /* for what purpose */
> char **userpwd) /* pointer to allocated string */
> {
>@@ -1427,7 +1460,7 @@
> GetStr(&config->krb4level, nextarg);
> break;
> case 'y': /* --max-filesize */
>- if(str2num(&config->max_filesize, nextarg))
>+ if(str2offset(&config->max_filesize, nextarg))
> return PARAM_BAD_NUMERIC;
> break;
> case 'z': /* --disable-eprt */
>@@ -1519,7 +1552,7 @@
> case 'C':
> /* This makes us continue an ftp transfer at given position */
> if(!curl_strequal(nextarg, "-")) {
>- if(str2num(&config->resume_from, nextarg))
>+ if(str2offset(&config->resume_from, nextarg))
> return PARAM_BAD_NUMERIC;
> config->resume_from_current = FALSE;
> }
>@@ -2305,7 +2338,7 @@
> double prev;
> int width;
> FILE *out; /* where to write everything to */
>- int initial_size;
>+ off_t initial_size;
> };
>
> int myprogress (void *clientp,
>@@ -2606,7 +2639,7 @@
> bool infdfopen;
> FILE *headerfilep = NULL;
> char *urlbuffer=NULL;
>- long uploadfilesize; /* -1 means unknown */
>+ off_t uploadfilesize; /* -1 means unknown */
> bool stillflags=TRUE;
>
> bool allocuseragent=FALSE;
>@@ -3130,7 +3163,7 @@
> }
>
> /* size of uploaded file: */
>- curl_easy_setopt(curl, CURLOPT_INFILESIZE, uploadfilesize);
>+ curl_easy_setopt(curl, CURLOPT_INFILESIZE_BIG, uploadfilesize);
> curl_easy_setopt(curl, CURLOPT_URL, url); /* what to fetch */
> curl_easy_setopt(curl, CURLOPT_PROXY, config->proxy); /* proxy to use */
> curl_easy_setopt(curl, CURLOPT_HEADER, config->conf&CONF_HEADER);
>@@ -3173,7 +3206,7 @@
> curl_easy_setopt(curl, CURLOPT_FTPPORT, config->ftpport);
> curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, config->low_speed_limit);
> curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
>- curl_easy_setopt(curl, CURLOPT_RESUME_FROM,
>+ curl_easy_setopt(curl, CURLOPT_RESUME_FROM_BIG,
> config->use_resume?config->resume_from:0);
> curl_easy_setopt(curl, CURLOPT_COOKIE, config->cookie);
> curl_easy_setopt(curl, CURLOPT_HTTPHEADER, config->headers);
>@@ -3291,7 +3324,8 @@
>
> /* new in curl 7.10.8 */
> if (config->max_filesize)
>- curl_easy_setopt(curl, CURLOPT_MAXFILESIZE, config->max_filesize);
>+ curl_easy_setopt(curl, CURLOPT_MAXFILESIZE_BIG,
>+ config->max_filesize);
>
> res = curl_easy_perform(curl);
>
>diff -ur curl-7.10.8.orig/tests/libtest/lib505.c curl-7.10.8.large_ftp/tests/libtest/lib505.c
>--- curl-7.10.8.orig/tests/libtest/lib505.c Tue Apr 15 07:20:21 2003
>+++ curl-7.10.8.large_ftp/tests/libtest/lib505.c Wed Dec 10 10:42:11 2003
>@@ -92,8 +92,8 @@
> curl_easy_setopt(curl, CURLOPT_INFILE, hd_src);
>
> /* and give the size of the upload (optional) */
>- curl_easy_setopt(curl, CURLOPT_INFILESIZE,
>- (long)file_info.st_size);
>+ curl_easy_setopt(curl, CURLOPT_INFILESIZE_BIG,
>+ file_info.st_size);
>
> /* Now run off and do what you've been told! */
> res = curl_easy_perform(curl);
>
>
-- Robert A. Monat Jerand Technical Services, Inc. http://www.jerand.com Phone: 317-875-6087 FAX: 317-875-6612 Tollfree(US)888-4JERAND ------------------------------------------------------- This SF.net email is sponsored by: IBM Linux Tutorials. Become an expert in LINUX or just sharpen your skills. Sign up for IBM's Free Linux Tutorials. Learn everything from the bash shell to sys admin. Click now! http://ads.osdn.com/?ad_id=1278&alloc_id=3371&op=clickReceived on 2003-12-21