Fix possible double-free issue
[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 _app2sd_move_app_to_internal(const char *pkgid, GList *dir_list,
839                 uid_t uid, char *mmc_path)
840 {
841         int ret;
842         mode_t mode = DIR_PERMS;
843         char temp_dir_path[FILENAME_MAX];
844         char app_mmc_path[FILENAME_MAX];
845         char app_archive_path[FILENAME_MAX];
846         char application_path[FILENAME_MAX];
847         char loopback_device[FILENAME_MAX];
848         char *device_node;
849         FILE *fp;
850         GList *list;
851         app2ext_dir_details *dir_detail;
852         int reqd_size;
853         int free_internal_mem;
854         unsigned long long temp = 0;
855         char err_buf[1024];
856         const char *err_str;
857         int mount_type;
858
859         ret = _app2sd_get_loopback_device_path(mmc_path, pkgid, uid,
860                         loopback_device, sizeof(loopback_device));
861         if (ret)
862                 return ret;
863
864         _app2sd_set_application_path(pkgid, uid, application_path,
865                 sizeof(application_path));
866
867         /* check whether application is in external memory or not */
868         fp = fopen(loopback_device, "r+");
869         if (fp == NULL) {
870                 _E("application (%s) is not installed on SD Card",
871                      pkgid);
872                 return APP2EXT_ERROR_FILE_ABSENT;
873         }
874         fclose(fp);
875
876         /* find avialable free memory in the internal storage */
877         ret = _app2sd_get_available_free_memory(INTERNAL_STORAGE_PATH,
878                         &free_internal_mem);
879         if (ret) {
880                 _E("unable to get available free memory in internal (%d)", ret);
881                 return APP2EXT_ERROR_MMC_STATUS;
882         }
883
884         fp = fopen(loopback_device, "r+");
885         if (fp == NULL) {
886                 _E("app entry is not present in SD card");
887                 return APP2EXT_ERROR_INVALID_PACKAGE;
888         }
889         fclose(fp);
890
891         /* get installed app size*/
892         temp = _app2sd_calculate_file_size(loopback_device);
893         reqd_size = (int)((temp) / (1024 * 1024));
894         _D("reqd size is (%d)", reqd_size);
895
896         if (reqd_size == 0) {
897                 _E("app entry is not present in SD Card");
898                 return APP2EXT_ERROR_LOOPBACK_DEVICE_UNAVAILABLE;
899         }
900
901         _I("reqd size: (%d)MB, free internal mem: (%d)MB",
902                         reqd_size, free_internal_mem);
903
904         /* if avaialalbe free memory in internal storage is
905          * less than required size, return error
906          */
907         if (reqd_size > free_internal_mem) {
908                 _E("innsufficient memory in internal storage"
909                         " for application installation (%d)", ret);
910                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
911         }
912
913         device_node =
914                 _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
915         if (device_node == NULL) {
916                 /* do loopback setup */
917                 ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device,
918                                 false, uid, &device_node);
919                 if (ret) {
920                         _E("dmcrypt open device error(%d)", ret);
921                         return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
922                 }
923                 mount_type = MOUNT_TYPE_RW;
924         } else {
925                 mount_type = MOUNT_TYPE_RW_REMOUNT;
926         }
927         /* do mounting */
928         ret = _app2sd_mount_app_content(application_path,
929                         pkgid, device_node, mount_type,
930                         dir_list, APP2SD_MOVE_APP_TO_PHONE, uid);
931         if (ret) {
932                 _E("mount failed");
933                 ret = APP2EXT_ERROR_MOUNT_PATH;
934                 goto ERR;
935         }
936
937         ret = snprintf(app_mmc_path, sizeof(app_mmc_path), "%s/.mmc",
938                         application_path);
939         if (ret < 0 || ret > sizeof(app_mmc_path)) {
940                 _E("snprintf fail");
941                 ret = -1;
942                 goto ERR;
943         }
944         ret = snprintf(app_archive_path, sizeof(app_archive_path), "%s/.archive",
945                         application_path);
946         if (ret < 0 || ret > sizeof(app_archive_path)) {
947                 _E("snprintf fail");
948                 ret = -1;
949                 goto ERR;
950         }
951
952         ret = mkdir(app_archive_path, mode);
953         if (ret) {
954                 if (errno != EEXIST) {
955                         _E("unable to create directory for archiving,"
956                                         " error(%d)", errno);
957                         ret = APP2EXT_ERROR_CREATE_DIRECTORY;
958                         goto ERR;
959                 }
960         }
961
962         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
963                 dir_detail = (app2ext_dir_details *)list->data;
964                 if (dir_detail == NULL || dir_detail->name == NULL ||
965                                 dir_detail->type != APP2EXT_DIR_RO)
966                         continue;
967                 /* archiving code */
968                 ret = snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
969                                 app_mmc_path, dir_detail->name);
970                 if (ret < 0 || ret > sizeof(temp_dir_path)) {
971                         _E("snprintf fail");
972                         ret = -1;
973                         goto ERR;
974                 }
975                 _D("mmc2archive, temp_dir_path(%s)", temp_dir_path);
976                 ret = _app2sd_copy_dir(temp_dir_path, app_archive_path);
977                 if (ret) {
978                         if (ret == APP2EXT_ERROR_ACCESS_FILE) {
979                                 _E("unable to access (%s)", temp_dir_path);
980                         } else {
981                                 err_str = strerror_r(errno, err_buf,
982                                                 sizeof(err_buf));
983                                 _E("unable to copy from (%s) to (%s),"
984                                                 "error is (%s)", temp_dir_path,
985                                                 app_archive_path, err_str);
986                         }
987                         goto ERR;
988                 }
989                 /* delete the symbolic link files [bin, lib, res]*/
990                 ret = snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
991                                 application_path, dir_detail->name);
992                 if (ret < 0 || ret > sizeof(temp_dir_path)) {
993                         _E("snprintf fail");
994                         ret = -1;
995                         goto ERR;
996                 }
997                 _D("unlink, temp_dir_path(%s)", temp_dir_path);
998                 ret = unlink(temp_dir_path);
999                 if (ret) {
1000                         if (errno == ENOENT) {
1001                                 _W("(%s) does not exist", temp_dir_path);
1002                         } else {
1003                                 _E("unable to remove the symbolic link file "
1004                                                 "(%s), it is already unlinked",
1005                                                 temp_dir_path);
1006                                 goto ERR;
1007                         }
1008                 }
1009                 /* Copy content to destination */
1010                 ret = snprintf(temp_dir_path, sizeof(temp_dir_path), "%s/%s",
1011                                 app_archive_path, dir_detail->name);
1012                 if (ret < 0 || ret > sizeof(temp_dir_path)) {
1013                         _E("snprintf fail");
1014                         ret = -1;
1015                         goto ERR;
1016                 }
1017                 _D("archive2app, temp_dir_path(%s)", temp_dir_path);
1018                 ret = _app2sd_copy_dir(temp_dir_path, application_path);
1019                 if (ret) {
1020                         if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1021                                 _E("unable to access (%s)", temp_dir_path);
1022                         } else {
1023                                 err_str = strerror_r(errno, err_buf,
1024                                                 sizeof(err_buf));
1025                                 _E("unable to copy from (%s) to (%s), "
1026                                                 "error is (%s)", temp_dir_path,
1027                                                 application_path, err_str);
1028                         }
1029                         goto ERR;
1030                 }
1031         }
1032
1033         _D("copying file completed");
1034         ret = _app2sd_unmount_app_content(application_path);
1035         if (ret)
1036                 _E("unable to unmount SD directory for app (%s)", pkgid);
1037
1038         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1039         if (ret)
1040                 _E("close dmcrypt device error(%d)", ret);
1041
1042         ret = _app2sd_delete_loopback_device(loopback_device);
1043         if (ret)
1044                 _E("unable to delete the loopback device for (%s)", pkgid);
1045
1046         ret = _app2sd_delete_directory(app_mmc_path);
1047         if (ret)
1048                 _E("unable to delete (%s)", app_mmc_path);
1049
1050         ret = _app2sd_delete_directory(app_archive_path);
1051         if (ret)
1052                 _E("unable to delete (%s)", app_archive_path);
1053
1054         /* remove passwrd from DB */
1055         ret = _app2sd_initialize_db();
1056         if (ret)
1057                 _E("app2sd db initialize failed");
1058
1059         ret = _app2sd_remove_info_from_db(pkgid, uid);
1060         if (ret)
1061                 _E("cannot remove info from db");
1062
1063         return APP2EXT_SUCCESS;
1064
1065 ERR:
1066         if (device_node)
1067                 free(device_node);
1068
1069         return ret;
1070 }
1071
1072 int _app2sd_usr_move_app(const char *pkgid, app2ext_move_type move_type,
1073                 GList *dir_list, uid_t uid, char *mmc_path, char **image_path)
1074 {
1075         int ret;
1076
1077         switch (move_type) {
1078         case APP2EXT_MOVE_TO_EXT:
1079                 ret = _app2sd_move_app_to_external(pkgid, dir_list,
1080                                 uid, mmc_path, image_path);
1081                 if (ret) {
1082                         _E("move app to external memory failed(%d)", ret);
1083                         return ret;
1084                 }
1085                 break;
1086         case APP2EXT_MOVE_TO_PHONE:
1087                 ret = _app2sd_move_app_to_internal(pkgid, dir_list,
1088                                 uid, mmc_path);
1089                 if (ret) {
1090                         _E("move app to internal memory failed(%d)", ret);
1091                         return ret;
1092                 }
1093                 break;
1094         default:
1095                 _E("invalid argument");
1096                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
1097         }
1098
1099         return ret;
1100 }
1101
1102 int _app2sd_copy_ro_content(const char *src, const char *dest, GList *dir_list)
1103 {
1104         char path[FILENAME_MAX];
1105         int ret;
1106         GList *list;
1107         app2ext_dir_details *dir_detail;
1108
1109         for (list = g_list_first(dir_list); list; list = g_list_next(list)) {
1110                 dir_detail = (app2ext_dir_details *)list->data;
1111                 if (dir_detail == NULL || dir_detail->name == NULL ||
1112                                 dir_detail->type != APP2EXT_DIR_RO)
1113                         continue;
1114
1115                 snprintf(path, sizeof(path), "%s/%s", src, dir_detail->name);
1116                 ret = _app2sd_copy_dir(path, dest);
1117                 if (ret) {
1118                         if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1119                                 _E("unable to access (%s)", path);
1120                         } else {
1121                                 _E("unable to copy from (%s) "
1122                                                 "to (%s), errno is (%d)",
1123                                                 path, dest, errno);
1124                                 return APP2EXT_ERROR_MOVE;
1125                         }
1126                 }
1127         }
1128
1129         return APP2EXT_SUCCESS;
1130 }
1131
1132 int _app2sd_duplicate_device(const char *pkgid, const char *loopback_device,
1133                 const char *temp_pkgid, const char *temp_application_path,
1134                 const char *temp_loopback_device, GList *dir_list,
1135                 char *dev_node, int size, uid_t uid)
1136 {
1137         int ret;
1138         int err_res;
1139
1140         /* create a new loopback device */
1141         ret = _app2sd_create_loopback_device(temp_pkgid,
1142                         temp_loopback_device, (size + PKG_BUF_SIZE));
1143         if (ret) {
1144                 _E("package already present");
1145                 return ret;
1146         }
1147
1148         /* perform loopback encryption setup */
1149         dev_node = _app2sd_dmcrypt_duplicate_encryption_setup(pkgid,
1150                         temp_loopback_device, uid);
1151         if (!dev_node) {
1152                 _E("dmcrypt duplicate encryption setup failed");
1153                 _app2sd_delete_loopback_device(temp_loopback_device);
1154                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
1155         }
1156
1157         /* format the loopback file system */
1158         ret = _app2sd_create_file_system(dev_node);
1159         if (ret) {
1160                 _E("creating fs failed");
1161                 err_res = APP2EXT_ERROR_CREATE_FS;
1162                 goto FINISH_OFF;
1163         }
1164         _D("create filesystem SUCCESS");
1165
1166         /* do mounting for new dev*/
1167         ret = _app2sd_mount_app_content(temp_application_path, pkgid,
1168                         dev_node, MOUNT_TYPE_RW, dir_list,
1169                         APP2SD_PRE_UPGRADE, uid);
1170         if (ret) {
1171                 _E("remount failed");
1172                 err_res = APP2EXT_ERROR_MOUNT_PATH;
1173                 goto FINISH_OFF;
1174         }
1175
1176         return APP2EXT_SUCCESS;
1177
1178 FINISH_OFF:
1179         if (dev_node) {
1180                 ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1181                 if (ret)
1182                         _E("close dmcrypt device error(%d)", ret);
1183                 _app2sd_delete_loopback_device(temp_loopback_device);
1184                 free(dev_node);
1185         }
1186
1187         return err_res;
1188 }
1189
1190 int _app2sd_update_loopback_device_size(const char *pkgid,
1191                 const char *loopback_device, const char *application_path,
1192                 const char *temp_pkgid, const char *temp_loopback_device,
1193                 const char *temp_application_path, int size, GList *dir_list,
1194                 uid_t uid)
1195 {
1196         int ret;
1197         char *old_device_node;
1198         int err_res;
1199         char app_mmc_path[FILENAME_MAX];
1200         char temp_app_mmc_path[FILENAME_MAX];
1201         int mount_type;
1202
1203         ret = _app2sd_duplicate_device(pkgid, loopback_device, temp_pkgid,
1204                         temp_application_path, temp_loopback_device,
1205                         dir_list, NULL, size, uid);
1206         if (ret) {
1207                 _E("creating duplicate device failed");
1208                 return ret;
1209         }
1210
1211         /* get the associated device node for SD card applicatione */
1212         old_device_node =
1213                 _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
1214         if (old_device_node == NULL) {
1215                 /* do loopback setup */
1216                 ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device,
1217                         false, uid, &old_device_node);
1218                 if (ret) {
1219                         _E("dmcrypt open device error");
1220                         err_res = APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
1221                         goto FINISH_OFF;
1222                 }
1223                 mount_type = MOUNT_TYPE_RW;
1224         } else {
1225                 mount_type = MOUNT_TYPE_RW_REMOUNT;
1226         }
1227
1228         /* do mounting */
1229         ret = _app2sd_mount_app_content(application_path, pkgid,
1230                         old_device_node, mount_type, dir_list,
1231                         APP2SD_PRE_UPGRADE, uid);
1232         if (ret) {
1233                 _E("remount failed");
1234                 err_res = APP2EXT_ERROR_MOUNT_PATH;
1235         }
1236         free(old_device_node);
1237
1238         snprintf(app_mmc_path, sizeof(app_mmc_path),
1239                         "%s/.mmc", application_path);
1240         snprintf(temp_app_mmc_path, sizeof(temp_app_mmc_path),
1241                         "%s/.mmc", temp_application_path);
1242
1243         ret = _app2sd_copy_ro_content(app_mmc_path,
1244                         temp_app_mmc_path, dir_list);
1245         if (ret) {
1246                 _E("copy ro content failed");
1247                 err_res = ret;
1248         }
1249
1250         ret = _app2sd_unmount_app_content(application_path);
1251         if (ret) {
1252                 _E("unable to unmount the SD application");
1253                 err_res = APP2EXT_ERROR_UNMOUNT;
1254         }
1255
1256         ret = _app2sd_unmount_app_content(temp_application_path);
1257         if (ret) {
1258                 _E("unable to unmount the SD application");
1259                 err_res = APP2EXT_ERROR_UNMOUNT;
1260                 goto FINISH_OFF;
1261         }
1262
1263         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1264         if (ret) {
1265                 _E("close dmcrypt device error(%d)", ret);
1266                 err_res = APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
1267                 goto FINISH_OFF;
1268         }
1269
1270         ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1271         if (ret) {
1272                 _E("close dmcrypt device error(%d)", ret);
1273                 err_res = APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
1274                 goto FINISH_OFF;
1275         }
1276
1277         ret = _app2sd_delete_directory(loopback_device);
1278         if (ret) {
1279                 _E("unable to delete (%s)", loopback_device);
1280                 err_res = APP2EXT_ERROR_DELETE_DIRECTORY;
1281                 goto FINISH_OFF;
1282         }
1283
1284         ret = _app2sd_rename_dir(temp_loopback_device, loopback_device);
1285         if (ret) {
1286                 _E("unable to rename (%s)", temp_loopback_device);
1287                 err_res = APP2EXT_ERROR_MOVE;
1288                 goto FINISH_OFF;
1289         }
1290
1291         ret = _app2sd_delete_directory(temp_application_path);
1292         if (ret) {
1293                 _E("unable to delete (%s)", temp_application_path);
1294                 err_res = APP2EXT_ERROR_DELETE_DIRECTORY;
1295                 goto FINISH_OFF;
1296         }
1297
1298         return APP2EXT_SUCCESS;
1299
1300 FINISH_OFF:
1301         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1302         if (ret)
1303                 _E("close dmcrypt device error(%d)", ret);
1304
1305         ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1306         if (ret)
1307                 _E("close dmcrypt device error(%d)", ret);
1308
1309         _app2sd_delete_loopback_device(temp_loopback_device);
1310
1311         ret = _app2sd_delete_directory(temp_application_path);
1312         if (ret)
1313                 _E("unable to delete (%s)", temp_application_path);
1314
1315         return err_res;
1316 }
1317
1318 int _app2sd_force_clean(const char *pkgid, const char *application_path,
1319                 const char *loopback_device, uid_t uid)
1320 {
1321         int ret;
1322
1323         /* unmount the loopback encrypted pseudo device from
1324          * the application installation path
1325          */
1326         ret = _app2sd_unmount_app_content(application_path);
1327         if (ret)
1328                 _W("unable to unmount the app content (%d)", ret);
1329
1330         /* detach the loopback encryption setup for the application */
1331         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1332         if (ret)
1333                 _W("close dmcrypt device error (%d)", ret);
1334
1335         /* delete the loopback device from the SD card */
1336         ret = _app2sd_delete_loopback_device(loopback_device);
1337         if (ret)
1338                 _W("unable to detach the loopback encryption setup for "
1339                                 "the application");
1340
1341         /* delete symlink */
1342         _app2sd_delete_symlink(application_path);
1343
1344         /* remove passwrd from DB */
1345         ret = _app2sd_initialize_db();
1346         if (ret)
1347                 _W("app2sd db initialize failed");
1348
1349         ret = _app2sd_remove_info_from_db(pkgid, uid);
1350         if (ret)
1351                 _W("cannot remove info from db");
1352
1353         return ret;
1354 }