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