Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e0593ea authored by that's avatar that Committed by Dees Troy
Browse files

mtp: cleanup, fixes and performance improvements

- use std::map instead of linked list
- read directories on demand
- fix writing zip files to storage root
- fix creating directories
- lots of minor fixes
- simplify generation of storage IDs and make them spec compliant

Change-Id: I2137c27549ddbdc58466f2e3aeda464fac70a3c5
parent 66766fe4
Loading
Loading
Loading
Loading
+508 −644

File changed.

Preview size limit exceeded, changes collapsed.

+29 −14
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include "MtpServer.h"

class MtpDatabase;
struct inotify_event;

class MtpStorage {

@@ -43,16 +44,10 @@ private:
    uint64_t                mReserveSpace;
    bool                    mRemovable;
	MtpServer*				mServer;
	std::deque<std::string> mtpParentList;
	int mtpparentid;
    Tree *mtpdbtree;
    typedef std::map<int, Tree*> maptree;
    typedef maptree::iterator iter;
    maptree mtpmap;
	std::string mtpstorageparent;
	pthread_t inotify_thread;
	int inotify_fd;
	int inotify_wd;
	android::Mutex           mMutex;

public:
@@ -71,30 +66,50 @@ public:
    inline const char*      getPath() const { return (const char *)mFilePath; }
    inline bool             isRemovable() const { return mRemovable; }
    inline uint64_t         getMaxFileSize() const { return mMaxFileSize; }
	int readParentDirs(std::string path);

	struct PropEntry {
		MtpObjectHandle handle;
		uint16_t property;
		uint16_t datatype;
		uint64_t intvalue;
		std::string strvalue;
	};

	int readDir(const std::string& path, Tree* tree);
	int createDB();
	MtpObjectHandleList* getObjectList(MtpStorageID storageID, MtpObjectHandle parent);
	int getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info);
	MtpObjectHandle beginSendObject(const char* path, MtpObjectFormat format, MtpObjectHandle parent, MtpStorageID storage, uint64_t size, time_t modified);
	MtpObjectHandle beginSendObject(const char* path, MtpObjectFormat format, MtpObjectHandle parent, uint64_t size, time_t modified);
	void endSendObject(const char* path, MtpObjectHandle handle, MtpObjectFormat format, bool succeeded);
	int getObjectPropertyList(MtpObjectHandle handle, uint32_t format, uint32_t property, int groupCode, int depth, MtpDataPacket& packet);
	int getObjectFilePath(MtpObjectHandle handle, MtpString& outFilePath, int64_t& outFileLength, MtpObjectFormat& outFormat);
	int deleteFile(MtpObjectHandle handle);
	int renameObject(MtpObjectHandle handle, std::string newName);
	int getObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property, uint64_t &longValue);
	int getObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property, PropEntry& prop);
	void lockMutex(int thread_type);
	void unlockMutex(int thread_type);

private:
	void createEmptyDir(const char* path);
	pthread_t inotify();
	int inotify_t();
	typedef int (MtpStorage::*ThreadPtr)(void);
	typedef void* (*PThreadPtr)(void *);
	std::map<int, std::string> inotifymap;
	int addInotifyDirs(std::string path);
	void deleteTrees(int parent);
	std::map<int, Tree*> inotifymap;	// inotify wd -> tree
	pthread_t inotify_thread;
	int inotify_fd;
	int addInotify(Tree* tree);
	void handleInotifyEvent(struct inotify_event* event);

	bool sendEvents;
	int getParentObject(std::string parent_path);
	MtpObjectHandle handleCurrentlySending;

	Node* addNewNode(bool isDir, Tree* tree, const std::string& name);
	Node* findNode(MtpObjectHandle handle);
	Node* findNodeByPath(const std::string& path);
	std::string getNodePath(Node* node);

	void queryNodeProperties(std::vector<PropEntry>& results, Node* node, uint32_t property, int groupCode, MtpStorageID storageID);

	bool use_mutex;
	pthread_mutex_t inMutex; // inotify mutex
	pthread_mutex_t mtpMutex; // main mtp mutex
+30 −259
Original line number Diff line number Diff line
@@ -20,289 +20,60 @@
#include "MtpDebug.h"

// Constructor
Tree::Tree() {
	root = NULL;
	count = 0;
Tree::Tree(MtpObjectHandle handle, MtpObjectHandle parent, const std::string& name)
	: Node(handle, parent, name), alreadyRead(false) {
}

// Destructor
Tree::~Tree() {
	freeNode(root);
}

// Free the node
void Tree::freeNode(Node* leaf)
{
	if ( leaf != NULL )
	{
		freeNode(leaf->Left());
		freeNode(leaf->Right());
		delete leaf;
	}
	for (std::map<MtpObjectHandle, Node*>::iterator it = entries.begin(); it != entries.end(); ++it)
		delete it->second;
}

int Tree::getCount(void) {
	int count = entries.size();
	MTPD("node count: %d\n", count);
	return count;
}

Node* Tree::addNode(int mtpid, std::string path)
{
	MTPD("root: %d\n", root);
	// No elements. Add the root
	if ( root == NULL ) {
		Node* n = new Node();
		count++;
		MTPD("node count: %d\n", count);
		MTPD("adding node address: %d\n", n);
		MTPD("adding mtpid: %d\n", mtpid);
		n->setMtpid(mtpid);
		n->setPath(path);
		root = n;
		MTPD("set root to %d\n", root);
		return n;
	}
	else {
		count++;
		MTPD("node count: %d\n", count);
		MTPD("adding new child node\n");
		return addNode(mtpid, root, path);
	}
}

// Add a node (private)
Node* Tree::addNode(int mtpid, Node* leaf, std::string path) {
	Node* n;
	if ( mtpid <= leaf->Mtpid() )
	{
		if ( leaf->Left() != NULL )
			return addNode(mtpid, leaf->Left(), path);
		else {
			n = new Node();
			MTPD("adding mtpid: %d node: %d\n", mtpid, n);
			n->setMtpid(mtpid);
			n->setPath(path);
			n->setParent(leaf);
			leaf->setLeft(n);
		}
	}
	else
	{
		if ( leaf->Right() != NULL )
			return addNode(mtpid, leaf->Right(), path);
		else {
			n = new Node();
			MTPD("adding mtpid: %d node: %d\n", mtpid, n);
			n->setMtpid(mtpid);
			n->setPath(path);
			n->setParent(leaf);
			leaf->setRight(n);
		}
	}
	return n;
}

void Tree::setMtpParentId(int mtpparentid, Node* node) {
	node->setMtpParentId(mtpparentid);
}

std::string Tree::getPath(Node* node) {
	return node->getPath();
}

int Tree::getMtpParentId(Node* node) {
	return node->getMtpParentId();
}

Node* Tree::findNodePath(std::string path, Node* node) {
	Node* n;
	if ( node == NULL ) {
		return NULL;
	}
	if ( node->getPath().compare(path) == 0 && node->Mtpid() > 0) {
		return node;
	}
	else {
		n = findNodePath(path, node->Left());
		if (n)
			return n;
		n = findNodePath(path, node->Right());
		if (n)
			return n;
	}
	return NULL;
}

Node* Tree::getNext(Node *node) {
	if (node == NULL)
		return NULL;
	else {
		if (node->Left() != NULL)
			return node->Left();
		if (node->Right() != NULL)
			return node->Right();
	}
	return NULL;
}

Node* Tree::findNode(int key, Node* node) {
	//MTPD("key: %d\n", key);
	//MTPD("node: %d\n", node);
	if ( node == NULL ) {
		return NULL;
	}
	else if ( node->Mtpid() == key ) {
		return node;
	}
	else if ( key <= node->Mtpid() ) {
		return findNode(key, node->Left());
	}
	else if ( key > node->Mtpid() ) {
		return findNode(key, node->Right());
	}
	else {
		return NULL;
	}
	return NULL;
}

void Tree::getmtpids(Node* node, std::vector<int>* mtpids)
{
	if ( node )
	{
		MTPD("node: %d\n", node->Mtpid());
		mtpids->push_back(node->Mtpid());
		if (node->Left())
			getmtpids(node->Left(), mtpids);
		if (node->Right())
			getmtpids(node->Right(), mtpids);
	} else {
		mtpids->push_back(0);
void Tree::addEntry(Node* node) {
	if (node->Mtpid() == 0) {
		MTPE("Tree::addEntry: not adding node with 0 handle.\n");
		return;
	}
	if (node->Mtpid() == node->getMtpParentId()) {
		MTPE("Tree::addEntry: not adding node with handle %u == parent.\n", node->Mtpid());
		return;
	}

// Find the node with min key
// Traverse the left sub-tree recursively
// till left sub-tree is empty to get min
Node* Tree::min(Node* node)
{
	if ( node == NULL )
		return NULL;

	if ( node->Left() )
		min(node->Left());
	else
		return node;
	return NULL;
	entries[node->Mtpid()] = node;
}

// Find the node with max key
// Traverse the right sub-tree recursively
// till right sub-tree is empty to get max
Node* Tree::max(Node* node)
Node* Tree::findEntryByName(std::string name) {
	for (std::map<MtpObjectHandle, Node*>::iterator it = entries.begin(); it != entries.end(); ++it)
	{
	if ( node == NULL )
		return NULL;

	if ( node->Right() )
		max(node->Right());
	else
		Node* node = it->second;
		if (node->getName().compare(name) == 0 && node->Mtpid() > 0)
			return node;
	return NULL;
	}

// Find successor to a node
// Find the node, get the node with max value
// for the right sub-tree to get the successor
Node* Tree::successor(int key, Node *node)
{
	Node* thisKey = findNode(key, node);
	if ( thisKey )
		return max(thisKey->Right());
	return NULL;
}

// Find predecessor to a node
// Find the node, get the node with max value
// for the left sub-tree to get the predecessor
Node* Tree::predecessor(int key, Node *node)
{
	Node* thisKey = findNode(key, node);
	if ( thisKey )
		return max(thisKey->Left());
Node* Tree::findNode(MtpObjectHandle handle) {
	std::map<MtpObjectHandle, Node*>::iterator it = entries.find(handle);	
	if (it != entries.end())
		return it->second;
	return NULL;
}

void Tree::deleteNode(int key)
{
	// Find the node.
	Node* thisKey = findNode(key, root);
	MTPD("Tree::deleteNode found node: %d\n", thisKey);
	MTPD("handle: %d\n", thisKey->Mtpid());

	if (thisKey == root) {
		if (thisKey->Right()) {
			root = thisKey->Right();
			root->setParent(NULL);
			return;
		}
		if (thisKey->Left()) {
			root = thisKey->Left();
			root->setParent(NULL);
			return;
		}
		root = NULL;
		delete thisKey;
		return;
	}

	if ( thisKey->Left() == NULL && thisKey->Right() == NULL )
	{
		if ( thisKey->Mtpid() > thisKey->Parent()->Mtpid() ) {
			thisKey->Parent()->setRight(NULL);
		}
		else {
			thisKey->Parent()->setLeft(NULL);
		}
		delete thisKey;
		return;
	}

	if ( thisKey->Left() == NULL && thisKey->Right() != NULL )
	{
		if ( thisKey->Mtpid() > thisKey->Parent()->Mtpid() )
			thisKey->Parent()->setRight(thisKey->Right());
		else
			thisKey->Parent()->setLeft(thisKey->Right());
		thisKey->Right()->setParent(thisKey->Parent());
		delete thisKey;
		return;
void Tree::getmtpids(MtpObjectHandleList* mtpids) {
	for (std::map<MtpObjectHandle, Node*>::iterator it = entries.begin(); it != entries.end(); ++it)
		mtpids->push_back(it->second->Mtpid());
}
	if ( thisKey->Left() != NULL && thisKey->Right() == NULL )
	{
		if ( thisKey->Mtpid() > thisKey->Parent()->Mtpid() )
			thisKey->Parent()->setRight(thisKey->Left());
		else
			thisKey->Parent()->setLeft(thisKey->Left());
		thisKey->Left()->setParent(thisKey->Parent());
		delete thisKey;
		return;
	}

	if ( thisKey->Left() != NULL && thisKey->Right() != NULL )
	{
		Node* sub = predecessor(thisKey->Mtpid(), thisKey);
		if ( sub == NULL )
			sub = successor(thisKey->Mtpid(), thisKey);

		if ( sub->Parent()->Mtpid() <= sub->Mtpid() )
			sub->Parent()->setRight(sub->Right());
		else
			sub->Parent()->setLeft(sub->Left());

		thisKey->setMtpid(sub->Mtpid());
		delete sub;
		return;
void Tree::deleteNode(MtpObjectHandle handle) {
	std::map<MtpObjectHandle, Node*>::iterator it = entries.find(handle);	
	if (it != entries.end()) {
		delete it->second;
		entries.erase(it);
	}
}
+40 −54
Original line number Diff line number Diff line
@@ -17,79 +17,65 @@
#ifndef BTREE_HPP
#define BTREE_HPP

#include <iostream>
#include <vector>
#include <utils/threads.h>
#include "MtpDebug.h"
#include <map>
#include "MtpTypes.h"

// A generic tree node class
// A directory entry
class Node {
	int mtpid;
	int mtpparentid;
	std::string path;
	int parentID;
	Node* left;
	Node* right;
	Node* parent;
	MtpObjectHandle handle;
	MtpObjectHandle parent;
	std::string name;	// name only without path

public:
	Node();
	void setMtpid(int aMtpid);
	void setPath(std::string aPath);
	void rename(std::string aPath);
	void setLeft(Node* aLeft);
	void setRight(Node* aRight);
	void setParent(Node* aParent);
	void setMtpParentId(int id);
	int Mtpid();
	int getMtpParentId();
	std::string getPath();
	Node* Left();
	Node* Right();
	Node* Parent();
	void addProperty(uint64_t property, uint64_t valueInt, std::string valueStr, int dataType);
	void updateProperty(uint64_t property, uint64_t valueInt, std::string valueStr, int dataType);
	void addProperties(int storageID, int parent_object);
	uint64_t getIntProperty(uint64_t property);
	Node(MtpObjectHandle handle, MtpObjectHandle parent, const std::string& name);
	virtual ~Node() {}

	virtual bool isDir() const { return false; }

	void rename(const std::string& newName);
	MtpObjectHandle Mtpid() const;
	MtpObjectHandle getMtpParentId() const;
	const std::string& getName() const;

	void addProperty(MtpPropertyCode property, uint64_t valueInt, std::string valueStr, MtpDataType dataType);
	void updateProperty(MtpPropertyCode property, uint64_t valueInt, std::string valueStr, MtpDataType dataType);
	void addProperties(const std::string& path, int storageID);
	uint64_t getIntProperty(MtpPropertyCode property);
	struct mtpProperty {
		uint64_t property;
		MtpPropertyCode property;
		MtpDataType dataType;
		uint64_t valueInt;
		std::string valueStr;
		int dataType;
		mtpProperty() : property(0), dataType(0), valueInt(0) {}
	};
	std::vector<mtpProperty>& getMtpProps();
	std::vector<mtpProperty> mtpProp;
	const mtpProperty& getProperty(MtpPropertyCode property);
};

// Binary Search Tree class
class Tree {
	Node* root;
// A directory
class Tree : public Node {
	std::map<MtpObjectHandle, Node*> entries;
	bool alreadyRead;
public:
	Tree();
	Tree(MtpObjectHandle handle, MtpObjectHandle parent, const std::string& name);
	~Tree();
	Node* Root() {
		MTPD("root: %d\n", root);
		return root; 
	};
	Node* addNode(int mtpid, std::string path);
	void setMtpParentId(int mtpparentid, Node* node);
	Node* findNode(int key, Node* parent);
	void getmtpids(Node* node, std::vector<int>* mtpids);
	void deleteNode(int key);
	Node* min(Node* node);
	Node* max(Node* node);
	Node* successor(int key, Node* parent);
	Node* predecessor(int key, Node* parent);

	virtual bool isDir() const { return true; }

	void addEntry(Node* node);
	Node* findNode(MtpObjectHandle handle);
	void getmtpids(MtpObjectHandleList* mtpids);
	void deleteNode(MtpObjectHandle handle);
	std::string getPath(Node* node);
	int getMtpParentId() { return Node::getMtpParentId(); }
	int getMtpParentId(Node* node);
	Node* findNodePath(std::string path, Node* node);
	Node* getNext(Node* node);
	Node* findEntryByName(std::string name);
	int getCount();

private:
	Node* addNode(int mtpid, Node* leaf, std::string path);
	void freeNode(Node* leaf);
	int count;
	bool wasAlreadyRead() const { return alreadyRead; }
	void setAlreadyRead(bool b) { alreadyRead = b; }
};

#endif
+39 −64
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@
#include "MtpUtils.h"
#include "mtp.h"
#include "mtp_MtpDatabase.hpp"
#include "btree.hpp"
//#include "btree.hpp"

MyMtpDatabase::MyMtpDatabase()
{
@@ -75,6 +75,7 @@ int MyMtpDatabase::FILE_PROPERTIES[10] = {
	MTP_PROPERTY_PARENT_OBJECT,
	MTP_PROPERTY_PERSISTENT_UID,
	MTP_PROPERTY_NAME,
	// TODO: why is DISPLAY_NAME not here?
	MTP_PROPERTY_DATE_ADDED
};

@@ -214,8 +215,9 @@ MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
											MtpStorageID storage,
											uint64_t size,
											time_t modified) {
	MTPD("MyMtpDatabase::beginSendObject() which passes to MtpStorage.cpp\n");
	return storagemap[storage]->beginSendObject(path, format, parent, storage, size, modified);
	if (storagemap.find(storage) == storagemap.end())
		return kInvalidObjectHandle;
	return storagemap[storage]->beginSendObject(path, format, parent, size, modified);
}

void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
@@ -225,6 +227,9 @@ void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
		MTPE("endSendObject() failed, unlinking %s\n", path);
		unlink(path);
	}
	std::map<int, MtpStorage*>::iterator storit;
	for (storit = storagemap.begin(); storit != storagemap.end(); storit++)
		storit->second->endSendObject(path, handle, format, succeeded);
}

void MyMtpDatabase::createDB(MtpStorage* storage, MtpStorageID storageID) {
@@ -236,8 +241,7 @@ MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
									MtpObjectFormat format,
									MtpObjectHandle parent) {
	MTPD("storageID: %d\n", storageID);
	MtpObjectHandleList* list = new MtpObjectHandleList();
	list = storagemap[storageID]->getObjectList(storageID, parent);
	MtpObjectHandleList* list = storagemap[storageID]->getObjectList(storageID, parent);
	MTPD("list: %d\n", list->size());
	return list;
}
@@ -245,22 +249,20 @@ MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
int MyMtpDatabase::getNumObjects(MtpStorageID storageID,
									MtpObjectFormat format,
									MtpObjectHandle parent) {
	MTPE("MyMtpDatabase::getNumObjects not implemented, returning 0\n");
	int result = 0;
	//get number of objects on filesystem storage
	return result;
	MtpObjectHandleList* list = storagemap[storageID]->getObjectList(storageID, parent);
	int size = list->size();
	delete list;
	return size;
}

MtpObjectFormatList* MyMtpDatabase::getSupportedPlaybackFormats() {
	// This function tells the host PC which file formats the device supports
	int* formats;
	MtpObjectFormatList* list = new MtpObjectFormatList();
	formats = SUPPORTED_PLAYBACK_FORMATS;
	int length = sizeof(formats)/ sizeof(int);
	int length = sizeof(SUPPORTED_PLAYBACK_FORMATS) / sizeof(SUPPORTED_PLAYBACK_FORMATS[0]);
	MTPD("MyMtpDatabase::getSupportedPlaybackFormats length: %i\n", length);
	for (int i = 0; i < length; i++) {
		MTPD("supported playback format: %d\n", formats[i]);
		list->push(formats[i]);
		MTPD("supported playback format: %x\n", SUPPORTED_PLAYBACK_FORMATS[i]);
		list->push(SUPPORTED_PLAYBACK_FORMATS[i]);
	}
	return list;
}
@@ -284,25 +286,29 @@ MtpObjectPropertyList* MyMtpDatabase::getSupportedObjectProperties(MtpObjectForm
		case MTP_FORMAT_AAC:
			properties = AUDIO_PROPERTIES;
			length = sizeof(AUDIO_PROPERTIES) / sizeof(AUDIO_PROPERTIES[0]);
			break;
		case MTP_FORMAT_MPEG:
		case MTP_FORMAT_3GP_CONTAINER:
		case MTP_FORMAT_WMV:
			properties = VIDEO_PROPERTIES;
			length = sizeof(VIDEO_PROPERTIES) / sizeof(VIDEO_PROPERTIES[0]);
			break;
		case MTP_FORMAT_EXIF_JPEG:
		case MTP_FORMAT_GIF:
		case MTP_FORMAT_PNG:
		case MTP_FORMAT_BMP:
			properties = IMAGE_PROPERTIES;
			length = sizeof(IMAGE_PROPERTIES) / sizeof(IMAGE_PROPERTIES[0]);
			break;
		case 0:
			properties = ALL_PROPERTIES;
			length = sizeof(ALL_PROPERTIES) / sizeof(ALL_PROPERTIES[0]);
			break;
		default:
			properties = FILE_PROPERTIES;
			length = sizeof(FILE_PROPERTIES) / sizeof(FILE_PROPERTIES[0]);
	}
	MTPD("MyMtpDatabase::getSupportedObjectProperties length is: %i, format: %x, sizeof: %i", length, format);
	MTPD("MyMtpDatabase::getSupportedObjectProperties length is: %i, format: %x", length, format);
	for (int i = 0; i < length; i++) {
		MTPD("supported object property: %x\n", properties[i]);
		list->push(properties[i]);
@@ -313,35 +319,37 @@ MtpObjectPropertyList* MyMtpDatabase::getSupportedObjectProperties(MtpObjectForm
MtpDevicePropertyList* MyMtpDatabase::getSupportedDeviceProperties() {
	MtpDevicePropertyList* list = new MtpDevicePropertyList();
	int length = sizeof(DEVICE_PROPERTIES) / sizeof(DEVICE_PROPERTIES[0]);
	MTPD("MyMtpDatabase::getSupportedDeviceProperties length was: %i\n");
	MTPD("MyMtpDatabase::getSupportedDeviceProperties length was: %i\n", length);
	for (int i = 0; i < length; i++)
		list->push(DEVICE_PROPERTIES[i]);
	return list;
}

MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
											MtpObjectProperty property,
											MtpDataPacket& packet) {
	MTPD("MyMtpDatabase::getObjectPropertyValue mtpid: %i, property: %x\n", handle, property);
	MTPD("MyMtpDatabase::getObjectPropertyValue mtpid: %u, property: %x\n", handle, property);
	int type;
	MtpResponseCode result = MTP_RESPONSE_INVALID_OBJECT_HANDLE;
	uint64_t longValue;
	MtpStorage::PropEntry prop;
	if (!getObjectPropertyInfo(property, type)) {
		MTPE("MyMtpDatabase::setObjectPropertyValue returning MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED\n");
		MTPE("MyMtpDatabase::getObjectPropertyValue returning MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED\n");
		return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
	}
	std::map<int, MtpStorage*>::iterator storit;
	for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
		if (storit->second->getObjectPropertyValue(handle, property, longValue) == 0) {
		if (storit->second->getObjectPropertyValue(handle, property, prop) == 0) {
			result = MTP_RESPONSE_OK;
			break;
		}
	}

	if (result != MTP_RESPONSE_OK) {
		MTPE("MyMtpDatabase::setObjectPropertyValue unable to locate handle: %i\n", handle);
		MTPE("MyMtpDatabase::getObjectPropertyValue unable to locate handle: %u\n", handle);
		return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
	}

	uint64_t longValue = prop.intvalue;
	// special case date properties, which are strings to MTP
	// but stored internally as a uint64
	if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) {
@@ -387,7 +395,7 @@ MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
			packet.putInt128(longValue);
			break;
		case MTP_TYPE_UINT128:
			packet.putInt128(longValue);
			packet.putUInt128(longValue);
			break;
		case MTP_TYPE_STR:
			{
@@ -401,8 +409,10 @@ MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
				} else {
					packet.putEmptyString();
				}*/
				MTPE("STRING unsupported type in getObjectPropertyValue\n");
				result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
				packet.putString(prop.strvalue.c_str());
				MTPD("MTP_TYPE_STR: %x = %s\n", prop.property, prop.strvalue.c_str());
				//MTPE("STRING unsupported type in getObjectPropertyValue\n");
				//result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
				break;
			}
		default:
@@ -764,26 +774,21 @@ MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
	switch (property) {
		case MTP_PROPERTY_OBJECT_FORMAT:
			// use format as default value
			MTPD("MyMtpDatabase::getObjectPropertyDesc format\n");
			result = new MtpProperty(property, MTP_TYPE_UINT16, false, format);
			break;
		case MTP_PROPERTY_PROTECTION_STATUS:
		case MTP_PROPERTY_TRACK:
			MTPD("MyMtpDatabase::getObjectPropertyDesc track\n");
			result = new MtpProperty(property, MTP_TYPE_UINT16);
			break;
		case MTP_PROPERTY_STORAGE_ID:
		case MTP_PROPERTY_PARENT_OBJECT:
		case MTP_PROPERTY_DURATION:
			MTPD("MyMtpDatabase::getObjectPropertyDesc duration\n");
			result = new MtpProperty(property, MTP_TYPE_UINT32);
			break;
		case MTP_PROPERTY_OBJECT_SIZE:
			MTPD("MyMtpDatabase::getObjectPropertyDesc size\n");
			result = new MtpProperty(property, MTP_TYPE_UINT64);
			break;
		case MTP_PROPERTY_PERSISTENT_UID:
			MTPD("MyMtpDatabase::getObjectPropertyDesc persistent uid\n");
			result = new MtpProperty(property, MTP_TYPE_UINT128);
			break;
		case MTP_PROPERTY_NAME:
@@ -794,18 +799,15 @@ MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
		case MTP_PROPERTY_GENRE:
		case MTP_PROPERTY_COMPOSER:
		case MTP_PROPERTY_DESCRIPTION:
			MTPD("MyMtpDatabase::getObjectPropertyDesc description\n");
			result = new MtpProperty(property, MTP_TYPE_STR);
			break;
		case MTP_PROPERTY_DATE_MODIFIED:
		case MTP_PROPERTY_DATE_ADDED:
		case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
			MTPD("MyMtpDatabase::getObjectPropertyDesc date\n");
			result = new MtpProperty(property, MTP_TYPE_STR);
			result->setFormDateTime();
			break;
		case MTP_PROPERTY_OBJECT_FILE_NAME:
			MTPD("MyMtpDatabase::getObjectPropertyDesc file name\n");
			// We allow renaming files and folders
			result = new MtpProperty(property, MTP_TYPE_STR, true);
			break;
@@ -816,26 +818,19 @@ MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
	MtpProperty* result = NULL;
	int ret;
	bool writable = true;
	bool writable = false;
	switch (property) {
		case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
		case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
			ret = MTP_RESPONSE_OK;
			writable = true;
			// fall through
		case MTP_DEVICE_PROPERTY_IMAGE_SIZE:
			result = new MtpProperty(property, MTP_TYPE_STR, writable);
			ret = MTP_RESPONSE_OK;

			// get current value
			if (ret == MTP_RESPONSE_OK) {
			// TODO: add actual values
			result->setCurrentValue('\0');
			result->setDefaultValue('\0');
			} else {
				MTPE("unable to read device property, response: %04X", ret);
			}
			break;
		default:
			ret = MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
			break;
		}

@@ -854,26 +849,6 @@ void MyMtpDatabase::sessionEnded() {

// ----------------------------------------------------------------------------

static void
android_mtp_MtpDatabase_setup()
{
	MyMtpDatabase* database = new MyMtpDatabase();
}

static void
android_mtp_MtpDatabase_finalize()
{
	return;
}

static std::string
android_mtp_MtpPropertyGroup_format_date_time(long seconds)
{
	char date[20];
	formatDateTime(seconds, date, sizeof(date));
	return date;
}

void MyMtpDatabase::lockMutex(void) {
	std::map<int, MtpStorage*>::iterator storit;
	for (storit = storagemap.begin(); storit != storagemap.end(); storit++) {
Loading