summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHyihong Chae <hh.chae@samsung.com>2015-11-03 11:42:59 +0900
committerHyihong Chae <hh.chae@samsung.com>2015-11-03 11:47:18 +0900
commitbd85f3529a3cf4a566bd800842ca3bf78c9dd00c (patch)
tree5ddf23a8ac619b49605f8251de95e998af6e1387
parentf81378259c8c83019251fdcecab4d0628c7e3f67 (diff)
downloadmtp-responder-bd85f3529a3cf4a566bd800842ca3bf78c9dd00c.tar.gz
mtp-responder-bd85f3529a3cf4a566bd800842ca3bf78c9dd00c.tar.bz2
mtp-responder-bd85f3529a3cf4a566bd800842ca3bf78c9dd00c.zip
Change-Id: I1742218bdb2b3a01568236d72a65bba68aed4f68 Signed-off-by: HyiHong Chae <hh.chae@samsung.com>
-rwxr-xr-xCMakeLists.txt32
-rwxr-xr-xLICENSE.APLv2206
-rwxr-xr-xinclude/entity/mtp_device.h272
-rwxr-xr-xinclude/entity/mtp_object.h96
-rwxr-xr-xinclude/entity/mtp_property.h318
-rwxr-xr-xinclude/entity/mtp_store.h127
-rwxr-xr-xinclude/mtp_cmd_handler.h100
-rwxr-xr-xinclude/mtp_cmd_handler_util.h115
-rwxr-xr-xinclude/mtp_config.h243
-rwxr-xr-xinclude/mtp_datatype.h96
-rwxr-xr-xinclude/mtp_event_handler.h64
-rwxr-xr-xinclude/mtp_init.h30
-rwxr-xr-xinclude/mtp_inoti_handler.h48
-rwxr-xr-xinclude/ptp_container.h103
-rwxr-xr-xinclude/ptp_datacodes.h822
-rwxr-xr-xinclude/transport/mtp_transport.h57
-rwxr-xr-xinclude/transport/mtp_usb_driver.h60
-rwxr-xr-xinclude/util/mtp_fs.h97
-rwxr-xr-xinclude/util/mtp_list.h46
-rwxr-xr-xinclude/util/mtp_media_info.h105
-rwxr-xr-xinclude/util/mtp_msgq.h42
-rwxr-xr-xinclude/util/mtp_support.h58
-rwxr-xr-xinclude/util/mtp_thread.h60
-rwxr-xr-xinclude/util/mtp_util.h150
-rwxr-xr-xmtp-responder.conf61
-rwxr-xr-xmtp-responder.service10
-rwxr-xr-xpackaging/mtp-responder.manifest27
-rwxr-xr-xpackaging/mtp-responder.spec61
-rwxr-xr-xsrc/entity/mtp_device.c1107
-rwxr-xr-xsrc/entity/mtp_object.c755
-rwxr-xr-xsrc/entity/mtp_property.c4984
-rwxr-xr-xsrc/entity/mtp_store.c1233
-rwxr-xr-xsrc/mtp_cmd_handler.c3387
-rwxr-xr-xsrc/mtp_cmd_handler_util.c2418
-rwxr-xr-xsrc/mtp_event_handler.c447
-rwxr-xr-xsrc/mtp_init.c495
-rwxr-xr-xsrc/mtp_inoti_handler.c709
-rwxr-xr-xsrc/ptp_container.c425
-rwxr-xr-xsrc/transport/mtp_transport.c534
-rwxr-xr-xsrc/transport/mtp_usb_driver.c472
-rwxr-xr-xsrc/util/mtp_fs.c949
-rwxr-xr-xsrc/util/mtp_list.c153
-rwxr-xr-xsrc/util/mtp_media_info.c833
-rwxr-xr-xsrc/util/mtp_msgq.c124
-rwxr-xr-xsrc/util/mtp_support.c648
-rwxr-xr-xsrc/util/mtp_thread.c93
-rwxr-xr-xsrc/util/mtp_util.c293
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;
+}