c23153d8675ee300a237d70c7dd18d3a5217404d
[platform/core/system/libstorage.git] / src / storage-external.c
1 /*
2  * Copyright (c) 2016 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 #include <tzplatform_config.h>
25
26 #include "common.h"
27 #include "list.h"
28 #include "log.h"
29 #include "storage-external-dbus.h"
30
31 static dd_list *cb_list[STORAGE_CALLBACK_MAX];
32
33 static int storage_ext_get_dev_state(storage_ext_device *dev,
34                 enum storage_ext_state blk_state,
35                 storage_state_e *state)
36 {
37         if (!dev || !state)
38                 return -EINVAL;
39
40         switch (blk_state) {
41         case STORAGE_EXT_REMOVED:
42                 *state = STORAGE_STATE_REMOVED;
43                 return 0;
44         case STORAGE_EXT_CHANGED:
45                 switch (dev->state) {
46                 case STORAGE_EXT_UNMOUNTED:
47                         *state = STORAGE_STATE_UNMOUNTABLE;
48                         return 0;
49                 case STORAGE_EXT_MOUNTED:
50                         if (dev->flags & MOUNT_READONLY)
51                                 *state = STORAGE_STATE_MOUNTED_READ_ONLY;
52                         else
53                                 *state = STORAGE_STATE_MOUNTED;
54                         return 0;
55                 default:
56                         return -EINVAL;
57                 }
58         default:
59                 return -EINVAL;
60         }
61 }
62
63 int storage_ext_get_space(int storage_id,
64                 unsigned long long *total, unsigned long long *available)
65 {
66         storage_state_e state;
67         struct statvfs s;
68         int ret;
69         unsigned long long t = 0, a = 0;
70         storage_ext_device *dev;
71
72         if (storage_id < 0)
73                 return -ENOTSUP;
74
75         dev = calloc(1, sizeof(storage_ext_device));
76         if (!dev) {
77 //LCOV_EXCL_START System Error
78                 _E("calloc failed");
79                 return -ENOMEM;
80 //LCOV_EXCL_STOP
81         }
82
83         ret = storage_ext_get_device_info(storage_id, dev);
84         if (ret < 0) {
85                 _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
86                 goto out;
87         }
88
89         ret = storage_ext_get_dev_state(dev, STORAGE_EXT_CHANGED, &state);
90         if (ret < 0) {
91                 _E("Failed to get state of storage (id:%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
92                 goto out;
93         }
94
95         if (state >= STORAGE_STATE_MOUNTED) {
96 #ifndef __USE_FILE_OFFSET64
97                 ret = storage_get_external_memory_size_with_path(dev->mount_point, &s);
98 #else
99                 ret = storage_get_external_memory_size64_with_path(dev->mount_point, &s);
100 #endif
101                 if (ret < 0) {
102                         _E("Failed to get external memory size of (%s)(ret:%d)", dev->mount_point, ret); //LCOV_EXCL_LINE
103                         goto out;
104                 }
105
106                 t = (unsigned long long)s.f_frsize*s.f_blocks;
107                 a = (unsigned long long)s.f_bsize*s.f_bavail;
108         }
109
110         if (total)
111                 *total = t;
112         if (available)
113                 *available = a;
114
115         ret = 0;
116 out:
117         storage_ext_release_device(&dev);
118         return ret;
119 }
120
121 int storage_ext_foreach_device_list(storage_device_supported_cb callback, void *user_data)
122 {
123         int ret;
124         bool ret_cb;
125         dd_list *list = NULL, *elem;
126         storage_ext_device *dev;
127         storage_state_e state;
128
129         if (!callback)
130                 return -EINVAL;
131
132         ret = storage_ext_get_list(&list);
133         if (ret < 0) {
134                 _E("Failed to get external storage list from deviced (%d)", errno); //LCOV_EXCL_LINE
135                 return ret;
136         }
137
138         DD_LIST_FOREACH(list, elem, dev) {
139                 ret = storage_ext_get_dev_state(dev, STORAGE_EXT_CHANGED, &state);
140                 if (ret < 0) {
141                         _E("Failed to get storage state (devnode:%s, ret:%d)", dev->devnode, ret); //LCOV_EXCL_LINE
142                         continue;
143                 }
144
145                 ret_cb = callback(dev->storage_id, STORAGE_TYPE_EXTERNAL,
146                                 state, dev->mount_point, user_data);
147                 if (!ret_cb)
148                         break;
149         }
150
151         if (list)
152                 storage_ext_release_list(&list);
153         return 0;
154 }
155
156 //LCOV_EXCL_START Not called Callback
157 static int storage_ext_state_changed(storage_ext_device *dev, enum storage_ext_state blk_state, void *data)
158 {
159         enum storage_cb_type type = (enum storage_cb_type)data;
160         struct storage_cb_info *cb_info;
161         dd_list *elem;
162         storage_state_e state;
163         int ret;
164
165         if (!dev)
166                 return -EINVAL;
167
168         if (type != STORAGE_CALLBACK_STATE)
169                 return 0;
170
171         ret = storage_ext_get_dev_state(dev, blk_state, &state);
172         if (ret < 0) {
173                 _E("Failed to get storage state (devnode:%s, ret:%d)", dev->devnode, ret);
174                 return ret;
175         }
176
177         DD_LIST_FOREACH(cb_list[STORAGE_CALLBACK_STATE], elem, cb_info)
178                 cb_info->state_cb(cb_info->id, state, cb_info->user_data);
179
180         return 0;
181 }
182 //LCOV_EXCL_STOP
183
184 int storage_ext_register_cb(enum storage_cb_type type, struct storage_cb_info *info)
185 {
186         struct storage_cb_info *cb_info;
187         dd_list *elem;
188         int ret, n;
189
190         if (type < 0 || type >= STORAGE_CALLBACK_MAX)
191                 return -EINVAL;
192
193         if (!info)
194                 return -EINVAL;
195
196         /* check if it is the first request */
197         n = DD_LIST_LENGTH(cb_list[type]);
198         if (n == 0) {
199                 ret = storage_ext_register_device_change(storage_ext_state_changed, (void *)type);
200                 if (ret < 0)
201                         return -EPERM;
202         }
203
204         /* check for the same request */
205         DD_LIST_FOREACH(cb_list[type], elem, cb_info) {
206                 if (cb_info->id == info->id &&
207                     cb_info->state_cb == info->state_cb)
208                         return -EEXIST;
209         }
210
211         /* add device changed callback to list (local) */
212         cb_info = malloc(sizeof(struct storage_cb_info));
213         if (!cb_info)
214                 return -errno;
215
216         memcpy(cb_info, info, sizeof(struct storage_cb_info));
217         DD_LIST_APPEND(cb_list[type], cb_info);
218
219         return 0;
220 }
221
222 int storage_ext_unregister_cb(enum storage_cb_type type, struct storage_cb_info *info)
223 {
224         struct storage_cb_info *cb_info;
225         dd_list *elem;
226         int n;
227
228         if (type < 0 || type >= STORAGE_CALLBACK_MAX)
229                 return -EINVAL;
230
231         if (!info)
232                 return -EINVAL;
233
234         /* search for the same element with callback */
235         DD_LIST_FOREACH(cb_list[type], elem, cb_info) {
236                 if (cb_info->id == info->id &&
237                     cb_info->state_cb == info->state_cb)
238                         break;
239         }
240
241         if (!cb_info)
242                 return -EINVAL;
243
244         /* remove device callback from list (local) */
245         DD_LIST_REMOVE(cb_list[type], cb_info);
246         free(cb_info);
247
248         /* check if this callback is last element */
249         n = DD_LIST_LENGTH(cb_list[type]);
250         if (n == 0)
251                 storage_ext_unregister_device_change(storage_ext_state_changed);
252
253         return 0;
254 }
255
256 int storage_ext_get_root(int storage_id, char *path, size_t len)
257 {
258         storage_ext_device *dev;
259         int ret;
260
261         if (storage_id < 0)
262                 return -ENOTSUP;
263
264         if (!path)
265                 return -EINVAL;
266
267         dev = calloc(1, sizeof(storage_ext_device));
268         if (!dev) {
269 //LCOV_EXCL_START System Error
270                 _E("calloc failed");
271                 return -ENOMEM;
272 //LCOV_EXCL_STOP
273         }
274
275         ret = storage_ext_get_device_info(storage_id, dev);
276         if (ret < 0) {
277                 _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
278                 goto out;
279         }
280
281         snprintf(path, len, "%s", dev->mount_point);
282         ret = 0;
283
284 out:
285         storage_ext_release_device(&dev);
286         return ret;
287 }
288
289 int storage_ext_get_state(int storage_id, storage_state_e *state)
290 {
291         storage_ext_device *dev;
292         int ret;
293
294         if (storage_id < 0)
295                 return -ENOTSUP;
296
297         if (!state)
298                 return -EINVAL;
299
300         dev = calloc(1, sizeof(storage_ext_device));
301         if (!dev) {
302 //LCOV_EXCL_START System Error
303                 _E("calloc failed");
304                 return -ENOMEM;
305 //LCOV_EXCL_STOP
306         }
307
308         ret = storage_ext_get_device_info(storage_id, dev);
309         if (ret < 0) {
310                 _E("Cannot get the storage with id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
311                 goto out;
312         }
313
314         ret = storage_ext_get_dev_state(dev, STORAGE_EXT_CHANGED, state);
315         if (ret < 0)
316                 _E("Failed to get state of storage id (%d, ret:%d)", storage_id, ret); //LCOV_EXCL_LINE
317
318 out:
319         storage_ext_release_device(&dev);
320         return ret;
321 }
322
323 int storage_ext_get_primary_mmc_path(char *path, size_t len)
324 {
325         dd_list *list = NULL, *elem;
326         storage_ext_device *dev;
327         int ret;
328
329         ret = storage_ext_get_list(&list);
330         if (ret < 0) {
331                 _E("Failed to get external storage list from deviced (%d)", errno); //LCOV_EXCL_LINE
332                 return ret;
333         }
334
335         DD_LIST_FOREACH(list, elem, dev) {
336                 if (dev->primary) {
337                         snprintf(path, len, "%s", dev->mount_point);
338                         ret = 0;
339                         goto out;
340                 }
341         }
342
343         ret = -ENODEV;
344
345 out:
346         if (list)
347                 storage_ext_release_list(&list);
348         return ret;
349 }