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