1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker
25*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
26*6236dae4SAndroid Build Coastguard Worker
27*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_FILE
28*6236dae4SAndroid Build Coastguard Worker
29*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETINET_IN_H
30*6236dae4SAndroid Build Coastguard Worker #include <netinet/in.h>
31*6236dae4SAndroid Build Coastguard Worker #endif
32*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NETDB_H
33*6236dae4SAndroid Build Coastguard Worker #include <netdb.h>
34*6236dae4SAndroid Build Coastguard Worker #endif
35*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_ARPA_INET_H
36*6236dae4SAndroid Build Coastguard Worker #include <arpa/inet.h>
37*6236dae4SAndroid Build Coastguard Worker #endif
38*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_NET_IF_H
39*6236dae4SAndroid Build Coastguard Worker #include <net/if.h>
40*6236dae4SAndroid Build Coastguard Worker #endif
41*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_SYS_IOCTL_H
42*6236dae4SAndroid Build Coastguard Worker #include <sys/ioctl.h>
43*6236dae4SAndroid Build Coastguard Worker #endif
44*6236dae4SAndroid Build Coastguard Worker
45*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_SYS_PARAM_H
46*6236dae4SAndroid Build Coastguard Worker #include <sys/param.h>
47*6236dae4SAndroid Build Coastguard Worker #endif
48*6236dae4SAndroid Build Coastguard Worker
49*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_FCNTL_H
50*6236dae4SAndroid Build Coastguard Worker #include <fcntl.h>
51*6236dae4SAndroid Build Coastguard Worker #endif
52*6236dae4SAndroid Build Coastguard Worker
53*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_SYS_TYPES_H
54*6236dae4SAndroid Build Coastguard Worker #include <sys/types.h>
55*6236dae4SAndroid Build Coastguard Worker #endif
56*6236dae4SAndroid Build Coastguard Worker
57*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_DIRENT_H
58*6236dae4SAndroid Build Coastguard Worker #include <dirent.h>
59*6236dae4SAndroid Build Coastguard Worker #endif
60*6236dae4SAndroid Build Coastguard Worker
61*6236dae4SAndroid Build Coastguard Worker #include "strtoofft.h"
62*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
63*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
64*6236dae4SAndroid Build Coastguard Worker #include "progress.h"
65*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
66*6236dae4SAndroid Build Coastguard Worker #include "escape.h"
67*6236dae4SAndroid Build Coastguard Worker #include "file.h"
68*6236dae4SAndroid Build Coastguard Worker #include "speedcheck.h"
69*6236dae4SAndroid Build Coastguard Worker #include "getinfo.h"
70*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
71*6236dae4SAndroid Build Coastguard Worker #include "transfer.h"
72*6236dae4SAndroid Build Coastguard Worker #include "url.h"
73*6236dae4SAndroid Build Coastguard Worker #include "parsedate.h" /* for the week day and month names */
74*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
75*6236dae4SAndroid Build Coastguard Worker #include "curl_range.h"
76*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
77*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
78*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
79*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
80*6236dae4SAndroid Build Coastguard Worker
81*6236dae4SAndroid Build Coastguard Worker #if defined(_WIN32) || defined(MSDOS) || defined(__EMX__)
82*6236dae4SAndroid Build Coastguard Worker #define DOS_FILESYSTEM 1
83*6236dae4SAndroid Build Coastguard Worker #elif defined(__amigaos4__)
84*6236dae4SAndroid Build Coastguard Worker #define AMIGA_FILESYSTEM 1
85*6236dae4SAndroid Build Coastguard Worker #endif
86*6236dae4SAndroid Build Coastguard Worker
87*6236dae4SAndroid Build Coastguard Worker #ifdef OPEN_NEEDS_ARG3
88*6236dae4SAndroid Build Coastguard Worker # define open_readonly(p,f) open((p),(f),(0))
89*6236dae4SAndroid Build Coastguard Worker #else
90*6236dae4SAndroid Build Coastguard Worker # define open_readonly(p,f) open((p),(f))
91*6236dae4SAndroid Build Coastguard Worker #endif
92*6236dae4SAndroid Build Coastguard Worker
93*6236dae4SAndroid Build Coastguard Worker /*
94*6236dae4SAndroid Build Coastguard Worker * Forward declarations.
95*6236dae4SAndroid Build Coastguard Worker */
96*6236dae4SAndroid Build Coastguard Worker
97*6236dae4SAndroid Build Coastguard Worker static CURLcode file_do(struct Curl_easy *data, bool *done);
98*6236dae4SAndroid Build Coastguard Worker static CURLcode file_done(struct Curl_easy *data,
99*6236dae4SAndroid Build Coastguard Worker CURLcode status, bool premature);
100*6236dae4SAndroid Build Coastguard Worker static CURLcode file_connect(struct Curl_easy *data, bool *done);
101*6236dae4SAndroid Build Coastguard Worker static CURLcode file_disconnect(struct Curl_easy *data,
102*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
103*6236dae4SAndroid Build Coastguard Worker bool dead_connection);
104*6236dae4SAndroid Build Coastguard Worker static CURLcode file_setup_connection(struct Curl_easy *data,
105*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn);
106*6236dae4SAndroid Build Coastguard Worker
107*6236dae4SAndroid Build Coastguard Worker /*
108*6236dae4SAndroid Build Coastguard Worker * FILE scheme handler.
109*6236dae4SAndroid Build Coastguard Worker */
110*6236dae4SAndroid Build Coastguard Worker
111*6236dae4SAndroid Build Coastguard Worker const struct Curl_handler Curl_handler_file = {
112*6236dae4SAndroid Build Coastguard Worker "file", /* scheme */
113*6236dae4SAndroid Build Coastguard Worker file_setup_connection, /* setup_connection */
114*6236dae4SAndroid Build Coastguard Worker file_do, /* do_it */
115*6236dae4SAndroid Build Coastguard Worker file_done, /* done */
116*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* do_more */
117*6236dae4SAndroid Build Coastguard Worker file_connect, /* connect_it */
118*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* connecting */
119*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* doing */
120*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* proto_getsock */
121*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* doing_getsock */
122*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* domore_getsock */
123*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* perform_getsock */
124*6236dae4SAndroid Build Coastguard Worker file_disconnect, /* disconnect */
125*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* write_resp */
126*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* write_resp_hd */
127*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* connection_check */
128*6236dae4SAndroid Build Coastguard Worker ZERO_NULL, /* attach connection */
129*6236dae4SAndroid Build Coastguard Worker 0, /* defport */
130*6236dae4SAndroid Build Coastguard Worker CURLPROTO_FILE, /* protocol */
131*6236dae4SAndroid Build Coastguard Worker CURLPROTO_FILE, /* family */
132*6236dae4SAndroid Build Coastguard Worker PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */
133*6236dae4SAndroid Build Coastguard Worker };
134*6236dae4SAndroid Build Coastguard Worker
135*6236dae4SAndroid Build Coastguard Worker
file_setup_connection(struct Curl_easy * data,struct connectdata * conn)136*6236dae4SAndroid Build Coastguard Worker static CURLcode file_setup_connection(struct Curl_easy *data,
137*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn)
138*6236dae4SAndroid Build Coastguard Worker {
139*6236dae4SAndroid Build Coastguard Worker (void)conn;
140*6236dae4SAndroid Build Coastguard Worker /* allocate the FILE specific struct */
141*6236dae4SAndroid Build Coastguard Worker data->req.p.file = calloc(1, sizeof(struct FILEPROTO));
142*6236dae4SAndroid Build Coastguard Worker if(!data->req.p.file)
143*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
144*6236dae4SAndroid Build Coastguard Worker
145*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
146*6236dae4SAndroid Build Coastguard Worker }
147*6236dae4SAndroid Build Coastguard Worker
148*6236dae4SAndroid Build Coastguard Worker /*
149*6236dae4SAndroid Build Coastguard Worker * file_connect() gets called from Curl_protocol_connect() to allow us to
150*6236dae4SAndroid Build Coastguard Worker * do protocol-specific actions at connect-time. We emulate a
151*6236dae4SAndroid Build Coastguard Worker * connect-then-transfer protocol and "connect" to the file here
152*6236dae4SAndroid Build Coastguard Worker */
file_connect(struct Curl_easy * data,bool * done)153*6236dae4SAndroid Build Coastguard Worker static CURLcode file_connect(struct Curl_easy *data, bool *done)
154*6236dae4SAndroid Build Coastguard Worker {
155*6236dae4SAndroid Build Coastguard Worker char *real_path;
156*6236dae4SAndroid Build Coastguard Worker struct FILEPROTO *file = data->req.p.file;
157*6236dae4SAndroid Build Coastguard Worker int fd;
158*6236dae4SAndroid Build Coastguard Worker #ifdef DOS_FILESYSTEM
159*6236dae4SAndroid Build Coastguard Worker size_t i;
160*6236dae4SAndroid Build Coastguard Worker char *actual_path;
161*6236dae4SAndroid Build Coastguard Worker #endif
162*6236dae4SAndroid Build Coastguard Worker size_t real_path_len;
163*6236dae4SAndroid Build Coastguard Worker CURLcode result;
164*6236dae4SAndroid Build Coastguard Worker
165*6236dae4SAndroid Build Coastguard Worker if(file->path) {
166*6236dae4SAndroid Build Coastguard Worker /* already connected.
167*6236dae4SAndroid Build Coastguard Worker * the handler->connect_it() is normally only called once, but
168*6236dae4SAndroid Build Coastguard Worker * FILE does a special check on setting up the connection which
169*6236dae4SAndroid Build Coastguard Worker * calls this explicitly. */
170*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
171*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
172*6236dae4SAndroid Build Coastguard Worker }
173*6236dae4SAndroid Build Coastguard Worker
174*6236dae4SAndroid Build Coastguard Worker result = Curl_urldecode(data->state.up.path, 0, &real_path,
175*6236dae4SAndroid Build Coastguard Worker &real_path_len, REJECT_ZERO);
176*6236dae4SAndroid Build Coastguard Worker if(result)
177*6236dae4SAndroid Build Coastguard Worker return result;
178*6236dae4SAndroid Build Coastguard Worker
179*6236dae4SAndroid Build Coastguard Worker #ifdef DOS_FILESYSTEM
180*6236dae4SAndroid Build Coastguard Worker /* If the first character is a slash, and there is
181*6236dae4SAndroid Build Coastguard Worker something that looks like a drive at the beginning of
182*6236dae4SAndroid Build Coastguard Worker the path, skip the slash. If we remove the initial
183*6236dae4SAndroid Build Coastguard Worker slash in all cases, paths without drive letters end up
184*6236dae4SAndroid Build Coastguard Worker relative to the current directory which is not how
185*6236dae4SAndroid Build Coastguard Worker browsers work.
186*6236dae4SAndroid Build Coastguard Worker
187*6236dae4SAndroid Build Coastguard Worker Some browsers accept | instead of : as the drive letter
188*6236dae4SAndroid Build Coastguard Worker separator, so we do too.
189*6236dae4SAndroid Build Coastguard Worker
190*6236dae4SAndroid Build Coastguard Worker On other platforms, we need the slash to indicate an
191*6236dae4SAndroid Build Coastguard Worker absolute pathname. On Windows, absolute paths start
192*6236dae4SAndroid Build Coastguard Worker with a drive letter.
193*6236dae4SAndroid Build Coastguard Worker */
194*6236dae4SAndroid Build Coastguard Worker actual_path = real_path;
195*6236dae4SAndroid Build Coastguard Worker if((actual_path[0] == '/') &&
196*6236dae4SAndroid Build Coastguard Worker actual_path[1] &&
197*6236dae4SAndroid Build Coastguard Worker (actual_path[2] == ':' || actual_path[2] == '|')) {
198*6236dae4SAndroid Build Coastguard Worker actual_path[2] = ':';
199*6236dae4SAndroid Build Coastguard Worker actual_path++;
200*6236dae4SAndroid Build Coastguard Worker real_path_len--;
201*6236dae4SAndroid Build Coastguard Worker }
202*6236dae4SAndroid Build Coastguard Worker
203*6236dae4SAndroid Build Coastguard Worker /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */
204*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < real_path_len; ++i)
205*6236dae4SAndroid Build Coastguard Worker if(actual_path[i] == '/')
206*6236dae4SAndroid Build Coastguard Worker actual_path[i] = '\\';
207*6236dae4SAndroid Build Coastguard Worker else if(!actual_path[i]) { /* binary zero */
208*6236dae4SAndroid Build Coastguard Worker Curl_safefree(real_path);
209*6236dae4SAndroid Build Coastguard Worker return CURLE_URL_MALFORMAT;
210*6236dae4SAndroid Build Coastguard Worker }
211*6236dae4SAndroid Build Coastguard Worker
212*6236dae4SAndroid Build Coastguard Worker fd = open_readonly(actual_path, O_RDONLY|O_BINARY);
213*6236dae4SAndroid Build Coastguard Worker file->path = actual_path;
214*6236dae4SAndroid Build Coastguard Worker #else
215*6236dae4SAndroid Build Coastguard Worker if(memchr(real_path, 0, real_path_len)) {
216*6236dae4SAndroid Build Coastguard Worker /* binary zeroes indicate foul play */
217*6236dae4SAndroid Build Coastguard Worker Curl_safefree(real_path);
218*6236dae4SAndroid Build Coastguard Worker return CURLE_URL_MALFORMAT;
219*6236dae4SAndroid Build Coastguard Worker }
220*6236dae4SAndroid Build Coastguard Worker
221*6236dae4SAndroid Build Coastguard Worker #ifdef AMIGA_FILESYSTEM
222*6236dae4SAndroid Build Coastguard Worker /*
223*6236dae4SAndroid Build Coastguard Worker * A leading slash in an AmigaDOS path denotes the parent
224*6236dae4SAndroid Build Coastguard Worker * directory, and hence we block this as it is relative.
225*6236dae4SAndroid Build Coastguard Worker * Absolute paths start with 'volumename:', so we check for
226*6236dae4SAndroid Build Coastguard Worker * this first. Failing that, we treat the path as a real Unix
227*6236dae4SAndroid Build Coastguard Worker * path, but only if the application was compiled with -lunix.
228*6236dae4SAndroid Build Coastguard Worker */
229*6236dae4SAndroid Build Coastguard Worker fd = -1;
230*6236dae4SAndroid Build Coastguard Worker file->path = real_path;
231*6236dae4SAndroid Build Coastguard Worker
232*6236dae4SAndroid Build Coastguard Worker if(real_path[0] == '/') {
233*6236dae4SAndroid Build Coastguard Worker extern int __unix_path_semantics;
234*6236dae4SAndroid Build Coastguard Worker if(strchr(real_path + 1, ':')) {
235*6236dae4SAndroid Build Coastguard Worker /* Amiga absolute path */
236*6236dae4SAndroid Build Coastguard Worker fd = open_readonly(real_path + 1, O_RDONLY);
237*6236dae4SAndroid Build Coastguard Worker file->path++;
238*6236dae4SAndroid Build Coastguard Worker }
239*6236dae4SAndroid Build Coastguard Worker else if(__unix_path_semantics) {
240*6236dae4SAndroid Build Coastguard Worker /* -lunix fallback */
241*6236dae4SAndroid Build Coastguard Worker fd = open_readonly(real_path, O_RDONLY);
242*6236dae4SAndroid Build Coastguard Worker }
243*6236dae4SAndroid Build Coastguard Worker }
244*6236dae4SAndroid Build Coastguard Worker #else
245*6236dae4SAndroid Build Coastguard Worker fd = open_readonly(real_path, O_RDONLY);
246*6236dae4SAndroid Build Coastguard Worker file->path = real_path;
247*6236dae4SAndroid Build Coastguard Worker #endif
248*6236dae4SAndroid Build Coastguard Worker #endif
249*6236dae4SAndroid Build Coastguard Worker Curl_safefree(file->freepath);
250*6236dae4SAndroid Build Coastguard Worker file->freepath = real_path; /* free this when done */
251*6236dae4SAndroid Build Coastguard Worker
252*6236dae4SAndroid Build Coastguard Worker file->fd = fd;
253*6236dae4SAndroid Build Coastguard Worker if(!data->state.upload && (fd == -1)) {
254*6236dae4SAndroid Build Coastguard Worker failf(data, "Couldn't open file %s", data->state.up.path);
255*6236dae4SAndroid Build Coastguard Worker file_done(data, CURLE_FILE_COULDNT_READ_FILE, FALSE);
256*6236dae4SAndroid Build Coastguard Worker return CURLE_FILE_COULDNT_READ_FILE;
257*6236dae4SAndroid Build Coastguard Worker }
258*6236dae4SAndroid Build Coastguard Worker *done = TRUE;
259*6236dae4SAndroid Build Coastguard Worker
260*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
261*6236dae4SAndroid Build Coastguard Worker }
262*6236dae4SAndroid Build Coastguard Worker
file_done(struct Curl_easy * data,CURLcode status,bool premature)263*6236dae4SAndroid Build Coastguard Worker static CURLcode file_done(struct Curl_easy *data,
264*6236dae4SAndroid Build Coastguard Worker CURLcode status, bool premature)
265*6236dae4SAndroid Build Coastguard Worker {
266*6236dae4SAndroid Build Coastguard Worker struct FILEPROTO *file = data->req.p.file;
267*6236dae4SAndroid Build Coastguard Worker (void)status; /* not used */
268*6236dae4SAndroid Build Coastguard Worker (void)premature; /* not used */
269*6236dae4SAndroid Build Coastguard Worker
270*6236dae4SAndroid Build Coastguard Worker if(file) {
271*6236dae4SAndroid Build Coastguard Worker Curl_safefree(file->freepath);
272*6236dae4SAndroid Build Coastguard Worker file->path = NULL;
273*6236dae4SAndroid Build Coastguard Worker if(file->fd != -1)
274*6236dae4SAndroid Build Coastguard Worker close(file->fd);
275*6236dae4SAndroid Build Coastguard Worker file->fd = -1;
276*6236dae4SAndroid Build Coastguard Worker }
277*6236dae4SAndroid Build Coastguard Worker
278*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
279*6236dae4SAndroid Build Coastguard Worker }
280*6236dae4SAndroid Build Coastguard Worker
file_disconnect(struct Curl_easy * data,struct connectdata * conn,bool dead_connection)281*6236dae4SAndroid Build Coastguard Worker static CURLcode file_disconnect(struct Curl_easy *data,
282*6236dae4SAndroid Build Coastguard Worker struct connectdata *conn,
283*6236dae4SAndroid Build Coastguard Worker bool dead_connection)
284*6236dae4SAndroid Build Coastguard Worker {
285*6236dae4SAndroid Build Coastguard Worker (void)dead_connection; /* not used */
286*6236dae4SAndroid Build Coastguard Worker (void)conn;
287*6236dae4SAndroid Build Coastguard Worker return file_done(data, CURLE_OK, FALSE);
288*6236dae4SAndroid Build Coastguard Worker }
289*6236dae4SAndroid Build Coastguard Worker
290*6236dae4SAndroid Build Coastguard Worker #ifdef DOS_FILESYSTEM
291*6236dae4SAndroid Build Coastguard Worker #define DIRSEP '\\'
292*6236dae4SAndroid Build Coastguard Worker #else
293*6236dae4SAndroid Build Coastguard Worker #define DIRSEP '/'
294*6236dae4SAndroid Build Coastguard Worker #endif
295*6236dae4SAndroid Build Coastguard Worker
file_upload(struct Curl_easy * data)296*6236dae4SAndroid Build Coastguard Worker static CURLcode file_upload(struct Curl_easy *data)
297*6236dae4SAndroid Build Coastguard Worker {
298*6236dae4SAndroid Build Coastguard Worker struct FILEPROTO *file = data->req.p.file;
299*6236dae4SAndroid Build Coastguard Worker const char *dir = strchr(file->path, DIRSEP);
300*6236dae4SAndroid Build Coastguard Worker int fd;
301*6236dae4SAndroid Build Coastguard Worker int mode;
302*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
303*6236dae4SAndroid Build Coastguard Worker char *xfer_ulbuf;
304*6236dae4SAndroid Build Coastguard Worker size_t xfer_ulblen;
305*6236dae4SAndroid Build Coastguard Worker curl_off_t bytecount = 0;
306*6236dae4SAndroid Build Coastguard Worker struct_stat file_stat;
307*6236dae4SAndroid Build Coastguard Worker const char *sendbuf;
308*6236dae4SAndroid Build Coastguard Worker bool eos = FALSE;
309*6236dae4SAndroid Build Coastguard Worker
310*6236dae4SAndroid Build Coastguard Worker /*
311*6236dae4SAndroid Build Coastguard Worker * Since FILE: does not do the full init, we need to provide some extra
312*6236dae4SAndroid Build Coastguard Worker * assignments here.
313*6236dae4SAndroid Build Coastguard Worker */
314*6236dae4SAndroid Build Coastguard Worker
315*6236dae4SAndroid Build Coastguard Worker if(!dir)
316*6236dae4SAndroid Build Coastguard Worker return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
317*6236dae4SAndroid Build Coastguard Worker
318*6236dae4SAndroid Build Coastguard Worker if(!dir[1])
319*6236dae4SAndroid Build Coastguard Worker return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
320*6236dae4SAndroid Build Coastguard Worker
321*6236dae4SAndroid Build Coastguard Worker #ifdef O_BINARY
322*6236dae4SAndroid Build Coastguard Worker #define MODE_DEFAULT O_WRONLY|O_CREAT|O_BINARY
323*6236dae4SAndroid Build Coastguard Worker #else
324*6236dae4SAndroid Build Coastguard Worker #define MODE_DEFAULT O_WRONLY|O_CREAT
325*6236dae4SAndroid Build Coastguard Worker #endif
326*6236dae4SAndroid Build Coastguard Worker
327*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from)
328*6236dae4SAndroid Build Coastguard Worker mode = MODE_DEFAULT|O_APPEND;
329*6236dae4SAndroid Build Coastguard Worker else
330*6236dae4SAndroid Build Coastguard Worker mode = MODE_DEFAULT|O_TRUNC;
331*6236dae4SAndroid Build Coastguard Worker
332*6236dae4SAndroid Build Coastguard Worker fd = open(file->path, mode, data->set.new_file_perms);
333*6236dae4SAndroid Build Coastguard Worker if(fd < 0) {
334*6236dae4SAndroid Build Coastguard Worker failf(data, "cannot open %s for writing", file->path);
335*6236dae4SAndroid Build Coastguard Worker return CURLE_WRITE_ERROR;
336*6236dae4SAndroid Build Coastguard Worker }
337*6236dae4SAndroid Build Coastguard Worker
338*6236dae4SAndroid Build Coastguard Worker if(-1 != data->state.infilesize)
339*6236dae4SAndroid Build Coastguard Worker /* known size of data to "upload" */
340*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetUploadSize(data, data->state.infilesize);
341*6236dae4SAndroid Build Coastguard Worker
342*6236dae4SAndroid Build Coastguard Worker /* treat the negative resume offset value as the case of "-" */
343*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from < 0) {
344*6236dae4SAndroid Build Coastguard Worker if(fstat(fd, &file_stat)) {
345*6236dae4SAndroid Build Coastguard Worker close(fd);
346*6236dae4SAndroid Build Coastguard Worker failf(data, "cannot get the size of %s", file->path);
347*6236dae4SAndroid Build Coastguard Worker return CURLE_WRITE_ERROR;
348*6236dae4SAndroid Build Coastguard Worker }
349*6236dae4SAndroid Build Coastguard Worker data->state.resume_from = (curl_off_t)file_stat.st_size;
350*6236dae4SAndroid Build Coastguard Worker }
351*6236dae4SAndroid Build Coastguard Worker
352*6236dae4SAndroid Build Coastguard Worker result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
353*6236dae4SAndroid Build Coastguard Worker if(result)
354*6236dae4SAndroid Build Coastguard Worker goto out;
355*6236dae4SAndroid Build Coastguard Worker
356*6236dae4SAndroid Build Coastguard Worker while(!result && !eos) {
357*6236dae4SAndroid Build Coastguard Worker size_t nread;
358*6236dae4SAndroid Build Coastguard Worker ssize_t nwrite;
359*6236dae4SAndroid Build Coastguard Worker size_t readcount;
360*6236dae4SAndroid Build Coastguard Worker
361*6236dae4SAndroid Build Coastguard Worker result = Curl_client_read(data, xfer_ulbuf, xfer_ulblen, &readcount, &eos);
362*6236dae4SAndroid Build Coastguard Worker if(result)
363*6236dae4SAndroid Build Coastguard Worker break;
364*6236dae4SAndroid Build Coastguard Worker
365*6236dae4SAndroid Build Coastguard Worker if(!readcount)
366*6236dae4SAndroid Build Coastguard Worker break;
367*6236dae4SAndroid Build Coastguard Worker
368*6236dae4SAndroid Build Coastguard Worker nread = readcount;
369*6236dae4SAndroid Build Coastguard Worker
370*6236dae4SAndroid Build Coastguard Worker /* skip bytes before resume point */
371*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from) {
372*6236dae4SAndroid Build Coastguard Worker if((curl_off_t)nread <= data->state.resume_from) {
373*6236dae4SAndroid Build Coastguard Worker data->state.resume_from -= nread;
374*6236dae4SAndroid Build Coastguard Worker nread = 0;
375*6236dae4SAndroid Build Coastguard Worker sendbuf = xfer_ulbuf;
376*6236dae4SAndroid Build Coastguard Worker }
377*6236dae4SAndroid Build Coastguard Worker else {
378*6236dae4SAndroid Build Coastguard Worker sendbuf = xfer_ulbuf + data->state.resume_from;
379*6236dae4SAndroid Build Coastguard Worker nread -= (size_t)data->state.resume_from;
380*6236dae4SAndroid Build Coastguard Worker data->state.resume_from = 0;
381*6236dae4SAndroid Build Coastguard Worker }
382*6236dae4SAndroid Build Coastguard Worker }
383*6236dae4SAndroid Build Coastguard Worker else
384*6236dae4SAndroid Build Coastguard Worker sendbuf = xfer_ulbuf;
385*6236dae4SAndroid Build Coastguard Worker
386*6236dae4SAndroid Build Coastguard Worker /* write the data to the target */
387*6236dae4SAndroid Build Coastguard Worker nwrite = write(fd, sendbuf, nread);
388*6236dae4SAndroid Build Coastguard Worker if((size_t)nwrite != nread) {
389*6236dae4SAndroid Build Coastguard Worker result = CURLE_SEND_ERROR;
390*6236dae4SAndroid Build Coastguard Worker break;
391*6236dae4SAndroid Build Coastguard Worker }
392*6236dae4SAndroid Build Coastguard Worker
393*6236dae4SAndroid Build Coastguard Worker bytecount += nread;
394*6236dae4SAndroid Build Coastguard Worker
395*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetUploadCounter(data, bytecount);
396*6236dae4SAndroid Build Coastguard Worker
397*6236dae4SAndroid Build Coastguard Worker if(Curl_pgrsUpdate(data))
398*6236dae4SAndroid Build Coastguard Worker result = CURLE_ABORTED_BY_CALLBACK;
399*6236dae4SAndroid Build Coastguard Worker else
400*6236dae4SAndroid Build Coastguard Worker result = Curl_speedcheck(data, Curl_now());
401*6236dae4SAndroid Build Coastguard Worker }
402*6236dae4SAndroid Build Coastguard Worker if(!result && Curl_pgrsUpdate(data))
403*6236dae4SAndroid Build Coastguard Worker result = CURLE_ABORTED_BY_CALLBACK;
404*6236dae4SAndroid Build Coastguard Worker
405*6236dae4SAndroid Build Coastguard Worker out:
406*6236dae4SAndroid Build Coastguard Worker close(fd);
407*6236dae4SAndroid Build Coastguard Worker Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);
408*6236dae4SAndroid Build Coastguard Worker
409*6236dae4SAndroid Build Coastguard Worker return result;
410*6236dae4SAndroid Build Coastguard Worker }
411*6236dae4SAndroid Build Coastguard Worker
412*6236dae4SAndroid Build Coastguard Worker /*
413*6236dae4SAndroid Build Coastguard Worker * file_do() is the protocol-specific function for the do-phase, separated
414*6236dae4SAndroid Build Coastguard Worker * from the connect-phase above. Other protocols merely setup the transfer in
415*6236dae4SAndroid Build Coastguard Worker * the do-phase, to have it done in the main transfer loop but since some
416*6236dae4SAndroid Build Coastguard Worker * platforms we support do not allow select()ing etc on file handles (as
417*6236dae4SAndroid Build Coastguard Worker * opposed to sockets) we instead perform the whole do-operation in this
418*6236dae4SAndroid Build Coastguard Worker * function.
419*6236dae4SAndroid Build Coastguard Worker */
file_do(struct Curl_easy * data,bool * done)420*6236dae4SAndroid Build Coastguard Worker static CURLcode file_do(struct Curl_easy *data, bool *done)
421*6236dae4SAndroid Build Coastguard Worker {
422*6236dae4SAndroid Build Coastguard Worker /* This implementation ignores the hostname in conformance with
423*6236dae4SAndroid Build Coastguard Worker RFC 1738. Only local files (reachable via the standard file system)
424*6236dae4SAndroid Build Coastguard Worker are supported. This means that files on remotely mounted directories
425*6236dae4SAndroid Build Coastguard Worker (via NFS, Samba, NT sharing) can be accessed through a file:// URL
426*6236dae4SAndroid Build Coastguard Worker */
427*6236dae4SAndroid Build Coastguard Worker CURLcode result = CURLE_OK;
428*6236dae4SAndroid Build Coastguard Worker struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
429*6236dae4SAndroid Build Coastguard Worker Windows version to have a different struct without
430*6236dae4SAndroid Build Coastguard Worker having to redefine the simple word 'stat' */
431*6236dae4SAndroid Build Coastguard Worker curl_off_t expected_size = -1;
432*6236dae4SAndroid Build Coastguard Worker bool size_known;
433*6236dae4SAndroid Build Coastguard Worker bool fstated = FALSE;
434*6236dae4SAndroid Build Coastguard Worker int fd;
435*6236dae4SAndroid Build Coastguard Worker struct FILEPROTO *file;
436*6236dae4SAndroid Build Coastguard Worker char *xfer_buf;
437*6236dae4SAndroid Build Coastguard Worker size_t xfer_blen;
438*6236dae4SAndroid Build Coastguard Worker
439*6236dae4SAndroid Build Coastguard Worker *done = TRUE; /* unconditionally */
440*6236dae4SAndroid Build Coastguard Worker
441*6236dae4SAndroid Build Coastguard Worker if(data->state.upload)
442*6236dae4SAndroid Build Coastguard Worker return file_upload(data);
443*6236dae4SAndroid Build Coastguard Worker
444*6236dae4SAndroid Build Coastguard Worker file = data->req.p.file;
445*6236dae4SAndroid Build Coastguard Worker
446*6236dae4SAndroid Build Coastguard Worker /* get the fd from the connection phase */
447*6236dae4SAndroid Build Coastguard Worker fd = file->fd;
448*6236dae4SAndroid Build Coastguard Worker
449*6236dae4SAndroid Build Coastguard Worker /* VMS: This only works reliable for STREAMLF files */
450*6236dae4SAndroid Build Coastguard Worker if(-1 != fstat(fd, &statbuf)) {
451*6236dae4SAndroid Build Coastguard Worker if(!S_ISDIR(statbuf.st_mode))
452*6236dae4SAndroid Build Coastguard Worker expected_size = statbuf.st_size;
453*6236dae4SAndroid Build Coastguard Worker /* and store the modification time */
454*6236dae4SAndroid Build Coastguard Worker data->info.filetime = statbuf.st_mtime;
455*6236dae4SAndroid Build Coastguard Worker fstated = TRUE;
456*6236dae4SAndroid Build Coastguard Worker }
457*6236dae4SAndroid Build Coastguard Worker
458*6236dae4SAndroid Build Coastguard Worker if(fstated && !data->state.range && data->set.timecondition &&
459*6236dae4SAndroid Build Coastguard Worker !Curl_meets_timecondition(data, data->info.filetime))
460*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
461*6236dae4SAndroid Build Coastguard Worker
462*6236dae4SAndroid Build Coastguard Worker if(fstated) {
463*6236dae4SAndroid Build Coastguard Worker time_t filetime;
464*6236dae4SAndroid Build Coastguard Worker struct tm buffer;
465*6236dae4SAndroid Build Coastguard Worker const struct tm *tm = &buffer;
466*6236dae4SAndroid Build Coastguard Worker char header[80];
467*6236dae4SAndroid Build Coastguard Worker int headerlen;
468*6236dae4SAndroid Build Coastguard Worker static const char accept_ranges[]= { "Accept-ranges: bytes\r\n" };
469*6236dae4SAndroid Build Coastguard Worker if(expected_size >= 0) {
470*6236dae4SAndroid Build Coastguard Worker headerlen =
471*6236dae4SAndroid Build Coastguard Worker msnprintf(header, sizeof(header), "Content-Length: %" FMT_OFF_T "\r\n",
472*6236dae4SAndroid Build Coastguard Worker expected_size);
473*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
474*6236dae4SAndroid Build Coastguard Worker if(result)
475*6236dae4SAndroid Build Coastguard Worker return result;
476*6236dae4SAndroid Build Coastguard Worker
477*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_HEADER,
478*6236dae4SAndroid Build Coastguard Worker accept_ranges, sizeof(accept_ranges) - 1);
479*6236dae4SAndroid Build Coastguard Worker if(result != CURLE_OK)
480*6236dae4SAndroid Build Coastguard Worker return result;
481*6236dae4SAndroid Build Coastguard Worker }
482*6236dae4SAndroid Build Coastguard Worker
483*6236dae4SAndroid Build Coastguard Worker filetime = (time_t)statbuf.st_mtime;
484*6236dae4SAndroid Build Coastguard Worker result = Curl_gmtime(filetime, &buffer);
485*6236dae4SAndroid Build Coastguard Worker if(result)
486*6236dae4SAndroid Build Coastguard Worker return result;
487*6236dae4SAndroid Build Coastguard Worker
488*6236dae4SAndroid Build Coastguard Worker /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
489*6236dae4SAndroid Build Coastguard Worker headerlen =
490*6236dae4SAndroid Build Coastguard Worker msnprintf(header, sizeof(header),
491*6236dae4SAndroid Build Coastguard Worker "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
492*6236dae4SAndroid Build Coastguard Worker Curl_wkday[tm->tm_wday ? tm->tm_wday-1 : 6],
493*6236dae4SAndroid Build Coastguard Worker tm->tm_mday,
494*6236dae4SAndroid Build Coastguard Worker Curl_month[tm->tm_mon],
495*6236dae4SAndroid Build Coastguard Worker tm->tm_year + 1900,
496*6236dae4SAndroid Build Coastguard Worker tm->tm_hour,
497*6236dae4SAndroid Build Coastguard Worker tm->tm_min,
498*6236dae4SAndroid Build Coastguard Worker tm->tm_sec);
499*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
500*6236dae4SAndroid Build Coastguard Worker if(!result)
501*6236dae4SAndroid Build Coastguard Worker /* end of headers */
502*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_HEADER, "\r\n", 2);
503*6236dae4SAndroid Build Coastguard Worker if(result)
504*6236dae4SAndroid Build Coastguard Worker return result;
505*6236dae4SAndroid Build Coastguard Worker /* set the file size to make it available post transfer */
506*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetDownloadSize(data, expected_size);
507*6236dae4SAndroid Build Coastguard Worker if(data->req.no_body)
508*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
509*6236dae4SAndroid Build Coastguard Worker }
510*6236dae4SAndroid Build Coastguard Worker
511*6236dae4SAndroid Build Coastguard Worker /* Check whether file range has been specified */
512*6236dae4SAndroid Build Coastguard Worker result = Curl_range(data);
513*6236dae4SAndroid Build Coastguard Worker if(result)
514*6236dae4SAndroid Build Coastguard Worker return result;
515*6236dae4SAndroid Build Coastguard Worker
516*6236dae4SAndroid Build Coastguard Worker /* Adjust the start offset in case we want to get the N last bytes
517*6236dae4SAndroid Build Coastguard Worker * of the stream if the filesize could be determined */
518*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from < 0) {
519*6236dae4SAndroid Build Coastguard Worker if(!fstated) {
520*6236dae4SAndroid Build Coastguard Worker failf(data, "cannot get the size of file.");
521*6236dae4SAndroid Build Coastguard Worker return CURLE_READ_ERROR;
522*6236dae4SAndroid Build Coastguard Worker }
523*6236dae4SAndroid Build Coastguard Worker data->state.resume_from += (curl_off_t)statbuf.st_size;
524*6236dae4SAndroid Build Coastguard Worker }
525*6236dae4SAndroid Build Coastguard Worker
526*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from > 0) {
527*6236dae4SAndroid Build Coastguard Worker /* We check explicitly if we have a start offset, because
528*6236dae4SAndroid Build Coastguard Worker * expected_size may be -1 if we do not know how large the file is,
529*6236dae4SAndroid Build Coastguard Worker * in which case we should not adjust it. */
530*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from <= expected_size)
531*6236dae4SAndroid Build Coastguard Worker expected_size -= data->state.resume_from;
532*6236dae4SAndroid Build Coastguard Worker else {
533*6236dae4SAndroid Build Coastguard Worker failf(data, "failed to resume file:// transfer");
534*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_DOWNLOAD_RESUME;
535*6236dae4SAndroid Build Coastguard Worker }
536*6236dae4SAndroid Build Coastguard Worker }
537*6236dae4SAndroid Build Coastguard Worker
538*6236dae4SAndroid Build Coastguard Worker /* A high water mark has been specified so we obey... */
539*6236dae4SAndroid Build Coastguard Worker if(data->req.maxdownload > 0)
540*6236dae4SAndroid Build Coastguard Worker expected_size = data->req.maxdownload;
541*6236dae4SAndroid Build Coastguard Worker
542*6236dae4SAndroid Build Coastguard Worker if(!fstated || (expected_size <= 0))
543*6236dae4SAndroid Build Coastguard Worker size_known = FALSE;
544*6236dae4SAndroid Build Coastguard Worker else
545*6236dae4SAndroid Build Coastguard Worker size_known = TRUE;
546*6236dae4SAndroid Build Coastguard Worker
547*6236dae4SAndroid Build Coastguard Worker /* The following is a shortcut implementation of file reading
548*6236dae4SAndroid Build Coastguard Worker this is both more efficient than the former call to download() and
549*6236dae4SAndroid Build Coastguard Worker it avoids problems with select() and recv() on file descriptors
550*6236dae4SAndroid Build Coastguard Worker in Winsock */
551*6236dae4SAndroid Build Coastguard Worker if(size_known)
552*6236dae4SAndroid Build Coastguard Worker Curl_pgrsSetDownloadSize(data, expected_size);
553*6236dae4SAndroid Build Coastguard Worker
554*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from) {
555*6236dae4SAndroid Build Coastguard Worker if(!S_ISDIR(statbuf.st_mode)) {
556*6236dae4SAndroid Build Coastguard Worker if(data->state.resume_from !=
557*6236dae4SAndroid Build Coastguard Worker lseek(fd, data->state.resume_from, SEEK_SET))
558*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_DOWNLOAD_RESUME;
559*6236dae4SAndroid Build Coastguard Worker }
560*6236dae4SAndroid Build Coastguard Worker else {
561*6236dae4SAndroid Build Coastguard Worker return CURLE_BAD_DOWNLOAD_RESUME;
562*6236dae4SAndroid Build Coastguard Worker }
563*6236dae4SAndroid Build Coastguard Worker }
564*6236dae4SAndroid Build Coastguard Worker
565*6236dae4SAndroid Build Coastguard Worker result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
566*6236dae4SAndroid Build Coastguard Worker if(result)
567*6236dae4SAndroid Build Coastguard Worker goto out;
568*6236dae4SAndroid Build Coastguard Worker
569*6236dae4SAndroid Build Coastguard Worker if(!S_ISDIR(statbuf.st_mode)) {
570*6236dae4SAndroid Build Coastguard Worker while(!result) {
571*6236dae4SAndroid Build Coastguard Worker ssize_t nread;
572*6236dae4SAndroid Build Coastguard Worker /* Do not fill a whole buffer if we want less than all data */
573*6236dae4SAndroid Build Coastguard Worker size_t bytestoread;
574*6236dae4SAndroid Build Coastguard Worker
575*6236dae4SAndroid Build Coastguard Worker if(size_known) {
576*6236dae4SAndroid Build Coastguard Worker bytestoread = (expected_size < (curl_off_t)(xfer_blen-1)) ?
577*6236dae4SAndroid Build Coastguard Worker curlx_sotouz(expected_size) : (xfer_blen-1);
578*6236dae4SAndroid Build Coastguard Worker }
579*6236dae4SAndroid Build Coastguard Worker else
580*6236dae4SAndroid Build Coastguard Worker bytestoread = xfer_blen-1;
581*6236dae4SAndroid Build Coastguard Worker
582*6236dae4SAndroid Build Coastguard Worker nread = read(fd, xfer_buf, bytestoread);
583*6236dae4SAndroid Build Coastguard Worker
584*6236dae4SAndroid Build Coastguard Worker if(nread > 0)
585*6236dae4SAndroid Build Coastguard Worker xfer_buf[nread] = 0;
586*6236dae4SAndroid Build Coastguard Worker
587*6236dae4SAndroid Build Coastguard Worker if(nread <= 0 || (size_known && (expected_size == 0)))
588*6236dae4SAndroid Build Coastguard Worker break;
589*6236dae4SAndroid Build Coastguard Worker
590*6236dae4SAndroid Build Coastguard Worker if(size_known)
591*6236dae4SAndroid Build Coastguard Worker expected_size -= nread;
592*6236dae4SAndroid Build Coastguard Worker
593*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_BODY, xfer_buf, nread);
594*6236dae4SAndroid Build Coastguard Worker if(result)
595*6236dae4SAndroid Build Coastguard Worker goto out;
596*6236dae4SAndroid Build Coastguard Worker
597*6236dae4SAndroid Build Coastguard Worker if(Curl_pgrsUpdate(data))
598*6236dae4SAndroid Build Coastguard Worker result = CURLE_ABORTED_BY_CALLBACK;
599*6236dae4SAndroid Build Coastguard Worker else
600*6236dae4SAndroid Build Coastguard Worker result = Curl_speedcheck(data, Curl_now());
601*6236dae4SAndroid Build Coastguard Worker if(result)
602*6236dae4SAndroid Build Coastguard Worker goto out;
603*6236dae4SAndroid Build Coastguard Worker }
604*6236dae4SAndroid Build Coastguard Worker }
605*6236dae4SAndroid Build Coastguard Worker else {
606*6236dae4SAndroid Build Coastguard Worker #ifdef HAVE_OPENDIR
607*6236dae4SAndroid Build Coastguard Worker DIR *dir = opendir(file->path);
608*6236dae4SAndroid Build Coastguard Worker struct dirent *entry;
609*6236dae4SAndroid Build Coastguard Worker
610*6236dae4SAndroid Build Coastguard Worker if(!dir) {
611*6236dae4SAndroid Build Coastguard Worker result = CURLE_READ_ERROR;
612*6236dae4SAndroid Build Coastguard Worker goto out;
613*6236dae4SAndroid Build Coastguard Worker }
614*6236dae4SAndroid Build Coastguard Worker else {
615*6236dae4SAndroid Build Coastguard Worker while((entry = readdir(dir))) {
616*6236dae4SAndroid Build Coastguard Worker if(entry->d_name[0] != '.') {
617*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_BODY,
618*6236dae4SAndroid Build Coastguard Worker entry->d_name, strlen(entry->d_name));
619*6236dae4SAndroid Build Coastguard Worker if(result)
620*6236dae4SAndroid Build Coastguard Worker break;
621*6236dae4SAndroid Build Coastguard Worker result = Curl_client_write(data, CLIENTWRITE_BODY, "\n", 1);
622*6236dae4SAndroid Build Coastguard Worker if(result)
623*6236dae4SAndroid Build Coastguard Worker break;
624*6236dae4SAndroid Build Coastguard Worker }
625*6236dae4SAndroid Build Coastguard Worker }
626*6236dae4SAndroid Build Coastguard Worker closedir(dir);
627*6236dae4SAndroid Build Coastguard Worker }
628*6236dae4SAndroid Build Coastguard Worker #else
629*6236dae4SAndroid Build Coastguard Worker failf(data, "Directory listing not yet implemented on this platform.");
630*6236dae4SAndroid Build Coastguard Worker result = CURLE_READ_ERROR;
631*6236dae4SAndroid Build Coastguard Worker #endif
632*6236dae4SAndroid Build Coastguard Worker }
633*6236dae4SAndroid Build Coastguard Worker
634*6236dae4SAndroid Build Coastguard Worker if(Curl_pgrsUpdate(data))
635*6236dae4SAndroid Build Coastguard Worker result = CURLE_ABORTED_BY_CALLBACK;
636*6236dae4SAndroid Build Coastguard Worker
637*6236dae4SAndroid Build Coastguard Worker out:
638*6236dae4SAndroid Build Coastguard Worker Curl_multi_xfer_buf_release(data, xfer_buf);
639*6236dae4SAndroid Build Coastguard Worker return result;
640*6236dae4SAndroid Build Coastguard Worker }
641*6236dae4SAndroid Build Coastguard Worker
642*6236dae4SAndroid Build Coastguard Worker #endif
643