1
/*****************************************************************************
1
/***************************************************************************
3
3
* Project ___| | | | _ \| |
4
4
* / __| | | | |_) | |
5
5
* | (__| |_| | _ <| |___
6
6
* \___|\___/|_| \_\_____|
8
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
10
* In order to be useful for every potential user, curl and libcurl are
11
* dual-licensed under the MPL and the MIT/X-derivate licenses.
8
* Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
10
* This software is licensed as described in the file COPYING, which
11
* you should have received as part of this distribution. The terms
12
* are also available at http://curl.haxx.se/docs/copyright.html.
13
14
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
14
15
* copies of the Software, and permit persons to whom the Software is
15
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
16
* licenses. You may pick one of these licenses.
16
* furnished to do so, under the terms of the COPYING file.
18
18
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
* KIND, either express or implied.
21
* $Id: file.c,v 1.22 2001/10/11 09:32:19 bumblebury Exp $
22
*****************************************************************************/
21
* $Id: file.c,v 1.53 2004/04/06 15:14:10 bagder Exp $
22
***************************************************************************/
26
#ifndef CURL_DISABLE_FILE
26
27
/* -- WIN32 approved -- */
28
29
#include <string.h>
82
81
#include "progress.h"
84
83
#include "escape.h"
85
#include "speedcheck.h"
87
#include "transfer.h" /* for Curl_readwrite_init() */
86
89
#define _MPRINTF_REPLACE /* use our functions only */
87
90
#include <curl/mprintf.h>
89
92
/* The last #include file should be: */
91
94
#include "memdebug.h"
94
97
/* Emulate a connect-then-transfer protocol. We connect to the file here */
95
98
CURLcode Curl_file_connect(struct connectdata *conn)
97
char *actual_path = curl_unescape(conn->path, 0);
100
char *real_path = curl_unescape(conn->path, 0);
101
struct FILEPROTO *file;
100
103
#if defined(WIN32) || defined(__EMX__)
104
file = (struct FILE *)malloc(sizeof(struct FILE));
108
file = (struct FILEPROTO *)calloc(sizeof(struct FILEPROTO), 1);
106
110
return CURLE_OUT_OF_MEMORY;
108
memset(file, 0, sizeof(struct FILE));
109
112
conn->proto.file = file;
111
114
#if defined(WIN32) || defined(__EMX__)
115
/* If the first character is a slash, and there's
116
something that looks like a drive at the beginning of
117
the path, skip the slash. If we remove the initial
118
slash in all cases, paths without drive letters end up
119
relative to the current directory which isn't how
122
Some browsers accept | instead of : as the drive letter
123
separator, so we do too.
125
On other platforms, we need the slash to indicate an
126
absolute pathname. On Windows, absolute paths start
129
actual_path = real_path;
130
if ((actual_path[0] == '/') &&
132
(actual_path[2] == ':' || actual_path[2] == '|'))
134
actual_path[2] = ':';
112
138
/* change path separators from '/' to '\\' for Windows and OS/2 */
113
139
for (i=0; actual_path[i] != '\0'; ++i)
114
140
if (actual_path[i] == '/')
141
171
CURLcode res = CURLE_OK;
142
172
struct stat statbuf;
143
ssize_t expected_size=-1;
173
curl_off_t expected_size=0;
145
176
struct SessionHandle *data = conn->data;
146
177
char *buf = data->state.buffer;
148
struct timeval start = Curl_tvnow();
149
struct timeval now = start;
178
curl_off_t bytecount = 0;
180
struct timeval now = Curl_tvnow();
182
Curl_readwrite_init(conn);
184
Curl_pgrsStartNow(data);
152
186
/* get the fd from the connection phase */
153
187
fd = conn->proto.file->fd;
155
/*VMS?? -- This only works reliable for STREAMLF files */
189
/* VMS: This only works reliable for STREAMLF files */
156
190
if( -1 != fstat(fd, &statbuf)) {
157
191
/* we could stat it, then read out the size */
158
192
expected_size = statbuf.st_size;
196
/* If we have selected NOBODY and HEADER, it means that we only want file
197
information. Which for FILE can't be much more than the file size and
199
if(conn->bits.no_body && data->set.include_header && fstated) {
201
sprintf(buf, "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size);
202
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
206
sprintf(buf, "Accept-ranges: bytes\r\n");
207
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
214
time_t clock = (time_t)statbuf.st_mtime;
217
tm = (struct tm *)gmtime_r(&clock, &buffer);
221
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
222
strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
224
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
230
/* Added by Dolbneff A.V & Spiridonoff A.V */
231
if (conn->resume_from <= expected_size)
232
expected_size -= conn->resume_from;
234
/* Is this error code suitable in such situation? */
235
return CURLE_FTP_BAD_DOWNLOAD_RESUME;
237
if (fstated && (expected_size == 0))
161
240
/* The following is a shortcut implementation of file reading
162
241
this is both more efficient than the former call to download() and
163
242
it avoids problems with select() and recv() on file descriptors
165
if(expected_size != -1)
166
245
Curl_pgrsSetDownloadSize(data, expected_size);
247
if(conn->resume_from)
248
lseek(fd, conn->resume_from, SEEK_SET);
250
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
168
252
while (res == CURLE_OK) {
169
253
nread = read(fd, buf, BUFSIZE-1);