diff options
author | Hyihong Chae <hh.chae@samsung.com> | 2015-11-03 11:42:59 +0900 |
---|---|---|
committer | Hyihong Chae <hh.chae@samsung.com> | 2015-11-03 11:47:18 +0900 |
commit | bd85f3529a3cf4a566bd800842ca3bf78c9dd00c (patch) | |
tree | 5ddf23a8ac619b49605f8251de95e998af6e1387 | |
parent | f81378259c8c83019251fdcecab4d0628c7e3f67 (diff) | |
download | mtp-responder-bd85f3529a3cf4a566bd800842ca3bf78c9dd00c.tar.gz mtp-responder-bd85f3529a3cf4a566bd800842ca3bf78c9dd00c.tar.bz2 mtp-responder-bd85f3529a3cf4a566bd800842ca3bf78c9dd00c.zip |
Code Sync up from tizen_2.4submit/tizen_common/20151229.154718submit/tizen_common/20151229.144031submit/tizen_common/20151229.142028submit/tizen/20151211.044210accepted/tizen/wearable/20151211.061203accepted/tizen/tv/20151211.062312accepted/tizen/mobile/20151211.055324
Change-Id: I1742218bdb2b3a01568236d72a65bba68aed4f68
Signed-off-by: HyiHong Chae <hh.chae@samsung.com>
47 files changed, 23565 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..7346a98 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,32 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(mtp-responder C) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include/entity) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include/transport) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include/util) + +AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src SRCS) +AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src/entity SRCS) +AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src/transport SRCS) +AUX_SOURCE_DIRECTORY(${CMAKE_SOURCE_DIR}/src/util SRCS) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs REQUIRED glib-2.0 capi-content-media-content + capi-media-metadata-extractor vconf dlog tapi libprivilege-control capi-system-info) + +FOREACH(flag ${pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wall -Werror-implicit-function-declaration") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fexceptions -fvisibility=hidden") + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIE") +SET(CMAKE_EXE_LINKER_FLAGS " -Wl,--as-needed -pie -Wl,--hash-style=both") + +ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} pthread rt gcrypt) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) +INSTALL(FILES mtp-responder.conf DESTINATION /opt/var/lib/misc) diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100755 index 0000000..ec68963 --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,206 @@ +Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+
diff --git a/include/entity/mtp_device.h b/include/entity/mtp_device.h new file mode 100755 index 0000000..3e53f6c --- /dev/null +++ b/include/entity/mtp_device.h @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_DEVICE_H_ +#define _MTP_DEVICE_H_ + +#include "mtp_store.h" +#include "mtp_property.h" + +#define MTP_NUM_DEVICE_DEFAULT 3 + +#define MTP_NUM_DEVICE_WMP11 1 + +#ifdef MTP_SUPPORT_DEVICEPROP_BATTERYLEVEL +#define MTP_NUM_DEVICE_BATTLEVEL 1 +#else /*MTP_SUPPORT_DEVICEPROP_BATTERYLEVEL*/ +#define MTP_NUM_DEVICE_BATTLEVEL 0 +#endif /*MTP_SUPPORT_DEVICEPROP_BATTERYLEVEL*/ + +#ifdef MTP_SUPPORT_DEVICE_CLASS +#define MTP_NUM_DEVICE_DSC 1 +#else /*MTP_SUPPORT_DEVICE_CLASS*/ +#define MTP_NUM_DEVICE_DSC 0 +#endif /*MTP_SUPPORT_DEVICE_CLASS*/ + +#define MTP_NUM_DEVICE_SVC 0 + +/* currently not supported */ +#define MTP_NUM_DEVICE_PLAYBACK_2WIRE 4 +#define MTP_NUM_DEVICE_OMADRM 1 + +#define NUM_DEVICE_PROPERTIES (MTP_NUM_DEVICE_DEFAULT + \ + MTP_NUM_DEVICE_WMP11 + \ + MTP_NUM_DEVICE_BATTLEVEL + MTP_NUM_DEVICE_DSC + \ + MTP_NUM_DEVICE_SVC) + +/*This number can be changed based on MAX number or stores allowed*/ +#define MAX_NUM_DEVICE_STORES 3 + +#define MTP_STANDARD_VERSION 0x64 +#define MTP_VENDOR_EXTN_ID 0x06 +#define MTP_VENDOR_EXTN_VERSION 0x64 + + +/* This enumeration specifies the type of store. */ +typedef enum { + MTP_STORAGE_INTERNAL = 0, + MTP_STORAGE_EXTERNAL, + MTP_STORAGE_ALL +} store_type_t; + + +/* Defines the status of the Device */ +typedef enum { + DEVICE_STATUSOK = 0, /* Device OK */ + DEVICE_DEVICEERROR = 4 /* Fatal device error, can't continue */ +} device_status_t; + +/* Defines the phase in which device is*/ +typedef enum { + DEVICE_PHASE_NOTREADY = 0, /* busy state */ + DEVICE_PHASE_IDLE = 1, /* idle state */ + DEVICE_PHASE_DATAIN = 3, /* data-in phase */ + DEVICE_PHASE_DATAOUT = 4, /* data out phase */ + DEVICE_PHASE_RESPONSE = 5 /* response phase */ +} device_phase_t; + +/* + * device_info_t structure + * brief Structure for MTP device information. + */ +typedef struct { + mtp_uint16 std_version; /* Version of the MTP spec supported */ + mtp_uint32 vendor_extn_id; /* Vendor extension ID */ + mtp_uint16 vendor_extn_version; /* Vendor extension version */ + ptp_string_t vendor_extn_desc; /* Vendor extension description */ + mtp_uint16 functional_mode; /* Funtional mode. */ + mtp_uint16 *ops_supported; /* Array of operations supported */ + mtp_uint16 *events_supported; /* Array of events supported */ + mtp_uint16 *device_prop_supported;/* Array of device prop supported */ + mtp_uint16 *capture_fmts; /* Array of captured fmts supported */ + mtp_uint16 *object_fmts; /* Array of file fmts supported */ + ptp_string_t manufacturer; /* The manufacturer's name. */ + ptp_string_t model; /* model name string */ + ptp_string_t device_version; /* Device version string */ + ptp_string_t serial_no; /* The serial number string. */ +} device_info_t; + +/* + * MTP device structure. + * A structure containing an instance of the MTP device. + */ +typedef struct { + device_status_t status; /* device status */ + device_phase_t phase; /* device phase */ + device_info_t device_info; /* Device information */ + mtp_store_t *store_list; /* pointer to List of stores */ + mtp_uchar num_stores; /* Number of valid stores */ + /* Used when SendObjectInfo does not specift store_id */ + mtp_uint32 default_store_id; + /* Used when SendObjectInfo doesn't specify Parent Object Handle */ + mtp_uint32 default_hparent; + /* A pointer to array of device property. */ + device_prop_desc_t *device_prop_list; + mtp_char device_name[MTP_MAX_REG_STRING + 1]; + mtp_char sync_partner[MTP_MAX_REG_STRING + 1]; + mtp_bool is_mounted[MTP_STORAGE_ALL]; +} mtp_device_t; + +/* + * void _init_mtp_device(void) + * This function initializes mtp device structure. + * @return none. + */ +void _init_mtp_device(void); + +/* + * mtp_uint32 _get_device_info_size() + * This function returns the size of device_info structure + * @return returns the size of this device_info. + */ +mtp_uint32 _get_device_info_size(void); + +/* + * mtp_uint32 _pack_device_info(mtp_uchar *buf, mtp_uint32 buf_sz) + * This Functions Fills the device_info structure + * @param[in] buf address of a buffer + * @param[in] buf_sz size of the buffer + * @return the length of useful data in the buffer. + */ +mtp_uint32 _pack_device_info(mtp_uchar *buf, mtp_uint32 buf_sz); + +/* + * void _reset_mtp_device() + * This functions resets device state to IDLE/Command Ready + * @return none + */ +void _reset_mtp_device(void); + +/* + * device_prop_desc_t *_device_get_device_property(mtp_uint32 prop_code) + * This function will get the property with the input property code + * @param[in] prop_code Property code + * @return pointer to the property if success else NULL. + */ +device_prop_desc_t *_device_get_device_property(mtp_uint32 prop_code); + +mtp_bool _device_is_store_mounted(mtp_int32 store_type); + +/* + * mtp_bool _device_install_storage(mtp_int32 type) + * This function add the storage. + * @param[in] type Specifies the Storage : AUTO, INTERNAL, EXTERNAL, ALL + * @return If success, returns TRUE. Otherwise returns FALSE. + */ +mtp_bool _device_install_storage(mtp_int32 type); + +/* mtp_bool _device_uninstall_storage(mtp_int32 type) + * This function removes the storage. + * @param[in] type Specifies the Storage : AUTO, INTERNAL, EXTERNAL, ALL + * @return If success, returns TRUE. Otherwise returns FALSE. + */ +mtp_bool _device_uninstall_storage(mtp_int32 type); + +/* + * mtp_store_t *_device_get_store(mtp_uint32 store_id) + * This function will get the store with store_id. + * @param[in] store_id ID of the store + * @return the pointer to the store with store ID, otherwise NULL. + */ +mtp_store_t *_device_get_store(mtp_uint32 store_id); + +/* + * mtp_uint32 _device_get_store_ids(ptp_array_t *store_ids) + * This function returns a list of storage ID's of all stores in the device. + * @param[out] store_ids reference to the store ID list + * @return the number of Storage IDs in the list. + */ +mtp_uint32 _device_get_store_ids(ptp_array_t *store_ids); + +/* + * mtp_uint32 _device_get_num_objects(mtp_uint32 store_id) + * This functions will get the number of objects in the store + * @param[in] store_id storage id + * @return the number of objects. + */ +mtp_uint32 _device_get_num_objects(mtp_uint32 store_id); + +/* + * mtp_uint32 _device_get_num_objects_with_format(mtp_uint32 store_id, + * mtp_uint32 format) + * This function will get the number of objects with certain format code in the + * specified store + * @param[in] store_id storage id + * @param[in] format format code of the objects + * @return the number of objects with the formatcode. + */ +mtp_uint32 _device_get_num_objects_with_format(mtp_uint32 store_id, + mtp_uint32 format); + +/* + * mtp_obj_t *_device_get_object_with_handle(mtp_uint32 obj_handle) + * This fuctions returns the object with the obj_handle + * @param[in] obj_handle object handle of the desired object + * @return the object pointer if find; otherwise NULL; + */ +mtp_obj_t *_device_get_object_with_handle(mtp_uint32 obj_handle); + +/* + * mtp_obj_t *_device_get_object_with_path(mtp_char *full_path) + * This function return the pointer to the object if it exists. + * @param[in] full_path points to the object full path + * @return the object pointer if found; otherwise NULL; + */ +mtp_obj_t *_device_get_object_with_path(mtp_char *full_path); + +/* + * mtp_uint16 _device_delete_object(mtp_uint32 obj_handle, mtp_uint32 fmt) + * This function will delete the objects entry corresponding to the + * object handle and the formatcode. + * @param[in] obj_handle Object handle number + * @param[in] fmt Object formatCode + * @return the response of the delete. + */ +mtp_uint16 _device_delete_object(mtp_uint32 obj_handle, mtp_uint32 fmt); + +/* + * mtp_store_t *_device_get_store_containing_obj(mtp_uint32 obj_handle) + * This function will return the pointer to the store where the the object is. + * @param[in] obj_handle Object handle number + * @return the store pointer if find, otherwise NULL. + */ +mtp_store_t *_device_get_store_containing_obj(mtp_uint32 obj_handle); +mtp_store_t *_device_get_store_at_index(mtp_uint32 index); +device_prop_desc_t *_device_get_ref_prop_list(void); + +/* + * Get current playback object from device property + */ +mtp_bool _device_get_playback_obj(mtp_uint32 *playback_obj); + +/* + * Set current playback object in device property, + * and send out property change event. + */ +mtp_bool _device_set_playback_obj(mtp_uint32 playback_obj); +void _device_get_serial(mtp_char *serial_no, mtp_uint32 len); +void _device_set_phase(device_phase_t phase); +device_phase_t _device_get_phase(void); +mtp_uint32 _device_get_default_store_id(void); +mtp_uint32 _device_get_default_parent_handle(void); +mtp_uint32 _device_get_num_stores(void); +device_status_t _device_get_status(void); +void _device_set_device_name(mtp_char *dev_name); +mtp_char *_device_get_device_name(void); +mtp_char *_device_get_sync_partner(void); +void _device_set_sync_partner(mtp_char *sync_ptr); + +#endif /* _MTP_DEVICE_H_ */ diff --git a/include/entity/mtp_object.h b/include/entity/mtp_object.h new file mode 100755 index 0000000..46128a7 --- /dev/null +++ b/include/entity/mtp_object.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_OBJECT_H_ +#define _MTP_OBJECT_H_ + +#include "mtp_list.h" +#include "ptp_datacodes.h" +#include "mtp_fs.h" +#include "mtp_media_info.h" + +#define FIXED_LENGTH_MEMBERS_SIZE \ + (4 * sizeof(mtp_uint16) + 11 * sizeof(mtp_uint32)) + +/* + * MAX size for sendObjectInfo + * SIZE_IN_BYTES_OF_FIXED_LENGTH_MEMBERS + 4 * (sizeof(ptp_string_t)) = 2096 + */ +#define MAX_SIZE_IN_BYTES_OF_OBJECT_INFO (4000*8) + +/* + * obj_info_t structure : Contains object metadata related information + * Size = 26 Bytes + */ +typedef struct { + mtp_uint32 store_id; /* The storage the object resides */ + mtp_uint16 obj_fmt; /* object format code */ + mtp_uint16 protcn_status; /* object protection status */ + mtp_uint64 file_size; /* object compressed size */ + mtp_uint32 thumb_file_size; /* thumbnail compressedsize */ + mtp_uint32 h_parent; /* parent object handle */ + mtp_uint16 association_type; /* association type */ +} obj_info_t; + +/* + * mtp_obj_t structure : Contains object related information + * Gets created for each enumerated file/dir on the device + * Size : 42 Bytes + */ +typedef struct { + mtp_uint32 obj_handle; + obj_info_t *obj_info; + mtp_char *file_path; + ptp_array_t child_array; /* Include all the renferences */ + slist_t propval_list; /* Object Properties implemented */ +} mtp_obj_t; + +mtp_bool _entity_get_file_times(mtp_obj_t *obj, ptp_time_string_t *create_tm, + ptp_time_string_t *modify_tm); +obj_info_t *_entity_alloc_object_info(void); +void _entity_init_object_info(obj_info_t *info); +mtp_uint32 _entity_get_object_info_size(mtp_obj_t *obj, ptp_string_t *file_name); +void _entity_init_object_info_params(obj_info_t *obj_info, mtp_uint32 dwStore, + mtp_uint32 hParent, mtp_char *pszFilename, dir_entry_t *fileInfo); +mtp_uint32 _entity_parse_raw_obj_info(mtp_uchar *buf, mtp_uint32 buf_sz, + obj_info_t *info, mtp_char *file_name, mtp_uint16 fname_len); +void _entity_copy_obj_info(obj_info_t *dst, obj_info_t *src); +mtp_uint32 _entity_pack_obj_info(mtp_obj_t *obj, ptp_string_t *file_name, + mtp_uchar *buf, mtp_uint32 buf_sz); +void _entity_dealloc_obj_info(obj_info_t *info); +mtp_obj_t *_entity_alloc_mtp_object(void); +mtp_bool _entity_init_mtp_object_params( + mtp_obj_t *obj, + mtp_uint32 store_id, + mtp_uint32 h_parent, + mtp_char *file_path, + mtp_char *file_name, + dir_entry_t *file_info); +mtp_bool _entity_set_object_file_path(mtp_obj_t *obj, void *file_path, + char_mode_t char_type); +mtp_bool _entity_check_child_obj_path(mtp_obj_t *obj, mtp_char *src_path, + mtp_char *dest_path); +mtp_bool _entity_set_child_object_path(mtp_obj_t *obj, mtp_char *src_path, + mtp_char *dest_path); +mtp_bool _entity_add_reference_child_array(mtp_obj_t *obj, mtp_uint32 handle); +ptp_array_t* _entity_get_reference_child_array(mtp_obj_t *obj); +mtp_bool _entity_set_reference_child_array(mtp_obj_t *obj, mtp_uchar *buf, + mtp_uint32 buf_sz); +void _entity_copy_mtp_object(mtp_obj_t *dst, mtp_obj_t *src); +mtp_bool _entity_remove_reference_child_array(mtp_obj_t *obj, mtp_uint32 handle); +void _entity_dealloc_mtp_obj(mtp_obj_t *obj); + +#endif /* _MTP_OBJECT_H_ */ diff --git a/include/entity/mtp_property.h b/include/entity/mtp_property.h new file mode 100755 index 0000000..4bb6591 --- /dev/null +++ b/include/entity/mtp_property.h @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_PROPERTY_H_ +#define _MTP_PROPERTY_H_ + +#include "mtp_list.h" +#include "mtp_object.h" + +#define MAX_SIZE_IN_BYTES_OF_PROP_VALUE 16000 +#define ELEMENT_NOT_FOUND -1 +#define INITIAL_ARRAY_SIZE 100 +#define NUM_OBJECT_PROP_DESC 38 +#define NUM_OBJECT_PROP_DESC_DEFAULT 13 +#define NUM_OBJECT_PROP_DESC_MP3 14 +#define NUM_OBJECT_PROP_DESC_WMA 14 +#define MTP_HEAP_CAL_INTERVAL 100 + +#ifdef MTP_SUPPORT_PROPERTY_SAMPLE +#define NUM_OBJECT_PROP_DESC_WMV 28 +#else /* MTP_SUPPORT_PROPERTY_SAMPLE */ +#define NUM_OBJECT_PROP_DESC_WMV 22 +#endif /* MTP_SUPPORT_PROPERTY_SAMPLE */ + +#ifdef MTP_SUPPORT_PROPERTY_SAMPLE +#define NUM_OBJECT_PROP_DESC_ALBUM 8 +#else /* MTP_SUPPORT_PROPERTY_SAMPLE */ +#define NUM_OBJECT_PROP_DESC_ALBUM 2 +#endif /* MTP_SUPPORT_PROPERTY_SAMPLE */ + +typedef struct _interdep_prop_config { + mtp_uint32 format_code; + slist_t propdesc_list; +} interdep_prop_config_t; + +/* + * brief The property form flag. + * This enumerated type defines what kind of data the structure contains. + */ +typedef enum { + NONE = 0x00, + RANGE_FORM = 0x01, + ENUM_FORM = 0x02, + DATE_TIME_FORM = 0x03, + REGULAR_EXPRESSION_FORM = 0x04, + BYTE_ARRAY_FORM = 0x05, + LONG_STRING_FORM = 0xFF, +} form_flag_t; + +enum { + GROUP_CODE_NONE = 0x00000000, + GROUP_CODE_SYNC_PROPS = 0x00000001, + GROUP_CODE_UI_PROPS = 0x00000002, + GROUP_CODE_OBJ_Info = 0x00000004, + GROUP_CODE_OFTEN_USED = 0x00000008, + GROUP_CODE_SUPPLEMENTAL = 0x00000100, + GROUP_CODE_UNKNOWN_PROP = 0x00010000, + GROUP_CODE_SLOW = 0x00FF0000, + GROUP_CODE_ALL = 0xFFFFFFFF +}; + +#define MTP_PROP_GROUPCODE_GENERAL GROUP_CODE_OFTEN_USED +#define MTP_PROP_GROUPCODE_OBJECT GROUP_CODE_OFTEN_USED +#define MTP_PROP_GROUPCODE_ALBUMART GROUP_CODE_OFTEN_USED + +#define node_alloc_and_append()\ + do {\ + mtp_bool ret;\ + ret = _util_add_node(&(obj->propval_list), (void *)prop_val);\ + if (FALSE == ret) {\ + _prop_destroy_obj_propval(prop_val);\ + ERR("_util_add_node() Fail");\ + return (FALSE);\ + }\ + } while (0); + +#define propvalue_alloc_and_check(prop_val)\ + do {\ + prop_val = _prop_alloc_obj_propval(prop);\ + if (prop_val == NULL) {\ + ERR("prop_val == NULL");\ + return (FALSE);\ + } \ + } while (0); + +#define init_default_value(value)\ + do {\ + memset(&default_val, 0, sizeof(default_val));\ + default_val = value;\ + } while (0); + +typedef struct { + mtp_uint32 min_val; /* Minimum value */ + mtp_uint32 max_val; /* Maximum value */ + mtp_uint32 step_size; /* Step value */ +} range_form_t; + +/* This structure contains property info */ +typedef struct { + mtp_uint16 prop_code; /* Property code */ + mtp_uint16 data_type; /* type of the data */ + mtp_uint32 dts_size; /* Count of Byte Size of the + Data-Type-Specific value (DTS) */ + mtp_uchar get_set; /* Set possible or not */ + mtp_uchar form_flag; /* Indicates the form of the valid values */ + range_form_t range; /* Range Values */ + slist_t supp_value_list; /*Enum Values */ + union { + mtp_uchar integer[16]; /* Default value for any integer value + type (UINT8, mtp_uint16, mtp_uint32) */ + ptp_string_t *str; /* Default value for String type */ + ptp_array_t *array; /* Default array */ + } default_val; /* Default value */ +} prop_info_t; + +/* This structure contains device property description dataset */ +typedef struct { + prop_info_t propinfo; + union { + mtp_uchar integer[16]; /* Current value for any integer value + type (UINT8, mtp_uint16, mtp_uint32) */ + ptp_string_t *str; /* Current value for String type */ + ptp_array_t *array; /* Current value for array data type + (AINT8, AUINT8) */ + } current_val; /*Current value */ +} device_prop_desc_t; + +/* This structure contains object property description dataset */ +typedef struct { + prop_info_t propinfo; + mtp_uint32 group_code; /* Identifies the group of this property */ + union { + ptp_string_t *reg_exp; /* Regular Expression Form */ + mtp_uint32 max_len; /* LongString Form */ + } prop_forms; /*Object property-specific forms */ +} obj_prop_desc_t; + +/* This structure contains current value of a object property */ +typedef struct { + obj_prop_desc_t *prop; + union { + mtp_uchar integer[16]; /* Current value for any integer */ + ptp_string_t *str; /* Current value for String type */ + ptp_array_t *array; + } current_val; +} obj_prop_val_t; + +/* This structure defines ObjectPropQuad for GetObjectPropList */ +typedef struct { + mtp_uint32 obj_handle; + mtp_uint16 prop_code; + mtp_uint16 data_type; + mtp_uchar *pval; + mtp_uint32 val_size; /* a useful helper, + not part of the Object Property Quadruple */ +} prop_quad_t; + +/* This structure contains a list of MTP Object properties */ +typedef struct { + slist_t prop_quad_list; +} obj_proplist_t; + +/* This structure contains a list of InterdependentProperties */ +typedef struct { + slist_t plist; +} obj_interdep_proplist_t ; + +/* + * Ptparray functions + */ +void _prop_init_ptparray(ptp_array_t *parray, data_type_t type); +ptp_array_t *_prop_alloc_ptparray(data_type_t type); +mtp_uint32 _prop_get_size_ptparray(ptp_array_t *parray); +mtp_uint32 _prop_get_size_ptparray_without_elemsize(ptp_array_t *parray); +mtp_bool _prop_grow_ptparray(ptp_array_t *parray, mtp_uint32 new_size); +mtp_int32 _prop_find_ele_ptparray(ptp_array_t *parray, mtp_uint32 element); +mtp_bool _prop_get_ele_ptparray(ptp_array_t *parray, mtp_uint32 index, void *ele); +mtp_bool _prop_append_ele_ptparray(ptp_array_t *parray, mtp_uint32 element); +mtp_bool _prop_append_ele128_ptparray(ptp_array_t *parray, mtp_uint64 *element); +mtp_bool _prop_copy_ptparray(ptp_array_t *dst, ptp_array_t *src); +mtp_uint32 _prop_pack_ptparray(ptp_array_t *parray, mtp_uchar *buf, + mtp_uint32 bufsize); +mtp_uint32 _prop_pack_ptparray_without_elemsize(ptp_array_t *parray, + mtp_uchar *buf, mtp_uint32 bufsize); +mtp_bool _prop_rem_elem_ptparray(ptp_array_t *parray, mtp_uint32 element); +void _prop_deinit_ptparray(ptp_array_t *parray); +void _prop_destroy_ptparray(ptp_array_t *parray); + +/* + * PtpString Functions + */ +void _prop_init_ptpstring(ptp_string_t *pstring); +void _prop_init_ptptimestring(ptp_time_string_t *pstring); +void _prop_copy_time_to_ptptimestring(ptp_time_string_t *pString, + system_time_t *sys_time); +void _prop_copy_ptpstring(ptp_string_t *dst, ptp_string_t *src); +void _prop_copy_ptptimestring(ptp_time_string_t *dst, ptp_time_string_t *src); +void _prop_copy_char_to_ptpstring(ptp_string_t *pstring, void *str, + char_mode_t cmode); +mtp_uint32 _prop_size_ptpstring(ptp_string_t *pstring); +mtp_uint32 _prop_size_ptptimestring(ptp_time_string_t *pstring); +mtp_uint32 _prop_pack_ptpstring(ptp_string_t *pstring, mtp_uchar *buf, + mtp_uint32 size); +mtp_uint32 _prop_pack_ptptimestring(ptp_time_string_t *pstring, mtp_uchar *buf, + mtp_uint32 size); +mtp_uint32 _prop_parse_rawstring(ptp_string_t *pstring, mtp_uchar *buf, + mtp_uint32 size); +void _prop_destroy_ptpstring(ptp_string_t *pstring); + +/* + * DevicePropDesc Functions + */ +void _prop_init_device_property_desc(device_prop_desc_t *prop, + mtp_uint16 propcode, mtp_uint16 data_type, mtp_uchar get_set, + mtp_uchar form_flag); +mtp_uint32 _prop_size_device_prop_desc(device_prop_desc_t *prop); +mtp_uint32 _prop_pack_device_prop_desc(device_prop_desc_t *prop, + mtp_uchar *buf, mtp_uint32 size); +mtp_uint32 _prop_pack_curval_device_prop_desc(device_prop_desc_t *prop, + mtp_uchar *buf, mtp_uint32 size); +void _prop_reset_device_prop_desc(device_prop_desc_t *prop); + +/* + * ObjectPropVal Functions + */ +obj_prop_val_t *_prop_alloc_obj_propval(obj_prop_desc_t *prop); +obj_prop_val_t *_prop_get_prop_val(mtp_obj_t *obj, mtp_uint32 prop_code); +mtp_uint32 _prop_pack_obj_propval(obj_prop_val_t *val, mtp_uchar *buf, + mtp_uint32 size); +mtp_uint32 _prop_size_obj_propval(obj_prop_val_t *val); +void _prop_destroy_obj_propval(obj_prop_val_t *pval); +mtp_bool _prop_set_default_integer(prop_info_t *prop_info, mtp_uchar *value); +mtp_bool _prop_set_default_string(prop_info_t *prop_info, mtp_wchar *val); +mtp_bool _prop_set_range_integer(prop_info_t *prop_info, mtp_uint32 min, + mtp_uint32 max, mtp_uint32 step); +mtp_bool _prop_set_maxlen(obj_prop_desc_t *prop, mtp_uint32 max); +mtp_bool _prop_set_default_array(prop_info_t *prop_info, mtp_uchar *parray, + mtp_uint32 num_ele); +mtp_bool _prop_add_supp_integer_val(prop_info_t *prop_info, mtp_uint32 val); +mtp_bool _prop_add_supp_string_val(prop_info_t *prop_info, mtp_wchar *val); +mtp_bool _prop_is_valid_integer(prop_info_t *prop_info, mtp_uint64 value); +mtp_bool _prop_is_valid_string(prop_info_t *prop, ptp_string_t *str); +mtp_bool _prop_is_equal_ptpstring(ptp_string_t *dst, ptp_string_t *src); +mtp_bool _prop_set_current_integer(device_prop_desc_t *prop, mtp_uint32 val); +mtp_bool _prop_set_current_string(device_prop_desc_t *prop, ptp_string_t *str); +mtp_bool _prop_set_current_array(device_prop_desc_t *prop, mtp_uchar *arr); +mtp_bool _prop_set_current_device_prop(device_prop_desc_t *prop, mtp_uchar *val, + mtp_uint32 size); +mtp_bool _prop_set_current_integer_val(obj_prop_val_t *propval, mtp_uint64 val); +mtp_bool _prop_set_current_string_val(obj_prop_val_t *propval, ptp_string_t *str); +mtp_bool _prop_set_current_array_val(obj_prop_val_t *propval, mtp_uchar *arr, + mtp_uint32 size); +#ifdef __BIG_ENDIAN__ +mtp_bool _prop_set_current_array_val_usbrawdata(obj_prop_val_t *val, + mtp_uchar *arr, mtp_uint32 size); +#endif /* __BIG_ENDIAN__ */ +mtp_bool _prop_set_regexp(obj_prop_desc_t *prop, mtp_wchar *regex); + +/* + * ObjectPropDesc Functions + */ +mtp_uint32 _prop_size_obj_prop_desc(obj_prop_desc_t *prop); +mtp_uint32 _prop_pack_obj_prop_desc(obj_prop_desc_t *prop, mtp_uchar *buf, + mtp_uint32 size); +mtp_uint32 _prop_pack_default_val_obj_prop_desc(obj_prop_desc_t *prop, + mtp_uchar *buf, mtp_uint32 size); +obj_prop_desc_t *_prop_get_obj_prop_desc(mtp_uint32 format_code, + mtp_uint32 prop_code); + +/* + * ObjectProplist Functions + */ +mtp_bool _prop_update_property_values_list(mtp_obj_t *obj); +mtp_uint32 _prop_size_obj_proplist(obj_proplist_t *prop_list); +mtp_uint32 _prop_get_obj_proplist(mtp_obj_t *pObject, mtp_uint32 prop_code, + mtp_uint32 group_code, obj_proplist_t *prop_list); +mtp_uint32 _prop_pack_obj_proplist(obj_proplist_t *prop_list, mtp_uchar *buf, + mtp_uint32 size); +void _prop_destroy_obj_proplist(obj_proplist_t *prop_list); + +/* + * ObjectProp Functions + */ +mtp_uint32 _prop_get_supp_obj_props(mtp_uint32 format_code, + ptp_array_t *supp_props); +mtp_bool _prop_build_supp_props_mp3(void); +mtp_bool _prop_build_supp_props_wma(void); +mtp_bool _prop_build_supp_props_wmv(void); +mtp_bool _prop_build_supp_props_album(void); +mtp_bool _prop_build_supp_props_default(void); +void _prop_destroy_supp_obj_props(void); + +/* + *Interdependent Prop Functions + */ +mtp_uint32 _prop_get_size_interdep_prop(interdep_prop_config_t *prop); +mtp_uint32 _prop_pack_interdep_prop(interdep_prop_config_t *prop, mtp_uchar *buf, + mtp_uint32 size); +mtp_uint32 _prop_get_size_interdep_proplist(obj_interdep_proplist_t *config_list, + mtp_uint32 format_code); +mtp_uint32 _prop_pack_interdep_proplist(obj_interdep_proplist_t *config_list, + mtp_uint32 format_code, mtp_uchar *buf, mtp_uint32 size); +mtp_bool _get_oma_drm_status(void); + +#endif /* _MTP_PROPERTY_H_ */ diff --git a/include/entity/mtp_store.h b/include/entity/mtp_store.h new file mode 100755 index 0000000..32f2427 --- /dev/null +++ b/include/entity/mtp_store.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_STORE_H_ +#define _MTP_STORE_H_ + +#include "mtp_object.h" + + +/* First six members of SStorageInfo structure */ +#define FIXED_LENGTH_MEMBERS_MTPSTORE_SIZE \ + (sizeof(mtp_uint16) * 3 + sizeof(mtp_uint64) * 2 + sizeof(mtp_uint32)) + +typedef enum { + MTPSTORE_WMPINFO_PHONE = 1, + MTPSTORE_WMPINFO_CARD +} store_special_obj_t; + +/* + * store_info + * This structure stores store information for each store + */ +typedef struct { + mtp_uint16 store_type; /*storage type*/ + mtp_uint16 fs_type; /*file system type*/ + mtp_uint16 access; /*access capability(read/write)*/ + mtp_uint64 capacity; /*maximum capacity in bytes*/ + mtp_uint64 free_space; /*free space in bytes*/ + mtp_uint32 free_space_in_objs; /*free space in objects*/ + ptp_string_t store_desc; + ptp_string_t vol_label; /*optional volume label: variable length*/ +} store_info_t; + +/* + * MTP store structure. + * This structure is instantiated for each store within the MTP device. + */ +typedef struct { + mtp_char *root_path; /* Root path of the store */ + mtp_uint32 store_id; + store_info_t store_info; + slist_t obj_list; + mtp_bool is_hidden; /*for hidden storage*/ +} mtp_store_t; + +typedef struct { + mtp_uint32 h_parent; + mtp_store_t *store; + ptp_array_t child_data; +} missing_child_data_t; + +typedef enum { + MTP_INTERNAL_STORE_ID = 0x10001, + MTP_EXTERNAL_STORE_ID = 0x20001 +} mtp_store_id_t; + +typedef enum { + MTP_ADDREM_AUTO, + MTP_ADDREM_INTERNAL, + MTP_ADDREM_EXTERNAL, + MTP_ADDREM_ALL +} add_rem_store_t; + +void _entity_update_store_info_run_time(store_info_t *info, + mtp_char *root_path); +mtp_bool _entity_get_store_path_by_id(mtp_uint32 store_id, mtp_char *path); +mtp_uint32 _entity_get_store_info_size(store_info_t *info); +mtp_uint32 _entity_pack_store_info(store_info_t *info, mtp_uchar *buf, + mtp_uint32 buf_sz); +mtp_uint32 _entity_get_store_id_by_path(const mtp_char *path_name); +mtp_bool _entity_init_mtp_store(mtp_store_t *store, mtp_uint32 store_id, + mtp_char *store_path); +mtp_obj_t *_entity_add_file_to_store(mtp_store_t *store, mtp_uint32 h_parent, + mtp_char *file_path, mtp_char *file_name, dir_entry_t *file_info); +mtp_obj_t *_entity_add_folder_to_store(mtp_store_t *store, mtp_uint32 h_parent, + mtp_char *file_path, mtp_char *file_name, dir_entry_t *file_info); +mtp_bool _entity_add_object_to_store(mtp_store_t *store, mtp_obj_t *obj); +mtp_obj_t *_entity_get_object_from_store(mtp_store_t *store, mtp_uint32 handle); +mtp_obj_t *_entity_get_last_object_from_store(mtp_store_t *store, + mtp_uint32 handle); +mtp_obj_t *_entity_get_object_from_store_by_path(mtp_store_t *store, + mtp_char *file_path); +mtp_uint32 _entity_get_objects_from_store(mtp_store_t *store, + mtp_uint32 obj_handle, mtp_uint32 fmt, ptp_array_t *obj_arr); +mtp_uint32 _entity_get_objects_from_store_till_depth(mtp_store_t *store, + mtp_uint32 obj_handle, mtp_uint32 fmt_code, mtp_uint32 depth, + ptp_array_t *obj_arr); +mtp_uint32 _entity_get_objects_from_store_by_format(mtp_store_t *store, + mtp_uint32 format, ptp_array_t *obj_arr); +mtp_uint32 _entity_get_num_object_with_same_format(mtp_store_t *store, + mtp_uint32 format); +mtp_uint32 _entity_get_num_children(mtp_store_t *store, mtp_uint32 h_parent, + mtp_uint32 format); +mtp_uint32 _entity_get_child_handles(mtp_store_t *store, mtp_uint32 h_parent, + ptp_array_t *child_arr); +mtp_uint32 _entity_get_child_handles_with_same_format(mtp_store_t *store, + mtp_uint32 h_parent, mtp_uint32 format, ptp_array_t *child_arr); +mtp_bool _entity_remove_object_mtp_store(mtp_store_t *store, mtp_obj_t *obj, + mtp_uint32 format, mtp_uint16 *response, mtp_bool *atleast_one, + mtp_bool read_only); +mtp_uint16 _entity_delete_obj_mtp_store(mtp_store_t *store, + mtp_uint32 obj_handle, mtp_uint32 fmt, mtp_bool read_only); +mtp_uint32 _entity_get_object_tree_size(mtp_store_t *store, mtp_obj_t *obj); +mtp_bool _entity_check_if_B_parent_of_A(mtp_store_t *store, + mtp_uint32 handleA, mtp_uint32 handleB); +mtp_uint32 _entity_generate_next_obj_handle(void); +mtp_uint16 _entity_format_store(mtp_store_t *store, mtp_uint32 fs_format); +void _entity_destroy_mtp_store(mtp_store_t *store); +void _entity_store_recursive_enum_folder_objects(mtp_store_t *store, + mtp_obj_t *pobj); +void _entity_list_modified_files(mtp_uint32 minutes); +void _entity_copy_store_data(mtp_store_t *dst, mtp_store_t *src); + +#endif /* _MTP_STORE_H_ */ diff --git a/include/mtp_cmd_handler.h b/include/mtp_cmd_handler.h new file mode 100755 index 0000000..1fc6992 --- /dev/null +++ b/include/mtp_cmd_handler.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_CMD_HANDLER_H_ +#define _MTP_CMD_HANDLER_H_ + +#include "mtp_object.h" +#include "mtp_device.h" +#include "ptp_container.h" +#include "mtp_event_handler.h" + +#ifdef MTP_SUPPORT_PRINT_COMMAND +#define MTP_MAX_CMD_LENGTH 40 +#endif /* MTP_SUPPORT_PRINT_COMMAND */ + +/* + * A structure for containing the object infomation. It is used for saving + * information in between paired operations like send_obj_info + * and send_object. + * @see obj_info + */ +typedef struct { + mtp_uint32 store_id; /* The storage ID. */ + mtp_uint32 h_parent; /* Handle of the parent object */ + /* Reserved Handle for the incoming object. */ + mtp_uint32 obj_handle; + /* Indicates if the ObjectInfo dataset is valid. */ + mtp_bool is_valid; + mtp_bool is_data_sent; /* Indicates whether data was actually sent */ + mtp_uint64 file_size; + mtp_obj_t *obj; /* Object containing info for SendObject */ +} data_4send_object_t; + +/* + * A structure for handling the operations of the MTP protocol. + * It is the main driving structure behind the MTP protocol handling. The + * MTP device contains device information and other data buffers. + * + * @see mtp_device + * @see cmd_blk_t + * @see data4_send_obj + */ +typedef struct { + cmd_container_t usb_cmd; /* A USB command container block. */ + /* Data saved during paired operations: SendObjectInfo/SendObject. */ + data_4send_object_t data4_send_obj; + mtp_uint32 session_id; /* Current session ID. */ + mtp_uint32 last_opcode; /* Current transaction ID. */ + mtp_uint16 last_fmt_code; /* Last Format Code */ +} mtp_handler_t; + +typedef struct { + mtp_uint32 recent_tid; + mtp_uint32 cur_index; + mtp_uint32 mod; +} wmp_meta_info_t; + +/* + * This structure specifies the buffer of Mtp. + */ +typedef struct { + mtp_char cmd_buf[MTP_MAX_CMD_BLOCK_SIZE]; + mtp_char header_buf[MTP_USB_HEADER_LENGTH]; + mtp_uint32 cmd_size; + mtp_uint32 data_size; + mtp_uint32 data_count; + mtp_uint32 fhandle; /* for temporary mtp file */ + mtp_char *filepath; + mtp_uint32 file_size; + mtp_uint32 size_remaining; + /* PC-> Device file transfer user space buffering till 512K*/ + mtp_char *temp_buff; +} temp_file_struct_t; + +typedef struct { + temp_file_struct_t ftemp_st; + mtp_handler_t hdlr; + wmp_meta_info_t meta_info; +} mtp_mgr_t; + +void _cmd_hdlr_reset_cmd(mtp_handler_t *hdlr); +mtp_bool _cmd_hdlr_send_response(mtp_handler_t *hdlr, mtp_uint16 resp, + mtp_uint32 num_param, mtp_uint32 *params); +mtp_bool _cmd_hdlr_send_response_code(mtp_handler_t *hdlr, mtp_uint16 resp); +void _receive_mq_data_cb(mtp_char *buffer, mtp_int32 buf_len); + +#endif /* _MTP_CMD_HANDLER_H_ */ diff --git a/include/mtp_cmd_handler_util.h b/include/mtp_cmd_handler_util.h new file mode 100755 index 0000000..f360329 --- /dev/null +++ b/include/mtp_cmd_handler_util.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_CMD_HANDLER_UTIL_H_ +#define _MTP_CMD_HANDLER_UTIL_H_ + +#include "mtp_device.h" + +typedef struct { + mtp_uint32 store_id; + mtp_uint64 obj_size; + mtp_obj_t *obj; +} obj_data_t; + +mtp_err_t _hutil_get_storage_entry(mtp_uint32 store_id, store_info_t *info); +mtp_err_t _hutil_get_storage_ids(ptp_array_t *store_ids); +mtp_err_t _hutil_get_device_property(mtp_uint32 prop_id, + device_prop_desc_t* dev_prop); +mtp_err_t _hutil_set_device_property(mtp_uint32 prop_id, void *data, + mtp_uint32 data_sz); +mtp_err_t _hutil_reset_device_entry(mtp_uint32 prop_id); +mtp_err_t _hutil_add_object_entry(obj_info_t *obj_info, mtp_char *file_name, + mtp_obj_t **new_obj); +mtp_err_t _hutil_remove_object_entry(mtp_uint32 obj_handle, mtp_uint32 format); +mtp_err_t _hutil_get_object_entry(mtp_uint32 obj_handle, mtp_obj_t **obj_ptr); +mtp_err_t _hutil_copy_object_entries(mtp_uint32 dst_store_id, + mtp_uint32 src_store_id, mtp_uint32 h_parent, mtp_uint32 obj_handle, + mtp_uint32 *new_hobj, mtp_bool keep_handle); +mtp_err_t _hutil_move_object_entry(mtp_uint32 dst_store_id, mtp_uint32 h_parent, + mtp_uint32 obj_handle); +mtp_err_t _hutil_duplicate_object_entry(mtp_uint32 dst_store_id, + mtp_uint32 h_parent, mtp_uint32 obj_handle, mtp_uint32 *new_handle); +mtp_err_t _hutil_read_file_data_from_offset(mtp_uint32 obj_handle, off_t offset, + void *data, mtp_uint32 *data_sz); +mtp_err_t _hutil_write_file_data(mtp_uint32 store_id, mtp_obj_t *obj, + mtp_char *fpath); +mtp_err_t _hutil_get_object_entry_size(mtp_uint32 obj_handle, mtp_uint64 *obj_sz); +mtp_err_t _hutil_set_protection(mtp_uint32 obj_handle, mtp_uint16 prot_status); +mtp_err_t _hutil_get_num_objects(mtp_uint32 store_id, mtp_uint32 h_parent, + mtp_uint32 format, mtp_uint32 *num_obj); +mtp_err_t _hutil_get_object_handles(mtp_uint32 store_id, mtp_uint32 format, + mtp_uint32 h_parent, ptp_array_t *handle_arr); +mtp_err_t _hutil_construct_object_entry(mtp_uint32 store_id, mtp_uint32 h_parent, + obj_data_t *objdata, mtp_obj_t **obj, void *data, mtp_uint32 data_sz); +mtp_err_t _hutil_construct_object_entry_prop_list( + mtp_uint32 store_id, + mtp_uint32 h_parent, + mtp_uint16 format, + mtp_uint64 obj_sz, + obj_data_t *obj_data, + mtp_obj_t **obj_ptr, + void *data, + mtp_int32 data_sz, + mtp_uint32 *err_idx); +mtp_err_t _hutil_get_object_prop_value(mtp_uint32 obj_handle, mtp_uint32 prop_code, + obj_prop_val_t *prop_val, mtp_obj_t **obj); +mtp_err_t _hutil_update_object_property( + mtp_uint32 obj_handle, + mtp_uint32 prop_code, + mtp_uint16 *data_type, + void *buf, + mtp_uint32 buf_sz, + mtp_uint32 *prop_sz); +mtp_err_t _hutil_get_prop_desc(mtp_uint32 format, mtp_uint32 prop_code, void *data); +mtp_err_t _hutil_get_object_prop_supported(mtp_uint32 format, + ptp_array_t *prop_arr); + +#ifdef MTP_USE_RUNTIME_GETOBJECTPROPVALUE +mtp_err_t _hutil_get_object_prop_list(mtp_uint32 obj_handle, + mtp_uint32 format, + mtp_uint32 prop_code, + mtp_uint32 group_code, + mtp_uint32 depth, + obj_proplist_t *prop_list, + ptp_array_t *obj_arr); +#else /* MTP_USE_RUNTIME_GETOBJECTPROPVALUE */ +mtp_err_t _hutil_get_object_prop_list( + mtp_uint32 obj_handle, + mtp_uint32 format, + mtp_uint32 prop_code, + mtp_uint32 group_code, + mtp_uint32 depth, + obj_proplist_t *prop_list); +#endif /* MTP_USE_RUNTIME_GETOBJECTPROPVALUE */ + +mtp_err_t _hutil_add_object_references_enhanced(mtp_uint32 obj_handle, + mtp_uchar *buffer, mtp_uint32 buf_sz); +mtp_err_t _hutil_remove_object_reference(mtp_uint32 obj_handle, + mtp_uint32 ref_handle); +mtp_err_t _hutil_get_object_references(mtp_uint32 obj_handle, + ptp_array_t *parray, mtp_uint32 *num_ele); +mtp_err_t _hutil_get_number_of_objects(mtp_uint32 store_id, + mtp_uint32 *num_obj); +mtp_err_t _hutil_get_interdep_prop_config_list_size(mtp_uint32 *list_sz, + mtp_uint32 format); +mtp_err_t _hutil_get_interdep_prop_config_list_data(void *data, + mtp_uint32 list_sz, mtp_uint32 format); +mtp_err_t _hutil_get_playback_skip(mtp_int32 skip_param); +mtp_err_t _hutil_format_storage(mtp_uint32 store_id, mtp_uint32 fs_format); +mtp_uint32 _hutil_get_storage_info_size(store_info_t *store_info); + +#endif /* _MTP_CMD_HANDLER_UTIL_H_ */ diff --git a/include/mtp_config.h b/include/mtp_config.h new file mode 100755 index 0000000..87d7d23 --- /dev/null +++ b/include/mtp_config.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_CONFIG_H_ +#define _MTP_CONFIG_H_ + +#include <stdbool.h> + +/* Function Features */ +#define MTP_USE_INFORMATION_REGISTRY /* for get and set some information value */ + +/* Set write-protection for read-only files */ +/*#define MTP_SUPPORT_SET_PROTECTION*/ + +/*MtpObject.c, for unknown metadata */ +#define MTP_USE_FILL_EMPTYMETADATA_WITH_UNKNOWN + +/*define MTP_USE_VARIABLE_PTP_STRING_MALLOC*/ /*allocPtpString in ptpstring.c*/ +#define MTP_USE_RUNTIME_GETOBJECTPROPVALUE /*use runtime get object property list*/ + +/*keywords has many space. not support*/ +/*#define MTP_USE_OBJPROPERTY_KEYWORDS*/ +/*#define MTP_USE_SELFMAKE_ABSTRACTION*/ + +/*after db loading(mass files), there are some duplicate open session packet*/ +/*#define MTP_USE_SKIP_CONTINUOUS_OPENSESSION*/ + +/* Support Features */ + +/* cancel transactio, device reset, mainly used in mtpmain.c */ +#define MTP_SUPPORT_CONTROL_REQUEST + +#define MTP_SUPPORT_ALBUM_ART /* album art image file */ +/*#define MTP_SUPPORT_DELETE_MEDIA_ALBUM_FILE*/ + +/*support battery level using mtp_pal_phone_get_status(MTP_PAL_BATTLEVEL) */ +#define MTP_SUPPORT_DEVICEPROP_BATTERYLEVEL + +/*support get wmpinfo.xml from hidden file list */ +/*#define MTP_SUPPORT_HIDE_WMPINFO_XML*/ + +/*support mtp command GetInterdependentPropDesc (0x9807) */ +/*#define MTP_SUPPORT_INTERDEPENDENTPROP*/ + +/*mobile class. this should be set with ms os descriptor. see portable device installation consideration */ +#define MTP_SUPPORT_DEVICE_CLASS + +/*#define MTP_SUPPORT_WMV_ENCODINGPROFILE */ /* for WMV encoding profile */ + +/*Representive Sample Properties are not supported by either music player or libmm-fileinfo */ +#ifdef MTP_SUPPORT_ALBUM_ART +/*#define MTP_SUPPORT_PROPERTY_SAMPLE*/ +#endif/*MTP_SUPPORT_ALBUM_ART*/ + +/* external features */ +#define MTP_SUPPORT_OBJECTADDDELETE_EVENT + +/*For printing Commands sent by initiator + *This needs to be diabled later before commercial binary release + */ +#define MTP_SUPPORT_PRINT_COMMAND + +/* + * Transport related configuration + */ +/* Internal Storage */ +#define MTP_STORE_PATH_CHAR "/opt/usr/media" + +/* External Storage */ +#define MTP_EXTERNAL_PATH_CHAR "/opt/storage/sdcard" +#define MTP_DEVICE_ICON "/usr/share/mtp/device_icon.ico" + +/* File For WMP extesions */ +#define MTP_FILES_MODIFIED_FILES "/tmp/mtp_mod_files.log" + +/* Base MTP USER Directory */ +#define MTP_USER_DIRECTORY "/opt/usr/media/user" + +/* Hidden Root directory */ +#define MTP_HIDDEN_PHONE ".HiddenPhone" +#define MTP_HIDDEN_CARD ".HiddenCard" + +/* Windows Media Player xml file */ +#define MTP_FILE_NAME_WMPINFO_XML "WMPInfo.xml" + +/* MTP extension name */ +#define MTP_EXT_NAME_REGISTRY "ini" + +/* special extension */ +#define MTP_ALBUMFILE_EXTENSION "alb" + +/* Reference Key name */ +#define MTP_REF_KEYNAME_CHAR "Reference" + +/*STORAGE*/ +#define MTP_MAX_STORAGE (30*1024*1024) /*30MB */ +#define MTP_MAX_STORAGE_IN_OBJTS 0xFFFFFFFF +#define MTP_MAX_INT_OBJECT_NUM 10000000 +#define MTP_MIN_EXT_OBJECT_NUM 5000000 + +#define MTP_BUF_SIZE_FOR_INT 11 /* 2^32 - 1 = 4294967295 (10 digits) */ + +/*To determine whether command is for Samsung mobile*/ +#define MTP_SAMSUNG_MOBILE 0x1000 +#define MTP_STORAGE_DESC_INT "Phone" +#define MTP_STORAGE_DESC_EXT "Card" + +/*Devices Property*/ +#define MTP_DEFAULT_MODEL_NAME "SAMSUNG Mobile" +#define MTP_DEFAULT_DEVICE_VERSION "" +#define MTP_DEV_PROPERTY_SYNCPARTNER "Longhorn Sync Engine" +#define MTP_DEV_PROPERTY_FRIENDLYNAME "SAMSUNG Mobile" +#define MTP_DEV_PROPERTY_NULL_SYNCPARTNER "{00000000-0000-0000-0000-000000000000}" + +/*temporary file*/ +#define MTP_TEMP_FILE ".mtptemp.tmp" +#define MTP_TEMP_FILE_DEFAULT "/tmp/.mtptemp.tmp" + +/*Unknown Metadata default name*/ +#define MTP_UNKNOWN_METADATA "Unknown" + +/*2006.10.20 empty metadata folder problem*/ +#define MTP_UNKNOWN_METADATAW L"Unknown" + +/* strlen(/opt/usr/share/crash/) + MTP path len limit */ +#define MTP_MAX_PATHNAME_SIZE (21 + 255) /* except \0 */ +#define MTP_MAX_FILENAME_SIZE (254) /* except \0 */ + +#define MTP_MAX_CMD_BLOCK_SIZE 36 /* Bytes */ + +#define MTP_MAX_PACKET_SIZE_SEND_HS 512 /* High speed */ +#define MTP_MAX_PACKET_SIZE_SEND_FS 64 /* Full speed */ +#define MTP_FILESIZE_4GB 4294967296L + +/* approximately 3 times of media files. consider album*/ +#define MTP_MAX_REFDB_ROWCNT 4500 +#define MTP_MAX_EXTENSION_LENGTH 11 +#define MTP_MAX_REG_STRING 128 + +#define MTP_SERIAL_LEN_MAX 32 +#define MD5_HASH_LEN 16 +#define MTP_MODEL_NAME_LEN_MAX 32 +#define MTP_DEVICE_NAME_LEN_MAX 64 + +/* + * User defined Configureations + */ +/*#define MTP_USE_DEPEND_DEFAULT_MEMORY*/ +#define MTP_SUPPORT_OMADRM_EXTENSION + +/* Image Height/Width */ +#define MTP_MAX_IMG_WIDTH 32672 +#define MTP_MAX_IMG_HEIGHT 32672 + +#define MTP_MAX_VIDEO_WIDTH 1920 +#define MTP_MAX_VIDEO_HEIGHT 1080 + +#define MTP_MIN_VIDEO_WIDTH 0 +#define MTP_MIN_VIDEO_HEIGHT 0 + +/* about 976kbytes for object property value like sample data*/ +#define MTP_MAX_PROP_DATASIZE 1000000 + +#define MTP_MAX_METADATA 204800 /* 200KB */ + +#define MTP_VENDOR_EXTENSIONDESC_CHAR \ + "microsoft.com/WMDRMPD:10.1;microsoft.com/playready:1.10; " + +#define MTP_MANUFACTURER_CHAR "Tizen" +#define HAVE_OWN_WCHAR_CONVERSION + +#define MTP_MMAP_THRESHOLD 524288 +#define MTP_READ_USB_SIZE 4096 +#define MTP_WRITE_USB_SIZE 4096 +#define MTP_READ_FILE_SIZE 524288 +#define MTP_WRITE_FILE_SIZE 524288 +#define MTP_INIT_RX_IPC_SIZE 32768 +#define MTP_INIT_TX_IPC_SIZE 262144 +#define MTP_MAX_RX_IPC_SIZE 32768 +#define MTP_MAX_TX_IPC_SIZE 262144 +#define MTP_MAX_IO_BUF_SIZE 10485760 /* 10MB */ +#define MTP_READ_FILE_DELAY 0 /* us */ + +#define MTP_SUPPORT_PTHREAD_SCHED false +#define MTP_INHERITSCHED 'i' +#define MTP_SCHEDPOLICY 'o' +#define MTP_FILE_SCHEDPARAM 0 +#define MTP_USB_SCHEDPARAM 0 + +#define MTP_CONFIG_FILE_PATH "/opt/var/lib/misc/mtp-responder.conf" + +typedef struct { + /* Speed related config */ + int mmap_threshold; /* Max. 512KB. If requested memory is lesser than this, malloc is used. Otherwise, mmap is used */ + + int read_usb_size; /* USB read request size */ + int write_usb_size; /* USB write request size */ + + int read_file_size; /* File read request size */ + int write_file_size; /* File write request size */ + + int init_rx_ipc_size; /* Init. Rx(PC -> Phone) IPC size between USB and File threads */ + int init_tx_ipc_size; /* Init. Tx(Phone -> PC) IPC size between USB and File threads */ + int max_rx_ipc_size; /* Max. Rx(PC -> Phone) IPC size between USB and File threads */ + int max_tx_ipc_size; /* Max. Tx(Phone -> PC) IPC size between USB and File threads */ + + int max_io_buf_size; /* Max. Heap memory size for buffer between USB and File threads */ + + int read_file_delay; + + /* Experimental */ + bool support_pthread_sched; + char inheritsched; /* i : Inherit, e : Explicit */ + char schedpolicy; /* f : FIFO, r : Round Robin, o : Other */ + int file_schedparam; /* File I/O thread's priority for scheduling */ + int usb_schedparam; /* USB I/O thread's priority for scheduling */ + + /* Experimental (End) */ + /* Speed related config (End) */ + + /* MTP Features */ + /* MTP Features (End) */ + + /* Vendor Features */ + /* Features (End) */ + + bool is_init; +} mtp_config_t; + +#endif /* _MTP_CONFIG_H_ */ diff --git a/include/mtp_datatype.h b/include/mtp_datatype.h new file mode 100755 index 0000000..07f51f4 --- /dev/null +++ b/include/mtp_datatype.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_DATATYPES_H_ +#define _MTP_DATATYPES_H_ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef _MTP_USE_OWNTYPES +#define _MTP_USE_OWNTYPES +#endif +#ifdef _MTP_USE_OWNTYPES + +#define INVALID_FILE (0) + +typedef unsigned char mtp_byte; +typedef unsigned char mtp_bool; +typedef unsigned char mtp_uchar; +typedef char mtp_char ; + +typedef unsigned short mtp_uint16; +typedef unsigned short mtp_word; +typedef unsigned short mtp_wchar; +typedef short mtp_int16; + +typedef unsigned int mtp_uint32; +typedef int mtp_htimer; +typedef int mtp_int32; + +typedef unsigned long mtp_ulong ; +typedef unsigned long mtp_dword ; + +typedef unsigned long long mtp_uint64; +typedef long long mtp_int64; + +#endif + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +typedef enum { + MTP_ERROR_NONE = 0, + MTP_ERROR_GENERAL = -1, + MTP_ERROR_INVALID_STORE = -2, + MTP_ERROR_STORE_READ_ONLY = -3, + MTP_ERROR_STORE_FULL = -4, + MTP_ERROR_INVALID_DATASET = -5, + MTP_ERROR_INVALID_OBJECTHANDLE = -6, + MTP_ERROR_INVALID_OBJ_PROP_CODE = -7, + MTP_ERROR_INVALID_OBJECT_PROP_FORMAT = -8, + MTP_ERROR_INVALID_OBJ_PROP_VALUE = -9, + MTP_ERROR_INVALID_PARENT = -10, + MTP_ERROR_ACCESS_DENIED = -11, + MTP_ERROR_STORE_NOT_AVAILABLE = -12, + MTP_ERROR_INVALID_PARAM = -13, + MTP_ERROR_INVALID_OBJECT_INFO = -14, + MTP_ERROR_OBJECT_WRITE_PROTECTED = -15, + MTP_ERROR_PARTIAL_DELETION = -16, + MTP_ERROR_NO_SPEC_BY_FORMAT = -17, + MTP_ERROR_OPERATION_NOT_SUPPORTED = -19, + MTP_ERROR_MAX = -20 +} mtp_err_t; + +#define WCHAR_SIZ 2 + +/** + * \brief The CharMode enumeration. + * + * The CharMode enumerates character type by which string is written. + * CHAR_TYPE means that one character consists of 8-bits. + * WCHAR_TYPE means that one character consists of 16-bits. + */ +typedef enum _char_mode { + CHAR_TYPE = 0, + WCHAR_TYPE +} char_mode_t; + +#endif /* _MTP_DATATYPES_H_ */ diff --git a/include/mtp_event_handler.h b/include/mtp_event_handler.h new file mode 100755 index 0000000..2a20cea --- /dev/null +++ b/include/mtp_event_handler.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_EVENT_HANDLER_H_ +#define _MTP_EVENT_HANDLER_H_ + +#include <vconf.h> +#include "mtp_datatype.h" +#include "mtp_util.h" + +typedef enum { + MTP_TURN_OFF, + MTP_ASK_TURN_ON, + MTP_ALWAYS_TURN_ON +} on_off_state_t; + +typedef enum { + USB_INSERTED, + USB_REMOVED +} usb_state_t; + +typedef struct { + mtp_uint32 action; + mtp_ulong param1; + mtp_ulong param2; + mtp_ulong param3; +} mtp_event_t; + +typedef enum { + EVENT_CANCEL_INITIALIZATION, + EVENT_START_MAIN_OP, + EVENT_CLOSE, + EVENT_USB_REMOVED, + EVENT_OBJECT_ADDED, + EVENT_OBJECT_REMOVED, + EVENT_OBJECT_PROP_CHANGED, + EVENT_START_DATAIN, + EVENT_DONE_DATAIN, + EVENT_START_DATAOUT, + EVENT_DONE_DATAOUT, + EVENT_MAX +} event_code_t; + +mtp_bool _eh_register_notification_callbacks(void); +mtp_bool _eh_handle_usb_events(mtp_uint32 type); +void _eh_deregister_notification_callbacks(void); +void _handle_mmc_notification(keynode_t *key, void *data); +void _eh_send_event_req_to_eh_thread(event_code_t action, mtp_ulong param1, + mtp_ulong param2, void *param3); + +#endif /* _MTP_EVENT_HANDLER_H_ */ diff --git a/include/mtp_init.h b/include/mtp_init.h new file mode 100755 index 0000000..2ce28a5 --- /dev/null +++ b/include/mtp_init.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MTPMAIN_H_INCLUDED +#define __MTPMAIN_H_INCLUDED + +#include "mtp_store.h" + +#define MTP_LOG_FILE "/var/log/mtp.log" +#define MTP_LOG_MAX_SIZE 5 * 1024 * 1024 /*5MB*/ + +void _mtp_init(add_rem_store_t sel); +void _mtp_deinit(void); +void _features_supported_info(void); +void mtp_end_event(void); + +#endif /* _MTP_MAIN_H_ */ diff --git a/include/mtp_inoti_handler.h b/include/mtp_inoti_handler.h new file mode 100755 index 0000000..778d226 --- /dev/null +++ b/include/mtp_inoti_handler.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_INOTI_HANDLER_H_ +#define _MTP_INOTI_HANDLER_H_ + +#include "mtp_config.h" +#ifdef MTP_SUPPORT_OBJECTADDDELETE_EVENT +#include <sys/inotify.h> +#include <limits.h> +#include "mtp_datatype.h" + +#define INOTI_EVENT_SIZE (sizeof(struct inotify_event)) +#define INOTI_BUF_LEN (INOTI_EVENT_SIZE + NAME_MAX + 1) +#define INOTI_FOLDER_COUNT_MAX (1024) + +typedef struct { + mtp_int32 wd; + mtp_char *forlder_name; +} inoti_watches_t; + +typedef struct _open_files_info { + mtp_char *name; + mtp_int32 wd; + struct _open_files_info* previous; + struct _open_files_info* next; +} open_files_info_t; + +void *_thread_inoti(void *arg); +void _inoti_add_watch_for_fs_events(mtp_char *path); +mtp_bool _inoti_init_filesystem_evnts(); +void _inoti_deinit_filesystem_events(); +#endif /* MTP_SUPPORT_OBJECTADDDELETE_EVENT */ + +#endif /* _MTP_INOTI_HANDLER_H_ */ diff --git a/include/ptp_container.h b/include/ptp_container.h new file mode 100755 index 0000000..e69380b --- /dev/null +++ b/include/ptp_container.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _PTP_CONTAINER_H_ +#define _PTP_CONTAINER_H_ + +#include "mtp_datatype.h" + +#define MAX_MTP_PARAMS 5 +#define MTP_USB_HEADER_LENGTH 12 + +typedef enum { + CONTAINER_UNDEFINED = 0x00, + CONTAINER_CMD_BLK, + CONTAINER_DATA_BLK, + CONTAINER_RESP_BLK, + CONTAINER_EVENT_BLK +} container_type_t; + +/* + * A generic USB container header. + */ +typedef struct { + mtp_uint32 len; /* the valid container size in BYTES */ + mtp_uint16 type; /* Container type */ + mtp_uint16 code; /* Operation, response or Event code */ + mtp_uint32 tid; /* host generated transaction id */ +} header_container_t; + +/* + * A generic USB container. + */ +typedef struct { + mtp_uint32 len; /* the valid container size in BYTES */ + mtp_uint16 type; /* Container type */ + mtp_uint16 code; /* Operation, response or Event code */ + mtp_uint32 tid; /* host generated transaction id */ + mtp_uint32 params[MAX_MTP_PARAMS]; + mtp_uint32 no_param; +} cmd_container_t; + +/* + * A USB container for sending data. + */ +typedef struct { + mtp_uint32 len; /* the valid container size in BYTES */ + mtp_uint16 type; /* Container type */ + mtp_uint16 code; /* Operation, response or Event code */ + mtp_uint32 tid; /* host generated transaction id */ + mtp_uint32 params[MAX_MTP_PARAMS]; + mtp_uint32 no_param; + mtp_uchar *data; +} data_container_t; + +typedef cmd_container_t cmd_blk_t; +typedef cmd_container_t resp_blk_t; +typedef data_container_t data_blk_t; + +void _hdlr_init_cmd_container(cmd_container_t *cntr); +mtp_uint32 _hdlr_get_param_cmd_container(cmd_container_t *cntr, + mtp_uint32 index); +void _hdlr_copy_cmd_container_unknown_params(cmd_container_t *src, + cmd_container_t *dst); +void _hdlr_copy_cmd_container(cmd_container_t *src, cmd_container_t *dst); +mtp_bool _hdlr_add_param_resp_container(resp_blk_t *dst, mtp_uint32 num, + mtp_uint32 *params); +mtp_bool _hdlr_validate_cmd_container(mtp_uchar *blk, mtp_uint32 size); +void _hdlr_init_data_container(data_container_t *dst, mtp_uint16 code, + mtp_uint32 trans_id); +mtp_uchar *_hdlr_alloc_buf_data_container(data_container_t *dst, + mtp_uint32 bufsz, mtp_uint64 pkt_size); +mtp_bool _hdlr_send_data_container(data_container_t *dst); +mtp_bool _hdlr_send_bulk_data(mtp_uchar *dst, mtp_uint32 len); +mtp_bool _hdlr_rcv_data_container(data_container_t *dst, mtp_uint32 size); +mtp_bool _hdlr_rcv_file_in_data_container(data_container_t *dst, + mtp_char *filepath, mtp_uint32 path_len); +mtp_uint32 _hdlr_get_payload_size(data_container_t *dst); +mtp_uchar *_hdlr_get_payload_data(data_container_t *dst); +void _hdlr_resp_container_init(cmd_container_t *dst, mtp_uint16 resp_code, + mtp_uint32 tid); +mtp_bool _hdlr_send_resp_container(cmd_container_t *dst); +void _hdlr_init_event_container(cmd_container_t *dst, mtp_uint16 code, + mtp_uint32 tid, mtp_uint32 param1, mtp_uint32 param2); +void _hdlr_init_event_container_with_param(cmd_container_t *dst, + mtp_uint16 code, mtp_uint32 tid, mtp_uint32 param1, mtp_uint32 param2); +mtp_bool _hdlr_send_event_container(cmd_container_t *dst); +void _hdlr_conv_cmd_container_byte_order(cmd_container_t *dst); +void _hdlr_conv_data_container_byte_order(data_container_t *dst); + +#endif /* _PTP_CONTAINER_H_ */ diff --git a/include/ptp_datacodes.h b/include/ptp_datacodes.h new file mode 100755 index 0000000..f524b21 --- /dev/null +++ b/include/ptp_datacodes.h @@ -0,0 +1,822 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _PTP_DATACODES_H_ +#define _PTP_DATACODES_H_ + +/* + * PTP Data type codes. + */ +#define PTP_DATATYPE_UNDEFINED 0x0000 +#define PTP_DATATYPE_INT8 0x0001 +#define PTP_DATATYPE_UINT8 0x0002 +#define PTP_DATATYPE_INT16 0x0003 +#define PTP_DATATYPE_UINT16 0x0004 +#define PTP_DATATYPE_INT32 0x0005 +#define PTP_DATATYPE_UINT32 0x0006 +#define PTP_DATATYPE_INT64 0x0007 +#define PTP_DATATYPE_UINT64 0x0008 +#define PTP_DATATYPE_INT128 0x0009 +#define PTP_DATATYPE_UINT128 0x000A +#define PTP_DATATYPE_AINT8 0x4001 +#define PTP_DATATYPE_AUINT8 0x4002 +#define PTP_DATATYPE_AINT16 0x4003 +#define PTP_DATATYPE_AUINT16 0x4004 +#define PTP_DATATYPE_AINT32 0x4005 +#define PTP_DATATYPE_AUINT32 0x4006 +#define PTP_DATATYPE_AINT64 0x4007 +#define PTP_DATATYPE_AUINT64 0x4008 +#define PTP_DATATYPE_AINT128 0x4009 +#define PTP_DATATYPE_AUINT128 0x400A +#define PTP_DATATYPE_STRING 0xFFFF +#define PTP_DATATYPE_ARRAYMASK 0x4FF0 +#define PTP_DATATYPE_ARRAY 0x4000 +#define PTP_DATATYPE_VALUEMASK 0xFFF0 +#define PTP_DATATYPE_VALUE 0x0000 + +/* + * Data code ranges and masks. Each data code has 16 bits: + * Bit 15(std/vendor) + * 0 -- the code is defined by PTP standard + * 1 -- the code is vendor specific + * + * Bit 14 - 12(data type) + * 14 13 12 + * 0 0 0 -- undefined data type + * 0 0 1 -- op code + * 0 1 0 -- response code + * 0 1 1 -- format code + * 1 0 0 -- event code + * 1 0 1 -- property code + * 1 1 0 -- reserved + * 1 1 1 -- reserved + * + * Bit 11 - bit 0 (data value) + */ +#define PTP_DATACODE_VENDORMASK 0x8000 +#define PTP_DATACODE_TYPEMASK 0x7000 +#define PTP_DATACODE_VALUEMASK 0x0FFF +#define PTP_DATACODE_TYPE_UNKNOWN 0x0000 +#define PTP_DATACODE_TYPE_OPERATION 0x1000 +#define PTP_DATACODE_TYPE_RESPONSE 0x2000 +#define PTP_DATACODE_TYPE_FORMAT 0x3000 +#define PTP_DATACODE_TYPE_EVENT 0x4000 +#define PTP_DATACODE_TYPE_PROPERTY 0x5000 +#define PTP_DATACODE_TYPE_RESERVED_1 0x6000 +#define PTP_DATACODE_TYPE_RESERVED_2 0x7000 + +/* + * To verify an op code + * (Code & PTP_DATACODE_TYPEMASK) == PTP_DATACODE_TYPE_OPERATION + * To verify a response code + * (Code & PTP_DATACODE_TYPEMASK) == PTP_DATACODE_TYPE_RESPONSE) + */ + +/* + * Image format codes receive special treatment. + */ +#define PTP_DATACODE_TYPEIMAGEMASK 0x7800; +#define PTP_DATACODE_TYPE_IMAGEFORMAT 0x3800; +#define PTP_DATACODE_VALUE_IMAGEVMASK 0x07FF; +/* + * To verify an image code + * (Code & PTP_DATACODE_TYPEIMAGEMASK) == PTP_DATACODE_TYPE_IMAGEFORMAT + */ + +/* + * PTP specially defined constants + */ +#define PTP_OBJECTHANDLE_ALL 0xFFFFFFFF +#define PTP_OBJECTHANDLE_UNDEFINED 0x0 +#define PTP_OBJECTHANDLE_ROOT 0x0 +#define PTP_PROPERTY_ALL 0xFFFFFFFF +#define PTP_PROPERTY_UNDEFINED 0x0 +#define PTP_STORAGEID_ALL 0xFFFFFFFF +#define PTP_STORAGEID_DEFAULT 0 +#define PTP_STORAGEID_UNDEFINED 0 +#define PTP_STORAGEID_PHYSICAL 0x0000FFFF +#define PTP_STORAGEID_LOGICAL 0xFFFF0000 +#define PTP_SESSIONID_ALL 0 +#define PTP_SESSIONID_NOSESSION 0 +#define PTP_FORMATCODE_NOTUSED 0x0 +#define PTP_FORMATCODE_ALL 0xFFFFFFFF +#define PTP_FORMATCODE_DEFAULT 0x0000 +#define PTP_TRANSACTIONID_ALL 0xFFFFFFFF +#define PTP_TRANSACTIONID_NOSESSION 0 + +/* + * standard operation codes: + */ +#define PTP_OPCODE_UNDEFINED 0x1000 +#define PTP_OPCODE_GETDEVICEINFO 0x1001 +#define PTP_OPCODE_OPENSESSION 0x1002 +#define PTP_OPCODE_CLOSESESSION 0x1003 +#define PTP_OPCODE_GETSTORAGEIDS 0x1004 +#define PTP_OPCODE_GETSTORAGEINFO 0x1005 +#define PTP_OPCODE_GETNUMOBJECTS 0x1006 +#define PTP_OPCODE_GETOBJECTHANDLES 0x1007 +#define PTP_OPCODE_GETOBJECTINFO 0x1008 +#define PTP_OPCODE_GETOBJECT 0x1009 +#define PTP_OPCODE_DELETEOBJECT 0x100B +#define PTP_OPCODE_SENDOBJECTINFO 0x100C +#define PTP_OPCODE_SENDOBJECT 0x100D +#define PTP_OPCODE_INITIATECAPTURE 0x100E +#define PTP_OPCODE_FORMATSTORE 0x100F +#define PTP_OPCODE_RESETDEVICE 0x1010 +#define PTP_OPCODE_SELFTEST 0x1011 +#define PTP_OPCODE_SETOBJECTPROTECTION 0x1012 +#define PTP_OPCODE_POWERDOWN 0x1013 +#define PTP_OPCODE_GETDEVICEPROPDESC 0x1014 +#define PTP_OPCODE_GETDEVICEPROPVALUE 0x1015 +#define PTP_OPCODE_SETDEVICEPROPVALUE 0x1016 +#define PTP_OPCODE_RESETDEVICEPROPVALUE 0x1017 +#define PTP_OPCODE_TERMINATECAPTURE 0x1018 +#define PTP_OPCODE_MOVEOBJECT 0x1019 +#define PTP_OPCODE_COPYOBJECT 0x101A +#define PTP_OPCODE_GETPARTIALOBJECT 0x101B +#define PTP_OPCODE_INITIATEOPENCAPTURE 0x101C +#define PTP_OPCODE_VENDOREXTENDEDBASE 0x9000 +#define PTP_CODE_VENDOR_OP1 0x9001 + +/* MTP extended operations */ +#define MTP_OPCODE_UNDEFINED 0x9800 +#define MTP_OPCODE_GETOBJECTPROPSUPPORTED 0x9801 +#define MTP_OPCODE_GETOBJECTPROPDESC 0x9802 +#define MTP_OPCODE_GETOBJECTPROPVALUE 0x9803 +#define MTP_OPCODE_SETOBJECTPROPVALUE 0x9804 +#define MTP_OPCODE_GETOBJECTPROPLIST 0x9805 +#define MTP_OPCODE_SETOBJECTPROPLIST 0x9806 +#define MTP_OPCODE_GETINTERDEPPROPDESC 0x9807 +#define MTP_OPCODE_SENDOBJECTPROPLIST 0x9808 +#define MTP_OPCODE_GETOBJECTREFERENCES 0x9810 +#define MTP_OPCODE_SETOBJECTREFERENCES 0x9811 + +/* MTP Playback control operation */ +#define MTP_OPCODE_PLAYBACK_SKIP 0x9820 + +/* Operation for Windows Media 10 MTP extension */ +#define MTP_OPCODE_WMP_UNDEFINED 0x9200 +#define MTP_OPCODE_WMP_METADATAROUNDTRIP 0x9201 +#define MTP_OPCODE_WMP_REPORTACQUIREDCONTENT 0x9202 + +/* + * standard event codes: + */ +#define PTP_EVENTCODE_UNDEFINED 0x4000 +#define PTP_EVENTCODE_CANCELTRANSACTION 0x4001 +#define PTP_EVENTCODE_OBJECTADDED 0x4002 +#define PTP_EVENTCODE_OBJECTREMOVED 0x4003 +#define PTP_EVENTCODE_STOREADDED 0x4004 +#define PTP_EVENTCODE_STOREREMOVED 0x4005 +#define PTP_EVENTCODE_DEVICEPROPCHANGED 0x4006 +#define PTP_EVENTCODE_OBJECTINFOCHANGED 0x4007 +#define PTP_EVENTCODE_DEVICEINFOCHANGED 0x4008 +#define PTP_EVENTCODE_REQUESTOBJECTTRANSFER 0x4009 +#define PTP_EVENTCODE_STOREFULL 0x400A +#define PTP_EVENTCODE_DEVICERESET 0x400B +#define PTP_EVENTCODE_STORAGEINFOCHANGED 0x400C +#define PTP_EVENTCODE_CAPTURECOMPLETE 0x400D +#define PTP_EVENTCODE_UNREPORTEDSTATUS 0x400E +#define PTP_EVENTCODE_VENDOREXTENTION1 0xC001 +#define PTP_EVENTCODE_VENDOREXTENTION2 0xC002 + +/* + * MTP-extended Events + */ +#define MTP_EVENTCODE_UNDEFINED 0xB800 +#define MTP_EVENTCODE_OBJECTPROPCHANGED 0xC801 +#define MTP_EVENTCODE_OBJECTPROPDESCCHANGED 0xC802 +#define MTP_EVENTCODE_OBJECTREFERENCESCHANGED 0xC803 +#define MTP_EVENTCODE_DEVICEPROPDESCCHANGED 0xB804 + +/* Events for Janus MTP extension */ +#define MTP_EVENTCODE_JANUS_UNDEFINED 0xC100 +#define MTP_EVENTCODE_JANUS_EVENT1 0xC101 + +/* + * standard response codes: + */ +#define PTP_RESPONSE_UNDEFINED 0x2000 +#define PTP_RESPONSE_OK 0x2001 +#define PTP_RESPONSE_GEN_ERROR 0x2002 +#define PTP_RESPONSE_SESSIONNOTOPEN 0x2003 +#define PTP_RESPONSE_INVALID_TRANSACTIONID 0x2004 +#define PTP_RESPONSE_OP_NOT_SUPPORTED 0x2005 +#define PTP_RESPONSE_PARAM_NOTSUPPORTED 0x2006 +#define PTP_RESPONSE_INCOMPLETETRANSFER 0x2007 +#define PTP_RESPONSE_INVALID_STORE_ID 0x2008 +#define PTP_RESPONSE_INVALID_OBJ_HANDLE 0x2009 +#define PTP_RESPONSE_PROP_NOTSUPPORTED 0x200A +#define PTP_RESPONSE_INVALID_OBJ_FMTCODE 0x200B +#define PTP_RESPONSE_STOREFULL 0x200C +#define PTP_RESPONSE_OBJ_WRITEPROTECTED 0x200D +#define PTP_RESPONSE_STORE_READONLY 0x200E +#define PTP_RESPONSE_ACCESSDENIED 0x200F +#define PTP_RESPONSE_SELFTEST_FAILED 0x2011 +#define PTP_RESPONSE_PARTIAL_DELETION 0x2012 +#define PTP_RESPONSE_STORENOTAVAILABLE 0x2013 +#define PTP_RESPONSE_NOSPECIFICATIONBYFORMAT 0x2014 +#define PTP_RESPONSE_NOVALID_OBJINFO 0x2015 +#define PTP_RESPONSE_INVALIDCODEFORMAT 0x2016 +#define PTP_RESPONSE_UNKNOWN_VENDORCODE 0x2017 +#define PTP_RESPONSE_CAPTURE_ALREADYTERMINATED 0x2018 +#define PTP_RESPONSE_DEVICEBUSY 0x2019 +#define PTP_RESPONSE_INVALIDPARENT 0x201A +#define PTP_RESPONSE_INVALIDPROPFORMAT 0x201B +#define PTP_RESPONSE_INVALIDPROPVALUE 0x201C +#define PTP_RESPONSE_INVALIDPARAM 0x201D +#define PTP_RESPONSE_SESSIONALREADYOPENED 0x201E +#define PTP_RESPONSE_TRANSACTIONCANCELLED 0x201F +/* + * MTP responses + */ +#define MTP_RESPONSE_UNDEFINED 0xA800 +#define MTP_RESPONSE_INVALIDOBJPROPCODE 0xA801 +#define MTP_RESPONSE_INVALIDOBJPROPFORMAT 0xA802 +#define MTP_RESPONSE_INVALIDOBJPROPVALUE 0xA803 +#define MTP_RESPONSE_INVALIDOBJREFERENCE 0xA804 +#define MTP_RESPONSE_INVALIDOBJGROUPCODE 0xA805 +#define MTP_RESPONSECODE_INVALIDDATASET 0xA806 +#define MTP_RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED 0xA807 +#define MTP_RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED 0xA808 +#define MTP_RESPONSE_OBJECT_TOO_LARGE 0xA809 + +/* + * standard property codes: + */ +#define PTP_PROPERTYCODE_UNDEFINED 0x5000 +#define PTP_PROPERTYCODE_BATTERYLEVEL 0x5001 +#define PTP_PROPERTYCODE_FUNCTIONMODE 0x5002 +#define PTP_PROPERTYCODE_IMAGESIZE 0x5003 +#define PTP_PROPERTYCODE_COMPRESSIONSETTING 0x5004 +#define PTP_PROPERTYCODE_WHITEBALANCE 0x5005 +#define PTP_PROPERTYCODE_RGBGAIN 0x5006 +#define PTP_PROPERTYCODE_FNUMBER 0x5007 +#define PTP_PROPERTYCODE_FOCALLENGTH 0x5008 +#define PTP_PROPERTYCODE_FOCUSDISTANCE 0x5009 +#define PTP_PROPERTYCODE_FOCUSMODE 0x500A +#define PTP_PROPERTYCODE_EXPOSUREMETERINGMODE 0x500B +#define PTP_PROPERTYCODE_FLASHMODE 0x500C +#define PTP_PROPERTYCODE_EXPOSURETIME 0x500D +#define PTP_PROPERTYCODE_EXPOSUREPROGRAMMODE 0x500E +#define PTP_PROPERTYCODE_EXPOSUREINDEX 0x500F +#define PTP_PROPERTYCODE_EXPOSURECOMPENSATION 0x5010 +#define PTP_PROPERTYCODE_DATETIME 0x5011 +#define PTP_PROPERTYCODE_CAPTUREDELAY 0x5012 +#define PTP_PROPERTYCODE_STILLCAPTUREMODE 0x5013 +#define PTP_PROPERTYCODE_CONTRAST 0x5014 +#define PTP_PROPERTYCODE_SHARPNESS 0x5015 +#define PTP_PROPERTYCODE_DIGITALZOOM 0x5016 +#define PTP_PROPERTYCODE_EFFECTMODE 0x5017 +#define PTP_PROPERTYCODE_BURSTNUMBER 0x5018 +#define PTP_PROPERTYCODE_BURSTINTERVAL 0x5019 +#define PTP_PROPERTYCODE_TIMELAPSENUMBER 0x501A +#define PTP_PROPERTYCODE_TIMELAPSEINTERVAL 0x501B +#define PTP_PROPERTYCODE_FOCUSMETERINGMODE 0x501C +#define PTP_PROPERTYCODE_UPLOADURL 0x501D +#define PTP_PROPERTYCODE_ARTIST 0x501E +#define PTP_PROPERTYCODE_COPYRIGHT 0x501F +#define PTP_PROPERTYCODE_VENDOREXTENTION1 0xD001 +#define PTP_PROPERTYCODE_VENDOREXTENTION2 0xD002 + +/* + * MTP defined Device properties + */ +#define MTP_PROPERTYCODE_UNDEFINED 0xD400 +#define MTP_PROPERTYCODE_SYNCHRONIZATIONPARTNER 0xD401 +#define MTP_PROPERTYCODE_DEVICEFRIENDLYNAME 0xD402 + +#define MTP_PROPERTYCODE_SUPPORTEDFORMATSORDERED 0xD404 +#define MTP_PROPERTYCODE_DEVICEICON 0xD405 + +#ifdef MTP_SUPPORT_DEVICE_CLASS +#define MTP_PROPERTYCODE_PERCEIVEDDEVICETYPE 0xD407 +#endif + +/* Device properties for MTP Playback */ +#define MTP_PROPERTYCODE_PLAYBACK_RATE 0xD410 +#define MTP_PROPERTYCODE_PLAYBACK_OBJECT 0xD411 +#define MTP_PROPERTYCODE_PLAYBACK_CONT_INDEX 0xD412 +#define MTP_PROPERTYCODE_PLAYBACK_POSITION 0xD413 + +/* MTP extended object property codes */ +#define MTP_OBJ_PROPERTYCODE_PURCHASE_ALBTRK 0xD901 + +/* for support OMA DRM, request of Vodafone */ +#define MTP_OBJ_PROPERTYCODE_OMADRMSTATUS 0xDB01 +#define MTP_OBJ_PROPERTYCODE_OMADRMRIGHTSOBJECT 0xDB02 + +#define MTP_OBJ_PROPERTYCODE_STORAGEID 0xDC01 +#define MTP_OBJ_PROPERTYCODE_OBJECTFORMAT 0xDC02 +#define MTP_OBJ_PROPERTYCODE_PROTECTIONSTATUS 0xDC03 +#define MTP_OBJ_PROPERTYCODE_OBJECTSIZE 0xDC04 +#define MTP_OBJ_PROPERTYCODE_ASSOCIATIONTYPE 0xDC05 +#define MTP_OBJ_PROPERTYCODE_ASSOCIATIONDESC 0xDC06 +#define MTP_OBJ_PROPERTYCODE_OBJECTFILENAME 0xDC07 +#define MTP_OBJ_PROPERTYCODE_DATECREATED 0xDC08 +#define MTP_OBJ_PROPERTYCODE_DATEMODIFIED 0xDC09 +#define MTP_OBJ_PROPERTYCODE_KEYWORDS 0xDC0A +#define MTP_OBJ_PROPERTYCODE_PARENT 0xDC0B + +#define MTP_OBJ_PROPERTYCODE_PERSISTENTGUID 0xDC41 +#define MTP_OBJ_PROPERTYCODE_SYNCID 0xDC42 +#define MTP_OBJ_PROPERTYCODE_PROPERTYBAG 0xDC43 +#define MTP_OBJ_PROPERTYCODE_NAME 0xDC44 +#define MTP_OBJ_PROPERTYCODE_CREATEDBY 0xDC45 +#define MTP_OBJ_PROPERTYCODE_ARTIST 0xDC46 +#define MTP_OBJ_PROPERTYCODE_DATEAUTHORED 0xDC47 +#define MTP_OBJ_PROPERTYCODE_DESCRIPTION 0xDC48 +#define MTP_OBJ_PROPERTYCODE_URLREFERENCE 0xDC49 +#define MTP_OBJ_PROPERTYCODE_LANGUAGELOCALE 0xDC4A +#define MTP_OBJ_PROPERTYCODE_COPYRIGHTINFO 0xDC4B +#define MTP_OBJ_PROPERTYCODE_SOURCE 0xDC4C +#define MTP_OBJ_PROPERTYCODE_ORIGINLOCATION 0xDC4D +#define MTP_OBJ_PROPERTYCODE_DATEADDED 0xDC4E +#define MTP_OBJ_PROPERTYCODE_NONCONSUMABLE 0xDC4F +#define MTP_OBJ_PROPERTYCODE_CORRUPTUNPLAYABLE 0xDC50 + +#define MTP_OBJ_PROPERTYCODE_SAMPLEFORMAT 0xDC81 +#define MTP_OBJ_PROPERTYCODE_SAMPLESIZE 0xDC82 +#define MTP_OBJ_PROPERTYCODE_SAMPLEHEIGHT 0xDC83 +#define MTP_OBJ_PROPERTYCODE_SAMPLEWIDTH 0xDC84 +#define MTP_OBJ_PROPERTYCODE_SAMPLEDURATION 0xDC85 +#define MTP_OBJ_PROPERTYCODE_SAMPLEDATA 0xDC86 +#define MTP_OBJ_PROPERTYCODE_WIDTH 0xDC87 +#define MTP_OBJ_PROPERTYCODE_HEIGHT 0xDC88 +#define MTP_OBJ_PROPERTYCODE_DURATION 0xDC89 +#define MTP_OBJ_PROPERTYCODE_USERRATING 0xDC8A +#define MTP_OBJ_PROPERTYCODE_TRACK 0xDC8B +#define MTP_OBJ_PROPERTYCODE_GENRE 0xDC8C +#define MTP_OBJ_PROPERTYCODE_CREDITS 0xDC8D +#define MTP_OBJ_PROPERTYCODE_LYRICS 0xDC8E +#define MTP_OBJ_PROPERTYCODE_SUBSCRIPCONTENTID 0xDC8F +#define MTP_OBJ_PROPERTYCODE_PRODUCEDBY 0xDC90 +#define MTP_OBJ_PROPERTYCODE_USECOUNT 0xDC91 +#define MTP_OBJ_PROPERTYCODE_SKIPCOUNT 0xDC92 +#define MTP_OBJ_PROPERTYCODE_LASTACCESSED 0xDC93 +#define MTP_OBJ_PROPERTYCODE_PARENTALRATING 0xDC94 +#define MTP_OBJ_PROPERTYCODE_METAGENRE 0xDC95 +#define MTP_OBJ_PROPERTYCODE_COMPOSER 0xDC96 +#define MTP_OBJ_PROPERTYCODE_EFFECTIVERATING 0xDC97 +#define MTP_OBJ_PROPERTYCODE_SUBTITLE 0xDC98 +#define MTP_OBJ_PROPERTYCODE_ORIGINALRELEASEDATE 0xDC99 +#define MTP_OBJ_PROPERTYCODE_ALBUMNAME 0xDC9A +#define MTP_OBJ_PROPERTYCODE_ALBUMARTIST 0xDC9B +#define MTP_OBJ_PROPERTYCODE_MOOD 0xDC9C +#define MTP_OBJ_PROPERTYCODE_DRMSTATUS 0xDC9D +#define MTP_OBJ_PROPERTYCODE_SUBDESCRIPTION 0xDC9E + +#define MTP_OBJ_PROPERTYCODE_ISCROPPED 0xDCD1 +#define MTP_OBJ_PROPERTYCODE_ISCOLORCORRECTED 0xDCD2 + +#define MTP_OBJ_PROPERTYCODE_TOTALBITRATE 0xDE91 +#define MTP_OBJ_PROPERTYCODE_BITRATETYPE 0xDE92 +#define MTP_OBJ_PROPERTYCODE_SAMPLERATE 0xDE93 +#define MTP_OBJ_PROPERTYCODE_NUMBEROFCHANNELS 0xDE94 +#define MTP_OBJ_PROPERTYCODE_AUDIOBITDEPTH 0xDE95 +#define MTP_OBJ_PROPERTYCODE_SCANTYPE 0xDE97 +#define MTP_OBJ_PROPERTYCODE_AUDIOWAVECODEC 0xDE99 +#define MTP_OBJ_PROPERTYCODE_AUDIOBITRATE 0xDE9A +#define MTP_OBJ_PROPERTYCODE_VIDEOFOURCCCODEC 0xDE9B +#define MTP_OBJ_PROPERTYCODE_VIDEOBITRATE 0xDE9C +#define MTP_OBJ_PROPERTYCODE_FRAMESPER1KSECONDS 0xDE9D +#define MTP_OBJ_PROPERTYCODE_KEYFRAMEDISTANCE 0xDE9E +#define MTP_OBJ_PROPERTYCODE_BUFFERSIZE 0xDE9F +#define MTP_OBJ_PROPERTYCODE_ENCODINGQUALITY 0xDEA0 +#define MTP_OBJ_PROPERTYCODE_ENCODINGPROFILE 0xDEA1 +#define MTP_OBJ_PROPERTYCODE_PLAYBACK_RATE 0xDF01 +#define MTP_OBJ_PROPERTYCODE_PLAYBACK_OBJECT 0xDF02 +#define MTP_OBJ_PROPERTYCODE_PLAYBACK_CONT_INDEX 0xDF03 +#define MTP_OBJ_PROPERTYCODE_PLAYBACK_POSITION 0xDF04 + +/* standard format codes */ +#define PTP_FORMATMASK_IMAGE 0x0800 + +#define PTP_FMT_UNDEF 0x3000 +#define PTP_FMT_ASSOCIATION 0x3001 +#define PTP_FMT_SCRIPT 0x3002 +#define PTP_FMT_EXEC 0x3003 +#define PTP_FMT_TEXT 0x3004 +#define PTP_FMT_HTML 0x3005 +#define PTP_FMT_DPOF 0x3006 +#define PTP_FMT_AIFF 0x3007 +#define PTP_FMT_WAVE 0x3008 +#define PTP_FMT_MP3 0x3009 +#define PTP_FMT_AVI 0x300A +#define PTP_FMT_MPEG 0x300B +#define PTP_FMT_ASF 0x300C + +#define PTP_FMT_IMG_UNDEF 0x3800 +#define PTP_FMT_IMG_EXIF 0x3801 +#define PTP_FMT_IMG_TIFFEP 0x3802 +#define PTP_FMT_IMG_FLASHPIX 0x3803 +#define PTP_FMT_IMG_BMP 0x3804 +#define PTP_FMT_IMG_CIFF 0x3805 +#define PTP_FMT_IMG_GIF 0x3807 +#define PTP_FMT_IMG_JFIF 0x3808 +#define PTP_FMT_IMG_PCD 0x3809 +#define PTP_FMT_IMG_PICT 0x380A +#define PTP_FMT_IMG_PNG 0x380B +#define PTP_FMT_IMG_TIFF 0x380D +#define PTP_FMT_IMG_TIFFIT 0x380E +#define PTP_FMT_IMG_JP2 0x380F +#define PTP_FMT_IMG_JPX 0x3810 + +/* MTP-defined Object Formats */ +#define MTP_FMT_UNDEFINED_FIRMWARE 0xB802 +#define MTP_FMT_WINDOWS_IMG_FORMAT 0xB881 +#define MTP_FMT_UNDEFINED_AUDIO 0xB900 +#define MTP_FMT_WMA 0xB901 +#define MTP_FMT_UNDEFINED_VIDEO 0xB980 +#define MTP_FMT_WMV 0xB981 +#define MTP_FMT_UNDEFINED_COLLECTION 0xBA00 +#define MTP_FMT_ABSTRACT_MULTIMEDIA_ALBUM 0xBA01 +#define MTP_FMT_ABSTRACT_IMG_ALBUM 0xBA02 +#define MTP_FMT_ABSTRACT_AUDIO_ALBUM 0xBA03 +#define MTP_FMT_ABSTRACT_VIDEO_ALBUM 0xBA04 +#define MTP_FMT_ABSTRACT_CONTACT_GROUP 0xBA06 +#define MTP_FMT_ABSTRACT_MESSAGE_FOLDER 0xBA07 +#define MTP_FMT_ABSTRACT_CHAPTERED_PRODUCTION 0xBA08 +#define MTP_FMT_UNDEFINED_DOC 0xBA80 +#define MTP_FMT_ABSTRACT_DOC 0xBA81 +#define MTP_FMT_UNDEFINED_MESSAGE 0xBB00 +#define MTP_FMT_ABSTRACT_MESSAGE 0xBB01 +#define MTP_FMT_UNDEFINED_CONTACT 0xBB80 +#define MTP_FMT_ABSTRACT_CONTACT 0xBB81 +#define MTP_FMT_VCARD2 0xBB82 +#define MTP_FMT_VCARD3 0xBB83 +#define MTP_FMT_UNDEFINED_CALENDAR_ITEM 0xBE00 +#define MTP_FMT_ABSTRACT_CALENDAR_ITEM 0xBE01 +#define MTP_FMT_VCALENDAR1 0xBE02 +#define MTP_FMT_UNDEFINED_WINDOWS_EXECUTABLE 0xBE80 + +#define MTP_FMT_FLAC 0xB906 +#define MTP_FMT_MP4 0xB982 +#define MTP_FMT_3GP 0xB984 + +/* + * Property description data set form flags definitions + */ +#define PTP_FORMFLAGS_NONE 0x00 +#define PTP_FORMFLAGS_RANGE 0x01 +#define PTP_FORMFLAGS_ENUM 0x02 + +/* + * power states: + */ +#define PTP_POWERSTATE_DEVICEOFF 0x0000 +#define PTP_POWERSTATE_SLEEP 0x0001 +#define PTP_POWERSTATE_FULL 0x0002 + +/* + * white balances: + */ +#define PTP_WHITEBALANCE_UNDEFINED 0x0000 +#define PTP_WHILEBALANCE_MANUAL 0x0001 +#define PTP_WHITEBALANCE_AUTOMATIC 0x0002 +#define PTP_WHITEBALANCE_ONEPUSHAUTO 0x0003 +#define PTP_WHITEBALANCE_DAYLIGHT 0x0004 +#define PTP_WHITEBALANCE_FLORESCENT 0x0005 +#define PTP_WHITEBALANCE_TUNGSTEN 0x0006 +#define PTP_WHITEBALANCE_FLASH 0x0007 + +/* + * focus modes: + */ +#define PTP_FOCUSMODE_UNDEFINED 0x0000 +#define PTP_FOCUSMODE_MANUAL 0x0001 +#define PTP_FOCUSMODE_AUTO 0x0002 +#define PTP_FOCUSMODE_MACRO 0x0003 + +/* + * focus metering: + */ +#define PTP_FOCUSMETERING_UNDEFINED 0x0000 +#define PTP_FOCUSMETERING_CENTERSPOT 0x0001 +#define PTP_FOCUSMETERING_MULTISPOT 0x0002 + +/* + * flash modes: + */ +#define PTP_FLASHMODE_UNDEFINED 0x0000 +#define PTP_FLASHMODE_AUTO 0x0001 +#define PTP_FLASHMODE_OFF 0x0002 +#define PTP_FLASHMODE_FILL 0x0003 +#define PTP_FLASHMODE_REDEYEAUTO 0x0004 +#define PTP_FLASHMODE_REDEYEFILL 0x0005 +#define PTP_FLASHMODE_EXTERNALSYNC 0x0006 +#define PTP_FLASHMODE_MASK 0xFFF0 + +/* + * exposure modes: + */ +#define PTP_EXPOSUREMODE_UNDEFINED 0x0000 +#define PTP_EXPOSUREMODE_MANUALSETTING 0x0001 +#define PTP_EXPOSUREMODE_AUTOPROGRAM 0x0002 +#define PTP_EXPOSUREMODE_APERTUREPRIORITY 0x0003 +#define PTP_EXPOSUREMODE_SHUTTERPRIORITY 0x0004 +#define PTP_EXPOSUREMODE_PROGRAMCREATIVE 0x0005 +#define PTP_EXPOSUREMODE_PROGRAMACTION 0x0006 +#define PTP_EXPOSUREMODE_PORTRAIT 0x0007 + +/* + * capturing modes + */ +#define PTP_CAPTUREMODE_UNDEFINED 0x0000 +#define PTP_CAPTUREMODE_NORMAL 0x0001 +#define PTP_CAPTUREMODE_BURST 0x0002 +#define PTP_CAPTUREMODE_TIMELAPSE 0x0003 + +/* + * focus metering modes + */ +#define PTP_FOCUSMETERMODE_UNDEFINED 0x0000 +#define PTP_FOCUSMETERMODE_CENTERSPOT 0x0001 +#define PTP_FOCUSMETERMODE_MULTISPOT 0x0002 + +/* + * effect modes + */ +#define PTP_EFFECTMODE_UNDEFINED 0x0000 +#define PTP_EFFECTMODE_COLOR 0x0001 +#define PTP_EFFECTMODE_BW 0x0002 +#define PTP_EFFECTMODE_SEPIA 0x0003 + +/* + * storage types + */ +#define PTP_STORAGETYPE_UNDEFINED 0x0000 +#define PTP_STORAGETYPE_FIXEDROM 0x0001 +#define PTP_STORAGETYPE_REMOVABLEROM 0x0002 +#define PTP_STORAGETYPE_FIXEDRAM 0x0003 +#define PTP_STORAGETYPE_REMOVABLERAM 0x0004 + +/* + * storage access capabilities + */ +#define PTP_STORAGEACCESS_RWD 0x0000 +#define PTP_STORAGEACCESS_R 0x0001 +#define PTP_STORAGEACCESS_RD 0x0002 + +/* + * association types: + */ +#define PTP_ASSOCIATIONTYPE_UNDEFINED 0x0000 +#define PTP_ASSOCIATIONTYPE_FOLDER 0x0001 +#define PTP_ASSOCIATIONTYPE_ALBUM 0x0002 +#define PTP_ASSOCIATIONTYPE_BURST 0x0003 +#define PTP_ASSOCIATIONTYPE_HPANORAMA 0x0004 +#define PTP_ASSOCIATIONTYPE_VPANORAMA 0x0005 +#define PTP_ASSOCIATIONTYPE_2DPANORAMA 0x0006 +#define PTP_ASSOCIATIONTYPE_ANCILLARYDATA 0x0007 +#define PTP_ASSOCIATIONTYPE_MASK 0xFFF0 + +/* + * protection status: + */ +#define PTP_PROTECTIONSTATUS_NOPROTECTION 0x0000 +#define PTP_PROTECTIONSTATUS_READONLY 0x0001 +#define MTP_PROTECTIONSTATUS_READONLY_DATA 0x8002 +#define MTP_PROTECTIONSTATUS_NONTRANSFERABLE_DATA 0x8003 + +/* file system types */ +#define PTP_FILESYSTEMTYPE_UNDEFINED 0x0000 +#define PTP_FILESYSTEMTYPE_FLAT 0x0001 +#define PTP_FILESYSTEMTYPE_HIERARCHICAL 0x0002 +#define PTP_FILESYSTEMTYPE_DCF 0x0003 + +/* + * functional modes: + */ +#define PTP_FUNCTIONMODE_STANDARD 0x0000 +#define PTP_FUNCTIONMODE_SLEEP 0x0001 + +/* + * Get/Set + */ +#define PTP_PROPGETSET_GETONLY 0x00 +#define PTP_PROPGETSET_GETSET 0x01 +#define PTP_PROPGETSET_GETSET2 0x02 + +/* Common Audio Sample Rate */ +#define MTP_AUDIO_SAMPLERATE_UNKNOWN 0 +#define MTP_AUDIO_SAMPLERATE_8K 8000 +#define MTP_AUDIO_SAMPLERATE_32K 32000 +#define MTP_AUDIO_SAMPLERATE_CD 44100 +#define MTP_AUDIO_SAMPLERATE_48K 48000 +#define MTP_AUDIO_SAMPLERATE_DVD 96000 + +/* Common Audio Bit Rate */ +#define MTP_AUDIO_BITRATE_UNKNOWN 0 +#define MTP_AUDIO_BITRATE_GSM 13000 +#define MTP_AUDIO_BITRATE_16K 16999 +#define MTP_AUDIO_BITRATE_G721 32000 +#define MTP_AUDIO_BITRATE_G711 64000 +#define MTP_AUDIO_BITRATE_128K 128999 +#define MTP_AUDIO_BITRATE_CDDA 144100 +#define MTP_AUDIO_BITRATE_160K 160999 +#define MTP_AUDIO_BITRATE_192K 192999 +#define MTP_AUDIO_BITRATE_256K 256999 +#define MTP_AUDIO_BITRATE_STUDIO 384999 +#define MTP_AUDIO_BITRATE_BLUERAY 10000000 + + +/* Common Video Bit Rate */ +#define MTP_VIDEO_BITRATE_MINIMUM 1000 +#define MTP_VIDEO_BITRATE_BLUERAY 40000000 + +/* Common Metagenre defined */ +#define MTP_METAGENRE_NOT_USED 0x0000 +#define MTP_METAGENRE_GENERIC_MUSIC_AUDIO_FILE 0x0001 +#define MTP_METAGENRE_GENERIC_NONMUSIC_AUDIO_FILE 0x0011 +#define MTP_METAGENRE_SPOKEN_WORD_AUDIO_BOOK_FILES 0x0012 +#define MTP_METAGENRE_SPOKEN_WORD_NONAUDIO_BOOK_FILES 0x0013 +#define MTP_METAGENRE_SPOKEN_WORD_NEWS 0x0014 +#define MTP_METAGENRE_SPOKEN_WORD_TALK_SHOWS 0x0015 +#define MTP_METAGENRE_GENERIC_VIDEO_FILE 0x0021 +#define MTP_METAGENRE_NEWS_VIDEO_FILE 0x0022 +#define MTP_METAGENRE_MUSIC_VIDEO_FILE 0x0023 +#define MTP_METAGENRE_HOME_VIDEO_FILE 0x0024 +#define MTP_METAGENRE_FEATURE_FILM_VIDEO_FILE 0x0025 +#define MTP_METAGENRE_TV_SHOW_VIDEO_FILE 0x0026 +#define MTP_METAGENRE_TRAINING_VIDEO_FILE 0x0027 +#define MTP_METAGENRE_PHOTO_MONTAGE_VIDEO_FILE 0x0028 +#define MTP_METAGENRE_GENERIC_NONAUDIO_NONVIDEO_FILE 0x0030 +#define MTP_METAGENRE_AUDIO_MEDIA_CAST_FILE 0x0040 +#define MTP_METAGENRE_VIDEO_MEDIA_CAST_FILE 0x0041 +#define MTP_METAGENRE_MIXED_MEDIA_CAST_FILE 0x0042 +#define MTP_METAGENRE_VENDOR_DEFINED_MASK 0x8000 + +/* Common NumberOfChannels defined */ +#define MTP_CHANNELS_NOT_USED 0x0000 +#define MTP_CHANNELS_MONO 0x0001 +#define MTP_CHANNELS_STEREO 0x0002 +#define MTP_CHANNELS_2DOT1 0x0003 +#define MTP_CHANNELS_3 0x0004 +#define MTP_CHANNELS_3DOT1 0x0005 +#define MTP_CHANNELS_4 0x0006 +#define MTP_CHANNELS_4DOT1 0x0007 +#define MTP_CHANNELS_5 0x0008 +#define MTP_CHANNELS_5DOT1 0x0009 +#define MTP_CHANNELS_6 0x000A +#define MTP_CHANNELS_6DOT1 0x000B +#define MTP_CHANNELS_7 0x000C +#define MTP_CHANNELS_7DOT1 0x000D +#define MTP_CHANNELS_8 0x000E +#define MTP_CHANNELS_8DOT1 0x000F +#define MTP_CHANNELS_9 0x0010 +#define MTP_CHANNELS_9DOT1 0x0011 + +/* Common ScanTypes defined */ +#define MTP_SCANTYPE_NOT_USED 0x0000 +#define MTP_SCANTYPE_PROGESSIVE 0x0001 +#define MTP_SCANTYPE_FIELDINTERLEAVEDUPPERFIRST 0x0002 +#define MTP_SCANTYPE_FIELDINTERLEAVEDLOWERFIRST 0x0003 +#define MTP_SCANTYPE_FIELDSINGLEUPPERFIRST 0x0004 +#define MTP_SCANTYPE_FIELDSINGLELOWERFIRST 0x0005 +#define MTP_SCANTYPE_MIXEDINTERLACE 0x0006 +#define MTP_SCANTYPE_MIXEDINTERLACEANDPROGRESSIVE 0x0007 + +/* Selected Audio Wave Formats */ +#define MTP_WAVEFORMAT_UNKNOWN 0x0000 +#define MTP_WAVEFORMAT_PCM 0x0001 +#define MTP_WAVEFORMAT_ADPCM 0x0002 +#define MTP_WAVEFORMAT_IEEEFLOAT 0x0003 +#define MTP_WAVEFORMAT_DTS 0x0008 +#define MTP_WAVEFORMAT_DRM 0x0009 +#define MTP_WAVEFORMAT_WMSP2 0x000B +#define MTP_WAVEFORMAT_GSM610 0x0031 +#define MTP_WAVEFORMAT_MSNAUDIO 0x0032 +#define MTP_WAVEFORMAT_MPEG 0x0050 +#define MTP_WAVEFORMAT_MPEGLAYER3 0x0055 +#define MTP_WAVEFORMAT_MSAUDIO1 0x0160 +#define MTP_WAVEFORMAT_MSAUDIO2 0x0161 +#define MTP_WAVEFORMAT_MSAUDIO3 0x0162 +#define MTP_WAVEFORMAT_WMAUDIOLOSSLESS 0x0163 +#define MTP_WAVEFORMAT_WMASPDIF 0x0164 +#define MTP_WAVEFORMAT_AAC 0xA106 +#define MTP_WAVEFORMAT_AMR_WB 0xA104 +#define MTP_WAVEFORMAT_RAW_AAC1 0x00FF +#define MTP_WAVEFORMAT_MPEG_HEAAC 0x1610 + + +/* + * Check Supported codec on Device + * Check Registered name on this site + * http://msdn.microsoft.com/en-us/library/aa904731.aspx + * Convert the name using this macro GST_MAKE_FOURCC(a, b, c, d) + */ +#define MTP_VIDEOFOURCC_UNKNOWN 0 +#define MTP_VIDEOFOURCC_MP42 0x3234504D +#define MTP_VIDEOFOURCC_MP43 0x3334504D +#define MTP_VIDEOFOURCC_WMV1 0x31564D57 +#define MTP_VIDEOFOURCC_WMV2 0x32564D57 +#define MTP_VIDEOFOURCC_WMV3 0x33564D57 +#define MTP_VIDEOFOURCC_DIVX 0x58564944 +#define MTP_VIDEOFOURCC_XVID 0x44495658 +#define MTP_VIDEOFOURCC_M4S2 0x3253344D +#define MTP_VIDEOFOURCC_MP4V 0x5634504D +#define MTP_VIDEOFOURCC_h264 0x34363268 +#define MTP_VIDEOFOURCC_H263 0x33363268 +#define MTP_VIDEOFOURCC_AVC1 0x31435641 +#define MTP_VIDEOFOURCC_H264 0x34363248 +#define MTP_VIDEOFOURCC_X264 0x34363258 +#define MTP_VIDEOFOURCC_N264 0x34363278 + +/* BIT RATE */ +#define MTP_MIN_VIDEO_BITRATE 0x0FA0 +#define MTP_MAX_VIDEO_BITRATE 0x1312D00 + +/* FPS */ +#define MTP_MIN_VIDEO_FPS 0 +#define MTP_MAX_VIDEO_FPS 0x7652 + +#define MTP_VIDEO_HEIGHT_WIDTH_INTERVAL 0x2 +#define MTP_AUDIO_SAMPLE_RATE_INTERVAL 0x19 + +/* + * USB class-specific requests + */ +#define USB_PTPREQUEST_TYPE_OUT 0x21 /* Host to Device */ +#define USB_PTPREQUEST_TYPE_IN 0xA1 /* Device to Host */ +#define USB_PTPREQUEST_CANCELIO 0x64 /* Cancel request */ +#define USB_PTPREQUEST_GETEVENT 0x65 /* Get extened event data */ +#define USB_PTPREQUEST_RESET 0x66 /* Reset Device */ +#define USB_PTPREQUEST_GETSTATUS 0x67 /* Get Device Status */ + +#define USB_PTPCANCELIO_ID 0x4001 +#define USB_PTPREQUEST_CANCELIO_SIZE 6 + +#define MAX_PTP_STRING_CHARS 255 +#define MAX_PTP_TIME_STRING_CHARS 20 /* eg: 20050526T171236 */ + +/* + * Enumerated type that defines the data witin the PTP array. + * Defines four types to be used with the PTP array. The types include + * unsigned 8-bit, unsigned 16-bit, unsigned 32-bit, and pointers. + */ +typedef enum { + UINT8_TYPE, + UINT16_TYPE, + UINT32_TYPE, + PTR_TYPE, + UINT128_TYPE +} data_type_t; + +/* + * brief A PTP array structure. + * The PTP array structure contains a variable length of data defined by the + * type field. + */ +typedef struct { + data_type_t type; + mtp_uint32 arr_size; + mtp_uint32 num_ele; + void *array_entry; +} ptp_array_t; + +typedef struct { + mtp_word year; + mtp_word month; + mtp_word day_of_week; + mtp_word day; + mtp_word hour; + mtp_word minute; + mtp_word second; + mtp_word millisecond; +} system_time_t; + +/* + * brief The PTP string structure. + * The PTP string structure contains a Unicode string (16-bit) that is limited + * to MAX_PTP_STRING_CHARS in length. The default string length is defined as + * 255 including the NUL terminating character. + */ +typedef struct { + /* Num of chars in string including the NUL */ + mtp_uchar num_chars; + /* Holds actual Unicode string with 2 bytes chars,'\0' terminated*/ + mtp_wchar str[MAX_PTP_STRING_CHARS]; +} ptp_string_t; + +typedef struct { + /* Num of chars in string including the NUL */ + mtp_uchar num_chars; + /* Holds actual Unicode string with 2 bytes chars,'\0' terminated*/ + mtp_wchar str[MAX_PTP_TIME_STRING_CHARS]; +} ptp_time_string_t; + +#endif /* _PTP_DATACODES_H_ */ diff --git a/include/transport/mtp_transport.h b/include/transport/mtp_transport.h new file mode 100755 index 0000000..e0138c1 --- /dev/null +++ b/include/transport/mtp_transport.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_TRANSPORT_H_ +#define _MTP_TRANSPORT_H_ + +#include "mtp_datatype.h" +#include "mtp_util.h" + +/* + * This structure specifies the status information of Mtp. + */ +typedef struct { + mtp_int32 ctrl_event_code; + mtp_state_t mtp_op_state; + mtp_bool cancel_intialization; + mtp_bool is_usb_discon; +} status_info_t; + +typedef void (*_cmd_handler_cb)(mtp_char *buf, mtp_int32 pkt_len); + +void _transport_save_cmd_buffer(mtp_char *buffer, mtp_uint32 size); +mtp_err_t _transport_rcv_temp_file_data(mtp_byte *buffer, mtp_uint32 size, + mtp_uint32 *count); +mtp_err_t _transport_rcv_temp_file_info(mtp_byte *buf, char *filepath, + mtp_uint64 *t_size, mtp_uint32 filepath_len); +mtp_err_t _transport_send_event(mtp_byte *buf, mtp_uint32 size, mtp_uint32 *count); +mtp_uint32 _transport_send_pkt_to_tx_mq(const mtp_byte *buf, mtp_uint32 pkt_len); +mtp_uint32 _transport_send_bulk_pkt_to_tx_mq(const mtp_byte *buf, + mtp_uint32 pkt_len); +void _transport_send_zlp(void); +mtp_bool _transport_init_interfaces(_cmd_handler_cb func); +void _transport_usb_finalize(void); +void _transport_init_status_info(void); +mtp_int32 _transport_get_control_event(void); +void _transport_set_control_event(mtp_int32 event_code); +mtp_state_t _transport_get_mtp_operation_state(void); +void _transport_set_mtp_operation_state(mtp_state_t state); +void _transport_set_usb_discon_state(mtp_bool is_usb_discon); +mtp_bool _transport_get_usb_discon_state(void); +void _transport_set_cancel_initialization(mtp_bool value); +mtp_bool _transport_get_cancel_initialization(void); + +#endif /* _MTP_TRANSPORT_H_ */ diff --git a/include/transport/mtp_usb_driver.h b/include/transport/mtp_usb_driver.h new file mode 100755 index 0000000..cc63874 --- /dev/null +++ b/include/transport/mtp_usb_driver.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_USB_DRIVER_H_ +#define _MTP_USB_DRIVER_H_ + +#include "mtp_datatype.h" +#include "mtp_msgq.h" + +/* Start of driver related defines */ +#define MTP_DRIVER_PATH "/dev/usb_mtp_gadget" + +/* These values come from f_mtp_slp.h of kernel source */ +#define MTP_IOCTL_LETTER 'Z' +#define MTP_GET_HIGH_FULL_SPEED _IOR(MTP_IOCTL_LETTER, 1, int) +#define MTP_DISABLE _IO(MTP_IOCTL_LETTER, 2) +#define MTP_CLEAR_HALT _IO(MTP_IOCTL_LETTER, 3) +#define MTP_WRITE_INT_DATA _IOW(MTP_IOCTL_LETTER, 4, char *) +#define MTP_SET_USER_PID _IOW(MTP_IOCTL_LETTER, 5, int) +#define MTP_GET_SETUP_DATA _IOR(MTP_IOCTL_LETTER, 6, char *) +#define MTP_SET_SETUP_DATA _IOW(MTP_IOCTL_LETTER, 7, char *) +#define MTP_SEND_RESET_ACK _IO(MTP_IOCTL_LETTER, 8) +#define MTP_SET_ZLP_DATA _IO(MTP_IOCTL_LETTER, 9) +#define MTP_GET_MAX_PKT_SIZE _IOR(MTP_IOCTL_LETTER, 22, void *) + +#define SIG_SETUP 44 +/* End of driver related defines */ + +typedef struct mtp_max_pkt_size { + mtp_uint32 tx; + mtp_uint32 rx; +} mtp_max_pkt_size_t; + +/* Maximum repeat count for USB error recovery */ +#define MTP_USB_ERROR_MAX_RETRY 5 + +mtp_bool _transport_init_usb_device(void); +void _transport_deinit_usb_device(void); +void *_transport_thread_usb_write(void *arg); +void *_transport_thread_usb_read(void *arg); +mtp_int32 _transport_mq_init(msgq_id_t *rx_mqid, msgq_id_t *tx_mqid); +mtp_bool _transport_mq_deinit(msgq_id_t *rx_mqid, msgq_id_t *tx_mqid); +mtp_uint32 _transport_get_usb_packet_len(void); +mtp_uint32 _get_tx_pkt_size(void); +mtp_uint32 _get_rx_pkt_size(void); + +#endif /* _MTP_USB_DRIVER_H_ */ diff --git a/include/util/mtp_fs.h b/include/util/mtp_fs.h new file mode 100755 index 0000000..3a88e55 --- /dev/null +++ b/include/util/mtp_fs.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_FS_H_ +#define _MTP_FS_H_ + +#include <dirent.h> +#include "mtp_datatype.h" +#include "mtp_config.h" + +#define LINUX_MAX_PATHNAME_LENGTH 4096 +#define MTP_FILE_ATTR_INVALID 0xFFFFFFFF +#define MTP_LOG_FILE "/var/log/mtp.log" +#define MTP_LOG_MAX_SIZE 5 * 1024 * 1024 /*5MB*/ + +typedef enum { + MTP_FILE_TYPE = 0, + MTP_DIR_TYPE, + MTP_ALL_TYPE +} file_type_t; + +typedef enum { + MTP_FILE_ATTR_MODE_NONE = 0x00000000, + MTP_FILE_ATTR_MODE_REG = 0x00000100, + MTP_FILE_ATTR_MODE_DIR = 0x00000200, + MTP_FILE_ATTR_MODE_READ_ONLY = 0x00000400, + MTP_FILE_ATTR_MODE_HIDDEN = 0x00000800, + MTP_FILE_ATTR_MODE_SYSTEM = 0x00001000 +} file_attr_mode_t; + +typedef struct { + file_attr_mode_t attribute; + mtp_uint64 fsize; + time_t ctime; /* created time */ + time_t mtime; /* modified time */ +} file_attr_t; + +typedef struct { + mtp_char filename[MTP_MAX_PATHNAME_SIZE + 1]; + file_type_t type; + file_attr_t attrs; +} dir_entry_t; + +typedef enum { + MTP_FILE_READ = 0x1, + MTP_FILE_WRITE = 0x2, + MTP_FILE_APPEND = 0x4, + MTP_FILE_TRUNCATE = 0x8 +} file_mode_t; + +typedef struct { + mtp_uint64 disk_size; + mtp_uint64 avail_size; + mtp_uint64 reserved_size; +} fs_info_t; + +mtp_uint32 _util_file_open(const mtp_char *filename, file_mode_t mode, + mtp_int32 *error); +void _util_file_read(mtp_uint32 fhandle, void *bufptr, mtp_uint32 size, + mtp_uint32 *read_count); +mtp_uint32 _util_file_write(mtp_uint32 fhandle, void *bufptr, mtp_uint32 size); +mtp_int32 _util_file_close(mtp_uint32 fhandle); +mtp_bool _util_file_seek(mtp_uint32 fhandle, off_t offset, mtp_int32 whence); +mtp_bool _util_file_copy(const mtp_char *origpath, const mtp_char *newpath, + mtp_int32 *error); +mtp_bool _util_copy_dir_children_recursive(const mtp_char *origpath, + const mtp_char *newpath, mtp_int32 *error); +mtp_bool _util_file_move(const mtp_char *origpath, const mtp_char *newpath, + mtp_int32 *error); +mtp_bool _util_get_file_attrs(const mtp_char *filename, file_attr_t *attrs); +mtp_bool _util_set_file_attrs(const mtp_char *filename, mtp_dword attrs); +mtp_bool _util_dir_create(const mtp_char *dirname, mtp_int32 *error); +mtp_int32 _util_remove_dir_children_recursive(const mtp_char *dirname, + mtp_uint32 *num_of_deleted_file, mtp_uint32 *num_of_file, mtp_bool readonly); +mtp_bool _util_ifind_next(char *dir_name, DIR *dirp, dir_entry_t *dir_info); +mtp_bool _util_ifind_first(char *dir_name, DIR **dirp, dir_entry_t *dir_info); +mtp_bool _util_is_file_opened(const mtp_char *fullpath); +mtp_bool _util_get_filesystem_info(mtp_char *storepath, fs_info_t *fs_info); +void _util_count_num_lines(mtp_uint32 fhandle, mtp_uint32 *num_lines); +void _util_fill_guid_array(void *guidarray, mtp_uint32 start_index, mtp_uint32 fhandle, + mtp_uint32 size); +void FLOGD(const char *fmt, ...); + +#endif /* _MTP_FS_H_ */ diff --git a/include/util/mtp_list.h b/include/util/mtp_list.h new file mode 100755 index 0000000..2c50729 --- /dev/null +++ b/include/util/mtp_list.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_LIST_H_ +#define _MTP_LIST_H_ + +#include "mtp_datatype.h" +#include "mtp_util.h" + +typedef struct _slist_node { + void *value; + struct _slist_node *link; +} slist_node_t; + +typedef struct { + slist_node_t *start; + slist_node_t *end; + mtp_uint32 nnodes; +} slist_t; + +typedef struct { + slist_node_t *node_ptr; +} slist_iterator; + +void _util_init_list(slist_t *l_ptr); +mtp_bool _util_add_node(slist_t *l_ptr, void *data); +slist_node_t *_util_delete_node(slist_t *l_ptr, void *data); +slist_iterator *_util_init_list_iterator(slist_t *l_ptr); +void *_util_get_list_next(slist_iterator *iter); +slist_node_t *_util_get_first_node(slist_t *l_ptr); +void _util_deinit_list_iterator(slist_iterator *iter); + +#endif /* _MTP_LIST_H_ */ diff --git a/include/util/mtp_media_info.h b/include/util/mtp_media_info.h new file mode 100755 index 0000000..553562e --- /dev/null +++ b/include/util/mtp_media_info.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_MEDIA_INFO_H_ +#define _MTP_MEDIA_INFO_H_ + +#include <glib.h> +#include <media_content.h> +#include "mtp_config.h" +#include "mtp_datatype.h" + +#define MEDIA_PATH_COND "MEDIA_PATH=" +#define MEDIA_PATH_COND_LEN 13 /* MEDIA_PATH="" */ +#define MEDIA_PATH_COND_OR " OR " +#define MEDIA_PATH_COND_OR_LEN 4 +#define MEDIA_PATH_COND_MAX_LEN MEDIA_PATH_COND_LEN + MTP_MAX_PATHNAME_SIZE + +#define MTP_PAL_SAFE_FREE(src) { g_free(src); src = NULL; } + +/* + * struct MtpCommonMetadata + * This structure contains common metadata fields between + * video and audio files. + */ +typedef struct { + mtp_char *artist; /* A pointer to Artist */ + mtp_char *album; /* A pointer to Album name. */ + mtp_char *genre; /* A pointer to Genre */ + mtp_char *author; /* A pointer to Author name */ + mtp_char *copyright; /* A pointer to Copyright info */ + mtp_char *year; /* A pointer to release year */ + mtp_char *description; /* A pointer to description */ + mtp_int32 duration; /* Duration of the track */ + mtp_int32 audio_bitrate; /* Audio bitrate */ + mtp_int32 sample_rate; + mtp_int32 num_channel; + mtp_int32 audio_codec; + mtp_int32 rating; +} common_meta_t; + +typedef struct { + mtp_int32 video_fps; + mtp_int32 video_br; + mtp_int32 video_h; + mtp_int32 video_w; + mtp_char *track; +} video_meta_t; + +typedef struct { + mtp_int32 track; +} audio_meta_t; + +typedef struct { + mtp_int32 ht; + mtp_int32 wt; +} image_meta_t; + +typedef struct { + common_meta_t commonmeta; + audio_meta_t audiometa; +} comp_audio_meta_t; + +typedef struct { + common_meta_t commonmeta; + video_meta_t videometa; +} comp_video_meta_t; + +typedef struct { + void *data; + mtp_int32 count; + guint tid; + pthread_mutex_t *lock; +} timeout_data_t; + +mtp_bool _util_get_audio_metadata(const mtp_char *filepath, + comp_audio_meta_t *audio_data); +mtp_bool _util_get_video_metadata(mtp_char *filepath, + comp_video_meta_t *video_data); +mtp_bool _util_get_image_ht_wt(const mtp_char *filepath, image_meta_t *image_data); +mtp_bool _util_get_audio_meta_from_extractor(const mtp_char *filepath, + comp_audio_meta_t *audio_data); +mtp_bool _util_get_video_meta_from_extractor(const mtp_char *filepath, + comp_video_meta_t *video_data); +void _util_flush_db(void); +void _util_delete_file_from_db(const mtp_char *filepath); +void _util_add_file_to_db(const mtp_char *filepath); +void _util_scan_folder_contents_in_db(const mtp_char *filepath); +void _util_free_common_meta(common_meta_t *metadata); +void _util_free_video_meta(video_meta_t *video); +void _util_free_image_meta(image_meta_t *image); + +#endif /* _MTP_MEDIA_INFO_H_ */ diff --git a/include/util/mtp_msgq.h b/include/util/mtp_msgq.h new file mode 100755 index 0000000..c6726c2 --- /dev/null +++ b/include/util/mtp_msgq.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_MSGQ_H_ +#define _MTP_MSGQ_H_ + +#include "mtp_datatype.h" +#include "mtp_util.h" + +typedef mtp_int32 msgq_id_t; + +typedef struct { + msg_type_t mtype; + mtp_uint32 length; + mtp_uint32 signal; + unsigned char *buffer; +} msgq_ptr_t; + +mtp_bool _util_msgq_init(msgq_id_t *mq_id, mtp_uint32 flags); +mtp_bool _util_msgq_send(msgq_id_t mq_id, void *buf, mtp_uint32 size, + mtp_uint32 flags); +mtp_bool _util_msgq_receive(msgq_id_t mq_id, void *buf, mtp_uint32 size, + mtp_uint32 flags, mtp_int32 *nbytes); +mtp_bool _util_msgq_deinit(msgq_id_t *msgq_id); +mtp_bool _util_msgq_set_size(msgq_id_t mq_id, mtp_uint32 nbytes); +mtp_bool _util_rcv_msg_from_mq(msgq_id_t mq_id, unsigned char **pkt, + mtp_uint32 *pkt_len, msg_type_t *mtype); + +#endif/*_MTP_MSGQ_H_*/ diff --git a/include/util/mtp_support.h b/include/util/mtp_support.h new file mode 100755 index 0000000..b0cc9c4 --- /dev/null +++ b/include/util/mtp_support.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_SUPPORT_H_ +#define _MTP_SUPPORT_H_ + +#include "mtp_datatype.h" +#include "mtp_config.h" + +typedef struct { + mtp_char *extn; + mtp_uint16 fmt_code; +} fmt_code_t; + +/* + * Convert byte order for big endian architecture + */ +void _util_conv_byte_order(void *data, mtp_int32 size); + +/* + * Convert byte order for WCHAR string + */ +void _util_conv_byte_order_wstring(mtp_uint16 *wstr, mtp_int32 size); +void _util_conv_byte_order_gen_str(void *str, mtp_int32 size, mtp_int32 elem_sz); +void _util_wchar_cpy(mtp_wchar *dest, const mtp_wchar *src); +void _util_wchar_ncpy(mtp_wchar *dest, const mtp_wchar *src, unsigned long n); +size_t _util_wchar_len(const mtp_wchar *s); +mtp_wchar *mtp_wcscat_charstr(mtp_wchar *str1, const mtp_char *char_str); +mtp_err_t _util_wchar_swprintf(mtp_wchar *mtp_wstr, mtp_int32 size, + mtp_char *format, ...); +mtp_int32 _util_utf16_to_utf8(char *dest, mtp_int32 size, const mtp_wchar *src); +mtp_int32 _util_utf8_to_utf16(mtp_wchar *dest, mtp_int32 no_of_item, const char *src); +mtp_uint16 _util_get_fmtcode(const mtp_char *extn); +mtp_bool _util_get_file_extn(const mtp_char *f_name, mtp_char *f_extn); +mtp_bool _util_get_file_name(const mtp_char *fullpath, mtp_char *f_name); +mtp_bool _util_get_file_name_wo_extn(const mtp_char *fullpath, mtp_char *f_name); +mtp_bool _util_is_path_len_valid(const mtp_char *path); +mtp_bool _util_create_path(mtp_char *path, mtp_uint32 size, const mtp_char *dir, + const mtp_char *filename); +void _util_get_parent_path(const mtp_char *fullpath, mtp_char *p_path); +void _util_conv_wstr_to_guid(mtp_wchar *wstr, mtp_uint64 *guid); +mtp_bool _util_get_unique_dir_path(const mtp_char *exist_path, mtp_char *new_path, + mtp_uint32 new_path_buf_len); + +#endif /* _MTP_SUPPORT_H_ */ diff --git a/include/util/mtp_thread.h b/include/util/mtp_thread.h new file mode 100755 index 0000000..41c4cfe --- /dev/null +++ b/include/util/mtp_thread.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_THREAD_H_ +#define _MTP_THREAD_H_ + +#include <pthread.h> +#include "mtp_datatype.h" +#include "mtp_util.h" + +typedef void *(*thread_func_t) (void *pArg); + +#define UTIL_LOCK_MUTEX(mut)\ + do {\ + int lock_ret = 0;\ + DBG("Thread [%d] trying to lock the Mutex \n", syscall(__NR_gettid));\ + lock_ret = pthread_mutex_lock(mut);\ + if(lock_ret != 0) {\ + if(lock_ret == EDEADLK) {\ + DBG("Mutex is already locked by the same thread");\ + } else {\ + ERR("Error locking mutex. Error = %d \n", lock_ret);\ + }\ + } else {\ + DBG("Mutex locked by thread [%d] \n", syscall(__NR_gettid));\ + }\ + } while (0);\ + + +#define UTIL_UNLOCK_MUTEX(mut)\ + do {\ + int unlock_ret = 0;\ + unlock_ret = pthread_mutex_unlock(mut);\ + if (unlock_ret != 0) {\ + ERR("Error unlocking mutex. Error = %d \n", unlock_ret);\ + } else {\ + DBG("Mutex unlocked by thread [%d] \n", syscall(__NR_gettid));\ + }\ + } while (0);\ + +mtp_bool _util_thread_create(pthread_t *tid, const mtp_char *tname, + mtp_int32 thread_state, thread_func_t thread_func, void *arg); +mtp_bool _util_thread_join(pthread_t tid, void **data); +mtp_bool _util_thread_cancel(pthread_t tid); +void _util_thread_exit(void *val_ptr); + +#endif /*_MTP_THREAD_H_*/ diff --git a/include/util/mtp_util.h b/include/util/mtp_util.h new file mode 100755 index 0000000..22a39fb --- /dev/null +++ b/include/util/mtp_util.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MTP_UTIL_H_ +#define _MTP_UTIL_H_ + +#include <errno.h> +#include "mtp_config.h" +#include "mtp_datatype.h" + +#ifndef LOG_TAG +#define LOG_TAG "MTP-RESPONDER" +#endif /* LOG_TAG */ +#include <dlog.h> + +#define FIND_CMD_LEN 300 +#define FIND_CMD "/usr/bin/find %s \\( -iname '*.jpg' -o -iname '*.gif' " \ + "-o -iname '*.exif' -o -iname '*.png' " \ + "-o -iname '*.mpeg' -o -iname '*.asf' " \ + "-o -iname '*.wmv' -o -iname '*.avi' -o -iname '*.wma' " \ + "-o -iname '*.mp3' \\) -mmin -%d >> %s" + +#define VCONFKEY_MTP_PREFIX "db/private/mtp" +#define VCONFKEY_MTP_SERIAL_NUMBER_STR VCONFKEY_MTP_PREFIX"/serial_number" +#define VCONFKEY_MTP_SYNC_PARTNER_STR VCONFKEY_MTP_PREFIX"/sync_partner" +#define VCONFKEY_MTP_SYNC_TIME_INT VCONFKEY_MTP_PREFIX"/sync_time" + +#define DBG(format, args...) SLOGD(format, ##args) +#define ERR(format, args...) SLOGE(format, ##args) +#define DBG_SECURE(format, args...) SECURE_SLOGD(format, ##args) +#define ERR_SECURE(format, args...) SECURE_SLOGE(format, ##args) + +#define ret_if(expr) \ + do { \ + if (expr) { \ + ERR("(%s)", #expr); \ + return; \ + } \ + } while (0) + +#define retv_if(expr, val) \ + do { \ + if (expr) { \ + ERR("(%s)", #expr); \ + return (val); \ + } \ + } while (0) + +#define retm_if(expr, fmt, arg...) \ + do { \ + if (expr) { \ + ERR(fmt, ##arg); \ + return; \ + } \ + } while (0) + +#define retvm_if(expr, val, fmt, arg...) \ + do { \ + if (expr) { \ + ERR(fmt, ##arg); \ + return (val); \ + } \ + } while (0) + +typedef enum { + MTP_PHONE_USB_CONNECTED = 0, + MTP_PHONE_USB_DISCONNECTED, + MTP_PHONE_MMC_INSERTED, + MTP_PHONE_MMC_NONE, + MTP_PHONE_USB_MODE_OTHER, +} phone_status_t; + +typedef struct { + phone_status_t mmc_state; + phone_status_t usb_state; + phone_status_t usb_mode_state; + phone_status_t lock_state; +} phone_state_t; + +typedef enum { + MTP_DATA_PACKET = 1, + MTP_BULK_PACKET, + MTP_EVENT_PACKET, + MTP_ZLP_PACKET, + MTP_UNDEFINED_PACKET +} msg_type_t; + +typedef enum { + MTP_STATE_STOPPED = 0, /* stopped working */ + MTP_STATE_INITIALIZING, /* initializing device or enumerating*/ + MTP_STATE_READY_SERVICE, /* ready to handle commands */ + MTP_STATE_ONSERVICE, /* handling a command */ + MTP_STATE_DATA_TRANSFER_DL, /* file downloading */ + MTP_STATE_DATA_PROCESSING /* data processing */ +} mtp_state_t; + +/* + * PTP Cancellation Request + * mtp_uint16 io_code : Identifier for cancellation. + * This must equal USB_PTPCANCELIO_ID. + * mtp_uint32 tid : Transaction to cancel. + */ +typedef struct { + mtp_uint16 io_code; + mtp_uint32 tid; +} cancel_req_t; + +/* + * PTP Status Request + * mtp_uint16 len : Total length of the status data. + * mtp_uint16 code : Response code + * mtp_uint32 params : Params depends on the status code. + */ +typedef struct { + mtp_uint16 len; + mtp_uint16 code; + mtp_uint32 params[1]; +} usb_status_req_t; + +void _util_print_error(); +mtp_int32 _util_get_battery_level(void); +mtp_bool _util_get_serial(mtp_char *serial, mtp_uint32 len); +void _util_get_model_name(mtp_char *model_name, mtp_uint32 len); +void _util_get_vendor_ext_desc(mtp_char *vendor_ext_desc, mtp_uint32 len); +void _util_get_device_version(mtp_char *device_version, mtp_uint32 len); +void _util_gen_alt_serial(mtp_char *serial, mtp_uint32 len); +void _util_get_usb_status(phone_status_t *val); +phone_status_t _util_get_local_usb_status(void); +void _util_set_local_usb_status(const phone_status_t val); +void _util_get_mmc_status(phone_status_t *val); +phone_status_t _util_get_local_mmc_status(void); +void _util_set_local_mmc_status(const phone_status_t val); +void _util_get_usbmode_status(phone_status_t *val); +phone_status_t _util_get_local_usbmode_status(void); +void _util_set_local_usbmode_status(const phone_status_t val); + +#endif /* _MTP_UTIL_H_ */ diff --git a/mtp-responder.conf b/mtp-responder.conf new file mode 100755 index 0000000..a31d87c --- /dev/null +++ b/mtp-responder.conf @@ -0,0 +1,61 @@ +### MTP features +#Nothing yet +### MTP features (End) + + +### Debug +# +# You can fix destination or source file path for SendObject or GetObject MTP commands when fake_copy is 1. +# Default is 0(Not use). +fake_copy=0 +# If you want to read data from USB without writing to file system, specify "write_to=null". +# Available value : null or /dev/null +write_to=null +# If you want to write arbitrary data to USB without reading from file system, specify "read_from=null". +# Available value : null or /dev/zero +read_from=null +### Debug (End) + + +### Speed related config +# +# Max. 512KB. If requested memory is lesser than this, malloc is used. Otherwise, mmap is used +mmap_threshold=524288 + +read_usb_size=4096 +write_usb_size=4096 + +# Init. IPC size between USB and File threads (< mmap_threshold and =< max_ipc_size) +init_rx_ipc_size=32768 +init_tx_ipc_size=262144 + +# Max. IPC size between USB and File threads (< mmap_threshold) +max_rx_ipc_size=32768 +max_tx_ipc_size=262144 + +# Max. Heap memory size for buffer between USb and File threads +max_io_buf_size=10485760 + +read_file_delay=0 + +### Experimental +# +# I/O thread priority handling +#support_pthread_sched=0 + +# i : Inherit, e : Explicit +#inheritsched=i + +# f : FIFO, r : Round Robin, o : Other +#schedpolicy=o + +# File I/O thread's priority for scheduling +#file_schedparam=0 + +# USB I/O thread's priority for scheduling +#usb_schedparam=0 +# I/O thread priority handling (End) + +# +### Experimental (End) +### Speed related config (End) diff --git a/mtp-responder.service b/mtp-responder.service new file mode 100755 index 0000000..223075d --- /dev/null +++ b/mtp-responder.service @@ -0,0 +1,10 @@ +[Unit] +Description=MTP responder + +[Service] +User=system +Group=system +SmackProcessLabel=mtp-responder +Type=simple +ExecStart=/usr/bin/mtp-responder +KillMode=process diff --git a/packaging/mtp-responder.manifest b/packaging/mtp-responder.manifest new file mode 100755 index 0000000..8d20faf --- /dev/null +++ b/packaging/mtp-responder.manifest @@ -0,0 +1,27 @@ +<manifest> + <define> + <domain name="mtp-responder"/> + <request> + <smack request="media-server" type="rwx"/> + <smack request="sound-server" type="rwx"/> + <smack request="device::mtp" type="rw"/> + <smack request="device::sys_logging" type="w"/> + <smack request="device::app_logging" type="w"/> + <smack request="system::media" type="rwxat"/> + <smack request="system::homedir" type="rwxat"/> + <smack request="system::share" type="rwxat"/> + <smack request="system::ext_storage" type="rl"/> + <smack request="tizen::vconf::public::r" type="rl"/> + <smack request="tizen::vconf::platform::rw" type="rw"/> + <smack request="tizen::vconf::public::r::platform::rw" type="rl"/> + <smack request="tizen::vconf::setting::admin" type="rl"/> + <smack request="telephony_framework::api_modem" type="rl"/> + </request> + <permit> + <smack permit="media-server" type="rw"/> + </permit> + </define> + <assign> + <filesystem path="/usr/bin/mtp-responder" exec_label="none"/> + </assign> +</manifest> diff --git a/packaging/mtp-responder.spec b/packaging/mtp-responder.spec new file mode 100755 index 0000000..0f62d7e --- /dev/null +++ b/packaging/mtp-responder.spec @@ -0,0 +1,61 @@ +ExclusiveArch: %arm aarch64 +%if "%{?tizen_profile_name}" == "tv" +ExcludeArch: %arm aarch64 +%endif + +Name: mtp-responder +Summary: Media Transfer Protocol daemon (responder) +Version: 0.0.2 +Release: 1 +Group: Network & Connectivity/Other +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz +Source1001: %{name}.manifest +BuildRequires: cmake +BuildRequires: libgcrypt-devel +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(vconf) +BuildRequires: pkgconfig(tapi) +BuildRequires: pkgconfig(libprivilege-control) +BuildRequires: pkgconfig(capi-content-media-content) +BuildRequires: pkgconfig(capi-media-metadata-extractor) +BuildRequires: pkgconfig(capi-system-info) +Requires(post): /usr/bin/vconftool + + +%description +This package includes a daemon which processes Media Transper Protocol(MTP) commands as MTP responder role. + + +%prep +%setup -q +cp %{SOURCE1001} . + + +%build +%cmake . + +make %{?jobs:-j%jobs} + + +%install +%make_install + +install -D -m 0644 mtp-responder.service %{buildroot}%{_libdir}/systemd/system/mtp-responder.service + +%post +/usr/bin/vconftool set -t string db/private/mtp/serial_number "" -u 5000 -g 5000 -i -f -s tizen::vconf::platform::rw +/usr/bin/vconftool set -t string db/private/mtp/sync_partner "" -u 5000 -g 5000 -i -f -s tizen::vconf::platform::rw +/usr/bin/vconftool set -t int db/private/mtp/sync_time 0 -u 5000 -g 5000 -i -f -s tizen::vconf::platform::rw + +mkdir -p %{_sysconfdir}/systemd/default-extra-dependencies/ignore-units.d/ +ln -sf %{_libdir}/systemd/system/mtp-responder.service %{_sysconfdir}/systemd/default-extra-dependencies/ignore-units.d/ + +%files +%manifest mtp-responder.manifest +%defattr(-,system,system,-) +%{_bindir}/mtp-responder +%{_libdir}/systemd/system/mtp-responder.service +/opt/var/lib/misc/mtp-responder.conf +#%license LICENSE.APLv2 diff --git a/src/entity/mtp_device.c b/src/entity/mtp_device.c new file mode 100755 index 0000000..dad5fcb --- /dev/null +++ b/src/entity/mtp_device.c @@ -0,0 +1,1107 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <unistd.h> +#include <glib.h> +#include "mtp_support.h" +#include "mtp_util.h" +#include "ptp_datacodes.h" +#include "mtp_device.h" +#include "mtp_transport.h" +#include "ptp_container.h" + +#define MTP_DEVICE_VERSION_CHAR "V1.0" + +/* + * GLOBAL AND EXTERN VARIABLES + */ +static mtp_device_t g_device = { 0 }; + +/* + * STATIC VARIABLES + */ +static device_prop_desc_t g_device_props[NUM_DEVICE_PROPERTIES]; +static mtp_store_t g_store_list[MAX_NUM_DEVICE_STORES]; +static mtp_uint16 g_device_props_supported[NUM_DEVICE_PROPERTIES]; + +static mtp_uint16 g_ops_supported[] = { + PTP_OPCODE_GETDEVICEINFO, + PTP_OPCODE_OPENSESSION, + PTP_OPCODE_CLOSESESSION, + PTP_OPCODE_GETSTORAGEIDS, + PTP_OPCODE_GETSTORAGEINFO, + PTP_OPCODE_GETNUMOBJECTS, + PTP_OPCODE_GETOBJECTHANDLES, + PTP_OPCODE_GETOBJECTINFO, + PTP_OPCODE_GETOBJECT, + PTP_OPCODE_DELETEOBJECT, + PTP_OPCODE_SENDOBJECTINFO, + PTP_OPCODE_SENDOBJECT, + PTP_OPCODE_FORMATSTORE, + PTP_OPCODE_GETDEVICEPROPDESC, + PTP_OPCODE_GETDEVICEPROPVALUE, + PTP_OPCODE_SETDEVICEPROPVALUE, + PTP_OPCODE_GETPARTIALOBJECT, + MTP_OPCODE_GETOBJECTREFERENCES, + MTP_OPCODE_SETOBJECTREFERENCES, + MTP_OPCODE_GETOBJECTPROPDESC, + MTP_OPCODE_GETOBJECTPROPSUPPORTED, + MTP_OPCODE_GETOBJECTPROPVALUE, + MTP_OPCODE_SETOBJECTPROPVALUE, + MTP_OPCODE_GETOBJECTPROPLIST, + MTP_OPCODE_SETOBJECTPROPLIST, +#ifndef PMP_VER + /*PTP_OPCODE_RESETDEVICE,*/ + PTP_OPCODE_SELFTEST, +#ifdef MTP_SUPPORT_SET_PROTECTION + PTP_OPCODE_SETOBJECTPROTECTION, +#endif /* MTP_SUPPORT_SET_PROTECTION */ + /*PTP_OPCODE_POWERDOWN,*/ + PTP_OPCODE_RESETDEVICEPROPVALUE, + PTP_OPCODE_MOVEOBJECT, + PTP_OPCODE_COPYOBJECT, +#ifdef MTP_SUPPORT_INTERDEPENDENTPROP + MTP_OPCODE_GETINTERDEPPROPDESC, +#endif /*MTP_SUPPORT_INTERDEPENDENTPROP*/ + MTP_OPCODE_SENDOBJECTPROPLIST, + /*PTP_CODE_VENDOR_OP1,*/ +#endif /*PMP_VER*/ + MTP_OPCODE_WMP_REPORTACQUIREDCONTENT, +}; + +static mtp_uint16 g_event_supported[] = { + /*PTP_EVENTCODE_CANCELTRANSACTION,*/ + PTP_EVENTCODE_OBJECTADDED, + PTP_EVENTCODE_OBJECTREMOVED, + PTP_EVENTCODE_STOREADDED, + PTP_EVENTCODE_STOREREMOVED, + /* PTP_EVENTCODE_DEVICEPROPCHANGED, + PTP_EVENTCODE_OBJECTINFOCHANGED, + PTP_EVENTCODE_DEVICEINFOCHANGED, + PTP_EVENTCODE_REQUESTOBJECTTRANSFER, + PTP_EVENTCODE_STOREFULL, + PTP_EVENTCODE_DEVICERESET, + PTP_EVENTCODE_STORAGEINFOCHANGED, + PTP_EVENTCODE_CAPTURECOMPLETE, + PTP_EVENTCODE_UNREPORTEDSTATUS, + PTP_EVENTCODE_VENDOREXTENTION1, + PTP_EVENTCODE_VENDOREXTENTION2 */ +}; + +static mtp_uint16 g_capture_fmts[] = { + /* PTP_FORMATCODE_IMAGE_EXIF */ + 0 +}; + +static mtp_uint16 g_object_fmts[] = { + MTP_FMT_3GP, + MTP_FMT_MP4, + PTP_FMT_MP3, + MTP_FMT_WMA, + MTP_FMT_WMV, + PTP_FMT_IMG_EXIF, + PTP_FMT_ASSOCIATION, + MTP_FMT_FLAC, + PTP_FMT_UNDEF, +#ifndef PMP_VER + PTP_FMT_IMG_GIF, + PTP_FMT_IMG_BMP, + /* PTP_FORMATCODE_IMAGE_JFIF, */ + PTP_FMT_IMG_PNG, + PTP_FMT_WAVE, + PTP_FMT_AVI, + PTP_FMT_MPEG, + PTP_FMT_ASF, + /* MTP_FORMATCODE_WINDOWS_IMAGE_FORMAT, + MTP_FORMATCODE_UNDEFINED_AUDIO, + MTP_FORMATCODE_UNDEFINED_VIDEO, + MTP_FORMATCODE_UNDEFINED_COLLECTION, + MTP_FORMATCODE_ABSTRACT_MULTIMEDIA_ALBUM, + MTP_FORMATCODE_ABSTRACT_IMAGE_ALBUM, + MTP_FORMATCODE_ABSTRACT_VIDEO_ALBUM, + MTP_FORMATCODE_ABSTRACT_CONTACT_GROUP, + MTP_FORMATCODE_UNDEFINED_DOCUMENT, + MTP_FORMATCODE_ABSTRACT_DOCUMENT, + MTP_FORMATCODE_UNDEFINED_MESSAGE, + MTP_FORMATCODE_ABSTRACT_MESSAGE, + MTP_FORMATCODE_UNDEFINED_CALENDAR_ITEM, + MTP_FORMATCODE_ABSTRACT_CALENDAR_ITEM, + MTP_FORMATCODE_VCALENDAR1, + MTP_FORMATCODE_UNDEFINED_WINDOWS_EXECUTABLE,*/ +#endif /*PMP_VER*/ + MTP_FMT_ABSTRACT_AUDIO_ALBUM, + /* MTP_FORMATCODE_UNDEFINED_FIRMWARE */ +}; + +/* + * STATIC FUNCTIONS + */ +static void __init_device_info(void); +static mtp_bool __init_device_props(void); +static mtp_err_t __clear_store_data(mtp_uint32 store_id); +static mtp_bool __remove_store_from_device(store_type_t store_type); +static mtp_bool __add_store_to_device(store_type_t store_type); + +/* + * FUNCTIONS + */ + +/* + * static void __device_init_device_info() + * This function initializes MTP device information + *@return none + */ +static void __init_device_info(void) +{ + mtp_int32 ii; + device_info_t *info = &(g_device.device_info); + mtp_char model_name[MTP_MODEL_NAME_LEN_MAX + 1] = { 0 }; + mtp_char device_version[MAX_PTP_STRING_CHARS + 1] = { 0 }; + mtp_char vendor_ext_desc[MAX_PTP_STRING_CHARS + 1] = { 0 }; + mtp_char serial_no[MTP_SERIAL_LEN_MAX + 1] = { 0 }; + mtp_wchar wtemp[MAX_PTP_STRING_CHARS + 1] = { 0 }; + + info->ops_supported = g_ops_supported; + info->events_supported = g_event_supported; + info->capture_fmts = g_capture_fmts; + info->object_fmts = g_object_fmts; + info->device_prop_supported = g_device_props_supported; + info->std_version = MTP_STANDARD_VERSION; + info->vendor_extn_id = MTP_VENDOR_EXTN_ID; + info->vendor_extn_version = MTP_VENDOR_EXTN_VERSION; + info->functional_mode = PTP_FUNCTIONMODE_SLEEP; + + _prop_init_ptpstring(&(info->vendor_extn_desc)); + _util_get_vendor_ext_desc(vendor_ext_desc, sizeof(vendor_ext_desc)); + _util_utf8_to_utf16(wtemp, sizeof(wtemp) / WCHAR_SIZ, vendor_ext_desc); + _prop_copy_char_to_ptpstring(&(info->vendor_extn_desc), wtemp, WCHAR_TYPE); + + for (ii = 0; ii < NUM_DEVICE_PROPERTIES; ii++) { + info->device_prop_supported[ii] = + g_device.device_prop_list[ii].propinfo.prop_code; + } + + _prop_init_ptpstring(&(info->manufacturer)); + _util_utf8_to_utf16(wtemp, sizeof(wtemp) / WCHAR_SIZ, MTP_MANUFACTURER_CHAR); + _prop_copy_char_to_ptpstring(&(info->manufacturer), wtemp, WCHAR_TYPE); + + _prop_init_ptpstring(&(info->model)); + _util_get_model_name(model_name, sizeof(model_name)); + _util_utf8_to_utf16(wtemp, sizeof(wtemp) / WCHAR_SIZ, model_name); + _prop_copy_char_to_ptpstring(&(info->model), wtemp, WCHAR_TYPE); + + _prop_init_ptpstring(&(info->device_version)); + _util_get_device_version(device_version, sizeof(device_version)); + _util_utf8_to_utf16(wtemp, sizeof(wtemp) / WCHAR_SIZ, device_version); + _prop_copy_char_to_ptpstring(&(info->device_version), wtemp, WCHAR_TYPE); + + _prop_init_ptpstring(&(info->serial_no)); + if (FALSE == _util_get_serial(serial_no, sizeof(serial_no))) { + ERR("_util_get_serial() Fail"); + _util_gen_alt_serial(serial_no, sizeof(serial_no)); + } + _util_utf8_to_utf16(wtemp, sizeof(wtemp) / WCHAR_SIZ, serial_no); + _prop_copy_char_to_ptpstring(&(info->serial_no), wtemp, WCHAR_TYPE); + + return; +} + +/* + * static mtp_bool __device_init_device_props() + * this function will initialise all the properties of the device. + * @return TRUE if success, otherwise FALSE. + */ +static mtp_bool __init_device_props() +{ + static mtp_bool already_init = FALSE; + + device_prop_desc_t *dev_prop = NULL; + mtp_uint16 i = 0; + ptp_string_t tmp = { 0 }; + mtp_uint32 default_val; + + if (TRUE == already_init) { + ERR("Already initialized. just return..."); + return TRUE; + } + + g_device.device_prop_list = g_device_props; +#ifdef MTP_SUPPORT_DEVICEPROP_BATTERYLEVEL + /* + * Battery level from 0 to 100, with step of 10, + * won't change after a reset + */ + dev_prop = &(g_device.device_prop_list[i]); + _prop_init_device_property_desc(dev_prop, PTP_PROPERTYCODE_BATTERYLEVEL, + PTP_DATATYPE_UINT8, PTP_PROPGETSET_GETONLY, RANGE_FORM); + { + mtp_int32 batt_level = 0; + + batt_level = _util_get_battery_level(); + _prop_set_range_integer(&(dev_prop->propinfo), 0, 100, 5); + _prop_set_current_integer(dev_prop, batt_level); + default_val = 100; + _prop_set_default_integer(&(dev_prop->propinfo), + (mtp_uchar *)&default_val); + } + i++; +#endif /*MTP_SUPPORT_DEVICEPROP_BATTERYLEVEL*/ + + /* Synchronization Partner */ + dev_prop = &(g_device.device_prop_list[i]); + _prop_init_device_property_desc(dev_prop, + MTP_PROPERTYCODE_SYNCHRONIZATIONPARTNER, + PTP_DATATYPE_STRING, PTP_PROPGETSET_GETSET, NONE); +#ifdef MTP_USE_INFORMATION_REGISTRY + { + mtp_char *sync_ptr = NULL; + mtp_wchar wtemp[MTP_MAX_REG_STRING + 1] = { 0 }; + mtp_wchar wpartner[MTP_MAX_REG_STRING + 1] = { 0 }; + + sync_ptr = _device_get_sync_partner(); + if (sync_ptr == NULL) { + _util_utf8_to_utf16(wtemp, sizeof(wpartner) / WCHAR_SIZ, + MTP_DEV_PROPERTY_SYNCPARTNER); + } else { + _util_utf8_to_utf16(wtemp, sizeof(wtemp) / WCHAR_SIZ, + sync_ptr); + } + + _util_utf8_to_utf16(wpartner, sizeof(wpartner) / WCHAR_SIZ, + MTP_DEV_PROPERTY_SYNCPARTNER); + _prop_copy_char_to_ptpstring(&tmp, wtemp, WCHAR_TYPE); + _prop_set_current_string(dev_prop, &tmp); + _prop_set_default_string(&(dev_prop->propinfo), wpartner); + g_free(sync_ptr); + } +#else/*MTP_USE_INFORMATION_REGISTRY*/ + { + mtp_wchar wtemp[MTP_MAX_REG_STRING + 1] = { 0 }; + + _util_utf8_to_utf16(wtemp, sizeof(wtemp) / WCHAR_SIZ, + MTP_DEV_PROPERTY_SYNCPARTNER); + _prop_copy_char_to_ptpstring(&tmp, wtemp, WCHAR_TYPE); + _prop_set_current_string(dev_prop, &tmp); + _prop_set_default_string(&(dev_prop->propinfo), wtemp); + } +#endif/*MTP_USE_INFORMATION_REGISTRY*/ + i++; + + /* Device Friendly Name */ + dev_prop = &(g_device.device_prop_list[i]); + _prop_init_device_property_desc(dev_prop, MTP_PROPERTYCODE_DEVICEFRIENDLYNAME, + PTP_DATATYPE_STRING, PTP_PROPGETSET_GETONLY, NONE); +#ifdef MTP_USE_INFORMATION_REGISTRY + { + mtp_char *dev_ptr = NULL; + mtp_wchar wmodel[MTP_MAX_REG_STRING + 1] = { 0 }; + + dev_ptr = _device_get_device_name(); + if (dev_ptr == NULL) { + ERR("_device_get_device_name() Fail"); + _util_utf8_to_utf16(wmodel, sizeof(wmodel) / WCHAR_SIZ, + MTP_DEV_PROPERTY_FRIENDLYNAME); + } else { + _util_utf8_to_utf16(wmodel, sizeof(wmodel) / WCHAR_SIZ, + dev_ptr); + g_free(dev_ptr); + } + _prop_copy_char_to_ptpstring(&tmp, wmodel, WCHAR_TYPE); + _prop_set_current_string(dev_prop, &tmp); + _prop_set_default_string(&(dev_prop->propinfo), wmodel); + } +#else /*MTP_USE_INFORMATION_REGISTRY*/ + { + mtp_wchar wmodel[MTP_MAX_REG_STRING + 1] = { 0 }; + + _util_utf8_to_utf16(wmodel, sizeof(wmodel) / WCHAR_SIZ, + MTP_DEV_PROPERTY_FRIENDLYNAME); + _prop_copy_char_to_ptpstring(&tmp, wmodel, WCHAR_TYPE); + _prop_set_current_string(dev_prop, &tmp); + _prop_set_default_string(&(dev_prop->propinfo), wmodel); + } +#endif /*MTP_USE_INFORMATION_REGISTRY*/ + i++; + + /* supported formats ordered */ + dev_prop = &(g_device.device_prop_list[i]); + _prop_init_device_property_desc(dev_prop, + MTP_PROPERTYCODE_SUPPORTEDFORMATSORDERED, + PTP_DATATYPE_UINT8, PTP_PROPGETSET_GETONLY, NONE); + { + default_val = 1; + _prop_set_default_integer(&(dev_prop->propinfo), (mtp_uchar *) &default_val); + _prop_set_current_integer(dev_prop, (mtp_uint32)1); + } + i++; + +#ifdef MTP_SUPPORT_DEVICE_CLASS + /* Perceived Device Type */ + dev_prop = &(g_device.device_prop_list[i]); + _prop_init_device_property_desc(dev_prop, + MTP_PROPERTYCODE_PERCEIVEDDEVICETYPE, + PTP_DATATYPE_UINT32, PTP_PROPGETSET_GETONLY, NONE); + { + /* + * 0:generic, 1: DSC, 2: Media Player, 3: mobile, + * 4: digital video camera, 5: PDA, 6: audio recoder + */ + default_val = 0x3; + _prop_set_default_integer(&(dev_prop->propinfo), (mtp_uchar *)&default_val); + _prop_set_current_integer(dev_prop, (mtp_uint32)0x3); + } + i++; +#endif /*MTP_SUPPORT_DEVICE_CLASS*/ + + dev_prop = &(g_device.device_prop_list[i]); + _prop_init_device_property_desc(dev_prop, MTP_PROPERTYCODE_DEVICEICON, + PTP_DATATYPE_AUINT8, PTP_PROPGETSET_GETONLY, NONE); + i++; + + already_init = TRUE; + + return TRUE; +} + +void _init_mtp_device(void) +{ + static mtp_bool already_init = FALSE; + + if (TRUE == already_init) { + DBG("Device is already initialized"); + return; + } + + already_init = TRUE; + + g_device.status = DEVICE_STATUSOK; + g_device.phase = DEVICE_PHASE_IDLE; + g_device.num_stores = 0; + g_device.store_list = g_store_list; + g_device.default_store_id = MTP_INTERNAL_STORE_ID; + g_device.default_hparent = PTP_OBJECTHANDLE_ROOT; + + __init_device_props(); + _prop_build_supp_props_mp3(); + _prop_build_supp_props_wmv(); + _prop_build_supp_props_wma(); + _prop_build_supp_props_album(); + _prop_build_supp_props_default(); + __init_device_info(); + + return; +} + +mtp_uint32 _get_device_info_size(void) +{ + mtp_uint32 size = 0; + device_info_t *info = &(g_device.device_info); + + size += sizeof(info->std_version); + size += sizeof(info->vendor_extn_id); + size += sizeof(info->vendor_extn_version); + size += _prop_size_ptpstring(&(info->vendor_extn_desc)); + size += sizeof(info->functional_mode); + size += sizeof(mtp_uint32); /*for number of supported ops*/ + size += sizeof(g_ops_supported); + size += sizeof(mtp_uint32); + size += sizeof(g_event_supported); + size += sizeof(mtp_uint32); + size += NUM_DEVICE_PROPERTIES * sizeof(mtp_uint16); + size += sizeof(mtp_uint32); + size += sizeof(g_capture_fmts); + size += sizeof(mtp_uint32); + size += sizeof(g_object_fmts); + size += _prop_size_ptpstring(&(info->manufacturer)); + size += _prop_size_ptpstring(&(info->model)); + size += _prop_size_ptpstring(&(info->device_version)); + size += _prop_size_ptpstring(&(info->serial_no)); + + return size; +} + +mtp_uint32 _pack_device_info(mtp_uchar *buf, mtp_uint32 buf_sz) +{ + mtp_uint16 ii = 0; + mtp_uchar *ptr = buf; + mtp_uint32 count = 0; + device_info_t *info = &(g_device.device_info); + + retv_if(NULL == buf, 0); + + if (buf_sz < _get_device_info_size()) { + ERR("buffer size [%d] is less than device_info Size\n", buf_sz); + return 0; + } + + memcpy(ptr, &info->std_version, sizeof(info->std_version)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(info->std_version)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(info->std_version); + + memcpy(ptr, &info->vendor_extn_id, sizeof(info->vendor_extn_id)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(info->vendor_extn_id)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(info->vendor_extn_id); + + memcpy(ptr, &info->vendor_extn_version, + sizeof(info->vendor_extn_version)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(info->vendor_extn_version)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(info->vendor_extn_version); + + ptr += _prop_pack_ptpstring(&(info->vendor_extn_desc), ptr, + _prop_size_ptpstring(&(info->vendor_extn_desc))); + + memcpy(ptr, &info->functional_mode, sizeof(info->functional_mode)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(info->functional_mode)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(info->functional_mode); + + count = (sizeof(g_ops_supported) / sizeof(mtp_uint16)); + memcpy(ptr, &count, sizeof(count)); + +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(count)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(count); + for (ii = 0; ii < count; ii++) { + memcpy(ptr, (void *)&(info->ops_supported[ii]), + sizeof(mtp_uint16)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(mtp_uint16)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(mtp_uint16); + } + + count = (sizeof(g_event_supported) / sizeof(mtp_uint16)); + memcpy(ptr, &count, sizeof(count)); + +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(count)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(count); + for (ii = 0; ii < count; ii++) { + memcpy(ptr, (void *)&(info->events_supported[ii]), + sizeof(mtp_uint16)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(mtp_uint16)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(mtp_uint16); + } + + count = NUM_DEVICE_PROPERTIES; + memcpy(ptr, &count, sizeof(count)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(count)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(count); + for (ii = 0; ii < NUM_DEVICE_PROPERTIES; ii++) { + memcpy(ptr, (void *)&(info->device_prop_supported[ii]), + sizeof(mtp_uint16)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(mtp_uint16)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(mtp_uint16); + } + + count = (sizeof(g_capture_fmts) / sizeof(mtp_uint16)); + memcpy(ptr, &count, sizeof(count)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(count)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(count); + + for (ii = 0; ii < count; ii++) { + memcpy(ptr, (void *)&(info->capture_fmts[ii]), + sizeof(mtp_uint16)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(mtp_uint16)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(mtp_uint16); + } + + count = (sizeof(g_object_fmts) / sizeof(mtp_uint16)); + memcpy(ptr, &count, sizeof(count)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(count)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(count); + for (ii = 0; ii < count; ii++) { + memcpy(ptr, (void *)&(info->object_fmts[ii]), + sizeof(mtp_uint16)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, sizeof(mtp_uint16)); +#endif /*__BIG_ENDIAN__*/ + ptr += sizeof(mtp_uint16); + } + + ptr += _prop_pack_ptpstring(&(info->manufacturer), ptr, + _prop_size_ptpstring(&(info->manufacturer))); + + ptr += _prop_pack_ptpstring(&(info->model), ptr, + _prop_size_ptpstring(&(info->model))); + + ptr += _prop_pack_ptpstring(&(info->device_version), ptr, + _prop_size_ptpstring(&(info->device_version))); + + ptr += _prop_pack_ptpstring(&(info->serial_no), ptr, + _prop_size_ptpstring(&(info->serial_no))); + + return (mtp_uint32)(ptr - buf); +} + +void _reset_mtp_device(void) +{ + _transport_set_control_event(0); + _transport_set_mtp_operation_state(MTP_STATE_ONSERVICE); + + /* resets device state to ok/Ready */ + /* reset device phase to idle */ + + g_device.status = DEVICE_STATUSOK; + g_device.phase = DEVICE_PHASE_IDLE; + return; +} + +device_prop_desc_t *_device_get_device_property(mtp_uint32 prop_code) +{ + mtp_uint16 ii = 0; + + for (ii = 0; ii < NUM_DEVICE_PROPERTIES; ii++) { + if (g_device.device_prop_list[ii].propinfo.prop_code == prop_code) + return &(g_device.device_prop_list[ii]); + } + return NULL; +} + +/* + * static mtp_bool _device_add_store(store_type_t store_type) + * This function will add the store to the device. + * @param[in] store_type Store Number + * @return TRUE if success, otherwise FALSE. + */ +static mtp_bool __add_store_to_device(store_type_t store_type) +{ + mtp_char *storage_path = NULL; + mtp_uint32 store_id = 0; + file_attr_t attrs = { 0, }; + + switch (store_type) { + case MTP_STORAGE_INTERNAL: + storage_path = MTP_STORE_PATH_CHAR; + store_id = MTP_INTERNAL_STORE_ID; + break; + case MTP_STORAGE_EXTERNAL: + storage_path = MTP_EXTERNAL_PATH_CHAR; + store_id = MTP_EXTERNAL_STORE_ID; + break; + default: + ERR("Unknown Storage [%d]\n", store_id); + return FALSE; + } + + if (FALSE == _util_get_file_attrs(storage_path, &attrs)) { + ERR("_util_get_file_attrs() Fail"); + return FALSE; + } + + if (MTP_FILE_ATTR_INVALID == attrs.attribute || + !(attrs.attribute & MTP_FILE_ATTR_MODE_DIR)) { + ERR("attribute [0x%x], dir[0x%x]\n", + attrs.attribute, MTP_FILE_ATTR_MODE_DIR); + ERR("Storage [%d]\n", store_id); + return FALSE; + } + + + if (g_device.num_stores + 1 > MAX_NUM_DEVICE_STORES) { + ERR("reached to max [%d]\n", MAX_NUM_DEVICE_STORES); + return FALSE; + } + + if (FALSE == _entity_init_mtp_store(&(g_device.store_list[g_device.num_stores]), + store_id, storage_path)) { + ERR("_entity_init_mtp_store() Fail"); + return FALSE; + } + + g_device.num_stores++; + g_device.is_mounted[store_type] = TRUE; + + return TRUE; +} + +/* + * static mtp_bool _device_remove_store(store_type_t store_type) + * This function will remove the store from the device. + * @param[in] store_type Store type + * @return TRUE if success, otherwise FALSE. + */ +static mtp_bool __remove_store_from_device(store_type_t store_type) +{ + mtp_int32 ii = 0; + mtp_device_t *device = &g_device; + mtp_store_t *store = NULL; + mtp_uint32 store_id = 0; + + switch (store_type) { + case MTP_STORAGE_INTERNAL: + store_id = MTP_INTERNAL_STORE_ID; + break; + case MTP_STORAGE_EXTERNAL: + store_id = MTP_EXTERNAL_STORE_ID; + break; + default: + ERR("Unknown Storage [%d]\n", store_type); + return FALSE; + } + + for (ii = 0; ii < device->num_stores; ii++) { + store = &(device->store_list[ii]); + if (store->store_id == store_id) { + __clear_store_data(store->store_id); + device->is_mounted[store_type] = FALSE; + break; + } + } + + return TRUE; +} + +mtp_bool _device_is_store_mounted(mtp_int32 store_type) +{ + if (store_type < MTP_STORAGE_INTERNAL || + store_type >= MTP_STORAGE_ALL) { + ERR("unknown storage(%d)\n", store_type); + return FALSE; + } + + return g_device.is_mounted[store_type]; +} + +mtp_bool _device_install_storage(mtp_int32 type) +{ + mtp_int32 int_status = TRUE; + mtp_int32 ext_status = TRUE; + mtp_bool mounted; + + switch (type) { + case MTP_ADDREM_AUTO: + DBG(" case MTP_ADDREM_AUTO:"); + int_status = _device_is_store_mounted(MTP_STORAGE_INTERNAL); + if (int_status == FALSE) + __add_store_to_device(MTP_STORAGE_INTERNAL); + + mounted = _util_get_local_mmc_status(); + if (mounted == MTP_PHONE_MMC_INSERTED) { + + ext_status = + _device_is_store_mounted(MTP_STORAGE_EXTERNAL); + if (ext_status == FALSE) + __add_store_to_device(MTP_STORAGE_EXTERNAL); + } + break; + + case MTP_ADDREM_INTERNAL: + DBG("case MTP_ADDREM_INTERNAL:"); + if (FALSE == _device_is_store_mounted(MTP_STORAGE_INTERNAL)) + __add_store_to_device(MTP_STORAGE_INTERNAL); + break; + + case MTP_ADDREM_EXTERNAL: + DBG(" case MTP_ADDREM_EXTERNAL:"); + if (MTP_PHONE_MMC_INSERTED != _util_get_local_mmc_status()) + break; + mounted = _device_is_store_mounted(MTP_STORAGE_EXTERNAL); + if (mounted == FALSE) { + if (__add_store_to_device(MTP_STORAGE_EXTERNAL)== FALSE) { + ERR("__add_store_to_device() Fail"); + return FALSE; + } + } + break; + + case MTP_ADDREM_ALL: + DBG(" case MTP_ADDREM_ALL:"); + __add_store_to_device(MTP_STORAGE_INTERNAL); + __add_store_to_device(MTP_STORAGE_EXTERNAL); + break; + + default: + ERR("_device_install_storage : unknown type [%d]\n", type); + break; + } + + return TRUE; +} + +mtp_bool _device_uninstall_storage(mtp_int32 type) +{ + switch (type) { + case MTP_ADDREM_AUTO: + if (TRUE == _device_is_store_mounted(MTP_STORAGE_EXTERNAL)) + __remove_store_from_device(MTP_STORAGE_EXTERNAL); + if (TRUE == _device_is_store_mounted(MTP_STORAGE_INTERNAL)) + __remove_store_from_device(MTP_STORAGE_INTERNAL); + break; + case MTP_ADDREM_INTERNAL: + if (TRUE == _device_is_store_mounted(MTP_STORAGE_INTERNAL)) + __remove_store_from_device(MTP_STORAGE_INTERNAL); + break; + case MTP_ADDREM_EXTERNAL: + if (TRUE == _device_is_store_mounted(MTP_STORAGE_EXTERNAL)) + __remove_store_from_device(MTP_STORAGE_EXTERNAL); + break; + case MTP_ADDREM_ALL: + __remove_store_from_device(MTP_STORAGE_INTERNAL); + __remove_store_from_device(MTP_STORAGE_EXTERNAL); + break; + default: + ERR("unknown mode [%d]\n", type); + break; + } + + return TRUE; +} + +/* + * static mtp_err_t __device_clear_store_data(mtp_uint32 store_id) + * This function removes the storage entry. + * @param[in] store_id Specifies the storage id to remove + * @return This function returns MTP_ERROR_NONE on success + * ERROR number on failure. + */ +static mtp_err_t __clear_store_data(mtp_uint32 store_id) +{ + mtp_uint16 idx = 0; + mtp_store_t *store = NULL; + mtp_uint32 count = g_device.num_stores; + + for (idx = 0; idx < count; idx++) { + if (g_device.store_list[idx].store_id == store_id) { + + _entity_destroy_mtp_store(&(g_device.store_list[idx])); + + store = &(g_device.store_list[idx]); + store->store_id = 0; + store->is_hidden = FALSE; + g_free(store->root_path); + store->root_path = NULL; + + for (; idx < count - 1; idx++) { + _entity_copy_store_data(&(g_device.store_list[idx]), + &(g_device.store_list[idx + 1])); + } + + g_device.store_list[count - 1].store_id = 0; + g_device.store_list[count - 1].root_path = NULL; + g_device.store_list[count - 1].is_hidden = FALSE; + _util_init_list(&(g_device.store_list[count - 1].obj_list)); + + /*Initialize the destroyed store*/ + g_device.num_stores--; + return MTP_ERROR_NONE; + } + } + return MTP_ERROR_GENERAL; +} + +mtp_store_t *_device_get_store(mtp_uint32 store_id) +{ + mtp_int32 ii = 0; + mtp_store_t *store = NULL; + + for (ii = 0; ii < g_device.num_stores; ii++) { + + store = &(g_device.store_list[ii]); + if (store->store_id == store_id) + return store; + } + return NULL; +} + +mtp_uint32 _device_get_store_ids(ptp_array_t *store_ids) +{ + mtp_store_t *store = NULL; + mtp_int32 ii = 0; + + for (ii = g_device.num_stores - 1; ii >= 0; ii--) { + + store = &(g_device.store_list[ii]); + if ((store != NULL) && (FALSE == store->is_hidden)) + _prop_append_ele_ptparray(store_ids, store->store_id); + } + return store_ids->num_ele; +} + +mtp_uint32 _device_get_num_objects(mtp_uint32 store_id) +{ + mtp_uint32 num_objs = 0; + mtp_store_t *store = NULL; + mtp_uint32 ii = 0; + + for (ii = 0; ii < g_device.num_stores; ii++) { + + store = &(g_device.store_list[ii]); + if ((store->store_id == store_id) || + (store_id == PTP_STORAGEID_ALL)) { + num_objs += store->obj_list.nnodes; + } + } + + return num_objs; +} + +mtp_uint32 _device_get_num_objects_with_format(mtp_uint32 store_id, + mtp_uint32 format) +{ + mtp_uint32 num_objs = 0; + mtp_store_t *store = NULL; + mtp_uint32 ii = 0; + + for (ii = 0; ii < g_device.num_stores; ii++) { + + store = &(g_device.store_list[ii]); + if ((store->store_id != store_id) && + (store_id != PTP_STORAGEID_ALL)) { + continue; + } + num_objs += _entity_get_num_object_with_same_format(store, + format); + } + + return num_objs; +} + +mtp_obj_t *_device_get_object_with_handle(mtp_uint32 obj_handle) +{ + mtp_int32 ii = 0; + mtp_obj_t *obj = NULL; + mtp_store_t *store = NULL; + + for (ii = 0; ii < g_device.num_stores; ii++) { + + store = &(g_device.store_list[ii]); + obj = _entity_get_object_from_store(store, obj_handle); + if (obj == NULL) + continue; + break; + } + return obj; +} + +mtp_obj_t* _device_get_object_with_path(mtp_char *full_path) +{ + mtp_int32 i = 0; + mtp_obj_t *obj = NULL; + mtp_store_t *store = NULL; + + retv_if(NULL == full_path, NULL); + + for (i = 0; i < g_device.num_stores; i++) { + store = &(g_device.store_list[i]); + obj = _entity_get_object_from_store_by_path(store, full_path); + if (obj == NULL) + continue; + break; + } + return obj; +} + +mtp_uint16 _device_delete_object(mtp_uint32 obj_handle, mtp_uint32 fmt) +{ + mtp_uint32 ii = 0; + mtp_uint16 response = PTP_RESPONSE_OK; + mtp_store_t *store = NULL; + mtp_bool all_del = TRUE; + mtp_bool atlst_one = FALSE; + + if (PTP_OBJECTHANDLE_ALL != obj_handle) { + store = _device_get_store_containing_obj(obj_handle); + if (store == NULL) { + response = PTP_RESPONSE_INVALID_OBJ_HANDLE; + } else { + response = _entity_delete_obj_mtp_store(store, + obj_handle, fmt, TRUE); + } + return response; + } + + for (ii = 0; ii < g_device.num_stores; ii++) { + store = &(g_device.store_list[ii]); + response = _entity_delete_obj_mtp_store(store, obj_handle, + fmt, TRUE); + switch (response) { + case PTP_RESPONSE_STORE_READONLY: + all_del = FALSE; + break; + case PTP_RESPONSE_PARTIAL_DELETION: + all_del = FALSE; + atlst_one = TRUE; + break; + case PTP_RESPONSE_OBJ_WRITEPROTECTED: + case PTP_RESPONSE_ACCESSDENIED: + all_del = FALSE; + break; + case PTP_RESPONSE_OK: + default: + atlst_one = TRUE; + break; + } + } + + if (all_del) + response = PTP_RESPONSE_OK; + else if (atlst_one) + response = PTP_RESPONSE_PARTIAL_DELETION; + + return response; +} + +mtp_store_t *_device_get_store_containing_obj(mtp_uint32 obj_handle) +{ + mtp_uint32 ii = 0; + mtp_obj_t *obj = NULL; + mtp_store_t *store = NULL; + + for (ii = 0; ii < g_device.num_stores; ii++) { + store = &(g_device.store_list[ii]); + obj = _entity_get_object_from_store(store, obj_handle); + if (obj != NULL) + return store; + } + return NULL; +} + +mtp_store_t *_device_get_store_at_index(mtp_uint32 index) +{ + if (index >= g_device.num_stores) { + ERR("Index not valid"); + return NULL; + } + + return &(g_device.store_list[index]); +} + +device_prop_desc_t *_device_get_ref_prop_list(void) +{ + return g_device.device_prop_list; +} + +mtp_bool _device_get_playback_obj(mtp_uint32 *playback_obj) +{ + device_prop_desc_t *device_prop = NULL; + + device_prop = _device_get_device_property(MTP_PROPERTYCODE_PLAYBACK_OBJECT); + if (NULL == device_prop) { + ERR("device_prop is NULL"); + return FALSE; + } + memcpy(playback_obj, device_prop->current_val.integer, + sizeof(mtp_uint32)); + + return TRUE; +} + +mtp_bool _device_set_playback_obj(mtp_uint32 playback_obj) +{ + device_prop_desc_t *device_prop = NULL; + cmd_container_t event = { 0, }; + + device_prop = _device_get_device_property(MTP_PROPERTYCODE_PLAYBACK_OBJECT); + if (device_prop == NULL) { + ERR("device_prop is NULL"); + return FALSE; + } + _prop_set_current_integer(device_prop, playback_obj); + _hdlr_init_event_container(&event, + PTP_EVENTCODE_DEVICEPROPCHANGED, 0, 0, 0); + _hdlr_send_event_container(&event); + return TRUE; +} + +void _device_get_serial(mtp_char *serial_no, mtp_uint32 len) +{ + ret_if(serial_no == NULL); + + _util_utf16_to_utf8(serial_no, len, + g_device.device_info.serial_no.str); + return; +} + +void _device_set_phase(device_phase_t phase) +{ + DBG("Devie phase is set [%d]\n", phase); + g_device.phase = phase; + return; +} + +device_phase_t _device_get_phase(void) +{ + return g_device.phase; +} + +mtp_uint32 _device_get_default_store_id(void) +{ + return g_device.default_store_id; +} + +mtp_uint32 _device_get_default_parent_handle(void) +{ + return g_device.default_hparent; +} + +mtp_uint32 _device_get_num_stores(void) +{ + return g_device.num_stores; +} + +device_status_t _device_get_status(void) +{ + return g_device.status; +} + +mtp_char *_device_get_device_name(void) +{ + return g_strdup(g_device.device_name); +} + +void _device_set_device_name(mtp_char *dev_name) +{ + ret_if(dev_name == NULL); + + g_strlcpy(g_device.device_name, dev_name, sizeof(g_device.device_name)); + return; +} + +mtp_char *_device_get_sync_partner(void) +{ + return g_strdup(g_device.sync_partner); +} + +void _device_set_sync_partner(mtp_char *sync_ptr) +{ + ret_if(sync_ptr == NULL); + + g_strlcpy(g_device.sync_partner, sync_ptr, + sizeof(g_device.sync_partner)); + return; +} diff --git a/src/entity/mtp_object.c b/src/entity/mtp_object.c new file mode 100755 index 0000000..1cc13bf --- /dev/null +++ b/src/entity/mtp_object.c @@ -0,0 +1,755 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <glib.h> +#include "mtp_fs.h" +#include "mtp_support.h" +#include "mtp_util.h" +#include "mtp_device.h" + + +extern mtp_bool g_is_full_enum; + + +mtp_bool _entity_get_file_times(mtp_obj_t *obj, ptp_time_string_t *create_tm, + ptp_time_string_t *modify_tm) +{ + file_attr_t attrs = {0}; + system_time_t local_time = {0}; + struct tm new_time = {0}; + + if (FALSE == _util_get_file_attrs(obj->file_path, &attrs)) { + ERR("_util_get_file_attrs Fail"); + return FALSE; + } + + if (NULL != localtime_r((time_t*)&attrs.ctime, &new_time)) { + local_time.year = new_time.tm_year + 1900; + local_time.month = new_time.tm_mon + 1; + local_time.day = new_time.tm_mday; + local_time.hour = new_time.tm_hour; + local_time.minute = new_time.tm_min; + local_time.second = new_time.tm_sec; + local_time.day_of_week = 0; + local_time.millisecond = 0; + } else { + ERR("localtime_r returned NULL"); + _util_print_error(); + return FALSE; + } + _prop_copy_time_to_ptptimestring(create_tm, &local_time); + + if (NULL != localtime_r((time_t*)&attrs.mtime, &new_time)) { + local_time.year = new_time.tm_year + 1900; + local_time.month = new_time.tm_mon + 1; + local_time.day = new_time.tm_mday; + local_time.hour = new_time.tm_hour; + local_time.minute = new_time.tm_min; + local_time.second = new_time.tm_sec; + local_time.day_of_week = 0; + local_time.millisecond = 0; + } else { + ERR("localtime_r returned NULL"); + _util_print_error(); + return FALSE; + } + _prop_copy_time_to_ptptimestring(modify_tm, &local_time); + + return TRUE; +} + +obj_info_t *_entity_alloc_object_info(void) +{ + obj_info_t *info = NULL; + + info = (obj_info_t *)g_malloc(sizeof(obj_info_t)); + if (NULL == info) { + ERR("Memory allocation Fail"); + return NULL; + } + + _entity_init_object_info(info); + + return info; +} + +void _entity_init_object_info(obj_info_t *info) +{ + ret_if(info == NULL); + + memset(info, 0, sizeof(obj_info_t)); +} + +mtp_uint32 _entity_get_object_info_size(mtp_obj_t *obj, ptp_string_t *file_name) +{ + int ret; + ptp_string_t keywords; + ptp_time_string_t create_time_str = {0}; + ptp_time_string_t modify_time_str = {0}; + mtp_uint32 size = FIXED_LENGTH_MEMBERS_SIZE; + + retv_if(obj == NULL, 0); + + ret = _entity_get_file_times(obj, &create_time_str, &modify_time_str); + if (FALSE == ret) { + ERR("_entity_get_file_times() Fail"); + return 0; + } + + _prop_copy_char_to_ptpstring(&keywords, (mtp_wchar *)"", WCHAR_TYPE); + + size += _prop_size_ptpstring(file_name); + size += _prop_size_ptptimestring(&create_time_str); + size += _prop_size_ptptimestring(&modify_time_str); + size += _prop_size_ptpstring(&keywords); + + return (size); +} + +void _entity_init_object_info_params(obj_info_t *info, mtp_uint32 store_id, + mtp_uint32 parent_handle, mtp_char *file_name, dir_entry_t *dir) +{ + mtp_char extn[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + + _entity_init_object_info(info); + + info->store_id = store_id; + info->h_parent = parent_handle; + + _util_get_file_extn(file_name, extn); + + if (dir->attrs.attribute == MTP_FILE_ATTR_INVALID) { + ERR("File attribute invalid"); + return; + } +#ifndef MTP_SUPPORT_SET_PROTECTION + info->protcn_status = PTP_PROTECTIONSTATUS_NOPROTECTION; +#else /* MTP_SUPPORT_SET_PROTECTION */ + info->protcn_status = (dir->attrs.attribute & + MTP_FILE_ATTR_MODE_READ_ONLY) ? + PTP_PROTECTIONSTATUS_READONLY : + PTP_PROTECTIONSTATUS_NOPROTECTION; +#endif /* MTP_SUPPORT_SET_PROTECTION */ + + if (dir->attrs.attribute & MTP_FILE_ATTR_MODE_DIR) { + info->obj_fmt = PTP_FMT_ASSOCIATION; + info->association_type = PTP_ASSOCIATIONTYPE_FOLDER; + return; + } + + info->file_size = dir->attrs.fsize; + info->obj_fmt = _util_get_fmtcode(extn); + + return; +} + +mtp_uint32 _entity_parse_raw_obj_info(mtp_uchar *buf, mtp_uint32 buf_sz, + obj_info_t *info, mtp_char *file_name, mtp_uint16 fname_len) +{ + mtp_uchar *temp = buf; + ptp_string_t str = {0}; + mtp_uint32 bytes_parsed = 0; + + retv_if(buf == NULL, 0); + retvm_if(buf_sz < FIXED_LENGTH_MEMBERS_SIZE, 0, "buf_sz[%d] is less", buf_sz); + + /* Copy Obj Props from store_id till file_size */ + memcpy(&(info->store_id), temp, (sizeof(mtp_uint16) * 2 + sizeof(mtp_uint32) * 2)); + temp += (sizeof(mtp_uint16) * 2 + sizeof(mtp_uint32) * 2); + + /* Skip ObjProp:thumb format .No need to store ,the prop has + * a default value. + */ + temp += sizeof(mtp_uint16); + + memcpy(&(info->thumb_file_size), temp, sizeof(mtp_uint32)); + temp += sizeof(mtp_uint32); + + /* Skip ObjProps:ThumbPixWidth,ThumbPixHeight,ImagePixWidth, + * ImagePixHeight,ImageBitDepth.No need to store,they have default value + */ + temp += sizeof(mtp_uint32) * 5; + + memcpy(&(info->h_parent), temp, sizeof(mtp_uint32)); + temp += sizeof(mtp_uint32); + + memcpy(&(info->association_type), temp, sizeof(mtp_uint16)); + temp += sizeof(mtp_uint16); + + /* Skip ObjProps:association_desc, sequence_desc */ + temp += sizeof(mtp_uint32) * 2; + +#ifdef __BIG_ENDIAN__ + /* Byte swap the structure elements if needed. + * This works since the data elements will have the same size, + * the only difference is the byte order. + */ + _util_conv_byte_order(&(info->store_id), sizeof(info->store_id)); + _util_conv_byte_order(&(info->obj_fmt), sizeof(info->obj_fmt)); + _util_conv_byte_order(&(info->protcn_status), + sizeof(info->protcn_status)); + _util_conv_byte_order(&(info->file_size), sizeof(info->file_size)); + _util_conv_byte_order(&(info->thumb_file_size), + sizeof(info->thumb_file_size)); + _util_conv_byte_order(&(info->h_parent), sizeof(info->h_parent)); + _util_conv_byte_order(&(info->association_type), + sizeof(info->association_type)); +#endif /*__BIG_ENDIAN__*/ + + ptp_string_t fname = { 0 }; + bytes_parsed = _prop_parse_rawstring(&fname, temp, buf_sz); + temp += bytes_parsed; + + _util_utf16_to_utf8(file_name, fname_len, fname.str); + + /* Skip ObjProps: datecreated/datemodified/keywords. + * The values are retrieved using stat. + */ + memcpy(&(str.num_chars), temp, sizeof(mtp_uchar)); + temp += _prop_size_ptpstring(&str); + + memcpy(&(str.num_chars), temp, sizeof(mtp_uchar)); + temp += _prop_size_ptpstring(&str); + + memcpy(&(str.num_chars), temp, sizeof(mtp_uchar)); + temp += _prop_size_ptpstring(&str); + + return (mtp_uint32)(temp - buf); +} + +void _entity_copy_obj_info(obj_info_t *dst, obj_info_t *src) +{ + memcpy(&(dst->store_id), &(src->store_id), (2 * sizeof(mtp_uint16) + + sizeof(mtp_uint32) + sizeof(mtp_uint64))); + + /* Copy Object Props:thumb_file_size,h_parent, association_type */ + memcpy(&(dst->thumb_file_size), &(src->thumb_file_size), + (2 * sizeof(mtp_uint32) + sizeof(mtp_uint16))); + + return; +} + +mtp_uint32 _entity_pack_obj_info(mtp_obj_t *obj, ptp_string_t *file_name, + mtp_uchar *buf, mtp_uint32 buf_sz) +{ + int ret; + mtp_uint32 num_bytes = 0; + mtp_uint32 objSize = 0; + mtp_uint16 thumb_fmt = 0; + mtp_uint32 thumb_width = 0; + mtp_uint32 thumb_height = 0; + obj_info_t *info = obj->obj_info; + ptp_time_string_t create_time_str = { 0 }; + ptp_time_string_t modify_time_str = { 0 }; + ptp_string_t keywords; + + retv_if(buf == NULL, 0); + retv_if(obj == NULL, 0); + + ret = _entity_get_file_times(obj, &create_time_str, &modify_time_str); + if (FALSE == ret) { + ERR("_entity_get_file_times() Fail"); + return 0; + } + + _prop_copy_char_to_ptpstring(&keywords, (mtp_wchar *)"", WCHAR_TYPE); + + if (buf_sz < _entity_get_object_info_size(obj, file_name)) { + ERR("Buffer size is less than object info size"); + return 0; + } + + /* As per Spec ObjectCompressedSize field in ObjectInfo dataset is + * 4 bytes. In case file size greater than 4Gb, value 0xFFFFFFFF is sent + */ + objSize = (info->file_size >= MTP_FILESIZE_4GB) ? + 0xFFFFFFFF : (mtp_uint32)info->file_size; + +#ifdef __BIG_ENDIAN__ + memcpy(&(buf[num_bytes]), &(info->store_id), sizeof(mtp_uint32)); + _util_conv_byte_order(buf, sizeof(mtp_uint32)); + num_bytes += sizeof(mtp_uint32); + + memcpy(&(buf[num_bytes]), &(info->obj_fmt), sizeof(mtp_uint16)); + _util_conv_byte_order(buf, sizeof(mtp_uint16)); + num_bytes += sizeof(mtp_uint16); + + memcpy(&(buf[num_bytes]), &(info->protcn_status), sizeof(mtp_uint16)); + _util_conv_byte_order(buf, sizeof(mtp_uint16)); + num_bytes += sizeof(mtp_uint16); + + memcpy(&(buf[num_bytes]), &objSize, sizeof(mtp_uint32)); + _util_conv_byte_order(buf, sizeof(mtp_uint32)); + num_bytes += sizeof(mtp_uint32); + + /* Thumb format has a constant value of 2 bytes */ + memset(&(buf[num_bytes]), &thumb_fmt, sizeof(mtp_uint16)); + _util_conv_byte_order(buf, sizeof(mtp_uint16)); + num_bytes += sizeof(mtp_uint16); + + memcpy(&(buf[num_bytes]), &(info->thumb_file_size), sizeof(mtp_uint32)); + _util_conv_byte_order(buf, sizeof(mtp_uint32)); + num_bytes += sizeof(mtp_uint32); + + memcpy(&(buf[num_bytes]), &thumb_width, sizeof(mtp_uint32)); + _util_conv_byte_order(buf, sizeof(mtp_uint32)); + num_bytes += sizeof(mtp_uint32); + + memcpy(&(buf[num_bytes]), &thumb_height, sizeof(mtp_uint32)); + _util_conv_byte_order(buf, sizeof(mtp_uint32)); + num_bytes += sizeof(mtp_uint32); + + /* ObjProps:image_width, image_height, image_bit_depth values + * currently are always 0 for any type of FILE/FOLDER + */ + memset(&(buf[num_bytes]), 0, sizeof(mtp_uint32) * 3); + _util_conv_byte_order(buf, sizeof(mtp_uint32) * 3); + num_bytes += (sizeof(mtp_uint32) * 3); + + memcpy(&(buf[num_bytes]), &(info->h_parent), sizeof(mtp_uint32)); + _util_conv_byte_order(buf, sizeof(mtp_uint32)); + num_bytes += sizeof(mtp_uint32); + + memcpy(&(buf[num_bytes]), + &(info->association_type), sizeof(mtp_uint16)); + _util_conv_byte_order(buf, sizeof(mtp_uint16)); + num_bytes += sizeof(mtp_uint16); + + /* ObjProps:association desc,sequence number values are always 0 */ + memset(&(buf[num_bytes]), 0, sizeof(mtp_uint32) * 2); + _util_conv_byte_order(buf, sizeof(mtp_uint32) * 2); + num_bytes += (sizeof(mtp_uint32) * 2); + +#else /* __BIG_ENDIAN__ */ + + /* ObjProps:store_id, obj_format, protection status */ + memcpy(buf, &(info->store_id), + (sizeof(mtp_uint32) + sizeof(mtp_uint16) * 2)); + num_bytes += (sizeof(mtp_uint32) + sizeof(mtp_uint16) * 2); + + memcpy(&buf[num_bytes], &objSize, sizeof(mtp_uint32)); + num_bytes += sizeof(mtp_uint32); + + /* ObjProp:thumb format */ + memcpy(&buf[num_bytes], &thumb_fmt, sizeof(mtp_uint16)); + num_bytes += sizeof(mtp_uint16); + + /* ObjProp: thumb file size */ + memcpy(&buf[num_bytes], &(info->thumb_file_size), sizeof(mtp_uint32)); + num_bytes += sizeof(mtp_uint32); + + /* ObjProp:thumb_width */ + memcpy(&buf[num_bytes], &thumb_width, sizeof(mtp_uint32)); + num_bytes += sizeof(mtp_uint32); + + /* ObjProp:thumb_height */ + memcpy(&buf[num_bytes], &thumb_height, sizeof(mtp_uint32)); + num_bytes += sizeof(mtp_uint32); + + /* ObjProp:image_width, image_height, + * image_bit_depth values currently are always 0 + */ + memset(&(buf[num_bytes]), 0, sizeof(mtp_uint32) * 3); + num_bytes += (sizeof(mtp_uint32) * 3); + + /* ObjProp:parent_handle */ + memcpy(&buf[num_bytes], &(info->h_parent), sizeof(mtp_uint32)); + num_bytes += sizeof(mtp_uint32); + + /* ObjProp:association_type */ + memcpy(&buf[num_bytes], &(info->association_type), sizeof(mtp_uint16)); + num_bytes += sizeof(mtp_uint16); + + /* ObjProp:association_desc,sequence Number values are always 0 */ + memset(&buf[num_bytes], 0, sizeof(mtp_uint32) * 2); + num_bytes += sizeof(mtp_uint32) * 2; +#endif /* __BIG_ENDIAN__ */ + + num_bytes += _prop_pack_ptpstring(file_name, buf + num_bytes, + _prop_size_ptpstring(file_name)); + + num_bytes += _prop_pack_ptptimestring(&create_time_str, + buf + num_bytes, + _prop_size_ptptimestring(&create_time_str)); + + num_bytes += _prop_pack_ptptimestring(&modify_time_str, + buf + num_bytes, + _prop_size_ptptimestring(&modify_time_str)); + + num_bytes += _prop_pack_ptpstring(&keywords, + buf + num_bytes, + _prop_size_ptpstring(&keywords)); + + DBG("number of bytes for objectinfo :[%d]\n", num_bytes); + return num_bytes; +} + +void _entity_dealloc_obj_info(obj_info_t *info) +{ + g_free(info); + info = NULL; + return; +} + +mtp_obj_t *_entity_alloc_mtp_object(void) +{ + return ((mtp_obj_t *)g_malloc(sizeof(mtp_obj_t))); +} + +mtp_bool _entity_init_mtp_object_params( + mtp_obj_t *obj, + mtp_uint32 store_id, + mtp_uint32 h_parent, + mtp_char *file_path, + mtp_char *file_name, + dir_entry_t *file_info) +{ + retv_if(obj == NULL, FALSE); + + obj->obj_handle = 0; + obj->obj_info = NULL; + obj->file_path = NULL; + obj->obj_handle = _entity_generate_next_obj_handle(); + _entity_set_object_file_path(obj, file_path, CHAR_TYPE); + obj->obj_info = _entity_alloc_object_info(); + + if (NULL == obj->obj_info) { + g_free(obj->file_path); + return FALSE; + } + _entity_init_object_info_params(obj->obj_info, store_id, h_parent, + file_name, file_info); + + _util_init_list(&(obj->propval_list)); + memset(&(obj->child_array), 0, sizeof(ptp_array_t)); + obj->child_array.type = UINT32_TYPE; + + return TRUE; +} + +mtp_bool _entity_set_object_file_path(mtp_obj_t *obj, void *file_path, + char_mode_t char_type) +{ + mtp_char temp[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + + if (char_type == WCHAR_TYPE) { + _util_utf16_to_utf8(temp, sizeof(temp), (mtp_wchar *)file_path); + g_free(obj->file_path); + obj->file_path = g_strdup(temp); + } else { + g_free(obj->file_path); + obj->file_path = g_strdup((char *)file_path); + } + return TRUE; +} + +mtp_bool _entity_check_child_obj_path(mtp_obj_t *obj, + mtp_char *src_path, mtp_char *dest_path) +{ + mtp_uint16 idx = 0; + mtp_char *ptr = NULL; + mtp_obj_t *child_obj = NULL; + ptp_array_t child_arr = { 0 }; + mtp_store_t *src_store = NULL; + mtp_char dest_chld_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char temp_chld_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_wchar dest_chld_wpath[MTP_MAX_PATHNAME_SIZE * 2 + 1] = { 0 }; + mtp_wchar temp_chld_wpath[MTP_MAX_PATHNAME_SIZE * 2 + 1] = { 0 }; + + retv_if(obj == NULL, FALSE); + + if (strlen(dest_path) > MTP_MAX_PATHNAME_SIZE - 1) { + ERR("dest_path is too long[%d]\n", strlen(dest_path)); + return FALSE; + } + + if (strlen(src_path) > MTP_MAX_PATHNAME_SIZE - 1) { + ERR("src_path is too long[%d]\n", strlen(src_path)); + return FALSE; + } + + src_store = _device_get_store_containing_obj(obj->obj_handle); + if (NULL == src_store) { + ERR("Object not present in store"); + return FALSE; + } + + _prop_init_ptparray(&child_arr, UINT32_TYPE); + _entity_get_child_handles(src_store, obj->obj_handle, &child_arr); + + DBG("obj_handle[%d], src_path[%s], dest_path[%s], num elements[%ld]\n", + obj->obj_handle, src_path, dest_path, child_arr.num_ele); + + for (idx = 0; idx < child_arr.num_ele; idx++) { + mtp_uint32 *ptr32 = child_arr.array_entry; + + child_obj = _entity_get_object_from_store(src_store, ptr32[idx]); + if (NULL == child_obj) { + continue; + } + + if (_util_is_file_opened(child_obj->file_path) == TRUE) { + ERR_SECURE("File [%s] is already opened\n", + child_obj->file_path); + return FALSE; + } + + g_strlcpy(temp_chld_path, child_obj->file_path, + MTP_MAX_PATHNAME_SIZE + 1); + _util_utf8_to_utf16(temp_chld_wpath, + sizeof(temp_chld_wpath) / WCHAR_SIZ, temp_chld_path); + if (_util_wchar_len(temp_chld_wpath) > + MTP_MAX_PATHNAME_SIZE - 1) { + ERR("Child Object Full Path is too long[%d]\n", + strlen(child_obj->file_path)); + _prop_deinit_ptparray(&child_arr); + return FALSE; + } + + ptr = strstr(child_obj->file_path, src_path); + if (NULL == ptr) { + continue; + } + + _util_utf8_to_utf16(dest_chld_wpath, + sizeof(dest_chld_wpath) / WCHAR_SIZ, src_path); + + if (_util_wchar_len(dest_chld_wpath) < + MTP_MAX_PATHNAME_SIZE - 1) { + g_strlcpy(dest_chld_path, dest_path, + MTP_MAX_PATHNAME_SIZE + 1); + } else { + ERR("dest_chld_wpath is too long[%d]\n", + strlen(dest_path)); + _prop_deinit_ptparray(&child_arr); + return FALSE; + } + + ptr += strlen(src_path); + if ((strlen(dest_chld_path) + strlen(ptr)) < + MTP_MAX_PATHNAME_SIZE) { + g_strlcat(dest_chld_path, ptr, + MTP_MAX_PATHNAME_SIZE + 1); + } else { + ERR("dest_chld_path + ptr is too long[%d]\n", + (strlen(ptr) + strlen(ptr))); + _prop_deinit_ptparray(&child_arr); + return FALSE; + } + DBG("dest_chld_path[%s], ptr[%s]\n", dest_chld_path, ptr); + + if (_entity_check_child_obj_path(child_obj, + temp_chld_path, dest_chld_path) == FALSE) { + ERR("set full path Fail"); + _prop_deinit_ptparray(&child_arr); + return FALSE; + } + } + + _prop_deinit_ptparray(&child_arr); + return TRUE; +} + +mtp_bool _entity_set_child_object_path(mtp_obj_t *obj, mtp_char *src_path, + mtp_char *dest_path) +{ + mtp_uint16 idx = 0; + mtp_char *ptr = NULL; + ptp_array_t child_arr = {0}; + mtp_obj_t *child_obj = NULL; + mtp_store_t *src_store = NULL; + mtp_uint32 *child_handle_arr = NULL; + mtp_char dest_child_path[MTP_MAX_PATHNAME_SIZE + 1] = {0}; + mtp_char temp_child_path[MTP_MAX_PATHNAME_SIZE + 1] = {0}; + + retv_if(NULL == obj, FALSE); + retv_if(NULL == src_path, FALSE); + retv_if(NULL == dest_path, FALSE); + + src_store = _device_get_store_containing_obj(obj->obj_handle); + if (NULL == src_store) { + ERR("Object not present in store"); + return FALSE; + } + + _prop_init_ptparray(&child_arr, UINT32_TYPE); + _entity_get_child_handles(src_store, obj->obj_handle, &child_arr); + DBG("Object handle[%ld], src_path[%s], dest_path[%s], Numchild[%ld]\n", + obj->obj_handle, src_path, dest_path, child_arr.num_ele); + + for (idx = 0; idx < child_arr.num_ele; idx++) { + child_handle_arr = child_arr.array_entry; + child_obj = _entity_get_object_from_store(src_store, child_handle_arr[idx]); + if (NULL == child_obj) + continue; + DBG_SECURE("obj_handle[%ld], full path[%s]\n", child_obj->obj_handle, + child_obj->file_path); + g_strlcpy(temp_child_path, child_obj->file_path, + sizeof(temp_child_path)); + + ptr = strstr(child_obj->file_path, src_path); + if (NULL == ptr) + continue; + + g_strlcpy(dest_child_path, dest_path, sizeof(dest_child_path)); + + ptr += strlen(src_path); + if (g_strlcat(dest_child_path, ptr, sizeof(dest_child_path)) >= + sizeof(dest_child_path)) { + ERR("g_strlcat truncation occured,failed to create\ + dest_child_path"); + _entity_remove_reference_child_array(obj, + child_obj->obj_handle); + _entity_dealloc_mtp_obj(child_obj); + continue; + } + _util_delete_file_from_db(child_obj->file_path); + + if (_entity_set_object_file_path(child_obj, dest_child_path, + CHAR_TYPE) == FALSE) { + ERR("Failed to set full path!!"); + _entity_remove_reference_child_array(obj, + child_obj->obj_handle); + _entity_dealloc_mtp_obj(child_obj); + continue; + } + + if (child_obj->obj_info == NULL) { + ERR("obj_info is NULL"); + continue; + } + + if ((child_obj->obj_info->obj_fmt == PTP_FMT_ASSOCIATION)) { + if (_entity_set_child_object_path(child_obj, temp_child_path, + dest_child_path) == FALSE) { + ERR("Fail to set the full path!!"); + _entity_remove_reference_child_array(obj, + child_obj->obj_handle); + _entity_dealloc_mtp_obj(child_obj); + continue; + } + } + } + + _prop_deinit_ptparray(&child_arr); + return TRUE; +} + +mtp_bool _entity_add_reference_child_array(mtp_obj_t *obj, mtp_uint32 handle) +{ + if (_prop_find_ele_ptparray(&(obj->child_array), handle) == + ELEMENT_NOT_FOUND) { + return (_prop_append_ele_ptparray(&(obj->child_array), handle)); + } + + return TRUE; +} + +ptp_array_t *_entity_get_reference_child_array(mtp_obj_t *obj) +{ + return &(obj->child_array); +} + +mtp_bool _entity_set_reference_child_array(mtp_obj_t *obj, mtp_uchar *buf, + mtp_uint32 buf_sz) +{ + mtp_uint32 i = 0; + mtp_uint32 no_ref = 0; + mtp_uint32 ref_handle = 0; + + retv_if(NULL == buf, FALSE); + + /*Retrieve the number of references*/ + no_ref = buf_sz; + + /*Clean up the reference array*/ + _entity_remove_reference_child_array(obj, PTP_OBJECTHANDLE_ALL); + + /* Grow the array to accommodate all references*/ + if (_prop_grow_ptparray(&(obj->child_array), no_ref) == FALSE) { + ERR("grow ptp Array Fail"); + return FALSE; + } + + ref_handle = 0; + for (i = 0; i < no_ref; i++) { + memcpy(&ref_handle, buf, sizeof(mtp_uint32)); + buf += sizeof(mtp_uint32); + _prop_append_ele_ptparray(&(obj->child_array), ref_handle); + } + + return TRUE; +} + +void _entity_copy_mtp_object(mtp_obj_t *dst, mtp_obj_t *src) +{ + /*Copy same information*/ + dst->obj_info = _entity_alloc_object_info(); + if (dst->obj_info == NULL) { + ERR("Object info allocation Fail."); + return; + } + _entity_copy_obj_info(dst->obj_info, src->obj_info); + dst->obj_handle = 0; + dst->file_path = NULL; + +#ifndef MTP_USE_RUNTIME_GETOBJECTPROPVALUE + _prop_update_property_values_list(dst); +#endif /* MTP_USE_RUNTIME_GETOBJECTPROPVALUE */ + return; +} + +mtp_bool _entity_remove_reference_child_array(mtp_obj_t *obj, mtp_uint32 handle) +{ + if (handle == PTP_OBJECTHANDLE_ALL) { + _prop_deinit_ptparray(&(obj->child_array)); + return TRUE; + } + return _prop_rem_elem_ptparray(&(obj->child_array), handle); +} + +void _entity_dealloc_mtp_obj(mtp_obj_t *obj) +{ + mtp_uint16 ii = 0; + slist_node_t *node = NULL; + slist_node_t *next_node = NULL; + + ret_if(NULL == obj); + + if (obj->obj_info) { + _entity_dealloc_obj_info(obj->obj_info); + obj->obj_info = NULL; + } + + _entity_remove_reference_child_array(obj, PTP_OBJECTHANDLE_ALL); + + for (ii = 0, next_node = obj->propval_list.start; + ii < obj->propval_list.nnodes; ii++) { + node = next_node; + next_node = node->link; + _prop_destroy_obj_propval((obj_prop_val_t *)node->value); + g_free(node); + } + + g_free(obj->file_path); + g_free(obj); + obj = NULL; + return; +} diff --git a/src/entity/mtp_property.c b/src/entity/mtp_property.c new file mode 100755 index 0000000..37151d2 --- /dev/null +++ b/src/entity/mtp_property.c @@ -0,0 +1,4984 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <glib.h> +#include "mtp_property.h" +#include "mtp_media_info.h" +#include "mtp_support.h" +#include "mtp_transport.h" + +/* + * EXTERN AND GLOBAL VARIABLES + */ +obj_interdep_proplist_t interdep_proplist; +/* + * STATIC VARIABLES + */ +static obj_prop_desc_t props_list_mp3[NUM_OBJECT_PROP_DESC_MP3]; +static obj_prop_desc_t props_list_wma[NUM_OBJECT_PROP_DESC_WMA]; +static obj_prop_desc_t props_list_wmv[NUM_OBJECT_PROP_DESC_WMV]; +static obj_prop_desc_t props_list_album[NUM_OBJECT_PROP_DESC_ALBUM]; +static obj_prop_desc_t props_list_default[NUM_OBJECT_PROP_DESC_DEFAULT]; + +/* + * STATIC FUNCTIONS + */ +static mtp_uint16 __get_ptp_array_elem_size(data_type_t type); +static mtp_bool __check_object_propcode(obj_prop_desc_t *prop, + mtp_uint32 propcode, mtp_uint32 group_code); +static mtp_bool __create_prop_integer(mtp_obj_t *obj, + mtp_uint16 propcode, mtp_uint64 value); +static mtp_bool __create_prop_string(mtp_obj_t *obj, mtp_uint16 propcode, + mtp_wchar *value); +static mtp_bool __create_prop_array(mtp_obj_t *obj, mtp_uint16 propcode, + mtp_char *arr, mtp_uint32 size); +#ifdef MTP_SUPPORT_PROPERTY_SAMPLE +static mtp_bool __create_prop_sample(mtp_obj_t *obj); +static void __build_supported_sample_props(mtp_uchar *count, + obj_prop_desc_t *prop); +#endif /*MTP_SUPPORT_PROPERTY_SAMPLE*/ +static mtp_bool __update_prop_values_audio(mtp_obj_t *obj); +static mtp_bool __update_prop_values_video(mtp_obj_t *obj); +static mtp_bool __update_prop_values_image(mtp_obj_t *obj); +static mtp_bool __prop_common_metadata(mtp_obj_t *obj, + common_meta_t *p_metata); +static void __build_supported_common_props(mtp_uchar *count, + obj_prop_desc_t *prop); +/* PtpString Functions */ +#ifndef MTP_USE_VARIABLE_PTP_STRING_MALLOC +static ptp_string_t *__alloc_ptpstring(void); +#else /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ +static ptp_string_t *__alloc_ptpstring(mtp_uint32 size); +#endif /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ +static void __init_obj_propval(obj_prop_val_t *val, obj_prop_desc_t *prop); +static void __init_ptptimestring(ptp_time_string_t *pstring); +static mtp_uint32 __size_curval_device_prop(device_prop_desc_t *prop); +static void __init_obj_prop_desc(obj_prop_desc_t *prop, mtp_uint16 propcode, + mtp_uint16 data_type, mtp_uchar get_set, mtp_uchar form_flag, + mtp_uint32 group_code); +static mtp_uint32 __get_size_default_val_obj_prop_desc(obj_prop_desc_t *prop); +static void __destroy_obj_prop_desc(obj_prop_desc_t *prop); +static mtp_uint32 __count_obj_proplist(obj_proplist_t *plist); +static mtp_bool __append_obj_proplist(obj_proplist_t *prop_list, mtp_uint32 obj_handle, + mtp_uint16 prop_code, mtp_uint32 data_type, mtp_uchar *val); +#ifdef MTP_SUPPORT_INTERDEPENDENTPROP +static mtp_bool __append_interdep_prop(interdep_prop_config_t *config, + obj_prop_desc_t *prop); +#endif /* MTP_SUPPORT_INTERDEPENDENTPROP */ +static mtp_uint32 __count_interdep_proplist(obj_interdep_proplist_t *config_list, + mtp_uint32 format_code); +/* + * FUNCTIONS + */ +static mtp_bool __check_object_propcode(obj_prop_desc_t *prop, + mtp_uint32 propcode, mtp_uint32 group_code) +{ + if ((prop->propinfo.prop_code == propcode) || + ((propcode == PTP_PROPERTY_ALL) && + !(prop->group_code & GROUP_CODE_SLOW)) || + ((propcode == PTP_PROPERTY_UNDEFINED) && + (prop->group_code & group_code))) { + return TRUE; + } + + return FALSE; +} + +static mtp_bool __create_prop_integer(mtp_obj_t *obj, + mtp_uint16 propcode, mtp_uint64 value) +{ + obj_prop_desc_t *prop = NULL; + obj_prop_val_t *prop_val = NULL; + mtp_uint32 fmt_code = obj->obj_info->obj_fmt; + + retv_if(obj == NULL, FALSE); + retv_if(obj->obj_info == NULL, FALSE); + + prop = _prop_get_obj_prop_desc(fmt_code, propcode); + if (NULL == prop) { + ERR("Create property Fail.. Prop = [0x%X]\n", propcode); + return FALSE; + } + + propvalue_alloc_and_check(prop_val); + _prop_set_current_integer_val(prop_val, value); + node_alloc_and_append(); + + return TRUE; +} + +static mtp_bool __create_prop_string(mtp_obj_t *obj, mtp_uint16 propcode, + mtp_wchar *value) +{ + ptp_string_t ptp_str = {0}; + obj_prop_desc_t *prop = NULL; + obj_prop_val_t *prop_val = NULL; + mtp_uint32 fmt_code = obj->obj_info->obj_fmt; + + retv_if(obj == NULL, FALSE); + retv_if(obj->obj_info == NULL, FALSE); + + prop = _prop_get_obj_prop_desc(fmt_code, propcode); + if (NULL == prop) { + ERR("Create property Fail.. Prop = [0x%X]\n", propcode); + return FALSE; + } + + propvalue_alloc_and_check(prop_val); + _prop_copy_char_to_ptpstring(&ptp_str, value, WCHAR_TYPE); + _prop_set_current_string_val(prop_val, &ptp_str); + node_alloc_and_append(); + + return TRUE; +} + +static mtp_bool __create_prop_timestring(mtp_obj_t *obj, + mtp_uint32 propcode, ptp_time_string_t *value) +{ + obj_prop_desc_t *prop = NULL; + obj_prop_val_t *prop_val= NULL; + mtp_uint32 fmt_code = obj->obj_info->obj_fmt; + + retv_if(obj == NULL, FALSE); + retv_if(obj->obj_info == NULL, FALSE); + + prop = _prop_get_obj_prop_desc(fmt_code, propcode); + if (NULL == prop) { + ERR("Create property Fail.. Prop = [0x%X]\n", propcode); + return FALSE; + } + + propvalue_alloc_and_check(prop_val); + _prop_set_current_string_val(prop_val, (ptp_string_t *)value); + node_alloc_and_append(); + + return TRUE; +} + +static mtp_bool __create_prop_array(mtp_obj_t *obj, mtp_uint16 propcode, + mtp_char *arr, mtp_uint32 size) +{ + obj_prop_desc_t *prop = NULL; + obj_prop_val_t *prop_val = NULL; + mtp_uint32 fmt_code = obj->obj_info->obj_fmt; + + retv_if(obj == NULL, FALSE); + retv_if(obj->obj_info == NULL, FALSE); + + prop = _prop_get_obj_prop_desc(fmt_code, propcode); + if (NULL == prop) { + ERR("Create property Fail.. Prop = [0x%X]\n", propcode); + return FALSE; + } + + propvalue_alloc_and_check(prop_val); + _prop_set_current_array_val(prop_val, (mtp_uchar *)arr, size); + node_alloc_and_append(); + + return TRUE; +} + +static mtp_bool __update_prop_values_audio(mtp_obj_t *obj) +{ + mtp_bool success = TRUE; + mtp_int32 converted_rating = 0; + comp_audio_meta_t audio_data = {{0}, {0}}; + + retv_if(obj == NULL, FALSE); + retv_if(obj->obj_info == NULL, FALSE); + + if (_util_get_audio_metadata(obj->file_path, &audio_data) == FALSE) { + if (_util_get_audio_meta_from_extractor(obj->file_path, + &audio_data) == FALSE) { + success = FALSE; + goto DONE; + } + } + + /*Update common metadata information*/ + if (FALSE == __prop_common_metadata(obj, + &(audio_data.commonmeta))) { + ERR("Common metadata update Fail"); + success = FALSE; + goto DONE; + } + + + /*--------------TRACK--------------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_TRACK, audio_data.audiometa.track)) { + success = FALSE; + goto DONE; + } + + /*--------------USER RATING--------------*/ + /* DCM rating -> MTP (WMP) rating */ + switch (audio_data.commonmeta.rating) { + case 1: + converted_rating = 1; /* 1-12 */ + break; + case 2: + converted_rating = 25; /* 13-37 */ + break; + case 3: + converted_rating = 50; /* 37-62 */ + break; + case 4: + converted_rating = 75; /* 63-86 */ + break; + case 5: + converted_rating = 99; /* 87-100 */ + break; + default: + converted_rating = 0; /* otherwise */ + break; + } + + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_USERRATING, converted_rating)) { + success = FALSE; + goto DONE; + + } + + /*-------------AUDIOWAVECODEC--------------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_AUDIOWAVECODEC, + MTP_WAVEFORMAT_UNKNOWN)) { + success = FALSE; + goto DONE; + } + +DONE: + _util_free_common_meta(&(audio_data.commonmeta)); + return success; +} + +static mtp_bool __update_prop_values_video(mtp_obj_t *obj) +{ + mtp_bool success = TRUE; + mtp_int32 converted_rating = 0; + comp_video_meta_t video_data = { {0,}, {0,} }; + video_meta_t *viddata = &(video_data.videometa); + mtp_wchar buf[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + + retv_if(obj == NULL, FALSE); + retv_if(obj->obj_info == NULL, FALSE); + retv_if(obj->file_path == NULL, FALSE); + + if (_util_get_video_metadata(obj->file_path, &video_data) == FALSE) { + if (_util_get_video_meta_from_extractor(obj->file_path, + &video_data) == FALSE) { + success = FALSE; + goto DONE; + } + } + + /*Update common metadata information*/ + if (FALSE == __prop_common_metadata(obj, + &(video_data.commonmeta))) { + ERR("Common metadata update Fail"); + success = FALSE; + goto DONE; + } + + /*--------------TRACK--------------*/ + if ((viddata->track != NULL) && strlen(viddata->track) > 0) { + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_TRACK, + atoi(viddata->track))) { + success = FALSE; + goto DONE; + } + } + + /*--------------AUDIO WAVE CODEC--------------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_AUDIOWAVECODEC, 0)) { + success = FALSE; + goto DONE; + } + + /*--------------VIDEO CODEC--------------*/ + /* + * Conversion needs to be decided from audio_codec to + * exact format by spec + */ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_VIDEOFOURCCCODEC, 0)) { + success = FALSE; + goto DONE; + } + + /*--------------VIDEO FRAMES PER 1K SECONDS--------------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_FRAMESPER1KSECONDS, + viddata->video_fps * 1000)) { + success = FALSE; + goto DONE; + } + + /*--------------VIDEO BITRATE--------------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_VIDEOBITRATE, + viddata->video_br)) { + success = FALSE; + goto DONE; + } + + /*--------------VIDEO WIDTH--------------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_WIDTH, viddata->video_w)) { + success = FALSE; + goto DONE; + } + + /*--------------VIDEO HEIGHT--------------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_HEIGHT, viddata->video_h)) { + success = FALSE; + goto DONE; + } + + /*--------------USER RATING--------------*/ + switch (video_data.commonmeta.rating) { + case 1: + converted_rating = 1; /* 1-12 */ + break; + case 2: + converted_rating = 25; /* 13-37 */ + break; + case 3: + converted_rating = 50; /* 37-62 */ + break; + case 4: + converted_rating = 75; /* 63-86 */ + break; + case 5: + converted_rating = 99; /* 87-100 */ + break; + default: + converted_rating = 0; /* otherwise */ + break; + } + + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_USERRATING, converted_rating)) { + success = FALSE; + goto DONE; + } + + /*----------ENCODING PROFILE----------*/ + _util_utf8_to_utf16(buf, sizeof(buf) / WCHAR_SIZ, ""); + if (FALSE == __create_prop_string(obj, + MTP_OBJ_PROPERTYCODE_COPYRIGHTINFO, buf)) { + success = FALSE; + goto DONE; + } + + /*----------METAGENRE-----------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_METAGENRE, 0x00)) { + success = FALSE; + goto DONE; + } + + /*---------SCAN TYPE---------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_SCANTYPE, 0x00)) { + success = FALSE; + goto DONE; + } + +DONE: + _util_free_common_meta(&(video_data.commonmeta)); + _util_free_video_meta(&(video_data.videometa)); + return success; +} + +static mtp_bool __update_prop_values_image(mtp_obj_t *obj) +{ + image_meta_t image_data; + + retv_if(obj == NULL, FALSE); + retv_if(obj->obj_info == NULL, FALSE); + + if (_util_get_image_ht_wt(obj->file_path, &image_data) == FALSE) + return FALSE; + + /*--------------IMAGE WIDTH--------------*/ + if (FALSE == __create_prop_integer(obj, MTP_OBJ_PROPERTYCODE_WIDTH, + image_data.wt)) + return FALSE; + + /*--------------IMAGE HEIGHT--------------*/ + if (FALSE == __create_prop_integer(obj, MTP_OBJ_PROPERTYCODE_HEIGHT, + image_data.ht)) + return FALSE; + + return TRUE; +} + +static mtp_bool __prop_common_metadata(mtp_obj_t *obj, + common_meta_t *p_metata) +{ + mtp_wchar buf[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + + /*--------------ARTIST--------------*/ + if (p_metata->artist != NULL && strlen(p_metata->artist) > 0) { + _util_utf8_to_utf16(buf, sizeof(buf) / WCHAR_SIZ, + p_metata->artist); + } +#ifdef MTP_USE_FILL_EMPTYMETADATA_WITH_UNKNOWN + else { + DBG("got null artist"); + _util_utf8_to_utf16(buf, sizeof(buf) / WCHAR_SIZ, + MTP_UNKNOWN_METADATA); + } +#endif /*MTP_USE_FILL_EMPTYMETADATA_WITH_UNKNOWN*/ + + if (FALSE == __create_prop_string(obj, + MTP_OBJ_PROPERTYCODE_ARTIST, buf)) { + return FALSE; + } + + /*--------------ALBUM--------------*/ + if (p_metata->album != NULL && strlen(p_metata->album) > 0) { + _util_utf8_to_utf16(buf, sizeof(buf) / WCHAR_SIZ, + p_metata->album); + } +#ifdef MTP_USE_FILL_EMPTYMETADATA_WITH_UNKNOWN + else { + DBG("got null album"); + _util_utf8_to_utf16(buf, sizeof(buf) / WCHAR_SIZ, + MTP_UNKNOWN_METADATA); + } +#endif /*MTP_USE_FILL_EMPTYMETADATA_WITH_UNKNOWN*/ + + if (FALSE == __create_prop_string(obj, + MTP_OBJ_PROPERTYCODE_ALBUMNAME, buf)) { + return FALSE; + } + + /*--------------GENRE--------------*/ + if (p_metata->genre != NULL && strlen(p_metata->genre) > 0) { + _util_utf8_to_utf16(buf, sizeof(buf) / WCHAR_SIZ, + p_metata->genre); + } +#ifdef MTP_USE_FILL_EMPTYMETADATA_WITH_UNKNOWN + else { + DBG("got null genre"); + _util_utf8_to_utf16(buf, sizeof(buf) / WCHAR_SIZ, + MTP_UNKNOWN_METADATA); + } +#endif /*MTP_USE_FILL_EMPTYMETADATA_WITH_UNKNOWN*/ + + if (FALSE == __create_prop_string(obj, + MTP_OBJ_PROPERTYCODE_GENRE, buf)) { + return FALSE; + } + + /*--------------AUTHOR--------------*/ + if (p_metata->author != NULL && strlen(p_metata->author) > 0) { + _util_utf8_to_utf16(buf, sizeof(buf) / WCHAR_SIZ, + p_metata->author); + } +#ifdef MTP_USE_FILL_EMPTYMETADATA_WITH_UNKNOWN + else { + DBG("got null author"); + _util_utf8_to_utf16(buf, sizeof(buf) / WCHAR_SIZ, + MTP_UNKNOWN_METADATA); + } +#endif /*MTP_USE_FILL_EMPTYMETADATA_WITH_UNKNOWN*/ + + if (FALSE == __create_prop_string(obj, + MTP_OBJ_PROPERTYCODE_COMPOSER, buf)) { + return FALSE; + } + + /*--------------COPYRIGHT--------------*/ + if ((p_metata->copyright != NULL) && strlen(p_metata->copyright) > 0) { + _util_utf8_to_utf16(buf, + sizeof(buf) / WCHAR_SIZ, + p_metata->copyright); + } else { + _util_utf8_to_utf16(buf, + sizeof(buf) / WCHAR_SIZ, ""); + } + + if (FALSE == __create_prop_string(obj, + MTP_OBJ_PROPERTYCODE_COPYRIGHTINFO, buf)) { + return FALSE; + } + + /*--------------DURATION--------------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_DURATION, p_metata->duration)) { + return FALSE; + } + + /*--------------AUDIO BITRATE--------------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_AUDIOBITRATE, p_metata->audio_bitrate)) { + return FALSE; + } + + /*--------------RELEASE YEAR--------------*/ + if ((p_metata->year != NULL) && strlen(p_metata->year) > 0) { + _util_utf8_to_utf16(buf, + sizeof(buf) / WCHAR_SIZ, + p_metata->year); + } else { + _util_utf8_to_utf16(buf, + sizeof(buf) / WCHAR_SIZ, ""); + } + + if (FALSE == __create_prop_string(obj, + MTP_OBJ_PROPERTYCODE_ORIGINALRELEASEDATE, buf)) { + return FALSE; + } + + /*--------------DESCRIPTION--------------*/ + if ((p_metata->description != NULL) && + strlen(p_metata->description) > 0) { + _util_utf8_to_utf16(buf, + sizeof(buf) / WCHAR_SIZ, + p_metata->description); + } else { + _util_utf8_to_utf16(buf, + sizeof(buf) / WCHAR_SIZ, ""); + } + + if (FALSE == __create_prop_string(obj, + MTP_OBJ_PROPERTYCODE_DESCRIPTION, buf)) { + return FALSE; + } + + /*--------------SAMPLE RATE--------------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_SAMPLERATE, p_metata->sample_rate)) { + return FALSE; + } + + /*-------------NUMBEROFCHANNELS--------------*/ + if (FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_NUMBEROFCHANNELS, p_metata->num_channel)) { + return FALSE; + } + + return TRUE; +} + +static void __build_supported_common_props(mtp_uchar *count, + obj_prop_desc_t *prop) +{ + mtp_uchar i = 0; + mtp_wchar str[MTP_MAX_REG_STRING + 1] = { 0 }; + mtp_uint32 default_val; + + _util_utf8_to_utf16(str, sizeof(str) / WCHAR_SIZ, ""); + + /* + * MTP_OBJ_PROPERTYCODE_ARTIST (1) + */ + __init_obj_prop_desc((prop + i), + MTP_OBJ_PROPERTYCODE_ARTIST, + PTP_DATATYPE_STRING, + PTP_PROPGETSET_GETONLY, + NONE, + MTP_PROP_GROUPCODE_OBJECT); + _prop_set_default_string(&(prop[i].propinfo), str); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_DURATION (2) + */ + __init_obj_prop_desc((prop + i), + MTP_OBJ_PROPERTYCODE_DURATION, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, + MTP_PROP_GROUPCODE_OBJECT); + + default_val = 0x0; + _prop_set_range_integer(&(prop[i].propinfo), 0, 0xffffffff, 1L); + _prop_set_default_integer(&((prop[i].propinfo)), (mtp_uchar *) &default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_USERRATING (3) + */ + __init_obj_prop_desc((prop + i), + MTP_OBJ_PROPERTYCODE_USERRATING, + PTP_DATATYPE_UINT16, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, + MTP_PROP_GROUPCODE_OBJECT); + + default_val = 0x0; + _prop_set_range_integer(&(prop[i].propinfo), 0, 100, 1L); + _prop_set_default_integer(&(prop[i].propinfo), + (mtp_uchar *) &default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_TRACK (4) + */ + __init_obj_prop_desc((prop + i), + MTP_OBJ_PROPERTYCODE_TRACK, + PTP_DATATYPE_UINT16, + PTP_PROPGETSET_GETONLY, + NONE, + MTP_PROP_GROUPCODE_OBJECT); + + default_val = 0x0; + _prop_set_default_integer(&(prop[i].propinfo), + (mtp_uchar *) &default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_GENRE (5) + */ + __init_obj_prop_desc((prop + i), + MTP_OBJ_PROPERTYCODE_GENRE, + PTP_DATATYPE_STRING, + PTP_PROPGETSET_GETONLY, + NONE, + MTP_PROP_GROUPCODE_OBJECT); + _prop_set_default_string(&(prop[i].propinfo), str); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_ORIGINALRELEASEDATE (6) + */ + __init_obj_prop_desc((prop + i), + MTP_OBJ_PROPERTYCODE_ORIGINALRELEASEDATE, + PTP_DATATYPE_STRING, + PTP_PROPGETSET_GETONLY, + DATE_TIME_FORM, + MTP_PROP_GROUPCODE_OBJECT); + _prop_set_default_string(&(prop[i].propinfo), str); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_ALBUMNAME (7) + */ + __init_obj_prop_desc((prop + i), + MTP_OBJ_PROPERTYCODE_ALBUMNAME, + PTP_DATATYPE_STRING, + PTP_PROPGETSET_GETONLY, + NONE, + MTP_PROP_GROUPCODE_OBJECT); + _prop_set_default_string(&(prop[i].propinfo), str); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_COMPOSER (8) + */ + __init_obj_prop_desc((prop + i), + MTP_OBJ_PROPERTYCODE_COMPOSER, + PTP_DATATYPE_STRING, + PTP_PROPGETSET_GETONLY, + NONE, + MTP_PROP_GROUPCODE_OBJECT); + _prop_set_default_string(&(prop[i].propinfo), str); + i++; + + *count += i; + + return; +} + +/* PTP Array Functions */ +void _prop_init_ptparray(ptp_array_t *parray, data_type_t type) +{ + mtp_uint16 size = 0; + parray->num_ele = 0; + parray->type = type; + + size = __get_ptp_array_elem_size(type); + if (size == 0) + return; + + parray->array_entry = g_malloc(size * INITIAL_ARRAY_SIZE); + if (parray->array_entry == NULL) { + parray->arr_size = 0; + } else { + parray->arr_size = INITIAL_ARRAY_SIZE; + memset(parray->array_entry, 0, size * INITIAL_ARRAY_SIZE); + } + return; +} + +ptp_array_t *_prop_alloc_ptparray(data_type_t type) +{ + ptp_array_t *parray; + parray = (ptp_array_t *)g_malloc(sizeof(ptp_array_t)); + if (parray != NULL) { + _prop_init_ptparray(parray, type); + } + + return (parray); +} + +mtp_uint32 _prop_get_size_ptparray(ptp_array_t *parray) +{ + mtp_uint16 size = 0; + + if (parray == NULL) { + ERR("ptp_array_t is NULL"); + return 0; + } + + size = __get_ptp_array_elem_size(parray->type); + if (size == 0) + return 0; + + return (sizeof(mtp_uint32) + (size *parray->num_ele)); +} + +mtp_uint32 _prop_get_size_ptparray_without_elemsize(ptp_array_t *parray) +{ + mtp_uint16 size = 0; + + size = __get_ptp_array_elem_size(parray->type); + if (size == 0) + return 0; + + return (size * parray->num_ele); +} + +mtp_bool _prop_grow_ptparray(ptp_array_t *parray, mtp_uint32 new_size) +{ + mtp_uint16 size = 0; + + size = __get_ptp_array_elem_size(parray->type); + if (size == 0) + return FALSE; + + if (parray->arr_size == 0) + _prop_init_ptparray(parray, parray->type); + + if (new_size < parray->arr_size) + return TRUE; + + parray->array_entry = + g_realloc(parray->array_entry, size * new_size); + if (parray->array_entry == NULL) { + parray->arr_size = 0; + return FALSE; + } + parray->arr_size = new_size; + + return TRUE; +} + +mtp_int32 _prop_find_ele_ptparray(ptp_array_t *parray, mtp_uint32 element) +{ + mtp_uchar *ptr8 = NULL; + mtp_uint16 *ptr16 = NULL; + mtp_uint32 *ptr32 = NULL; + mtp_int32 ii; + + retv_if(parray->array_entry == NULL, ELEMENT_NOT_FOUND); + + switch (parray->type) { + case UINT8_TYPE: + ptr8 = parray->array_entry; + for (ii = 0; ii < parray->num_ele; ii++) { + if (ptr8[ii] == (mtp_uchar) element) { + return ii; + } + } + break; + + case UINT16_TYPE: + ptr16 = parray->array_entry; + for (ii = 0; ii < parray->num_ele; ii++) { + if (ptr16[ii] == (mtp_uint16) element) { + return ii; + } + } + break; + + case PTR_TYPE: + case UINT32_TYPE: + ptr32 = parray->array_entry; + for (ii = 0; ii < parray->num_ele; ii++) { + if (ptr32[ii] == (mtp_uint32)element) { + return ii; + } + } + break; + + default: + break; + } + return ELEMENT_NOT_FOUND; +} + +mtp_bool _prop_get_ele_ptparray(ptp_array_t *parray, mtp_uint32 index, void *ele) +{ + mtp_uchar *ptr8 = NULL; + mtp_uint16 *ptr16 = NULL; + mtp_uint32 *ptr32 = NULL; + + retv_if(parray->array_entry == NULL, FALSE); + + if (index >= parray->num_ele) + return FALSE; + + switch (parray->type) { + case UINT8_TYPE: + ptr8 = parray->array_entry; + *((mtp_uchar *)ele) = ptr8[index]; + break; + case UINT16_TYPE: + ptr16 = parray->array_entry; + *((mtp_uint16 *)ele) = ptr16[index]; + break; + + case PTR_TYPE: + case UINT32_TYPE: + ptr32 = parray->array_entry; + *((mtp_uint32 *)ele) = ptr32[index]; + break; + default: + return FALSE; + } + return TRUE; +} + +mtp_bool _prop_append_ele_ptparray(ptp_array_t *parray, mtp_uint32 element) +{ + + mtp_uchar *ptr8 = NULL; + mtp_uint16 *ptr16 = NULL; + mtp_uint32 *ptr32 = NULL; + + if (parray->num_ele >= parray->arr_size) { + ERR("parray->num_ele [%d] is bigger than parray->arr_size [%d]\n", + parray->num_ele, parray->arr_size); + if (FALSE == _prop_grow_ptparray(parray, + ((parray->arr_size * 3) >> 1) + 2)) + return FALSE; + } + + switch (parray->type) { + case UINT8_TYPE: + ptr8 = parray->array_entry; + ptr8[parray->num_ele++] = (mtp_uchar)element; + break; + + case UINT16_TYPE: + ptr16 = parray->array_entry; + ptr16[parray->num_ele++] = (mtp_uint16) element; + break; + + case PTR_TYPE: + case UINT32_TYPE: + ptr32 = parray->array_entry; + ptr32[parray->num_ele++] = (mtp_uint32)element; + break; + + default: + break; + } + + return TRUE; +} + +mtp_bool _prop_append_ele128_ptparray(ptp_array_t *parray, mtp_uint64 *element) +{ + mtp_uchar *ptr = NULL; + mtp_bool ret = FALSE; + if (parray->num_ele >= parray->arr_size) { + if (FALSE == _prop_grow_ptparray(parray, + ((parray->arr_size * 3) >> 1) + 2)) + return FALSE; + } + + switch (parray->type) { + case UINT128_TYPE: + ptr = parray->array_entry; + memcpy(&(ptr[(parray->num_ele * 16)]), element, + sizeof(mtp_uint64) * 2); + parray->num_ele++; + ret = TRUE; + break; + + default: + break; + } + + return ret; +} + +mtp_bool _prop_copy_ptparray(ptp_array_t *dst, ptp_array_t *src) +{ + mtp_uchar *ptr8src = NULL; + mtp_uint16 *ptr16src = NULL; + mtp_uint32 *ptr32src = NULL; + mtp_uint32 ii; + + dst->type = src->type; + + switch (src->type) { + case UINT8_TYPE: + ptr8src = src->array_entry; + for (ii = 0; ii < src->num_ele; ii++) + _prop_append_ele_ptparray(dst, ptr8src[ii]); + break; + + case UINT16_TYPE: + ptr16src = src->array_entry; + for (ii = 0; ii < src->num_ele; ii++) + _prop_append_ele_ptparray(dst, ptr16src[ii]); + break; + + case PTR_TYPE: + case UINT32_TYPE: + ptr32src = src->array_entry; + for (ii = 0; ii < src->num_ele; ii++) + _prop_append_ele_ptparray(dst, ptr32src[ii]); + break; + + default: + return 0; + } + return TRUE; +} + +mtp_uint32 _prop_pack_ptparray(ptp_array_t *parray, mtp_uchar *buf, + mtp_uint32 bufsize) +{ + if (parray == NULL || buf == NULL) { + ERR("pArray or buf is NULL"); + return 0; + } + + mtp_uint16 size = 1; + + size = __get_ptp_array_elem_size(parray->type); + if (size == 0) + return 0; + + if ((buf == NULL) || (bufsize < (sizeof(mtp_uint32) + + parray->num_ele * size))) + return 0; + + memcpy(buf, &(parray->num_ele), sizeof(mtp_uint32)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(buf, sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + + if (parray->num_ele != 0) { +#ifdef __BIG_ENDIAN__ + mtp_uint32 ii; + mtp_uchar *temp = buf + sizeof(mtp_uint32); + mtp_uchar *ptr_entry = parray->array_entry; + + for (ii = 0; ii < parray->num_ele; ii++) { + memcpy(temp, ptr_entry, size); + _util_conv_byte_order(temp, size); + temp += size; + ptr_entry += size; + } +#else /* __BIG_ENDIAN__ */ + memcpy(buf + sizeof(mtp_uint32), parray->array_entry, + parray->num_ele * size); +#endif /* __BIG_ENDIAN__ */ + } + return (sizeof(mtp_uint32) + parray->num_ele * size); +} + +mtp_uint32 _prop_pack_ptparray_without_elemsize(ptp_array_t *parray, + mtp_uchar *buf, mtp_uint32 bufsize) +{ + mtp_uint16 size = 1; +#ifdef __BIG_ENDIAN__ + mtp_uchar *temp; + mtp_uint32 ii; +#endif /* __BIG_ENDIAN__ */ + + size = __get_ptp_array_elem_size(parray->type); + if (size == 0) + return 0; + + if ((buf == NULL) || (bufsize < (parray->num_ele * size))) + return 0; + + if (parray->num_ele != 0) + memcpy(buf, parray->array_entry, parray->num_ele * size); + +#ifdef __BIG_ENDIAN__ + /* Swap all the elements */ + temp = buf; + for (ii = 0; ii < parray->num_ele; ii++) { + _util_conv_byte_order(temp, size); + temp += size; + } +#endif /* __BIG_ENDIAN__ */ + + return (parray->num_ele * size); +} + +mtp_bool _prop_rem_elem_ptparray(ptp_array_t *parray, mtp_uint32 element) +{ + mtp_uchar *ptr8 = NULL; + mtp_uint16 *ptr16 = NULL; + mtp_uint32 *ptr32 = NULL; + mtp_int32 ii; + + ii = _prop_find_ele_ptparray(parray, element); + + if (ii == ELEMENT_NOT_FOUND) + return FALSE; + + switch (parray->type) { + case UINT8_TYPE: + ptr8 = parray->array_entry; + for (; ii < (parray->num_ele - 1); ii++) + ptr8[ii] = ptr8[ii + 1]; + break; + + case UINT16_TYPE: + ptr16 = parray->array_entry; + for (; ii < (parray->num_ele - 1); ii++) + ptr16[ii] = ptr16[ii + 1]; + break; + + case UINT32_TYPE: + ptr32 = parray->array_entry; + for (; ii < (parray->num_ele - 1); ii++) + ptr32[ii] = ptr32[ii + 1]; + break; + + case PTR_TYPE: + ptr32 = parray->array_entry; + for (; ii < (parray->num_ele - 1); ii++) + ptr32[ii] = ptr32[ii + 1]; + break; + + default: + break; + } + + parray->num_ele--; + + return TRUE; + +} + +void _prop_deinit_ptparray(ptp_array_t *parray) +{ + parray->num_ele = 0; + parray->arr_size = 0; + if (parray->array_entry) { + g_free(parray->array_entry); + } + parray->array_entry = NULL; + return; +} + +void _prop_destroy_ptparray(ptp_array_t *parray) +{ + if (parray == NULL) + return; + + if (parray->array_entry != NULL) { + g_free(parray->array_entry); + } + parray->arr_size = 0; + parray->num_ele = 0; + g_free(parray); + return; +} + +mtp_uint16 __get_ptp_array_elem_size(data_type_t type) +{ + mtp_uint16 size = 0; + + switch (type) { + case UINT8_TYPE: + size = 1; + break; + case UINT16_TYPE: + size = 2; + break; + case PTR_TYPE: + case UINT32_TYPE: + size = 4; + break; + case UINT128_TYPE: + size = 16; + break; + default: + size = 0; + break; + } + + return size; +} + +/* PtpString Functions */ +#ifndef MTP_USE_VARIABLE_PTP_STRING_MALLOC +static ptp_string_t *__alloc_ptpstring(void) +{ + ptp_string_t *pstring = NULL; + + pstring = (ptp_string_t *)g_malloc(sizeof(ptp_string_t)); + if (pstring != NULL) { + _prop_init_ptpstring(pstring); + } + + return (pstring); +} +#else /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ +static ptp_string_t *__alloc_ptpstring(mtp_uint32 size) +{ + ptp_string_t *pstring = NULL; + mtp_int32 size_tmp = 0; + mtp_int32 alloc_size = 0; + + size_tmp = sizeof(wchar_t) * size + sizeof(wchar_t) * 2; + alloc_size = ((size_tmp >> 5) + 1) << 5; /* multiple of 32 */ + + pstring = (ptp_string_t *)g_malloc(alloc_size); /* for margin */ + if (pstring != NULL) { + _prop_init_ptpstring(pstring); + } + + return (pstring); +} +#endif /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + +void _prop_init_ptpstring(ptp_string_t *pstring) +{ + pstring->num_chars = 0; + return; +} + +static void __init_ptptimestring(ptp_time_string_t *pstring) +{ + pstring->num_chars = 0; +} + +void _prop_copy_char_to_ptpstring(ptp_string_t *pstring, void *str, + char_mode_t cmode) +{ + if (pstring == NULL) + return; + + mtp_char *pchar = NULL; + mtp_wchar *pwchar = NULL; + mtp_uchar i = 0; + + pchar = (mtp_char *)str; + pwchar = (mtp_wchar *)str; + + if (str == NULL) { + pstring->num_chars = 0; + return; + } + + if (cmode == CHAR_TYPE) { + if (pchar[0] == 0) { + pstring->num_chars = 0; + return; + } + for (i = 0; i < MAX_PTP_STRING_CHARS && pchar[i]; i++) { + pstring->str[i] = (mtp_wchar)pchar[i]; + } + } else if (cmode == WCHAR_TYPE) { + if (pwchar[0] == 0) { + pstring->num_chars = 0; + return; + } + for (i = 0; i < MAX_PTP_STRING_CHARS && pwchar[i]; i++) { + pstring->str[i] = pwchar[i]; + } + } else { + ERR("Unknown character mode : %d\n", cmode); + pstring->num_chars = 0; + return; + } + + if (i == MAX_PTP_STRING_CHARS) + pstring->num_chars = i; + else + pstring->num_chars = i + 1; + + pstring->str[pstring->num_chars - 1] = (mtp_wchar)0; + + return; +} + +void _prop_copy_time_to_ptptimestring(ptp_time_string_t *pstring, + system_time_t *sys_time) +{ + char time[17] = { 0 }; + + if (sys_time == NULL) { + __init_ptptimestring(pstring); + } else { +#if defined(NEED_TO_PORT) + _util_wchar_swprintf(pstring->str, sizeof(pstring->str) / WCHAR_SIZ, + "%04d%02d%02dT%02d%02d%02d.%01d", + sys_time->year, sys_time->month, + sys_time->day, sys_time->hour, + sys_time->minute, sys_time->second, + (sys_time->millisecond) / 100); +#else + g_snprintf(time, sizeof(time), "%04d%02d%02dT%02d%02d%02d.%01d", + sys_time->year, sys_time->month, sys_time->day, + sys_time->hour, sys_time->minute, + sys_time->second, (sys_time->millisecond) / 100); + + _util_utf8_to_utf16(pstring->str, sizeof(pstring->str) / WCHAR_SIZ, time); +#endif + pstring->num_chars = 17; + pstring->str[17] = '\0'; + } + return; +} + +void _prop_copy_ptpstring(ptp_string_t *dst, ptp_string_t *src) +{ + mtp_uint16 ii; + + dst->num_chars = src->num_chars; + for (ii = 0; ii < src->num_chars; ii++) { + dst->str[ii] = src->str[ii]; + } + return; +} + +void _prop_copy_ptptimestring(ptp_time_string_t *dst, ptp_time_string_t *src) +{ + mtp_uint16 ii; + + dst->num_chars = src->num_chars; + for (ii = 0; ii < src->num_chars; ii++) { + dst->str[ii] = src->str[ii]; + } + return; +} + +mtp_bool _prop_is_equal_ptpstring(ptp_string_t *dst, ptp_string_t *src) +{ + mtp_uint16 ii; + + if (dst->num_chars != src->num_chars) + return FALSE; + + for (ii = 0; ii < dst->num_chars; ii++) { + if (dst->str[ii] != src->str[ii]) + return FALSE; + } + return TRUE; +} + +mtp_uint32 _prop_size_ptpstring(ptp_string_t *pstring) +{ + if (pstring == NULL) + return 0; + + return (pstring->num_chars * sizeof(mtp_wchar) + 1); +} + +mtp_uint32 _prop_size_ptptimestring(ptp_time_string_t *pstring) +{ + if (pstring == NULL) + return 0; + + return (pstring->num_chars * sizeof(mtp_wchar) + 1); +} + +mtp_uint32 _prop_pack_ptpstring(ptp_string_t *pstring, mtp_uchar *buf, + mtp_uint32 size) +{ + mtp_uint32 bytes_written = 0; + mtp_uint32 ii; + mtp_uchar *pchar = NULL; +#ifdef __BIG_ENDIAN__ + mtp_wchar conv_str[MAX_PTP_STRING_CHARS]; +#endif /* __BIG_ENDIAN__ */ + + if ((buf == NULL) || (pstring == NULL) || (size == 0) || + (size < _prop_size_ptpstring(pstring))) { + return bytes_written; + } + + if (pstring->num_chars == 0) { + buf[0] = 0; + bytes_written = 1; + } else { +#ifdef __BIG_ENDIAN__ + memcpy(conv_str, pstring->str, + pstring->num_chars * sizeof(mtp_wchar)); + _util_conv_byte_orderForWString(conv_str, pstring->num_chars); + pchar = (mtp_uchar *) conv_str; +#else /* __BIG_ENDIAN__ */ + pchar = (mtp_uchar *) pstring->str; +#endif /* __BIG_ENDIAN__ */ + buf[0] = pstring->num_chars; + + bytes_written = _prop_size_ptpstring(pstring); + for (ii = 0; ii < (bytes_written - 1); ii++) { + buf[ii + 1] = pchar[ii]; + } + } + return bytes_written; +} + +mtp_uint32 _prop_pack_ptptimestring(ptp_time_string_t *pstring, mtp_uchar *buf, + mtp_uint32 size) +{ + mtp_uint32 bytes_written = 0; + mtp_uchar *pchar = NULL; +#ifdef __BIG_ENDIAN__ + mtp_wchar conv_str[MAX_PTP_STRING_CHARS]; +#endif /* __BIG_ENDIAN__ */ + + if ((buf == NULL) || (pstring == NULL) || (size == 0) || + (size < _prop_size_ptptimestring(pstring))) { + return bytes_written; + } + + if (pstring->num_chars == 0) { + buf[0] = 0; + bytes_written = 1; + } else { +#ifdef __BIG_ENDIAN__ + memcpy(conv_str, pstring->str, + pstring->num_chars * sizeof(mtp_wchar)); + _util_conv_byte_order_wstring(conv_str, pstring->num_chars); + pchar = (mtp_uchar *)conv_str; +#else /* __BIG_ENDIAN__ */ + pchar = (mtp_uchar *)pstring->str; +#endif /* __BIG_ENDIAN__ */ + buf[0] = pstring->num_chars; + + bytes_written = _prop_size_ptptimestring(pstring); + + memcpy(&buf[1], pchar, bytes_written - 1); + + } + return bytes_written; +} + +mtp_uint32 _prop_parse_rawstring(ptp_string_t *pstring, mtp_uchar *buf, + mtp_uint32 size) +{ + mtp_uint16 ii; + + if (buf == NULL) { + return 0; + } + + if (buf[0] == 0) { + pstring->num_chars = 0; + return 1; + } else { + pstring->num_chars = buf[0]; + ii = (mtp_uint16) ((size - 1) / sizeof(mtp_wchar)); + if (pstring->num_chars > ii) { + pstring->num_chars = (mtp_uchar)ii; + } + + for (ii = 1; ii <= pstring->num_chars; ii++) { +#ifdef __BIG_ENDIAN__ + pstring->str[ii - 1] = + buf[2 * ii] | (buf[2 * ii - 1] << 8); +#else /* __BIG_ENDIAN__ */ + pstring->str[ii - 1] = + buf[2 * ii - 1] | (buf[2 * ii] << 8); +#endif /* __BIG_ENDIAN__ */ + } + pstring->str[pstring->num_chars - 1] = (mtp_wchar) 0; + return _prop_size_ptpstring(pstring); + } +} + +void _prop_destroy_ptpstring(ptp_string_t *pstring) +{ + if (pstring != NULL) { + g_free(pstring); + } + return; +} + +mtp_bool _prop_is_valid_integer(prop_info_t *prop_info, mtp_uint64 value) +{ + if ((prop_info->data_type & PTP_DATATYPE_VALUEMASK) != + PTP_DATATYPE_VALUE) { + return FALSE; + } + + if (prop_info->form_flag == RANGE_FORM) { + if ((value >= prop_info->range.min_val) && + (value <= prop_info->range.max_val)) { + return TRUE; + } else { + /* invalid value */ + return FALSE; + } + } else if (prop_info->form_flag == ENUM_FORM) { + slist_node_t *node = prop_info->supp_value_list.start; + mtp_uint32 ii; + for (ii = 0; ii < prop_info->supp_value_list.nnodes; + ii++, node = node->link) { + if (value == (mtp_uint32) node->value) { + return TRUE; + } + } + + /* if it hits here, must be an invalid value */ + return FALSE; + } else if (prop_info->form_flag == NONE) { + /* No restrictions */ + return TRUE; + } + + /* shouldn't be here */ + return FALSE; +} + +mtp_bool _prop_is_valid_string(prop_info_t *prop_info, ptp_string_t *pstring) +{ + if ((prop_info->data_type != PTP_DATATYPE_STRING) || (pstring == NULL)) { + return FALSE; + } + + if (prop_info->form_flag == ENUM_FORM) + { + slist_node_t *node = NULL; + mtp_uint32 ii; + ptp_string_t *ele_str = NULL; + + node = prop_info->supp_value_list.start; + for (ii = 0; ii < prop_info->supp_value_list.nnodes; + ii++, node = node->link) { + ele_str = (ptp_string_t *) node->value; + if (ele_str != NULL) { + if (_prop_is_equal_ptpstring(pstring, ele_str)) { + /* value found in the list of supported values */ + return TRUE; + } + } + } + /* if it hits here, must be an invalid value */ + return FALSE; + } else if (prop_info->form_flag == NONE) { + /* No restrictions */ + return TRUE; + } else if (prop_info->form_flag == DATE_TIME_FORM) { + mtp_wchar *date_time = pstring->str; + if ((date_time[8] != L'T') && (pstring->num_chars > 9)) { + ERR("invalid data time format"); + return FALSE; + } + return TRUE; + } else if (prop_info->form_flag == REGULAR_EXPRESSION_FORM) { + return TRUE; + } + + return TRUE; +} + +mtp_bool _prop_set_default_string(prop_info_t *prop_info, mtp_wchar *val) +{ + if (prop_info->data_type == PTP_DATATYPE_STRING) { + _prop_destroy_ptpstring(prop_info->default_val.str); +#ifndef MTP_USE_VARIABLE_PTP_STRING_MALLOC + prop_info->default_val.str = __alloc_ptpstring(); +#else /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + prop_info->default_val.str = __alloc_ptpstring(_util_wchar_len(val)); +#endif /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + if (NULL == prop_info->default_val.str) + return FALSE; + + _prop_copy_char_to_ptpstring(prop_info->default_val.str, + val, WCHAR_TYPE); + return TRUE; + } + else { + return FALSE; + } +} + +mtp_bool _prop_set_default_integer(prop_info_t *prop_info, mtp_uchar *value) +{ + if ((prop_info->data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + memcpy(prop_info->default_val.integer, value, + prop_info->dts_size); + return TRUE; + } else { + return FALSE; + } +} + +mtp_bool _prop_set_default_array(prop_info_t *prop_info, mtp_uchar *parray, + mtp_uint32 num_ele) +{ + /* Allocate memory for the PTP array */ + if ((prop_info->data_type == PTP_DATATYPE_AUINT8) || + (prop_info->data_type == PTP_DATATYPE_AINT8)) + prop_info->default_val.array = _prop_alloc_ptparray(UINT8_TYPE); + else if ((prop_info->data_type == PTP_DATATYPE_AUINT16) || + (prop_info->data_type == PTP_DATATYPE_AINT16)) + prop_info->default_val.array = _prop_alloc_ptparray(UINT16_TYPE); + else if ((prop_info->data_type == PTP_DATATYPE_AUINT32) || + (prop_info->data_type == PTP_DATATYPE_AINT32)) + prop_info->default_val.array = _prop_alloc_ptparray(UINT32_TYPE); + else + return FALSE; + + if (prop_info->default_val.array == NULL) + return FALSE; + + /* Copies the data into the PTP array */ + if ((prop_info->default_val.array != NULL) && (num_ele != 0)) + { + mtp_uchar *ptr8 = NULL; + mtp_uint16 *ptr16 = NULL; + mtp_uint32 *ptr32 = NULL; + mtp_uint32 ii; + + _prop_grow_ptparray(prop_info->default_val.array, num_ele); + + if ((prop_info->data_type == PTP_DATATYPE_AUINT8) || + (prop_info->data_type == PTP_DATATYPE_AINT8)) + { + ptr8 = (mtp_uchar *) parray; + for (ii = 0; ii < num_ele; ii++) + _prop_append_ele_ptparray(prop_info->default_val.array, + ptr8[ii]); + + } else if ((prop_info->data_type == PTP_DATATYPE_AUINT16) || + (prop_info->data_type == PTP_DATATYPE_AINT16)) { + + ptr16 = (mtp_uint16 *) parray; + for (ii = 0; ii < num_ele; ii++) + _prop_append_ele_ptparray(prop_info->default_val.array, + ptr16[ii]); + + } else if ((prop_info->data_type == PTP_DATATYPE_AUINT32) || + (prop_info->data_type == PTP_DATATYPE_AINT32)) { + + ptr32 = (mtp_uint32 *)parray; + for (ii = 0; ii < num_ele; ii++) + _prop_append_ele_ptparray(prop_info->default_val.array, + ptr32[ii]); + } + return TRUE; + } + return FALSE; +} + +mtp_bool _prop_set_current_integer(device_prop_desc_t *prop, mtp_uint32 val) +{ + if (_prop_is_valid_integer(&(prop->propinfo), val)) { + mtp_int32 ii; + mtp_uchar *ptr; + + ptr = (mtp_uchar *) &val; + + for (ii = 0; ii < sizeof(mtp_uint32); ii++) { + prop->current_val.integer[ii] = ptr[ii]; + } + + return TRUE; + } else { + /* setting invalid value */ + return FALSE; + } +} + +mtp_bool _prop_set_current_string(device_prop_desc_t *prop, ptp_string_t *str) +{ + if (_prop_is_valid_string(&(prop->propinfo), str)) + { + _prop_destroy_ptpstring(prop->current_val.str); +#ifndef MTP_USE_VARIABLE_PTP_STRING_MALLOC + prop->current_val.str = __alloc_ptpstring(); +#else /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + prop->current_val.str = __alloc_ptpstring(str->num_chars); +#endif /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + if (prop->current_val.str != NULL) { + _prop_copy_ptpstring(prop->current_val.str, str); + return TRUE; + } + else { + _prop_destroy_ptpstring(prop->current_val.str); + return FALSE; + } + } else { + /* setting invalid value */ + return FALSE; + } +} + +mtp_bool _prop_set_current_array(device_prop_desc_t *prop, mtp_uchar *arr) +{ + mtp_uint32 num_ele = 0; + mtp_uchar *pval = NULL; + memcpy(&num_ele, arr, sizeof(mtp_uint32)); + pval = arr + sizeof(mtp_uint32); + +#ifdef __BIG_ENDIAN__ + /* Byte swap the number of elements */ + _util_conv_byte_order(&num_ele, sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + + /* Allocate memory for the PTP array */ + if ((prop->propinfo.data_type == PTP_DATATYPE_AUINT8) || + (prop->propinfo.data_type == PTP_DATATYPE_AINT8)) { + _prop_destroy_ptparray(prop->current_val.array); + prop->current_val.array = _prop_alloc_ptparray(UINT8_TYPE); + + } else if ((prop->propinfo.data_type == PTP_DATATYPE_AUINT16) || + (prop->propinfo.data_type == PTP_DATATYPE_AINT16)) { + + _prop_destroy_ptparray(prop->current_val.array); + prop->current_val.array = _prop_alloc_ptparray(UINT16_TYPE); + + } else if ((prop->propinfo.data_type == PTP_DATATYPE_AUINT32) || + (prop->propinfo.data_type == PTP_DATATYPE_AINT32)) { + + _prop_destroy_ptparray(prop->current_val.array); + prop->current_val.array = _prop_alloc_ptparray(UINT32_TYPE); + + } else + return FALSE; + + /* Copies the data into the PTP array */ + if ((prop->current_val.array != NULL) && (num_ele != 0)) { + mtp_uchar *ptr8 = NULL; + mtp_uint16 *ptr16 = NULL; + mtp_uint32 *ptr32 = NULL; + mtp_uint32 ii; +#ifdef __BIG_ENDIAN__ + /* Some temporary variables for swapping the bytes */ + mtp_uint16 swap16; + mtp_uint32 swap32; +#endif /* __BIG_ENDIAN__ */ + + _prop_grow_ptparray(prop->current_val.array, num_ele); + + if ((prop->propinfo.data_type == PTP_DATATYPE_AUINT8) || + (prop->propinfo.data_type == PTP_DATATYPE_AINT8)) { + + ptr8 = (mtp_uchar *) pval; + for (ii = 0; ii < num_ele; ii++) + _prop_append_ele_ptparray(prop->current_val.array, + ptr8[ii]); + + } else if ((prop->propinfo.data_type == PTP_DATATYPE_AUINT16) || + (prop->propinfo.data_type == PTP_DATATYPE_AINT16)) { + + ptr16 = (mtp_uint16 *) pval; + for (ii = 0; ii < num_ele; ii++) { +#ifdef __BIG_ENDIAN__ + swap16 = ptr16[ii]; + _util_conv_byte_order(&swap16, sizeof(mtp_uint16)); + _prop_append_ele_ptparray(prop->current_val.array, + swap16); +#else /* __BIG_ENDIAN__ */ + _prop_append_ele_ptparray(prop->current_val.array, + ptr16[ii]); +#endif /* __BIG_ENDIAN__ */ + } + } else if ((prop->propinfo.data_type == PTP_DATATYPE_AUINT32) || + (prop->propinfo.data_type == PTP_DATATYPE_AINT32)) { + + ptr32 = (mtp_uint32 *) pval; + for (ii = 0; ii < num_ele; ii++) { +#ifdef __BIG_ENDIAN__ + swap32 = ptr32[ii]; + _util_conv_byte_order(&swap32, sizeof(mtp_uint32)); + _prop_append_ele_ptparray(prop->current_val.array, + swap32); +#else /* __BIG_ENDIAN__ */ + _prop_append_ele_ptparray(prop->current_val.array, + ptr32[ii]); +#endif /* __BIG_ENDIAN__ */ + } + } + return TRUE; + } + + return FALSE; +} + +mtp_bool _prop_set_current_device_prop(device_prop_desc_t *prop, mtp_uchar *val, + mtp_uint32 size) +{ + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + ptp_string_t str; + _prop_init_ptpstring(&str); + _prop_parse_rawstring(&str, val, size); + return _prop_set_current_string(prop, &str); + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + mtp_uint32 *ptr = (mtp_uint32 *) val; + if (size < sizeof(mtp_uint32)) { + return FALSE; + } + if (size < sizeof(mtp_uint32) + ptr[0] * prop->propinfo.dts_size) { + return FALSE; + } + return _prop_set_current_array(prop, val); + + } + else if ((prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + + if (prop->propinfo.dts_size > size) { + return FALSE; + } + + if ((prop->propinfo.data_type == PTP_DATATYPE_INT64) || + (prop->propinfo.data_type == PTP_DATATYPE_UINT64) || + (prop->propinfo.data_type == PTP_DATATYPE_INT128) || + (prop->propinfo.data_type == PTP_DATATYPE_UINT128)) { + + /* No validation at this time */ + memcpy(prop->current_val.integer, val, + prop->propinfo.dts_size); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(prop->current_val.integer, + prop->propinfo.dts_size); +#endif /* __BIG_ENDIAN__ */ + return TRUE; + } else { + /* avoid using new_val = *(ddword*)val; */ + mtp_uint32 new_val = (mtp_uint32)0; + memcpy(&new_val, val, size); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(&new_val, sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + return _prop_set_current_integer(prop, new_val); + } + } + + return FALSE; +} + +mtp_bool _prop_set_current_integer_val(obj_prop_val_t *pval, mtp_uint64 val) +{ + if (_prop_is_valid_integer(&(pval->prop->propinfo), val)) { + memset(pval->current_val.integer, 0, + pval->prop->propinfo.dts_size * sizeof(mtp_byte)); + memcpy(pval->current_val.integer, &val, + pval->prop->propinfo.dts_size * sizeof(mtp_byte)); + return TRUE; + } else { + /* setting invalid value */ + return FALSE; + } +} + +mtp_bool _prop_set_current_string_val(obj_prop_val_t *pval, ptp_string_t *str) +{ + if (_prop_is_valid_string(&(pval->prop->propinfo), str)) { + _prop_destroy_ptpstring(pval->current_val.str); +#ifndef MTP_USE_VARIABLE_PTP_STRING_MALLOC + pval->current_val.str = __alloc_ptpstring(); +#else /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + pval->current_val.str = __alloc_ptpstring(str->num_chars); +#endif /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + if (pval->current_val.str != NULL) { + _prop_copy_ptpstring (pval->current_val.str, str); + return TRUE; + } else + return FALSE; + } else { + /* setting invalid value */ + return FALSE; + } +} + +mtp_bool _prop_set_current_array_val(obj_prop_val_t *pval, mtp_uchar *arr, + mtp_uint32 size) +{ + mtp_uint32 num_ele = 0; + mtp_uchar *value = NULL; + prop_info_t *propinfo = NULL; + + propinfo = &(pval->prop->propinfo); + + if (propinfo->data_type == PTP_DATATYPE_STRING) { + ptp_string_t str; + _prop_init_ptpstring(&str); + _prop_parse_rawstring(&str, arr, size); + return _prop_set_current_string_val(pval, &str); + + } else if ((propinfo->data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + if (size < sizeof(mtp_uint32)) + return FALSE; + + memcpy(&num_ele, arr, sizeof(mtp_uint32)); + DBG("parsed array num [%d]\n", num_ele); + + if (size < sizeof(mtp_uint32) + + num_ele * (propinfo->dts_size)) { + + ERR("buffer size is not enough [%d]\n", size); + return FALSE; + } + + value = arr + sizeof(mtp_uint32); + + if ((propinfo->data_type == PTP_DATATYPE_AUINT8) || + (propinfo->data_type == PTP_DATATYPE_AINT8)) { + + _prop_destroy_ptparray(pval->current_val.array); + pval->current_val.array = _prop_alloc_ptparray(UINT8_TYPE); + + } else if ((propinfo->data_type == PTP_DATATYPE_AUINT16) || + (propinfo->data_type == PTP_DATATYPE_AINT16)) { + + _prop_destroy_ptparray(pval->current_val.array); + pval->current_val.array = _prop_alloc_ptparray(UINT16_TYPE); + + } else if ((propinfo->data_type == PTP_DATATYPE_AUINT32) || + (propinfo->data_type == PTP_DATATYPE_AINT32)) { + + _prop_destroy_ptparray(pval->current_val.array); + pval->current_val.array = _prop_alloc_ptparray(UINT32_TYPE); + } + + /* Copies the data into the PTP array */ + if ((pval->current_val.array != NULL) && (num_ele != 0)) { + mtp_uchar *ptr8 = NULL; + mtp_uint16 *ptr16 = NULL; + mtp_uint32 *ptr32 = NULL; + mtp_uint32 ii; + + _prop_grow_ptparray(pval->current_val.array, num_ele); + + if ((propinfo->data_type == PTP_DATATYPE_AUINT8) || + (propinfo->data_type == PTP_DATATYPE_AINT8)) { + + ptr8 = (mtp_uchar *) value; + for (ii = 0; ii < num_ele; ii++) + _prop_append_ele_ptparray(pval->current_val.array, + ptr8[ii]); + + } else if ((propinfo->data_type == PTP_DATATYPE_AUINT16) || + (propinfo->data_type == PTP_DATATYPE_AINT16)) { + ptr16 = (mtp_uint16 *) value; + for (ii = 0; ii < num_ele; ii++) + _prop_append_ele_ptparray(pval->current_val.array, + ptr16[ii]); + + } else if ((propinfo->data_type == PTP_DATATYPE_AUINT32) || + (propinfo->data_type == PTP_DATATYPE_AINT32)) { + + ptr32 = (mtp_uint32 *)value; + for (ii = 0; ii < num_ele; ii++) + _prop_append_ele_ptparray(pval->current_val.array, + ptr32[ii]); + } + } + return TRUE; + } else if ((propinfo->data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + + if (propinfo->dts_size > size) + return FALSE; + + if ((propinfo->data_type == PTP_DATATYPE_INT64) || + (propinfo->data_type == PTP_DATATYPE_UINT64) || + (propinfo->data_type == PTP_DATATYPE_INT128) || + (propinfo->data_type == PTP_DATATYPE_UINT128)) { + + if (propinfo->data_type == PTP_DATATYPE_UINT64) { + memcpy(pval->current_val.integer, arr, + propinfo->dts_size); + } + memcpy(pval->current_val.integer, arr, + propinfo->dts_size); + return TRUE; + } else { + + mtp_uint32 new_val = 0; + memcpy(&new_val, arr, propinfo->dts_size); + return _prop_set_current_integer_val(pval, + new_val); + } + } + return FALSE; +} + +#ifdef __BIG_ENDIAN__ +mtp_bool _prop_set_current_array_val_usbrawdata(obj_prop_val_t *pval, + mtp_uchar *arr, mtp_uint32 size) +{ + mtp_uint32 num_ele = 0; + mtp_uchar *value = NULL; + prop_info_t *propinfo = NULL; + + propinfo = &(pval->prop->propinfo); + + if (propinfo->data_type == PTP_DATATYPE_STRING) { + ptp_string_t str; + _prop_init_ptpstring(&str); + _prop_parse_rawstring(&str, arr, size); + return _prop_set_current_string_val(pval, &str); + + } else if ((propinfo->data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + if (size < sizeof(mtp_uint32)) + return FALSE; + + memcpy(&num_ele, arr, sizeof(mtp_uint32)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(&num_ele, sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + if (size < sizeof(mtp_uint32) + num_ele * propinfo->dts_size) + return FALSE; + + value = arr + sizeof(mtp_uint32); + + if ((propinfo->data_type == PTP_DATATYPE_AUINT8) || + (propinfo->data_type == PTP_DATATYPE_AINT8)) { + + _prop_destroy_ptparray(pval->current_val.array); + pval->current_val.array = _prop_alloc_ptparray(UINT8_TYPE); + + } else if ((propinfo->data_type == PTP_DATATYPE_AUINT16) || + (propinfo->data_type == PTP_DATATYPE_AINT16)) { + + _prop_destroy_ptparray(pval->current_val.array); + pval->current_val.array = _prop_alloc_ptparray(UINT16_TYPE); + + } else if ((propinfo->data_type == PTP_DATATYPE_AUINT32) || + (propinfo->data_type == PTP_DATATYPE_AINT32)) { + + _prop_destroy_ptparray(pval->current_val.array); + pval->current_val.array = _prop_alloc_ptparray(UINT32_TYPE); + + } + + /* Copies the data into the PTP array */ + if ((pval->current_val.array != NULL) && (num_ele != 0)) { + + mtp_uchar *ptr8 = NULL; + mtp_uint16 *ptr16 = NULL; + mtp_uint32 *ptr32 = NULL; + mtp_uint32 ii; + + _prop_grow_ptparray(pval->current_val.array, num_ele); + + if ((propinfo->data_type == PTP_DATATYPE_AUINT8) || + (propinfo->data_type == PTP_DATATYPE_AINT8)) { + + ptr8 = (mtp_uchar *) arr; + for (ii = 0; ii < num_ele; ii++) + _prop_append_ele_ptparray(pval->current_val.array, + ptr8[ii]); + + } else if ((propinfo->data_type == PTP_DATATYPE_AUINT16) || + (propinfo->data_type == + PTP_DATATYPE_AINT16)) { + + ptr16 = (mtp_uint16 *) arr; +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order_gen_str(ptr16, + num_ele, sizeof(mtp_uint16)); +#endif /* __BIG_ENDIAN__ */ + for (ii = 0; ii < num_ele; ii++) + _prop_append_ele_ptparray(pval->current_val.array, + ptr16[ii]); + + } else if ((propinfo->data_type == PTP_DATATYPE_AUINT32) || + (propinfo->data_type == + PTP_DATATYPE_AINT32)) { + + ptr32 = (mtp_uint32 *) arr; +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order_gen_str(ptr32, num_ele, + sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + for (ii = 0; ii < num_ele; ii++) + _prop_append_ele_ptparray(pval->current_val.array, + ptr32[ii]); + } + } + return TRUE; + } else if ((propinfo->data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + + if (propinfo->dts_size > size) + return FALSE; + + if ((propinfo->data_type == PTP_DATATYPE_INT64) || + (propinfo->data_type == PTP_DATATYPE_UINT64) || + (propinfo->data_type == PTP_DATATYPE_INT128) || + (propinfo->data_type == PTP_DATATYPE_UINT128)) { + + memcpy(pval->current_val.integer, arr, + propinfo->dts_size); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(pval->current_val.integer, + propinfo->dts_size); +#endif /* __BIG_ENDIAN__ */ + return TRUE; + } else { + mtp_uint32 new_val = 0; + memcpy(&new_val, arr, propinfo->dts_size); + return _prop_set_current_integer_val(pval, new_val); + } + } + return FALSE; +} +#endif /* __BIG_ENDIAN__ */ + +mtp_bool _prop_set_range_integer(prop_info_t *prop_info, mtp_uint32 min, + mtp_uint32 max, mtp_uint32 step) +{ + if (((prop_info->data_type & PTP_DATATYPE_VALUEMASK) != + PTP_DATATYPE_VALUE) || (prop_info->form_flag != RANGE_FORM)) { + return FALSE; + + } else { + prop_info->range.min_val = min; + prop_info->range.max_val = max; + prop_info->range.step_size = step; + return TRUE; + } +} + +mtp_bool _prop_set_regexp(obj_prop_desc_t *prop, mtp_wchar *regex) +{ + ptp_string_t *str; + + if ((prop->propinfo.data_type != PTP_DATATYPE_STRING) || + (prop->propinfo.form_flag != REGULAR_EXPRESSION_FORM)) { + return FALSE; + } +#ifndef MTP_USE_VARIABLE_PTP_STRING_MALLOC + str = __alloc_ptpstring(); +#else /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + str = __alloc_ptpstring(_util_wchar_len(regex)); +#endif /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + if (str == NULL) + return FALSE; + + _prop_copy_char_to_ptpstring(str, regex, WCHAR_TYPE); + prop->prop_forms.reg_exp = str; + + return TRUE; +} + +mtp_bool _prop_set_maxlen(obj_prop_desc_t *prop, mtp_uint32 max) +{ + if ((prop->propinfo.form_flag != BYTE_ARRAY_FORM) && + (prop->propinfo.form_flag != LONG_STRING_FORM)) { + return FALSE; + } + + if ((prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) != + PTP_DATATYPE_ARRAY) { + return FALSE; + } + + prop->prop_forms.max_len = max; + return TRUE; + +} + +/* DeviceObjectPropDesc Functions */ +void _prop_init_device_property_desc(device_prop_desc_t *prop, + mtp_uint16 propcode, mtp_uint16 data_type, mtp_uchar get_set, + mtp_uchar form_flag) +{ + mtp_int32 ii; + + prop->propinfo.prop_code = propcode; + prop->propinfo.data_type = data_type; + prop->propinfo.get_set = get_set; + prop->propinfo.default_val.str = NULL; + prop->current_val.str = NULL; + prop->propinfo.form_flag = form_flag; + + for (ii = 0; ii < 16; ii++) { + prop->current_val.integer[ii] = 0; + prop->propinfo.default_val.integer[ii] = 0; + } + + /* size of default value: DTS */ + switch (prop->propinfo.data_type) { + case PTP_DATATYPE_UINT8: + case PTP_DATATYPE_INT8: + case PTP_DATATYPE_AINT8: + case PTP_DATATYPE_AUINT8: + prop->propinfo.dts_size = sizeof(mtp_uchar); + break; + + case PTP_DATATYPE_UINT16: + case PTP_DATATYPE_INT16: + case PTP_DATATYPE_AINT16: + case PTP_DATATYPE_AUINT16: + prop->propinfo.dts_size = sizeof(mtp_uint16); + break; + + case PTP_DATATYPE_UINT32: + case PTP_DATATYPE_INT32: + case PTP_DATATYPE_AINT32: + case PTP_DATATYPE_AUINT32: + prop->propinfo.dts_size = sizeof(mtp_uint32); + break; + + case PTP_DATATYPE_UINT64: + case PTP_DATATYPE_INT64: + case PTP_DATATYPE_AINT64: + case PTP_DATATYPE_AUINT64: + prop->propinfo.dts_size = sizeof(mtp_int64); + break; + + case PTP_DATATYPE_UINT128: + case PTP_DATATYPE_INT128: + case PTP_DATATYPE_AINT128: + case PTP_DATATYPE_AUINT128: + prop->propinfo.dts_size = 2 * sizeof(mtp_int64); + break; + + case PTP_DATATYPE_STRING: + default: + /* don't know how to handle at this point (including PTP_DATATYPE_STRING) */ + prop->propinfo.dts_size = 0; + break; + } + + _util_init_list(&(prop->propinfo.supp_value_list)); + + return; +} + +mtp_uint32 _prop_size_device_prop_desc(device_prop_desc_t *prop) +{ + /* size :PropCode,Datatype,Getset,formflag */ + mtp_uint32 size = sizeof(mtp_uint16) + sizeof(mtp_uint16) + + sizeof(mtp_uchar) + sizeof(mtp_uchar); + + /* size of default value: DTS */ + /* size of current value: DTS */ + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + + size += _prop_size_ptpstring(prop->propinfo.default_val.str); + size += _prop_size_ptpstring(prop->current_val.str); + + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + size += _prop_get_size_ptparray(prop->propinfo.default_val.array); + size += _prop_get_size_ptparray(prop->current_val.array); + + } else { + size += 2 * prop->propinfo.dts_size; + } + + /* Add the size of the Form followed */ + switch (prop->propinfo.form_flag) { + case NONE: + break; + + case RANGE_FORM: + size += 3 * prop->propinfo.dts_size; + break; + + case ENUM_FORM: + /* Number of Values */ + size += sizeof(mtp_uint16); + if (prop->propinfo.data_type != PTP_DATATYPE_STRING) { + + size += prop->propinfo.supp_value_list.nnodes * + prop->propinfo.dts_size; + + } else { + slist_node_t *node = NULL; + mtp_uint16 ii; + + for (ii = 0, node = prop->propinfo.supp_value_list.start; + ii < prop->propinfo.supp_value_list.nnodes; + ii++, node = node->link) { + + size += _prop_size_ptpstring((ptp_string_t *) node->value); + } + } + break; + + default: + /* don't know how to handle */ + break; + + } + + return size; +} + +static mtp_uint32 __size_curval_device_prop(device_prop_desc_t *prop) +{ + mtp_uint32 size = 0; + + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + + size = _prop_size_ptpstring(prop->current_val.str); + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + size = _prop_get_size_ptparray(prop->current_val.array); + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + + size = prop->propinfo.dts_size; + } + return size; +} + +mtp_uint32 _prop_pack_device_prop_desc(device_prop_desc_t *prop, + mtp_uchar *buf, mtp_uint32 size) +{ + mtp_uchar *temp = buf; + mtp_uint32 count = 0; + mtp_uint32 bytes_to_write = 0; + slist_node_t *node = NULL; + mtp_uint32 ii; + + if (!buf || size < _prop_size_device_prop_desc(prop)) { + return 0; + } + + /* Pack propcode, data_type, & get_set */ + bytes_to_write = sizeof(mtp_uint16); + memcpy(temp, &(prop->propinfo.prop_code), bytes_to_write); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, bytes_to_write); +#endif /* __BIG_ENDIAN__ */ + temp += bytes_to_write; + + bytes_to_write = sizeof(mtp_uint16); + memcpy(temp, &(prop->propinfo.data_type), bytes_to_write); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, bytes_to_write); +#endif /* __BIG_ENDIAN__ */ + temp += bytes_to_write; + + bytes_to_write = sizeof(mtp_uchar); + memcpy(temp, &(prop->propinfo.get_set), bytes_to_write); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, bytes_to_write); +#endif /* __BIG_ENDIAN__ */ + temp += bytes_to_write; + + /* Pack Default/Current Value: DTS */ + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + + bytes_to_write = _prop_size_ptpstring(prop->propinfo.default_val.str); + if (bytes_to_write != + _prop_pack_ptpstring(prop->propinfo.default_val.str, + temp, bytes_to_write)) { + + return (mtp_uint32)(temp - buf); + } + temp += bytes_to_write; + + bytes_to_write = _prop_size_ptpstring(prop->current_val.str); + if (bytes_to_write != + _prop_pack_ptpstring(prop->current_val.str, + temp, bytes_to_write)) { + + return (mtp_uint32)(temp - buf); + } + temp += bytes_to_write; + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + bytes_to_write = _prop_get_size_ptparray(prop->propinfo.default_val.array); + if (bytes_to_write != + _prop_pack_ptparray(prop->propinfo.default_val.array, + temp, bytes_to_write)) { + + return (mtp_uint32)(temp - buf); + } + temp += bytes_to_write; + + bytes_to_write = _prop_get_size_ptparray(prop->current_val.array); + if (bytes_to_write != + _prop_pack_ptparray(prop->current_val.array, + temp, bytes_to_write)) { + + return (mtp_uint32)(temp - buf); + } + temp += bytes_to_write; + + /* Add support for other array data types */ + } else if ((prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + + bytes_to_write = prop->propinfo.dts_size; + memcpy(temp, prop->propinfo.default_val.integer, bytes_to_write); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, bytes_to_write); +#endif /* __BIG_ENDIAN__ */ + temp += bytes_to_write; + + memcpy(temp, prop->current_val.integer, bytes_to_write); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, bytes_to_write); +#endif /* __BIG_ENDIAN__ */ + temp += bytes_to_write; + } + + + /* Now pack the FormFlag */ + memcpy(temp, &(prop->propinfo.form_flag), sizeof(mtp_uchar)); + temp += sizeof(mtp_uchar); + + /* Finally pack the Form followed */ + switch (prop->propinfo.form_flag) { + case NONE: + break; + + case RANGE_FORM: + /* Min, Max, & Step */ + memcpy(temp, &(prop->propinfo.range.min_val), + prop->propinfo.dts_size); + temp += prop->propinfo.dts_size; + memcpy(temp, &(prop->propinfo.range.max_val), + prop->propinfo.dts_size); + temp += prop->propinfo.dts_size; + memcpy(temp, &(prop->propinfo.range.step_size), + prop->propinfo.dts_size); + temp += prop->propinfo.dts_size; + break; + + case ENUM_FORM: + + /* Pack Number of Values in this enumeration */ + count = prop->propinfo.supp_value_list.nnodes; + + memcpy(temp, &count, sizeof(mtp_uint16)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, sizeof(mtp_uint16)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uint16); + + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + + for (ii = 0, node = prop->propinfo.supp_value_list.start; + ii < prop->propinfo.supp_value_list.nnodes; + ii++, node = node->link) { + + bytes_to_write = + _prop_size_ptpstring((ptp_string_t *) node->value); + if (bytes_to_write != + _prop_pack_ptpstring((ptp_string_t *) node->value, + temp, bytes_to_write)) { + + return (mtp_uint32)(temp - buf); + } + temp += bytes_to_write; + } + + } else { + mtp_uint32 value = 0; + + for (ii = 0, node = prop->propinfo.supp_value_list.start; + ii < prop->propinfo.supp_value_list.nnodes; + ii++, node = node->link) { + + value = (mtp_uint32)node->value; + memcpy(temp, &value, prop->propinfo.dts_size); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, prop->propinfo.dts_size); +#endif /* __BIG_ENDIAN__ */ + temp += prop->propinfo.dts_size; + } + } + break; + + default: + /*don't know how to handle */ + break; + + } + + return (mtp_uint32)(temp - buf); +} + +mtp_uint32 _prop_pack_curval_device_prop_desc(device_prop_desc_t *prop, + mtp_uchar *buf, mtp_uint32 size) +{ + mtp_uint32 bytes_to_write; + + bytes_to_write = __size_curval_device_prop(prop); + + if ((!bytes_to_write) || (buf == NULL) || (size < bytes_to_write)) { + return 0; + } + + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + if (bytes_to_write != _prop_pack_ptpstring(prop->current_val.str, + buf, bytes_to_write)) { + return 0; + } + } else if ((prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + if (bytes_to_write != _prop_pack_ptparray(prop->current_val.array, + buf, bytes_to_write)) { + return 0; + } + } else if ((prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + /* this property is of type UINT8, ... */ + memcpy(buf, prop->current_val.integer, bytes_to_write); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(buf, bytes_to_write); +#endif /* __BIG_ENDIAN__ */ + } else { + return 0; + } + + return bytes_to_write; +} + +void _prop_reset_device_prop_desc(device_prop_desc_t *prop) +{ + ret_if(prop == NULL); + + if (prop->propinfo.get_set == PTP_PROPGETSET_GETONLY) + return; + + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + + _prop_destroy_ptpstring(prop->current_val.str); +#ifndef MTP_USE_VARIABLE_PTP_STRING_MALLOC + prop->current_val.str = __alloc_ptpstring(); +#else /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + prop->current_val.str = __alloc_ptpstring(prop->propinfo.default_val.str->num_chars); +#endif /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + if (NULL == prop->current_val.str) + return; + + _prop_copy_ptpstring (prop->current_val.str, + prop->propinfo.default_val.str); + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + _prop_destroy_ptparray(prop->current_val.array); + prop->current_val.array = _prop_alloc_ptparray(UINT32_TYPE); + if (NULL == prop->current_val.array) + return; + + _prop_copy_ptparray(prop->current_val.array, + prop->propinfo.default_val.array); + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + + mtp_int32 ii; + for (ii = 0; ii < 16; ii++) + prop->current_val.integer[ii] = + prop->propinfo.default_val.integer[ii]; + } +} + +/* ObjectPropVal Functions */ +obj_prop_val_t * _prop_alloc_obj_propval(obj_prop_desc_t *prop) +{ + obj_prop_val_t *pval = NULL; + pval = (obj_prop_val_t *)g_malloc(sizeof(obj_prop_val_t)); + + if (pval != NULL) { + __init_obj_propval(pval, prop); + } + + return pval; +} + +static void __init_obj_propval(obj_prop_val_t *pval, obj_prop_desc_t *prop) +{ + mtp_int32 ii; + + pval->prop = prop; + + for (ii = 0; ii < 16; ii++) { + pval->current_val.integer[ii] = 0; + } + + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + +#ifndef MTP_USE_VARIABLE_PTP_STRING_MALLOC + pval->current_val.str = __alloc_ptpstring(); +#else /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + pval->current_val.str = __alloc_ptpstring(prop->propinfo.default_val.str->num_chars); +#endif /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + if (NULL == pval->current_val.str) + return; + _prop_copy_ptpstring (pval->current_val.str, + prop->propinfo.default_val.str); + } else if ((prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + + memcpy(pval->current_val.integer, + prop->propinfo.default_val.integer, + prop->propinfo.dts_size); + } else { + if ((prop->propinfo.data_type == PTP_DATATYPE_AUINT8) || + (prop->propinfo.data_type == PTP_DATATYPE_AINT8)) { + + pval->current_val.array = _prop_alloc_ptparray(UINT8_TYPE); + if (NULL == pval->current_val.array) + return; + + _prop_copy_ptparray(pval->current_val.array, + prop->propinfo.default_val.array); + + } else if ((prop->propinfo.data_type == PTP_DATATYPE_AUINT16) || + (prop->propinfo.data_type == PTP_DATATYPE_AINT16)) { + + pval->current_val.array = _prop_alloc_ptparray(UINT16_TYPE); + if (NULL == pval->current_val.array) + return; + + _prop_copy_ptparray(pval->current_val.array, + prop->propinfo.default_val.array); + + } else if ((prop->propinfo.data_type == PTP_DATATYPE_AUINT32) || + (prop->propinfo.data_type == PTP_DATATYPE_AINT32)) { + + pval->current_val.array = _prop_alloc_ptparray(UINT32_TYPE); + if (NULL == pval->current_val.array) + return; + + _prop_copy_ptparray(pval->current_val.array, + prop->propinfo.default_val.array); + } + + /* Add support for other array data types */ + } + return; +} + +obj_prop_val_t *_prop_get_prop_val(mtp_obj_t *obj, mtp_uint32 propcode) +{ + obj_prop_val_t *prop_val = NULL; + slist_node_t *node = NULL; + mtp_uint32 ii = 0; + + /*Update the properties if count is zero*/ + if (obj->propval_list.nnodes == 0) + _prop_update_property_values_list(obj); + + for (ii = 0, node = obj->propval_list.start; + ii < obj->propval_list.nnodes; ii++, node = node->link) { + if (node == NULL || node->value == NULL) + goto ERROR_CATCH; + + prop_val = (obj_prop_val_t *)node->value; + if (prop_val) { + if (prop_val->prop->propinfo.prop_code == propcode) { + return prop_val; + } + } + } + + return NULL; + +ERROR_CATCH: + /* update property and try again */ + _prop_update_property_values_list(obj); + + for (ii = 0, node = obj->propval_list.start; + ii < obj->propval_list.nnodes; + ii++, node = node->link) { + if (node == NULL || node->value == NULL) + break; + + prop_val = (obj_prop_val_t *)node->value; + if ((prop_val) && (prop_val->prop->propinfo.prop_code == + propcode)) { + return prop_val; + } + } + ERR("node or node->value is null. try again but not found"); + return NULL; +} + +mtp_uint32 _prop_pack_obj_propval(obj_prop_val_t *pval, mtp_uchar *buf, + mtp_uint32 size) +{ + mtp_uint32 bytes_to_write = _prop_size_obj_propval(pval); + + if ((!bytes_to_write) || (buf == NULL) || (size < bytes_to_write)) { + return 0; + } + + if (pval->prop->propinfo.data_type == PTP_DATATYPE_STRING) { + + if (bytes_to_write != _prop_pack_ptpstring(pval->current_val.str, + buf, bytes_to_write)) { + return 0; + } + } else if ((pval->prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + if (bytes_to_write != _prop_pack_ptparray(pval->current_val.array, + buf, size)) { + return 0; + } + + } else if ((pval->prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + + /* this property is of type UINT8, ... */ + memcpy(buf, pval->current_val.integer, bytes_to_write); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(buf, bytes_to_write); +#endif /* __BIG_ENDIAN__ */ + } else { + return 0; + } + + return bytes_to_write; +} + + +mtp_uint32 _prop_size_obj_propval(obj_prop_val_t *pval) +{ + mtp_uint32 size = 0; + + if (pval == NULL || pval->prop == NULL) + return size; + + if (pval->prop->propinfo.data_type == PTP_DATATYPE_STRING) { + if (pval->current_val.str == NULL) { + size = 0; + } else { + size = _prop_size_ptpstring(pval->current_val.str); + } + + } else if ((pval->prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + size = _prop_get_size_ptparray(pval->current_val.array); + + } else if ((pval->prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + size = pval->prop->propinfo.dts_size; + } + + return size; +} + +void _prop_destroy_obj_propval(obj_prop_val_t *pval) +{ + if (pval == NULL) { + return; + } + + if (pval->prop == NULL) { + g_free(pval); + pval = NULL; + return; + } + + if (pval->prop->propinfo.data_type == PTP_DATATYPE_STRING) { + if (pval->current_val.str) { + _prop_destroy_ptpstring(pval->current_val.str); + pval->current_val.str = NULL; + } + } else if ((pval->prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + _prop_destroy_ptparray(pval->current_val.array); + pval->current_val.array = NULL; + } + + if (pval != NULL) { + g_free(pval); + pval = NULL; + } + + return; +} + +static void __init_obj_prop_desc(obj_prop_desc_t *prop, mtp_uint16 propcode, + mtp_uint16 data_type, mtp_uchar get_set, mtp_uchar form_flag, + mtp_uint32 group_code) +{ + mtp_int32 ii; + prop->propinfo.prop_code = propcode;/*Property code for this property*/ + prop->propinfo.data_type = data_type; /* 2=byte, 4=word, + * 6=dword, 0xFFFF=String) + */ + prop->propinfo.get_set = get_set; /* 0=get-only, 1=get-set */ + prop->propinfo.default_val.str = NULL; /* Default value for a String value type */ + + prop->propinfo.form_flag = form_flag; + + if (prop->propinfo.form_flag == BYTE_ARRAY_FORM) { + prop->propinfo.data_type = PTP_DATATYPE_AUINT8; + } else if (prop->propinfo.form_flag == LONG_STRING_FORM) { + prop->propinfo.data_type = PTP_DATATYPE_AUINT16; + } + + prop->group_code = group_code; + + /* Zero out the integer byte array */ + for (ii = 0; ii < 16; ii++) + prop->propinfo.default_val.integer[ii] = 0; + + /* size of default value: DTS */ + switch (prop->propinfo.data_type) { + + case PTP_DATATYPE_UINT8: + case PTP_DATATYPE_INT8: + case PTP_DATATYPE_AINT8: + case PTP_DATATYPE_AUINT8: + prop->propinfo.dts_size = sizeof(mtp_uchar); + break; + + case PTP_DATATYPE_UINT16: + case PTP_DATATYPE_INT16: + case PTP_DATATYPE_AINT16: + case PTP_DATATYPE_AUINT16: + prop->propinfo.dts_size = sizeof(mtp_uint16); + break; + + case PTP_DATATYPE_UINT32: + case PTP_DATATYPE_INT32: + case PTP_DATATYPE_AINT32: + case PTP_DATATYPE_AUINT32: + prop->propinfo.dts_size = sizeof(mtp_uint32); + break; + + case PTP_DATATYPE_UINT64: + case PTP_DATATYPE_INT64: + case PTP_DATATYPE_AINT64: + case PTP_DATATYPE_AUINT64: + prop->propinfo.dts_size = sizeof(mtp_int64); + break; + + case PTP_DATATYPE_UINT128: + case PTP_DATATYPE_INT128: + case PTP_DATATYPE_AINT128: + case PTP_DATATYPE_AUINT128: + prop->propinfo.dts_size = 2 * sizeof(mtp_int64); + break; + + case PTP_DATATYPE_STRING: + default: + prop->propinfo.dts_size = 0; + break; + } + + _util_init_list(&(prop->propinfo.supp_value_list)); + + prop->prop_forms.reg_exp = NULL; + prop->prop_forms.max_len = 0; + + return; +} + +static mtp_uint32 __get_size_default_val_obj_prop_desc(obj_prop_desc_t *prop) +{ + mtp_uint32 size = 0; + + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + + size = _prop_size_ptpstring(prop->propinfo.default_val.str); + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + size = _prop_get_size_ptparray(prop->propinfo.default_val.array); + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + + size = prop->propinfo.dts_size; + } + + return size; +} + +mtp_uint32 _prop_size_obj_prop_desc(obj_prop_desc_t *prop) +{ + mtp_uint32 size = + sizeof(mtp_uint16) + sizeof(mtp_uint16) + sizeof(mtp_uchar) + + sizeof(mtp_uint32) + sizeof(mtp_uchar); + + /* size of default value: DTS */ + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + + size += _prop_size_ptpstring(prop->propinfo.default_val.str); + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + size += _prop_get_size_ptparray(prop->propinfo.default_val.array); + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + + size += prop->propinfo.dts_size; + } + + /* Add the size of the Form followed */ + switch (prop->propinfo.form_flag) { + case NONE: + break; + + case RANGE_FORM: + if (prop->propinfo.data_type != PTP_DATATYPE_STRING) { + size += 3 * prop->propinfo.dts_size;/* Min,Max,Step */ + } + break; + + case ENUM_FORM: + /* Number of Values */ + size += sizeof(mtp_uint16); + if (prop->propinfo.data_type != PTP_DATATYPE_STRING) { + size += prop->propinfo.supp_value_list.nnodes * + prop->propinfo.dts_size; + } else { + slist_node_t *node = NULL; + mtp_uint32 ii; + + for (ii = 0, node = prop->propinfo.supp_value_list.start; + ii < prop->propinfo.supp_value_list.nnodes; + ii++, node = node->link) { + + size += _prop_size_ptpstring((ptp_string_t *) node->value); + } + } + break; + + case DATE_TIME_FORM: + break; + + case REGULAR_EXPRESSION_FORM: + size += _prop_size_ptpstring(prop->prop_forms.reg_exp); + break; + + case BYTE_ARRAY_FORM: + case LONG_STRING_FORM: + size += sizeof(prop->prop_forms.max_len); + break; + + default: + /*don't know how to handle */ + break; + + } + + return size; +} + +mtp_uint32 _prop_pack_obj_prop_desc(obj_prop_desc_t *prop, mtp_uchar *buf, + mtp_uint32 size) +{ + mtp_uchar *temp = buf; + mtp_uint32 count = 0; + mtp_uint32 bytes_to_write = 0; + slist_node_t *node = NULL; + mtp_uint16 ii; + + if (!buf || size < _prop_size_obj_prop_desc(prop)) { + return 0; + } + + /* Pack propcode, data_type, & get_set */ + bytes_to_write = sizeof(mtp_uint16); + memcpy(temp, &(prop->propinfo.prop_code), bytes_to_write); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, bytes_to_write); +#endif /* __BIG_ENDIAN__ */ + temp += bytes_to_write; + + bytes_to_write = sizeof(mtp_uint16); + memcpy(temp, &(prop->propinfo.data_type), bytes_to_write); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, bytes_to_write); +#endif /* __BIG_ENDIAN__ */ + temp += bytes_to_write; + + bytes_to_write = sizeof(mtp_uchar); + memcpy(temp, &(prop->propinfo.get_set), bytes_to_write); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, bytes_to_write); +#endif /* __BIG_ENDIAN__ */ + temp += bytes_to_write; + + /* Pack Default Value: DTS */ + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + + bytes_to_write = + _prop_size_ptpstring(prop->propinfo.default_val.str); + if (bytes_to_write != _prop_pack_ptpstring(prop->propinfo.default_val.str, + temp, bytes_to_write)) { + return (mtp_uint32)(temp - buf); + } + temp += bytes_to_write; + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + bytes_to_write = _prop_get_size_ptparray(prop->propinfo.default_val.array); + if (bytes_to_write != _prop_pack_ptparray(prop->propinfo.default_val.array, + temp, bytes_to_write)) { + return (mtp_uint32)(temp - buf); + } + temp += bytes_to_write; + + } else if ((prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + + bytes_to_write = prop->propinfo.dts_size; + memcpy(temp, prop->propinfo.default_val.integer, bytes_to_write); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, bytes_to_write); +#endif /* __BIG_ENDIAN__ */ + temp += bytes_to_write; + } + + /* Pack group_code */ + memcpy(temp, &(prop->group_code), sizeof(mtp_uint32)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uint32); + + /* Pack the FormFlag */ + memcpy(temp, &(prop->propinfo.form_flag), sizeof(mtp_uchar)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, sizeof(mtp_uchar)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uchar); + + /* Pack the Form Flag values */ + switch (prop->propinfo.form_flag) { + case NONE: + break; + + case RANGE_FORM: + /* Min, Max, & Step */ + memcpy(temp, &(prop->propinfo.range.min_val), + prop->propinfo.dts_size); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, prop->propinfo.dts_size); +#endif /* __BIG_ENDIAN__ */ + temp += prop->propinfo.dts_size; + memcpy(temp, &(prop->propinfo.range.max_val), + prop->propinfo.dts_size); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, prop->propinfo.dts_size); +#endif /* __BIG_ENDIAN__ */ + temp += prop->propinfo.dts_size; + memcpy(temp, &(prop->propinfo.range.step_size), + prop->propinfo.dts_size); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, prop->propinfo.dts_size); +#endif /* __BIG_ENDIAN__ */ + temp += prop->propinfo.dts_size; + break; + + case ENUM_FORM: + + /* Pack Number of Values in this enumeration */ + count = prop->propinfo.supp_value_list.nnodes; + + memcpy(temp, &count, sizeof(mtp_uint16)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, sizeof(mtp_uint16)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uint16); + + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + + for (ii = 0, node = prop->propinfo.supp_value_list.start; + ii < prop->propinfo.supp_value_list.nnodes; + ii++, node = node->link) { + + bytes_to_write = + _prop_size_ptpstring((ptp_string_t *) node->value); + if (bytes_to_write != + _prop_pack_ptpstring((ptp_string_t *) node->value, + temp, bytes_to_write)) { + return (mtp_uint32) (temp - buf); + } + temp += bytes_to_write; + } + } else { + mtp_uint32 value = 0; + + for (ii = 0, node = prop->propinfo.supp_value_list.start; + ii < prop->propinfo.supp_value_list.nnodes; + ii++, node = node->link) { + + value = (mtp_uint32)node->value; + memcpy(temp, &value, prop->propinfo.dts_size); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, prop->propinfo.dts_size); +#endif /* __BIG_ENDIAN__ */ + temp += prop->propinfo.dts_size; + } + } + break; + + case DATE_TIME_FORM: + break; + + case REGULAR_EXPRESSION_FORM: + bytes_to_write = _prop_size_ptpstring(prop->prop_forms.reg_exp); + if (bytes_to_write != + _prop_pack_ptpstring(prop->prop_forms.reg_exp, + temp, bytes_to_write)) { + + return (mtp_uint32)(temp - buf); + } + temp += bytes_to_write; + break; + + case BYTE_ARRAY_FORM: + case LONG_STRING_FORM: + memcpy(temp, &prop->prop_forms.max_len, + sizeof(prop->prop_forms.max_len)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, sizeof(prop->prop_forms.max_len)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(prop->prop_forms.max_len); + break; + + default: + /*don't know how to handle */ + break; + + } + + return (mtp_uint32)(temp - buf); +} + +mtp_uint32 _prop_pack_default_val_obj_prop_desc(obj_prop_desc_t *prop, + mtp_uchar *buf, mtp_uint32 size) +{ + mtp_uint32 bytes_to_write; + + bytes_to_write = __get_size_default_val_obj_prop_desc(prop); + + if ((!bytes_to_write) || (buf == NULL) || (size < bytes_to_write)) { + return 0; + } + + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + if (bytes_to_write != + _prop_pack_ptpstring(prop->propinfo.default_val.str, + buf, bytes_to_write)) { + return 0; + } + } else if ((prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + if (bytes_to_write != + _prop_pack_ptparray(prop->propinfo.default_val.array, + buf, bytes_to_write)) { + return 0; + } + } else if ((prop->propinfo.data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + /* this property is of type UINT8, ... */ + memcpy(buf, prop->propinfo.default_val.integer, bytes_to_write); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(buf, bytes_to_write); +#endif /* __BIG_ENDIAN__ */ + } else { + return 0; + } + + return bytes_to_write; +} + +obj_prop_desc_t *_prop_get_obj_prop_desc(mtp_uint32 format_code, + mtp_uint32 propcode) +{ + mtp_uint32 i = 0; + int num_default_obj_props = 0; + + /*Default*/ + if (_get_oma_drm_status() == TRUE) { + num_default_obj_props = NUM_OBJECT_PROP_DESC_DEFAULT; + } else { + num_default_obj_props = NUM_OBJECT_PROP_DESC_DEFAULT - 1; + } + + for (i = 0; i < num_default_obj_props; i++) { + if (props_list_default[i].propinfo.prop_code == propcode) { + return &(props_list_default[i]); + } + } + + switch (format_code) { + case PTP_FMT_MP3: + case PTP_FMT_WAVE: + for (i = 0; i < NUM_OBJECT_PROP_DESC_MP3; i++) { + if (props_list_mp3[i].propinfo.prop_code == propcode) { + return &(props_list_mp3[i]); + } + } + break; + case MTP_FMT_WMA: + for (i = 0; i < NUM_OBJECT_PROP_DESC_WMA; i++) { + if (props_list_wma[i].propinfo.prop_code == propcode) { + return &(props_list_wma[i]); + } + } + break; + case MTP_FMT_WMV: + case PTP_FMT_ASF: + case MTP_FMT_MP4: + case PTP_FMT_AVI: + case PTP_FMT_MPEG: + case MTP_FMT_3GP: + for (i = 0; i < NUM_OBJECT_PROP_DESC_WMV; i++) { + if (props_list_wmv[i].propinfo.prop_code == propcode) { + return &(props_list_wmv[i]); + } + } + break; + case MTP_FMT_ABSTRACT_AUDIO_ALBUM: + case PTP_FMT_IMG_EXIF: + case PTP_FMT_IMG_GIF: + case PTP_FMT_IMG_BMP: + case PTP_FMT_IMG_PNG: + for (i = 0; i < NUM_OBJECT_PROP_DESC_ALBUM; i++) { + if (props_list_album[i].propinfo.prop_code == propcode) { + return &(props_list_album[i]); + } + } + break; + + default: + break; + } + + ERR("No matched property[0x%x], format[0x%x]!!\n", propcode, + format_code); + return NULL; +} + +static void __destroy_obj_prop_desc(obj_prop_desc_t *prop) +{ + slist_node_t *node = NULL; + slist_node_t *next_node = NULL; + mtp_uint32 ii; + + if (prop->propinfo.data_type == PTP_DATATYPE_STRING) { + + if (prop->propinfo.default_val.str) { + + _prop_destroy_ptpstring(prop->propinfo.default_val.str); + prop->propinfo.default_val.str = NULL; + } + + if (prop->propinfo.form_flag == ENUM_FORM) { + + for (node = prop->propinfo.supp_value_list.start, ii = 0; + ii < prop->propinfo.supp_value_list.nnodes; + node = node->link, ii++) { + _prop_destroy_ptpstring((ptp_string_t *) node->value); + } + } + + if (prop->propinfo.form_flag == REGULAR_EXPRESSION_FORM) { + + if (prop->prop_forms.reg_exp != NULL) { + _prop_destroy_ptpstring(prop->prop_forms.reg_exp); + prop->prop_forms.reg_exp = NULL; + } + } + } else if ((prop->propinfo.data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + if (prop->propinfo.default_val.array) { + + _prop_destroy_ptparray(prop->propinfo.default_val.array); + prop->propinfo.default_val.array = NULL; + } + } + + /* deallocate memory consumed by list elements */ + next_node = prop->propinfo.supp_value_list.start; + for (ii = 0; ii < prop->propinfo.supp_value_list.nnodes; ii++) { + node = next_node; + next_node = next_node->link; + g_free(node); + } + return; +} + +/* Objectproplist functions */ +static mtp_uint32 __count_obj_proplist(obj_proplist_t *prop_list) +{ + return prop_list->prop_quad_list.nnodes; +} + +mtp_uint32 _prop_size_obj_proplist(obj_proplist_t *prop_list) +{ + prop_quad_t *quad = NULL; + slist_node_t *node = NULL; + mtp_uint32 ii; + mtp_uint32 size; + + /* for the NumberOfElements field in objpropvalList Dataset */ + size = sizeof(mtp_uint32); + + /* add all the fixed length members of the list */ + size += prop_list->prop_quad_list.nnodes * (sizeof(mtp_uint32) + + sizeof(mtp_uint16) + sizeof(mtp_uint16)); + node = prop_list->prop_quad_list.start; + for (ii = 0; ii < prop_list->prop_quad_list.nnodes; ii++) { + quad = (prop_quad_t *) node->value; + if (quad) { + size += quad->val_size; + } + node = node->link; + } + return size; +} + +mtp_uint32 _prop_get_obj_proplist(mtp_obj_t *obj, mtp_uint32 propcode, + mtp_uint32 group_code, obj_proplist_t *prop_list) +{ + obj_prop_val_t *propval = NULL; + slist_node_t *node = NULL; + mtp_uint32 ii = 0; + + if (obj->propval_list.nnodes == 0) { + if (FALSE == _prop_update_property_values_list(obj)) { + ERR("update Property Values FAIL!!"); + return 0; + } + } + for (ii = 0, node = obj->propval_list.start; + ii < obj->propval_list.nnodes; + ii++, node = node->link) { + propval = (obj_prop_val_t *)node->value; + + if (NULL == propval) { + continue; + } + + if (FALSE == __check_object_propcode(propval->prop, + propcode, group_code)) { + continue; + } + __append_obj_proplist(prop_list, obj->obj_handle, + propval->prop->propinfo.prop_code, + propval->prop->propinfo.data_type, + (mtp_uchar *)propval->current_val.integer); + } + + return __count_obj_proplist(prop_list); +} + +mtp_bool _prop_update_property_values_list(mtp_obj_t *obj) +{ + mtp_uint32 ii = 0; + mtp_char guid[16] = { 0 }; + slist_node_t *node = NULL; + slist_node_t *next_node = NULL; + ptp_time_string_t create_tm, modify_tm; + mtp_uint32 fmt_code = obj->obj_info->obj_fmt; + mtp_wchar buf[MTP_MAX_PATHNAME_SIZE+1] = { 0 }; + mtp_char file_name[MTP_MAX_FILENAME_SIZE + 1] = { 0 }; + mtp_wchar w_file_name[MTP_MAX_FILENAME_SIZE + 1] = { 0 }; + char filename_wo_extn[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_wchar object_fullpath[MTP_MAX_PATHNAME_SIZE * 2 + 1] = { 0 }; + + retv_if(obj == NULL, FALSE); + retv_if(obj->obj_info == NULL, FALSE); + + if (obj->propval_list.nnodes > 0) { + /* + * Remove all the old property value, + * and ready to set up new list + */ + for (ii = 0, next_node = obj->propval_list.start; + ii < obj->propval_list.nnodes; ii++) { + node = next_node; + next_node = node->link; + _prop_destroy_obj_propval((obj_prop_val_t *) + node->value); + g_free(node); + } + obj->propval_list.start = NULL; + obj->propval_list.end = NULL; + obj->propval_list.nnodes = 0; + node = NULL; + } + + /* Populate Object Info to Object properties */ + if (obj->file_path == NULL || obj->file_path[0] != '/') { + ERR_SECURE("Path is not valid.. path = [%s]\n", + obj->file_path); + return FALSE; + } + + /*STORAGE ID*/ + retv_if(FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_STORAGEID, + obj->obj_info->store_id), FALSE); + + /*OBJECT FORMAT*/ + retv_if(FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_OBJECTFORMAT, + obj->obj_info->obj_fmt), FALSE); + + /*PROTECTION STATUS*/ + retv_if(FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_PROTECTIONSTATUS, + obj->obj_info->protcn_status), FALSE); + + /*OBJECT SIZE*/ + retv_if(FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_OBJECTSIZE, + obj->obj_info->file_size), FALSE); + + /*OBJECT FILENAME*/ + _util_get_file_name(obj->file_path, file_name); + _util_utf8_to_utf16(w_file_name, sizeof(w_file_name) / WCHAR_SIZ, file_name); + retv_if(FALSE == __create_prop_string(obj, + MTP_OBJ_PROPERTYCODE_OBJECTFILENAME, w_file_name), FALSE); + + /*PARENT*/ + retv_if(FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_PARENT, obj->obj_info->h_parent), FALSE); + + /*PERSISTENT GUID*/ + _util_utf8_to_utf16(object_fullpath, + sizeof(object_fullpath) / WCHAR_SIZ, obj->file_path); + _util_conv_wstr_to_guid(object_fullpath, (mtp_uint64 *) guid); + retv_if((FALSE == __create_prop_array(obj, + MTP_OBJ_PROPERTYCODE_PERSISTENTGUID, + guid, sizeof(guid))), FALSE); + + /*NON-CONSUMABLE*/ + retv_if(FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_NONCONSUMABLE, 0), FALSE); + + _entity_get_file_times(obj, &create_tm, &modify_tm); + /*DATE MODIFIED*/ + retv_if(FALSE == __create_prop_timestring(obj, MTP_OBJ_PROPERTYCODE_DATEMODIFIED, + &modify_tm), FALSE); + + /*DATE CREATED*/ + retv_if(FALSE == __create_prop_timestring(obj, MTP_OBJ_PROPERTYCODE_DATECREATED, + &create_tm), FALSE); + + /* NAME */ + _util_get_file_name_wo_extn(obj->file_path, + filename_wo_extn); + _util_utf8_to_utf16(buf, sizeof(buf) / WCHAR_SIZ, filename_wo_extn); + retv_if(FALSE == __create_prop_string(obj, + MTP_OBJ_PROPERTYCODE_NAME, buf), FALSE); + + /*ASSOCIATION TYPE*/ + retv_if(FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_ASSOCIATIONTYPE, + obj->obj_info->association_type), FALSE); + + /* OMADRM STATUS */ + if (_get_oma_drm_status() == TRUE) { + retv_if(FALSE == __create_prop_integer(obj, + MTP_OBJ_PROPERTYCODE_OMADRMSTATUS, 0), FALSE); + } + + /*Get DCM data*/ + if (fmt_code == PTP_FMT_MP3 || + fmt_code == MTP_FMT_WMA || + fmt_code == PTP_FMT_WAVE || + fmt_code == MTP_FMT_FLAC) { + __update_prop_values_audio(obj); + + } else if (fmt_code == MTP_FMT_WMV || + fmt_code == PTP_FMT_ASF || + fmt_code == MTP_FMT_MP4 || + fmt_code == PTP_FMT_AVI || + fmt_code == PTP_FMT_MPEG) { + __update_prop_values_video(obj); + + } else if (fmt_code == PTP_FMT_IMG_EXIF || + fmt_code == PTP_FMT_IMG_BMP || + fmt_code == PTP_FMT_IMG_GIF || + fmt_code == PTP_FMT_IMG_PNG) { + __update_prop_values_image(obj); + } + + return TRUE; +} + +static mtp_bool __append_obj_proplist(obj_proplist_t *prop_list, mtp_uint32 obj_handle, + mtp_uint16 propcode, mtp_uint32 data_type, mtp_uchar *val) +{ + ptp_string_t *str = NULL; + prop_quad_t *quad = NULL; + ptp_array_t *arr_uint8; + ptp_array_t *arr_uint16; + ptp_array_t *arr_uint32; + + quad = (prop_quad_t *)g_malloc(sizeof(prop_quad_t)); + if (NULL == quad) + return FALSE; + + quad->obj_handle = obj_handle; + quad->prop_code = propcode; + quad->data_type = data_type; + quad->pval = val; + + switch (data_type) { + case PTP_DATATYPE_UINT8: + case PTP_DATATYPE_INT8: + quad->val_size = sizeof(mtp_uchar); + break; + + case PTP_DATATYPE_UINT16: + case PTP_DATATYPE_INT16: + quad->val_size = sizeof(mtp_uint16); + break; + + case PTP_DATATYPE_UINT32: + case PTP_DATATYPE_INT32: + quad->val_size = sizeof(mtp_uint32); + break; + + case PTP_DATATYPE_UINT64: + case PTP_DATATYPE_INT64: + quad->val_size = sizeof(mtp_int64); + break; + + case PTP_DATATYPE_UINT128: + case PTP_DATATYPE_INT128: + quad->val_size = 2 * sizeof(mtp_int64); + break; + + case PTP_DATATYPE_AUINT8: + case PTP_DATATYPE_AINT8: + memcpy(&arr_uint8, val, sizeof(ptp_array_t *)); + quad->val_size = (arr_uint8 != NULL) ? + _prop_get_size_ptparray(arr_uint8) : 0; + quad->pval = (mtp_uchar *)arr_uint8; + break; + + case PTP_DATATYPE_AUINT16: + case PTP_DATATYPE_AINT16: + memcpy(&arr_uint16, val, sizeof(ptp_array_t *)); + quad->val_size = (arr_uint16 != NULL) ? + _prop_get_size_ptparray(arr_uint16) : 0; + quad->pval = (mtp_uchar *)arr_uint16; + break; + + case PTP_DATATYPE_AUINT32: + case PTP_DATATYPE_AINT32: + memcpy(&arr_uint32, val, sizeof(ptp_array_t *)); + quad->val_size = (arr_uint32 != NULL) ? _prop_get_size_ptparray(arr_uint32) : 0; + quad->pval = (mtp_uchar *)arr_uint32; + break; + + case PTP_DATATYPE_STRING: + memcpy(&str, val, sizeof(ptp_string_t *)); + quad->val_size = (str != NULL) ? _prop_size_ptpstring(str) : 1; + quad->pval = (mtp_uchar *)str; + break; + default: + /* don't know */ + quad->val_size = 0; + break; + } + + _util_add_node(&(prop_list->prop_quad_list), quad); + return TRUE; +} + +mtp_uint32 _prop_pack_obj_proplist(obj_proplist_t *prop_list, mtp_uchar *buf, + mtp_uint32 size) +{ + mtp_uchar *temp = buf; + ptp_string_t *str = NULL; + prop_quad_t *quad = NULL; + mtp_uint32 ii; + slist_node_t *node = NULL; + + if (!buf || size < _prop_size_obj_proplist(prop_list)) { + return 0; + } + + *(mtp_uint32 *) buf = prop_list->prop_quad_list.nnodes; +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uint32); + + /* Pack the array elements */ + node = prop_list->prop_quad_list.start; + for (ii = 0; ii < prop_list->prop_quad_list.nnodes; ii++) { + quad = (prop_quad_t *) node->value; + node = node->link; + /* pack the fixed length members */ + memcpy(temp, &quad->obj_handle, sizeof(mtp_uint32)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uint32); + + memcpy(temp, &quad->prop_code, sizeof(mtp_uint16)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uint16); + + memcpy(temp, &quad->data_type, sizeof(mtp_uint16)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uint16); + + /* Pack property value */ + if ((quad->data_type & PTP_DATATYPE_VALUEMASK) == + PTP_DATATYPE_VALUE) { + + memcpy(temp, quad->pval, quad->val_size); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(temp, quad->val_size); +#endif /* __BIG_ENDIAN__ */ + temp += quad->val_size; + + } else if (quad->data_type == PTP_DATATYPE_STRING) { + + str = (ptp_string_t *) quad->pval; + if (str) { + temp += _prop_pack_ptpstring(str, temp, + _prop_size_ptpstring (str)); + } else { + /* Put in an empty string: NumOfChars = 0; */ + *temp++ = 0; + } + } else if ((quad->data_type & PTP_DATATYPE_ARRAYMASK) == + PTP_DATATYPE_ARRAY) { + + if (quad->pval != NULL) { + + if (quad->val_size != + _prop_pack_ptparray((ptp_array_t *)quad->pval, + temp, quad->val_size)) { + return (mtp_uint32) (temp - buf); + } + temp += quad->val_size; + } else { + /* Fill in an empty array: mtp_uint32 */ + mtp_uint32 zero = 0; + memcpy(temp, &zero, sizeof(mtp_uint32)); + temp += sizeof(mtp_uint32); + } + } + } + + return (mtp_uint32)(temp - buf); +} + +void _prop_destroy_obj_proplist(obj_proplist_t *prop_list) +{ + slist_node_t *node = NULL; + slist_node_t *next_node = NULL; + mtp_uint32 ii; + + for (ii = 0, node = prop_list->prop_quad_list.start; + ii < prop_list->prop_quad_list.nnodes; ii++, node = node->link) { + g_free(node->value); + } + + next_node = prop_list->prop_quad_list.start; + + for (ii = 0; ii < prop_list->prop_quad_list.nnodes; ii++) { + node = next_node; + next_node = node->link; + g_free(node); + } + return; +} + +mtp_bool _prop_add_supp_integer_val(prop_info_t *prop_info, mtp_uint32 value) +{ + if (((prop_info->data_type & PTP_DATATYPE_VALUEMASK) != + PTP_DATATYPE_VALUE) || (prop_info->form_flag != ENUM_FORM)) { + return FALSE; + } + + /* Create the node and append it. */ + _util_add_node(&(prop_info->supp_value_list), (void *)value); + + return TRUE; +} + +mtp_bool _prop_add_supp_string_val(prop_info_t *prop_info, mtp_wchar *val) +{ + ptp_string_t *str = NULL; + mtp_bool ret; + + if ((prop_info->data_type != PTP_DATATYPE_STRING) || + (prop_info->form_flag != ENUM_FORM)) { + return FALSE; + } +#ifndef MTP_USE_VARIABLE_PTP_STRING_MALLOC + str = __alloc_ptpstring(); +#else /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + str = __alloc_ptpstring(_util_wchar_len(val)); +#endif /* MTP_USE_VARIABLE_PTP_STRING_MALLOC */ + + if (str != NULL) { + _prop_copy_char_to_ptpstring(str, val, WCHAR_TYPE); + ret = _util_add_node(&(prop_info->supp_value_list), (void *)str); + if (ret == FALSE) { + ERR("List add Fail"); + g_free(str); + return FALSE; + } + return TRUE; + } + return FALSE; +} + +/* ObjectProp Functions */ +mtp_uint32 _prop_get_supp_obj_props(mtp_uint32 format_code, + ptp_array_t *supp_props) +{ + mtp_uint32 i = 0; + mtp_uint32 num_default_obj_props = 0; + + /*Default*/ + if (_get_oma_drm_status() == TRUE) { + num_default_obj_props = NUM_OBJECT_PROP_DESC_DEFAULT; + } else { + num_default_obj_props = NUM_OBJECT_PROP_DESC_DEFAULT - 1; + } + + for (i = 0; i < num_default_obj_props; i++) { + _prop_append_ele_ptparray(supp_props, + props_list_default[i].propinfo.prop_code); + } + + switch (format_code) { + case PTP_FMT_MP3: + case PTP_FMT_WAVE: + for (i = 0; i < NUM_OBJECT_PROP_DESC_MP3; i++) { + _prop_append_ele_ptparray(supp_props, + props_list_mp3[i].propinfo.prop_code); + } + break; + case MTP_FMT_WMA: + for (i = 0; i < NUM_OBJECT_PROP_DESC_WMA; i++) { + _prop_append_ele_ptparray(supp_props, + props_list_wma[i].propinfo.prop_code); + } + break; + case MTP_FMT_WMV: + case PTP_FMT_ASF: + case MTP_FMT_MP4: + case PTP_FMT_AVI: + case PTP_FMT_MPEG: + case MTP_FMT_3GP: + for (i = 0; i < NUM_OBJECT_PROP_DESC_WMV; i++) { + _prop_append_ele_ptparray(supp_props, + props_list_wmv[i].propinfo.prop_code); + } + break; + case MTP_FMT_ABSTRACT_AUDIO_ALBUM: + case PTP_FMT_IMG_EXIF: + case PTP_FMT_IMG_GIF: + case PTP_FMT_IMG_BMP: + case PTP_FMT_IMG_PNG: + for (i = 0; i < NUM_OBJECT_PROP_DESC_ALBUM; i++) { + _prop_append_ele_ptparray(supp_props, + props_list_album[i].propinfo.prop_code); + } + break; + default: + break; + } + DBG("getsupp_props : format [0x%x], supported list [%d]\n", + format_code, supp_props->num_ele); + return supp_props->num_ele; +} + +mtp_bool _prop_build_supp_props_default(void) +{ + mtp_wchar temp[MTP_MAX_REG_STRING + 1] = { 0 }; + static mtp_bool initialized = FALSE; + mtp_uchar i = 0; + mtp_uint32 default_val; + + if (initialized == TRUE) { + DBG("already supported list is in there. just return!!"); + return TRUE; + } + + /* + * MTP_OBJ_PROPERTYCODE_STORAGEID (1) + */ + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_STORAGEID, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + NONE, + MTP_PROP_GROUPCODE_GENERAL); + + default_val = 0x0; + _prop_set_default_integer(&(props_list_default[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_OBJECTFORMAT (2) + */ + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_OBJECTFORMAT, + PTP_DATATYPE_UINT16, + PTP_PROPGETSET_GETONLY, + NONE, + MTP_PROP_GROUPCODE_GENERAL); + + default_val = PTP_FMT_UNDEF; + _prop_set_default_integer(&(props_list_default[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_PROTECTIONSTATUS (3) + */ + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_PROTECTIONSTATUS, + PTP_DATATYPE_UINT16, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + default_val = PTP_PROTECTIONSTATUS_NOPROTECTION; + _prop_add_supp_integer_val(&(props_list_default[i].propinfo), + PTP_PROTECTIONSTATUS_NOPROTECTION); + _prop_add_supp_integer_val(&(props_list_default[i].propinfo), + PTP_PROTECTIONSTATUS_READONLY); + _prop_add_supp_integer_val(&(props_list_default[i].propinfo), + MTP_PROTECTIONSTATUS_READONLY_DATA); + _prop_add_supp_integer_val(&(props_list_default[i].propinfo), + (mtp_uint32)MTP_PROTECTIONSTATUS_NONTRANSFERABLE_DATA); + _prop_set_default_integer(&(props_list_default[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_OBJECTSIZE (4) + */ + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_OBJECTSIZE, + PTP_DATATYPE_UINT64, + PTP_PROPGETSET_GETONLY, + NONE, + MTP_PROP_GROUPCODE_GENERAL); + + _prop_add_supp_integer_val(&(props_list_default[i].propinfo), 0x0); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_OBJECTFILENAME (5) + */ + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_OBJECTFILENAME, + PTP_DATATYPE_STRING, + PTP_PROPGETSET_GETSET, + REGULAR_EXPRESSION_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + _util_utf8_to_utf16(temp, sizeof(temp) / WCHAR_SIZ, + "[a-zA-Z!#\\$%&`\\(\\)\\-0-9@\\^_\\'\\{\\}\\~]{1,8}\\.[[a-zA-Z!#\\$%&`\\(\\)\\-0-9@\\^_\\'\\{\\}\\~]{1,3}]"); + _prop_set_regexp(&(props_list_default[i]), temp); + + _util_utf8_to_utf16(temp, sizeof(temp) / WCHAR_SIZ, ""); + _prop_set_default_string(&(props_list_default[i].propinfo), temp); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_PARENT (6) + */ + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_PARENT, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + NONE, + MTP_PROP_GROUPCODE_GENERAL); + + default_val = 0x0; + _prop_set_default_integer(&(props_list_default[i].propinfo), + (mtp_uchar *) &default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_PERSISTENTGUID (7) + */ + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_PERSISTENTGUID, + PTP_DATATYPE_UINT128, + PTP_PROPGETSET_GETONLY, + NONE, + MTP_PROP_GROUPCODE_GENERAL); + + { + mtp_uchar guid[16] = { 0 }; + _prop_set_default_integer(&(props_list_default[i].propinfo), + guid); + } + i++; + + /* + * MTP_OBJ_PROPERTYCODE_NONCONSUMABLE (8) + */ + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_NONCONSUMABLE, + PTP_DATATYPE_UINT8, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + default_val = 0x0; + _prop_add_supp_integer_val(&(props_list_default[i].propinfo), 0x0); + _prop_add_supp_integer_val(&(props_list_default[i].propinfo), 0x1); + _prop_set_default_integer(&(props_list_default[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + *MTP_OBJ_PROPERTYCODE_DATEMODIFIED (9) + */ + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_DATEMODIFIED, + PTP_DATATYPE_STRING, + PTP_PROPGETSET_GETONLY, + DATE_TIME_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + _prop_set_default_string(&(props_list_default[i].propinfo), temp); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_DATECREATED (10) + */ + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_DATECREATED, + PTP_DATATYPE_STRING, + PTP_PROPGETSET_GETONLY, + DATE_TIME_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + _prop_set_default_string(&(props_list_default[i].propinfo), temp); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_NAME (11) + */ + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_NAME, + PTP_DATATYPE_STRING, + PTP_PROPGETSET_GETONLY, + NONE, + MTP_PROP_GROUPCODE_GENERAL); + + _prop_set_default_string(&(props_list_default[i].propinfo), temp); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_ASSOCIATIONTYPE (12) + */ + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_ASSOCIATIONTYPE, + PTP_DATATYPE_UINT16, + PTP_PROPGETSET_GETSET, + ENUM_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + default_val = PTP_ASSOCIATIONTYPE_UNDEFINED; + _prop_add_supp_integer_val(&(props_list_default[i].propinfo), + PTP_ASSOCIATIONTYPE_UNDEFINED); + _prop_add_supp_integer_val(&(props_list_default[i].propinfo), + PTP_ASSOCIATIONTYPE_FOLDER); + _prop_set_default_integer(&(props_list_default[i].propinfo), + (mtp_uchar *)&default_val); + + if (_get_oma_drm_status() == TRUE) { + /* + * MTP_OBJ_PROPERTYCODE_OMADRMSTATUS (13) + */ + i++; + __init_obj_prop_desc(&(props_list_default[i]), + MTP_OBJ_PROPERTYCODE_OMADRMSTATUS, + PTP_DATATYPE_UINT8, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + default_val = 0; + _prop_add_supp_integer_val(&(props_list_default[i].propinfo), 0); + _prop_add_supp_integer_val(&(props_list_default[i].propinfo), 1); + _prop_set_default_integer(&(props_list_default[i].propinfo), + (mtp_uchar *)&default_val); + } + + initialized = TRUE; + + return TRUE; +} + +mtp_bool _prop_build_supp_props_mp3(void) +{ + static mtp_bool initialized = FALSE; + mtp_uchar i = 0; + mtp_uint32 default_val; + + if (initialized == TRUE) { + DBG("already supported list is in there. just return!!"); + return TRUE; + } + + /*Common properties 1 - 8 */ + __build_supported_common_props(&i, &props_list_mp3[i]); + + /* + * MTP_OBJ_PROPERTYCODE_AUDIOBITRATE (9) + */ + __init_obj_prop_desc(&(props_list_mp3[i]), + MTP_OBJ_PROPERTYCODE_AUDIOBITRATE, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, + MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_AUDIO_BITRATE_UNKNOWN; + _prop_set_range_integer(&(props_list_mp3[i].propinfo), + MTP_AUDIO_BITRATE_UNKNOWN, MTP_AUDIO_BITRATE_BLUERAY, 1L); + _prop_set_default_integer(&(props_list_mp3[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_SAMPLERATE (10) + */ + __init_obj_prop_desc(&(props_list_mp3[i]), + MTP_OBJ_PROPERTYCODE_SAMPLERATE, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, + MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_AUDIO_SAMPLERATE_UNKNOWN; + _prop_set_range_integer(&(props_list_mp3[i].propinfo), + MTP_AUDIO_SAMPLERATE_8K, MTP_AUDIO_SAMPLERATE_48K, 1L); + _prop_set_default_integer(&(props_list_mp3[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_NUMBEROFCHANNELS (11) + */ + __init_obj_prop_desc(&(props_list_mp3[i]), + MTP_OBJ_PROPERTYCODE_NUMBEROFCHANNELS, + PTP_DATATYPE_UINT16, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, + MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_CHANNELS_MONO; + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_CHANNELS_NOT_USED); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_CHANNELS_MONO); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_CHANNELS_STEREO); + _prop_set_default_integer(&(props_list_mp3[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_AUDIOWAVECODEC (12) + */ + __init_obj_prop_desc(&(props_list_mp3[i]), + MTP_OBJ_PROPERTYCODE_AUDIOWAVECODEC, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, + MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_WAVEFORMAT_UNKNOWN; + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_UNKNOWN); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_PCM); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_ADPCM); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_IEEEFLOAT); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_DTS); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_DRM); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_WMSP2); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_GSM610); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_MSNAUDIO); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_MPEG); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_MPEGLAYER3); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_MSAUDIO1); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_MSAUDIO2); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_MSAUDIO3); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_WMAUDIOLOSSLESS); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_WMASPDIF); + _prop_add_supp_integer_val(&(props_list_mp3[i].propinfo), + MTP_WAVEFORMAT_AAC); + _prop_set_default_integer(&(props_list_mp3[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_DESCRIPTION (13) + */ + __init_obj_prop_desc(&(props_list_mp3[i]), + MTP_OBJ_PROPERTYCODE_DESCRIPTION, + PTP_DATATYPE_AUINT16, + PTP_PROPGETSET_GETONLY, + LONG_STRING_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + _prop_set_maxlen(&(props_list_mp3[i]), MAX_PTP_STRING_CHARS); + _prop_set_default_array(&(props_list_mp3[i].propinfo), NULL, 0); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_COPYRIGHTINFO (14) + */ + __init_obj_prop_desc(&(props_list_mp3[i]), + MTP_OBJ_PROPERTYCODE_COPYRIGHTINFO, + PTP_DATATYPE_AUINT16, + PTP_PROPGETSET_GETONLY, + LONG_STRING_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + _prop_set_maxlen(&(props_list_mp3[i]), MAX_PTP_STRING_CHARS); + _prop_set_default_array(&(props_list_mp3[i].propinfo), NULL, 0); + + initialized = TRUE; + return TRUE; +} + +mtp_bool _prop_build_supp_props_wma(void) +{ + static mtp_bool initialized = FALSE; + mtp_uchar i = 0; + mtp_uint32 default_val; + + if (initialized == TRUE) { + DBG("already supported list is in there. just return!!"); + return TRUE; + } + + /*Common properties 1 - 8 */ + __build_supported_common_props(&i, &props_list_wma[i]); + /* + * MTP_OBJ_PROPERTYCODE_AUDIOBITRATE (9) + */ + __init_obj_prop_desc(&(props_list_wma[i]), + MTP_OBJ_PROPERTYCODE_AUDIOBITRATE, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, + MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_AUDIO_BITRATE_UNKNOWN; + _prop_set_range_integer(&(props_list_wma[i].propinfo), + MTP_AUDIO_BITRATE_UNKNOWN, MTP_AUDIO_BITRATE_BLUERAY, 1L); + _prop_set_default_integer(&(props_list_wma[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_SAMPLERATE (10) + */ + __init_obj_prop_desc(&(props_list_wma[i]), + MTP_OBJ_PROPERTYCODE_SAMPLERATE, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, + MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_AUDIO_SAMPLERATE_UNKNOWN; + _prop_set_range_integer(&(props_list_wma[i].propinfo), + MTP_AUDIO_SAMPLERATE_8K, MTP_AUDIO_SAMPLERATE_48K, 1L); + _prop_set_default_integer(&(props_list_wma[i]).propinfo, + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_NUMBEROFCHANNELS (11) + */ + __init_obj_prop_desc(&(props_list_wma[i]), + MTP_OBJ_PROPERTYCODE_NUMBEROFCHANNELS, + PTP_DATATYPE_UINT16, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, + MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_CHANNELS_MONO; + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_CHANNELS_NOT_USED); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_CHANNELS_MONO); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_CHANNELS_STEREO); + _prop_set_default_integer(&(props_list_wma[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_AUDIOWAVECODEC (12) + */ + __init_obj_prop_desc(&(props_list_wma[i]), + MTP_OBJ_PROPERTYCODE_AUDIOWAVECODEC, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, + MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_WAVEFORMAT_UNKNOWN; + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_UNKNOWN); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_PCM); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_ADPCM); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_IEEEFLOAT); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_DTS); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_DRM); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_WMSP2); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_GSM610); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_MSNAUDIO); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_MPEG); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_MPEGLAYER3); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_MSAUDIO1); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_MSAUDIO2); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_MSAUDIO3); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_WMAUDIOLOSSLESS); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_WMASPDIF); + _prop_add_supp_integer_val(&(props_list_wma[i].propinfo), + MTP_WAVEFORMAT_AAC); + _prop_set_default_integer(&(props_list_wma[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_DESCRIPTION (13) + */ + __init_obj_prop_desc(&(props_list_wma[i]), + MTP_OBJ_PROPERTYCODE_DESCRIPTION, + PTP_DATATYPE_AUINT16, + PTP_PROPGETSET_GETONLY, + LONG_STRING_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + _prop_set_maxlen(&(props_list_wma[i]), MAX_PTP_STRING_CHARS); + _prop_set_default_array(&(props_list_wma[i].propinfo), NULL, 0); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_COPYRIGHTINFO (14) + */ + __init_obj_prop_desc(&(props_list_wma[i]), + MTP_OBJ_PROPERTYCODE_COPYRIGHTINFO, + PTP_DATATYPE_AUINT16, + PTP_PROPGETSET_GETONLY, + LONG_STRING_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + _prop_set_maxlen(&(props_list_wma[i]), MAX_PTP_STRING_CHARS); + _prop_set_default_array(&(props_list_wma[i].propinfo), NULL, 0); + + /*------------------------------------------------------------- + * Valid Configurations for interdependent Object properties + *------------------------------------------------------------- + */ +#ifdef MTP_SUPPORT_INTERDEPENDENTPROP + { + interdep_prop_config_t *ptr_interdep_prop_cfg = NULL; + obj_prop_desc_t *prop = NULL; + mtp_uint32 default_val; + + _util_init_list(&(interdep_proplist.plist)); + + prop = (obj_prop_desc_t *)g_malloc(sizeof(obj_prop_desc_t) * 4); + if (!prop) { + ERR("prop g_malloc fail"); + return FALSE; + } + /* Valid config. 1 for Bit Rate and Sample Rate */ + ptr_interdep_prop_cfg = + (interdep_prop_config_t *)g_malloc(sizeof(interdep_prop_config_t)); + if (!ptr_interdep_prop_cfg) { + g_free(prop); + ERR("ptr_interdep_prop_config g_malloc fail"); + return FALSE; + } + + _util_init_list(&(ptr_interdep_prop_cfg->propdesc_list)); + if (!ptr_interdep_prop_cfg) { + g_free(prop); + return FALSE; + } + ptr_interdep_prop_cfg->format_code = MTP_FMT_WMA; + i = 0; + + __init_obj_prop_desc(&(prop[i]), + MTP_OBJ_PROPERTYCODE_TOTALBITRATE, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, MTP_PROP_GROUPCODE_GENERAL); + + default_val = MTP_AUDIO_BITRATE_192K; + _prop_set_range_integer(&(prop[i].propinfo), + MTP_AUDIO_BITRATE_192K, + MTP_AUDIO_BITRATE_256K, 1000L); + _prop_set_default_integer(&(prop[i].propinfo), + (mtp_uchar *)&default_val); + __append_interdep_prop(ptr_interdep_prop_cfg, &(prop[i])); + i++; + + __init_obj_prop_desc(&(prop[i]), + MTP_OBJ_PROPERTYCODE_SAMPLERATE, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, MTP_PROP_GROUPCODE_GENERAL); + + _prop_add_supp_integer_val(&(prop[i].propinfo), + MTP_AUDIO_SAMPLERATE_DVD); + _prop_set_default_integer(&(prop[i].propinfo), + (mtp_uchar *)MTP_AUDIO_SAMPLERATE_DVD); + __append_interdep_prop(ptr_interdep_prop_cfg, &(prop[i])); + i++; + + /* Created one valid configuration */ + + mtp_bool ret; + ret = _util_add_node(&(interdep_proplist.plist), + (void *)ptr_interdep_prop_cfg); + if (ret == FALSE) { + g_free(prop); + ERR("List add Fail"); + return FALSE; + } + + /* Valid config. 2 for Bit Rate and Sample Rate */ + ptr_interdep_prop_cfg = + (interdep_prop_config_t *)g_malloc(sizeof(interdep_prop_config_t)); + if (!ptr_interdep_prop_cfg) { + g_free(prop); + ERR("ptr_interdep_prop_cfg g_malloc fail"); + return FALSE; + } + _util_init_list(&(ptr_interdep_prop_cfg->propdesc_list)); + + if (!ptr_interdep_prop_cfg) { + g_free(prop); + return FALSE; + } + ptr_interdep_prop_cfg->format_code = MTP_FMT_WMA; + + __init_obj_prop_desc(&(prop[i]), + MTP_OBJ_PROPERTYCODE_TOTALBITRATE, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, MTP_PROP_GROUPCODE_GENERAL); + + default_val = 0x0; + _prop_set_range_integer(&(prop[i].propinfo), + MTP_AUDIO_BITRATE_GSM, + MTP_AUDIO_BITRATE_BLUERAY, 1L); + _prop_set_default_integer(&(prop[i].propinfo), + (mtp_uchar *)&default_val); + __append_interdep_prop(ptr_interdep_prop_cfg, &(prop[i])); + i++; + + __init_obj_prop_desc(&(prop[i]), + MTP_OBJ_PROPERTYCODE_SAMPLERATE, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, MTP_PROP_GROUPCODE_GENERAL); + + default_val = MTP_AUDIO_SAMPLERATE_CD; + _prop_add_supp_integer_val(&(prop[i].propinfo), + MTP_AUDIO_SAMPLERATE_32K); + _prop_add_supp_integer_val(&(prop[i].propinfo), + MTP_AUDIO_SAMPLERATE_CD); + _prop_set_default_integer(&(prop[i].propinfo), + (mtp_uchar *)&default_val); + __append_interdep_prop(ptr_interdep_prop_cfg, &(prop[i])); + i++; + + /* Created one valid configuration */ + ret = _util_add_node(&(interdep_proplist.plist), + (void *)ptr_interdep_prop_cfg); + if (ret == FALSE) { + g_free(prop); + ERR("List add Fail"); + return FALSE; + } + g_free(prop); + } +#endif /*MTP_SUPPORT_INTERDEPENDENTPROP*/ + + initialized = TRUE; + + return TRUE; +} + +mtp_bool _prop_build_supp_props_wmv(void) +{ + static mtp_bool initialized = FALSE; + mtp_wchar buff[3] = { 0 }; + mtp_uchar i = 0; + mtp_uint32 default_val; + + if (initialized == TRUE) { + DBG("already supported list is in there. just return!!"); + return TRUE; + } + _util_utf8_to_utf16(buff, sizeof(buff) / WCHAR_SIZ, ""); + + /*Common properties 1 - 8 */ + __build_supported_common_props(&i, &props_list_wmv[i]); + + /* + * MTP_OBJ_PROPERTYCODE_WIDTH (9) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_WIDTH, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = 0x0; + _prop_set_range_integer(&(props_list_wmv[i].propinfo), + MTP_MIN_VIDEO_WIDTH, MTP_MAX_VIDEO_WIDTH, + MTP_VIDEO_HEIGHT_WIDTH_INTERVAL); + _prop_set_default_integer(&(props_list_wmv[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_HEIGHT (10) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_HEIGHT, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = 0x0; + _prop_set_range_integer(&(props_list_wmv[i].propinfo), + MTP_MIN_VIDEO_HEIGHT, MTP_MAX_VIDEO_HEIGHT, + MTP_VIDEO_HEIGHT_WIDTH_INTERVAL); + _prop_set_default_integer(&(props_list_wmv[i].propinfo), + (mtp_uchar *)&default_val); + + i++; + + /* + * MTP_OBJ_PROPERTYCODE_SAMPLERATE (11) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_SAMPLERATE, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_AUDIO_SAMPLERATE_8K; + _prop_set_range_integer(&(props_list_wmv[i]).propinfo, + MTP_AUDIO_SAMPLERATE_8K, + MTP_AUDIO_SAMPLERATE_DVD, MTP_AUDIO_SAMPLE_RATE_INTERVAL); + _prop_set_default_integer(&(props_list_wmv[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_NUMBEROFCHANNELS (12) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_NUMBEROFCHANNELS, + PTP_DATATYPE_UINT16, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_CHANNELS_MONO; + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_CHANNELS_NOT_USED); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_CHANNELS_MONO); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_CHANNELS_STEREO); + _prop_set_default_integer(&(props_list_wmv[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_AUDIOWAVECODEC (13) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_AUDIOWAVECODEC, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_WAVEFORMAT_UNKNOWN; + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_WAVEFORMAT_UNKNOWN); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_WAVEFORMAT_MPEGLAYER3); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_WAVEFORMAT_MSAUDIO1); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_WAVEFORMAT_MSAUDIO2); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_WAVEFORMAT_PCM); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_WAVEFORMAT_ADPCM); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_WAVEFORMAT_MSAUDIO3); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_WAVEFORMAT_RAW_AAC1); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_WAVEFORMAT_MPEG_HEAAC); + _prop_set_default_integer(&(props_list_wmv[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_AUDIOBITRATE (14) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_AUDIOBITRATE, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_AUDIO_BITRATE_UNKNOWN; + _prop_set_range_integer(&(props_list_wmv[i].propinfo), + MTP_AUDIO_BITRATE_UNKNOWN, + MTP_AUDIO_BITRATE_BLUERAY, 1L); + _prop_set_default_integer(&(props_list_wmv[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_VIDEOFOURCCCODEC (15) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_VIDEOFOURCCCODEC, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_VIDEOFOURCC_MP42; + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_UNKNOWN); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_H263); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_H264); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_MP42); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_MP43); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_WMV1); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_WMV2); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_WMV3); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_DIVX); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_XVID); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_M4S2); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_MP4V); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_AVC1); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_h264); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_X264); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_VIDEOFOURCC_N264); + _prop_set_default_integer(&(props_list_wmv[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_VIDEOBITRATE (16) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_VIDEOBITRATE, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_MIN_VIDEO_BITRATE; + _prop_set_range_integer(&(props_list_wmv[i].propinfo), + MTP_MIN_VIDEO_BITRATE, MTP_MAX_VIDEO_BITRATE, 1L); + _prop_set_default_integer(&(props_list_wmv[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_FRAMESPER1KSECONDS (17) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_FRAMESPER1KSECONDS, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_MIN_VIDEO_FPS; + _prop_set_range_integer(&(props_list_wmv[i].propinfo), MTP_MIN_VIDEO_FPS, + MTP_MAX_VIDEO_FPS, 1L); + _prop_set_default_integer(&(props_list_wmv[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_DESCRIPTION (18) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_DESCRIPTION, + PTP_DATATYPE_AUINT16, + PTP_PROPGETSET_GETONLY, + LONG_STRING_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + _prop_set_maxlen(&(props_list_wmv[i]), MAX_PTP_STRING_CHARS); + _prop_set_default_array(&(props_list_wmv[i].propinfo), NULL, 0); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_COPYRIGHTINFO (19) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_COPYRIGHTINFO, + PTP_DATATYPE_AUINT16, + PTP_PROPGETSET_GETONLY, + LONG_STRING_FORM, + MTP_PROP_GROUPCODE_GENERAL); + + _prop_set_maxlen(&(props_list_wmv[i]), MAX_PTP_STRING_CHARS); + _prop_set_default_array(&(props_list_wmv[i].propinfo), NULL, 0); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_ENCODINGPROFILE (20) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_ENCODINGPROFILE, + PTP_DATATYPE_STRING, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, MTP_PROP_GROUPCODE_OBJECT); + + _util_utf8_to_utf16(buff, sizeof(buff) / WCHAR_SIZ, "SP"); + _prop_add_supp_string_val(&(props_list_wmv[i].propinfo), buff); + _util_utf8_to_utf16(buff, sizeof(buff) / WCHAR_SIZ, "MP"); + _prop_add_supp_string_val(&(props_list_wmv[i].propinfo), buff); + _util_utf8_to_utf16(buff, sizeof(buff) / WCHAR_SIZ, "SP"); + _prop_set_default_string(&(props_list_wmv[i].propinfo), buff); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_METAGENRE (21) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_METAGENRE, + PTP_DATATYPE_UINT16, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_METAGENRE_NOT_USED; + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_NOT_USED); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_GENERIC_MUSIC_AUDIO_FILE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_GENERIC_NONMUSIC_AUDIO_FILE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_SPOKEN_WORD_AUDIO_BOOK_FILES); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_SPOKEN_WORD_NONAUDIO_BOOK_FILES); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_SPOKEN_WORD_NEWS); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_GENERIC_VIDEO_FILE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_NEWS_VIDEO_FILE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_MUSIC_VIDEO_FILE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_HOME_VIDEO_FILE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_FEATURE_FILM_VIDEO_FILE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_TV_SHOW_VIDEO_FILE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_TRAINING_VIDEO_FILE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_PHOTO_MONTAGE_VIDEO_FILE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_GENERIC_NONAUDIO_NONVIDEO_FILE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_AUDIO_MEDIA_CAST_FILE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_METAGENRE_VIDEO_MEDIA_CAST_FILE); + _prop_set_default_integer(&(props_list_wmv[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_SCANTYPE (22) + */ + __init_obj_prop_desc(&(props_list_wmv[i]), + MTP_OBJ_PROPERTYCODE_SCANTYPE, + PTP_DATATYPE_UINT16, + PTP_PROPGETSET_GETONLY, + ENUM_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = MTP_SCANTYPE_NOT_USED; + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_SCANTYPE_NOT_USED); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_SCANTYPE_PROGESSIVE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_SCANTYPE_FIELDINTERLEAVEDUPPERFIRST); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_SCANTYPE_FIELDINTERLEAVEDLOWERFIRST); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_SCANTYPE_FIELDSINGLEUPPERFIRST); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_SCANTYPE_FIELDSINGLELOWERFIRST); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_SCANTYPE_MIXEDINTERLACE); + _prop_add_supp_integer_val(&(props_list_wmv[i].propinfo), + MTP_SCANTYPE_MIXEDINTERLACEANDPROGRESSIVE); + _prop_set_default_integer(&(props_list_wmv[i].propinfo), + (mtp_uchar *)&default_val); + +#ifdef MTP_SUPPORT_PROPERTY_SAMPLE + __build_supported_sample_props(&i, &props_list_wmv[i]); +#endif /*MTP_SUPPORT_PROPERTY_SAMPLE*/ + + initialized = TRUE; + + return TRUE; +} + +mtp_bool _prop_build_supp_props_album(void) +{ + static mtp_bool initialized = FALSE; + mtp_uchar i = 0; + mtp_uint32 default_val; + + if (initialized == TRUE) { + DBG("already supported list is in there. just return!!"); + return TRUE; + } + + /* + * MTP_OBJ_PROPERTYCODE_WIDTH (1) + */ + __init_obj_prop_desc(&(props_list_album[i]), + MTP_OBJ_PROPERTYCODE_WIDTH, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = 0x0; + _prop_set_range_integer(&(props_list_album[i].propinfo), 0, + MTP_MAX_IMG_WIDTH, 1L); + _prop_set_default_integer(&(props_list_album[i].propinfo), + (mtp_uchar *)&default_val); + i++; + + /* + * MTP_OBJ_PROPERTYCODE_HEIGHT (2) + */ + __init_obj_prop_desc(&(props_list_album[i]), + MTP_OBJ_PROPERTYCODE_HEIGHT, + PTP_DATATYPE_UINT32, + PTP_PROPGETSET_GETONLY, + RANGE_FORM, MTP_PROP_GROUPCODE_OBJECT); + + default_val = 0x0; + _prop_set_range_integer(&(props_list_album[i].propinfo), 0, + MTP_MAX_IMG_HEIGHT, 1L); + _prop_set_default_integer(&(props_list_album[i].propinfo), + (mtp_uchar *)&default_val); + + /* + * SAMPLE PROPERTIES (3-8) + */ +#ifdef MTP_SUPPORT_PROPERTY_SAMPLE + i++ + __build_supported_sample_props(&i, &props_list_album[i]); +#endif /*MTP_SUPPORT_PROPERTY_SAMPLE*/ + + initialized = TRUE; + + return TRUE; +} + +void _prop_destroy_supp_obj_props(void) +{ + mtp_uint32 i = 0; + int num_default_obj_prps = 0; + + for (i = 0; i < NUM_OBJECT_PROP_DESC_MP3; i++) { + __destroy_obj_prop_desc(&(props_list_mp3[i])); + } + + for (i = 0; i < NUM_OBJECT_PROP_DESC_WMA; i++) { + __destroy_obj_prop_desc(&(props_list_wma[i])); + } + + for (i = 0; i < NUM_OBJECT_PROP_DESC_WMV; i++) { + __destroy_obj_prop_desc(&(props_list_wmv[i])); + } + + for (i = 0; i < NUM_OBJECT_PROP_DESC_ALBUM; i++) { + __destroy_obj_prop_desc(&(props_list_album[i])); + } + + if (_get_oma_drm_status() == TRUE) { + num_default_obj_prps = NUM_OBJECT_PROP_DESC_DEFAULT; + } else { + num_default_obj_prps = NUM_OBJECT_PROP_DESC_DEFAULT - 1; + } + + for (i = 0; i < num_default_obj_prps; i++) { + __destroy_obj_prop_desc(&(props_list_default[i])); + } + return; +} + +#ifdef MTP_SUPPORT_INTERDEPENDENTPROP +static mtp_bool __append_interdep_prop(interdep_prop_config_t *prop_config, + obj_prop_desc_t *prop) +{ + mtp_bool ret; + if (prop != NULL) { + ret = _util_add_node(&(prop_config->propdesc_list), + (void*)prop); + if (ret == FALSE) { + ERR("list add Fail"); + return FALSE; + } + return TRUE; + } + return FALSE; +} +#endif /* MTP_SUPPORT_INTERDEPENDENTPROP */ + +mtp_uint32 _prop_get_size_interdep_prop(interdep_prop_config_t *prop_config) +{ + obj_prop_desc_t *prop = NULL; + slist_node_t *node; + mtp_int32 ii; + mtp_uint32 size = sizeof(mtp_uint32); + + node = prop_config->propdesc_list.start; + for (ii = 0; ii < prop_config->propdesc_list.nnodes; ii++) { + prop = node->value; + if (prop) { + size += _prop_size_obj_prop_desc(prop); + } + } + return size; +} + +mtp_uint32 _prop_pack_interdep_prop(interdep_prop_config_t *prop_config, + mtp_uchar *buf, mtp_uint32 size) +{ + mtp_uchar *temp = buf; + obj_prop_desc_t *prop = NULL; + slist_node_t *node; + mtp_uint32 ele_size = 0; + mtp_int32 ii; + + if (!buf || size < _prop_get_size_interdep_prop(prop_config)) { + return 0; + } + + *(mtp_uint32 *) buf = prop_config->propdesc_list.nnodes; +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(buf, sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uint32); + + node = prop_config->propdesc_list.start; + for (ii = 0; ii < prop_config->propdesc_list.nnodes; ii++) { + prop = node->value; + + if (prop) { + ele_size = _prop_size_obj_prop_desc(prop); + _prop_pack_obj_prop_desc(prop, temp, ele_size); + temp += ele_size; + } + } + + return (mtp_uint32)(temp - buf); +} + +static mtp_uint32 __count_interdep_proplist(obj_interdep_proplist_t *config_list, + mtp_uint32 format_code) +{ + mtp_uint32 count = 0; + interdep_prop_config_t *prop_config = NULL; + slist_node_t *node; + mtp_int32 ii; + + node = config_list->plist.start; + + for (ii = 0; ii < config_list->plist.nnodes; ii++) { + prop_config = node->value; + if ((prop_config->format_code == format_code) || + (prop_config->format_code == PTP_FORMATCODE_NOTUSED)) { + count++; + } + } + return count; +} + +mtp_uint32 _prop_get_size_interdep_proplist(obj_interdep_proplist_t *config_list, + mtp_uint32 format_code) +{ + mtp_uint32 size = sizeof(mtp_uint32); + interdep_prop_config_t *prop_config = NULL; + slist_node_t *node; + mtp_int32 ii; + + node = config_list->plist.start; + + for (ii = 0; ii < config_list->plist.nnodes; ii++) { + prop_config = node->value; + if ((prop_config->format_code == format_code) || + (prop_config->format_code == PTP_FORMATCODE_NOTUSED)) { + + size += _prop_get_size_interdep_prop(prop_config); + } + } + return size; +} + +mtp_uint32 _prop_pack_interdep_proplist(obj_interdep_proplist_t *config_list, + mtp_uint32 format_code, mtp_uchar *buf, mtp_uint32 size) +{ + mtp_uchar *temp = buf; + interdep_prop_config_t *prop_config = NULL; + slist_node_t *node; + mtp_int32 ii; + mtp_uint32 ele_size = 0; + + if (!buf || + size < _prop_get_size_interdep_proplist(config_list, format_code)) { + return 0; + } + + *(mtp_uint32 *)buf = __count_interdep_proplist(config_list, + format_code); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(buf, sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uint32); + + node = config_list->plist.start; + + for (ii = 0; ii < config_list->plist.nnodes; ii++) { + + prop_config = node->value; + if ((prop_config->format_code == format_code) || + (prop_config->format_code == PTP_FORMATCODE_NOTUSED)) { + + ele_size = _prop_get_size_interdep_prop(prop_config); + _prop_pack_interdep_prop(prop_config, temp, ele_size); + temp += ele_size; + } + } + + return (mtp_uint32)(temp - buf); +} + +mtp_bool _get_oma_drm_status(void) +{ +#ifdef MTP_SUPPORT_OMADRM_EXTENSION + return TRUE; +#else /* MTP_SUPPORT_OMADRM_EXTENSION */ + return FALSE; +#endif /* MTP_SUPPORT_OMADRM_EXTENSION */ +} diff --git a/src/entity/mtp_store.c b/src/entity/mtp_store.c new file mode 100755 index 0000000..dbf744e --- /dev/null +++ b/src/entity/mtp_store.c @@ -0,0 +1,1233 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <glib.h> +#include <unistd.h> +#include <sys/types.h> +#include <dirent.h> +#include "mtp_util.h" +#include "mtp_support.h" +#include "mtp_device.h" +#include "mtp_media_info.h" +#include "mtp_transport.h" +#include "mtp_inoti_handler.h" + + +extern mtp_char g_last_deleted[MTP_MAX_PATHNAME_SIZE + 1]; +static mtp_uint32 g_next_obj_handle = 1; + + +static inline mtp_bool UTIL_CHECK_LIST_NEXT(slist_iterator *iter) +{ + return (iter && iter->node_ptr) ? TRUE : FALSE; +} + +static void __init_store_info(store_info_t *info) +{ + ret_if(info == NULL); + + memset(info, 0x00, sizeof(store_info_t)); + + info->store_type = PTP_STORAGETYPE_FIXEDRAM; + info->fs_type = PTP_FILESYSTEMTYPE_DCF; + info->access = PTP_STORAGEACCESS_RWD; + + info->capacity = MTP_MAX_STORAGE; + info->free_space = MTP_MAX_STORAGE - 1; + info->free_space_in_objs = MTP_MAX_STORAGE_IN_OBJTS; + + return; +} + +static void __init_store_info_params(store_info_t *info, + mtp_uint64 capacity, mtp_uint16 store_type, mtp_uint16 fs_type, + mtp_uint16 access, mtp_wchar *store_desc, mtp_wchar *label) +{ + info->store_type = store_type; + info->fs_type = fs_type; + info->access = access; + + info->capacity = capacity; + info->free_space = capacity; + info->free_space_in_objs = MTP_MAX_STORAGE_IN_OBJTS; + + _prop_copy_char_to_ptpstring(&(info->store_desc), store_desc, WCHAR_TYPE); + _prop_copy_char_to_ptpstring(&(info->vol_label), label, WCHAR_TYPE); + return; +} + +void _entity_update_store_info_run_time(store_info_t *info, + mtp_char *root_path) +{ + fs_info_t fs_info = { 0 }; + + ret_if(info == NULL); + ret_if(root_path == NULL); + + if (FALSE == _util_get_filesystem_info(root_path, &fs_info)) { + ERR("_util_get_filesystem_info fail [%s]\n", root_path); + return; + } + + info->capacity = fs_info.disk_size; + info->free_space = fs_info.avail_size; + + return; +} + +mtp_bool _entity_get_store_path_by_id(mtp_uint32 store_id, mtp_char *path) +{ + switch(store_id) { + case MTP_INTERNAL_STORE_ID : + g_strlcpy(path, MTP_STORE_PATH_CHAR, + MTP_MAX_PATHNAME_SIZE + 1); + break; + case MTP_EXTERNAL_STORE_ID : + g_strlcpy(path, MTP_EXTERNAL_PATH_CHAR, + MTP_MAX_PATHNAME_SIZE + 1); + break; + default : + ERR("No valid match for the store id [0x%x]\n", store_id); + return FALSE; + + } + return TRUE; +} + +mtp_uint32 _entity_get_store_info_size(store_info_t *info) +{ + mtp_uint32 size = FIXED_LENGTH_MEMBERS_MTPSTORE_SIZE; + + size += _prop_size_ptpstring(&(info->store_desc)); + size += _prop_size_ptpstring(&(info->vol_label)); + + return (size); +} + +mtp_uint32 _entity_pack_store_info(store_info_t *info, mtp_uchar *buf, + mtp_uint32 buf_sz) +{ + mtp_uint32 num_bytes = 0; + + retv_if(buf == NULL, 0); + + if (buf_sz < _entity_get_store_info_size(info)) { + ERR("Buffer size is less [%u]\n", buf_sz); + return 0; + } +#ifdef __BIG_ENDIAN__ + memcpy(&(buf[num_bytes]), &(info->store_type), + sizeof(info->StorageType)); + _util_conv_byte_order(buf, sizeof(info->store_type)); + num_bytes += sizeof(info->store_type); + + memcpy(&(buf[num_bytes]), &(info->fs_type), sizeof(info->fs_type)); + _util_conv_byte_order(buf, sizeof(info->fs_type)); + num_bytes += sizeof(info->fs_type); + + memcpy(&(buf[num_bytes]), &(info->access), sizeof(info->access)); + _util_conv_byte_order(buf, sizeof(info->access)); + num_bytes += sizeof(info->access); + + memcpy(&(buf[num_bytes]), &(info->capacity), sizeof(info->capacity)); + _util_conv_byte_order(buf, sizeof(info->capacity)); + num_bytes += sizeof(info->capacity); + + memcpy(&(buf[num_bytes]), &(info->free_space), + sizeof(info->free_space)); + _util_conv_byte_order(buf, sizeof(info->free_space)); + num_bytes += sizeof(info->free_space); + + memcpy(&(buf[num_bytes]), &(info->free_space_in_objs), + sizeof(info->free_space_in_objs)); + _util_conv_byte_order(buf, sizeof(info->free_space_in_objs)); + num_bytes += sizeof(info->free_space_in_objs); +#else /*__BIG_ENDIAN__*/ + memcpy(buf, &(info->store_type), sizeof(mtp_uint16) *3); + num_bytes += sizeof(mtp_uint16) * 3; + memcpy(&(buf[num_bytes]), &(info->capacity), + sizeof(mtp_uint64) * 2 + sizeof(mtp_uint32)); + num_bytes += sizeof(mtp_uint64) * 2 + sizeof(mtp_uint32); +#endif /*__BIG_ENDIAN__*/ + num_bytes += _prop_pack_ptpstring(&(info->store_desc), buf + num_bytes, + _prop_size_ptpstring(&(info->store_desc))); + + num_bytes += _prop_pack_ptpstring(&(info->vol_label), buf + num_bytes, + _prop_size_ptpstring(&(info->vol_label))); + + return num_bytes; +} + +mtp_uint32 _entity_get_store_id_by_path(const mtp_char *path_name) +{ + mtp_uint32 store_id = 0; + + retv_if(NULL == path_name, FALSE); + + if (!strncmp(path_name, MTP_STORE_PATH_CHAR, + strlen(MTP_STORE_PATH_CHAR))) { + store_id = MTP_INTERNAL_STORE_ID; + } else if (!strncmp(path_name, MTP_EXTERNAL_PATH_CHAR, + strlen(MTP_EXTERNAL_PATH_CHAR))) { + store_id = MTP_EXTERNAL_STORE_ID; + } + + DBG_SECURE("Path : %s, store_id : 0x%x\n", path_name, store_id); + + return store_id; +} + +mtp_bool _entity_init_mtp_store(mtp_store_t *store, mtp_uint32 store_id, + mtp_char *store_path) +{ + mtp_char temp[MTP_SERIAL_LEN_MAX + 1] = { 0 }; + mtp_wchar wtemp[MTP_MAX_REG_STRING + 1] = { 0 }; + mtp_char serial[MTP_MAX_REG_STRING + 1] = { 0 }; + mtp_wchar wserial[MTP_MAX_REG_STRING + 1] = { 0 }; + + retv_if(store == NULL, FALSE); + + store->store_id = store_id; + store->root_path = g_strdup(store_path); + + __init_store_info(&(store->store_info)); + _entity_update_store_info_run_time(&(store->store_info), + store->root_path); + + _device_get_serial(temp, sizeof(temp)); + g_snprintf(serial, sizeof(serial), "%s-%x", temp, store_id); + _util_utf8_to_utf16(wserial, sizeof(wserial) / WCHAR_SIZ, serial); + + switch (store_id) { + case MTP_INTERNAL_STORE_ID: + store->is_hidden = FALSE; + _util_utf8_to_utf16(wtemp, sizeof(wtemp) / WCHAR_SIZ, + MTP_STORAGE_DESC_INT); + __init_store_info_params(&(store->store_info), + store->store_info.capacity, PTP_STORAGETYPE_FIXEDRAM, + PTP_FILESYSTEMTYPE_HIERARCHICAL, PTP_STORAGEACCESS_RWD, + wtemp, wserial); + break; + + case MTP_EXTERNAL_STORE_ID: + store->is_hidden = FALSE; + _util_utf8_to_utf16(wtemp, sizeof(wtemp) / WCHAR_SIZ, + MTP_STORAGE_DESC_EXT); + __init_store_info_params(&(store->store_info), + store->store_info.capacity, + PTP_STORAGETYPE_REMOVABLERAM, + PTP_FILESYSTEMTYPE_HIERARCHICAL, + PTP_STORAGEACCESS_RWD, wtemp, wserial); + break; + + default: + ERR("store initialization Fail"); + return FALSE; + } + + _util_init_list(&(store->obj_list)); + + return TRUE; +} + +mtp_obj_t *_entity_add_file_to_store(mtp_store_t *store, mtp_uint32 h_parent, + mtp_char *file_path, mtp_char *file_name, dir_entry_t *file_info) +{ + mtp_obj_t *obj = NULL; + + retv_if(NULL == store, NULL); + + obj = _entity_alloc_mtp_object(); + if (NULL == obj) { + ERR("Memory allocation Fail"); + return NULL; + } + + if (_entity_init_mtp_object_params(obj, store->store_id, h_parent, + file_path, file_name, file_info) == FALSE) { + ERR("_entity_init_mtp_object_params Fail"); + g_free(obj); + return NULL; + } + + _entity_add_object_to_store(store, obj); + return obj; +} + +mtp_obj_t *_entity_add_folder_to_store(mtp_store_t *store, mtp_uint32 h_parent, + mtp_char *file_path, mtp_char *file_name, dir_entry_t *file_info) +{ + mtp_obj_t *obj = NULL; + + retv_if(NULL == store, NULL); + + obj = _entity_alloc_mtp_object(); + if (NULL == obj) { + ERR("Memory allocation Fail"); + return NULL; + } + + if (_entity_init_mtp_object_params(obj, store->store_id, h_parent, + file_path, file_name, file_info) == FALSE) { + ERR("_entity_init_mtp_object_params Fail"); + g_free(obj); + return NULL; + } + + _entity_add_object_to_store(store, obj); + return obj; +} + +mtp_bool _entity_add_object_to_store(mtp_store_t *store, mtp_obj_t *obj) +{ + mtp_obj_t *par_obj = NULL; + + retv_if(obj == NULL, FALSE); + retv_if(NULL == store, FALSE); + retv_if(obj->obj_info == NULL, FALSE); + + if (_util_add_node(&(store->obj_list), obj) == FALSE) { + ERR("Node add to list Fail"); + return FALSE; + } + + /* references */ + if (PTP_OBJECTHANDLE_ROOT != obj->obj_info->h_parent) { + par_obj = _entity_get_object_from_store(store, obj->obj_info->h_parent); + if (NULL != par_obj) { + _entity_add_reference_child_array(par_obj, obj->obj_handle); + } + } + + return TRUE; +} + +mtp_obj_t *_entity_get_object_from_store(mtp_store_t *store, mtp_uint32 handle) +{ + mtp_obj_t *obj = NULL; + slist_iterator *iter = NULL; + + retv_if(NULL == store, NULL); + + iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list)); + if (iter == NULL) { + ERR("Iterator init Fail, Store id = [0x%x]\n", store->store_id); + return NULL; + } + + while(UTIL_CHECK_LIST_NEXT(iter) == TRUE) { + obj = (mtp_obj_t *)_util_get_list_next(iter); + + if (obj && obj->obj_handle == handle) { + _util_deinit_list_iterator(iter); + return obj; + } + } + + ERR("Object not found in the list handle [%d] in store[0x%x]\n", handle, store->store_id); + _util_deinit_list_iterator(iter); + return NULL; +} + +mtp_obj_t *_entity_get_last_object_from_store(mtp_store_t *store, + mtp_uint32 handle) +{ + mtp_obj_t *obj = NULL; + mtp_obj_t *temp_obj = NULL; + slist_iterator *iter = NULL; + + retv_if(NULL == store, NULL); + + iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list)); + if (iter == NULL) { + ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id); + return NULL; + } + + while(UTIL_CHECK_LIST_NEXT(iter) == TRUE) { + + temp_obj = (mtp_obj_t *)_util_get_list_next(iter); + if (temp_obj && temp_obj->obj_handle == handle) { + obj = temp_obj; + } + } + + _util_deinit_list_iterator(iter); + return obj; +} + +mtp_obj_t *_entity_get_object_from_store_by_path(mtp_store_t *store, + mtp_char *file_path) +{ + mtp_obj_t *obj = NULL; + slist_iterator *iter = NULL; + + retv_if(NULL == store, NULL); + + iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list)); + if (iter == NULL) { + ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id); + return NULL; + } + + while(UTIL_CHECK_LIST_NEXT(iter) == TRUE) { + obj = (mtp_obj_t *)_util_get_list_next(iter); + if (obj == NULL) { + ERR("Object is NULL"); + continue; + } + + if (!g_strcmp0(file_path, obj->file_path)) { + _util_deinit_list_iterator(iter); + return obj; + } + } + ERR_SECURE("Object [%s] not found in the list\n", file_path); + _util_deinit_list_iterator(iter); + return NULL; +} + +/* + * _entity_get_objects_from_store + * called in case of PTP_OBJECTHANDLE_ALL + * fills the obj_array with objects matching the format code + */ +mtp_uint32 _entity_get_objects_from_store(mtp_store_t *store, + mtp_uint32 obj_handle, mtp_uint32 fmt, ptp_array_t *obj_arr) +{ + mtp_obj_t *obj = NULL; + slist_iterator *iter = NULL; + + retv_if(store == NULL, 0); + retv_if(obj_arr == NULL, 0); + + if (obj_handle != PTP_OBJECTHANDLE_ALL) { + ERR("Object Handle is not PTP_OBJECTHANDLE_ALL"); + return 0; + } + + iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list)); + if (iter == NULL) { + ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id); + return 0; + } + + while(UTIL_CHECK_LIST_NEXT(iter) == TRUE) { + + obj = (mtp_obj_t *)_util_get_list_next(iter); + if (obj == NULL) { + ERR("Object is NULL"); + continue; + } + if ((fmt == obj->obj_info->obj_fmt) || + (fmt == PTP_FORMATCODE_ALL) || + (fmt == PTP_FORMATCODE_NOTUSED)) { + _prop_append_ele_ptparray(obj_arr, (mtp_uint32)obj); + } + } + _util_deinit_list_iterator(iter); + return obj_arr->num_ele; +} + +mtp_uint32 _entity_get_objects_from_store_till_depth(mtp_store_t *store, + mtp_uint32 obj_handle, mtp_uint32 fmt_code, mtp_uint32 depth, + ptp_array_t *obj_arr) +{ + mtp_obj_t *obj = NULL; + + retv_if(store == NULL, 0); + retv_if(obj_arr == NULL, 0); + + if (PTP_OBJECTHANDLE_ALL == obj_handle) { + _entity_get_objects_from_store(store, obj_handle, fmt_code, + obj_arr); + DBG("Number of object filled [%u]\n", obj_arr->num_ele); + return obj_arr->num_ele; + } + + if (PTP_OBJECTHANDLE_ROOT != obj_handle) { + obj = _entity_get_object_from_store(store, obj_handle); + if (obj) { + _prop_append_ele_ptparray(obj_arr, (mtp_uint32)obj); + } + } + if (depth > 0) { + ptp_array_t *child_arr = NULL; + mtp_uint32 *ptr = NULL; + mtp_uint32 ii = 0; + + child_arr = _prop_alloc_ptparray(UINT32_TYPE); + if (child_arr == NULL || child_arr->array_entry == NULL) + return 0; + + depth--; + + _entity_get_child_handles_with_same_format(store, obj_handle, + fmt_code, child_arr); + ptr = child_arr->array_entry; + + for (ii = 0; ii < child_arr->num_ele; ii++) { + _entity_get_objects_from_store_till_depth(store, + ptr[ii], fmt_code, depth, obj_arr); + } + _prop_destroy_ptparray(child_arr); + } + + DBG("Handle[%u] : array count [%u]!!\n", obj_handle, + obj_arr->num_ele); + return obj_arr->num_ele; +} + +mtp_uint32 _entity_get_objects_from_store_by_format(mtp_store_t *store, + mtp_uint32 format, ptp_array_t *obj_arr) +{ + mtp_obj_t *obj = NULL; + slist_iterator *iter = NULL; + + retv_if(store == NULL, 0); + retv_if(obj_arr == NULL, 0); + + iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list)); + if (iter == NULL) { + ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id); + return 0; + } + + while(UTIL_CHECK_LIST_NEXT(iter) == TRUE) { + + obj = (mtp_obj_t *)_util_get_list_next(iter); + if (obj == NULL || obj->obj_info == NULL) + continue; + if ((format == PTP_FORMATCODE_NOTUSED) || + (format == obj->obj_info->obj_fmt) || + ((format == PTP_FORMATCODE_ALL) && + (obj->obj_info->obj_fmt != + PTP_FMT_ASSOCIATION))) { + _prop_append_ele_ptparray(obj_arr, + (mtp_uint32)obj->obj_handle); + } + + } + + _util_deinit_list_iterator(iter); + return (obj_arr->num_ele); +} + +mtp_uint32 _entity_get_num_object_with_same_format(mtp_store_t *store, + mtp_uint32 format) +{ + mtp_uint32 count = 0; + mtp_obj_t *obj = NULL; + slist_iterator *iter = NULL; + + retv_if(store == NULL, 0); + + if (PTP_FORMATCODE_NOTUSED == format) { + return store->obj_list.nnodes; + } + + iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list)); + if (iter == NULL) { + ERR("Iterator init Fail, store id = [0x%x]\n", store->store_id); + return 0; + } + + while(UTIL_CHECK_LIST_NEXT(iter) == TRUE) { + + obj = (mtp_obj_t *)_util_get_list_next(iter); + if (obj == NULL || obj->obj_info == NULL) + continue; + + if ((obj->obj_info->obj_fmt == format) || + (obj->obj_info->obj_fmt != PTP_FMT_ASSOCIATION && + PTP_FORMATCODE_ALL == format)) { + count++; + } + } + + _util_deinit_list_iterator(iter); + return count; +} + +mtp_uint32 _entity_get_num_children(mtp_store_t *store, mtp_uint32 h_parent, + mtp_uint32 format) +{ + mtp_uint32 count = 0; + mtp_obj_t *obj = NULL; + slist_iterator *iter = NULL; + + retv_if(store == NULL, 0); + + iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list)); + if (iter == NULL) { + ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id); + return 0; + } + + while(UTIL_CHECK_LIST_NEXT(iter) == TRUE) { + + obj = (mtp_obj_t *)_util_get_list_next(iter); + if (obj == NULL || obj->obj_info == NULL) + continue; + + if ((obj->obj_info->h_parent == h_parent) && + ((format == obj->obj_info->obj_fmt) || + (format == PTP_FORMATCODE_NOTUSED) || + ((format == PTP_FORMATCODE_ALL) && + (obj->obj_info->obj_fmt != + PTP_FMT_ASSOCIATION)))) { + count++; + } + } + + _util_deinit_list_iterator(iter); + return count; +} + +mtp_uint32 _entity_get_child_handles(mtp_store_t *store, mtp_uint32 h_parent, + ptp_array_t *child_arr) +{ + mtp_obj_t *obj = NULL; + slist_iterator *iter = NULL; + mtp_obj_t *parent_obj = NULL; + + retv_if(store == NULL, 0); + retv_if(child_arr == NULL, 0); + + parent_obj = _entity_get_object_from_store(store, h_parent); + + if (NULL == parent_obj) { + ERR("parent object is NULL"); + return FALSE; + } + + iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list)); + if (iter == NULL) { + ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id); + return 0; + } + + while(UTIL_CHECK_LIST_NEXT(iter) == TRUE) { + + obj = (mtp_obj_t *)_util_get_list_next(iter); + if (obj == NULL || obj->obj_info == NULL) + continue; + + if (obj->obj_info->h_parent == h_parent) { + _prop_append_ele_ptparray(child_arr, obj->obj_handle); + } + } + + _util_deinit_list_iterator(iter); + return child_arr->num_ele; +} + +mtp_uint32 _entity_get_child_handles_with_same_format(mtp_store_t *store, + mtp_uint32 h_parent, mtp_uint32 format, ptp_array_t *child_arr) +{ + mtp_obj_t *obj = NULL; + slist_iterator *iter = NULL; + + retv_if(store == NULL, 0); + retv_if(child_arr == NULL, 0); + + iter = (slist_iterator *)_util_init_list_iterator(&(store->obj_list)); + if (iter == NULL) { + ERR("Iterator init Fail Store id = [0x%x]\n", store->store_id); + return 0; + } + + while(UTIL_CHECK_LIST_NEXT(iter) == TRUE) { + + obj = (mtp_obj_t *)_util_get_list_next(iter); + if (obj == NULL || obj->obj_info == NULL) + continue; + + if ((obj->obj_info->h_parent == h_parent) && + ((obj->obj_info->obj_fmt == format) || + (format == PTP_FORMATCODE_NOTUSED))) { + + _prop_append_ele_ptparray(child_arr, obj->obj_handle); + } + + } + + _util_deinit_list_iterator(iter); + return child_arr->num_ele; +} + +mtp_bool _entity_remove_object_mtp_store(mtp_store_t *store, mtp_obj_t *obj, + mtp_uint32 format, mtp_uint16 *response, mtp_bool *atleast_one, + mtp_bool read_only) +{ + mtp_uint64 size = 0; + mtp_bool all_del = TRUE; + mtp_uint32 h_parent = 0; + obj_info_t *objinfo = NULL; + mtp_int32 ret = MTP_ERROR_NONE; + + retv_if(store == NULL, 0); + + if (TRUE == _transport_get_cancel_initialization() || + TRUE == _transport_get_usb_discon_state()) { + ERR("Delete operation cancelled or USB is disconnected"); + *response = PTP_RESPONSE_PARTIAL_DELETION; + return FALSE; + } + + if (NULL == obj || NULL == obj->obj_info || NULL == store) { + *response = PTP_RESPONSE_UNDEFINED; + return FALSE; + } + + objinfo = obj->obj_info; + + if ((objinfo->obj_fmt != format) && (format != PTP_FORMATCODE_ALL) && + (format != PTP_FORMATCODE_NOTUSED)) { + *response = PTP_RESPONSE_UNDEFINED; + return FALSE; + } + + if ((PTP_FORMATCODE_ALL == format) && + (PTP_FMT_ASSOCIATION == objinfo->obj_fmt)) { + + *response = PTP_RESPONSE_UNDEFINED; + return FALSE; + } + +#ifdef MTP_SUPPORT_SET_PROTECTION + /* Delete readonly files/folder */ + if (!read_only) + objinfo->protcn_status = PTP_PROTECTIONSTATUS_NOPROTECTION; +#endif /* MTP_SUPPORT_SET_PROTECTION */ + + if (PTP_FMT_ASSOCIATION == objinfo->obj_fmt) { + /* If this is an association, delete children first + * the reference list contain all the children handle + * or find a child each time; + */ + + mtp_uint32 i = 0; + ptp_array_t child_arr = { 0 }; + mtp_obj_t *child_obj = NULL; + + _prop_init_ptparray(&child_arr, UINT32_TYPE); + _entity_get_child_handles(store, obj->obj_handle, &child_arr); + + if (child_arr.num_ele) { + + for (i = 0; i < child_arr.num_ele; i++) { + mtp_uint32 *ptr32 = child_arr.array_entry; + /*check cancel transaction*/ + if (_transport_get_cancel_initialization() == TRUE || + _transport_get_usb_discon_state() == TRUE) { + ERR("child handle. USB is disconnected \ + format operation is cancelled."); + *response = + PTP_RESPONSE_PARTIAL_DELETION; + return FALSE; + } + + child_obj = _entity_get_object_from_store(store, + ptr32[i]); + if (NULL == child_obj) { + continue; + } + if (_entity_remove_object_mtp_store(store, child_obj, + format, response, atleast_one, + read_only)) { + slist_node_t *node; + node = _util_delete_node(&(store->obj_list), + child_obj); + g_free(node); + *atleast_one = TRUE; + _entity_dealloc_mtp_obj(child_obj); + } else { + all_del = FALSE; + /*check cancel transaction*/ + if (TRUE == _transport_get_cancel_initialization() || + TRUE == _transport_get_usb_discon_state()) { + ERR("USB is disconnected format\ + operation is cancelled."); + *response = + PTP_RESPONSE_PARTIAL_DELETION; + return FALSE; + } + } + + } + _prop_deinit_ptparray(&child_arr); + + } else { + /* Non-Enumerated Folder */ + mtp_uint32 num_of_deleted_file = 0; + mtp_uint32 num_of_file = 0; + + ret = _util_remove_dir_children_recursive(obj->file_path, + &num_of_deleted_file, &num_of_file, read_only); + if (MTP_ERROR_GENERAL == ret || + MTP_ERROR_ACCESS_DENIED == ret) { + ERR_SECURE("directory children deletion Fail [%s]\n", + obj->file_path); + *response = PTP_RESPONSE_GEN_ERROR; + if (MTP_ERROR_ACCESS_DENIED == ret) + *response = + PTP_RESPONSE_ACCESSDENIED; + return FALSE; + } + if (num_of_file == 0) + DBG_SECURE("Folder[%s] is empty\n", obj->file_path); + else if (num_of_deleted_file == 0) { + DBG_SECURE("Folder[%s] contains only read-only files\n", + obj->file_path); + all_del = FALSE; + } else if (num_of_deleted_file < num_of_file){ + DBG("num of files[%d] is present in folder[%s]\ + and number of deleted files[%d]\n", + num_of_file, obj->file_path, + num_of_deleted_file); + *atleast_one = TRUE; + all_del = FALSE; + } + } + _util_scan_folder_contents_in_db(obj->file_path); + if (all_del) { + g_snprintf(g_last_deleted, + MTP_MAX_PATHNAME_SIZE + 1, "%s", + obj->file_path); + + if (rmdir(obj->file_path) < 0) { + memset(g_last_deleted, 0, + MTP_MAX_PATHNAME_SIZE + 1); + *response = PTP_RESPONSE_GEN_ERROR; + if (EACCES == errno) + *response = + PTP_RESPONSE_ACCESSDENIED; + return FALSE; + } + } else { + ERR("all member in this folder is not deleted."); + } + } else { +#ifdef MTP_SUPPORT_SET_PROTECTION + size = objinfo->file_size; +#endif /* MTP_SUPPORT_SET_PROTECTION */ + + if (objinfo->protcn_status == + PTP_PROTECTIONSTATUS_READONLY || + objinfo->protcn_status == + MTP_PROTECTIONSTATUS_READONLY_DATA) { + *response = PTP_RESPONSE_OBJ_WRITEPROTECTED; + return FALSE; + } + + /* delete the real file */ + g_snprintf(g_last_deleted, MTP_MAX_PATHNAME_SIZE + 1, + "%s", obj->file_path); + if (remove(obj->file_path) < 0) { + memset(g_last_deleted, 0, + MTP_MAX_PATHNAME_SIZE + 1); + *response = PTP_RESPONSE_GEN_ERROR; + if (EACCES == errno) + *response = PTP_RESPONSE_ACCESSDENIED; + return FALSE; + } + *atleast_one = TRUE; + + /* Upate store's available space */ + store->store_info.free_space += size; + } + + if (all_del) { + *response = PTP_RESPONSE_OK; + /* delete references;*/ + h_parent = objinfo->h_parent; + if (h_parent != PTP_OBJECTHANDLE_ROOT) { + mtp_obj_t *parent_obj = + _entity_get_object_from_store(store, h_parent); + if (NULL != parent_obj) { + _entity_remove_reference_child_array(parent_obj, + obj->obj_handle); + } + } + } else if(*atleast_one) { + *response = PTP_RESPONSE_PARTIAL_DELETION; + return FALSE; + } else { + *response = PTP_RESPONSE_OBJ_WRITEPROTECTED; + return FALSE; + } + + return TRUE; +} + +mtp_uint16 _entity_delete_obj_mtp_store(mtp_store_t *store, + mtp_uint32 obj_handle, mtp_uint32 fmt, mtp_bool read_only) +{ + mtp_uint16 response; + mtp_obj_t *obj = NULL; + mtp_bool all_del = TRUE; + mtp_bool atleas_one = FALSE; + + retv_if(store == NULL, PTP_RESPONSE_GEN_ERROR); + + if (PTP_STORAGEACCESS_R == store->store_info.access) { + ERR("Read only store"); + return PTP_RESPONSE_STORE_READONLY; + } + + if (PTP_OBJECTHANDLE_ALL == obj_handle) { + slist_node_t *node = NULL; + node = store->obj_list.start; + while (NULL != node) { + if (TRUE == _transport_get_cancel_initialization() || + TRUE == _transport_get_usb_discon_state()) { + ERR("USB is disconnected format\ + operation is cancelled."); + response = PTP_RESPONSE_GEN_ERROR; + return response; + } + /* protect from disconnect USB */ + if (NULL == store || NULL == node || + NULL == node->value) { + response = PTP_RESPONSE_GEN_ERROR; + return response; + } + + obj = (mtp_obj_t *)node->value; + if (_entity_remove_object_mtp_store(store, obj, + fmt, &response, &atleas_one, read_only)) { + + slist_node_t *temp = NULL; + + node = node->link; + temp = _util_delete_node(&(store->obj_list), obj); + g_free(temp); + _util_delete_file_from_db(obj->file_path); + _entity_dealloc_mtp_obj(obj); + } else { + node = node->link; + } + + switch (response) { + case PTP_RESPONSE_PARTIAL_DELETION: + all_del = FALSE; + break; + case PTP_RESPONSE_OBJ_WRITEPROTECTED: + case PTP_RESPONSE_ACCESSDENIED: + all_del = FALSE; + break; + case PTP_RESPONSE_UNDEFINED: + default: + break; + } + + } + } else { + DBG("object handle is not PTP_OBJECTHANDLE_ALL. [%ld]\n", + obj_handle); + obj = _entity_get_object_from_store(store, obj_handle); + if (_entity_remove_object_mtp_store(store, obj, PTP_FORMATCODE_NOTUSED, + &response, &atleas_one, read_only)) { + slist_node_t *temp = NULL; + + temp = _util_delete_node(&(store->obj_list), obj); + g_free(temp); + _util_delete_file_from_db(obj->file_path); + _entity_dealloc_mtp_obj(obj); + } else { + switch (response) { + case PTP_RESPONSE_PARTIAL_DELETION: + all_del = FALSE; + break; + case PTP_RESPONSE_OBJ_WRITEPROTECTED: + case PTP_RESPONSE_ACCESSDENIED: + all_del = FALSE; + break; + case PTP_RESPONSE_UNDEFINED: + default: + /* do nothing */ + break; + } + } + } + + if (all_del) { + response = PTP_RESPONSE_OK; + } else if (atleas_one) + response = PTP_RESPONSE_PARTIAL_DELETION; + + return response; +} + +mtp_uint32 _entity_get_object_tree_size(mtp_store_t *store, mtp_obj_t *obj) +{ + mtp_uint32 i = 0; + mtp_uint64 size = 0; + + retv_if(store == NULL, 0); + retv_if(obj == NULL, 0); + + if (obj->obj_info->obj_fmt != PTP_FMT_ASSOCIATION) { + size = obj->obj_info->file_size; + } else { + ptp_array_t child_arr = { 0 }; + mtp_obj_t *child_obj = NULL; + + _prop_init_ptparray(&child_arr, UINT32_TYPE); + + _entity_get_child_handles(store, obj->obj_handle, &child_arr); + + for (i = 0; i < child_arr.num_ele; i++) { + mtp_uint32 *ptr32 = child_arr.array_entry; + child_obj = _entity_get_object_from_store(store, + ptr32[i]); + size += _entity_get_object_tree_size(store, child_obj); + } + _prop_deinit_ptparray(&child_arr); + } + + return size; +} + +mtp_bool _entity_check_if_B_parent_of_A(mtp_store_t *store, + mtp_uint32 handleA, mtp_uint32 handleB) +{ + mtp_uint32 i = 0; + mtp_obj_t *obj = NULL; + ptp_array_t child_arr = {0}; + + retv_if(store == NULL, FALSE); + + _prop_init_ptparray(&child_arr, UINT32_TYPE); + _entity_get_child_handles(store, handleB, &child_arr); + + for (i = 0; i < child_arr.num_ele; i++) { + mtp_uint32 *ptr32 = child_arr.array_entry; + if (handleA == ptr32[i]) { + _prop_deinit_ptparray(&child_arr); + return TRUE; + } + + obj = _entity_get_object_from_store(store, ptr32[i]); + if (obj == NULL || obj->obj_info == NULL || + obj->obj_info->obj_fmt == + PTP_FMT_ASSOCIATION) { + continue; + } + if (_entity_check_if_B_parent_of_A(store, handleA, ptr32[i])) { + _prop_deinit_ptparray(&child_arr); + return TRUE; + } + } + _prop_deinit_ptparray(&child_arr); + return FALSE; +} + +mtp_uint32 _entity_generate_next_obj_handle(void) +{ + return g_next_obj_handle++; +} + +mtp_uint16 _entity_format_store(mtp_store_t *store, mtp_uint32 fs_format) +{ + mtp_uint16 response; + + retv_if(store == NULL, PTP_RESPONSE_GEN_ERROR); + + /* Is store ready only? */ + if (store->store_info.access == PTP_STORAGEACCESS_R) { + ERR("Read only storage"); + return PTP_RESPONSE_STORE_READONLY; + } + + /* Is FilesystemFormat supported? */ + if ((fs_format != PTP_FILESYSTEMTYPE_UNDEFINED) && + (fs_format != PTP_FILESYSTEMTYPE_FLAT) && + (fs_format != PTP_FILESYSTEMTYPE_HIERARCHICAL) && + (fs_format != PTP_FILESYSTEMTYPE_DCF)) { + ERR("File system type not supported"); + return PTP_RESPONSE_INVALIDPARAM; + } + + /* check cancel transaction */ + if (TRUE == _transport_get_cancel_initialization() || + TRUE == _transport_get_usb_discon_state()) { + ERR("USB is disconnected format operation is cancelled."); + return PTP_RESPONSE_GEN_ERROR; + } + + response = _entity_delete_obj_mtp_store(store, PTP_OBJECTHANDLE_ALL, + PTP_FORMATCODE_NOTUSED, TRUE); + + if (PTP_RESPONSE_OK != response) { + ERR("format is not completed [0x%X].\n", response); + return response; + } + + return PTP_RESPONSE_OK; +} + +void _entity_destroy_mtp_store(mtp_store_t *store) +{ + mtp_uint32 ii = 0; + slist_node_t *node = NULL; + slist_node_t *next_node = NULL; + + ret_if(store == NULL); + + for (ii = 0, next_node = store->obj_list.start; + ii < store->obj_list.nnodes; ii++) { + + node = next_node; + next_node = node->link; + _entity_dealloc_mtp_obj((mtp_obj_t *)node->value); + g_free(node); + } + + _util_init_list(&(store->obj_list)); + return; +} + +void _entity_store_recursive_enum_folder_objects(mtp_store_t *store, + mtp_obj_t *pobj) +{ + DIR *h_dir = 0; + mtp_char file_name[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_bool status = FALSE; + mtp_obj_t *obj = NULL; + dir_entry_t entry = { { 0 }, 0 }; + mtp_char *folder_name; + mtp_uint32 h_parent; + + ret_if(NULL == store); + + if (!pobj) { + folder_name = store->root_path; + h_parent = PTP_OBJECTHANDLE_ROOT; + } else { + folder_name = pobj->file_path; + h_parent = pobj->obj_handle; + } + + if (folder_name == NULL || folder_name[0] != '/') { + ERR("foldername has no root slash!!"); + return; + } + + if (FALSE == _util_ifind_first(folder_name, &h_dir, &entry)) { + DBG("No more files"); + return; + } + + do { + if (TRUE == _transport_get_usb_discon_state()) { + DBG("USB is disconnected"); + if (closedir(h_dir) < 0) { + ERR("Close directory Fail"); + } + return; + } + + _util_get_file_name(entry.filename, file_name); + if (0 == strlen(file_name)) { + ERR("szFilename size is 0"); + goto NEXT; + } + + if (file_name[0] == '.') { + DBG_SECURE("Hidden file [%s]\n", entry.filename); + } else if (entry.type == MTP_DIR_TYPE) { + obj = _entity_add_folder_to_store(store, h_parent, + entry.filename, file_name, &entry); + + if (NULL == obj) { + ERR("pObject is NULL"); + goto NEXT; + } + + _entity_store_recursive_enum_folder_objects(store, obj); + } else if (entry.type == MTP_FILE_TYPE) { + _entity_add_file_to_store(store, h_parent, + entry.filename, file_name, &entry); + } else { + DBG("UNKNOWN TYPE"); + } +NEXT: + status = (mtp_bool)_util_ifind_next(folder_name, h_dir, + &entry); + } while (status); + + if (closedir(h_dir) < 0) { + ERR("close directory fail"); + } +#ifdef MTP_SUPPORT_OBJECTADDDELETE_EVENT + _inoti_add_watch_for_fs_events(folder_name); +#endif /*MTP_SUPPORT_OBJECTADDDELETE_EVENT*/ + + return; +} + +void _entity_list_modified_files(mtp_uint32 minutes) +{ + if (minutes == 0) + return; + mtp_int32 ret; + mtp_char command[FIND_CMD_LEN] = { 0 }; + + if (TRUE == _device_is_store_mounted(MTP_STORAGE_INTERNAL)) { + g_snprintf(command, FIND_CMD_LEN, FIND_CMD, + MTP_STORE_PATH_CHAR, minutes, + MTP_FILES_MODIFIED_FILES); + DBG("find query is [%s]\n", command); + ret = system(command); + if (WIFSIGNALED(ret) && + (WTERMSIG(ret) == SIGINT || + WTERMSIG(ret) == SIGQUIT)) { + ERR("SYSTEM Fail"); + return; + } + } + if (TRUE == _device_is_store_mounted(MTP_STORAGE_EXTERNAL)) { + g_snprintf(command, FIND_CMD_LEN, FIND_CMD, + MTP_EXTERNAL_PATH_CHAR, minutes, + MTP_FILES_MODIFIED_FILES); + DBG("find query is [%s]\n", command); + ret = system(command); + if (WIFSIGNALED(ret) && + (WTERMSIG(ret) == SIGINT || + WTERMSIG(ret) == SIGQUIT)) { + ERR("SYSTEM Fail"); + return; + } + } + + return; +} + +void _entity_copy_store_data(mtp_store_t *dst, mtp_store_t *src) +{ + dst->store_id = src->store_id; + dst->root_path = src->root_path; + dst->is_hidden = src->is_hidden; + + memcpy(&(dst->obj_list), &(src->obj_list), sizeof(slist_t)); + _entity_update_store_info_run_time(&(dst->store_info), dst->root_path); + _prop_copy_ptpstring(&(dst->store_info.store_desc), &(src->store_info.store_desc)); + _prop_copy_ptpstring(&(dst->store_info.vol_label), &(src->store_info.vol_label)); + + return; +} diff --git a/src/mtp_cmd_handler.c b/src/mtp_cmd_handler.c new file mode 100755 index 0000000..48908fc --- /dev/null +++ b/src/mtp_cmd_handler.c @@ -0,0 +1,3387 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/vfs.h> +#include <linux/magic.h> +#include <sys/time.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <glib.h> +#include <glib/gprintf.h> +#include <vconf.h> +#include "mtp_support.h" +#include "ptp_datacodes.h" +#include "mtp_media_info.h" +#include "mtp_usb_driver.h" +#include "mtp_cmd_handler.h" +#include "mtp_cmd_handler_util.h" +#include "mtp_transport.h" +#include "mtp_thread.h" + +/* + * GLOBAL AND EXTERN VARIABLES + */ +extern mtp_mgr_t g_mtp_mgr; +extern mtp_bool g_is_full_enum; +extern pthread_mutex_t g_cmd_inoti_mutex; +extern mtp_config_t g_conf; + +mtp_bool g_is_sync_estab = FALSE; + +/* + * STATIC VARIABLES + */ +static mtp_mgr_t *g_mgr = &g_mtp_mgr; +static mtp_bool g_has_round_trip = FALSE; +#ifdef MTP_USE_SKIP_CONTINUOUS_OPENSESSION +static mtp_uint16 g_count_open_session = 0; +static mtp_uint32 g_old_open_session_time = 0; +#endif/*MTP_USE_SKIP_CONTINUOUS_OPENSESSION*/ + +/* + * STATIC FUNCTIONS + */ +static void __process_commands(mtp_handler_t *hdlr, cmd_blk_t *cmd); +static void __open_session(mtp_handler_t *hdlr); +static void __get_device_info(mtp_handler_t *hdlr); +static void __get_storage_ids(mtp_handler_t *hdlr); +static void __get_storage_info(mtp_handler_t *hdlr); +static void __get_num_objects(mtp_handler_t *hdlr); +static void __get_object_handles(mtp_handler_t *hdlr); +static void __get_object_info(mtp_handler_t *hdlr); +static void __get_object(mtp_handler_t *hdlr); +static void __send_object_info(mtp_handler_t *hdlr); +static void __send_object(mtp_handler_t *hdlr); +static void __delete_object(mtp_handler_t *hdlr); +static void __format_store(mtp_handler_t *hdlr); +static void __reset_device(mtp_handler_t *hdlr); +static void __get_device_prop_desc(mtp_handler_t *hdlr); +static void __get_device_prop_value(mtp_handler_t *hdlr); +static void __set_device_prop_value(mtp_handler_t *hdlr); +static void __get_partial_object(mtp_handler_t *hdlr); +static void __get_object_references(mtp_handler_t *hdlr); +static void __set_object_references(mtp_handler_t *hdlr); +static void __get_object_prop_desc(mtp_handler_t *hdlr); +static void __get_object_prop_supported(mtp_handler_t *hdlr); +static void __get_object_prop_value(mtp_handler_t *hdlr); +static void __set_object_prop_value(mtp_handler_t *hdlr); +static void __get_object_prop_list(mtp_handler_t *hdlr); +static void __set_object_prop_list(mtp_handler_t *hdlr); +static void __report_acquired_content(mtp_handler_t *hdlr); +static void __send_playback_skip(mtp_handler_t *hdlr); +#ifndef PMP_VER +static void __self_test(mtp_handler_t *hdlr); +#ifdef MTP_SUPPORT_SET_PROTECTION +static void __set_object_protection(mtp_handler_t *hdlr); +#endif /* MTP_SUPPORT_SET_PROTECTION */ +static void __power_down(mtp_handler_t *hdlr); +static void __move_object(mtp_handler_t *hdlr); +static void __copy_object(mtp_handler_t *hdlr); +static void __reset_device_prop_value(mtp_handler_t *hdlr); +static void __vendor_command1(mtp_handler_t *hdlr); +static void __get_interdep_prop_desc(mtp_handler_t *hdlr); +static void __send_object_prop_list(mtp_handler_t *hdlr); +#endif /* PMP_VER */ +static void __close_session(mtp_handler_t *hdlr); +#ifdef MTP_SUPPORT_PRINT_COMMAND +static void __print_command(mtp_uint16 code); +#endif /* MTP_SUPPORT_PRINT_COMMAND */ +static void __enum_store_not_enumerated(mtp_uint32 obj_handle, + mtp_uint32 fmt, mtp_uint32 depth); +static mtp_bool __receive_temp_file_first_packet(mtp_char *data, + mtp_int32 data_len); +static mtp_bool __receive_temp_file_next_packets(mtp_char *data, + mtp_int32 data_len); +static void __finish_receiving_file_packets(mtp_char *data, mtp_int32 data_len); + +/* + * FUNCTIONS + */ +void _cmd_hdlr_reset_cmd(mtp_handler_t *hdlr) +{ + if (hdlr->data4_send_obj.obj != NULL) { + _entity_dealloc_mtp_obj(hdlr->data4_send_obj.obj); + } + + memset(hdlr, 0x00, sizeof(mtp_handler_t)); + +#ifdef MTP_USE_SKIP_CONTINUOUS_OPENSESSION + /* reset open session count */ + g_count_open_session = 0; + g_old_open_session_time = 0; +#endif /* MTP_USE_SKIP_CONTINUOUS_OPENSESSION */ +} + +static void __process_commands(mtp_handler_t *hdlr, cmd_blk_t *cmd) +{ + mtp_store_t *store = NULL; + + /* Keep a local copy for this command */ + _hdlr_copy_cmd_container(cmd, &(hdlr->usb_cmd)); + + if (hdlr->usb_cmd.code == PTP_OPCODE_GETDEVICEINFO) { + DBG("COMMAND CODE = [0x%4x]!!\n", hdlr->usb_cmd.code); +#ifdef MTP_SUPPORT_PRINT_COMMAND + __print_command(hdlr->usb_cmd.code); +#endif /*MTP_SUPPORT_PRINT_COMMAND*/ + __get_device_info(hdlr); + goto DONE; + } + + /* Process OpenSession Command */ + if (hdlr->usb_cmd.code == PTP_OPCODE_OPENSESSION) { + DBG("COMMAND CODE = [0x%4X]!!\n", hdlr->usb_cmd.code); +#ifdef MTP_SUPPORT_PRINT_COMMAND + __print_command(hdlr->usb_cmd.code); +#endif /*MTP_SUPPORT_PRINT_COMMAND*/ +#ifdef MTP_USE_SKIP_CONTINUOUS_OPENSESSION + time_t t; + mtp_uint32 cur_time = 0; + time(&t); + cur_time = (mtp_uint32)t; + /*first opensession*/ + if (g_count_open_session == 0) { + g_old_open_session_time = cur_time; + } else if (cur_time <= g_old_open_session_time + 1) { + /*under 1 sec. it might be skipped*/ + ERR("skip continuous OPEN session"); + goto DONE; + } + ++g_count_open_session; + +#endif /* MTP_USE_SKIP_CONTINUOUS_OPENSESSION */ + __open_session(hdlr); + goto DONE; + } +#ifdef MTP_USE_SKIP_CONTINUOUS_OPENSESSION + g_count_open_session = 0; +#endif /* MTP_USE_SKIP_CONTINUOUS_OPENSESSION */ + + /* Check if session is open or not, if not respond */ + if (hdlr->session_id == 0) { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_SESSIONNOTOPEN); + _device_set_phase(DEVICE_PHASE_IDLE); + goto DONE; + } + DBG("COMMAND CODE = [0x%4x]!!\n", hdlr->usb_cmd.code); +#ifdef MTP_SUPPORT_PRINT_COMMAND + __print_command(hdlr->usb_cmd.code); +#endif /* MTP_SUPPORT_PRINT_COMMAND */ + + switch (hdlr->usb_cmd.code) { + case PTP_OPCODE_CLOSESESSION: + __close_session(hdlr); + break; + case PTP_OPCODE_GETSTORAGEIDS: + __get_storage_ids(hdlr); + break; + case PTP_OPCODE_GETSTORAGEINFO: + __get_storage_info(hdlr); + break; + case PTP_OPCODE_GETNUMOBJECTS: + __get_num_objects(hdlr); + break; + case PTP_OPCODE_GETOBJECTHANDLES: + __get_object_handles(hdlr); + break; + case PTP_OPCODE_GETOBJECTINFO: + __get_object_info(hdlr); + break; + case PTP_OPCODE_GETOBJECT: + _eh_send_event_req_to_eh_thread(EVENT_START_DATAIN, 0, 0, NULL); + __get_object(hdlr); + _eh_send_event_req_to_eh_thread(EVENT_DONE_DATAIN, 0, 0, NULL); + break; + case PTP_OPCODE_DELETEOBJECT: + __delete_object(hdlr); + break; + case PTP_OPCODE_FORMATSTORE: + __format_store(hdlr); + break; + case PTP_OPCODE_GETDEVICEPROPDESC: + __get_device_prop_desc(hdlr); + break; + case PTP_OPCODE_GETDEVICEPROPVALUE: + __get_device_prop_value(hdlr); + break; + case PTP_OPCODE_GETPARTIALOBJECT: + __get_partial_object(hdlr); + break; + case MTP_OPCODE_GETOBJECTREFERENCES: + __get_object_references(hdlr); + break; + case MTP_OPCODE_GETOBJECTPROPDESC: + __get_object_prop_desc(hdlr); + break; + case MTP_OPCODE_GETOBJECTPROPSUPPORTED: + __get_object_prop_supported(hdlr); + break; + case MTP_OPCODE_GETOBJECTPROPVALUE: + __get_object_prop_value(hdlr); + break; + case MTP_OPCODE_GETOBJECTPROPLIST: + __get_object_prop_list(hdlr); + break; +#ifndef PMP_VER + case PTP_OPCODE_RESETDEVICE: + __reset_device(hdlr); + break; + case PTP_OPCODE_SELFTEST: + __self_test(hdlr); + break; +#ifdef MTP_SUPPORT_SET_PROTECTION + case PTP_OPCODE_SETOBJECTPROTECTION: + __set_object_protection(hdlr); + break; +#endif /* MTP_SUPPORT_SET_PROTECTION */ + case PTP_OPCODE_POWERDOWN: + __power_down(hdlr); + break; + case PTP_OPCODE_RESETDEVICEPROPVALUE: + __reset_device_prop_value(hdlr); + break; + case PTP_OPCODE_MOVEOBJECT: + __move_object(hdlr); + break; + case PTP_OPCODE_COPYOBJECT: + __copy_object(hdlr); + break; + case MTP_OPCODE_GETINTERDEPPROPDESC: + __get_interdep_prop_desc(hdlr); + break; + case PTP_CODE_VENDOR_OP1: /* Vendor-specific operations */ + __vendor_command1(hdlr); + break; +#endif /* PMP_VER */ + case MTP_OPCODE_PLAYBACK_SKIP: /* Playback control */ + __send_playback_skip(hdlr); + break; + + case MTP_OPCODE_WMP_REPORTACQUIREDCONTENT: + /* Windows Media 11 extension*/ + __report_acquired_content(hdlr); + break; + case PTP_OPCODE_SENDOBJECTINFO: + case PTP_OPCODE_SENDOBJECT: + case PTP_OPCODE_SETDEVICEPROPVALUE: + case MTP_OPCODE_SETOBJECTREFERENCES: + case MTP_OPCODE_SETOBJECTPROPVALUE: + case MTP_OPCODE_SETOBJECTPROPLIST: +#ifndef PMP_VER + case MTP_OPCODE_SENDOBJECTPROPLIST: +#endif /* PMP_VER */ + /* DATA_HANDLE_PHASE: Send operation will be blocked + * until data packet is received + */ + if (_device_get_phase() == DEVICE_PHASE_IDLE) { + DBG("DATAOUT COMMAND PHASE!!"); + if (hdlr->usb_cmd.code == PTP_OPCODE_SENDOBJECT) + _eh_send_event_req_to_eh_thread(EVENT_START_DATAOUT, + 0, 0, NULL); + _device_set_phase(DEVICE_PHASE_DATAOUT); + return; /* in command phase, just return and wait next data */ + } + switch (hdlr->usb_cmd.code) { + case PTP_OPCODE_SENDOBJECTINFO: + __send_object_info(hdlr); + break; + case PTP_OPCODE_SENDOBJECT: + __send_object(hdlr); + _eh_send_event_req_to_eh_thread(EVENT_DONE_DATAOUT, + 0, 0, NULL); + break; + case PTP_OPCODE_SETDEVICEPROPVALUE: + __set_device_prop_value(hdlr); + break; + case MTP_OPCODE_SETOBJECTREFERENCES: + __set_object_references(hdlr); + break; + case MTP_OPCODE_SETOBJECTPROPVALUE: + __set_object_prop_value(hdlr); + break; + case MTP_OPCODE_SETOBJECTPROPLIST: + __set_object_prop_list(hdlr); + break; +#ifndef PMP_VER + case MTP_OPCODE_SENDOBJECTPROPLIST: + __send_object_prop_list(hdlr); + break; +#endif /* PMP_VER */ + } + break; + + default: + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_OP_NOT_SUPPORTED); + DBG("Unsupported COMMAND[%d]\n", hdlr->usb_cmd.code); + break; + } +DONE: + if (((hdlr->last_opcode == PTP_OPCODE_SENDOBJECTINFO) || + (hdlr->last_opcode == MTP_OPCODE_SENDOBJECTPROPLIST)) && + ((hdlr->last_fmt_code != PTP_FMT_ASSOCIATION) && + (hdlr->last_fmt_code != PTP_FMT_UNDEF))) { + DBG("Processed, last_opcode[0x%x], last_fmt_code[%d]\n", + hdlr->last_opcode, hdlr->last_fmt_code); + + if ((hdlr->usb_cmd.code != PTP_OPCODE_SENDOBJECT) && + hdlr->data4_send_obj.is_valid && + hdlr->data4_send_obj.is_data_sent) { + + DBG("Processed, COMMAND[0x%x]!!\n", hdlr->usb_cmd.code); + store = _device_get_store(hdlr->data4_send_obj.store_id); + if (store != NULL) { + /*Restore reserved space*/ + store->store_info.free_space += + hdlr->data4_send_obj.file_size; + } + + if (hdlr->data4_send_obj.obj) { + _entity_dealloc_mtp_obj(hdlr->data4_send_obj.obj); + hdlr->data4_send_obj.obj = NULL; + } + memset(&(hdlr->data4_send_obj), 0x00, + sizeof(hdlr->data4_send_obj)); + } + } + hdlr->last_opcode = hdlr->usb_cmd.code; /* Last operation code*/ +} + +static void __open_session(mtp_handler_t *hdlr) +{ + mtp_uint32 session_id; + /*Check the parameters*/ + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + /*Unknown parameters*/ + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + /* Validate parameters*/ + session_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + + if (session_id == 0 || (hdlr->usb_cmd.tid != 0)) { + /*Session Id cannot be zero, while TransactionId must be zero.*/ + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_INVALIDPARAM); + return; + } + + if (hdlr->session_id) { /*Session already open*/ + _cmd_hdlr_send_response(hdlr, + PTP_RESPONSE_SESSIONALREADYOPENED, 1, + (mtp_uint32 *)&(hdlr->session_id)); + } else { /*Save the Session ID*/ + hdlr->session_id = session_id; + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + } +} + +static void __get_device_info(mtp_handler_t *hdlr) +{ + /* Check the parameters*/ + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + /* Unknown parameters*/ + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + /* When used outside a session, both the SessionID and TransactionID + * in the Operation Request dataset must be 0; + */ + + if ((hdlr->session_id == 0) && + (hdlr->usb_cmd.tid != 0)) { /*INVALIDPARAMETER*/ + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + ERR("Invalid Session ID[%u], Transaction ID[%u]\n", + hdlr->session_id, hdlr->usb_cmd.tid); + return; + } + + /*Build the data block for device info.*/ + data_blk_t blk = { 0 }; + mtp_uint32 num_bytes = 0; + mtp_uchar *buf_ptr = NULL; + + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + num_bytes = _get_device_info_size(); + buf_ptr = _hdlr_alloc_buf_data_container(&blk, num_bytes, num_bytes); + if (num_bytes == _pack_device_info(buf_ptr, num_bytes)) { + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + } else { + /* Host Cancelled data-in transfer */ + _device_set_phase(DEVICE_PHASE_NOTREADY); + DBG("Device phase is set to DEVICE_PHASE_NOTREADY"); + } + } else { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + } + + g_free(blk.data); +} + +static void __get_storage_ids(mtp_handler_t *hdlr) +{ + data_blk_t blk = { 0 }; + ptp_array_t ids = { 0 }; + mtp_uint32 resp = PTP_RESPONSE_GEN_ERROR; + mtp_uint32 num_bytes = 0; + mtp_uchar *ptr = NULL; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + _prop_init_ptparray(&ids, UINT32_TYPE); + + if (_hutil_get_storage_ids(&ids) == MTP_ERROR_NONE) + { + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, + hdlr->usb_cmd.tid); + num_bytes = _prop_get_size_ptparray(&ids); + ptr = _hdlr_alloc_buf_data_container(&blk, num_bytes, num_bytes); + if (NULL != ptr) { + /*Pack storage IDs*/ + _prop_pack_ptparray(&ids, ptr, num_bytes); + _device_set_phase(DEVICE_PHASE_DATAIN); + /*Send the data block*/ + if (FALSE == _hdlr_send_data_container(&blk)) { + /*Host Cancelled data-in transfer*/ + _device_set_phase(DEVICE_PHASE_NOTREADY); + DBG("DEVICE_PHASE_NOTREADY!!"); + } else { + resp = PTP_RESPONSE_OK; + } + } + g_free(blk.data); + } + _prop_deinit_ptparray(&ids); + _cmd_hdlr_send_response_code(hdlr, (mtp_uint16) resp); +} + +static void __get_storage_info(mtp_handler_t *hdlr) +{ + mtp_uint32 store_id = 0; + store_info_t store_info = { 0 }; + mtp_uint32 pkt_sz = 0; + data_blk_t blk = { 0 }; + mtp_uchar *ptr = NULL; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + /*Unknown parameters*/ + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + store_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + + if (_hutil_get_storage_entry(store_id, &store_info) != MTP_ERROR_NONE) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_INVALID_STORE_ID); + return; + } + + /* Build the data block for StorageInfo Dataset.*/ + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + pkt_sz = _hutil_get_storage_info_size(&store_info); + ptr = _hdlr_alloc_buf_data_container(&blk, pkt_sz, pkt_sz); + + if (pkt_sz == _entity_pack_store_info(&store_info, ptr, pkt_sz)) { + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + } else { + /*Host Cancelled data-in transfer*/ + _device_set_phase(DEVICE_PHASE_NOTREADY); + DBG("DEVICE_PHASE_NOTREADY!!"); + } + } else { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + } + + g_free(blk.data); +} + +static void __get_num_objects(mtp_handler_t *hdlr) +{ + mtp_uint16 resp = 0; + mtp_uint32 store_id = 0; + mtp_uint32 h_parent = 0; + mtp_uint32 fmt = 0; + mtp_uint32 num_obj = 0; + + store_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + fmt = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + h_parent = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2); + + switch (_hutil_get_num_objects(store_id, h_parent, fmt, + (mtp_uint32 *)(&num_obj))) { + case MTP_ERROR_INVALID_STORE: + resp = PTP_RESPONSE_INVALID_STORE_ID; + break; + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + break; + case MTP_ERROR_INVALID_PARENT: + resp = PTP_RESPONSE_INVALIDPARENT; + break; + case MTP_ERROR_STORE_NOT_AVAILABLE: + resp = PTP_RESPONSE_STORENOTAVAILABLE; + break; + case MTP_ERROR_NONE: + resp = PTP_RESPONSE_OK; + break; + default: + resp = PTP_RESPONSE_GEN_ERROR; + } + + if (resp == PTP_RESPONSE_OK) { + _cmd_hdlr_send_response(hdlr, resp, 1, (mtp_uint32 *)&num_obj); + } else { + _cmd_hdlr_send_response_code(hdlr, resp); + } +} + +static void __get_object_handles(mtp_handler_t *hdlr) +{ + mtp_uint32 store_id = 0; + mtp_uint32 fmt = 0; + mtp_uint32 h_parent = 0; + ptp_array_t handle_arr = { 0 }; + data_blk_t blk = { 0 }; + mtp_uint32 num_bytes = 0; + mtp_uchar *ptr = NULL; + mtp_uint16 resp = 0; + + _prop_init_ptparray(&handle_arr, UINT32_TYPE); + + store_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + fmt = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + h_parent = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2); + + DBG("store_id = [0x%x], Format Code = [0x%x], parent handle = [0x%x]\n", + store_id, fmt, h_parent); + switch (_hutil_get_object_handles(store_id, fmt, h_parent, + &handle_arr)) { + case MTP_ERROR_INVALID_STORE: + resp = PTP_RESPONSE_INVALID_STORE_ID; + break; + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + break; + case MTP_ERROR_INVALID_PARENT: + resp = PTP_RESPONSE_INVALIDPARENT; + break; + case MTP_ERROR_STORE_NOT_AVAILABLE: + resp = PTP_RESPONSE_STORENOTAVAILABLE; + break; + case MTP_ERROR_NONE: + resp = PTP_RESPONSE_OK; + break; + default: + resp = PTP_RESPONSE_GEN_ERROR; + } + + if (resp != PTP_RESPONSE_OK) { + _prop_deinit_ptparray(&handle_arr); + _cmd_hdlr_send_response_code(hdlr, resp); + return; + } + + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + num_bytes = _prop_get_size_ptparray(&handle_arr); + ptr = _hdlr_alloc_buf_data_container(&blk, num_bytes, num_bytes); + if (NULL != ptr) { + _prop_pack_ptparray(&handle_arr, ptr, num_bytes); + _prop_deinit_ptparray(&handle_arr); + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + } else { + /*Host Cancelled data-in transfer.*/ + _device_set_phase(DEVICE_PHASE_NOTREADY); + DBG("DEVICE_PHASE_NOTREADY!!"); + } + } else { + _prop_deinit_ptparray(&handle_arr); + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + } + + g_free(blk.data); +} + +static void __get_object_info(mtp_handler_t *hdlr) +{ + mtp_uint32 obj_handle = 0; + data_blk_t blk = { 0 }; + mtp_uint32 num_bytes = 0; + mtp_uchar *ptr = NULL; + mtp_obj_t *obj = NULL; + mtp_char f_name[MTP_MAX_FILENAME_SIZE + 1] = { 0 }; + mtp_wchar wf_name[MTP_MAX_FILENAME_SIZE + 1] = { 0 }; + ptp_string_t ptp_string = { 0 }; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + obj_handle = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + if (MTP_ERROR_NONE != _hutil_get_object_entry(obj_handle, &obj)) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_INVALID_OBJ_HANDLE); + return; + } + + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + + _util_get_file_name(obj->file_path, f_name); + _util_utf8_to_utf16(wf_name, sizeof(wf_name) / WCHAR_SIZ, f_name); + _prop_copy_char_to_ptpstring(&ptp_string, wf_name, WCHAR_TYPE); + + num_bytes = _entity_get_object_info_size(obj, &ptp_string); + ptr = _hdlr_alloc_buf_data_container(&blk, num_bytes, num_bytes); + if (num_bytes == _entity_pack_obj_info(obj, &ptp_string, ptr, + num_bytes)) { + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + } else { + /* Host Cancelled data-in transfer*/ + _device_set_phase(DEVICE_PHASE_NOTREADY); + DBG("DEVICE_PHASE_NOTREADY!!"); + } + } else { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + } + + g_free(blk.data); +} + +static void __get_object(mtp_handler_t *hdlr) +{ + mtp_uint32 obj_handle; + mtp_obj_t *obj; + mtp_uchar *ptr; + data_blk_t blk; + mtp_char *path; + mtp_uint64 num_bytes; + mtp_uint64 total_len; + mtp_uint64 sent = 0; + mtp_uint16 resp = PTP_RESPONSE_OK; + mtp_uint32 packet_len; + mtp_uint32 read_len = 0; + mtp_uint32 h_file = INVALID_FILE; + mtp_int32 error = 0; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + obj_handle = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + obj = _device_get_object_with_handle(obj_handle); + if (obj == NULL) { + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + _cmd_hdlr_send_response_code(hdlr, resp); + return; + } + +#ifdef MTP_SUPPORT_SET_PROTECTION + /* Check to see if the data is non-transferable */ + if (obj->obj_info->protcn_status == + MTP_PROTECTIONSTATUS_NONTRANSFERABLE_DATA) { + resp = PTP_RESPONSE_ACCESSDENIED; + _cmd_hdlr_send_response_code(hdlr, resp); + return; + } +#endif /* MTP_SUPPORT_SET_PROTECTION */ + + path = obj->file_path; + num_bytes = obj->obj_info->file_size; + total_len = num_bytes + sizeof(header_container_t); + packet_len = total_len < g_conf.read_file_size ? num_bytes : + (g_conf.read_file_size - sizeof(header_container_t)); + + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + ptr = _hdlr_alloc_buf_data_container(&blk, packet_len, num_bytes); + if (NULL == ptr) { + ERR("_hdlr_alloc_buf_data_container() Fail"); + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + return; + } + + _device_set_phase(DEVICE_PHASE_DATAIN); + h_file = _util_file_open(path, MTP_FILE_READ, &error); + if (h_file == INVALID_FILE) { + ERR("_util_file_open() Fail"); + _device_set_phase(DEVICE_PHASE_NOTREADY); + if (EACCES == error) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_ACCESSDENIED); + return; + } + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + return; + } + + _util_file_read(h_file, ptr, packet_len, &read_len); + if (0 == read_len) { + ERR("_util_file_read() Fail"); + ERR_SECURE("filename[%s]", path); + _device_set_phase(DEVICE_PHASE_NOTREADY); + resp = PTP_RESPONSE_INCOMPLETETRANSFER; + goto Done; + } + + /* First Packet with Header */ + if (PTP_EVENTCODE_CANCELTRANSACTION == _transport_get_control_event() || + FALSE == _hdlr_send_bulk_data(blk.data, blk.len)) { + _device_set_phase(DEVICE_PHASE_NOTREADY); + resp = PTP_RESPONSE_INCOMPLETETRANSFER; + ERR("First Packet send Fail"); + ERR_SECURE("filename[%s]\n", path); + goto Done; + } + + sent = sizeof(header_container_t) + read_len; + ptr = blk.data; + + while (sent < total_len) { + _util_file_read(h_file, ptr, g_conf.read_file_size, &read_len); + if (0 == read_len) { + ERR("_util_file_read() Fail"); + ERR_SECURE("filename[%s]\n", path); + _device_set_phase(DEVICE_PHASE_NOTREADY); + resp = PTP_RESPONSE_INCOMPLETETRANSFER; + goto Done; + } + + if (PTP_EVENTCODE_CANCELTRANSACTION == _transport_get_control_event() || + FALSE == _hdlr_send_bulk_data(ptr, read_len)) { + _device_set_phase(DEVICE_PHASE_NOTREADY); + resp = PTP_RESPONSE_INCOMPLETETRANSFER; + ERR("Packet send Fail"); + ERR_SECURE("filename[%s]\n", path); + goto Done; + } + + sent += read_len; + } + + if (total_len % ((mtp_uint64)_transport_get_usb_packet_len()) == 0) { + _transport_send_zlp(); + } + +Done: + _util_file_close(h_file); + + g_free(blk.data); + _cmd_hdlr_send_response_code(hdlr, resp); +} + +static void __send_object_info(mtp_handler_t *hdlr) +{ + mtp_uint16 resp = PTP_RESPONSE_UNDEFINED; + mtp_uint32 store_id = 0; + mtp_uint32 h_parent = 0; + mtp_uint32 num_bytes = 0; + data_blk_t blk = { 0 }; + mtp_uint32 resp_param[3] = { 0 }; + mtp_obj_t *obj = NULL; + mtp_err_t ret = 0; + obj_data_t obdata = { 0 }; + + store_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + if (store_id == 0) { + store_id = _device_get_default_store_id(); + } + h_parent = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + resp = PTP_RESPONSE_PARAM_NOTSUPPORTED; + if (_device_get_phase() != DEVICE_PHASE_NOTREADY) { + _cmd_hdlr_send_response_code(hdlr, resp); + } + return; + } + + _device_set_phase(DEVICE_PHASE_DATAOUT); + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + num_bytes = MAX_SIZE_IN_BYTES_OF_OBJECT_INFO; + if (_hdlr_rcv_data_container(&blk, num_bytes) == FALSE) { + _device_set_phase(DEVICE_PHASE_NOTREADY); + } else { + if (TRUE == hdlr->data4_send_obj.is_valid) { + obdata.store_id = hdlr->data4_send_obj.store_id; + obdata.obj_size = hdlr->data4_send_obj.file_size; + obdata.obj = hdlr->data4_send_obj.obj; + hdlr->data4_send_obj.obj = NULL; + } + ret = _hutil_construct_object_entry(store_id, h_parent, + ((hdlr->data4_send_obj.is_valid == TRUE) ? (&obdata) + : (NULL)), &obj, _hdlr_get_payload_data(&blk), + _hdlr_get_payload_size(&blk)); + hdlr->data4_send_obj.is_valid = FALSE; + switch (ret) { + case MTP_ERROR_NONE: + if (obj->obj_info->obj_fmt == PTP_FMT_ASSOCIATION) { + hdlr->data4_send_obj.obj = NULL; + hdlr->data4_send_obj.is_valid = FALSE; + hdlr->data4_send_obj.obj_handle = obj->obj_handle; + hdlr->data4_send_obj.h_parent = h_parent; + hdlr->data4_send_obj.store_id = store_id; + } +#ifdef MTP_USE_SELFMAKE_ABSTRACTION + else if (obj->obj_info->file_size == 0 && + obj->obj_info->obj_fmt > MTP_FMT_UNDEFINED_COLLECTION && + obj->obj_info->obj_fmt < MTP_FMT_UNDEFINED_DOC) { + hdlr->data4_send_obj.obj = NULL; + hdlr->data4_send_obj.is_valid = FALSE; + hdlr->data4_send_obj.obj_handle = obj->obj_handle; + hdlr->data4_send_obj.h_parent = h_parent; + hdlr->data4_send_obj.store_id = store_id; + } +#endif /*MTP_USE_SELFMAKE_ABSTRACTION*/ + else { + hdlr->data4_send_obj.is_valid = TRUE; + hdlr->data4_send_obj.obj_handle = obj->obj_handle; + hdlr->data4_send_obj.h_parent = h_parent; + hdlr->data4_send_obj.store_id = store_id; + hdlr->data4_send_obj.obj = obj; + hdlr->data4_send_obj.file_size = + obj->obj_info->file_size; + } + resp = PTP_RESPONSE_OK; + break; + case MTP_ERROR_STORE_NOT_AVAILABLE: + resp = PTP_RESPONSE_STORENOTAVAILABLE; + DBG("PTP_RESPONSE_STORENOTAVAILABLE"); + break; + case MTP_ERROR_INVALID_PARAM: + resp = PTP_RESPONSE_PARAM_NOTSUPPORTED; + DBG("PTP_RESPONSE_PARAM_NOTSUPPORTED"); + break; + case MTP_ERROR_INVALID_STORE: + resp = PTP_RESPONSE_INVALID_STORE_ID; + DBG("PTP_RESPONSE_INVALID_STORE_ID"); + break; + case MTP_ERROR_STORE_READ_ONLY: + resp = PTP_RESPONSE_STORE_READONLY; + break; + case MTP_ERROR_STORE_FULL: + resp = PTP_RESPONSE_STOREFULL; + DBG("PTP_RESPONSE_STOREFULL"); + break; + case MTP_ERROR_GENERAL: + resp = PTP_RESPONSE_GEN_ERROR; + DBG("PTP_RESPONSE_GEN_ERROR"); + break; + case MTP_ERROR_INVALID_OBJECT_INFO: + resp = MTP_RESPONSECODE_INVALIDDATASET; + DBG("MTP_RESPONSECODE_INVALIDDATASET"); + break; + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + DBG("PTP_RESPONSE_INVALID_OBJ_HANDLE"); + break; + case MTP_ERROR_INVALID_PARENT: + resp = PTP_RESPONSE_INVALIDPARENT; + DBG("PTP_RESPONSE_INVALIDPARENT"); + break; + case MTP_ERROR_ACCESS_DENIED: + resp = PTP_RESPONSE_ACCESSDENIED; + DBG("PTP_RESPONSE_ACCESSDENIED"); + break; + default: + resp = PTP_RESPONSE_GEN_ERROR; + DBG("PTP_RESPONSE_GEN_ERROR"); + break; + } + } + + g_free(blk.data); + if (_device_get_phase() != DEVICE_PHASE_NOTREADY) { + if (resp == PTP_RESPONSE_OK) { + hdlr->last_fmt_code = obj->obj_info->obj_fmt; + resp_param[0] = hdlr->data4_send_obj.store_id; + + /* PTP spec here requires that 0xFFFFFFFF be sent if root is the parent object, + * while in some situations(e.g. MoveObject, CopyObject), 0x00000000 (as + * PTP_OBJECTHANDLE_ROOT is defined) represents the root. + */ + resp_param[1] = (hdlr->data4_send_obj.h_parent + != PTP_OBJECTHANDLE_ROOT) ? + hdlr->data4_send_obj.h_parent : + 0xFFFFFFFF; + resp_param[2] = hdlr->data4_send_obj.obj_handle; + _cmd_hdlr_send_response(hdlr, resp, 3, resp_param); + } else { + _cmd_hdlr_send_response_code(hdlr, resp); + } + } +} + +static void __send_object(mtp_handler_t *hdlr) +{ + data_blk_t blk = { 0 }; + mtp_uint16 resp = PTP_RESPONSE_OK; + mtp_char temp_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + + ERR("unsupported parameter"); + _device_set_phase(DEVICE_PHASE_NOTREADY); + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_INVALIDPARAM); + return; + } +#ifndef MTP_USE_SELFMAKE_ABSTRACTION + if (hdlr->data4_send_obj.is_valid != TRUE) { + DBG("invalide object info"); + _device_set_phase(DEVICE_PHASE_NOTREADY); + return; + } +#endif /*MTP_USE_SELFMAKE_ABSTRACTION*/ + + _device_set_phase(DEVICE_PHASE_DATAOUT); + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + + if (_hdlr_rcv_file_in_data_container(&blk, temp_fpath, + MTP_MAX_PATHNAME_SIZE + 1) == FALSE) { + _device_set_phase(DEVICE_PHASE_IDLE); + + ERR("_hdlr_rcv_file_in_data_container() Fail"); + g_free(blk.data); + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + return; + } + + switch (_hutil_write_file_data(hdlr->data4_send_obj.store_id, + hdlr->data4_send_obj.obj, temp_fpath)) { + + case MTP_ERROR_INVALID_OBJECT_INFO: + resp = PTP_RESPONSE_NOVALID_OBJINFO; + DBG("PTP_RESPONSE_NOVALID_OBJINFO"); + break; +#ifdef MTP_USE_SELFMAKE_ABSTRACTION + case MTP_ERROR_INVALID_PARAM: /* association file*/ +#endif /*MTP_USE_SELFMAKE_ABSTRACTION*/ + case MTP_ERROR_NONE: + resp = PTP_RESPONSE_OK; + DBG("PTP_RESPONSE_OK"); + break; + case MTP_ERROR_STORE_FULL: + resp = PTP_RESPONSE_STOREFULL; + DBG("PTP_RESPONSE_STOREFULL"); + break; + default: + resp = PTP_RESPONSE_GEN_ERROR; + DBG("PTP_RESPONSE_GEN_ERROR"); + } + _cmd_hdlr_send_response_code(hdlr, resp); + + /* This object info has been consumed.*/ + hdlr->data4_send_obj.obj = NULL; + hdlr->data4_send_obj.is_valid = FALSE; + + g_free(blk.data); +} + +static void __delete_object(mtp_handler_t *hdlr) +{ + mtp_uint32 obj_handle = 0; + mtp_uint32 fmt = 0; + mtp_uint16 resp = 0; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + + ERR("Parameters not supported"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + obj_handle = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + fmt = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + if ((PTP_FORMATCODE_NOTUSED != fmt) && + (obj_handle != PTP_OBJECTHANDLE_ALL)) { + ERR("Invalid object format"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_INVALID_OBJ_FMTCODE); + return; + } + + _transport_set_mtp_operation_state(MTP_STATE_DATA_PROCESSING); + + switch (_hutil_remove_object_entry(obj_handle, fmt)) { + case MTP_ERROR_NONE: + resp = PTP_RESPONSE_OK; + break; + case MTP_ERROR_STORE_READ_ONLY: + resp = PTP_RESPONSE_STORE_READONLY; + break; + case MTP_ERROR_PARTIAL_DELETION: + resp = PTP_RESPONSE_PARTIAL_DELETION; + break; + case MTP_ERROR_OBJECT_WRITE_PROTECTED: + resp = PTP_RESPONSE_OBJ_WRITEPROTECTED; + break; + case MTP_ERROR_ACCESS_DENIED: + resp = PTP_RESPONSE_ACCESSDENIED; + break; + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + break; + default: + resp = PTP_RESPONSE_GEN_ERROR; + } + + _transport_set_mtp_operation_state(MTP_STATE_ONSERVICE); + _cmd_hdlr_send_response_code(hdlr, resp); +} + +static void __format_store(mtp_handler_t *hdlr) +{ + mtp_uint32 store_id = 0; + mtp_uint32 fs_fmt = 0; + mtp_uint16 ret = 0; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + store_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + fs_fmt = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + + ret = _hutil_format_storage(store_id, fs_fmt); + + /* although there is remain file, send OK */ + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); +} + +static void __reset_device(mtp_handler_t *hdlr) +{ + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); +} + +static void __get_device_prop_desc(mtp_handler_t *hdlr) +{ + device_prop_desc_t dev_prop = { { 0 }, }; + device_prop_desc_t *prop_ptr = NULL; + ptp_string_t ptp_str = { 0, { 0 } }; + data_blk_t blk = { 0 }; + mtp_uint32 prop_id = 0; + mtp_uint32 resp = 0; + mtp_uint32 num_bytes = 0; + mtp_uchar *ptr = NULL; + mtp_wchar temp[MTP_MAX_REG_STRING + 1] = { 0 }; + + prop_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + switch (prop_id) { +#ifdef MTP_SUPPORT_DEVICEPROP_BATTERYLEVEL + case PTP_PROPERTYCODE_BATTERYLEVEL: + { + mtp_int32 batt = 0; + + prop_ptr = _device_get_device_property(prop_id); + if (NULL == prop_ptr) { + ERR("prop_ptr is NULL!"); + break; + } + + batt = _util_get_battery_level(); + if (FALSE == _prop_set_current_integer(prop_ptr, batt)) + ERR("_util_get_battery_level() Fail"); + break; + } +#endif /* MTP_SUPPORT_DEVICEPROP_BATTERYLEVEL */ + + case MTP_PROPERTYCODE_DEVICEFRIENDLYNAME: + { + mtp_char *dev_name = _device_get_device_name(); + if (dev_name == NULL) { + ERR("_device_get_device_name() Fail"); + break; + } + + prop_ptr = _device_get_device_property(prop_id); + if (NULL == prop_ptr) { + ERR("prop_ptr is Null"); + g_free(dev_name); + break; + } + _util_utf8_to_utf16(temp, sizeof(temp) / WCHAR_SIZ, dev_name); + _prop_copy_char_to_ptpstring(&ptp_str, temp, WCHAR_TYPE); + _prop_set_current_string(prop_ptr, &ptp_str); + g_free(dev_name); + break; + } + + case MTP_PROPERTYCODE_SYNCHRONIZATIONPARTNER: + { + mtp_char *sync_ptr = _device_get_sync_partner(); + if (NULL == sync_ptr) { + ERR("_device_get_sync_partner() Fail"); + break; + } + prop_ptr = _device_get_device_property(prop_id); + if (NULL == prop_ptr) { + ERR("prop_ptr is Null"); + g_free(sync_ptr); + break; + } + + _util_utf8_to_utf16(temp, sizeof(temp) / WCHAR_SIZ, sync_ptr); + _prop_copy_char_to_ptpstring(&ptp_str, temp, WCHAR_TYPE); + _prop_set_current_string(prop_ptr, &ptp_str); + g_free(sync_ptr); + break; + } + case MTP_PROPERTYCODE_DEVICEICON: + { + mtp_uint32 h_file; + mtp_uint32 bytes_read = 0; + mtp_uint32 file_size = 0; + struct stat buf; + mtp_uchar *data = NULL; + mtp_int32 err = 0; + + prop_ptr = _device_get_device_property(prop_id); + if (NULL == prop_ptr) { + ERR("prop_ptr is Null"); + break; + } + + h_file = _util_file_open(MTP_DEVICE_ICON, MTP_FILE_READ, &err); + if (h_file == INVALID_FILE) { + ERR("file handle is not valid"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + if (fstat(fileno((FILE *)h_file), &buf) != 0) { + _util_file_close(h_file); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + file_size = buf.st_size; + data = (mtp_uchar *)g_malloc(file_size + sizeof(mtp_uint32)); + if (data == NULL) { + ERR("g_malloc() Fail"); + _util_file_close(h_file); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + memcpy(data, &file_size, sizeof(mtp_uint32)); + _util_file_read(h_file, &data[sizeof(mtp_uint32)], file_size, + &bytes_read); + if (bytes_read != file_size) { + ERR("Number of read bytes less than requested"); + _util_file_close(h_file); + g_free(data); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + + _prop_set_current_array(prop_ptr, data); + _prop_set_default_array(&(prop_ptr->propinfo), + (mtp_uchar *)&data[sizeof(mtp_uint32)], bytes_read); + g_free(data); + _util_file_close(h_file); + break; + } + + default: + ERR("Unknown PropId : [0x%x]\n", prop_id); + break; + } + + if (_hutil_get_device_property(prop_id, &dev_prop) != MTP_ERROR_NONE) { + ERR("_hutil_get_device_property returned error"); + resp = PTP_RESPONSE_PROP_NOTSUPPORTED; + _cmd_hdlr_send_response_code(hdlr, resp); + return; + } + num_bytes = _prop_size_device_prop_desc(&dev_prop); + + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + ptr = _hdlr_alloc_buf_data_container(&blk, num_bytes, num_bytes); + if (ptr == NULL) { + resp = PTP_RESPONSE_GEN_ERROR; + _cmd_hdlr_send_response_code(hdlr, resp); + return; + } + + if (_prop_pack_device_prop_desc(&dev_prop, ptr, num_bytes) != num_bytes) { + resp = PTP_RESPONSE_GEN_ERROR; + _cmd_hdlr_send_response_code(hdlr, resp); + g_free(blk.data); + return; + } + + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + else { + _device_set_phase(DEVICE_PHASE_NOTREADY); + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + } + + g_free(blk.data); + return; +} + +static void __get_device_prop_value(mtp_handler_t *hdlr) +{ + + ptp_string_t ptp_str = { 0, { 0 } }; + data_blk_t blk = { 0 }; + mtp_uint32 prop_id = 0; + mtp_uint32 no_bytes = 0; + mtp_uchar *ptr = NULL; + mtp_wchar temp[MTP_MAX_REG_STRING + 1] = { 0 }; + + prop_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + + switch(prop_id) { +#ifdef MTP_SUPPORT_DEVICEPROP_BATTERYLEVEL + case PTP_PROPERTYCODE_BATTERYLEVEL: { + mtp_int32 batt = 0; + + batt = _util_get_battery_level(); + no_bytes = sizeof(batt); + + ptr = _hdlr_alloc_buf_data_container(&blk, no_bytes, no_bytes); + if (ptr == NULL) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + memcpy(ptr, &batt, no_bytes); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(ptr, no_bytes); +#endif /*__BIG_ENDIAN__*/ + break; + } +#endif /* MTP_SUPPORT_DEVICEPROP_BATTERYLEVEL */ + + case MTP_PROPERTYCODE_DEVICEFRIENDLYNAME: + { + + mtp_char *device = _device_get_device_name(); + if (device == NULL) { + ERR("_device_get_device_name() Fail"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + + _util_utf8_to_utf16(temp, sizeof(temp) / WCHAR_SIZ, device); + _prop_copy_char_to_ptpstring(&ptp_str, temp, WCHAR_TYPE); + no_bytes = _prop_size_ptpstring(&ptp_str); + g_free(device); + + ptr = _hdlr_alloc_buf_data_container(&blk, no_bytes, no_bytes); + if (ptr == NULL) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + + if (_prop_pack_ptpstring(&ptp_str, ptr, no_bytes) != no_bytes) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + g_free(blk.data); + return; + } + break; + } + + case MTP_PROPERTYCODE_SYNCHRONIZATIONPARTNER: + { + + mtp_char *sync_ptr = _device_get_sync_partner(); + if (sync_ptr == NULL) { + ERR("_device_get_sync_partner() Fail"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + _util_utf8_to_utf16(temp, sizeof(temp) / WCHAR_SIZ, sync_ptr); + g_free(sync_ptr); + + _prop_copy_char_to_ptpstring(&ptp_str, temp, WCHAR_TYPE); + no_bytes = _prop_size_ptpstring(&ptp_str); + + ptr = _hdlr_alloc_buf_data_container(&blk, no_bytes, no_bytes); + if (ptr == NULL) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + + if (_prop_pack_ptpstring(&ptp_str, ptr, no_bytes) != no_bytes) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + g_free(blk.data); + return; + } + break; + } + + case MTP_PROPERTYCODE_DEVICEICON: + { + + mtp_uint32 h_file; + mtp_uint32 read_bytes = 0; + mtp_uint32 file_size = 0; + struct stat buf; + mtp_uchar *data = NULL; + mtp_int32 err = 0; + ptp_array_t val_arr = { 0 }; + mtp_uint32 ii; + + h_file = _util_file_open(MTP_DEVICE_ICON, MTP_FILE_READ, &err); + if (h_file == INVALID_FILE) { + ERR("file handle is not valid"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + if (fstat(fileno((FILE *)h_file), &buf) != 0) { + _util_file_close(h_file); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + + file_size = buf.st_size; + data = (mtp_uchar *)g_malloc(file_size); + if (data == NULL) { + ERR("g_malloc() Fail"); + _util_file_close(h_file); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + + _util_file_read(h_file, &data, file_size, &read_bytes); + if (read_bytes != file_size) { + ERR("Number of read bytes less than requested"); + _util_file_close(h_file); + g_free(data); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + return; + } + + _prop_init_ptparray(&val_arr, UINT8_TYPE); + _prop_grow_ptparray(&val_arr, read_bytes); + for (ii = 0; ii < read_bytes; ii++) { + _prop_append_ele_ptparray(&val_arr, data[ii]); + } + + no_bytes = _prop_get_size_ptparray(&val_arr); + ptr = _hdlr_alloc_buf_data_container(&blk, no_bytes, no_bytes); + if (ptr == NULL) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + g_free(data); + _util_file_close(h_file); + _prop_deinit_ptparray(&val_arr); + return; + } + if (_prop_pack_ptparray(&val_arr, ptr, no_bytes) != no_bytes) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + g_free(blk.data); + g_free(data); + _prop_deinit_ptparray(&val_arr); + _util_file_close(h_file); + return; + } + + g_free(data); + _prop_deinit_ptparray(&val_arr); + _util_file_close(h_file); + + break; + } + + default: + ERR("Unknown PropId : [0x%x]\n", prop_id); + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + return; + } + + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + } else { + _device_set_phase(DEVICE_PHASE_NOTREADY); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_INCOMPLETETRANSFER); + } + g_free(blk.data); + return; +} + +static void __set_device_prop_value(mtp_handler_t *hdlr) +{ + mtp_uint32 prop_id = 0; + data_blk_t blk = { 0 }; + mtp_uint32 max_bytes = 0; + mtp_uint16 resp = PTP_RESPONSE_OK; + mtp_err_t ret = 0; + mtp_char *d_raw = NULL; + + prop_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + _device_set_phase(DEVICE_PHASE_DATAOUT); + + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + max_bytes = MAX_SIZE_IN_BYTES_OF_PROP_VALUE; + + if (FALSE == _hdlr_rcv_data_container(&blk, max_bytes)) { + ERR("_hdlr_rcv_data_container() Fail"); + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + return; + } + + d_raw = (mtp_char *)_hdlr_get_payload_data(&blk); + if (NULL != d_raw) { + ret = _hutil_set_device_property(prop_id, d_raw, + _hdlr_get_payload_size(&blk)); + } else { + ret = MTP_ERROR_INVALID_OBJ_PROP_CODE; + } + + switch (ret) { + case MTP_ERROR_NONE: { +#ifdef MTP_USE_INFORMATION_REGISTRY + + mtp_char temp[MTP_MAX_REG_STRING * 3 + 1] = { 0 }; + mtp_wchar parsed_buf[MTP_MAX_REG_STRING + 1] = { 0 }; + mtp_uchar parse_sz = 0; + + if (MTP_PROPERTYCODE_SYNCHRONIZATIONPARTNER == prop_id) { + parse_sz = d_raw[0]; + _util_wchar_ncpy(parsed_buf, (mtp_wchar *)&d_raw[1], + parse_sz > MTP_MAX_REG_STRING ? + MTP_MAX_REG_STRING : parse_sz); + _util_utf16_to_utf8(temp, sizeof(temp), parsed_buf); + _device_set_sync_partner(temp); + if (!g_strcmp0(temp, + MTP_DEV_PROPERTY_NULL_SYNCPARTNER)) { + vconf_set_str(VCONFKEY_MTP_SYNC_PARTNER_STR, + ""); + } else { + vconf_set_str(VCONFKEY_MTP_SYNC_PARTNER_STR, + temp); + } + } +#endif /*MTP_USE_INFORMATION_REGISTRY*/ + } + resp = PTP_RESPONSE_OK; + break; + case MTP_ERROR_ACCESS_DENIED: + resp = PTP_RESPONSE_ACCESSDENIED; + break; + case MTP_ERROR_INVALID_OBJ_PROP_VALUE: + resp = PTP_RESPONSE_INVALIDPROPVALUE; + break; + default: + resp = PTP_RESPONSE_PROP_NOTSUPPORTED; + } + + _cmd_hdlr_send_response_code(hdlr, resp); + + g_free(blk.data); + return; +} + +static void __get_partial_object(mtp_handler_t *hdlr) +{ + mtp_uint32 h_obj = 0; + off_t offset = 0; + mtp_uint32 data_sz = 0; + mtp_uint32 send_bytes = 0; + data_blk_t blk = { 0 }; + mtp_uchar *ptr = NULL; + mtp_uint16 resp = 0; + mtp_uint64 f_size = 0; + mtp_uint64 total_sz = 0; + + offset = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + data_sz = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2); + h_obj = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + + switch (_hutil_get_object_entry_size(h_obj, &f_size)) { + + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + break; + case MTP_ERROR_NONE: + if (data_sz > (f_size - offset)) + send_bytes = f_size - offset; + else + send_bytes = data_sz; + resp = PTP_RESPONSE_OK; + break; + default: + resp = PTP_RESPONSE_GEN_ERROR; + break; + } + + if (PTP_RESPONSE_OK != resp) { + _cmd_hdlr_send_response_code(hdlr, resp); + return; + } + + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + ptr = _hdlr_alloc_buf_data_container(&blk, send_bytes, send_bytes); + + if (NULL != ptr) { + switch (_hutil_read_file_data_from_offset(h_obj, offset, ptr, &send_bytes)) { + case MTP_ERROR_NONE: + resp = PTP_RESPONSE_OK; + break; + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + break; + default: + resp = PTP_RESPONSE_GEN_ERROR; + } + } else { + resp = PTP_RESPONSE_GEN_ERROR; + } + + if (PTP_RESPONSE_OK == resp) { + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) { + total_sz = send_bytes + sizeof(header_container_t); + if (total_sz % _transport_get_usb_packet_len() == 0) + _transport_send_zlp(); + _cmd_hdlr_send_response(hdlr, resp, 1, &send_bytes); + g_free(blk.data); + return; + } + + /*Host Cancelled data-in transfer*/ + _device_set_phase(DEVICE_PHASE_NOTREADY); + g_free(blk.data); + return; + } + + _cmd_hdlr_send_response_code(hdlr, resp); + + g_free(blk.data); + return; +} + +static void __get_object_references(mtp_handler_t *hdlr) +{ + mtp_uint32 h_obj = 0; + ptp_array_t ref_arr = { 0 }; + data_blk_t blk = { 0 }; + mtp_uint32 num_bytes = 0; + mtp_uchar *ptr = NULL; + mtp_uint32 num_ele = 0; + mtp_uint16 resp = 0; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + + ERR("Unsupported Parameters"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + h_obj = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + + switch (_hutil_get_object_references(h_obj, &ref_arr, &num_ele)) { + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + break; + case MTP_ERROR_NONE: + resp = PTP_RESPONSE_OK; + break; + default : + resp = PTP_RESPONSE_GEN_ERROR; + } + + if (resp != PTP_RESPONSE_OK) { + _cmd_hdlr_send_response_code(hdlr, resp); + return; + } + + if (resp == PTP_RESPONSE_OK && num_ele == 0) { + _cmd_hdlr_send_response_code(hdlr, resp); + return; + } + + num_bytes = _prop_get_size_ptparray(&ref_arr); + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + + ptr = _hdlr_alloc_buf_data_container(&blk, num_bytes, num_bytes); + if (num_bytes == _prop_pack_ptparray(&ref_arr, ptr, num_bytes)) { + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + } else { + /* Host Cancelled data-in transfer*/ + _device_set_phase(DEVICE_PHASE_NOTREADY); + } + } else { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + } + + _prop_deinit_ptparray(&ref_arr); + g_free(blk.data); + + return; +} + +static void __set_object_references(mtp_handler_t *hdlr) +{ + mtp_uint32 h_obj = 0; + data_blk_t blk = { 0 }; + mtp_uint32 max_bytes = 0; + mtp_uint16 resp = PTP_RESPONSE_OK; + mtp_uint32 num_ref = 0; + mtp_uint32 idx = 0; + mtp_uint32 *ref_ptr = NULL; + mtp_uchar *ptr = NULL; + mtp_uint32 ref_handle = 0; + + h_obj = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + + resp = PTP_RESPONSE_PARAM_NOTSUPPORTED; + _cmd_hdlr_send_response_code(hdlr, resp); + } + + _device_set_phase(DEVICE_PHASE_DATAOUT); + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + + /* temporarily set a big number for data size received */ + + max_bytes = MTP_MAX_REFDB_ROWCNT * sizeof(mtp_uint32); + if (_hdlr_rcv_data_container(&blk, max_bytes) == FALSE) { + DBG("_hdlr_rcv_data_container() Fail"); + _device_set_phase(DEVICE_PHASE_IDLE); + resp = PTP_RESPONSE_GEN_ERROR; + } + + if (PTP_RESPONSE_OK != resp) { + _cmd_hdlr_send_response_code(hdlr, resp); + g_free(blk.data); + return; + } + + ptr = _hdlr_get_payload_data(&blk); + if (ptr == NULL) { + return; + } + + memcpy(&num_ref, ptr, sizeof(mtp_uint32)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(&num_ref, sizeof(DWORD)); +#endif /* __BIG_ENDIAN__ */ + + ptr += sizeof(mtp_uint32); + if (_hdlr_get_payload_size(&blk) < (num_ref + 1) * sizeof(mtp_uint32)) { + + resp = PTP_RESPONSE_GEN_ERROR; + _cmd_hdlr_send_response_code(hdlr, resp); + g_free(blk.data); + return; + } + + ref_ptr = (mtp_uint32 *)ptr; + if (MTP_ERROR_NONE != _hutil_remove_object_reference(h_obj, + PTP_OBJECTHANDLE_ALL)) { + resp = PTP_RESPONSE_GEN_ERROR; + _cmd_hdlr_send_response_code(hdlr, resp); + g_free(blk.data); + } + + for (idx = 0; idx < num_ref; idx++) { + ref_handle = ref_ptr[idx]; +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(&ref_handle, sizeof(mtp_uint32)); +#endif /*__BIG_ENDIAN__*/ + _device_get_object_with_handle(ref_handle); + } + + _hutil_add_object_references_enhanced(h_obj, (mtp_uchar *)ref_ptr, + num_ref); + _cmd_hdlr_send_response_code(hdlr, resp); + + g_free(blk.data); + return; +} + +static void __get_object_prop_desc(mtp_handler_t *hdlr) +{ + mtp_uint32 prop_id = 0; + mtp_uint32 fmt = 0; + obj_prop_desc_t prop = { { 0 }, }; + data_blk_t blk = { 0, }; + mtp_uint32 num_bytes = 0; + mtp_uchar *ptr = NULL; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + prop_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + fmt = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + + if (MTP_ERROR_NONE != _hutil_get_prop_desc(fmt, prop_id, &prop)) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PROP_NOTSUPPORTED); + return; + } + + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + num_bytes = _prop_size_obj_prop_desc(&prop); + ptr = _hdlr_alloc_buf_data_container(&blk, num_bytes, num_bytes); + + if (num_bytes == _prop_pack_obj_prop_desc(&prop, ptr, num_bytes)) { + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + } else { + /* Host Cancelled data-in transfer */ + _device_set_phase(DEVICE_PHASE_NOTREADY); + } + } else { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + } + + g_free(blk.data); + return; +} + +static void __get_object_prop_supported(mtp_handler_t *hdlr) +{ + mtp_uint32 fmt = 0; + data_blk_t blk = { 0 }; + ptp_array_t props_supported = { 0 }; + mtp_uint32 num_bytes = 0; + mtp_uchar *ptr = NULL; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + fmt = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + _prop_init_ptparray(&props_supported, UINT16_TYPE); + + if (MTP_ERROR_NONE != _hutil_get_object_prop_supported(fmt, + &props_supported)) { + _prop_deinit_ptparray(&props_supported); + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + return; + } + + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + num_bytes = _prop_get_size_ptparray(&props_supported); + ptr = _hdlr_alloc_buf_data_container(&blk, num_bytes, num_bytes); + + if (NULL != ptr) { + _prop_pack_ptparray(&props_supported, ptr, num_bytes); + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + } else { + /* Host Cancelled data-in transfer */ + _device_set_phase(DEVICE_PHASE_NOTREADY); + } + } else { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + } + + _prop_deinit_ptparray(&props_supported); + + g_free(blk.data); + return; +} + +static void __get_object_prop_value(mtp_handler_t *hdlr) +{ + mtp_uint32 h_obj = 0; + mtp_uint32 prop_id = 0; + mtp_uchar *ptr = NULL; + mtp_uint32 num_bytes = 0; + data_blk_t blk = { 0 }; + obj_prop_val_t prop_val = { 0 }; + mtp_err_t ret = 0; + mtp_obj_t *obj = NULL; +#ifdef MTP_USE_RUNTIME_GETOBJECTPROPVALUE + slist_node_t *node = NULL; + slist_node_t *next_node = NULL; + mtp_uint32 ii = 0; +#endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/ + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + h_obj = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + prop_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + ret = _hutil_get_object_prop_value(h_obj, prop_id, &prop_val, &obj); + + if (MTP_ERROR_NONE == ret) { + num_bytes = _prop_size_obj_propval(&prop_val); + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, + hdlr->usb_cmd.tid); + ptr = _hdlr_alloc_buf_data_container(&blk, num_bytes, + num_bytes); + if (num_bytes == + _prop_pack_obj_propval(&prop_val, ptr, num_bytes)) { + + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_OK); + } else { + /* Host Cancelled data-in transfer */ + _device_set_phase(DEVICE_PHASE_NOTREADY); + } + } else { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_GEN_ERROR); + } + + g_free(blk.data); + + } else if (ret == MTP_ERROR_INVALID_OBJECTHANDLE) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_INVALID_OBJ_HANDLE); + } else { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + } + +#ifdef MTP_USE_RUNTIME_GETOBJECTPROPVALUE + if (NULL == obj) { + ERR("Invalid object"); + return; + } + + for (ii = 0, next_node = obj->propval_list.start; + ii < obj->propval_list.nnodes; ii++) { + node = next_node; + next_node = node->link; + _prop_destroy_obj_propval((obj_prop_val_t *)node->value); + g_free(node); + } + obj->propval_list.start = NULL; + obj->propval_list.end = NULL; + obj->propval_list.nnodes = 0; +#endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/ + + return; +} + +static void __set_object_prop_value(mtp_handler_t *hdlr) +{ + mtp_uint32 h_obj = 0; + mtp_uint32 prop_id = 0; + mtp_uint16 resp = PTP_RESPONSE_OK; + data_blk_t blk = { 0 }; + mtp_uint32 max_bytes = 0; + mtp_err_t ret = 0; + + h_obj = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + prop_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + ERR("Unsupported parameters"); + resp = PTP_RESPONSE_PARAM_NOTSUPPORTED; + _cmd_hdlr_send_response_code(hdlr, resp); + return; + } + + _device_set_phase(DEVICE_PHASE_DATAOUT); + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + max_bytes = MTP_MAX_PROP_DATASIZE; + + if (_hdlr_rcv_data_container(&blk, max_bytes) == FALSE) { + ERR("_hdlr_rcv_data_container() Fail"); + _device_set_phase(DEVICE_PHASE_IDLE); + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_INVALIDPROPVALUE); + g_free(blk.data); + return; + } + + ret = _hutil_update_object_property(h_obj, prop_id, NULL, + _hdlr_get_payload_data(&blk), + _hdlr_get_payload_size(&blk), NULL); + switch (ret) { + case MTP_ERROR_ACCESS_DENIED: + resp = PTP_RESPONSE_ACCESSDENIED; + break; + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + break; + case MTP_ERROR_INVALID_OBJ_PROP_CODE: + resp = PTP_RESPONSE_PROP_NOTSUPPORTED; + break; + case MTP_ERROR_GENERAL: + resp = PTP_RESPONSE_GEN_ERROR; + break; + case MTP_ERROR_NONE: + resp = PTP_RESPONSE_OK; + break; + default: + resp = PTP_RESPONSE_INVALIDPROPVALUE; + break; + } + + _cmd_hdlr_send_response_code(hdlr, resp); + + g_free(blk.data); + return; +} + +static void __get_object_prop_list(mtp_handler_t *hdlr) +{ + mtp_uint32 h_obj = 0; + mtp_uint32 fmt = 0; + mtp_uint32 prop_id = 0; + mtp_uint32 group_code = 0; + mtp_uint32 depth = 0; + mtp_err_t ret = 0; + mtp_uint16 resp = 0; + obj_proplist_t prop_list = { { 0 } }; + data_blk_t blk = { 0 }; + mtp_uint32 num_bytes = 0; + mtp_uchar *ptr = NULL; +#ifdef MTP_USE_RUNTIME_GETOBJECTPROPVALUE + ptp_array_t obj_arr = { 0 }; + slist_node_t *node = NULL; + slist_node_t *next_node = NULL; + mtp_uint32 ii = 0; + mtp_uint32 jj = 0; + mtp_obj_t **ptr_array = NULL; + mtp_obj_t *obj = NULL; +#endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/ + + h_obj = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + fmt = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + prop_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2); + group_code = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 3); + depth = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 4); + + __enum_store_not_enumerated(h_obj, fmt, depth); + +#ifdef MTP_USE_RUNTIME_GETOBJECTPROPVALUE + ret = _hutil_get_object_prop_list(h_obj, fmt, prop_id, group_code, + depth, &prop_list, &obj_arr); +#else /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/ + ret = _hutil_get_object_prop_list(h_obj, fmt, prop_id, group_code, + depth, &prop_list); +#endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/ + + switch (ret) { + case MTP_ERROR_NONE: + resp = PTP_RESPONSE_OK; + break; + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + break; + case MTP_ERROR_INVALID_PARAM: + resp = PTP_RESPONSE_INVALIDPARAM; + break; + case MTP_ERROR_NO_SPEC_BY_FORMAT: + resp = PTP_RESPONSE_NOSPECIFICATIONBYFORMAT; + break; + case MTP_ERROR_GENERAL: + default: + resp = PTP_RESPONSE_GEN_ERROR; + } + + if (PTP_RESPONSE_OK != resp) { + _cmd_hdlr_send_response_code(hdlr, resp); + _prop_deinit_ptparray(&obj_arr); + return; + } + + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + num_bytes = _prop_size_obj_proplist(&prop_list); + ptr = _hdlr_alloc_buf_data_container(&blk, num_bytes, num_bytes); + if (num_bytes == _prop_pack_obj_proplist(&prop_list, ptr, num_bytes)) { + + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) { + _cmd_hdlr_send_response_code(hdlr, resp); + } else { + /* Host Cancelled data-in transfer*/ + _device_set_phase(DEVICE_PHASE_NOTREADY); + } + } + + _prop_destroy_obj_proplist(&prop_list); + g_free(blk.data); + +#ifdef MTP_USE_RUNTIME_GETOBJECTPROPVALUE + if (resp == PTP_RESPONSE_OK && obj_arr.array_entry) { + ptr_array = obj_arr.array_entry; + + for (ii = 0; ii < obj_arr.num_ele; ii++) { + obj = ptr_array[ii]; + if (NULL == obj || obj->propval_list.nnodes == 0) { + continue; + } + /*Remove all the old property value, and ready to set up new */ + for (jj = 0, next_node = obj->propval_list.start; + jj < obj->propval_list.nnodes; jj++) { + node = next_node; + next_node = node->link; + _prop_destroy_obj_propval + ((obj_prop_val_t *)node->value); + g_free(node); + } + obj->propval_list.start = NULL; + obj->propval_list.end = NULL; + obj->propval_list.nnodes = 0; + node = NULL; + } + } + _prop_deinit_ptparray(&obj_arr); +#endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/ + return; +} + +static void __set_object_prop_list(mtp_handler_t *hdlr) +{ + mtp_uint32 i = 0; + mtp_uint16 resp = PTP_RESPONSE_OK; + data_blk_t blk = { 0 }; + mtp_uint32 max_num_obj = 0; + mtp_uint32 max_bytes = 0; + mtp_uint32 h_obj = 0; + mtp_uint32 prop_id = 0; + mtp_uint32 data_type = 0; + mtp_uchar *temp = NULL; + mtp_int32 bytes_left = 0; + mtp_uint32 prop_val_sz = 0; + mtp_uint32 num_elem = 0; + mtp_err_t ret = 0; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 3) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 4)) { + resp = PTP_RESPONSE_PARAM_NOTSUPPORTED; + } + + _device_set_phase(DEVICE_PHASE_DATAOUT); + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + + /* Gestimate the amount of data we will be receiving */ + _hutil_get_number_of_objects(PTP_STORAGEID_ALL, &max_num_obj); + max_bytes = max_num_obj * 1000; + + /* If Host sent more data than we could receive, a device stall happens, + * which cancels the data transfer + */ + if (max_bytes > 1000000) { + max_bytes = 1000000; + ERR("max_bytes is overflowed"); + } + if (FALSE == _hdlr_rcv_data_container(&blk, max_bytes)) { + ERR("_hdlr_rcv_data_container() Fail"); + _device_set_phase(DEVICE_PHASE_NOTREADY); + resp = PTP_RESPONSE_GEN_ERROR; + } + + if (PTP_RESPONSE_OK != resp) { + _cmd_hdlr_send_response(hdlr, resp, 1, &i); + g_free(blk.data); + return; + } + + temp = _hdlr_get_payload_data(&blk); + bytes_left = (mtp_int32)_hdlr_get_payload_size(&blk); + if (bytes_left < sizeof(mtp_uint32)) { + + resp = MTP_RESPONSE_INVALIDOBJPROPFORMAT; + _cmd_hdlr_send_response(hdlr, resp, 1, &i); + g_free(blk.data); + + ERR("invalid object format, bytes_left [%d]:[%u]\n", bytes_left, + sizeof(mtp_uint32)); + return; + } + + num_elem = 0; + memcpy(&num_elem, temp, sizeof(mtp_uint32)); + temp += sizeof(mtp_uint32); + bytes_left -= sizeof(mtp_uint32); + + for (i = 0; i < num_elem; i++) { + if (bytes_left < 0) + break; + + /*Get object handle*/ + memcpy(&h_obj, temp, sizeof(mtp_uint32)); + temp += sizeof(mtp_uint32); + bytes_left -= sizeof(mtp_uint32); + if (bytes_left < 0) + break; + + /* Get property code */ + memcpy(&prop_id, temp, sizeof(mtp_uint16)); + temp += sizeof(mtp_uint16); + bytes_left -= sizeof(mtp_uint16); + if (bytes_left < 0) + break; + + /* Get data type*/ + memcpy(&data_type, temp, sizeof(mtp_uint16)); + temp += sizeof(mtp_uint16); + bytes_left -= sizeof(mtp_uint16); + if (bytes_left < 0) + break; + + /* Update property*/ + ret = _hutil_update_object_property(h_obj, prop_id, + (mtp_uint16 *)&data_type, temp, bytes_left, + &prop_val_sz); + + switch (ret) { + case MTP_ERROR_INVALID_OBJECT_PROP_FORMAT: + resp = MTP_RESPONSE_INVALIDOBJPROPFORMAT; + _cmd_hdlr_send_response(hdlr, resp, 1, &i); + g_free(blk.data); + ERR("invalid object format"); + return; + break; + case MTP_ERROR_ACCESS_DENIED: + resp = PTP_RESPONSE_ACCESSDENIED; + _cmd_hdlr_send_response(hdlr, resp, 1, &i); + g_free(blk.data); + ERR("access denied"); + return; + break; + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + _cmd_hdlr_send_response(hdlr, resp, 1, &i); + g_free(blk.data); + ERR("invalid object handle"); + return; + break; + case MTP_ERROR_INVALID_OBJ_PROP_CODE: + resp = PTP_RESPONSE_PROP_NOTSUPPORTED; + _cmd_hdlr_send_response(hdlr, resp, 1, &i); + g_free(blk.data); + ERR("property not supported"); + return; + break; + case MTP_ERROR_NONE: + temp += prop_val_sz; + bytes_left -= prop_val_sz; + break; + default: + resp = PTP_RESPONSE_INVALIDPROPVALUE; + _cmd_hdlr_send_response(hdlr, resp, 1, &i); + g_free(blk.data); + ERR("invalid property value"); + return; + break; + } + } + i = 0; + resp = PTP_RESPONSE_OK; + _cmd_hdlr_send_response(hdlr, resp, 1, &i); + g_free(blk.data); + return; +} + +static void __report_acquired_content(mtp_handler_t *hdlr) +{ + mtp_uint32 tid = 0; + mtp_uint32 start_idx = 0; + mtp_uint32 max_size = 0; + mtp_uint16 resp = PTP_RESPONSE_OK; + mtp_uint32 resp_param[3] = { 0 }; + data_blk_t blk = { 0 }; + mtp_uchar *ptr = NULL; + ptp_array_t guid_arr = { 0 }; + mtp_uint32 num_mod = 0; + mtp_uint32 num_bytes = 0; + mtp_uint32 num_lines = 0; + mtp_uint32 rem_modified = 0; + mtp_uint32 h_file; + time_t cur_time; + time_t l_time; + mtp_int32 diff_time; + mtp_int32 err = 0; + mtp_int32 ret = 0; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 3)) { + + ERR("Unsupported parameters"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + tid = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + start_idx = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + max_size = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2); + + if (tid == 0) { + + if (access(MTP_FILES_MODIFIED_FILES, F_OK) == 0) + if (remove(MTP_FILES_MODIFIED_FILES) < 0) { + ERR("remove(%s) Fail", MTP_FILES_MODIFIED_FILES); + } + resp = PTP_RESPONSE_OK; + _prop_grow_ptparray(&guid_arr, 1); + _prop_append_ele_ptparray(&guid_arr, 0); + goto DONE; + } + + g_is_sync_estab = TRUE; + + if (!g_has_round_trip && start_idx == 0) { + time(&cur_time); + ret = vconf_get_int(VCONFKEY_MTP_SYNC_TIME_INT, (int *)&l_time); + if (ret == -1) { + ERR("Error to get key value at [%s] path\n", + VCONFKEY_MTP_SYNC_TIME_INT); + resp = PTP_RESPONSE_OK; + _prop_grow_ptparray(&guid_arr, 1); + _prop_append_ele_ptparray(&guid_arr, 0); + goto DONE; + } + diff_time = (cur_time - l_time) / 60; + if (diff_time < 0) { + resp = PTP_RESPONSE_GEN_ERROR; + _prop_init_ptparray(&guid_arr, UINT32_TYPE); + _prop_append_ele_ptparray(&guid_arr, 0); + goto DONE; + } + _entity_list_modified_files(diff_time); + } + + h_file = _util_file_open(MTP_FILES_MODIFIED_FILES, MTP_FILE_READ, &err); + if (h_file == INVALID_FILE) { + resp = PTP_RESPONSE_GEN_ERROR; + _prop_init_ptparray(&guid_arr, UINT32_TYPE); + _prop_append_ele_ptparray(&guid_arr, 0); + goto DONE; + } + + if (!g_has_round_trip && start_idx == 0) { + _util_count_num_lines(h_file, &g_mgr->meta_info.mod); + _util_file_seek(h_file, 0, SEEK_SET); + } + num_lines = g_mgr->meta_info.mod; + num_mod = ((num_lines - start_idx) > max_size) ? + max_size : num_lines - start_idx; + + rem_modified = (num_lines - start_idx > max_size) ? + (num_lines - start_idx- max_size) : 0; + + g_has_round_trip = FALSE; + _prop_init_ptparray(&guid_arr, UINT32_TYPE); + _prop_grow_ptparray(&guid_arr, (num_mod * sizeof(mtp_uint32)) + 1); + _prop_append_ele_ptparray(&guid_arr, num_mod); + _util_fill_guid_array(&guid_arr, start_idx, h_file, num_mod); + + _util_file_close(h_file); + if (rem_modified == 0) { + if (remove(MTP_FILES_MODIFIED_FILES) < 0) { + ERR("remove(%s) Fail", MTP_FILES_MODIFIED_FILES); + } + g_mgr->meta_info.mod = 0; + } + +DONE: + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + num_bytes = _prop_get_size_ptparray_without_elemsize(&guid_arr); + ptr = _hdlr_alloc_buf_data_container(&blk, num_bytes, num_bytes); + + if (NULL != ptr) { + _prop_pack_ptparray_without_elemsize(&guid_arr, ptr, num_bytes); + _device_set_phase(DEVICE_PHASE_DATAIN); + } + + if (_hdlr_send_data_container(&blk)) { + resp = PTP_RESPONSE_OK; + } else { + resp = PTP_RESPONSE_GEN_ERROR; + } + + _prop_deinit_ptparray(&guid_arr); + g_free(blk.data); + + if (PTP_RESPONSE_OK == resp) { + + resp_param[0] = hdlr->usb_cmd.tid; + resp_param[1] = rem_modified; + resp_param[2] = 0; + _cmd_hdlr_send_response(hdlr, resp, 3, resp_param); + } else { + _cmd_hdlr_send_response_code(hdlr, resp); + } + return; +} + +static void __send_playback_skip(mtp_handler_t *hdlr) +{ + mtp_int32 skip = 0; + mtp_uint16 resp = PTP_RESPONSE_INVALIDPARAM; + + skip = (mtp_int32) _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + if (MTP_ERROR_NONE == _hutil_get_playback_skip(skip)) { + resp = PTP_RESPONSE_OK; + } + _cmd_hdlr_send_response_code(hdlr, resp); + return; +} + +#ifndef PMP_VER +static void __self_test(mtp_handler_t *hdlr) +{ + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + ERR("Unsupported parameters"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + /* Do device-specific tests */ + /* After the test */ + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + return; +} + +#ifdef MTP_SUPPORT_SET_PROTECTION +static void __set_object_protection(mtp_handler_t *hdlr) +{ + mtp_uint32 h_obj = 0; + mtp_uint16 protcn_status = 0; + mtp_uint16 resp = 0; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + ERR("Unsupported parameter"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + h_obj = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + protcn_status = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + + if ((protcn_status != PTP_PROTECTIONSTATUS_NOPROTECTION) && + (protcn_status != PTP_PROTECTIONSTATUS_READONLY) && + (protcn_status != MTP_PROTECTIONSTATUS_READONLY_DATA) && + (protcn_status != MTP_PROTECTIONSTATUS_NONTRANSFERABLE_DATA)) { + + resp = PTP_RESPONSE_INVALIDPARAM; + _cmd_hdlr_send_response_code(hdlr, resp); + return; + + } + switch (_hutil_set_protection(h_obj, protcn_status)) { + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + break; + case MTP_ERROR_OBJECT_WRITE_PROTECTED: + resp = PTP_RESPONSE_OBJ_WRITEPROTECTED; + break; + case MTP_ERROR_NONE: + resp = PTP_RESPONSE_OK; + break; + case MTP_ERROR_OPERATION_NOT_SUPPORTED: + resp = PTP_RESPONSE_OP_NOT_SUPPORTED; + break; + default: + resp = PTP_RESPONSE_GEN_ERROR; + } + + _cmd_hdlr_send_response_code(hdlr, resp); + return; +} +#endif /* MTP_SUPPORT_SET_PROTECTION */ + +static void __power_down(mtp_handler_t *hdlr) +{ + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + ERR("Unsupported Parameter"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + usleep(1000); + _cmd_hdlr_reset_cmd(hdlr); + return; +} + +static void __move_object(mtp_handler_t *hdlr) +{ + mtp_uint32 store_id = 0; + mtp_uint32 obj_handle = 0; + mtp_uint32 h_parent = 0; + mtp_uint32 resp = 0; + + obj_handle = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + store_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + h_parent = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2); + + _transport_set_mtp_operation_state(MTP_STATE_DATA_PROCESSING); + + switch (_hutil_move_object_entry(store_id, h_parent, obj_handle)) { + case MTP_ERROR_NONE: + resp = PTP_RESPONSE_OK; + break; + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + break; + case MTP_ERROR_OBJECT_WRITE_PROTECTED: + resp = PTP_RESPONSE_OBJ_WRITEPROTECTED; + break; + case MTP_ERROR_ACCESS_DENIED: + resp = PTP_RESPONSE_ACCESSDENIED; + break; + case MTP_ERROR_STORE_NOT_AVAILABLE: + resp = PTP_RESPONSE_STORENOTAVAILABLE; + break; + case MTP_ERROR_INVALID_PARENT: + resp = PTP_RESPONSE_INVALIDPARENT; + break; + case MTP_ERROR_INVALID_PARAM: + resp = PTP_RESPONSE_INVALIDPARAM; + break; + case MTP_ERROR_STORE_FULL: + resp = PTP_RESPONSE_STOREFULL; + break; + default: + resp = PTP_RESPONSE_GEN_ERROR; + } + + _transport_set_mtp_operation_state(MTP_STATE_ONSERVICE); + _cmd_hdlr_send_response_code(hdlr, resp); + return; +} + +static void __copy_object(mtp_handler_t *hdlr) +{ + mtp_uint32 store_id = 0; + mtp_uint32 h_obj = 0; + mtp_uint32 h_parent = 0; + mtp_uint32 new_handle = 0; + mtp_uint16 resp = 0; + + h_obj = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + store_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + h_parent = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2); + + _transport_set_mtp_operation_state(MTP_STATE_DATA_PROCESSING); + + switch (_hutil_duplicate_object_entry(store_id, h_parent, h_obj, + &new_handle)) { + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + break; + case MTP_ERROR_OBJECT_WRITE_PROTECTED: + resp = PTP_RESPONSE_OBJ_WRITEPROTECTED; + break; + case MTP_ERROR_STORE_NOT_AVAILABLE: + resp = PTP_RESPONSE_STORENOTAVAILABLE; + break; + case MTP_ERROR_STORE_READ_ONLY: + resp = PTP_RESPONSE_STORE_READONLY; + break; + case MTP_ERROR_INVALID_PARENT: + resp = PTP_RESPONSE_INVALIDPARENT; + break; + case MTP_ERROR_INVALID_PARAM: + resp = PTP_RESPONSE_INVALIDPARAM; + break; + case MTP_ERROR_STORE_FULL: + resp = PTP_RESPONSE_STOREFULL; + break; + case MTP_ERROR_NONE: + resp = PTP_RESPONSE_OK; + break; + case MTP_ERROR_ACCESS_DENIED: + resp = PTP_RESPONSE_ACCESSDENIED; + break; + default: + resp = PTP_RESPONSE_GEN_ERROR; + } + _transport_set_mtp_operation_state(MTP_STATE_ONSERVICE); + + if (resp == PTP_RESPONSE_OK) { + _cmd_hdlr_send_response(hdlr, resp, 1, &new_handle); + } else { + _cmd_hdlr_send_response_code(hdlr, resp); + } + + return; +} + +static void __reset_device_prop_value(mtp_handler_t *hdlr) +{ + mtp_uint32 prop_id = 0; + device_prop_desc_t *prop = NULL; + mtp_char temp[MTP_MAX_REG_STRING * 3 + 1] = { 0 }; + + prop_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + + if (MTP_ERROR_NONE != _hutil_reset_device_entry(prop_id)) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PROP_NOTSUPPORTED); + return; + } + + if (MTP_PROPERTYCODE_DEVICEFRIENDLYNAME == prop_id) { + prop = _device_get_device_property(prop_id); + if (prop == NULL) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PROP_NOTSUPPORTED); + return; + } + + _util_utf16_to_utf8(temp, sizeof(temp), + prop->current_val.str->str); + _device_set_device_name(temp); + + } else if (MTP_PROPERTYCODE_SYNCHRONIZATIONPARTNER == prop_id) { + prop = _device_get_device_property(prop_id); + if (NULL == prop) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PROP_NOTSUPPORTED); + return; + } + + _util_utf16_to_utf8(temp, sizeof(temp), + prop->current_val.str->str); + _device_set_sync_partner(temp); + + if (!g_strcmp0(temp, MTP_DEV_PROPERTY_NULL_SYNCPARTNER)) { + vconf_set_str(VCONFKEY_MTP_SYNC_PARTNER_STR, ""); + } else { + vconf_set_str(VCONFKEY_MTP_SYNC_PARTNER_STR, temp); + } + } + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + + return; +} + +/* Vendor-specific operations */ +#define GET_DEVICEPC_NAME 1 +static void __vendor_command1(mtp_handler_t *hdlr) +{ + switch (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0)) { + case GET_DEVICEPC_NAME: + break; + default: + break; + } + /* Vendor command not properly handled*/ + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + return; +} + +static void __get_interdep_prop_desc(mtp_handler_t *hdlr) +{ + mtp_uint32 fmt = 0; + data_blk_t blk = { 0 }; + mtp_uint32 num_bytes = 0; + mtp_uchar *ptr = NULL; + + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + return; + } + + fmt = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + if (0x0 == fmt || 0xFFFFFFFF == fmt) { + ERR("Invalid format code"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_INVALIDCODEFORMAT); + return; + } + + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + _hutil_get_interdep_prop_config_list_size(&num_bytes, fmt); + ptr = _hdlr_alloc_buf_data_container(&blk, num_bytes, num_bytes); + + if (MTP_ERROR_NONE != _hutil_get_interdep_prop_config_list_data(ptr, + num_bytes, fmt)) { + ERR("_hutil_get_interdep_prop_config_list_data() Fail"); + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_GEN_ERROR); + return; + } + + _device_set_phase(DEVICE_PHASE_DATAIN); + if (_hdlr_send_data_container(&blk)) { + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + } else { + /*Host Cancelled data-in transfer*/ + _device_set_phase(DEVICE_PHASE_NOTREADY); + } + + g_free(blk.data); + return; +} + +/* + * void __cmd_hdlr_send_object_prop_list(mtp_handler_t *hdlr) + * This function is used as an alternative first operation when the initiator + * wants to send an object to the responder. This operation sends a + * modified ObjectPropList dataset from the initiator to the Responder. + *@param[in] hdlr + *@return none + */ +static void __send_object_prop_list(mtp_handler_t *hdlr) +{ + mtp_uint32 idx = 0; + mtp_uint16 resp = PTP_RESPONSE_OK; + mtp_uint32 resp_param[MAX_MTP_PARAMS] = { 0 }; + mtp_obj_t *obj = NULL; + mtp_uint16 fmt = 0; + mtp_uint64 f_size = 0; + mtp_uint64 fsize_hbits = 0; + mtp_uint32 store_id; + mtp_uint32 h_parent; + data_blk_t blk = { 0 }; + mtp_uint32 max_bytes = 0; + mtp_err_t ret = 0; + obj_data_t objdata = { 0 }; + + store_id = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0); + h_parent = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1); + fmt = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2); + fsize_hbits = _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 3); + + f_size = (fsize_hbits << 32) + _hdlr_get_param_cmd_container + (&(hdlr->usb_cmd), 4); + + _device_set_phase(DEVICE_PHASE_DATAOUT); + _hdlr_init_data_container(&blk, hdlr->usb_cmd.code, hdlr->usb_cmd.tid); + + max_bytes = MTP_MAX_METADATA; + if (FALSE == _hdlr_rcv_data_container(&blk, max_bytes)) { + _device_set_phase(DEVICE_PHASE_IDLE); + ERR("_hdlr_rcv_data_container() Fail"); + resp = PTP_RESPONSE_GEN_ERROR; + } + + idx = 0; + if (store_id) { + if (!h_parent) { + h_parent = _device_get_default_parent_handle(); + } else if (h_parent == 0xFFFFFFFF) { + h_parent = PTP_OBJECTHANDLE_ROOT; + } + } else { + store_id = _device_get_default_store_id(); + if (!store_id) + resp = PTP_RESPONSE_STORENOTAVAILABLE; + if (h_parent) + /* If the second parameter is used, the first must + * also be used + * */ + resp = PTP_RESPONSE_PARAM_NOTSUPPORTED; + else + h_parent = _device_get_default_parent_handle(); + } + + if (f_size >= MTP_FILESIZE_4GB) { + + mtp_store_t *store = NULL; + struct statfs buf = { 0 }; + mtp_int32 ret = 0; + + store = _device_get_store(store_id); + if (store == NULL) { + ERR("Store Not Available"); + resp = PTP_RESPONSE_STORENOTAVAILABLE; + } else { + DBG("StorePath = [%s]\n", store->root_path); + ret = statfs(store->root_path, &buf); + if (ret < 0 || buf.f_type == MSDOS_SUPER_MAGIC) { + ERR("File System does not support files over 4gb"); + resp = MTP_RESPONSE_OBJECT_TOO_LARGE; + } + } + } + + if (PTP_RESPONSE_OK == resp) { + + mtp_uchar *data = NULL; + + if (TRUE == hdlr->data4_send_obj.is_valid) { + + objdata.store_id = hdlr->data4_send_obj.store_id; + objdata.obj_size = hdlr->data4_send_obj.file_size; + objdata.obj = hdlr->data4_send_obj.obj; + hdlr->data4_send_obj.obj = NULL; + } + + data = _hdlr_get_payload_data(&blk); + if (data == NULL) + return; + + ret = _hutil_construct_object_entry_prop_list(store_id, h_parent, + fmt, f_size, ((hdlr->data4_send_obj.is_valid == TRUE) ? + (&objdata) : (NULL)), &obj, data, + _hdlr_get_payload_size(&blk), &idx); + hdlr->data4_send_obj.is_valid = FALSE; + + switch (ret) { + case MTP_ERROR_INVALID_STORE: + resp = PTP_RESPONSE_INVALID_STORE_ID; + break; + case MTP_ERROR_STORE_READ_ONLY: + resp = PTP_RESPONSE_STORE_READONLY; + break; + case MTP_ERROR_STORE_FULL: + resp = PTP_RESPONSE_STOREFULL; + break; + case MTP_ERROR_GENERAL: + resp = PTP_RESPONSE_GEN_ERROR; + break; + case MTP_ERROR_INVALID_DATASET: + resp = MTP_RESPONSECODE_INVALIDDATASET; + break; + case MTP_ERROR_INVALID_OBJECTHANDLE: + resp = PTP_RESPONSE_INVALID_OBJ_HANDLE; + break; + case MTP_ERROR_INVALID_OBJ_PROP_CODE: + resp = MTP_RESPONSE_INVALIDOBJPROPCODE; + break; + case MTP_ERROR_INVALID_OBJECT_PROP_FORMAT: + resp = MTP_RESPONSE_INVALIDOBJPROPFORMAT; + break; + case MTP_ERROR_INVALID_OBJ_PROP_VALUE: + resp = MTP_RESPONSE_INVALIDOBJPROPVALUE; + break; + case MTP_ERROR_INVALID_PARENT: + resp = PTP_RESPONSE_INVALIDPARENT; + break; + case MTP_ERROR_ACCESS_DENIED: + resp = PTP_RESPONSE_ACCESSDENIED; + break; + case MTP_ERROR_NONE: +#ifdef MTP_USE_SELFMAKE_ABSTRACTION + if ((obj->obj_info->obj_fmt == PTP_FMT_ASSOCIATION) || + (obj->obj_info->file_size == 0 && + obj->obj_info->obj_fmt > + MTP_FMT_UNDEFINED_COLLECTION && + obj->obj_info->obj_fmt < + MTP_FMT_UNDEFINED_DOC)) +#else /*MTP_USE_SELFMAKE_ABSTRACTION*/ + if (obj->obj_info->obj_fmt == PTP_FMT_ASSOCIATION) +#endif /*MTP_USE_SELFMAKE_ABSTRACTION*/ + { + hdlr->data4_send_obj.obj = NULL; + hdlr->data4_send_obj.is_valid = FALSE; + hdlr->data4_send_obj.obj_handle = obj->obj_handle; + hdlr->data4_send_obj.h_parent = h_parent; + hdlr->data4_send_obj.store_id = store_id; + hdlr->data4_send_obj.file_size = 0; + } else { + hdlr->data4_send_obj.is_valid = TRUE; + hdlr->data4_send_obj.obj_handle = obj->obj_handle; + hdlr->data4_send_obj.h_parent = h_parent; + hdlr->data4_send_obj.store_id = store_id; + hdlr->data4_send_obj.obj = obj; + hdlr->data4_send_obj.file_size = + obj->obj_info->file_size; + } + resp = PTP_RESPONSE_OK; + break; + default: + resp = PTP_RESPONSE_GEN_ERROR; + } + } + + if (PTP_RESPONSE_OK != resp) { + if (hdlr->data4_send_obj.obj) { + _entity_dealloc_mtp_obj(hdlr->data4_send_obj.obj); + } + + hdlr->data4_send_obj.obj = NULL; + hdlr->data4_send_obj.is_valid = FALSE; + resp_param[3] = idx; + } else { + resp_param[0] = hdlr->data4_send_obj.store_id; + + /* PTP spec here requires that 0xFFFFFFFF be sent if root is the parent, + * while in some situations (e.g. Move Object, Copy Object), 0x00000000 + *(as PTP_OBJECTHANDLE_ROOT is defined) represents the root + */ + resp_param[1] = (hdlr->data4_send_obj.h_parent != + PTP_OBJECTHANDLE_ROOT) ? hdlr->data4_send_obj.h_parent + : 0xFFFFFFFF; + resp_param[2] = hdlr->data4_send_obj.obj_handle; + resp_param[3] = 0; + } + + _cmd_hdlr_send_response(hdlr, resp, 4, resp_param); + + g_free(blk.data); + return; +} +#endif /*PMP_VER*/ + +void __close_session(mtp_handler_t *hdlr) +{ + if (_hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 0) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 1) || + _hdlr_get_param_cmd_container(&(hdlr->usb_cmd), 2)) { + + ERR("PTP_RESPONSE_PARAM_NOTSUPPORTED"); + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_PARAM_NOTSUPPORTED); + + return; + } + + if (hdlr->session_id) { + hdlr->session_id = 0; + _cmd_hdlr_send_response_code(hdlr, PTP_RESPONSE_OK); + } else { + _cmd_hdlr_send_response_code(hdlr, + PTP_RESPONSE_SESSIONNOTOPEN); + ERR("PTP_RESPONSE_SESSIONNOTOPEN"); + } + return; +} + +mtp_bool _cmd_hdlr_send_response(mtp_handler_t *hdlr, mtp_uint16 resp, + mtp_uint32 num_param, mtp_uint32 *params) +{ + mtp_bool ret = FALSE; + resp_blk_t blk = { 0 }; + + _hdlr_resp_container_init(&blk, resp, hdlr->usb_cmd.tid); + + ret = _hdlr_add_param_resp_container(&blk, num_param, params); + + _device_set_phase(DEVICE_PHASE_RESPONSE); + ret = _hdlr_send_resp_container(&blk); + _device_set_phase(DEVICE_PHASE_IDLE); + + if ((resp == PTP_RESPONSE_OK) && (ret == TRUE)) { + DBG("[%s], Opcode[0x%4x], ResponseCode[0x%4x], NumParams[%d]\n", + "SUCCESS", hdlr->usb_cmd.code, resp, num_param); + } else { + ERR("[%s], Opcode = [0x%4x] ResponseCode[0x%4x], NumParams[%u]\n", + "FAIL", hdlr->usb_cmd.code, resp, num_param); + } + return ret; +} + +mtp_bool _cmd_hdlr_send_response_code(mtp_handler_t *hdlr, mtp_uint16 resp) +{ + return _cmd_hdlr_send_response(hdlr, resp, 0, NULL); +} + +#ifdef MTP_SUPPORT_PRINT_COMMAND +static void __print_command(mtp_uint16 code) +{ + switch(code) { + case PTP_OPCODE_GETDEVICEINFO : + DBG("COMMAND ======== GET DEVICE INFO==========="); + break; + case PTP_OPCODE_OPENSESSION : + DBG("COMMAND ======== OPEN SESSION ==========="); + break; + case PTP_OPCODE_CLOSESESSION : + DBG("COMMAND ======== CLOSE SESSION ==========="); + break; + case PTP_OPCODE_GETSTORAGEIDS : + DBG("COMMAND ======== GET STORAGE IDS ==========="); + break; + case PTP_OPCODE_GETSTORAGEINFO : + DBG("COMMAND ======== GET STORAGE INFO ==========="); + break; + case PTP_OPCODE_GETNUMOBJECTS : + DBG("COMMAND ======== GET NUM OBJECTS ==========="); + break; + case PTP_OPCODE_GETOBJECTHANDLES : + DBG("COMMAND ======== GET OBJECT HANDLES ==========="); + break; + case PTP_OPCODE_GETOBJECTINFO : + DBG("COMMAND ======== GET OBJECT INFO ==========="); + break; + case PTP_OPCODE_GETOBJECT : + DBG("COMMAND ======== GET OBJECT ==========="); + break; + case PTP_OPCODE_DELETEOBJECT : + DBG("COMMAND ======== DELETE OBJECT ==========="); + break; + case PTP_OPCODE_SENDOBJECTINFO : + DBG("COMMAND ======== SEND OBJECT INFO ==========="); + break; + case PTP_OPCODE_SENDOBJECT : + DBG("COMMAND ======== SEND OBJECT ==========="); + break; + case PTP_OPCODE_INITIATECAPTURE : + DBG("COMMAND ======== INITIATE CAPTURE ==========="); + break; + case PTP_OPCODE_FORMATSTORE : + DBG("COMMAND ======== FORMAT STORE ==========="); + break; + case PTP_OPCODE_RESETDEVICE : + DBG("COMMAND ======== RESET DEVICE ==========="); + break; + case PTP_OPCODE_SELFTEST : + DBG("COMMAND ======== SELF TEST ==========="); + break; + case PTP_OPCODE_SETOBJECTPROTECTION : + DBG("COMMAND ======== SET OBJECT PROTECTION ==========="); + break; + case PTP_OPCODE_POWERDOWN : + DBG("COMMAND ======== POWER DOWN ==========="); + break; + case PTP_OPCODE_GETDEVICEPROPDESC : + DBG("COMMAND ======== GET DEVICE PROP DESC ==========="); + break; + case PTP_OPCODE_GETDEVICEPROPVALUE : + DBG("COMMAND ======== GET DEVICE PROP VALUE ==========="); + break; + case PTP_OPCODE_SETDEVICEPROPVALUE : + DBG("COMMAND ======== SET DEVICE PROP VALUE ==========="); + break; + case PTP_OPCODE_RESETDEVICEPROPVALUE : + DBG("COMMAND ======== RESET DEVICE PROP VALUE ==========="); + break; + case PTP_OPCODE_TERMINATECAPTURE : + DBG("COMMAND ======== TERMINATE CAPTURE ==========="); + break; + case PTP_OPCODE_MOVEOBJECT : + DBG("COMMAND ======== MOVE OBJECT ==========="); + break; + case PTP_OPCODE_COPYOBJECT : + DBG("COMMAND ======== COPY OBJECT ==========="); + break; + case PTP_OPCODE_GETPARTIALOBJECT : + DBG("COMMAND ======== GET PARTIAL OBJECT ==========="); + break; + case PTP_OPCODE_INITIATEOPENCAPTURE : + DBG("COMMAND ======== INITIATE OPEN CAPTURE ==========="); + break; + case MTP_OPCODE_WMP_UNDEFINED : + DBG("COMMAND ======== WMP UNDEFINED =========="); + break; + case MTP_OPCODE_WMP_REPORTACQUIREDCONTENT : + DBG("COMMAND ======= REPORT ACQUIRED CONTENT ========="); + break; + case MTP_OPCODE_GETOBJECTPROPSUPPORTED : + DBG("COMMAND ======= GET OBJECT PROP SUPPORTED ========"); + break; + case MTP_OPCODE_GETOBJECTPROPDESC : + DBG("COMMAND ======== GET OBJECT PROP DESC =========="); + break; + case MTP_OPCODE_GETOBJECTPROPVALUE : + DBG("COMMAND ======== GET OBJECT PROP VALUE =========="); + break; + case MTP_OPCODE_SETOBJECTPROPVALUE : + DBG("COMMAND ======== SET OBJECT PROP VALUE =========="); + break; + case MTP_OPCODE_GETOBJECTPROPLIST : + DBG("COMMAND ======== GET OBJECT PROP LIST =========="); + break; + case MTP_OPCODE_SETOBJECTPROPLIST : + DBG("COMMAND ======== SET OBJECT PROP LIST =========="); + break; + case MTP_OPCODE_GETINTERDEPPROPDESC : + DBG("COMMAND ======== GET INTERDEP PROP DESC =========="); + break; + case MTP_OPCODE_SENDOBJECTPROPLIST : + DBG("COMMAND ======== SEND OBJECT PROP LIST =========="); + break; + case MTP_OPCODE_GETOBJECTREFERENCES : + DBG("COMMAND ======== GET OBJECT REFERENCES =========="); + break; + case MTP_OPCODE_SETOBJECTREFERENCES : + DBG("COMMAND ======== SET OBJECT REFERENCES =========="); + break; + case MTP_OPCODE_PLAYBACK_SKIP : + DBG("COMMAND ======== PLAYBACK SKIP =========="); + break; + default : + DBG("======== UNKNOWN COMMAND =========="); + break; + } + + return; +} +#endif /*MTP_SUPPORT_PRINT_COMMAND*/ + +static void __enum_store_not_enumerated(mtp_uint32 obj_handle, + mtp_uint32 fmt, mtp_uint32 depth) +{ + mtp_uint32 ii; + mtp_store_t *store = NULL; + mtp_obj_t *obj = NULL; + + if (TRUE == g_is_full_enum) { + DBG("Full Enumeration has been already done"); + return; + } + + DBG("obj_handle = [%u], format =[ %u], depth = [%u]\n", obj_handle, + fmt, depth); + if (obj_handle == PTP_OBJECTHANDLE_ALL || obj_handle == PTP_OBJECTHANDLE_ROOT) { + for (ii = 0; ii < _device_get_num_stores(); ii++) { + store = _device_get_store_at_index(ii); + if (store && store->obj_list.nnodes == 0) + _entity_store_recursive_enum_folder_objects(store, NULL); + } + g_is_full_enum = TRUE; + } else if (obj_handle != PTP_OBJECTHANDLE_ROOT) { + store = _device_get_store_containing_obj(obj_handle); + obj = _entity_get_object_from_store(store, obj_handle); + if (obj == NULL) { + ERR("pObject is NULL"); + return; + } + _entity_store_recursive_enum_folder_objects(store, obj); + } + return; +} + +void _receive_mq_data_cb(mtp_char *buffer, mtp_int32 buf_len) +{ + cmd_blk_t cmd = { 0 }; + mtp_uint32 rx_size = _get_rx_pkt_size(); + + if (_transport_get_mtp_operation_state() < MTP_STATE_READY_SERVICE) { + ERR("MTP is stopped or initializing. ignore all"); + return; + } + +#ifdef MTP_SUPPORT_CONTROL_REQUEST + /* process control request */ + switch (_transport_get_control_event()) { + case PTP_EVENTCODE_CANCELTRANSACTION: + DBG("PTP_EVENTCODE_CANCELTRANSACTION, just change state to IDLE"); + _transport_set_control_event(PTP_EVENTCODE_CANCELTRANSACTION); + _device_set_phase(DEVICE_PHASE_IDLE); + if ((buf_len == rx_size) || + (buf_len < sizeof(header_container_t))) { + DBG("Cancelling Transaction. data length [%d]\n", + buf_len); + _transport_set_control_event(PTP_EVENTCODE_CANCELTRANSACTION); + return; + } + + mtp_int32 i = 0; + cmd_container_t *tmp; + mtp_dword len = 0; + mtp_word type = 0; + mtp_word code = 0; + mtp_dword trid = 0; + + for (i = 0; i < MAX_MTP_PARAMS; i++) { /* check size */ + /* check number of parameter */ + tmp = (cmd_container_t *)&buffer[buf_len - + sizeof(header_container_t) - + sizeof(mtp_dword) * i]; + + len = tmp->len; + type = tmp->type; + + if ((len == sizeof(header_container_t) + + sizeof(mtp_dword) * i) && + (type == CONTAINER_CMD_BLK)) { + DBG("Found Command in remaining data"); + memcpy(buffer, tmp, len); + buf_len = len; + break; + } + DBG("Not found command, length[%lu]\n", len); + } + + len = tmp->len; + type = tmp->type; + code = tmp->code; + trid = tmp->tid; + + DBG("len[%ld], type[0x%x], code [0x%x], trid[0x%x]\n", + len, type, code, trid); + + if (_hdlr_validate_cmd_container((mtp_byte *)tmp, len) + == FALSE) { + ERR("Cancelling Transaction, invalid header, but last packet"); + } else { /*another command, cancelling is finished*/ + DBG("Cancelling Transaction, Finished."); + } + + _transport_set_control_event(0); + _transport_set_mtp_operation_state(MTP_STATE_ONSERVICE); + if (g_mgr->ftemp_st.fhandle != INVALID_FILE) { + DBG("In Cancel Transaction fclose "); + _util_file_close(g_mgr->ftemp_st.fhandle); + g_mgr->ftemp_st.fhandle = INVALID_FILE; + DBG("In Cancel Transaction, remove "); + if (remove(g_mgr->ftemp_st.filepath) < 0) { + ERR_SECURE("remove(%s) Fail", g_mgr->ftemp_st.filepath); + } + } else { + DBG("g_mgr->ftemp_st.fhandle is not valid, return"); + } + break; + + case PTP_EVENTCODE_DEVICERESET: + DBG("Implement later, PTP_EVENTCODE_DEVICERESET"); + _device_set_phase(DEVICE_PHASE_IDLE); + /* do close session, just skip save reference + * mtp_save_object_references_mtp_device(MtpHandler.pDevice); + */ + g_mgr->hdlr.session_id = 0; + _transport_set_control_event(0); + _transport_set_mtp_operation_state(MTP_STATE_ONSERVICE); + break; + + default: + break; + } +#endif/* MTP_SUPPORT_CONTROL_REQUEST */ + + /* main processing */ + if (_device_get_phase() == DEVICE_PHASE_IDLE) { + if (_hdlr_validate_cmd_container((mtp_uchar *)buffer, buf_len) + == FALSE) { + _device_set_phase(DEVICE_PHASE_NOTREADY); + ERR("MTP device phase NOT READY, invalid Command block"); + return; + } + + _transport_save_cmd_buffer(buffer, buf_len); + _hdlr_copy_cmd_container_unknown_params((cmd_container_t *)buffer, + &cmd); +#ifdef __BIG_ENDIAN__ + _hdlr_conv_cmd_container_byte_order(&cmd); +#endif /* __BIG_ENDIAN__ */ + + UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex); + __process_commands(&g_mtp_mgr.hdlr, &cmd); + UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex); + } else if (_device_get_phase() == DEVICE_PHASE_DATAOUT) { + if (g_mgr->ftemp_st.data_count == 0) + __receive_temp_file_first_packet(buffer, buf_len); + else + __receive_temp_file_next_packets(buffer, buf_len); + return; + } else { + /* ignore other case */ + ERR("MTP device phase[%d], unknown device PHASE\n", + _device_get_phase()); + ERR("PhaseUnknown-> pData[0x%x], length=[%d]", buffer, buf_len); + _device_set_phase(DEVICE_PHASE_IDLE); + _transport_set_mtp_operation_state(MTP_STATE_ONSERVICE); + } + return; +} + +static mtp_bool __receive_temp_file_first_packet(mtp_char *data, + mtp_int32 data_len) +{ + mtp_char *filepath = g_mgr->ftemp_st.filepath; + mtp_uint32 *fhandle = &g_mgr->ftemp_st.fhandle; + mtp_int32 error = 0; + mtp_uint32 *data_sz = &g_mgr->ftemp_st.data_size; + mtp_char *buffer = g_mgr->ftemp_st.temp_buff; + + _transport_set_mtp_operation_state(MTP_STATE_DATA_TRANSFER_DL); + if (access(filepath, F_OK) == 0) { + if (*fhandle != INVALID_FILE) { + _util_file_close(*fhandle); + *fhandle = INVALID_FILE; /* initialize */ + } + + if (remove(filepath) < 0) { + ERR_SECURE("remove(%s) Fail", filepath); + __finish_receiving_file_packets(data, data_len); + return FALSE; + } + } + + *fhandle = _util_file_open(filepath, MTP_FILE_WRITE, &error); + if (*fhandle == INVALID_FILE) { + ERR("First file handle is invalid!!"); + __finish_receiving_file_packets(data, data_len); + return FALSE; + } + /* consider header size */ + memcpy(&g_mgr->ftemp_st.header_buf, data, sizeof(header_container_t)); + + g_mgr->ftemp_st.file_size = ((header_container_t *)data)->len - + sizeof(header_container_t); + *data_sz = data_len - sizeof(header_container_t); + + /* check whether last data packet */ + if (*data_sz == g_mgr->ftemp_st.file_size) { + if (_util_file_write(*fhandle, &data[sizeof(header_container_t)], + data_len - sizeof(header_container_t)) != + data_len - sizeof(header_container_t)) { + ERR("fwrite error!"); + } + *data_sz = 0; + _util_file_close(*fhandle); + *fhandle = INVALID_FILE; /* initialize */ + __finish_receiving_file_packets(data, data_len); + } else { + g_mgr->ftemp_st.data_count++; + g_mgr->ftemp_st.size_remaining = *data_sz; + + memcpy(buffer, data + sizeof(header_container_t), *data_sz); + } + return TRUE; +} + +static mtp_bool __receive_temp_file_next_packets(mtp_char *data, + mtp_int32 data_len) +{ + mtp_uint32 rx_size = _get_rx_pkt_size(); + mtp_uint32 *data_sz = &g_mgr->ftemp_st.data_size; + mtp_char *buffer = g_mgr->ftemp_st.temp_buff; + mtp_uint32 *fhandle = &g_mgr->ftemp_st.fhandle; + + g_mgr->ftemp_st.data_count++; + g_mgr->ftemp_st.size_remaining += data_len; + + if ((*data_sz + (mtp_uint32)data_len) > g_conf.write_file_size) { + /* copy oversized packet to temp file */ + if (_util_file_write(*fhandle, buffer, *data_sz) != *data_sz) + ERR("fwrite error writeSize=[%u]\n", *data_sz); + + *data_sz = 0; + } + + memcpy(&buffer[*data_sz], data, data_len); + *data_sz += data_len; + + /*Complete file is recieved, so close the file*/ + if (data_len < rx_size || + g_mgr->ftemp_st.size_remaining == g_mgr->ftemp_st.file_size) { + + if (_util_file_write(*fhandle, buffer, *data_sz) != *data_sz) { + ERR("fwrite error write size=[%u]\n", *data_sz); + } + *data_sz = 0; + _util_file_close(*fhandle); + *fhandle = INVALID_FILE; /* initialize */ + __finish_receiving_file_packets(data, data_len); + } + return TRUE; +} + +static void __finish_receiving_file_packets(mtp_char *data, mtp_int32 data_len) +{ + cmd_blk_t cmd = { 0 }; + mtp_uchar *cmd_buf = NULL; + + g_mgr->ftemp_st.data_count = 0; + cmd_buf = (mtp_uchar *)data; + + if (!_hdlr_validate_cmd_container(cmd_buf, (mtp_uint32)data_len)) { + cmd_buf = (mtp_uchar *)g_mgr->ftemp_st.cmd_buf; + if (!_hdlr_validate_cmd_container(cmd_buf, + g_mgr->ftemp_st.cmd_size)) { + _device_set_phase(DEVICE_PHASE_IDLE); + ERR("DATA PROCESS, device phase[%d], invalid Command\ + block\n", _device_get_phase()); + return; + } + } + + _transport_set_mtp_operation_state(MTP_STATE_ONSERVICE); + _hdlr_copy_cmd_container_unknown_params((cmd_container_t *)cmd_buf, + &cmd); + +#ifdef __BIG_ENDIAN__ + _hdlr_conv_cmd_container_byte_order(&cmd); +#endif /* __BIG_ENDIAN__ */ + + UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex); + __process_commands(&g_mtp_mgr.hdlr, &cmd); + UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex); + + DBG("MTP device phase[%d], processing Command is complete\n", + _device_get_phase()); + + return; +} diff --git a/src/mtp_cmd_handler_util.c b/src/mtp_cmd_handler_util.c new file mode 100755 index 0000000..5b1b7c5 --- /dev/null +++ b/src/mtp_cmd_handler_util.c @@ -0,0 +1,2418 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <unistd.h> +#include <glib.h> +#include <glib/gprintf.h> +#include "mtp_cmd_handler.h" +#include "mtp_cmd_handler_util.h" +#include "mtp_support.h" +#include "mtp_media_info.h" +#include "mtp_transport.h" + +/* + * GLOBAL AND EXTERN VARIABLES + */ +mtp_bool g_is_full_enum = FALSE; +extern mtp_mgr_t g_mtp_mgr; +extern obj_interdep_proplist_t interdep_proplist; +extern mtp_char g_last_created_dir[MTP_MAX_PATHNAME_SIZE + 1]; +extern mtp_char g_last_moved[MTP_MAX_PATHNAME_SIZE + 1]; +extern mtp_char g_last_copied[MTP_MAX_PATHNAME_SIZE + 1]; +extern mtp_char g_last_deleted[MTP_MAX_PATHNAME_SIZE + 1]; + +/* + * STATIC VARIABLES + */ +static mtp_mgr_t *g_mgr = &g_mtp_mgr; + +/* + * FUNCTIONS + */ + +/* + * This function gets the storage entry. + * @param[in] store_id Specifies the storage id to get. + * @param[in] info Points the storage info structure + * @return This function returns MTP_ERROR_NONE on success or + * ERROR_No on failure. + */ +mtp_err_t _hutil_get_storage_entry(mtp_uint32 store_id, store_info_t *info) +{ + mtp_store_t *store = NULL; + + store = _device_get_store(store_id); + if (store == NULL) { + ERR("Not able to retrieve store"); + return MTP_ERROR_GENERAL; + } + _entity_update_store_info_run_time(&(store->store_info), + store->root_path); + + _prop_copy_ptpstring(&(info->store_desc), &(store->store_info.store_desc)); + _prop_copy_ptpstring(&(info->vol_label), &(store->store_info.vol_label)); + info->access = store->store_info.access; + info->fs_type = store->store_info.fs_type; + info->free_space = store->store_info.free_space; + info->capacity = store->store_info.capacity; + info->store_type = store->store_info.store_type; + info->free_space_in_objs = store->store_info.free_space_in_objs; + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_get_storage_ids(ptp_array_t *store_ids) +{ + mtp_uint32 num_elem = 0; + mtp_uint32 num_stores = 0; + + num_elem = _device_get_store_ids(store_ids); + num_stores = _device_get_num_stores(); + if (num_elem == num_stores) { + return MTP_ERROR_NONE; + } + + ERR("get storage id Fail. num_elem[%d], num_stores[%d]\n", + num_elem, num_stores); + return MTP_ERROR_GENERAL; +} + +/* + * This function gets the device property. + * @param[in] prop_id Specifies the property id to retrieve + * @param[in] dev_prop Points the device prop structure + * @return This function returns MTP_ERROR_NONE on success, + * or ERROR_NO on failure. + */ +mtp_err_t _hutil_get_device_property(mtp_uint32 prop_id, + device_prop_desc_t* dev_prop) +{ + device_prop_desc_t *prop = NULL; + + prop = _device_get_device_property(prop_id); + if (prop == NULL) + return MTP_ERROR_GENERAL; + + memcpy(dev_prop, prop, sizeof(device_prop_desc_t)); + return MTP_ERROR_NONE; +} + +/* + * This function sets the device property. + * @param[in] prop_id Specifies the property id to retrieve. + * @param[in] data Points the associated data buffer. + * @param[in] data_sz Specifies the data size of property. + * @return This function returns MTP_ERROR_NONE on success or + * appropriate error on failure. + */ +mtp_err_t _hutil_set_device_property(mtp_uint32 prop_id, void *data, + mtp_uint32 data_sz) +{ + device_prop_desc_t *prop = NULL; + + prop = _device_get_device_property(prop_id); + if (prop == NULL) + return MTP_ERROR_GENERAL; + + if (prop->propinfo.get_set == PTP_PROPGETSET_GETONLY) + return MTP_ERROR_ACCESS_DENIED; + + if (FALSE == _prop_set_current_device_prop(prop, data, data_sz)) + return MTP_ERROR_INVALID_OBJ_PROP_VALUE; + + return MTP_ERROR_NONE; +} + +/* + * This function resets the device property. + * @param[in] prop_id Specifies the property id to retrieve. + * @return This function returns MTP_ERROR_NONE on success, + * appropriate error on failure. + */ +mtp_err_t _hutil_reset_device_entry(mtp_uint32 prop_id) +{ + device_prop_desc_t *prop = NULL; + mtp_uint16 ii = 0; + + if (prop_id == 0xFFFFFFFF) { + + prop = _device_get_ref_prop_list(); + if (prop == NULL) { + ERR("property reference is NULL"); + return MTP_ERROR_GENERAL; + } + for (ii = 0; ii < NUM_DEVICE_PROPERTIES; ii++) { + _prop_reset_device_prop_desc(&prop[ii]); + } + } else { + prop = _device_get_device_property(prop_id); + if (prop == NULL) + return MTP_ERROR_GENERAL; + + _prop_reset_device_prop_desc(prop); + } + + return MTP_ERROR_NONE; +} + +/* + * This function adds the object entry. + * @param[in] obj_info Points the objectinfo. + * @param[in] file_name Points the file name of the object. + * @param[out] new_obj Points to the new object added. + * @return This function returns MTP_ERROR_NONE on success or + * appropriate error on failure. + */ +mtp_err_t _hutil_add_object_entry(obj_info_t *obj_info, mtp_char *file_name, + mtp_obj_t **new_obj) +{ + mtp_obj_t *obj = NULL; + mtp_obj_t *par_obj = NULL; + mtp_store_t *store = NULL; + mtp_wchar temp_wfname[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char utf8_temp[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char new_f_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_int32 i = 0; + mtp_int32 error; + mtp_bool is_made_by_mtp = FALSE; + mtp_wchar w_file_name[MTP_MAX_FILENAME_SIZE + 1] = { 0 }; + + if (obj_info->h_parent != PTP_OBJECTHANDLE_ROOT) { + par_obj = _device_get_object_with_handle(obj_info->h_parent); + if (par_obj == NULL) { + ERR("parent is not existed."); + _entity_dealloc_obj_info(obj_info); + return MTP_ERROR_INVALID_OBJECTHANDLE; + } + + if (par_obj->obj_info->obj_fmt != PTP_FMT_ASSOCIATION) { + ERR("parent handle is not association format[0x%x]\ + handle[%d]\n", par_obj->obj_info->obj_fmt, + par_obj->obj_info->h_parent); + _entity_dealloc_obj_info(obj_info); + return MTP_ERROR_INVALID_PARENT; + } + } + + store = _device_get_store(obj_info->store_id); + if (store == NULL) { + ERR("store is null"); + _entity_dealloc_obj_info(obj_info); + return MTP_ERROR_GENERAL; + } + + if (store->store_info.free_space < obj_info->file_size) { + ERR("free space is not enough [%ld] bytes, object size[%ld]\n", + store->store_info.free_space, obj_info->file_size); + _entity_dealloc_obj_info(obj_info); + return MTP_ERROR_STORE_FULL; + } + + obj = _entity_alloc_mtp_object(); + if (obj == NULL) { + ERR("allocation memory Fail"); + _entity_dealloc_obj_info(obj_info); + return MTP_ERROR_GENERAL; + } + + memset(obj, 0, sizeof(mtp_obj_t)); + obj->child_array.type = UINT32_TYPE; + obj->obj_handle = _entity_generate_next_obj_handle(); + obj->obj_info = obj_info; + + /* For PC->MMC read-only file/folder transfer + * and for PC->Phone read-only folder transfer + * store PTP_PROTECTIONSTATUS_NOPROTECTION in + * the field obj_info->ProtectionStatus + */ + if (MTP_EXTERNAL_STORE_ID == obj_info->store_id || + obj_info->obj_fmt == PTP_FMT_ASSOCIATION) { + obj_info->protcn_status = PTP_PROTECTIONSTATUS_NOPROTECTION; + } + + if (strlen(file_name) == 0) { + /* Generate a filename in 8.3 format for this object */ + g_snprintf(utf8_temp, MTP_MAX_PATHNAME_SIZE + 1, + "Tmp_%04u.dat", obj->obj_handle); + _util_utf8_to_utf16(temp_wfname, + sizeof(temp_wfname) / WCHAR_SIZ, utf8_temp); + } else { + _util_utf8_to_utf16(temp_wfname, + sizeof(temp_wfname) / WCHAR_SIZ, file_name); + } + + /* Does this path/filename already exist ? */ + for (i = 0; ; i++) { + mtp_bool file_exist = FALSE; + mtp_uint32 path_len = 0; + + /* Get/Generate the Full Path for the new Object; */ + if (obj_info->h_parent == PTP_OBJECTHANDLE_ROOT) { + _util_utf16_to_utf8(utf8_temp, sizeof(utf8_temp), + temp_wfname); + + if (_util_create_path(new_f_path, sizeof(new_f_path), + store->root_path, utf8_temp) == FALSE) { + _entity_dealloc_mtp_obj(obj); + return MTP_ERROR_GENERAL; + } +#ifdef MTP_SUPPORT_HIDE_WMPINFO_XML + /* WMPInfo.xml and DevLogo.fil.*/ + /* find WMPInfo.xml and add file mtp store */ + { + mtp_char wmp_info_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char wmp_hidden_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + + if (obj_info->store_id == MTP_INTERNAL_STORE_ID) { + g_snprintf(wmp_hidden_path, + MTP_MAX_PATHNAME_SIZE + 1, + "%s/%s/%s", MTP_USER_DIRECTORY, + MTP_HIDDEN_PHONE, + MTP_FILE_NAME_WMPINFO_XML); + g_snprintf(wmp_info_path, + MTP_MAX_PATHNAME_SIZE + 1, + "%s/%s", MTP_STORE_PATH_CHAR, + MTP_FILE_NAME_WMPINFO_XML); + } else { + g_snprintf(wmp_hidden_path, + MTP_MAX_PATHNAME_SIZE + 1, + "%s/%s/%s", MTP_USER_DIRECTORY, + MTP_HIDDEN_CARD, + MTP_FILE_NAME_WMPINFO_XML); + g_snprintf(wmp_info_path, + MTP_MAX_PATHNAME_SIZE + 1, + "%s/%s", MTP_EXTERNAL_PATH_CHAR, + MTP_FILE_NAME_WMPINFO_XML); + } + + if (!strcasecmp(wmp_info_path, new_f_path)) { + DBG("substitute file[%s]-->[%s]\n", + wmp_info_path, wmp_hidden_path); + + g_strlcpy(new_f_path, wmp_hidden_path, + sizeof(new_f_path)); + + if (obj_info->store_id == + MTP_INTERNAL_STORE_ID) { + obj->obj_handle = + MTP_MAX_INT_OBJECT_NUM - + MTPSTORE_WMPINFO_PHONE; + } else { + obj->obj_handle = + MTP_MAX_INT_OBJECT_NUM - + MTPSTORE_WMPINFO_CARD; + } + } + } +#endif /*MTP_SUPPORT_HIDE_WMPINFO_XML*/ + } else { + _util_utf16_to_utf8(utf8_temp, sizeof(utf8_temp), + temp_wfname); + if (_util_create_path(new_f_path, sizeof(new_f_path), + par_obj->file_path, utf8_temp) == FALSE) { + _entity_dealloc_mtp_obj(obj); + return MTP_ERROR_GENERAL; + } + } + + /* + * g_mgr->ftemp_st.filepath was allocated g_strdup("/tmp/.mtptemp.tmp"); + * So if we need to change the path we need to allocate sufficient memory + * otherwise memory corruption may happen + */ + + path_len = strlen(store->root_path) + strlen(MTP_TEMP_FILE) + 2; + g_mgr->ftemp_st.filepath = g_realloc(g_mgr->ftemp_st.filepath, path_len); + if (g_mgr->ftemp_st.filepath == NULL) { + ERR("g_realloc Fail"); + _entity_dealloc_mtp_obj(obj); + return MTP_ERROR_GENERAL; + } + + if (_util_create_path(g_mgr->ftemp_st.filepath, path_len, + store->root_path, MTP_TEMP_FILE) == FALSE) { + ERR("Tempfile fullPath is too long"); + _entity_dealloc_mtp_obj(obj); + return MTP_ERROR_GENERAL; + } + + DBG_SECURE("Temp file path [%s]\n", g_mgr->ftemp_st.filepath); + + +#ifdef MTP_SUPPORT_ALBUM_ART + if (access(new_f_path, F_OK) == 0) { + file_exist = TRUE; + /* if file is album, overwrite it. */ + mtp_char alb_buf[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char alb_ext[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + + /* find extension, if album or pla, overwrite that. */ + _util_utf16_to_utf8(alb_buf, sizeof(alb_buf), temp_wfname); + + if (obj_info->obj_fmt != PTP_FMT_ASSOCIATION || + (obj_info->obj_fmt == PTP_FMT_ASSOCIATION && + obj_info->association_type != + PTP_ASSOCIATIONTYPE_UNDEFINED && + obj_info->association_type != + PTP_ASSOCIATIONTYPE_FOLDER)) { + + _util_get_file_extn(alb_buf, alb_ext); + if (!strcasecmp(alb_ext, "alb")) { + if (remove(new_f_path) == 0) { + file_exist = FALSE; + DBG("[%s] file is found. Delete\ + old and make new one\n", + alb_ext); + } else + ERR("[%s] file is found. but \ + cannot delete it\n", + alb_ext); + } + } + } +#endif /*MTP_SUPPORT_ALBUM_ART*/ + + if (file_exist == FALSE) { + DBG_SECURE("Found a unique file name for the incoming object\ + [%s]\n", temp_wfname); + break; + } + +#ifdef MTP_USE_SELFMAKE_ABSTRACTION + is_made_by_mtp = obj_info->file_size == 0 && + obj_info->obj_fmt > MTP_FMT_UNDEFINED_COLLECTION && + obj_info->obj_fmt < MTP_FMT_UNDEFINED_DOC; +#endif /*MTP_USE_SELFMAKE_ABSTRACTION*/ + if (obj_info->obj_fmt == PTP_FMT_ASSOCIATION || + is_made_by_mtp) { + *new_obj = _device_get_object_with_path(new_f_path); + if (*new_obj) { + _entity_dealloc_mtp_obj(obj); + return MTP_ERROR_NONE; + } else { + DBG("+ not found object. [%s]\n", new_f_path); + break; + } + } + + /* Rename the Filename for this object */ + memset(temp_wfname, 0, (MTP_MAX_PATHNAME_SIZE + 1) * 2); + _util_utf8_to_utf16(w_file_name, sizeof(w_file_name) / WCHAR_SIZ, + file_name); + _util_wchar_swprintf(temp_wfname, + MTP_MAX_PATHNAME_SIZE + 1, "COPY%d_%s", i, w_file_name); + } + + /* Save the full path to this object */ + _entity_set_object_file_path(obj, new_f_path, CHAR_TYPE); + + /* + * Is this an association (or folder)? + * Associations are fully qualified by the ObjectInfo Dataset. + */ +#ifdef MTP_USE_SELFMAKE_ABSTRACTION + is_made_by_mtp = (obj_info->file_size == 0 && + obj_info->obj_fmt > MTP_FMT_UNDEFINED_COLLECTION && + obj_info->obj_fmt < MTP_FMT_UNDEFINED_DOC); +#endif /*MTP_USE_SELFMAKE_ABSTRACTION*/ + + if (obj_info->obj_fmt == PTP_FMT_ASSOCIATION || is_made_by_mtp) { + /* Create the new object */ + DBG("[normal] create association file/folder[%s][0x%x]\n", + new_f_path, obj_info->association_type); + + if ((obj_info->association_type != + PTP_ASSOCIATIONTYPE_UNDEFINED && + obj_info->association_type != + PTP_ASSOCIATIONTYPE_FOLDER) || + is_made_by_mtp) { + mtp_uint32 h_abs_file = INVALID_FILE; + h_abs_file = _util_file_open(new_f_path, + MTP_FILE_WRITE, &error); + if (h_abs_file == INVALID_FILE) { + ERR("create file fail!!"); + _entity_dealloc_mtp_obj(obj); + return MTP_ERROR_GENERAL; + } + _util_file_close(h_abs_file); + } else { + g_snprintf(g_last_created_dir, + MTP_MAX_PATHNAME_SIZE + 1, "%s", new_f_path); + if (_util_dir_create(new_f_path, &error) == FALSE) { + /* We failed to create the folder */ + ERR("create directory Fail"); + memset(g_last_created_dir, 0, + sizeof(g_last_created_dir)); + _entity_dealloc_mtp_obj(obj); + return MTP_ERROR_GENERAL; + } + } + + _entity_set_object_file_path(obj, new_f_path, CHAR_TYPE); + if (_entity_add_object_to_store(store, obj) == FALSE) { + ERR("_entity_add_object_to_store Fail"); + _entity_dealloc_mtp_obj(obj); + return MTP_ERROR_STORE_FULL; + } + } else { + /* Reserve space for the object: Object itself, and probably + * some Filesystem-specific overhead + */ + store->store_info.free_space -= obj_info->file_size; + } + + *new_obj = obj; + + return MTP_ERROR_NONE; +} + +/* + * This function removes the object entry. + * @param[in] obj_handle Specifies the object to remove. + * @param[in] format Specifies the format code. + * @return This function returns MTP_ERROR_NONE on success or + * appropriate error on failure. + */ +mtp_err_t _hutil_remove_object_entry(mtp_uint32 obj_handle, mtp_uint32 format) +{ + mtp_err_t resp = MTP_ERROR_GENERAL; + mtp_uint16 ret = 0; + +#ifdef MTP_SUPPORT_SET_PROTECTION + /* this will check to see if the protection is set */ + mtp_obj_t *obj = NULL; + if (obj_handle != 0xFFFFFFFF) { + obj = _device_get_object_with_handle(obj_handle); + if (obj != NULL) { + if ((obj->obj_info->protcn_status == + MTP_PROTECTIONSTATUS_READONLY_DATA) || + (obj->obj_info->protcn_status == + PTP_PROTECTIONSTATUS_READONLY)) { + ERR("Protection status is [0x%x]\n", + obj->obj_info->protcn_status); + return MTP_ERROR_OBJECT_WRITE_PROTECTED; + } + } + } +#endif /*MTP_SUPPORT_SET_PROTECTION*/ + + ret = _device_delete_object(obj_handle, format); + switch (ret) { + case PTP_RESPONSE_OK: + resp = MTP_ERROR_NONE; + break; + case PTP_RESPONSE_STORE_READONLY: + resp = MTP_ERROR_STORE_READ_ONLY; + break; + case PTP_RESPONSE_PARTIAL_DELETION: + resp = MTP_ERROR_PARTIAL_DELETION; + break; + case PTP_RESPONSE_OBJ_WRITEPROTECTED: + resp = MTP_ERROR_OBJECT_WRITE_PROTECTED; + break; + case PTP_RESPONSE_ACCESSDENIED: + resp = MTP_ERROR_ACCESS_DENIED; + break; + case PTP_RESPONSE_INVALID_OBJ_HANDLE: + resp =MTP_ERROR_INVALID_OBJECTHANDLE; + break; + default: + break; + } + + return resp; +} + +/* + * This function gets the object entry. + * @param[in] obj_handle Specifies the object to get. + * @param[out] obj_ptr Points to object found. + * @return This function returns MTP_ERROR_NONE on success + * or appropriate error on failure. + */ +mtp_err_t _hutil_get_object_entry(mtp_uint32 obj_handle, mtp_obj_t **obj_ptr) +{ + mtp_obj_t *obj = NULL; + + obj = _device_get_object_with_handle(obj_handle); + if (NULL == obj || NULL == obj->obj_info) { + return MTP_ERROR_GENERAL; + } + + *obj_ptr = obj; + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_copy_object_entries(mtp_uint32 dst_store_id, + mtp_uint32 src_store_id, mtp_uint32 h_parent, mtp_uint32 obj_handle, + mtp_uint32 *new_hobj, mtp_bool keep_handle) +{ + mtp_store_t *dst = NULL; + mtp_store_t *src = NULL; + mtp_obj_t *obj = NULL; + mtp_obj_t *par_obj = NULL; + mtp_obj_t *new_obj = NULL; + mtp_int32 error = 0; + mtp_char fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char utf8_temp[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_err_t ret = MTP_ERROR_NONE; + mtp_uint32 num_of_deleted_file = 0; + mtp_uint32 num_of_file = 0; + ptp_array_t child_arr = { 0 }; + mtp_obj_t *child_obj = NULL; + mtp_uint32 ii = 0; + + src = _device_get_store(src_store_id); + dst = _device_get_store(dst_store_id); + obj = _device_get_object_with_handle(obj_handle); + + if ((src == NULL) || (dst == NULL) || (obj == NULL)) { + ERR("NULL!!"); + return MTP_ERROR_GENERAL; + } + + if (h_parent > 0) { + if (keep_handle) { + /* two sam handle can occurs in folder copy case + * (find last appended object in target storage) + */ + par_obj = _entity_get_last_object_from_store(dst, + h_parent); + } else + par_obj = _device_get_object_with_handle(h_parent); + } else { + par_obj = NULL; + } + + _util_get_file_name(obj->file_path, utf8_temp); + + if (par_obj == NULL) { + /* Parent is the root of this store */ + if (_util_create_path(fpath, sizeof(fpath), dst->root_path, + utf8_temp) == FALSE) { + ERR("new path is too LONG"); + return MTP_ERROR_GENERAL; + } + } else { + if (_util_create_path(fpath, sizeof(fpath), par_obj->file_path, + utf8_temp) == FALSE) { + ERR("New path is too LONG!!"); + return MTP_ERROR_GENERAL; + } + } + + if (!strcasecmp(fpath, obj->file_path)) { + ERR("Identical path of source and destination[%s]\n", fpath); + return MTP_ERROR_GENERAL; + } + + new_obj = _entity_alloc_mtp_object(); + if (new_obj == NULL) { + ERR("_entity_alloc_mtp_object Fail"); + return MTP_ERROR_GENERAL; + } + + memset(new_obj, 0, sizeof(mtp_obj_t)); + new_obj->child_array.type = UINT32_TYPE; + + _entity_copy_mtp_object(new_obj, obj); + if (new_obj->obj_info == NULL) { + _entity_dealloc_mtp_obj(new_obj); + return MTP_ERROR_GENERAL; + } + + new_obj->obj_info->store_id = dst_store_id; + _entity_set_object_file_path(new_obj, fpath, CHAR_TYPE); + + if (MTP_EXTERNAL_STORE_ID == new_obj->obj_info->store_id) { + new_obj->obj_info->protcn_status = + PTP_PROTECTIONSTATUS_NOPROTECTION; + } + + new_obj->obj_handle = (keep_handle) ? obj->obj_handle : + _entity_generate_next_obj_handle(); + new_obj->obj_info->h_parent = (par_obj == NULL) ? PTP_OBJECTHANDLE_ROOT : + par_obj->obj_handle; + + if (new_obj->obj_info->obj_fmt != PTP_FMT_ASSOCIATION) { + DBG("Non-association type!!"); + g_snprintf(g_last_copied, MTP_MAX_PATHNAME_SIZE + 1, "%s", + new_obj->file_path); + if (_util_file_copy(obj->file_path, new_obj->file_path, + &error) == FALSE) { + memset(g_last_copied, 0, MTP_MAX_PATHNAME_SIZE + 1); + ERR("Copy file Fail"); + _entity_dealloc_mtp_obj(new_obj); + if (EACCES == error) + return MTP_ERROR_ACCESS_DENIED; + else if (ENOSPC == error) + return MTP_ERROR_STORE_FULL; + return MTP_ERROR_GENERAL; + + } +#ifdef MTP_SUPPORT_SET_PROTECTION + file_attr_t attr = { 0 }; + attr.attribute = MTP_FILE_ATTR_MODE_REG; + if (PTP_PROTECTIONSTATUS_READONLY == + new_obj->obj_info->protcn_status) { + if (FALSE == _util_set_file_attrs(new_obj->file_path, + attr.attribute | MTP_FILE_ATTR_MODE_READ_ONLY)) + return MTP_ERROR_GENERAL; + } +#endif /* MTP_SUPPORT_SET_PROTECTION */ + + /* Update the storeinfo after successfully copy of the object */ + dst->store_info.free_space -= obj->obj_info->file_size; + + /* move case */ + if (keep_handle) { + _entity_add_object_to_store(dst, new_obj); + /* Reference Copy */ + _prop_copy_ptparray(&(new_obj->child_array), + &(obj->child_array)); + } else { + _entity_add_object_to_store(dst, new_obj); + } + + *new_hobj = new_obj->obj_handle; + return MTP_ERROR_NONE; + } + + DBG("Association type!!"); + if (access(new_obj->file_path, F_OK) == 0) { + if (TRUE == keep_handle) { + /*generate unique_path*/ + mtp_char unique_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + if (FALSE == _util_get_unique_dir_path(new_obj->file_path, + unique_fpath, sizeof(unique_fpath))) { + _entity_dealloc_mtp_obj(new_obj); + return MTP_ERROR_GENERAL; + } + _entity_set_object_file_path(new_obj, unique_fpath, CHAR_TYPE); + g_snprintf(g_last_created_dir, MTP_MAX_PATHNAME_SIZE + 1, + "%s", new_obj->file_path); + if (_util_dir_create(new_obj->file_path, &error) == FALSE) { + memset(g_last_created_dir, 0, + MTP_MAX_PATHNAME_SIZE + 1); + ERR("Creating folder Fail!!"); + _entity_dealloc_mtp_obj(new_obj); + if (ENOSPC == error) + return MTP_ERROR_STORE_FULL; + return MTP_ERROR_GENERAL; + } + + /* Add the new object to this store's object list */ + _entity_add_object_to_store(dst, new_obj); + } else { + DBG("Already existed association type!!"); + _entity_dealloc_mtp_obj(new_obj); + new_obj = _entity_get_object_from_store_by_path(dst, fpath); + if (!new_obj) { + ERR("But object is not registered!!"); + return MTP_ERROR_GENERAL; + } + } + } else { + g_snprintf(g_last_created_dir, MTP_MAX_PATHNAME_SIZE + 1, + "%s", new_obj->file_path); + if (_util_dir_create(new_obj->file_path, &error) == FALSE) { + memset(g_last_created_dir, 0, + MTP_MAX_PATHNAME_SIZE + 1); + ERR("Creating folder Fail!!"); + _entity_dealloc_mtp_obj(new_obj); + if (ENOSPC == error) + return MTP_ERROR_STORE_FULL; + return MTP_ERROR_GENERAL; + } + + /* Add the new object to this store's object list */ + _entity_add_object_to_store(dst, new_obj); + } + + /* Child addition to data structures is not required in Copy + * case as on demand enumeration is supported + */ + if (FALSE == keep_handle) { + if (FALSE == _util_copy_dir_children_recursive(obj->file_path, + new_obj->file_path, &error)) { + ERR_SECURE("Recursive copy Fail [%s]->[%s]", + obj->file_path, new_obj->file_path); + ret = MTP_ERROR_GENERAL; + if (EACCES == error) + ret = MTP_ERROR_ACCESS_DENIED; + else if (ENOSPC == error) + ret = MTP_ERROR_STORE_FULL; + if (_util_remove_dir_children_recursive(new_obj->file_path, + &num_of_deleted_file, &num_of_file, + FALSE) == MTP_ERROR_NONE) { + g_snprintf(g_last_deleted, + MTP_MAX_PATHNAME_SIZE + 1, + "%s", new_obj->file_path); + if (rmdir(new_obj->file_path) < 0) { + memset(g_last_deleted, 0, + MTP_MAX_PATHNAME_SIZE + 1); + } + } + return ret; + } + + *new_hobj = new_obj->obj_handle; + + return MTP_ERROR_NONE; + } + + + /* Since this is an association, copy its children as well*/ + _prop_init_ptparray(&child_arr, UINT32_TYPE); + _entity_get_child_handles(src, obj->obj_handle, &child_arr); + + for (ii = 0; ii < child_arr.num_ele; ii++) { + mtp_uint32 *ptr32 = child_arr.array_entry; + + child_obj = _entity_get_object_from_store(src, ptr32[ii]); + if (child_obj == NULL) { + continue; + } + + ret = _hutil_copy_object_entries(dst_store_id, src_store_id, + new_obj->obj_handle, child_obj->obj_handle, + new_hobj, keep_handle); + if (ret != MTP_ERROR_NONE) { + ERR("Copy file Fail"); + _prop_deinit_ptparray(&child_arr); + return ret; + } + } + + /* Recursive copy is required when folder is not enumerated so it may + * return 0 child handles + */ + if (!((child_arr.num_ele > 0) || + _util_copy_dir_children_recursive(obj->file_path, + new_obj->file_path, &error))) { + ERR_SECURE("Recursive copy Fail [%d], [%s]->[%s]", + child_arr.num_ele, + obj->file_path, new_obj->file_path); + _prop_deinit_ptparray(&child_arr); + if (_util_remove_dir_children_recursive(new_obj->file_path, + &num_of_deleted_file, &num_of_file, FALSE) == + MTP_ERROR_NONE) { + g_snprintf(g_last_deleted, MTP_MAX_PATHNAME_SIZE + 1, + "%s", new_obj->file_path); + if (rmdir(new_obj->file_path) < 0) { + memset(g_last_deleted, 0, + MTP_MAX_PATHNAME_SIZE + 1); + } + } + if (error == ENOSPC) + return MTP_ERROR_STORE_FULL; + return MTP_ERROR_GENERAL; + } + + _prop_deinit_ptparray(&child_arr); + *new_hobj = new_obj->obj_handle; + + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_move_object_entry(mtp_uint32 dst_store_id, mtp_uint32 h_parent, + mtp_uint32 obj_handle) +{ + mtp_store_t *src = NULL; + mtp_store_t *dst = NULL; + mtp_obj_t *obj = NULL; + mtp_obj_t *par_obj = NULL; + mtp_char str_buf[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char utf8_temp[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_uint32 new_handle = 0; + mtp_int32 error = 0; + mtp_err_t ret = MTP_ERROR_NONE; + + obj = _device_get_object_with_handle(obj_handle); + if (NULL == obj) { + ERR("object is [%p]\n", obj); + return MTP_ERROR_INVALID_OBJECTHANDLE; + } + if (NULL == obj->obj_info) { + ERR("obj_info is [%p]\n", obj->obj_info); + return MTP_ERROR_GENERAL; + } + + src = _device_get_store_containing_obj(obj_handle); + if (src == NULL) { + ERR("error retrieving source store"); + return MTP_ERROR_STORE_NOT_AVAILABLE; + } + + if (src->store_info.access == PTP_STORAGEACCESS_R) { + ERR("Store access is read only"); + return MTP_ERROR_STORE_READ_ONLY; + } + + dst = _device_get_store(dst_store_id); + if (dst == NULL) { + ERR("error retrieving destination store"); + return MTP_ERROR_STORE_NOT_AVAILABLE; + } + + if (dst->store_info.access != PTP_STORAGEACCESS_RWD) { + ERR("Write permission not there on target store"); + return MTP_ERROR_STORE_READ_ONLY; + } + + /* Get the Parent Object Handle */ + if (h_parent > 0) { + par_obj = _device_get_object_with_handle(h_parent); + + if (par_obj == NULL || par_obj->obj_info == NULL) { + ERR("par_obj[%p] or par_obj->obj_info is NULL\n", par_obj); + return MTP_ERROR_INVALID_PARENT; + } else if (PTP_FMT_ASSOCIATION != par_obj->obj_info->obj_fmt) { + ERR("par obj fmt = [0x%x]\n", par_obj->obj_info->obj_fmt); + return MTP_ERROR_INVALID_PARENT; + } + + if (dst != _device_get_store_containing_obj(h_parent)) { + ERR("parent is not on the destination store"); + return MTP_ERROR_INVALID_PARENT; + } + + /* Parent must not be a descendant of the object to be moved */ + if (dst->store_id == src->store_id) { + if (_entity_check_if_B_parent_of_A(dst, h_parent, + obj_handle)) + return MTP_ERROR_INVALID_PARAM; + } + } else { + par_obj = NULL; /* Parent is the root */ + } + + /* Check if the source store is the target store */ + if (dst->store_id == src->store_id) { + + mtp_obj_t *old_par = NULL; + mtp_char new_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char dst_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char *parent_path = NULL; + + DBG("same storage , type[0x%x]\n", + obj->obj_info->association_type); + _util_get_file_name(obj->file_path, utf8_temp); + + if (par_obj == NULL) + parent_path = dst->root_path; + else + parent_path = par_obj->file_path; + + if (_util_create_path(dst_fpath, sizeof(dst_fpath), parent_path, + utf8_temp) == FALSE) { + ERR("dst path is too LONG!!"); + return MTP_ERROR_GENERAL; + } + + /* Do a real "Move" for the object in the same store: no need to + * check space available + */ + g_strlcpy(str_buf, obj->file_path, sizeof(str_buf)); + + if (obj->obj_info != NULL && obj->obj_info->obj_fmt == + PTP_FMT_ASSOCIATION) { + + if (access(dst_fpath, F_OK) == 0) { + if (FALSE == _util_get_unique_dir_path(dst_fpath, + new_fpath, sizeof(new_fpath))) { + return MTP_ERROR_GENERAL; + } + } else { + g_strlcpy(new_fpath, dst_fpath, sizeof(new_fpath)); + } + + g_snprintf(g_last_moved, MTP_MAX_PATHNAME_SIZE + 1, + "%s", str_buf); + if (rename(str_buf, new_fpath) < 0) { + /* Failed to move the object */ + error = errno; + memset(g_last_moved, 0, + MTP_MAX_PATHNAME_SIZE + 1); + ERR_SECURE("Directory rename fail in same storage\ + [%s]->[%s]\n", str_buf, new_fpath); + if (EACCES == error) + return MTP_ERROR_ACCESS_DENIED; + else if (ENOSPC == error) + return MTP_ERROR_STORE_FULL; + return MTP_ERROR_GENERAL; + } + + _util_scan_folder_contents_in_db(str_buf); + _entity_set_object_file_path(obj, new_fpath, CHAR_TYPE); + _entity_set_child_object_path(obj, str_buf, new_fpath); + _util_scan_folder_contents_in_db(new_fpath); + } else { + g_snprintf(g_last_moved, MTP_MAX_PATHNAME_SIZE + 1, + "%s", str_buf); + if (FALSE == _util_file_move(str_buf, dst_fpath, + &error)) { + /* Failed to move the object */ + memset(g_last_moved, 0, + MTP_MAX_PATHNAME_SIZE + 1); + ERR("move file Fail in same storage\ + [%s]->[%s]\n", str_buf, dst_fpath); + if (EACCES == error) + return MTP_ERROR_ACCESS_DENIED; + else if (ENOSPC == error) + return MTP_ERROR_STORE_FULL; + return MTP_ERROR_GENERAL; + } + + _util_delete_file_from_db(obj->file_path); + _entity_set_object_file_path(obj, dst_fpath, CHAR_TYPE); + _util_add_file_to_db(obj->file_path); + } + + if (obj->obj_info->h_parent != PTP_OBJECTHANDLE_ROOT) { + old_par = _entity_get_object_from_store(src, + obj->obj_info->h_parent); + if (old_par) { + _entity_remove_reference_child_array(old_par, + obj->obj_handle); + } + } + + if (par_obj != NULL) { + obj->obj_info->h_parent = par_obj->obj_handle; + _entity_add_reference_child_array(par_obj, + obj->obj_handle); + } else { + obj->obj_info->h_parent = PTP_OBJECTHANDLE_ROOT; + } + + return MTP_ERROR_NONE; + } else { + /* Move is called between two stores */ + /* Calculate the space required for the new object(s) */ + mtp_obj_t *new_obj = NULL; + DBG("Different storage or a folder, type[0x%x]\n", + obj->obj_info->association_type); + + /* Simulate a Move operation: First copy the Object, + * then remove the old object + */ + ret = _hutil_copy_object_entries(dst->store_id, src->store_id, + (par_obj == NULL) ? 0 : (par_obj->obj_handle), + obj->obj_handle, &new_handle, TRUE); + if (ret != MTP_ERROR_NONE) { + _entity_delete_obj_mtp_store(dst, obj->obj_handle, + PTP_FORMATCODE_NOTUSED, FALSE); + return ret; + } + + _entity_delete_obj_mtp_store(src, obj->obj_handle, + PTP_FORMATCODE_NOTUSED, FALSE); + new_obj = _device_get_object_with_handle(new_handle); + if (NULL == new_obj || NULL == new_obj->obj_info) + return MTP_ERROR_GENERAL; + + if (new_obj->obj_info->obj_fmt == PTP_FMT_ASSOCIATION) + _util_scan_folder_contents_in_db(new_obj->file_path); + else + _util_add_file_to_db(new_obj->file_path); + + return MTP_ERROR_NONE; + } + return MTP_ERROR_GENERAL; +} + +mtp_err_t _hutil_duplicate_object_entry(mtp_uint32 dst_store_id, + mtp_uint32 h_parent, mtp_uint32 obj_handle, mtp_uint32 *new_handle) +{ + mtp_store_t *src = NULL; + mtp_store_t *dst = NULL; + mtp_obj_t *obj = NULL; + mtp_obj_t *par_obj = NULL; + mtp_obj_t *new_obj = NULL; + mtp_uint32 space_req = 0; + mtp_err_t ret = MTP_ERROR_NONE; + + obj = _device_get_object_with_handle(obj_handle); + if (NULL == obj) { + ERR("Object not found"); + return MTP_ERROR_INVALID_OBJECTHANDLE; + } + + src = _device_get_store_containing_obj(obj_handle); + if (NULL == src) { + ERR("Source store not found"); + return MTP_ERROR_STORE_NOT_AVAILABLE; + } + + dst = _device_get_store(dst_store_id); + if (NULL == dst) { + ERR("Destination store not found"); + return MTP_ERROR_STORE_NOT_AVAILABLE; + } + + if (dst->store_info.access != PTP_STORAGEACCESS_RWD) { + ERR("Store is read only"); + return MTP_ERROR_STORE_READ_ONLY; + } + + if (h_parent > 0) { + par_obj = _device_get_object_with_handle(h_parent); + if ((par_obj == NULL) || (par_obj->obj_info->obj_fmt != + PTP_FMT_ASSOCIATION)) + return MTP_ERROR_INVALID_PARENT; + + if (dst != _device_get_store_containing_obj(h_parent)) + return MTP_ERROR_INVALID_PARENT; + + if (dst->store_id == src->store_id) { + if (_entity_check_if_B_parent_of_A(dst, h_parent, + obj_handle)) + return MTP_ERROR_INVALID_PARENT; + } + } else + par_obj = NULL; + + space_req = _entity_get_object_tree_size(src, obj); + if (dst->store_info.free_space < space_req) { + ERR("Insufficient free space"); + return MTP_ERROR_STORE_FULL; + } + + if((ret = _hutil_copy_object_entries(dst_store_id, src->store_id, + h_parent, obj_handle, new_handle, FALSE)) != MTP_ERROR_NONE) { + return ret; + } + /* + * After this command, Initiator will ask get object prop list (0x9805). + * update the media DB. + */ + new_obj = _device_get_object_with_handle(*new_handle); + if (NULL == new_obj || NULL == new_obj->obj_info) { + ERR("new obj or info is NULL"); + return MTP_ERROR_GENERAL; + } + + if (new_obj->obj_info->obj_fmt == PTP_FMT_ASSOCIATION) { + _util_scan_folder_contents_in_db(new_obj->file_path); + } else { + _util_add_file_to_db(new_obj->file_path); + } + + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_read_file_data_from_offset(mtp_uint32 obj_handle, off_t offset, + void *data, mtp_uint32 *data_sz) +{ + mtp_obj_t *obj = NULL; + mtp_uint32 h_file = INVALID_FILE; + mtp_int32 error = 0; + mtp_char fname[MTP_MAX_PATHNAME_SIZE + 1]; + off_t result = 0; + mtp_uint32 num_bytes; + + obj = _device_get_object_with_handle(obj_handle); + if (obj == NULL) { + ERR("_device_get_object_with_handle returned NULL object"); + return MTP_ERROR_INVALID_OBJECTHANDLE; + } + + if (obj->obj_info->protcn_status == + MTP_PROTECTIONSTATUS_NONTRANSFERABLE_DATA) { + + ERR("protection data, NONTRANSFERABLE_OBJECT"); + return MTP_ERROR_GENERAL; + } + + g_strlcpy(fname, obj->file_path, MTP_MAX_PATHNAME_SIZE + 1); + h_file = _util_file_open(fname, MTP_FILE_READ, &error); + if (h_file == INVALID_FILE) { + ERR("file open Fail[%s]\n", fname); + return MTP_ERROR_GENERAL; + } + + result = _util_file_seek(h_file, offset, SEEK_SET); + if (result < 0) { + ERR("file seek Fail [%d]\n", errno); + _util_file_close(h_file); + return MTP_ERROR_GENERAL; + } + + num_bytes = *data_sz; + _util_file_read(h_file, data, *data_sz, data_sz); + + if (num_bytes != *data_sz) { + ERR("requested[%d] and read[%d] number of bytes do not match\n", + *data_sz, num_bytes); + _util_file_close(h_file); + return MTP_ERROR_GENERAL; + } + + _util_file_close(h_file); + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_write_file_data(mtp_uint32 store_id, mtp_obj_t *obj, + mtp_char *fpath) +{ + mtp_store_t *store; + mtp_char fname[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; +#ifdef MTP_SUPPORT_DELETE_MEDIA_ALBUM_FILE + mtp_char extn[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; +#endif /*MTP_SUPPORT_DELETE_MEDIA_ALBUM_FILE*/ + mtp_int32 error = 0; + + retv_if(obj == NULL, MTP_ERROR_INVALID_PARAM); + retv_if(obj->obj_info == NULL, MTP_ERROR_INVALID_PARAM); + + store = _device_get_store(store_id); + if (store == NULL) { + ERR("destination store is not valid"); + return MTP_ERROR_INVALID_OBJECT_INFO; + } + + g_strlcpy(fname, obj->file_path, MTP_MAX_PATHNAME_SIZE + 1); + if (access(fpath, F_OK) < 0) { + ERR("temp file does not exist"); + return MTP_ERROR_GENERAL; + } + +#ifdef MTP_SUPPORT_DELETE_MEDIA_ALBUM_FILE + /* in case of alb extension, does not make real file just skip below */ + if (obj_info->obj_fmt != PTP_FMT_ASSOCIATION || + (obj_info->obj_fmt == PTP_FMT_ASSOCIATION && + obj_info->association_type != PTP_ASSOCIATIONTYPE_UNDEFINED && + obj_info->association_type != PTP_ASSOCIATIONTYPE_FOLDER)) { + + _util_get_file_extn(fname, extn); + if (strlen(extn) && !strcasecmp(extn, "alb")) { + DBG("No need to create album file"); + remove(fpath, &error); + return MTP_ERROR_NONE; + } + } +#endif /*MTP_SUPPORT_DELETE_MEDIA_ALBUM_FILE*/ + + g_snprintf(g_last_moved, MTP_MAX_PATHNAME_SIZE + 1, "%s", fpath); + if (FALSE == _util_file_move(fpath, fname, &error)) { + memset(g_last_moved, 0, MTP_MAX_PATHNAME_SIZE + 1); + ERR("move to real file fail [%s]->[%s] \n", fpath, fname); + _entity_dealloc_mtp_obj(obj); + + return MTP_ERROR_STORE_FULL; + } + +#ifdef MTP_SUPPORT_SET_PROTECTION + if ((obj_info->protcn_status == PTP_PROTECTIONSTATUS_READONLY) || + (obj_info->ProtectionStatus == + MTP_PROTECTIONSTATUS_READONLY_DATA)) { + file_attr_t attrs; + if (_util_get_file_attrs(fname, &attrs) == FALSE) { + ERR("real file get attributes Fail"); + _entity_dealloc_mtp_obj(obj); + return MTP_ERROR_GENERAL; + } + _util_set_file_attrs(fname, attrs.attribute | + MTP_FILE_ATTR_MODE_READ_ONLY); + } +#endif /* MTP_SUPPORT_SET_PROTECTION */ + + _util_add_file_to_db(obj->file_path); + +#ifndef MTP_USE_RUNTIME_GETOBJECTPROPVALUE + if (updatePropertyValuesMtpObject(obj) == FALSE) { + ERR("update property values mtp obj Fail"); + _entity_dealloc_mtp_obj(obj); + return MTP_ERROR_GENERAL; + } +#endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/ + + _entity_add_object_to_store(store, obj); + + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_get_object_entry_size(mtp_uint32 obj_handle, + mtp_uint64 *obj_sz) +{ + mtp_obj_t *obj = NULL; + + obj = _device_get_object_with_handle(obj_handle); + if (obj == NULL) { + ERR("_device_get_object_with_handle returned Null object"); + return MTP_ERROR_INVALID_OBJECTHANDLE; + } + + *obj_sz = obj->obj_info->file_size; + return MTP_ERROR_NONE; +} + +#ifdef MTP_SUPPORT_SET_PROTECTION +mtp_err_t _hutil_set_protection(mtp_uint32 obj_handle, mtp_uint16 prot_status) +{ + mtp_obj_t *obj = NULL; + mtp_char fname[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + file_attr_t attrs = { 0 }; + + obj = _device_get_object_with_handle(obj_handle); + if (obj == NULL) + return MTP_ERROR_INVALID_OBJECTHANDLE; + + if (MTP_EXTERNAL_STORE_ID == obj->obj_info->store_id) { + ERR("Storage is external"); + return MTP_ERROR_OPERATION_NOT_SUPPORTED; + } + + g_strlcpy(fname, obj->file_path, MTP_MAX_PATHNAME_SIZE + 1); + obj->obj_info->protcn_status = prot_status; + + if (FALSE == _util_get_file_attrs(fname, &attrs)) { + ERR("Failed to get file[%s] attrs\n", fname); + return MTP_ERROR_GENERAL; + } + + if (MTP_FILE_ATTR_MODE_NONE == attrs.attribute) { + return MTP_ERROR_GENERAL; + } + + if (prot_status == PTP_PROTECTIONSTATUS_READONLY) { + attrs.attribute |= MTP_FILE_ATTR_MODE_READ_ONLY; + } else { + attrs.attribute &= ~MTP_FILE_ATTR_MODE_READ_ONLY; + } + + if (FALSE == _util_set_file_attrs(fname, attrs.attribute)) { + ERR("Failed to set file[%s] attrs\n", fname); + return MTP_ERROR_GENERAL; + } + + return MTP_ERROR_NONE; +} +#endif /* MTP_SUPPORT_SET_PROTECTION */ + +mtp_err_t _hutil_get_num_objects(mtp_uint32 store_id, mtp_uint32 h_parent, + mtp_uint32 format, mtp_uint32 *num_obj) +{ + mtp_store_t *store = NULL; + mtp_obj_t *obj = NULL; + mtp_int32 i = 0; + mtp_uint32 numobj = 0; + + *num_obj = 0; + if (store_id != PTP_STORAGEID_ALL) { + store = _device_get_store(store_id); + if (store == NULL) { + ERR("specific store is null"); + return MTP_ERROR_INVALID_STORE; + } + } + + if (!h_parent) { + if (!format) { + *num_obj = _device_get_num_objects(store_id); + } else { + *num_obj = _device_get_num_objects_with_format(store_id, + format); + } + return MTP_ERROR_NONE; + } + + /* return the number of direct children for a particular association + * (in a single store) + */ + if (h_parent == PTP_OBJECTHANDLE_ALL) { + + h_parent = PTP_OBJECTHANDLE_ROOT; + if (store_id == PTP_STORAGEID_ALL) { + for (i = (_device_get_num_stores() - 1); i >= 0; i--) { + store = _device_get_store_at_index(i); + if (store == NULL) { + ERR("Store is null"); + return MTP_ERROR_STORE_NOT_AVAILABLE; + } + numobj += _entity_get_num_children(store, + h_parent, format); + } + *num_obj = numobj; + + return MTP_ERROR_NONE; + } + } else { + /* Initiator wants number of children of a particular association */ + obj = _device_get_object_with_handle(h_parent); + if (obj == NULL) { + ERR("obj is null"); + return MTP_ERROR_INVALID_OBJECTHANDLE; + } + + if (obj->obj_info->obj_fmt != PTP_FMT_ASSOCIATION) { + ERR("format is not association"); + return MTP_ERROR_INVALID_PARENT; + } + + store = _device_get_store_containing_obj(h_parent); + } + + if (store == NULL) { + ERR("store is null"); + return MTP_ERROR_STORE_NOT_AVAILABLE; + } + + *num_obj = _entity_get_num_children(store, h_parent, format); + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_get_object_handles(mtp_uint32 store_id, mtp_uint32 format, + mtp_uint32 h_parent, ptp_array_t *handle_arr) +{ + mtp_store_t *store = NULL; + mtp_int32 i = 0; + + if (h_parent == PTP_OBJECTHANDLE_ALL || h_parent == PTP_OBJECTHANDLE_ROOT) { + for (i = 0; i < _device_get_num_stores(); i++) { + store = _device_get_store_at_index(i); + if (store && store->obj_list.nnodes == 0) + _entity_store_recursive_enum_folder_objects(store, NULL); + } + g_is_full_enum = TRUE; + } + + if (store_id == PTP_STORAGEID_ALL && h_parent == PTP_OBJECTHANDLE_ROOT) { + for (i = 0; i < _device_get_num_stores(); i++) { + store = _device_get_store_at_index(i); + _entity_get_objects_from_store_by_format(store, format, handle_arr); + } + return MTP_ERROR_NONE; + + } else if (store_id == PTP_STORAGEID_ALL && h_parent == PTP_OBJECTHANDLE_ALL) { + h_parent = PTP_OBJECTHANDLE_ROOT; + for (i = 0; i < _device_get_num_stores(); i++) { + store = _device_get_store_at_index(i); + _entity_get_child_handles_with_same_format(store, h_parent, format, handle_arr); + } + return MTP_ERROR_NONE; + + } else if (store_id != PTP_STORAGEID_ALL && h_parent == PTP_OBJECTHANDLE_ROOT) { + store = _device_get_store(store_id); + if (store == NULL) { + ERR("invalid store id [%d]\n", store_id); + return MTP_ERROR_INVALID_STORE; + } + + _entity_get_objects_from_store_by_format(store, format, handle_arr); + return MTP_ERROR_NONE; + + } else if (store_id != PTP_STORAGEID_ALL && h_parent == PTP_OBJECTHANDLE_ALL) { + h_parent = PTP_OBJECTHANDLE_ROOT; + store = _device_get_store(store_id); + if (store == NULL) { + ERR("invalid store id [%d]\n", store_id); + return MTP_ERROR_INVALID_STORE; + } + _entity_get_child_handles_with_same_format(store, h_parent, format, handle_arr); + return MTP_ERROR_NONE; + } + + store = _device_get_store(store_id); + if (store == NULL) { + ERR("invalid store id [%d]\n", store_id); + return MTP_ERROR_INVALID_STORE; + } + + _entity_get_child_handles_with_same_format(store, h_parent, format, handle_arr); + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_construct_object_entry(mtp_uint32 store_id, + mtp_uint32 h_parent, obj_data_t *objdata, mtp_obj_t **obj, void *data, + mtp_uint32 data_sz) +{ + mtp_store_t *store = NULL; + mtp_obj_t *tobj = NULL; + obj_info_t *obj_info = NULL; + mtp_char file_name[MTP_MAX_FILENAME_SIZE + 1] = { 0 }; + + if (store_id) { + if (!h_parent) { + h_parent = _device_get_default_parent_handle(); + } else if (h_parent == 0xFFFFFFFF) { + h_parent = PTP_OBJECTHANDLE_ROOT; + } + } else { + store_id = _device_get_default_store_id(); + + if (!store_id) { + ERR("_device_get_default_store_id Fail"); + return MTP_ERROR_STORE_NOT_AVAILABLE; + } + + if (h_parent) { + /* If the second parameter is used, + * the first must also be used. + */ + return MTP_ERROR_INVALID_PARAM; + } else { + h_parent = _device_get_default_parent_handle(); + } + } + + if (objdata != NULL) { + store = _device_get_store(objdata->store_id); + if (store != NULL) { + DBG("check free size instead of re-calculation"); + _entity_update_store_info_run_time(&(store->store_info), + (store->root_path)); + } + + /* Delete and invalidate the old obj_info for send object */ + if (objdata->obj != NULL) { + _entity_dealloc_mtp_obj(objdata->obj); + } + } + + store = _device_get_store(store_id); + if (store == NULL) { + ERR("Store not found"); + return MTP_ERROR_INVALID_STORE; + } + + if (store->store_info.access == PTP_STORAGEACCESS_R) { + ERR("Read only storage"); + return MTP_ERROR_STORE_READ_ONLY; + } + + if ((store->store_info.free_space) == 0 || + (store->store_info.free_space > + store->store_info.capacity)) { + ERR("free space is not enough [%ld:%ld]\n", + store->store_info.free_space, + store->store_info.capacity); + return MTP_ERROR_STORE_FULL; + } + + obj_info = _entity_alloc_object_info(); + if (obj_info == NULL) { + ERR("_entity_alloc_object_info Fail"); + return MTP_ERROR_GENERAL; + } + + if (_entity_parse_raw_obj_info(data, data_sz, obj_info, file_name, + sizeof(file_name)) != data_sz) { + /* wrong object info sent from Host.*/ + ERR("Invalid objet info"); + _entity_dealloc_obj_info(obj_info); + return MTP_ERROR_INVALID_OBJECT_INFO; + } + obj_info->store_id = store_id; + obj_info->h_parent = h_parent; + + switch (_hutil_add_object_entry(obj_info, file_name, &tobj)) { + case MTP_ERROR_NONE: + *obj = tobj; + break; + + case MTP_ERROR_STORE_FULL: + return MTP_ERROR_STORE_FULL; + + case MTP_ERROR_INVALID_OBJECTHANDLE: + return MTP_ERROR_INVALID_OBJECTHANDLE; + + case MTP_ERROR_INVALID_PARENT: + return MTP_ERROR_INVALID_PARENT; + + default: + return MTP_ERROR_GENERAL; + } + + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_construct_object_entry_prop_list(mtp_uint32 store_id, + mtp_uint32 h_parent, mtp_uint16 format, mtp_uint64 obj_sz, + obj_data_t *obj_data, mtp_obj_t **obj_ptr, void *data, + mtp_int32 data_sz, mtp_uint32 *err_idx) +{ + mtp_uint32 index = 0; + mtp_store_t *store = NULL; + mtp_obj_t *obj = NULL; + obj_prop_desc_t *prop_desc = NULL; + obj_prop_val_t *prop_val = NULL; + mtp_uint32 num_elem = 0; + mtp_int32 quad_sz = 0; + mtp_uint32 obj_handle = 0; + mtp_uint16 prop_code = 0; + mtp_uint16 data_type = 0; + obj_info_t *obj_info = NULL; + mtp_uchar *temp = NULL; + mtp_int32 bytes_left = data_sz; + mtp_err_t resp = 0; + +#ifdef MTP_SUPPORT_ALBUM_ART + mtp_uint16 albumFormat = 0; + mtp_char alb_extn[MTP_MAX_EXTENSION_LENGTH + 1] = { 0 }; + mtp_char *alb_buf = NULL; + mtp_uint32 alb_sz = 0; + mtp_uint32 h_temp = INVALID_FILE; + mtp_int32 error = 0; +#endif /*MTP_SUPPORT_ALBUM_ART*/ + mtp_char file_name[MTP_MAX_FILENAME_SIZE + 1] = { 0 }; + + if (obj_data != NULL && obj_data->obj != NULL) { + store = _device_get_store(obj_data->store_id); + if (store != NULL) { + DBG("check free size instead of re-calculation"); + _entity_update_store_info_run_time(&(store->store_info), + (store->root_path)); + } + _entity_dealloc_mtp_obj(obj_data->obj); + } + + store = _device_get_store(store_id); + if (store == NULL) { + ERR("Could not get the store"); + return MTP_ERROR_INVALID_STORE; + } + + if (store->store_info.access == PTP_STORAGEACCESS_R) { + ERR("Only read access allowed on store"); + return MTP_ERROR_STORE_READ_ONLY; + } + + if ((store->store_info.free_space) == 0 || + (store->store_info.free_space > store->store_info.capacity)) { + ERR("free space is not enough [%ld bytes]\n", + store->store_info.free_space); + return MTP_ERROR_STORE_FULL; + } + + obj_info = _entity_alloc_object_info(); + if (obj_info == NULL) { + ERR("_entity_alloc_object_info Fail"); + return MTP_ERROR_GENERAL; + } + + obj_info->obj_fmt = format; + if (obj_info->obj_fmt == PTP_FMT_ASSOCIATION) { + obj_info->association_type = PTP_ASSOCIATIONTYPE_FOLDER; + } + + obj_info->file_size = obj_sz; + + /* Prop value quadruple: Object Handle, PropertyCode, DataType + * and DTS Prop Value (assume a byte value) + */ + temp = (mtp_uchar *) data; + bytes_left = data_sz; + quad_sz = sizeof(mtp_uint32) + sizeof(mtp_uint16) + sizeof(mtp_uint16) + + sizeof(mtp_char); + memcpy(&num_elem, temp, sizeof(mtp_uint32)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(&num_elem, sizeof(mtp_uint32)); +#endif + temp += sizeof(mtp_uint32); + bytes_left -= sizeof(mtp_uint32); + + /* frequent disconnect/connect make bluscreen since below process + * is not finished + */ + for (index = 0; index < num_elem; index++) { + if (MTP_PHONE_USB_DISCONNECTED == _util_get_local_usb_status() || + TRUE == _transport_get_usb_discon_state()) { + /* seems usb is disconnected, stop */ + _entity_dealloc_obj_info(obj_info); + resp = MTP_ERROR_GENERAL; + goto ERROR_EXIT; + } + + *err_idx = index; + if (bytes_left < quad_sz) { + /* seems invalid dataset received: Stops parsing */ + _entity_dealloc_obj_info(obj_info); + resp = MTP_ERROR_INVALID_DATASET; + goto ERROR_EXIT; + } + + /* Get ObjectHandle & validate */ + memcpy(&obj_handle, temp, sizeof(mtp_uint32)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(&obj_handle, sizeof(mtp_uint32)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uint32); + bytes_left -= sizeof(mtp_uint32); + if (obj_handle != 0x00000000) { + _entity_dealloc_obj_info(obj_info); + resp = MTP_ERROR_INVALID_OBJECTHANDLE; + goto ERROR_EXIT; + } + + /* Get PropCode & Validate */ + memcpy(&prop_code, temp, sizeof(mtp_uint16)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(&prop_code, sizeof(mtp_uint16)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uint16); + bytes_left -= sizeof(mtp_uint16); + prop_desc = _prop_get_obj_prop_desc(obj_info->obj_fmt, prop_code); + if (prop_desc == NULL) { + _entity_dealloc_obj_info(obj_info); + ERR("property may be unsupported!!"); + resp = MTP_ERROR_INVALID_OBJ_PROP_CODE; + goto ERROR_EXIT; + } + + /* Verify that properties already present in parameters + * don't get repeated in the list + */ + if ((prop_code == MTP_OBJ_PROPERTYCODE_STORAGEID) || + (prop_code == MTP_OBJ_PROPERTYCODE_PARENT) || + (prop_code == MTP_OBJ_PROPERTYCODE_OBJECTFORMAT) || + (prop_code == MTP_OBJ_PROPERTYCODE_OBJECTSIZE)) { + _entity_dealloc_obj_info(obj_info); + resp = MTP_ERROR_INVALID_DATASET; + goto ERROR_EXIT; + } + + /* Get DataType */ + memcpy(&data_type, temp, sizeof(mtp_uint16)); +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(&data_type, sizeof(mtp_uint16)); +#endif /* __BIG_ENDIAN__ */ + temp += sizeof(mtp_uint16); + bytes_left -= sizeof(mtp_uint16); + if (data_type != prop_desc->propinfo.data_type) { + _entity_dealloc_obj_info(obj_info); + resp = MTP_ERROR_INVALID_OBJECT_PROP_FORMAT; + goto ERROR_EXIT; + } + + /* Acquire object information related data. */ + prop_val = _prop_alloc_obj_propval(prop_desc); + if (prop_val == NULL) { + continue; + } + _prop_set_current_array_val(prop_val, temp, bytes_left); + switch (prop_code) { + case MTP_OBJ_PROPERTYCODE_WIDTH: + // TODO: find mechanism to save (integer) + break; + case MTP_OBJ_PROPERTYCODE_TRACK: + // TODO: find mechanism to save (integer) + break; + case MTP_OBJ_PROPERTYCODE_GENRE: + // TODO: find mechanism to save (string) + break; + case MTP_OBJ_PROPERTYCODE_HEIGHT: + // TODO: find mechanism to save (integer) + break; + case MTP_OBJ_PROPERTYCODE_ARTIST: + // TODO: find mechanism to save (string) + break; + case MTP_OBJ_PROPERTYCODE_DURATION: + // TODO: find mechanism to save (integer) + break; + case MTP_OBJ_PROPERTYCODE_COMPOSER: + // TODO: find mechanism to save (string) + break; + case MTP_OBJ_PROPERTYCODE_ALBUMNAME: + // TODO: find mechanism to save (string) + break; + case MTP_OBJ_PROPERTYCODE_SAMPLERATE: + // TODO: find mechanism to save (integer) + break; + case MTP_OBJ_PROPERTYCODE_DATECREATED: + // TODO: find mechanism to save (string) + break; + case MTP_OBJ_PROPERTYCODE_DATEMODIFIED: + // TODO: find mechanism to save (string) + break; + case MTP_OBJ_PROPERTYCODE_AUDIOBITRATE: + // TODO: find mechanism to save (integer) + break; + case MTP_OBJ_PROPERTYCODE_VIDEOBITRATE: + // TODO: find mechanism to save (integer) + break; + case MTP_OBJ_PROPERTYCODE_OBJECTFILENAME: + /* empty metadata folder problem + * emtpy file name + */ + if (prop_val->current_val.str->num_chars == 0) { + g_strlcpy(file_name, MTP_UNKNOWN_METADATA, sizeof(file_name)); + } else { + _util_utf16_to_utf8(file_name, sizeof(file_name), + prop_val->current_val.str->str); + } + break; + + case MTP_OBJ_PROPERTYCODE_PROTECTIONSTATUS: +#ifdef MTP_SUPPORT_SET_PROTECTION + memcpy(&obj_info->protcn_status, prop_val->current_val.integer, + sizeof(mtp_uint16)); +#else /* MTP_SUPPORT_SET_PROTECTION */ + obj_info->protcn_status = PTP_PROTECTIONSTATUS_NOPROTECTION; +#endif /*MTP_SUPPORT_SET_PROTECTION*/ + break; + + case MTP_OBJ_PROPERTYCODE_ASSOCIATIONTYPE: + memcpy(&obj_info->association_type, prop_val->current_val.integer, + sizeof(mtp_uint16)); + break; + + case MTP_OBJ_PROPERTYCODE_NUMBEROFCHANNELS: + // TODO: find mechanism to save (integer) + break; + case MTP_OBJ_PROPERTYCODE_FRAMESPER1KSECONDS: + // TODO: find mechanism to save (integer) + break; +#ifdef MTP_SUPPORT_ALBUM_ART + case MTP_OBJ_PROPERTYCODE_SAMPLEDATA: + /* save sample data(album cover data) with + * sample format, otherwise no extension + * update db with sample data path + * there is no case that this position is called + * again but prevent detect this + */ + g_free(alb_buf); + alb_buf = NULL; + alb_buf = g_malloc(sizeof(mtp_uchar) * + (prop_val->current_val.array->num_ele) + 1); + alb_sz = prop_val->current_val.array->num_ele; + if (alb_buf != NULL) { + memset(alb_buf, 0, + sizeof(mtp_uchar) * alb_sz + 1); + if (alb_sz > 0) + memcpy(alb_buf, + (prop_val->current_val.array->array_entry), + sizeof(mtp_uchar) * alb_sz); + } else { + ERR("album art test mem allocation Fail"); + _prop_destroy_obj_propval(prop_val); + _entity_dealloc_obj_info(obj_info); + return MTP_ERROR_GENERAL; + } + break; + + case MTP_OBJ_PROPERTYCODE_SAMPLEFORMAT: + /* if is_albumart is turned on, Move file with + * new extension. And update db with data path + */ + memcpy(&albumFormat, prop_val->current_val.integer, + sizeof(mtp_uint16)); + switch (albumFormat) { + case PTP_FMT_IMG_EXIF: + g_snprintf(alb_extn, sizeof(alb_extn), "%s", "jpg"); + break; + case PTP_FMT_IMG_GIF: + g_snprintf(alb_extn, sizeof(alb_extn), "%s", "gif"); + break; + case PTP_FMT_IMG_PNG: + g_snprintf(alb_extn, sizeof(alb_extn), "%s", "png"); + break; + case MTP_FMT_WMA: + g_snprintf(alb_extn, sizeof(alb_extn), "%s", "wma"); + break; + case PTP_FMT_MPEG: + g_snprintf(alb_extn, sizeof(alb_extn), "%s", "mpg"); + break; + default: + g_snprintf(alb_extn, sizeof(alb_extn), "%s", "dat"); + break; + } + + ERR("sampleformatl![0x%x], extension[%s]\n", prop_code, alb_extn); + break; + case MTP_OBJ_PROPERTYCODE_SAMPLESIZE: + case MTP_OBJ_PROPERTYCODE_SAMPLEHEIGHT: + case MTP_OBJ_PROPERTYCODE_SAMPLEWIDTH: + case MTP_OBJ_PROPERTYCODE_SAMPLEDURATION: + DBG("Sample data is not supported [0x%x]\n", prop_code); + break; +#endif /*MTP_SUPPORT_ALBUM_ART*/ + + default: + DBG("Unsupported Property [0x%x]\n", prop_code); + break; + } + + temp += _prop_size_obj_propval(prop_val); + bytes_left -= _prop_size_obj_propval(prop_val); + _prop_destroy_obj_propval(prop_val); + } + + obj_info->store_id = store_id; + obj_info->h_parent = h_parent; + + if ((resp = _hutil_add_object_entry(obj_info, file_name, &obj)) != + MTP_ERROR_NONE) { + goto ERROR_EXIT; + } + +#ifdef MTP_SUPPORT_ALBUM_ART + mtp_char full_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char extn[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + + g_strlcpy(full_path, obj->file_path, MTP_MAX_PATHNAME_SIZE + 1); + + /* in case of album, if there is album data, fill it in this file */ + if (obj_info->obj_fmt != PTP_FMT_ASSOCIATION || + (obj_info->obj_fmt == PTP_FMT_ASSOCIATION && + obj_info->association_type != PTP_ASSOCIATIONTYPE_UNDEFINED && + obj_info->association_type != PTP_ASSOCIATIONTYPE_FOLDER)) { + + _util_get_file_extn(full_path, extn); + if (!strcasecmp(extn, "alb")) { + /* check db whether it contains sample form + * save sample data(album cover data) with + * sample format, otherwise no extension + */ + if (alb_buf != NULL) { + /* file write */ + h_temp = _util_file_open(full_path, + MTP_FILE_WRITE, &error); + if (h_temp != INVALID_FILE) { + _util_file_write(h_temp, alb_buf, + sizeof(mtp_uchar) *alb_sz); + _util_file_close(h_temp); + } else { + ERR("open album file Fail!!"); + } + } else { + ERR("no album art data"); + } + } + } + + g_free(alb_buf); +#endif /* MTP_SUPPORT_ALBUM_ART */ + *obj_ptr = obj; + return MTP_ERROR_NONE; + +ERROR_EXIT: +#ifdef MTP_SUPPORT_ALBUM_ART + g_free(alb_buf); +#endif /* MTP_SUPPORT_ALBUM_ART */ + return resp; +} + +mtp_err_t _hutil_get_object_prop_value(mtp_uint32 obj_handle, + mtp_uint32 prop_code, obj_prop_val_t *prop_val, mtp_obj_t **obj) +{ + obj_prop_val_t *tprop = NULL; + mtp_obj_t *tobj = NULL; + + tobj = _device_get_object_with_handle(obj_handle); + if (NULL == tobj) { + ERR("requested handle does not exist[0x%x]\n",obj_handle); + return MTP_ERROR_INVALID_OBJECTHANDLE; + } + + tprop = _prop_get_prop_val(tobj, prop_code); + if (tprop != NULL) { + memcpy(prop_val, tprop, sizeof(obj_prop_val_t)); + *obj = tobj; + return MTP_ERROR_NONE; + } + + ERR("can not get the prop value for propcode [0x%x]\n", prop_code); + return MTP_ERROR_GENERAL; +} + +mtp_err_t _hutil_update_object_property(mtp_uint32 obj_handle, + mtp_uint32 prop_code, mtp_uint16 *data_type, void *buf, + mtp_uint32 buf_sz, mtp_uint32 *prop_sz) +{ + mtp_int32 error = 0; + mtp_uint32 p_size = 0; + mtp_obj_t *obj = NULL; + obj_info_t *obj_info = NULL; + obj_prop_desc_t *prp_dev = NULL; + mtp_char temp_buf[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char orig_pfpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_wchar mov_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char orig_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char dest_fpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + + retv_if(NULL == buf, MTP_ERROR_INVALID_PARAM); + + obj = _device_get_object_with_handle(obj_handle); + if ((NULL == obj) || (NULL == obj->obj_info)) { + ERR("Object not found"); + return MTP_ERROR_INVALID_OBJECTHANDLE; + } + + obj_info = obj->obj_info; + /* Avoid to rename file/folder during file operating by phone side. */ + if (_util_is_file_opened(obj->file_path) == TRUE) { + ERR_SECURE("Object [%s] is already opened\n", obj->file_path); + return MTP_ERROR_GENERAL; + } + + prp_dev = _prop_get_obj_prop_desc(obj_info->obj_fmt, prop_code); + if (prp_dev == NULL) { + ERR("_prop_get_obj_prop_desc Fail"); + return MTP_ERROR_INVALID_OBJ_PROP_CODE; + } + +#ifdef MTP_SUPPORT_SET_PROTECTION + if (obj_info->protcn_status == PTP_PROTECTIONSTATUS_READONLY) { + ERR("protection is PTP_PROTECTIONSTATUS_READONLY"); + return MTP_ERROR_ACCESS_DENIED; + } +#endif /* MTP_SUPPORT_SET_PROTECTION */ + + if (prp_dev->propinfo.get_set == PTP_PROPGETSET_GETONLY) { + ERR("property type is GETONLY"); + return MTP_ERROR_ACCESS_DENIED; + } + + if (data_type != NULL && *data_type != prp_dev->propinfo.data_type) { + ERR("Not matched data type [%d][%d]\n", + *data_type, prp_dev->propinfo.data_type); + return MTP_ERROR_INVALID_OBJECT_PROP_FORMAT; + } + + /* Set up needed object info fields */ + if (prop_code == MTP_OBJ_PROPERTYCODE_OBJECTFILENAME) { + ptp_string_t fname = { 0 }; + + _prop_init_ptpstring(&fname); + _prop_parse_rawstring(&fname, buf, buf_sz); + + _util_utf16_to_utf8(temp_buf, sizeof(temp_buf), + fname.str); + g_strlcpy(orig_fpath, obj->file_path, + MTP_MAX_PATHNAME_SIZE + 1); + _util_get_parent_path(orig_fpath, orig_pfpath); + + if (_util_create_path(dest_fpath, sizeof(dest_fpath), + orig_pfpath, temp_buf) == FALSE) { + ERR("Path is too long"); + return MTP_ERROR_ACCESS_DENIED; + } + _util_utf8_to_utf16(mov_fpath, + sizeof(mov_fpath) / WCHAR_SIZ, dest_fpath); + + /* when changed name is different */ + if (strcasecmp(orig_fpath, dest_fpath)) { + /* Extension change is not permitted */ + mtp_char orig_extn[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char dest_extn[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + + _util_get_file_extn(orig_fpath, orig_extn); + _util_get_file_extn(dest_fpath, dest_extn); + + if (strcasecmp(orig_extn, dest_extn)) { + ERR("file extension is different with original\ + one [%s]:[%s]\n", orig_extn, dest_extn); + return MTP_ERROR_INVALID_OBJECT_PROP_FORMAT; + } + + /* FILE RENAME */ + if (_entity_check_child_obj_path(obj, orig_fpath, + dest_fpath) == FALSE) { + ERR("_entity_check_child_obj_path FALSE. "); + return MTP_ERROR_GENERAL; + } + g_snprintf(g_last_moved, MTP_MAX_PATHNAME_SIZE + 1, + "%s", orig_fpath); + if (FALSE == _util_file_move(orig_fpath, dest_fpath, + &error)) { + if (EACCES == error) + return MTP_ERROR_ACCESS_DENIED; + return MTP_ERROR_GENERAL; + } + + if (obj->obj_info->obj_fmt == PTP_FMT_ASSOCIATION) { + _util_scan_folder_contents_in_db(orig_fpath); + _util_scan_folder_contents_in_db(dest_fpath); + } else { + _util_delete_file_from_db(orig_fpath); + _util_add_file_to_db(dest_fpath); + + } + + /* Finally assign new handle and update full path */ + _entity_set_object_file_path(obj, dest_fpath, + CHAR_TYPE); + + /* FILE RENAME */ + if (_entity_set_child_object_path(obj, orig_fpath, + dest_fpath) == FALSE) { + ERR("failed to set the full path!!"); + return MTP_ERROR_INVALID_OBJECT_PROP_FORMAT; + } + + DBG("File moved to [%s]\n", dest_fpath); + } else { + ERR_SECURE("changed name is same with original one. [%s]\n", + dest_fpath); + } + p_size = _prop_size_ptpstring(&fname); + } else if (prop_code == MTP_OBJ_PROPERTYCODE_ASSOCIATIONTYPE) { + memcpy(&obj_info->association_type, buf, sizeof(mtp_uint16)); + p_size = sizeof(mtp_uint16); + } else { + ERR("Propert [0x%x] is GETONLY\n", prop_code); + } + + if (prop_sz != NULL) { + *prop_sz = p_size; + } + + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_get_prop_desc(mtp_uint32 format, mtp_uint32 prop_code, + void *data) +{ + obj_prop_desc_t *prop = NULL; + + prop = _prop_get_obj_prop_desc(format, prop_code); + if (prop == NULL) { + ERR("pProperty is NULL"); + return MTP_ERROR_GENERAL; + } + + memcpy(data, prop, sizeof(obj_prop_desc_t)); + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_get_object_prop_supported(mtp_uint32 format, + ptp_array_t *prop_arr) +{ + _prop_get_supp_obj_props(format, prop_arr); + return MTP_ERROR_NONE; +} + +#ifndef MTP_USE_RUNTIME_GETOBJECTPROPVALUE +mtp_err_t _hutil_get_object_prop_list(mtp_uint32 obj_handle, mtp_uint32 format, + mtp_uint32 prop_code, mtp_uint32 group_code, mtp_uint32 depth, + obj_proplist_t *prop_list) +#else /* MTP_USE_RUNTIME_GETOBJECTPROPVALUE */ +mtp_err_t _hutil_get_object_prop_list(mtp_uint32 obj_handle, mtp_uint32 format, + mtp_uint32 prop_code, mtp_uint32 group_code, mtp_uint32 depth, + obj_proplist_t *prop_list, ptp_array_t *obj_arr) +#endif /* MTP_USE_RUNTIME_GETOBJECTPROPVALUE */ +{ +#ifndef MTP_USE_RUNTIME_GETOBJECTPROPVALUE + ptp_array_t obj_arr = { 0 }; +#endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/ + mtp_obj_t *obj = NULL; + mtp_uint32 i = 0; + mtp_uint32 ii = 0; + mtp_store_t *store = NULL; + + if ((obj_handle != PTP_OBJECTHANDLE_UNDEFINED) && + (obj_handle != PTP_OBJECTHANDLE_ALL)) { + /* Is this object handle valid? */ + store = _device_get_store_containing_obj(obj_handle); + if (store == NULL) { + ERR("invalid object handle"); + return MTP_ERROR_INVALID_OBJECTHANDLE; + } + } + + if (prop_code == PTP_PROPERTY_UNDEFINED) { + /* PropGroupCode should be used if Property code + * is not specified. + * */ + if (group_code == 0x0) { + ERR("PropGroupCode is zero"); + return MTP_ERROR_INVALID_PARAM; + } + } + + if (!(obj_handle == PTP_OBJECTHANDLE_ALL || + obj_handle == PTP_OBJECTHANDLE_UNDEFINED) && + !(format == PTP_FORMATCODE_NOTUSED || + format == PTP_FORMATCODE_ALL)) { + ERR("both object handle and format code is specified!\ + return nospecification by format"); + return MTP_ERROR_NO_SPEC_BY_FORMAT; + } + + _util_init_list(&(prop_list->prop_quad_list)); + _prop_init_ptparray(obj_arr, PTR_TYPE); + + if (store != NULL) { + _entity_get_objects_from_store_till_depth(store, obj_handle, + format, depth, obj_arr); + } else { + for (ii = 0; ii < _device_get_num_stores(); ii++) { + store = _device_get_store_at_index(ii); + _entity_get_objects_from_store_till_depth(store, + obj_handle, format, depth, obj_arr); + } + } + + if (obj_arr->num_ele != 0) { + mtp_obj_t **ptr_obj; + ptr_obj = obj_arr->array_entry; + + for (i = 0; i < obj_arr->num_ele; i++) { + obj = ptr_obj[i]; + if (!obj) + continue; + + if (_prop_get_obj_proplist(obj, prop_code, group_code, + prop_list) == FALSE) { + ERR("Fail to create Proplist"); +#ifndef MTP_USE_RUNTIME_GETOBJECTPROPVALUE + _prop_deinit_ptparray(&obj_arr); +#endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/ + return MTP_ERROR_GENERAL; + } + } + } + +#ifndef MTP_USE_RUNTIME_GETOBJECTPROPVALUE + prop_deinit_ptparray(&obj_arr); +#endif /*MTP_USE_RUNTIME_GETOBJECTPROPVALUE*/ + + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_remove_object_reference(mtp_uint32 obj_handle, + mtp_uint32 ref_handle) +{ + mtp_obj_t *obj = NULL; + + obj = _device_get_object_with_handle(obj_handle); + if (obj == NULL) { + ERR("No object for handle[%d]\n", obj_handle); + return MTP_ERROR_NONE; + } + + if (_entity_remove_reference_child_array(obj, ref_handle) == FALSE) { + ERR("_entity_remove_reference_child_array Fail"); + } + + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_add_object_references_enhanced(mtp_uint32 obj_handle, + mtp_uchar *buffer, mtp_uint32 buf_sz) +{ + mtp_obj_t *obj = NULL; + + obj = _device_get_object_with_handle(obj_handle); + if (obj == NULL) { + DBG("No object for handle[0x%x]\n", obj_handle); + return MTP_ERROR_NONE; + } + + if (_entity_set_reference_child_array(obj, buffer, buf_sz) == FALSE) { + ERR("_entity_set_reference_child_array Fail"); + return MTP_ERROR_GENERAL; + } + + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_get_object_references(mtp_uint32 obj_handle, + ptp_array_t *parray, mtp_uint32 *num_ele) +{ + mtp_obj_t *obj = NULL; + mtp_obj_t *ref_obj = NULL; + mtp_uint16 idx = 0; + mtp_uint32 *ref_ptr = NULL; + ptp_array_t ref_arr = { 0 }; + + obj = _device_get_object_with_handle(obj_handle); + if (NULL == obj || NULL == obj->obj_info) { + *num_ele = 0; + return MTP_ERROR_INVALID_OBJECTHANDLE; + } + + if (parray == NULL) { + *num_ele = 0; + return MTP_ERROR_GENERAL; + } + + if (obj->child_array.num_ele == 0) { + *num_ele = 0; + return MTP_ERROR_NONE; + } + + _prop_init_ptparray(&ref_arr, obj->child_array.type); + _prop_copy_ptparray(&ref_arr, &(obj->child_array)); + ref_ptr = (mtp_uint32 *)(ref_arr.array_entry); + + for (idx = 0; idx < ref_arr.num_ele; idx++) { + ref_obj = _device_get_object_with_handle(ref_ptr[idx]); + if (ref_obj == NULL) { + _entity_remove_reference_child_array(obj, ref_ptr[idx]); + } + } + + *num_ele = obj->child_array.num_ele; + if (*num_ele) { + _prop_init_ptparray(parray, obj->child_array.type); + _prop_grow_ptparray(parray, *num_ele); + _prop_copy_ptparray(parray, &(obj->child_array)); + } + + _prop_deinit_ptparray(&ref_arr); + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_get_number_of_objects(mtp_uint32 store_id, mtp_uint32 *num_obj) +{ + *num_obj = _device_get_num_objects(store_id); + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_get_interdep_prop_config_list_size(mtp_uint32 *list_sz, + mtp_uint32 format) +{ + *list_sz = _prop_get_size_interdep_proplist(&interdep_proplist, + format); + return MTP_ERROR_NONE; +} + +mtp_err_t _hutil_get_interdep_prop_config_list_data(void *data, + mtp_uint32 list_sz, mtp_uint32 format) +{ + if (list_sz == _prop_pack_interdep_proplist(&interdep_proplist, + format, data, list_sz)) { + return MTP_ERROR_NONE; + } + + ERR("packet and requested size do not match"); + return MTP_ERROR_GENERAL; +} + +mtp_err_t _hutil_get_playback_skip(mtp_int32 skip_param) +{ + mtp_int32 idx = 0; + mtp_obj_t *obj = NULL; + mtp_uint32 new_idx = 0; + mtp_uint32 new_hobj = 0; + mtp_uint32 obj_handle = 0; + mtp_obj_t *par_obj = NULL; + obj_info_t *obj_info = NULL; + ptp_array_t *ref_arr = NULL; + device_prop_desc_t *dev_prop = NULL; + + retv_if(skip_param == 0, MTP_ERROR_INVALID_PARAM); + + if (_device_get_playback_obj(&obj_handle) == FALSE) { + ERR("_device_get_playback_obj Fail"); + return MTP_ERROR_GENERAL; + } + + if (obj_handle == 0x0) { + return MTP_ERROR_NONE; + } + + obj = _device_get_object_with_handle(obj_handle); + if (obj == NULL || obj->obj_info == NULL) { + ERR("obj or obj_info is NULL"); + return MTP_ERROR_GENERAL; + } + + obj_info = obj->obj_info; + if ((obj_info->obj_fmt == PTP_FMT_WAVE) || + (obj_info->obj_fmt == PTP_FMT_MP3) || + (obj_info->obj_fmt == MTP_FMT_WMA) || + (obj_info->obj_fmt == MTP_FMT_WMV) || + (obj_info->obj_fmt == MTP_FMT_UNDEFINED_AUDIO)) { + par_obj = _device_get_object_with_handle(obj_info->h_parent); + if (!par_obj) { + ERR("parent not found in obj_list"); + return MTP_ERROR_GENERAL; + } + ref_arr = _entity_get_reference_child_array(par_obj); + idx = _prop_find_ele_ptparray(ref_arr, obj_handle); + if (idx != ELEMENT_NOT_FOUND) { + if (((long long)idx + (long long)skip_param) > UINT_MAX) { + new_idx = ref_arr->num_ele - 1; + } else if ((idx + skip_param) >= ref_arr->num_ele) { + new_idx = 0; + } else { + new_idx = idx + skip_param; + } + + if (_prop_get_ele_ptparray(ref_arr, new_idx, + (void *)(&new_hobj)) == TRUE) { + dev_prop = _device_get_device_property( + MTP_PROPERTYCODE_PLAYBACK_CONT_INDEX); + if (dev_prop == NULL) { + ERR("dev_prop is null"); + return MTP_ERROR_GENERAL; + } + _prop_set_current_integer(dev_prop, 0xFFFFFFFF); + _device_set_playback_obj(new_hobj); + } + } + } else if ((obj_info->obj_fmt == MTP_FMT_ABSTRACT_AUDIO_ALBUM) || + (obj_info->obj_fmt == MTP_FMT_ABSTRACT_VIDEO_ALBUM)) { + dev_prop = _device_get_device_property( + MTP_PROPERTYCODE_PLAYBACK_CONT_INDEX); + if (dev_prop == NULL) { + ERR("dev_prop is null"); + return MTP_ERROR_GENERAL; + } + memcpy(&idx, dev_prop->current_val.integer, sizeof(mtp_uint32)); + ref_arr = _entity_get_reference_child_array(obj); + if (((long long)idx + (long long)skip_param) > UINT_MAX) { + new_idx = ref_arr->num_ele - 1; + } else if ((idx + skip_param) >= ref_arr->num_ele) { + new_idx = 0; + } else { + new_idx = idx + skip_param; + } + _prop_set_current_integer(dev_prop, new_idx); + return MTP_ERROR_NONE; + } + + return MTP_ERROR_GENERAL; +} + +mtp_err_t _hutil_format_storage(mtp_uint32 store_id, mtp_uint32 fs_format) +{ + mtp_err_t error = MTP_ERROR_GENERAL; + mtp_store_t *store = NULL; + + store = _device_get_store(store_id); + if (store == NULL) { + ERR("Store is NULL"); + return error; + } + + error = _entity_format_store(store, fs_format); + if (error == PTP_RESPONSE_OK) { + return MTP_ERROR_NONE; + } + + ERR("Format store Fail"); + return error; +} + +mtp_uint32 _hutil_get_storage_info_size(store_info_t *store_info) +{ + mtp_uint32 size = 0; + + size += sizeof(store_info->access); + size += sizeof(store_info->fs_type); + size += sizeof(store_info->free_space); + size += sizeof(store_info->free_space_in_objs); + size += sizeof(store_info->capacity); + size += sizeof(store_info->store_type); + size += _prop_size_ptpstring(&(store_info->store_desc)); + size += _prop_size_ptpstring(&(store_info->vol_label)); + + return size; +} diff --git a/src/mtp_event_handler.c b/src/mtp_event_handler.c new file mode 100755 index 0000000..2be6496 --- /dev/null +++ b/src/mtp_event_handler.c @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <unistd.h> +#include <sys/types.h> +#include <signal.h> +#include <vconf.h> +#include <vconf-keys.h> +#include <glib.h> +#include "mtp_event_handler.h" +#include "mtp_cmd_handler.h" +#include "mtp_util.h" +#include "mtp_thread.h" +#include "mtp_init.h" +#include "mtp_usb_driver.h" +#include "mtp_transport.h" +#include "mtp_media_info.h" + +/* + * GLOBAL AND EXTERN VARIABLES + */ +extern mtp_mgr_t g_mtp_mgr; +pthread_t g_eh_thrd; /* event handler thread */ +mtp_int32 g_pipefd[2]; + +/* + * STATIC VARIABLES + */ +static mtp_mgr_t *g_mgr = &g_mtp_mgr; + +/* + * STATIC FUNCTIONS + */ +static mtp_bool __process_event_request(mtp_event_t *evt); +static void *__thread_event_handler(void *arg); +static mtp_bool __send_events_from_device_to_pc(mtp_dword store_id, + mtp_uint16 ptp_event, mtp_uint32 param1, mtp_uint32 param2); +static void __handle_usb_notification(keynode_t *key, void *data); +static void __handle_usb_mode_notification(keynode_t *key, void *data); +static mtp_bool __send_start_event_to_eh_thread(void); + +/* + * FUNCTIONS + */ +mtp_bool _eh_register_notification_callbacks(void) +{ + mtp_int32 ret; + phone_status_t val = 0; + + _util_get_usb_status(&val); + _util_set_local_usb_status(val); + ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_USB_STATUS, + __handle_usb_notification, NULL); + if (ret < 0) { + ERR("vconf_notify_key_changed(%s) Fail", VCONFKEY_SYSMAN_USB_STATUS); + return FALSE; + } + + _util_get_usbmode_status(&val); + _util_set_local_usbmode_status(val); + ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT, + __handle_usb_mode_notification, NULL); + if (ret < 0) { + ERR("vconf_notify_key_changed(%s) Fail", VCONFKEY_SETAPPL_USB_MODE_INT); + return FALSE; + } + + _util_get_mmc_status(&val); + _util_set_local_mmc_status(val); + + DBG("Phone status: USB = [%d] MMC = [%d] USB_MODE = [%d]\n", + _util_get_local_usb_status(), _util_get_local_mmc_status(), + _util_get_local_usbmode_status()); + + return TRUE; +} + +mtp_bool _eh_handle_usb_events(mtp_uint32 type) +{ + mtp_state_t state = MTP_STATE_STOPPED; + mtp_int32 res = 0; + /* Prevent repeated USB insert/remove mal-function */ + static mtp_int32 is_usb_inserted = 0; + static mtp_int32 is_usb_removed = 0; + + state = _transport_get_mtp_operation_state(); + + switch (type) { + case USB_INSERTED: + if (is_usb_inserted == 1) { + ERR("USB is already connected"); + return TRUE; + } + + is_usb_inserted = 1; + /* check USB connection state */ + if (MTP_PHONE_USB_DISCONNECTED == _util_get_local_usb_status()) { + ERR("USB is disconnected. So just return."); + return FALSE; + } + + _transport_set_usb_discon_state(FALSE); + _transport_set_cancel_initialization(FALSE); + + if (state == MTP_STATE_INITIALIZING) { + ERR("MTP is already being initialized"); + break; + } + + res = pipe(g_pipefd); + if (res < 0) { + ERR("pipe() Fail"); + _util_print_error(); + return FALSE; + } + + res = _util_thread_create(&g_eh_thrd, + "Mtp Event Request Handler", PTHREAD_CREATE_JOINABLE, + __thread_event_handler, NULL); + if (FALSE == res) { + ERR("_util_thread_create() Fail"); + return FALSE; + } + + __send_start_event_to_eh_thread(); + + break; + + case USB_REMOVED: + if (is_usb_removed == 1) { + ERR("USB is already removed"); + return TRUE; + } + + is_usb_removed = 1; + DBG("USB is disconnected"); + + _transport_set_usb_discon_state(TRUE); + _transport_set_cancel_initialization(TRUE); + + /* cancel all transaction */ + _transport_set_control_event(PTP_EVENTCODE_CANCELTRANSACTION); + + _transport_usb_finalize(); + _transport_set_mtp_operation_state(MTP_STATE_STOPPED); + + /* + * Temp file should be deleted after usb usb read/write threads + * are terminated. Because data receive thread tries to + * write the temp file until sink thread is terminated. + */ + if (g_mgr->ftemp_st.filepath != NULL && + (access(g_mgr->ftemp_st.filepath, F_OK) == 0)) { + DBG("USB disconnected but temp file is remaind.\ + It will be deleted."); + + if (g_mgr->ftemp_st.fhandle != INVALID_FILE) { + DBG("handle is found. At first close file"); + _util_file_close(g_mgr->ftemp_st.fhandle); + g_mgr->ftemp_st.fhandle = INVALID_FILE; + } + if (remove(g_mgr->ftemp_st.filepath) < 0) { + ERR_SECURE("remove(%s) Fail", g_mgr->ftemp_st.filepath); + _util_print_error(); + } + g_free(g_mgr->ftemp_st.filepath); + g_mgr->ftemp_st.filepath = NULL; + } + + _mtp_deinit(); + _device_uninstall_storage(MTP_ADDREM_AUTO); + _eh_send_event_req_to_eh_thread(EVENT_CLOSE, 1, 0, NULL); + break; + + default: + ERR("can be ignored notify [0x%x]\n", type); + break; + } + return TRUE; +} + +static mtp_bool __process_event_request(mtp_event_t *evt) +{ + retv_if(evt == NULL, FALSE); + + switch (evt->action) { + case EVENT_CANCEL_INITIALIZATION: + DBG("EVENT_CANCEL_INITIALIZATION entered."); + _device_uninstall_storage(MTP_ADDREM_AUTO); + break; + + case EVENT_START_MAIN_OP: + DBG("EVENT_START_MAIN_OP entered."); + + /* start MTP */ + _transport_set_cancel_initialization(FALSE); + _transport_set_mtp_operation_state(MTP_STATE_INITIALIZING); + + _mtp_init(evt->param1); + _transport_set_mtp_operation_state(MTP_STATE_READY_SERVICE); + if (FALSE == _transport_init_interfaces(_receive_mq_data_cb)) { + ERR("USB init fail"); + kill(getpid(), SIGTERM); + break; + } + _transport_set_mtp_operation_state(MTP_STATE_ONSERVICE); + break; + + case EVENT_USB_REMOVED: + _util_flush_db(); + _eh_handle_usb_events(USB_REMOVED); + break; + + case EVENT_OBJECT_ADDED: + __send_events_from_device_to_pc(0, PTP_EVENTCODE_OBJECTADDED, + evt->param1, 0); + break; + + case EVENT_OBJECT_REMOVED: + __send_events_from_device_to_pc(0, + PTP_EVENTCODE_OBJECTREMOVED, evt->param1, 0); + break; + + case EVENT_OBJECT_PROP_CHANGED: + __send_events_from_device_to_pc(0, + MTP_EVENTCODE_OBJECTPROPCHANGED, evt->param1, + evt->param2); + break; + + case EVENT_CLOSE: + break; + + default: + ERR("Unknown action"); + break; + } + return TRUE; +} + +static void *__thread_event_handler(void *arg) +{ + DBG("__thread_event_handler is started "); + + mtp_int32 flag = 1; + mtp_event_t evt; + + while (flag) { + mtp_int32 status = 0; + status = read(g_pipefd[0], &evt, sizeof(mtp_event_t)); + if(( status== -1) && errno == EINTR) { + ERR("read() Fail"); + continue; + } + + __process_event_request(&evt); + + if (evt.action == EVENT_CLOSE) { + /* USB removed, terminate the thread */ + flag = 0; + } + } + + DBG("######### MTP TERMINATED #########"); + close(g_pipefd[0]); + close(g_pipefd[1]); + + _util_thread_exit("__thread_event_handler thread is over."); + return NULL; +} + +static mtp_bool __send_events_from_device_to_pc(mtp_dword store_id, + mtp_uint16 ptp_event, mtp_uint32 param1, mtp_uint32 param2) +{ + cmd_container_t event = { 0, }; + + memset(&event, 0, sizeof(cmd_container_t)); + + switch (ptp_event) { + case PTP_EVENTCODE_STOREADDED: + DBG("case PTP_EVENTCODE_STOREADDED:"); + DBG("store_id [0x%x]\n", store_id); + _hdlr_init_event_container(&event, PTP_EVENTCODE_STOREADDED, 0, + store_id, 0); + break; + + case PTP_EVENTCODE_STOREREMOVED: + DBG("case PTP_EVENTCODE_STOREREMOVED"); + DBG("store_id [0x%x]\n", store_id); + _hdlr_init_event_container(&event, + PTP_EVENTCODE_STOREREMOVED, 0, store_id, 0); + break; + + case PTP_EVENTCODE_OBJECTADDED: + DBG("case PTP_EVENTCODE_OBJECTADDED"); + DBG("param1 : [0x%x]\n", param1); + _hdlr_init_event_container(&event, PTP_EVENTCODE_OBJECTADDED, + 0, param1, 0); + break; + + case PTP_EVENTCODE_OBJECTREMOVED: + DBG("case PTP_EVENTCODE_OBJECTREMOVED"); + DBG("param1 [0x%x]\n", param1); + _hdlr_init_event_container(&event, PTP_EVENTCODE_OBJECTREMOVED, + 0, param1 , 0); + break; + + case MTP_EVENTCODE_OBJECTPROPCHANGED: + DBG("case MTP_EVENTCODE_OBJECTPROPCHANGED"); + DBG("param1 [0x%x]\n", param1); + DBG("param2 [0x%x]\n", param2); + _hdlr_init_event_container_with_param(&event, + MTP_EVENTCODE_OBJECTPROPCHANGED, 0, param1 , param2); + break; + + default: + DBG("Event not supported"); + return FALSE; + } + + return _hdlr_send_event_container(&event); +} + +static void __handle_usb_notification(keynode_t *key, void *data) +{ + phone_status_t val = MTP_PHONE_USB_DISCONNECTED; + mtp_int32 intval = VCONFKEY_SYSMAN_USB_DISCONNECTED; + + ret_if(key == NULL); + + intval = vconf_keynode_get_int(key); + if (-1 == intval) { + ERR("vconf_keynode_get_int() Fail"); + return; + } + + if (VCONFKEY_SYSMAN_USB_DISCONNECTED == intval) { + DBG("USB Disconnected"); + _util_set_local_usb_status(val); + mtp_end_event(); + return; + } + + val = MTP_PHONE_USB_CONNECTED; + _util_set_local_usb_status(val); + DBG("USB Connected. Just return."); + return; +} + +static void __handle_usb_mode_notification(keynode_t *key, void *data) +{ + phone_status_t val = MTP_PHONE_USB_MODE_OTHER; + + ret_if(key == NULL); + + val = vconf_keynode_get_int(key); + + _util_set_local_usbmode_status(val); + return; +} + +void _handle_mmc_notification(keynode_t *key, void *data) +{ + phone_status_t val = MTP_PHONE_MMC_NONE; + + _util_get_mmc_status(&val); + _util_set_local_mmc_status(val); + + if (MTP_PHONE_MMC_INSERTED == val) { + _device_install_storage(MTP_ADDREM_EXTERNAL); + __send_events_from_device_to_pc(MTP_EXTERNAL_STORE_ID, + PTP_EVENTCODE_STOREADDED, 0, 0); + + } else if (MTP_PHONE_MMC_NONE == val) { + _device_uninstall_storage(MTP_ADDREM_EXTERNAL); + + __send_events_from_device_to_pc(MTP_EXTERNAL_STORE_ID, + PTP_EVENTCODE_STOREREMOVED, 0, 0); + } + + return; +} + +void _eh_deregister_notification_callbacks(void) +{ + vconf_ignore_key_changed(VCONFKEY_SYSMAN_USB_STATUS, + __handle_usb_notification); + vconf_ignore_key_changed(VCONFKEY_SETAPPL_USB_MODE_INT, + __handle_usb_mode_notification); + + return; +} + +void _eh_send_event_req_to_eh_thread(event_code_t action, mtp_ulong param1, + mtp_ulong param2, void *param3) +{ + mtp_event_t event = { 0 }; + mtp_int32 status; + + event.action = action; + event.param1 = param1; + event.param2 = param2; + event.param3 = (mtp_ulong)param3; + + DBG("action[%d], param1[%ld], param2[%ld]\n", action, param1, param2); + + status = write(g_pipefd[1], &event, sizeof(mtp_event_t)); + if(status== -1 || errno == EINTR) { + ERR("Event write over pipe Fail, status = [%d], pipefd = [%d], errno [%d]\n", + status, g_pipefd[1], errno); + } + return; +} + +static mtp_bool __send_start_event_to_eh_thread(void) +{ + mtp_event_t event; + mtp_int32 status; + + event.action = EVENT_START_MAIN_OP; + event.param1 = (mtp_ulong) MTP_ADDREM_AUTO; + event.param2 = 0; + event.param3 = 0; + + DBG("Action : START MTP OPERATION"); + + status = write(g_pipefd[1], &event, sizeof(mtp_event_t)); + if(status== -1 || errno == EINTR) { + ERR("Event write over pipe Fail, status= [%d],pipefd = [%d], errno [%d]\n", + status, g_pipefd[1], errno); + return FALSE; + } + + return TRUE; +} diff --git a/src/mtp_init.c b/src/mtp_init.c new file mode 100755 index 0000000..55b8fde --- /dev/null +++ b/src/mtp_init.c @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <unistd.h> +#include <sys/types.h> +#include <sys/syscall.h> +#include <privilege-control.h> +#include <glib.h> +#include <glib-object.h> +#include <malloc.h> +#include <vconf.h> +#include "mtp_init.h" +#include "mtp_config.h" +#include "mtp_thread.h" +#include "mtp_support.h" +#include "mtp_device.h" +#include "mtp_event_handler.h" +#include "mtp_cmd_handler.h" +#include "mtp_inoti_handler.h" +#include "mtp_transport.h" +#include "mtp_util.h" +#include "mtp_media_info.h" + +/* + * GLOBAL AND EXTERN VARIABLES + */ +extern pthread_t g_eh_thrd; +extern pthread_mutex_t g_cmd_inoti_mutex; +extern mtp_bool g_is_sync_estab; + +mtp_mgr_t g_mtp_mgr; +mtp_config_t g_conf; + +/* + * STATIC VARIABLES AND FUNCTIONS + */ +static GMainLoop *g_mainloop = NULL; +static mtp_mgr_t *g_mgr = &g_mtp_mgr; +static void __read_mtp_conf(void); +static void __init_mtp_info(void); +static void __mtp_exit(void); +/* + * FUNCTIONS + */ + +/* + * static void __mtp_exit(void) + * This function send MTP stopped state to event handler thread and MTP UI + * @param[in] None. + * @param[out] None. + * @return None. + */ +static void __mtp_exit(void) +{ + long cur_time; + + DBG("## Terminate all threads"); + if (g_eh_thrd) { + _eh_send_event_req_to_eh_thread(EVENT_USB_REMOVED, 0, 0, NULL); + if (_util_thread_join(g_eh_thrd, NULL) == FALSE) { + ERR("_util_thread_join() Fail"); + } + g_eh_thrd = 0; + } + + if (g_is_sync_estab) { + time(&cur_time); + vconf_set_int(VCONFKEY_MTP_SYNC_TIME_INT, (int)cur_time); + } + + DBG("## Terminate main loop"); + + g_main_loop_quit(g_mainloop); + + return; +} + +void _mtp_init(add_rem_store_t sel) +{ + mtp_char wmpinfopath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char *device_name = NULL; + mtp_char *sync_partner = NULL; + mtp_bool ret = 0; + int vconf_ret = 0; + mtp_int32 error = 0; + + DBG("Initialization start!"); + + __read_mtp_conf(); + + if (g_conf.mmap_threshold) { + if (!mallopt(M_MMAP_THRESHOLD, g_conf.mmap_threshold)) + ERR("mallopt(M_MMAP_THRESHOLD) Fail"); + + if (!mallopt(M_TRIM_THRESHOLD, g_conf.mmap_threshold * 2)) + ERR("mallopt(M_TRIM_THRESHOLD) Fail"); + } + + __init_mtp_info(); + + _transport_init_status_info(); + _transport_set_mtp_operation_state(MTP_STATE_INITIALIZING); + + device_name = vconf_get_str(VCONFKEY_SETAPPL_DEVICE_NAME_STR); + if (device_name != NULL) { + _device_set_device_name(device_name); + g_free(device_name); + } else { + _device_set_device_name(MTP_DEV_PROPERTY_FRIENDLYNAME); + } + + sync_partner = vconf_get_str(VCONFKEY_MTP_SYNC_PARTNER_STR); + if (sync_partner != NULL && strlen(sync_partner) > 0) { + _device_set_sync_partner(sync_partner); + g_free(sync_partner); + } else { + _device_set_sync_partner(MTP_DEV_PROPERTY_SYNCPARTNER); + } + + + g_mgr->ftemp_st.filepath = g_strdup(MTP_TEMP_FILE_DEFAULT); + if (g_mgr->ftemp_st.filepath == NULL) { + ERR("g_strdup() Fail"); + goto MTP_INIT_FAIL; + } + + if (g_mgr->ftemp_st.temp_buff == NULL) { + /* Allocate memory for temporary */ + g_mgr->ftemp_st.temp_buff = (mtp_char *)g_malloc(g_conf.write_file_size); + if (g_mgr->ftemp_st.temp_buff == NULL) { + ERR("memory allocation fail"); + goto MTP_INIT_FAIL; + } + } + + /* Internal Storage */ + if (access(MTP_STORE_PATH_CHAR, F_OK) < 0) { + if (FALSE == _util_dir_create(MTP_STORE_PATH_CHAR, &error)) { + ERR("Cannot make directory!! [%s]\n", + MTP_STORE_PATH_CHAR); + goto MTP_INIT_FAIL; + } + } + /* External Storage */ + if (MTP_PHONE_MMC_INSERTED == _util_get_local_mmc_status()) { + if (access(MTP_EXTERNAL_PATH_CHAR, F_OK) < 0) { + if (FALSE == _util_dir_create(MTP_EXTERNAL_PATH_CHAR, &error)) { + ERR("Cannot make directory!! [%s]\n", + MTP_EXTERNAL_PATH_CHAR); + goto MTP_INIT_FAIL; + } + } + } +#ifndef MTP_SUPPORT_HIDE_WMPINFO_XML + /* Update WMPInfo.xml for preventing frequent saving */ + ret = _util_create_path(wmpinfopath, sizeof(wmpinfopath), + MTP_STORE_PATH_CHAR, MTP_FILE_NAME_WMPINFO_XML); + if (FALSE == ret) { + ERR("szWMPInfoPath is too long"); + goto MTP_INIT_FAIL; + } +#endif /*MTP_SUPPORT_HIDE_WMPINFO_XML*/ + + /* Set mtpdeviceinfo */ + _init_mtp_device(); + + _features_supported_info(); + + /* Install storage */ + _device_install_storage(sel); + +#ifdef MTP_SUPPORT_OBJECTADDDELETE_EVENT + _inoti_init_filesystem_evnts(); +#endif /*MTP_SUPPORT_OBJECTADDDELETE_EVENT*/ + + vconf_ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_MMC_STATUS, + _handle_mmc_notification, NULL); + if (vconf_ret < 0) { + ERR("vconf_notify_key_changed(%s) Fail", VCONFKEY_SYSMAN_MMC_STATUS); + goto MTP_INIT_FAIL; + } + + return; + +MTP_INIT_FAIL: + /* Set MTP state to stopped */ + _transport_set_mtp_operation_state(MTP_STATE_STOPPED); + mtp_end_event(); + + return; +} + +void _mtp_deinit(void) +{ + _cmd_hdlr_reset_cmd(&g_mgr->hdlr); + + /* initialize MTP_USE_FILE_BUFFER*/ + if (g_mgr->ftemp_st.temp_buff != NULL) { + g_free(g_mgr->ftemp_st.temp_buff); + g_mgr->ftemp_st.temp_buff = NULL; + } + +#ifdef MTP_SUPPORT_OBJECTADDDELETE_EVENT + _inoti_deinit_filesystem_events(); +#endif /*MTP_SUPPORT_OBJECTADDDELETE_EVENT*/ + + vconf_ignore_key_changed(VCONFKEY_SYSMAN_MMC_STATUS, + _handle_mmc_notification); + + return; +} + +static void __print_mtp_conf(void) +{ + if (g_conf.is_init == false) { + ERR("g_conf is not initialized"); + return; + } + + DBG("MMAP_THRESHOLD : %d\n", g_conf.mmap_threshold); + DBG("INIT_RX_IPC_SIZE : %d\n", g_conf.init_rx_ipc_size); + DBG("INIT_TX_IPC_SIZE : %d\n", g_conf.init_tx_ipc_size); + DBG("MAX_RX_IPC_SIZE : %d\n", g_conf.max_rx_ipc_size); + DBG("MAX_TX_IPC_SIZE : %d\n", g_conf.max_tx_ipc_size); + DBG("READ_USB_SIZE : %d\n", g_conf.read_usb_size); + DBG("WRITE_USB_SIZE : %d\n", g_conf.write_usb_size); + DBG("READ_FILE_SIZE : %d\n", g_conf.read_file_size); + DBG("WRITE_FILE_SIZE : %d\n", g_conf.write_file_size); + DBG("MAX_IO_BUF_SIZE : %d\n\n", g_conf.max_io_buf_size); + + DBG("SUPPORT_PTHEAD_SHCED : %s\n", g_conf.support_pthread_sched ? "Support" : "Not support"); + DBG("INHERITSCHED : %c\n", g_conf.inheritsched); + DBG("SCHEDPOLICY : %c\n", g_conf.schedpolicy); + DBG("FILE_SCHEDPARAM: %d\n", g_conf.file_schedparam); + DBG("USB_SCHEDPARAM: %d\n\n", g_conf.usb_schedparam); +} + +static void __read_mtp_conf(void) +{ + FILE *fp; + char buf[256]; + char *token; + + g_conf.mmap_threshold = MTP_MMAP_THRESHOLD; + + g_conf.read_usb_size = MTP_READ_USB_SIZE; + g_conf.write_usb_size = MTP_WRITE_USB_SIZE; + + g_conf.read_file_size = MTP_READ_FILE_SIZE; + g_conf.write_file_size = MTP_WRITE_FILE_SIZE; + + g_conf.init_rx_ipc_size = MTP_INIT_RX_IPC_SIZE; + g_conf.init_tx_ipc_size = MTP_INIT_TX_IPC_SIZE; + + g_conf.max_rx_ipc_size = MTP_MAX_RX_IPC_SIZE; + g_conf.max_tx_ipc_size = MTP_MAX_TX_IPC_SIZE; + + g_conf.max_io_buf_size = MTP_MAX_IO_BUF_SIZE; + g_conf.read_file_delay = MTP_READ_FILE_DELAY; + + if (MTP_SUPPORT_PTHREAD_SCHED) { + g_conf.support_pthread_sched = MTP_SUPPORT_PTHREAD_SCHED; + g_conf.inheritsched = MTP_INHERITSCHED; + g_conf.schedpolicy = MTP_SCHEDPOLICY; + g_conf.file_schedparam = MTP_FILE_SCHEDPARAM; + g_conf.usb_schedparam = MTP_USB_SCHEDPARAM; + } + + fp = fopen(MTP_CONFIG_FILE_PATH, "r"); + if (fp == NULL) { + DBG("Default configuration is used"); + g_conf.is_init = true; + + __print_mtp_conf(); + return; + } + + while (fgets(buf, sizeof(buf), fp)) { + if (buf[0] == '#' || buf[0] == '\n') + continue; + + token = strrchr(buf, '\n'); + if (token == NULL) { + ERR("g_conf is too long"); + break; + } + *token = '\0'; + + token = strtok(buf, "="); + if (token == NULL) { + continue; + } + + if (strcasecmp(token, "mmap_threshold") == 0) { + token = strtok(NULL, "="); + g_conf.mmap_threshold = atoi(token); + + } else if (strcasecmp(token, "init_rx_ipc_size") == 0) { + token = strtok(NULL, "="); + g_conf.init_rx_ipc_size = atoi(token); + + } else if (strcasecmp(token, "init_tx_ipc_size") == 0) { + token = strtok(NULL, "="); + g_conf.init_tx_ipc_size = atoi(token); + + } else if (strcasecmp(token, "max_rx_ipc_size") == 0) { + token = strtok(NULL, "="); + g_conf.max_rx_ipc_size = atoi(token); + + } else if (strcasecmp(token, "max_tx_ipc_size") == 0) { + token = strtok(NULL, "="); + g_conf.max_tx_ipc_size = atoi(token); + + } else if (strcasecmp(token, "read_usb_size") == 0) { + token = strtok(NULL, "="); + g_conf.read_usb_size = atoi(token); + + } else if (strcasecmp(token, "write_usb_size") == 0) { + token = strtok(NULL, "="); + g_conf.write_usb_size = atoi(token); + + } else if (strcasecmp(token, "read_file_size") == 0) { + token = strtok(NULL, "="); + g_conf.read_file_size = atoi(token); + + } else if (strcasecmp(token, "write_file_size") == 0) { + token = strtok(NULL, "="); + g_conf.write_file_size = atoi(token); + + } else if (strcasecmp(token, "max_io_buf_size") == 0) { + token = strtok(NULL, "="); + g_conf.max_io_buf_size = atoi(token); + + } else if (strcasecmp(token, "read_file_delay") == 0) { + token = strtok(NULL, "="); + g_conf.read_file_delay = atoi(token); + + } else if (strcasecmp(token, "support_pthread_sched") == 0) { + token = strtok(NULL, "="); + g_conf.support_pthread_sched = atoi(token) ? true : false; + + } else if (strcasecmp(token, "inheritsched") == 0) { + token = strtok(NULL, "="); + g_conf.inheritsched = *token; + + } else if (strcasecmp(token, "schedpolicy") == 0) { + token = strtok(NULL, "="); + g_conf.schedpolicy = *token; + + } else if (strcasecmp(token, "file_schedparam") == 0) { + token = strtok(NULL, "="); + g_conf.file_schedparam = atoi(token); + + } else if (strcasecmp(token, "usb_schedparam") == 0) { + token = strtok(NULL, "="); + g_conf.usb_schedparam = atoi(token); + + } else { + ERR("Unknown option : %s\n", buf); + } + } + fclose(fp); + g_conf.is_init = true; + + __print_mtp_conf(); + return; +} + +void __init_mtp_info(void) +{ + /* initialize struct one time*/ + memset(&g_mgr->ftemp_st, 0, sizeof(g_mgr->ftemp_st)); + memset(&g_mgr->hdlr, 0, sizeof(g_mgr->hdlr)); + memset(&g_mgr->meta_info, 0, sizeof(g_mgr->meta_info)); + + return ; +} + +void _features_supported_info(void) +{ + DBG("***********************************************************"); + DBG("### MTP Information ###"); + DBG("### 1. Solution : SLP"); + DBG("### 2. MTP Version : 1.0"); + DBG("### 3. DB Limitation : Reference(%d)\n", MTP_MAX_REFDB_ROWCNT); + + DBG("***********************************************************"); + DBG("### Extension ###"); + if (_get_oma_drm_status() == TRUE) { + DBG("### 2. OMADRM : [ON]"); + } else { + DBG("### 2. OMADRM : [OFF]"); + } + + DBG("***********************************************************"); + DBG("### Feature ###"); + +#ifdef MTP_SUPPORT_ALBUM_ART + DBG("### 2. MTP_SUPPORT_ALBUM_ART : [ON]"); +#else /* MTP_SUPPORT_ALBUM_ART */ + DBG("### 2. MTP_SUPPORT_ALBUM_ART : [OFF]"); +#endif /* MTP_SUPPORT_ALBUM_ART */ + +#ifdef MTP_SUPPORT_SET_PROTECTION + DBG("### 3. MTP_SUPPORT_SET_PROTECTION : [ON]"); +#else /* MTP_SUPPORT_SET_PROTECTION */ + DBG("### 3. MTP_SUPPORT_SET_PROTECTION : [OFF]"); +#endif /* MTP_SUPPORT_SET_PROTECTION */ + DBG("***********************************************************"); + return; +} + +/* + * void mtp_end_event(void) + * This function terminates mtp. + * It must not be called in gthr_mtp_event thread. + * It makes dead lock state if it is called in gthr_mtp_event thread. + */ +void mtp_end_event(void) +{ + __mtp_exit(); +} + +static inline int _main_init() +{ + pthread_mutexattr_t mutex_attr; + + pthread_mutexattr_init(&mutex_attr); + pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE); + if (0 != pthread_mutex_init(&g_cmd_inoti_mutex, &mutex_attr)) { + ERR("pthread_mutex_init() Fail"); + _util_print_error(); + pthread_mutexattr_destroy(&mutex_attr); + return MTP_ERROR_GENERAL; + } + pthread_mutexattr_destroy(&mutex_attr); + + if (_eh_handle_usb_events(USB_INSERTED) == FALSE) { + ERR("_eh_handle_usb_events() Fail"); + return MTP_ERROR_GENERAL; + } + + g_mainloop = g_main_loop_new(NULL, FALSE); + if (g_mainloop == NULL) { + ERR("g_mainloop is NULL"); + return MTP_ERROR_GENERAL; + } + + return MTP_ERROR_NONE; +} + +int main(int argc, char *argv[]) +{ + mtp_int32 ret; + + ret = media_content_connect(); + if (MEDIA_CONTENT_ERROR_NONE != ret) { + ERR("media_content_connect() Fail(%d)", ret); + return MTP_ERROR_GENERAL; + } + + if (_eh_register_notification_callbacks() == FALSE) { + ERR("_eh_register_notification_callbacks() Fail"); + return MTP_ERROR_GENERAL; + } + + ret = _main_init(); + if (MTP_ERROR_NONE != ret) { + ERR("_main_init() Fail(%d)", ret); + _eh_deregister_notification_callbacks(); + media_content_disconnect(); + return MTP_ERROR_GENERAL; + } + DBG("MTP UID = [%u] and GID = [%u]\n", getuid(), getgid()); + + g_main_loop_run(g_mainloop); + + _eh_deregister_notification_callbacks(); + media_content_disconnect(); + + return MTP_ERROR_NONE; +} diff --git a/src/mtp_inoti_handler.c b/src/mtp_inoti_handler.c new file mode 100755 index 0000000..64aeafc --- /dev/null +++ b/src/mtp_inoti_handler.c @@ -0,0 +1,709 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <unistd.h> +#include <sys/types.h> +#include <sys/syscall.h> +#include <sys/stat.h> +#include <glib.h> +#include <glib/gprintf.h> +#include "mtp_thread.h" +#include "mtp_inoti_handler.h" +#include "mtp_event_handler.h" +#include "mtp_support.h" +#include "mtp_device.h" +#include "mtp_util.h" + +/* + * GLOBAL AND STATIC VARIABLES + */ +pthread_mutex_t g_cmd_inoti_mutex; + +#ifdef MTP_SUPPORT_OBJECTADDDELETE_EVENT +mtp_char g_last_created_dir[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; +mtp_char g_last_deleted[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; +mtp_char g_last_moved[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; +mtp_char g_last_copied[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; +static pthread_t g_inoti_thrd; +static mtp_int32 g_cnt_watch_folder = 0; +static mtp_int32 g_inoti_fd; +static open_files_info_t *g_open_files_list; +static inoti_watches_t g_inoti_watches[INOTI_FOLDER_COUNT_MAX]; +#endif /*MTP_SUPPORT_OBJECTADDDELETE_EVENT*/ + +/* + * STATIC FUNCTIONS + */ +#ifdef MTP_SUPPORT_OBJECTADDDELETE_EVENT +static mtp_bool __process_inoti_event(struct inotify_event *event); +static void __remove_inoti_watch(mtp_char *path); +static mtp_bool __add_file_to_inoti_open_files_list(mtp_int32 wd, + mtp_char *event_name); +static open_files_info_t *__find_file_in_inoti_open_files_list(mtp_int32 wd, + mtp_char *event_name); +static void __remove_file_from_inoti_open_files_list(open_files_info_t *node); +static mtp_int32 __get_inoti_watch_id(mtp_int32 iwd); +static mtp_bool __get_inoti_event_full_path(mtp_int32 wd, mtp_char *event_name, + mtp_char *path, mtp_int32 path_len, mtp_char *parent_path); +static void __remove_recursive_inoti_watch(mtp_char *path); +static void __clean_up_inoti(void *data); +static void __delete_children_from_store_inoti(mtp_store_t *store, + mtp_obj_t *obj); +static void __process_object_added_event(mtp_char *fullpath, + mtp_char *file_name, mtp_char *parent_path); +static void __process_object_deleted_event(mtp_char *fullpath, + mtp_char *file_name, mtp_bool isdir); +static void __destroy_inoti_open_files_list(); +#endif /* MTP_SUPPORT_OBJECTADDDELETE_EVENT */ + +/* + * FUNCTIONS + */ +#ifdef MTP_SUPPORT_OBJECTADDDELETE_EVENT +void *_thread_inoti(void *arg) +{ + mtp_int32 i = 0; + mtp_int32 length = 0; + mtp_int64 temp_idx; + mtp_char buffer[INOTI_BUF_LEN] = { 0 }; + struct inotify_event *event = NULL; + + pthread_cleanup_push(__clean_up_inoti, NULL); + + DBG("START INOTIFY SYSTEM"); + + while (1) { + pthread_testcancel(); + errno = 0; + i = 0; + length = read(g_inoti_fd, buffer, sizeof(buffer)); + if (length < 0) { + ERR("read() Fail"); + _util_print_error(); + break; + } + + while (i < length) { + event = (struct inotify_event *)(&buffer[i]); + __process_inoti_event(event); + temp_idx = i + event->len + INOTI_EVENT_SIZE; + if (temp_idx > length) { + break; + } else { + i = temp_idx; + } + } + } + + DBG("Inoti thread exited"); + pthread_cleanup_pop(1); + + return NULL; +} + +void _inoti_add_watch_for_fs_events(mtp_char *path) +{ + mtp_int32 i = 0; + + ret_if(path == NULL); + + if (g_cnt_watch_folder == INOTI_FOLDER_COUNT_MAX) { + /* find empty cell */ + for (i = 0; i < INOTI_FOLDER_COUNT_MAX; i++) { + /* If not empty */ + if (g_inoti_watches[i].wd != 0) { + continue; + } else { + break; + } + } + + if (i == INOTI_FOLDER_COUNT_MAX) { + ERR("no empty space for a new inotify watch."); + return; + } + DBG("g_watch_folders[%d] add watch : %s\n", i, path); + g_inoti_watches[i].forlder_name = g_strdup(path); + g_inoti_watches[i].wd = inotify_add_watch(g_inoti_fd, + g_inoti_watches[i].forlder_name, + IN_CLOSE_WRITE | IN_CREATE | + IN_DELETE | IN_MOVED_FROM | + IN_MOVED_TO); + return; + } + + DBG("g_watch_folders[%d] add watch : %s\n", g_cnt_watch_folder, path); + g_inoti_watches[g_cnt_watch_folder].forlder_name = g_strdup(path); + g_inoti_watches[g_cnt_watch_folder].wd = inotify_add_watch(g_inoti_fd, + g_inoti_watches[g_cnt_watch_folder].forlder_name, + IN_CLOSE_WRITE | + IN_CREATE | IN_DELETE | + IN_MOVED_FROM | + IN_MOVED_TO); + g_cnt_watch_folder++; + + return; +} + +mtp_bool _inoti_init_filesystem_evnts() +{ + mtp_bool ret = FALSE; + + g_inoti_fd = inotify_init(); + if (g_inoti_fd < 0) { + ERR("inotify_init() Fail : g_inoti_fd = %d", g_inoti_fd); + return FALSE; + } + + ret = _util_thread_create(&g_inoti_thrd, "File system inotify thread\n", + PTHREAD_CREATE_JOINABLE, _thread_inoti, NULL); + if (FALSE == ret) { + ERR("_util_thread_create() Fail"); + _util_print_error(); + close(g_inoti_fd); + return FALSE; + } + + return TRUE; +} + +static mtp_bool __process_inoti_event(struct inotify_event *event) +{ + static mtp_int32 last_moved_cookie = -1; + + mtp_bool res = FALSE; + mtp_char full_path[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char parentpath[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + + if (event->len == 0 || event->len > MTP_MAX_FILENAME_SIZE) { + ERR_SECURE("Event len is invalid[%d], event->name[%s]\n", event->len, + event->name); + return FALSE; + } else if (event->wd < 1) { + ERR("invalid wd : %d\n", event->wd); + return FALSE; + } + + /* start of one event */ + res = __get_inoti_event_full_path(event->wd, event->name, full_path, + sizeof(full_path), parentpath); + if (res == FALSE) { + ERR("__get_inoti_event_full_path() Fail"); + return FALSE; + } + + if (_util_is_path_len_valid(full_path) == FALSE) { + ERR("path len is invalid"); + return FALSE; + } + DBG_SECURE("Event full path = %s\n", full_path); + if (event->mask & IN_MOVED_FROM) { + if (!g_strcmp0(g_last_moved, full_path)) { + /* Ignore this case as this is generated due to MTP*/ + DBG("[%s] is moved_from by MTP\n", full_path); + memset(g_last_moved, 0, + MTP_MAX_PATHNAME_SIZE + 1); + last_moved_cookie = event->cookie; + } else if (event->mask & IN_ISDIR) { + DBG("IN_MOVED_FROM --> IN_ISDIR"); + UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex); + __process_object_deleted_event(full_path, + event->name, TRUE); + UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex); + } else { + DBG("IN_MOVED_FROM --> NOT IN_ISDIR"); + UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex); + __process_object_deleted_event(full_path, + event->name, FALSE); + UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex); + } + } else if (event->mask & IN_MOVED_TO) { + DBG("Moved To event, path = [%s]\n", full_path); + if (last_moved_cookie == event->cookie) { + /* Ignore this case as this is generated due to MTP*/ + DBG("%s is moved_to by MTP\n", full_path); + last_moved_cookie = -1; + } else { + UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex); + __process_object_added_event(full_path, + event->name, parentpath); + UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex); + } + } else if (event->mask & IN_CREATE) { + if (event->mask & IN_ISDIR) { + DBG("IN_CREATE --> IN_ISDIR"); + if (!g_strcmp0(g_last_created_dir, full_path)) { + /* Ignore this case as this is generated due to MTP*/ + DBG("%s folder is generated by MTP\n", + full_path); + memset(g_last_created_dir, 0, + MTP_MAX_PATHNAME_SIZE + 1); + } else { + UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex); + __process_object_added_event(full_path, + event->name, parentpath); + UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex); + } + } else { + if (FALSE == __add_file_to_inoti_open_files_list(event->wd, + event->name)) { + DBG_SECURE("__add_file_to_inoti_open_files_list fail\ + %s\n", event->name); + } + DBG("IN_CREATE --> NOT IN_ISDIR"); + } + } else if (event->mask & IN_DELETE) { + if (!g_strcmp0(g_last_deleted, full_path)) { + /* Ignore this case as this is generated due to MTP*/ + DBG("%s is deleted by MTP\n", full_path); + memset(g_last_deleted, 0, + MTP_MAX_PATHNAME_SIZE + 1); + } else if (event->mask & IN_ISDIR) { + DBG("IN_DELETE --> IN_ISDIR"); + UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex); + __process_object_deleted_event(full_path, + event->name, TRUE); + UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex); + } else { + DBG("IN_DELETE --> NOT IN_ISDIR"); + UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex); + __process_object_deleted_event(full_path, + event->name, FALSE); + UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex); + } + } else if (event->mask & IN_CLOSE_WRITE) { + DBG_SECURE("IN_CLOSE_WRITE %d, %s\n", event->wd, event->name); + if (!g_strcmp0(g_last_copied, full_path)) { + /* Ignore this case as this is generated due to MTP*/ + DBG("[%s] is copied by MTP\n", full_path); + memset(g_last_copied, 0, + MTP_MAX_PATHNAME_SIZE + 1); + } else { + open_files_info_t *node = NULL; + node = __find_file_in_inoti_open_files_list(event->wd, + event->name); + + if (node != NULL) { + UTIL_LOCK_MUTEX(&g_cmd_inoti_mutex); + __process_object_added_event(full_path, + event->name, parentpath); + UTIL_UNLOCK_MUTEX(&g_cmd_inoti_mutex); + __remove_file_from_inoti_open_files_list(node); + } + } + } else { + DBG("This case is ignored"); + return FALSE; + } + + return TRUE; +} + +void _inoti_deinit_filesystem_events() +{ + if (TRUE != _util_thread_cancel(g_inoti_thrd)) { + ERR("thread cancel fail."); + return; + } + + if (_util_thread_join(g_inoti_thrd, 0) == FALSE) { + ERR("_util_thread_join() Fail"); + } + + return; +} + +static void __remove_inoti_watch(mtp_char *path) +{ + mtp_int32 i = 0; + + for (i = 0; i < g_cnt_watch_folder; i++) { + if (g_inoti_watches[i].forlder_name == NULL) { + continue; + } + + if (g_strcmp0(g_inoti_watches[i].forlder_name, path) != 0) { + continue; + } + + g_free(g_inoti_watches[i].forlder_name); + g_inoti_watches[i].forlder_name = NULL; + inotify_rm_watch(g_inoti_fd, g_inoti_watches[i].wd); + g_inoti_watches[i].wd = 0; + + break; + } + + if (i == g_cnt_watch_folder) + ERR("Path not found in g_noti_watches"); + return; +} + +static mtp_bool __add_file_to_inoti_open_files_list(mtp_int32 wd, + mtp_char *event_name) +{ + open_files_info_t *new_node = NULL; + + new_node = (open_files_info_t *)g_malloc(sizeof(open_files_info_t)); + if (NULL == new_node) { + ERR("new_node is null malloc fail"); + return FALSE; + } + + new_node->name = g_strdup(event_name); + new_node->wd = wd; + + /* First created file */ + if (NULL == g_open_files_list) { + new_node->previous = NULL; + } else { + g_open_files_list->next = new_node; + new_node->previous = g_open_files_list; + } + new_node->next = NULL; + g_open_files_list = new_node; + + return TRUE; +} + +static open_files_info_t *__find_file_in_inoti_open_files_list(mtp_int32 wd, + mtp_char *event_name) +{ + open_files_info_t *current_node = g_open_files_list; + + while (NULL != current_node) { + if ((current_node->wd == wd) && + (g_strcmp0(current_node->name, event_name) == 0)) { + return current_node; + } + + current_node = current_node->previous; + } + + ERR("Cannot find file in open file's list"); + return NULL; +} + +static void __remove_file_from_inoti_open_files_list(open_files_info_t *node) +{ + if (NULL != node->previous) { + node->previous->next = node->next; + } + + if (NULL != node->next) { + node->next->previous = node->previous; + } + + if (node == g_open_files_list) { + g_open_files_list = node->previous; + } + g_free(node->name); + g_free(node); + + return; +} + +static mtp_int32 __get_inoti_watch_id(mtp_int32 iwd) +{ + mtp_int32 i = 0; + + for (i = 0; i < INOTI_FOLDER_COUNT_MAX; i++) { + if (iwd == g_inoti_watches[i].wd) + break; + } + + if (i >= INOTI_FOLDER_COUNT_MAX) { + ERR("inoti_folder is not found"); + return -1; + } + + return i; +} + +static mtp_bool __get_inoti_event_full_path(mtp_int32 wd, mtp_char *event_name, + mtp_char *path, mtp_int32 path_len, mtp_char *parent_path) +{ + mtp_int32 inoti_id = 0; + + retv_if(wd == 0, FALSE); + retv_if(path == NULL, FALSE); + retv_if(event_name == NULL, FALSE); + + inoti_id = __get_inoti_watch_id(wd); + if (inoti_id < 0) { + ERR("FAIL to find last_inoti_id : %d\n", inoti_id); + return FALSE; + } + + /* 2 is for / and null character */ + if (path_len < (strlen(g_inoti_watches[inoti_id].forlder_name) + + strlen(event_name) + 2)) + return FALSE; + + g_snprintf(path, path_len, "%s/%s", + g_inoti_watches[inoti_id].forlder_name, event_name); + g_snprintf(parent_path, path_len, "%s", + g_inoti_watches[inoti_id].forlder_name); + + return TRUE; +} + +static void __remove_recursive_inoti_watch(mtp_char *path) +{ + mtp_int32 i = 0; + mtp_char *res = NULL; + + for (i = 0; i < g_cnt_watch_folder; i++) { + if (g_inoti_watches[i].forlder_name == NULL) + continue; + + res = strstr(g_inoti_watches[i].forlder_name, path); + if (res == NULL) + continue; + + g_free(g_inoti_watches[i].forlder_name); + g_inoti_watches[i].forlder_name = NULL; + inotify_rm_watch(g_inoti_fd, g_inoti_watches[i].wd); + g_inoti_watches[i].wd = 0; + } + + return; +} + +static void __clean_up_inoti(void *data) +{ + __remove_recursive_inoti_watch(MTP_STORE_PATH_CHAR); + __remove_recursive_inoti_watch(MTP_EXTERNAL_PATH_CHAR); + __destroy_inoti_open_files_list(); + + close(g_inoti_fd); + g_inoti_fd = 0; + return; +} + +static void __delete_children_from_store_inoti(mtp_store_t *store, + mtp_obj_t *obj) +{ + mtp_uint32 i = 0; + ptp_array_t child_arr = { 0 }; + mtp_obj_t *child_obj = NULL; + slist_node_t *node = NULL; + + __remove_inoti_watch(obj->file_path); + + _prop_init_ptparray(&child_arr, UINT32_TYPE); + _entity_get_child_handles(store, obj->obj_handle, &child_arr); + + for (i = 0; i < child_arr.num_ele; i++) { + + mtp_uint32 *ptr32 = child_arr.array_entry; + child_obj = _entity_get_object_from_store(store, ptr32[i]); + + if (child_obj != NULL && child_obj->obj_info != NULL && + child_obj->obj_info->obj_fmt == + PTP_FMT_ASSOCIATION) { + __delete_children_from_store_inoti(store, child_obj); + } + + node = _util_delete_node(&(store->obj_list), child_obj); + g_free(node); + _entity_dealloc_mtp_obj(child_obj); + } + + _prop_deinit_ptparray(&child_arr); + return; +} + +static void __process_object_added_event(mtp_char *fullpath, + mtp_char *file_name, mtp_char *parent_path) +{ + mtp_uint32 store_id = 0; + mtp_store_t *store = NULL; + mtp_obj_t *parent_obj = NULL; + mtp_uint32 h_parent = 0; + mtp_obj_t *obj = NULL; + struct stat stat_buf = { 0 }; + mtp_int32 ret = 0; + dir_entry_t dir_info = { { 0 }, 0 }; + + if (NULL != g_strrstr(file_name, MTP_TEMP_FILE)) { + ERR("File is a temp file"); + return; + } + + if (file_name[0] == '.') { + DBG_SECURE("Hidden file filename=[%s]\n", file_name); + return; + } + + store_id = _entity_get_store_id_by_path(fullpath); + store = _device_get_store(store_id); + if (NULL == store) { + ERR("store is NULL so return"); + return; + } + parent_obj = _entity_get_object_from_store_by_path(store, parent_path); + if (NULL == parent_obj) { + if (!g_strcmp0(parent_path, MTP_STORE_PATH_CHAR) || + !g_strcmp0(parent_path, MTP_EXTERNAL_PATH_CHAR)) + { + DBG("parent is the root folder"); + h_parent = 0; + } else { + DBG("Cannot find the parent, return"); + return; + } + } else { + h_parent = parent_obj->obj_handle; + } + + ret = stat(fullpath, &stat_buf); + if (ret < 0) { + ERR("stat() Fail"); + _util_print_error(); + return; + } + + g_strlcpy(dir_info.filename, fullpath, MTP_MAX_PATHNAME_SIZE + 1); + dir_info.attrs.mtime = stat_buf.st_mtime; + dir_info.attrs.fsize = stat_buf.st_size; + + /* Reset the attributes */ + dir_info.attrs.attribute = MTP_FILE_ATTR_MODE_NONE; + if (S_ISBLK(stat_buf.st_mode) || S_ISCHR(stat_buf.st_mode) || + S_ISLNK(stat_buf.st_mode) || S_ISSOCK(stat_buf.st_mode)) { + dir_info.attrs.attribute |= MTP_FILE_ATTR_MODE_SYSTEM; + } + + if (S_ISREG(stat_buf.st_mode)) { + dir_info.type = MTP_FILE_TYPE; + dir_info.attrs.attribute |= MTP_FILE_ATTR_MODE_NONE; + + if (!((S_IWUSR & stat_buf.st_mode) || + (S_IWGRP & stat_buf.st_mode) || + (S_IWOTH & stat_buf.st_mode))) { + dir_info.attrs.attribute |= MTP_FILE_ATTR_MODE_READ_ONLY; + } + + obj = _entity_add_file_to_store(store, h_parent, fullpath, + file_name, &dir_info); + if (NULL == obj) { + ERR("_entity_add_file_to_store fail."); + return; + } + } else if (S_ISDIR(stat_buf.st_mode)) { + dir_info.type = MTP_DIR_TYPE; + dir_info.attrs.attribute |= MTP_FILE_ATTR_MODE_DIR; + obj = _entity_add_folder_to_store(store, h_parent, fullpath, + file_name, &dir_info); + if (NULL == obj) { + ERR("_entity_add_folder_to_store fail."); + return; + } + } else { + ERR("%s type is neither DIR nor FILE.\n", fullpath); + return; + } + + _eh_send_event_req_to_eh_thread(EVENT_OBJECT_ADDED, + obj->obj_handle, 0, NULL); + + return; +} + +static void __process_object_deleted_event(mtp_char *fullpath, + mtp_char *file_name, mtp_bool isdir) +{ + mtp_obj_t *obj = NULL; + mtp_obj_t *parent_obj = NULL; + mtp_store_t *store = NULL; + mtp_uint32 storageid = 0; + mtp_uint32 h_parent = 0; + mtp_uint32 obj_handle = 0; + slist_node_t *node = NULL; + + if (NULL != strstr(fullpath, MTP_TEMP_FILE)) { + ERR("File is a temp file, need to ignore"); + return; + } + + if (file_name[0] == '.') { + DBG_SECURE("Hidden file filename=[%s], Ignore\n", file_name); + return; + } + + storageid = _entity_get_store_id_by_path(fullpath); + store = _device_get_store(storageid); + if (NULL == store) { + ERR("store is NULL so return"); + return; + } + + obj = _entity_get_object_from_store_by_path(store, fullpath); + if (NULL == obj) { + ERR("object is NULL so return"); + return; + } + + obj_handle = obj->obj_handle; + h_parent = obj->obj_info->h_parent; + if (h_parent != PTP_OBJECTHANDLE_ROOT) { + parent_obj = _entity_get_object_from_store(store, h_parent); + if (NULL != parent_obj) { + _entity_remove_reference_child_array(parent_obj, + obj->obj_handle); + } + } + + if (TRUE == isdir) { + __delete_children_from_store_inoti(store, obj); + } + + node = _util_delete_node(&(store->obj_list), obj); + g_free(node); + _entity_dealloc_mtp_obj(obj); + + _eh_send_event_req_to_eh_thread(EVENT_OBJECT_REMOVED, obj_handle, + 0, NULL); + + return; +} + +static void __destroy_inoti_open_files_list() +{ + open_files_info_t *current = NULL; + + ret_if(g_open_files_list == NULL); + + while(g_open_files_list) { + current = g_open_files_list; + g_open_files_list = g_open_files_list->previous; + + if (g_open_files_list) { + g_open_files_list->next = NULL; + } + + g_free(current->name); + current->wd = 0; + current->previous = NULL; + current->next = NULL; + g_free(current); + } + + g_open_files_list = NULL; + return; +} +#endif /*MTP_SUPPORT_OBJECTADDDELETE_EVENT*/ diff --git a/src/ptp_container.c b/src/ptp_container.c new file mode 100755 index 0000000..d9a8aa8 --- /dev/null +++ b/src/ptp_container.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <glib.h> +#include "ptp_container.h" +#include "ptp_datacodes.h" +#include "mtp_transport.h" +#include "mtp_support.h" +#include "mtp_util.h" + +/* + * FUNCTIONS + */ +void _hdlr_init_cmd_container(cmd_container_t *cntr) +{ + cntr->tid = 0; + cntr->type = CONTAINER_UNDEFINED; + cntr->code = PTP_OPCODE_UNDEFINED; + cntr->len = sizeof(header_container_t); + cntr->no_param = 0; + return; +} + +mtp_uint32 _hdlr_get_param_cmd_container(cmd_container_t *cntr, + mtp_uint32 index) +{ + if (index < cntr->no_param) { + return cntr->params[index]; + } + return 0; +} + +void _hdlr_copy_cmd_container_unknown_params(cmd_container_t *src, + cmd_container_t *dst) +{ + mtp_uint16 ii; + + dst->tid = src->tid; + dst->type = src->type; + dst->code = src->code; + dst->len = src->len; + dst->no_param = + (src->len - sizeof(header_container_t)) / sizeof(mtp_uint32); + + for (ii = 0; ii < dst->no_param; ii++) { + dst->params[ii] = src->params[ii]; + } + return; +} + +void _hdlr_copy_cmd_container(cmd_container_t *src, cmd_container_t *dst) +{ + mtp_uint16 ii; + + dst->tid = src->tid; + dst->type = src->type; + dst->code = src->code; + dst->len = src->len; + dst->no_param = src->no_param; + + for (ii = 0; ii < dst->no_param; ii++) { + dst->params[ii] = src->params[ii]; + } + + return; +} + +mtp_bool _hdlr_add_param_resp_container(resp_blk_t *dst, mtp_uint32 num, + mtp_uint32 *params) +{ + mtp_uint16 ii; + + retvm_if(num > MAX_MTP_PARAMS, FALSE, "num(%d) exceed", num); + retvm_if(num != 0 && params == NULL, FALSE, "num = %d, params = %p", num, params); + + dst->no_param = num; + dst->len = sizeof(header_container_t) + sizeof(mtp_uint32) * (dst->no_param); + + for (ii = 0; ii < dst->no_param; ii++) { + dst->params[ii] = params[ii]; +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(&(dst->params[ii]), + sizeof(dst->params[ii])); +#endif /* __BIG_ENDIAN__ */ + } +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(&(dst->no_param), sizeof(dst->no_param)); + _util_conv_byte_order(&(dst->len), sizeof(dst->len)); +#endif /* __BIG_ENDIAN__ */ + + return TRUE; +} + +mtp_bool _hdlr_validate_cmd_container(mtp_uchar *blk, mtp_uint32 size) +{ + if (size < sizeof(header_container_t) || size > sizeof(cmd_container_t)) + return FALSE; + + cmd_container_t *ptr = NULL; + + ptr = (cmd_container_t *)blk; + + if (ptr->len != size || ptr->type != CONTAINER_CMD_BLK) { + ERR("size = [%d] length[%d] type[%d]\n", size, ptr->len, + ptr->type); + return FALSE; + } + + return TRUE; +} + +void _hdlr_init_data_container(data_container_t *dst, mtp_uint16 code, + mtp_uint32 trans_id) +{ + _hdlr_init_cmd_container((cmd_container_t *)dst); + dst->type = CONTAINER_DATA_BLK; + dst->code = code; + dst->tid = trans_id; + dst->data = NULL; +#ifdef __BIG_ENDIAN__ + _hdlr_conv_data_container_byte_order(dst); +#endif /* __BIG_ENDIAN__ */ + return; +} + +mtp_uchar *_hdlr_alloc_buf_data_container(data_container_t *dst, + mtp_uint32 bufsz, mtp_uint64 pkt_size) +{ + mtp_uint32 blk_len; + header_container_t *header = NULL; + + pkt_size = (pkt_size + sizeof(header_container_t) > 0xFFFFFFFF) ? + 0xFFFFFFFF : pkt_size + sizeof(header_container_t); + + + blk_len = bufsz + sizeof(header_container_t); + dst->data = (mtp_uchar *)g_malloc(blk_len); + if (dst->data == NULL) { + ERR("g_malloc() Fail"); + return NULL; + } + + memset(dst->data, 0, blk_len); + dst->len = bufsz + sizeof(header_container_t); + header = (header_container_t *)dst->data; + header->len = pkt_size; +#ifdef __BIG_ENDIAN__ + _util_conv_byte_order(&(header->len), sizeof(header->len)); +#endif /* __BIG_ENDIAN__ */ + header->type = dst->type; + header->code = dst->code; + header->tid = dst->tid; + return (dst->data + sizeof(header_container_t)); +} + +mtp_bool _hdlr_send_data_container(data_container_t *dst) +{ + mtp_uint32 sent; + + sent = _transport_send_pkt_to_tx_mq(dst->data, dst->len); + + if (sent != dst->len) + return FALSE; + + return TRUE; +} + +mtp_bool _hdlr_send_bulk_data(mtp_uchar *dst, mtp_uint32 len) +{ + mtp_uint32 sent = 0; + + sent = _transport_send_bulk_pkt_to_tx_mq(dst, len); + if (sent != len) + return FALSE; + + return TRUE; +} + +mtp_bool _hdlr_rcv_data_container(data_container_t *dst, mtp_uint32 size) +{ + mtp_uint32 blk_size; + mtp_uint32 bytes_rcvd; + mtp_uint16 exp_code; + mtp_uint32 exp_tid; + header_container_t *header = NULL; + + g_free(dst->data); + dst->data = NULL; + + /* Allocated space for data + header */ + /* Also allocate extra space in case chip writes DWORDS */ + + blk_size = size + sizeof(header_container_t) + sizeof(mtp_uint32); + dst->data = (mtp_uchar *)g_malloc(blk_size); + if (dst->data == NULL) { + ERR("g_malloc() Fail"); + return FALSE; + } + bytes_rcvd = 0; + + _transport_rcv_temp_file_data(dst->data, blk_size, &bytes_rcvd); + exp_code = dst->code; + exp_tid = dst->tid; + header = (header_container_t *)dst->data; + +#ifdef __BIG_ENDIAN__ + _hdlr_conv_data_container_byte_order((data_container_t *)dst->data); +#endif /* __BIG_ENDIAN__ */ + + /* Copy the header from the data block to the structure */ + dst->len = header->len; + dst->type = header->type; + dst->code = header->code; + dst->tid = header->tid; + if (dst->len != bytes_rcvd || dst->type != CONTAINER_DATA_BLK || + dst->code != exp_code || dst->tid != exp_tid) { + ERR("HEADER FAILURE"); + ERR("HEADER length[%d], Type[%d], Code[%d], tid[%d]\n", + dst->len, dst->type, dst->code, dst->tid); + ERR("EXPECTED length[%d], Type[%d], Code[%d], tid[%d]\n", + bytes_rcvd, CONTAINER_DATA_BLK, exp_code, exp_tid); + return FALSE; + } + + return TRUE; +} + +mtp_bool _hdlr_rcv_file_in_data_container(data_container_t *dst, + mtp_char *filepath, mtp_uint32 path_len) +{ + mtp_uint32 blk_size; + mtp_uint64 bytes_rcvd; + mtp_uint16 exp_code; + mtp_uint32 exp_tid; + header_container_t *header = NULL; + + g_free(dst->data); + dst->data = NULL; + + /* Allocated space for data + header */ + /* Also allocate extra space in case chip writes DWORDS */ + + blk_size = sizeof(header_container_t) + sizeof(mtp_uint32); + dst->data = (mtp_uchar *)g_malloc((mtp_uint32) blk_size); + if (dst->data == NULL) { + ERR("g_malloc() Fail"); + return FALSE; + } + + bytes_rcvd = 0; + _transport_rcv_temp_file_info(dst->data, filepath, &bytes_rcvd, + path_len); + exp_code = dst->code; + exp_tid = dst->tid; + header = (header_container_t *)dst->data; + +#ifdef __BIG_ENDIAN__ + _hdlr_conv_data_container_byte_order((data_container_t *)dst->data); +#endif /* __BIG_ENDIAN__ */ + + /* Copy the header from the data block to the structure */ + dst->len = header->len; + dst->type = header->type; + dst->code = header->code; + dst->tid = header->tid; + + if ((dst->len != bytes_rcvd && bytes_rcvd < MTP_FILESIZE_4GB) || + dst->type != CONTAINER_DATA_BLK || + dst->code != exp_code || dst->tid != exp_tid) { + ERR("HEADER FAILURE"); + ERR("HEADER length[%d], Type[%d], Code[%d], tid[%d]\n", + dst->len, dst->type, dst->code, dst->tid); + ERR("EXPECTED length[%d], Type[%d], Code[%d], tid[%d]\n", + bytes_rcvd, CONTAINER_DATA_BLK, exp_code, exp_tid); + return FALSE; + } + + return TRUE; +} + +mtp_uint32 _hdlr_get_payload_size(data_container_t *dst) +{ + if (dst->data == NULL) { + ERR("Payload data is NULL"); + return 0; + } + + return (dst->len - sizeof(header_container_t)); +} + +mtp_uchar *_hdlr_get_payload_data(data_container_t *dst) +{ + if (dst->data == NULL) { + ERR("Payload data is NULL"); + return NULL; + } + + return (dst->data + sizeof(header_container_t)); +} + +void _hdlr_resp_container_init(cmd_container_t *dst, mtp_uint16 resp_code, + mtp_uint32 tid) +{ + _hdlr_init_cmd_container(dst); + dst->type = CONTAINER_RESP_BLK; + dst->code = resp_code; + dst->tid = tid; +#ifdef __BIG_ENDIAN__ + _hdlr_conv_cmd_container_byte_order(dst); +#endif /* __BIG_ENDIAN__ */ + return; +} + +mtp_bool _hdlr_send_resp_container(cmd_container_t *dst) +{ + mtp_uint32 sent = 0; + +#ifdef __BIG_ENDIAN__ + resp_blk_t resp_blk; + + _hdlr_copy_cmd_container(dst, &resp_blk); + _hdlr_conv_cmd_container_byte_order(&resp_blk); + sent = _transport_send_pkt_to_tx_mq((mtp_uchar *)&resp_blk, dst->len); +#else /* __BIG_ENDIAN__ */ + + sent = _transport_send_pkt_to_tx_mq((mtp_uchar *)dst, dst->len); +#endif + if (sent != dst->len) { + ERR("_transport_send_pkt_to_tx_mq() Fail: dst->len(%u), sent(%u)", + dst->len, sent); + return FALSE; + } + + return TRUE; +} + +void _hdlr_init_event_container(cmd_container_t *dst, mtp_uint16 code, + mtp_uint32 tid, mtp_uint32 param1, mtp_uint32 param2) +{ + dst->type = CONTAINER_EVENT_BLK; + dst->code = code; + dst->tid = tid; + dst->no_param = 1; + dst->params[0] = param1; + dst->len = sizeof(header_container_t) + sizeof(mtp_uint32) * 1; +#ifdef __BIG_ENDIAN__ + _hdlr_conv_cmd_container_byte_order(dst); +#endif /* __BIG_ENDIAN__ */ + return; +} + +void _hdlr_init_event_container_with_param(cmd_container_t *dst, + mtp_uint16 code, mtp_uint32 tid, mtp_uint32 param1, mtp_uint32 param2) +{ + dst->type = CONTAINER_EVENT_BLK; + dst->code = code; + dst->tid = tid; + dst->no_param = 2; + dst->params[0] = param1; + dst->params[1] = param2; + dst->len = sizeof(header_container_t) + sizeof(mtp_uint32) * 3; +#ifdef __BIG_ENDIAN__ + _hdlr_conv_cmd_container_byte_order(dst); +#endif /* __BIG_ENDIAN__ */ + return; +} +mtp_bool _hdlr_send_event_container(cmd_container_t *dst) +{ + mtp_uint32 sent = 0; + mtp_err_t retval; + + retval = _transport_send_event((mtp_uchar *)dst, dst->len, &sent); + return (retval == MTP_ERROR_NONE && sent == dst->len) ? + TRUE : FALSE; +} + +void _hdlr_conv_cmd_container_byte_order(cmd_container_t *dst) +{ +#ifdef __BIG_ENDIAN__ + mtp_uchar idx; + + _util_conv_byte_order(&(dst->code), sizeof(dst->code)); + _util_conv_byte_order(&(dst->len), sizeof(dst->len)); + _util_conv_byte_order(&(dst->no_param), sizeof(dst->NumParams)); + _util_conv_byte_order(&(dst->tid), sizeof(dst->tid)); + _util_conv_byte_order(&(dst->type), sizeof(dst->Type)); + + for (idx = 0; idx < dst->no_param; idx++) { + _util_conv_byte_order(&(dst->params[idx]), + sizeof(dst->params[idx])); + } +#endif /* __BIG_ENDIAN__ */ + return; +} + +void _hdlr_conv_data_container_byte_order(data_container_t *dst) +{ +#ifdef __BIG_ENDIAN__ + mtp_uchar idx; + + _util_conv_byte_order(&(dst->code), sizeof(dst->code)); + _util_conv_byte_order(&(dst->len), sizeof(dst->len)); + _util_conv_byte_order(&(dst->no_param), sizeof(dst->NumParams)); + _util_conv_byte_order(&(dst->tid), sizeof(dst->tid)); + _util_conv_byte_order(&(dst->type), sizeof(dst->Type)); + for (idx = 0; idx < dst->no_param; idx++) { + _util_conv_byte_order(&(dst->params[idx]), + sizeof(dst->params[idx])); + } +#endif /* __BIG_ENDIAN__ */ + return; +} diff --git a/src/transport/mtp_transport.c b/src/transport/mtp_transport.c new file mode 100755 index 0000000..2e382c3 --- /dev/null +++ b/src/transport/mtp_transport.c @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <unistd.h> +#include <glib.h> +#include "mtp_config.h" +#include "mtp_transport.h" +#include "mtp_support.h" +#include "mtp_util.h" +#include "ptp_datacodes.h" +#include "mtp_device.h" +#include "mtp_msgq.h" +#include "mtp_cmd_handler.h" +#include "mtp_thread.h" +#include "mtp_usb_driver.h" + +/* + * GLOBAL AND EXTERN VARIABLES + */ +extern mtp_config_t g_conf; +extern mtp_mgr_t g_mtp_mgr; + +/* + * STATIC VARIABLES + */ +static mtp_mgr_t *g_mgr = &g_mtp_mgr; +static mtp_bool g_usb_threads_created = FALSE; +static pthread_t g_tx_thrd = 0; +static pthread_t g_rx_thrd = 0; +static pthread_t g_data_rcv = 0; +static msgq_id_t mtp_to_usb_mqid; +static msgq_id_t g_usb_to_mtp_mqid; +static status_info_t g_status; + +/* + * STATIC FUNCTIONS + */ +static void *__transport_thread_data_rcv(void *func); +static mtp_err_t __transport_init_io(); +static void __transport_deinit_io(); + +/* + * FUNCTIONS + */ +void _transport_save_cmd_buffer(mtp_char *buffer, mtp_uint32 size) +{ + memcpy(g_mgr->ftemp_st.cmd_buf, buffer, size); + g_mgr->ftemp_st.cmd_size = size; + g_mgr->ftemp_st.data_count = 0; + return; +} + +mtp_err_t _transport_rcv_temp_file_data(mtp_byte *buffer, mtp_uint32 size, + mtp_uint32 *count) +{ + mtp_uint32 h_file = INVALID_FILE; + mtp_int32 error = 0; + mtp_uint32 data_sz; + + + h_file = _util_file_open(g_mgr->ftemp_st.filepath, + MTP_FILE_READ, &error); + if (h_file == INVALID_FILE) { + DBG_SECURE("_util_file_open(%s) Fail", g_mgr->ftemp_st.filepath); + return MTP_ERROR_NONE; + } + + /*copy header */ + memcpy(buffer, g_mgr->ftemp_st.header_buf, + sizeof(header_container_t)); + + /*copy body packet */ + data_sz = size - sizeof(header_container_t); + _util_file_read(h_file, &buffer[sizeof(header_container_t)], + data_sz, count); + if (*count <= 0) { + ERR("file read error expected [%u] actual [%u]\n", + data_sz, *count); + } + + *count += sizeof(header_container_t); + + if (_util_file_close(h_file) != 0) { + ERR("_util_file_close Fail"); + _util_print_error(); + } + + /* delete temp file, it have to be called in receive_data fn */ + if (remove(g_mgr->ftemp_st.filepath) < 0) { + ERR_SECURE("remove(%s) Fail", g_mgr->ftemp_st.filepath); + _util_print_error(); + } + + g_mgr->ftemp_st.data_size = 0; + g_mgr->ftemp_st.data_count = 0; + + return MTP_ERROR_NONE; +} + +mtp_err_t _transport_rcv_temp_file_info(mtp_byte *buf, char *filepath, + mtp_uint64 *t_size, mtp_uint32 filepath_len) +{ + file_attr_t atttrs = { 0 }; + mtp_bool ret = FALSE; + + memcpy(buf, g_mgr->ftemp_st.header_buf, + sizeof(header_container_t)); + + ret = _util_get_file_attrs(g_mgr->ftemp_st.filepath, &atttrs); + if (FALSE == ret) { + ERR_SECURE("_util_get_file_attrs(%s) Fail", g_mgr->ftemp_st.filepath); + return MTP_ERROR_GENERAL; + } + + *t_size = sizeof(header_container_t) + atttrs.fsize; + g_strlcpy(filepath, g_mgr->ftemp_st.filepath, filepath_len); + + g_mgr->ftemp_st.data_size = 0; + g_mgr->ftemp_st.data_count = 0; + + g_strlcpy(g_mgr->ftemp_st.filepath, MTP_TEMP_FILE_DEFAULT, + MTP_MAX_PATHNAME_SIZE + 1); + g_mgr->ftemp_st.fhandle = INVALID_FILE; + g_mgr->ftemp_st.file_size = 0; + + return MTP_ERROR_NONE; +} + +mtp_err_t _transport_send_event(mtp_byte *buf, mtp_uint32 size, + mtp_uint32 *count) +{ + mtp_bool resp = FALSE; + msgq_ptr_t pkt = { 0 }; + + retv_if(buf == NULL, MTP_ERROR_INVALID_PARAM); + retvm_if(size > _get_tx_pkt_size(), MTP_ERROR_INVALID_PARAM, + "size = %d, _get_tx_pkt_size() = (%d)", size, _get_tx_pkt_size()); + + pkt.mtype = MTP_EVENT_PACKET; + pkt.signal = 0x0000; + pkt.length = size; + + pkt.buffer = (mtp_uchar *)g_malloc(size); + if (NULL == pkt.buffer) { + ERR("g_malloc() Fail"); + return MTP_ERROR_GENERAL; + } + memcpy(pkt.buffer, buf, size); + resp = _util_msgq_send(mtp_to_usb_mqid, (void *)&pkt, + sizeof(msgq_ptr_t) - sizeof(long), 0); + if (resp == FALSE) { + ERR("_util_msgq_send() Fail"); + return MTP_ERROR_GENERAL; + } + + *count = size; + return MTP_ERROR_NONE; +} + +/* + * This function writes data to Message Queue, which will be read by a thread. + * the thread will write message, read from MQ, on USB. + * @param buf [in] A pointer to data written. + * @param pkt_len [in] Specifies the number of bytes to write. + * @return This function returns length of written data in bytes + */ +mtp_uint32 _transport_send_pkt_to_tx_mq(const mtp_byte *buf, + mtp_uint32 pkt_len) +{ + mtp_bool ret = 0; + mtp_uint32 len = pkt_len; + mtp_uint32 sent_len = 0; + msgq_ptr_t pkt = { 0 }; + mtp_uint32 tx_size = _get_tx_pkt_size(); + const mtp_uchar *temp = (const mtp_uchar *)buf; + + retv_if(buf == NULL, 0); + retv_if(pkt_len == 0, 0); + + pkt.mtype = MTP_DATA_PACKET; + pkt.signal = 0x0000; + + while (len) { + sent_len = len < tx_size ? len : tx_size; + + pkt.length = sent_len; + pkt.buffer = (mtp_uchar *)g_malloc(sent_len); + if (NULL == pkt.buffer) { + ERR("g_malloc() Fail"); + return 0; + } + + memcpy(pkt.buffer, temp, sent_len); + ret = _util_msgq_send(mtp_to_usb_mqid, (void *)&pkt, + sizeof(msgq_ptr_t) - sizeof(long), 0); + if (ret == FALSE) { + ERR("_util_msgq_send() Fail"); + g_free(pkt.buffer); + return 0; + } + + len -= sent_len; + temp += sent_len; + } + + return pkt_len; +} + +mtp_uint32 _transport_send_bulk_pkt_to_tx_mq(const mtp_byte *buf, + mtp_uint32 pkt_len) +{ + mtp_uint32 sent_len = 0; + mtp_uint32 tx_size = _get_tx_pkt_size(); + msgq_ptr_t pkt = {MTP_BULK_PACKET, 0, 0, NULL}; + + retv_if(buf == NULL, 0); + retv_if(pkt_len == 0, 0); + + pkt.length = tx_size; + while (pkt_len > tx_size) { + pkt.buffer = (mtp_uchar *)g_malloc(pkt.length); + if (NULL == pkt.buffer) { + ERR("g_malloc() Fail"); + return 0; + } + memcpy(pkt.buffer, &buf[sent_len], pkt.length); + + if (!_util_msgq_send(mtp_to_usb_mqid, (void *)&pkt, + sizeof(msgq_ptr_t) - sizeof(long), 0)) { + ERR("_util_msgq_send() Fail"); + g_free(pkt.buffer); + return 0; + } + + pkt_len -= pkt.length; + sent_len += pkt.length; + } + + pkt.length = pkt_len; + pkt.buffer = (mtp_uchar *)g_malloc(pkt.length); + if (NULL == pkt.buffer) { + ERR("g_malloc() Fail"); + return 0; + } + memcpy(pkt.buffer, &buf[sent_len], pkt.length); + + if (!_util_msgq_send(mtp_to_usb_mqid, (void *)&pkt, + sizeof(msgq_ptr_t) - sizeof(long), 0)) { + ERR("_util_msgq_send() Fail"); + g_free(pkt.buffer); + return 0; + } + sent_len += pkt.length; + + return sent_len; +} + +void _transport_send_zlp(void) +{ + msgq_ptr_t pkt = { 0 }; + mtp_bool resp = FALSE; + + pkt.mtype = MTP_ZLP_PACKET; + pkt.signal = 0x0000; + pkt.length = 0; + pkt.buffer = NULL; + + resp = _util_msgq_send(mtp_to_usb_mqid, (void *)&pkt, + sizeof(msgq_ptr_t) - sizeof(long), 0); + if (resp == FALSE) + ERR("_util_msgq_send() Fail"); + return; +} + +static mtp_err_t __transport_init_io() +{ + mtp_int32 res = 0; + thread_func_t usb_write_thread = _transport_thread_usb_write; + thread_func_t usb_read_thread = _transport_thread_usb_read; + + res = _util_thread_create(&g_tx_thrd, "usb write thread", + PTHREAD_CREATE_JOINABLE, usb_write_thread, + (void *)&mtp_to_usb_mqid); + if (FALSE == res) { + ERR("_util_thread_create(TX) Fail"); + goto cleanup; + } + + res = _util_thread_create(&g_rx_thrd, "usb read thread", + PTHREAD_CREATE_JOINABLE, usb_read_thread, + (void *)&g_usb_to_mtp_mqid); + if (FALSE == res) { + ERR("_util_thread_create(RX) Fail"); + goto cleanup; + } + + g_usb_threads_created = TRUE; + + return MTP_ERROR_NONE; + +cleanup: + _util_print_error(); + + if (g_rx_thrd) { + res = _util_thread_cancel(g_rx_thrd); + DBG("pthread_cancel [%d]\n", res); + g_rx_thrd = 0; + } + if (g_tx_thrd) { + res = _util_thread_cancel(g_tx_thrd); + DBG("pthread_cancel [%d]\n", res); + g_tx_thrd = 0; + } + g_usb_threads_created = FALSE; + + return MTP_ERROR_GENERAL; +} + +static void __transport_deinit_io() +{ + if (g_usb_threads_created == FALSE) { + ERR("io threads are not created."); + return; + } + errno = 0; + + if (FALSE == _util_thread_cancel(g_rx_thrd)) + ERR("_util_thread_cancel(rx) Fail"); + + if (_util_thread_join(g_rx_thrd, 0) == FALSE) + ERR("_util_thread_join(rx) Fail"); + + g_rx_thrd = 0; + + if (FALSE == _util_thread_cancel(g_tx_thrd)) + ERR("_util_thread_cancel(tx) Fail"); + + if (_util_thread_join(g_tx_thrd, 0) == FALSE) + ERR("_util_thread_join(tx) Fail"); + + g_tx_thrd = 0; + + g_usb_threads_created = FALSE; + return; +} + +mtp_bool _transport_init_interfaces(_cmd_handler_cb func) +{ + mtp_int32 res = 0; + mtp_bool ret = FALSE; + + ret = _transport_init_usb_device(); + if (ret == FALSE) { + /* mtp driver open failed */ + ERR("_transport_init_usb_device() Fail"); + return FALSE; + } + + if (_transport_mq_init(&g_usb_to_mtp_mqid, &mtp_to_usb_mqid) == FALSE) { + ERR("_transport_mq_init() Fail"); + _transport_deinit_usb_device(); + return FALSE; + } + + if (__transport_init_io() != MTP_ERROR_NONE) { + ERR("__transport_init_io() Fail"); + _transport_mq_deinit(&g_usb_to_mtp_mqid, &mtp_to_usb_mqid); + _transport_deinit_usb_device(); + return FALSE; + } + + res = _util_thread_create(&g_data_rcv, "Data Receive thread", + PTHREAD_CREATE_JOINABLE, __transport_thread_data_rcv, + (void *)func); + if (res == FALSE) { + ERR("_util_thread_create(data_rcv) Fail"); + __transport_deinit_io(); + _transport_mq_deinit(&g_usb_to_mtp_mqid, &mtp_to_usb_mqid); + _transport_deinit_usb_device(); + return FALSE; + } + + return TRUE; +} + +void _transport_usb_finalize(void) +{ + mtp_int32 res = 0; + void *th_result = NULL; + msgq_ptr_t pkt; + mtp_uint32 rx_size = _get_rx_pkt_size(); + + __transport_deinit_io(); + + if (g_data_rcv != 0) { + pkt.buffer = (mtp_uchar *)g_malloc(rx_size); + if (pkt.buffer == NULL) { + ERR("g_malloc() Fail"); + return; + } + pkt.mtype = MTP_DATA_PACKET; + pkt.signal = 0xABCD; + pkt.length = 6; + memset(pkt.buffer, 0, rx_size); + if (FALSE == _util_msgq_send(g_usb_to_mtp_mqid, (void *)&pkt, + sizeof(msgq_ptr_t) - sizeof(long), 0)) { + ERR("_util_msgq_send() Fail"); + } + + res = _util_thread_join(g_data_rcv, &th_result); + if (res == FALSE) { + ERR("_util_thread_join(data_rcv) Fail"); + } + } + + if (_transport_mq_deinit(&g_usb_to_mtp_mqid, &mtp_to_usb_mqid) == FALSE) { + ERR("_transport_mq_deinit() Fail"); + } + + _transport_deinit_usb_device(); + + return; +} + +static void *__transport_thread_data_rcv(void *func) +{ + msgq_ptr_t pkt = { 0 }; + mtp_uchar *pkt_data = NULL; + mtp_uint32 pkt_len = 0; + mtp_int32 flag = 1; + mtp_int32 len = 0; + _cmd_handler_cb _cmd_handler_func = (_cmd_handler_cb )func; + + while (flag) { + if (_util_msgq_receive(g_usb_to_mtp_mqid, (void *)&pkt, + sizeof(pkt) - sizeof(long), 0, &len) == FALSE) { + ERR("_util_msgq_receive() Fail"); + flag = 0; + break; + } + if (len == sizeof(msgq_ptr_t) - sizeof(long)) { + len = pkt.length; + if (pkt.length == 6 && pkt.signal == 0xABCD) { + ERR("Got NULL character in MQ"); + flag = 0; + break; + } + pkt_data = pkt.buffer; + pkt_len = pkt.length; + _cmd_handler_func((mtp_char *)pkt_data, pkt_len); + g_free(pkt_data); + pkt_data = NULL; + pkt_len = 0; + memset(&pkt, 0, sizeof(pkt)); + } else { + g_free(pkt.buffer); + pkt.buffer = NULL; + ERR("Received packet is less than real size"); + } + } + + ERR("thread_data_rcv[%u] exiting\n", g_data_rcv); + _util_thread_exit("__transport_thread_data_rcv is over"); + return NULL; +} + +void _transport_init_status_info(void) +{ + memset((void *)&g_status, 0, sizeof(status_info_t)); + return; +} + +mtp_int32 _transport_get_control_event(void) +{ + mtp_uint32 event_code; + + event_code = g_status.ctrl_event_code; + + /* initialize for next usage */ + if (event_code != 0) + g_status.ctrl_event_code = 0; + + return event_code; +} + +void _transport_set_control_event(mtp_int32 event_code) +{ + g_status.ctrl_event_code = event_code; +} + +mtp_state_t _transport_get_mtp_operation_state(void) +{ + return g_status.mtp_op_state; +} + +void _transport_set_mtp_operation_state(mtp_state_t state) +{ + g_status.mtp_op_state = state; + return; +} + +void _transport_set_usb_discon_state(mtp_bool is_usb_discon) +{ + g_status.is_usb_discon = is_usb_discon; + return; +} + +mtp_bool _transport_get_usb_discon_state(void) +{ + return g_status.is_usb_discon; +} + +void _transport_set_cancel_initialization(mtp_bool value) +{ + g_status.cancel_intialization = value; +} + +mtp_bool _transport_get_cancel_initialization(void) +{ + return g_status.cancel_intialization; +} diff --git a/src/transport/mtp_usb_driver.c b/src/transport/mtp_usb_driver.c new file mode 100755 index 0000000..91a9b73 --- /dev/null +++ b/src/transport/mtp_usb_driver.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <signal.h> +#include <glib.h> +#include "mtp_usb_driver.h" +#include "mtp_device.h" +#include "ptp_datacodes.h" +#include "mtp_support.h" +#include "ptp_container.h" +#include "mtp_msgq.h" +#include "mtp_util.h" +#include "mtp_thread.h" +#include "mtp_transport.h" +#include "mtp_event_handler.h" + +/* + * GLOBAL AND EXTERN VARIABLES + */ +extern mtp_config_t g_conf; + +/* + * STATIC VARIABLES AND FUNCTIONS + */ +static mtp_int32 g_usb_fd = -1; +static mtp_max_pkt_size_t pkt_size; +static mtp_uint32 rx_mq_sz; +static mtp_uint32 tx_mq_sz; + +static mtp_int32 __handle_usb_read_err(mtp_int32 err, + mtp_uchar *buf, mtp_int32 buf_len); +static void __clean_up_msg_queue(void *pmsqid); +static void __handle_control_request(mtp_int32 request); +static void __receive_signal(mtp_int32 n, siginfo_t *info, void *unused); + +/* + * FUNCTIONS + */ +mtp_bool _transport_init_usb_device(void) +{ + mtp_int32 status = 0; + struct sigaction sig; + pid_t mtp_pid = 0; + int msg_size; + + /* Kernel will inform to User Space using signal. */ + memset(&sig, 0, sizeof(sig)); + sig.sa_sigaction = __receive_signal; + sig.sa_flags = SA_SIGINFO; + sigaction(SIG_SETUP, &sig, NULL); + + if (g_usb_fd > 0) { + DBG("Device Already open"); + return TRUE; + } + + g_usb_fd = open(MTP_DRIVER_PATH, O_RDWR); + if (g_usb_fd < 0) { + ERR("Device node [%s] open Fail,errno [%d]\n", MTP_DRIVER_PATH, errno); + return FALSE; + } + + mtp_pid = getpid(); + status = ioctl(g_usb_fd, MTP_SET_USER_PID, &mtp_pid); + if (status < 0) { + ERR("IOCTL MTP_SET_USER_PID Fail = [%d]\n", status); + _transport_deinit_usb_device(); + return FALSE; + } + + pkt_size.rx = g_conf.read_usb_size; + pkt_size.tx = g_conf.write_usb_size; + + DBG("Final : Tx pkt size:[%u], Rx pkt size:[%u]\n", pkt_size.tx, pkt_size.rx); + + msg_size = sizeof(msgq_ptr_t) - sizeof(long); + rx_mq_sz = (g_conf.max_io_buf_size / g_conf.max_rx_ipc_size) * msg_size; + tx_mq_sz = (g_conf.max_io_buf_size / g_conf.max_tx_ipc_size) * msg_size; + + DBG("RX MQ size :[%u], TX MQ size:[%u]\n", rx_mq_sz, tx_mq_sz); + + return TRUE; +} + +void _transport_deinit_usb_device(void) +{ + if (g_usb_fd >= 0) + close(g_usb_fd); + g_usb_fd = -1; + + return; +} + +mtp_uint32 _get_tx_pkt_size(void) +{ + return pkt_size.tx; +} + +mtp_uint32 _get_rx_pkt_size(void) +{ + return pkt_size.rx; +} + +/* + * static mtp_int32 _transport_mq_init() + * This function create a message queue for MTP, + * A created message queue will be used to help data transfer between + * MTP module and usb buffer. + * @return This function returns TRUE on success or + * returns FALSE on failure. + */ +mtp_int32 _transport_mq_init(msgq_id_t *rx_mqid, msgq_id_t *tx_mqid) +{ + if (_util_msgq_init(rx_mqid, 0) == FALSE) { + ERR("RX MQ init Fail [%d]\n", errno); + return FALSE; + } + + if (_util_msgq_set_size(*rx_mqid, rx_mq_sz) == FALSE) + ERR("RX MQ setting size Fail [%d]\n", errno); + + if (_util_msgq_init(tx_mqid, 0) == FALSE) { + ERR("TX MQ init Fail [%d]\n", errno); + _util_msgq_deinit(rx_mqid); + *rx_mqid = -1; + return FALSE; + } + + if (_util_msgq_set_size(*tx_mqid, tx_mq_sz) == FALSE) + ERR("TX MQ setting size Fail [%d]\n", errno); + + return TRUE; +} + +void *_transport_thread_usb_write(void *arg) +{ + mtp_int32 status = 0; + mtp_uint32 len = 0; + unsigned char *mtp_buf = NULL; + msg_type_t mtype = MTP_UNDEFINED_PACKET; + msgq_id_t *mqid = (msgq_id_t *)arg; + + pthread_cleanup_push(__clean_up_msg_queue, mqid); + + do { + /* original LinuxThreads cancelation didn't work right + * so test for it explicitly. + */ + pthread_testcancel(); + + _util_rcv_msg_from_mq(*mqid, &mtp_buf, &len, &mtype); + + if (mtype == MTP_BULK_PACKET || mtype == MTP_DATA_PACKET) { + status = write(g_usb_fd, mtp_buf, len); + if (status < 0) { + ERR("USB write fail : %d\n", errno); + if (errno == ENOMEM || errno == ECANCELED) { + status = 0; + __clean_up_msg_queue(mqid); + } + } + g_free(mtp_buf); + mtp_buf = NULL; + } else if (MTP_EVENT_PACKET == mtype) { + /* Handling the MTP Asynchronous Events */ + DBG("Send Interrupt data to kernel by IOCTL "); + status = ioctl(g_usb_fd, MTP_WRITE_INT_DATA, mtp_buf); + g_free(mtp_buf); + mtp_buf = NULL; + } else if (MTP_ZLP_PACKET == mtype) { + DBG("Send ZLP data to kernel by IOCTL "); + status = ioctl(g_usb_fd, MTP_SET_ZLP_DATA, NULL); + } else { + DBG("mtype = %d is not valid\n", mtype); + status = -1; + } + + if (status < 0) { + ERR("write data to the device node Fail:\ + status = %d\n", status); + break; + } + } while (status >= 0); + + DBG("exited Source thread with status %d\n", status); + pthread_cleanup_pop(1); + g_free(mtp_buf); + + return NULL; +} + +void *_transport_thread_usb_read(void *arg) +{ + mtp_int32 status = 0; + msgq_ptr_t pkt = {MTP_DATA_PACKET, 0, 0, NULL}; + msgq_id_t *mqid = (msgq_id_t *)arg; + mtp_uint32 rx_size = _get_rx_pkt_size(); + + pthread_cleanup_push(__clean_up_msg_queue, mqid); + + do { + pthread_testcancel(); + + pkt.buffer = (mtp_uchar *)g_malloc(rx_size); + if (NULL == pkt.buffer) { + ERR("Sink thread: memalloc Fail."); + break; + } + + status = read(g_usb_fd, pkt.buffer, rx_size); + if (status <= 0) { + status = __handle_usb_read_err(status, pkt.buffer, rx_size); + if (status <= 0) { + ERR("__handle_usb_read_err Fail"); + g_free(pkt.buffer); + break; + } + } + + pkt.length = status; + if (FALSE == _util_msgq_send(*mqid, (void *)&pkt, + sizeof(msgq_ptr_t) - sizeof(long), 0)) { + ERR("msgsnd Fail"); + g_free(pkt.buffer); + } + } while (status > 0); + + DBG("status[%d] errno[%d]\n", status, errno); + pthread_cleanup_pop(1); + + return NULL; +} + +static mtp_int32 __handle_usb_read_err(mtp_int32 err, + mtp_uchar *buf, mtp_int32 buf_len) +{ + mtp_int32 retry = 0; + mtp_bool ret; + + while (retry++ < MTP_USB_ERROR_MAX_RETRY) { + if (err == 0) { + DBG("ZLP(Zero Length Packet). Skip"); + } else if (err < 0 && errno == EINTR) { + DBG("read () is interrupted. Skip"); + } else if (err < 0 && errno == EIO) { + DBG("EIO"); + + if (MTP_PHONE_USB_CONNECTED != + _util_get_local_usb_status()) { + ERR("USB is disconnected"); + break; + } + + _transport_deinit_usb_device(); + ret = _transport_init_usb_device(); + if (ret == FALSE) { + ERR("_transport_init_usb_device Fail"); + continue; + } + } else { + ERR("Unknown error : %d, errno [%d] \n", err, errno); + break; + } + + err = read(g_usb_fd, buf, buf_len); + if (err > 0) + break; + } + + if (err <= 0) + ERR("USB error handling Fail"); + + return err; +} + +static void __clean_up_msg_queue(void *mq_id) +{ + mtp_int32 len = 0; + msgq_ptr_t pkt = { 0 }; + msgq_id_t l_mqid = *(msgq_id_t *)mq_id; + + ret_if(mq_id == NULL); + + _transport_set_control_event(PTP_EVENTCODE_CANCELTRANSACTION); + while (TRUE == _util_msgq_receive(l_mqid, (void *)&pkt, + sizeof(msgq_ptr_t) - sizeof(long), 1, &len)) { + g_free(pkt.buffer); + memset(&pkt, 0, sizeof(msgq_ptr_t)); + } + + return; +} + +static void __handle_control_request(mtp_int32 request) +{ + static mtp_bool kernel_reset = FALSE; + static mtp_bool host_cancel = FALSE; + mtp_int32 status = 0; + + switch (request) { + case USB_PTPREQUEST_CANCELIO: + DBG("USB_PTPREQUEST_CANCELIO"); + cancel_req_t cancelreq_data; + mtp_byte buffer[USB_PTPREQUEST_CANCELIO_SIZE + 1] = { 0 }; + + host_cancel = TRUE; + _transport_set_control_event(PTP_EVENTCODE_CANCELTRANSACTION); + status = ioctl(g_usb_fd, MTP_GET_SETUP_DATA, buffer); + if (status < 0) { + ERR("IOCTL GET_SETUP_DATA Fail [%d]\n", status); + return; + } + + memcpy(&(cancelreq_data.io_code), buffer, sizeof(mtp_word)); + memcpy(&(cancelreq_data.tid), &buffer[2], sizeof(mtp_dword)); + DBG("cancel io code [%d], transaction id [%ld]\n", + cancelreq_data.io_code, cancelreq_data.tid); + break; + + case USB_PTPREQUEST_RESET: + + DBG("USB_PTPREQUEST_RESET"); + _reset_mtp_device(); + if (kernel_reset == FALSE) { + kernel_reset = TRUE; + } + + status = ioctl(g_usb_fd, MTP_SEND_RESET_ACK, NULL); + if (status < 0) { + ERR("IOCTL MTP_SEND_RESET_ACK Fail [%d]\n", + status); + } + break; + + case USB_PTPREQUEST_GETSTATUS: + + DBG("USB_PTPREQUEST_GETSTATUS"); + + /* Send busy status response just once. This flag is also for + * the case that mtp misses the cancel request packet. + */ + static mtp_bool sent_busy = FALSE; + usb_status_req_t statusreq_data = { 0 }; + mtp_dword num_param = 0; + + memset(&statusreq_data, 0x00, sizeof(usb_status_req_t)); + if (host_cancel == TRUE || (sent_busy == FALSE && + kernel_reset == FALSE)) { + DBG("Send busy response, set host_cancel to FALSE"); + statusreq_data.len = 0x08; + statusreq_data.code = PTP_RESPONSE_DEVICEBUSY; + host_cancel = FALSE; + } else if (_device_get_phase() == DEVICE_PHASE_NOTREADY) { + statusreq_data.code = + PTP_RESPONSE_TRANSACTIONCANCELLED; + DBG("PTP_RESPONSE_TRANSACTIONCANCELLED"); + statusreq_data.len = (mtp_word)(sizeof(usb_status_req_t) + + (num_param - 2) * sizeof(mtp_dword)); + } else if (_device_get_status() == DEVICE_STATUSOK) { + DBG("PTP_RESPONSE_OK"); + statusreq_data.len = 0x08; + statusreq_data.code = PTP_RESPONSE_OK; + + if (kernel_reset == TRUE) + kernel_reset = FALSE; + } else { + DBG("PTP_RESPONSE_GEN_ERROR"); + statusreq_data.len = 0x08; + statusreq_data.code = PTP_RESPONSE_GEN_ERROR; + } + + if (statusreq_data.code == PTP_RESPONSE_DEVICEBUSY) { + sent_busy = TRUE; + } else { + sent_busy = FALSE; + } + + status = ioctl(g_usb_fd, MTP_SET_SETUP_DATA, &statusreq_data); + if (status < 0) { + DBG("IOCTL MTP_SET_SETUP_DATA Fail [%d]\n", + status); + return; + } + break; + + case USB_PTPREQUEST_GETEVENT: + DBG("USB_PTPREQUEST_GETEVENT"); + break; + + default: + DBG("Invalid class specific setup request"); + break; + } + return; +} + +static void __receive_signal(mtp_int32 n, siginfo_t *info, void *arg) +{ + mtp_int32 request = info->si_int; + + DBG("Received SIgnal From Kernel"); + __handle_control_request(request); + return; +} + +/* + * mtp_bool __transport_mq_deinit() + * This function destroy a message queue for MTP, + * @return This function returns TRUE on success or + * returns FALSE on failure. + */ +mtp_bool _transport_mq_deinit(msgq_id_t *rx_mqid, msgq_id_t *tx_mqid) +{ + mtp_int32 res = TRUE; + + if (*rx_mqid) { + res = _util_msgq_deinit(rx_mqid); + if (res == FALSE) { + ERR("rx_mqid deinit Fail [%d]\n", errno); + } else { + *rx_mqid = 0; + } + } + + if (*tx_mqid) { + res = _util_msgq_deinit(tx_mqid); + if (res == FALSE) { + ERR("tx_mqid deinit fail [%d]\n", errno); + } else { + *tx_mqid = 0; + } + } + + return res; +} + +mtp_uint32 _transport_get_usb_packet_len(void) +{ + mtp_int32 status = 0; + static mtp_int32 usb_speed = 0; + + if (usb_speed == 0) { + + status = ioctl(g_usb_fd, MTP_GET_HIGH_FULL_SPEED, &usb_speed); + if (status < 0) { + ERR("MTP_GET_HIGH_FULL_SPEED Fail [%d]\n", status); + return MTP_MAX_PACKET_SIZE_SEND_FS; + } + } + + if (usb_speed % MTP_MAX_PACKET_SIZE_SEND_HS) { + return MTP_MAX_PACKET_SIZE_SEND_FS; + } + + return MTP_MAX_PACKET_SIZE_SEND_HS; +} diff --git a/src/util/mtp_fs.c b/src/util/mtp_fs.c new file mode 100755 index 0000000..4257446 --- /dev/null +++ b/src/util/mtp_fs.c @@ -0,0 +1,949 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define __USE_STDIO__ +#define _GNU_SOURCE +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/vfs.h> +#include <sys/sendfile.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <glib.h> +#include <glib/gprintf.h> +#include "mtp_fs.h" +#include "mtp_util.h" +#include "mtp_support.h" +#include "ptp_datacodes.h" + +/* + * FUNCTIONS + */ + +/* + * mtp_uint32 _util_file_open(const mtp_char *filename, + * file_mode_t mode, mtp_int32 *error) + * This function opens the file in specific mode. + * + * @param[in] filename Specifies the name of file to open. + * @param[in] mode Specifies the mode of file to open. + * @param[out] error Specifies the type of error + * @return This function returns the file handle on success, + or INVALID_FILE on failure + */ +mtp_uint32 _util_file_open(const mtp_char *filename, file_mode_t mode, + mtp_int32 *error) +{ +#ifdef __USE_STDIO__ + FILE *fhandle = NULL; + char *fmode = NULL; + + switch ((int)mode) { + case MTP_FILE_READ: + fmode = "rm"; + break; + + case MTP_FILE_WRITE: + fmode = "w"; + break; + + case MTP_FILE_APPEND: + fmode = "a"; + break; + + case MTP_FILE_READ | MTP_FILE_WRITE: + fmode = "r+"; + break; + + case MTP_FILE_READ | MTP_FILE_WRITE | MTP_FILE_APPEND: + fmode = "a+"; + break; + + default: + ERR("Invalid mode : %d\n", mode); + *error = EINVAL; + return INVALID_FILE; + } + + fhandle = fopen(filename, fmode); + if (fhandle == NULL) { + ERR("File open Fail:mode[0x%x], errno [%d]\n", mode, errno); + ERR_SECURE("filename[%s]\n", filename); + *error = errno; + return INVALID_FILE; + } + + fcntl(fileno(fhandle), F_SETFL, O_NOATIME); + + return (mtp_uint32)fhandle; + +#else /* __USE_STDIO__ */ + + mtp_int32 fhandle = 0; + mtp_int32 flags = 0; + mode_t perm = 0; + + switch ((int)mode) { + case MTP_FILE_READ: + flags = O_RDONLY; + break; + + case MTP_FILE_WRITE: + flags = O_WRONLY | O_CREAT | O_TRUNC; + perm = 0644; + break; + + case MTP_FILE_APPEND: + flags = O_WRONLY | O_APPEND | O_CREAT; + perm = 0644; + break; + + case MTP_FILE_READ | MTP_FILE_WRITE: + flags = O_RDWR; + break; + + case MTP_FILE_READ | MTP_FILE_WRITE | MTP_FILE_APPEND: + flags = O_RDWR | O_APPEND | O_CREAT; + perm = 0644; + break; + + default: + ERR("Invalid mode : %d\n", mode); + *error = EINVAL; + return INVALID_FILE; + } + + if (perm) + fhandle = open(filename, flags, perm); + else + fhandle = open(filename, flags); + + if (fhandle < 0) { + ERR("File open Fail:mode[0x%x], errno [%d]\n", mode, errno); + ERR_SECURE("filename[%s]\n", filename); + *error = errno; + return INVALID_FILE; + } + + return (mtp_uint32)fhandle; +#endif /* __USE_STDIO__ */ +} + +/* + * void _util_file_read(mtp_uint32 handle, void *bufptr, mtp_uint32 size, + * mtp_uint32 *preadcount) + * + * This function reads data from the file handle into the data buffer. + * + * @param[in] handle Specifies the handle of file to read. + * @param[out] bufptr Points to buff where data is to be read. + * @param[in] size Specifies the num bytes to be read. + * @param[out] preadcount Will store the actual num bytes read. + * @return None + */ +void _util_file_read(mtp_uint32 fhandle, void *bufptr, mtp_uint32 size, + mtp_uint32 *read_count) +{ + mtp_uint32 bytes_read = 0; + +#ifdef __USE_STDIO__ + bytes_read = fread_unlocked(bufptr, sizeof(mtp_char), size, (FILE *)fhandle); +#else /* __USE_STDIO__ */ + bytes_read = read(fhandle, bufptr, size); +#endif /* __USE_STDIO__ */ + + *read_count = bytes_read; +} +/** + * mtp_uint32 _util_file_write(mtp_uint32 fhandle, void *bufptr, mtp_uint32 size) + * + * This function writes data to the file using the data buffer passed. + * + * @param[in] handle Specifies the handle of file to write. + * @param[in] bufptr Points the buffer which holds the data. + * @param[in] size Specifies num bytes to be written. + * @return This function returns num bytes written. + */ + +mtp_uint32 _util_file_write(mtp_uint32 fhandle, void *bufptr, mtp_uint32 size) +{ + mtp_uint32 bytes_written = 0; + +#ifdef __USE_STDIO__ + bytes_written = fwrite_unlocked(bufptr, sizeof(mtp_char), size, (FILE *)fhandle); +#else /* __USE_STDIO__ */ + mtp_int32 ret = 0; + + ret = write(fhandle, bufptr, size); + if (ret < 0) + ret = 0; + + bytes_written = ret; +#endif /* __USE_STDIO__ */ + + return bytes_written; +} + +/** + * mtp_int32 _util_file_close(mtp_uint32 fhandle) + * This function closes the file. + * + * @param[in] handle Specifies the handle of file to close. + * @return 0 in case of success or EOF on failure. + */ +mtp_int32 _util_file_close(mtp_uint32 fhandle) +{ +#ifdef __USE_STDIO__ + return fclose((FILE *)fhandle); +#else /* __USE_STDIO__ */ + return close(fhandle); +#endif /* __USE_STDIO__ */ +} + +/* + * This function seeks to a particular location in a file. + * + * @param[in] handle Specifies the handle of file to seek. + * @param[in] offset Specifies the starting point. + * @param[in] whence Specifies the setting value + * @return Returns TRUE in case of success or FALSE on Failure. + */ +mtp_bool _util_file_seek(mtp_uint32 handle, off_t offset, mtp_int32 whence) +{ + mtp_int64 ret_val = 0; + +#ifdef __USE_STDIO__ + ret_val = fseek((FILE *)handle, offset, whence); +#else /* __USE_STDIO__ */ + ret_val = lseek(handle, offset, whence); + if (ret_val > 0) + ret_val = 0; +#endif /* __USE_STDIO__ */ + if (ret_val < 0) { + ERR(" _util_file_seek error errno [%d]\n", errno); + return FALSE; + } + + return TRUE; +} + +mtp_bool _util_file_copy(const mtp_char *origpath, const mtp_char *newpath, + mtp_int32 *error) +{ +#ifdef __USE_STDIO__ + FILE *fold = NULL; + FILE *fnew = NULL; + size_t nmemb = 0; + mtp_int32 ret = 0; + mtp_char buf[BUFSIZ] = { 0 }; + + if ((fold = fopen(origpath, "rb")) == NULL) { + ERR("In-file open Fail errno [%d]\n", errno); + *error = errno; + return FALSE; + } + + if ((fnew = fopen(newpath, "wb")) == NULL) { + ERR("Out-file open Fail errno [%d]\n", errno); + *error = errno; + fclose(fold); + return FALSE; + } + + do { + nmemb = fread(buf, sizeof(mtp_char), BUFSIZ, fold); + if (nmemb < BUFSIZ && ferror(fold)) { + ERR("fread Fail errno [%d] \n", errno); + *error = errno; + fclose(fnew); + fclose(fold); + if (remove(newpath) < 0) + ERR("Remove Fail"); + return FALSE; + } + + ret = fwrite(buf, sizeof(mtp_char), nmemb, fnew); + if (ret < nmemb && ferror(fnew)) { + ERR("fwrite Fail errno [%d]\n", errno); + *error = errno; + fclose(fnew); + fclose(fold); + if (remove(newpath) < 0) + ERR("Remove Fail"); + return FALSE; + } + } while (!feof(fold)); + + fclose(fnew); + fclose(fold); +#else /* __USE_STDIO__ */ + mtp_int32 in_fd = 0; + mtp_int32 out_fd = 0; + mtp_int32 ret = 0; + off_t offset = 0; + + if ((in_fd = open(origpath, O_RDONLY)) < 0) { + ERR("In-file open Fail, errno [%d]\n", errno); + *error = errno; + return FALSE; + } + + if ((out_fd = open(newpath, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { + ERR("Out-file open Fail errno [%d] \n", errno); + *error = errno; + close(in_fd); + return FALSE; + } + + do { + ret = sendfile(out_fd, in_fd, &offset, BUFSIZ); + if (ret < 0) { + ERR("sendfile Fail errno [%d]\n", errno); + *error = errno; + close(out_fd); + close(in_fd); + if (remove(newpath) < 0) + ERR("Remove Fail"); + return FALSE; + } + } while (ret == BUFSIZ); + + close(out_fd); + close(in_fd); +#endif /* __USE_STDIO__ */ + + return TRUE; +} + +mtp_bool _util_copy_dir_children_recursive(const mtp_char *origpath, + const mtp_char *newpath, mtp_int32 *error) +{ + DIR *dir = NULL; + struct dirent entry = { 0 }; + struct dirent *entryptr = NULL; + mtp_int32 retval = 0; + mtp_char old_pathname[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + mtp_char new_pathname[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + struct stat entryinfo; + + retv_if(origpath == NULL, FALSE); + retv_if(newpath == NULL, FALSE); + + /* Open the given directory */ + dir = opendir(origpath); + if (dir == NULL) { + ERR("opendir(%s) Fail", origpath); + _util_print_error(); + return FALSE; + } + + retval = readdir_r(dir, &entry, &entryptr); + + while (retval == 0 && entryptr != NULL) { + /* Skip the names "." and ".." as we don't want to recurse on them. */ + if (!g_strcmp0(entry.d_name, ".") || + !g_strcmp0(entry.d_name, "..")) { + retval = readdir_r(dir, &entry, &entryptr); + continue; + } + g_snprintf(old_pathname, MTP_MAX_PATHNAME_SIZE + 1, + "%s/%s", origpath, entry.d_name); + g_snprintf(new_pathname, MTP_MAX_PATHNAME_SIZE + 1, + "%s/%s", newpath, entry.d_name); + + if (stat(old_pathname, &entryinfo) != 0) { + ERR("Error statting [%s] errno [%d]\n", old_pathname, errno); + closedir(dir); + return FALSE; + } + + if (S_ISDIR(entryinfo.st_mode)) { + if (FALSE == _util_dir_create(new_pathname, error)) { + /* dir already exists + merge the contents */ + if (EEXIST != *error) { + ERR("directory[%s] create Fail errno [%d]\n", new_pathname, errno); + closedir(dir); + return FALSE; + } + } + if (FALSE == _util_copy_dir_children_recursive(old_pathname, + new_pathname, error)) { + ERR("Recursive Copy of Children Fail\ + [%s]->[%s], errno [%d]\n", old_pathname, new_pathname, errno); + closedir(dir); + return FALSE; + } + } else { + if (FALSE == _util_file_copy(old_pathname, new_pathname, error)) { + ERR("file copy fail [%s]->[%s]\n", + old_pathname, new_pathname); + /* Cannot overwrite a read-only file, + Skip copy and retain the read-only file + on destination */ + if (EACCES == *error) + goto DONE; + closedir(dir); + return FALSE; + } +#ifdef MTP_SUPPORT_SET_PROTECTION + mtp_bool ret = FALSE; + + if (!((S_IWUSR & entryInfo.st_mode) || + (S_IWGRP & entryInfo.st_mode) || + (S_IWOTH & entryInfo.st_mode))) { + ret = _util_set_file_attrs(newPathName, + MTP_FILE_ATTR_MODE_REG | + MTP_FILE_ATTR_MODE_READ_ONLY); + if (!ret) { + ERR("Failed to set directory attributes errno [%d]\n", errno); + closedir(dir); + return FALSE; + } + } +#endif /* MTP_SUPPORT_SET_PROTECTION */ + } +DONE: + retval = readdir_r(dir, &entry, &entryptr); + } + + closedir(dir); + return (retval == 0) ? TRUE : FALSE; +} + +mtp_bool _util_file_move(const mtp_char *origpath, const mtp_char *newpath, + mtp_int32 *error) +{ + mtp_int32 ret = 0; + + ret = rename(origpath, newpath); + if (ret < 0) { + if (errno == EXDEV) { + DBG("oldpath and newpath are not on the same\ + mounted file system."); + if (_util_file_copy(origpath, newpath, error) == FALSE) { + ERR("_util_file_copy Fail errno [%d]\n", errno); + return FALSE; + } + if (remove(origpath) < 0) { + ERR("remove Fail : %d\n", errno); + return FALSE; + } + } else { + ERR("rename Fail : %d\n", errno); + *error = errno; + return FALSE; + } + } + + return TRUE; +} + +mtp_bool _util_is_file_opened(const mtp_char *fullpath) +{ + mtp_int32 ret = 0; + + ret = rename(fullpath, fullpath); + return (ret != 0); +} + +mtp_bool _util_dir_create(const mtp_char *dirname, mtp_int32 *error) +{ + + if (mkdir(dirname, S_IRWXU | S_IRGRP | + S_IXGRP | S_IROTH | S_IXOTH) < 0) { + *error = errno; + return FALSE; + } + return TRUE; +} + +mtp_int32 _util_remove_dir_children_recursive(const mtp_char *dirname, + mtp_uint32 *num_of_deleted_file, mtp_uint32 *num_of_file, mtp_bool breadonly) +{ + retv_if(dirname == NULL, FALSE); + + DIR *dir = NULL; + struct dirent entry = { 0 }; + struct dirent *entryptr = NULL; + mtp_int32 retval = 0; + mtp_char pathname[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + struct stat entryinfo; + mtp_int32 ret = MTP_ERROR_NONE; + + /* Open the given directory */ + dir = opendir(dirname); + if (dir == NULL) { + ERR("Open directory Fail[%s], errno [%d]", dirname, errno); + return MTP_ERROR_GENERAL; + } + + retval = readdir_r(dir, &entry, &entryptr); + + while (retval == 0 && entryptr != NULL) { + /* Skip the names "." and ".." + as we don't want to recurse on them. */ + if (!g_strcmp0(entry.d_name, ".") || + !g_strcmp0(entry.d_name, "..")) { + retval = readdir_r(dir, &entry, &entryptr); + continue; + } + g_snprintf(pathname, MTP_MAX_PATHNAME_SIZE + 1, + "%s/%s", dirname, entry.d_name); + if (stat(pathname, &entryinfo) != 0) { + ERR("Error statting %s errno [%d]\n", pathname, errno); + closedir(dir); + return MTP_ERROR_GENERAL; + } + *num_of_file += 1; + if (S_ISDIR(entryinfo.st_mode)) { + ret = _util_remove_dir_children_recursive(pathname, + num_of_deleted_file, num_of_file, breadonly); + if (MTP_ERROR_GENERAL == ret || MTP_ERROR_ACCESS_DENIED == ret) { + ERR("deletion fail [%s]\n", pathname); + closedir(dir); + return ret; + } + if (MTP_ERROR_OBJECT_WRITE_PROTECTED == ret) { + DBG("Folder[%s] contains read-only files,hence\ + folder is not deleted\n",pathname); + /* Read the next entry */ + goto DONE; + } + if (rmdir(pathname) < 0) { + ERR("deletion fail [%s], errno [%d]\n", pathname, errno); + closedir(dir); + if (EACCES == errno) + return MTP_ERROR_ACCESS_DENIED; + return MTP_ERROR_GENERAL; + } + *num_of_deleted_file += 1; + } else { + /* Only during Deleteobject, bReadOnly(TRUE) + do not delete read-only files */ +#ifdef MTP_SUPPORT_SET_PROTECTION + if (breadonly) { + /* check for file attributes */ + if (!((S_IWUSR & entryinfo.st_mode) || + (S_IWGRP & entryinfo.st_mode) || + (S_IWOTH & entryinfo.st_mode))) { + ret = MTP_ERROR_OBJECT_WRITE_PROTECTED; + DBG("File [%s] is readOnly:Deletion Fail\n",pathname); + goto DONE; + } + } +#endif /* MTP_SUPPORT_SET_PROTECTION */ + if (unlink(pathname) < 0) { + ERR("deletion fail [%s], errno [%d]\n", pathname, errno); + closedir(dir); + if (EACCES == errno) + return MTP_ERROR_ACCESS_DENIED; + return MTP_ERROR_GENERAL; + } + *num_of_deleted_file += 1; + } +DONE: + retval = readdir_r(dir, &entry, &entryptr); + if (retval != 0) { + closedir(dir); + return MTP_ERROR_GENERAL; + } + } + + closedir(dir); + return ret; +} + +/* + * mtp_bool _util_get_file_attrs(const mtp_char *filename, file_attr_t *attrs) + * This function gets the file attributes. + * + * @param[in] filename Specifies the name of file to find. + * @param[out] attrs Points the file Attributes. + * @return This function returns TRUE if gets the attributes + * successfully, otherwise FALSE. + */ +mtp_bool _util_get_file_attrs(const mtp_char *filename, file_attr_t *attrs) +{ + struct stat fileinfo = { 0 }; + + if (stat(filename, &fileinfo) < 0) { + ERR_SECURE("%s : stat Fail errno [%d]\n", filename, errno); + return FALSE; + } + + memset(attrs, 0, sizeof(file_attr_t)); + attrs->fsize = fileinfo.st_size; + attrs->ctime = fileinfo.st_ctime; + attrs->mtime = fileinfo.st_mtime; + + /*Reset attribute mode */ + attrs->attribute = MTP_FILE_ATTR_MODE_NONE; + if (S_ISREG(fileinfo.st_mode)) { + attrs->attribute |= MTP_FILE_ATTR_MODE_REG; + if (!((S_IWUSR & fileinfo.st_mode) || + (S_IWGRP & fileinfo.st_mode) || + (S_IWOTH & fileinfo.st_mode))) { + attrs->attribute |= MTP_FILE_ATTR_MODE_READ_ONLY; + } + } else if (S_ISDIR(fileinfo.st_mode)) { + attrs->attribute |= MTP_FILE_ATTR_MODE_DIR; + } else if (S_ISBLK(fileinfo.st_mode) || S_ISCHR(fileinfo.st_mode) || + S_ISLNK(fileinfo.st_mode) || S_ISSOCK(fileinfo.st_mode)) { + attrs->attribute |= MTP_FILE_ATTR_MODE_SYSTEM; + } + return TRUE; +} + +mtp_bool _util_set_file_attrs(const mtp_char *filename, mtp_dword attrib) +{ + mtp_dword attrs = 0; + + if (MTP_FILE_ATTR_MODE_REG & attrib) { + /*Reqular file */ + if (MTP_FILE_ATTR_MODE_READ_ONLY & attrib) + attrs |= (S_IRUSR | S_IRGRP | S_IROTH); + else + attrs |= (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + } else { + /* do nothing for files other than File/Folder */ + DBG("entered here nothing"); + return FALSE; + } + + if (0 != chmod(filename, attrs)) { + if (EPERM == errno) + return TRUE; + ERR_SECURE("Change mode of [File : %s] Fail\n", filename); + _util_print_error(); + return FALSE; + } + return TRUE; +} + +/* + * mtp_bool _util_ifind_first(mtp_char *dirname, DIR **dirp, + * dir_entry_t *dir_info) + * This function finds the first file in the directory stream. + * + * @param[in] dirname specifies the name of directory. + * @param[out] dirp pointer to the directory stream. + * @param[in] dir_info pointer to the file information. + * @return This function returns TRUE on success, otherwise FALSE. + */ +mtp_bool _util_ifind_first(mtp_char *dirname, DIR **dirp, dir_entry_t *dir_info) +{ + DIR *dir; + + retv_if(dirp == NULL, FALSE); + retv_if(dirname == NULL, FALSE); + retv_if(dir_info == NULL, FALSE); + + dir = opendir(dirname); + if (NULL == dir) { + ERR("opendir(%s) Fail", dirname); + _util_print_error(); + + return FALSE; + } + + if (_util_ifind_next(dirname, dir, dir_info) == FALSE) { + DBG("Stop enumeration"); + _util_print_error(); + closedir(dir); + return FALSE; + } + + *dirp = dir; + + return TRUE; +} + +/* + * mtp_bool _util_ifind_next(mtp_char *dirname, DIR *dirp, dir_entry_t *dir_info) + * This function finds the next successive file in the directory stream. + * + * @param[in] dirname name of the directory. + * @param[in] dirp pointer to the directory stream. + * @param[out] dir_info Points the file information. + * @return This function returns TRUE on success, otherwise FALSE. + */ +mtp_bool _util_ifind_next(mtp_char *dir_name, DIR *dirp, dir_entry_t *dir_info) +{ + mtp_int32 ret = 0; + struct dirent entry = {0}; + struct stat stat_buf = {0}; + struct dirent *result = NULL; + mtp_char path_name[MTP_MAX_PATHNAME_SIZE + 1] = { 0 }; + + retv_if(dir_name == NULL, FALSE); + retv_if(dir_info == NULL, FALSE); + + do { + ret = readdir_r(dirp, &entry, &result); + if (ret != 0) { + ERR("readdir_r Fail : %d\n", ret); + return FALSE; + } else if (result == NULL) { + DBG("There is no more entry"); + return FALSE; + } + + if (_util_create_path(path_name, sizeof(path_name), + dir_name, entry.d_name) == FALSE) { + continue; + } + + if (stat(path_name, &stat_buf) < 0) { + ERR_SECURE("stat Fail, skip [%s]\n", path_name); + continue; + } + break; + } while (1); + + g_strlcpy(dir_info->filename, path_name, sizeof(dir_info->filename)); + dir_info->attrs.attribute = MTP_FILE_ATTR_MODE_NONE; + + switch (stat_buf.st_mode & S_IFMT) { + case S_IFREG: + dir_info->type = MTP_FILE_TYPE; + if (!(stat_buf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) { + dir_info->attrs.attribute |= MTP_FILE_ATTR_MODE_READ_ONLY; + } + break; + + case S_IFDIR: + dir_info->type = MTP_DIR_TYPE; + dir_info->attrs.attribute = MTP_FILE_ATTR_MODE_DIR; + break; + + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: + case S_IFLNK: + case S_IFSOCK: + dir_info->attrs.attribute |= MTP_FILE_ATTR_MODE_SYSTEM; + break; + + default: + dir_info->attrs.attribute |= MTP_FILE_ATTR_MODE_SYSTEM; + ERR_SECURE("%s has unknown type. mode[0x%x]\n", + dir_info->filename, stat_buf.st_mode); + break; + } + + /* Directory Information */ + dir_info->attrs.mtime = stat_buf.st_mtime; + dir_info->attrs.fsize = stat_buf.st_size; + + return TRUE; +} + +mtp_bool _util_get_filesystem_info(mtp_char *storepath, fs_info_t *fs_info) +{ + struct statfs buf = { 0 }; + mtp_uint64 avail_size = 0; + mtp_uint64 capacity = 0; + mtp_uint64 used_size = 0; + + if (statfs(storepath, &buf) != 0) { + ERR("statfs Fail"); + return FALSE; + } + + capacity = used_size = avail_size = buf.f_bsize; + DBG("Block size : %d\n", buf.f_bsize); + capacity *= buf.f_blocks; + used_size *= (buf.f_blocks - buf.f_bavail); + avail_size *= buf.f_bavail; + + fs_info->disk_size = capacity; + fs_info->reserved_size = used_size; + fs_info->avail_size = avail_size; + + return TRUE; +} + +void _util_count_num_lines(mtp_uint32 fhandle, mtp_uint32 *num_lines) +{ + if (fhandle == INVALID_FILE) + return; + + mtp_uint32 line_count = 0; + mtp_char *buffer = NULL; + mtp_int32 read_bytes; + mtp_uint32 line_max_length; + + line_max_length = LINUX_MAX_PATHNAME_LENGTH + 2; + buffer = (mtp_char *)g_malloc(line_max_length); + if (buffer == NULL) { + ERR("Malloc Fail"); + return; + } + +#ifdef __USE_STDIO__ + while((read_bytes = getline(&buffer, + &line_max_length, (FILE *)fhandle)) != -1) { + if (read_bytes > MTP_MAX_PATHNAME_SIZE + 1) + continue; + line_count++; + } +#else /* __USE_STDIO__ */ + + mtp_uint16 ii = 0; + mtp_uint32 prev_pos = -1; + mtp_uint32 new_pos; + mtp_uint32 filename_len = 0; + while((read_bytes = read(fhandle, buffer, LINUX_MAX_PATHNAME_LENGTH)) > 0) { + for (ii = 0; ii < read_bytes; ii++) { + if (buffer[ii] != '\n') + continue; + new_pos = ii; + filename_len = new_pos - prev_pos -1; + prev_pos = new_pos; + if (filename_len > MTP_MAX_PATHNAME_SIZE) + continue; + line_count++; + } + if (buffer[read_bytes - 1] != '\n') { + _util_file_seek(fhandle, prev_pos + 1 - read_bytes, SEEK_CUR); + } + prev_pos = -1; + } +#endif /* __USE_STDIO__ */ + + *num_lines = line_count; + g_free(buffer); + return; +} + +void _util_fill_guid_array(void *guidarray, mtp_uint32 start_index, + mtp_uint32 fhandle, mtp_uint32 size) +{ + ptp_array_t *pguidarray = NULL; + mtp_uint32 *guidptr = NULL; + mtp_uint32 num_lines = 0; + mtp_wchar objfullpath[MTP_MAX_PATHNAME_SIZE * 2 + 1] = { 0 }; + mtp_char guid[16] = { 0 }; + mtp_char *buffer = NULL; + mtp_uint32 line_max_length; + mtp_uint32 len = 0; + + line_max_length = LINUX_MAX_PATHNAME_LENGTH + 2; + pguidarray = (ptp_array_t *)guidarray; + guidptr = (mtp_uint32 *)(pguidarray->array_entry); + + buffer = (mtp_char *)g_malloc(line_max_length); + if (buffer == NULL) { + ERR("Malloc Fail"); + return; + } + +#ifdef __USE_STDIO__ + while ((len = getline(&buffer, &line_max_length, (FILE *)fhandle)) != -1 && + (num_lines - start_index) <= size) { + if (len > MTP_MAX_PATHNAME_SIZE + 1) + continue; + num_lines++; + if (num_lines < start_index) + continue; + buffer[len - 1] = '\0'; + _util_utf8_to_utf16(objfullpath, + sizeof(objfullpath) / WCHAR_SIZ, buffer); + _util_conv_wstr_to_guid(objfullpath, (mtp_uint64 *)guid); + memcpy(&(guidptr[pguidarray->num_ele]), + guid, sizeof(guid)); + pguidarray->num_ele += sizeof(mtp_uint32); + } +#else /* __USE_STDIO__ */ + mtp_uint16 ii = 0; + mtp_uint32 prev_pos = -1; + mtp_uint32 new_pos; + mtp_char file_name[MTP_MAX_PATHNAME_SIZE + 1]; + mtp_int32 read_bytes; + + while ((read_bytes = read(fHandle, buffer, + LINUX_MAX_PATHNAME_LENGTH)) > 0 && + (num_lines - start_index) <= size) { + + for (ii = 0; ii < read_bytes; ii++) { + if (buffer[ii] != '\n') + continue; + new_pos = ii; + len = new_pos - prev_pos - 1; + prev_pos = new_pos; + if (len > MTP_MAX_PATHNAME_SIZE) + continue; + num_lines++; + if (num_lines < start_index) + continue; + strncpy(file_name, &buffer[new_pos - len], len); + file_name[len] = '\0'; + _util_utf8_to_utf16(objfullpath, + sizeof(objfullpath) / WCHAR_SIZ, file_name); + _util_conv_wstr_to_guid(objfullpath, (mtp_uint64 *)guid); + memcpy(&(guidptr[pguidarray->num_elements]), + guid, sizeof(guid)); + pguidarray->num_elements += sizeof(mtp_uint32); + } + + if (buffer[read_bytes - 1] != '\n') { + _util_file_seek(fhandle, prev_pos + 1 - read_bytes, SEEK_CUR); + } + prev_pos = -1; + } +#endif /* __USE_STDIO__ */ + + g_free(buffer); + + return; +} + +/* + * void FLOGD(const char *fmt, ...) + * This function writes MTP debug message to MTP log file + * + * @param[in] fmt Formatted debug message. + * @param[out] None. + * @return None. + */ +void FLOGD(const char *fmt, ...) +{ + static int written_bytes = 0; + FILE *fp = NULL; + va_list ap; + + if (written_bytes == 0 || written_bytes > MTP_LOG_MAX_SIZE) { + fp = fopen(MTP_LOG_FILE, "w"); + written_bytes = 0; + } else { + fp = fopen(MTP_LOG_FILE, "a+"); + } + + if (fp == NULL) { + return; + } + + written_bytes += fprintf(fp, "%s ", __FILE__); + va_start(ap, fmt); + written_bytes += vfprintf(fp, fmt, ap); + va_end(ap); + + fclose(fp); + return; +} diff --git a/src/util/mtp_list.c b/src/util/mtp_list.c new file mode 100755 index 0000000..1ba7050 --- /dev/null +++ b/src/util/mtp_list.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <glib.h> +#include "mtp_list.h" + +/* + * FUNCTIONS + */ +static slist_node_t *__util_del_first_node(slist_t *l_ptr); + +void _util_init_list(slist_t *l_ptr) +{ + ret_if(l_ptr == NULL); + + l_ptr->start = NULL; + l_ptr->end = NULL; + l_ptr->nnodes = 0; + + return; +} + +mtp_bool _util_add_node(slist_t *l_ptr, void *data) +{ + retv_if(l_ptr == NULL, FALSE); + + slist_node_t *node = NULL; + + node = (slist_node_t *)g_malloc(sizeof(slist_node_t)); + if (node == NULL) { + ERR("g_malloc() Fail"); + return FALSE; + } + + node->value = data; + node->link = NULL; + + if (l_ptr->start == NULL) + l_ptr->start = node; + else + l_ptr->end->link = node; + + l_ptr->end = node; + l_ptr->nnodes += 1; + return TRUE; +} + +slist_node_t* _util_delete_node(slist_t *l_ptr, void *data) +{ + retv_if(data == NULL, NULL); + retv_if(l_ptr == NULL, NULL); + retv_if(l_ptr->start == NULL, NULL); + + slist_node_t *nptr = l_ptr->start; + slist_node_t *temp = NULL; + + if (nptr->value == data) { + return __util_del_first_node(l_ptr); + } + + while (nptr->link) { + if (nptr->link->value == data) + break; + nptr = nptr->link; + } + + if (nptr->link == NULL) { + ERR("Node not found in the list"); + return NULL; + } + + temp = nptr->link; + nptr->link = nptr->link->link; + l_ptr->nnodes -= 1; + + if (temp == l_ptr->end) + l_ptr->end = nptr; + + return temp; +} + +static slist_node_t *__util_del_first_node(slist_t *l_ptr) +{ + slist_node_t *temp = NULL; + + temp = l_ptr->start; + l_ptr->nnodes -= 1; + l_ptr->start = temp->link; + if (temp == l_ptr->end) { + l_ptr->end = NULL; + } + + return temp; +} + +/* This API will send NULL if list does not have elements */ +slist_iterator* _util_init_list_iterator(slist_t *l_ptr) +{ + slist_iterator *temp = NULL; + + retv_if(l_ptr == NULL, NULL); + retv_if(l_ptr->start == NULL, NULL); + + temp = (slist_iterator *)g_malloc(sizeof(slist_iterator)); + if (temp == NULL) { + ERR("g_malloc() Fail"); + return NULL; + } + + temp->node_ptr = l_ptr->start; + return temp; +} + +/* Befor calling this please make sure + next element exists using _util_check_list_next */ +void* _util_get_list_next(slist_iterator *iter) +{ + slist_node_t *temp = NULL; + + retv_if(iter == NULL, NULL); + + temp = iter->node_ptr; + iter->node_ptr = iter->node_ptr->link; + + return temp->value; +} + +slist_node_t* _util_get_first_node(slist_t *l_ptr) +{ + retv_if(l_ptr == NULL, NULL); + + return l_ptr->start; +} + +void _util_deinit_list_iterator(slist_iterator *iter) +{ + ret_if(iter == NULL); + + g_free(iter); +} diff --git a/src/util/mtp_media_info.c b/src/util/mtp_media_info.c new file mode 100755 index 0000000..eb0421e --- /dev/null +++ b/src/util/mtp_media_info.c @@ -0,0 +1,833 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <glib.h> +#include <glib/gprintf.h> +#include <metadata_extractor.h> +#include "mtp_media_info.h" +#include "mtp_util.h" +#include "mtp_support.h" +#include "mtp_fs.h" + +static bool __fill_media_id_cb(media_info_h media, void *user_data) +{ + media_info_h *media_id = (media_info_h *)user_data; + DBG("INTO MEdia id retrieval callback"); + media_info_clone(media_id, media); + + return FALSE; +} + +static void __scan_folder_cb(media_content_error_e err, void *user_data) +{ + if (err != MEDIA_CONTENT_ERROR_NONE) { + ERR("Scan folder callback returns error = [%d]\n", err); + } + + return; +} + +mtp_bool _util_get_audio_metadata(const mtp_char *filepath, + comp_audio_meta_t *audio_data) +{ + char *temp = NULL; + audio_meta_h audio; + filter_h filter = NULL; + media_info_h media_item = NULL; + mtp_int32 ret = MEDIA_CONTENT_ERROR_NONE; + mtp_char condition[MEDIA_PATH_COND_MAX_LEN + 1]; + + retv_if(filepath == NULL, FALSE); + retv_if(audio_data == NULL, FALSE); + + g_snprintf(condition, MEDIA_PATH_COND_MAX_LEN + 1, "%s\"%s\"", + MEDIA_PATH_COND, filepath); + + ret = media_filter_create(&filter); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("Fail to create filter "); + return FALSE; + } + + ret = media_filter_set_condition(filter, condition, + MEDIA_CONTENT_COLLATE_DEFAULT); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("Failed to set condition "); + media_filter_destroy(filter); + return FALSE; + } + + ret = media_info_foreach_media_from_db(filter, __fill_media_id_cb, + &media_item); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("media_info_foreach_media_from_db Fail"); + media_filter_destroy(filter); + return FALSE; + } + + media_filter_destroy(filter); + + if (media_item == NULL) { + ERR("File entry not found in db"); + return FALSE; + } + + ret = media_info_get_audio(media_item, &audio); + if (ret != MEDIA_CONTENT_ERROR_NONE || audio == NULL) { + ERR("media_info_get_audio Fail or Audio is NULL"); + media_info_destroy(media_item); + return FALSE; + } + + ret = audio_meta_get_album(audio, &(audio_data->commonmeta.album)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_ALBUM Fail"); + goto ERROR_EXIT; + } + + ret = audio_meta_get_artist(audio, &(audio_data->commonmeta.artist)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_ARTIST Fail"); + goto ERROR_EXIT; + } + + ret = audio_meta_get_bit_rate(audio, + &(audio_data->commonmeta.audio_bitrate)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_AUDIO_BITRATE Fail"); + goto ERROR_EXIT; + } + + ret =audio_meta_get_composer(audio, &(audio_data->commonmeta.author)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_AUTHOR Fail"); + goto ERROR_EXIT; + } + + ret = audio_meta_get_copyright(audio, + &(audio_data->commonmeta.copyright)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_COPYRIGHT Fail"); + goto ERROR_EXIT; + } + + ret = audio_meta_get_duration(audio, + &(audio_data->commonmeta.duration)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_DURATION Fail"); + goto ERROR_EXIT; + } + + ret = audio_meta_get_genre(audio, &(audio_data->commonmeta.genre)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_GENRE Fail"); + goto ERROR_EXIT; + } + + ret = audio_meta_get_recorded_date(audio, + &(audio_data->commonmeta.year)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_RECDATE Fail"); + goto ERROR_EXIT; + } + + ret = audio_meta_get_track_num(audio, &temp); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_TRACK_NUM Fail"); + goto ERROR_EXIT; + } + + if (NULL != temp) { + audio_data->audiometa.track = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = audio_meta_get_channel(audio, + &(audio_data->commonmeta.num_channel)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_NUM_CHANNEL Fail"); + goto ERROR_EXIT; + } + + ret = audio_meta_get_sample_rate(audio, + &(audio_data->commonmeta.sample_rate)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_SAMPLE_RATE Fail"); + goto ERROR_EXIT; + } + + audio_data->commonmeta.description = g_strdup("Unknown"); + audio_data->commonmeta.audio_codec = 0; + + audio_meta_destroy(audio); + media_info_destroy(media_item); + return TRUE; + +ERROR_EXIT: + + audio_meta_destroy(audio); + media_info_destroy(media_item); + return FALSE; +} + +mtp_bool _util_get_video_metadata(mtp_char *filepath, + comp_video_meta_t *video_data) +{ + filter_h filter = NULL; + video_meta_h video; + media_info_h media_item = NULL; + mtp_int32 ret = MEDIA_CONTENT_ERROR_NONE; + mtp_char condition[MEDIA_PATH_COND_MAX_LEN + 1]; + + retv_if(filepath == NULL, FALSE); + retv_if(video_data == NULL, FALSE); + + g_snprintf(condition, sizeof(condition), "%s\"%s\"", MEDIA_PATH_COND, filepath); + + ret = media_filter_create(&filter); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("Fail to create filter "); + return FALSE; + } + + ret = media_filter_set_condition(filter, condition, + MEDIA_CONTENT_COLLATE_DEFAULT); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("Failed to set condition "); + media_filter_destroy(filter); + return FALSE; + } + + ret = media_info_foreach_media_from_db(filter, __fill_media_id_cb, + &media_item); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("media_info_foreach_media_from_db Fail"); + media_filter_destroy(filter); + return FALSE; + } + + media_filter_destroy(filter); + + if (media_item == NULL) { + ERR("File entry not found in db"); + return FALSE; + } + + ret = media_info_get_video(media_item, &video); + if (ret != MEDIA_CONTENT_ERROR_NONE || video == NULL) { + ERR("media_info_get_audio Fail or video is NULL"); + media_info_destroy(media_item); + return FALSE; + } + + ret = video_meta_get_album(video, &(video_data->commonmeta.album)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_ALBUM Fail"); + goto ERROR_EXIT; + } + + ret = video_meta_get_artist(video, &(video_data->commonmeta.artist)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_ARTIST Fail"); + goto ERROR_EXIT; + } + + /* AUDIO BITRATE */ + video_data->commonmeta.audio_bitrate = 0; + + ret = video_meta_get_composer(video, &(video_data->commonmeta.author)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_AUTHOR Fail"); + goto ERROR_EXIT; + } + + ret = video_meta_get_copyright(video, + &(video_data->commonmeta.copyright)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_COPYRIGHT Fail"); + goto ERROR_EXIT; + } + + /* Description */ + video_data->commonmeta.description = g_strdup("Unknown"); + + ret = video_meta_get_duration(video, + &(video_data->commonmeta.duration)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_DURATION Fail"); + goto ERROR_EXIT; + } + + ret = video_meta_get_genre(video, &(video_data->commonmeta.genre)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_GENRE Fail"); + goto ERROR_EXIT; + } + + ret = video_meta_get_recorded_date(video, + &(video_data->commonmeta.year)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_REC_DATE Fail"); + goto ERROR_EXIT; + } + + /* METADATA_AUDIO_CHANNELS */ + video_data->commonmeta.num_channel = 0; + + /* METADAT_RATING */ + video_data->commonmeta.rating = 0; + + /* METADATA_SAMPLE_RATE */ + video_data->commonmeta.sample_rate = 0; + + ret = video_meta_get_track_num(video, &(video_data->videometa.track)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_TRACK_NUM Fail"); + goto ERROR_EXIT; + } + + ret = video_meta_get_bit_rate(video, &(video_data->videometa.video_br)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_VIDEO_BITRATE Fail"); + goto ERROR_EXIT; + } + + /* VIDEO_FPS */ + video_data->videometa.video_fps = 0; + video_data->commonmeta.audio_codec = 0; + video_data->videometa.video_br = 0; + + ret = video_meta_get_height(video, &(video_data->videometa.video_h)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_HEIGHT Fail"); + goto ERROR_EXIT; + } + + ret = video_meta_get_width(video, &(video_data->videometa.video_w)); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("METADATA_WIDTH Fail"); + goto ERROR_EXIT; + } + + video_meta_destroy(video); + media_info_destroy(media_item); + return TRUE; +ERROR_EXIT: + video_meta_destroy(video); + media_info_destroy(media_item); + + return FALSE; +} + +static media_info_h __util_find_media_info(mtp_char *condition) +{ + int ret; + filter_h filter = NULL; + media_info_h media_item = NULL; + + ret = media_filter_create(&filter); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("Fail to create filter "); + return NULL; + } + + do { + ret = media_filter_set_condition(filter, condition, MEDIA_CONTENT_COLLATE_DEFAULT); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("media_filter_set_condition() Fail"); + break; + } + + ret = media_filter_set_offset(filter, 0, 1); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("media_filter_set_offset() Fail"); + break; + } + + ret = media_info_foreach_media_from_db(filter, __fill_media_id_cb, &media_item); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("media_info_foreach_media_from_db() Fail"); + break; + } + }while (0); + + media_filter_destroy(filter); + + return media_item; +} + + +static mtp_bool __util_get_height_width(image_meta_h image, int *h, int *w) +{ + int ret; + + ret = image_meta_get_height(image, h); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("image_meta_get_height() Fail(%d)", ret); + return FALSE; + } + + ret = image_meta_get_width(image, w); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("image_meta_get_width() Fail(%d)", ret); + return FALSE; + } + + return TRUE; +} + +mtp_bool _util_get_image_ht_wt(const mtp_char *filepath, + image_meta_t *image_data) +{ + mtp_int32 ret; + image_meta_h image; + media_info_h media_item; + mtp_char condition[MEDIA_PATH_COND_MAX_LEN + 1]; + + retv_if(filepath == NULL, FALSE); + retv_if(image_data == NULL, FALSE); + + g_snprintf(condition, sizeof(condition), "%s\"%s\"", MEDIA_PATH_COND, filepath); + + media_item = __util_find_media_info(condition); + if (media_item == NULL) { + ERR("File entry not found in db"); + return FALSE; + } + + ret = media_info_get_image(media_item, &image); + if (ret != MEDIA_CONTENT_ERROR_NONE || image == NULL) { + ERR("media_info_get_image() Fail(%d) or image(%p) is NULL", ret, image); + media_info_destroy(media_item); + return FALSE; + } + + ret = __util_get_height_width(image, &image_data->ht, &image_data->wt); + if (FALSE == ret) + ERR("__util_get_height_width() Fail"); + + media_info_destroy(media_item); + image_meta_destroy(image); + + return ret; +} + +mtp_bool _util_get_audio_meta_from_extractor(const mtp_char *filepath, + comp_audio_meta_t *audio_data) +{ + mtp_int32 ret = 0; + mtp_char *temp = NULL; + metadata_extractor_h metadata = NULL; + + retv_if(filepath == NULL, FALSE); + retv_if(audio_data == NULL, FALSE); + + ret = metadata_extractor_create(&metadata); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("metadata extractor create Fail"); + return FALSE; + } + + ret = metadata_extractor_set_path(metadata, filepath); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("metadata extractor set path Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_ALBUM, + &(audio_data->commonmeta.album)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_ALBUM Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_ARTIST, + &(audio_data->commonmeta.artist)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_ARTIST Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_AUDIO_BITRATE, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_AUDIO_BITRATE Fail"); + goto ERROR_EXIT; + } + + if (NULL != temp) { + audio_data->commonmeta.audio_bitrate = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_AUTHOR, + &(audio_data->commonmeta.author)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_AUTHOR Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_COPYRIGHT, + &(audio_data->commonmeta.copyright)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_COPYRIGHT Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_DESCRIPTION, + &(audio_data->commonmeta.description)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_DESCRIPTION Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_DURATION, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_DURATION Fail"); + goto ERROR_EXIT; + } + + if (NULL != temp) { + audio_data->commonmeta.duration = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_GENRE, + &(audio_data->commonmeta.genre)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_GENRE Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_RECDATE, + &(audio_data->commonmeta.year)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_RECDATE Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_TRACK_NUM, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_TRACK_NUM Fail"); + goto ERROR_EXIT; + } + if (NULL != temp) { + audio_data->audiometa.track = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_RATING, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_RATING Fail"); + goto ERROR_EXIT; + } + if (NULL != temp) { + audio_data->commonmeta.rating = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = metadata_extractor_get_metadata(metadata, + METADATA_AUDIO_SAMPLERATE, &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_SAMPLERATE Fail"); + goto ERROR_EXIT; + } + if (NULL != temp) { + audio_data->commonmeta.sample_rate = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_AUDIO_CHANNELS, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_CHANNELS Fail"); + goto ERROR_EXIT; + } + if (NULL != temp) { + audio_data->commonmeta.num_channel = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + audio_data->commonmeta.audio_codec = 0; + + metadata_extractor_destroy(metadata); + return TRUE; + +ERROR_EXIT: + metadata_extractor_destroy(metadata); + return FALSE; +} + +mtp_bool _util_get_video_meta_from_extractor(const mtp_char *filepath, + comp_video_meta_t *video_data) +{ + mtp_int32 ret = 0; + mtp_char *temp = NULL; + metadata_extractor_h metadata = NULL; + + retv_if(filepath == NULL, FALSE); + retv_if(video_data == NULL, FALSE); + + ret = metadata_extractor_create(&metadata); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("metadata extractor create Fail"); + return FALSE; + } + + ret = metadata_extractor_set_path(metadata, filepath); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("metadata extractor set path Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_ALBUM, + &(video_data->commonmeta.album)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_ALBUM Fail"); + goto ERROR_EXIT; + + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_ARTIST, + &(video_data->commonmeta.artist)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_ARTIST Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_AUDIO_BITRATE, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_AUDIO_BITRATE Fail"); + goto ERROR_EXIT; + } + if (NULL != temp) { + video_data->commonmeta.audio_bitrate = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_AUTHOR, + &(video_data->commonmeta.author)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_AUTHOR Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_COPYRIGHT, + &(video_data->commonmeta.copyright)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_COPYRIGHT Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_DESCRIPTION, + &(video_data->commonmeta.description)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_DESCRIPTION Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_DURATION, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_DURATION Fail"); + goto ERROR_EXIT; + } + if (NULL != temp) { + video_data->commonmeta.duration = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_GENRE, + &(video_data->commonmeta.genre)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_GENRE Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_RECDATE, + &(video_data->commonmeta.year)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_RECDATE Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_AUDIO_CHANNELS, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_AUDIO_CHANNELS Fail"); + goto ERROR_EXIT; + } + if (NULL != temp) { + video_data->commonmeta.num_channel = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_RATING, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_RATING Fail"); + goto ERROR_EXIT; + } + + if (NULL != temp) { + video_data->commonmeta.rating = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = metadata_extractor_get_metadata(metadata, + METADATA_AUDIO_SAMPLERATE, &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_AUDIO_SAMPLERATE Fail"); + goto ERROR_EXIT; + } + if (NULL != temp) { + video_data->commonmeta.sample_rate = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_TRACK_NUM, + &(video_data->videometa.track)); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_TRACK_NUM Fail"); + goto ERROR_EXIT; + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_VIDEO_BITRATE, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_VIDEO_BITRATE Fail"); + goto ERROR_EXIT; + } + if (NULL != temp) { + video_data->videometa.video_br = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_VIDEO_FPS, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_VIDEO_FPS Fail"); + goto ERROR_EXIT; + } + video_data->videometa.video_fps = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + + ret = metadata_extractor_get_metadata(metadata, METADATA_VIDEO_HEIGHT, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_VIDEO_HEIGHT Fail"); + goto ERROR_EXIT; + } + if (NULL != temp) { + video_data->videometa.video_h = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + ret = metadata_extractor_get_metadata(metadata, METADATA_VIDEO_WIDTH, + &temp); + if (ret != METADATA_EXTRACTOR_ERROR_NONE) { + ERR("METADATA_VIDEO_WIDTH Fail"); + goto ERROR_EXIT; + } + if (NULL != temp) { + video_data->videometa.video_w = atoi(temp); + MTP_PAL_SAFE_FREE(temp); + } + + metadata_extractor_destroy(metadata); + return TRUE; + +ERROR_EXIT: + metadata_extractor_destroy(metadata); + return FALSE; + +} + +void _util_flush_db(void) +{ + _util_add_file_to_db(NULL); + _util_delete_file_from_db(NULL); +} + +void _util_delete_file_from_db(const mtp_char *filepath) +{ + int ret; + + ret_if(NULL == filepath); + + ret = media_info_delete_from_db(filepath); + if (MEDIA_CONTENT_ERROR_NONE != ret) + ERR("media_info_delete_from_db() Fail(%d)", ret); + + return; +} + +void _util_add_file_to_db(const mtp_char *filepath) +{ + mtp_int32 ret; + media_info_h info = NULL; + + ret_if(NULL == filepath); + + ret = media_info_insert_to_db(filepath, &info); + if (MEDIA_CONTENT_ERROR_NONE != ret) + ERR("media_info_insert_to_db() Fail(%d)", ret); + + if (info) + media_info_destroy(info); + + return; +} + +void _util_scan_folder_contents_in_db(const mtp_char *filepath) +{ + mtp_int32 ret; + + ret_if(filepath == NULL); + + ret = media_content_scan_folder(filepath, true, __scan_folder_cb, NULL); + if (ret != MEDIA_CONTENT_ERROR_NONE) { + ERR("media_content_scan_folder Fail : %d\n", ret); + } + + return; +} + +void _util_free_common_meta(common_meta_t *metadata) +{ + MTP_PAL_SAFE_FREE(metadata->album); + MTP_PAL_SAFE_FREE(metadata->artist); + MTP_PAL_SAFE_FREE(metadata->author); + MTP_PAL_SAFE_FREE(metadata->copyright); + MTP_PAL_SAFE_FREE(metadata->description); + MTP_PAL_SAFE_FREE(metadata->genre); + MTP_PAL_SAFE_FREE(metadata->year); + + return; +} +void _util_free_video_meta(video_meta_t *video) +{ + MTP_PAL_SAFE_FREE(video->track); + return; +} diff --git a/src/util/mtp_msgq.c b/src/util/mtp_msgq.c new file mode 100755 index 0000000..ad98fa5 --- /dev/null +++ b/src/util/mtp_msgq.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/msg.h> +#include "mtp_msgq.h" + +/* + * FUNCTIONS + */ +mtp_bool _util_msgq_init(msgq_id_t *mq_id, mtp_uint32 flags) +{ + *mq_id = msgget(IPC_PRIVATE, 0666 | IPC_CREAT); + if (*mq_id == -1) { + ERR("msgget() Fail"); + _util_print_error(); + return FALSE; + } + return TRUE; +} + +mtp_bool _util_msgq_send(msgq_id_t mq_id, void *buf, mtp_uint32 size, + mtp_uint32 flags) +{ + if (-1 == msgsnd(mq_id, buf, size, flags)) { + ERR("msgsnd() Fail : mq_id = [%d]", mq_id); + _util_print_error(); + return FALSE; + } + return TRUE; +} + +mtp_bool _util_msgq_receive(msgq_id_t mq_id, void *buf, mtp_uint32 size, + mtp_uint32 flags, mtp_int32 *nbytes) +{ + int ret = 0; + + if (flags == 1) { + ret = msgrcv(mq_id, buf, size, 0, IPC_NOWAIT); + } else { + ret = msgrcv(mq_id, buf, size, 0, 0); + } + + if (ret == -1) { + ERR("msgrcv() Fail"); + _util_print_error(); + *nbytes = 0; + return FALSE; + } + + *nbytes = ret; + return TRUE; +} + +mtp_bool _util_msgq_deinit(msgq_id_t *msgq_id) +{ + if (-1 == msgctl(*msgq_id, IPC_RMID, 0)) { + ERR("msgctl(IPC_RMID) Fail"); + return FALSE; + } + return TRUE; +} + +mtp_bool _util_msgq_set_size(msgq_id_t mq_id, mtp_uint32 nbytes) +{ + struct msqid_ds attr; + + /* Getting the attributes of Message Queue */ + if (msgctl(mq_id, MSG_STAT, &attr) == -1) { + ERR("msgctl(MSG_STAT) Fail"); + return FALSE; + } + + attr.msg_qbytes = nbytes; + + /* Setting the message queue size */ + if (msgctl(mq_id, IPC_SET, &attr) == -1) { + ERR("msgctl(IPC_SET) Fail"); + return FALSE; + } + return TRUE; +} + +/* + * _util_rcv_msg_from_mq + * + * This function receives a message pointer from Message Queue + * @param[in] mq_id Message Queue Id + * @param[out] pkt Shall be assigned with received buffer ptr + * @param[out] pkt_len Will hold the length of received data + * @param[out] mtype Will be assigned the type of message received + */ +mtp_bool _util_rcv_msg_from_mq(msgq_id_t mq_id, unsigned char **pkt, + mtp_uint32 *pkt_len, msg_type_t *mtype) +{ + msgq_ptr_t msg = { 0 }; + mtp_int32 nbytes = 0; + + if (FALSE == _util_msgq_receive(mq_id, (void *)&msg, + sizeof(msgq_ptr_t) - sizeof(long), 0, &nbytes)) { + ERR("_util_msgq_receive() Fail : mq_id = [%d]", mq_id); + return FALSE; + } + + *pkt_len = msg.length; + *pkt = msg.buffer; + *mtype = msg.mtype; + + return TRUE; +} diff --git a/src/util/mtp_support.c b/src/util/mtp_support.c new file mode 100755 index 0000000..b5e01da --- /dev/null +++ b/src/util/mtp_support.c @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <glib.h> +#include <glib/gprintf.h> +#include <unistd.h> +#include "mtp_support.h" +#include "ptp_datacodes.h" +#include "mtp_util.h" + +/* + * STATIC FUNCTIONS + */ +static mtp_char *__util_conv_int_to_hex_str(mtp_int32 int_val, mtp_char *str); + +/* + * FUNCTIONS + */ +void _util_conv_byte_order(void *data, mtp_int32 size) +{ + mtp_int32 idx; + mtp_uchar temp; + mtp_int32 h_size; + mtp_uchar *l_data = (mtp_uchar *)data; + + ret_if(data == NULL); + retm_if(size <= 1, "size(%d) is invalid", size); + + h_size = size / 2; + for (idx = 0; idx < h_size; idx++) { + temp = l_data[idx]; + l_data[idx] = l_data[size - idx - 1]; + l_data[size - idx - 1] = temp; + } + + return; +} + +void _util_conv_byte_order_wstring(mtp_uint16 *wstr, mtp_int32 size) +{ + _util_conv_byte_order_gen_str(wstr, size, sizeof(mtp_uint16)); + return; +} + +void _util_conv_byte_order_gen_str(void *str, mtp_int32 size, mtp_int32 elem_sz) +{ + mtp_int32 idx; + mtp_int32 f_size = size * elem_sz; + mtp_uchar *l_str = (mtp_uchar *)str; + + ret_if(str == NULL); + retm_if(elem_sz <= 1, "elem_sz(%d) is invalid", elem_sz); + + for (idx = 0; idx < f_size; idx += elem_sz) { + _util_conv_byte_order(&(l_str[idx]), elem_sz); + } + + return; +} + +/* + * If items_written is greater than or equal to dest_size, + * src is truncated when it is copied to dest. + */ +mtp_int32 _util_utf16_to_utf8(char *dest, mtp_int32 dest_size, + const mtp_wchar *src) +{ + gchar *utf8 = NULL; + GError *error = NULL; + glong items_read = 0; + glong items_written = 0; + const gunichar2 *utf16 = (const gunichar2 *)src; + + retv_if(src == NULL, 0); + retv_if(dest == NULL, 0); + + utf8 = g_utf16_to_utf8(utf16, -1, &items_read, &items_written, &error); + if (utf8 == NULL) { + ERR("%s\n", error->message); + g_error_free(error); + + dest[0] = '\0'; + items_written = 0; + } else { + g_strlcpy(dest, (char *)utf8, dest_size); + g_free(utf8); + } + + return (mtp_int32)items_written; +} + +/* + * If items_written is greater than or equal to dest_items, + * src is truncated when it is copied to dest. + */ +mtp_int32 _util_utf8_to_utf16(mtp_wchar *dest, mtp_int32 dest_items, + const char *src) +{ + GError *error = NULL; + glong items_read = 0; + gunichar2 *utf16 = NULL; + glong items_written = 0; + + retv_if(src == NULL, 0); + retv_if(dest == NULL, 0); + + utf16 = g_utf8_to_utf16(src, -1, &items_read, &items_written, &error); + if (utf16 == NULL) { + ERR("%s\n", error->message); + g_error_free(error); + error = NULL; + + dest[0] = (mtp_wchar)'\0'; + items_written = 0; + } else { + _util_wchar_ncpy(dest, utf16, dest_items); + g_free(utf16); + } + + return (mtp_int32)items_written; +} + + +/* + * Copies a unicode string. + * @param[in] src Null-terminated source string + * @param[out] dest Destination buffer + * @return None + */ +void _util_wchar_cpy(mtp_wchar *dest, const mtp_wchar *src) +{ + ret_if(src == NULL); + ret_if(dest == NULL); + + if (!((int)dest & 0x1) && !((int)src & 0x1)){ + /* 2-byte aligned */ + mtp_wchar *temp = dest; + + while ((*temp++ = *src++) != '\0') { + ; /* DO NOTHING */ + } + } else { + /* not-aligned, byte to byte approach - slow */ + mtp_char *pc1 = (mtp_char *)dest; + mtp_char *pc2 = (mtp_char *)src; + + while (*pc2 || *(pc2 + 1)) { + *pc1 = *pc2; + *(pc1 + 1) = *(pc2 + 1); + + pc1 += 2; + pc2 += 2; + } + } + + return; +} + +/* + * Copies a unicode string a given numbers of character. + * @param[in] src Null-terminated source string + * @param[out] dest Destination buffer + * @return None + */ +void _util_wchar_ncpy(mtp_wchar *dest, const mtp_wchar *src, unsigned long n) +{ + char *pc1 = NULL; + char *pc2 = NULL; + mtp_wchar *temp = NULL; + + ret_if(src == NULL); + ret_if(dest == NULL); + + if (!((int)dest & 0x1) && !((int)src & 0x1)) { /* 2-byte aligned */ + temp = dest; + + while (n && (*temp++ = *src++)) { + n--; + } + + if (n) { + while (--n) { + *temp++ = 0; + } + } + } else { /* not-aligned, byte to byte approach - slow */ + + pc1 = (char *)dest; + pc2 = (char *)src; + + while (n && (*pc2 || *(pc2 + 1))) { + --n; + *pc1++ = *pc2++; + *pc1++ = *pc2++; + } + + if (n) { + while (--n) { + *pc1++ = 0; + *pc1++ = 0; + } + } + } + + return; +} + +/* + * Returns the length of wide character string + * @param[in] src Wide char string + * @return length + */ +size_t _util_wchar_len(const mtp_wchar *s) +{ + if (!((int)s & 0x1)) { /* 2-byte aligned */ + mtp_wchar *temp = (mtp_wchar *)s; + + while (*temp++) { + /* DO NOTHING */ ; + } + + DBG("Length : %d\n", temp - s - 1); + return ((size_t)(temp - s - 1)); + } else { /* not-aligned, byte to byte approach - slow */ + + unsigned char *temp = (unsigned char *)s; + + while (*temp || *(temp + 1)) { + temp += 2; + } + + DBG("Length : %d\n", (temp - (unsigned char *)s) / 2); + return ((size_t) (temp - (unsigned char *)s) / 2); + } +} + +static mtp_char* __util_conv_int_to_hex_str(mtp_int32 int_val, mtp_char *str) +{ + mtp_char *nstr = str; + mtp_int32 val = int_val; + mtp_char hex[] = { "0123456789ABCDEF" }; + + retv_if(str == NULL, NULL); + + *nstr++ = '0'; + *nstr++ = 'x'; + + for (val = int_val; val; val <<= 4) { + *nstr++ = hex[(val >> (sizeof(int) * 8 - 4)) & 0xF]; + } + *nstr = '\0'; + return str; +} + +/* + * This is very minimal implementation. + * Be cautious using this function. + */ +mtp_err_t _util_wchar_swprintf(mtp_wchar *mtp_wstr, mtp_int32 size, + mtp_char *format, ...) +{ + mtp_char *ptr; + mtp_wchar wsHex[24]; + mtp_int32 count = 0; + mtp_wchar *wbuf = mtp_wstr; + mtp_char *bptr_val = NULL; + mtp_wchar *wstr_val = NULL; + mtp_int32 int_val = 0, len = 0; + mtp_char buf[MTP_MAX_PATHNAME_SIZE + 1]; + + va_list arg_list; + va_start(arg_list, format); + for (ptr = format; *ptr && count < (size - 1); ptr++) { + if (*ptr == '%') { + switch (*(ptr + 1)) { + case 'd': + int_val = va_arg(arg_list, int); + wbuf[count++] = (mtp_wchar) (int_val + '0'); + ptr++; + break; + case 's': + bptr_val = va_arg(arg_list, char *); + wstr_val = (mtp_wchar *) bptr_val; + len = _util_wchar_len(wstr_val); + if (len + count > size - 1) { + len = size - 1 - count; + _util_wchar_ncpy(&wbuf[count], wstr_val, + len); + } else { + _util_wchar_cpy(&wbuf[count], wstr_val); + } + count += len; + ptr++; + break; + case 'x': + int_val = va_arg(arg_list, int); + __util_conv_int_to_hex_str(int_val, buf); + _util_utf8_to_utf16(wsHex, + sizeof(wsHex) / WCHAR_SIZ, buf); + len = strlen(buf); + if (len + count > size - 1) { + len = size - 1 - count; + _util_wchar_ncpy(&wbuf[count], wsHex, + len); + } else { + _util_wchar_cpy(&wbuf[count], wsHex); + } + count += len; + ptr++; + break; + + default: + DBG("swprintf not handling: %c", *(ptr + 1)); + break; + } + } else { + wbuf[count++] = (mtp_wchar)(*ptr); + } + } + + va_end(arg_list); + wbuf[count] = (mtp_wchar)'\0'; + _util_utf16_to_utf8(buf, sizeof(buf), wbuf); + + return MTP_ERROR_NONE; +} + +mtp_uint16 _util_get_fmtcode(const mtp_char *extn) +{ + static fmt_code_t fmt_code_table[] = { + {"ALB", MTP_FMT_ABSTRACT_AUDIO_ALBUM}, + {"MP3", PTP_FMT_MP3}, + {"WMA", MTP_FMT_WMA}, + {"WMV", MTP_FMT_WMV}, + {"JPG", PTP_FMT_IMG_EXIF}, + {"GIF", PTP_FMT_IMG_GIF}, + {"BMP", PTP_FMT_IMG_BMP}, + {"PNG", PTP_FMT_IMG_PNG}, + {"ASF", PTP_FMT_ASF}, + {"WAV", PTP_FMT_WAVE}, + {"AVI", PTP_FMT_AVI}, + {"MPG", PTP_FMT_MPEG}, + {"TXT", PTP_FMT_TEXT}, + {"3GP", MTP_FMT_3GP}, + {"ODF", MTP_FMT_3GP}, + {"O4A", MTP_FMT_3GP}, + {"O4V", MTP_FMT_3GP}, + {"MP4", MTP_FMT_MP4}, + {"FLAC", MTP_FMT_FLAC}, + {"", PTP_FMT_UNDEF} + }; + + fmt_code_t *p = NULL; + p = fmt_code_table; + + while (p->fmt_code != PTP_FMT_UNDEF) { + if (!strncasecmp(extn, p->extn, strlen(p->extn))) + break; + + p++; + } + + /* will return FormatCode or PTP_FORMATCODE_UNDEFINED + * if we hit end of list. + */ + return p->fmt_code; +} + +/* + * This function gets the file extension. + * @param[in] fileName Specifies the file name. + * @param[out] file_extn holds the extension of the file. + * @return Returns TRUE on success and FALSE on failure. + */ +mtp_bool _util_get_file_extn(const mtp_char *f_name, mtp_char *f_extn) +{ + char *ptr; + + retv_if(NULL == f_name, FALSE); + retv_if(NULL == f_extn, FALSE); + + ptr = strrchr(f_name, '.'); + + if (ptr != NULL) { + g_strlcpy(f_extn, ptr + 1, MTP_MAX_PATHNAME_SIZE); + return TRUE; + } + + return FALSE; +} + +mtp_bool _util_get_file_name(const mtp_char *fullpath, mtp_char *f_name) +{ + mtp_int32 i, j; + + retv_if(f_name == NULL, FALSE); + retv_if(fullpath == NULL, FALSE); + + i = strlen(fullpath); + + for (j=0; i >= 0; i--) { + if (fullpath[i] == '/') { + g_strlcpy(f_name, &fullpath[i + 1], j); + return TRUE; + } + j++; + } + g_strlcpy(f_name, fullpath, j); + + return TRUE; +} +/* + * This function gives file name without extension. + * @param[in] fullpath pointer to absolute file path + * @param[out] f_name gets filled with filename w/o extension + * @return True or False based on success or failure + */ +mtp_bool _util_get_file_name_wo_extn(const mtp_char *fullpath, mtp_char *f_name) +{ + mtp_char *fname_ptr; + mtp_uint32 fname_len; + mtp_char *extn_ptr = NULL; + + retv_if(f_name == NULL, FALSE); + retv_if(fullpath == NULL, FALSE); + + fname_ptr = strrchr(fullpath, '/'); + + if (fname_ptr == NULL) { + ERR("Invalid File Name"); + return FALSE; + } + + fname_ptr = fname_ptr + sizeof(char); + fname_len = strlen(fname_ptr); + extn_ptr = strrchr(fname_ptr, '.'); + + if (extn_ptr == NULL) { + g_strlcpy(f_name, fname_ptr, fname_len + 1); + return TRUE; + } + + g_strlcpy(f_name, fname_ptr, ((mtp_uint32)(extn_ptr - fname_ptr) + 1)); + return TRUE; +} + +mtp_bool _util_is_path_len_valid(const mtp_char *path) +{ + mtp_uint32 limit = 0; + mtp_uint32 mtp_path_len = 0; + mtp_uint32 root_path_len = 0; + + static mtp_uint32 max_store_len = 0; + static mtp_bool is_initialized = FALSE; + static mtp_uint32 internal_store_len = 0; + static mtp_uint32 external_store_len = 0; + + retv_if(path == NULL, FALSE); + + if (!is_initialized) { + is_initialized = TRUE; + internal_store_len = strlen(MTP_STORE_PATH_CHAR); + external_store_len = strlen(MTP_EXTERNAL_PATH_CHAR); + + max_store_len = internal_store_len > external_store_len ? + internal_store_len : external_store_len; + + DBG("max store len : [%u]\n", max_store_len); + } + + if (!strncmp(path, MTP_STORE_PATH_CHAR, internal_store_len)) { + root_path_len = internal_store_len; + } else if (!strncmp(path, MTP_EXTERNAL_PATH_CHAR, external_store_len)) { + root_path_len = external_store_len; + } + else { + ERR("Unknown store's path : %s\n", path); + return FALSE; + } + + /* Path len should be calculated except root path(eg. /opt/usr/media) */ + mtp_path_len = strlen(path) - root_path_len; + + /* MTP_MAX_PATHNAME_SIZE includes maximum length of root path */ + limit = MTP_MAX_PATHNAME_SIZE - max_store_len; + + if (mtp_path_len > limit) { + ERR("Too long path : [%u] > [%u]\n", mtp_path_len, limit); + return FALSE; + } + + return TRUE; +} + +mtp_bool _util_create_path(mtp_char *path, mtp_uint32 size, const mtp_char *dir, + const mtp_char *filename) +{ + mtp_int32 ret = 0; + mtp_uint32 len = 0; + + retv_if(dir == NULL, FALSE); + retv_if(path == NULL, FALSE); + retv_if(filename == NULL, FALSE); + + len = strlen(filename); + if (len > MTP_MAX_FILENAME_SIZE) { + ERR("filename is too long :[%u] > [%u]\n", len, + MTP_MAX_FILENAME_SIZE); + return FALSE; + } + + ret = g_snprintf(path, size, "%s/%s", dir, filename); + if (ret > size) { + ERR("path is truncated"); + return FALSE; + } + + if (_util_is_path_len_valid(path) == FALSE) { + ERR("path length exceeds the limit"); + return FALSE; + } + + return TRUE; +} + +/* + * This function gets the parent path. + * @param[in] fullpath Pointer to a buffer containing full file path. + * @param[out] p_path Points the buffer to hold parent path. + * @return None + */ +void _util_get_parent_path(const mtp_char *fullpath, mtp_char *p_path) +{ + mtp_char *ptr = NULL; + + ret_if(NULL == p_path); + ret_if(NULL == fullpath); + + ptr = strrchr(fullpath, '/'); + if (!ptr) { + ERR("Path does not have parent path"); + return; + } + + g_strlcpy(p_path, fullpath, (mtp_uint32)(ptr - fullpath) + 1); + return; +} + +void _util_conv_wstr_to_guid(mtp_wchar *wstr, mtp_uint64 *guid) +{ + mtp_uint32 skip_idx; + mtp_uint32 cur_idx; + mtp_uint64 temp[2]; + mtp_int32 count = 0; + mtp_int32 cpy_sz = 0; + + ret_if(wstr == NULL); + ret_if(guid == NULL); + + while (wstr[count] != 0) { + count++; + } + + memset(guid, 0, sizeof(temp)); + skip_idx = sizeof(temp) / sizeof(mtp_wchar); + + for (cur_idx = 0; cur_idx < count; cur_idx += skip_idx) { + + memset(temp, 0, sizeof(temp)); + cpy_sz = (count - cur_idx) * sizeof(mtp_wchar); + if (cpy_sz > sizeof(temp)) { + cpy_sz = sizeof(temp); + } + memcpy(temp, &(wstr[cur_idx]), cpy_sz); + guid[0] += temp[0]; + guid[1] += temp[1]; + } + + return; +} + +mtp_bool _util_get_unique_dir_path(const mtp_char *exist_path, + mtp_char *new_path, mtp_uint32 new_path_buf_len) +{ + mtp_uint32 num_bytes = 0; + mtp_uint32 max_value = 1; + mtp_uint32 count = 1; + mtp_uint32 val = 1; + mtp_char *buf = NULL; + mtp_uint32 len = strlen(exist_path); + + retv_if(new_path == NULL, FALSE); + retv_if(exist_path == NULL, FALSE); + + /* Excluding '_' */ + num_bytes = new_path_buf_len - len - 1; + if (num_bytes <= 0) { + ERR("No space to append data[%d]\n", num_bytes); + return FALSE; + } + + if (num_bytes >= MTP_BUF_SIZE_FOR_INT - 1) { + max_value = UINT_MAX; + } else { + while (count <= num_bytes) { + max_value *= 10; + count++; + } + DBG("max_value[%u]\n", max_value); + } + + buf = (mtp_char *)g_malloc(new_path_buf_len); + if (buf == NULL) { + ERR("g_malloc Fail"); + return FALSE; + } + g_strlcpy(buf, exist_path, new_path_buf_len); + while (val < max_value) { + /* Including NUL and '_' */ + g_snprintf(&buf[len], num_bytes + 2, "_%u", val++); + if (access(buf, F_OK) < 0) { + goto SUCCESS; + } + } + + g_free(buf); + ERR("Unable to generate Unique Dir Name"); + return FALSE; + +SUCCESS: + g_strlcpy(new_path, buf, new_path_buf_len); + g_free(buf); + DBG_SECURE("Unique dir name[%s]\n", new_path); + return TRUE; +} diff --git a/src/util/mtp_thread.c b/src/util/mtp_thread.c new file mode 100755 index 0000000..e1f48e3 --- /dev/null +++ b/src/util/mtp_thread.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <mtp_thread.h> + +/* + * FUNCTIONS + */ +mtp_bool _util_thread_create(pthread_t *tid, const mtp_char *tname, + mtp_int32 thread_state, thread_func_t thread_func, void *arg) +{ + int error = 0; + pthread_attr_t attr; + + retv_if(tname == NULL, FALSE); + retv_if(thread_func == NULL, FALSE); + + error = pthread_attr_init(&attr); + if (error != 0) { + ERR("pthread_attr_init Fail [%d], errno [%d]\n", error, errno); + return FALSE; + } + + if (thread_state == PTHREAD_CREATE_JOINABLE) { + error = pthread_attr_setdetachstate(&attr, + PTHREAD_CREATE_JOINABLE); + if (error != 0) { + ERR("pthread_attr_setdetachstate Fail [%d], errno [%d]\n", error, errno); + pthread_attr_destroy(&attr); + return FALSE; + } + } + + error = pthread_create(tid, &attr, thread_func, arg); + if (error != 0) { + ERR( "[%s] Thread creation Fail errno [%d]\n", tname, errno); + pthread_attr_destroy(&attr); + return FALSE; + } + + error = pthread_attr_destroy(&attr); + if (error != 0) { + ERR("pthread_attr_destroy Fail [%d] errno [%d]\n", error, errno); + } + + return TRUE; +} + +mtp_bool _util_thread_join(pthread_t tid, void **data) +{ + mtp_int32 res = 0; + + res = pthread_join(tid, data); + if (res != 0) { + ERR("pthread_join Fail res = [%d] for thread [%u] errno [%d]\n", + res, tid, errno); + return FALSE; + } + + return TRUE; +} + +mtp_bool _util_thread_cancel(pthread_t tid) +{ + mtp_int32 res; + + res = pthread_cancel(tid); + if (res != 0) { + ERR("pthread_cancel Fail [%d] errno [%d]\n", tid, errno); + return FALSE; + } + + return TRUE; +} + +void _util_thread_exit(void *val_ptr) +{ + pthread_exit(val_ptr); + return; +} diff --git a/src/util/mtp_util.c b/src/util/mtp_util.c new file mode 100755 index 0000000..5b0ee9c --- /dev/null +++ b/src/util/mtp_util.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> +#include <time.h> +#include <pthread.h> +#include <tapi_common.h> +#include <ITapiModem.h> +#include <system_info.h> +#include <vconf.h> +#include <gcrypt.h> +#include "mtp_util.h" +#include "mtp_support.h" +#include "mtp_fs.h" + +static phone_state_t g_ph_status = { 0 }; + + +void _util_print_error() +{ + /*In glibc-2.7, the longest error message string is 50 characters + ("Invalid or incomplete multibyte or wide character"). */ + mtp_char buff[100] = {0}; + + strerror_r(errno, buff, sizeof(buff)); + ERR("Error: [%d]:[%s]\n", errno, buff); +} + +mtp_int32 _util_get_battery_level(void) +{ + mtp_int32 result = 0; + mtp_int32 battery_level = 100; + + result = vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CAPACITY, + &battery_level); + if (result != 0) { + ERR("VCONFKEY_SYSMAN_BATTERY_CAPACITY Fail!"); + } + return battery_level; +} + +mtp_bool _util_get_serial(mtp_char *serial, mtp_uint32 len) +{ + TapiHandle *handle = NULL; + mtp_char *imei_no = NULL; + mtp_char *serial_no = NULL; + mtp_uint16 i = 0; + char hash_value[MD5_HASH_LEN] = { 0 }; + + if (serial == NULL || len <= MD5_HASH_LEN * 2) { + ERR("serial is null or length is less than (MD5_HASH_LEN * 2)"); + return FALSE; + } + + serial_no = vconf_get_str(VCONFKEY_MTP_SERIAL_NUMBER_STR); + if (serial_no == NULL) { + ERR("vconf_get Fail for %s\n", + VCONFKEY_MTP_SERIAL_NUMBER_STR); + return FALSE; + } + + if (strlen(serial_no) > 0) { + g_strlcpy(serial, serial_no, len); + g_free(serial_no); + return TRUE; + } + g_free(serial_no); + + handle = tel_init(NULL); + if (!handle) { + ERR("tel_init Fail"); + return FALSE; + } + + imei_no = tel_get_misc_me_imei_sync(handle); + if (!imei_no) { + ERR("tel_get_misc_me_imei_sync Fail"); + tel_deinit(handle); + return FALSE; + } + + tel_deinit(handle); + + gcry_md_hash_buffer(GCRY_MD_MD5, hash_value, imei_no, strlen(imei_no)); + + for (i = 0; i < MD5_HASH_LEN; i++) { + g_snprintf(&serial[i*2], 3, "%02X", hash_value[i]); + } + + if (vconf_set_str(VCONFKEY_MTP_SERIAL_NUMBER_STR, serial) == -1) { + ERR("vconf_set Fail for %s\n", + VCONFKEY_MTP_SERIAL_NUMBER_STR); + g_free(imei_no); + return TRUE; + } + + g_free(imei_no); + return TRUE; +} + +void _util_get_vendor_ext_desc(mtp_char *vendor_ext_desc, mtp_uint32 len) +{ + mtp_int32 ret = SYSTEM_INFO_ERROR_NONE; + mtp_char *version = NULL; + + ret_if(len == 0); + ret_if(vendor_ext_desc == NULL); + + ret = system_info_get_platform_string( + "http://tizen.org/feature/platform.version", &version); + + if (ret != SYSTEM_INFO_ERROR_NONE) { + ERR("system_info_get_value_string Fail : 0x%X\n", ret); + g_strlcpy(vendor_ext_desc, MTP_VENDOR_EXTENSIONDESC_CHAR, len); + return; + } + g_snprintf(vendor_ext_desc, len, "%stizen.org:%s; ", + MTP_VENDOR_EXTENSIONDESC_CHAR, version); + g_free(version); + return; +} + +void _util_get_model_name(mtp_char *model_name, mtp_uint32 len) +{ + mtp_int32 ret = SYSTEM_INFO_ERROR_NONE; + mtp_char *model = NULL; + + ret_if(len == 0); + ret_if(model_name == NULL); + + ret = system_info_get_platform_string( + "http://tizen.org/system/model_name", &model); + + if (ret != SYSTEM_INFO_ERROR_NONE) { + ERR("system_info_get_value_string Fail : 0x%X\n", ret); + g_strlcpy(model_name, MTP_DEFAULT_MODEL_NAME, len); + return; + } + g_strlcpy(model_name, model, len); + g_free(model); + return; +} + +void _util_get_device_version(mtp_char *device_version, mtp_uint32 len) +{ + mtp_int32 ret = SYSTEM_INFO_ERROR_NONE; + mtp_char *version = NULL; + mtp_char *build_info = NULL; + + ret_if(len == 0); + ret_if(device_version == NULL); + + ret = system_info_get_platform_string( + "http://tizen.org/feature/platform.version", &version); + + if (ret != SYSTEM_INFO_ERROR_NONE) { + ERR("system_info_get_value_string Fail : 0x%X\n", ret); + g_strlcpy(device_version, MTP_DEFAULT_DEVICE_VERSION, len); + return; + } + + ret = system_info_get_platform_string( + "http://tizen.org/system/build.string", &build_info); + + if (ret != SYSTEM_INFO_ERROR_NONE) { + ERR("system_info_get_value_string Fail : 0x%X\n", ret); + g_strlcpy(device_version, MTP_DEFAULT_DEVICE_VERSION, len); + g_free(version); + return; + } + g_snprintf(device_version, len, "TIZEN %s (%s)", version, build_info); + g_free(version); + g_free(build_info); + return; +} + +void _util_gen_alt_serial(mtp_char *serial, mtp_uint32 len) +{ + struct timeval st; + mtp_char model_name[MTP_MODEL_NAME_LEN_MAX + 1] = { 0 }; + + ret_if(len == 0); + ret_if(serial == NULL); + + if (gettimeofday(&st, NULL) < 0) { + ERR("gettimeofday Fail"); + _util_print_error(); + return; + } + _util_get_model_name(model_name, sizeof(model_name)); + g_snprintf(serial, len, "%s-%010ld-%011ld", model_name, + st.tv_sec, st.tv_usec); + + if (vconf_set_str(VCONFKEY_MTP_SERIAL_NUMBER_STR, serial) == -1) { + ERR("vconf_set Fail %s\n", VCONFKEY_MTP_SERIAL_NUMBER_STR); + } + + return; +} + +void _util_get_usb_status(phone_status_t *val) +{ + mtp_int32 ret = 0; + mtp_int32 state = 0; + + ret = vconf_get_int(VCONFKEY_SYSMAN_USB_STATUS, &state); + if (ret == -1 || state == VCONFKEY_SYSMAN_USB_DISCONNECTED) { + *val = MTP_PHONE_USB_DISCONNECTED; + return; + } + + *val = MTP_PHONE_USB_CONNECTED; + return; +} + +phone_status_t _util_get_local_usb_status(void) +{ + return g_ph_status.usb_state; +} + +void _util_set_local_usb_status(const phone_status_t val) +{ + g_ph_status.usb_state = val; + return; +} + +void _util_get_mmc_status(phone_status_t *val) +{ + mtp_int32 ret = 0; + mtp_int32 state = 0; + + ret = vconf_get_int(VCONFKEY_SYSMAN_MMC_STATUS, &state); + if (ret == -1 || state != + VCONFKEY_SYSMAN_MMC_MOUNTED) { + *val = MTP_PHONE_MMC_NONE; + return; + } + + *val = MTP_PHONE_MMC_INSERTED; + return; +} + +phone_status_t _util_get_local_mmc_status(void) +{ + return g_ph_status.mmc_state; +} + +void _util_set_local_mmc_status(const phone_status_t val) +{ + g_ph_status.mmc_state = val; + return; +} + +void _util_get_usbmode_status(phone_status_t *val) +{ + mtp_int32 ret = 0; + mtp_int32 state = 0; + + ret = vconf_get_int(VCONFKEY_SETAPPL_USB_MODE_INT, + &state); + if (ret < 0) + *val = MTP_PHONE_USB_MODE_OTHER; + else + *val = state; + return; +} + +phone_status_t _util_get_local_usbmode_status(void) +{ + return g_ph_status.usb_mode_state; +} + +void _util_set_local_usbmode_status(const phone_status_t val) +{ + g_ph_status.usb_mode_state = val; + return; +} |