26b4036b9169f012086376a7b550f509dbe28344
[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 <system_settings.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                         ret = system_settings_get_value_string(SYSTEM_SETTINGS_KEY_INCOMING_CALL_RINGTONE, &temp2);
168                         if (ret < 0) {
169                                 _E("Failed to get ringtone path : %d", ret); //LCOV_EXCL_LINE
170                                 return STORAGE_ERROR_OPERATION_FAILED;
171                         }
172                         end = strrchr(temp2, '/');
173                         if (end)
174                                 *end = '\0';
175                         snprintf(temp, PATH_MAX, "%s", temp2);
176                         free(temp2);
177                 } else
178                         snprintf(temp, PATH_MAX, "%s/%s", root, dir_path[type]);
179
180                 goto out;
181         }
182
183         /* external storage */
184         if (type == STORAGE_DIRECTORY_SYSTEM_RINGTONES) {
185                 _E("Not support directory : id(%d) type(%d)", storage_id, type); //LCOV_EXCL_LINE
186                 return STORAGE_ERROR_NOT_SUPPORTED;
187         }
188
189         ret = storage_ext_get_root(storage_id, root, sizeof(root));
190         if (ret < 0) {
191                 _E("Failed to get root dir for external storage(id:%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
192                 return STORAGE_ERROR_OPERATION_FAILED;
193         }
194
195         snprintf(temp, sizeof(temp), "%s/%s", root, dir_path[type]);
196
197 out:
198         *path = strdup(temp);
199         if (!*path) {
200                 _E("Failed to copy the directory(%d) string : %d", type, errno); //LCOV_EXCL_LINE
201                 return STORAGE_ERROR_OUT_OF_MEMORY;
202         }
203
204         return STORAGE_ERROR_NONE;
205 }
206
207 API int storage_get_type(int storage_id, storage_type_e *type)
208 {
209         const struct storage_ops *st;
210         dd_list *elem;
211
212         if (storage_id < 0)
213                 return STORAGE_ERROR_NOT_SUPPORTED;
214
215         if (!type) {
216                 _E("Invalid parameger");
217                 return STORAGE_ERROR_INVALID_PARAMETER;
218         }
219
220         /* internal storage */
221         DD_LIST_FOREACH(st_int_head, elem, st) {
222                 if (st->storage_id != storage_id)
223                         continue;
224                 *type = st->type;
225                 return STORAGE_ERROR_NONE;
226         }
227
228         /* external storage */
229         *type = STORAGE_TYPE_EXTERNAL;
230
231         return STORAGE_ERROR_NONE;
232 }
233
234 API int storage_get_state(int storage_id, storage_state_e *state)
235 {
236         const struct storage_ops *ops;
237         storage_state_e st;
238         dd_list *elem;
239         int ret;
240
241         if (storage_id < 0)
242                 return STORAGE_ERROR_NOT_SUPPORTED;
243
244         if (!state) {
245                 _E("Invalid parameger");
246                 return STORAGE_ERROR_INVALID_PARAMETER;
247         }
248
249         /* internal storage */
250         DD_LIST_FOREACH(st_int_head, elem, ops) {
251                 if (ops->storage_id != storage_id)
252                         continue;
253                 *state = ops->get_state();
254                 return STORAGE_ERROR_NONE;
255         }
256
257         /* external storage */
258         ret = storage_ext_get_state(storage_id, &st);
259         if (ret < 0) {
260                 _E("Failed to get state (storage id(%d), ret(%d))", storage_id, ret); //LCOV_EXCL_LINE
261                 return STORAGE_ERROR_OPERATION_FAILED;
262         }
263
264         *state = st;
265         return STORAGE_ERROR_NONE;
266 }
267
268 static void compat_cb(int storage_id,
269                 storage_dev_e dev, storage_state_e state,
270                 const char *fstype, const char *fsuuid, const char *mountpath,
271                 bool primary, int flags, void *user_data)
272 {
273         struct compat_cb_info* ccb_info;
274         dd_list *elem;
275
276         if (storage_id == STORAGE_TYPE_EXTERNAL && dev == STORAGE_DEV_EXT_SDCARD)
277                 DD_LIST_FOREACH(compat_cb_list, elem, ccb_info)
278                         ccb_info->user_cb(storage_id, state, ccb_info->user_data);
279 }
280
281 API int storage_set_state_changed_cb(int storage_id, storage_state_changed_cb callback, void *user_data)
282 {
283         const struct storage_ops *st;
284         struct storage_cb_info info;
285         int ret;
286         dd_list *elem;
287
288         struct compat_cb_info* ccb_info;
289         static int compat_cb_init = 0;
290
291         if (storage_id < 0)
292                 return STORAGE_ERROR_NOT_SUPPORTED;
293
294         if (!callback) {
295                 _E("Invalid parameger");
296                 return STORAGE_ERROR_INVALID_PARAMETER;
297         }
298
299         /* For backward compatability */
300         if (storage_id == STORAGE_TYPE_EXTERNAL) {
301                 if (!compat_cb_init) {
302                         ret = storage_set_changed_cb(STORAGE_TYPE_EXTERNAL, compat_cb, NULL);
303                         if (ret == STORAGE_ERROR_NONE)
304                                 compat_cb_init = 1;
305                         else
306                                 return ret;
307                 }
308
309                 ccb_info = malloc(sizeof(struct compat_cb_info));
310                 if (ccb_info == NULL)
311                         return STORAGE_ERROR_OPERATION_FAILED;
312                 ccb_info->user_cb = callback;
313                 ccb_info->user_data = user_data;
314                 DD_LIST_APPEND(compat_cb_list, ccb_info);
315
316                 return STORAGE_ERROR_NONE;
317         }
318
319         /* Internal storage does not support registering changed callback */
320         DD_LIST_FOREACH(st_int_head, elem, st)
321                 if (st->storage_id == storage_id)
322                         return STORAGE_ERROR_NONE;
323
324         /* external storage */
325         info.id = storage_id;
326         info.state_cb = callback;
327         info.user_data = user_data;
328
329         ret = storage_ext_register_cb(STORAGE_CALLBACK_ID, &info);
330         if (ret < 0) {
331                 _E("Failed to register callback : id(%d)", storage_id); //LCOV_EXCL_LINE
332                 return STORAGE_ERROR_OPERATION_FAILED;
333         }
334
335         return STORAGE_ERROR_NONE;
336 }
337
338 API int storage_unset_state_changed_cb(int storage_id, storage_state_changed_cb callback)
339 {
340         const struct storage_ops *st;
341         struct storage_cb_info info;
342         int ret;
343         dd_list *elem;
344
345         if (storage_id < 0)
346                 return STORAGE_ERROR_NOT_SUPPORTED;
347
348         if (!callback) {
349                 _E("Invalid parameger");
350                 return STORAGE_ERROR_INVALID_PARAMETER;
351         }
352
353         /* For backward compatability */
354         if (storage_id == STORAGE_TYPE_EXTERNAL) {
355                 dd_list *elem_n;
356                 struct compat_cb_info* ccb_info;
357
358                 DD_LIST_FOREACH_SAFE(compat_cb_list, elem, elem_n, ccb_info) {
359                         if (ccb_info->user_cb == callback) {
360                                 DD_LIST_REMOVE(compat_cb_list, ccb_info);
361                                 free(ccb_info);
362                                 return STORAGE_ERROR_NONE;
363                         }
364                 }
365                 return STORAGE_ERROR_OPERATION_FAILED;
366         }
367
368         /* Internal storage does not support registering changed callback */
369         DD_LIST_FOREACH(st_int_head, elem, st)
370                 if (st->storage_id == storage_id)
371                         return STORAGE_ERROR_NONE;
372
373         /* external storage */
374         info.id = storage_id;
375         info.state_cb = callback;
376
377         ret = storage_ext_unregister_cb(STORAGE_CALLBACK_ID, &info);
378         if (ret < 0) {
379                 _E("Failed to unregister callback : id(%d)", storage_id); //LCOV_EXCL_LINE
380                 return STORAGE_ERROR_OPERATION_FAILED;
381         }
382
383         return STORAGE_ERROR_NONE;
384 }
385
386 API int storage_get_total_space(int storage_id, unsigned long long *bytes)
387 {
388         const struct storage_ops *st;
389         unsigned long long total;
390         int ret;
391         dd_list *elem;
392
393         if (storage_id < 0)
394                 return STORAGE_ERROR_NOT_SUPPORTED;
395
396         if (!bytes) {
397                 _E("Invalid parameger");
398                 return STORAGE_ERROR_INVALID_PARAMETER;
399         }
400
401         /* internal storage */
402         DD_LIST_FOREACH(st_int_head, elem, st) {
403                 if (st->storage_id != storage_id)
404                         continue;
405                 ret = st->get_space(&total, NULL);
406                 goto out;
407         }
408
409         /* external storage */
410         ret = storage_ext_get_space(storage_id, &total, NULL);
411
412 out:
413         if (ret < 0) {
414                 _E("Failed to get total memory : id(%d)", storage_id); //LCOV_EXCL_LINE
415                 if (ret == -ENOTSUP)
416                         return STORAGE_ERROR_NOT_SUPPORTED;
417                 return STORAGE_ERROR_OPERATION_FAILED;
418         }
419
420         *bytes = total;
421         return STORAGE_ERROR_NONE;
422 }
423
424 API int storage_get_available_space(int storage_id, unsigned long long *bytes)
425 {
426         const struct storage_ops *st;
427         unsigned long long avail;
428         int ret;
429         dd_list *elem;
430
431         if (storage_id < 0)
432                 return STORAGE_ERROR_NOT_SUPPORTED;
433
434         if (!bytes) {
435                 _E("Invalid parameger");
436                 return STORAGE_ERROR_INVALID_PARAMETER;
437         }
438
439         /* internal storage */
440         DD_LIST_FOREACH(st_int_head, elem, st) {
441                 if (st->storage_id != storage_id)
442                         continue;
443                 ret = st->get_space(NULL, &avail);
444                 goto out;
445         }
446
447         /* external storage */
448         ret = storage_ext_get_space(storage_id, NULL, &avail);
449
450 out:
451         if (ret < 0) {
452                 _E("Failed to get available memory : id(%d)", storage_id); //LCOV_EXCL_LINE
453                 if (ret == -ENOTSUP)
454                         return STORAGE_ERROR_NOT_SUPPORTED;
455                 return STORAGE_ERROR_OPERATION_FAILED;
456         }
457
458         *bytes = avail;
459         return STORAGE_ERROR_NONE;
460 }
461
462 API int storage_set_changed_cb(storage_type_e type, storage_changed_cb callback, void *user_data)
463 {
464         int ret;
465         struct storage_cb_info info;
466
467         if (type == STORAGE_TYPE_INTERNAL) {
468                 _E("Internal storage is not supported");
469                 return STORAGE_ERROR_NOT_SUPPORTED;
470         }
471
472         if (type != STORAGE_TYPE_EXTERNAL) {
473                 _E("Invalid type (%d)", type);
474                 return STORAGE_ERROR_INVALID_PARAMETER;
475         }
476
477         if (!callback) {
478                 _E("Callback is NULL");
479                 return STORAGE_ERROR_INVALID_PARAMETER;
480         }
481
482         /* external storage */
483         info.type = type;
484         info.type_cb = callback;
485         info.user_data = user_data;
486
487         ret = storage_ext_register_cb(STORAGE_CALLBACK_TYPE, &info);
488         if (ret < 0) {
489                 _E("Failed to register storage callback(ret:%d)", ret); //LCOV_EXCL_LINE
490                 return STORAGE_ERROR_OPERATION_FAILED;
491         }
492
493         return STORAGE_ERROR_NONE;
494 }
495
496 API int storage_unset_changed_cb(storage_type_e type, storage_changed_cb callback)
497 {
498         struct storage_cb_info info;
499         int ret;
500
501         if (type == STORAGE_TYPE_INTERNAL) {
502                 _E("Internal storage is not supported");
503                 return STORAGE_ERROR_NOT_SUPPORTED;
504         }
505
506         if (type != STORAGE_TYPE_EXTERNAL) {
507                 _E("Invalid type (%d)", type);
508                 return STORAGE_ERROR_INVALID_PARAMETER;
509         }
510
511         if (!callback) {
512                 _E("Callback is NULL");
513                 return STORAGE_ERROR_INVALID_PARAMETER;
514         }
515
516         /* external storage */
517         info.type = type;
518         info.type_cb = callback;
519
520         ret = storage_ext_unregister_cb(STORAGE_CALLBACK_TYPE, &info);
521         if (ret < 0) {
522                 _E("Failed to unregister storage callback(ret:%d)", ret); //LCOV_EXCL_LINE
523                 return STORAGE_ERROR_OPERATION_FAILED;
524         }
525
526         return STORAGE_ERROR_NONE;
527 }