diff options
Diffstat (limited to 'lib/file.c')
-rw-r--r-- | lib/file.c | 163 |
1 files changed, 85 insertions, 78 deletions
diff --git a/lib/file.c b/lib/file.c index 8e4ee075f..038bf42e1 100644 --- a/lib/file.c +++ b/lib/file.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2012, 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 @@ -20,33 +20,13 @@ * ***************************************************************************/ -#include "setup.h" +#include "curl_setup.h" #ifndef CURL_DISABLE_FILE -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#include <fcntl.h> -#else -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif + #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif #ifdef HAVE_NETDB_H #include <netdb.h> #endif @@ -68,8 +48,6 @@ #include <fcntl.h> #endif -#endif /* WIN32 */ - #include "strtoofft.h" #include "urldata.h" #include <curl/curl.h> @@ -83,6 +61,7 @@ #include "url.h" #include "curl_memory.h" #include "parsedate.h" /* for the week day and month names */ +#include "warnless.h" #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> @@ -90,7 +69,8 @@ /* The last #include file should be: */ #include "memdebug.h" -#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) || defined(__SYMBIAN32__) +#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) || \ + defined(__SYMBIAN32__) #define DOS_FILESYSTEM 1 #endif @@ -108,6 +88,9 @@ static CURLcode file_do(struct connectdata *, bool *done); static CURLcode file_done(struct connectdata *conn, CURLcode status, bool premature); static CURLcode file_connect(struct connectdata *conn, bool *done); +static CURLcode file_disconnect(struct connectdata *conn, + bool dead_connection); + /* * FILE scheme handler. @@ -124,10 +107,13 @@ const struct Curl_handler Curl_handler_file = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ + file_disconnect, /* disconnect */ + ZERO_NULL, /* readwrite */ 0, /* defport */ - PROT_FILE /* protocol */ + CURLPROTO_FILE, /* protocol */ + PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */ }; @@ -192,7 +178,7 @@ static CURLcode file_range(struct connectdata *conn) static CURLcode file_connect(struct connectdata *conn, bool *done) { struct SessionHandle *data = conn->data; - char *real_path = curl_easy_unescape(data, data->state.path, 0, NULL); + char *real_path; struct FILEPROTO *file; int fd; #ifdef DOS_FILESYSTEM @@ -200,13 +186,14 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) char *actual_path; #endif - if(!real_path) - return CURLE_OUT_OF_MEMORY; - /* If there already is a protocol-specific struct allocated for this sessionhandle, deal with it */ Curl_reset_reqproto(conn); + real_path = curl_easy_unescape(data, data->state.path, 0, NULL); + if(!real_path) + return CURLE_OUT_OF_MEMORY; + if(!data->state.proto.file) { file = calloc(1, sizeof(struct FILEPROTO)); if(!file) { @@ -219,10 +206,9 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) /* file is not a protocol that can deal with "persistancy" */ file = data->state.proto.file; Curl_safefree(file->freepath); + file->path = NULL; if(file->fd != -1) close(file->fd); - file->path = NULL; - file->freepath = NULL; file->fd = -1; } @@ -244,18 +230,17 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) actual_path = real_path; if((actual_path[0] == '/') && actual_path[1] && - (actual_path[2] == ':' || actual_path[2] == '|')) - { + (actual_path[2] == ':' || actual_path[2] == '|')) { actual_path[2] = ':'; actual_path++; } /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */ - for (i=0; actual_path[i] != '\0'; ++i) + for(i=0; actual_path[i] != '\0'; ++i) if(actual_path[i] == '/') actual_path[i] = '\\'; - fd = open_readonly(actual_path, O_RDONLY|O_BINARY); /* no CR/LF translation */ + fd = open_readonly(actual_path, O_RDONLY|O_BINARY); file->path = actual_path; #else fd = open_readonly(real_path, O_RDONLY); @@ -280,10 +265,31 @@ static CURLcode file_done(struct connectdata *conn, struct FILEPROTO *file = conn->data->state.proto.file; (void)status; /* not used */ (void)premature; /* not used */ - Curl_safefree(file->freepath); - if(file->fd != -1) - close(file->fd); + if(file) { + Curl_safefree(file->freepath); + file->path = NULL; + if(file->fd != -1) + close(file->fd); + file->fd = -1; + } + + return CURLE_OK; +} + +static CURLcode file_disconnect(struct connectdata *conn, + bool dead_connection) +{ + struct FILEPROTO *file = conn->data->state.proto.file; + (void)dead_connection; /* not used */ + + if(file) { + Curl_safefree(file->freepath); + file->path = NULL; + if(file->fd != -1) + close(file->fd); + file->fd = -1; + } return CURLE_OK; } @@ -298,7 +304,8 @@ static CURLcode file_upload(struct connectdata *conn) { struct FILEPROTO *file = conn->data->state.proto.file; const char *dir = strchr(file->path, DIRSEP); - FILE *fp; + int fd; + int mode; CURLcode res=CURLE_OK; struct SessionHandle *data = conn->data; char *buf = data->state.buffer; @@ -321,29 +328,21 @@ static CURLcode file_upload(struct connectdata *conn) return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ if(!dir[1]) - return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ - - if(data->state.resume_from) - fp = fopen( file->path, "ab" ); - else { - int fd; + return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */ -#ifdef DOS_FILESYSTEM - fd = open(file->path, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, - conn->data->set.new_file_perms); +#ifdef O_BINARY +#define MODE_DEFAULT O_WRONLY|O_CREAT|O_BINARY #else - fd = open(file->path, O_WRONLY|O_CREAT|O_TRUNC, - conn->data->set.new_file_perms); +#define MODE_DEFAULT O_WRONLY|O_CREAT #endif - if(fd < 0) { - failf(data, "Can't open %s for writing", file->path); - return CURLE_WRITE_ERROR; - } - close(fd); - fp = fopen(file->path, "wb"); - } - if(!fp) { + if(data->state.resume_from) + mode = MODE_DEFAULT|O_APPEND; + else + mode = MODE_DEFAULT|O_TRUNC; + + fd = open(file->path, mode, conn->data->set.new_file_perms); + if(fd < 0) { failf(data, "Can't open %s for writing", file->path); return CURLE_WRITE_ERROR; } @@ -354,8 +353,8 @@ static CURLcode file_upload(struct connectdata *conn) /* treat the negative resume offset value as the case of "-" */ if(data->state.resume_from < 0) { - if(fstat(fileno(fp), &file_stat)) { - fclose(fp); + if(fstat(fd, &file_stat)) { + close(fd); failf(data, "Can't get the size of %s", file->path); return CURLE_WRITE_ERROR; } @@ -376,7 +375,7 @@ static CURLcode file_upload(struct connectdata *conn) /*skip bytes before resume point*/ if(data->state.resume_from) { - if( (curl_off_t)nread <= data->state.resume_from ) { + if((curl_off_t)nread <= data->state.resume_from ) { data->state.resume_from -= nread; nread = 0; buf2 = buf; @@ -391,7 +390,7 @@ static CURLcode file_upload(struct connectdata *conn) buf2 = buf; /* write the data to the target */ - nwrite = fwrite(buf2, 1, nread, fp); + nwrite = write(fd, buf2, nread); if(nwrite != nread) { res = CURLE_SEND_ERROR; break; @@ -409,7 +408,7 @@ static CURLcode file_upload(struct connectdata *conn) if(!res && Curl_pgrsUpdate(conn)) res = CURLE_ABORTED_BY_CALLBACK; - fclose(fp); + close(fd); return res; } @@ -436,7 +435,6 @@ static CURLcode file_do(struct connectdata *conn, bool *done) curl_off_t expected_size=0; bool fstated=FALSE; ssize_t nread; - size_t bytestoread; struct SessionHandle *data = conn->data; char *buf = data->state.buffer; curl_off_t bytecount = 0; @@ -455,7 +453,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done) fd = conn->data->state.proto.file->fd; /* VMS: This only works reliable for STREAMLF files */ - if( -1 != fstat(fd, &statbuf)) { + if(-1 != fstat(fd, &statbuf)) { /* we could stat it, then read out the size */ expected_size = statbuf.st_size; /* and store the modification time */ @@ -463,6 +461,13 @@ static CURLcode file_do(struct connectdata *conn, bool *done) fstated = TRUE; } + if(fstated && !data->state.range && data->set.timecondition) { + if(!Curl_meets_timecondition(data, (time_t)data->info.filetime)) { + *done = TRUE; + return CURLE_OK; + } + } + /* If we have selected NOBODY and HEADER, it means that we only want file information. Which for FILE can't be much more than the file size and date. */ @@ -480,14 +485,13 @@ static CURLcode file_do(struct connectdata *conn, bool *done) return result; if(fstated) { - const struct tm *tm; time_t filetime = (time_t)statbuf.st_mtime; -#ifdef HAVE_GMTIME_R struct tm buffer; - tm = (const struct tm *)gmtime_r(&filetime, &buffer); -#else - tm = gmtime(&filetime); -#endif + const struct tm *tm = &buffer; + result = Curl_gmtime(filetime, &buffer); + if(result) + return result; + /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ snprintf(buf, BUFSIZE-1, "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", @@ -529,7 +533,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done) } /* A high water mark has been specified so we obey... */ - if (data->req.maxdownload > 0) + if(data->req.maxdownload > 0) expected_size = data->req.maxdownload; if(fstated && (expected_size == 0)) @@ -552,13 +556,16 @@ static CURLcode file_do(struct connectdata *conn, bool *done) while(res == CURLE_OK) { /* Don't fill a whole buffer if we want less than all data */ - bytestoread = (expected_size < BUFSIZE-1)?(size_t)expected_size:BUFSIZE-1; + size_t bytestoread = + (expected_size < CURL_OFF_T_C(BUFSIZE) - CURL_OFF_T_C(1)) ? + curlx_sotouz(expected_size) : BUFSIZE - 1; + nread = read(fd, buf, bytestoread); - if( nread > 0) + if(nread > 0) buf[nread] = 0; - if (nread <= 0 || expected_size == 0) + if(nread <= 0 || expected_size == 0) break; bytecount += nread; |