2 * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <glib/gprintf.h>
20 #include "mtp_cmd_handler.h"
21 #include "mtp_cmd_handler_util.h"
22 #include "mtp_support.h"
23 #include "mtp_media_info.h"
24 #include "mtp_transport.h"
27 * GLOBAL AND EXTERN VARIABLES
29 mtp_bool g_is_full_enum = FALSE;
30 extern mtp_mgr_t g_mtp_mgr;
31 extern obj_interdep_proplist_t interdep_proplist;
32 extern mtp_char g_last_created_dir[MTP_MAX_PATHNAME_SIZE + 1];
33 extern mtp_char g_last_moved[MTP_MAX_PATHNAME_SIZE + 1];
34 extern mtp_char g_last_copied[MTP_MAX_PATHNAME_SIZE + 1];
35 extern mtp_char g_last_deleted[MTP_MAX_PATHNAME_SIZE + 1];
40 static mtp_mgr_t *g_mgr = &g_mtp_mgr;
47 * This function gets the storage entry.
48 * @param[in] store_id Specifies the storage id to get.
49 * @param[in] info Points the storage info structure
50 * @return This function returns MTP_ERROR_NONE on success or
51 * ERROR_No on failure.
53 mtp_err_t _hutil_get_storage_entry(mtp_uint32 store_id, store_info_t *info)
55 mtp_store_t *store = NULL;
57 store = _device_get_store(store_id);
59 ERR("Not able to retrieve store");
60 return MTP_ERROR_GENERAL;
62 _entity_update_store_info_run_time(&(store->store_info),
65 _prop_copy_ptpstring(&(info->store_desc), &(store->store_info.store_desc));
66 _prop_copy_ptpstring(&(info->vol_label), &(store->store_info.vol_label));
67 info->access = store->store_info.access;
68 info->fs_type = store->store_info.fs_type;
69 info->free_space = store->store_info.free_space;
70 info->capacity = store->store_info.capacity;
71 info->store_type = store->store_info.store_type;
72 info->free_space_in_objs = store->store_info.free_space_in_objs;
73 return MTP_ERROR_NONE;
76 mtp_err_t _hutil_get_storage_ids(ptp_array_t *store_ids)
78 mtp_uint32 num_elem = 0;
79 mtp_uint32 num_stores = 0;
81 num_elem = _device_get_store_ids(store_ids);
82 num_stores = _device_get_num_stores();
83 if (num_elem == num_stores) {
84 return MTP_ERROR_NONE;
87 ERR("get storage id Fail. num_elem[%d], num_stores[%d]\n",
88 num_elem, num_stores);
89 return MTP_ERROR_GENERAL;
93 * This function gets the device property.
94 * @param[in] prop_id Specifies the property id to retrieve
95 * @param[in] dev_prop Points the device prop structure
96 * @return This function returns MTP_ERROR_NONE on success,
97 * or ERROR_NO on failure.
99 mtp_err_t _hutil_get_device_property(mtp_uint32 prop_id,
100 device_prop_desc_t* dev_prop)
102 device_prop_desc_t *prop = NULL;
104 prop = _device_get_device_property(prop_id);
106 return MTP_ERROR_GENERAL;
108 memcpy(dev_prop, prop, sizeof(device_prop_desc_t));
109 return MTP_ERROR_NONE;
113 * This function sets the device property.
114 * @param[in] prop_id Specifies the property id to retrieve.
115 * @param[in] data Points the associated data buffer.
116 * @param[in] data_sz Specifies the data size of property.
117 * @return This function returns MTP_ERROR_NONE on success or
118 * appropriate error on failure.
120 mtp_err_t _hutil_set_device_property(mtp_uint32 prop_id, void *data,
123 device_prop_desc_t *prop = NULL;
125 prop = _device_get_device_property(prop_id);
127 return MTP_ERROR_GENERAL;
129 if (prop->propinfo.get_set == PTP_PROPGETSET_GETONLY)
130 return MTP_ERROR_ACCESS_DENIED;
132 if (FALSE == _prop_set_current_device_prop(prop, data, data_sz))
133 return MTP_ERROR_INVALID_OBJ_PROP_VALUE;
135 return MTP_ERROR_NONE;
139 * This function resets the device property.
140 * @param[in] prop_id Specifies the property id to retrieve.
141 * @return This function returns MTP_ERROR_NONE on success,
142 * appropriate error on failure.
144 mtp_err_t _hutil_reset_device_entry(mtp_uint32 prop_id)
146 device_prop_desc_t *prop = NULL;
149 if (prop_id == 0xFFFFFFFF) {
151 prop = _device_get_ref_prop_list();
153 ERR("property reference is NULL");
154 return MTP_ERROR_GENERAL;
156 for (ii = 0; ii < NUM_DEVICE_PROPERTIES; ii++) {
157 _prop_reset_device_prop_desc(&prop[ii]);
160 prop = _device_get_device_property(prop_id);
162 return MTP_ERROR_GENERAL;
164 _prop_reset_device_prop_desc(prop);
167 return MTP_ERROR_NONE;
171 * This function adds the object entry.
172 * @param[in] obj_info Points the objectinfo.
173 * @param[in] file_name Points the file name of the object.
174 * @param[out] new_obj Points to the new object added.
175 * @return This function returns MTP_ERROR_NONE on success or
176 * appropriate error on failure.
178 mtp_err_t _hutil_add_object_entry(obj_info_t *obj_info, mtp_char *file_name,
181 mtp_obj_t *obj = NULL;
182 mtp_obj_t *par_obj = NULL;
183 mtp_store_t *store = NULL;
184 mtp_wchar temp_wfname[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
185 mtp_char utf8_temp[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
186 mtp_char new_f_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
189 mtp_bool is_made_by_mtp = FALSE;
190 mtp_wchar w_file_name[MTP_MAX_FILENAME_SIZE + 1] = { 0 };
192 if (obj_info->h_parent != PTP_OBJECTHANDLE_ROOT) {
193 par_obj = _device_get_object_with_handle(obj_info->h_parent);
194 if (par_obj == NULL) {
195 ERR("parent is not existed.");
196 _entity_dealloc_obj_info(obj_info);
197 return MTP_ERROR_INVALID_OBJECTHANDLE;
200 if (par_obj->obj_info->obj_fmt != PTP_FMT_ASSOCIATION) {
201 ERR("parent handle is not association format[0x%x]\
202 handle[%d]\n", par_obj->obj_info->obj_fmt,
203 par_obj->obj_info->h_parent);
204 _entity_dealloc_obj_info(obj_info);
205 return MTP_ERROR_INVALID_PARENT;
209 store = _device_get_store(obj_info->store_id);
211 ERR("store is null");
212 _entity_dealloc_obj_info(obj_info);
213 return MTP_ERROR_GENERAL;
216 if (store->store_info.free_space < obj_info->file_size) {
217 ERR("free space is not enough [%ld] bytes, object size[%ld]\n",
218 store->store_info.free_space, obj_info->file_size);
219 _entity_dealloc_obj_info(obj_info);
220 return MTP_ERROR_STORE_FULL;
223 obj = _entity_alloc_mtp_object();
225 ERR("allocation memory Fail");
226 _entity_dealloc_obj_info(obj_info);
227 return MTP_ERROR_GENERAL;
230 memset(obj, 0, sizeof(mtp_obj_t));
231 obj->child_array.type = UINT32_TYPE;
232 obj->obj_handle = _entity_generate_next_obj_handle();
233 obj->obj_info = obj_info;
235 /* For PC->MMC read-only file/folder transfer
236 * and for PC->Phone read-only folder transfer
237 * store PTP_PROTECTIONSTATUS_NOPROTECTION in
238 * the field obj_info->ProtectionStatus
240 if (MTP_EXTERNAL_STORE_ID == obj_info->store_id ||
241 obj_info->obj_fmt == PTP_FMT_ASSOCIATION) {
242 obj_info->protcn_status = PTP_PROTECTIONSTATUS_NOPROTECTION;
245 if (strlen(file_name) == 0) {
246 /* Generate a filename in 8.3 format for this object */
247 g_snprintf(utf8_temp, MTP_MAX_PATHNAME_SIZE + 1,
248 "Tmp_%04u.dat", obj->obj_handle);
249 _util_utf8_to_utf16(temp_wfname,
250 sizeof(temp_wfname) / WCHAR_SIZ, utf8_temp);
252 _util_utf8_to_utf16(temp_wfname,
253 sizeof(temp_wfname) / WCHAR_SIZ, file_name);
256 /* Does this path/filename already exist ? */
258 mtp_bool file_exist = FALSE;
259 mtp_uint32 path_len = 0;
261 /* Get/Generate the Full Path for the new Object; */
262 if (obj_info->h_parent == PTP_OBJECTHANDLE_ROOT) {
263 _util_utf16_to_utf8(utf8_temp, sizeof(utf8_temp),
266 if (_util_create_path(new_f_path, sizeof(new_f_path),
267 store->root_path, utf8_temp) == FALSE) {
268 _entity_dealloc_mtp_obj(obj);
269 return MTP_ERROR_GENERAL;
271 #ifdef MTP_SUPPORT_HIDE_WMPINFO_XML
272 /* WMPInfo.xml and DevLogo.fil.*/
273 /* find WMPInfo.xml and add file mtp store */
275 mtp_char wmp_info_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
276 mtp_char wmp_hidden_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
278 if (obj_info->store_id == MTP_INTERNAL_STORE_ID) {
279 char inter_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
280 _util_get_internal_path(inter_path);
282 g_snprintf(wmp_hidden_path,
283 MTP_MAX_PATHNAME_SIZE + 1,
284 "%s/%s/%s", MTP_USER_DIRECTORY,
286 MTP_FILE_NAME_WMPINFO_XML);
287 g_snprintf(wmp_info_path,
288 MTP_MAX_PATHNAME_SIZE + 1,
290 MTP_FILE_NAME_WMPINFO_XML);
292 char ext_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
293 _util_get_external_path(ext_path);
295 g_snprintf(wmp_hidden_path,
296 MTP_MAX_PATHNAME_SIZE + 1,
297 "%s/%s/%s", MTP_USER_DIRECTORY,
299 MTP_FILE_NAME_WMPINFO_XML);
300 g_snprintf(wmp_info_path,
301 MTP_MAX_PATHNAME_SIZE + 1,
303 MTP_FILE_NAME_WMPINFO_XML);
306 if (!strcasecmp(wmp_info_path, new_f_path)) {
307 DBG("substitute file[%s]-->[%s]\n",
308 wmp_info_path, wmp_hidden_path);
310 g_strlcpy(new_f_path, wmp_hidden_path,
313 if (obj_info->store_id ==
314 MTP_INTERNAL_STORE_ID) {
316 MTP_MAX_INT_OBJECT_NUM -
317 MTPSTORE_WMPINFO_PHONE;
320 MTP_MAX_INT_OBJECT_NUM -
321 MTPSTORE_WMPINFO_CARD;
325 #endif /*MTP_SUPPORT_HIDE_WMPINFO_XML*/
327 _util_utf16_to_utf8(utf8_temp, sizeof(utf8_temp),
329 if (_util_create_path(new_f_path, sizeof(new_f_path),
330 par_obj->file_path, utf8_temp) == FALSE) {
331 _entity_dealloc_mtp_obj(obj);
332 return MTP_ERROR_GENERAL;
337 * g_mgr->ftemp_st.filepath was allocated g_strdup("/tmp/.mtptemp.tmp");
338 * So if we need to change the path we need to allocate sufficient memory
339 * otherwise memory corruption may happen
342 path_len = strlen(store->root_path) + strlen(MTP_TEMP_FILE) + 2;
343 g_mgr->ftemp_st.filepath = g_realloc(g_mgr->ftemp_st.filepath, path_len);
344 if (g_mgr->ftemp_st.filepath == NULL) {
345 ERR("g_realloc Fail");
346 _entity_dealloc_mtp_obj(obj);
347 return MTP_ERROR_GENERAL;
350 if (_util_create_path(g_mgr->ftemp_st.filepath, path_len,
351 store->root_path, MTP_TEMP_FILE) == FALSE) {
352 ERR("Tempfile fullPath is too long");
353 _entity_dealloc_mtp_obj(obj);
354 return MTP_ERROR_GENERAL;
357 DBG_SECURE("Temp file path [%s]\n", g_mgr->ftemp_st.filepath);
360 #ifdef MTP_SUPPORT_ALBUM_ART
361 if (access(new_f_path, F_OK) == 0) {
363 /* if file is album, overwrite it. */
364 mtp_char alb_buf[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
365 mtp_char alb_ext[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
367 /* find extension, if album or pla, overwrite that. */
368 _util_utf16_to_utf8(alb_buf, sizeof(alb_buf), temp_wfname);
370 if (obj_info->obj_fmt != PTP_FMT_ASSOCIATION ||
371 (obj_info->obj_fmt == PTP_FMT_ASSOCIATION &&
372 obj_info->association_type !=
373 PTP_ASSOCIATIONTYPE_UNDEFINED &&
374 obj_info->association_type !=
375 PTP_ASSOCIATIONTYPE_FOLDER)) {
377 _util_get_file_extn(alb_buf, alb_ext);
378 if (!strcasecmp(alb_ext, "alb")) {
379 if (remove(new_f_path) == 0) {
381 DBG("[%s] file is found. Delete\
382 old and make new one\n",
385 ERR("[%s] file is found. but \
391 #endif /*MTP_SUPPORT_ALBUM_ART*/
393 if (file_exist == FALSE) {
394 DBG_SECURE("Found a unique file name for the incoming object\
395 [%s]\n", temp_wfname);
399 #ifdef MTP_USE_SELFMAKE_ABSTRACTION
400 is_made_by_mtp = obj_info->file_size == 0 &&
401 obj_info->obj_fmt > MTP_FMT_UNDEFINED_COLLECTION &&
402 obj_info->obj_fmt < MTP_FMT_UNDEFINED_DOC;
403 #endif /*MTP_USE_SELFMAKE_ABSTRACTION*/
404 if (obj_info->obj_fmt == PTP_FMT_ASSOCIATION ||
406 *new_obj = _device_get_object_with_path(new_f_path);
408 _entity_dealloc_mtp_obj(obj);
409 return MTP_ERROR_NONE;
411 DBG("+ not found object. [%s]\n", new_f_path);
416 /* Rename the Filename for this object */
417 memset(temp_wfname, 0, (MTP_MAX_PATHNAME_SIZE + 1) * 2);
418 _util_utf8_to_utf16(w_file_name, sizeof(w_file_name) / WCHAR_SIZ,
420 _util_wchar_swprintf(temp_wfname,
421 MTP_MAX_PATHNAME_SIZE + 1, "COPY%d_%s", i, w_file_name);
424 /* Save the full path to this object */
425 _entity_set_object_file_path(obj, new_f_path, CHAR_TYPE);
428 * Is this an association (or folder)?
429 * Associations are fully qualified by the ObjectInfo Dataset.
431 #ifdef MTP_USE_SELFMAKE_ABSTRACTION
432 is_made_by_mtp = (obj_info->file_size == 0 &&
433 obj_info->obj_fmt > MTP_FMT_UNDEFINED_COLLECTION &&
434 obj_info->obj_fmt < MTP_FMT_UNDEFINED_DOC);
435 #endif /*MTP_USE_SELFMAKE_ABSTRACTION*/
437 if (obj_info->obj_fmt == PTP_FMT_ASSOCIATION || is_made_by_mtp) {
438 /* Create the new object */
439 DBG("[normal] create association file/folder[%s][0x%x]\n",
440 new_f_path, obj_info->association_type);
442 if ((obj_info->association_type !=
443 PTP_ASSOCIATIONTYPE_UNDEFINED &&
444 obj_info->association_type !=
445 PTP_ASSOCIATIONTYPE_FOLDER) ||
447 mtp_uint32 h_abs_file = INVALID_FILE;
448 h_abs_file = _util_file_open(new_f_path,
449 MTP_FILE_WRITE, &error);
450 if (h_abs_file == INVALID_FILE) {
451 ERR("create file fail!!");
452 _entity_dealloc_mtp_obj(obj);
453 return MTP_ERROR_GENERAL;
455 _util_file_close(h_abs_file);
457 g_snprintf(g_last_created_dir,
458 MTP_MAX_PATHNAME_SIZE + 1, "%s", new_f_path);
459 if (_util_dir_create(new_f_path, &error) == FALSE) {
460 /* We failed to create the folder */
461 ERR("create directory Fail");
462 memset(g_last_created_dir, 0,
463 sizeof(g_last_created_dir));
464 _entity_dealloc_mtp_obj(obj);
465 return MTP_ERROR_GENERAL;
469 _entity_set_object_file_path(obj, new_f_path, CHAR_TYPE);
470 if (_entity_add_object_to_store(store, obj) == FALSE) {
471 ERR("_entity_add_object_to_store Fail");
472 _entity_dealloc_mtp_obj(obj);
473 return MTP_ERROR_STORE_FULL;
476 /* Reserve space for the object: Object itself, and probably
477 * some Filesystem-specific overhead
479 store->store_info.free_space -= obj_info->file_size;
484 return MTP_ERROR_NONE;
488 * This function removes the object entry.
489 * @param[in] obj_handle Specifies the object to remove.
490 * @param[in] format Specifies the format code.
491 * @return This function returns MTP_ERROR_NONE on success or
492 * appropriate error on failure.
494 mtp_err_t _hutil_remove_object_entry(mtp_uint32 obj_handle, mtp_uint32 format)
496 mtp_err_t resp = MTP_ERROR_GENERAL;
499 #ifdef MTP_SUPPORT_SET_PROTECTION
500 /* this will check to see if the protection is set */
501 mtp_obj_t *obj = NULL;
502 if (obj_handle != 0xFFFFFFFF) {
503 obj = _device_get_object_with_handle(obj_handle);
505 if ((obj->obj_info->protcn_status ==
506 MTP_PROTECTIONSTATUS_READONLY_DATA) ||
507 (obj->obj_info->protcn_status ==
508 PTP_PROTECTIONSTATUS_READONLY)) {
509 ERR("Protection status is [0x%x]\n",
510 obj->obj_info->protcn_status);
511 return MTP_ERROR_OBJECT_WRITE_PROTECTED;
515 #endif /*MTP_SUPPORT_SET_PROTECTION*/
517 ret = _device_delete_object(obj_handle, format);
519 case PTP_RESPONSE_OK:
520 resp = MTP_ERROR_NONE;
522 case PTP_RESPONSE_STORE_READONLY:
523 resp = MTP_ERROR_STORE_READ_ONLY;
525 case PTP_RESPONSE_PARTIAL_DELETION:
526 resp = MTP_ERROR_PARTIAL_DELETION;
528 case PTP_RESPONSE_OBJ_WRITEPROTECTED:
529 resp = MTP_ERROR_OBJECT_WRITE_PROTECTED;
531 case PTP_RESPONSE_ACCESSDENIED:
532 resp = MTP_ERROR_ACCESS_DENIED;
534 case PTP_RESPONSE_INVALID_OBJ_HANDLE:
535 resp =MTP_ERROR_INVALID_OBJECTHANDLE;
545 * This function gets the object entry.
546 * @param[in] obj_handle Specifies the object to get.
547 * @param[out] obj_ptr Points to object found.
548 * @return This function returns MTP_ERROR_NONE on success
549 * or appropriate error on failure.
551 mtp_err_t _hutil_get_object_entry(mtp_uint32 obj_handle, mtp_obj_t **obj_ptr)
553 mtp_obj_t *obj = NULL;
555 obj = _device_get_object_with_handle(obj_handle);
556 if (NULL == obj || NULL == obj->obj_info) {
557 return MTP_ERROR_GENERAL;
561 return MTP_ERROR_NONE;
564 mtp_err_t _hutil_copy_object_entries(mtp_uint32 dst_store_id,
565 mtp_uint32 src_store_id, mtp_uint32 h_parent, mtp_uint32 obj_handle,
566 mtp_uint32 *new_hobj, mtp_bool keep_handle)
568 mtp_store_t *dst = NULL;
569 mtp_store_t *src = NULL;
570 mtp_obj_t *obj = NULL;
571 mtp_obj_t *par_obj = NULL;
572 mtp_obj_t *new_obj = NULL;
574 mtp_char fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
575 mtp_char utf8_temp[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
576 mtp_err_t ret = MTP_ERROR_NONE;
577 mtp_uint32 num_of_deleted_file = 0;
578 mtp_uint32 num_of_file = 0;
579 ptp_array_t child_arr = { 0 };
580 mtp_obj_t *child_obj = NULL;
583 src = _device_get_store(src_store_id);
584 dst = _device_get_store(dst_store_id);
585 obj = _device_get_object_with_handle(obj_handle);
587 if ((src == NULL) || (dst == NULL) || (obj == NULL)) {
589 return MTP_ERROR_GENERAL;
594 /* two sam handle can occurs in folder copy case
595 * (find last appended object in target storage)
597 par_obj = _entity_get_last_object_from_store(dst,
600 par_obj = _device_get_object_with_handle(h_parent);
605 _util_get_file_name(obj->file_path, utf8_temp);
607 if (par_obj == NULL) {
608 /* Parent is the root of this store */
609 if (_util_create_path(fpath, sizeof(fpath), dst->root_path,
610 utf8_temp) == FALSE) {
611 ERR("new path is too LONG");
612 return MTP_ERROR_GENERAL;
615 if (_util_create_path(fpath, sizeof(fpath), par_obj->file_path,
616 utf8_temp) == FALSE) {
617 ERR("New path is too LONG!!");
618 return MTP_ERROR_GENERAL;
622 if (!strcasecmp(fpath, obj->file_path)) {
623 ERR("Identical path of source and destination[%s]\n", fpath);
624 return MTP_ERROR_GENERAL;
627 new_obj = _entity_alloc_mtp_object();
628 if (new_obj == NULL) {
629 ERR("_entity_alloc_mtp_object Fail");
630 return MTP_ERROR_GENERAL;
633 memset(new_obj, 0, sizeof(mtp_obj_t));
634 new_obj->child_array.type = UINT32_TYPE;
636 _entity_copy_mtp_object(new_obj, obj);
637 if (new_obj->obj_info == NULL) {
638 _entity_dealloc_mtp_obj(new_obj);
639 return MTP_ERROR_GENERAL;
642 new_obj->obj_info->store_id = dst_store_id;
643 _entity_set_object_file_path(new_obj, fpath, CHAR_TYPE);
645 if (MTP_EXTERNAL_STORE_ID == new_obj->obj_info->store_id) {
646 new_obj->obj_info->protcn_status =
647 PTP_PROTECTIONSTATUS_NOPROTECTION;
650 new_obj->obj_handle = (keep_handle) ? obj->obj_handle :
651 _entity_generate_next_obj_handle();
652 new_obj->obj_info->h_parent = (par_obj == NULL) ? PTP_OBJECTHANDLE_ROOT :
655 if (new_obj->obj_info->obj_fmt != PTP_FMT_ASSOCIATION) {
656 DBG("Non-association type!!");
657 g_snprintf(g_last_copied, MTP_MAX_PATHNAME_SIZE + 1, "%s",
659 if (_util_file_copy(obj->file_path, new_obj->file_path,
661 memset(g_last_copied, 0, MTP_MAX_PATHNAME_SIZE + 1);
662 ERR("Copy file Fail");
663 _entity_dealloc_mtp_obj(new_obj);
665 return MTP_ERROR_ACCESS_DENIED;
666 else if (ENOSPC == error)
667 return MTP_ERROR_STORE_FULL;
668 return MTP_ERROR_GENERAL;
671 #ifdef MTP_SUPPORT_SET_PROTECTION
672 file_attr_t attr = { 0 };
673 attr.attribute = MTP_FILE_ATTR_MODE_REG;
674 if (PTP_PROTECTIONSTATUS_READONLY ==
675 new_obj->obj_info->protcn_status) {
676 if (FALSE == _util_set_file_attrs(new_obj->file_path,
677 attr.attribute | MTP_FILE_ATTR_MODE_READ_ONLY))
678 return MTP_ERROR_GENERAL;
680 #endif /* MTP_SUPPORT_SET_PROTECTION */
682 /* Update the storeinfo after successfully copy of the object */
683 dst->store_info.free_space -= obj->obj_info->file_size;
687 _entity_add_object_to_store(dst, new_obj);
689 _prop_copy_ptparray(&(new_obj->child_array),
690 &(obj->child_array));
692 _entity_add_object_to_store(dst, new_obj);
695 *new_hobj = new_obj->obj_handle;
696 return MTP_ERROR_NONE;
699 DBG("Association type!!");
700 if (access(new_obj->file_path, F_OK) == 0) {
701 if (TRUE == keep_handle) {
702 /*generate unique_path*/
703 mtp_char unique_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
704 if (FALSE == _util_get_unique_dir_path(new_obj->file_path,
705 unique_fpath, sizeof(unique_fpath))) {
706 _entity_dealloc_mtp_obj(new_obj);
707 return MTP_ERROR_GENERAL;
709 _entity_set_object_file_path(new_obj, unique_fpath, CHAR_TYPE);
710 g_snprintf(g_last_created_dir, MTP_MAX_PATHNAME_SIZE + 1,
711 "%s", new_obj->file_path);
712 if (_util_dir_create(new_obj->file_path, &error) == FALSE) {
713 memset(g_last_created_dir, 0,
714 MTP_MAX_PATHNAME_SIZE + 1);
715 ERR("Creating folder Fail!!");
716 _entity_dealloc_mtp_obj(new_obj);
718 return MTP_ERROR_STORE_FULL;
719 return MTP_ERROR_GENERAL;
722 /* Add the new object to this store's object list */
723 _entity_add_object_to_store(dst, new_obj);
725 DBG("Already existed association type!!");
726 _entity_dealloc_mtp_obj(new_obj);
727 new_obj = _entity_get_object_from_store_by_path(dst, fpath);
729 ERR("But object is not registered!!");
730 return MTP_ERROR_GENERAL;
734 g_snprintf(g_last_created_dir, MTP_MAX_PATHNAME_SIZE + 1,
735 "%s", new_obj->file_path);
736 if (_util_dir_create(new_obj->file_path, &error) == FALSE) {
737 memset(g_last_created_dir, 0,
738 MTP_MAX_PATHNAME_SIZE + 1);
739 ERR("Creating folder Fail!!");
740 _entity_dealloc_mtp_obj(new_obj);
742 return MTP_ERROR_STORE_FULL;
743 return MTP_ERROR_GENERAL;
746 /* Add the new object to this store's object list */
747 _entity_add_object_to_store(dst, new_obj);
750 /* Child addition to data structures is not required in Copy
751 * case as on demand enumeration is supported
753 if (FALSE == keep_handle) {
754 if (FALSE == _util_copy_dir_children_recursive(obj->file_path,
755 new_obj->file_path, &error)) {
756 ERR_SECURE("Recursive copy Fail [%s]->[%s]",
757 obj->file_path, new_obj->file_path);
758 ret = MTP_ERROR_GENERAL;
760 ret = MTP_ERROR_ACCESS_DENIED;
761 else if (ENOSPC == error)
762 ret = MTP_ERROR_STORE_FULL;
763 if (_util_remove_dir_children_recursive(new_obj->file_path,
764 &num_of_deleted_file, &num_of_file,
765 FALSE) == MTP_ERROR_NONE) {
766 g_snprintf(g_last_deleted,
767 MTP_MAX_PATHNAME_SIZE + 1,
768 "%s", new_obj->file_path);
769 if (rmdir(new_obj->file_path) < 0) {
770 memset(g_last_deleted, 0,
771 MTP_MAX_PATHNAME_SIZE + 1);
777 *new_hobj = new_obj->obj_handle;
779 return MTP_ERROR_NONE;
783 /* Since this is an association, copy its children as well*/
784 _prop_init_ptparray(&child_arr, UINT32_TYPE);
785 _entity_get_child_handles(src, obj->obj_handle, &child_arr);
787 for (ii = 0; ii < child_arr.num_ele; ii++) {
788 mtp_uint32 *ptr32 = child_arr.array_entry;
790 child_obj = _entity_get_object_from_store(src, ptr32[ii]);
791 if (child_obj == NULL) {
795 ret = _hutil_copy_object_entries(dst_store_id, src_store_id,
796 new_obj->obj_handle, child_obj->obj_handle,
797 new_hobj, keep_handle);
798 if (ret != MTP_ERROR_NONE) {
799 ERR("Copy file Fail");
800 _prop_deinit_ptparray(&child_arr);
805 /* Recursive copy is required when folder is not enumerated so it may
806 * return 0 child handles
808 if (!((child_arr.num_ele > 0) ||
809 _util_copy_dir_children_recursive(obj->file_path,
810 new_obj->file_path, &error))) {
811 ERR_SECURE("Recursive copy Fail [%d], [%s]->[%s]",
813 obj->file_path, new_obj->file_path);
814 _prop_deinit_ptparray(&child_arr);
815 if (_util_remove_dir_children_recursive(new_obj->file_path,
816 &num_of_deleted_file, &num_of_file, FALSE) ==
818 g_snprintf(g_last_deleted, MTP_MAX_PATHNAME_SIZE + 1,
819 "%s", new_obj->file_path);
820 if (rmdir(new_obj->file_path) < 0) {
821 memset(g_last_deleted, 0,
822 MTP_MAX_PATHNAME_SIZE + 1);
826 return MTP_ERROR_STORE_FULL;
827 return MTP_ERROR_GENERAL;
830 _prop_deinit_ptparray(&child_arr);
831 *new_hobj = new_obj->obj_handle;
833 return MTP_ERROR_NONE;
836 mtp_err_t _hutil_move_object_entry(mtp_uint32 dst_store_id, mtp_uint32 h_parent,
837 mtp_uint32 obj_handle)
839 mtp_store_t *src = NULL;
840 mtp_store_t *dst = NULL;
841 mtp_obj_t *obj = NULL;
842 mtp_obj_t *par_obj = NULL;
843 mtp_char str_buf[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
844 mtp_char utf8_temp[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
845 mtp_uint32 new_handle = 0;
847 mtp_err_t ret = MTP_ERROR_NONE;
849 obj = _device_get_object_with_handle(obj_handle);
851 ERR("object is [%p]\n", obj);
852 return MTP_ERROR_INVALID_OBJECTHANDLE;
854 if (NULL == obj->obj_info) {
855 ERR("obj_info is [%p]\n", obj->obj_info);
856 return MTP_ERROR_GENERAL;
859 src = _device_get_store_containing_obj(obj_handle);
861 ERR("error retrieving source store");
862 return MTP_ERROR_STORE_NOT_AVAILABLE;
865 if (src->store_info.access == PTP_STORAGEACCESS_R) {
866 ERR("Store access is read only");
867 return MTP_ERROR_STORE_READ_ONLY;
870 dst = _device_get_store(dst_store_id);
872 ERR("error retrieving destination store");
873 return MTP_ERROR_STORE_NOT_AVAILABLE;
876 if (dst->store_info.access != PTP_STORAGEACCESS_RWD) {
877 ERR("Write permission not there on target store");
878 return MTP_ERROR_STORE_READ_ONLY;
881 /* Get the Parent Object Handle */
883 par_obj = _device_get_object_with_handle(h_parent);
885 if (par_obj == NULL || par_obj->obj_info == NULL) {
886 ERR("par_obj[%p] or par_obj->obj_info is NULL\n", par_obj);
887 return MTP_ERROR_INVALID_PARENT;
888 } else if (PTP_FMT_ASSOCIATION != par_obj->obj_info->obj_fmt) {
889 ERR("par obj fmt = [0x%x]\n", par_obj->obj_info->obj_fmt);
890 return MTP_ERROR_INVALID_PARENT;
893 if (dst != _device_get_store_containing_obj(h_parent)) {
894 ERR("parent is not on the destination store");
895 return MTP_ERROR_INVALID_PARENT;
898 /* Parent must not be a descendant of the object to be moved */
899 if (dst->store_id == src->store_id) {
900 if (_entity_check_if_B_parent_of_A(dst, h_parent,
902 return MTP_ERROR_INVALID_PARAM;
905 par_obj = NULL; /* Parent is the root */
908 /* Check if the source store is the target store */
909 if (dst->store_id == src->store_id) {
911 mtp_obj_t *old_par = NULL;
912 mtp_char new_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
913 mtp_char dst_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
914 mtp_char *parent_path = NULL;
916 DBG("same storage , type[0x%x]\n",
917 obj->obj_info->association_type);
918 _util_get_file_name(obj->file_path, utf8_temp);
921 parent_path = dst->root_path;
923 parent_path = par_obj->file_path;
925 if (_util_create_path(dst_fpath, sizeof(dst_fpath), parent_path,
926 utf8_temp) == FALSE) {
927 ERR("dst path is too LONG!!");
928 return MTP_ERROR_GENERAL;
931 /* Do a real "Move" for the object in the same store: no need to
932 * check space available
934 g_strlcpy(str_buf, obj->file_path, sizeof(str_buf));
936 if (obj->obj_info != NULL && obj->obj_info->obj_fmt ==
937 PTP_FMT_ASSOCIATION) {
939 if (access(dst_fpath, F_OK) == 0) {
940 if (FALSE == _util_get_unique_dir_path(dst_fpath,
941 new_fpath, sizeof(new_fpath))) {
942 return MTP_ERROR_GENERAL;
945 g_strlcpy(new_fpath, dst_fpath, sizeof(new_fpath));
948 g_snprintf(g_last_moved, MTP_MAX_PATHNAME_SIZE + 1,
950 if (rename(str_buf, new_fpath) < 0) {
951 /* Failed to move the object */
953 memset(g_last_moved, 0,
954 MTP_MAX_PATHNAME_SIZE + 1);
955 ERR_SECURE("Directory rename fail in same storage\
956 [%s]->[%s]\n", str_buf, new_fpath);
958 return MTP_ERROR_ACCESS_DENIED;
959 else if (ENOSPC == error)
960 return MTP_ERROR_STORE_FULL;
961 return MTP_ERROR_GENERAL;
964 _util_scan_folder_contents_in_db(str_buf);
965 _entity_set_object_file_path(obj, new_fpath, CHAR_TYPE);
966 _entity_set_child_object_path(obj, str_buf, new_fpath);
967 _util_scan_folder_contents_in_db(new_fpath);
969 g_snprintf(g_last_moved, MTP_MAX_PATHNAME_SIZE + 1,
971 if (FALSE == _util_file_move(str_buf, dst_fpath,
973 /* Failed to move the object */
974 memset(g_last_moved, 0,
975 MTP_MAX_PATHNAME_SIZE + 1);
976 ERR("move file Fail in same storage\
977 [%s]->[%s]\n", str_buf, dst_fpath);
979 return MTP_ERROR_ACCESS_DENIED;
980 else if (ENOSPC == error)
981 return MTP_ERROR_STORE_FULL;
982 return MTP_ERROR_GENERAL;
985 _util_delete_file_from_db(obj->media_id);
986 _entity_set_object_file_path(obj, dst_fpath, CHAR_TYPE);
987 _util_add_file_to_db(obj, obj->file_path);
990 if (obj->obj_info->h_parent != PTP_OBJECTHANDLE_ROOT) {
991 old_par = _entity_get_object_from_store(src,
992 obj->obj_info->h_parent);
994 _entity_remove_reference_child_array(old_par,
999 if (par_obj != NULL) {
1000 obj->obj_info->h_parent = par_obj->obj_handle;
1001 _entity_add_reference_child_array(par_obj,
1004 obj->obj_info->h_parent = PTP_OBJECTHANDLE_ROOT;
1007 return MTP_ERROR_NONE;
1009 /* Move is called between two stores */
1010 /* Calculate the space required for the new object(s) */
1011 mtp_obj_t *new_obj = NULL;
1012 DBG("Different storage or a folder, type[0x%x]\n",
1013 obj->obj_info->association_type);
1015 /* Simulate a Move operation: First copy the Object,
1016 * then remove the old object
1018 ret = _hutil_copy_object_entries(dst->store_id, src->store_id,
1019 (par_obj == NULL) ? 0 : (par_obj->obj_handle),
1020 obj->obj_handle, &new_handle, TRUE);
1021 if (ret != MTP_ERROR_NONE) {
1022 _entity_delete_obj_mtp_store(dst, obj->obj_handle,
1023 PTP_FORMATCODE_NOTUSED, FALSE);
1027 _entity_delete_obj_mtp_store(src, obj->obj_handle,
1028 PTP_FORMATCODE_NOTUSED, FALSE);
1029 new_obj = _device_get_object_with_handle(new_handle);
1030 if (NULL == new_obj || NULL == new_obj->obj_info)
1031 return MTP_ERROR_GENERAL;
1033 if (new_obj->obj_info->obj_fmt == PTP_FMT_ASSOCIATION)
1034 _util_scan_folder_contents_in_db(new_obj->file_path);
1036 _util_add_file_to_db(new_obj, new_obj->file_path);
1038 return MTP_ERROR_NONE;
1040 return MTP_ERROR_GENERAL;
1043 mtp_err_t _hutil_duplicate_object_entry(mtp_uint32 dst_store_id,
1044 mtp_uint32 h_parent, mtp_uint32 obj_handle, mtp_uint32 *new_handle)
1046 mtp_store_t *src = NULL;
1047 mtp_store_t *dst = NULL;
1048 mtp_obj_t *obj = NULL;
1049 mtp_obj_t *par_obj = NULL;
1050 mtp_obj_t *new_obj = NULL;
1051 mtp_uint32 space_req = 0;
1052 mtp_err_t ret = MTP_ERROR_NONE;
1054 obj = _device_get_object_with_handle(obj_handle);
1056 ERR("Object not found");
1057 return MTP_ERROR_INVALID_OBJECTHANDLE;
1060 src = _device_get_store_containing_obj(obj_handle);
1062 ERR("Source store not found");
1063 return MTP_ERROR_STORE_NOT_AVAILABLE;
1066 dst = _device_get_store(dst_store_id);
1068 ERR("Destination store not found");
1069 return MTP_ERROR_STORE_NOT_AVAILABLE;
1072 if (dst->store_info.access != PTP_STORAGEACCESS_RWD) {
1073 ERR("Store is read only");
1074 return MTP_ERROR_STORE_READ_ONLY;
1078 par_obj = _device_get_object_with_handle(h_parent);
1079 if ((par_obj == NULL) || (par_obj->obj_info->obj_fmt !=
1080 PTP_FMT_ASSOCIATION))
1081 return MTP_ERROR_INVALID_PARENT;
1083 if (dst != _device_get_store_containing_obj(h_parent))
1084 return MTP_ERROR_INVALID_PARENT;
1086 if (dst->store_id == src->store_id) {
1087 if (_entity_check_if_B_parent_of_A(dst, h_parent,
1089 return MTP_ERROR_INVALID_PARENT;
1094 space_req = _entity_get_object_tree_size(src, obj);
1095 if (dst->store_info.free_space < space_req) {
1096 ERR("Insufficient free space");
1097 return MTP_ERROR_STORE_FULL;
1100 if((ret = _hutil_copy_object_entries(dst_store_id, src->store_id,
1101 h_parent, obj_handle, new_handle, FALSE)) != MTP_ERROR_NONE) {
1105 * After this command, Initiator will ask get object prop list (0x9805).
1106 * update the media DB.
1108 new_obj = _device_get_object_with_handle(*new_handle);
1109 if (NULL == new_obj || NULL == new_obj->obj_info) {
1110 ERR("new obj or info is NULL");
1111 return MTP_ERROR_GENERAL;
1114 if (new_obj->obj_info->obj_fmt == PTP_FMT_ASSOCIATION) {
1115 _util_scan_folder_contents_in_db(new_obj->file_path);
1117 _util_add_file_to_db(new_obj, new_obj->file_path);
1120 return MTP_ERROR_NONE;
1123 mtp_err_t _hutil_read_file_data_from_offset(mtp_uint32 obj_handle, off_t offset,
1124 void *data, mtp_uint32 *data_sz)
1126 mtp_obj_t *obj = NULL;
1127 mtp_uint32 h_file = INVALID_FILE;
1128 mtp_int32 error = 0;
1129 mtp_char fname[MTP_MAX_PATHNAME_SIZE + 1];
1131 mtp_uint32 num_bytes;
1133 obj = _device_get_object_with_handle(obj_handle);
1135 ERR("_device_get_object_with_handle returned NULL object");
1136 return MTP_ERROR_INVALID_OBJECTHANDLE;
1139 if (obj->obj_info->protcn_status ==
1140 MTP_PROTECTIONSTATUS_NONTRANSFERABLE_DATA) {
1142 ERR("protection data, NONTRANSFERABLE_OBJECT");
1143 return MTP_ERROR_GENERAL;
1146 g_strlcpy(fname, obj->file_path, MTP_MAX_PATHNAME_SIZE + 1);
1147 h_file = _util_file_open(fname, MTP_FILE_READ, &error);
1148 if (h_file == INVALID_FILE) {
1149 ERR("file open Fail[%s]\n", fname);
1150 return MTP_ERROR_GENERAL;
1153 result = _util_file_seek(h_file, offset, SEEK_SET);
1155 ERR("file seek Fail [%d]\n", errno);
1156 _util_file_close(h_file);
1157 return MTP_ERROR_GENERAL;
1160 num_bytes = *data_sz;
1161 _util_file_read(h_file, data, *data_sz, data_sz);
1163 if (num_bytes != *data_sz) {
1164 ERR("requested[%d] and read[%d] number of bytes do not match\n",
1165 *data_sz, num_bytes);
1166 _util_file_close(h_file);
1167 return MTP_ERROR_GENERAL;
1170 _util_file_close(h_file);
1171 return MTP_ERROR_NONE;
1174 mtp_err_t _hutil_write_file_data(mtp_uint32 store_id, mtp_obj_t *obj,
1178 mtp_char fname[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1179 #ifdef MTP_SUPPORT_DELETE_MEDIA_ALBUM_FILE
1180 mtp_char extn[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1181 #endif /*MTP_SUPPORT_DELETE_MEDIA_ALBUM_FILE*/
1182 mtp_int32 error = 0;
1184 retv_if(obj == NULL, MTP_ERROR_INVALID_PARAM);
1185 retv_if(obj->obj_info == NULL, MTP_ERROR_INVALID_PARAM);
1187 store = _device_get_store(store_id);
1188 if (store == NULL) {
1189 ERR("destination store is not valid");
1190 return MTP_ERROR_INVALID_OBJECT_INFO;
1193 g_strlcpy(fname, obj->file_path, MTP_MAX_PATHNAME_SIZE + 1);
1194 if (access(fpath, F_OK) < 0) {
1195 ERR("temp file does not exist");
1196 return MTP_ERROR_GENERAL;
1199 #ifdef MTP_SUPPORT_DELETE_MEDIA_ALBUM_FILE
1200 /* in case of alb extension, does not make real file just skip below */
1201 if (obj_info->obj_fmt != PTP_FMT_ASSOCIATION ||
1202 (obj_info->obj_fmt == PTP_FMT_ASSOCIATION &&
1203 obj_info->association_type != PTP_ASSOCIATIONTYPE_UNDEFINED &&
1204 obj_info->association_type != PTP_ASSOCIATIONTYPE_FOLDER)) {
1206 _util_get_file_extn(fname, extn);
1207 if (strlen(extn) && !strcasecmp(extn, "alb")) {
1208 DBG("No need to create album file");
1209 remove(fpath, &error);
1210 return MTP_ERROR_NONE;
1213 #endif /*MTP_SUPPORT_DELETE_MEDIA_ALBUM_FILE*/
1215 g_snprintf(g_last_moved, MTP_MAX_PATHNAME_SIZE + 1, "%s", fpath);
1216 if (FALSE == _util_file_move(fpath, fname, &error)) {
1217 memset(g_last_moved, 0, MTP_MAX_PATHNAME_SIZE + 1);
1218 ERR("move to real file fail [%s]->[%s] \n", fpath, fname);
1219 _entity_dealloc_mtp_obj(obj);
1221 return MTP_ERROR_STORE_FULL;
1224 #ifdef MTP_SUPPORT_SET_PROTECTION
1225 if ((obj_info->protcn_status == PTP_PROTECTIONSTATUS_READONLY) ||
1226 (obj_info->ProtectionStatus ==
1227 MTP_PROTECTIONSTATUS_READONLY_DATA)) {
1229 if (_util_get_file_attrs(fname, &attrs) == FALSE) {
1230 ERR("real file get attributes Fail");
1231 _entity_dealloc_mtp_obj(obj);
1232 return MTP_ERROR_GENERAL;
1234 _util_set_file_attrs(fname, attrs.attribute |
1235 MTP_FILE_ATTR_MODE_READ_ONLY);
1237 #endif /* MTP_SUPPORT_SET_PROTECTION */
1239 _util_add_file_to_db(obj, obj->file_path);
1241 #ifndef MTP_USE_RUNTIME_GETOBJECTPROPVALUE
1242 if (updatePropertyValuesMtpObject(obj) == FALSE) {
1243 ERR("update property values mtp obj Fail");
1244 _entity_dealloc_mtp_obj(obj);
1245 return MTP_ERROR_GENERAL;
1247 #endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/
1249 _entity_add_object_to_store(store, obj);
1251 return MTP_ERROR_NONE;
1254 mtp_err_t _hutil_get_object_entry_size(mtp_uint32 obj_handle,
1257 mtp_obj_t *obj = NULL;
1259 obj = _device_get_object_with_handle(obj_handle);
1261 ERR("_device_get_object_with_handle returned Null object");
1262 return MTP_ERROR_INVALID_OBJECTHANDLE;
1265 *obj_sz = obj->obj_info->file_size;
1266 return MTP_ERROR_NONE;
1269 #ifdef MTP_SUPPORT_SET_PROTECTION
1270 mtp_err_t _hutil_set_protection(mtp_uint32 obj_handle, mtp_uint16 prot_status)
1272 mtp_obj_t *obj = NULL;
1273 mtp_char fname[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1274 file_attr_t attrs = { 0 };
1276 obj = _device_get_object_with_handle(obj_handle);
1278 return MTP_ERROR_INVALID_OBJECTHANDLE;
1280 if (MTP_EXTERNAL_STORE_ID == obj->obj_info->store_id) {
1281 ERR("Storage is external");
1282 return MTP_ERROR_OPERATION_NOT_SUPPORTED;
1285 g_strlcpy(fname, obj->file_path, MTP_MAX_PATHNAME_SIZE + 1);
1286 obj->obj_info->protcn_status = prot_status;
1288 if (FALSE == _util_get_file_attrs(fname, &attrs)) {
1289 ERR("Failed to get file[%s] attrs\n", fname);
1290 return MTP_ERROR_GENERAL;
1293 if (MTP_FILE_ATTR_MODE_NONE == attrs.attribute) {
1294 return MTP_ERROR_GENERAL;
1297 if (prot_status == PTP_PROTECTIONSTATUS_READONLY) {
1298 attrs.attribute |= MTP_FILE_ATTR_MODE_READ_ONLY;
1300 attrs.attribute &= ~MTP_FILE_ATTR_MODE_READ_ONLY;
1303 if (FALSE == _util_set_file_attrs(fname, attrs.attribute)) {
1304 ERR("Failed to set file[%s] attrs\n", fname);
1305 return MTP_ERROR_GENERAL;
1308 return MTP_ERROR_NONE;
1310 #endif /* MTP_SUPPORT_SET_PROTECTION */
1312 mtp_err_t _hutil_get_num_objects(mtp_uint32 store_id, mtp_uint32 h_parent,
1313 mtp_uint32 format, mtp_uint32 *num_obj)
1315 mtp_store_t *store = NULL;
1316 mtp_obj_t *obj = NULL;
1318 mtp_uint32 numobj = 0;
1321 if (store_id != PTP_STORAGEID_ALL) {
1322 store = _device_get_store(store_id);
1323 if (store == NULL) {
1324 ERR("specific store is null");
1325 return MTP_ERROR_INVALID_STORE;
1331 *num_obj = _device_get_num_objects(store_id);
1333 *num_obj = _device_get_num_objects_with_format(store_id,
1336 return MTP_ERROR_NONE;
1339 /* return the number of direct children for a particular association
1340 * (in a single store)
1342 if (h_parent == PTP_OBJECTHANDLE_ALL) {
1344 h_parent = PTP_OBJECTHANDLE_ROOT;
1345 if (store_id == PTP_STORAGEID_ALL) {
1346 for (i = (_device_get_num_stores() - 1); i >= 0; i--) {
1347 store = _device_get_store_at_index(i);
1348 if (store == NULL) {
1349 ERR("Store is null");
1350 return MTP_ERROR_STORE_NOT_AVAILABLE;
1352 numobj += _entity_get_num_children(store,
1357 return MTP_ERROR_NONE;
1360 /* Initiator wants number of children of a particular association */
1361 obj = _device_get_object_with_handle(h_parent);
1364 return MTP_ERROR_INVALID_OBJECTHANDLE;
1367 if (obj->obj_info->obj_fmt != PTP_FMT_ASSOCIATION) {
1368 ERR("format is not association");
1369 return MTP_ERROR_INVALID_PARENT;
1372 store = _device_get_store_containing_obj(h_parent);
1375 if (store == NULL) {
1376 ERR("store is null");
1377 return MTP_ERROR_STORE_NOT_AVAILABLE;
1380 *num_obj = _entity_get_num_children(store, h_parent, format);
1381 return MTP_ERROR_NONE;
1384 mtp_err_t _hutil_get_object_handles(mtp_uint32 store_id, mtp_uint32 format,
1385 mtp_uint32 h_parent, ptp_array_t *handle_arr)
1387 mtp_store_t *store = NULL;
1390 if (h_parent == PTP_OBJECTHANDLE_ALL || h_parent == PTP_OBJECTHANDLE_ROOT) {
1391 for (i = 0; i < _device_get_num_stores(); i++) {
1392 store = _device_get_store_at_index(i);
1393 if (store && store->obj_list.nnodes == 0)
1394 _entity_store_recursive_enum_folder_objects(store, NULL);
1396 g_is_full_enum = TRUE;
1399 if (store_id == PTP_STORAGEID_ALL && h_parent == PTP_OBJECTHANDLE_ROOT) {
1400 for (i = 0; i < _device_get_num_stores(); i++) {
1401 store = _device_get_store_at_index(i);
1402 _entity_get_objects_from_store_by_format(store, format, handle_arr);
1404 return MTP_ERROR_NONE;
1406 } else if (store_id == PTP_STORAGEID_ALL && h_parent == PTP_OBJECTHANDLE_ALL) {
1407 h_parent = PTP_OBJECTHANDLE_ROOT;
1408 for (i = 0; i < _device_get_num_stores(); i++) {
1409 store = _device_get_store_at_index(i);
1410 _entity_get_child_handles_with_same_format(store, h_parent, format, handle_arr);
1412 return MTP_ERROR_NONE;
1414 } else if (store_id != PTP_STORAGEID_ALL && h_parent == PTP_OBJECTHANDLE_ROOT) {
1415 store = _device_get_store(store_id);
1416 if (store == NULL) {
1417 ERR("invalid store id [%d]\n", store_id);
1418 return MTP_ERROR_INVALID_STORE;
1421 _entity_get_objects_from_store_by_format(store, format, handle_arr);
1422 return MTP_ERROR_NONE;
1424 } else if (store_id != PTP_STORAGEID_ALL && h_parent == PTP_OBJECTHANDLE_ALL) {
1425 h_parent = PTP_OBJECTHANDLE_ROOT;
1426 store = _device_get_store(store_id);
1427 if (store == NULL) {
1428 ERR("invalid store id [%d]\n", store_id);
1429 return MTP_ERROR_INVALID_STORE;
1431 _entity_get_child_handles_with_same_format(store, h_parent, format, handle_arr);
1432 return MTP_ERROR_NONE;
1435 store = _device_get_store(store_id);
1436 if (store == NULL) {
1437 ERR("invalid store id [%d]\n", store_id);
1438 return MTP_ERROR_INVALID_STORE;
1441 _entity_get_child_handles_with_same_format(store, h_parent, format, handle_arr);
1442 return MTP_ERROR_NONE;
1445 mtp_err_t _hutil_construct_object_entry(mtp_uint32 store_id,
1446 mtp_uint32 h_parent, obj_data_t *objdata, mtp_obj_t **obj, void *data,
1449 mtp_store_t *store = NULL;
1450 mtp_obj_t *tobj = NULL;
1451 obj_info_t *obj_info = NULL;
1452 mtp_char file_name[MTP_MAX_FILENAME_SIZE + 1] = { 0 };
1456 h_parent = _device_get_default_parent_handle();
1457 } else if (h_parent == 0xFFFFFFFF) {
1458 h_parent = PTP_OBJECTHANDLE_ROOT;
1461 store_id = _device_get_default_store_id();
1464 ERR("_device_get_default_store_id Fail");
1465 return MTP_ERROR_STORE_NOT_AVAILABLE;
1469 /* If the second parameter is used,
1470 * the first must also be used.
1472 return MTP_ERROR_INVALID_PARAM;
1474 h_parent = _device_get_default_parent_handle();
1478 if (objdata != NULL) {
1479 store = _device_get_store(objdata->store_id);
1480 if (store != NULL) {
1481 DBG("check free size instead of re-calculation");
1482 _entity_update_store_info_run_time(&(store->store_info),
1483 (store->root_path));
1486 /* Delete and invalidate the old obj_info for send object */
1487 if (objdata->obj != NULL) {
1488 _entity_dealloc_mtp_obj(objdata->obj);
1492 store = _device_get_store(store_id);
1493 if (store == NULL) {
1494 ERR("Store not found");
1495 return MTP_ERROR_INVALID_STORE;
1498 if (store->store_info.access == PTP_STORAGEACCESS_R) {
1499 ERR("Read only storage");
1500 return MTP_ERROR_STORE_READ_ONLY;
1503 if ((store->store_info.free_space) == 0 ||
1504 (store->store_info.free_space >
1505 store->store_info.capacity)) {
1506 ERR("free space is not enough [%ld:%ld]\n",
1507 store->store_info.free_space,
1508 store->store_info.capacity);
1509 return MTP_ERROR_STORE_FULL;
1512 obj_info = _entity_alloc_object_info();
1513 if (obj_info == NULL) {
1514 ERR("_entity_alloc_object_info Fail");
1515 return MTP_ERROR_GENERAL;
1518 if (_entity_parse_raw_obj_info(data, data_sz, obj_info, file_name,
1519 sizeof(file_name)) != data_sz) {
1520 /* wrong object info sent from Host.*/
1521 ERR("Invalid objet info");
1522 _entity_dealloc_obj_info(obj_info);
1523 return MTP_ERROR_INVALID_OBJECT_INFO;
1525 obj_info->store_id = store_id;
1526 obj_info->h_parent = h_parent;
1528 switch (_hutil_add_object_entry(obj_info, file_name, &tobj)) {
1529 case MTP_ERROR_NONE:
1533 case MTP_ERROR_STORE_FULL:
1534 return MTP_ERROR_STORE_FULL;
1536 case MTP_ERROR_INVALID_OBJECTHANDLE:
1537 return MTP_ERROR_INVALID_OBJECTHANDLE;
1539 case MTP_ERROR_INVALID_PARENT:
1540 return MTP_ERROR_INVALID_PARENT;
1543 return MTP_ERROR_GENERAL;
1546 return MTP_ERROR_NONE;
1549 mtp_err_t _hutil_construct_object_entry_prop_list(mtp_uint32 store_id,
1550 mtp_uint32 h_parent, mtp_uint16 format, mtp_uint64 obj_sz,
1551 obj_data_t *obj_data, mtp_obj_t **obj_ptr, void *data,
1552 mtp_int32 data_sz, mtp_uint32 *err_idx)
1554 mtp_uint32 index = 0;
1555 mtp_store_t *store = NULL;
1556 mtp_obj_t *obj = NULL;
1557 obj_prop_desc_t *prop_desc = NULL;
1558 obj_prop_val_t *prop_val = NULL;
1559 mtp_uint32 num_elem = 0;
1560 mtp_int32 quad_sz = 0;
1561 mtp_uint32 obj_handle = 0;
1562 mtp_uint16 prop_code = 0;
1563 mtp_uint16 data_type = 0;
1564 obj_info_t *obj_info = NULL;
1565 mtp_uchar *temp = NULL;
1566 mtp_int32 bytes_left = data_sz;
1569 #ifdef MTP_SUPPORT_ALBUM_ART
1570 mtp_uint16 albumFormat = 0;
1571 mtp_char alb_extn[MTP_MAX_EXTENSION_LENGTH + 1] = { 0 };
1572 mtp_char *alb_buf = NULL;
1573 mtp_uint32 alb_sz = 0;
1574 mtp_uint32 h_temp = INVALID_FILE;
1575 mtp_int32 error = 0;
1576 #endif /*MTP_SUPPORT_ALBUM_ART*/
1577 mtp_char file_name[MTP_MAX_FILENAME_SIZE + 1] = { 0 };
1579 if (obj_data != NULL && obj_data->obj != NULL) {
1580 store = _device_get_store(obj_data->store_id);
1581 if (store != NULL) {
1582 DBG("check free size instead of re-calculation");
1583 _entity_update_store_info_run_time(&(store->store_info),
1584 (store->root_path));
1586 _entity_dealloc_mtp_obj(obj_data->obj);
1589 store = _device_get_store(store_id);
1590 if (store == NULL) {
1591 ERR("Could not get the store");
1592 return MTP_ERROR_INVALID_STORE;
1595 if (store->store_info.access == PTP_STORAGEACCESS_R) {
1596 ERR("Only read access allowed on store");
1597 return MTP_ERROR_STORE_READ_ONLY;
1600 if ((store->store_info.free_space) == 0 ||
1601 (store->store_info.free_space > store->store_info.capacity)) {
1602 ERR("free space is not enough [%ld bytes]\n",
1603 store->store_info.free_space);
1604 return MTP_ERROR_STORE_FULL;
1607 obj_info = _entity_alloc_object_info();
1608 if (obj_info == NULL) {
1609 ERR("_entity_alloc_object_info Fail");
1610 return MTP_ERROR_GENERAL;
1613 obj_info->obj_fmt = format;
1614 if (obj_info->obj_fmt == PTP_FMT_ASSOCIATION) {
1615 obj_info->association_type = PTP_ASSOCIATIONTYPE_FOLDER;
1618 obj_info->file_size = obj_sz;
1620 /* Prop value quadruple: Object Handle, PropertyCode, DataType
1621 * and DTS Prop Value (assume a byte value)
1623 temp = (mtp_uchar *) data;
1624 bytes_left = data_sz;
1625 quad_sz = sizeof(mtp_uint32) + sizeof(mtp_uint16) + sizeof(mtp_uint16) +
1627 memcpy(&num_elem, temp, sizeof(mtp_uint32));
1628 #ifdef __BIG_ENDIAN__
1629 _util_conv_byte_order(&num_elem, sizeof(mtp_uint32));
1631 temp += sizeof(mtp_uint32);
1632 bytes_left -= sizeof(mtp_uint32);
1634 /* frequent disconnect/connect make bluscreen since below process
1637 for (index = 0; index < num_elem; index++) {
1638 if (MTP_PHONE_USB_DISCONNECTED == _util_get_local_usb_status() ||
1639 TRUE == _transport_get_usb_discon_state()) {
1640 /* seems usb is disconnected, stop */
1641 _entity_dealloc_obj_info(obj_info);
1642 resp = MTP_ERROR_GENERAL;
1647 if (bytes_left < quad_sz) {
1648 /* seems invalid dataset received: Stops parsing */
1649 _entity_dealloc_obj_info(obj_info);
1650 resp = MTP_ERROR_INVALID_DATASET;
1654 /* Get ObjectHandle & validate */
1655 memcpy(&obj_handle, temp, sizeof(mtp_uint32));
1656 #ifdef __BIG_ENDIAN__
1657 _util_conv_byte_order(&obj_handle, sizeof(mtp_uint32));
1658 #endif /* __BIG_ENDIAN__ */
1659 temp += sizeof(mtp_uint32);
1660 bytes_left -= sizeof(mtp_uint32);
1661 if (obj_handle != 0x00000000) {
1662 _entity_dealloc_obj_info(obj_info);
1663 resp = MTP_ERROR_INVALID_OBJECTHANDLE;
1667 /* Get PropCode & Validate */
1668 memcpy(&prop_code, temp, sizeof(mtp_uint16));
1669 #ifdef __BIG_ENDIAN__
1670 _util_conv_byte_order(&prop_code, sizeof(mtp_uint16));
1671 #endif /* __BIG_ENDIAN__ */
1672 temp += sizeof(mtp_uint16);
1673 bytes_left -= sizeof(mtp_uint16);
1674 prop_desc = _prop_get_obj_prop_desc(obj_info->obj_fmt, prop_code);
1675 if (prop_desc == NULL) {
1676 _entity_dealloc_obj_info(obj_info);
1677 ERR("property may be unsupported!!");
1678 resp = MTP_ERROR_INVALID_OBJ_PROP_CODE;
1682 /* Verify that properties already present in parameters
1683 * don't get repeated in the list
1685 if ((prop_code == MTP_OBJ_PROPERTYCODE_STORAGEID) ||
1686 (prop_code == MTP_OBJ_PROPERTYCODE_PARENT) ||
1687 (prop_code == MTP_OBJ_PROPERTYCODE_OBJECTFORMAT) ||
1688 (prop_code == MTP_OBJ_PROPERTYCODE_OBJECTSIZE)) {
1689 _entity_dealloc_obj_info(obj_info);
1690 resp = MTP_ERROR_INVALID_DATASET;
1695 memcpy(&data_type, temp, sizeof(mtp_uint16));
1696 #ifdef __BIG_ENDIAN__
1697 _util_conv_byte_order(&data_type, sizeof(mtp_uint16));
1698 #endif /* __BIG_ENDIAN__ */
1699 temp += sizeof(mtp_uint16);
1700 bytes_left -= sizeof(mtp_uint16);
1701 if (data_type != prop_desc->propinfo.data_type) {
1702 _entity_dealloc_obj_info(obj_info);
1703 resp = MTP_ERROR_INVALID_OBJECT_PROP_FORMAT;
1707 /* Acquire object information related data. */
1708 prop_val = _prop_alloc_obj_propval(prop_desc);
1709 if (prop_val == NULL) {
1712 _prop_set_current_array_val(prop_val, temp, bytes_left);
1713 switch (prop_code) {
1714 case MTP_OBJ_PROPERTYCODE_WIDTH:
1715 // TODO: find mechanism to save (integer)
1717 case MTP_OBJ_PROPERTYCODE_TRACK:
1718 // TODO: find mechanism to save (integer)
1720 case MTP_OBJ_PROPERTYCODE_GENRE:
1721 // TODO: find mechanism to save (string)
1723 case MTP_OBJ_PROPERTYCODE_HEIGHT:
1724 // TODO: find mechanism to save (integer)
1726 case MTP_OBJ_PROPERTYCODE_ARTIST:
1727 // TODO: find mechanism to save (string)
1729 case MTP_OBJ_PROPERTYCODE_DURATION:
1730 // TODO: find mechanism to save (integer)
1732 case MTP_OBJ_PROPERTYCODE_COMPOSER:
1733 // TODO: find mechanism to save (string)
1735 case MTP_OBJ_PROPERTYCODE_ALBUMNAME:
1736 // TODO: find mechanism to save (string)
1738 case MTP_OBJ_PROPERTYCODE_SAMPLERATE:
1739 // TODO: find mechanism to save (integer)
1741 case MTP_OBJ_PROPERTYCODE_DATECREATED:
1742 // TODO: find mechanism to save (string)
1744 case MTP_OBJ_PROPERTYCODE_DATEMODIFIED:
1745 // TODO: find mechanism to save (string)
1747 case MTP_OBJ_PROPERTYCODE_AUDIOBITRATE:
1748 // TODO: find mechanism to save (integer)
1750 case MTP_OBJ_PROPERTYCODE_VIDEOBITRATE:
1751 // TODO: find mechanism to save (integer)
1753 case MTP_OBJ_PROPERTYCODE_OBJECTFILENAME:
1754 /* empty metadata folder problem
1757 if (prop_val->current_val.str->num_chars == 0) {
1758 g_strlcpy(file_name, MTP_UNKNOWN_METADATA, sizeof(file_name));
1760 _util_utf16_to_utf8(file_name, sizeof(file_name),
1761 prop_val->current_val.str->str);
1765 case MTP_OBJ_PROPERTYCODE_PROTECTIONSTATUS:
1766 #ifdef MTP_SUPPORT_SET_PROTECTION
1767 memcpy(&obj_info->protcn_status, prop_val->current_val.integer,
1768 sizeof(mtp_uint16));
1769 #else /* MTP_SUPPORT_SET_PROTECTION */
1770 obj_info->protcn_status = PTP_PROTECTIONSTATUS_NOPROTECTION;
1771 #endif /*MTP_SUPPORT_SET_PROTECTION*/
1774 case MTP_OBJ_PROPERTYCODE_ASSOCIATIONTYPE:
1775 memcpy(&obj_info->association_type, prop_val->current_val.integer,
1776 sizeof(mtp_uint16));
1779 case MTP_OBJ_PROPERTYCODE_NUMBEROFCHANNELS:
1780 // TODO: find mechanism to save (integer)
1782 case MTP_OBJ_PROPERTYCODE_FRAMESPER1KSECONDS:
1783 // TODO: find mechanism to save (integer)
1785 #ifdef MTP_SUPPORT_ALBUM_ART
1786 case MTP_OBJ_PROPERTYCODE_SAMPLEDATA:
1787 /* save sample data(album cover data) with
1788 * sample format, otherwise no extension
1789 * update db with sample data path
1790 * there is no case that this position is called
1791 * again but prevent detect this
1795 alb_buf = g_malloc(sizeof(mtp_uchar) *
1796 (prop_val->current_val.array->num_ele) + 1);
1797 alb_sz = prop_val->current_val.array->num_ele;
1798 if (alb_buf != NULL) {
1800 sizeof(mtp_uchar) * alb_sz + 1);
1803 (prop_val->current_val.array->array_entry),
1804 sizeof(mtp_uchar) * alb_sz);
1806 ERR("album art test mem allocation Fail");
1807 _prop_destroy_obj_propval(prop_val);
1808 _entity_dealloc_obj_info(obj_info);
1809 return MTP_ERROR_GENERAL;
1813 case MTP_OBJ_PROPERTYCODE_SAMPLEFORMAT:
1814 /* if is_albumart is turned on, Move file with
1815 * new extension. And update db with data path
1817 memcpy(&albumFormat, prop_val->current_val.integer,
1818 sizeof(mtp_uint16));
1819 switch (albumFormat) {
1820 case PTP_FMT_IMG_EXIF:
1821 g_snprintf(alb_extn, sizeof(alb_extn), "%s", "jpg");
1823 case PTP_FMT_IMG_GIF:
1824 g_snprintf(alb_extn, sizeof(alb_extn), "%s", "gif");
1826 case PTP_FMT_IMG_PNG:
1827 g_snprintf(alb_extn, sizeof(alb_extn), "%s", "png");
1830 g_snprintf(alb_extn, sizeof(alb_extn), "%s", "wma");
1833 g_snprintf(alb_extn, sizeof(alb_extn), "%s", "mpg");
1836 g_snprintf(alb_extn, sizeof(alb_extn), "%s", "dat");
1840 ERR("sampleformatl![0x%x], extension[%s]\n", prop_code, alb_extn);
1842 case MTP_OBJ_PROPERTYCODE_SAMPLESIZE:
1843 case MTP_OBJ_PROPERTYCODE_SAMPLEHEIGHT:
1844 case MTP_OBJ_PROPERTYCODE_SAMPLEWIDTH:
1845 case MTP_OBJ_PROPERTYCODE_SAMPLEDURATION:
1846 DBG("Sample data is not supported [0x%x]\n", prop_code);
1848 #endif /*MTP_SUPPORT_ALBUM_ART*/
1851 DBG("Unsupported Property [0x%x]\n", prop_code);
1855 temp += _prop_size_obj_propval(prop_val);
1856 bytes_left -= _prop_size_obj_propval(prop_val);
1857 _prop_destroy_obj_propval(prop_val);
1860 obj_info->store_id = store_id;
1861 obj_info->h_parent = h_parent;
1863 if ((resp = _hutil_add_object_entry(obj_info, file_name, &obj)) !=
1868 #ifdef MTP_SUPPORT_ALBUM_ART
1869 mtp_char full_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1870 mtp_char extn[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1872 g_strlcpy(full_path, obj->file_path, MTP_MAX_PATHNAME_SIZE + 1);
1874 /* in case of album, if there is album data, fill it in this file */
1875 if (obj_info->obj_fmt != PTP_FMT_ASSOCIATION ||
1876 (obj_info->obj_fmt == PTP_FMT_ASSOCIATION &&
1877 obj_info->association_type != PTP_ASSOCIATIONTYPE_UNDEFINED &&
1878 obj_info->association_type != PTP_ASSOCIATIONTYPE_FOLDER)) {
1880 _util_get_file_extn(full_path, extn);
1881 if (!strcasecmp(extn, "alb")) {
1882 /* check db whether it contains sample form
1883 * save sample data(album cover data) with
1884 * sample format, otherwise no extension
1886 if (alb_buf != NULL) {
1888 h_temp = _util_file_open(full_path,
1889 MTP_FILE_WRITE, &error);
1890 if (h_temp != INVALID_FILE) {
1891 _util_file_write(h_temp, alb_buf,
1892 sizeof(mtp_uchar) *alb_sz);
1893 _util_file_close(h_temp);
1895 ERR("open album file Fail!!");
1898 ERR("no album art data");
1904 #endif /* MTP_SUPPORT_ALBUM_ART */
1906 return MTP_ERROR_NONE;
1909 #ifdef MTP_SUPPORT_ALBUM_ART
1911 #endif /* MTP_SUPPORT_ALBUM_ART */
1915 mtp_err_t _hutil_get_object_prop_value(mtp_uint32 obj_handle,
1916 mtp_uint32 prop_code, obj_prop_val_t *prop_val, mtp_obj_t **obj)
1918 obj_prop_val_t *tprop = NULL;
1919 mtp_obj_t *tobj = NULL;
1921 tobj = _device_get_object_with_handle(obj_handle);
1923 ERR("requested handle does not exist[0x%x]\n",obj_handle);
1924 return MTP_ERROR_INVALID_OBJECTHANDLE;
1927 tprop = _prop_get_prop_val(tobj, prop_code);
1928 if (tprop != NULL) {
1929 memcpy(prop_val, tprop, sizeof(obj_prop_val_t));
1931 return MTP_ERROR_NONE;
1934 ERR("can not get the prop value for propcode [0x%x]\n", prop_code);
1935 return MTP_ERROR_GENERAL;
1938 mtp_err_t _hutil_update_object_property(mtp_uint32 obj_handle,
1939 mtp_uint32 prop_code, mtp_uint16 *data_type, void *buf,
1940 mtp_uint32 buf_sz, mtp_uint32 *prop_sz)
1942 mtp_int32 error = 0;
1943 mtp_uint32 p_size = 0;
1944 mtp_obj_t *obj = NULL;
1945 obj_info_t *obj_info = NULL;
1946 obj_prop_desc_t *prp_dev = NULL;
1947 mtp_char temp_buf[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1948 mtp_char orig_pfpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1949 mtp_wchar mov_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1950 mtp_char orig_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1951 mtp_char dest_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
1953 retv_if(NULL == buf, MTP_ERROR_INVALID_PARAM);
1955 obj = _device_get_object_with_handle(obj_handle);
1956 if ((NULL == obj) || (NULL == obj->obj_info)) {
1957 ERR("Object not found");
1958 return MTP_ERROR_INVALID_OBJECTHANDLE;
1961 obj_info = obj->obj_info;
1962 /* Avoid to rename file/folder during file operating by phone side. */
1963 if (_util_is_file_opened(obj->file_path) == TRUE) {
1964 ERR_SECURE("Object [%s] is already opened\n", obj->file_path);
1965 return MTP_ERROR_GENERAL;
1968 prp_dev = _prop_get_obj_prop_desc(obj_info->obj_fmt, prop_code);
1969 if (prp_dev == NULL) {
1970 ERR("_prop_get_obj_prop_desc Fail");
1971 return MTP_ERROR_INVALID_OBJ_PROP_CODE;
1974 #ifdef MTP_SUPPORT_SET_PROTECTION
1975 if (obj_info->protcn_status == PTP_PROTECTIONSTATUS_READONLY) {
1976 ERR("protection is PTP_PROTECTIONSTATUS_READONLY");
1977 return MTP_ERROR_ACCESS_DENIED;
1979 #endif /* MTP_SUPPORT_SET_PROTECTION */
1981 if (prp_dev->propinfo.get_set == PTP_PROPGETSET_GETONLY) {
1982 ERR("property type is GETONLY");
1983 return MTP_ERROR_ACCESS_DENIED;
1986 if (data_type != NULL && *data_type != prp_dev->propinfo.data_type) {
1987 ERR("Not matched data type [%d][%d]\n",
1988 *data_type, prp_dev->propinfo.data_type);
1989 return MTP_ERROR_INVALID_OBJECT_PROP_FORMAT;
1992 /* Set up needed object info fields */
1993 if (prop_code == MTP_OBJ_PROPERTYCODE_OBJECTFILENAME) {
1994 ptp_string_t fname = { 0 };
1996 _prop_init_ptpstring(&fname);
1997 _prop_parse_rawstring(&fname, buf, buf_sz);
1999 _util_utf16_to_utf8(temp_buf, sizeof(temp_buf),
2001 g_strlcpy(orig_fpath, obj->file_path,
2002 MTP_MAX_PATHNAME_SIZE + 1);
2003 _util_get_parent_path(orig_fpath, orig_pfpath);
2005 if (_util_create_path(dest_fpath, sizeof(dest_fpath),
2006 orig_pfpath, temp_buf) == FALSE) {
2007 ERR("Path is too long");
2008 return MTP_ERROR_ACCESS_DENIED;
2010 _util_utf8_to_utf16(mov_fpath,
2011 sizeof(mov_fpath) / WCHAR_SIZ, dest_fpath);
2013 /* when changed name is different */
2014 if (strcasecmp(orig_fpath, dest_fpath)) {
2015 /* Extension change is not permitted */
2016 mtp_char orig_extn[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
2017 mtp_char dest_extn[MTP_MAX_PATHNAME_SIZE + 1] = { 0 };
2019 _util_get_file_extn(orig_fpath, orig_extn);
2020 _util_get_file_extn(dest_fpath, dest_extn);
2022 if (strcasecmp(orig_extn, dest_extn)) {
2023 ERR("file extension is different with original\
2024 one [%s]:[%s]\n", orig_extn, dest_extn);
2025 return MTP_ERROR_INVALID_OBJECT_PROP_FORMAT;
2029 if (_entity_check_child_obj_path(obj, orig_fpath,
2030 dest_fpath) == FALSE) {
2031 ERR("_entity_check_child_obj_path FALSE. ");
2032 return MTP_ERROR_GENERAL;
2034 g_snprintf(g_last_moved, MTP_MAX_PATHNAME_SIZE + 1,
2036 if (FALSE == _util_file_move(orig_fpath, dest_fpath,
2038 if (EACCES == error)
2039 return MTP_ERROR_ACCESS_DENIED;
2040 return MTP_ERROR_GENERAL;
2043 if (obj->obj_info->obj_fmt == PTP_FMT_ASSOCIATION) {
2044 _util_scan_folder_contents_in_db(orig_fpath);
2045 _util_scan_folder_contents_in_db(dest_fpath);
2047 _util_delete_file_from_db(obj->media_id);
2048 _util_add_file_to_db(obj, dest_fpath);
2051 /* Finally assign new handle and update full path */
2052 _entity_set_object_file_path(obj, dest_fpath,
2056 if (_entity_set_child_object_path(obj, orig_fpath,
2057 dest_fpath) == FALSE) {
2058 ERR("failed to set the full path!!");
2059 return MTP_ERROR_INVALID_OBJECT_PROP_FORMAT;
2062 DBG("File moved to [%s]\n", dest_fpath);
2064 ERR_SECURE("changed name is same with original one. [%s]\n",
2067 p_size = _prop_size_ptpstring(&fname);
2068 } else if (prop_code == MTP_OBJ_PROPERTYCODE_ASSOCIATIONTYPE) {
2069 memcpy(&obj_info->association_type, buf, sizeof(mtp_uint16));
2070 p_size = sizeof(mtp_uint16);
2072 ERR("Propert [0x%x] is GETONLY\n", prop_code);
2075 if (prop_sz != NULL) {
2079 return MTP_ERROR_NONE;
2082 mtp_err_t _hutil_get_prop_desc(mtp_uint32 format, mtp_uint32 prop_code,
2085 obj_prop_desc_t *prop = NULL;
2087 prop = _prop_get_obj_prop_desc(format, prop_code);
2089 ERR("pProperty is NULL");
2090 return MTP_ERROR_GENERAL;
2093 memcpy(data, prop, sizeof(obj_prop_desc_t));
2094 return MTP_ERROR_NONE;
2097 mtp_err_t _hutil_get_object_prop_supported(mtp_uint32 format,
2098 ptp_array_t *prop_arr)
2100 _prop_get_supp_obj_props(format, prop_arr);
2101 return MTP_ERROR_NONE;
2104 #ifndef MTP_USE_RUNTIME_GETOBJECTPROPVALUE
2105 mtp_err_t _hutil_get_object_prop_list(mtp_uint32 obj_handle, mtp_uint32 format,
2106 mtp_uint32 prop_code, mtp_uint32 group_code, mtp_uint32 depth,
2107 obj_proplist_t *prop_list)
2108 #else /* MTP_USE_RUNTIME_GETOBJECTPROPVALUE */
2109 mtp_err_t _hutil_get_object_prop_list(mtp_uint32 obj_handle, mtp_uint32 format,
2110 mtp_uint32 prop_code, mtp_uint32 group_code, mtp_uint32 depth,
2111 obj_proplist_t *prop_list, ptp_array_t *obj_arr)
2112 #endif /* MTP_USE_RUNTIME_GETOBJECTPROPVALUE */
2114 #ifndef MTP_USE_RUNTIME_GETOBJECTPROPVALUE
2115 ptp_array_t obj_arr = { 0 };
2116 #endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/
2117 mtp_obj_t *obj = NULL;
2120 mtp_store_t *store = NULL;
2122 if ((obj_handle != PTP_OBJECTHANDLE_UNDEFINED) &&
2123 (obj_handle != PTP_OBJECTHANDLE_ALL)) {
2124 /* Is this object handle valid? */
2125 store = _device_get_store_containing_obj(obj_handle);
2126 if (store == NULL) {
2127 ERR("invalid object handle");
2128 return MTP_ERROR_INVALID_OBJECTHANDLE;
2132 if (prop_code == PTP_PROPERTY_UNDEFINED) {
2133 /* PropGroupCode should be used if Property code
2136 if (group_code == 0x0) {
2137 ERR("PropGroupCode is zero");
2138 return MTP_ERROR_INVALID_PARAM;
2142 if (!(obj_handle == PTP_OBJECTHANDLE_ALL ||
2143 obj_handle == PTP_OBJECTHANDLE_UNDEFINED) &&
2144 !(format == PTP_FORMATCODE_NOTUSED ||
2145 format == PTP_FORMATCODE_ALL)) {
2146 ERR("both object handle and format code is specified!\
2147 return nospecification by format");
2148 return MTP_ERROR_NO_SPEC_BY_FORMAT;
2151 _util_init_list(&(prop_list->prop_quad_list));
2152 _prop_init_ptparray(obj_arr, PTR_TYPE);
2154 if (store != NULL) {
2155 _entity_get_objects_from_store_till_depth(store, obj_handle,
2156 format, depth, obj_arr);
2158 for (ii = 0; ii < _device_get_num_stores(); ii++) {
2159 store = _device_get_store_at_index(ii);
2160 _entity_get_objects_from_store_till_depth(store,
2161 obj_handle, format, depth, obj_arr);
2165 if (obj_arr->num_ele != 0) {
2166 mtp_obj_t **ptr_obj;
2167 ptr_obj = obj_arr->array_entry;
2169 for (i = 0; i < obj_arr->num_ele; i++) {
2174 if (_prop_get_obj_proplist(obj, prop_code, group_code,
2175 prop_list) == FALSE) {
2176 ERR("Fail to create Proplist");
2177 #ifndef MTP_USE_RUNTIME_GETOBJECTPROPVALUE
2178 _prop_deinit_ptparray(&obj_arr);
2179 #endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/
2180 return MTP_ERROR_GENERAL;
2185 #ifndef MTP_USE_RUNTIME_GETOBJECTPROPVALUE
2186 prop_deinit_ptparray(&obj_arr);
2187 #endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/
2189 return MTP_ERROR_NONE;
2192 mtp_err_t _hutil_remove_object_reference(mtp_uint32 obj_handle,
2193 mtp_uint32 ref_handle)
2195 mtp_obj_t *obj = NULL;
2197 obj = _device_get_object_with_handle(obj_handle);
2199 ERR("No object for handle[%d]\n", obj_handle);
2200 return MTP_ERROR_NONE;
2203 if (_entity_remove_reference_child_array(obj, ref_handle) == FALSE) {
2204 ERR("_entity_remove_reference_child_array Fail");
2207 return MTP_ERROR_NONE;
2210 mtp_err_t _hutil_add_object_references_enhanced(mtp_uint32 obj_handle,
2211 mtp_uchar *buffer, mtp_uint32 buf_sz)
2213 mtp_obj_t *obj = NULL;
2215 obj = _device_get_object_with_handle(obj_handle);
2217 DBG("No object for handle[0x%x]\n", obj_handle);
2218 return MTP_ERROR_NONE;
2221 if (_entity_set_reference_child_array(obj, buffer, buf_sz) == FALSE) {
2222 ERR("_entity_set_reference_child_array Fail");
2223 return MTP_ERROR_GENERAL;
2226 return MTP_ERROR_NONE;
2229 mtp_err_t _hutil_get_object_references(mtp_uint32 obj_handle,
2230 ptp_array_t *parray, mtp_uint32 *num_ele)
2232 mtp_obj_t *obj = NULL;
2233 mtp_obj_t *ref_obj = NULL;
2235 mtp_uint32 *ref_ptr = NULL;
2236 ptp_array_t ref_arr = { 0 };
2238 obj = _device_get_object_with_handle(obj_handle);
2239 if (NULL == obj || NULL == obj->obj_info) {
2241 return MTP_ERROR_INVALID_OBJECTHANDLE;
2244 if (parray == NULL) {
2246 return MTP_ERROR_GENERAL;
2249 if (obj->child_array.num_ele == 0) {
2251 return MTP_ERROR_NONE;
2254 _prop_init_ptparray(&ref_arr, obj->child_array.type);
2255 _prop_copy_ptparray(&ref_arr, &(obj->child_array));
2256 ref_ptr = (mtp_uint32 *)(ref_arr.array_entry);
2258 for (idx = 0; idx < ref_arr.num_ele; idx++) {
2259 ref_obj = _device_get_object_with_handle(ref_ptr[idx]);
2260 if (ref_obj == NULL) {
2261 _entity_remove_reference_child_array(obj, ref_ptr[idx]);
2265 *num_ele = obj->child_array.num_ele;
2267 _prop_init_ptparray(parray, obj->child_array.type);
2268 _prop_grow_ptparray(parray, *num_ele);
2269 _prop_copy_ptparray(parray, &(obj->child_array));
2272 _prop_deinit_ptparray(&ref_arr);
2273 return MTP_ERROR_NONE;
2276 mtp_err_t _hutil_get_number_of_objects(mtp_uint32 store_id, mtp_uint32 *num_obj)
2278 *num_obj = _device_get_num_objects(store_id);
2279 return MTP_ERROR_NONE;
2282 mtp_err_t _hutil_get_interdep_prop_config_list_size(mtp_uint32 *list_sz,
2285 *list_sz = _prop_get_size_interdep_proplist(&interdep_proplist,
2287 return MTP_ERROR_NONE;
2290 mtp_err_t _hutil_get_interdep_prop_config_list_data(void *data,
2291 mtp_uint32 list_sz, mtp_uint32 format)
2293 if (list_sz == _prop_pack_interdep_proplist(&interdep_proplist,
2294 format, data, list_sz)) {
2295 return MTP_ERROR_NONE;
2298 ERR("packet and requested size do not match");
2299 return MTP_ERROR_GENERAL;
2302 mtp_err_t _hutil_get_playback_skip(mtp_int32 skip_param)
2305 mtp_obj_t *obj = NULL;
2306 mtp_uint32 new_idx = 0;
2307 mtp_uint32 new_hobj = 0;
2308 mtp_uint32 obj_handle = 0;
2309 mtp_obj_t *par_obj = NULL;
2310 obj_info_t *obj_info = NULL;
2311 ptp_array_t *ref_arr = NULL;
2312 device_prop_desc_t *dev_prop = NULL;
2314 retv_if(skip_param == 0, MTP_ERROR_INVALID_PARAM);
2316 if (_device_get_playback_obj(&obj_handle) == FALSE) {
2317 ERR("_device_get_playback_obj Fail");
2318 return MTP_ERROR_GENERAL;
2321 if (obj_handle == 0x0) {
2322 return MTP_ERROR_NONE;
2325 obj = _device_get_object_with_handle(obj_handle);
2326 if (obj == NULL || obj->obj_info == NULL) {
2327 ERR("obj or obj_info is NULL");
2328 return MTP_ERROR_GENERAL;
2331 obj_info = obj->obj_info;
2332 if ((obj_info->obj_fmt == PTP_FMT_WAVE) ||
2333 (obj_info->obj_fmt == PTP_FMT_MP3) ||
2334 (obj_info->obj_fmt == MTP_FMT_WMA) ||
2335 (obj_info->obj_fmt == MTP_FMT_WMV) ||
2336 (obj_info->obj_fmt == MTP_FMT_UNDEFINED_AUDIO)) {
2337 par_obj = _device_get_object_with_handle(obj_info->h_parent);
2339 ERR("parent not found in obj_list");
2340 return MTP_ERROR_GENERAL;
2342 ref_arr = _entity_get_reference_child_array(par_obj);
2343 idx = _prop_find_ele_ptparray(ref_arr, obj_handle);
2344 if (idx != ELEMENT_NOT_FOUND) {
2345 if (((long long)idx + (long long)skip_param) > UINT_MAX) {
2346 new_idx = ref_arr->num_ele - 1;
2347 } else if ((idx + skip_param) >= ref_arr->num_ele) {
2350 new_idx = idx + skip_param;
2353 if (_prop_get_ele_ptparray(ref_arr, new_idx,
2354 (void *)(&new_hobj)) == TRUE) {
2355 dev_prop = _device_get_device_property(
2356 MTP_PROPERTYCODE_PLAYBACK_CONT_INDEX);
2357 if (dev_prop == NULL) {
2358 ERR("dev_prop is null");
2359 return MTP_ERROR_GENERAL;
2361 _prop_set_current_integer(dev_prop, 0xFFFFFFFF);
2362 _device_set_playback_obj(new_hobj);
2365 } else if ((obj_info->obj_fmt == MTP_FMT_ABSTRACT_AUDIO_ALBUM) ||
2366 (obj_info->obj_fmt == MTP_FMT_ABSTRACT_VIDEO_ALBUM)) {
2367 dev_prop = _device_get_device_property(
2368 MTP_PROPERTYCODE_PLAYBACK_CONT_INDEX);
2369 if (dev_prop == NULL) {
2370 ERR("dev_prop is null");
2371 return MTP_ERROR_GENERAL;
2373 memcpy(&idx, dev_prop->current_val.integer, sizeof(mtp_uint32));
2374 ref_arr = _entity_get_reference_child_array(obj);
2375 if (((long long)idx + (long long)skip_param) > UINT_MAX) {
2376 new_idx = ref_arr->num_ele - 1;
2377 } else if ((idx + skip_param) >= ref_arr->num_ele) {
2380 new_idx = idx + skip_param;
2382 _prop_set_current_integer(dev_prop, new_idx);
2383 return MTP_ERROR_NONE;
2386 return MTP_ERROR_GENERAL;
2389 mtp_err_t _hutil_format_storage(mtp_uint32 store_id, mtp_uint32 fs_format)
2391 mtp_err_t error = MTP_ERROR_GENERAL;
2392 mtp_store_t *store = NULL;
2394 store = _device_get_store(store_id);
2395 if (store == NULL) {
2396 ERR("Store is NULL");
2400 error = _entity_format_store(store, fs_format);
2401 if (error == PTP_RESPONSE_OK) {
2402 return MTP_ERROR_NONE;
2405 ERR("Format store Fail");
2409 mtp_uint32 _hutil_get_storage_info_size(store_info_t *store_info)
2411 mtp_uint32 size = 0;
2413 size += sizeof(store_info->access);
2414 size += sizeof(store_info->fs_type);
2415 size += sizeof(store_info->free_space);
2416 size += sizeof(store_info->free_space_in_objs);
2417 size += sizeof(store_info->capacity);
2418 size += sizeof(store_info->store_type);
2419 size += _prop_size_ptpstring(&(store_info->store_desc));
2420 size += _prop_size_ptpstring(&(store_info->vol_label));