Fix wrong available mem calculation of internal storage
[platform/core/appfw/app2sd.git] / plugin / app2sd / server / app2sd_internals.c
1 /*
2  * app2ext
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Garima Shrivastava<garima.s@samsung.com>
7  *      Jyotsna Dhumale <jyotsna.a@samsung.com>
8  *      Venkatesha Sarpangala <sarpangala.v@samsung.com>
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */
23
24 #include <dirent.h>
25 #include <time.h>
26 #include <pwd.h>
27
28 #include "app2sd_internals.h"
29
30 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
31 #define DMCRYPT_ITER_TIME       50
32 #define DMCRYPT_KEY_LEN         128
33 #endif
34
35 static int _app2sd_make_directory(const char *path, uid_t uid)
36 {
37         int ret = 0;
38         int fd = -1;
39         mode_t mode = DIR_PERMS;
40         struct passwd pwd;
41         struct passwd *pwd_result;
42         char buf[1024] = { 0, };
43
44         ret = _app2sd_delete_directory(path);
45         if (ret) {
46                 _E("unable to delete (%s), errno(%d)", path, errno);
47                 return APP2EXT_ERROR_DELETE_DIRECTORY;
48         }
49
50         ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &pwd_result);
51         if (ret != 0 || pwd_result == NULL) {
52                 _E("get uid failed(%d)", ret);
53                 return APP2EXT_ERROR_ACCESS_FILE;
54         }
55         _D("uid(%d), gid(%d)", uid, pwd.pw_gid);
56
57         /* create directory */
58         ret = mkdir(path, mode);
59         if (ret) {
60                 if (errno != EEXIST) {
61                         _E("create directory failed," \
62                                 " error no is (%d)", errno);
63                         return APP2EXT_ERROR_CREATE_DIRECTORY;
64                 }
65         }
66
67         fd = open(path, O_RDONLY|O_DIRECTORY);
68         if (fd < 0) {
69                 _E("can't open path(%s)", path);
70                 return APP2EXT_ERROR_OPEN_DIR;
71         }
72
73         ret = fchmod(fd, 0755);
74         if (ret < 0) {
75                 _E("change file permission error");
76                 close(fd);
77                 return APP2EXT_ERROR_ACCESS_FILE;
78         }
79
80         ret = fchown(fd, uid, pwd.pw_gid);
81         if (ret < 0) {
82                 _E("change file owner error");
83                 close(fd);
84                 return APP2EXT_ERROR_ACCESS_FILE;
85         }
86
87         close(fd);
88
89         return APP2EXT_SUCCESS;
90 }
91
92 char *_app2sd_find_associated_device_node(const char *loopback_device)
93 {
94         char *ret_result = NULL;
95         char delims[] = ":";
96         char *result = NULL;
97         char dev[FILENAME_MAX] = { 0, };
98         char *devnode = NULL;
99
100         result = (char *)_app2sd_find_associated_device(loopback_device);
101         if (result == NULL) {
102                 _D("there is no the associated file (%s)", loopback_device);
103                 return NULL;
104         }
105
106         /* process the string*/
107         snprintf(dev, sizeof(dev), "%s", result);
108
109         if (strstr(dev, "dev") == NULL) {
110                 _E("unable to find the associated file");
111                 free(result);
112                 return NULL;
113         } else {
114                 char *saveptr = NULL;
115                 ret_result = strtok_r(dev, delims, &saveptr);
116                 if (ret_result)
117                         devnode = strdup(ret_result);
118         }
119
120         free(result);
121
122         return devnode;
123 }
124
125 char *_app2sd_create_loopdevice_node(void)
126 {
127         char *ret_result = NULL;
128         mode_t mode = DIR_PERMS;
129         int count = 0;
130         int ret = APP2EXT_SUCCESS;
131         char *result = NULL;
132         FILE *fp = NULL;
133
134         result = (char *)_app2sd_find_free_device();
135         _D("find_free_device(%s)", result);
136
137         /* validate the result */
138         if (result == NULL || strstr(result, "/dev") == NULL) {
139                 _D("no device found, creating device node");
140
141                 if (result) {
142                         free(result);
143                         result = NULL;
144                 }
145                 count = 0;
146                 char dev_path[BUF_SIZE] = { 0, };
147                 snprintf(dev_path, sizeof(dev_path), "/dev/loop%d", count);
148                 while ((fp = fopen(dev_path, "r+")) != NULL) {
149                         count = count + 1;
150                         snprintf(dev_path, sizeof(dev_path), "/dev/loop%d", count);
151                         _D("next dev path for checking is (%s)",
152                                      dev_path);
153                         fclose(fp);
154                 }
155                 _D("device node candidate is (%s)", dev_path);
156                 dev_t dev_node;
157                 dev_node = makedev(DEV_MAJOR, count);
158                 ret = mknod(dev_path, S_IFBLK | mode, dev_node);
159                 if (ret < 0) {
160                         _E("error while creating the device node: errno is (%d)",
161                              errno);
162                         return NULL;
163                 }
164                 ret_result = (char *)malloc(strlen(dev_path) + 1);
165                 if (ret_result == NULL) {
166                         _E("unable to allocate memory");
167                         return NULL;
168                 }
169                 memset(ret_result, '\0', strlen(dev_path) + 1);
170                 memcpy(ret_result, dev_path, strlen(dev_path));
171         } else {
172                 ret_result = (char *)malloc(strlen(result) + 1);
173                 if (ret_result == NULL) {
174                         _E("malloc failed");
175                         free(result);
176                         result = NULL;
177                         return NULL;
178                 }
179                 memset(ret_result, '\0', strlen(result) + 1);
180                 if (strlen(result) > 0)
181                         memcpy(ret_result, result, strlen(result) - 1);
182
183                 free(result);
184                 result = NULL;
185
186         }
187         return ret_result;
188 }
189
190 char *_app2sd_do_loopback_encryption_setup(const char *pkgid,
191         const char *loopback_device, uid_t uid)
192 {
193         int ret = APP2EXT_SUCCESS;
194         char *passwd = NULL;
195         char *result = NULL;
196         char *device_node = NULL;
197
198         if (pkgid == NULL) {
199                 _E("invalid argument");
200                 return NULL;
201         }
202
203         /* get password for loopback encryption */
204         ret = _app2sd_initialize_db();
205         if (ret) {
206                 _E("app2sd db initialize failed");
207                 return NULL;
208         }
209
210         if ((passwd = _app2sd_get_password_from_db(pkgid, uid)) == NULL) {
211                 passwd = (char *)_app2sd_generate_password();
212                 if (NULL == passwd) {
213                         _E("unable to generate password");
214                         return NULL;
215                 } else {
216                         if ((ret = _app2sd_set_info_in_db(pkgid,
217                                 passwd, loopback_device, uid)) < 0) {
218                                 _E("unable to save info");
219                                 free(passwd);
220                                 passwd = NULL;
221                                 return NULL;
222                         }
223                 }
224         }
225
226         /* get free device node*/
227         device_node = _app2sd_create_loopdevice_node();
228         if (NULL == device_node) {
229                 free(passwd);
230                 passwd = NULL;
231                 _E("unable to find free loopback node");
232                 return NULL;
233         }
234
235         _D("device_node (%s)", device_node);
236
237         result = (char *)_app2sd_encrypt_device(device_node,
238                 loopback_device, passwd);
239         if (result == NULL) {
240                 _E("encryption failed");
241                 free(passwd);
242                 passwd = NULL;
243                 return NULL;
244         } else {
245                 _D("result (%s)", result);
246                 free(result);
247                 result = NULL;
248                 free(passwd);
249                 passwd = NULL;
250                 return device_node;
251         }
252 }
253
254 char *_app2sd_do_loopback_duplicate_encryption_setup(const char *pkgid,
255                 const char *temp_pkgid, const char *temp_loopback_device,
256                 char *passwd, uid_t uid)
257 {
258         char *result = NULL;
259         char *device_node = NULL;
260
261         if (pkgid == NULL || temp_pkgid == NULL ||
262                 temp_loopback_device == NULL || passwd == NULL) {
263                 _E("invalid argument");
264                 return NULL;
265         }
266
267         /* get free device node*/
268         device_node = _app2sd_create_loopdevice_node();
269         if (NULL == device_node) {
270                 _E("unable to find free loopback node");
271                 return NULL;
272         }
273         result = (char *)_app2sd_encrypt_device(device_node,
274                 temp_loopback_device, passwd);
275         if (result == NULL) {
276                 _E("encryption failed");
277                 return NULL;
278         } else {
279                 if (strlen(result) == 0) {
280                         free(result);
281                         result = NULL;
282                         return device_node;
283                 } else {
284                         _E("error is (%s)", result);
285                         free(result);
286                         result = NULL;
287                         return NULL;
288                 }
289         }
290
291         return device_node;
292 }
293
294 int _app2sd_remove_loopback_encryption_setup(const char *loopback_device)
295 {
296         int ret = APP2EXT_SUCCESS;
297         char *result = NULL;
298         char *dev_node = NULL;
299
300         if ((dev_node = _app2sd_find_associated_device_node(loopback_device))
301                 == NULL) {
302                 _E("Unable to find the association");
303                 ret = APP2EXT_ERROR_FIND_ASSOCIATED_DEVICE_NODE;
304         }
305
306         result = (char *)_app2sd_detach_loop_device(dev_node);
307         if (result == NULL) {
308                 _E("error in detaching");
309                 ret = APP2EXT_ERROR_DETACH_LOOPBACK_DEVICE;
310         } else {
311                 free(result);
312                 result = NULL;
313         }
314
315         if (dev_node) {
316                 free(dev_node);
317                 dev_node = NULL;
318         }
319
320         return ret;
321 }
322
323 int _app2sd_remove_all_loopback_encryption_setups(const char *loopback_device)
324 {
325         int ret = APP2EXT_SUCCESS;
326         char *result = NULL;
327         char *dev_node = NULL;
328         while (1) {
329                 if ((dev_node =
330                         _app2sd_find_associated_device_node(loopback_device))
331                         == NULL) {
332                         _E("finish to find the association");
333                         ret = APP2EXT_SUCCESS;
334                         break;
335                 }
336
337                 _D("find node (%s)", dev_node);
338
339                 result = (char *)_app2sd_detach_loop_device(dev_node);
340                 if (result == NULL) {
341                         _E("error in detaching");
342                         ret = APP2EXT_ERROR_DETACH_LOOPBACK_DEVICE;
343                         break;
344                 } else {
345                         free(result);
346                         result = NULL;
347                 }
348                 if (dev_node) {
349                         free(dev_node);
350                         dev_node = NULL;
351                 }
352         }
353
354         return ret;
355 }
356
357 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
358 int _app2sd_dmcrypt_setup_device(const char *pkgid,
359                 const char *loopback_device, bool is_dup, uid_t uid)
360 {
361         int ret = APP2EXT_SUCCESS;
362         char *passwd = NULL;
363         char dmcrypt_setup_cmd[BUF_SIZE] = { 0, };
364         char err_buf[BUF_SIZE] = { 0, };
365
366         if (pkgid == NULL || loopback_device == NULL) {
367                 _E("invalid argument");
368                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
369         }
370
371         /* get password for dmcrypt encryption */
372         ret = _app2sd_initialize_db();
373         if (ret) {
374                 _E("app2sd db initialize failed");
375                 return APP2EXT_ERROR_DB_INITIALIZE;
376         }
377
378         passwd = _app2sd_get_password_from_db(pkgid, uid);
379         if (passwd == NULL) {
380                 if (is_dup) {
381                         _E("no password found for (%s)", pkgid);
382                         return APP2EXT_ERROR_SQLITE_REGISTRY;
383                 }
384                 passwd = (char *)_app2sd_generate_password();
385                 if (NULL == passwd) {
386                         _E("unable to generate password\n");
387                         return APP2EXT_ERROR_PASSWD_GENERATION;
388                 } else {
389                         if ((ret = _app2sd_set_info_in_db(pkgid, passwd,
390                                 loopback_device, uid)) < 0) {
391                                 _E("unable to save password");
392                                 free(passwd);
393                                 passwd = NULL;
394                                 return APP2EXT_ERROR_SQLITE_REGISTRY;
395                         }
396                 }
397         }
398
399         snprintf(dmcrypt_setup_cmd, sizeof(dmcrypt_setup_cmd),
400                 "/bin/echo '%s' | /sbin/cryptsetup -q -i %d " \
401                 "-c aes-cbc-lmk -s %d --align-payload=8 luksFormat %s",
402                 passwd, DMCRYPT_ITER_TIME, DMCRYPT_KEY_LEN, loopback_device);
403
404         ret = system(dmcrypt_setup_cmd);
405         if (ret) {
406                 strerror_r(errno, err_buf, sizeof(err_buf));
407                 _E("Error setting up dmcrypt on app2sd file, " \
408                         "error(%s), ret(%d)", err_buf, ret);
409                 if (passwd) {
410                         free(passwd);
411                         passwd = NULL;
412                 }
413                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
414         }
415
416         if (passwd) {
417                 free(passwd);
418                 passwd = NULL;
419         }
420
421         return ret;
422 }
423
424 int _app2sd_dmcrypt_open_device(const char *pkgid, const char *loopback_device,
425                 bool is_dup, uid_t uid, char **dev_node)
426 {
427         int ret = APP2EXT_SUCCESS;
428         char *passwd;
429         char dmcrypt_open_cmd[BUF_SIZE] = { 0, };
430         char dev_name[BUF_SIZE] = { 0, };
431         char buf[BUF_SIZE] = { 0, };
432         int len = 0;
433
434         if (pkgid == NULL || loopback_device == NULL) {
435                 _E("invalid argument");
436                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
437         }
438
439         if (is_dup)
440                 snprintf(dev_name, sizeof(dev_name), "%s.new_%d", pkgid, uid);
441         else
442                 snprintf(dev_name, sizeof(dev_name), "%s_%d", pkgid, uid);
443
444         /* get password for dmcrypt encryption */
445         ret = _app2sd_initialize_db();
446         if (ret) {
447                 _E("app2sd db initialize failed");
448                 return APP2EXT_ERROR_DB_INITIALIZE;
449         }
450
451         passwd = _app2sd_get_password_from_db(pkgid, uid);
452         if (passwd == NULL) {
453                 _E("no password found for [%s]", pkgid);
454                 return APP2EXT_ERROR_SQLITE_REGISTRY;
455         }
456
457         if (_app2sd_check_is_luks_device(loopback_device) == 0) {
458                 _W("legacy image format!");
459                 snprintf(dmcrypt_open_cmd, sizeof(dmcrypt_open_cmd),
460                         "/bin/echo '%s' | /sbin/cryptsetup " \
461                         "-M plain -c aes-cbc-plain -h plain open %s %s",
462                         passwd, loopback_device, dev_name);
463         } else {
464                 snprintf(dmcrypt_open_cmd, sizeof(dmcrypt_open_cmd),
465                         "/bin/echo '%s' | /sbin/cryptsetup -q luksOpen %s %s",
466                         passwd, loopback_device, dev_name);
467         }
468         free(passwd);
469
470         ret = system(dmcrypt_open_cmd);
471         if (ret) {
472                 strerror_r(errno, buf, sizeof(buf));
473                 _E("error opening dmcrypt device, error: [%s]", buf);
474                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
475         }
476
477         snprintf(buf, sizeof(buf), "/dev/mapper/%s", dev_name);
478         len = strlen(buf);
479         *dev_node = (char *)calloc(len + 1, sizeof(char));
480         if (*dev_node == NULL) {
481                 _E("memory alloc failed");
482                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
483         }
484         snprintf(*dev_node, len + 1, "%s", buf);
485
486         return ret;
487 }
488
489 int _app2sd_dmcrypt_close_device(const char *pkgid, uid_t uid)
490 {
491         int ret = APP2EXT_SUCCESS;
492         char dev_node[BUF_SIZE] = { '\0' };
493         char dmcrypt_close_cmd[BUF_SIZE] = { '\0' };
494         char err_buf[BUF_SIZE] = { '\0' };
495         char *t_dev_node = NULL;
496
497         if (pkgid == NULL) {
498                 _E("invalid argument\n");
499                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
500         }
501
502         t_dev_node = _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
503         if (!t_dev_node) {
504                 _W("no associated device node(%s_%d) found", pkgid, uid);
505                 return APP2EXT_ERROR_DMCRYPT_DEVICE_UNAVAILABLE;
506         }
507
508         free(t_dev_node);
509         t_dev_node = NULL;
510
511         snprintf(dev_node, sizeof(dev_node), "/dev/mapper/%s_%d", pkgid, uid);
512         snprintf(dmcrypt_close_cmd, sizeof(dmcrypt_close_cmd),
513                 "/sbin/cryptsetup -q luksClose %s", dev_node);
514         ret = system(dmcrypt_close_cmd);
515         if (ret) {
516                 strerror_r(errno, err_buf, sizeof(err_buf));
517                 _E("error closing dmcrypt on app2sd file,"\
518                         " error: [%s]", err_buf);
519                 return APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
520         }
521
522         return ret;
523 }
524
525 char *_app2sd_find_associated_dmcrypt_device_node(const char *pkgid, uid_t uid)
526 {
527         char *dev_node = NULL;
528         char buf[BUF_SIZE] = { 0, };
529         int len = 0;
530
531         snprintf(buf, sizeof(buf), "/dev/mapper/%s_%d", pkgid, uid);
532         len = strlen(buf);
533         dev_node = (char *)calloc(len + 1, sizeof(char));
534         if (dev_node == NULL) {
535                 _E("memory alloc failed");
536                 return NULL;
537         }
538         snprintf(dev_node, len + 1, "%s", buf);
539
540         if (access(dev_node, F_OK) == 0) {
541                 _D("device_node: (%s)", dev_node);
542                 return dev_node;
543         }
544         _D("can not access dev_node(%s), errno(%d)", dev_node, errno);
545
546         free(dev_node);
547         dev_node = NULL;
548
549         return NULL;
550 }
551
552 char *_app2sd_dmcrypt_duplicate_encryption_setup(const char *pkgid,
553                 const char *temp_loopback_device, uid_t uid)
554 {
555         int ret = APP2EXT_SUCCESS;
556         char *device_node = NULL;
557
558         if (pkgid == NULL || temp_loopback_device == NULL) {
559                 _E("invalid argument\n");
560                 return NULL;
561         }
562
563         ret = _app2sd_dmcrypt_setup_device(pkgid, temp_loopback_device, true, uid);
564         if (ret) {
565                 _E("dmcrypt setup device error(%d)", ret);
566                 return NULL;
567         }
568
569         ret = _app2sd_dmcrypt_open_device(pkgid, temp_loopback_device, true,
570                 uid, &device_node);
571         if (ret) {
572                 _E("dmcrypt open device error");
573                 return NULL;
574         }
575
576         return device_node;
577 }
578 #endif
579
580 int _app2sd_create_loopback_device(const char *pkgid,
581                 const char *loopback_device, int size)
582 {
583         int ret = APP2EXT_SUCCESS;
584         char command[FILENAME_MAX] = { 0, };
585         char buff[BUF_SIZE] = { 0, };
586         FILE *fp = NULL;
587
588         if (NULL == pkgid || size <= 0) {
589                 _E("invalid argument");
590                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
591         }
592         snprintf(command, sizeof(command), "of=%s", loopback_device);
593         snprintf(buff, sizeof(buff), "count=%d", size);
594
595         const char *argv1[] = { "/bin/dd", "if=/dev/zero",
596                 command, "bs=1M", buff, NULL };
597
598         if ((fp = fopen(loopback_device, "r+")) != NULL) {
599                 _W("encrypted file already exists (%s)",
600                         loopback_device);
601                 fclose(fp);
602                 return APP2EXT_ERROR_PKG_EXISTS;
603         }
604
605         ret = _xsystem(argv1);
606         if (ret)
607                 _E("command (%s) failed, ret(%d), errno(%d)", command, ret, errno);
608
609         return ret;
610 }
611
612 int _app2sd_delete_loopback_device(const char *loopback_device)
613 {
614         int ret = APP2EXT_SUCCESS;
615
616         ret = unlink(loopback_device);
617         if (ret) {
618                 if (errno == ENOENT) {
619                         _W("unable to access file (%s)", loopback_device);
620                 } else {
621                         _E("unable to delete (%s)", loopback_device);
622                         return APP2EXT_ERROR_DELETE_LOOPBACK_DEVICE;
623                 }
624         }
625
626         return APP2EXT_SUCCESS;
627 }
628
629 int _app2sd_create_file_system(const char *device_path)
630 {
631         int ret = APP2EXT_SUCCESS;
632         FILE *fp = NULL;
633         char err_buf[1024] = {0,};
634
635         if (device_path == NULL) {
636                 _E("invalid param");
637                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
638         }
639
640         /* Format the filesystem [create a filesystem]*/
641         const char *argv[] = { "/sbin/mkfs.ext4", device_path, NULL };
642         fp = fopen(device_path, "r+");
643         if (fp == NULL) {
644                 strerror_r(errno, err_buf, sizeof(err_buf));
645                 _E("unable to access (%s) error is (%d, %s)",
646                      device_path, errno, err_buf);
647                 return APP2EXT_ERROR_ACCESS_FILE;
648         } else {
649                 fclose(fp);
650         }
651         ret = _xsystem(argv);
652         if (ret) {
653                 strerror_r(errno, err_buf, sizeof(err_buf));
654                 _E("creating file system failed, error is (%s)",
655                      err_buf);
656                 return APP2EXT_ERROR_CREATE_FS;
657         }
658         return ret;
659 }
660
661 static int _app2sd_create_dir_with_link(const char *application_path,
662                 const char *pkgid, const char *dir_name, uid_t uid)
663 {
664         int ret = APP2EXT_SUCCESS;
665         char app_dir_mmc_path[FILENAME_MAX] = { 0, };
666         char app_dir_path[FILENAME_MAX] = { 0, };
667
668         snprintf(app_dir_mmc_path, sizeof(app_dir_mmc_path), "%s/.mmc/%s",
669                 application_path, dir_name);
670         snprintf(app_dir_path, sizeof(app_dir_path), "%s/%s",
671                 application_path, dir_name);
672
673         ret = _app2sd_make_directory(app_dir_mmc_path, uid);
674         if (ret) {
675                 _E("create directory failed");
676                 return APP2EXT_ERROR_CREATE_DIRECTORY;
677         }
678
679         if ((ret = symlink(app_dir_mmc_path,
680                 app_dir_path)) < 0) {
681                 if (errno == EEXIST) {
682                         _D("file with symlink name present (%s)",
683                                 app_dir_path);
684                 } else {
685                         _E("symbolic link creation "
686                                 "failed, error no is (%d)", errno);
687                         return APP2EXT_ERROR_CREATE_SYMLINK;
688                 }
689         }
690
691         return APP2EXT_SUCCESS;
692 }
693
694 static int _app2sd_create_directory_entry(const char *application_path,
695                 const char *pkgid, GList *dir_list, uid_t uid)
696 {
697         int ret = APP2EXT_SUCCESS;
698         GList *list = NULL;
699         app2ext_dir_details *dir_detail = NULL;
700
701         list = g_list_first(dir_list);
702         while (list) {
703                 dir_detail = (app2ext_dir_details *)list->data;
704                 if (dir_detail && dir_detail->name
705                         && dir_detail->type == APP2EXT_DIR_RO) {
706                         ret = _app2sd_create_dir_with_link(application_path,
707                                 pkgid, dir_detail->name, uid);
708                         if (ret)
709                                 return ret;
710                 }
711                 list = g_list_next(list);
712         }
713         return APP2EXT_SUCCESS;
714 }
715
716 int _app2sd_mount_app_content(const char *application_path, const char *pkgid,
717                 const char *dev, int mount_type, GList *dir_list,
718                 app2sd_cmd cmd, uid_t uid)
719 {
720         int ret = APP2EXT_SUCCESS;
721         int fd = -1;
722         char app_mmc_path[FILENAME_MAX] = { 0, };
723         char temp_path[FILENAME_MAX] = { 0, };
724         char err_buf[1024] = {0,};
725         struct timespec time = {
726                 .tv_sec = 0,
727                 .tv_nsec = 1000 * 1000 * 200
728         };
729
730         if (NULL == dev) {
731                 _E("input param is NULL (%s)",
732                              dev);
733                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
734         }
735
736         /* check directory existence */
737         fd = open(application_path, O_RDONLY|O_DIRECTORY);
738         if (fd < 0) {
739                 _E("path(%s) error(%d)", application_path, errno);
740                 return APP2EXT_ERROR_OPEN_DIR;
741         }
742         close(fd);
743
744         snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
745                 application_path);
746         fd = open(app_mmc_path, O_RDONLY|O_DIRECTORY);
747         if (fd < 0) {
748                 _E("path(%s) error(%d)", app_mmc_path, errno);
749                 return APP2EXT_ERROR_OPEN_DIR;
750         }
751         close(fd);
752
753         nanosleep(&time, NULL); /* 200ms sleep */
754         _D("give a delay for mount");
755
756         switch (mount_type) {
757         case MOUNT_TYPE_RD:
758                 if ((ret = mount(dev, app_mmc_path, FS_TYPE,
759                         MS_MGC_VAL | MS_RDONLY | MS_NOSUID, NULL)) < 0) {
760                         _E("read only mount failed, " \
761                                 "errono is (%d), " \
762                                 "dev is (%s) path is (%s)",
763                                 errno, dev, app_mmc_path);
764                         ret = APP2EXT_ERROR_MOUNT;
765                 }
766                 break;
767         case MOUNT_TYPE_RW:
768                 if ((ret = mount(dev, app_mmc_path, FS_TYPE,
769                         MS_MGC_VAL | MS_NOSUID, NULL)) < 0) {
770                         _E("read write mount failed, " \
771                                 "errono is (%d)", errno);
772                         ret = APP2EXT_ERROR_MOUNT;
773                 }
774                 break;
775         case MOUNT_TYPE_RW_NOEXEC:
776                 if ((ret = mount(dev, app_mmc_path, FS_TYPE,
777                         MS_MGC_VAL | MS_NOEXEC | MS_NOSUID, NULL)) < 0) {
778                         _E("rwnx mount failed " \
779                                 "errono is (%d)", errno);
780                         ret = APP2EXT_ERROR_MOUNT;
781                 }
782                 break;
783         case MOUNT_TYPE_RD_REMOUNT:
784                 if ((ret = mount(dev, app_mmc_path, FS_TYPE,
785                         MS_MGC_VAL | MS_RDONLY | MS_REMOUNT | MS_NOSUID,
786                         NULL)) < 0) {
787                         _E("read remount failed "
788                                 "errono is (%d)", errno);
789                         ret = APP2EXT_ERROR_MOUNT;
790                 }
791                 break;
792         case MOUNT_TYPE_RW_REMOUNT:
793                 if ((ret = mount(dev, app_mmc_path, FS_TYPE,
794                         MS_MGC_VAL | MS_REMOUNT | MS_NOSUID, NULL)) < 0) {
795                         _E("read write remount failed "
796                                 "errono(%d), errstr(%s)", errno,
797                                 strerror_r(errno, err_buf, sizeof(err_buf)));
798                                 ret = APP2EXT_ERROR_MOUNT;
799                 }
800                 break;
801         default:
802                 _E("invalid mount type");
803                 break;
804         }
805
806         if (cmd == APP2SD_PRE_INSTALL || cmd == APP2SD_MOVE_APP_TO_MMC ||
807                 cmd == APP2SD_PRE_UPGRADE) {
808                 ret = _app2sd_create_directory_entry(application_path,
809                         pkgid, dir_list, uid);
810         }
811
812         if (mount_type != MOUNT_TYPE_RD &&
813                 mount_type != MOUNT_TYPE_RD_REMOUNT) {
814                 /* change lost+found permission */
815                 snprintf(temp_path, sizeof(temp_path), "%s/lost+found",
816                                 app_mmc_path);
817                 ret = _app2sd_make_directory(temp_path, uid);
818                 if (ret) {
819                         _E("create directory(%s) failed", temp_path);
820                         return APP2EXT_ERROR_CREATE_DIRECTORY;
821                 }
822         }
823
824         return ret;
825 }
826
827 int _app2sd_unmount_app_content(const char *application_path)
828 {
829         int ret = APP2EXT_SUCCESS;
830         char app_mmc_path[FILENAME_MAX] = { 0, };
831         char err_buf[1024] = {0,};
832
833         snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
834                 application_path);
835         if ((ret = umount(app_mmc_path)) < 0) {
836                 strerror_r(errno, err_buf, sizeof(err_buf));
837                 _D("unable to umount the dir, ret(%d) error(%d, %s)",
838                         ret, errno, err_buf);
839         }
840
841         return ret;
842 }
843
844 static int _app2sd_move_to_archive(const char *src_path, const char *arch_path)
845 {
846         int ret = APP2EXT_SUCCESS;
847
848         ret = _app2sd_copy_dir(src_path, arch_path);
849         if (ret && ret != APP2EXT_ERROR_ACCESS_FILE) {
850                 char err_buf[1024] = {0,};
851                 strerror_r(errno, err_buf, sizeof(err_buf));
852                 _E("unable to copy from (%s) to (%s), err is (%s)",
853                         src_path, arch_path, err_buf);
854                 return APP2EXT_ERROR_MOVE;
855         }
856
857         ret = _app2sd_delete_directory((char *)src_path);
858         if (ret) {
859                 _E("unable to delete (%s)", src_path);
860                 return APP2EXT_ERROR_DELETE_DIRECTORY;
861         }
862
863         return ret;
864 }
865
866 static int _app2sd_move_app_to_external(const char *pkgid, GList *dir_list,
867                 uid_t uid, char *mmc_path, char **image_path)
868 {
869         int ret = APP2EXT_SUCCESS;
870         mode_t mode = DIR_PERMS;
871         char temp_dir_path[FILENAME_MAX] = { 0, };
872         char app_mmc_path[FILENAME_MAX] = { 0, };
873         char app_archive_path[FILENAME_MAX] = { 0, };
874         char application_path[FILENAME_MAX] = { 0, };
875         char loopback_device[FILENAME_MAX] = { 0, };
876         unsigned long long total_size = 0;
877         int reqd_size = 0;
878         int reqd_disk_size = 0;
879         char *device_node = NULL;
880 #if !defined(TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION)
881         char *devi = NULL;
882 #endif
883         int free_mmc_mem = 0;
884         FILE *fp = NULL;
885         GList *list = NULL;
886         app2ext_dir_details *dir_detail = NULL;
887         char err_buf[1024] = { 0,};
888         char *encoded_id = NULL;
889
890         encoded_id = _app2sd_get_encoded_name(pkgid, uid);
891         if (encoded_id == NULL)
892                 return APP2EXT_ERROR_MEMORY_ALLOC_FAILED;
893
894         snprintf(loopback_device, sizeof(loopback_device), "%s/%s/%s",
895                         mmc_path, EXTIMG_DIR, encoded_id);
896         free(encoded_id);
897         _app2sd_set_application_path(pkgid, uid, application_path,
898                 sizeof(application_path));
899
900         /* check whether application is in external memory or not */
901         fp = fopen(loopback_device, "r+");
902         if (fp != NULL) {
903                 _W("Already %s entry is present in the SD Card, " \
904                         "delete entry and go on without return", pkgid);
905                 fclose(fp);
906                 _app2sd_force_clean(pkgid, application_path, loopback_device, uid);
907         }
908
909         snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
910                 application_path);
911         snprintf(app_archive_path, sizeof(app_archive_path), "%s/.archive",
912                 application_path);
913
914         ret = mkdir(app_mmc_path, mode);
915         if (ret) {
916                 if (errno != EEXIST) {
917                         _E("unable to create directory for archiving," \
918                                 " error(%d)", errno);
919                         return APP2EXT_ERROR_CREATE_DIRECTORY;
920                 }
921         }
922
923         ret = mkdir(app_archive_path, mode);
924         if (ret) {
925                 if (errno != EEXIST) {
926                         _E("unable to create directory for archiving," \
927                                 " error(%d)", errno);
928                         return APP2EXT_ERROR_CREATE_DIRECTORY;
929                 }
930         }
931
932         list = g_list_first(dir_list);
933         while (list) {
934                 dir_detail = (app2ext_dir_details *)list->data;
935                 if (dir_detail && dir_detail->name
936                         && dir_detail->type == APP2EXT_DIR_RO) {
937                         memset(temp_dir_path, '\0', sizeof(temp_dir_path));
938                         snprintf(temp_dir_path, sizeof(temp_dir_path),
939                                  "%s/%s", application_path,
940                                  dir_detail->name);
941                         _D("cal size of app dirs, temp_dir_path(%s)",
942                                 temp_dir_path);
943                         total_size +=
944                             _app2sd_calculate_dir_size(temp_dir_path);
945                 }
946                 list = g_list_next(list);
947         }
948
949         reqd_size = ((total_size) / (1024 * 1024)) + 2;
950         reqd_disk_size = reqd_size + ceil(reqd_size * 0.2);
951
952         /* find avialable free memory in the MMC card */
953         ret = _app2sd_get_available_free_memory(mmc_path, &free_mmc_mem);
954         if (ret) {
955                 _E("unable to get available free memory in MMC (%d)", ret);
956                 return APP2EXT_ERROR_MMC_STATUS;
957         }
958         /* if avaialalbe free memory in MMC is less than
959          * required size + 5MB, return error
960          */
961         if (reqd_disk_size > free_mmc_mem) {
962                 _E("insufficient memory in MMC for application installation (%d)",
963                         ret);
964                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
965         }
966         /* create a loopback device */
967         ret = _app2sd_create_loopback_device(pkgid, loopback_device,
968                 (reqd_disk_size + PKG_BUF_SIZE));
969         if (ret) {
970                 _E("loopback node creation failed");
971                 return ret;
972         }
973
974 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
975         ret = _app2sd_dmcrypt_setup_device(pkgid, loopback_device, false, uid);
976         if (ret) {
977                 _E("dmcrypt setup device error(%d)", ret);
978                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
979         }
980
981         ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device, false,
982                 uid, &device_node);
983         if (ret) {
984                 _E("dmcrypt open device error");
985                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
986         }
987 #else
988         /* perform loopback encryption setup */
989         device_node = _app2sd_do_loopback_encryption_setup(pkgid,
990                 loopback_device, uid);
991         if (!device_node) {
992                 _E("loopback encryption setup failed");
993                 return APP2EXT_ERROR_DO_LOSETUP;
994         }
995         _D("device_node (%s)", device_node);
996         /* check whether loopback device is associated with device node or not */
997         devi = _app2sd_find_associated_device_node(loopback_device);
998         if (devi == NULL) {
999                 _E("finding associated device node failed");
1000                 ret = APP2EXT_ERROR_DO_LOSETUP;
1001                 goto ERR;
1002         } else {
1003                 free(devi);
1004                 devi = NULL;
1005         }
1006 #endif
1007         /* format the loopback file system */
1008         ret = _app2sd_create_file_system(device_node);
1009         if (ret) {
1010                 _E("create ext4 filesystem failed");
1011                 ret = APP2EXT_ERROR_CREATE_FS;
1012                 goto ERR;
1013         }
1014
1015         list = g_list_first(dir_list);
1016         while (list) {
1017                 dir_detail = (app2ext_dir_details *)list->data;
1018                 if (dir_detail && dir_detail->name
1019                         && dir_detail->type == APP2EXT_DIR_RO) {
1020                         memset(temp_dir_path, '\0', FILENAME_MAX);
1021                         snprintf(temp_dir_path, sizeof(temp_dir_path),
1022                                  "%s/%s", application_path,
1023                                 dir_detail->name);
1024                         _D("app2archive, temp_dir_path(%s)",
1025                                 temp_dir_path);
1026                         ret = _app2sd_move_to_archive(temp_dir_path,
1027                                 app_archive_path);
1028                         if (ret) {
1029                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1030                                         _E("unable to access (%s)",
1031                                                 temp_dir_path);
1032                                 } else {
1033                                         _E("unable to copy from (%s) to (%s)",
1034                                              temp_dir_path,
1035                                              app_archive_path);
1036                                 }
1037                                 goto ERR;
1038                         }
1039                 }
1040                 list = g_list_next(list);
1041         }
1042
1043         /* mount the loopback encrypted pseudo device on application installation path
1044          * as with Read Write permission
1045          */
1046         ret = _app2sd_mount_app_content(application_path, pkgid, device_node,
1047                 MOUNT_TYPE_RW, dir_list, APP2SD_MOVE_APP_TO_MMC, uid);
1048         if (ret) {
1049                 _E("mount failed");
1050                 goto ERR;
1051         }
1052
1053         list = g_list_first(dir_list);
1054         while (list) {
1055                 dir_detail = (app2ext_dir_details *)list->data;
1056                 if (dir_detail && dir_detail->name
1057                         && dir_detail->type == APP2EXT_DIR_RO) {
1058                         memset(temp_dir_path, '\0', sizeof(temp_dir_path));
1059                         snprintf(temp_dir_path, sizeof(temp_dir_path),
1060                                 "%s/%s", app_archive_path,
1061                                 dir_detail->name);
1062                         _D("archive2mmc, temp_dir_path(%s)",
1063                                 temp_dir_path);
1064                         ret = _app2sd_copy_dir(temp_dir_path,
1065                                 app_mmc_path);
1066                         if (ret) {
1067                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1068                                         _E("unable to access (%s)",
1069                                                 temp_dir_path);
1070                                 } else {
1071                                         strerror_r(errno,
1072                                                 err_buf, sizeof(err_buf));
1073                                         _E("unable to copy from (%s) to (%s)," \
1074                                                 " error is (%s)",
1075                                                 temp_dir_path,
1076                                                 app_mmc_path, err_buf);
1077                                 }
1078                                 goto ERR;
1079                         }
1080                         ret = _app2sd_delete_directory(temp_dir_path);
1081                         if (ret) {
1082                                 _E("unable to delete (%s)", temp_dir_path);
1083                                 goto ERR;
1084                         }
1085                 }
1086                 list = g_list_next(list);
1087         }
1088
1089         ret = _app2sd_delete_directory(app_archive_path);
1090         if (ret) {
1091                 _E("unable to delete (%s)", app_archive_path);
1092                 ret = APP2EXT_ERROR_DELETE_DIRECTORY;
1093                 goto ERR;
1094         }
1095
1096         *image_path = strdup(loopback_device);
1097         return APP2EXT_SUCCESS;
1098
1099 ERR:
1100         if (device_node) {
1101                 free(device_node);
1102                 device_node = NULL;
1103         }
1104
1105         *image_path = NULL;
1106         return ret;
1107 }
1108
1109 static int _app2sd_move_app_to_internal(const char *pkgid, GList *dir_list,
1110                 uid_t uid, char *mmc_path)
1111 {
1112         int ret = APP2EXT_SUCCESS;
1113         mode_t mode = DIR_PERMS;
1114         char temp_dir_path[FILENAME_MAX] = { 0, };
1115         char app_mmc_path[FILENAME_MAX] = { 0, };
1116         char app_archive_path[FILENAME_MAX] = { 0, };
1117         char application_path[FILENAME_MAX] = { 0, };
1118         char loopback_device[FILENAME_MAX] = { 0, };
1119         char *device_node = NULL;
1120         FILE *fp = NULL;
1121         GList *list = NULL;
1122         app2ext_dir_details *dir_detail = NULL;
1123         int reqd_size = 0;
1124         int free_internal_mem = 0;
1125         unsigned long long temp = 0;
1126         char err_buf[1024] = {0,};
1127         char *encoded_id = NULL;
1128
1129         encoded_id = _app2sd_get_encoded_name(pkgid, uid);
1130         if (encoded_id == NULL)
1131                 return APP2EXT_ERROR_MEMORY_ALLOC_FAILED;
1132
1133         snprintf(loopback_device, sizeof(loopback_device), "%s/%s/%s",
1134                         mmc_path, EXTIMG_DIR, encoded_id);
1135         free(encoded_id);
1136         _app2sd_set_application_path(pkgid, uid, application_path,
1137                 sizeof(application_path));
1138
1139         /* check whether application is in external memory or not */
1140         fp = fopen(loopback_device, "r+");
1141         if (fp == NULL) {
1142                 _E("application (%s) is not installed on SD Card",
1143                      pkgid);
1144                 return APP2EXT_ERROR_FILE_ABSENT;
1145         } else {
1146                 fclose(fp);
1147                 fp = NULL;
1148         }
1149
1150         /* find avialable free memory in the internal storage */
1151         ret = _app2sd_get_available_free_memory(INTERNAL_STORAGE_PATH,
1152                 &free_internal_mem);
1153         if (ret) {
1154                 _E("unable to get available free memory in internal (%d)",
1155                         ret);
1156                 return APP2EXT_ERROR_MMC_STATUS;
1157         }
1158
1159         fp = fopen(loopback_device, "r+");
1160         if (fp == NULL) {
1161                 _E("app entry is not present in SD card");
1162                 return APP2EXT_ERROR_INVALID_PACKAGE;
1163         }
1164         fclose(fp);
1165
1166         /* get installed app size*/
1167         temp = _app2sd_calculate_file_size(loopback_device);
1168         reqd_size = (int)((temp) / (1024 * 1024));
1169         _D("reqd size is (%d)", reqd_size);
1170
1171         if (reqd_size == 0) {
1172                 _E("app entry is not present in SD Card");
1173                 return APP2EXT_ERROR_LOOPBACK_DEVICE_UNAVAILABLE;
1174         }
1175
1176         _I("reqd size: (%d)MB, free internal mem: (%d)MB",
1177                 reqd_size, free_internal_mem);
1178
1179         /* if avaialalbe free memory in internal storage is
1180          * less than required size, return error
1181          */
1182         if (reqd_size > free_internal_mem) {
1183                 _E("innsufficient memory in internal storage" \
1184                         " for application installation (%d)", ret);
1185                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
1186         }
1187
1188 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1189         device_node =
1190                 _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
1191 #else
1192         device_node = _app2sd_find_associated_device_node(loopback_device);
1193 #endif
1194         if (NULL == device_node) {
1195                 /* do loopback setup */
1196 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1197                 ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device,
1198                         false, uid, &device_node);
1199                 if (ret) {
1200                         _E("dmcrypt open device error(%d)", ret);
1201                         return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
1202                 }
1203 #else
1204                 device_node = _app2sd_do_loopback_encryption_setup(pkgid,
1205                         loopback_device, uid);
1206                 if (device_node == NULL) {
1207                         _E("loopback encryption setup failed");
1208                         return APP2EXT_ERROR_DO_LOSETUP;
1209                 }
1210 #endif
1211                 /* do mounting */
1212                 ret = _app2sd_mount_app_content(application_path,
1213                         pkgid, device_node, MOUNT_TYPE_RW,
1214                         dir_list, APP2SD_MOVE_APP_TO_PHONE, uid);
1215                 if (ret) {
1216                         _E("mount failed");
1217                         ret = APP2EXT_ERROR_MOUNT_PATH;
1218                         goto ERR;
1219                 }
1220         } else {
1221                 /* do re-mounting */
1222                 ret = _app2sd_mount_app_content(application_path,
1223                         pkgid, device_node, MOUNT_TYPE_RW_REMOUNT,
1224                         dir_list, APP2SD_MOVE_APP_TO_PHONE, uid);
1225                 if (ret) {
1226                         _E("re-mount failed");
1227                         ret = APP2EXT_ERROR_MOUNT_PATH;
1228                         goto ERR;
1229                 }
1230         }
1231
1232         snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
1233                 application_path);
1234         snprintf(app_archive_path, sizeof(app_archive_path), "%s/.archive",
1235                 application_path);
1236
1237         ret = mkdir(app_archive_path, mode);
1238         if (ret) {
1239                 if (errno != EEXIST) {
1240                         _E("unable to create directory for archiving," \
1241                                 " error(%d)", errno);
1242                         ret = APP2EXT_ERROR_CREATE_DIRECTORY;
1243                         goto ERR;
1244                 }
1245         }
1246
1247         list = g_list_first(dir_list);
1248         while (list) {
1249                 dir_detail = (app2ext_dir_details *)list->data;
1250                 if (dir_detail && dir_detail->name
1251                         && dir_detail->type == APP2EXT_DIR_RO) {
1252                         /* archiving code */
1253                         memset(temp_dir_path, '\0', sizeof(temp_dir_path));
1254                         snprintf(temp_dir_path, sizeof(temp_dir_path),
1255                                  "%s/%s", app_mmc_path,
1256                                  dir_detail->name);
1257                         _D("mmc2archive, temp_dir_path(%s)", temp_dir_path);
1258                         ret = _app2sd_copy_dir(temp_dir_path,
1259                                      app_archive_path);
1260                         if (ret) {
1261                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1262                                         _E("unable to access (%s)",
1263                                                 temp_dir_path);
1264                                 } else {
1265                                         strerror_r(errno,
1266                                                 err_buf, sizeof(err_buf));
1267                                         _E("unable to copy from (%s) to (%s),"
1268                                                 " error is (%s)",
1269                                                 temp_dir_path,
1270                                                 app_archive_path, err_buf);
1271                                 }
1272                                 goto ERR;
1273                         }
1274
1275                         /* delete the symbolic link files [bin, lib, res]*/
1276                         memset(temp_dir_path, '\0', sizeof(temp_dir_path));
1277                         snprintf(temp_dir_path, sizeof(temp_dir_path),
1278                                  "%s/%s", application_path,
1279                                  dir_detail->name);
1280                         _D("unlink, temp_dir_path(%s)", temp_dir_path);
1281                         ret = unlink(temp_dir_path);
1282                         if (ret) {
1283                                 if (errno == ENOENT) {
1284                                         _W("directory (%s) does not exist",
1285                                                 temp_dir_path);
1286                                 } else {
1287                                         _E("unable to remove the symbolic link file (%s)," \
1288                                                 " it is already unlinked",
1289                                                 temp_dir_path);
1290                                         goto ERR;
1291                                 }
1292                         }
1293
1294                         /* Copy content to destination */
1295                         memset(temp_dir_path, '\0', sizeof(temp_dir_path));
1296                         snprintf(temp_dir_path, sizeof(temp_dir_path),
1297                                 "%s/%s", app_archive_path,
1298                                 dir_detail->name);
1299                         _D("archive2app, temp_dir_path(%s)", temp_dir_path);
1300                         ret = _app2sd_copy_dir(temp_dir_path, application_path);
1301                         if (ret) {
1302                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1303                                         _E("unable to access (%s)",
1304                                                 temp_dir_path);
1305                                 } else {
1306                                         strerror_r(errno,
1307                                                 err_buf, sizeof(err_buf));
1308                                         _E("unable to copy from (%s) to (%s) " \
1309                                                 ", error is (%s)",
1310                                                 temp_dir_path,
1311                                                 application_path, err_buf);
1312                                 }
1313                                 goto ERR;
1314                         }
1315                 }
1316                 list = g_list_next(list);
1317         }
1318
1319         _D("copying file completed");
1320         ret = _app2sd_unmount_app_content(application_path);
1321         if (ret)
1322                 _E("unable to unmount SD directory for app (%s)",
1323                      pkgid);
1324
1325 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1326         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1327         if (ret)
1328                 _E("close dmcrypt device error(%d)", ret);
1329 #else
1330         ret = _app2sd_remove_loopback_encryption_setup(loopback_device);
1331         if (ret)
1332                 _E("unable to detach loopback setup for (%s)",
1333                      pkgid);
1334 #endif
1335
1336         ret = _app2sd_delete_loopback_device(loopback_device);
1337         if (ret)
1338                 _E("unable to delete the loopback device for (%s)",
1339                      pkgid);
1340
1341         ret = _app2sd_delete_directory(app_mmc_path);
1342         if (ret)
1343                 _E("unable to delete (%s)", app_mmc_path);
1344
1345         ret = _app2sd_delete_directory(app_archive_path);
1346         if (ret)
1347                 _E("unable to delete (%s)", app_archive_path);
1348
1349         /* remove passwrd from DB */
1350         ret = _app2sd_initialize_db();
1351         if (ret)
1352                 _E("app2sd db initialize failed");
1353
1354         ret = _app2sd_remove_info_from_db(pkgid, uid);
1355         if (ret)
1356                 _E("cannot remove info from db");
1357
1358         return APP2EXT_SUCCESS;
1359
1360 ERR:
1361         if (device_node) {
1362                 free(device_node);
1363                 device_node = NULL;
1364         }
1365
1366         return ret;
1367 }
1368
1369 int _app2sd_usr_move_app(const char *pkgid, app2ext_move_type move_type,
1370                 GList *dir_list, uid_t uid, char *mmc_path, char **image_path)
1371 {
1372         int ret = APP2EXT_SUCCESS;
1373
1374         switch (move_type) {
1375         case APP2EXT_MOVE_TO_EXT:
1376                 ret = _app2sd_move_app_to_external(pkgid, dir_list,
1377                         uid, mmc_path, image_path);
1378                 if (ret) {
1379                         _E("move app to external memory failed(%d)", ret);
1380                         return ret;
1381                 }
1382                 break;
1383         case APP2EXT_MOVE_TO_PHONE:
1384                 ret = _app2sd_move_app_to_internal(pkgid, dir_list,
1385                         uid, mmc_path);
1386                 if (ret) {
1387                         _E("move app to internal memory failed(%d)", ret);
1388                         return ret;
1389                 }
1390                 break;
1391         default:
1392                 _E("invalid argument");
1393                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
1394         }
1395
1396         return ret;
1397 }
1398
1399 int _app2sd_copy_ro_content(const char *src, const char *dest, GList *dir_list)
1400 {
1401         char path[FILENAME_MAX] = { 0, };
1402         int ret = APP2EXT_SUCCESS;
1403         GList *list = NULL;
1404         app2ext_dir_details *dir_detail = NULL;
1405
1406         list = g_list_first(dir_list);
1407         while (list) {
1408                 dir_detail = (app2ext_dir_details *)list->data;
1409                 if (dir_detail && dir_detail->name
1410                         && dir_detail->type == APP2EXT_DIR_RO) {
1411                         memset((void *)&path, '\0', sizeof(path));
1412                         snprintf(path, sizeof(path), "%s/%s", src,
1413                                  dir_detail->name);
1414                         ret = _app2sd_copy_dir(path, dest);
1415                         if (ret) {
1416                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1417                                         _E("unable to access (%s)", path);
1418                                 } else {
1419                                         _E("unable to copy from (%s) " \
1420                                                 "to (%s), errno is (%d)",
1421                                                 path, dest, errno);
1422                                         return APP2EXT_ERROR_MOVE;
1423                                 }
1424                         }
1425                 }
1426                 list = g_list_next(list);
1427         }
1428
1429         return APP2EXT_SUCCESS;
1430 }
1431
1432 int _app2sd_duplicate_device(const char *pkgid,
1433                 const char *loopback_device,
1434                 const char *temp_pkgid,
1435                 const char *temp_application_path,
1436                 const char *temp_loopback_device,
1437                 GList *dir_list, char *dev_node, int size,
1438                 uid_t uid)
1439 {
1440         int ret = 0;
1441         int err_res = 0;
1442 #if !defined(TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION)
1443         char *devi = NULL;
1444         char *result = NULL;
1445         char *passwd = NULL;
1446 #endif
1447
1448         /* create a new loopback device */
1449         ret = _app2sd_create_loopback_device(temp_pkgid,
1450                 temp_loopback_device, (size + PKG_BUF_SIZE));
1451         if (ret) {
1452                 _E("package already present");
1453                 return ret;
1454         }
1455
1456         /* perform loopback encryption setup */
1457 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1458         dev_node = _app2sd_dmcrypt_duplicate_encryption_setup(pkgid,
1459                 temp_loopback_device, uid);
1460         if (!dev_node) {
1461                 _E("dmcrypt duplicate encryption setup failed");
1462                 _app2sd_delete_loopback_device(temp_loopback_device);
1463                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
1464         }
1465 #else
1466         /* get password for loopback encryption */
1467         ret = _app2sd_initialize_db();
1468         if (ret) {
1469                 _E("app2sd db initialize failed");
1470                 return APP2EXT_ERROR_DB_INITIALIZE;
1471         }
1472
1473         if ((passwd = _app2sd_get_password_from_db(pkgid, uid)) == NULL) {
1474                 passwd = (char *)_app2sd_generate_password();
1475                 if (NULL == passwd) {
1476                         _E("unable to generate password");
1477                         return APP2EXT_ERROR_PASSWD_GENERATION;
1478                 } else {
1479                         if ((ret = _app2sd_set_info_in_db(pkgid,
1480                                 passwd, loopback_device, uid)) < 0) {
1481                                 _E("unable to save info");
1482                                 free(passwd);
1483                                 passwd = NULL;
1484                                 return APP2EXT_ERROR_SQLITE_REGISTRY;
1485                         }
1486                 }
1487         }
1488
1489         dev_node = _app2sd_do_loopback_duplicate_encryption_setup(pkgid,
1490                 temp_pkgid, temp_loopback_device, passwd, uid);
1491         if (!dev_node) {
1492                 _E("losetup failed, device node is (%s)", dev_node);
1493                 _app2sd_delete_loopback_device(temp_loopback_device);
1494                 free(passwd);
1495                 passwd = NULL;
1496                 return APP2EXT_ERROR_DO_LOSETUP;
1497         }
1498         free(passwd);
1499         passwd = NULL;
1500         _D("duplicate setup SUCCESS");
1501
1502         /* check whether loopback device is associated with
1503          * device node or not
1504          */
1505         devi = _app2sd_find_associated_device_node(temp_loopback_device);
1506         if (devi == NULL) {
1507                 _E("finding associated device node failed");
1508                 err_res = APP2EXT_ERROR_DO_LOSETUP;
1509                 goto FINISH_OFF;
1510         }
1511         _D("losetup SUCCESS");
1512 #endif
1513
1514         /* format the loopback file system */
1515         ret = _app2sd_create_file_system(dev_node);
1516         if (ret) {
1517                 _E("creating fs failed");
1518                 err_res = APP2EXT_ERROR_CREATE_FS;
1519                 goto FINISH_OFF;
1520         }
1521         _D("create filesystem SUCCESS");
1522
1523         /* do mounting for new dev*/
1524         ret = _app2sd_mount_app_content(temp_application_path, pkgid,
1525                 dev_node, MOUNT_TYPE_RW, dir_list,
1526                 APP2SD_PRE_UPGRADE, uid);
1527         if (ret) {
1528                 _E("remount failed");
1529                 err_res = APP2EXT_ERROR_MOUNT_PATH;
1530                 goto FINISH_OFF;
1531         }
1532
1533 #if !defined(TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION)
1534         if (devi) {
1535                 free(devi);
1536                 devi = NULL;
1537         }
1538 #endif
1539
1540         return APP2EXT_SUCCESS;
1541
1542 FINISH_OFF:
1543         if (dev_node) {
1544 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1545                 ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1546                 if (ret)
1547                         _E("close dmcrypt device error(%d)", ret);
1548 #else
1549                 result = _app2sd_detach_loop_device(dev_node);
1550                 if (result) {
1551                         free(result);
1552                         result = NULL;
1553                 }
1554 #endif
1555                 _app2sd_delete_loopback_device(temp_loopback_device);
1556                 free(dev_node);
1557                 dev_node = NULL;
1558         }
1559
1560         return err_res;
1561 }
1562
1563 int _app2sd_update_loopback_device_size(const char *pkgid,
1564                 const char *loopback_device,
1565                 const char *application_path,
1566                 const char *temp_pkgid,
1567                 const char *temp_loopback_device,
1568                 const char *temp_application_path,
1569                 int size, GList *dir_list,
1570                 uid_t uid)
1571 {
1572         int ret = 0;
1573         char *device_node = NULL;
1574         char *old_device_node = NULL;
1575         int err_res = 0;
1576         char app_mmc_path[FILENAME_MAX] = { 0, };
1577         char temp_app_mmc_path[FILENAME_MAX] = { 0, };
1578
1579         ret = _app2sd_duplicate_device(pkgid, loopback_device,
1580                 temp_pkgid, temp_application_path, temp_loopback_device,
1581                 dir_list, device_node, size, uid);
1582         if (ret) {
1583                 _E("creating duplicate device failed");
1584                 return ret;
1585         }
1586
1587         /* get the associated device node for SD card applicatione */
1588 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1589         old_device_node =
1590                 _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
1591 #else
1592         old_device_node = _app2sd_find_associated_device_node(loopback_device);
1593 #endif
1594         if (NULL == old_device_node) {
1595                 /* do loopback setup */
1596 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1597                 ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device,
1598                         false, uid, &old_device_node);
1599                 if (ret) {
1600                         _E("dmcrypt open device error");
1601                         err_res = APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
1602                         goto FINISH_OFF;
1603                 }
1604 #else
1605                 old_device_node = _app2sd_do_loopback_encryption_setup(pkgid,
1606                         loopback_device, uid);
1607                 if (old_device_node == NULL) {
1608                         _E("loopback encryption setup failed");
1609                         err_res = APP2EXT_ERROR_DO_LOSETUP;
1610                         goto FINISH_OFF;
1611                 }
1612 #endif
1613                 /* do mounting */
1614                 ret = _app2sd_mount_app_content(application_path, pkgid,
1615                         old_device_node, MOUNT_TYPE_RW, dir_list,
1616                         APP2SD_PRE_UPGRADE, uid);
1617                 if (ret) {
1618                         _E("remount failed");
1619                         err_res = APP2EXT_ERROR_MOUNT_PATH;
1620                 }
1621         } else {
1622                 /* do re-mounting */
1623                 ret = _app2sd_mount_app_content(application_path, pkgid,
1624                         old_device_node, MOUNT_TYPE_RW_REMOUNT, dir_list,
1625                         APP2SD_PRE_UPGRADE, uid);
1626                 if (ret) {
1627                         _E("remount failed");
1628                         err_res = APP2EXT_ERROR_MOUNT_PATH;
1629                 }
1630         }
1631
1632         snprintf(app_mmc_path, sizeof(app_mmc_path),
1633                  "%s/.mmc", application_path);
1634         snprintf(temp_app_mmc_path, sizeof(temp_app_mmc_path),
1635                 "%s/.mmc", temp_application_path);
1636
1637         ret = _app2sd_copy_ro_content(app_mmc_path,
1638                 temp_app_mmc_path, dir_list);
1639         if (ret) {
1640                 _E("copy ro content failed");
1641                 err_res = ret;
1642         }
1643
1644         ret = _app2sd_unmount_app_content(application_path);
1645         if (ret) {
1646                 _E("unable to unmount the SD application");
1647                 err_res = APP2EXT_ERROR_UNMOUNT;
1648         }
1649
1650         ret = _app2sd_unmount_app_content(temp_application_path);
1651         if (ret) {
1652                 _E("unable to unmount the SD application");
1653                 err_res = APP2EXT_ERROR_UNMOUNT;
1654                 goto FINISH_OFF;
1655         }
1656
1657 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1658         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1659         if (ret) {
1660                 _E("close dmcrypt device error(%d)", ret);
1661                 err_res = APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
1662                 goto FINISH_OFF;
1663         }
1664
1665         ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1666         if (ret) {
1667                 _E("close dmcrypt device error(%d)", ret);
1668                 err_res = APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
1669                 goto FINISH_OFF;
1670         }
1671 #else
1672         ret = _app2sd_remove_loopback_encryption_setup(loopback_device);
1673         if (ret) {
1674                 _E("unable to remove loopback setup");
1675                 err_res = APP2EXT_ERROR_DELETE_LOOPBACK_DEVICE;
1676         }
1677
1678         ret = _app2sd_remove_loopback_encryption_setup(temp_loopback_device);
1679         if (ret) {
1680                 _E("unable to remove loopback setup");
1681                 err_res = APP2EXT_ERROR_DELETE_LOOPBACK_DEVICE;
1682                 goto FINISH_OFF;
1683         }
1684 #endif
1685
1686         ret = _app2sd_delete_directory(loopback_device);
1687         if (ret) {
1688                 _E("unable to delete (%s)", loopback_device);
1689                 err_res = APP2EXT_ERROR_DELETE_DIRECTORY;
1690                 goto FINISH_OFF;
1691         }
1692
1693         ret = _app2sd_rename_dir(temp_loopback_device, loopback_device);
1694         if (ret) {
1695                 _E("unable to rename (%s)", temp_loopback_device);
1696                 err_res = APP2EXT_ERROR_MOVE;
1697                 goto FINISH_OFF;
1698         }
1699
1700         ret = _app2sd_delete_directory(temp_application_path);
1701         if (ret) {
1702                 _E("unable to delete (%s)", temp_application_path);
1703                 err_res = APP2EXT_ERROR_DELETE_DIRECTORY;
1704                 goto FINISH_OFF;
1705         }
1706
1707         return APP2EXT_SUCCESS;
1708
1709 FINISH_OFF:
1710         if (old_device_node) {
1711                 free(old_device_node);
1712                 old_device_node = NULL;
1713         }
1714
1715 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1716         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1717         if (ret)
1718                 _E("close dmcrypt device error(%d)", ret);
1719
1720         ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1721
1722         if (ret)
1723                 _E("close dmcrypt device error(%d)", ret);
1724 #else
1725         ret = _app2sd_remove_loopback_encryption_setup(loopback_device);
1726         if (ret)
1727                 _E("unable to remove loopback setup");
1728
1729         ret = _app2sd_remove_loopback_encryption_setup(temp_loopback_device);
1730         if (ret)
1731                 _E("unable to remove loopback setup");
1732 #endif
1733
1734         _app2sd_delete_loopback_device(temp_loopback_device);
1735
1736         ret = _app2sd_delete_directory(temp_application_path);
1737         if (ret)
1738                 _E("unable to delete (%s)", temp_application_path);
1739
1740         return err_res;
1741 }
1742
1743 int _app2sd_force_clean(const char *pkgid, const char *application_path,
1744                 const char *loopback_device, uid_t uid)
1745 {
1746         int ret = APP2EXT_SUCCESS;
1747
1748         /* unmount the loopback encrypted pseudo device from the application installation path */
1749         ret = _app2sd_unmount_app_content(application_path);
1750         if (ret)
1751                 _W("unable to unmount the app content (%d)", ret);
1752
1753         /* detach the loopback encryption setup for the application */
1754 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1755         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1756         if (ret)
1757                 _W("close dmcrypt device error (%d)", ret);
1758 #else
1759         ret = _app2sd_remove_all_loopback_encryption_setups(loopback_device);
1760         if (ret)
1761                 _W("unable to detach the loopback encryption setup for the application");
1762 #endif
1763
1764         /* delete the loopback device from the SD card */
1765         ret = _app2sd_delete_loopback_device(loopback_device);
1766         if (ret)
1767                 _W("unable to detach the loopback encryption setup for the application");
1768
1769         /* delete symlink */
1770         _app2sd_delete_symlink(application_path);
1771
1772         /* remove passwrd from DB */
1773         ret = _app2sd_initialize_db();
1774         if (ret)
1775                 _W("app2sd db initialize failed");
1776
1777         ret = _app2sd_remove_info_from_db(pkgid, uid);
1778         if (ret)
1779                 _W("cannot remove info from db");
1780
1781
1782         return ret;
1783 }