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