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