Sync code with Tizen 3.0 branch
[platform/core/connectivity/mtp-responder.git] / src / entity / mtp_store.c
1 /*
2  * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
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 #include <glib.h>
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include <dirent.h>
21 #include "mtp_util.h"
22 #include "mtp_support.h"
23 #include "mtp_device.h"
24 #include "mtp_media_info.h"
25 #include "mtp_transport.h"
26 #include "mtp_inoti_handler.h"
27
28
29 extern mtp_char g_last_deleted[MTP_MAX_PATHNAME_SIZE + 1];
30 static mtp_uint32 g_next_obj_handle = 1;
31
32
33 static inline mtp_bool UTIL_CHECK_LIST_NEXT(slist_iterator *iter)
34 {
35         return (iter && iter->node_ptr) ? TRUE : FALSE;
36 }
37
38 static void __init_store_info(store_info_t *info)
39 {
40         ret_if(info == NULL);
41
42         memset(info, 0x00, sizeof(store_info_t));
43
44         info->store_type = PTP_STORAGETYPE_FIXEDRAM;
45         info->fs_type = PTP_FILESYSTEMTYPE_DCF;
46         info->access = PTP_STORAGEACCESS_RWD;
47
48         info->capacity = MTP_MAX_STORAGE;
49         info->free_space = MTP_MAX_STORAGE - 1;
50         info->free_space_in_objs = MTP_MAX_STORAGE_IN_OBJTS;
51
52         return;
53 }
54
55 static void __init_store_info_params(store_info_t *info,
56                 mtp_uint64 capacity, mtp_uint16 store_type, mtp_uint16 fs_type,
57                 mtp_uint16 access, mtp_wchar *store_desc, mtp_wchar *label)
58 {
59         info->store_type = store_type;
60         info->fs_type = fs_type;
61         info->access = access;
62
63         info->capacity = capacity;
64         info->free_space = capacity;
65         info->free_space_in_objs = MTP_MAX_STORAGE_IN_OBJTS;
66
67         _prop_copy_char_to_ptpstring(&(info->store_desc), store_desc, WCHAR_TYPE);
68         _prop_copy_char_to_ptpstring(&(info->vol_label), label, WCHAR_TYPE);
69         return;
70 }
71
72 void _entity_update_store_info_run_time(store_info_t *info,
73                 mtp_char *root_path)
74 {
75         fs_info_t fs_info = { 0 };
76
77         ret_if(info == NULL);
78         ret_if(root_path == NULL);
79
80         if (FALSE == _util_get_filesystem_info(root_path, &fs_info)) {
81                 ERR("_util_get_filesystem_info fail [%s]\n", root_path);
82                 return;
83         }
84
85         info->capacity = fs_info.disk_size;
86         info->free_space = fs_info.avail_size;
87
88         return;
89 }
90
91 mtp_bool _entity_get_store_path_by_id(mtp_uint32 store_id, mtp_char *path)
92 {
93         char sto_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
94
95         switch (store_id) {
96         case MTP_INTERNAL_STORE_ID:
97                 _util_get_internal_path(sto_path);
98                 g_strlcpy(path, sto_path,
99                                 MTP_MAX_PATHNAME_SIZE + 1);
100                 break;
101         case MTP_EXTERNAL_STORE_ID:
102                 _util_get_external_path(sto_path);
103                 g_strlcpy(path, sto_path,
104                                 MTP_MAX_PATHNAME_SIZE + 1);
105                 break;
106         default:
107                 ERR("No valid match for the store id [0x%x]\n", store_id);
108                 return FALSE;
109
110         }
111         return TRUE;
112 }
113
114 mtp_uint32 _entity_get_store_info_size(store_info_t *info)
115 {
116         mtp_uint32 size = FIXED_LENGTH_MEMBERS_MTPSTORE_SIZE;
117
118         size += _prop_size_ptpstring(&(info->store_desc));
119         size += _prop_size_ptpstring(&(info->vol_label));
120
121         return (size);
122 }
123
124 mtp_uint32 _entity_pack_store_info(store_info_t *info, mtp_uchar *buf,
125                 mtp_uint32 buf_sz)
126 {
127         mtp_uint32 num_bytes = 0;
128
129         retv_if(buf == NULL, 0);
130
131         if (buf_sz < _entity_get_store_info_size(info)) {
132                 ERR("Buffer size is less [%u]\n", buf_sz);
133                 return 0;
134         }
135 #ifdef __BIG_ENDIAN__
136         memcpy(&(buf[num_bytes]), &(info->store_type),
137                         sizeof(info->StorageType));
138         _util_conv_byte_order(buf, sizeof(info->store_type));
139         num_bytes += sizeof(info->store_type);
140
141         memcpy(&(buf[num_bytes]), &(info->fs_type), sizeof(info->fs_type));
142         _util_conv_byte_order(buf, sizeof(info->fs_type));
143         num_bytes += sizeof(info->fs_type);
144
145         memcpy(&(buf[num_bytes]), &(info->access), sizeof(info->access));
146         _util_conv_byte_order(buf, sizeof(info->access));
147         num_bytes += sizeof(info->access);
148
149         memcpy(&(buf[num_bytes]), &(info->capacity), sizeof(info->capacity));
150         _util_conv_byte_order(buf, sizeof(info->capacity));
151         num_bytes += sizeof(info->capacity);
152
153         memcpy(&(buf[num_bytes]), &(info->free_space),
154                         sizeof(info->free_space));
155         _util_conv_byte_order(buf, sizeof(info->free_space));
156         num_bytes += sizeof(info->free_space);
157
158         memcpy(&(buf[num_bytes]), &(info->free_space_in_objs),
159                         sizeof(info->free_space_in_objs));
160         _util_conv_byte_order(buf, sizeof(info->free_space_in_objs));
161         num_bytes += sizeof(info->free_space_in_objs);
162 #else /*__BIG_ENDIAN__*/
163         memcpy(buf, &(info->store_type), sizeof(mtp_uint16) *3);
164         num_bytes += sizeof(mtp_uint16) * 3;
165         memcpy(&(buf[num_bytes]), &(info->capacity),
166                         sizeof(mtp_uint64) * 2 + sizeof(mtp_uint32));
167         num_bytes += sizeof(mtp_uint64) * 2 + sizeof(mtp_uint32);
168 #endif /*__BIG_ENDIAN__*/
169         num_bytes += _prop_pack_ptpstring(&(info->store_desc), buf + num_bytes,
170                         _prop_size_ptpstring(&(info->store_desc)));
171
172         num_bytes += _prop_pack_ptpstring(&(info->vol_label), buf + num_bytes,
173                         _prop_size_ptpstring(&(info->vol_label)));
174
175         return num_bytes;
176 }
177
178 mtp_uint32 _entity_get_store_id_by_path(const mtp_char *path_name)
179 {
180         mtp_uint32 store_id = 0;
181         char ext_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
182         char inter_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
183
184         retv_if(NULL == path_name, FALSE);
185
186         _util_get_external_path(ext_path);
187         _util_get_internal_path(inter_path);
188
189         if (!strncmp(path_name, inter_path,
190                                 strlen(inter_path))) {
191                 store_id = MTP_INTERNAL_STORE_ID;
192         } else if (!strncmp(path_name, ext_path,
193                                 strlen(ext_path))) {
194                 store_id = MTP_EXTERNAL_STORE_ID;
195         }
196
197         DBG_SECURE("Path : %s, store_id : 0x%x\n", path_name, store_id);
198
199         return store_id;
200 }
201
202 mtp_bool _entity_init_mtp_store(mtp_store_t *store, mtp_uint32 store_id,
203                 mtp_char *store_path)
204 {
205         mtp_char temp[MTP_SERIAL_LEN_MAX + 1] = { 0 };
206         mtp_wchar wtemp[MTP_MAX_REG_STRING + 1] = { 0 };
207         mtp_char serial[MTP_MAX_REG_STRING + 1] = { 0 };
208         mtp_wchar wserial[MTP_MAX_REG_STRING + 1] = { 0 };
209
210         retv_if(store == NULL, FALSE);
211
212         store->store_id = store_id;
213         store->root_path = g_strdup(store_path);
214
215         __init_store_info(&(store->store_info));
216         _entity_update_store_info_run_time(&(store->store_info),
217                         store->root_path);
218
219         _device_get_serial(temp, sizeof(temp));
220         g_snprintf(serial, sizeof(serial), "%s-%x", temp, store_id);
221         _util_utf8_to_utf16(wserial, sizeof(wserial) / WCHAR_SIZ, serial);
222
223         switch (store_id) {
224         case MTP_INTERNAL_STORE_ID:
225                 store->is_hidden = FALSE;
226                 _util_utf8_to_utf16(wtemp, sizeof(wtemp) / WCHAR_SIZ,
227                                 MTP_STORAGE_DESC_INT);
228                 __init_store_info_params(&(store->store_info),
229                                 store->store_info.capacity, PTP_STORAGETYPE_FIXEDRAM,
230                                 PTP_FILESYSTEMTYPE_HIERARCHICAL, PTP_STORAGEACCESS_RWD,
231                                 wtemp, wserial);
232                 break;
233
234         case MTP_EXTERNAL_STORE_ID:
235                 store->is_hidden = FALSE;
236                 _util_utf8_to_utf16(wtemp, sizeof(wtemp) / WCHAR_SIZ,
237                                 MTP_STORAGE_DESC_EXT);
238                 __init_store_info_params(&(store->store_info),
239                                 store->store_info.capacity,
240                                 PTP_STORAGETYPE_REMOVABLERAM,
241                                 PTP_FILESYSTEMTYPE_HIERARCHICAL,
242                                 PTP_STORAGEACCESS_RWD, wtemp, wserial);
243                 break;
244
245         default:
246                 ERR("store initialization Fail");
247                 return FALSE;
248         }
249
250         _util_init_list(&(store->obj_list));
251
252         return TRUE;
253 }
254
255 mtp_obj_t *_entity_add_file_to_store(mtp_store_t *store, mtp_uint32 h_parent,
256                 mtp_char *file_path, mtp_char *file_name, dir_entry_t *file_info)
257 {
258         mtp_obj_t *obj = NULL;
259
260         retv_if(NULL == store, NULL);
261
262         obj = _entity_alloc_mtp_object();
263         if (NULL == obj) {
264                 ERR("Memory allocation Fail");
265                 return NULL;
266         }
267
268         if (_entity_init_mtp_object_params(obj, store->store_id, h_parent,
269                                 file_path, file_name, file_info) == FALSE) {
270                 ERR("_entity_init_mtp_object_params Fail");
271                 g_free(obj);
272                 return NULL;
273         }
274
275         _entity_add_object_to_store(store, obj);
276         return obj;
277 }
278
279 mtp_obj_t *_entity_add_folder_to_store(mtp_store_t *store, mtp_uint32 h_parent,
280                 mtp_char *file_path, mtp_char *file_name, dir_entry_t *file_info)
281 {
282         mtp_obj_t *obj = NULL;
283
284         retv_if(NULL == store, NULL);
285
286         obj = _entity_alloc_mtp_object();
287         if (NULL == obj) {
288                 ERR("Memory allocation Fail");
289                 return NULL;
290         }
291
292         if (_entity_init_mtp_object_params(obj, store->store_id, h_parent,
293                                 file_path, file_name, file_info) == FALSE) {
294                 ERR("_entity_init_mtp_object_params Fail");
295                 g_free(obj);
296                 return NULL;
297         }
298
299         _entity_add_object_to_store(store, obj);
300         return obj;
301 }
302
303 mtp_bool _entity_add_object_to_store(mtp_store_t *store, mtp_obj_t *obj)
304 {
305         mtp_obj_t *par_obj = NULL;
306
307         retv_if(obj == NULL, FALSE);
308         retv_if(NULL == store, FALSE);
309         retv_if(obj->obj_info == NULL, FALSE);
310
311         if (_util_add_node(&(store->obj_list), obj) == FALSE) {
312                 ERR("Node add to list Fail");
313                 return FALSE;
314         }
315
316         /* references */
317         if (PTP_OBJECTHANDLE_ROOT != obj->obj_info->h_parent) {
318                 par_obj = _entity_get_object_from_store(store, obj->obj_info->h_parent);
319                 if (NULL != par_obj)
320                         _entity_add_reference_child_array(par_obj, obj->obj_handle);
321         }
322
323         return TRUE;
324 }
325
326 mtp_obj_t *_entity_get_object_from_store(mtp_store_t *store, mtp_uint32 handle)
327 {
328         mtp_obj_t *obj = NULL;
329         slist_iterator *iter = NULL;
330
331         retv_if(NULL == store, NULL);
332
333         iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list));
334         if (iter == NULL) {
335                 ERR("Iterator init Fail, Store id = [0x%x]\n", store->store_id);
336                 return NULL;
337         }
338
339         while (UTIL_CHECK_LIST_NEXT(iter) == TRUE) {
340                 obj = (mtp_obj_t *)_util_get_list_next(iter);
341
342                 if (obj && obj->obj_handle == handle) {
343                         _util_deinit_list_iterator(iter);
344                         return obj;
345                 }
346         }
347
348         ERR("Object not found in the list handle [%d] in store[0x%x]\n", handle, store->store_id);
349         _util_deinit_list_iterator(iter);
350         return NULL;
351 }
352
353 mtp_obj_t *_entity_get_last_object_from_store(mtp_store_t *store,
354                 mtp_uint32 handle)
355 {
356         mtp_obj_t *obj = NULL;
357         mtp_obj_t *temp_obj = NULL;
358         slist_iterator *iter = NULL;
359
360         retv_if(NULL == store, NULL);
361
362         iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list));
363         if (iter == NULL) {
364                 ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id);
365                 return NULL;
366         }
367
368         while (UTIL_CHECK_LIST_NEXT(iter) == TRUE) {
369
370                 temp_obj = (mtp_obj_t *)_util_get_list_next(iter);
371                 if (temp_obj && temp_obj->obj_handle == handle)
372                         obj = temp_obj;
373         }
374
375         _util_deinit_list_iterator(iter);
376         return obj;
377 }
378
379 mtp_obj_t *_entity_get_object_from_store_by_path(mtp_store_t *store,
380                 mtp_char *file_path)
381 {
382         mtp_obj_t *obj = NULL;
383         slist_iterator *iter = NULL;
384
385         retv_if(NULL == store, NULL);
386
387         iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list));
388         if (iter == NULL) {
389                 ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id);
390                 return NULL;
391         }
392
393         while (UTIL_CHECK_LIST_NEXT(iter) == TRUE) {
394                 obj = (mtp_obj_t *)_util_get_list_next(iter);
395                 if (obj == NULL) {
396                         ERR("Object is NULL");
397                         continue;
398                 }
399
400                 if (!g_strcmp0(file_path, obj->file_path)) {
401                         _util_deinit_list_iterator(iter);
402                         return obj;
403                 }
404         }
405         ERR_SECURE("Object [%s] not found in the list\n", file_path);
406         _util_deinit_list_iterator(iter);
407         return NULL;
408 }
409
410 /*
411  * _entity_get_objects_from_store
412  * called in case of PTP_OBJECTHANDLE_ALL
413  * fills the obj_array with objects matching the format code
414  */
415 mtp_uint32 _entity_get_objects_from_store(mtp_store_t *store,
416                 mtp_uint32 obj_handle, mtp_uint32 fmt, ptp_array_t *obj_arr)
417 {
418         mtp_obj_t *obj = NULL;
419         slist_iterator *iter = NULL;
420
421         retv_if(store == NULL, 0);
422         retv_if(obj_arr == NULL, 0);
423
424         if (obj_handle != PTP_OBJECTHANDLE_ALL) {
425                 ERR("Object Handle is not PTP_OBJECTHANDLE_ALL");
426                 return 0;
427         }
428
429         iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list));
430         if (iter == NULL) {
431                 ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id);
432                 return 0;
433         }
434
435         while (UTIL_CHECK_LIST_NEXT(iter) == TRUE) {
436
437                 obj = (mtp_obj_t *)_util_get_list_next(iter);
438                 if (obj == NULL) {
439                         ERR("Object is NULL");
440                         continue;
441                 }
442                 if ((fmt == obj->obj_info->obj_fmt) ||
443                                 (fmt == PTP_FORMATCODE_ALL) ||
444                                 (fmt == PTP_FORMATCODE_NOTUSED)) {
445                         _prop_append_ele_ptparray(obj_arr, obj->obj_handle);
446                 }
447         }
448         _util_deinit_list_iterator(iter);
449         return obj_arr->num_ele;
450 }
451
452 mtp_uint32 _entity_get_objects_from_store_till_depth(mtp_store_t *store,
453                 mtp_uint32 obj_handle, mtp_uint32 fmt_code, mtp_uint32 depth,
454                 ptp_array_t *obj_arr)
455 {
456         retv_if(store == NULL, 0);
457         retv_if(obj_arr == NULL, 0);
458
459         if (PTP_OBJECTHANDLE_ALL == obj_handle) {
460                 _entity_get_objects_from_store(store, obj_handle, fmt_code,
461                                 obj_arr);
462                 DBG("Number of object filled [%u]\n", obj_arr->num_ele);
463                 return obj_arr->num_ele;
464         }
465
466         if (PTP_OBJECTHANDLE_ROOT != obj_handle)
467                 _prop_append_ele_ptparray(obj_arr, obj_handle);
468
469         if (depth > 0) {
470                 ptp_array_t *child_arr = NULL;
471                 mtp_uint32 *ptr = NULL;
472                 mtp_uint32 ii = 0;
473
474                 child_arr = _prop_alloc_ptparray(UINT32_TYPE);
475                 if (child_arr == NULL || child_arr->array_entry == NULL)
476                         return 0;
477
478                 depth--;
479
480                 _entity_get_child_handles_with_same_format(store, obj_handle,
481                                 fmt_code, child_arr);
482                 ptr = child_arr->array_entry;
483
484                 for (ii = 0; ii < child_arr->num_ele; ii++) {
485                         _entity_get_objects_from_store_till_depth(store,
486                                         ptr[ii], fmt_code, depth, obj_arr);
487                 }
488                 _prop_destroy_ptparray(child_arr);
489         }
490
491         DBG("Handle[%u] : array count [%u]!!\n", obj_handle,
492                         obj_arr->num_ele);
493         return obj_arr->num_ele;
494 }
495
496 mtp_uint32 _entity_get_objects_from_store_by_format(mtp_store_t *store,
497                 mtp_uint32 format, ptp_array_t *obj_arr)
498 {
499         mtp_obj_t *obj = NULL;
500         slist_iterator *iter = NULL;
501
502         retv_if(store == NULL, 0);
503         retv_if(obj_arr == NULL, 0);
504
505         iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list));
506         if (iter == NULL) {
507                 ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id);
508                 return 0;
509         }
510
511         while (UTIL_CHECK_LIST_NEXT(iter) == TRUE) {
512
513                 obj = (mtp_obj_t *)_util_get_list_next(iter);
514                 if (obj == NULL || obj->obj_info == NULL)
515                         continue;
516                 if ((format == PTP_FORMATCODE_NOTUSED) ||
517                                 (format == obj->obj_info->obj_fmt) ||
518                                 ((format == PTP_FORMATCODE_ALL) &&
519                                  (obj->obj_info->obj_fmt !=
520                                   PTP_FMT_ASSOCIATION))) {
521                         _prop_append_ele_ptparray(obj_arr,
522                                         (mtp_uint32)obj->obj_handle);
523                 }
524
525         }
526
527         _util_deinit_list_iterator(iter);
528         return (obj_arr->num_ele);
529 }
530
531 mtp_uint32 _entity_get_num_object_with_same_format(mtp_store_t *store,
532                 mtp_uint32 format)
533 {
534         mtp_uint32 count = 0;
535         mtp_obj_t *obj = NULL;
536         slist_iterator *iter = NULL;
537
538         retv_if(store == NULL, 0);
539
540         if (PTP_FORMATCODE_NOTUSED == format)
541                 return store->obj_list.nnodes;
542
543         iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list));
544         if (iter == NULL) {
545                 ERR("Iterator init Fail, store id = [0x%x]\n", store->store_id);
546                 return 0;
547         }
548
549         while (UTIL_CHECK_LIST_NEXT(iter) == TRUE) {
550
551                 obj = (mtp_obj_t *)_util_get_list_next(iter);
552                 if (obj == NULL || obj->obj_info == NULL)
553                         continue;
554
555                 if ((obj->obj_info->obj_fmt == format) ||
556                                 (obj->obj_info->obj_fmt != PTP_FMT_ASSOCIATION &&
557                                  PTP_FORMATCODE_ALL == format)) {
558                         count++;
559                 }
560         }
561
562         _util_deinit_list_iterator(iter);
563         return count;
564 }
565
566 mtp_uint32 _entity_get_num_children(mtp_store_t *store, mtp_uint32 h_parent,
567                 mtp_uint32 format)
568 {
569         mtp_uint32 count = 0;
570         mtp_obj_t *obj = NULL;
571         slist_iterator *iter = NULL;
572
573         retv_if(store == NULL, 0);
574
575         iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list));
576         if (iter == NULL) {
577                 ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id);
578                 return 0;
579         }
580
581         while (UTIL_CHECK_LIST_NEXT(iter) == TRUE) {
582
583                 obj = (mtp_obj_t *)_util_get_list_next(iter);
584                 if (obj == NULL || obj->obj_info == NULL)
585                         continue;
586
587                 if ((obj->obj_info->h_parent == h_parent) &&
588                                 ((format == obj->obj_info->obj_fmt) ||
589                                  (format == PTP_FORMATCODE_NOTUSED) ||
590                                  ((format == PTP_FORMATCODE_ALL) &&
591                                   (obj->obj_info->obj_fmt !=
592                                    PTP_FMT_ASSOCIATION)))) {
593                         count++;
594                 }
595         }
596
597         _util_deinit_list_iterator(iter);
598         return count;
599 }
600
601 mtp_uint32 _entity_get_child_handles(mtp_store_t *store, mtp_uint32 h_parent,
602                 ptp_array_t *child_arr)
603 {
604         mtp_obj_t *obj = NULL;
605         slist_iterator *iter = NULL;
606         mtp_obj_t *parent_obj = NULL;
607
608         retv_if(store == NULL, 0);
609         retv_if(child_arr == NULL, 0);
610
611         parent_obj = _entity_get_object_from_store(store, h_parent);
612
613         if (NULL == parent_obj) {
614                 ERR("parent object is NULL");
615                 return FALSE;
616         }
617
618         iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list));
619         if (iter == NULL) {
620                 ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id);
621                 return 0;
622         }
623
624         while (UTIL_CHECK_LIST_NEXT(iter) == TRUE) {
625
626                 obj = (mtp_obj_t *)_util_get_list_next(iter);
627                 if (obj == NULL || obj->obj_info == NULL)
628                         continue;
629
630                 if (obj->obj_info->h_parent == h_parent)
631                         _prop_append_ele_ptparray(child_arr, obj->obj_handle);
632         }
633
634         _util_deinit_list_iterator(iter);
635         return child_arr->num_ele;
636 }
637
638 mtp_uint32 _entity_get_child_handles_with_same_format(mtp_store_t *store,
639                 mtp_uint32 h_parent, mtp_uint32 format, ptp_array_t *child_arr)
640 {
641         mtp_obj_t *obj = NULL;
642         slist_iterator *iter = NULL;
643
644         retv_if(store == NULL, 0);
645         retv_if(child_arr == NULL, 0);
646
647         iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list));
648         if (iter == NULL) {
649                 ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id);
650                 return 0;
651         }
652
653         while (UTIL_CHECK_LIST_NEXT(iter) == TRUE) {
654
655                 obj = (mtp_obj_t *)_util_get_list_next(iter);
656                 if (obj == NULL || obj->obj_info == NULL)
657                         continue;
658
659                 if ((obj->obj_info->h_parent == h_parent) &&
660                                 ((obj->obj_info->obj_fmt == format) ||
661                                  (format == PTP_FORMATCODE_NOTUSED))) {
662
663                         _prop_append_ele_ptparray(child_arr, obj->obj_handle);
664                 }
665
666         }
667
668         _util_deinit_list_iterator(iter);
669         return child_arr->num_ele;
670 }
671
672 mtp_bool _entity_remove_object_mtp_store(mtp_store_t *store, mtp_obj_t *obj,
673                 mtp_uint32 format, mtp_uint16 *response, mtp_bool *atleast_one,
674                 mtp_bool read_only)
675 {
676         mtp_uint64 size = 0;
677         mtp_bool all_del = TRUE;
678         mtp_uint32 h_parent = 0;
679         obj_info_t *objinfo = NULL;
680         mtp_int32 ret = MTP_ERROR_NONE;
681
682         retv_if(store == NULL, 0);
683
684         if (TRUE == _transport_get_cancel_initialization() ||
685                         TRUE == _transport_get_usb_discon_state()) {
686                 ERR("Delete operation cancelled or USB is disconnected");
687                 *response = PTP_RESPONSE_PARTIAL_DELETION;
688                 return FALSE;
689         }
690
691         if (NULL == obj || NULL == obj->obj_info || NULL == store) {
692                 *response = PTP_RESPONSE_UNDEFINED;
693                 return FALSE;
694         }
695
696         objinfo = obj->obj_info;
697
698         if ((objinfo->obj_fmt != format) && (format != PTP_FORMATCODE_ALL) &&
699                         (format != PTP_FORMATCODE_NOTUSED)) {
700                 *response = PTP_RESPONSE_UNDEFINED;
701                 return FALSE;
702         }
703
704         if ((PTP_FORMATCODE_ALL == format) &&
705                         (PTP_FMT_ASSOCIATION == objinfo->obj_fmt)) {
706
707                 *response = PTP_RESPONSE_UNDEFINED;
708                 return FALSE;
709         }
710
711 #ifdef MTP_SUPPORT_SET_PROTECTION
712         /* Delete readonly files/folder */
713         if (!read_only)
714                 objinfo->protcn_status = PTP_PROTECTIONSTATUS_NOPROTECTION;
715 #endif /* MTP_SUPPORT_SET_PROTECTION */
716
717         if (PTP_FMT_ASSOCIATION == objinfo->obj_fmt) {
718                 /* If this is an association, delete children first
719                  * the reference list contain all the children handle
720                  * or find a child each time;
721                  */
722
723                 mtp_uint32 i = 0;
724                 ptp_array_t child_arr = { 0 };
725                 mtp_obj_t *child_obj = NULL;
726
727                 _prop_init_ptparray(&child_arr, UINT32_TYPE);
728                 _entity_get_child_handles(store, obj->obj_handle, &child_arr);
729
730                 if (child_arr.num_ele) {
731
732                         for (i = 0; i < child_arr.num_ele; i++) {
733                                 mtp_uint32 *ptr32 = child_arr.array_entry;
734                                 /*check cancel transaction*/
735                                 if (_transport_get_cancel_initialization() == TRUE ||
736                                                 _transport_get_usb_discon_state() == TRUE) {
737                                         ERR("child handle. USB is disconnected \
738                                                         format operation is cancelled.");
739                                         *response =
740                                                 PTP_RESPONSE_PARTIAL_DELETION;
741                                         return FALSE;
742                                 }
743
744                                 child_obj = _entity_get_object_from_store(store,
745                                                 ptr32[i]);
746                                 if (NULL == child_obj)
747                                         continue;
748
749                                 if (_entity_remove_object_mtp_store(store, child_obj,
750                                                         format, response, atleast_one,
751                                                         read_only)) {
752                                         slist_node_t *node;
753                                         node = _util_delete_node(&(store->obj_list),
754                                                         child_obj);
755                                         g_free(node);
756                                         *atleast_one = TRUE;
757                                         _entity_dealloc_mtp_obj(child_obj);
758                                 } else {
759                                         all_del = FALSE;
760                                         /*check cancel transaction*/
761                                         if (TRUE == _transport_get_cancel_initialization() ||
762                                                         TRUE == _transport_get_usb_discon_state()) {
763                                                 ERR("USB is disconnected format\
764                                                                 operation is cancelled.");
765                                                 *response =
766                                                         PTP_RESPONSE_PARTIAL_DELETION;
767                                                 return FALSE;
768                                         }
769                                 }
770
771                         }
772                         _prop_deinit_ptparray(&child_arr);
773
774                 } else {
775                         /* Non-Enumerated Folder */
776                         mtp_uint32 num_of_deleted_file = 0;
777                         mtp_uint32 num_of_file = 0;
778
779                         ret = _util_remove_dir_children_recursive(obj->file_path,
780                                         &num_of_deleted_file, &num_of_file, read_only);
781                         if (MTP_ERROR_GENERAL == ret ||
782                                         MTP_ERROR_ACCESS_DENIED == ret) {
783                                 ERR_SECURE("directory children deletion Fail [%s]\n",
784                                                 obj->file_path);
785                                 *response = PTP_RESPONSE_GEN_ERROR;
786                                 if (MTP_ERROR_ACCESS_DENIED == ret)
787                                         *response =
788                                                 PTP_RESPONSE_ACCESSDENIED;
789                                 return FALSE;
790                         }
791                         if (num_of_file == 0)
792                                 DBG_SECURE("Folder[%s] is empty\n", obj->file_path);
793                         else if (num_of_deleted_file == 0) {
794                                 DBG_SECURE("Folder[%s] contains only read-only files\n",
795                                                 obj->file_path);
796                                 all_del = FALSE;
797                         } else if (num_of_deleted_file < num_of_file) {
798                                 DBG("num of files[%d] is present in folder[%s]\
799                                                 and number of deleted files[%d]\n",
800                                                 num_of_file, obj->file_path,
801                                                 num_of_deleted_file);
802                                 *atleast_one = TRUE;
803                                 all_del = FALSE;
804                         }
805                 }
806                 _util_scan_folder_contents_in_db(obj->file_path);
807                 if (all_del) {
808                         g_snprintf(g_last_deleted,
809                                         MTP_MAX_PATHNAME_SIZE + 1, "%s",
810                                         obj->file_path);
811
812                         if (rmdir(obj->file_path) < 0) {
813                                 memset(g_last_deleted, 0,
814                                                 MTP_MAX_PATHNAME_SIZE + 1);
815                                 *response = PTP_RESPONSE_GEN_ERROR;
816                                 if (EACCES == errno)
817                                         *response =
818                                                 PTP_RESPONSE_ACCESSDENIED;
819                                 return FALSE;
820                         }
821                 } else {
822                         ERR("all member in this folder is not deleted.");
823                 }
824         } else {
825 #ifdef MTP_SUPPORT_SET_PROTECTION
826                 size = objinfo->file_size;
827 #endif /* MTP_SUPPORT_SET_PROTECTION */
828
829                 if (objinfo->protcn_status ==
830                                 PTP_PROTECTIONSTATUS_READONLY ||
831                                 objinfo->protcn_status ==
832                                 MTP_PROTECTIONSTATUS_READONLY_DATA) {
833                         *response = PTP_RESPONSE_OBJ_WRITEPROTECTED;
834                         return FALSE;
835                 }
836
837                 /* delete the real file */
838                 g_snprintf(g_last_deleted, MTP_MAX_PATHNAME_SIZE + 1,
839                                 "%s", obj->file_path);
840                 if (remove(obj->file_path) < 0) {
841                         memset(g_last_deleted, 0,
842                                         MTP_MAX_PATHNAME_SIZE + 1);
843                         *response = PTP_RESPONSE_GEN_ERROR;
844                         if (EACCES == errno)
845                                 *response = PTP_RESPONSE_ACCESSDENIED;
846                         return FALSE;
847                 }
848                 *atleast_one = TRUE;
849
850                 /* Upate store's available space */
851                 store->store_info.free_space += size;
852         }
853
854         if (all_del) {
855                 *response = PTP_RESPONSE_OK;
856                 /* delete references;*/
857                 h_parent = objinfo->h_parent;
858                 if (h_parent != PTP_OBJECTHANDLE_ROOT) {
859                         mtp_obj_t *parent_obj =
860                                 _entity_get_object_from_store(store, h_parent);
861                         if (NULL != parent_obj) {
862                                 _entity_remove_reference_child_array(parent_obj,
863                                                 obj->obj_handle);
864                         }
865                 }
866         } else if (*atleast_one) {
867                 *response = PTP_RESPONSE_PARTIAL_DELETION;
868                 return FALSE;
869         } else {
870                 *response = PTP_RESPONSE_OBJ_WRITEPROTECTED;
871                 return FALSE;
872         }
873
874         return TRUE;
875 }
876
877 mtp_uint16 _entity_delete_obj_mtp_store(mtp_store_t *store,
878                 mtp_uint32 obj_handle, mtp_uint32 fmt, mtp_bool read_only)
879 {
880         mtp_uint16 response;
881         mtp_obj_t *obj = NULL;
882         mtp_bool all_del = TRUE;
883         mtp_bool atleas_one = FALSE;
884
885         retv_if(store == NULL, PTP_RESPONSE_GEN_ERROR);
886
887         if (PTP_STORAGEACCESS_R == store->store_info.access) {
888                 ERR("Read only store");
889                 return PTP_RESPONSE_STORE_READONLY;
890         }
891
892         if (PTP_OBJECTHANDLE_ALL == obj_handle) {
893                 slist_node_t *node = NULL;
894                 node = store->obj_list.start;
895                 while (NULL != node) {
896                         if (TRUE == _transport_get_cancel_initialization() ||
897                                         TRUE == _transport_get_usb_discon_state()) {
898                                 ERR("USB is disconnected format\
899                                                 operation is cancelled.");
900                                 response = PTP_RESPONSE_GEN_ERROR;
901                                 return response;
902                         }
903                         /* protect from disconnect USB */
904                         if (NULL == store || NULL == node ||
905                                         NULL == node->value) {
906                                 response = PTP_RESPONSE_GEN_ERROR;
907                                 return response;
908                         }
909
910                         obj = (mtp_obj_t *)node->value;
911                         if (_entity_remove_object_mtp_store(store, obj,
912                                                 fmt, &response, &atleas_one, read_only)) {
913
914                                 slist_node_t *temp = NULL;
915
916                                 node = node->link;
917                                 temp = _util_delete_node(&(store->obj_list), obj);
918                                 g_free(temp);
919                                 _util_delete_file_from_db(obj->file_path);
920                                 _entity_dealloc_mtp_obj(obj);
921                         } else {
922                                 node = node->link;
923                         }
924
925                         switch (response) {
926                         case PTP_RESPONSE_PARTIAL_DELETION:
927                                 all_del = FALSE;
928                                 break;
929                         case PTP_RESPONSE_OBJ_WRITEPROTECTED:
930                         case PTP_RESPONSE_ACCESSDENIED:
931                                 all_del = FALSE;
932                                 break;
933                         case PTP_RESPONSE_UNDEFINED:
934                         default:
935                                 break;
936                         }
937
938                 }
939         } else {
940                 DBG("object handle is not PTP_OBJECTHANDLE_ALL. [%ld]\n",
941                                 obj_handle);
942                 obj = _entity_get_object_from_store(store, obj_handle);
943
944                 if (NULL != obj) {
945                         if (_entity_remove_object_mtp_store(store, obj, PTP_FORMATCODE_NOTUSED,
946                                                 &response, &atleas_one, read_only)) {
947                                 slist_node_t *temp = NULL;
948
949                                 temp = _util_delete_node(&(store->obj_list), obj);
950                                 g_free(temp);
951                                 _util_delete_file_from_db(obj->file_path);
952                                 _entity_dealloc_mtp_obj(obj);
953                         } else {
954                                 switch (response) {
955                                 case PTP_RESPONSE_PARTIAL_DELETION:
956                                         all_del = FALSE;
957                                         break;
958                                 case PTP_RESPONSE_OBJ_WRITEPROTECTED:
959                                 case PTP_RESPONSE_ACCESSDENIED:
960                                         all_del = FALSE;
961                                         break;
962                                 case PTP_RESPONSE_UNDEFINED:
963                                 default:
964                                         /* do nothing */
965                                         break;
966                                 }
967                         }
968                 }
969         }
970
971         if (all_del)
972                 response = PTP_RESPONSE_OK;
973         else if (atleas_one)
974                 response = PTP_RESPONSE_PARTIAL_DELETION;
975
976         return response;
977 }
978
979 mtp_uint32 _entity_get_object_tree_size(mtp_store_t *store, mtp_obj_t *obj)
980 {
981         mtp_uint32 i = 0;
982         mtp_uint64 size = 0;
983
984         retv_if(store == NULL, 0);
985         retv_if(obj == NULL, 0);
986
987         if (obj->obj_info->obj_fmt != PTP_FMT_ASSOCIATION) {
988                 size = obj->obj_info->file_size;
989         } else {
990                 ptp_array_t child_arr = { 0 };
991                 mtp_obj_t *child_obj = NULL;
992
993                 _prop_init_ptparray(&child_arr, UINT32_TYPE);
994
995                 _entity_get_child_handles(store, obj->obj_handle, &child_arr);
996
997                 for (i = 0; i < child_arr.num_ele; i++) {
998                         mtp_uint32 *ptr32 = child_arr.array_entry;
999                         child_obj = _entity_get_object_from_store(store,
1000                                         ptr32[i]);
1001                         size += _entity_get_object_tree_size(store, child_obj);
1002                 }
1003                 _prop_deinit_ptparray(&child_arr);
1004         }
1005
1006         return size;
1007 }
1008
1009 mtp_bool _entity_check_if_B_parent_of_A(mtp_store_t *store,
1010                 mtp_uint32 handleA, mtp_uint32 handleB)
1011 {
1012         mtp_uint32 i = 0;
1013         mtp_obj_t *obj = NULL;
1014         ptp_array_t child_arr = {0};
1015
1016         retv_if(store == NULL, FALSE);
1017
1018         _prop_init_ptparray(&child_arr, UINT32_TYPE);
1019         _entity_get_child_handles(store, handleB, &child_arr);
1020
1021         for (i = 0; i < child_arr.num_ele; i++) {
1022                 mtp_uint32 *ptr32 = child_arr.array_entry;
1023                 if (handleA == ptr32[i]) {
1024                         _prop_deinit_ptparray(&child_arr);
1025                         return TRUE;
1026                 }
1027
1028                 obj = _entity_get_object_from_store(store, ptr32[i]);
1029                 if (obj == NULL || obj->obj_info == NULL ||
1030                                 obj->obj_info->obj_fmt ==
1031                                 PTP_FMT_ASSOCIATION) {
1032                         continue;
1033                 }
1034                 if (_entity_check_if_B_parent_of_A(store, handleA, ptr32[i])) {
1035                         _prop_deinit_ptparray(&child_arr);
1036                         return TRUE;
1037                 }
1038         }
1039         _prop_deinit_ptparray(&child_arr);
1040         return FALSE;
1041 }
1042
1043 mtp_uint32 _entity_generate_next_obj_handle(void)
1044 {
1045         return g_next_obj_handle++;
1046 }
1047
1048 mtp_uint16 _entity_format_store(mtp_store_t *store, mtp_uint32 fs_format)
1049 {
1050         mtp_uint16 response;
1051
1052         retv_if(store == NULL, PTP_RESPONSE_GEN_ERROR);
1053
1054         /* Is store ready only? */
1055         if (store->store_info.access == PTP_STORAGEACCESS_R) {
1056                 ERR("Read only storage");
1057                 return PTP_RESPONSE_STORE_READONLY;
1058         }
1059
1060         /* Is FilesystemFormat supported? */
1061         if ((fs_format != PTP_FILESYSTEMTYPE_UNDEFINED) &&
1062                         (fs_format != PTP_FILESYSTEMTYPE_FLAT) &&
1063                         (fs_format != PTP_FILESYSTEMTYPE_HIERARCHICAL) &&
1064                         (fs_format != PTP_FILESYSTEMTYPE_DCF)) {
1065                 ERR("File system type not supported");
1066                 return PTP_RESPONSE_INVALIDPARAM;
1067         }
1068
1069         /* check cancel transaction */
1070         if (TRUE == _transport_get_cancel_initialization() ||
1071                         TRUE == _transport_get_usb_discon_state()) {
1072                 ERR("USB is disconnected format operation is cancelled.");
1073                 return PTP_RESPONSE_GEN_ERROR;
1074         }
1075
1076         response = _entity_delete_obj_mtp_store(store, PTP_OBJECTHANDLE_ALL,
1077                         PTP_FORMATCODE_NOTUSED, TRUE);
1078
1079         if (PTP_RESPONSE_OK != response) {
1080                 ERR("format is not completed [0x%X].\n", response);
1081                 return response;
1082         }
1083
1084         return PTP_RESPONSE_OK;
1085 }
1086
1087 void _entity_destroy_mtp_store(mtp_store_t *store)
1088 {
1089         mtp_uint32 ii = 0;
1090         slist_node_t *node = NULL;
1091         slist_node_t *next_node = NULL;
1092
1093         ret_if(store == NULL);
1094
1095         for (ii = 0, next_node = store->obj_list.start;
1096                         ii < store->obj_list.nnodes; ii++) {
1097
1098                 node = next_node;
1099                 next_node = node->link;
1100                 _entity_dealloc_mtp_obj((mtp_obj_t *)node->value);
1101                 g_free(node);
1102         }
1103
1104         _util_init_list(&(store->obj_list));
1105         return;
1106 }
1107
1108 void _entity_store_recursive_enum_folder_objects(mtp_store_t *store,
1109                 mtp_obj_t *pobj)
1110 {
1111         DIR *h_dir = 0;
1112         mtp_char file_name[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1113         mtp_bool status = FALSE;
1114         mtp_obj_t *obj = NULL;
1115         dir_entry_t entry = { { 0 }, 0 };
1116         mtp_char *folder_name;
1117         mtp_uint32 h_parent;
1118
1119         ret_if(NULL == store);
1120
1121         if (!pobj) {
1122                 folder_name = store->root_path;
1123                 h_parent = PTP_OBJECTHANDLE_ROOT;
1124         } else {
1125                 folder_name = pobj->file_path;
1126                 h_parent = pobj->obj_handle;
1127         }
1128
1129         if (folder_name == NULL || folder_name[0] != '/') {
1130                 ERR("foldername has no root slash!!");
1131                 return;
1132         }
1133
1134         if (FALSE == _util_ifind_first(folder_name, &h_dir, &entry)) {
1135                 DBG("No more files");
1136                 return;
1137         }
1138
1139         do {
1140                 if (TRUE == _transport_get_usb_discon_state()) {
1141                         DBG("USB is disconnected");
1142                         if (closedir(h_dir) < 0)
1143                                 ERR("Close directory Fail");
1144
1145                         return;
1146                 }
1147
1148                 _util_get_file_name(entry.filename, file_name);
1149                 if (0 == strlen(file_name)) {
1150                         ERR("szFilename size is 0");
1151                         goto NEXT;
1152                 }
1153
1154                 if (file_name[0] == '.') {
1155                         DBG_SECURE("Hidden file [%s]\n", entry.filename);
1156                 } else if (entry.type == MTP_DIR_TYPE) {
1157                         obj = _entity_add_folder_to_store(store, h_parent,
1158                                         entry.filename, file_name, &entry);
1159
1160                         if (NULL == obj) {
1161                                 ERR("pObject is NULL");
1162                                 goto NEXT;
1163                         }
1164
1165                         _entity_store_recursive_enum_folder_objects(store, obj);
1166                 } else if (entry.type == MTP_FILE_TYPE) {
1167                         _entity_add_file_to_store(store, h_parent,
1168                                         entry.filename, file_name, &entry);
1169                 } else {
1170                         DBG("UNKNOWN TYPE");
1171                 }
1172 NEXT:
1173                 status = (mtp_bool)_util_ifind_next(folder_name, h_dir,
1174                                 &entry);
1175         } while (status);
1176
1177         if (closedir(h_dir) < 0)
1178                 ERR("close directory fail");
1179
1180 #ifdef MTP_SUPPORT_OBJECTADDDELETE_EVENT
1181         _inoti_add_watch_for_fs_events(folder_name);
1182 #endif /*MTP_SUPPORT_OBJECTADDDELETE_EVENT*/
1183
1184         return;
1185 }
1186
1187 void _entity_list_modified_files(mtp_uint32 minutes)
1188 {
1189         if (minutes == 0)
1190                 return;
1191         mtp_int32 ret;
1192         mtp_char command[FIND_CMD_LEN] = { 0 };
1193
1194         if (TRUE == _device_is_store_mounted(MTP_STORAGE_INTERNAL)) {
1195                 char inter_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1196                 _util_get_internal_path(inter_path);
1197
1198                 g_snprintf(command, FIND_CMD_LEN, FIND_CMD,
1199                                 inter_path, minutes,
1200                                 MTP_FILES_MODIFIED_FILES);
1201                 DBG("find query is [%s]\n", command);
1202                 ret = system(command);
1203                 if (WIFSIGNALED(ret) &&
1204                                 (WTERMSIG(ret) == SIGINT ||
1205                                  WTERMSIG(ret) == SIGQUIT)) {
1206                         ERR("SYSTEM Fail");
1207                         return;
1208                 }
1209         }
1210         if (TRUE == _device_is_store_mounted(MTP_STORAGE_EXTERNAL)) {
1211                 char ext_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1212                 _util_get_external_path(ext_path);
1213
1214                 g_snprintf(command, FIND_CMD_LEN, FIND_CMD,
1215                                 ext_path, minutes,
1216                                 MTP_FILES_MODIFIED_FILES);
1217                 DBG("find query is [%s]\n", command);
1218                 ret = system(command);
1219                 if (WIFSIGNALED(ret) &&
1220                                 (WTERMSIG(ret) == SIGINT ||
1221                                  WTERMSIG(ret) == SIGQUIT)) {
1222                         ERR("SYSTEM Fail");
1223                         return;
1224                 }
1225         }
1226
1227         return;
1228 }
1229
1230 void _entity_copy_store_data(mtp_store_t *dst, mtp_store_t *src)
1231 {
1232         dst->store_id = src->store_id;
1233         dst->root_path = src->root_path;
1234         dst->is_hidden = src->is_hidden;
1235
1236         memcpy(&(dst->obj_list), &(src->obj_list), sizeof(slist_t));
1237         _entity_update_store_info_run_time(&(dst->store_info), dst->root_path);
1238         _prop_copy_ptpstring(&(dst->store_info.store_desc), &(src->store_info.store_desc));
1239         _prop_copy_ptpstring(&(dst->store_info.vol_label), &(src->store_info.vol_label));
1240
1241         return;
1242 }