Change internal storage media path returned from storage_get_directory()
[platform/core/system/libstorage.git] / src / storage.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <vconf.h>
23 #include <tzplatform_config.h>
24
25 #include "common.h"
26 #include "list.h"
27 #include "log.h"
28 #include "storage-external.h"
29
30 #define USER_UID_START          5000
31
32 const char *dir_path[STORAGE_DIRECTORY_MAX];
33
34 const int tz_id[STORAGE_DIRECTORY_MAX] = {
35         [STORAGE_DIRECTORY_IMAGES] = TZ_USER_IMAGES,
36         [STORAGE_DIRECTORY_SOUNDS] = TZ_USER_SOUNDS,
37         [STORAGE_DIRECTORY_VIDEOS] = TZ_USER_VIDEOS,
38         [STORAGE_DIRECTORY_CAMERA] = TZ_USER_CAMERA,
39         [STORAGE_DIRECTORY_DOWNLOADS] = TZ_USER_DOWNLOADS,
40         [STORAGE_DIRECTORY_MUSIC] = TZ_USER_MUSIC,
41         [STORAGE_DIRECTORY_DOCUMENTS] = TZ_USER_DOCUMENTS,
42         [STORAGE_DIRECTORY_OTHERS] = TZ_USER_OTHERS,
43 };
44
45 static dd_list *st_int_head; /* Internal storage list */
46
47 static dd_list *compat_cb_list;
48 struct compat_cb_info {
49         storage_state_changed_cb user_cb;
50         void *user_data;
51 };
52
53 void add_device(const struct storage_ops *st)
54 {
55         DD_LIST_APPEND(st_int_head, st);
56 }
57
58 void remove_device(const struct storage_ops *st)
59 {
60         DD_LIST_REMOVE(st_int_head, st);
61 }
62
63 API int storage_foreach_device_supported(storage_device_supported_cb callback, void *user_data)
64 {
65         const struct storage_ops *st;
66         dd_list *elem;
67         int ret;
68         bool user = true;
69
70         if (!callback) {
71                 _E("Invalid parameter");
72                 return STORAGE_ERROR_INVALID_PARAMETER;
73         }
74
75         if (getuid() <= USER_UID_START)
76                 user = false;
77
78         DD_LIST_FOREACH(st_int_head, elem, st) {
79                 if (user) {
80                         ret = callback(st->storage_id, st->type, st->get_state(),
81                                         st->root(), user_data);
82                         /* if the return value is false, will be stop to iterate */
83                         if (!ret)
84                                 break;
85                 }
86         }
87
88         if (!storage_ext_is_supported()) {
89                 _D("Block module is not enabled");
90                 return STORAGE_ERROR_NONE;
91         }
92
93         ret = storage_ext_foreach_device_list(callback, user_data);
94         if (ret < 0) {
95                 _E("Failed to iterate external devices (%d)", ret); //LCOV_EXCL_LINE
96                 return STORAGE_ERROR_OPERATION_FAILED;
97         }
98
99         return STORAGE_ERROR_NONE;
100 }
101
102 API int storage_get_root_directory(int storage_id, char **path)
103 {
104         const struct storage_ops *st;
105         dd_list *elem;
106         char root[PATH_MAX];
107         int ret;
108         bool extendedint;
109         bool user = true;
110
111         if (storage_id < 0)
112                 return STORAGE_ERROR_NOT_SUPPORTED;
113
114         if (!path) {
115                 _E("Invalid parameger");
116                 return STORAGE_ERROR_INVALID_PARAMETER;
117         }
118
119         if (getuid() <= USER_UID_START)
120                 user = false;
121
122         /* internal storage */
123         DD_LIST_FOREACH(st_int_head, elem, st) {
124                 if (st->storage_id != storage_id)
125                         continue;
126                 if (!user) {
127                         _E("Only Tizen applications and user session daemons can use\
128                                 storage_get_root_directory(INTERNAL_STORAGE_ID, ...)");
129                         return STORAGE_ERROR_INVALID_PARAMETER;
130                 }
131
132                 *path = strdup(st->root());
133                 if (!*path) {
134 //LCOV_EXCL_START System Error
135                         _E("Failed to copy the root string : %d", errno);
136                         return STORAGE_ERROR_OUT_OF_MEMORY;
137 //LCOV_EXCL_STOP
138                 }
139                 return STORAGE_ERROR_NONE;
140         }
141
142         /* external storage */
143         ret = storage_ext_get_root(storage_id, root, sizeof(root), &extendedint);
144         if (ret < 0) {
145                 _E("Failed to get root path of external storage(%d, %d", storage_id, ret); //LCOV_EXCL_LINE
146                 return STORAGE_ERROR_INVALID_PARAMETER;
147         }
148
149         *path = strdup(root);
150         if (!*path) {
151                 _E("Failed to copy the root string : %d", errno); //LCOV_EXCL_LINE System Error
152                 return STORAGE_ERROR_OUT_OF_MEMORY;
153         }
154
155         return STORAGE_ERROR_NONE;
156 }
157
158 API int storage_get_directory(int storage_id, storage_directory_e type, char **path)
159 {
160         const struct storage_ops *st;
161         char root[PATH_MAX];
162         char temp[PATH_MAX];
163         char *temp2, *end;
164         int ret;
165         dd_list *elem;
166         bool found;
167         bool extendedint;
168         bool user = true;
169
170         if (storage_id < 0)
171                 return STORAGE_ERROR_NOT_SUPPORTED;
172
173         if (!path) {
174                 _E("Invalid parameger");
175                 return STORAGE_ERROR_INVALID_PARAMETER;
176         }
177
178         if (type < 0 || type >= STORAGE_DIRECTORY_MAX) {
179                 _E("Invalid parameter");
180                 return STORAGE_ERROR_INVALID_PARAMETER;
181         }
182
183         /* internal storage */
184         found = false;
185         DD_LIST_FOREACH(st_int_head, elem, st) {
186                 if (st->storage_id != storage_id)
187                         continue;
188                 found = true;
189                 break;
190         }
191
192         if (getuid() <= USER_UID_START)
193                 user = false;
194
195         if (found && st) {
196                 if (!user) {
197                         _E("Only Tizen applications and user session daemons can use\
198                                 storage_get_directory(INTERNAL_STORAGE_ID, ...)");
199                         return STORAGE_ERROR_INVALID_PARAMETER;
200                 }
201
202                 snprintf(root, sizeof(root), "%s", st->root());
203                 if (type == STORAGE_DIRECTORY_SYSTEM_RINGTONES) {
204                         temp2 = vconf_get_str(VCONFKEY_SETAPPL_CALL_RINGTONE_PATH_STR);
205                         if (temp2 == NULL)
206                                 return STORAGE_ERROR_OPERATION_FAILED;
207                         end = strrchr(temp2, '/');
208                         if (end)
209                                 *end = '\0';
210                         snprintf(temp, PATH_MAX, "%s", temp2);
211                         free(temp2);
212                 } else
213                         snprintf(temp, PATH_MAX, "%s/%s", root, dir_path[type]);
214
215                 goto out;
216         }
217
218         /* external storage */
219         if (type == STORAGE_DIRECTORY_SYSTEM_RINGTONES) {
220                 _E("Not support directory : id(%d) type(%d)", storage_id, type); //LCOV_EXCL_LINE
221                 return STORAGE_ERROR_NOT_SUPPORTED;
222         }
223
224         ret = storage_ext_get_root(storage_id, root, sizeof(root), &extendedint);
225         if (ret < 0) {
226                 _E("Failed to get root dir for external storage(id:%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
227                 return STORAGE_ERROR_NOT_SUPPORTED;
228         }
229         /* The operation is not decided */
230         if (extendedint)
231                 return STORAGE_ERROR_NOT_SUPPORTED;
232
233         snprintf(temp, sizeof(temp), "%s/%s", root, dir_path[type]);
234
235 out:
236         *path = strdup(temp);
237         if (!*path) {
238                 _E("Failed to copy the directory(%d) string : %d", type, errno); //LCOV_EXCL_LINE
239                 return STORAGE_ERROR_OUT_OF_MEMORY;
240         }
241
242         return STORAGE_ERROR_NONE;
243 }
244
245 API int storage_get_type(int storage_id, storage_type_e *type)
246 {
247         const struct storage_ops *st;
248         dd_list *elem;
249         char root[PATH_MAX];
250         int ret;
251         bool extendedint;
252
253         if (storage_id < 0)
254                 return STORAGE_ERROR_NOT_SUPPORTED;
255
256         if (!type) {
257                 _E("Invalid parameger");
258                 return STORAGE_ERROR_INVALID_PARAMETER;
259         }
260
261         /* internal storage */
262         DD_LIST_FOREACH(st_int_head, elem, st) {
263                 if (st->storage_id != storage_id)
264                         continue;
265                 *type = st->type;
266                 return STORAGE_ERROR_NONE;
267         }
268
269         /* external storage */
270         ret = storage_ext_get_root(storage_id, root, sizeof(root), &extendedint);
271         if (ret < 0) {
272                 _E("Failed to get type of external storage");
273                 return STORAGE_ERROR_NOT_SUPPORTED;
274         }
275         if (extendedint)
276                 *type = STORAGE_TYPE_EXTENDED_INTERNAL;
277         else
278                 *type = STORAGE_TYPE_EXTERNAL;
279
280         return STORAGE_ERROR_NONE;
281 }
282
283 API int storage_get_state(int storage_id, storage_state_e *state)
284 {
285         const struct storage_ops *ops;
286         storage_state_e st;
287         dd_list *elem;
288         int ret;
289
290         if (storage_id < 0)
291                 return STORAGE_ERROR_NOT_SUPPORTED;
292
293         if (!state) {
294                 _E("Invalid parameger");
295                 return STORAGE_ERROR_INVALID_PARAMETER;
296         }
297
298         /* internal storage */
299         DD_LIST_FOREACH(st_int_head, elem, ops) {
300                 if (ops->storage_id != storage_id)
301                         continue;
302                 *state = ops->get_state();
303                 return STORAGE_ERROR_NONE;
304         }
305
306         /* external storage */
307         ret = storage_ext_get_state(storage_id, &st);
308         if (ret < 0) {
309                 _E("Failed to get state (storage id(%d), ret(%d))", storage_id, ret); //LCOV_EXCL_LINE
310                 return STORAGE_ERROR_OPERATION_FAILED;
311         }
312
313         *state = st;
314         return STORAGE_ERROR_NONE;
315 }
316
317 //LCOV_EXCL_START Not called Callback
318 static void compat_cb(int storage_id,
319                 storage_dev_e dev, storage_state_e state,
320                 const char *fstype, const char *fsuuid, const char *mountpath,
321                 bool primary, int flags, void *user_data)
322 {
323         struct compat_cb_info* ccb_info;
324         dd_list *elem;
325
326         if (storage_id == STORAGE_TYPE_EXTERNAL && dev == STORAGE_DEV_EXT_SDCARD)
327                 DD_LIST_FOREACH(compat_cb_list, elem, ccb_info)
328                         ccb_info->user_cb(storage_id, state, ccb_info->user_data);
329 }
330 //LCOV_EXCL_STOP
331
332 API int storage_set_state_changed_cb(int storage_id, storage_state_changed_cb callback, void *user_data)
333 {
334         const struct storage_ops *st;
335         struct storage_cb_info info;
336         int ret;
337         dd_list *elem;
338
339         struct compat_cb_info* ccb_info;
340         static int compat_cb_init = 0;
341
342         if (storage_id < 0)
343                 return STORAGE_ERROR_NOT_SUPPORTED;
344
345         if (!callback) {
346                 _E("Invalid parameger");
347                 return STORAGE_ERROR_INVALID_PARAMETER;
348         }
349
350         /* For backward compatability */
351         if (storage_id == STORAGE_TYPE_EXTERNAL) {
352                 if (!compat_cb_init) {
353                         ret = storage_set_changed_cb(STORAGE_TYPE_EXTERNAL, compat_cb, NULL);
354                         if (ret == STORAGE_ERROR_NONE)
355                                 compat_cb_init = 1;
356                         else
357                                 return ret;
358                 }
359
360                 ccb_info = malloc(sizeof(struct compat_cb_info));
361                 if (ccb_info == NULL)
362                         return STORAGE_ERROR_OPERATION_FAILED;
363                 ccb_info->user_cb = callback;
364                 ccb_info->user_data = user_data;
365                 DD_LIST_APPEND(compat_cb_list, ccb_info);
366
367                 return STORAGE_ERROR_NONE;
368         }
369
370         /* Internal storage does not support registering changed callback */
371         DD_LIST_FOREACH(st_int_head, elem, st)
372                 if (st->storage_id == storage_id)
373                         return STORAGE_ERROR_NONE;
374
375         /* external storage */
376         info.id = storage_id;
377         info.state_cb = callback;
378         info.user_data = user_data;
379
380         ret = storage_ext_register_cb(STORAGE_CALLBACK_ID, &info);
381         if (ret < 0) {
382                 _E("Failed to register callback : id(%d)", storage_id); //LCOV_EXCL_LINE
383                 return STORAGE_ERROR_OPERATION_FAILED;
384         }
385
386         return STORAGE_ERROR_NONE;
387 }
388
389 API int storage_unset_state_changed_cb(int storage_id, storage_state_changed_cb callback)
390 {
391         const struct storage_ops *st;
392         struct storage_cb_info info;
393         int ret;
394         dd_list *elem;
395
396         if (storage_id < 0)
397                 return STORAGE_ERROR_NOT_SUPPORTED;
398
399         if (!callback) {
400                 _E("Invalid parameger");
401                 return STORAGE_ERROR_INVALID_PARAMETER;
402         }
403
404         /* For backward compatability */
405         if (storage_id == STORAGE_TYPE_EXTERNAL) {
406                 dd_list *elem_n;
407                 struct compat_cb_info* ccb_info;
408
409                 DD_LIST_FOREACH_SAFE(compat_cb_list, elem, elem_n, ccb_info) {
410                         if (ccb_info->user_cb == callback) {
411                                 DD_LIST_REMOVE(compat_cb_list, ccb_info);
412                                 free(ccb_info);
413                                 return STORAGE_ERROR_NONE;
414                         }
415                 }
416                 return STORAGE_ERROR_OPERATION_FAILED;
417         }
418
419         /* Internal storage does not support registering changed callback */
420         DD_LIST_FOREACH(st_int_head, elem, st)
421                 if (st->storage_id == storage_id)
422                         return STORAGE_ERROR_NONE;
423
424         /* external storage */
425         info.id = storage_id;
426         info.state_cb = callback;
427
428         ret = storage_ext_unregister_cb(STORAGE_CALLBACK_ID, &info);
429         if (ret < 0) {
430                 _E("Failed to unregister callback : id(%d)", storage_id); //LCOV_EXCL_LINE
431                 return STORAGE_ERROR_OPERATION_FAILED;
432         }
433
434         return STORAGE_ERROR_NONE;
435 }
436
437 API int storage_get_total_space(int storage_id, unsigned long long *bytes)
438 {
439         const struct storage_ops *st;
440         unsigned long long total;
441         int ret;
442         dd_list *elem;
443
444         if (storage_id < 0)
445                 return STORAGE_ERROR_NOT_SUPPORTED;
446
447         if (!bytes) {
448                 _E("Invalid parameger");
449                 return STORAGE_ERROR_INVALID_PARAMETER;
450         }
451
452         /* internal storage */
453         DD_LIST_FOREACH(st_int_head, elem, st) {
454                 if (st->storage_id != storage_id)
455                         continue;
456                 ret = st->get_space(&total, NULL);
457                 goto out;
458         }
459
460         /* external storage */
461         ret = storage_ext_get_space(storage_id, &total, NULL);
462
463 out:
464         if (ret < 0) {
465                 _E("Failed to get total memory : id(%d)", storage_id); //LCOV_EXCL_LINE
466                 if (ret == -ENOTSUP)
467                         return STORAGE_ERROR_NOT_SUPPORTED;
468                 return STORAGE_ERROR_OPERATION_FAILED;
469         }
470
471         *bytes = total;
472         return STORAGE_ERROR_NONE;
473 }
474
475 API int storage_get_available_space(int storage_id, unsigned long long *bytes)
476 {
477         const struct storage_ops *st;
478         unsigned long long avail;
479         int ret;
480         dd_list *elem;
481
482         if (storage_id < 0)
483                 return STORAGE_ERROR_NOT_SUPPORTED;
484
485         if (!bytes) {
486                 _E("Invalid parameger");
487                 return STORAGE_ERROR_INVALID_PARAMETER;
488         }
489
490         /* internal storage */
491         DD_LIST_FOREACH(st_int_head, elem, st) {
492                 if (st->storage_id != storage_id)
493                         continue;
494                 ret = st->get_space(NULL, &avail);
495                 goto out;
496         }
497
498         /* external storage */
499         ret = storage_ext_get_space(storage_id, NULL, &avail);
500
501 out:
502         if (ret < 0) {
503                 _E("Failed to get available memory : id(%d)", storage_id); //LCOV_EXCL_LINE
504                 if (ret == -ENOTSUP)
505                         return STORAGE_ERROR_NOT_SUPPORTED;
506                 return STORAGE_ERROR_OPERATION_FAILED;
507         }
508
509         *bytes = avail;
510         return STORAGE_ERROR_NONE;
511 }
512
513 API int storage_set_changed_cb(storage_type_e type, storage_changed_cb callback, void *user_data)
514 {
515         int ret;
516         struct storage_cb_info info;
517
518         if (type == STORAGE_TYPE_INTERNAL) {
519                 _E("Internal storage is not supported");
520                 return STORAGE_ERROR_NOT_SUPPORTED;
521         }
522
523         if (type != STORAGE_TYPE_EXTERNAL && type != STORAGE_TYPE_EXTENDED_INTERNAL) {
524                 _E("Invalid type (%d)", type);
525                 return STORAGE_ERROR_INVALID_PARAMETER;
526         }
527
528         if (!callback) {
529                 _E("Callback is NULL");
530                 return STORAGE_ERROR_INVALID_PARAMETER;
531         }
532
533         if (!storage_ext_is_supported()) {
534                 _E("Block module is not enabled");
535                 return STORAGE_ERROR_NOT_SUPPORTED;
536         }
537
538         /* external storage */
539         info.type = type;
540         info.type_cb = callback;
541         info.user_data = user_data;
542
543         ret = storage_ext_register_cb(STORAGE_CALLBACK_TYPE, &info);
544         if (ret < 0) {
545                 _E("Failed to register storage callback(ret:%d)", ret); //LCOV_EXCL_LINE
546                 return STORAGE_ERROR_OPERATION_FAILED;
547         }
548
549         return STORAGE_ERROR_NONE;
550 }
551
552 API int storage_unset_changed_cb(storage_type_e type, storage_changed_cb callback)
553 {
554         struct storage_cb_info info;
555         int ret;
556
557         if (type == STORAGE_TYPE_INTERNAL) {
558                 _E("Internal storage is not supported");
559                 return STORAGE_ERROR_NOT_SUPPORTED;
560         }
561
562         if (type != STORAGE_TYPE_EXTERNAL && type != STORAGE_TYPE_EXTENDED_INTERNAL) {
563                 _E("Invalid type (%d)", type);
564                 return STORAGE_ERROR_INVALID_PARAMETER;
565         }
566
567         if (!callback) {
568                 _E("Callback is NULL");
569                 return STORAGE_ERROR_INVALID_PARAMETER;
570         }
571
572         if (!storage_ext_is_supported()) {
573                 _E("Block module is not enabled");
574                 return STORAGE_ERROR_NOT_SUPPORTED;
575         }
576
577         /* external storage */
578         info.type = type;
579         info.type_cb = callback;
580
581         ret = storage_ext_unregister_cb(STORAGE_CALLBACK_TYPE, &info);
582         if (ret < 0) {
583                 _E("Failed to unregister storage callback(ret:%d)", ret); //LCOV_EXCL_LINE
584                 return STORAGE_ERROR_OPERATION_FAILED;
585         }
586
587         return STORAGE_ERROR_NONE;
588 }
589
590 API int storage_get_type_dev(int storage_id, storage_type_e *type, storage_dev_e *dev)
591 {
592         storage_ext_device *ext_dev;
593         int ret;
594
595         if (storage_id < 0 || !type || !dev) {
596                 _E("Invalid parameter");
597                 return STORAGE_ERROR_INVALID_PARAMETER;
598         }
599
600         ret = storage_get_type(storage_id, type);
601         if (ret != STORAGE_ERROR_NONE) {
602                 _E("Failed to get storage type: %d", ret);
603                 return ret;
604         }
605         if (*type == STORAGE_TYPE_INTERNAL || *type == STORAGE_TYPE_EXTENDED_INTERNAL)
606                 return STORAGE_ERROR_INVALID_PARAMETER;
607
608         ext_dev = calloc(1, sizeof(storage_ext_device));
609         if (!ext_dev) {
610                 //LCOV_EXCL_START System Error
611                 _E("calloc failed");
612                 return STORAGE_ERROR_OUT_OF_MEMORY;
613                 //LCOV_EXCL_STOP
614         }
615
616         ret = storage_ext_get_device_info(storage_id, ext_dev);
617         if (ret < 0) {
618                 _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
619                 ret = STORAGE_ERROR_OPERATION_FAILED;
620                 goto out;
621         }
622
623         if (ext_dev->type == STORAGE_EXT_SCSI)
624                 *dev = STORAGE_DEV_EXT_USB_MASS_STORAGE;
625         else if (ext_dev->type == STORAGE_EXT_MMC)
626                 *dev = STORAGE_DEV_EXT_SDCARD;
627         ret = STORAGE_ERROR_NONE;
628         _I("type: %d(internal:0, external:1) dev: %d(sdcard: 1001, usb: 1002)", *type, *dev);
629
630 out:
631         storage_ext_release_device(&ext_dev);
632         return ret;
633 }
634
635 static void __CONSTRUCTOR__ init(void)
636 {
637         const char *tmp;
638         char *token;
639         int i;
640
641         for (i = 0 ; i <= STORAGE_DIRECTORY_OTHERS ; i++) {
642                 tmp = tzplatform_getenv(tz_id[i]);
643                 if (tmp != NULL) {
644                         token = rindex(tmp, '/');
645                         if (token != NULL) {
646                                 token++;
647                                 dir_path[i] = strdup(token);
648                         }
649                 }
650         }
651 }