Add cache support
[platform/framework/web/download-provider.git] / cache / cache-agent-storage.c
1 /*
2  * Copyright (c) 2023 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 <pthread.h>
18 #include <ftw.h>
19 #include "include/cache-agent-interface.h"
20
21 static pthread_mutex_t mutex_ca_info_list = PTHREAD_MUTEX_INITIALIZER;
22 static pthread_mutex_t mutex_ca_file_io = PTHREAD_MUTEX_INITIALIZER;
23 static ca_info_t *ca_info_list[CA_MAX_ID];
24 static ca_size_t cache_dir_size;
25
26 static char *__get_file_name(const char *file_path)
27 {
28         char *file_name = CA_NULL;
29
30         file_name = strrchr(file_path, '/');
31         if (file_name)
32                 ++file_name;
33         else
34                 return strdup(file_path);
35
36         return strdup(file_name);
37 }
38
39 static void __ca_progress_cb(int cache_id,
40                 unsigned long long copied_size, void *user_req_data, void *user_client_data)
41 {
42         CA_LOGI("__ca_progress_cb id: %d, copied size: %llu", cache_id, copied_size);
43 }
44
45 static int __sum(const char *fpath, const struct stat *sb, int typeflag) {
46         cache_dir_size += sb->st_size;
47         return 0;
48 }
49
50 static void __destroy_ca_req_info(ca_req_info_t *req_info)
51 {
52         if (req_info) {
53                 if (req_info->install_path)
54                         free(req_info->install_path);
55                 if (req_info->file_name)
56                         free(req_info->file_name);
57                 if (req_info->pkg_name)
58                         free(req_info->pkg_name);
59
60                 req_info->user_req_data = CA_NULL;
61                 req_info->user_client_data = CA_NULL;
62         }
63 }
64
65 static void __init_ca_info(int id)
66 {
67         ca_info_t *ca_info = CA_NULL;
68         ca_req_info_t *req_info = CA_NULL;
69
70         ca_info = (ca_info_t *)calloc(1, sizeof(ca_info_t));
71         if (!ca_info) {
72                 CA_LOGE("Fail to calloc. id[%d]", id);
73                 ca_info_list[id] = CA_NULL;
74                 return;
75         }
76
77         req_info = (ca_req_info_t *)calloc(1, sizeof(ca_req_info_t));
78         if (!req_info) {
79                 CA_LOGE("Fail to calloc. id[%d]", id);
80                 free(ca_info);
81                 return;
82         }
83
84         CA_MUTEX_INIT(&(ca_info->mutex_state), CA_NULL);
85         CA_COND_INIT(&(ca_info->cond), CA_NULL);
86
87         ca_info->state = CA_STATE_NONE;
88         ca_info->ca_id = CA_INVALID_ID;
89         ca_info->req_info = req_info;
90         ca_info_list[id] = ca_info;
91 }
92
93 static int __remove_func(const char *filename,
94                         const struct stat *statptr, int fileflags)
95 {
96         int ret = 0;
97         char *cache_path = ca_config_get_cache_path();
98
99         if (strlen(filename) == strlen(cache_path)) {
100                 free(cache_path);
101                 return ret;
102         }
103
104         ret = unlink(filename);
105         if (ret < 0) {
106                 char err_buf[CA_MAX_ERROR_STR_LEN] = { 0, };
107
108                 strerror_r(errno, err_buf, CA_MAX_ERROR_STR_LEN);
109                 CA_LOGE("Unable to remove the file: %s, error [%d/%s]", filename, errno, err_buf);
110         }
111
112         free(cache_path);
113         return ret;
114 }
115
116 void ca_destroy_ca_info(int id)
117 {
118         ca_info_t *ca_info = CA_NULL;
119
120         CA_MUTEX_LOCK(&mutex_ca_info_list);
121
122         ca_info = ca_info_list[id];
123         if (ca_info) {
124                 if (ca_info->dst_fp)
125                         fclose(ca_info->dst_fp);
126
127                 if (ca_info->src_file)
128                         free(ca_info->src_file);
129
130                 if (ca_info->dst_file)
131                         free(ca_info->dst_file);
132
133                 if (ca_info->file_name)
134                         free(ca_info->file_name);
135
136                 if (ca_info->req_info) {
137                         __destroy_ca_req_info(ca_info->req_info);
138                         free(ca_info->req_info);
139                 }
140
141                 CA_MUTEX_DESTROY(&(ca_info->mutex_state));
142                 CA_COND_DESTROY(&(ca_info->cond));
143
144                 free(ca_info);
145                 ca_info_list[id] = CA_NULL;
146         }
147
148         CA_MUTEX_UNLOCK(&mutex_ca_info_list);
149 }
150
151 ca_info_t *ca_get_ca_info(int ca_id)
152 {
153         CA_MUTEX_LOCK(&mutex_ca_info_list);
154         ca_info_t *ca_info = ca_info_list[ca_id];
155         CA_MUTEX_UNLOCK(&mutex_ca_info_list);
156
157         return ca_info;
158 }
159
160 int ca_check_ca_id(ca_info_t *ca_info, int ca_id)
161 {
162         int ret = CA_ERR_INVALID_ARGUMENT;
163
164         CA_MUTEX_LOCK(&mutex_ca_info_list);
165
166         if (ca_info && ca_info->ca_id == ca_id)
167                 ret = CA_RESULT_OK;
168
169         CA_MUTEX_UNLOCK(&mutex_ca_info_list);
170
171         return ret;
172 }
173
174 int ca_get_info_with_ca_id(int id, ca_info_t **out_info)
175 {
176         int ret = CA_ERR_INVALID_ARGUMENT;
177
178         CA_MUTEX_LOCK(&mutex_ca_info_list);
179
180         for (int i = 0; i < CA_MAX_ID; i++) {
181                 if (CA_NULL != ca_info_list[i] && ca_info_list[i]->ca_id == id) {
182                         *out_info = ca_info_list[i];
183                         ret = CA_RESULT_OK;
184                         break;
185                 }
186         }
187
188         CA_MUTEX_UNLOCK(&mutex_ca_info_list);
189
190         return ret;
191 }
192
193 void ca_cancel_all_cache_operations(void)
194 {
195         CA_MUTEX_LOCK(&mutex_ca_info_list);
196
197         for (int i = 0; i < CA_MAX_ID; i++) {
198                 if (CA_NULL != ca_info_list[i])
199                         ca_request_to_cancel_cache_download(ca_info_list[i]);
200         }
201
202         CA_MUTEX_UNLOCK(&mutex_ca_info_list);
203 }
204
205 int ca_clear_all_cache_files(void)
206 {
207         int ret = CA_RESULT_OK;
208         char *cache_path = ca_config_get_cache_path();
209
210         if (ftw(cache_path, __remove_func, 1) == -1)
211                 ret = CA_ERR_FAIL_TO_ACCESS_FILE;
212
213         free(cache_path);
214         return ret;
215 }
216
217 int ca_request_to_cancel_cache_download(ca_info_t *ca_info)
218 {
219         int ret = CA_RESULT_OK;
220
221         CA_MUTEX_LOCK(&(ca_info->mutex_state));
222         CA_LOGD("state [%d]", ca_info->state);
223
224         switch (ca_info->state) {
225         case CA_STATE_PAUSED:
226                 CA_COND_SIGNAL(&(ca_info->cond));
227                 ca_info->state = CA_STATE_CANCELED;
228                 break;
229         case CA_STATE_COPYING:
230                 ca_info->state = CA_STATE_CANCELED;
231                 break;
232         case CA_STATE_CANCELED:
233                 ret = CA_ERR_ALREADY_CANCELED;
234                 break;
235         case CA_STATE_NONE:
236         case CA_STATE_COMPLETED:
237         case CA_STATE_FAILED:
238                 ret = CA_ERR_INVALID_STATE;
239                 break;
240         default:
241                 ret = CA_ERR_INVALID_STATE;
242                 break;
243         }
244
245         CA_MUTEX_UNLOCK(&(ca_info->mutex_state));
246         return ret;
247 }
248
249 int ca_request_to_suspend_cache_download(ca_info_t *ca_info)
250 {
251         int ret = CA_RESULT_OK;
252
253         CA_MUTEX_LOCK(&(ca_info->mutex_state));
254         CA_LOGD("state [%d]", ca_info->state);
255
256         switch (ca_info->state) {
257         case CA_STATE_PAUSED:
258                 ret = CA_ERR_ALREADY_SUSPENDED;
259                 break;
260         case CA_STATE_COPYING:
261                 ca_info->state = CA_STATE_PAUSED;
262                 break;
263         case CA_STATE_NONE:
264         case CA_STATE_COMPLETED:
265         case CA_STATE_CANCELED:
266         case CA_STATE_FAILED:
267                 ret = CA_ERR_INVALID_STATE;
268                 break;
269         default:
270                 ret = CA_ERR_INVALID_STATE;
271                 break;
272         }
273
274         CA_MUTEX_UNLOCK(&(ca_info->mutex_state));
275         return ret;
276 }
277
278 int ca_request_to_resume_cache_download(ca_info_t *ca_info)
279 {
280         int ret = CA_RESULT_OK;
281
282         CA_MUTEX_LOCK(&(ca_info->mutex_state));
283         CA_LOGD("state [%d]", ca_info->state);
284
285         switch (ca_info->state) {
286         case CA_STATE_PAUSED:
287                 CA_COND_SIGNAL(&(ca_info->cond));
288                 ca_info->state = CA_STATE_COPYING;
289                 break;
290         case CA_STATE_COPYING:
291         case CA_STATE_NONE:
292         case CA_STATE_COMPLETED:
293         case CA_STATE_CANCELED:
294         case CA_STATE_FAILED:
295                 ret = CA_ERR_INVALID_STATE;
296                 break;
297         default:
298                 ret = CA_ERR_INVALID_STATE;
299                 break;
300         }
301
302         CA_MUTEX_UNLOCK(&(ca_info->mutex_state));
303         return ret;
304 }
305
306 int ca_get_available_ca_id(int *available_id)
307 {
308         int ret = CA_ERR_ALREADY_MAX_COPY;
309         int i = 0;
310
311         CA_MUTEX_LOCK(&mutex_ca_info_list);
312
313         for (i = 0; i < CA_MAX_ID; i++) {
314                 if (ca_info_list[i] == CA_NULL) {
315                         *available_id = i;
316                         CA_LOGV("available cache id[%d]", *available_id);
317
318                         __init_ca_info(i);
319                         ret = CA_RESULT_OK;
320
321                         break;
322                 }
323         }
324
325         CA_MUTEX_UNLOCK(&mutex_ca_info_list);
326
327         return ret;
328 }
329
330 void ca_storage_get_file_size(const char *file_path, ca_size_t *file_size)
331 {
332         struct stat dir_state;
333         int stat_ret;
334
335         *file_size = -1;
336
337         if (!file_path) {
338                 CA_LOGE("NULL CHECK!: file path");
339                 return;
340         }
341
342         CA_MUTEX_LOCK(&mutex_ca_file_io);
343         stat_ret = stat(file_path, &dir_state);
344         CA_MUTEX_UNLOCK(&mutex_ca_file_io);
345
346         if (stat_ret != 0)
347                 return;
348
349         if (dir_state.st_mode & S_IFREG) {
350                 CA_LOGV("file size = %lu", dir_state.st_size);
351                 *file_size = dir_state.st_size;
352         }
353 }
354
355 static ca_file_state_e __get_file_state(const char *file_path)
356 {
357         struct stat dir_state;
358         int stat_ret;
359
360         if (file_path == CA_NULL) {
361                 CA_LOGE("file path is CA_NULL");
362                 return CA_NOT_EXIST_FILE;
363         }
364
365         CA_MUTEX_LOCK(&mutex_ca_file_io);
366         stat_ret = stat(file_path, &dir_state);
367         CA_MUTEX_UNLOCK(&mutex_ca_file_io);
368
369         if (stat_ret == 0) {
370                 if (dir_state.st_mode & S_IFREG)
371                         return CA_REGULAR_FILE;
372
373                 return CA_OTHER_FILE;
374         }
375         return CA_NOT_EXIST_FILE;
376 }
377
378 static int __extract_file_name_and_extension(const char *in_file_name, char **pure_file_name, char **extension)
379 {
380         char *file_name = CA_NULL;
381         char *tmp_ptr = CA_NULL;
382         char temp_file[CA_MAX_FILE_NAME_LEN + 1] = {0,};
383         char tmp_ext[CA_MAX_FILE_NAME_LEN] = {0,};
384         int len = 0;
385
386         if (!in_file_name || !pure_file_name)
387                 return CA_ERR_INVALID_ARGUMENT;
388
389         file_name = (char *)in_file_name;
390         tmp_ptr = strrchr(file_name, '.');
391
392         if (!tmp_ptr || tmp_ptr == file_name)
393                 tmp_ptr = CA_NULL;
394         else
395                 tmp_ptr++;
396
397         if (tmp_ptr && extension) {
398                 strncpy((char*)tmp_ext, tmp_ptr, sizeof(tmp_ext) - 1);
399                 *extension = strdup((const char *)tmp_ext);
400                 CA_LOGD("extension [%s]", *extension);
401         }
402
403         if (tmp_ptr)
404                 len = tmp_ptr - file_name - 1;
405         else
406                 len = strlen(file_name);
407
408         if (len >= CA_MAX_FILE_NAME_LEN) {
409                 strncpy((char*)temp_file, file_name, CA_MAX_FILE_NAME_LEN);
410                 temp_file[CA_MAX_FILE_NAME_LEN] = '\0';
411         } else {
412                 strncpy((char*) temp_file, file_name, len);
413                 temp_file[len] = '\0';
414         }
415
416         if (strlen(temp_file) >= 1)
417                 *pure_file_name = strdup((const char*)temp_file);
418
419         CA_LOGD("pure file name [%s]", *pure_file_name ? *pure_file_name : "NoName");
420         return CA_RESULT_OK;
421 }
422
423 static char *__generate_cache_file_name(char *dst_path, char *file_name)
424 {
425         int i;
426         char *cache_path;
427
428         CA_MUTEX_LOCK(&mutex_ca_file_io);
429
430         cache_path = ca_config_get_cache_path();
431
432         for (i = 1; i <= CA_MAX_DUP_FILE_COUNT; i++) {
433                 if (access(dst_path, F_OK) != 0)
434                         break;
435
436                 snprintf(dst_path, CA_MAX_FILE_PATH_LEN, "%s/%s.%d", cache_path, file_name, i);
437         }
438
439         CA_MUTEX_UNLOCK(&mutex_ca_file_io);
440
441         free(cache_path);
442
443         if (i > CA_MAX_DUP_FILE_COUNT)
444                 return CA_NULL;
445
446         return __get_file_name(dst_path);
447 }
448
449 static char *__generate_dst_file_name(char *dst_path, const char *dir_path, const char *file_name)
450 {
451         int i;
452         char *pure_file_name = CA_NULL;
453         char *extension = CA_NULL;
454
455         __extract_file_name_and_extension(file_name, &pure_file_name, &extension);
456         if (!pure_file_name)
457                 return CA_NULL;
458
459         CA_MUTEX_LOCK(&mutex_ca_file_io);
460
461         for (i = 1; i <= CA_MAX_DUP_FILE_COUNT; i++) {
462                 if (access(dst_path, F_OK) != 0)
463                         break;
464
465                 if (extension)
466                         snprintf(dst_path, CA_MAX_FILE_PATH_LEN, "%s/%s(%d).%s", dir_path, pure_file_name, i, extension);
467                 else
468                         snprintf(dst_path, CA_MAX_FILE_PATH_LEN, "%s/%s(%d)", dir_path, pure_file_name, i);
469         }
470
471         CA_MUTEX_UNLOCK(&mutex_ca_file_io);
472
473         free(pure_file_name);
474         free(extension);
475
476         if (i > CA_MAX_DUP_FILE_COUNT)
477                 return CA_NULL;
478
479         return __get_file_name(dst_path);
480 }
481
482 static int __is_realpath(const char *file_path)
483 {
484         char *resolved_path = CA_NULL;
485
486         if (!file_path)
487                 return CA_ERR_INVALID_ARGUMENT;
488
489         CA_MUTEX_LOCK(&mutex_ca_file_io);
490         resolved_path = realpath(file_path, NULL);
491         CA_MUTEX_UNLOCK(&mutex_ca_file_io);
492
493         if (resolved_path) {
494                 /* Check if actual_file_path is symbolic file or not */
495                 if (strcmp(resolved_path, file_path) != 0) {
496                         free(resolved_path);
497                         return CA_ERR_INVALID_ARGUMENT;
498                 }
499         } else if (errno != ENOENT) {
500                 return CA_ERR_INVALID_ARGUMENT;
501         }
502
503         free(resolved_path);
504         return CA_RESULT_OK;
505 }
506
507 static void *__open_dst_file(const char *dst_file)
508 {
509         void *fp = CA_NULL;
510
511         if (!dst_file) {
512                 CA_LOGE("NULL CHECK!: dst_file");
513                 return CA_NULL;
514         }
515
516         CA_MUTEX_LOCK(&mutex_ca_file_io);
517         fp = fopen(dst_file, "wb");
518         CA_MUTEX_UNLOCK(&mutex_ca_file_io);
519
520         if (fp == CA_NULL) {
521                 char err_buf[CA_MAX_ERROR_STR_LEN] = { 0, };
522
523                 strerror_r(errno, err_buf, CA_MAX_ERROR_STR_LEN);
524                 CA_LOGE("File open failed [%d/%s]", errno, err_buf);
525
526                 if (errno == ENOSPC)
527                         CA_LOGE("Disk full!");
528                 else
529                         CA_LOGE("Fail to access file!");
530         }
531
532         return fp;
533 }
534
535 static void *__open_src_file(const char *src_file)
536 {
537         void *fp = CA_NULL;
538
539         if (!src_file) {
540                 CA_LOGE("NULL CHECK!: src_file");
541                 return CA_NULL;
542         }
543
544         CA_MUTEX_LOCK(&mutex_ca_file_io);
545         fp = fopen(src_file, "rb");
546         CA_MUTEX_UNLOCK(&mutex_ca_file_io);
547
548         if (fp == CA_NULL) {
549                 char err_buf[CA_MAX_ERROR_STR_LEN] = { 0, };
550
551                 strerror_r(errno, err_buf, CA_MAX_ERROR_STR_LEN);
552                 CA_LOGE("File open failed [%d/%s]", errno, err_buf);
553         }
554
555         return fp;
556 }
557
558 static void __call_started_cb(int error, ca_info_t *ca_info, ca_size_t src_file_size)
559 {
560         cache_info_t cache_info = { 0, CA_RESULT_OK, 0, CA_NULL, CA_NULL };
561
562         if (!ca_info)
563                 return;
564
565         cache_info.cache_id = ca_info->ca_id;
566         cache_info.error = error;
567         cache_info.file_size = src_file_size;
568         cache_info.content_name = ca_info->file_name;
569         cache_info.saved_path = ca_info->dst_file;
570
571         if (ca_info->cb_info.cache_info_cb)
572                 ca_info->cb_info.cache_info_cb(&cache_info,
573                                 ca_info->req_info->user_req_data, ca_info->req_info->user_client_data);
574 }
575
576
577 static void __call_finidhed_cb(int error, int http_status, ca_info_t *ca_info, ca_size_t src_file_size)
578 {
579         ca_finished_info_t finished_info = { 0, CA_RESULT_OK, 0, CA_NULL, 0};
580
581         if (!ca_info || !ca_info->is_cb_update)
582                 return;
583
584         finished_info.cache_id = ca_info->ca_id;
585         finished_info.error = error;
586         finished_info.file_size = src_file_size;
587
588         if (error == CA_RESULT_OK)
589                 finished_info.saved_path = ca_info->dst_file;
590
591         finished_info.http_status = http_status;
592
593         if (ca_info->cb_info.finished_cb)
594                 ca_info->cb_info.finished_cb(&finished_info,
595                                 ca_info->req_info->user_req_data, ca_info->req_info->user_client_data);
596 }
597
598 static void __call_paused_cb(ca_info_t *ca_info)
599 {
600         if (!ca_info || !ca_info->is_cb_update)
601                 return;
602
603         if (ca_info->cb_info.paused_cb)
604                 ca_info->cb_info.paused_cb(ca_info->ca_id,
605                                 ca_info->req_info->user_req_data, ca_info->req_info->user_client_data);
606 }
607
608 static void __set_cache_state(int state, ca_info_t *ca_info)
609 {
610         CA_MUTEX_LOCK(&(ca_info->mutex_state));
611
612         ca_info->state = state;
613
614         CA_MUTEX_UNLOCK(&(ca_info->mutex_state));
615 }
616
617 static ca_bool_t __check_cancel_state(ca_info_t *ca_info)
618 {
619         ca_bool_t ret = CA_TRUE;
620
621         CA_MUTEX_LOCK(&(ca_info->mutex_state));
622         if (ca_info->state != CA_STATE_CANCELED)
623                 ret = CA_FALSE;
624         CA_MUTEX_UNLOCK(&(ca_info->mutex_state));
625
626         return ret;
627 }
628
629 static void __handle_suspend_state(ca_info_t *ca_info)
630 {
631         CA_MUTEX_LOCK(&(ca_info->mutex_state));
632         if (ca_info->state != CA_STATE_PAUSED) {
633                 CA_MUTEX_UNLOCK(&(ca_info->mutex_state));
634                 return;
635         }
636         CA_MUTEX_UNLOCK(&(ca_info->mutex_state));
637
638         __call_paused_cb(ca_info);
639
640         CA_MUTEX_LOCK(&(ca_info->mutex_state));
641         CA_COND_WAIT(&(ca_info->cond), &(ca_info->mutex_state));
642         CA_MUTEX_UNLOCK(&(ca_info->mutex_state));
643 }
644
645 static int __copy_content(ca_info_t *ca_info)
646 {
647         int ret = CA_RESULT_OK;
648         FILE *src_fp = CA_NULL;
649         FILE *dst_fp = CA_NULL;
650         void *file_buff = CA_NULL;
651         size_t r_size = 0;
652         size_t w_size = 0;
653         ca_size_t src_file_size = 0;
654         ca_size_t dst_file_size = 0;
655         struct timespec curr_time = {0};
656         __time_t prev_time = 0;
657
658         if (!ca_info || !ca_info->src_file || !ca_info->dst_file) {
659                 CA_LOGE("NULL CHECK!: ca_info, src_file, dst_file");
660                 ret = CA_ERR_INVALID_ARGUMENT;
661                 goto done;
662         }
663
664         CA_LOGI("=====START thread : ca_id[%d]=====", ca_info->ca_id);
665
666         file_buff = calloc(CA_MAX_FILE_BUFFER_SIZE, sizeof(char));
667         if (!file_buff) {
668                 CA_LOGE("Out of memory");
669                 ret = CA_ERR_FAIL_TO_MEMALLOC;
670                 goto done;
671         }
672
673         ca_storage_get_file_size(ca_info->src_file, &src_file_size);
674         if (src_file_size < 0) {
675                 CA_LOGE("Unable to get dst file size!");
676                 ret = CA_ERR_FAIL_TO_ACCESS_FILE;
677                 goto done;
678         }
679
680         if (ca_info->dst_fp) {
681                 dst_fp = ca_info->dst_fp;
682         } else {
683                 dst_fp = __open_dst_file(ca_info->dst_file);
684                 if (!dst_fp) {
685                         CA_LOGE("Unable to open dst file!");
686                         ret = CA_ERR_FAIL_TO_ACCESS_FILE;
687                         goto done;
688                 }
689                 ca_info->dst_fp = dst_fp;
690         }
691
692         src_fp = (FILE *)__open_src_file(ca_info->src_file);
693         if (!src_fp) {
694                 CA_LOGE("Unable to open src file!");
695                 ret = CA_ERR_FAIL_TO_ACCESS_FILE;
696                 goto done;
697         }
698
699         if (ca_info->is_cb_update)
700                 __call_started_cb(CA_RESULT_OK, ca_info, src_file_size);
701
702         while (0 < (r_size = fread(file_buff, 1, CA_MAX_FILE_BUFFER_SIZE, src_fp)) ) {
703                 w_size = fwrite(file_buff, 1, r_size, dst_fp);
704                 if (w_size != r_size)
705                         break;
706
707                 dst_file_size += w_size;
708
709                 __handle_suspend_state(ca_info);
710
711                 if (__check_cancel_state(ca_info)) {
712                         dst_file_size = src_file_size;
713                         ret = CA_RESULT_USER_CANCELED;
714                         break;
715                 }
716
717                 if (!ca_info->is_cb_update)
718                         continue;
719
720                 clock_gettime(CLOCK_MONOTONIC_COARSE, &curr_time);
721                 if (curr_time.tv_sec - prev_time >= 1) {
722                         if (ca_info->cb_info.progress_cb)
723                                 ca_info->cb_info.progress_cb(ca_info->ca_id, dst_file_size,
724                                                 ca_info->req_info->user_req_data, ca_info->req_info->user_client_data);
725
726                         prev_time = curr_time.tv_sec;
727                 }
728         }
729
730         if (dst_file_size != src_file_size) {
731                 ret = CA_ERR_FAIL_TO_ACCESS_FILE;
732                 CA_LOGE("The file sizes of the src and dst do not match!");
733         }
734
735         fclose(src_fp);
736         fclose(dst_fp);
737         ca_info->dst_fp = CA_NULL;
738
739 done:
740         if (file_buff)
741                 free(file_buff);
742
743         if (ret == CA_RESULT_OK)
744                 __call_finidhed_cb(CA_RESULT_OK, 200, ca_info, src_file_size);
745         else
746                 __call_finidhed_cb(ret, 0, ca_info, src_file_size);
747
748         if (ca_info && ca_info->is_cache_adding && ret == CA_RESULT_OK) {
749                 ca_size_t cache_size;
750
751                 ca_config_get_cache_size(&cache_size);
752                 cache_size += dst_file_size;
753                 ca_config_set_cache_size(cache_size);
754         }
755
756         return ret;
757 }
758
759 static void *__thread_start_copy(void *data)
760 {
761         ca_info_t *ca_info = CA_NULL;
762         int ca_id = CA_INVALID_ID;
763         int ret = CA_RESULT_OK;
764
765         pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, CA_NULL);
766
767         ca_info = (ca_info_t *)data;
768         if (!ca_info) {
769                 CA_LOGE("[NULL Check] ca_info");
770                 goto done;
771         }
772
773         __set_cache_state(CA_STATE_COPYING, ca_info);
774
775         ca_id = ca_info->ca_id;
776
777         ret = __copy_content(ca_info);
778         if (ret != CA_RESULT_OK) {
779                 CA_LOGE("Failed to copy file");
780
781                 if (ca_info->dst_file)
782                         unlink(ca_info->dst_file);
783         }
784
785         ca_destroy_ca_info(ca_id);
786 done:
787         CA_LOGI("=====EXIT thread : ca_id[%d]=====", ca_id);
788         pthread_exit((void *)CA_NULL);
789
790         return CA_NULL;
791 }
792
793 static void __reduce_cache_size(ca_size_t total_file_size)
794 {
795         ca_size_t cache_size;
796
797         if (total_file_size <= 0)
798                 return;
799
800         ca_config_get_cache_size(&cache_size);
801         cache_size -= total_file_size;
802         ca_config_set_cache_size(cache_size);
803 }
804
805 int ca_storage_init()
806 {
807         ca_size_t size;
808         CA_LOGI("");
809
810         if (CA_RESULT_OK != ca_storage_get_used_cache_size(&size))
811                 return CA_ERR_FAIL_TO_ACCESS_FILE;
812
813         return ca_config_set_cache_size(size);
814 }
815
816 int ca_storage_deinit()
817 {
818         int ret = CA_RESULT_OK;
819         CA_LOGI("");
820         ca_cancel_all_cache_operations();
821
822         return ret;
823 }
824
825 char *ca_storage_store_file(const char *file_path)
826 {
827         int ret = CA_RESULT_OK;
828         int ca_id = CA_INVALID_ID;
829         char dst_path[CA_MAX_FILE_PATH_LEN] = { 0, };
830         char *file_name = CA_NULL;
831         char *dst_file_name = CA_NULL;
832         ca_info_t *ca_info = CA_NULL;
833         void *dst_fp = CA_NULL;
834         char *cache_path = ca_config_get_cache_path();
835
836         if (__get_file_state(file_path) != CA_REGULAR_FILE) {
837                 CA_LOGE("Not a regular file!");
838                 free(cache_path);
839                 return CA_NULL;
840         }
841
842         if (__is_realpath(file_path) != CA_RESULT_OK) {
843                 CA_LOGE("Not a real file!");
844                 free(cache_path);
845                 return CA_NULL;
846         }
847
848         ret = ca_get_available_ca_id(&ca_id);
849         if (ret != CA_RESULT_OK) {
850                 CA_LOGD("No available cache id");
851                 free(cache_path);
852                 return CA_NULL;
853         }
854
855         ca_cb_t ca_cb = {
856                         CA_NULL,
857                         __ca_progress_cb,
858                         CA_NULL,
859                         CA_NULL
860         };
861
862         ca_info = ca_info_list[ca_id];
863         ca_info->ca_id = ca_id;
864
865         file_name = __get_file_name(file_path);
866         snprintf(dst_path, CA_MAX_FILE_PATH_LEN, "%s/%s", cache_path, file_name);
867         dst_file_name = __generate_cache_file_name(dst_path, file_name);
868         free(cache_path);
869         free(file_name);
870
871         if (dst_file_name == CA_NULL) {
872                 CA_LOGE("Fail to generate dst file name!");
873                 ca_destroy_ca_info(ca_info->ca_id);
874                 return CA_NULL;
875         }
876
877         dst_fp = __open_dst_file(dst_path);
878         if (dst_fp == CA_NULL) {
879                 CA_LOGE("Unable to open dst file!");
880                 free(dst_file_name);
881                 ca_destroy_ca_info(ca_info->ca_id);
882                 return CA_NULL;
883         }
884
885         ca_info->dst_fp = (FILE *)dst_fp;
886         ca_info->src_file = strdup(file_path);
887         ca_info->dst_file = strdup(dst_path);
888         ca_info->file_name = strdup(dst_file_name);
889
890         ca_info->is_cb_update = CA_TRUE;
891         ca_info->is_cache_adding = CA_TRUE;
892         memcpy(&(ca_info->cb_info), &ca_cb, sizeof(ca_cb_t));
893
894         ret = ca_storage_copy_file(ca_info);
895
896         if (ret != CA_RESULT_OK) {
897                 free(dst_file_name);
898                 dst_file_name = CA_NULL;
899
900                 if (ca_info->dst_fp) {
901                         fclose(ca_info->dst_fp);
902                         ca_info->dst_fp = CA_NULL;
903                         unlink(dst_path);
904                 }
905
906                 ca_destroy_ca_info(ca_info->ca_id);
907         }
908
909         CA_LOGI("file name: %s, id: %d, ret: %d", dst_file_name, ca_id, ret);
910
911         return dst_file_name;
912 }
913
914 int ca_storage_remove_files(int file_count, const char *cache_files[])
915 {
916         int ret = CA_RESULT_OK;
917         char dst_path[CA_MAX_FILE_PATH_LEN] = { 0, };
918         char *cache_path = ca_config_get_cache_path();
919         ca_size_t total_file_size = 0;
920         ca_size_t file_size = 0;
921
922         for (int i = 0; i < file_count; i++) {
923                 if (!cache_files[i]) {
924                         CA_LOGE("[NULL-CHECK] cache_files[%d]", i);
925
926                         ret = CA_ERR_INVALID_ARGUMENT;
927                         break;
928                 }
929
930                 snprintf(dst_path, CA_MAX_FILE_PATH_LEN, "%s/%s", cache_path, cache_files[i]);
931                 ca_storage_get_file_size(dst_path, &file_size);
932
933                 if (unlink(dst_path) < 0) {
934                         char err_buf[CA_MAX_ERROR_STR_LEN] = { 0, };
935
936                         strerror_r(errno, err_buf, CA_MAX_ERROR_STR_LEN);
937                         CA_LOGE("Unable to remove the file: %s, error [%d/%s]", dst_path, errno, err_buf);
938
939                         ret = CA_ERR_INVALID_PATH;
940                         break;
941                 }
942
943                 if (file_size > 0)
944                         total_file_size += file_size;
945         }
946
947         free(cache_path);
948         __reduce_cache_size(total_file_size);
949
950         return ret;
951 }
952
953 int ca_storage_is_file_available(const char *cache_file)
954 {
955         int ret = CA_RESULT_OK;
956         char dst_path[CA_MAX_FILE_PATH_LEN] = { 0, };
957         char *cache_path = ca_config_get_cache_path();
958
959         snprintf(dst_path, CA_MAX_FILE_PATH_LEN, "%s/%s", cache_path, cache_file);
960
961         if (__get_file_state(dst_path) != CA_REGULAR_FILE) {
962                 CA_LOGE("Not a regular file!");
963                 ret = CA_ERR_INVALID_ARGUMENT;
964                 goto done;
965         }
966
967         if (__is_realpath(dst_path) != CA_RESULT_OK) {
968                 CA_LOGE("Not a real file!");
969                 ret = CA_ERR_INVALID_ARGUMENT;
970         }
971
972 done:
973         free(cache_path);
974         return ret;
975 }
976
977 int ca_storage_get_used_cache_size(ca_size_t *size)
978 {
979         cache_dir_size = 0;
980         char *cache_path = ca_config_get_cache_path();
981
982         if (ftw(cache_path, __sum, 1) != 0) {
983                 CA_LOGE("Failed to get cache directory size!");
984                 free(cache_path);
985                 return CA_ERR_INVALID_ARGUMENT;
986         }
987
988         *size = cache_dir_size;
989
990         CA_LOGD("size(Bytes): %lld", *size);
991         free(cache_path);
992
993         return CA_RESULT_OK;
994 }
995
996 int ca_storage_copy_file(ca_info_t *ca_info)
997 {
998         pthread_attr_t thread_attr;
999         pthread_t tid;
1000
1001         if (pthread_attr_init(&thread_attr) != 0)
1002                 return CA_ERR_FAIL_TO_CREATE_THREAD;
1003
1004         if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED) != 0)
1005                 return CA_ERR_FAIL_TO_CREATE_THREAD;
1006
1007         if (pthread_create(&(tid), &thread_attr, __thread_start_copy, ca_info) != 0) {
1008                 CA_LOGE("Fail to make thread:id[%d]", ca_info->ca_id);
1009                 return CA_ERR_FAIL_TO_CREATE_THREAD;
1010         }
1011
1012         ca_info->thread_id = tid;
1013         CA_LOGI("Thread is created:thread id[%lu]", ca_info->thread_id);
1014
1015         return CA_RESULT_OK;
1016 }
1017
1018 int ca_init_cache_download_data(ca_info_t *ca_info,
1019                 const char *cache_file, ca_req_data_t *ext_data)
1020 {
1021         char src_path[CA_MAX_FILE_PATH_LEN] = { 0, };
1022         char dst_path[CA_MAX_FILE_PATH_LEN] = { 0, };
1023         char *gen_dst_file_name = CA_NULL;
1024         void *dst_fp = CA_NULL;
1025         const char *dst_file_name = ext_data->file_name;
1026         const char *dst_file_path = ext_data->install_path;
1027         char *cache_path = ca_config_get_cache_path();
1028
1029         if (!dst_file_name || !dst_file_path) {
1030                 CA_LOGE("Invalid dst file path or dst file name!");
1031                 free(cache_path);
1032                 return CA_ERR_INVALID_ARGUMENT;
1033         }
1034
1035         snprintf(src_path, CA_MAX_FILE_PATH_LEN, "%s/%s", cache_path, cache_file);
1036         snprintf(dst_path, CA_MAX_FILE_PATH_LEN, "%s/%s", dst_file_path, dst_file_name);
1037
1038         free(cache_path);
1039
1040         if (__get_file_state(src_path) != CA_REGULAR_FILE) {
1041                 CA_LOGE("No src file exist!");
1042                 return CA_ERR_INVALID_PATH;
1043         }
1044
1045         gen_dst_file_name = __generate_dst_file_name(dst_path, dst_file_path, dst_file_name);
1046
1047         if (gen_dst_file_name == CA_NULL) {
1048                 CA_LOGE("Fail to generate dst file name!");
1049                 return CA_ERR_INVALID_STATE;
1050         }
1051
1052         dst_fp = __open_dst_file(dst_path);
1053         if (dst_fp == CA_NULL) {
1054                 CA_LOGE("Unable to open dst file!");
1055                 free(gen_dst_file_name);
1056                 return CA_ERR_FAIL_TO_ACCESS_FILE;
1057         }
1058
1059         ca_info->dst_fp = (FILE *)dst_fp;
1060         ca_info->src_file = strdup(src_path);
1061         ca_info->dst_file = strdup(dst_path);
1062         ca_info->file_name = gen_dst_file_name;
1063
1064         ca_req_info_t *req_info = ca_info->req_info;
1065
1066         if (ext_data->install_path)
1067                 req_info->install_path = strdup(ext_data->install_path);
1068         if (ext_data->file_name)
1069                 req_info->file_name = strdup(ext_data->file_name);
1070         if (ext_data->pkg_name)
1071                 req_info->pkg_name = strdup(ext_data->pkg_name);
1072         if (ext_data->user_req_data)
1073                 req_info->user_req_data = ext_data->user_req_data;
1074         if (ext_data->user_client_data)
1075                 req_info->user_client_data = ext_data->user_client_data;
1076
1077         return CA_RESULT_OK;
1078 }
1079