00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "setup.h"
00025
00026 #ifndef CURL_DISABLE_FILE
00027
00028 #include <stdio.h>
00029 #include <string.h>
00030 #include <stdarg.h>
00031 #include <stdlib.h>
00032 #include <ctype.h>
00033
00034 #ifdef WIN32
00035 #include <time.h>
00036 #include <io.h>
00037 #include <fcntl.h>
00038 #else
00039 #ifdef HAVE_SYS_SOCKET_H
00040 #include <sys/socket.h>
00041 #endif
00042 #ifdef HAVE_NETINET_IN_H
00043 #include <netinet/in.h>
00044 #endif
00045 #ifdef HAVE_SYS_TIME_H
00046 #include <sys/time.h>
00047 #endif
00048 #ifdef HAVE_UNISTD_H
00049 #include <unistd.h>
00050 #endif
00051 #ifdef HAVE_NETDB_H
00052 #include <netdb.h>
00053 #endif
00054 #ifdef HAVE_ARPA_INET_H
00055 #include <arpa/inet.h>
00056 #endif
00057 #ifdef HAVE_NET_IF_H
00058 #include <net/if.h>
00059 #endif
00060 #include <sys/ioctl.h>
00061 #include <signal.h>
00062
00063 #ifdef HAVE_SYS_PARAM_H
00064 #include <sys/param.h>
00065 #endif
00066
00067 #ifdef HAVE_FCNTL_H
00068 #include <fcntl.h>
00069 #endif
00070
00071 #endif
00072
00073 #include "urldata.h"
00074 #include <curl/curl.h>
00075 #include "progress.h"
00076 #include "sendf.h"
00077 #include "escape.h"
00078 #include "file.h"
00079 #include "speedcheck.h"
00080 #include "getinfo.h"
00081 #include "transfer.h"
00082 #include "url.h"
00083 #include "memory.h"
00084 #include "parsedate.h"
00085
00086 #define _MPRINTF_REPLACE
00087 #include <curl/mprintf.h>
00088
00089
00090 #include "memdebug.h"
00091
00092
00093
00094
00095
00096
00097 CURLcode Curl_file_connect(struct connectdata *conn)
00098 {
00099 char *real_path = curl_easy_unescape(conn->data, conn->data->reqdata.path, 0, NULL);
00100 struct FILEPROTO *file;
00101 int fd;
00102 #if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
00103 int i;
00104 char *actual_path;
00105 #endif
00106
00107 if(!real_path)
00108 return CURLE_OUT_OF_MEMORY;
00109
00110 file = (struct FILEPROTO *)calloc(sizeof(struct FILEPROTO), 1);
00111 if(!file) {
00112 free(real_path);
00113 return CURLE_OUT_OF_MEMORY;
00114 }
00115
00116 if (conn->data->reqdata.proto.file) {
00117 free(conn->data->reqdata.proto.file);
00118 }
00119
00120 conn->data->reqdata.proto.file = file;
00121
00122 #if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 actual_path = real_path;
00138 if ((actual_path[0] == '/') &&
00139 actual_path[1] &&
00140 (actual_path[2] == ':' || actual_path[2] == '|'))
00141 {
00142 actual_path[2] = ':';
00143 actual_path++;
00144 }
00145
00146
00147 for (i=0; actual_path[i] != '\0'; ++i)
00148 if (actual_path[i] == '/')
00149 actual_path[i] = '\\';
00150
00151 fd = open(actual_path, O_RDONLY | O_BINARY);
00152 file->path = actual_path;
00153 #else
00154 fd = open(real_path, O_RDONLY);
00155 file->path = real_path;
00156 #endif
00157 file->freepath = real_path;
00158
00159 file->fd = fd;
00160 if(!conn->data->set.upload && (fd == -1)) {
00161 failf(conn->data, "Couldn't open file %s", conn->data->reqdata.path);
00162 Curl_file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE);
00163 return CURLE_FILE_COULDNT_READ_FILE;
00164 }
00165
00166 return CURLE_OK;
00167 }
00168
00169 CURLcode Curl_file_done(struct connectdata *conn,
00170 CURLcode status, bool premature)
00171 {
00172 struct FILEPROTO *file = conn->data->reqdata.proto.file;
00173 (void)status;
00174 (void)premature;
00175 Curl_safefree(file->freepath);
00176
00177 if(file->fd != -1)
00178 close(file->fd);
00179
00180 return CURLE_OK;
00181 }
00182
00183 #if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
00184 #define DIRSEP '\\'
00185 #else
00186 #define DIRSEP '/'
00187 #endif
00188
00189 static CURLcode file_upload(struct connectdata *conn)
00190 {
00191 struct FILEPROTO *file = conn->data->reqdata.proto.file;
00192 char *dir = strchr(file->path, DIRSEP);
00193 FILE *fp;
00194 CURLcode res=CURLE_OK;
00195 struct SessionHandle *data = conn->data;
00196 char *buf = data->state.buffer;
00197 size_t nread;
00198 size_t nwrite;
00199 curl_off_t bytecount = 0;
00200 struct timeval now = Curl_tvnow();
00201 struct_stat file_stat;
00202 char* buf2;
00203
00204
00205
00206
00207
00208 conn->fread = data->set.fread;
00209 conn->fread_in = data->set.in;
00210 conn->data->reqdata.upload_fromhere = buf;
00211
00212 if(!dir)
00213 return CURLE_FILE_COULDNT_READ_FILE;
00214
00215 if(!dir[1])
00216 return CURLE_FILE_COULDNT_READ_FILE;
00217
00218 if(data->reqdata.resume_from)
00219 fp = fopen( file->path, "ab" );
00220 else {
00221 int fd;
00222
00223 #if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
00224 fd = open(file->path, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
00225 conn->data->set.new_file_perms);
00226 #else
00227 fd = open(file->path, O_WRONLY|O_CREAT|O_TRUNC,
00228 conn->data->set.new_file_perms);
00229 #endif
00230 if (fd < 0) {
00231 failf(data, "Can't open %s for writing", file->path);
00232 return CURLE_WRITE_ERROR;
00233 }
00234 fp = fdopen(fd, "wb");
00235 }
00236
00237 if(!fp) {
00238 failf(data, "Can't open %s for writing", file->path);
00239 return CURLE_WRITE_ERROR;
00240 }
00241
00242 if(-1 != data->set.infilesize)
00243
00244 Curl_pgrsSetUploadSize(data, data->set.infilesize);
00245
00246
00247 if(data->reqdata.resume_from < 0){
00248 if(stat(file->path, &file_stat)){
00249 fclose(fp);
00250 failf(data, "Can't get the size of %s", file->path);
00251 return CURLE_WRITE_ERROR;
00252 }
00253 else
00254 data->reqdata.resume_from = (curl_off_t)file_stat.st_size;
00255 }
00256
00257 while (res == CURLE_OK) {
00258 int readcount;
00259 res = Curl_fillreadbuffer(conn, BUFSIZE, &readcount);
00260 if(res)
00261 break;
00262
00263 if (readcount <= 0)
00264 break;
00265
00266 nread = (size_t)readcount;
00267
00268
00269 if(data->reqdata.resume_from) {
00270 if( (curl_off_t)nread <= data->reqdata.resume_from ) {
00271 data->reqdata.resume_from -= nread;
00272 nread = 0;
00273 buf2 = buf;
00274 }
00275 else {
00276 buf2 = buf + data->reqdata.resume_from;
00277 nread -= data->reqdata.resume_from;
00278 data->reqdata.resume_from = 0;
00279 }
00280 }
00281 else
00282 buf2 = buf;
00283
00284
00285 nwrite = fwrite(buf2, 1, nread, fp);
00286 if(nwrite != nread) {
00287 res = CURLE_SEND_ERROR;
00288 break;
00289 }
00290
00291 bytecount += nread;
00292
00293 Curl_pgrsSetUploadCounter(data, bytecount);
00294
00295 if(Curl_pgrsUpdate(conn))
00296 res = CURLE_ABORTED_BY_CALLBACK;
00297 else
00298 res = Curl_speedcheck(data, now);
00299 }
00300 if(!res && Curl_pgrsUpdate(conn))
00301 res = CURLE_ABORTED_BY_CALLBACK;
00302
00303 fclose(fp);
00304
00305 return res;
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 CURLcode Curl_file(struct connectdata *conn, bool *done)
00317 {
00318
00319
00320
00321
00322
00323 CURLcode res = CURLE_OK;
00324 struct_stat statbuf;
00325
00326
00327 curl_off_t expected_size=0;
00328 bool fstated=FALSE;
00329 ssize_t nread;
00330 struct SessionHandle *data = conn->data;
00331 char *buf = data->state.buffer;
00332 curl_off_t bytecount = 0;
00333 int fd;
00334 struct timeval now = Curl_tvnow();
00335
00336 *done = TRUE;
00337
00338 Curl_readwrite_init(conn);
00339 Curl_initinfo(data);
00340 Curl_pgrsStartNow(data);
00341
00342 if(data->set.upload)
00343 return file_upload(conn);
00344
00345
00346 fd = conn->data->reqdata.proto.file->fd;
00347
00348
00349 if( -1 != fstat(fd, &statbuf)) {
00350
00351 expected_size = statbuf.st_size;
00352 fstated = TRUE;
00353 }
00354
00355
00356
00357
00358 if(conn->bits.no_body && data->set.include_header && fstated) {
00359 CURLcode result;
00360 snprintf(buf, sizeof(data->state.buffer),
00361 "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size);
00362 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
00363 if(result)
00364 return result;
00365
00366 result = Curl_client_write(conn, CLIENTWRITE_BOTH,
00367 (char *)"Accept-ranges: bytes\r\n", 0);
00368 if(result)
00369 return result;
00370
00371 if(fstated) {
00372 struct tm *tm;
00373 time_t clock = (time_t)statbuf.st_mtime;
00374 #ifdef HAVE_GMTIME_R
00375 struct tm buffer;
00376 tm = (struct tm *)gmtime_r(&clock, &buffer);
00377 #else
00378 tm = gmtime(&clock);
00379 #endif
00380
00381 snprintf(buf, BUFSIZE-1,
00382 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
00383 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
00384 tm->tm_mday,
00385 Curl_month[tm->tm_mon],
00386 tm->tm_year + 1900,
00387 tm->tm_hour,
00388 tm->tm_min,
00389 tm->tm_sec);
00390 result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
00391 }
00392 return result;
00393 }
00394
00395 if (data->reqdata.resume_from <= expected_size)
00396 expected_size -= data->reqdata.resume_from;
00397 else {
00398 failf(data, "failed to resume file:// transfer");
00399 return CURLE_BAD_DOWNLOAD_RESUME;
00400 }
00401
00402 if (fstated && (expected_size == 0))
00403 return CURLE_OK;
00404
00405
00406
00407
00408
00409 if(fstated)
00410 Curl_pgrsSetDownloadSize(data, expected_size);
00411
00412 if(data->reqdata.resume_from) {
00413 if(data->reqdata.resume_from !=
00414 lseek(fd, data->reqdata.resume_from, SEEK_SET))
00415 return CURLE_BAD_DOWNLOAD_RESUME;
00416 }
00417
00418 Curl_pgrsTime(data, TIMER_STARTTRANSFER);
00419
00420 while (res == CURLE_OK) {
00421 nread = read(fd, buf, BUFSIZE-1);
00422
00423 if ( nread > 0)
00424 buf[nread] = 0;
00425
00426 if (nread <= 0)
00427 break;
00428
00429 bytecount += nread;
00430
00431 res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread);
00432 if(res)
00433 return res;
00434
00435 Curl_pgrsSetDownloadCounter(data, bytecount);
00436
00437 if(Curl_pgrsUpdate(conn))
00438 res = CURLE_ABORTED_BY_CALLBACK;
00439 else
00440 res = Curl_speedcheck(data, now);
00441 }
00442 if(Curl_pgrsUpdate(conn))
00443 res = CURLE_ABORTED_BY_CALLBACK;
00444
00445 return res;
00446 }
00447
00448 #endif