494a16263a4c195731a459521d5a6a5ee11bd113
[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 #define _GNU_SOURCE
25 #include <dirent.h>
26 #include <time.h>
27 #include <pwd.h>
28
29 #include "app2sd_internals.h"
30
31 #define DMCRYPT_ITER_TIME       50
32 #define DMCRYPT_KEY_LEN         128
33
34 static int _app2sd_make_directory(const char *path, uid_t uid)
35 {
36         int ret;
37         int fd;
38         mode_t mode = DIR_PERMS;
39         struct passwd pwd;
40         struct passwd *pwd_result;
41         char buf[1024];
42
43         ret = _app2sd_delete_directory(path);
44         if (ret) {
45                 _E("unable to delete (%s), errno(%d)", path, errno);
46                 return APP2EXT_ERROR_DELETE_DIRECTORY;
47         }
48
49         ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &pwd_result);
50         if (ret != 0 || pwd_result == NULL) {
51                 _E("get uid failed(%d)", ret);
52                 return APP2EXT_ERROR_ACCESS_FILE;
53         }
54         _D("uid(%d), gid(%d)", uid, pwd.pw_gid);
55
56         /* create directory */
57         ret = mkdir(path, mode);
58         if (ret) {
59                 if (errno != EEXIST) {
60                         _E("create directory failed, error is (%d)", errno);
61                         return APP2EXT_ERROR_CREATE_DIRECTORY;
62                 }
63         }
64
65         fd = open(path, O_RDONLY|O_DIRECTORY);
66         if (fd < 0) {
67                 _E("can't open path(%s)", path);
68                 return APP2EXT_ERROR_OPEN_DIR;
69         }
70
71         ret = fchmod(fd, 0755);
72         if (ret < 0) {
73                 _E("change file permission error");
74                 close(fd);
75                 return APP2EXT_ERROR_ACCESS_FILE;
76         }
77
78         ret = fchown(fd, uid, pwd.pw_gid);
79         if (ret < 0) {
80                 _E("change file owner error");
81                 close(fd);
82                 return APP2EXT_ERROR_ACCESS_FILE;
83         }
84
85         close(fd);
86
87         return APP2EXT_SUCCESS;
88 }
89
90 int _app2sd_dmcrypt_setup_device(const char *pkgid,
91                 const char *loopback_device, bool is_dup, uid_t uid)
92 {
93         int ret;
94         char *passwd;
95         char dmcrypt_setup_cmd[BUF_SIZE];
96         char err_buf[BUF_SIZE];
97         const char *err_str;
98
99         if (pkgid == NULL || loopback_device == NULL) {
100                 _E("invalid argument");
101                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
102         }
103
104         /* get password for dmcrypt encryption */
105         ret = _app2sd_initialize_db();
106         if (ret) {
107                 _E("app2sd db initialize failed");
108                 return APP2EXT_ERROR_DB_INITIALIZE;
109         }
110
111         passwd = _app2sd_get_password_from_db(pkgid, uid);
112         if (passwd == NULL) {
113                 if (is_dup) {
114                         _E("no password found for (%s)", pkgid);
115                         return APP2EXT_ERROR_SQLITE_REGISTRY;
116                 }
117                 passwd = _app2sd_generate_password();
118                 if (passwd == NULL) {
119                         _E("unable to generate password");
120                         return APP2EXT_ERROR_PASSWD_GENERATION;
121                 }
122
123                 ret = _app2sd_set_info_in_db(pkgid, passwd, loopback_device,
124                                 uid);
125                 if (ret < 0) {
126                         _E("unable to save password");
127                         free(passwd);
128                         return APP2EXT_ERROR_SQLITE_REGISTRY;
129                 }
130         }
131
132         snprintf(dmcrypt_setup_cmd, sizeof(dmcrypt_setup_cmd),
133                         "/bin/echo '%s' | /sbin/cryptsetup -q -i %d "
134                         "-c aes-cbc-lmk -s %d --align-payload=8 luksFormat %s",
135                         passwd, DMCRYPT_ITER_TIME, DMCRYPT_KEY_LEN,
136                         loopback_device);
137         memset(passwd, 0, strlen(passwd));
138         free(passwd);
139         ret = system(dmcrypt_setup_cmd);
140         memset(dmcrypt_setup_cmd, 0, BUF_SIZE);
141         if (ret) {
142                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
143                 _E("Error setting up dmcrypt on app2sd file, error:%s, ret:%d",
144                                 err_str, ret);
145                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
146         }
147
148         return ret;
149 }
150
151 int _app2sd_dmcrypt_open_device(const char *pkgid, const char *loopback_device,
152                 bool is_dup, uid_t uid, char **dev_node)
153 {
154         int ret;
155         int size;
156         char *passwd;
157         char dmcrypt_open_cmd[BUF_SIZE];
158         char dev_name[BUF_SIZE];
159         char buf[BUF_SIZE];
160         const char *err_str;
161
162         if (pkgid == NULL || loopback_device == NULL) {
163                 _E("invalid argument");
164                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
165         }
166
167         if (is_dup)
168                 snprintf(dev_name, sizeof(dev_name), "%s.new_%d", pkgid, uid);
169         else
170                 snprintf(dev_name, sizeof(dev_name), "%s_%d", pkgid, uid);
171
172         /* get password for dmcrypt encryption */
173         ret = _app2sd_initialize_db();
174         if (ret) {
175                 _E("app2sd db initialize failed");
176                 return APP2EXT_ERROR_DB_INITIALIZE;
177         }
178
179         passwd = _app2sd_get_password_from_db(pkgid, uid);
180         if (passwd == NULL) {
181                 _E("no password found for [%s]", pkgid);
182                 return APP2EXT_ERROR_SQLITE_REGISTRY;
183         }
184
185         if (_app2sd_check_is_luks_device(loopback_device) == 0) {
186                 _W("legacy image format!");
187                 ret = snprintf(dmcrypt_open_cmd, sizeof(dmcrypt_open_cmd),
188                                 "/bin/echo '%s' | /sbin/cryptsetup "
189                                 "-M plain -c aes-cbc-plain -h plain open %s %s",
190                                 passwd, loopback_device, dev_name);
191                 if (ret < 0 || ret > sizeof(dmcrypt_open_cmd)) {
192                         free(passwd);
193                         _E("snprintf fail\n");
194                         return -1;
195                 }
196         } else {
197                 ret = snprintf(dmcrypt_open_cmd, sizeof(dmcrypt_open_cmd),
198                                 "/bin/echo '%s' | /sbin/cryptsetup -q luksOpen "
199                                 "%s %s",
200                                 passwd, loopback_device, dev_name);
201                 if (ret < 0 || ret > sizeof(dmcrypt_open_cmd)) {
202                         _E("snprintf fail\n");
203                         free(passwd);
204                         return -1;
205                 }
206         }
207         free(passwd);
208
209         ret = system(dmcrypt_open_cmd);
210         if (ret) {
211                 err_str = strerror_r(errno, buf, sizeof(buf));
212                 _E("error opening dmcrypt device, error: [%s]", err_str);
213                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
214         }
215
216         size = strlen("/dev/mapper/%s") + strlen(dev_name) + 1;
217         *dev_node = (char *)malloc(size);
218         if (*dev_node == NULL) {
219                 _E("memory alloc failed");
220                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
221         }
222         ret = snprintf(*dev_node, size, "/dev/mapper/%s", dev_name);
223         if (ret < 0 || ret > size) {
224                         _E("snprintf fail\n");
225                         free(*dev_node);
226                         *dev_node = NULL;
227                         return -1;
228         }
229         return 0;
230 }
231
232 int _app2sd_dmcrypt_close_device(const char *pkgid, uid_t uid)
233 {
234         int ret;
235         char dev_node[BUF_SIZE];
236         char dmcrypt_close_cmd[BUF_SIZE];
237         char err_buf[BUF_SIZE];
238         const char *err_str;
239         char *t_dev_node;
240
241         if (pkgid == NULL) {
242                 _E("invalid argument");
243                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
244         }
245
246         t_dev_node = _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
247         if (!t_dev_node) {
248                 _W("no associated device node(%s_%d) found", pkgid, uid);
249                 return APP2EXT_ERROR_DMCRYPT_DEVICE_UNAVAILABLE;
250         }
251
252         free(t_dev_node);
253
254         ret = snprintf(dev_node, sizeof(dev_node), "/dev/mapper/%s_%d", pkgid, uid);
255         if (ret < 0 || ret > sizeof(dev_node)) {
256                 _E("snprintf fail");
257                 return APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
258         }
259         ret = snprintf(dmcrypt_close_cmd, sizeof(dmcrypt_close_cmd),
260                         "/sbin/cryptsetup -q luksClose %s", dev_node);
261         if (ret < 0 || ret > sizeof(dmcrypt_close_cmd)) {
262                 _E("snprintf fail");
263                 return APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
264         }
265         ret = system(dmcrypt_close_cmd);
266         if (ret) {
267                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
268                 _E("error closing dmcrypt on app2sd file: %s", err_str);
269                 return APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
270         }
271
272         return ret;
273 }
274
275 char *_app2sd_find_associated_dmcrypt_device_node(const char *pkgid, uid_t uid)
276 {
277         char *dev_node;
278         char buf[BUF_SIZE];
279
280         snprintf(buf, sizeof(buf), "/dev/mapper/%s_%d", pkgid, uid);
281         if (access(buf, F_OK) == 0) {
282                 dev_node = strdup(buf);
283                 if (dev_node == NULL) {
284                         _E("memory alloc failed");
285                         return NULL;
286                 }
287                 _D("device_node: (%s)", dev_node);
288                 return dev_node;
289         }
290         _D("can not access dev_node(%s), errno(%d)", buf, errno);
291
292         return NULL;
293 }
294
295 char *_app2sd_dmcrypt_duplicate_encryption_setup(const char *pkgid,
296                 const char *temp_loopback_device, uid_t uid)
297 {
298         int ret;
299         char *device_node;
300
301         if (pkgid == NULL || temp_loopback_device == NULL) {
302                 _E("invalid argument");
303                 return NULL;
304         }
305
306         ret = _app2sd_dmcrypt_setup_device(pkgid, temp_loopback_device, true,
307                         uid);
308         if (ret) {
309                 _E("dmcrypt setup device error(%d)", ret);
310                 return NULL;
311         }
312
313         ret = _app2sd_dmcrypt_open_device(pkgid, temp_loopback_device, true,
314                         uid, &device_node);
315         if (ret) {
316                 _E("dmcrypt open device error");
317                 return NULL;
318         }
319
320         return device_node;
321 }
322
323 int _app2sd_create_loopback_device(const char *pkgid,
324                 const char *loopback_device, int size)
325 {
326         int ret;
327         char command[FILENAME_MAX];
328         char buff[BUF_SIZE];
329         FILE *fp;
330         const char *argv[] = { "/bin/dd", "if=/dev/zero", command,
331                 "bs=1M", buff, NULL };
332
333         if (pkgid == NULL || size <= 0) {
334                 _E("invalid argument");
335                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
336         }
337
338         fp = fopen(loopback_device, "r+");
339         if (fp != NULL) {
340                 _W("encrypted file already exists (%s)", loopback_device);
341                 fclose(fp);
342                 return APP2EXT_ERROR_PKG_EXISTS;
343         }
344
345         snprintf(command, sizeof(command), "of=%s", loopback_device);
346         snprintf(buff, sizeof(buff), "count=%d", size);
347
348         ret = _xsystem(argv);
349         if (ret)
350                 _E("command (%s) failed, ret(%d), errno(%d)",
351                                 command, ret, errno);
352
353         return ret;
354 }
355
356 int _app2sd_delete_loopback_device(const char *loopback_device)
357 {
358         int ret;
359
360         ret = unlink(loopback_device);
361         if (ret) {
362                 if (errno == ENOENT) {
363                         _W("unable to access file (%s)", loopback_device);
364                 } else {
365                         _E("unable to delete (%s)", loopback_device);
366                         return APP2EXT_ERROR_DELETE_LOOPBACK_DEVICE;
367                 }
368         }
369
370         return APP2EXT_SUCCESS;
371 }
372
373 int _app2sd_create_file_system(const char *device_path)
374 {
375         int ret;
376         FILE *fp;
377         char err_buf[1024];
378         const char *err_str;
379         const char *argv[] = { "/sbin/mkfs.ext4", device_path, NULL };
380
381         if (device_path == NULL) {
382                 _E("invalid param");
383                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
384         }
385
386         /* Format the filesystem [create a filesystem]*/
387         fp = fopen(device_path, "r+");
388         if (fp == NULL) {
389                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
390                 _E("unable to access (%s) error is (%d, %s)",
391                                 device_path, errno, err_str);
392                 return APP2EXT_ERROR_ACCESS_FILE;
393         }
394         fclose(fp);
395
396         ret = _xsystem(argv);
397         if (ret) {
398                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
399                 _E("creating file system failed, error is (%s)", err_str);
400                 return APP2EXT_ERROR_CREATE_FS;
401         }
402         return ret;
403 }
404
405 static int _app2sd_create_dir_with_link(const char *application_path,
406                 const char *pkgid, const char *dir_name, uid_t uid)
407 {
408         int ret;
409         char app_dir_mmc_path[FILENAME_MAX];
410         char app_dir_path[FILENAME_MAX];
411
412         snprintf(app_dir_mmc_path, sizeof(app_dir_mmc_path), "%s/.mmc/%s",
413                         application_path, dir_name);
414         snprintf(app_dir_path, sizeof(app_dir_path), "%s/%s",
415                         application_path, dir_name);
416
417         ret = _app2sd_make_directory(app_dir_mmc_path, uid);
418         if (ret) {
419                 _E("create directory failed");
420                 return APP2EXT_ERROR_CREATE_DIRECTORY;
421         }
422
423         ret = symlink(app_dir_mmc_path, app_dir_path);
424         if (ret < 0) {
425                 if (errno == EEXIST) {
426                         _D("file with symlink name present (%s)", app_dir_path);
427                 } else {
428                         _E("symbolic link creation failed, error: %d", errno);
429                         return APP2EXT_ERROR_CREATE_SYMLINK;
430                 }
431         }
432
433         return APP2EXT_SUCCESS;
434 }
435
436 static int _app2sd_create_directory_entry(const char *application_path,
437                 const char *pkgid, GList *dir_list, uid_t uid)
438 {
439         int ret;
440         GList *list;
441         app2ext_dir_details *dir_detail;
442
443         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
444                 dir_detail = (app2ext_dir_details *)list->data;
445                 if (dir_detail == NULL || dir_detail->name == NULL ||
446                                 dir_detail->type != APP2EXT_DIR_RO)
447                         continue;
448                 ret = _app2sd_create_dir_with_link(application_path,
449                                 pkgid, dir_detail->name, uid);
450                 if (ret)
451                         return ret;
452         }
453         return APP2EXT_SUCCESS;
454 }
455
456 int _app2sd_mount_app_content(const char *application_path, const char *pkgid,
457                 const char *dev, int mount_type, GList *dir_list,
458                 app2sd_cmd cmd, uid_t uid)
459 {
460         int ret;
461         int fd;
462         char app_mmc_path[FILENAME_MAX];
463         char temp_path[FILENAME_MAX];
464         char err_buf[1024];
465         const char *err_str;
466         struct timespec time = {
467                 .tv_sec = 0,
468                 .tv_nsec = 1000 * 1000 * 200
469         };
470         char mountflags_str[BUF_SIZE];
471         const char *argv_mount[] = { "/bin/app2sd-mount-helper", dev,
472                 app_mmc_path, FS_TYPE, mountflags_str, NULL };
473
474         if (dev == NULL) {
475                 _E("input param is NULL (%s)", dev);
476                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
477         }
478
479         /* check directory existence */
480         fd = open(application_path, O_RDONLY | O_DIRECTORY);
481         if (fd < 0) {
482                 _E("path(%s) error(%d)", application_path, errno);
483                 return APP2EXT_ERROR_OPEN_DIR;
484         }
485         close(fd);
486
487         ret = snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
488                         application_path);
489         if (ret < 0 || ret > sizeof(app_mmc_path)) {
490                 _E("snprintf fail");
491                 return APP2EXT_ERROR_OPEN_DIR;
492         }
493         fd = open(app_mmc_path, O_RDONLY | O_DIRECTORY);
494         if (fd < 0) {
495                 _E("path(%s) error(%d)", app_mmc_path, errno);
496                 return APP2EXT_ERROR_OPEN_DIR;
497         }
498         close(fd);
499
500         nanosleep(&time, NULL); /* 200ms sleep */
501         _D("give a delay for mount");
502
503         switch (mount_type) {
504         case MOUNT_TYPE_RD:
505                 snprintf(mountflags_str, sizeof(mountflags_str), "%u",
506                                 MS_MGC_VAL | MS_RDONLY | MS_NOSUID);
507                 ret = _xsystem(argv_mount);
508                 if (ret) {
509                         _E("read only mount failed, errono is (%d), "
510                                         "dev is (%s) path is (%s)",
511                                         ret, dev, app_mmc_path);
512                         ret = APP2EXT_ERROR_MOUNT;
513                 }
514                 break;
515         case MOUNT_TYPE_RW:
516                 snprintf(mountflags_str, sizeof(mountflags_str), "%u",
517                                 MS_MGC_VAL | MS_NOSUID);
518                 ret = _xsystem(argv_mount);
519                 if (ret) {
520                         _E("read write mount failed, errno is (%d)", ret);
521                         ret = APP2EXT_ERROR_MOUNT;
522                 }
523                 break;
524         case MOUNT_TYPE_RW_NOEXEC:
525                 snprintf(mountflags_str, sizeof(mountflags_str), "%u",
526                                 MS_MGC_VAL | MS_NOEXEC | MS_NOSUID);
527                 ret = _xsystem(argv_mount);
528                 if (ret) {
529                         _E("rwnx mount failed errno is (%d)", ret);
530                         ret = APP2EXT_ERROR_MOUNT;
531                 }
532                 break;
533         case MOUNT_TYPE_RD_REMOUNT:
534                 snprintf(mountflags_str, sizeof(mountflags_str), "%u",
535                                 MS_MGC_VAL | MS_RDONLY | MS_REMOUNT |
536                                 MS_NOSUID);
537                 ret = _xsystem(argv_mount);
538                 if (ret) {
539                         _E("read remount failed errno is (%d)", ret);
540                         ret = APP2EXT_ERROR_MOUNT;
541                 }
542                 break;
543         case MOUNT_TYPE_RW_REMOUNT:
544                 snprintf(mountflags_str, sizeof(mountflags_str), "%u",
545                                 MS_MGC_VAL | MS_REMOUNT | MS_NOSUID);
546                 ret = _xsystem(argv_mount);
547                 err_str = strerror_r(ret, err_buf, sizeof(err_buf));
548                 if (ret) {
549                         _E("read write remount failed errno(%d), errstr(%s)",
550                                         ret, err_str);
551                         ret = APP2EXT_ERROR_MOUNT;
552                 }
553                 break;
554         default:
555                 _E("invalid mount type");
556                 break;
557         }
558
559         if (cmd == APP2SD_PRE_INSTALL || cmd == APP2SD_MOVE_APP_TO_MMC ||
560                         cmd == APP2SD_PRE_UPGRADE) {
561                 ret = _app2sd_create_directory_entry(application_path,
562                                 pkgid, dir_list, uid);
563         }
564
565         if (mount_type != MOUNT_TYPE_RD &&
566                         mount_type != MOUNT_TYPE_RD_REMOUNT) {
567                 /* change lost+found permission */
568                 ret = snprintf(temp_path, sizeof(temp_path), "%s/lost+found",
569                                 app_mmc_path);
570                 if (ret < 0 || ret > sizeof(temp_path)) {
571                         _E("snprintf fail");
572                         return APP2EXT_ERROR_CREATE_DIRECTORY;
573                 }
574                 ret = _app2sd_make_directory(temp_path, uid);
575                 if (ret) {
576                         _E("create directory(%s) failed", temp_path);
577                         return APP2EXT_ERROR_CREATE_DIRECTORY;
578                 }
579         }
580
581         return ret;
582 }
583
584 int _app2sd_unmount_app_content(const char *application_path)
585 {
586         int ret;
587         char app_mmc_path[FILENAME_MAX];
588         char err_buf[1024];
589         const char *err_str;
590
591         snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
592                         application_path);
593         ret = umount(app_mmc_path);
594         if (ret < 0) {
595                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
596                 _D("unable to umount the dir, ret(%d) error(%d, %s)",
597                                 ret, errno, err_str);
598         }
599
600         return ret;
601 }
602
603 static int _app2sd_move_to_archive(const char *src_path, const char *arch_path)
604 {
605         int ret;
606         char err_buf[1024];
607         const char *err_str;
608
609         ret = _app2sd_copy_dir(src_path, arch_path);
610         if (ret && ret != APP2EXT_ERROR_ACCESS_FILE) {
611                 err_str = strerror_r(errno, err_buf, sizeof(err_buf));
612                 _E("unable to copy from (%s) to (%s), err is (%s)",
613                                 src_path, arch_path, err_str);
614                 return APP2EXT_ERROR_MOVE;
615         }
616
617         ret = _app2sd_delete_directory(src_path);
618         if (ret) {
619                 _E("unable to delete (%s)", src_path);
620                 return APP2EXT_ERROR_DELETE_DIRECTORY;
621         }
622
623         return ret;
624 }
625
626 static int _app2sd_move_app_to_external(const char *pkgid, GList *dir_list,
627                 uid_t uid, char *mmc_path, char **image_path)
628 {
629         int ret;
630         mode_t mode = DIR_PERMS;
631         char temp_dir_path[FILENAME_MAX];
632         char app_mmc_path[FILENAME_MAX];
633         char app_archive_path[FILENAME_MAX];
634         char application_path[FILENAME_MAX];
635         char loopback_device[FILENAME_MAX];
636         unsigned long long total_size = 0;
637         int reqd_size;
638         int reqd_disk_size;
639         char *device_node;
640         int free_mmc_mem;
641         FILE *fp;
642         GList *list;
643         app2ext_dir_details *dir_detail;
644         char err_buf[1024];
645         const char *err_str;
646
647         ret = _app2sd_get_loopback_device_path(mmc_path, pkgid, uid,
648                         loopback_device, sizeof(loopback_device));
649         if (ret)
650                 return ret;
651
652         _app2sd_set_application_path(pkgid, uid, application_path,
653                         sizeof(application_path));
654
655         /* check whether application is in external memory or not */
656         fp = fopen(loopback_device, "r+");
657         if (fp != NULL) {
658                 _W("Already %s entry is present in the SD Card, "
659                                 "delete entry and go on without return", pkgid);
660                 fclose(fp);
661                 _app2sd_force_clean(pkgid, application_path, loopback_device,
662                                 uid);
663         }
664
665         ret = snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
666                         application_path);
667         if (ret < 0 || ret > sizeof(app_mmc_path)) {
668                 _E("snprintf fail");
669                 return APP2EXT_ERROR_CREATE_DIRECTORY;
670         }
671         ret = snprintf(app_archive_path, sizeof(app_archive_path), "%s/.archive",
672                         application_path);
673         if (ret < 0 || ret > sizeof(app_archive_path)) {
674                 _E("snprintf fail");
675                 return APP2EXT_ERROR_CREATE_DIRECTORY;
676         }
677
678         ret = mkdir(app_mmc_path, mode);
679         if (ret) {
680                 if (errno != EEXIST) {
681                         _E("unable to create directory for archiving,"
682                                         " error(%d)", errno);
683                         return APP2EXT_ERROR_CREATE_DIRECTORY;
684                 }
685         }
686
687         ret = mkdir(app_archive_path, mode);
688         if (ret) {
689                 if (errno != EEXIST) {
690                         _E("unable to create directory for archiving,"
691                                         " error(%d)", errno);
692                         return APP2EXT_ERROR_CREATE_DIRECTORY;
693                 }
694         }
695
696         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
697                 dir_detail = (app2ext_dir_details *)list->data;
698                 if (dir_detail == NULL || dir_detail->name == NULL ||
699                                 dir_detail->type != APP2EXT_DIR_RO)
700                         continue;
701                 ret = snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
702                                 application_path, dir_detail->name);
703                 if (ret < 0 || ret > sizeof(temp_dir_path)) {
704                         _E("snprintf fail");
705                         return APP2EXT_ERROR_MMC_STATUS;
706                 }
707                 _D("cal size of app dirs, temp_dir_path(%s)", temp_dir_path);
708                 total_size += _app2sd_calculate_dir_size(temp_dir_path);
709         }
710
711         reqd_size = ((total_size) / (1024 * 1024)) + 2;
712         reqd_disk_size = reqd_size + ceil(reqd_size * 0.2);
713
714         /* find avialable free memory in the MMC card */
715         ret = _app2sd_get_available_free_memory(mmc_path, &free_mmc_mem);
716         if (ret) {
717                 _E("unable to get available free memory in MMC (%d)", ret);
718                 return APP2EXT_ERROR_MMC_STATUS;
719         }
720         /* if avaialalbe free memory in MMC is less than
721          * required size + 5MB, return error
722          */
723         if (reqd_disk_size > free_mmc_mem) {
724                 _E("insufficient memory in MMC for "
725                                 "application installation (%d)", ret);
726                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
727         }
728         /* create a loopback device */
729         ret = _app2sd_create_loopback_device(pkgid, loopback_device,
730                         (reqd_disk_size + PKG_BUF_SIZE));
731         if (ret) {
732                 _E("loopback node creation failed");
733                 return ret;
734         }
735
736         ret = _app2sd_dmcrypt_setup_device(pkgid, loopback_device, false, uid);
737         if (ret) {
738                 _E("dmcrypt setup device error(%d)", ret);
739                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
740         }
741
742         ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device, false,
743                         uid, &device_node);
744         if (ret) {
745                 _E("dmcrypt open device error");
746                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
747         }
748         /* format the loopback file system */
749         ret = _app2sd_create_file_system(device_node);
750         if (ret) {
751                 _E("create ext4 filesystem failed");
752                 ret = APP2EXT_ERROR_CREATE_FS;
753                 goto ERR;
754         }
755
756         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
757                 dir_detail = (app2ext_dir_details *)list->data;
758                 if (dir_detail == NULL || dir_detail->name == NULL ||
759                                 dir_detail->type != APP2EXT_DIR_RO)
760                         continue;
761                 ret = snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
762                                 application_path, dir_detail->name);
763                 if (ret < 0 || ret > sizeof(temp_dir_path)) {
764                         _E("snprintf fail");
765                         ret = APP2EXT_ERROR_MOVE;
766                         goto ERR;
767                 }
768                 _D("app2archive, temp_dir_path(%s)", temp_dir_path);
769                 ret = _app2sd_move_to_archive(temp_dir_path, app_archive_path);
770                 if (ret) {
771                         _E("unable to copy from (%s) to (%s)",
772                                         temp_dir_path, app_archive_path);
773                         goto ERR;
774                 }
775         }
776
777         /* mount the loopback encrypted pseudo device on
778          * application installation path as with Read Write permission
779          */
780         ret = _app2sd_mount_app_content(application_path, pkgid, device_node,
781                         MOUNT_TYPE_RW, dir_list, APP2SD_MOVE_APP_TO_MMC, uid);
782         if (ret) {
783                 _E("mount failed");
784                 goto ERR;
785         }
786
787         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
788                 dir_detail = (app2ext_dir_details *)list->data;
789                 if (dir_detail == NULL || dir_detail->name == NULL ||
790                                 dir_detail->type != APP2EXT_DIR_RO)
791                         continue;
792                 ret = snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
793                                 app_archive_path, dir_detail->name);
794                 if (ret < 0 || ret > sizeof(temp_dir_path)) {
795                         _E("snprintf fail");
796                         ret = APP2EXT_ERROR_COPY_DIRECTORY;
797                         goto ERR;
798                 }
799                 _D("archive2mmc, temp_dir_path(%s)", temp_dir_path);
800                 ret = _app2sd_copy_dir(temp_dir_path, app_mmc_path);
801                 if (ret) {
802                         if (ret == APP2EXT_ERROR_ACCESS_FILE) {
803                                 _E("unable to access (%s)", temp_dir_path);
804                         } else {
805                                 err_str = strerror_r(errno, err_buf,
806                                                 sizeof(err_buf));
807                                 _E("unable to copy from (%s) to (%s),"
808                                                 " error is (%s)", temp_dir_path,
809                                                 app_mmc_path, err_str);
810                         }
811                         goto ERR;
812                 }
813                 ret = _app2sd_delete_directory(temp_dir_path);
814                 if (ret) {
815                         _E("unable to delete (%s)", temp_dir_path);
816                         goto ERR;
817                 }
818         }
819
820         ret = _app2sd_delete_directory(app_archive_path);
821         if (ret) {
822                 _E("unable to delete (%s)", app_archive_path);
823                 ret = APP2EXT_ERROR_DELETE_DIRECTORY;
824                 goto ERR;
825         }
826
827         *image_path = strdup(loopback_device);
828         return APP2EXT_SUCCESS;
829
830 ERR:
831         if (device_node)
832                 free(device_node);
833
834         *image_path = NULL;
835         return ret;
836 }
837
838 static int __check_storage_availability(
839                 const char *loopback_device, int free_internal_mem) {
840         unsigned long long temp;
841         int reqd_size;
842
843         temp = _app2sd_calculate_file_size(loopback_device);
844         reqd_size = (int)((temp) / (1024 * 1024));
845         _D("reqd size is (%d)", reqd_size);
846
847         if (reqd_size == 0) {
848                 _E("app entry is not present in SD Card");
849                 return APP2EXT_ERROR_LOOPBACK_DEVICE_UNAVAILABLE;
850         }
851
852         _I("reqd size: (%d)MB, free internal mem: (%d)MB",
853                         reqd_size, free_internal_mem);
854
855         /* if avaialalbe free memory in internal storage is
856          * less than required size, return error
857          */
858         if (reqd_size > free_internal_mem) {
859                 _E("innsufficient memory in internal storage"
860                         " for application installation");
861                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
862         }
863
864         return 0;
865 }
866
867 static int __copy_directories(const char *app_mmc_path, const char *app_archive_path,
868                 const char *application_path, app2ext_dir_details *dir_detail)
869 {
870         int ret;
871         char temp_dir_path[FILENAME_MAX];
872         char err_buf[1024];
873         const char *err_str;
874
875         ret = snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
876                         app_mmc_path, dir_detail->name);
877         if (ret < 0 || ret > sizeof(temp_dir_path)) {
878                 _E("snprintf fail");
879                 return -1;
880         }
881         _D("mmc2archive, temp_dir_path(%s)", temp_dir_path);
882         ret = _app2sd_copy_dir(temp_dir_path, app_archive_path);
883         if (ret) {
884                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
885                         _E("unable to access (%s)", temp_dir_path);
886                 } else {
887                         err_str = strerror_r(errno, err_buf,
888                                         sizeof(err_buf));
889                         _E("unable to copy from (%s) to (%s),"
890                                         "error is (%s)", temp_dir_path,
891                                         app_archive_path, err_str);
892                 }
893                 return -1;
894         }
895         /* delete the symbolic link files [bin, lib, res]*/
896         ret = snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
897                         application_path, dir_detail->name);
898         if (ret < 0 || ret > sizeof(temp_dir_path)) {
899                 _E("snprintf fail");
900                 return -1;
901         }
902         _D("unlink, temp_dir_path(%s)", temp_dir_path);
903         ret = unlink(temp_dir_path);
904         if (ret) {
905                 if (errno == ENOENT) {
906                         _W("(%s) does not exist", temp_dir_path);
907                 } else {
908                         _E("unable to remove the symbolic link file "
909                                         "(%s), it is already unlinked",
910                                         temp_dir_path);
911                         return -1;
912                 }
913         }
914         /* Copy content to destination */
915         ret = snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
916                         app_archive_path, dir_detail->name);
917         if (ret < 0 || ret > sizeof(temp_dir_path)) {
918                 _E("snprintf fail");
919                 return -1;
920         }
921         _D("archive2app, temp_dir_path(%s)", temp_dir_path);
922         ret = _app2sd_copy_dir(temp_dir_path, application_path);
923         if (ret) {
924                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
925                         _E("unable to access (%s)", temp_dir_path);
926                 } else {
927                         err_str = strerror_r(errno, err_buf,
928                                         sizeof(err_buf));
929                         _E("unable to copy from (%s) to (%s), "
930                                         "error is (%s)", temp_dir_path,
931                                         application_path, err_str);
932                 }
933                 return -1;
934         }
935         return 0;
936 }
937
938 static int _app2sd_move_app_to_internal(const char *pkgid, GList *dir_list,
939                 uid_t uid, char *mmc_path)
940 {
941         int ret;
942         mode_t mode = DIR_PERMS;
943         char app_mmc_path[FILENAME_MAX];
944         char app_archive_path[FILENAME_MAX];
945         char application_path[FILENAME_MAX];
946         char loopback_device[FILENAME_MAX];
947         char *device_node;
948         FILE *fp;
949         GList *list;
950         app2ext_dir_details *dir_detail;
951         int free_internal_mem;
952         int mount_type;
953
954         ret = _app2sd_get_loopback_device_path(mmc_path, pkgid, uid,
955                         loopback_device, sizeof(loopback_device));
956         if (ret)
957                 return ret;
958
959         _app2sd_set_application_path(pkgid, uid, application_path,
960                         sizeof(application_path));
961
962         /* check whether application is in external memory or not */
963         fp = fopen(loopback_device, "r+");
964         if (fp == NULL) {
965                 _E("application (%s) is not installed on SD Card",
966                                 pkgid);
967                 return APP2EXT_ERROR_FILE_ABSENT;
968         }
969         fclose(fp);
970
971         /* find avialable free memory in the internal storage */
972         ret = _app2sd_get_available_free_memory(INTERNAL_STORAGE_PATH,
973                         &free_internal_mem);
974         if (ret) {
975                 _E("unable to get available free memory in internal (%d)", ret);
976                 return APP2EXT_ERROR_MMC_STATUS;
977         }
978
979         fp = fopen(loopback_device, "r+");
980         if (fp == NULL) {
981                 _E("app entry is not present in SD card");
982                 return APP2EXT_ERROR_INVALID_PACKAGE;
983         }
984         fclose(fp);
985
986         /* get installed app size*/
987         ret = __check_storage_availability(loopback_device, free_internal_mem);
988         if (ret)
989                 return ret;
990
991         device_node =
992                 _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
993         if (device_node == NULL) {
994                 /* do loopback setup */
995                 ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device,
996                                 false, uid, &device_node);
997                 if (ret) {
998                         _E("dmcrypt open device error(%d)", ret);
999                         return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
1000                 }
1001                 mount_type = MOUNT_TYPE_RW;
1002         } else {
1003                 mount_type = MOUNT_TYPE_RW_REMOUNT;
1004         }
1005         /* do mounting */
1006         ret = _app2sd_mount_app_content(application_path,
1007                         pkgid, device_node, mount_type,
1008                         dir_list, APP2SD_MOVE_APP_TO_PHONE, uid);
1009         if (ret) {
1010                 _E("mount failed");
1011                 ret = APP2EXT_ERROR_MOUNT_PATH;
1012                 goto ERR;
1013         }
1014
1015         ret = snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
1016                         application_path);
1017         if (ret < 0 || ret > sizeof(app_mmc_path)) {
1018                 _E("snprintf fail");
1019                 ret = -1;
1020                 goto ERR;
1021         }
1022         ret = snprintf(app_archive_path, sizeof(app_archive_path), "%s/.archive",
1023                         application_path);
1024         if (ret < 0 || ret > sizeof(app_archive_path)) {
1025                 _E("snprintf fail");
1026                 ret = -1;
1027                 goto ERR;
1028         }
1029
1030         ret = mkdir(app_archive_path, mode);
1031         if (ret) {
1032                 if (errno != EEXIST) {
1033                         _E("unable to create directory for archiving,"
1034                                         " error(%d)", errno);
1035                         ret = APP2EXT_ERROR_CREATE_DIRECTORY;
1036                         goto ERR;
1037                 }
1038         }
1039
1040         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
1041                 dir_detail = (app2ext_dir_details *)list->data;
1042                 if (dir_detail == NULL || dir_detail->name == NULL ||
1043                                 dir_detail->type != APP2EXT_DIR_RO)
1044                         continue;
1045                 /* archiving code */
1046                 ret = __copy_directories(app_mmc_path, app_archive_path,
1047                                 application_path, dir_detail);
1048                 if (ret != 0) {
1049                         ret = -1;
1050                         goto ERR;
1051                 }
1052         }
1053
1054         _D("copying file completed");
1055         ret = _app2sd_unmount_app_content(application_path);
1056         if (ret)
1057                 _E("unable to unmount SD directory for app (%s)", pkgid);
1058
1059         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1060         if (ret)
1061                 _E("close dmcrypt device error(%d)", ret);
1062
1063         ret = _app2sd_delete_loopback_device(loopback_device);
1064         if (ret)
1065                 _E("unable to delete the loopback device for (%s)", pkgid);
1066
1067         ret = _app2sd_delete_directory(app_mmc_path);
1068         if (ret)
1069                 _E("unable to delete (%s)", app_mmc_path);
1070
1071         ret = _app2sd_delete_directory(app_archive_path);
1072         if (ret)
1073                 _E("unable to delete (%s)", app_archive_path);
1074
1075         /* remove passwrd from DB */
1076         ret = _app2sd_initialize_db();
1077         if (ret)
1078                 _E("app2sd db initialize failed");
1079
1080         ret = _app2sd_remove_info_from_db(pkgid, uid);
1081         if (ret)
1082                 _E("cannot remove info from db");
1083
1084         return APP2EXT_SUCCESS;
1085
1086 ERR:
1087         if (device_node)
1088                 free(device_node);
1089
1090         return ret;
1091 }
1092
1093 int _app2sd_usr_move_app(const char *pkgid, app2ext_move_type move_type,
1094                 GList *dir_list, uid_t uid, char *mmc_path, char **image_path)
1095 {
1096         int ret;
1097
1098         switch (move_type) {
1099         case APP2EXT_MOVE_TO_EXT:
1100                 ret = _app2sd_move_app_to_external(pkgid, dir_list,
1101                                 uid, mmc_path, image_path);
1102                 if (ret) {
1103                         _E("move app to external memory failed(%d)", ret);
1104                         return ret;
1105                 }
1106                 break;
1107         case APP2EXT_MOVE_TO_PHONE:
1108                 ret = _app2sd_move_app_to_internal(pkgid, dir_list,
1109                                 uid, mmc_path);
1110                 if (ret) {
1111                         _E("move app to internal memory failed(%d)", ret);
1112                         return ret;
1113                 }
1114                 break;
1115         default:
1116                 _E("invalid argument");
1117                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
1118         }
1119
1120         return ret;
1121 }
1122
1123 int _app2sd_copy_ro_content(const char *src, const char *dest, GList *dir_list)
1124 {
1125         char path[FILENAME_MAX];
1126         int ret;
1127         GList *list;
1128         app2ext_dir_details *dir_detail;
1129
1130         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
1131                 dir_detail = (app2ext_dir_details *)list->data;
1132                 if (dir_detail == NULL || dir_detail->name == NULL ||
1133                                 dir_detail->type != APP2EXT_DIR_RO)
1134                         continue;
1135
1136                 snprintf(path, sizeof(path), "%s/%s", src, dir_detail->name);
1137                 ret = _app2sd_copy_dir(path, dest);
1138                 if (ret) {
1139                         if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1140                                 _E("unable to access (%s)", path);
1141                         } else {
1142                                 _E("unable to copy from (%s) "
1143                                                 "to (%s), errno is (%d)",
1144                                                 path, dest, errno);
1145                                 return APP2EXT_ERROR_MOVE;
1146                         }
1147                 }
1148         }
1149
1150         return APP2EXT_SUCCESS;
1151 }
1152
1153 int _app2sd_duplicate_device(const char *pkgid, const char *loopback_device,
1154                 const char *temp_pkgid, const char *temp_application_path,
1155                 const char *temp_loopback_device, GList *dir_list,
1156                 char *dev_node, int size, uid_t uid)
1157 {
1158         int ret;
1159         int err_res;
1160
1161         /* create a new loopback device */
1162         ret = _app2sd_create_loopback_device(temp_pkgid,
1163                         temp_loopback_device, (size + PKG_BUF_SIZE));
1164         if (ret) {
1165                 _E("package already present");
1166                 return ret;
1167         }
1168
1169         /* perform loopback encryption setup */
1170         dev_node = _app2sd_dmcrypt_duplicate_encryption_setup(pkgid,
1171                         temp_loopback_device, uid);
1172         if (!dev_node) {
1173                 _E("dmcrypt duplicate encryption setup failed");
1174                 _app2sd_delete_loopback_device(temp_loopback_device);
1175                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
1176         }
1177
1178         /* format the loopback file system */
1179         ret = _app2sd_create_file_system(dev_node);
1180         if (ret) {
1181                 _E("creating fs failed");
1182                 err_res = APP2EXT_ERROR_CREATE_FS;
1183                 goto FINISH_OFF;
1184         }
1185         _D("create filesystem SUCCESS");
1186
1187         /* do mounting for new dev*/
1188         ret = _app2sd_mount_app_content(temp_application_path, pkgid,
1189                         dev_node, MOUNT_TYPE_RW, dir_list,
1190                         APP2SD_PRE_UPGRADE, uid);
1191         if (ret) {
1192                 _E("remount failed");
1193                 err_res = APP2EXT_ERROR_MOUNT_PATH;
1194                 goto FINISH_OFF;
1195         }
1196
1197         return APP2EXT_SUCCESS;
1198
1199 FINISH_OFF:
1200         if (dev_node) {
1201                 ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1202                 if (ret)
1203                         _E("close dmcrypt device error(%d)", ret);
1204                 _app2sd_delete_loopback_device(temp_loopback_device);
1205                 free(dev_node);
1206         }
1207
1208         return err_res;
1209 }
1210
1211 int _app2sd_update_loopback_device_size(const char *pkgid,
1212                 const char *loopback_device, const char *application_path,
1213                 const char *temp_pkgid, const char *temp_loopback_device,
1214                 const char *temp_application_path, int size, GList *dir_list,
1215                 uid_t uid)
1216 {
1217         int ret;
1218         char *old_device_node;
1219         int err_res;
1220         char app_mmc_path[FILENAME_MAX];
1221         char temp_app_mmc_path[FILENAME_MAX];
1222         int mount_type;
1223
1224         ret = _app2sd_duplicate_device(pkgid, loopback_device, temp_pkgid,
1225                         temp_application_path, temp_loopback_device,
1226                         dir_list, NULL, size, uid);
1227         if (ret) {
1228                 _E("creating duplicate device failed");
1229                 return ret;
1230         }
1231
1232         /* get the associated device node for SD card applicatione */
1233         old_device_node =
1234                 _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
1235         if (old_device_node == NULL) {
1236                 /* do loopback setup */
1237                 ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device,
1238                         false, uid, &old_device_node);
1239                 if (ret) {
1240                         _E("dmcrypt open device error");
1241                         err_res = APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
1242                         goto FINISH_OFF;
1243                 }
1244                 mount_type = MOUNT_TYPE_RW;
1245         } else {
1246                 mount_type = MOUNT_TYPE_RW_REMOUNT;
1247         }
1248
1249         /* do mounting */
1250         ret = _app2sd_mount_app_content(application_path, pkgid,
1251                         old_device_node, mount_type, dir_list,
1252                         APP2SD_PRE_UPGRADE, uid);
1253         if (ret) {
1254                 _E("remount failed");
1255                 err_res = APP2EXT_ERROR_MOUNT_PATH;
1256         }
1257         free(old_device_node);
1258
1259         snprintf(app_mmc_path, sizeof(app_mmc_path),
1260                         "%s/.mmc", application_path);
1261         snprintf(temp_app_mmc_path, sizeof(temp_app_mmc_path),
1262                         "%s/.mmc", temp_application_path);
1263
1264         ret = _app2sd_copy_ro_content(app_mmc_path,
1265                         temp_app_mmc_path, dir_list);
1266         if (ret) {
1267                 _E("copy ro content failed");
1268                 err_res = ret;
1269         }
1270
1271         ret = _app2sd_unmount_app_content(application_path);
1272         if (ret) {
1273                 _E("unable to unmount the SD application");
1274                 err_res = APP2EXT_ERROR_UNMOUNT;
1275         }
1276
1277         ret = _app2sd_unmount_app_content(temp_application_path);
1278         if (ret) {
1279                 _E("unable to unmount the SD application");
1280                 err_res = APP2EXT_ERROR_UNMOUNT;
1281                 goto FINISH_OFF;
1282         }
1283
1284         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1285         if (ret) {
1286                 _E("close dmcrypt device error(%d)", ret);
1287                 err_res = APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
1288                 goto FINISH_OFF;
1289         }
1290
1291         ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1292         if (ret) {
1293                 _E("close dmcrypt device error(%d)", ret);
1294                 err_res = APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
1295                 goto FINISH_OFF;
1296         }
1297
1298         ret = _app2sd_delete_directory(loopback_device);
1299         if (ret) {
1300                 _E("unable to delete (%s)", loopback_device);
1301                 err_res = APP2EXT_ERROR_DELETE_DIRECTORY;
1302                 goto FINISH_OFF;
1303         }
1304
1305         ret = _app2sd_rename_dir(temp_loopback_device, loopback_device);
1306         if (ret) {
1307                 _E("unable to rename (%s)", temp_loopback_device);
1308                 err_res = APP2EXT_ERROR_MOVE;
1309                 goto FINISH_OFF;
1310         }
1311
1312         ret = _app2sd_delete_directory(temp_application_path);
1313         if (ret) {
1314                 _E("unable to delete (%s)", temp_application_path);
1315                 err_res = APP2EXT_ERROR_DELETE_DIRECTORY;
1316                 goto FINISH_OFF;
1317         }
1318
1319         return APP2EXT_SUCCESS;
1320
1321 FINISH_OFF:
1322         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1323         if (ret)
1324                 _E("close dmcrypt device error(%d)", ret);
1325
1326         ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1327         if (ret)
1328                 _E("close dmcrypt device error(%d)", ret);
1329
1330         _app2sd_delete_loopback_device(temp_loopback_device);
1331
1332         ret = _app2sd_delete_directory(temp_application_path);
1333         if (ret)
1334                 _E("unable to delete (%s)", temp_application_path);
1335
1336         return err_res;
1337 }
1338
1339 int _app2sd_force_clean(const char *pkgid, const char *application_path,
1340                 const char *loopback_device, uid_t uid)
1341 {
1342         int ret;
1343
1344         /* unmount the loopback encrypted pseudo device from
1345          * the application installation path
1346          */
1347         ret = _app2sd_unmount_app_content(application_path);
1348         if (ret)
1349                 _W("unable to unmount the app content (%d)", ret);
1350
1351         /* detach the loopback encryption setup for the application */
1352         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1353         if (ret)
1354                 _W("close dmcrypt device error (%d)", ret);
1355
1356         /* delete the loopback device from the SD card */
1357         ret = _app2sd_delete_loopback_device(loopback_device);
1358         if (ret)
1359                 _W("unable to detach the loopback encryption setup for "
1360                                 "the application");
1361
1362         /* delete symlink */
1363         _app2sd_delete_symlink(application_path);
1364
1365         /* remove passwrd from DB */
1366         ret = _app2sd_initialize_db();
1367         if (ret)
1368                 _W("app2sd db initialize failed");
1369
1370         ret = _app2sd_remove_info_from_db(pkgid, uid);
1371         if (ret)
1372                 _W("cannot remove info from db");
1373
1374         return ret;
1375 }