Fix memory leak
[platform/core/appfw/app2sd.git] / plugin / app2sd / src / app2sd_internals.c
1 /*
2  * app2ext
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Garima Shrivastava<garima.s@samsung.com>
7  *      Jyotsna Dhumale <jyotsna.a@samsung.com>
8  *      Venkatesha Sarpangala <sarpangala.v@samsung.com>
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */
23
24 #include <dirent.h>
25 #include <time.h>
26 #include <pwd.h>
27
28 #include "app2sd_internals.h"
29
30 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
31 #define DMCRYPT_ITER_TIME       50
32 #define DMCRYPT_KEY_LEN         128
33 #endif
34
35 static int _app2sd_make_directory(const char *path, uid_t uid)
36 {
37         int ret = 0;
38         int fd = -1;
39         mode_t mode = DIR_PERMS;
40         struct passwd pwd;
41         struct passwd *pwd_result;
42         char buf[1024] = { 0, };
43
44         ret = _app2sd_delete_directory(path);
45         if (ret) {
46                 _E("unable to delete (%s), errno(%d)", path, errno);
47                 return APP2EXT_ERROR_DELETE_DIRECTORY;
48         }
49
50         ret = getpwuid_r(uid, &pwd, buf, sizeof(buf), &pwd_result);
51         if (ret != 0 || pwd_result == NULL) {
52                 _E("get uid failed(%d)", ret);
53                 return APP2EXT_ERROR_ACCESS_FILE;
54         }
55         _D("uid(%d), gid(%d)", uid, pwd.pw_gid);
56
57         /* create directory */
58         ret = mkdir(path, mode);
59         if (ret) {
60                 if (errno != EEXIST) {
61                         _E("create directory failed," \
62                                 " error no is (%d)", errno);
63                         return APP2EXT_ERROR_CREATE_DIRECTORY;
64                 }
65         }
66
67         fd = open(path, O_RDONLY|O_DIRECTORY);
68         if (fd < 0) {
69                 _E("can't open path(%s)", path);
70                 return APP2EXT_ERROR_OPEN_DIR;
71         }
72
73         ret = fchmod(fd, 0755);
74         if (ret < 0) {
75                 _E("change file permission error");
76                 close(fd);
77                 return APP2EXT_ERROR_ACCESS_FILE;
78         }
79
80         ret = fchown(fd, uid, pwd.pw_gid);
81         if (ret < 0) {
82                 _E("change file owner error");
83                 close(fd);
84                 return APP2EXT_ERROR_ACCESS_FILE;
85         }
86
87         close(fd);
88
89         return APP2EXT_SUCCESS;
90 }
91
92 char *_app2sd_find_associated_device_node(const char *loopback_device)
93 {
94         char *ret_result = NULL;
95         char delims[] = ":";
96         char *result = NULL;
97         char dev[FILENAME_MAX] = { 0, };
98         char *devnode = NULL;
99
100         result = (char *)_app2sd_find_associated_device(loopback_device);
101         if (result == NULL) {
102                 _D("there is no the associated file (%s)", loopback_device);
103                 return NULL;
104         }
105
106         /* process the string*/
107         snprintf(dev, FILENAME_MAX - 1, "%s", result);
108
109         if (strstr(dev, "dev") == NULL) {
110                 _E("unable to find the associated file");
111                 free(result);
112                 return NULL;
113         } else {
114                 char *saveptr = NULL;
115                 ret_result = strtok_r(dev, delims, &saveptr);
116                 if (ret_result)
117                         devnode = strdup(ret_result);
118         }
119
120         free(result);
121
122         return devnode;
123 }
124
125 char *_app2sd_create_loopdevice_node(void)
126 {
127         char *ret_result = NULL;
128         mode_t mode = DIR_PERMS;
129         int count = 0;
130         int ret = APP2EXT_SUCCESS;
131         char *result = NULL;
132         FILE *fp = NULL;
133
134         result = (char *)_app2sd_find_free_device();
135         _D("find_free_device(%s)", result);
136
137         /* validate the result */
138         if (result == NULL || strstr(result, "/dev") == NULL) {
139                 _D("no device found, creating device node");
140
141                 if (result) {
142                         free(result);
143                         result = NULL;
144                 }
145                 count = 0;
146                 char dev_path[BUF_SIZE] = { 0, };
147                 snprintf(dev_path, BUF_SIZE, "/dev/loop%d", count);
148                 while ((fp = fopen(dev_path, "r+")) != NULL) {
149                         count = count + 1;
150                         snprintf(dev_path, BUF_SIZE, "/dev/loop%d", count);
151                         _D("next dev path for checking is (%s)",
152                                      dev_path);
153                         fclose(fp);
154                 }
155                 _D("device node candidate is (%s)", dev_path);
156                 dev_t dev_node;
157                 dev_node = makedev(DEV_MAJOR, count);
158                 ret = mknod(dev_path, S_IFBLK | mode, dev_node);
159                 if (ret < 0) {
160                         _E("error while creating the device node: errno is (%d)",
161                              errno);
162                         return NULL;
163                 }
164                 ret_result = (char *)malloc(strlen(dev_path) + 1);
165                 if (ret_result == NULL) {
166                         _E("unable to allocate memory");
167                         return NULL;
168                 }
169                 memset(ret_result, '\0', strlen(dev_path) + 1);
170                 memcpy(ret_result, dev_path, strlen(dev_path));
171         } else {
172                 ret_result = (char *)malloc(strlen(result) + 1);
173                 if (ret_result == NULL) {
174                         _E("malloc failed");
175                         free(result);
176                         result = NULL;
177                         return NULL;
178                 }
179                 memset(ret_result, '\0', strlen(result) + 1);
180                 if (strlen(result) > 0)
181                         memcpy(ret_result, result, strlen(result) - 1);
182
183                 free(result);
184                 result = NULL;
185
186         }
187         return ret_result;
188 }
189
190 char *_app2sd_do_loopback_encryption_setup(const char *pkgid,
191         const char *loopback_device, uid_t uid)
192 {
193         int ret = APP2EXT_SUCCESS;
194         char *passwd = NULL;
195         char *result = NULL;
196         char *device_node = NULL;
197
198         if (pkgid == NULL) {
199                 _E("invalid argument");
200                 return NULL;
201         }
202
203         /* get password for loopback encryption */
204         ret = _app2sd_initialize_db();
205         if (ret) {
206                 _E("app2sd db initialize failed");
207                 return NULL;
208         }
209
210         if ((passwd = _app2sd_get_password_from_db(pkgid, uid)) == NULL) {
211                 passwd = (char *)_app2sd_generate_password(pkgid);
212                 if (NULL == passwd) {
213                         _E("unable to generate password");
214                         return NULL;
215                 } else {
216                         if ((ret = _app2sd_set_info_in_db(pkgid,
217                                 passwd, loopback_device, uid)) < 0) {
218                                 _E("unable to save info");
219                                 free(passwd);
220                                 passwd = NULL;
221                                 return NULL;
222                         }
223                 }
224         }
225
226         /* get free device node*/
227         device_node = _app2sd_create_loopdevice_node();
228         if (NULL == device_node) {
229                 free(passwd);
230                 passwd = NULL;
231                 _E("unable to find free loopback node");
232                 return NULL;
233         }
234
235         _D("device_node (%s)", device_node);
236
237         result = (char *)_app2sd_encrypt_device(device_node,
238                 loopback_device, passwd);
239         if (result == NULL) {
240                 _E("encryption failed");
241                 free(passwd);
242                 passwd = NULL;
243                 return NULL;
244         } else {
245                 _D("result (%s)", result);
246                 free(result);
247                 result = NULL;
248                 free(passwd);
249                 passwd = NULL;
250                 return device_node;
251         }
252 }
253
254 char *_app2sd_do_loopback_duplicate_encryption_setup(const char *pkgid,
255                 const char *temp_pkgid, const char *temp_loopback_device,
256                 char *passwd, uid_t uid)
257 {
258         char *result = NULL;
259         char *device_node = NULL;
260
261         if (pkgid == NULL || temp_pkgid == NULL ||
262                 temp_loopback_device == NULL || passwd == NULL) {
263                 _E("invalid argument");
264                 return NULL;
265         }
266
267         /* get free device node*/
268         device_node = _app2sd_create_loopdevice_node();
269         if (NULL == device_node) {
270                 _E("unable to find free loopback node");
271                 return NULL;
272         }
273         result = (char *)_app2sd_encrypt_device(device_node,
274                 temp_loopback_device, passwd);
275         if (result == NULL) {
276                 _E("encryption failed");
277                 return NULL;
278         } else {
279                 if (strlen(result) == 0) {
280                         free(result);
281                         result = NULL;
282                         return device_node;
283                 } else {
284                         _E("error is (%s)", result);
285                         free(result);
286                         result = NULL;
287                         return NULL;
288                 }
289         }
290
291         return device_node;
292 }
293
294 int _app2sd_remove_loopback_encryption_setup(const char *loopback_device)
295 {
296         int ret = APP2EXT_SUCCESS;
297         char *result = NULL;
298         char *dev_node = NULL;
299
300         if ((dev_node = _app2sd_find_associated_device_node(loopback_device))
301                 == NULL) {
302                 _E("Unable to find the association");
303                 ret = APP2EXT_ERROR_FIND_ASSOCIATED_DEVICE_NODE;
304         }
305
306         result = (char *)_app2sd_detach_loop_device(dev_node);
307         if (result == NULL) {
308                 _E("error in detaching");
309                 ret = APP2EXT_ERROR_DETACH_LOOPBACK_DEVICE;
310         } else {
311                 free(result);
312                 result = NULL;
313         }
314
315         if (dev_node) {
316                 free(dev_node);
317                 dev_node = NULL;
318         }
319
320         return ret;
321 }
322
323 int _app2sd_remove_all_loopback_encryption_setups(const char *loopback_device)
324 {
325         int ret = APP2EXT_SUCCESS;
326         char *result = NULL;
327         char *dev_node = NULL;
328         while (1) {
329                 if ((dev_node =
330                         _app2sd_find_associated_device_node(loopback_device))
331                         == NULL) {
332                         _E("finish to find the association");
333                         ret = APP2EXT_SUCCESS;
334                         break;
335                 }
336
337                 _D("find node (%s)", dev_node);
338
339                 result = (char *)_app2sd_detach_loop_device(dev_node);
340                 if (result == NULL) {
341                         _E("error in detaching");
342                         ret = APP2EXT_ERROR_DETACH_LOOPBACK_DEVICE;
343                         break;
344                 } else {
345                         free(result);
346                         result = NULL;
347                 }
348                 if (dev_node) {
349                         free(dev_node);
350                         dev_node = NULL;
351                 }
352         }
353
354         return ret;
355 }
356
357 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
358 int _app2sd_dmcrypt_setup_device(const char *pkgid,
359                 const char *loopback_device, bool is_dup, uid_t uid)
360 {
361         int ret = APP2EXT_SUCCESS;
362         char *passwd = NULL;
363         char dmcrypt_setup_cmd[BUF_SIZE] = { 0, };
364         char err_buf[BUF_SIZE] = { 0, };
365
366         if (pkgid == NULL || loopback_device == NULL) {
367                 _E("invalid argument");
368                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
369         }
370
371         /* get password for dmcrypt encryption */
372         ret = _app2sd_initialize_db();
373         if (ret) {
374                 _E("app2sd db initialize failed");
375                 return APP2EXT_ERROR_DB_INITIALIZE;
376         }
377
378         passwd = _app2sd_get_password_from_db(pkgid, uid);
379         if (passwd == NULL) {
380                 if (is_dup) {
381                         _E("no password found for (%s)", pkgid);
382                         return APP2EXT_ERROR_SQLITE_REGISTRY;
383                 }
384                 passwd = (char *)_app2sd_generate_password(pkgid);
385                 if (NULL == passwd) {
386                         _E("unable to generate password\n");
387                         return APP2EXT_ERROR_PASSWD_GENERATION;
388                 } else {
389                         if ((ret = _app2sd_set_info_in_db(pkgid, passwd,
390                                 loopback_device, uid)) < 0) {
391                                 _E("unable to save password");
392                                 free(passwd);
393                                 passwd = NULL;
394                                 return APP2EXT_ERROR_SQLITE_REGISTRY;
395                         }
396                 }
397         }
398
399         snprintf(dmcrypt_setup_cmd, BUF_SIZE, "/bin/echo '%s' | /sbin/cryptsetup -q -i %d " \
400                 "-c aes-cbc-lmk -s %d --align-payload=8 luksFormat %s",
401                 passwd, DMCRYPT_ITER_TIME, DMCRYPT_KEY_LEN, loopback_device);
402
403         ret = system(dmcrypt_setup_cmd);
404         if (ret) {
405                 strerror_r(errno, err_buf, sizeof(err_buf));
406                 _E("Error setting up dmcrypt on app2sd file, " \
407                         "error(%s), ret(%d)", err_buf, ret);
408                 if (passwd) {
409                         free(passwd);
410                         passwd = NULL;
411                 }
412                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
413         }
414
415         if (passwd) {
416                 free(passwd);
417                 passwd = NULL;
418         }
419
420         return ret;
421 }
422
423 int _app2sd_dmcrypt_open_device(const char *pkgid, const char *loopback_device,
424                 bool is_dup, uid_t uid, char **dev_node)
425 {
426         int ret = APP2EXT_SUCCESS;
427         char *passwd;
428         char dmcrypt_open_cmd[BUF_SIZE] = { 0, };
429         char dev_name[BUF_SIZE] = { 0, };
430         char buf[BUF_SIZE] = { 0, };
431         int len = 0;
432
433         if (pkgid == NULL || loopback_device == NULL) {
434                 _E("invalid argument");
435                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
436         }
437
438         if (is_dup)
439                 snprintf(dev_name, BUF_SIZE, "%s.new_%d", pkgid, uid);
440         else
441                 snprintf(dev_name, BUF_SIZE, "%s_%d", pkgid, uid);
442
443         /* get password for dmcrypt encryption */
444         ret = _app2sd_initialize_db();
445         if (ret) {
446                 _E("app2sd db initialize failed");
447                 return APP2EXT_ERROR_DB_INITIALIZE;
448         }
449
450         passwd = _app2sd_get_password_from_db(pkgid, uid);
451         if (passwd == NULL) {
452                 _E("no password found for [%s]", pkgid);
453                 return APP2EXT_ERROR_SQLITE_REGISTRY;
454         }
455
456         snprintf(dmcrypt_open_cmd, BUF_SIZE, "/bin/echo '%s' | /sbin/cryptsetup -q luksOpen %s %s",
457                 passwd, loopback_device, dev_name);
458         free(passwd);
459
460         ret = system(dmcrypt_open_cmd);
461         if (ret) {
462                 strerror_r(errno, buf, sizeof(buf));
463                 _E("error opening dmcrypt device, error: [%s]", buf);
464                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
465         }
466
467         snprintf(buf, BUF_SIZE, "/dev/mapper/%s", dev_name);
468         len = strlen(buf);
469         *dev_node = (char *)calloc(len + 1, sizeof(char));
470         if (*dev_node == NULL) {
471                 _E("memory alloc failed");
472                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
473         }
474         snprintf(*dev_node, len + 1, "%s", buf);
475
476         return ret;
477 }
478
479 int _app2sd_dmcrypt_close_device(const char *pkgid, uid_t uid)
480 {
481         int ret = APP2EXT_SUCCESS;
482         char dev_node[BUF_SIZE] = { '\0' };
483         char dmcrypt_close_cmd[BUF_SIZE] = { '\0' };
484         char err_buf[BUF_SIZE] = { '\0' };
485         char *t_dev_node = NULL;
486
487         if (pkgid == NULL) {
488                 _E("invalid argument\n");
489                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
490         }
491
492         t_dev_node = _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
493         if (!t_dev_node) {
494                 _E("no associated device node(%s_%d) found", pkgid, uid);
495                 return APP2EXT_ERROR_DMCRYPT_DEVICE_UNAVAILABLE;
496         }
497
498         free(t_dev_node);
499         t_dev_node = NULL;
500
501         snprintf(dev_node, BUF_SIZE, "/dev/mapper/%s_%d", pkgid, uid);
502         snprintf(dmcrypt_close_cmd, BUF_SIZE, "/sbin/cryptsetup -q luksClose %s", dev_node);
503         ret = system(dmcrypt_close_cmd);
504         if (ret) {
505                 strerror_r(errno, err_buf, sizeof(err_buf));
506                 _E("error closing dmcrypt on app2sd file,"\
507                         " error: [%s]", err_buf);
508                 return APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
509         }
510
511         return ret;
512 }
513
514 char *_app2sd_find_associated_dmcrypt_device_node(const char *pkgid, uid_t uid)
515 {
516         char *dev_node = NULL;
517         char buf[BUF_SIZE] = { 0, };
518         int len = 0;
519
520         snprintf(buf, BUF_SIZE, "/dev/mapper/%s_%d", pkgid, uid);
521         len = strlen(buf);
522         dev_node = (char *)calloc(len + 1, sizeof(char));
523         if (dev_node == NULL) {
524                 _E("memory alloc failed");
525                 return NULL;
526         }
527         snprintf(dev_node, len + 1, "%s", buf);
528
529         if (access(dev_node, F_OK) == 0) {
530                 _D("device_node: (%s)", dev_node);
531                 return dev_node;
532         }
533
534         free(dev_node);
535         dev_node = NULL;
536
537         return NULL;
538 }
539
540 char *_app2sd_dmcrypt_duplicate_encryption_setup(const char *pkgid,
541                 const char *temp_loopback_device, uid_t uid)
542 {
543         int ret = APP2EXT_SUCCESS;
544         char *device_node = NULL;
545
546         if (pkgid == NULL || temp_loopback_device == NULL) {
547                 _E("invalid argument\n");
548                 return NULL;
549         }
550
551         ret = _app2sd_dmcrypt_setup_device(pkgid, temp_loopback_device, true, uid);
552         if (ret) {
553                 _E("dmcrypt setup device error(%d)", ret);
554                 return NULL;
555         }
556
557         ret = _app2sd_dmcrypt_open_device(pkgid, temp_loopback_device, true,
558                 uid, &device_node);
559         if (ret) {
560                 _E("dmcrypt open device error");
561                 return NULL;
562         }
563
564         return device_node;
565 }
566 #endif
567
568 int _app2sd_create_loopback_device(const char *pkgid,
569                 const char *loopback_device, int size)
570 {
571         int ret = APP2EXT_SUCCESS;
572         char command[FILENAME_MAX] = { 0, };
573         char buff[BUF_SIZE] = { 0, };
574         FILE *fp = NULL;
575
576         if (NULL == pkgid || size <= 0) {
577                 _E("invalid argument");
578                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
579         }
580         snprintf(command, FILENAME_MAX - 1, "of=%s", loopback_device);
581         snprintf(buff, BUF_SIZE - 1, "count=%d", size);
582
583         const char *argv1[] = { "/bin/dd", "if=/dev/zero",
584                 command, "bs=1M", buff, NULL };
585
586         if ((fp = fopen(loopback_device, "r+")) != NULL) {
587                 _W("encrypted file already exists (%s)",
588                         loopback_device);
589                 fclose(fp);
590                 return APP2EXT_ERROR_PKG_EXISTS;
591         }
592
593         ret = _xsystem(argv1);
594         if (ret)
595                 _E("command (%s) failed, ret(%d), errno(%d)", command, ret, errno);
596
597         return ret;
598 }
599
600 int _app2sd_delete_loopback_device(const char *loopback_device)
601 {
602         int ret = APP2EXT_SUCCESS;
603
604         ret = unlink(loopback_device);
605         if (ret) {
606                 if (errno == ENOENT) {
607                         _W("unable to access file (%s)", loopback_device);
608                 } else {
609                         _E("unable to delete (%s)", loopback_device);
610                         return APP2EXT_ERROR_DELETE_LOOPBACK_DEVICE;
611                 }
612         }
613
614         return APP2EXT_SUCCESS;
615 }
616
617 int _app2sd_create_file_system(const char *device_path)
618 {
619         int ret = APP2EXT_SUCCESS;
620         FILE *fp = NULL;
621         char err_buf[1024] = {0,};
622
623         if (device_path == NULL) {
624                 _E("invalid param");
625                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
626         }
627
628         /* Format the filesystem [create a filesystem]*/
629         const char *argv[] = { "/sbin/mkfs.ext4", device_path, NULL };
630         fp = fopen(device_path, "r+");
631         if (fp == NULL) {
632                 strerror_r(errno, err_buf, sizeof(err_buf));
633                 _E("unable to access (%s) error is (%d, %s)",
634                      device_path, errno, err_buf);
635                 return APP2EXT_ERROR_ACCESS_FILE;
636         } else {
637                 fclose(fp);
638         }
639         ret = _xsystem(argv);
640         if (ret) {
641                 strerror_r(errno, err_buf, sizeof(err_buf));
642                 _E("creating file system failed, error is (%s)",
643                      err_buf);
644                 return APP2EXT_ERROR_CREATE_FS;
645         }
646         return ret;
647 }
648
649 static int _app2sd_create_dir_with_link(const char *application_path,
650                 const char *pkgid, const char *dir_name, uid_t uid)
651 {
652         int ret = APP2EXT_SUCCESS;
653         char application_dir_mmc_path[FILENAME_MAX] = { 0, };
654         char application_dir_path[FILENAME_MAX] = { 0, };
655
656         snprintf(application_dir_mmc_path, FILENAME_MAX - 1, "%s/.mmc/%s",
657                 application_path, dir_name);
658         snprintf(application_dir_path, FILENAME_MAX, "%s/%s",
659                 application_path, dir_name);
660
661         ret = _app2sd_make_directory(application_dir_mmc_path, uid);
662         if (ret) {
663                 _E("create directory failed");
664                 return APP2EXT_ERROR_CREATE_DIRECTORY;
665         }
666
667         if ((ret = symlink(application_dir_mmc_path,
668                 application_dir_path)) < 0) {
669                 if (errno == EEXIST) {
670                         _D("file with symlink name present (%s)",
671                                 application_dir_path);
672                 } else {
673                         _E("symbolic link creation "
674                                 "failed, error no is (%d)", errno);
675                         return APP2EXT_ERROR_CREATE_SYMLINK;
676                 }
677         }
678
679         return APP2EXT_SUCCESS;
680 }
681
682 static int _app2sd_create_directory_entry(const char *application_path,
683                 const char *pkgid, GList *dir_list, uid_t uid)
684 {
685         int ret = APP2EXT_SUCCESS;
686         GList *list = NULL;
687         app2ext_dir_details *dir_detail = NULL;
688
689         list = g_list_first(dir_list);
690         while (list) {
691                 dir_detail = (app2ext_dir_details *)list->data;
692                 if (dir_detail && dir_detail->name
693                         && dir_detail->type == APP2EXT_DIR_RO) {
694                         ret = _app2sd_create_dir_with_link(application_path,
695                                 pkgid, dir_detail->name, uid);
696                         if (ret)
697                                 return ret;
698                 }
699                 list = g_list_next(list);
700         }
701         return APP2EXT_SUCCESS;
702 }
703
704 int _app2sd_mount_app_content(const char *application_path, const char *pkgid,
705                 const char *dev, int mount_type, GList *dir_list,
706                 app2sd_cmd cmd, uid_t uid)
707 {
708         int ret = APP2EXT_SUCCESS;
709         int fd = -1;
710         char application_mmc_path[FILENAME_MAX] = { 0, };
711         char temp_path[FILENAME_MAX] = { 0, };
712         char err_buf[1024] = {0,};
713         struct timespec time = {
714                 .tv_sec = 0,
715                 .tv_nsec = 1000 * 1000 * 200
716         };
717
718         if (NULL == dev) {
719                 _E("input param is NULL (%s)",
720                              dev);
721                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
722         }
723
724         /* check directory existence */
725         fd = open(application_path, O_RDONLY|O_DIRECTORY);
726         if (fd < 0) {
727                 _E("path(%s) error(%d)", application_path, errno);
728                 return APP2EXT_ERROR_OPEN_DIR;
729         }
730         close(fd);
731
732         snprintf(application_mmc_path, FILENAME_MAX - 1, "%s/.mmc",
733                 application_path);
734         fd = open(application_mmc_path, O_RDONLY|O_DIRECTORY);
735         if (fd < 0) {
736                 _E("path(%s) error(%d)", application_mmc_path, errno);
737                 return APP2EXT_ERROR_OPEN_DIR;
738         }
739         close(fd);
740
741         nanosleep(&time, NULL); /* 200ms sleep */
742         _D("give a delay for mount");
743
744         switch (mount_type) {
745         case MOUNT_TYPE_RD:
746                 if ((ret = mount(dev, application_mmc_path, FS_TYPE,
747                         MS_MGC_VAL | MS_RDONLY | MS_NOSUID, NULL)) < 0) {
748                         _E("read only mount failed, " \
749                                 "errono is (%d), " \
750                                 "dev is (%s) path is (%s)",
751                                 errno, dev, application_mmc_path);
752                         ret = APP2EXT_ERROR_MOUNT;
753                 }
754                 break;
755         case MOUNT_TYPE_RW:
756                 if ((ret = mount(dev, application_mmc_path, FS_TYPE,
757                         MS_MGC_VAL | MS_NOSUID, NULL)) < 0) {
758                         _E("read write mount failed, " \
759                                 "errono is (%d)", errno);
760                         ret = APP2EXT_ERROR_MOUNT;
761                 }
762                 break;
763         case MOUNT_TYPE_RW_NOEXEC:
764                 if ((ret = mount(dev, application_mmc_path, FS_TYPE,
765                         MS_MGC_VAL | MS_NOEXEC | MS_NOSUID, NULL)) < 0) {
766                         _E("rwnx mount failed " \
767                                 "errono is (%d)", errno);
768                         ret = APP2EXT_ERROR_MOUNT;
769                 }
770                 break;
771         case MOUNT_TYPE_RD_REMOUNT:
772                 if ((ret = mount(dev, application_mmc_path, FS_TYPE,
773                         MS_MGC_VAL | MS_RDONLY | MS_REMOUNT | MS_NOSUID,
774                         NULL)) < 0) {
775                         _E("read remount failed "
776                                 "errono is (%d)", errno);
777                         ret = APP2EXT_ERROR_MOUNT;
778                 }
779                 break;
780         case MOUNT_TYPE_RW_REMOUNT:
781                 if ((ret = mount(dev, application_mmc_path, FS_TYPE,
782                         MS_MGC_VAL | MS_REMOUNT | MS_NOSUID, NULL)) < 0) {
783                         _E("read write remount failed "
784                                 "errono(%d), errstr(%s)", errno,
785                                 strerror_r(errno, err_buf, sizeof(err_buf)));
786                                 ret = APP2EXT_ERROR_MOUNT;
787                 }
788                 break;
789         default:
790                 _E("invalid mount type");
791                 break;
792         }
793
794         if (cmd == APP2SD_PRE_INSTALL || cmd == APP2SD_MOVE_APP_TO_MMC ||
795                 cmd == APP2SD_PRE_UPGRADE) {
796                 ret = _app2sd_create_directory_entry(application_path,
797                         pkgid, dir_list, uid);
798         }
799
800         if (mount_type != MOUNT_TYPE_RD &&
801                 mount_type != MOUNT_TYPE_RD_REMOUNT) {
802                 /* change lost+found permission */
803                 snprintf(temp_path, FILENAME_MAX - 1, "%s/lost+found",
804                                 application_mmc_path);
805                 ret = _app2sd_make_directory(temp_path, uid);
806                 if (ret) {
807                         _E("create directory(%s) failed", temp_path);
808                         return APP2EXT_ERROR_CREATE_DIRECTORY;
809                 }
810         }
811
812         return ret;
813 }
814
815 int _app2sd_unmount_app_content(const char *application_path)
816 {
817         int ret = APP2EXT_SUCCESS;
818         char application_dir_mmc_path[FILENAME_MAX] = { 0, };
819         char err_buf[1024] = {0,};
820
821         snprintf(application_dir_mmc_path, FILENAME_MAX - 1, "%s/.mmc",
822                 application_path);
823         if ((ret = umount(application_dir_mmc_path)) < 0) {
824                 strerror_r(errno, err_buf, sizeof(err_buf));
825                 _E("unable to umount the dir, ret(%d) error(%d, %s)",
826                         ret, errno, err_buf);
827         }
828
829         return ret;
830 }
831
832 static int _app2sd_move_to_archive(const char *src_path, const char *arch_path)
833 {
834         int ret = APP2EXT_SUCCESS;
835
836         ret = _app2sd_copy_dir(src_path, arch_path);
837         if (ret && ret != APP2EXT_ERROR_ACCESS_FILE) {
838                 char err_buf[1024] = {0,};
839                 strerror_r(errno, err_buf, sizeof(err_buf));
840                 _E("unable to copy from (%s) to (%s), err is (%s)",
841                         src_path, arch_path, err_buf);
842                 return APP2EXT_ERROR_MOVE;
843         }
844
845         ret = _app2sd_delete_directory((char *)src_path);
846         if (ret) {
847                 _E("unable to delete (%s)", src_path);
848                 return APP2EXT_ERROR_DELETE_DIRECTORY;
849         }
850
851         return ret;
852 }
853
854 static int _app2sd_move_app_to_external(const char *pkgid, GList *dir_list,
855                 uid_t uid, char *mmc_path)
856 {
857         int ret = APP2EXT_SUCCESS;
858         mode_t mode = DIR_PERMS;
859         char temp_dir_path[FILENAME_MAX] = { 0, };
860         char application_mmc_path[FILENAME_MAX] = { 0, };
861         char application_archive_path[FILENAME_MAX] = { 0, };
862         char application_path[FILENAME_MAX] = { 0, };
863         char loopback_device[FILENAME_MAX] = { 0, };
864         unsigned long long total_size = 0;
865         int reqd_size = 0;
866         int reqd_disk_size = 0;
867         char *device_node = NULL;
868 #if !defined(TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION)
869         char *devi = NULL;
870 #endif
871         int free_mmc_mem = 0;
872         FILE *fp = NULL;
873         GList *list = NULL;
874         app2ext_dir_details *dir_detail = NULL;
875         char err_buf[1024] = { 0,};
876         char *encoded_id = NULL;
877
878         encoded_id = _app2sd_get_encoded_name(pkgid, uid);
879         if (encoded_id == NULL)
880                 return APP2EXT_ERROR_MEMORY_ALLOC_FAILED;
881
882         snprintf(loopback_device, FILENAME_MAX - 1, "%s/%s/%s",
883                         mmc_path, EXTIMG_DIR, encoded_id);
884         free(encoded_id);
885         if (_is_global(uid)) {
886                 snprintf(application_path, FILENAME_MAX - 1, "%s/%s",
887                         tzplatform_getenv(TZ_SYS_RW_APP), pkgid);
888         } else {
889                 tzplatform_set_user(uid);
890                 snprintf(application_path, FILENAME_MAX - 1, "%s/%s",
891                         tzplatform_getenv(TZ_USER_APP), pkgid);
892                 tzplatform_reset_user();
893         }
894
895         /* check whether application is in external memory or not */
896         fp = fopen(loopback_device, "r+");
897         if (fp != NULL) {
898                 _W("Already %s entry is present in the SD Card, " \
899                         "delete entry and go on without return", pkgid);
900                 fclose(fp);
901                 _app2sd_force_clean(pkgid, application_path, loopback_device, uid);
902         }
903
904         snprintf(application_mmc_path, FILENAME_MAX - 1, "%s/.mmc",
905                 application_path);
906         snprintf(application_archive_path, FILENAME_MAX - 1, "%s/.archive",
907                 application_path);
908
909         ret = mkdir(application_mmc_path, mode);
910         if (ret) {
911                 if (errno != EEXIST) {
912                         _E("unable to create directory for archiving," \
913                                 " error(%d)", errno);
914                         return APP2EXT_ERROR_CREATE_DIRECTORY;
915                 }
916         }
917
918         ret = mkdir(application_archive_path, mode);
919         if (ret) {
920                 if (errno != EEXIST) {
921                         _E("unable to create directory for archiving," \
922                                 " error(%d)", errno);
923                         return APP2EXT_ERROR_CREATE_DIRECTORY;
924                 }
925         }
926
927         list = g_list_first(dir_list);
928         while (list) {
929                 dir_detail = (app2ext_dir_details *)list->data;
930                 if (dir_detail && dir_detail->name
931                         && dir_detail->type == APP2EXT_DIR_RO) {
932                         memset(temp_dir_path, '\0', FILENAME_MAX);
933                         snprintf(temp_dir_path, FILENAME_MAX,
934                                  "%s/%s", application_path,
935                                  dir_detail->name);
936                         _D("cal size of app dirs, temp_dir_path(%s)",
937                                 temp_dir_path);
938                         total_size +=
939                             _app2sd_calculate_dir_size(temp_dir_path);
940                 }
941                 list = g_list_next(list);
942         }
943
944         reqd_size = ((total_size) / (1024 * 1024)) + 2;
945         reqd_disk_size = reqd_size + ceil(reqd_size * 0.2);
946
947         /* find avialable free memory in the MMC card */
948         ret = _app2sd_get_available_free_memory(mmc_path, &free_mmc_mem);
949         if (ret) {
950                 _E("unable to get available free memory in MMC (%d)", ret);
951                 return APP2EXT_ERROR_MMC_STATUS;
952         }
953         /* if avaialalbe free memory in MMC is less than
954          * required size + 5MB, return error
955          */
956         if (reqd_disk_size > free_mmc_mem) {
957                 _E("insufficient memory in MMC for application installation (%d)",
958                         ret);
959                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
960         }
961         /* create a loopback device */
962         ret = _app2sd_create_loopback_device(pkgid, loopback_device,
963                 (reqd_disk_size + PKG_BUF_SIZE));
964         if (ret) {
965                 _E("loopback node creation failed");
966                 return ret;
967         }
968
969 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
970         ret = _app2sd_dmcrypt_setup_device(pkgid, loopback_device, false, uid);
971         if (ret) {
972                 _E("dmcrypt setup device error(%d)", ret);
973                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
974         }
975
976         ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device, false,
977                 uid, &device_node);
978         if (ret) {
979                 _E("dmcrypt open device error");
980                 return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
981         }
982 #else
983         /* perform loopback encryption setup */
984         device_node = _app2sd_do_loopback_encryption_setup(pkgid,
985                 loopback_device, uid);
986         if (!device_node) {
987                 _E("loopback encryption setup failed");
988                 return APP2EXT_ERROR_DO_LOSETUP;
989         }
990         _D("device_node (%s)", device_node);
991         /* check whether loopback device is associated with device node or not */
992         devi = _app2sd_find_associated_device_node(loopback_device);
993         if (devi == NULL) {
994                 _E("finding associated device node failed");
995                 ret = APP2EXT_ERROR_DO_LOSETUP;
996                 goto ERR;
997         } else {
998                 free(devi);
999                 devi = NULL;
1000         }
1001 #endif
1002         /* format the loopback file system */
1003         ret = _app2sd_create_file_system(device_node);
1004         if (ret) {
1005                 _E("create ext4 filesystem failed");
1006                 ret = APP2EXT_ERROR_CREATE_FS;
1007                 goto ERR;
1008         }
1009
1010         list = g_list_first(dir_list);
1011         while (list) {
1012                 dir_detail = (app2ext_dir_details *)list->data;
1013                 if (dir_detail && dir_detail->name
1014                         && dir_detail->type == APP2EXT_DIR_RO) {
1015                         memset(temp_dir_path, '\0', FILENAME_MAX);
1016                         snprintf(temp_dir_path, FILENAME_MAX,
1017                                  "%s/%s", application_path,
1018                                 dir_detail->name);
1019                         _D("app2archive, temp_dir_path(%s)",
1020                                 temp_dir_path);
1021                         ret = _app2sd_move_to_archive(temp_dir_path,
1022                                 application_archive_path);
1023                         if (ret) {
1024                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1025                                         _E("unable to access (%s)",
1026                                                 temp_dir_path);
1027                                 } else {
1028                                         _E("unable to copy from (%s) to (%s)",
1029                                              temp_dir_path,
1030                                              application_archive_path);
1031                                 }
1032                                 goto ERR;
1033                         }
1034                 }
1035                 list = g_list_next(list);
1036         }
1037
1038         /* mount the loopback encrypted pseudo device on application installation path
1039          * as with Read Write permission
1040          */
1041         ret = _app2sd_mount_app_content(application_path, pkgid, device_node,
1042                 MOUNT_TYPE_RW, dir_list, APP2SD_MOVE_APP_TO_MMC, uid);
1043         if (ret) {
1044                 _E("mount failed");
1045                 goto ERR;
1046         }
1047
1048         list = g_list_first(dir_list);
1049         while (list) {
1050                 dir_detail = (app2ext_dir_details *)list->data;
1051                 if (dir_detail && dir_detail->name
1052                         && dir_detail->type == APP2EXT_DIR_RO) {
1053                         memset(temp_dir_path, '\0', FILENAME_MAX);
1054                         snprintf(temp_dir_path, FILENAME_MAX,
1055                                 "%s/%s", application_archive_path,
1056                                 dir_detail->name);
1057                         _D("archive2mmc, temp_dir_path(%s)",
1058                                 temp_dir_path);
1059                         ret = _app2sd_copy_dir(temp_dir_path,
1060                                 application_mmc_path);
1061                         if (ret) {
1062                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1063                                         _E("unable to access (%s)",
1064                                                 temp_dir_path);
1065                                 } else {
1066                                         strerror_r(errno,
1067                                                 err_buf, sizeof(err_buf));
1068                                         _E("unable to copy from (%s) to (%s)," \
1069                                                 " error is (%s)",
1070                                                 temp_dir_path,
1071                                                 application_mmc_path, err_buf);
1072                                 }
1073                                 goto ERR;
1074                         }
1075                         ret = _app2sd_delete_directory(temp_dir_path);
1076                         if (ret) {
1077                                 _E("unable to delete (%s)", temp_dir_path);
1078                                 goto ERR;
1079                         }
1080                 }
1081                 list = g_list_next(list);
1082         }
1083
1084         ret = _app2sd_delete_directory(application_archive_path);
1085         if (ret) {
1086                 _E("unable to delete (%s)", application_archive_path);
1087                 ret = APP2EXT_ERROR_DELETE_DIRECTORY;
1088                 goto ERR;
1089         }
1090
1091         return APP2EXT_SUCCESS;
1092
1093 ERR:
1094         if (device_node) {
1095                 free(device_node);
1096                 device_node = NULL;
1097         }
1098
1099         return ret;
1100 }
1101
1102 static int _app2sd_move_app_to_internal(const char *pkgid, GList *dir_list,
1103                 uid_t uid, char *mmc_path)
1104 {
1105         int ret = APP2EXT_SUCCESS;
1106         mode_t mode = DIR_PERMS;
1107         char temp_dir_path[FILENAME_MAX] = { 0, };
1108         char application_mmc_path[FILENAME_MAX] = { 0, };
1109         char application_archive_path[FILENAME_MAX] = { 0, };
1110         char application_path[FILENAME_MAX] = { 0, };
1111         char loopback_device[FILENAME_MAX] = { 0, };
1112         char *device_node = NULL;
1113         FILE *fp = NULL;
1114         GList *list = NULL;
1115         app2ext_dir_details *dir_detail = NULL;
1116         int reqd_size = 0;
1117         int free_internal_mem = 0;
1118         struct statvfs buf = {0,};
1119         unsigned long long temp = 0;
1120         char err_buf[1024] = {0,};
1121         char *encoded_id = NULL;
1122
1123         encoded_id = _app2sd_get_encoded_name(pkgid, uid);
1124         if (encoded_id == NULL)
1125                 return APP2EXT_ERROR_MEMORY_ALLOC_FAILED;
1126
1127         snprintf(loopback_device, FILENAME_MAX - 1, "%s/%s/%s",
1128                         mmc_path, EXTIMG_DIR, encoded_id);
1129         free(encoded_id);
1130         if (_is_global(uid)) {
1131                 snprintf(application_path, FILENAME_MAX - 1, "%s/%s",
1132                         tzplatform_getenv(TZ_SYS_RW_APP), pkgid);
1133         } else {
1134                 tzplatform_set_user(uid);
1135                 snprintf(application_path, FILENAME_MAX - 1, "%s/%s",
1136                         tzplatform_getenv(TZ_USER_APP), pkgid);
1137                 tzplatform_reset_user();
1138         }
1139
1140         /* check whether application is in external memory or not */
1141         fp = fopen(loopback_device, "r+");
1142         if (fp == NULL) {
1143                 _E("application (%s) is not installed on SD Card",
1144                      pkgid);
1145                 return APP2EXT_ERROR_FILE_ABSENT;
1146         } else {
1147                 fclose(fp);
1148                 fp = NULL;
1149         }
1150
1151         memset((void *)&buf, '\0', sizeof(struct statvfs));
1152         ret = statvfs(INTERNAL_STORAGE_PATH, &buf);
1153         if (0 == ret) {
1154                 temp = (buf.f_bsize * buf.f_bavail) / (1024 * 1024);
1155                 free_internal_mem = (int)temp;
1156         } else {
1157                 _E("unable to get internal storage size");
1158                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
1159         }
1160
1161         fp = fopen(loopback_device, "r+");
1162         if (fp == NULL) {
1163                 _E("app entry is not present in SD card");
1164                 return APP2EXT_ERROR_INVALID_PACKAGE;
1165         }
1166         fclose(fp);
1167
1168         /* get installed app size*/
1169         temp = _app2sd_calculate_file_size(loopback_device);
1170         reqd_size = (int)((temp) / (1024 * 1024));
1171         _D("reqd size is (%d)", reqd_size);
1172
1173         if (reqd_size == 0) {
1174                 _E("app entry is not present in SD Card");
1175                 return APP2EXT_ERROR_LOOPBACK_DEVICE_UNAVAILABLE;
1176         }
1177
1178         _D("reqd size: (%d)MB, free internal mem: (%d)MB",
1179                 reqd_size, free_internal_mem);
1180
1181         /* if avaialalbe free memory in internal storage is
1182          * less than required size, return error
1183          */
1184         if (reqd_size > free_internal_mem) {
1185                 _E("innsufficient memory in internal storage" \
1186                         " for application installation (%d)", ret);
1187                 return APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY;
1188         }
1189
1190 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1191         device_node =
1192                 _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
1193 #else
1194         device_node = _app2sd_find_associated_device_node(loopback_device);
1195 #endif
1196         if (NULL == device_node) {
1197                 /* do loopback setup */
1198 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1199                 ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device,
1200                         false, uid, &device_node);
1201                 if (ret) {
1202                         _E("dmcrypt open device error(%d)", ret);
1203                         return APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
1204                 }
1205 #else
1206                 device_node = _app2sd_do_loopback_encryption_setup(pkgid,
1207                         loopback_device, uid);
1208                 if (device_node == NULL) {
1209                         _E("loopback encryption setup failed");
1210                         return APP2EXT_ERROR_DO_LOSETUP;
1211                 }
1212 #endif
1213                 /* do mounting */
1214                 ret = _app2sd_mount_app_content(application_path,
1215                         pkgid, device_node, MOUNT_TYPE_RW,
1216                         dir_list, APP2SD_MOVE_APP_TO_PHONE, uid);
1217                 if (ret) {
1218                         _E("mount failed");
1219                         ret = APP2EXT_ERROR_MOUNT_PATH;
1220                         goto ERR;
1221                 }
1222         } else {
1223                 /* do re-mounting */
1224                 ret = _app2sd_mount_app_content(application_path,
1225                         pkgid, device_node, MOUNT_TYPE_RW_REMOUNT,
1226                         dir_list, APP2SD_MOVE_APP_TO_PHONE, uid);
1227                 if (ret) {
1228                         _E("re-mount failed");
1229                         ret = APP2EXT_ERROR_MOUNT_PATH;
1230                         goto ERR;
1231                 }
1232         }
1233
1234         snprintf(application_mmc_path, FILENAME_MAX - 1, "%s/.mmc",
1235                 application_path);
1236         snprintf(application_archive_path, FILENAME_MAX - 1, "%s/.archive",
1237                 application_path);
1238
1239         ret = mkdir(application_archive_path, mode);
1240         if (ret) {
1241                 if (errno != EEXIST) {
1242                         _E("unable to create directory for archiving," \
1243                                 " error(%d)", errno);
1244                         ret = APP2EXT_ERROR_CREATE_DIRECTORY;
1245                         goto ERR;
1246                 }
1247         }
1248
1249         list = g_list_first(dir_list);
1250         while (list) {
1251                 dir_detail = (app2ext_dir_details *)list->data;
1252                 if (dir_detail && dir_detail->name
1253                         && dir_detail->type == APP2EXT_DIR_RO) {
1254                         /* archiving code */
1255                         memset(temp_dir_path, '\0', FILENAME_MAX);
1256                         snprintf(temp_dir_path, FILENAME_MAX,
1257                                  "%s/%s", application_mmc_path,
1258                                  dir_detail->name);
1259                         _D("mmc2archive, temp_dir_path(%s)", temp_dir_path);
1260                         ret = _app2sd_copy_dir(temp_dir_path,
1261                                      application_archive_path);
1262                         if (ret) {
1263                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1264                                         _E("unable to access (%s)",
1265                                                 temp_dir_path);
1266                                 } else {
1267                                         strerror_r(errno,
1268                                                 err_buf, sizeof(err_buf));
1269                                         _E("unable to copy from (%s) to (%s),"
1270                                                 " error is (%s)",
1271                                                 temp_dir_path,
1272                                                 application_archive_path, err_buf);
1273                                 }
1274                                 goto ERR;
1275                         }
1276
1277                         /* delete the symbolic link files [bin, lib, res]*/
1278                         memset(temp_dir_path, '\0', FILENAME_MAX);
1279                         snprintf(temp_dir_path, FILENAME_MAX,
1280                                  "%s/%s", application_path,
1281                                  dir_detail->name);
1282                         _D("unlink, temp_dir_path(%s)", temp_dir_path);
1283                         ret = unlink(temp_dir_path);
1284                         if (ret) {
1285                                 if (errno == ENOENT) {
1286                                         _W("directory (%s) does not exist",
1287                                                 temp_dir_path);
1288                                 } else {
1289                                         _E("unable to remove the symbolic link file (%s)," \
1290                                                 " it is already unlinked",
1291                                                 temp_dir_path);
1292                                         goto ERR;
1293                                 }
1294                         }
1295
1296                         /* Copy content to destination */
1297                         memset(temp_dir_path, '\0', FILENAME_MAX);
1298                         snprintf(temp_dir_path, FILENAME_MAX,
1299                                 "%s/%s", application_archive_path,
1300                                 dir_detail->name);
1301                         _D("archive2app, temp_dir_path(%s)", temp_dir_path);
1302                         ret = _app2sd_copy_dir(temp_dir_path, application_path);
1303                         if (ret) {
1304                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1305                                         _E("unable to access (%s)",
1306                                                 temp_dir_path);
1307                                 } else {
1308                                         strerror_r(errno,
1309                                                 err_buf, sizeof(err_buf));
1310                                         _E("unable to copy from (%s) to (%s) " \
1311                                                 ", error is (%s)",
1312                                                 temp_dir_path,
1313                                                 application_path, err_buf);
1314                                 }
1315                                 goto ERR;
1316                         }
1317                 }
1318                 list = g_list_next(list);
1319         }
1320
1321         _D("copying file completed");
1322         ret = _app2sd_unmount_app_content(application_path);
1323         if (ret)
1324                 _E("unable to unmount SD directory for app (%s)",
1325                      pkgid);
1326
1327 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1328         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1329         if (ret)
1330                 _E("close dmcrypt device error(%d)", ret);
1331 #else
1332         ret = _app2sd_remove_loopback_encryption_setup(loopback_device);
1333         if (ret)
1334                 _E("unable to detach loopback setup for (%s)",
1335                      pkgid);
1336 #endif
1337
1338         ret = _app2sd_delete_loopback_device(loopback_device);
1339         if (ret)
1340                 _E("unable to delete the loopback device for (%s)",
1341                      pkgid);
1342
1343         ret = _app2sd_delete_directory(application_mmc_path);
1344         if (ret)
1345                 _E("unable to delete (%s)", application_mmc_path);
1346
1347         ret = _app2sd_delete_directory(application_archive_path);
1348         if (ret)
1349                 _E("unable to delete (%s)", application_archive_path);
1350
1351         /* remove passwrd from DB */
1352         ret = _app2sd_initialize_db();
1353         if (ret)
1354                 _E("app2sd db initialize failed");
1355
1356         ret = _app2sd_remove_info_from_db(pkgid, uid);
1357         if (ret)
1358                 _E("cannot remove info from db");
1359
1360         return APP2EXT_SUCCESS;
1361
1362 ERR:
1363         if (device_node) {
1364                 free(device_node);
1365                 device_node = NULL;
1366         }
1367
1368         return ret;
1369 }
1370
1371 int _app2sd_usr_move_app(const char *pkgid, app2ext_move_type move_type,
1372                 GList *dir_list, uid_t uid, char *mmc_path)
1373 {
1374         int ret = APP2EXT_SUCCESS;
1375
1376         switch (move_type) {
1377         case APP2EXT_MOVE_TO_EXT:
1378                 ret = _app2sd_move_app_to_external(pkgid, dir_list,
1379                         uid, mmc_path);
1380                 if (ret) {
1381                         _E("move app to external memory failed(%d)", ret);
1382                         return ret;
1383                 }
1384                 break;
1385         case APP2EXT_MOVE_TO_PHONE:
1386                 ret = _app2sd_move_app_to_internal(pkgid, dir_list,
1387                         uid, mmc_path);
1388                 if (ret) {
1389                         _E("move app to internal memory failed(%d)", ret);
1390                         return ret;
1391                 }
1392                 break;
1393         default:
1394                 _E("invalid argument");
1395                 return APP2EXT_ERROR_INVALID_ARGUMENTS;
1396         }
1397
1398         return ret;
1399 }
1400
1401 int _app2sd_copy_ro_content(const char *src, const char *dest, GList *dir_list)
1402 {
1403         char path[FILENAME_MAX] = { 0, };
1404         int ret = APP2EXT_SUCCESS;
1405         GList *list = NULL;
1406         app2ext_dir_details *dir_detail = NULL;
1407
1408         list = g_list_first(dir_list);
1409         while (list) {
1410                 dir_detail = (app2ext_dir_details *)list->data;
1411                 if (dir_detail && dir_detail->name
1412                         && dir_detail->type == APP2EXT_DIR_RO) {
1413                         memset((void *)&path, '\0', FILENAME_MAX);
1414                         snprintf(path, FILENAME_MAX - 1, "%s/%s", src,
1415                                  dir_detail->name);
1416                         ret = _app2sd_copy_dir(path, dest);
1417                         if (ret) {
1418                                 if (ret == APP2EXT_ERROR_ACCESS_FILE) {
1419                                         _E("unable to access (%s)", path);
1420                                 } else {
1421                                         _E("unable to copy from (%s) " \
1422                                                 "to (%s), errno is (%d)",
1423                                                 path, dest, errno);
1424                                         return APP2EXT_ERROR_MOVE;
1425                                 }
1426                         }
1427                 }
1428                 list = g_list_next(list);
1429         }
1430
1431         return APP2EXT_SUCCESS;
1432 }
1433
1434 int _app2sd_duplicate_device(const char *pkgid,
1435                 const char *loopback_device,
1436                 const char *temp_pkgid,
1437                 const char *temp_application_path,
1438                 const char *temp_loopback_device,
1439                 GList *dir_list, char *dev_node, int size,
1440                 uid_t uid)
1441 {
1442         int ret = 0;
1443         int err_res = 0;
1444 #if !defined(TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION)
1445         char *devi = NULL;
1446         char *result = NULL;
1447         char *passwd = NULL;
1448 #endif
1449
1450         /* create a new loopback device */
1451         ret = _app2sd_create_loopback_device(temp_pkgid,
1452                 temp_loopback_device, (size + PKG_BUF_SIZE));
1453         if (ret) {
1454                 _E("package already present");
1455                 return ret;
1456         }
1457
1458         /* perform loopback encryption setup */
1459 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1460         dev_node = _app2sd_dmcrypt_duplicate_encryption_setup(pkgid,
1461                 temp_loopback_device, uid);
1462         if (!dev_node) {
1463                 _E("dmcrypt duplicate encryption setup failed");
1464                 _app2sd_delete_loopback_device(temp_loopback_device);
1465                 return APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE;
1466         }
1467 #else
1468         /* get password for loopback encryption */
1469         ret = _app2sd_initialize_db();
1470         if (ret) {
1471                 _E("app2sd db initialize failed");
1472                 return APP2EXT_ERROR_DB_INITIALIZE;
1473         }
1474
1475         if ((passwd = _app2sd_get_password_from_db(pkgid, uid)) == NULL) {
1476                 passwd = (char *)_app2sd_generate_password(pkgid);
1477                 if (NULL == passwd) {
1478                         _E("unable to generate password");
1479                         return APP2EXT_ERROR_PASSWD_GENERATION;
1480                 } else {
1481                         if ((ret = _app2sd_set_info_in_db(pkgid,
1482                                 passwd, loopback_device, uid)) < 0) {
1483                                 _E("unable to save info");
1484                                 free(passwd);
1485                                 passwd = NULL;
1486                                 return APP2EXT_ERROR_SQLITE_REGISTRY;
1487                         }
1488                 }
1489         }
1490
1491         dev_node = _app2sd_do_loopback_duplicate_encryption_setup(pkgid,
1492                 temp_pkgid, temp_loopback_device, passwd, uid);
1493         if (!dev_node) {
1494                 _E("losetup failed, device node is (%s)", dev_node);
1495                 _app2sd_delete_loopback_device(temp_loopback_device);
1496                 free(passwd);
1497                 passwd = NULL;
1498                 return APP2EXT_ERROR_DO_LOSETUP;
1499         }
1500         free(passwd);
1501         passwd = NULL;
1502         _D("duplicate setup SUCCESS");
1503
1504         /* check whether loopback device is associated with
1505          * device node or not
1506          */
1507         devi = _app2sd_find_associated_device_node(temp_loopback_device);
1508         if (devi == NULL) {
1509                 _E("finding associated device node failed");
1510                 err_res = APP2EXT_ERROR_DO_LOSETUP;
1511                 goto FINISH_OFF;
1512         }
1513         _D("losetup SUCCESS");
1514 #endif
1515
1516         /* format the loopback file system */
1517         ret = _app2sd_create_file_system(dev_node);
1518         if (ret) {
1519                 _E("creating fs failed");
1520                 err_res = APP2EXT_ERROR_CREATE_FS;
1521                 goto FINISH_OFF;
1522         }
1523         _D("create filesystem SUCCESS");
1524
1525         /* do mounting for new dev*/
1526         ret = _app2sd_mount_app_content(temp_application_path, pkgid,
1527                 dev_node, MOUNT_TYPE_RW, dir_list,
1528                 APP2SD_PRE_UPGRADE, uid);
1529         if (ret) {
1530                 _E("remount failed");
1531                 err_res = APP2EXT_ERROR_MOUNT_PATH;
1532                 goto FINISH_OFF;
1533         }
1534
1535 #if !defined(TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION)
1536         if (devi) {
1537                 free(devi);
1538                 devi = NULL;
1539         }
1540 #endif
1541
1542         return APP2EXT_SUCCESS;
1543
1544 FINISH_OFF:
1545         if (dev_node) {
1546 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1547                 ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1548                 if (ret)
1549                         _E("close dmcrypt device error(%d)", ret);
1550 #else
1551                 result = _app2sd_detach_loop_device(dev_node);
1552                 if (result) {
1553                         free(result);
1554                         result = NULL;
1555                 }
1556 #endif
1557                 _app2sd_delete_loopback_device(temp_loopback_device);
1558                 free(dev_node);
1559                 dev_node = NULL;
1560         }
1561
1562         return err_res;
1563 }
1564
1565 int _app2sd_update_loopback_device_size(const char *pkgid,
1566                 const char *loopback_device,
1567                 const char *application_path,
1568                 const char *temp_pkgid,
1569                 const char *temp_loopback_device,
1570                 const char *temp_application_path,
1571                 int size, GList *dir_list,
1572                 uid_t uid)
1573 {
1574         int ret = 0;
1575         char *device_node = NULL;
1576         char *old_device_node = NULL;
1577         int err_res = 0;
1578         char application_mmc_path[FILENAME_MAX] = { 0, };
1579         char temp_application_mmc_path[FILENAME_MAX] = { 0, };
1580
1581         ret = _app2sd_duplicate_device(pkgid, loopback_device,
1582                 temp_pkgid, temp_application_path, temp_loopback_device,
1583                 dir_list, device_node, size, uid);
1584         if (ret) {
1585                 _E("creating duplicate device failed");
1586                 return ret;
1587         }
1588
1589         /* get the associated device node for SD card applicatione */
1590 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1591         old_device_node =
1592                 _app2sd_find_associated_dmcrypt_device_node(pkgid, uid);
1593 #else
1594         old_device_node = _app2sd_find_associated_device_node(loopback_device);
1595 #endif
1596         if (NULL == old_device_node) {
1597                 /* do loopback setup */
1598 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1599                 ret = _app2sd_dmcrypt_open_device(pkgid, loopback_device,
1600                         false, uid, &old_device_node);
1601                 if (ret) {
1602                         _E("dmcrypt open device error");
1603                         err_res = APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE;
1604                         goto FINISH_OFF;
1605                 }
1606 #else
1607                 old_device_node = _app2sd_do_loopback_encryption_setup(pkgid,
1608                         loopback_device, uid);
1609                 if (old_device_node == NULL) {
1610                         _E("loopback encryption setup failed");
1611                         err_res = APP2EXT_ERROR_DO_LOSETUP;
1612                         goto FINISH_OFF;
1613                 }
1614 #endif
1615                 /* do mounting */
1616                 ret = _app2sd_mount_app_content(application_path, pkgid,
1617                         old_device_node, MOUNT_TYPE_RW, dir_list,
1618                         APP2SD_PRE_UPGRADE, uid);
1619                 if (ret) {
1620                         _E("remount failed");
1621                         err_res = APP2EXT_ERROR_MOUNT_PATH;
1622                 }
1623         } else {
1624                 /* do re-mounting */
1625                 ret = _app2sd_mount_app_content(application_path, pkgid,
1626                         old_device_node, MOUNT_TYPE_RW_REMOUNT, dir_list,
1627                         APP2SD_PRE_UPGRADE, uid);
1628                 if (ret) {
1629                         _E("remount failed");
1630                         err_res = APP2EXT_ERROR_MOUNT_PATH;
1631                 }
1632         }
1633
1634         snprintf(application_mmc_path, FILENAME_MAX - 1,
1635                  "%s/.mmc", application_path);
1636         snprintf(temp_application_mmc_path, FILENAME_MAX - 1,
1637                 "%s/.mmc", temp_application_path);
1638
1639         ret = _app2sd_copy_ro_content(application_mmc_path,
1640                 temp_application_mmc_path, dir_list);
1641         if (ret) {
1642                 _E("copy ro content failed");
1643                 err_res = ret;
1644         }
1645
1646         ret = _app2sd_unmount_app_content(application_path);
1647         if (ret) {
1648                 _E("unable to unmount the SD application");
1649                 err_res = APP2EXT_ERROR_UNMOUNT;
1650         }
1651
1652         ret = _app2sd_unmount_app_content(temp_application_path);
1653         if (ret) {
1654                 _E("unable to unmount the SD application");
1655                 err_res = APP2EXT_ERROR_UNMOUNT;
1656                 goto FINISH_OFF;
1657         }
1658
1659 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1660         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1661         if (ret) {
1662                 _E("close dmcrypt device error(%d)", ret);
1663                 err_res = APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
1664                 goto FINISH_OFF;
1665         }
1666
1667         ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1668         if (ret) {
1669                 _E("close dmcrypt device error(%d)", ret);
1670                 err_res = APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE;
1671                 goto FINISH_OFF;
1672         }
1673 #else
1674         ret = _app2sd_remove_loopback_encryption_setup(loopback_device);
1675         if (ret) {
1676                 _E("unable to remove loopback setup");
1677                 err_res = APP2EXT_ERROR_DELETE_LOOPBACK_DEVICE;
1678         }
1679
1680         ret = _app2sd_remove_loopback_encryption_setup(temp_loopback_device);
1681         if (ret) {
1682                 _E("unable to remove loopback setup");
1683                 err_res = APP2EXT_ERROR_DELETE_LOOPBACK_DEVICE;
1684                 goto FINISH_OFF;
1685         }
1686 #endif
1687
1688         ret = _app2sd_delete_directory(loopback_device);
1689         if (ret) {
1690                 _E("unable to delete (%s)", loopback_device);
1691                 err_res = APP2EXT_ERROR_DELETE_DIRECTORY;
1692                 goto FINISH_OFF;
1693         }
1694
1695         ret = _app2sd_rename_dir(temp_loopback_device, loopback_device);
1696         if (ret) {
1697                 _E("unable to rename (%s)", temp_loopback_device);
1698                 err_res = APP2EXT_ERROR_MOVE;
1699                 goto FINISH_OFF;
1700         }
1701
1702         ret = _app2sd_delete_directory(temp_application_path);
1703         if (ret) {
1704                 _E("unable to delete (%s)", temp_application_path);
1705                 err_res = APP2EXT_ERROR_DELETE_DIRECTORY;
1706                 goto FINISH_OFF;
1707         }
1708
1709         return APP2EXT_SUCCESS;
1710
1711 FINISH_OFF:
1712         if (old_device_node) {
1713                 free(old_device_node);
1714                 old_device_node = NULL;
1715         }
1716
1717 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1718         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1719         if (ret)
1720                 _E("close dmcrypt device error(%d)", ret);
1721
1722         ret = _app2sd_dmcrypt_close_device(temp_pkgid, uid);
1723
1724         if (ret)
1725                 _E("close dmcrypt device error(%d)", ret);
1726 #else
1727         ret = _app2sd_remove_loopback_encryption_setup(loopback_device);
1728         if (ret)
1729                 _E("unable to remove loopback setup");
1730
1731         ret = _app2sd_remove_loopback_encryption_setup(temp_loopback_device);
1732         if (ret)
1733                 _E("unable to remove loopback setup");
1734 #endif
1735
1736         _app2sd_delete_loopback_device(temp_loopback_device);
1737
1738         ret = _app2sd_delete_directory(temp_application_path);
1739         if (ret)
1740                 _E("unable to delete (%s)", temp_application_path);
1741
1742         return err_res;
1743 }
1744
1745 int _app2sd_force_clean(const char *pkgid, const char *application_path,
1746                 const char *loopback_device, uid_t uid)
1747 {
1748         int ret = APP2EXT_SUCCESS;
1749
1750         /* unmount the loopback encrypted pseudo device from the application installation path */
1751         ret = _app2sd_unmount_app_content(application_path);
1752         if (ret)
1753                 _E("unable to unmount the app content (%d)", ret);
1754
1755         /* detach the loopback encryption setup for the application */
1756 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
1757         ret = _app2sd_dmcrypt_close_device(pkgid, uid);
1758         if (ret)
1759                 _E("close dmcrypt device error (%d)", ret);
1760 #else
1761         ret = _app2sd_remove_all_loopback_encryption_setups(loopback_device);
1762         if (ret)
1763                 _E("unable to detach the loopback encryption setup for the application");
1764 #endif
1765
1766         /* delete the loopback device from the SD card */
1767         ret = _app2sd_delete_loopback_device(loopback_device);
1768         if (ret)
1769                 _E("unable to detach the loopback encryption setup for the application");
1770
1771         /* delete symlink */
1772         _app2sd_delete_symlink(application_path);
1773
1774         /* remove passwrd from DB */
1775         ret = _app2sd_initialize_db();
1776         if (ret)
1777                 _E("app2sd db initialize failed");
1778
1779         ret = _app2sd_remove_info_from_db(pkgid, uid);
1780         if (ret)
1781                 _E("cannot remove info from db");
1782
1783
1784         return ret;
1785 }