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