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