Coverity: fileio module memory errors fixed.
[scilab.git] / scilab / modules / fileio / src / c / dlManager.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012-2013 - S/E - Sylvestre LEDRU
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15
16 #ifndef _MSC_VER
17 #define _GNU_SOURCE             /* basename crashes this extension otherwise */
18 #endif
19 #include "sci_malloc.h"
20 #include <curl/curl.h>
21 #include <libxml/uri.h>
22 #include <string.h>
23 #include "dlManager.h"
24 #include "Scierror.h"
25 #include "sci_home.h"
26 #include "PATH_MAX.h"
27 #include "isdir.h"
28 #include "charEncoding.h"
29 #include "localization.h"
30 #include "getos.h"
31 #include "machine.h"
32 #include "scicurdir.h"
33 #include "splitpath.h"
34 #include "getScilabPreference.h"
35 #include "os_string.h"
36 #include "freeArrayOfString.h"
37 /* ==================================================================== */
38 #ifndef HAVE_BASENAME
39 static char *Curl_basename(char *path);
40 #define basename(x)  Curl_basename((x))
41 #endif
42 /* ==================================================================== */
43 static char errorBuffer[CURL_ERROR_SIZE];
44 /* ==================================================================== */
45 static int getProxyValues(char **proxyHost, long *proxyPort, char **proxyUserPwd);
46 /* ==================================================================== */
47 typedef struct __INPUTSTRING__
48 {
49     char *ptr;
50     size_t len;
51 } inputString;
52 /* ==================================================================== */
53 static void init_string(inputString *s)
54 {
55     s->len = 0;
56     s->ptr = (char*)CALLOC(s->len + 1, sizeof(char));
57     if (s->ptr == NULL)
58     {
59         Scierror(999, "Internal error: calloc() failed.\n");
60         return;
61     }
62 }
63 /* ==================================================================== */
64 static void free_string(inputString *s)
65 {
66     if (s->ptr)
67     {
68         FREE(s->ptr);
69         s->ptr = NULL;
70     }
71 }
72 /* ==================================================================== */
73 static size_t writefunc(void *ptr, size_t size, size_t nmemb, inputString *s)
74 {
75     size_t new_len = s->len + size * nmemb;
76
77     s->ptr = (char*)REALLOC(s->ptr, new_len + 1);
78     if (s->ptr == NULL)
79     {
80         Scierror(999, "Internal error: realloc() failed.\n");
81         return 0;
82     }
83     memcpy(s->ptr + s->len, ptr, size * nmemb);
84     s->ptr[new_len] = '\0';
85     s->len = new_len;
86
87     return size * nmemb;
88 }
89 /* ==================================================================== */
90 static char *getFileNameFromURL(char *url)
91 {
92     char *filename = NULL;
93     xmlURIPtr c = xmlParseURI(url);
94
95     if (c == NULL)
96     {
97         Scierror(999, _("Could not parse the URL.\n"));
98         return NULL;
99     }
100
101     if (c->path == NULL || strstr(c->path, "/") == 0 || strcmp(c->path, "/") == 0)
102     {
103         filename = (char *)MALLOC((strlen(DEFAULT_FILENAME) + 1) * sizeof(char));
104         strcpy(filename, DEFAULT_FILENAME);
105     }
106     else
107     {
108         char bname[PATH_MAX] = {0};
109         strncpy(bname, basename(c->path), sizeof(bname));
110         filename = (char *)MALLOC((strlen(bname) + 1) * sizeof(char));
111         strcpy(filename, bname);
112     }
113     return filename;
114
115 }
116 /* ==================================================================== */
117 int getProxyValues(char **proxyHost, long *proxyPort, char **proxyUserPwd)
118 {
119     const char * attrs[] = {"enabled", "host", "port", "user", "password"};
120     const unsigned int N = sizeof(attrs) / sizeof(char*);
121     char ** values = getPrefAttributesValues("//web/body/proxy", attrs, N);
122
123     if (!values)
124     {
125         return 0;
126     }
127
128     if (stricmp(values[0]/*enabled*/, "true") == 0)
129     {
130         const unsigned int ulen = (const unsigned int)strlen(values[3]);
131         const unsigned int plen = (const unsigned int)strlen(values[4]);
132
133         *proxyHost = values[1]; //host;
134         *proxyPort = strtol(values[2], NULL, 10); //port;
135         FREE(values[2]);
136
137         if (plen == 0)
138         {
139             *proxyUserPwd = values[3]; //user
140         }
141         else
142         {
143             *proxyUserPwd = (char *)MALLOC((ulen + 1 + plen + 1) * sizeof(char));
144             sprintf(*proxyUserPwd, "%s:%s", values[3]/*user*/, values[4]/*password*/);
145             (*proxyUserPwd)[ulen + 1 + plen] = '\0';
146             FREE(values[3]);
147         }
148
149         FREE(values[4]);
150         FREE(values[0]);
151         FREE(values);
152     }
153     else
154     {
155         freeArrayOfString(values, N);
156         return 0;
157     }
158
159     return 1;
160 }
161 /* ==================================================================== */
162 char *downloadFile(char *url, char *dest, char *username, char *password, char **content)
163 {
164     CURL *curl;
165     CURLcode res;
166     char *filename = NULL;
167     FILE *file;
168     inputString buffer;
169     char *destdir = NULL;
170     char *destfile = NULL;
171
172     curl = curl_easy_init();
173     if (curl == NULL)
174     {
175         Scierror(999, "Failed opening the curl handle.\n");
176         return NULL;
177     }
178
179     res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
180     if (res != CURLE_OK)
181     {
182         Scierror(999, "Failed to set error buffer [%d]\n", res);
183         return NULL;
184     }
185
186     // Get destination directory and filename
187     if (dest != NULL)
188     {
189         // Destination is specified in argument
190         char* pathdrive = (char*)MALLOC(sizeof(char) * (PATH_MAX + 1));
191         char* pathdir = (char*)MALLOC(sizeof(char) * (PATH_MAX + 1));
192         char* pathfile = (char*)MALLOC(sizeof(char) * (PATH_MAX + 1));
193         char* pathext = (char*)MALLOC(sizeof(char) * (PATH_MAX + 1));
194
195         splitpath(dest, TRUE, pathdrive, pathdir, pathfile, pathext);
196
197         if (!isdir(dest))
198         {
199             // Destination is a file
200             destdir = (char *)MALLOC((strlen(pathdrive) + strlen(pathdir) + 1) * sizeof(char));
201             strcpy(destdir, pathdrive);
202             strcat(destdir, pathdir);
203
204             // Get filename
205             destfile = (char *)MALLOC((strlen(pathfile) + strlen(pathext) + 1) * sizeof(char));
206             strcpy(destfile, pathfile);
207             strcat(destfile, pathext);
208         }
209         else
210         {
211             // Destination is a directory
212             destdir = (char *)MALLOC((strlen(pathdrive) + strlen(pathdir) + strlen(pathfile) + strlen(pathext) + strlen(DIR_SEPARATOR) + 1) * sizeof(char));
213             strcpy(destdir, pathdrive);
214             strcat(destdir, pathdir);
215             strcat(destdir, pathfile);
216             strcat(destdir, pathext);
217             strcat(destdir, DIR_SEPARATOR);
218
219             // Retrieve filename from URL
220             destfile = getFileNameFromURL(url);
221         }
222
223         FREE(pathdrive);
224         FREE(pathdir);
225         FREE(pathfile);
226         FREE(pathext);
227     }
228     else
229     {
230         // Destination is not specified in argument
231         // Destination directory is current dir
232         int err = 0;
233         char *currentdir;
234         currentdir = scigetcwd(&err);
235         if (!err)
236         {
237             destdir = (char *)MALLOC((strlen(currentdir) + strlen(DIR_SEPARATOR) + 1) * sizeof(char));
238             strcpy(destdir, currentdir);
239             strcat(destdir, DIR_SEPARATOR);
240             FREE(currentdir);
241         }
242         else
243         {
244             Scierror(999, _("Failed getting current dir, error code: %d\n"), err);
245             return NULL;
246         }
247
248         // Destination filename retrieved from URL
249         destfile = getFileNameFromURL(url);
250     }
251
252     if (destfile == NULL)
253     {
254         FREE(destdir);
255         return NULL;
256     }
257
258     // Build file path
259     filename = (char *)MALLOC((strlen(destdir) + strlen(destfile) + 1) * sizeof(char));
260     strcpy(filename, destdir);
261     strcat(filename, destfile);
262     FREE(destdir);
263     FREE(destfile);
264
265     res = curl_easy_setopt(curl, CURLOPT_URL, url);
266     if (res != CURLE_OK)
267     {
268         Scierror(999, _("Failed to set URL [%s]\n"), errorBuffer);
269         FREE(filename);
270         return NULL;
271     }
272
273     //Set authentication variables
274     if (username != NULL)
275     {
276         char * userpass;
277         int uplen = (int)strlen(username);
278         if (password != NULL)
279         {
280             uplen = uplen + (int)strlen(password);
281         }
282
283         res = curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
284         if (res != CURLE_OK)
285         {
286             Scierror(999, "Failed to set httpauth type to ANY [%s]\n", errorBuffer);
287             FREE(filename);
288             return NULL;
289         }
290
291         userpass = (char *)MALLOC((uplen + 2) * sizeof(char));
292         strcpy(userpass, username);
293         strcat(userpass, ":");
294         if (password != NULL)
295         {
296             strcat(userpass, password);
297         }
298
299         res = curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
300         if (res != CURLE_OK)
301         {
302             Scierror(999, _("Failed to set user:pwd [%s]\n"), errorBuffer);
303             FREE(filename);
304             return NULL;
305         }
306
307         FREE(userpass);
308     } /* end authentication section */
309
310     {
311         //Set proxy variables
312         char *proxyHost = NULL;
313         char *proxyUserPwd = NULL;
314         long proxyPort = 1080;
315         int proxySet = 0;
316
317         proxySet = getProxyValues(&proxyHost, &proxyPort, &proxyUserPwd);
318
319         if (proxySet == 1)
320         {
321             res = curl_easy_setopt(curl, CURLOPT_PROXY, proxyHost);
322             if (res != CURLE_OK)
323             {
324                 Scierror(999, _("Failed to set proxy host [%s]\n"), errorBuffer);
325                 FREE(proxyHost);
326                 FREE(proxyUserPwd);
327                 FREE(filename);
328                 return NULL;
329             }
330
331             res = curl_easy_setopt(curl, CURLOPT_PROXYPORT, proxyPort);
332             if (res != CURLE_OK)
333             {
334                 Scierror(999, _("Failed to set proxy port [%s]\n"), errorBuffer);
335                 FREE(proxyHost);
336                 FREE(proxyUserPwd);
337                 FREE(filename);
338                 return NULL;
339             }
340             if (proxyUserPwd != NULL)
341             {
342                 res = curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxyUserPwd);
343                 if (res != CURLE_OK)
344                 {
345                     Scierror(999, _("Failed to set proxy user:password [%s]\n"), errorBuffer);
346                     FREE(proxyHost);
347                     FREE(proxyUserPwd);
348                     FREE(filename);
349                     return NULL;
350                 }
351             }
352
353             FREE(proxyHost);
354             FREE(proxyUserPwd);
355         }
356     } /* end of the set of the proxy */
357
358     res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
359     if (res != CURLE_OK)
360     {
361         Scierror(999, _("Failed to set write function [%s]\n"), errorBuffer);
362         FREE(filename);
363         return NULL;
364     }
365
366     init_string(&buffer);
367
368     //Get data to be written to the variable
369     res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
370     if (res != CURLE_OK)
371     {
372         Scierror(999, _("Failed to set write data [%s]\n"), errorBuffer);
373         FREE(filename);
374         free_string(&buffer);
375         return NULL;
376     }
377
378     // Follow redirects
379     res = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
380     if (res != CURLE_OK)
381     {
382         Scierror(999, _("Failed to set 'Follow Location' [%s]\n"), errorBuffer);
383         FREE(filename);
384         free_string(&buffer);
385         return NULL;
386     }
387
388     res = curl_easy_perform(curl);
389     if (res != 0)
390     {
391         Scierror(999, _("Transfer did not complete successfully: %s\n"), errorBuffer);
392         FREE(filename);
393         free_string(&buffer);
394         return NULL;
395     }
396
397     wcfopen(file, (char*)filename, "wb");
398     if (file == NULL)
399     {
400         Scierror(999, _("Failed opening '%s' for writing.\n"), filename);
401         free_string(&buffer);
402         FREE(filename);
403         return NULL;
404     }
405
406     /* Write the file */
407     fwrite(buffer.ptr, sizeof(char), buffer.len, file);
408
409     /* Create the variable which contains the output argument */
410     *content = buffer.ptr;
411
412     /* always cleanup */
413     curl_easy_cleanup(curl);
414
415     fclose(file);
416     return filename;
417 }
418 /* ==================================================================== */
419 static char *Curl_basename(char *path)
420 {
421     char *s1 = NULL;
422     char *s2 = NULL;
423
424     s1 = strrchr(path, '/');
425     s2 = strrchr(path, '\\');
426
427     if (s1 && s2)
428     {
429         path = (s1 > s2 ? s1 : s2) + 1;
430     }
431     else if (s1)
432     {
433         path = s1 + 1;
434     }
435     else if (s2)
436     {
437         path = s2 + 1;
438     }
439     return path;
440 }
441 /* ==================================================================== */