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