make app2sd more robust on some failure cases.
[platform/core/appfw/app2sd.git] / plugin / app2sd / src / 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, FILENAME_MAX - 1, "%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, BUF_SIZE, "/dev/loop%d", count);
148                 while ((fp = fopen(dev_path, "r+")) != NULL) {
149                         count = count + 1;
150                         snprintf(dev_path, BUF_SIZE, "/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(pkgid);
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(pkgid);
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, BUF_SIZE, "/bin/echo '%s' | /sbin/cryptsetup -q -i %d " \
400                 "-c aes-cbc-lmk -s %d --align-payload=8 luksFormat %s",
401                 passwd, DMCRYPT_ITER_TIME, DMCRYPT_KEY_LEN, loopback_device);
402
403         ret = system(dmcrypt_setup_cmd);
404         if (ret) {
405                 strerror_r(errno, err_buf, sizeof(err_buf));
406                 _E("Error setting up dmcrypt on app2sd file, " \
407                         "error(%s), ret(%d)", err_buf, ret);
408                 if (passwd) {
409                         free(passwd);
410                         passwd = NULL;
411                 }
412                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
413         }
414
415         if (passwd) {
416                 free(passwd);
417                 passwd = NULL;
418         }
419
420         return ret;
421 }
422
423 int _app2sd_dmcrypt_open_device(const char *pkgid, const char *loopback_device,
424                 bool is_dup, uid_t uid, char **dev_node)
425 {
426         int ret = APP2EXT_SUCCESS;
427         char *passwd = NULL;
428         char dmcrypt_open_cmd[BUF_SIZE] = { 0, };
429         char dev_name[BUF_SIZE] = { 0, };
430         char buf[BUF_SIZE] = { 0, };
431         int len = 0;
432
433         if (pkgid == NULL || loopback_device == NULL) {
434                 _E("invalid argument");
435                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
436         }
437
438         if (is_dup)
439                 snprintf(dev_name, BUF_SIZE, "%s.new_%d", pkgid, uid);
440         else
441                 snprintf(dev_name, BUF_SIZE, "%s_%d", pkgid, uid);
442
443         /* get password for dmcrypt encryption */
444         ret = _app2sd_initialize_db();
445         if (ret) {
446                 _E("app2sd db initialize failed");
447                 return APP2EXT_ERROR_DB_INITIALIZE;
448         }
449         if ((passwd = _app2sd_get_password_from_db(pkgid, uid)) == NULL) {
450                 _E("no password found for [%s]", pkgid);
451                 return APP2EXT_ERROR_SQLITE_REGISTRY;
452         }
453
454         snprintf(dmcrypt_open_cmd, BUF_SIZE, "/bin/echo '%s' | /sbin/cryptsetup -q luksOpen %s %s",
455                 passwd, loopback_device, dev_name);
456
457         ret = system(dmcrypt_open_cmd);
458         if (ret) {
459                 strerror_r(errno, buf, sizeof(buf));
460                 _E("error opening dmcrypt device, error: [%s]", buf);
461                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
462         }
463
464         snprintf(buf, BUF_SIZE, "/dev/mapper/%s", dev_name);
465         len = strlen(buf);
466         *dev_node = (char *)calloc(len + 1, sizeof(char));
467         if (*dev_node == NULL) {
468                 _E("memory alloc failed");
469                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
470         }
471         snprintf(*dev_node, len + 1, "%s", buf);
472
473         return ret;
474 }
475
476 int _app2sd_dmcrypt_close_device(const char *pkgid, uid_t uid)
477 {
478         int ret = APP2EXT_SUCCESS;
479         char dev_node[BUF_SIZE] = { '\0' };
480         char dmcrypt_close_cmd[BUF_SIZE] = { '\0' };
481         char err_buf[BUF_SIZE] = { '\0' };
482         char *t_dev_node = NULL;
483
484         if (pkgid == NULL) {
485                 _E("invalid argument\n");
486                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
487         }
488
489         t_dev_node = _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
490         if (!t_dev_node) {
491                 _E("no associated device node(%s_%d) found", pkgid, uid);
492                 return APP2EXT_ERROR_DMCRYPT_DEVICE_UNAVAILABLE;
493         }
494
495         free(t_dev_node);
496         t_dev_node = NULL;
497
498         snprintf(dev_node, BUF_SIZE, "/dev/mapper/%s_%d", pkgid, uid);
499         snprintf(dmcrypt_close_cmd, BUF_SIZE, "/sbin/cryptsetup -q luksClose %s", dev_node);
500         ret = system(dmcrypt_close_cmd);
501         if (ret) {
502                 strerror_r(errno, err_buf, sizeof(err_buf));
503                 _E("error closing dmcrypt on app2sd file,"\
504                         " error: [%s]", err_buf);
505                 return APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
506         }
507
508         return ret;
509 }
510
511 char *_app2sd_find_associated_dmcrypt_device_node(const char *pkgid, uid_t uid)
512 {
513         char *dev_node = NULL;
514         char buf[BUF_SIZE] = { 0, };
515         int len = 0;
516
517         snprintf(buf, BUF_SIZE, "/dev/mapper/%s_%d", pkgid, uid);
518         len = strlen(buf);
519         dev_node = (char *)calloc(len + 1, sizeof(char));
520         if (dev_node == NULL) {
521                 _E("memory alloc failed");
522                 return NULL;
523         }
524         snprintf(dev_node, len + 1, "%s", buf);
525
526         if (access(dev_node, F_OK) == 0) {
527                 _D("device_node: (%s)", dev_node);
528                 return dev_node;
529         }
530
531         free(dev_node);
532         dev_node = NULL;
533
534         return NULL;
535 }
536
537 char *_app2sd_dmcrypt_duplicate_encryption_setup(const char *pkgid,
538                 const char *temp_loopback_device, uid_t uid)
539 {
540         int ret = APP2EXT_SUCCESS;
541         char *device_node = NULL;
542
543         if (pkgid == NULL || temp_loopback_device == NULL) {
544                 _E("invalid argument\n");
545                 return NULL;
546         }
547
548         ret = _app2sd_dmcrypt_setup_device(pkgid, temp_loopback_device, true, uid);
549         if (ret) {
550                 _E("dmcrypt setup device error(%d)", ret);
551                 return NULL;
552         }
553
554         ret = _app2sd_dmcrypt_open_device(pkgid, temp_loopback_device, true,
555                 uid, &device_node);
556         if (ret) {
557                 _E("dmcrypt open device error");
558                 return NULL;
559         }
560
561         return device_node;
562 }
563 #endif
564
565 int _app2sd_create_loopback_device(const char *pkgid,
566                 const char *loopback_device, int size)
567 {
568         int ret = APP2EXT_SUCCESS;
569         char command[FILENAME_MAX] = { 0, };
570         char buff[BUF_SIZE] = { 0, };
571         FILE *fp = NULL;
572
573         if (NULL == pkgid || size <= 0) {
574                 _E("invalid argument");
575                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
576         }
577         snprintf(command, FILENAME_MAX - 1, "of=%s", loopback_device);
578         snprintf(buff, BUF_SIZE - 1, "count=%d", size);
579
580         const char *argv1[] = { "/bin/dd", "if=/dev/zero",
581                 command, "bs=1M", buff, NULL };
582
583         if ((fp = fopen(loopback_device, "r+")) != NULL) {
584                 _W("encrypted file already exists (%s)",
585                         loopback_device);
586                 fclose(fp);
587                 return APP2EXT_ERROR_PKG_EXISTS;
588         }
589
590         ret = _xsystem(argv1);
591         if (ret)
592                 _E("command (%s) failed, ret(%d), errno(%d)", command, ret, errno);
593
594         return ret;
595 }
596
597 int _app2sd_delete_loopback_device(const char *loopback_device)
598 {
599         int ret = APP2EXT_SUCCESS;
600
601         ret = unlink(loopback_device);
602         if (ret) {
603                 if (errno == ENOENT) {
604                         _W("unable to access file (%s)", loopback_device);
605                 } else {
606                         _E("unable to delete (%s)", loopback_device);
607                         return APP2EXT_ERROR_DELETE_LOOPBACK_DEVICE;
608                 }
609         }
610
611         return APP2EXT_SUCCESS;
612 }
613
614 int _app2sd_create_file_system(const char *device_path)
615 {
616         int ret = APP2EXT_SUCCESS;
617         FILE *fp = NULL;
618         char err_buf[1024] = {0,};
619
620         if (device_path == NULL) {
621                 _E("invalid param");
622                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
623         }
624
625         /* Format the filesystem [create a filesystem]*/
626         const char *argv[] = { "/sbin/mkfs.ext4", device_path, NULL };
627         fp = fopen(device_path, "r+");
628         if (fp == NULL) {
629                 strerror_r(errno, err_buf, sizeof(err_buf));
630                 _E("unable to access (%s) error is (%d, %s)",
631                      device_path, errno, err_buf);
632                 return APP2EXT_ERROR_ACCESS_FILE;
633         } else {
634                 fclose(fp);
635         }
636         ret = _xsystem(argv);
637         if (ret) {
638                 strerror_r(errno, err_buf, sizeof(err_buf));
639                 _E("creating file system failed, error is (%s)",
640                      err_buf);
641                 return APP2EXT_ERROR_CREATE_FS;
642         }
643         return ret;
644 }
645
646 static int _app2sd_create_dir_with_link(const char *application_path,
647                 const char *pkgid, const char *dir_name, uid_t uid)
648 {
649         int ret = APP2EXT_SUCCESS;
650         char application_dir_mmc_path[FILENAME_MAX] = { 0, };
651         char application_dir_path[FILENAME_MAX] = { 0, };
652
653         snprintf(application_dir_mmc_path, FILENAME_MAX - 1, "%s/.mmc/%s",
654                 application_path, dir_name);
655         snprintf(application_dir_path, FILENAME_MAX, "%s/%s",
656                 application_path, dir_name);
657
658         ret = _app2sd_make_directory(application_dir_mmc_path, uid);
659         if (ret) {
660                 _E("create directory failed");
661                 return APP2EXT_ERROR_CREATE_DIRECTORY;
662         }
663
664         if ((ret = symlink(application_dir_mmc_path,
665                 application_dir_path)) < 0) {
666                 if (errno == EEXIST) {
667                         _D("file with symlink name present (%s)",
668                                 application_dir_path);
669                 } else {
670                         _E("symbolic link creation "
671                                 "failed, error no is (%d)", errno);
672                         return APP2EXT_ERROR_CREATE_SYMLINK;
673                 }
674         }
675
676         return APP2EXT_SUCCESS;
677 }
678
679 static int _app2sd_create_directory_entry(const char *application_path,
680                 const char *pkgid, GList *dir_list, uid_t uid)
681 {
682         int ret = APP2EXT_SUCCESS;
683         GList *list = NULL;
684         app2ext_dir_details *dir_detail = NULL;
685
686         list = g_list_first(dir_list);
687         while (list) {
688                 dir_detail = (app2ext_dir_details *)list->data;
689                 if (dir_detail && dir_detail->name
690                         && dir_detail->type == APP2EXT_DIR_RO) {
691                         ret = _app2sd_create_dir_with_link(application_path,
692                                 pkgid, dir_detail->name, uid);
693                         if (ret)
694                                 return ret;
695                 }
696                 list = g_list_next(list);
697         }
698         return APP2EXT_SUCCESS;
699 }
700
701 int _app2sd_mount_app_content(const char *application_path, const char *pkgid,
702                 const char *dev, int mount_type, GList *dir_list,
703                 app2sd_cmd cmd, uid_t uid)
704 {
705         int ret = APP2EXT_SUCCESS;
706         int fd = -1;
707         char application_mmc_path[FILENAME_MAX] = { 0, };
708         char temp_path[FILENAME_MAX] = { 0, };
709         char err_buf[1024] = {0,};
710         struct timespec time = {
711                 .tv_sec = 0,
712                 .tv_nsec = 1000 * 1000 * 200
713         };
714
715         if (NULL == dev) {
716                 _E("input param is NULL (%s)",
717                              dev);
718                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
719         }
720
721         /* check directory existence */
722         fd = open(application_path, O_RDONLY|O_DIRECTORY);
723         if (fd < 0) {
724                 _E("path(%s) error(%d)", application_path, errno);
725                 return APP2EXT_ERROR_OPEN_DIR;
726         }
727         close(fd);
728
729         snprintf(application_mmc_path, FILENAME_MAX - 1, "%s/.mmc",
730                 application_path);
731         fd = open(application_mmc_path, O_RDONLY|O_DIRECTORY);
732         if (fd < 0) {
733                 _E("path(%s) error(%d)", application_mmc_path, errno);
734                 return APP2EXT_ERROR_OPEN_DIR;
735         }
736         close(fd);
737
738         nanosleep(&time, NULL); /* 200ms sleep */
739         _D("give a delay for mount");
740
741         switch (mount_type) {
742         case MOUNT_TYPE_RD:
743                 if ((ret = mount(dev, application_mmc_path, FS_TYPE,
744                         MS_MGC_VAL | MS_RDONLY | MS_NOSUID, NULL)) < 0) {
745                         _E("read only mount failed, " \
746                                 "errono is (%d), " \
747                                 "dev is (%s) path is (%s)",
748                                 errno, dev, application_mmc_path);
749                         ret = APP2EXT_ERROR_MOUNT;
750                 }
751                 break;
752         case MOUNT_TYPE_RW:
753                 if ((ret = mount(dev, application_mmc_path, FS_TYPE,
754                         MS_MGC_VAL | MS_NOSUID, NULL)) < 0) {
755                         _E("read write mount failed, " \
756                                 "errono is (%d)", errno);
757                         ret = APP2EXT_ERROR_MOUNT;
758                 }
759                 break;
760         case MOUNT_TYPE_RW_NOEXEC:
761                 if ((ret = mount(dev, application_mmc_path, FS_TYPE,
762                         MS_MGC_VAL | MS_NOEXEC | MS_NOSUID, NULL)) < 0) {
763                         _E("rwnx mount failed " \
764                                 "errono is (%d)", errno);
765                         ret = APP2EXT_ERROR_MOUNT;
766                 }
767                 break;
768         case MOUNT_TYPE_RD_REMOUNT:
769                 if ((ret = mount(dev, application_mmc_path, FS_TYPE,
770                         MS_MGC_VAL | MS_RDONLY | MS_REMOUNT | MS_NOSUID,
771                         NULL)) < 0) {
772                         _E("read remount failed "
773                                 "errono is (%d)", errno);
774                         ret = APP2EXT_ERROR_MOUNT;
775                 }
776                 break;
777         case MOUNT_TYPE_RW_REMOUNT:
778                 if ((ret = mount(dev, application_mmc_path, FS_TYPE,
779                         MS_MGC_VAL | MS_REMOUNT | MS_NOSUID, NULL)) < 0) {
780                         _E("read write remount failed "
781                                 "errono(%d), errstr(%s)", errno,
782                                 strerror_r(errno, err_buf, sizeof(err_buf)));
783                                 ret = APP2EXT_ERROR_MOUNT;
784                 }
785                 break;
786         default:
787                 _E("invalid mount type");
788                 break;
789         }
790
791         if (cmd == APP2SD_PRE_INSTALL || cmd == APP2SD_MOVE_APP_TO_MMC ||
792                 cmd == APP2SD_PRE_UPGRADE) {
793                 ret = _app2sd_create_directory_entry(application_path,
794                         pkgid, dir_list, uid);
795         }
796
797         if (mount_type != MOUNT_TYPE_RD &&
798                 mount_type != MOUNT_TYPE_RD_REMOUNT) {
799                 /* change lost+found permission */
800                 snprintf(temp_path, FILENAME_MAX - 1, "%s/lost+found",
801                                 application_mmc_path);
802                 ret = _app2sd_make_directory(temp_path, uid);
803                 if (ret) {
804                         _E("create directory(%s) failed", temp_path);
805                         return APP2EXT_ERROR_CREATE_DIRECTORY;
806                 }
807         }
808
809         return ret;
810 }
811
812 int _app2sd_unmount_app_content(const char *application_path)
813 {
814         int ret = APP2EXT_SUCCESS;
815         char application_dir_mmc_path[FILENAME_MAX] = { 0, };
816         char err_buf[1024] = {0,};
817
818         snprintf(application_dir_mmc_path, FILENAME_MAX - 1, "%s/.mmc",
819                 application_path);
820         if ((ret = umount(application_dir_mmc_path)) < 0) {
821                 strerror_r(errno, err_buf, sizeof(err_buf));
822                 _E("unable to umount the dir, ret(%d) error(%d, %s)",
823                         ret, errno, err_buf);
824         }
825
826         return ret;
827 }
828
829 static int _app2sd_move_to_archive(const char *src_path, const char *arch_path)
830 {
831         int ret = APP2EXT_SUCCESS;
832
833         ret = _app2sd_copy_dir(src_path, arch_path);
834         if (ret && ret != APP2EXT_ERROR_ACCESS_FILE) {
835                 char err_buf[1024] = {0,};
836                 strerror_r(errno, err_buf, sizeof(err_buf));
837                 _E("unable to copy from (%s) to (%s), err is (%s)",
838                         src_path, arch_path, err_buf);
839                 return APP2EXT_ERROR_MOVE;
840         }
841
842         ret = _app2sd_delete_directory((char *)src_path);
843         if (ret) {
844                 _E("unable to delete (%s)", src_path);
845                 return APP2EXT_ERROR_DELETE_DIRECTORY;
846         }
847
848         return ret;
849 }
850
851 static int _app2sd_move_app_to_external(const char *pkgid, GList *dir_list,
852                 uid_t uid, char *mmc_path)
853 {
854         int ret = APP2EXT_SUCCESS;
855         mode_t mode = DIR_PERMS;
856         char temp_dir_path[FILENAME_MAX] = { 0, };
857         char application_mmc_path[FILENAME_MAX] = { 0, };
858         char application_archive_path[FILENAME_MAX] = { 0, };
859         char application_path[FILENAME_MAX] = { 0, };
860         char loopback_device[FILENAME_MAX] = { 0, };
861         unsigned long long total_size = 0;
862         int reqd_size = 0;
863         int reqd_disk_size = 0;
864         char *device_node = NULL;
865 #if !defined(TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION)
866         char *devi = NULL;
867 #endif
868         int free_mmc_mem = 0;
869         FILE *fp = NULL;
870         GList *list = NULL;
871         app2ext_dir_details *dir_detail = NULL;
872         char err_buf[1024] = { 0,};
873         char *encoded_id = NULL;
874
875         encoded_id = _app2sd_get_encoded_name(pkgid, uid);
876         if (encoded_id == NULL)
877                 return APP2EXT_ERROR_MEMORY_ALLOC_FAILED;
878
879         snprintf(loopback_device, FILENAME_MAX - 1, "%s/%s/%s",
880                         mmc_path, EXTIMG_DIR, encoded_id);
881         free(encoded_id);
882         if (_is_global(uid)) {
883                 snprintf(application_path, FILENAME_MAX - 1, "%s/%s",
884                         tzplatform_getenv(TZ_SYS_RW_APP), pkgid);
885         } else {
886                 tzplatform_set_user(uid);
887                 snprintf(application_path, FILENAME_MAX - 1, "%s/%s",
888                         tzplatform_getenv(TZ_USER_APP), pkgid);
889                 tzplatform_reset_user();
890         }
891
892         /* check whether application is in external memory or not */
893         fp = fopen(loopback_device, "r+");
894         if (fp != NULL) {
895                 _W("Already %s entry is present in the SD Card, " \
896                         "delete entry and go on without return", pkgid);
897                 fclose(fp);
898                 _app2sd_force_clean(pkgid, application_path, loopback_device, uid);
899         }
900
901         snprintf(application_mmc_path, FILENAME_MAX - 1, "%s/.mmc",
902                 application_path);
903         snprintf(application_archive_path, FILENAME_MAX - 1, "%s/.archive",
904                 application_path);
905
906         ret = mkdir(application_mmc_path, mode);
907         if (ret) {
908                 if (errno != EEXIST) {
909                         _E("unable to create directory for archiving," \
910                                 " error(%d)", errno);
911                         return APP2EXT_ERROR_CREATE_DIRECTORY;
912                 }
913         }
914
915         ret = mkdir(application_archive_path, mode);
916         if (ret) {
917                 if (errno != EEXIST) {
918                         _E("unable to create directory for archiving," \
919                                 " error(%d)", errno);
920                         return APP2EXT_ERROR_CREATE_DIRECTORY;
921                 }
922         }
923
924         list = g_list_first(dir_list);
925         while (list) {
926                 dir_detail = (app2ext_dir_details *)list->data;
927                 if (dir_detail && dir_detail->name
928                         && dir_detail->type == APP2EXT_DIR_RO) {
929                         memset(temp_dir_path, '\0', FILENAME_MAX);
930                         snprintf(temp_dir_path, FILENAME_MAX,
931                                  "%s/%s", application_path,
932                                  dir_detail->name);
933                         _D("cal size of app dirs, temp_dir_path(%s)",
934                                 temp_dir_path);
935                         total_size +=
936                             _app2sd_calculate_dir_size(temp_dir_path);
937                 }
938                 list = g_list_next(list);
939         }
940
941         reqd_size = ((total_size) / (1024 * 1024)) + 2;
942         reqd_disk_size = reqd_size + ceil(reqd_size * 0.2);
943
944         /* find avialable free memory in the MMC card */
945         ret = _app2sd_get_available_free_memory(mmc_path, &free_mmc_mem);
946         if (ret) {
947                 _E("unable to get available free memory in MMC (%d)", ret);
948                 return APP2EXT_ERROR_MMC_STATUS;
949         }
950         /* if avaialalbe free memory in MMC is less than
951          * required size + 5MB, return error
952          */
953         if (reqd_disk_size > free_mmc_mem) {
954                 _E("insufficient memory in MMC for application installation (%d)",
955                         ret);
956                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
957         }
958         /* create a loopback device */
959         ret = _app2sd_create_loopback_device(pkgid, loopback_device,
960                 (reqd_disk_size + PKG_BUF_SIZE));
961         if (ret) {
962                 _E("loopback node creation failed");
963                 return ret;
964         }
965
966 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
967         ret = _app2sd_dmcrypt_setup_device(pkgid, loopback_device, false, uid);
968         if (ret) {
969                 _E("dmcrypt setup device error(%d)", ret);
970                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
971         }
972
973         ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device, false,
974                 uid, &device_node);
975         if (ret) {
976                 _E("dmcrypt open device error");
977                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
978         }
979 #else
980         /* perform loopback encryption setup */
981         device_node = _app2sd_do_loopback_encryption_setup(pkgid,
982                 loopback_device, uid);
983         if (!device_node) {
984                 _E("loopback encryption setup failed");
985                 return APP2EXT_ERROR_DO_LOSETUP;
986         }
987         _D("device_node (%s)", device_node);
988         /* check whether loopback device is associated with device node or not */
989         devi = _app2sd_find_associated_device_node(loopback_device);
990         if (devi == NULL) {
991                 _E("finding associated device node failed");
992                 ret = APP2EXT_ERROR_DO_LOSETUP;
993                 goto ERR;
994         } else {
995                 free(devi);
996                 devi = NULL;
997         }
998 #endif
999         /* format the loopback file system */
1000         ret = _app2sd_create_file_system(device_node);
1001         if (ret) {
1002                 _E("create ext4 filesystem failed");
1003                 ret = APP2EXT_ERROR_CREATE_FS;
1004                 goto ERR;
1005         }
1006
1007         list = g_list_first(dir_list);
1008         while (list) {
1009                 dir_detail = (app2ext_dir_details *)list->data;
1010                 if (dir_detail && dir_detail->name
1011                         && dir_detail->type == APP2EXT_DIR_RO) {
1012                         memset(temp_dir_path, '\0', FILENAME_MAX);
1013                         snprintf(temp_dir_path, FILENAME_MAX,
1014                                  "%s/%s", application_path,
1015                                 dir_detail->name);
1016                         _D("app2archive, temp_dir_path(%s)",
1017                                 temp_dir_path);
1018                         ret = _app2sd_move_to_archive(temp_dir_path,
1019                                 application_archive_path);
1020                         if (ret) {
1021                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1022                                         _E("unable to access (%s)",
1023                                                 temp_dir_path);
1024                                 } else {
1025                                         _E("unable to copy from (%s) to (%s)",
1026                                              temp_dir_path,
1027                                              application_archive_path);
1028                                 }
1029                                 goto ERR;
1030                         }
1031                 }
1032                 list = g_list_next(list);
1033         }
1034
1035         /* mount the loopback encrypted pseudo device on application installation path
1036          * as with Read Write permission
1037          */
1038         ret = _app2sd_mount_app_content(application_path, pkgid, device_node,
1039                 MOUNT_TYPE_RW, dir_list, APP2SD_MOVE_APP_TO_MMC, uid);
1040         if (ret) {
1041                 _E("mount failed");
1042                 goto ERR;
1043         }
1044
1045         list = g_list_first(dir_list);
1046         while (list) {
1047                 dir_detail = (app2ext_dir_details *)list->data;
1048                 if (dir_detail && dir_detail->name
1049                         && dir_detail->type == APP2EXT_DIR_RO) {
1050                         memset(temp_dir_path, '\0', FILENAME_MAX);
1051                         snprintf(temp_dir_path, FILENAME_MAX,
1052                                 "%s/%s", application_archive_path,
1053                                 dir_detail->name);
1054                         _D("archive2mmc, temp_dir_path(%s)",
1055                                 temp_dir_path);
1056                         ret = _app2sd_copy_dir(temp_dir_path,
1057                                 application_mmc_path);
1058                         if (ret) {
1059                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1060                                         _E("unable to access (%s)",
1061                                                 temp_dir_path);
1062                                 } else {
1063                                         strerror_r(errno,
1064                                                 err_buf, sizeof(err_buf));
1065                                         _E("unable to copy from (%s) to (%s)," \
1066                                                 " error is (%s)",
1067                                                 temp_dir_path,
1068                                                 application_mmc_path, err_buf);
1069                                 }
1070                                 goto ERR;
1071                         }
1072                         ret = _app2sd_delete_directory(temp_dir_path);
1073                         if (ret) {
1074                                 _E("unable to delete (%s)", temp_dir_path);
1075                                 goto ERR;
1076                         }
1077                 }
1078                 list = g_list_next(list);
1079         }
1080
1081         ret = _app2sd_delete_directory(application_archive_path);
1082         if (ret) {
1083                 _E("unable to delete (%s)", application_archive_path);
1084                 ret = APP2EXT_ERROR_DELETE_DIRECTORY;
1085                 goto ERR;
1086         }
1087
1088         return APP2EXT_SUCCESS;
1089
1090 ERR:
1091         if (device_node) {
1092                 free(device_node);
1093                 device_node = NULL;
1094         }
1095
1096         return ret;
1097 }
1098
1099 static int _app2sd_move_app_to_internal(const char *pkgid, GList *dir_list,
1100                 uid_t uid, char *mmc_path)
1101 {
1102         int ret = APP2EXT_SUCCESS;
1103         mode_t mode = DIR_PERMS;
1104         char temp_dir_path[FILENAME_MAX] = { 0, };
1105         char application_mmc_path[FILENAME_MAX] = { 0, };
1106         char application_archive_path[FILENAME_MAX] = { 0, };
1107         char application_path[FILENAME_MAX] = { 0, };
1108         char loopback_device[FILENAME_MAX] = { 0, };
1109         char *device_node = NULL;
1110         FILE *fp = NULL;
1111         GList *list = NULL;
1112         app2ext_dir_details *dir_detail = NULL;
1113         int reqd_size = 0;
1114         int free_internal_mem = 0;
1115         struct statvfs buf = {0,};
1116         unsigned long long temp = 0;
1117         char err_buf[1024] = {0,};
1118         char *encoded_id = NULL;
1119
1120         encoded_id = _app2sd_get_encoded_name(pkgid, uid);
1121         if (encoded_id == NULL)
1122                 return APP2EXT_ERROR_MEMORY_ALLOC_FAILED;
1123
1124         snprintf(loopback_device, FILENAME_MAX - 1, "%s/%s/%s",
1125                         mmc_path, EXTIMG_DIR, encoded_id);
1126         free(encoded_id);
1127         if (_is_global(uid)) {
1128                 snprintf(application_path, FILENAME_MAX - 1, "%s/%s",
1129                         tzplatform_getenv(TZ_SYS_RW_APP), pkgid);
1130         } else {
1131                 tzplatform_set_user(uid);
1132                 snprintf(application_path, FILENAME_MAX - 1, "%s/%s",
1133                         tzplatform_getenv(TZ_USER_APP), pkgid);
1134                 tzplatform_reset_user();
1135         }
1136
1137         /* check whether application is in external memory or not */
1138         fp = fopen(loopback_device, "r+");
1139         if (fp == NULL) {
1140                 _E("application (%s) is not installed on SD Card",
1141                      pkgid);
1142                 return APP2EXT_ERROR_FILE_ABSENT;
1143         } else {
1144                 fclose(fp);
1145                 fp = NULL;
1146         }
1147
1148         memset((void *)&buf, '\0', sizeof(struct statvfs));
1149         ret = statvfs(INTERNAL_STORAGE_PATH, &buf);
1150         if (0 == ret) {
1151                 temp = (buf.f_bsize * buf.f_bavail) / (1024 * 1024);
1152                 free_internal_mem = (int)temp;
1153         } else {
1154                 _E("unable to get internal storage size");
1155                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
1156         }
1157
1158         fp = fopen(loopback_device, "r+");
1159         if (fp == NULL) {
1160                 _E("app entry is not present in SD card");
1161                 return APP2EXT_ERROR_INVALID_PACKAGE;
1162         }
1163         fclose(fp);
1164
1165         /* get installed app size*/
1166         temp = _app2sd_calculate_file_size(loopback_device);
1167         reqd_size = (int)((temp) / (1024 * 1024));
1168         _D("reqd size is (%d)", reqd_size);
1169
1170         if (reqd_size == 0) {
1171                 _E("app entry is not present in SD Card");
1172                 return APP2EXT_ERROR_LOOPBACK_DEVICE_UNAVAILABLE;
1173         }
1174
1175         _D("reqd size: (%d)MB, free internal mem: (%d)MB",
1176                 reqd_size, free_internal_mem);
1177
1178         /* if avaialalbe free memory in internal storage is
1179          * less than required size, return error
1180          */
1181         if (reqd_size > free_internal_mem) {
1182                 _E("innsufficient memory in internal storage" \
1183                         " for application installation (%d)", ret);
1184                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
1185         }
1186
1187 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1188         device_node =
1189                 _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
1190 #else
1191         device_node = _app2sd_find_associated_device_node(loopback_device);
1192 #endif
1193         if (NULL == device_node) {
1194                 /* do loopback setup */
1195 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1196                 ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device,
1197                         false, uid, &device_node);
1198                 if (ret) {
1199                         _E("dmcrypt open device error(%d)", ret);
1200                         return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
1201                 }
1202 #else
1203                 device_node = _app2sd_do_loopback_encryption_setup(pkgid,
1204                         loopback_device, uid);
1205                 if (device_node == NULL) {
1206                         _E("loopback encryption setup failed");
1207                         return APP2EXT_ERROR_DO_LOSETUP;
1208                 }
1209 #endif
1210                 /* do mounting */
1211                 ret = _app2sd_mount_app_content(application_path,
1212                         pkgid, device_node, MOUNT_TYPE_RW,
1213                         dir_list, APP2SD_MOVE_APP_TO_PHONE, uid);
1214                 if (ret) {
1215                         _E("mount failed");
1216                         ret = APP2EXT_ERROR_MOUNT_PATH;
1217                         goto ERR;
1218                 }
1219         } else {
1220                 /* do re-mounting */
1221                 ret = _app2sd_mount_app_content(application_path,
1222                         pkgid, device_node, MOUNT_TYPE_RW_REMOUNT,
1223                         dir_list, APP2SD_MOVE_APP_TO_PHONE, uid);
1224                 if (ret) {
1225                         _E("re-mount failed");
1226                         ret = APP2EXT_ERROR_MOUNT_PATH;
1227                         goto ERR;
1228                 }
1229         }
1230
1231         snprintf(application_mmc_path, FILENAME_MAX - 1, "%s/.mmc",
1232                 application_path);
1233         snprintf(application_archive_path, FILENAME_MAX - 1, "%s/.archive",
1234                 application_path);
1235
1236         ret = mkdir(application_archive_path, mode);
1237         if (ret) {
1238                 if (errno != EEXIST) {
1239                         _E("unable to create directory for archiving," \
1240                                 " error(%d)", errno);
1241                         ret = APP2EXT_ERROR_CREATE_DIRECTORY;
1242                         goto ERR;
1243                 }
1244         }
1245
1246         list = g_list_first(dir_list);
1247         while (list) {
1248                 dir_detail = (app2ext_dir_details *)list->data;
1249                 if (dir_detail && dir_detail->name
1250                         && dir_detail->type == APP2EXT_DIR_RO) {
1251                         /* archiving code */
1252                         memset(temp_dir_path, '\0', FILENAME_MAX);
1253                         snprintf(temp_dir_path, FILENAME_MAX,
1254                                  "%s/%s", application_mmc_path,
1255                                  dir_detail->name);
1256                         _D("mmc2archive, temp_dir_path(%s)", temp_dir_path);
1257                         ret = _app2sd_copy_dir(temp_dir_path,
1258                                      application_archive_path);
1259                         if (ret) {
1260                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1261                                         _E("unable to access (%s)",
1262                                                 temp_dir_path);
1263                                 } else {
1264                                         strerror_r(errno,
1265                                                 err_buf, sizeof(err_buf));
1266                                         _E("unable to copy from (%s) to (%s),"
1267                                                 " error is (%s)",
1268                                                 temp_dir_path,
1269                                                 application_archive_path, err_buf);
1270                                 }
1271                                 goto ERR;
1272                         }
1273
1274                         /* delete the symbolic link files [bin, lib, res]*/
1275                         memset(temp_dir_path, '\0', FILENAME_MAX);
1276                         snprintf(temp_dir_path, FILENAME_MAX,
1277                                  "%s/%s", application_path,
1278                                  dir_detail->name);
1279                         _D("unlink, temp_dir_path(%s)", temp_dir_path);
1280                         ret = unlink(temp_dir_path);
1281                         if (ret) {
1282                                 if (errno == ENOENT) {
1283                                         _W("directory (%s) does not exist",
1284                                                 temp_dir_path);
1285                                 } else {
1286                                         _E("unable to remove the symbolic link file (%s)," \
1287                                                 " it is already unlinked",
1288                                                 temp_dir_path);
1289                                         goto ERR;
1290                                 }
1291                         }
1292
1293                         /* Copy content to destination */
1294                         memset(temp_dir_path, '\0', FILENAME_MAX);
1295                         snprintf(temp_dir_path, FILENAME_MAX,
1296                                 "%s/%s", application_archive_path,
1297                                 dir_detail->name);
1298                         _D("archive2app, temp_dir_path(%s)", temp_dir_path);
1299                         ret = _app2sd_copy_dir(temp_dir_path, application_path);
1300                         if (ret) {
1301                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1302                                         _E("unable to access (%s)",
1303                                                 temp_dir_path);
1304                                 } else {
1305                                         strerror_r(errno,
1306                                                 err_buf, sizeof(err_buf));
1307                                         _E("unable to copy from (%s) to (%s) " \
1308                                                 ", error is (%s)",
1309                                                 temp_dir_path,
1310                                                 application_path, err_buf);
1311                                 }
1312                                 goto ERR;
1313                         }
1314                 }
1315                 list = g_list_next(list);
1316         }
1317
1318         _D("copying file completed");
1319         ret = _app2sd_unmount_app_content(application_path);
1320         if (ret)
1321                 _E("unable to unmount SD directory for app (%s)",
1322                      pkgid);
1323
1324 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1325         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1326         if (ret)
1327                 _E("close dmcrypt device error(%d)", ret);
1328 #else
1329         ret = _app2sd_remove_loopback_encryption_setup(loopback_device);
1330         if (ret)
1331                 _E("unable to detach loopback setup for (%s)",
1332                      pkgid);
1333 #endif
1334
1335         ret = _app2sd_delete_loopback_device(loopback_device);
1336         if (ret)
1337                 _E("unable to delete the loopback device for (%s)",
1338                      pkgid);
1339
1340         ret = _app2sd_delete_directory(application_mmc_path);
1341         if (ret)
1342                 _E("unable to delete (%s)", application_mmc_path);
1343
1344         ret = _app2sd_delete_directory(application_archive_path);
1345         if (ret)
1346                 _E("unable to delete (%s)", application_archive_path);
1347
1348         /* remove passwrd from DB */
1349         ret = _app2sd_initialize_db();
1350         if (ret)
1351                 _E("app2sd db initialize failed");
1352
1353         ret = _app2sd_remove_info_from_db(pkgid, uid);
1354         if (ret)
1355                 _E("cannot remove info from db");
1356
1357         return APP2EXT_SUCCESS;
1358
1359 ERR:
1360         if (device_node) {
1361                 free(device_node);
1362                 device_node = NULL;
1363         }
1364
1365         return ret;
1366 }
1367
1368 int _app2sd_usr_move_app(const char *pkgid, app2ext_move_type move_type,
1369                 GList *dir_list, uid_t uid, char *mmc_path)
1370 {
1371         int ret = APP2EXT_SUCCESS;
1372
1373         switch (move_type) {
1374         case APP2EXT_MOVE_TO_EXT:
1375                 ret = _app2sd_move_app_to_external(pkgid, dir_list,
1376                         uid, mmc_path);
1377                 if (ret) {
1378                         _E("move app to external memory failed(%d)", ret);
1379                         return ret;
1380                 }
1381                 break;
1382         case APP2EXT_MOVE_TO_PHONE:
1383                 ret = _app2sd_move_app_to_internal(pkgid, dir_list,
1384                         uid, mmc_path);
1385                 if (ret) {
1386                         _E("move app to internal memory failed(%d)", ret);
1387                         return ret;
1388                 }
1389                 break;
1390         default:
1391                 _E("invalid argument");
1392                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
1393         }
1394
1395         return ret;
1396 }
1397
1398 int _app2sd_copy_ro_content(const char *src, const char *dest, GList *dir_list)
1399 {
1400         char path[FILENAME_MAX] = { 0, };
1401         int ret = APP2EXT_SUCCESS;
1402         GList *list = NULL;
1403         app2ext_dir_details *dir_detail = NULL;
1404
1405         list = g_list_first(dir_list);
1406         while (list) {
1407                 dir_detail = (app2ext_dir_details *)list->data;
1408                 if (dir_detail && dir_detail->name
1409                         && dir_detail->type == APP2EXT_DIR_RO) {
1410                         memset((void *)&path, '\0', FILENAME_MAX);
1411                         snprintf(path, FILENAME_MAX - 1, "%s/%s", src,
1412                                  dir_detail->name);
1413                         ret = _app2sd_copy_dir(path, dest);
1414                         if (ret) {
1415                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1416                                         _E("unable to access (%s)", path);
1417                                 } else {
1418                                         _E("unable to copy from (%s) " \
1419                                                 "to (%s), errno is (%d)",
1420                                                 path, dest, errno);
1421                                         return APP2EXT_ERROR_MOVE;
1422                                 }
1423                         }
1424                 }
1425                 list = g_list_next(list);
1426         }
1427
1428         return APP2EXT_SUCCESS;
1429 }
1430
1431 int _app2sd_duplicate_device(const char *pkgid,
1432                 const char *loopback_device,
1433                 const char *temp_pkgid,
1434                 const char *temp_application_path,
1435                 const char *temp_loopback_device,
1436                 GList *dir_list, char *dev_node, int size,
1437                 uid_t uid)
1438 {
1439         int ret = 0;
1440         int err_res = 0;
1441 #if !defined(TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION)
1442         char *devi = NULL;
1443         char *result = NULL;
1444         char *passwd = NULL;
1445 #endif
1446
1447         /* create a new loopback device */
1448         ret = _app2sd_create_loopback_device(temp_pkgid,
1449                 temp_loopback_device, (size + PKG_BUF_SIZE));
1450         if (ret) {
1451                 _E("package already present");
1452                 return ret;
1453         }
1454
1455         /* perform loopback encryption setup */
1456 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1457         dev_node = _app2sd_dmcrypt_duplicate_encryption_setup(pkgid,
1458                 temp_loopback_device, uid);
1459         if (!dev_node) {
1460                 _E("dmcrypt duplicate encryption setup failed");
1461                 _app2sd_delete_loopback_device(temp_loopback_device);
1462                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
1463         }
1464 #else
1465         /* get password for loopback encryption */
1466         ret = _app2sd_initialize_db();
1467         if (ret) {
1468                 _E("app2sd db initialize failed");
1469                 return APP2EXT_ERROR_DB_INITIALIZE;
1470         }
1471
1472         if ((passwd = _app2sd_get_password_from_db(pkgid, uid)) == NULL) {
1473                 passwd = (char *)_app2sd_generate_password(pkgid);
1474                 if (NULL == passwd) {
1475                         _E("unable to generate password");
1476                         return APP2EXT_ERROR_PASSWD_GENERATION;
1477                 } else {
1478                         if ((ret = _app2sd_set_info_in_db(pkgid,
1479                                 passwd, loopback_device, uid)) < 0) {
1480                                 _E("unable to save info");
1481                                 free(passwd);
1482                                 passwd = NULL;
1483                                 return APP2EXT_ERROR_SQLITE_REGISTRY;
1484                         }
1485                 }
1486         }
1487
1488         dev_node = _app2sd_do_loopback_duplicate_encryption_setup(pkgid,
1489                 temp_pkgid, temp_loopback_device, passwd, uid);
1490         if (!dev_node) {
1491                 _E("losetup failed, device node is (%s)", dev_node);
1492                 _app2sd_delete_loopback_device(temp_loopback_device);
1493                 free(passwd);
1494                 passwd = NULL;
1495                 return APP2EXT_ERROR_DO_LOSETUP;
1496         }
1497         free(passwd);
1498         passwd = NULL;
1499         _D("duplicate setup SUCCESS");
1500
1501         /* check whether loopback device is associated with
1502          * device node or not
1503          */
1504         devi = _app2sd_find_associated_device_node(temp_loopback_device);
1505         if (devi == NULL) {
1506                 _E("finding associated device node failed");
1507                 err_res = APP2EXT_ERROR_DO_LOSETUP;
1508                 goto FINISH_OFF;
1509         }
1510         _D("losetup SUCCESS");
1511 #endif
1512
1513         /* format the loopback file system */
1514         ret = _app2sd_create_file_system(dev_node);
1515         if (ret) {
1516                 _E("creating fs failed");
1517                 err_res = APP2EXT_ERROR_CREATE_FS;
1518                 goto FINISH_OFF;
1519         }
1520         _D("create filesystem SUCCESS");
1521
1522         /* do mounting for new dev*/
1523         ret = _app2sd_mount_app_content(temp_application_path, pkgid,
1524                 dev_node, MOUNT_TYPE_RW, dir_list,
1525                 APP2SD_PRE_UPGRADE, uid);
1526         if (ret) {
1527                 _E("remount failed");
1528                 err_res = APP2EXT_ERROR_MOUNT_PATH;
1529                 goto FINISH_OFF;
1530         }
1531
1532 #if !defined(TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION)
1533         if (devi) {
1534                 free(devi);
1535                 devi = NULL;
1536         }
1537 #endif
1538
1539         return APP2EXT_SUCCESS;
1540
1541 FINISH_OFF:
1542         if (dev_node) {
1543 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1544                 ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1545                 if (ret)
1546                         _E("close dmcrypt device error(%d)", ret);
1547 #else
1548                 result = _app2sd_detach_loop_device(dev_node);
1549                 if (result) {
1550                         free(result);
1551                         result = NULL;
1552                 }
1553 #endif
1554                 _app2sd_delete_loopback_device(temp_loopback_device);
1555                 free(dev_node);
1556                 dev_node = NULL;
1557         }
1558
1559         return err_res;
1560 }
1561
1562 int _app2sd_update_loopback_device_size(const char *pkgid,
1563                 const char *loopback_device,
1564                 const char *application_path,
1565                 const char *temp_pkgid,
1566                 const char *temp_loopback_device,
1567                 const char *temp_application_path,
1568                 int size, GList *dir_list,
1569                 uid_t uid)
1570 {
1571         int ret = 0;
1572         char *device_node = NULL;
1573         char *old_device_node = NULL;
1574         int err_res = 0;
1575         char application_mmc_path[FILENAME_MAX] = { 0, };
1576         char temp_application_mmc_path[FILENAME_MAX] = { 0, };
1577
1578         ret = _app2sd_duplicate_device(pkgid, loopback_device,
1579                 temp_pkgid, temp_application_path, temp_loopback_device,
1580                 dir_list, device_node, size, uid);
1581         if (ret) {
1582                 _E("creating duplicate device failed");
1583                 return ret;
1584         }
1585
1586         /* get the associated device node for SD card applicatione */
1587 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1588         old_device_node =
1589                 _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
1590 #else
1591         old_device_node = _app2sd_find_associated_device_node(loopback_device);
1592 #endif
1593         if (NULL == old_device_node) {
1594                 /* do loopback setup */
1595 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1596                 ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device,
1597                         false, uid, &old_device_node);
1598                 if (ret) {
1599                         _E("dmcrypt open device error");
1600                         err_res = APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
1601                         goto FINISH_OFF;
1602                 }
1603 #else
1604                 old_device_node = _app2sd_do_loopback_encryption_setup(pkgid,
1605                         loopback_device, uid);
1606                 if (old_device_node == NULL) {
1607                         _E("loopback encryption setup failed");
1608                         err_res = APP2EXT_ERROR_DO_LOSETUP;
1609                         goto FINISH_OFF;
1610                 }
1611 #endif
1612                 /* do mounting */
1613                 ret = _app2sd_mount_app_content(application_path, pkgid,
1614                         old_device_node, MOUNT_TYPE_RW, dir_list,
1615                         APP2SD_PRE_UPGRADE, uid);
1616                 if (ret) {
1617                         _E("remount failed");
1618                         err_res = APP2EXT_ERROR_MOUNT_PATH;
1619                 }
1620         } else {
1621                 /* do re-mounting */
1622                 ret = _app2sd_mount_app_content(application_path, pkgid,
1623                         old_device_node, MOUNT_TYPE_RW_REMOUNT, dir_list,
1624                         APP2SD_PRE_UPGRADE, uid);
1625                 if (ret) {
1626                         _E("remount failed");
1627                         err_res = APP2EXT_ERROR_MOUNT_PATH;
1628                 }
1629         }
1630
1631         snprintf(application_mmc_path, FILENAME_MAX - 1,
1632                  "%s/.mmc", application_path);
1633         snprintf(temp_application_mmc_path, FILENAME_MAX - 1,
1634                 "%s/.mmc", temp_application_path);
1635
1636         ret = _app2sd_copy_ro_content(application_mmc_path,
1637                 temp_application_mmc_path, dir_list);
1638         if (ret) {
1639                 _E("copy ro content failed");
1640                 err_res = ret;
1641         }
1642
1643         ret = _app2sd_unmount_app_content(application_path);
1644         if (ret) {
1645                 _E("unable to unmount the SD application");
1646                 err_res = APP2EXT_ERROR_UNMOUNT;
1647         }
1648
1649         ret = _app2sd_unmount_app_content(temp_application_path);
1650         if (ret) {
1651                 _E("unable to unmount the SD application");
1652                 err_res = APP2EXT_ERROR_UNMOUNT;
1653                 goto FINISH_OFF;
1654         }
1655
1656 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1657         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1658         if (ret) {
1659                 _E("close dmcrypt device error(%d)", ret);
1660                 err_res = APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
1661                 goto FINISH_OFF;
1662         }
1663
1664         ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1665         if (ret) {
1666                 _E("close dmcrypt device error(%d)", ret);
1667                 err_res = APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
1668                 goto FINISH_OFF;
1669         }
1670 #else
1671         ret = _app2sd_remove_loopback_encryption_setup(loopback_device);
1672         if (ret) {
1673                 _E("unable to remove loopback setup");
1674                 err_res = APP2EXT_ERROR_DELETE_LOOPBACK_DEVICE;
1675         }
1676
1677         ret = _app2sd_remove_loopback_encryption_setup(temp_loopback_device);
1678         if (ret) {
1679                 _E("unable to remove loopback setup");
1680                 err_res = APP2EXT_ERROR_DELETE_LOOPBACK_DEVICE;
1681                 goto FINISH_OFF;
1682         }
1683 #endif
1684
1685         ret = _app2sd_delete_directory(loopback_device);
1686         if (ret) {
1687                 _E("unable to delete (%s)", loopback_device);
1688                 err_res = APP2EXT_ERROR_DELETE_DIRECTORY;
1689                 goto FINISH_OFF;
1690         }
1691
1692         ret = _app2sd_rename_dir(temp_loopback_device, loopback_device);
1693         if (ret) {
1694                 _E("unable to rename (%s)", temp_loopback_device);
1695                 err_res = APP2EXT_ERROR_MOVE;
1696                 goto FINISH_OFF;
1697         }
1698
1699         ret = _app2sd_delete_directory(temp_application_path);
1700         if (ret) {
1701                 _E("unable to delete (%s)", temp_application_path);
1702                 err_res = APP2EXT_ERROR_DELETE_DIRECTORY;
1703                 goto FINISH_OFF;
1704         }
1705
1706         return APP2EXT_SUCCESS;
1707
1708 FINISH_OFF:
1709         if (old_device_node) {
1710                 free(old_device_node);
1711                 old_device_node = NULL;
1712         }
1713
1714 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1715         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1716         if (ret)
1717                 _E("close dmcrypt device error(%d)", ret);
1718
1719         ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1720
1721         if (ret)
1722                 _E("close dmcrypt device error(%d)", ret);
1723 #else
1724         ret = _app2sd_remove_loopback_encryption_setup(loopback_device);
1725         if (ret)
1726                 _E("unable to remove loopback setup");
1727
1728         ret = _app2sd_remove_loopback_encryption_setup(temp_loopback_device);
1729         if (ret)
1730                 _E("unable to remove loopback setup");
1731 #endif
1732
1733         _app2sd_delete_loopback_device(temp_loopback_device);
1734
1735         ret = _app2sd_delete_directory(temp_application_path);
1736         if (ret)
1737                 _E("unable to delete (%s)", temp_application_path);
1738
1739         return err_res;
1740 }
1741
1742 int _app2sd_force_clean(const char *pkgid, const char *application_path,
1743                 const char *loopback_device, uid_t uid)
1744 {
1745         int ret = APP2EXT_SUCCESS;
1746
1747         /* unmount the loopback encrypted pseudo device from the application installation path */
1748         ret = _app2sd_unmount_app_content(application_path);
1749         if (ret)
1750                 _E("unable to unmount the app content (%d)", ret);
1751
1752         /* detach the loopback encryption setup for the application */
1753 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1754         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1755         if (ret)
1756                 _E("close dmcrypt device error (%d)", ret);
1757 #else
1758         ret = _app2sd_remove_all_loopback_encryption_setups(loopback_device);
1759         if (ret)
1760                 _E("unable to detach the loopback encryption setup for the application");
1761 #endif
1762
1763         /* delete the loopback device from the SD card */
1764         ret = _app2sd_delete_loopback_device(loopback_device);
1765         if (ret)
1766                 _E("unable to detach the loopback encryption setup for the application");
1767
1768         /* delete symlink */
1769         _app2sd_delete_symlink(application_path);
1770
1771         /* remove passwrd from DB */
1772         ret = _app2sd_initialize_db();
1773         if (ret)
1774                 _E("app2sd db initialize failed");
1775
1776         ret = _app2sd_remove_info_from_db(pkgid, uid);
1777         if (ret)
1778                 _E("cannot remove info from db");
1779
1780
1781         return ret;
1782 }