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