5dd5ff722d461cffb8af219b16044bff9d51c4a7
[platform/framework/web/download-provider.git] / agent / download-agent-file.c
1 /*
2  * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <dirent.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <sys/vfs.h>
23 #include <math.h>
24 #include <errno.h>
25
26 #include "download-agent-debug.h"
27 #include "download-agent-file.h"
28 #include "download-agent-mime-util.h"
29 /* FIXME Later */
30 #include "download-agent-http-msg-handler.h"
31 #include "download-agent-plugin-drm.h"
32 #include "download-agent-plugin-conf.h"
33 #include "download-provider-client-manager.h"
34 #include <storage.h>
35
36
37 #define NO_NAME_TEMP_STR "No name"
38 #define MAX_SUFFIX_COUNT        1000000000
39
40 da_ret_t __saved_file_open(file_info_t *file_info)
41 {
42         da_ret_t ret = DA_RESULT_OK;
43         char *actual_file_path = DA_NULL;
44         void *fd = DA_NULL;
45
46         DA_LOGV("");
47
48         actual_file_path = file_info->file_path;
49         if (!actual_file_path)
50                 return DA_ERR_INVALID_ARGUMENT;
51
52         fd = fopen(actual_file_path, "a+"); // for resume
53         if (fd == DA_NULL) {
54                 DA_LOGE("File open failed");
55                 if (errno == ENOSPC)
56                         ret = DA_ERR_DISK_FULL;
57                 else
58                         ret = DA_ERR_FAIL_TO_ACCESS_FILE;
59                 goto ERR;
60         }
61
62         file_info->file_handle = fd;
63         //DA_SECURE_LOGD("file path for saving[%s]", file_info->file_path);
64
65 ERR:
66         if (DA_RESULT_OK != ret) {
67                 file_info->file_handle = DA_NULL;
68         }
69         return ret;
70 }
71
72 da_ret_t __divide_file_name_into_pure_name_N_extesion(const char *in_file_name, char *url, char **out_pure_file_name, char **out_extension)
73 {
74     char *file_name = DA_NULL;
75     char *tmp_ptr = DA_NULL;
76     char temp_file[DA_MAX_FILE_NAME_LEN + 1] = {0,};
77     char tmp_ext[DA_MAX_STR_LEN] = {0,};
78     int len = 0;
79     da_ret_t ret = DA_RESULT_OK;
80
81     DA_LOGD("");
82
83     if (!in_file_name)
84         return DA_ERR_INVALID_ARGUMENT;
85
86     file_name = (char *)in_file_name;
87
88         tmp_ptr = strrchr(file_name, '.');
89         if (tmp_ptr)
90                 tmp_ptr++;
91         if (tmp_ptr && out_extension) {
92                 strncpy((char*) tmp_ext, tmp_ptr, sizeof(tmp_ext) - 1);
93                 *out_extension = strdup((const char*) tmp_ext);
94                 DA_SECURE_LOGD("extension [%s]", *out_extension);
95         } else if (!tmp_ptr && url) {
96                 char *extension = DA_NULL;
97                 da_bool_t b_ret = da_get_extension_name_from_url(url, &extension);
98                 if (b_ret && !extension) {
99 #if 0
100                         tmp_ptr = strrchr(file_name, '.');
101                         if (tmp_ptr)
102                                 tmp_ptr++;
103                         if (tmp_ptr && out_extension) {
104                                 strncpy((char*) tmp_ext, tmp_ptr, sizeof(tmp_ext) - 1);
105                                 *out_extension = strdup((const char*) tmp_ext);
106                                 DA_SECURE_LOGD("extension [%s]", *out_extension);
107                         }
108 #endif
109                         *out_extension = NULL;
110                 }
111         }
112
113     if (!out_pure_file_name)
114         return ret;
115
116     if (tmp_ptr)
117         len = tmp_ptr - file_name - 1;
118     else
119         len = strlen(file_name);
120
121     if (len >= DA_MAX_FILE_NAME_LEN) {
122         strncpy((char*) temp_file, file_name, DA_MAX_FILE_NAME_LEN);
123         temp_file[DA_MAX_FILE_NAME_LEN] = '\0';
124     } else {
125         strncpy((char*) temp_file, file_name, len);
126         temp_file[len] = '\0';
127     }
128
129     delete_prohibited_char((char*) temp_file,
130             strlen((char*) temp_file));
131     if (strlen(temp_file) < 1) {
132         *out_pure_file_name = strdup(NO_NAME_TEMP_STR);
133     } else {
134         *out_pure_file_name = strdup(
135                 (const char*) temp_file);
136     }
137
138     DA_LOGD( "pure file name [%s]", *out_pure_file_name);
139     return ret;
140 }
141
142 da_ret_t __file_write_buf_make_buf(file_info_t *file_info)
143 {
144         da_ret_t ret = DA_RESULT_OK;
145         char *buffer = DA_NULL;
146
147         DA_LOGV("");
148
149         buffer = (char*) calloc(1, DA_FILE_BUF_SIZE);
150         if (DA_NULL == buffer) {
151                 DA_LOGE("Calloc failure ");
152                 ret = DA_ERR_FAIL_TO_MEMALLOC;
153         } else {
154                 file_info->buffer_len = 0;
155                 file_info->buffer = buffer;
156         }
157
158         return ret;
159 }
160
161 da_ret_t __file_write_buf_destroy_buf(file_info_t *file_info)
162 {
163         da_ret_t ret = DA_RESULT_OK;
164
165         DA_LOGV("");
166         NULL_CHECK_RET(file_info);
167
168         free(file_info->buffer);
169         file_info->buffer = DA_NULL;
170         file_info->buffer_len = 0;
171
172         return ret;
173 }
174
175 da_ret_t __file_write_buf_flush_buf(file_info_t *file_info)
176 {
177         da_ret_t ret = DA_RESULT_OK;
178         char *buffer = DA_NULL;
179         size_t buffer_size = 0;
180         size_t write_success_len = 0;
181         void *fd = DA_NULL;
182
183         //      DA_LOGV("");
184
185         buffer = file_info->buffer;
186         buffer_size = file_info->buffer_len;
187
188         if (buffer_size == 0) {
189                 DA_LOGE("no data on buffer..");
190                 return ret;
191         }
192
193         fd = file_info->file_handle;
194         if (DA_NULL == fd) {
195                 DA_LOGE("There is no file handle.");
196
197                 ret = DA_ERR_FAIL_TO_ACCESS_FILE;
198                 goto ERR;
199         }
200
201         write_success_len = fwrite(buffer, sizeof(char), buffer_size,
202                         (FILE *) fd);
203         /* FIXME : This can be necessary later due to progressive download.
204          * The solution for reducing fflush is needed */
205         //fflush((FILE *) fd);
206         if (write_success_len != buffer_size) {
207                 DA_LOGE("write  fails ");
208                 if (errno == ENOSPC)
209                         ret = DA_ERR_DISK_FULL;
210                 else
211                         ret = DA_ERR_FAIL_TO_ACCESS_FILE;
212                 goto ERR;
213         }
214         file_info->bytes_written_to_file += write_success_len;
215         file_info->is_updated = DA_TRUE;
216         file_info->buffer_len = 0;
217 ERR:
218         return ret;
219 }
220
221 da_ret_t __file_write_buf_copy_to_buf(file_info_t *file_info, char *body,
222                 int body_len)
223 {
224         da_ret_t ret = DA_RESULT_OK;
225         char *buffer = DA_NULL;
226         size_t buffer_size = 0;
227
228         DA_LOGV("");
229
230         NULL_CHECK_RET(file_info->buffer);
231         buffer = file_info->buffer;
232         buffer_size = file_info->buffer_len;
233
234         memcpy(buffer + buffer_size, body, body_len);
235         file_info->buffer_len += body_len;
236
237         return ret;
238 }
239
240 da_ret_t __file_write_buf_directly_write(file_info_t *file_info,
241                 char *body, int body_len)
242 {
243         da_ret_t ret = DA_RESULT_OK;
244         size_t write_success_len = 0;
245         void *fd = DA_NULL;
246
247         //      DA_LOGV("");
248
249         fd = file_info->file_handle;
250         if (DA_NULL == fd) {
251                 DA_LOGE("There is no file handle.");
252                 ret = DA_ERR_FAIL_TO_ACCESS_FILE;
253                 goto ERR;
254         }
255
256         write_success_len = fwrite(body, sizeof(char), (size_t)body_len,
257                         (FILE *) fd);
258         /* FIXME : This can be necessary later due to progressive download.
259          * The solution for reducing fflush is needed */
260         //fflush((FILE *) fd);
261         if (write_success_len != (size_t)body_len) {
262                 DA_LOGE("write  fails ");
263                 if (errno == ENOSPC)
264                         ret = DA_ERR_DISK_FULL;
265                 else
266                         ret = DA_ERR_FAIL_TO_ACCESS_FILE;
267                 goto ERR;
268         }
269         file_info->bytes_written_to_file += write_success_len;
270         DA_LOGV( "write %llu bytes", write_success_len);
271         file_info->is_updated = DA_TRUE;
272
273 ERR:
274         return ret;
275 }
276
277 /* Priority to derive extension
278  * 1. extension name which client set
279  * 2. according to MIME-Type
280  * 3. if MIME-Type is ambiguous or blank,
281  *    3-1. derived from <Content-Disposition> field's "filename" attribute
282  *    3-2. derived from url
283  * 4. if url does not have extension, leave blank for extension
284  */
285 char *__get_extension_name(char *mime_type,
286                 char *file_name_from_header, char *url)
287 {
288         char *extension = DA_NULL;
289
290         /* Priority 1 */
291         if (mime_type && !is_ambiguous_MIME_Type(mime_type)) {
292             if (url) {
293                 DA_LOGV("If the file extension exists and mime type exists, choose the file extension over mime type");
294                 da_bool_t b_ret = da_get_extension_name_from_url(url, &extension);
295                 if (b_ret && extension)
296                     return extension;
297             }
298             char *extension = DA_NULL;
299             da_ret_t ret = get_extension_from_mime_type(mime_type, &extension);
300             if (ret == DA_RESULT_OK && extension)
301                 return extension;
302         }
303         /* Priority 2-1 */
304         if (file_name_from_header) {
305             char *extension = DA_NULL;
306             DA_SECURE_LOGI("Content-Disposition :[%s]", file_name_from_header);
307             __divide_file_name_into_pure_name_N_extesion(file_name_from_header, DA_NULL,
308                     DA_NULL, &extension);
309             if (extension)
310                 return extension;
311         }
312         /* Priority 2-2 */
313         if (url) {
314                 DA_LOGV("Get extension from url");
315                 da_bool_t b_ret = da_get_extension_name_from_url(url, &extension);
316                 if (b_ret && extension)
317                         return extension;
318         }
319         return DA_NULL;
320 }
321
322 /** Priority for deciding file name
323  * 1. file name which client set
324  * 2. 'filename' option on HTTP response header's Content-Disposition field
325  * 3. requesting URL
326  * 4. Otherwise, define it as "No name"
327  */
328 da_ret_t __get_candidate_file_name(const char *user_file_name, char *url,
329                 char *file_name_from_header,
330                 char **out_pure_file_name, char **out_extension)
331 {
332         da_ret_t ret = DA_RESULT_OK;
333
334         DA_LOGD("");
335
336         /* Priority 1 */
337         if (user_file_name) {
338             __divide_file_name_into_pure_name_N_extesion(
339                     user_file_name, url, out_pure_file_name, out_extension);
340         }
341         if (*out_pure_file_name)
342                 return ret;
343         /* Priority 2 */
344         if (file_name_from_header) {
345             DA_SECURE_LOGI("Content-Disposition:[%s]", file_name_from_header);
346             __divide_file_name_into_pure_name_N_extesion(file_name_from_header, DA_NULL,
347                     out_pure_file_name, DA_NULL);
348         }
349         if (*out_pure_file_name)
350                 return ret ;
351         /* Priority 3 */
352         if (url) {
353                 DA_LOGD("Get file name from url");
354                 da_get_file_name_from_url(url, out_pure_file_name);
355         }
356         if (*out_pure_file_name)
357                 return ret ;
358         /* Priority 4 */
359         *out_pure_file_name = strdup(NO_NAME_TEMP_STR);
360         if (*out_pure_file_name == DA_NULL)
361                 ret = DA_ERR_FAIL_TO_MEMALLOC;
362         return ret;
363 }
364
365 da_ret_t __decide_file_path(da_info_t *da_info)
366 {
367         da_ret_t ret = DA_RESULT_OK;
368         char *extension = DA_NULL;
369         char *file_name = DA_NULL;
370         char *tmp_file_path = DA_NULL;
371         char *file_name_from_header = DA_NULL;
372         char *url = DA_NULL;
373         const char *install_dir = DA_NULL;
374         const char *user_file_name = DA_NULL;
375         file_info_t *file_info = DA_NULL;
376         req_info_t *req_info = DA_NULL;
377         http_info_t *http_info = DA_NULL;
378         dp_client_slots_fmt *slot = DA_NULL;
379
380         DA_LOGV("");
381
382         NULL_CHECK_RET(da_info);
383         file_info = da_info->file_info;
384         NULL_CHECK_RET(file_info);
385         req_info = da_info->req_info;
386         NULL_CHECK_RET(req_info);
387         http_info = da_info->http_info;
388         NULL_CHECK_RET(http_info);
389         slot  =  req_info->user_client_data;
390         NULL_CHECK_RET(slot);
391
392         if (req_info->install_path)
393                 install_dir = (const char *)req_info->install_path;
394         else {
395                 tzplatform_set_user(slot->credential.uid);
396                 install_dir = DA_DEFAULT_INSTALL_PATH_FOR_PHONE;
397                 tzplatform_reset_user();
398         }
399         user_file_name = (const char *)req_info->file_name;
400         /* If there is location url from response header in case of redirection,
401          * it try to parse the file name from the location url */
402         if (http_info->location_url) {
403                 url = http_info->location_url;
404                 DA_LOGI("[TEST] location_url[%s][%p]",http_info->location_url, http_info->location_url);
405         } else
406                 url = req_info->url;
407
408         file_name_from_header = http_info->file_name_from_header;
409
410         /* extension is extracted only if User set specific name */
411         ret = __get_candidate_file_name(user_file_name, url, file_name_from_header,
412                         &file_name, &extension);
413         if (ret != DA_RESULT_OK)
414                 goto ERR;
415
416         if (file_name && strpbrk(file_name, DA_INVALID_PATH_STRING) != NULL) {
417                 DA_LOGI("Invalid string at file name");
418                 free(file_name);
419                 file_name = strdup(NO_NAME_TEMP_STR);
420                 if (!file_name) {
421                         ret = DA_ERR_FAIL_TO_MEMALLOC;
422                         goto ERR;
423                 }
424
425         }
426
427         DA_SECURE_LOGI("candidate file name [%s]", file_name);
428
429         if (!extension
430                 && file_info->mime_type
431                 && strncmp(file_info->mime_type, "application/json", strlen("application/json"))
432                 && strncmp(file_info->mime_type, "application/x-xz", strlen("application/x-xz"))
433                 && strncmp(file_info->mime_type, "application/rss+xml", strlen("application/rss+xml"))) {
434                 extension = __get_extension_name(file_info->mime_type,
435                                 file_name_from_header, url);
436         }
437         if (file_name && !file_info->pure_file_name) {
438                 file_info->pure_file_name = file_name;
439                 file_name = DA_NULL;
440         }
441         if (extension && !file_info->extension) {
442                 DA_LOGV("candidate extension [%s]", extension);
443                 file_info->extension = extension;
444                 extension = DA_NULL;
445         }
446
447         // for resume
448         tmp_file_path = get_full_path_avoided_duplication(install_dir,
449                 file_info->pure_file_name, file_info->extension);
450         if (tmp_file_path) {
451             file_info->file_path = tmp_file_path;
452             tmp_file_path = DA_NULL;
453         } else {
454             ret = DA_ERR_FAIL_TO_ACCESS_FILE;
455             goto ERR;
456         }
457
458 ERR:
459         DA_SECURE_LOGI("decided file path [%s]", file_info->file_path);
460         if(file_name)
461             free(file_name);
462         if(extension)
463             free(extension);
464         return ret;
465 }
466
467 // for resume with new download request
468 da_ret_t __decide_file_path_for_resume(file_info_t *file_info)
469 {
470         da_ret_t ret = DA_RESULT_OK;
471         char *extension = DA_NULL;
472         char *file_name = DA_NULL;
473         char *file_path = DA_NULL;
474         char *ptr = DA_NULL;
475         char *ptr2 = DA_NULL;
476
477         DA_LOGV("");
478
479         NULL_CHECK_RET(file_info);
480
481         file_path = file_info->file_path;
482
483         NULL_CHECK_RET(file_path);
484
485         ptr = strrchr(file_path, '/');
486         if (ptr) {
487                 ptr++;
488                 ptr2 = strrchr(ptr, '.');
489                 if (ptr2) {
490                         int len = 0;
491                         len = ptr2 - ptr;
492                         ptr2++;
493                         extension = strdup(ptr2);
494                         file_name = calloc(1, len + 1);
495                         if (file_name)
496                                 snprintf(file_name, len + 1, "%s", ptr);
497                 } else {
498                         file_name = strdup(ptr);
499                 }
500         }
501
502         if (file_name && !file_info->pure_file_name) {
503                 file_info->pure_file_name = file_name;
504                 file_name = DA_NULL;
505         } else {
506                 free(file_name);
507         }
508         if (extension && !file_info->extension) {
509                 DA_LOGV( "candidate extension [%s]", extension);
510                 file_info->extension = extension;
511                 extension = DA_NULL;
512         } else {
513                 free(extension);
514         }
515         return ret;
516 }
517
518 da_ret_t start_file_writing(da_info_t *da_info)
519 {
520         da_ret_t ret = DA_RESULT_OK;
521         file_info_t *file_info = DA_NULL;
522         req_info_t *req_info = DA_NULL;
523
524         DA_LOGV("");
525
526         NULL_CHECK_RET(da_info);
527         file_info = da_info->file_info;
528         NULL_CHECK_RET(file_info);
529         req_info = da_info->req_info;
530         NULL_CHECK_RET(req_info);
531
532         /* resume case */
533         if (req_info->etag || req_info->temp_file_path) {
534             char *file_path = DA_NULL;
535             char *origin_path = DA_NULL;
536             file_path = req_info->temp_file_path;
537             if (!file_path)
538                 return DA_ERR_INVALID_ARGUMENT;
539             origin_path = file_info->file_path;
540             file_info->file_path = strdup(file_path);
541             free(origin_path);
542             if(file_info) {
543                 ret = __decide_file_path_for_resume(file_info);
544             }
545         } else {
546                 ret = __decide_file_path(da_info);
547         }
548
549         if (ret != DA_RESULT_OK)
550                 goto ERR;
551
552         if (req_info->etag || req_info->temp_file_path) {
553                 da_size_t file_size = 0;
554                 get_file_size(req_info->temp_file_path, &file_size);
555                 if (file_size < 1)
556                         goto ERR;
557 #ifdef _RAF_SUPPORT
558                 file_info->file_size_of_temp_file = file_size;
559 #endif
560                 file_info->bytes_written_to_file = file_size;
561         } else {
562                 file_info->bytes_written_to_file = 0;
563         }
564         ret = __saved_file_open(file_info);
565 ERR:
566         return ret;
567 }
568
569 da_ret_t start_file_append(file_info_t *file_info)
570 {
571         da_ret_t ret = DA_RESULT_OK;
572
573         DA_LOGV("");
574
575         NULL_CHECK_RET(file_info);
576
577         ret = __saved_file_open(file_info);
578         return ret;
579 }
580
581 da_ret_t file_write_ongoing(file_info_t *file_info, char *body, int body_len)
582 {
583         da_ret_t ret = DA_RESULT_OK;
584         size_t buffer_size = 0;
585         char *buffer = DA_NULL;
586
587         DA_LOGV("");
588
589         buffer = file_info->buffer;
590         buffer_size = file_info->buffer_len;
591
592         if (DA_NULL == buffer) {
593                 if (body_len < DA_FILE_BUF_SIZE) {
594                         ret = __file_write_buf_make_buf(file_info);
595                         if (ret != DA_RESULT_OK)
596                                 goto ERR;
597                         __file_write_buf_copy_to_buf(file_info, body, body_len);
598                 } else {
599                         ret = __file_write_buf_directly_write(file_info,
600                                         body, body_len);
601                         if (ret != DA_RESULT_OK)
602                                 goto ERR;
603                 }
604         } else {
605                 if (DA_FILE_BUF_SIZE <= body_len) {
606                         ret = __file_write_buf_flush_buf(file_info);
607                         if (ret != DA_RESULT_OK)
608                                 goto ERR;
609                         ret = __file_write_buf_directly_write(file_info,
610                                         body, body_len);
611                         if (ret != DA_RESULT_OK)
612                                 goto ERR;
613                 } else if ((DA_FILE_BUF_SIZE - buffer_size) <= body_len) {
614                         ret = __file_write_buf_flush_buf(file_info);
615                         if (ret != DA_RESULT_OK)
616                                 goto ERR;
617                         __file_write_buf_copy_to_buf(file_info, body, body_len);
618                 } else {
619                         __file_write_buf_copy_to_buf(file_info, body, body_len);
620                 }
621         }
622 ERR:
623         if (ret != DA_RESULT_OK) {
624                 file_info->buffer_len = 0;
625                 free(file_info->buffer);
626                 file_info->buffer = DA_NULL;
627         }
628         return ret;
629 }
630
631 #ifdef _RAF_SUPPORT
632 da_ret_t file_write_complete_for_raf(file_info_t *file_info) {
633         da_ret_t ret = DA_RESULT_OK;
634         char *buffer = DA_NULL;
635         da_size_t wrriten_size = 0;
636         da_size_t file_size = 0;
637         void *fd = DA_NULL;
638
639         DA_LOGV("");
640         fd = file_info->file_handle;
641
642         wrriten_size = file_info->bytes_written_to_file;
643         // test code
644         get_file_size(file_info->file_path, &file_size);
645         DA_LOGI("wrriten_size:%llu file_size:%llu file[%s]",
646                         wrriten_size, file_size, file_info->file_path);
647         if (fd) {
648                 fclose(fd);
649                 fd = DA_NULL;
650         }
651         file_info->file_handle = DA_NULL;
652         if (wrriten_size < file_size) {
653                 DA_LOGD("Try truncate");
654                 if (truncate(file_info->file_path, wrriten_size) < 0) {
655                         DA_LOGE("Fail to ftruncate: errno[%d]", errno);
656                 }
657                 DA_LOGD("Try truncate done");
658         }
659
660         ERR:
661                 return ret;
662 }
663 #endif
664
665 da_ret_t file_write_complete(file_info_t *file_info)
666 {
667         da_ret_t ret = DA_RESULT_OK;
668         char *buffer = DA_NULL;
669         unsigned int buffer_size = 0;
670         void *fd = DA_NULL;
671
672         DA_LOGV("");
673
674         buffer = file_info->buffer;
675         buffer_size = file_info->buffer_len;
676
677         if (DA_NULL == buffer) {
678                 DA_LOGE("file buffer is NULL");
679         } else {
680                 if (buffer_size != 0) {
681                         ret = __file_write_buf_flush_buf(file_info);
682                         if (ret != DA_RESULT_OK)
683                                 goto ERR;
684                 }
685                 __file_write_buf_destroy_buf(file_info);
686         }
687         fd = file_info->file_handle;
688
689         if (fd) {
690                 fclose(fd);
691                 fd = DA_NULL;
692         }
693         file_info->file_handle = DA_NULL;
694 ERR:
695         return ret;
696 }
697
698 da_ret_t discard_download(file_info_t *file_info)
699 {
700         da_ret_t ret = DA_RESULT_OK;
701         FILE *f_handle = DA_NULL;
702
703         DA_LOGV("");
704
705         f_handle = file_info->file_handle;
706         if (f_handle) {
707                 fclose(f_handle);
708                 file_info->file_handle = DA_NULL;
709         }
710         return ret;
711 }
712
713 void clean_paused_file(file_info_t *file_info)
714 {
715         char *paused_file_path = DA_NULL;
716         FILE *fd = DA_NULL;
717
718         DA_LOGV("");
719
720         fd = file_info->file_handle;
721         if (fd) {
722                 fclose(fd);
723                 file_info->file_handle = DA_NULL;
724         }
725
726         paused_file_path = file_info->file_path;
727         file_info->bytes_written_to_file = 0; // Ignore resume flow after failed or cancled.
728         remove_file((const char*) paused_file_path);
729
730         return;
731 }
732
733 da_bool_t is_file_exist(const char *file_path)
734 {
735         struct stat dir_state;
736         int stat_ret;
737
738         if (file_path == DA_NULL) {
739                 DA_LOGE("file path is DA_NULL");
740                 return DA_FALSE;
741         }
742         stat_ret = stat(file_path, &dir_state);
743         if (stat_ret == 0) {
744                 if (dir_state.st_mode & S_IFREG) {
745                         //DA_SECURE_LOGD("Exist! %s is a regular file & its size = %lu", file_path, dir_state.st_size);
746                         return DA_TRUE;
747                 }
748
749                 return DA_FALSE;
750         }
751         return DA_FALSE;
752
753 }
754
755 void get_file_size(char *file_path, da_size_t *out_file_size)
756 {
757         struct stat dir_state;
758         int stat_ret;
759
760         *out_file_size = -1;
761
762         if (file_path == DA_NULL) {
763                 DA_LOGE("file path is DA_NULL");
764                 return;
765         }
766         /* Please do not use ftell() to obtain file size, use stat instead.
767          *  This is a guide from www.securecoding.cert.org
768          *    : FIO19-C. Do not use fseek() and ftell() to compute the size of a file
769          */
770         stat_ret = stat(file_path, &dir_state);
771         if (stat_ret == 0) {
772                 if (dir_state.st_mode & S_IFREG) {
773                         DA_LOGV( "size = %lu", dir_state.st_size);
774                         *out_file_size = dir_state.st_size;
775                 }
776         }
777         return;
778 }
779
780 char *get_full_path_avoided_duplication(const char *in_dir,
781                 char *in_candidate_file_name, char *in_extension)
782 {
783         char *dir = NULL;
784         char *file_name = in_candidate_file_name;
785         char *extension = in_extension;
786         char *final_path = DA_NULL;
787
788         int dir_path_len = 0;
789         int final_path_len = 0;
790         int extension_len = 0;
791
792         int suffix_count = 0;   /* means suffix on file name. up to "_99" */
793         int suffix_len = (int)log10(MAX_SUFFIX_COUNT + 1) + 1;  /* 1 means "_" */
794
795         if (!in_dir || !in_candidate_file_name)
796                 return DA_NULL;
797
798         dir = strdup(in_dir);
799         if (!dir)
800                 return DA_NULL;
801
802         //DA_SECURE_LOGI("in_candidate_file_name=[%s],in_extension=[%s]",
803                         //in_candidate_file_name, in_extension);
804
805         if (extension)
806                 extension_len = strlen(extension);
807
808         // to remove trailing slash from dir path
809         dir_path_len = strlen(dir);
810         if (dir[dir_path_len - 1] == '/') {
811                 dir[dir_path_len - 1] = '\0';
812                 --dir_path_len;
813         }
814
815         /* first 1 for "/", second 1 for ".", last 1 for DA_NULL */
816         final_path_len = dir_path_len + 1 + strlen(file_name) + 1
817                         + suffix_len + extension_len + 1;
818
819         final_path = (char*)calloc(1, final_path_len);
820         if (!final_path) {
821                 DA_LOGE("DA_ERR_FAIL_TO_MEMALLOC");
822                 free(dir);
823                 return DA_NULL;
824         }
825
826         do {
827                 /* e.g) /tmp/abc.jpg
828                  * if there is no extension name, just make a file name without extension */
829                 if (0 == extension_len) {
830                         if (suffix_count == 0) {
831                                 snprintf(final_path, final_path_len,
832                                                 "%s/%s", dir, file_name);
833                         } else {
834                                 snprintf(final_path, final_path_len,
835                                                 "%s/%s_%d", dir, file_name, suffix_count);
836                         }
837                 } else {
838                         if (suffix_count == 0) {
839                                 snprintf(final_path, final_path_len,
840                                                 "%s/%s.%s", dir, file_name, extension);
841                         } else {
842                                 snprintf(final_path, final_path_len,
843                                                 "%s/%s_%d.%s",
844                                                 dir, file_name, suffix_count, extension);
845                         }
846                 }
847                 if (is_file_exist(final_path)) {
848                         suffix_count++;
849                         if (suffix_count > MAX_SUFFIX_COUNT) {
850                                 free(final_path);
851                                 final_path = DA_NULL;
852                                 break;
853                         } else {
854                                 memset(final_path, 0x00, final_path_len);
855                                 continue;
856                         }
857                 }
858                 break;
859         } while (1);
860
861         //DA_SECURE_LOGD("decided path = [%s]", final_path);
862         free(dir);
863
864         return final_path;
865 }
866
867
868 da_ret_t check_drm_convert(file_info_t *file_info)
869 {
870         da_ret_t ret = DA_RESULT_OK;
871 #ifdef _ENABLE_OMA_DRM
872         da_bool_t ret_b = DA_TRUE;
873 #endif
874
875         DA_LOGD("");
876
877         NULL_CHECK_RET(file_info);
878
879 #ifdef _ENABLE_OMA_DRM
880
881         /* In case of OMA DRM 1.0 SD, it is not necessary to call DRM convert API.
882          * Because it is already converted itself.
883          * And, the case will return fail because The SD is not supported now.
884          */
885         if (is_content_drm_dcf(file_info->mime_type)) {
886                 DA_LOGI("DRM SD case");
887                 unlink(file_info->file_path);
888                 free(file_info->file_path);
889                 file_info->file_path = DA_NULL;
890                 return DA_ERR_DRM_FAIL;
891         }
892         if (is_content_drm_dm(file_info->mime_type)) {
893                 char *actual_file_path = DA_NULL;
894                 char *out_file_path = DA_NULL;
895
896                 actual_file_path = file_info->file_path;
897                 DA_SECURE_LOGD("actual_file_path = %s", actual_file_path);
898                 if (!actual_file_path)
899                         return DA_ERR_INVALID_ARGUMENT;
900                 ret_b = EDRM_convert(actual_file_path, &out_file_path);
901                 unlink(actual_file_path);
902                 free(actual_file_path);
903                 if (!ret_b)
904                         ret = DA_ERR_DRM_FAIL;
905                 file_info->file_path = out_file_path;
906         } else {
907                 return ret;
908         }
909 #endif
910
911         return ret;
912 }
913
914 void remove_file(const char *file_path)
915 {
916         DA_LOGV("");
917
918         if (file_path && is_file_exist(file_path)) {
919                 DA_SECURE_LOGD("remove file [%s]", file_path);
920                 if (unlink(file_path) < 0) {
921                         DA_LOGE("file removing failed.");
922                 }
923         }
924 }
925
926 da_ret_t get_available_memory(const char *dir_path, da_size_t len)
927 {
928         da_ret_t ret = DA_RESULT_OK;
929         int fs_ret = 0;
930         struct statfs filesys_info = {0, };
931         //struct statvfs filesys_info;
932
933         DA_LOGV("");
934
935         if (!dir_path)
936                 return DA_ERR_INVALID_INSTALL_PATH;
937         DA_LOGD("Dir_path : %s", dir_path);
938
939         fs_ret = statfs(dir_path, &filesys_info);
940         // Using this as it considers FOTA memory while returning available memory
941         //fs_ret = storage_get_internal_memory_size(&filesys_info);
942
943         if (fs_ret != 0) {
944         //      DA_LOGE("statfs error[%s]", strerror(errno));
945                 return DA_ERR_INVALID_ARGUMENT;
946         //      return DA_ERR_INVALID_INSTALL_PATH;
947         }
948
949         double available_size =  (double)filesys_info.f_frsize * filesys_info.f_bavail;
950         double total_size = (double)filesys_info.f_frsize * filesys_info.f_blocks;
951         DA_SECURE_LOGI(" total = %lf ", total_size);
952         DA_SECURE_LOGI(" available = %lf ",available_size);
953
954         DA_LOGV("Available Memory(f_bavail) : %lu", filesys_info.f_bavail);
955         DA_LOGV("Available Memory(f_bsize) : %d", filesys_info.f_bsize);
956         DA_LOGD("Available Memory(kbytes) : %lu", (filesys_info.f_bavail/1024)*filesys_info.f_bsize);
957         DA_LOGV("Content: %llu", len);
958         if (available_size < (len
959                         + SAVE_FILE_BUFFERING_SIZE_50KB)) /* 50KB buffering */
960                 ret = DA_ERR_DISK_FULL;
961
962         return ret;
963 }