libstorage: Fixed wrong space value
[platform/core/system/libstorage.git] / src / storage-sdcard.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 <sys/statvfs.h>
23 #include <vconf.h>
24
25 #include "common.h"
26 #include "list.h"
27 #include "log.h"
28
29 #define SDCARD_PATH "/opt/storage/sdcard"
30
31 #ifndef __USE_FILE_OFFSET64
32 int __WEAK__ storage_get_external_memory_size(struct statvfs *buf);
33 #else
34 int __WEAK__ storage_get_external_memory_size64(struct statvfs *buf);
35 #endif
36
37 static dd_list *cb_list[STORAGE_CALLBACK_MAX];
38
39 static int sdcard_get_state(void)
40 {
41         int val, ret;
42
43         ret = vconf_get_int(VCONFKEY_SYSMAN_MMC_STATUS, &val);
44         if (ret < 0)
45                 return -EPERM;
46
47         switch (val) {
48         case VCONFKEY_SYSMAN_MMC_MOUNTED:
49                 return STORAGE_STATE_MOUNTED;
50         case VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED:
51                 return STORAGE_STATE_UNMOUNTABLE;
52         case VCONFKEY_SYSMAN_MMC_REMOVED:
53         default:
54                 break;
55         }
56
57         return STORAGE_STATE_REMOVED;
58 }
59
60 static int sdcard_get_space(unsigned long long *total, unsigned long long *available)
61 {
62         storage_state_e state;
63         struct statvfs s;
64         int ret;
65         unsigned long long t = 0, a = 0;
66
67         state = sdcard_get_state();
68         if (state >= STORAGE_STATE_MOUNTED) {
69 #ifndef __USE_FILE_OFFSET64
70                 ret = storage_get_external_memory_size(&s);
71 #else
72                 ret = storage_get_external_memory_size64(&s);
73 #endif
74                 if (ret < 0)
75                         return -EPERM;
76
77                 t = (unsigned long long)s.f_frsize*s.f_blocks;
78                 a = (unsigned long long)s.f_bsize*s.f_bavail;
79         }
80
81         if (total)
82                 *total = t;
83         if (available)
84                 *available = a;
85
86         return 0;
87 }
88
89 static const char *sdcard_get_root(void)
90 {
91         return SDCARD_PATH;
92 }
93
94 static void sdcard_state_cb(keynode_t *key, void *data)
95 {
96         struct storage_cb_info *cb_info;
97         dd_list *elem;
98         storage_state_e state;
99
100         state = sdcard_get_state();
101
102         DD_LIST_FOREACH(cb_list[STORAGE_CALLBACK_STATE], elem, cb_info)
103                 cb_info->state_cb(cb_info->id, state, cb_info->user_data);
104 }
105
106 static int register_request(enum storage_cb_type type)
107 {
108         switch (type) {
109         case STORAGE_CALLBACK_STATE:
110                 return vconf_notify_key_changed(VCONFKEY_SYSMAN_MMC_STATUS,
111                                 sdcard_state_cb, NULL);
112         default:
113                 break;
114         }
115
116         return -EINVAL;
117 }
118
119 static int release_request(enum storage_cb_type type)
120 {
121         switch (type) {
122         case STORAGE_CALLBACK_STATE:
123                 return vconf_ignore_key_changed(VCONFKEY_SYSMAN_MMC_STATUS,
124                                 sdcard_state_cb);
125         default:
126                 break;
127         }
128
129         return -EINVAL;
130 }
131
132 static int sdcard_register_cb(enum storage_cb_type type, struct storage_cb_info *info)
133 {
134         struct storage_cb_info *cb_info;
135         dd_list *elem;
136         int ret, n;
137
138         if (type < 0 || type >= STORAGE_CALLBACK_MAX)
139                 return -EINVAL;
140
141         if (!info)
142                 return -EINVAL;
143
144         /* check if it is the first request */
145         n = DD_LIST_LENGTH(cb_list[type]);
146         if (n == 0) {
147                 ret = register_request(type);
148                 if (ret < 0)
149                         return -EPERM;
150         }
151
152         /* check for the same request */
153         DD_LIST_FOREACH(cb_list[type], elem, cb_info) {
154                 if (cb_info->id == info->id &&
155                     cb_info->state_cb == info->state_cb)
156                         return -EEXIST;
157         }
158
159         /* add device changed callback to list (local) */
160         cb_info = malloc(sizeof(struct storage_cb_info));
161         if (!cb_info)
162                 return -errno;
163
164         memcpy(cb_info, info, sizeof(struct storage_cb_info));
165         DD_LIST_APPEND(cb_list[type], cb_info);
166
167         return 0;
168 }
169
170 static int sdcard_unregister_cb(enum storage_cb_type type, struct storage_cb_info *info)
171 {
172         struct storage_cb_info *cb_info;
173         dd_list *elem;
174         int ret, n;
175
176         if (type < 0 || type >= STORAGE_CALLBACK_MAX)
177                 return -EINVAL;
178
179         if (!info)
180                 return -EINVAL;
181
182         /* search for the same element with callback */
183         DD_LIST_FOREACH(cb_list[type], elem, cb_info) {
184                 if (cb_info->id == info->id &&
185                     cb_info->state_cb == info->state_cb)
186                         break;
187         }
188
189         if (!cb_info)
190                 return -EINVAL;
191
192         /* remove device callback from list (local) */
193         DD_LIST_REMOVE(cb_list[type], cb_info);
194         free(cb_info);
195
196         /* check if this callback is last element */
197         n = DD_LIST_LENGTH(cb_list[type]);
198         if (n == 0) {
199                 ret = release_request(type);
200                 if (ret < 0)
201                         return -EPERM;
202         }
203
204         return 0;
205 }
206
207 const struct storage_ops sdcard = {
208         .type = STORAGE_TYPE_EXTERNAL,
209         .root = sdcard_get_root,
210         .get_state = sdcard_get_state,
211         .get_space = sdcard_get_space,
212         .register_cb = sdcard_register_cb,
213         .unregister_cb = sdcard_unregister_cb,
214 };
215
216 STORAGE_OPS_REGISTER(&sdcard)