xref: /aosp_15_r20/external/curl/lib/file.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
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