external: add functions to get storage size
[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 void add_device(const struct storage_ops *st)
44 {
45         DD_LIST_APPEND(st_int_head, st);
46 }
47
48 void remove_device(const struct storage_ops *st)
49 {
50         DD_LIST_REMOVE(st_int_head, st);
51 }
52
53 API int storage_foreach_device_supported(storage_device_supported_cb callback, void *user_data)
54 {
55         const struct storage_ops *st;
56         dd_list *elem;
57         int ret;
58
59         if (!callback) {
60                 _E("Invalid parameter");
61                 return STORAGE_ERROR_INVALID_PARAMETER;
62         }
63
64         DD_LIST_FOREACH(st_int_head, elem, st) {
65                 ret = callback(st->storage_id, st->type, st->get_state(),
66                                 st->root(), user_data);
67                 /* if the return value is false, will be stop to iterate */
68                 if (!ret)
69                         break;
70         }
71
72         ret = storage_ext_foreach_device_list(callback, user_data);
73         if (ret < 0) {
74                 _E("Failed to iterate external devices (%d)", ret);
75                 return STORAGE_ERROR_OPERATION_FAILED;
76         }
77
78         return STORAGE_ERROR_NONE;
79 }
80
81 API int storage_get_root_directory(int storage_id, char **path)
82 {
83         const struct storage_ops *st;
84         dd_list *elem;
85         char root[PATH_MAX];
86         int ret;
87
88         if (!path || storage_id < 0) {
89                 _E("Invalid parameger");
90                 return STORAGE_ERROR_INVALID_PARAMETER;
91         }
92
93         /* internal storage */
94         DD_LIST_FOREACH(st_int_head, elem, st) {
95                 if (st->storage_id != storage_id)
96                         continue;
97                 *path = strdup(st->root());
98                 if (!*path) {
99                         _E("Failed to copy the root string : %d", errno);
100                         return STORAGE_ERROR_OUT_OF_MEMORY;
101                 }
102                 return STORAGE_ERROR_NONE;
103         }
104
105         /* external storage */
106         ret = storage_ext_get_root(storage_id, root, sizeof(root));
107         if (ret < 0) {
108                 _E("Failed to get root path of external storage(%d, %d", storage_id, ret);
109                 return STORAGE_ERROR_INVALID_PARAMETER;
110         }
111
112         *path = strdup(root);
113         if (!*path) {
114                 _E("Failed to copy the root string : %d", errno);
115                 return STORAGE_ERROR_OUT_OF_MEMORY;
116         }
117
118         return STORAGE_ERROR_NONE;
119 }
120
121 API int storage_get_directory(int storage_id, storage_directory_e type, char **path)
122 {
123         const struct storage_ops *st;
124         char root[PATH_MAX];
125         char temp[PATH_MAX];
126         char *temp2, *end;
127         int ret;
128         dd_list *elem;
129         bool found;
130
131         if (!path || storage_id < 0) {
132                 _E("Invalid parameger");
133                 return STORAGE_ERROR_INVALID_PARAMETER;
134         }
135
136         if (type < 0 || type >= STORAGE_DIRECTORY_MAX) {
137                 _E("Invalid parameter");
138                 return STORAGE_ERROR_INVALID_PARAMETER;
139         }
140
141         /* internal storage */
142         found = false;
143         DD_LIST_FOREACH(st_int_head, elem, st) {
144                 if (st->storage_id != storage_id)
145                         continue;
146                 found = true;
147                 break;
148         }
149
150         if (found && st) {
151                 snprintf(root, sizeof(root), "%s", st->root());
152                 if (type == STORAGE_DIRECTORY_SYSTEM_RINGTONES) {
153                         ret = system_settings_get_value_string(SYSTEM_SETTINGS_KEY_INCOMING_CALL_RINGTONE, &temp2);
154                         if (ret < 0) {
155                                 _E("Failed to get ringtone path : %d", ret);
156                                 return STORAGE_ERROR_OPERATION_FAILED;
157                         }
158                         end = strrchr(temp2, '/');
159                         if (end)
160                                 *end = '\0';
161                         snprintf(temp, PATH_MAX, "%s", temp2);
162                         free(temp2);
163                 } else
164                         snprintf(temp, PATH_MAX, "%s/%s", root, dir_path[type]);
165
166                 goto out;
167         }
168
169         /* external storage */
170         if (type == STORAGE_DIRECTORY_SYSTEM_RINGTONES) {
171                 _E("Not support directory : id(%d) type(%d)", storage_id, type);
172                 return STORAGE_ERROR_NOT_SUPPORTED;
173         }
174
175         ret = storage_ext_get_root(storage_id, root, sizeof(root));
176         if (ret < 0) {
177                 _E("Failed to get root dir for external storage(id:%d, ret:%d)", storage_id, ret);
178                 return STORAGE_ERROR_OPERATION_FAILED;
179         }
180
181         snprintf(temp, sizeof(temp), "%s/%s", root, dir_path[type]);
182
183 out:
184         *path = strdup(temp);
185         if (!*path) {
186                 _E("Failed to copy the directory(%d) string : %d", type, errno);
187                 return STORAGE_ERROR_OUT_OF_MEMORY;
188         }
189
190         return STORAGE_ERROR_NONE;
191 }
192
193 API int storage_get_type(int storage_id, storage_type_e *type)
194 {
195         const struct storage_ops *st;
196         dd_list *elem;
197
198         if (!type || storage_id < 0) {
199                 _E("Invalid parameger");
200                 return STORAGE_ERROR_INVALID_PARAMETER;
201         }
202
203         /* internal storage */
204         DD_LIST_FOREACH(st_int_head, elem, st) {
205                 if (st->storage_id != storage_id)
206                         continue;
207                 *type = st->type;
208                 return STORAGE_ERROR_NONE;
209         }
210
211         /* external storage */
212         *type = STORAGE_TYPE_EXTERNAL;
213
214         return STORAGE_ERROR_NONE;
215 }
216
217 API int storage_get_state(int storage_id, storage_state_e *state)
218 {
219         const struct storage_ops *ops;
220         storage_state_e st;
221         dd_list *elem;
222         int ret;
223
224         if (!state || storage_id < 0) {
225                 _E("Invalid parameger");
226                 return STORAGE_ERROR_INVALID_PARAMETER;
227         }
228
229         /* internal storage */
230         DD_LIST_FOREACH(st_int_head, elem, ops) {
231                 if (ops->storage_id != storage_id)
232                         continue;
233                 *state = ops->get_state();
234                 return STORAGE_ERROR_NONE;
235         }
236
237         /* external storage */
238         ret = storage_ext_get_state(storage_id, &st);
239         if (ret < 0) {
240                 _E("Failed to get state (storage id(%d), ret(%d))", storage_id, ret);
241                 return STORAGE_ERROR_OPERATION_FAILED;
242         }
243
244         *state = st;
245         return STORAGE_ERROR_NONE;
246 }
247
248 API int storage_set_state_changed_cb(int storage_id, storage_state_changed_cb callback, void *user_data)
249 {
250         const struct storage_ops *st;
251         struct storage_cb_info info;
252         int ret;
253         dd_list *elem;
254
255         if (!callback) {
256                 _E("Invalid parameger");
257                 return STORAGE_ERROR_INVALID_PARAMETER;
258         }
259
260         /* Internal storage does not support registering changed callback */
261         DD_LIST_FOREACH(st_int_head, elem, st)
262                 if (st->storage_id == storage_id)
263                         return STORAGE_ERROR_NONE;
264
265         /* external storage */
266         info.id = storage_id;
267         info.state_cb = callback;
268         info.user_data = user_data;
269
270         ret = storage_ext_register_cb(STORAGE_CALLBACK_STATE, &info);
271         if (ret < 0) {
272                 _E("Failed to register callback : id(%d)", storage_id);
273                 return STORAGE_ERROR_OPERATION_FAILED;
274         }
275
276         return STORAGE_ERROR_NONE;
277 }
278
279 API int storage_unset_state_changed_cb(int storage_id, storage_state_changed_cb callback)
280 {
281         const struct storage_ops *st;
282         struct storage_cb_info info;
283         int ret;
284         dd_list *elem;
285
286         if (!callback) {
287                 _E("Invalid parameger");
288                 return STORAGE_ERROR_INVALID_PARAMETER;
289         }
290
291         /* Internal storage does not support registering changed callback */
292         DD_LIST_FOREACH(st_int_head, elem, st)
293                 if (st->storage_id == storage_id)
294                         return STORAGE_ERROR_NONE;
295
296         /* external storage */
297         info.id = storage_id;
298         info.state_cb = callback;
299
300         ret = storage_ext_unregister_cb(STORAGE_CALLBACK_STATE, &info);
301         if (ret < 0) {
302                 _E("Failed to unregister callback : id(%d)", storage_id);
303                 return STORAGE_ERROR_OPERATION_FAILED;
304         }
305
306         return STORAGE_ERROR_NONE;
307 }
308
309 API int storage_get_total_space(int storage_id, unsigned long long *bytes)
310 {
311         const struct storage_ops *st;
312         unsigned long long total;
313         int ret;
314         dd_list *elem;
315
316         if (!bytes || storage_id < 0) {
317                 _E("Invalid parameger");
318                 return STORAGE_ERROR_INVALID_PARAMETER;
319         }
320
321         /* internal storage */
322         DD_LIST_FOREACH(st_int_head, elem, st) {
323                 if (st->storage_id != storage_id)
324                         continue;
325                 ret = st->get_space(&total, NULL);
326                 goto out;
327         }
328
329         /* external storage */
330         ret = storage_ext_get_space(storage_id, &total, NULL);
331
332 out:
333         if (ret < 0) {
334                 _E("Failed to get total memory : id(%d)", storage_id);
335                 return STORAGE_ERROR_OPERATION_FAILED;
336         }
337
338         *bytes = total;
339         return STORAGE_ERROR_NONE;
340 }
341
342 API int storage_get_available_space(int storage_id, unsigned long long *bytes)
343 {
344         const struct storage_ops *st;
345         unsigned long long avail;
346         int ret;
347         dd_list *elem;
348
349         if (!bytes) {
350                 _E("Invalid parameger");
351                 return STORAGE_ERROR_INVALID_PARAMETER;
352         }
353
354         /* internal storage */
355         DD_LIST_FOREACH(st_int_head, elem, st) {
356                 if (st->storage_id != storage_id)
357                         continue;
358                 ret = st->get_space(NULL, &avail);
359                 goto out;
360         }
361
362         /* external storage */
363         ret = storage_ext_get_space(storage_id,NULL, &avail);
364
365 out:
366         if (ret < 0) {
367                 _E("Failed to get available memory : id(%d)", storage_id);
368                 return STORAGE_ERROR_OPERATION_FAILED;
369         }
370
371         *bytes = avail;
372         return STORAGE_ERROR_NONE;
373 }