From 9e0593eaf6defb15761f41246093c0d3661b140d Mon Sep 17 00:00:00 2001 From: that Date: Wed, 8 Oct 2014 00:01:24 +0200 Subject: 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 --- mtp/MtpStorage.cpp | 1152 +++++++++++++++++++++++----------------------------- 1 file changed, 508 insertions(+), 644 deletions(-) (limited to 'mtp/MtpStorage.cpp') diff --git a/mtp/MtpStorage.cpp b/mtp/MtpStorage.cpp index 57c87745e..4c55361fa 100755 --- a/mtp/MtpStorage.cpp +++ b/mtp/MtpStorage.cpp @@ -21,6 +21,7 @@ #include "MtpDataPacket.h" #include "MtpServer.h" #include "MtpEventPacket.h" +#include "MtpDatabase.h" #include #include @@ -35,12 +36,9 @@ #include #include #include -#include #define WATCH_FLAGS ( IN_CREATE | IN_DELETE | IN_MOVE | IN_MODIFY ) -static int mtpid = 0; - MtpStorage::MtpStorage(MtpStorageID id, const char* filePath, const char* description, uint64_t reserveSpace, bool removable, uint64_t maxFileSize, MtpServer* refserver) @@ -54,9 +52,9 @@ MtpStorage::MtpStorage(MtpStorageID id, const char* filePath, mServer(refserver) { MTPI("MtpStorage id: %d path: %s\n", id, filePath); - mtpparentid = 0; inotify_thread = 0; sendEvents = false; + handleCurrentlySending = 0; use_mutex = true; if (pthread_mutex_init(&mtpMutex, NULL) != 0) { MTPE("Failed to init mtpMutex\n"); @@ -71,8 +69,9 @@ MtpStorage::MtpStorage(MtpStorageID id, const char* filePath, MtpStorage::~MtpStorage() { if (inotify_thread) { + // TODO: what does this do? manpage says it does not kill the thread pthread_kill(inotify_thread, 0); - for (std::map::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) { + for (std::map::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) { inotify_rm_watch(inotify_fd, i->first); } close(inotify_fd); @@ -124,12 +123,8 @@ const char* MtpStorage::getDescription() const { int MtpStorage::createDB() { std::string mtpParent = ""; mtpstorageparent = getPath(); - readParentDirs(getPath()); - while (!mtpParentList.empty()) { - mtpParent = mtpParentList.front(); - mtpParentList.pop_front(); - readParentDirs(mtpParent); - } + // root directory is special: handle 0, parent 0, and empty path + mtpmap[0] = new Tree(0, 0, ""); MTPD("MtpStorage::createDB DONE\n"); if (use_mutex) { MTPD("Starting inotify thread\n"); @@ -138,524 +133,399 @@ int MtpStorage::createDB() { } else { MTPD("NOT starting inotify thread\n"); } + // for debugging and caching purposes, read the root dir already now + readDir(mtpstorageparent, mtpmap[0]); + // all other dirs are read on demand return 0; } MtpObjectHandleList* MtpStorage::getObjectList(MtpStorageID storageID, MtpObjectHandle parent) { - std::vector mtpids; - int local_mtpparentid; - MTPD("MtpStorage::getObjectList\n"); - MTPD("parent: %d\n", parent); + MTPD("MtpStorage::getObjectList, parent: %u\n", parent); //append object id (numerical #s) of database to int array MtpObjectHandleList* list = new MtpObjectHandleList(); if (parent == MTP_PARENT_ROOT) { MTPD("parent == MTP_PARENT_ROOT\n"); - local_mtpparentid = 1; - } - else { - for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) { - MTPD("root: %d\n", i->second->Root()); - Node* node = i->second->findNode(parent, i->second->Root()); - if (node != NULL) { - local_mtpparentid = i->second->getMtpParentId(node); - MTPD("path: %s\n", i->second->getPath(node).c_str()); - MTPD("mtpparentid: %d going to endloop\n", local_mtpparentid); - goto endloop; - } - } + parent = 0; } - MTPD("got to endloop\n"); - endloop: - if (mtpmap[local_mtpparentid] == NULL) { - MTPD("mtpmap[mtpparentid] == NULL, returning\n"); + if (mtpmap.find(parent) == mtpmap.end()) { + MTPE("parent handle not found, returning empty list\n"); return list; } - MTPD("root: %d\n", mtpmap[local_mtpparentid]->Root()); - mtpmap[local_mtpparentid]->getmtpids(mtpmap[local_mtpparentid]->Root(), &mtpids); - MTPD("here, mtpids->size(): %i\n", mtpids.size()); - - for (unsigned index = 0; index < mtpids.size(); index++) { - MTPD("mtpidhere[%i]: %d\n", index, mtpids.at(index)); - list->push(mtpids.at(index)); + Tree* tree = mtpmap[parent]; + if (!tree->wasAlreadyRead()) + { + std::string path = getNodePath(tree); + MTPD("reading directory on demand for tree %p (%u), path: %s\n", tree, tree->Mtpid(), path.c_str()); + readDir(path, tree); } + + mtpmap[parent]->getmtpids(list); + MTPD("returning %u objects in %s.\n", list->size(), tree->getName().c_str()); return list; } int MtpStorage::getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info) { struct stat st; uint64_t size = 0; - MTPD("MtpStorage::getObjectInfo handle: %d\n", handle); - for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) { - Node* node = i->second->findNode(handle, i->second->Root()); - MTPD("node returned: %d\n", node); - if (node != NULL) { - MTPD("found mtpid: %d\n", node->Mtpid()); - info.mStorageID = getStorageID(); - MTPD("info.mStorageID: %d\n", info.mStorageID); - info.mParent = node->getMtpParentId(); - MTPD("mParent: %d\n", info.mParent); - if (lstat(node->getPath().c_str(), &st) == 0) - size = st.st_size; - MTPD("size is: %llu\n", size); - info.mCompressedSize = size;//(size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size); - info.mDateModified = st.st_mtime; - if (S_ISDIR(st.st_mode)) { - info.mFormat = MTP_FORMAT_ASSOCIATION; - } - else { - info.mFormat = MTP_FORMAT_UNDEFINED; - } - info.mName = strdup(basename(node->getPath().c_str())); - MTPD("MtpStorage::getObjectInfo found, Exiting getObjectInfo()\n"); - return 0; - } + MTPD("MtpStorage::getObjectInfo, handle: %u\n", handle); + Node* node = findNode(handle); + if (!node) { + // Item is not on this storage device + return -1; } - // Item is not on this storage device - return -1; + + info.mStorageID = getStorageID(); + MTPD("info.mStorageID: %u\n", info.mStorageID); + info.mParent = node->getMtpParentId(); + MTPD("mParent: %u\n", info.mParent); + // TODO: do we want to lstat again here, or read from the node properties? + if (lstat(getNodePath(node).c_str(), &st) == 0) + size = st.st_size; + MTPD("size is: %llu\n", size); + info.mCompressedSize = (size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size); + info.mDateModified = st.st_mtime; + if (S_ISDIR(st.st_mode)) { + info.mFormat = MTP_FORMAT_ASSOCIATION; + } + else { + info.mFormat = MTP_FORMAT_UNDEFINED; + } + info.mName = strdup(node->getName().c_str()); + MTPD("MtpStorage::getObjectInfo found, Exiting getObjectInfo()\n"); + return 0; } MtpObjectHandle MtpStorage::beginSendObject(const char* path, MtpObjectFormat format, MtpObjectHandle parent, - MtpStorageID storage, uint64_t size, time_t modified) { - MTPD("MtpStorage::beginSendObject(), path: '%s', parent: %d, storage: %d, format: %04x\n", path, parent, storage, format); - Node* node; - std::string parentdir; + MTPD("MtpStorage::beginSendObject(), path: '%s', parent: %u, format: %04x\n", path, parent, format); + iter it = mtpmap.find(parent); + if (it == mtpmap.end()) { + MTPE("parent node not found, returning error\n"); + return kInvalidObjectHandle; + } + Tree* tree = it->second; + std::string pathstr(path); - int parent_id; - parentdir = pathstr.substr(0, pathstr.find_last_of('/')); - MTPD("MtpStorage::beginSendObject() parentdir: %s\n", parentdir.c_str()); - if (parentdir.compare(mtpstorageparent) == 0) { - // root directory - MTPD("MtpStorage::beginSendObject() root dir\n"); - parent_id = 1; - ++mtpid; - node = mtpmap[parent_id]->addNode(mtpid, path); - MTPD("node: %d\n", node); - node->addProperties(storage, 0); - if (format == MTP_FORMAT_ASSOCIATION) { - createEmptyDir(path); - } - return mtpid; - } else { - for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) { - node = i->second->findNodePath(parentdir, i->second->Root()); - if (node != NULL) { - MTPD("mtpid: %d\n", mtpid); - MTPD("path: %s\n", i->second->getPath(node).c_str()); - parentdir = i->second->getPath(node); - parent = i->second->getMtpParentId(node); - if (parent == 0) { - MTPD("MtpStorage::beginSendObject parent is 0, error.\n"); - return -1; - } else { - ++mtpid; - node = mtpmap[parent]->addNode(mtpid, path); - node->addProperties(getStorageID(), getParentObject(parentdir)); - for (iter i2 = mtpmap.begin(); i2 != mtpmap.end(); i2++) { - node = i2->second->findNodePath(path, i2->second->Root()); - if (node != NULL) { - i2->second->setMtpParentId(parent, node); - } - } - if (format == MTP_FORMAT_ASSOCIATION) { - createEmptyDir(path); - } - } - return mtpid; - } - } + size_t slashpos = pathstr.find_last_of('/'); + if (slashpos == std::string::npos) { + MTPE("path has no slash, returning error\n"); + return kInvalidObjectHandle; } - MTPE("MtpStorage::beginSendObject(), path: '%s', parent: %d, storage: %d, format: %04x\n", path, parent, storage, format); - return -1; + std::string parentdir = pathstr.substr(0, slashpos); + std::string basename = pathstr.substr(slashpos + 1); + if (parent != 0 && parentdir != getNodePath(tree)) { + MTPE("beginSendObject into path '%s' but parent tree has path '%s', returning error\n", parentdir.c_str(), getNodePath(tree).c_str()); + return kInvalidObjectHandle; + } + + MTPD("MtpStorage::beginSendObject() parentdir: %s basename: %s\n", parentdir.c_str(), basename.c_str()); + // note: for directories, the mkdir call is done later in MtpServer, here we just reserve a handle + bool isDir = format == MTP_FORMAT_ASSOCIATION; + Node* node = addNewNode(isDir, tree, basename); + handleCurrentlySending = node->Mtpid(); // suppress inotify for this node while sending + + return node->Mtpid(); +} + +void MtpStorage::endSendObject(const char* path, MtpObjectHandle handle, MtpObjectFormat format, bool succeeded) +{ + Node* node = findNode(handle); + if (!node) + return; // just ignore if this is for another storage + + node->addProperties(path, mStorageID); + handleCurrentlySending = 0; + // TODO: are we supposed to send an event about an upload by the initiator? + if (sendEvents) + mServer->sendObjectAdded(node->Mtpid()); } int MtpStorage::getObjectFilePath(MtpObjectHandle handle, MtpString& outFilePath, int64_t& outFileLength, MtpObjectFormat& outFormat) { - struct stat st; - Node* node; - MTPD("MtpStorage::getObjectFilePath handle: %i\n", handle); - for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) { - MTPD("handle: %d\n", handle); - node = i->second->findNode(handle, i->second->Root()); - MTPD("node returned: %d\n", node); - if (node != NULL) { - if (lstat(node->getPath().c_str(), &st) == 0) - outFileLength = st.st_size; - else - outFileLength = 0; - outFilePath = strdup(node->getPath().c_str()); - MTPD("outFilePath: %s\n", node->getPath().c_str()); - goto end; - } + MTPD("MtpStorage::getObjectFilePath handle: %u\n", handle); + Node* node = findNode(handle); + if (!node) + { + // Item is not on this storage device + return -1; } - // Item is not on this storage - return -1; -end: - outFormat = MTP_FORMAT_ASSOCIATION; + // TODO: do we want to lstat here, or just read the info from the node? + struct stat st; + if (lstat(getNodePath(node).c_str(), &st) == 0) + outFileLength = st.st_size; + else + outFileLength = 0; + outFilePath = getNodePath(node).c_str(); + MTPD("outFilePath: %s\n", outFilePath.string()); + outFormat = node->isDir() ? MTP_FORMAT_ASSOCIATION : MTP_FORMAT_UNDEFINED; return 0; } -int MtpStorage::readParentDirs(std::string path) { +int MtpStorage::readDir(const std::string& path, Tree* tree) +{ struct dirent *de; - struct stat st; - DIR *d; - std::string parent, item, prevparent = ""; - Node* node; int storageID = getStorageID(); + MtpObjectHandle parent = tree->Mtpid(); - d = opendir(path.c_str()); - MTPD("opening '%s'\n", path.c_str()); + DIR *d = opendir(path.c_str()); + MTPD("reading dir '%s', parent handle %u\n", path.c_str(), parent); if (d == NULL) { - MTPD("error opening '%s' -- error: %s\n", path.c_str(), strerror(errno)); - closedir(d); + MTPE("error opening '%s' -- error: %s\n", path.c_str(), strerror(errno)); + return -1; } + // TODO: for refreshing dirs: capture old entries here while ((de = readdir(d)) != NULL) { // Because exfat-fuse causes issues with dirent, we will use stat // for some things that dirent should be able to do - item = path + "/" + de->d_name; + std::string item = path + "/" + de->d_name; + struct stat st; if (lstat(item.c_str(), &st)) { MTPE("Error running lstat on '%s'\n", item.c_str()); return -1; } - if ((st.st_mode & S_IFDIR) && strcmp(de->d_name, ".") == 0) + // TODO: if we want to use this for refreshing dirs too, first find existing name and overwrite + if (strcmp(de->d_name, ".") == 0) continue; - if ((st.st_mode & S_IFDIR) && strcmp(de->d_name, "..") != 0) { - // Handle dirs - MTPD("dir: %s\n", item.c_str()); - mtpParentList.push_back(item); - parent = item.substr(0, item.find_last_of('/')); - ++mtpid; - MTPD("parent: %s\n", parent.c_str()); - MTPD("mtpid: %d\n", mtpid); - if (prevparent != parent) { - mtpparentid++; - MTPD("Handle dirs, prevparent != parent, mtpparentid: %d\n", mtpparentid); - mtpmap[mtpparentid] = new Tree(); - MTPD("prevparent addNode\n"); - for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) { - node = i->second->findNodePath(parent, i->second->Root()); - if (node != NULL) { - i->second->setMtpParentId(mtpparentid, node); - } - } - node = mtpmap[mtpparentid]->addNode(mtpid, item); - node->addProperties(storageID, getParentObject(path)); - if (sendEvents) - mServer->sendObjectAdded(mtpid); - } - else { - MTPD("add node\n"); - mtpmap[mtpparentid]->addNode(mtpid, item); - for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) { - node = i->second->findNodePath(item, i->second->Root()); - if (node != NULL) { - i->second->setMtpParentId(mtpparentid, node); - node->addProperties(storageID, getParentObject(path)); - } - } - if (sendEvents) - mServer->sendObjectAdded(mtpid); - } - prevparent = parent; - } - else { - if (strcmp(de->d_name, "..") != 0) { - // Handle files - item = path + "/" + de->d_name; - MTPD("file: %s\n", item.c_str()); - parent = item.substr(0, item.find_last_of('/')); - MTPD("parent: %s\n", parent.c_str()); - ++mtpid; - MTPD("mtpid: %d\n", mtpid); - if (prevparent != parent) { - mtpparentid++; - MTPD("mtpparentid1: %d\n", mtpparentid); - for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) { - node = i->second->findNodePath(path, i->second->Root()); - if (node != NULL) { - i->second->setMtpParentId(mtpparentid, node); - node->addProperties(storageID, getParentObject(path)); - } - } - } - if (mtpmap[mtpparentid] == NULL) { - mtpmap[mtpparentid] = new Tree(); - } - MTPD("blank addNode\n"); - node = mtpmap[mtpparentid]->addNode(mtpid, item); - node->addProperties(storageID, getParentObject(path)); - prevparent = parent; - if (sendEvents) - mServer->sendObjectAdded(mtpid); - } - else { - // Handle empty dirs? - MTPD("checking for empty dir '%s'\n", path.c_str()); - int count = 0; - DIR *dirc; - struct dirent *ep; - dirc = opendir(path.c_str()); - if (dirc != NULL) { - while ((ep = readdir(dirc))) - ++count; - MTPD("count: %d\n", count); - closedir(dirc); - } - if (count == 2) { - MTPD("'%s' is an empty dir\n", path.c_str()); - createEmptyDir(path.c_str()); - goto end; - } - } - } - } - end: - closedir(d); - return 0; -} - -void MtpStorage::deleteTrees(int parent) { - Node* node = mtpmap[parent]->Root(); - MTPD("MtpStorage::deleteTrees deleting %i\n", parent); - while (node != NULL) { - if (node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT) == MTP_FORMAT_ASSOCIATION) { - deleteTrees(node->getMtpParentId()); - } - node = mtpmap[parent]->getNext(node); + if (strcmp(de->d_name, "..") == 0) + continue; + Node* node = addNewNode(st.st_mode & S_IFDIR, tree, de->d_name); + node->addProperties(item, storageID); + //if (sendEvents) + // mServer->sendObjectAdded(node->Mtpid()); + // sending events here makes simple-mtpfs very slow, and it is probably the wrong thing to do anyway } - delete mtpmap[parent]; - mtpmap.erase(parent); - MTPD("MtpStorage::deleteTrees deleted %i\n", parent); + closedir(d); + // TODO: for refreshing dirs: remove entries that no longer exist (with their nodes) + tree->setAlreadyRead(true); + addInotify(tree); + return 0; } int MtpStorage::deleteFile(MtpObjectHandle handle) { - int local_parent_id = 0; - for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) { - MTPD("MtpStorage::deleteFile handle: %d\n", handle); - Node* node = i->second->findNode(handle, i->second->Root()); - MTPD("MtpStorage::deleteFile node returned: %d\n", node); - if (node != NULL) { - if (node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT) == MTP_FORMAT_ASSOCIATION) { - local_parent_id = node->getMtpParentId(); - } - MTPD("deleting handle: %d\n", handle); - i->second->deleteNode(handle); - MTPD("deleted\n"); - goto end; - } + MTPD("MtpStorage::deleteFile handle: %u\n", handle); + Node* node = findNode(handle); + if (!node) { + // Item is not on this storage device + return -1; } - return -1; -end: - if (local_parent_id) { - deleteTrees(local_parent_id); + MtpObjectHandle parent = node->getMtpParentId(); + Tree* tree = mtpmap[parent]; + if (!tree) { + MTPE("parent tree for handle %u not found\n", parent); + return -1; + } + if (node->isDir()) { + MTPD("deleting tree from mtpmap: %u\n", handle); + mtpmap.erase(handle); } + + MTPD("deleting handle: %u\n", handle); + tree->deleteNode(handle); + MTPD("deleted\n"); return 0; } -int MtpStorage::getObjectPropertyList(MtpObjectHandle handle, uint32_t format, uint32_t property, int groupCode, int depth, MtpDataPacket& packet) { - Node *n; - int local_mtpid = 0; - int local_mtpparentid = 0; - std::vector propertyCodes; - std::vector dataTypes; - std::vector valueStrs; - std::vector longValues; - int count = 0; - MTPD("MtpStorage::getObjectPropertyList handle: %d, format: %d, property: %lx\n", handle, format, property); - if (property == MTP_PROPERTY_OBJECT_FORMAT) { - MTPD("MtpStorage::getObjectPropertyList MTP_PROPERTY_OBJECT_FORMAT\n"); - for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) { - MTPD("root: %d\n", i->second->Root()); - Node *node = i->second->findNode(handle, i->second->Root()); - MTPD("index: %d\n", index); - MTPD("node: %d\n", node); - if (node != NULL) { - uint64_t longval = node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT); - local_mtpparentid = i->second->getMtpParentId(node); - MTPD("object format longValue: %llu\n", longval); - propertyCodes.push_back(MTP_PROPERTY_OBJECT_FORMAT); - longValues.push_back(node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT)); - valueStrs.push_back(""); - dataTypes.push_back(4); - count = 1; - local_mtpid = node->Mtpid(); - goto endloop; - } +void MtpStorage::queryNodeProperties(std::vector& results, Node* node, uint32_t property, int groupCode, MtpStorageID storageID) +{ + MTPD("queryNodeProperties handle %u, path: %s\n", node->Mtpid(), getNodePath(node).c_str()); + PropEntry pe; + pe.handle = node->Mtpid(); + pe.property = property; + + if (property == 0xffffffff) + { + // add all properties + MTPD("MtpStorage::queryNodeProperties for all properties\n"); + std::vector mtpprop = node->getMtpProps(); + for (size_t i = 0; i < mtpprop.size(); ++i) { + pe.property = mtpprop[i].property; + pe.datatype = mtpprop[i].dataType; + pe.intvalue = mtpprop[i].valueInt; + pe.strvalue = mtpprop[i].valueStr; + results.push_back(pe); } - } - else if (property == MTP_PROPERTY_STORAGE_ID) { - MTPD("MtpStorage::getObjectPropertyList MTP_PROPERTY_STORAGE_ID\n"); - for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) { - MTPD("root: %d\n", i->second->Root()); - Node *node = i->second->findNode(handle, i->second->Root()); - if (node != NULL) { - propertyCodes.push_back(MTP_PROPERTY_STORAGE_ID); - longValues.push_back(getStorageID()); - valueStrs.push_back(""); - dataTypes.push_back(4); - count = 1; - local_mtpid = node->Mtpid(); - goto endloop; - } + return; + } + else if (property == 0) + { + // TODO: use groupCode + } + + // single property + // TODO: this should probably be moved to the Node class and/or merged with getObjectPropertyValue + switch (property) { +// case MTP_PROPERTY_OBJECT_FORMAT: +// pe.datatype = MTP_TYPE_UINT16; +// pe.intvalue = node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT); +// break; + + case MTP_PROPERTY_STORAGE_ID: + pe.datatype = MTP_TYPE_UINT32; + pe.intvalue = storageID; + break; + + case MTP_PROPERTY_PROTECTION_STATUS: + pe.datatype = MTP_TYPE_UINT16; + pe.intvalue = 0; + break; + + case MTP_PROPERTY_OBJECT_SIZE: + { + pe.datatype = MTP_TYPE_UINT64; + struct stat st; + pe.intvalue = 0; + if (lstat(getNodePath(node).c_str(), &st) == 0) + pe.intvalue = st.st_size; + break; } - } - else if (property == MTP_PARENT_ROOT) { - MTPD("MtpStorage::getObjectPropertyList MTP_PARENT_ROOT\n"); - for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) { - MTPD("root: %d\n", i->second->Root()); - Node* node = i->second->findNode(handle, i->second->Root()); - if (node != NULL) { - local_mtpparentid = i->second->getMtpParentId(node); - MTPD("path: %s\n", i->second->getPath(node).c_str()); - MTPD("mtpparentid: %d going to endloop\n", local_mtpparentid); - std::vector mtpprop = node->getMtpProps(); - count = mtpprop.size(); - for (int i = 0; i < count; ++i) { - propertyCodes.push_back(mtpprop[i].property); - longValues.push_back(mtpprop[i].valueInt); - valueStrs.push_back(mtpprop[i].valueStr); - dataTypes.push_back(mtpprop[i].dataType); - } - local_mtpid = node->Mtpid(); - goto endloop; + + default: + { + const Node::mtpProperty& prop = node->getProperty(property); + if (prop.property != property) + { + MTPD("queryNodeProperties: unknown property %x\n", property); + return; } + pe.datatype = prop.dataType; + pe.intvalue = prop.valueInt; + pe.strvalue = prop.valueStr; + // TODO: all the special case stuff in MyMtpDatabase::getObjectPropertyValue is missing here } + } - else if (property == MTP_PROPERTY_PROTECTION_STATUS) { - MTPD("MtpStorage::getObjectPropertyList MTP_PROPERTY_PROTECTION_STATUS\n"); - for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) { - MTPD("root: %d\n", i->second->Root()); - Node *node = i->second->findNode(handle, i->second->Root()); - if (node != NULL) { - propertyCodes.push_back(MTP_PROPERTY_PROTECTION_STATUS); - longValues.push_back(0); - valueStrs.push_back(""); - dataTypes.push_back(8); - count = 1; - local_mtpid = node->Mtpid(); - goto endloop; + results.push_back(pe); +} + +int MtpStorage::getObjectPropertyList(MtpObjectHandle handle, uint32_t format, uint32_t property, int groupCode, int depth, MtpDataPacket& packet) { + MTPD("MtpStorage::getObjectPropertyList handle: %u, format: %x, property: %x\n", handle, format, property); + if (groupCode != 0) + { + MTPE("getObjectPropertyList: groupCode unsupported\n"); + return -1; // TODO: RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED + } + // TODO: support all the special stuff, like: + // handle == 0 -> all objects at the root level + // handle == 0xffffffff -> all objects (on all storages? how could we support that?) + // format == 0 -> all formats, otherwise filter by ObjectFormatCode + // property == 0xffffffff -> all properties except those with group code 0xffffffff + // if property == 0 then use groupCode + // groupCode == 0 -> return Specification_By_Group_Unsupported + // depth == 0xffffffff -> all objects incl. and below handle + + std::vector results; + + if (handle == 0xffffffff) { + // TODO: all object on all storages (needs a different design, result packet needs to be built by server instead of storage) + } else if (handle == 0) { + // all objects at the root level + Tree* root = mtpmap[0]; + MtpObjectHandleList list; + root->getmtpids(&list); + for (MtpObjectHandleList::iterator it = list.begin(); it != list.end(); ++it) { + Node* node = root->findNode(*it); + if (!node) { + MTPE("BUG: node not found for root entry with handle %u\n", *it); + break; } + queryNodeProperties(results, node, property, groupCode, mStorageID); } - } - else if (property == MTP_PROPERTY_OBJECT_SIZE) { - MTPD("MtpStorage::getObjectPropertyList MTP_PROPERTY_OBJECT_SIZE\n"); - for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) { - MTPD("root: %d\n", i->second->Root()); - Node *node = i->second->findNode(handle, i->second->Root()); - if (node != NULL) { - struct stat st; - uint64_t size = 0; - if (lstat(node->getPath().c_str(), &st) == 0) - size = st.st_size; - propertyCodes.push_back(MTP_PROPERTY_OBJECT_SIZE); - longValues.push_back(size); - valueStrs.push_back(""); - dataTypes.push_back(8); - count = 1; - local_mtpid = node->Mtpid(); - goto endloop; - } + } else { + // single object + Node* node = findNode(handle); + if (!node) { + // Item is not on this storage device + return -1; } - } - else { - // Either the property is not supported or the handle is not on this storage - return -1; - } - // handle not found on this storage - return -1; - -endloop: - MTPD("mtpparentid: %d\n", local_mtpparentid); - MTPD("count: %d\n", count); - packet.putUInt32(count); - - if (count > 0) { - std::string stringValuesArray; - for (int i = 0; i < count; ++i) { - packet.putUInt32(local_mtpid); - packet.putUInt16(propertyCodes[i]); - MTPD("dataTypes: %d\n", dataTypes[i]); - packet.putUInt16(dataTypes[i]); - MTPD("propertyCode: %s\n", MtpDebug::getObjectPropCodeName(propertyCodes[i])); - MTPD("longValues: %d\n", longValues[i]); - switch (dataTypes[i]) { - case MTP_TYPE_INT8: - MTPD("MTP_TYPE_INT8\n"); - packet.putInt8(longValues[i]); - break; - case MTP_TYPE_UINT8: - MTPD("MTP_TYPE_UINT8\n"); - packet.putUInt8(longValues[i]); - break; - case MTP_TYPE_INT16: - MTPD("MTP_TYPE_INT16\n"); - packet.putInt16(longValues[i]); - break; - case MTP_TYPE_UINT16: - MTPD("MTP_TYPE_UINT16\n"); - packet.putUInt16(longValues[i]); - break; - case MTP_TYPE_INT32: - MTPD("MTP_TYPE_INT32\n"); - packet.putInt32(longValues[i]); - break; - case MTP_TYPE_UINT32: - MTPD("MTP_TYPE_UINT32\n"); - packet.putUInt32(longValues[i]); - break; - case MTP_TYPE_INT64: - MTPD("MTP_TYPE_INT64\n"); - packet.putInt64(longValues[i]); - break; - case MTP_TYPE_UINT64: - MTPD("MTP_TYPE_UINT64\n"); - packet.putUInt64(longValues[i]); - break; - case MTP_TYPE_INT128: - MTPD("MTP_TYPE_INT128\n"); - packet.putInt128(longValues[i]); - break; - case MTP_TYPE_UINT128: - MTPD("MTP_TYPE_UINT128\n"); - packet.putUInt128(longValues[i]); - break; - case MTP_TYPE_STR: - MTPD("MTP_TYPE_STR: %s\n", valueStrs[i].c_str()); - packet.putString((const char*) valueStrs[i].c_str()); - break; - default: - MTPE("bad or unsupported data type: %i in MyMtpDatabase::getObjectPropertyList", dataTypes[i]); - break; - } + queryNodeProperties(results, node, property, groupCode, mStorageID); + } + + MTPD("count: %u\n", results.size()); + packet.putUInt32(results.size()); + + for (size_t i = 0; i < results.size(); ++i) { + PropEntry& p = results[i]; + MTPD("handle: %u, propertyCode: %x = %s, datatype: %x, value: %llu\n", + p.handle, p.property, MtpDebug::getObjectPropCodeName(p.property), + p.datatype, p.intvalue); + packet.putUInt32(p.handle); + packet.putUInt16(p.property); + packet.putUInt16(p.datatype); + switch (p.datatype) { + case MTP_TYPE_INT8: + MTPD("MTP_TYPE_INT8\n"); + packet.putInt8(p.intvalue); + break; + case MTP_TYPE_UINT8: + MTPD("MTP_TYPE_UINT8\n"); + packet.putUInt8(p.intvalue); + break; + case MTP_TYPE_INT16: + MTPD("MTP_TYPE_INT16\n"); + packet.putInt16(p.intvalue); + break; + case MTP_TYPE_UINT16: + MTPD("MTP_TYPE_UINT16\n"); + packet.putUInt16(p.intvalue); + break; + case MTP_TYPE_INT32: + MTPD("MTP_TYPE_INT32\n"); + packet.putInt32(p.intvalue); + break; + case MTP_TYPE_UINT32: + MTPD("MTP_TYPE_UINT32\n"); + packet.putUInt32(p.intvalue); + break; + case MTP_TYPE_INT64: + MTPD("MTP_TYPE_INT64\n"); + packet.putInt64(p.intvalue); + break; + case MTP_TYPE_UINT64: + MTPD("MTP_TYPE_UINT64\n"); + packet.putUInt64(p.intvalue); + break; + case MTP_TYPE_INT128: + MTPD("MTP_TYPE_INT128\n"); + packet.putInt128(p.intvalue); + break; + case MTP_TYPE_UINT128: + MTPD("MTP_TYPE_UINT128\n"); + packet.putUInt128(p.intvalue); + break; + case MTP_TYPE_STR: + MTPD("MTP_TYPE_STR: %s\n", p.strvalue.c_str()); + packet.putString(p.strvalue.c_str()); + break; + default: + MTPE("bad or unsupported data type: %x in MyMtpDatabase::getObjectPropertyList", p.datatype); + break; } } return 0; } int MtpStorage::renameObject(MtpObjectHandle handle, std::string newName) { - int index; - MTPD("MtpStorage::renameObject, handle: %d, new name: '%s'\n", handle, newName.c_str()); + MTPD("MtpStorage::renameObject, handle: %u, new name: '%s'\n", handle, newName.c_str()); if (handle == MTP_PARENT_ROOT) { MTPE("parent == MTP_PARENT_ROOT, cannot rename root\n"); return -1; } else { for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) { - MTPD("root: %d\n", i->second->Root()); - Node* node = i->second->findNode(handle, i->second->Root()); + Node* node = i->second->findNode(handle); if (node != NULL) { - std::string oldName = i->second->getPath(node); + std::string oldName = getNodePath(node); std::string parentdir = oldName.substr(0, oldName.find_last_of('/')); std::string newFullName = parentdir + "/" + newName; MTPD("old: '%s', new: '%s'\n", oldName.c_str(), newFullName.c_str()); if (rename(oldName.c_str(), newFullName.c_str()) == 0) { - node->rename(newFullName); + node->rename(newName); return 0; } else { - MTPE("MtpStorage::renameObject failed, handle: %d, new name: '%s'\n", handle, newName.c_str()); + MTPE("MtpStorage::renameObject failed, handle: %u, new name: '%s'\n", handle, newName.c_str()); return -1; } } @@ -665,32 +535,28 @@ int MtpStorage::renameObject(MtpObjectHandle handle, std::string newName) { return -1; } -void MtpStorage::createEmptyDir(const char* path) { - Node *node; - ++mtpparentid; - MtpStorageID storage = getStorageID(); - MTPD("MtpStorage::createEmptyDir path: '%s', storage: %i, mtpparentid: %d\n", path, storage, mtpparentid); - mtpmap[mtpparentid] = new Tree(); - for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) { - node = i->second->findNodePath(path, i->second->Root()); - if (node != NULL) { - mtpmap[mtpparentid]->setMtpParentId(mtpparentid, node); - } - } -} - -int MtpStorage::getObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property, uint64_t &longValue) { +int MtpStorage::getObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property, MtpStorage::PropEntry& pe) { Node *node; for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) { - node = i->second->findNode(handle, i->second->Root()); + node = i->second->findNode(handle); if (node != NULL) { - longValue = node->getIntProperty(property); + const Node::mtpProperty& prop = node->getProperty(property); + if (prop.property != property) { + MTPD("getObjectPropertyValue: unknown property %x for handle %u\n", property, handle); + return -1; + } + pe.datatype = prop.dataType; + pe.intvalue = prop.valueInt; + pe.strvalue = prop.valueStr; + pe.handle = handle; + pe.property = property; return 0; } } // handle not found on this storage return -1; } + pthread_t MtpStorage::inotify(void) { pthread_t thread; ThreadPtr inotifyptr = &MtpStorage::inotify_t; @@ -699,229 +565,227 @@ pthread_t MtpStorage::inotify(void) { return thread; } -int MtpStorage::addInotifyDirs(std::string path) { - struct dirent *de; - DIR *d; - struct stat st; - std::string inotifypath; - - d = opendir(path.c_str()); - if (d == NULL) { - MTPE("MtpStorage::addInotifyDirs unable to open '%s'\n", path.c_str()); - closedir(d); +int MtpStorage::addInotify(Tree* tree) { + std::string path = getNodePath(tree); + MTPD("adding inotify for tree %x, dir: %s\n", tree, path.c_str()); + int wd = inotify_add_watch(inotify_fd, path.c_str(), WATCH_FLAGS); + if (wd < 0) { + MTPE("inotify_add_watch failed: %s\n", strerror(errno)); return -1; } + inotifymap[wd] = tree; + return 0; +} - while ((de = readdir(d)) != NULL) { - inotifypath = path + "/" + de->d_name; - if (lstat(inotifypath.c_str(), &st)) { - MTPE("Error using lstat on '%s'\n", inotifypath.c_str()); - return -1; +void MtpStorage::handleInotifyEvent(struct inotify_event* event) +{ + std::map::iterator it = inotifymap.find(event->wd); + if (it == inotifymap.end()) { + MTPE("Unable to locate inotify_wd: %i\n", event->wd); + return; + } + Tree* tree = it->second; + MTPD("inotify_t tree: %x '%s'\n", tree, tree->getName().c_str()); + Node* node = tree->findEntryByName(basename(event->name)); + if (node && node->Mtpid() == handleCurrentlySending) { + MTPD("ignoring inotify event for currently uploading file, handle: %u\n", node->Mtpid()); + return; + } + if (event->mask & IN_CREATE || event->mask & IN_MOVED_TO) { + if (event->mask & IN_ISDIR) { + MTPD("inotify_t create is dir\n"); + } else { + MTPD("inotify_t create is file\n"); } - if (!(st.st_mode & S_IFDIR) || strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) - continue; - if (addInotifyDirs(inotifypath)) { - closedir(d); - return -1; + if (node == NULL) { + node = addNewNode(event->mask & IN_ISDIR, tree, event->name); + std::string item = getNodePath(tree) + "/" + event->name; + node->addProperties(item, getStorageID()); + mServer->sendObjectAdded(node->Mtpid()); + } else { + MTPD("inotify_t item already exists.\n"); + } + if (event->mask & IN_ISDIR) { + // TODO: do we need to do anything here? probably not until someone reads from the dir... + } + } else if (event->mask & IN_DELETE || event->mask & IN_MOVED_FROM) { + if (event->mask & IN_ISDIR) { + MTPD("inotify_t Directory %s deleted\n", event->name); + } else { + MTPD("inotify_t File %s deleted\n", event->name); + } + if (node) + { + if (event->mask & IN_ISDIR) { + for (std::map::iterator it = inotifymap.begin(); it != inotifymap.end(); ++it) { + if (it->second == node) { + inotify_rm_watch(inotify_fd, it->first); + MTPD("inotify_t removing watch on '%s'\n", getNodePath(it->second).c_str()); + inotifymap.erase(it->first); + break; + } + + } + } + MtpObjectHandle handle = node->Mtpid(); + deleteFile(handle); + mServer->sendObjectRemoved(handle); + } else { + MTPD("inotify_t already removed.\n"); + } + } else if (event->mask & IN_MODIFY) { + MTPD("inotify_t item %s modified.\n", event->name); + if (node != NULL) { + uint64_t orig_size = node->getProperty(MTP_PROPERTY_OBJECT_SIZE).valueInt; + struct stat st; + uint64_t new_size = 0; + if (lstat(getNodePath(node).c_str(), &st) == 0) + new_size = (uint64_t)st.st_size; + if (orig_size != new_size) { + MTPD("size changed from %llu to %llu on mtpid: %u\n", orig_size, new_size, node->Mtpid()); + node->updateProperty(MTP_PROPERTY_OBJECT_SIZE, new_size, "", MTP_TYPE_UINT64); + mServer->sendObjectUpdated(node->Mtpid()); + } + } else { + MTPE("inotify_t modified item not found\n"); } - inotify_wd = inotify_add_watch(inotify_fd, inotifypath.c_str(), WATCH_FLAGS); - inotifymap[inotify_wd] = inotifypath; - MTPD("added inotify dir: '%s'\n", inotifypath.c_str()); + } else if (event->mask & IN_DELETE_SELF || event->mask & IN_MOVE_SELF) { + // TODO: is this always already handled by IN_DELETE for the parent dir? } - closedir(d); - return 0; } int MtpStorage::inotify_t(void) { - int len, i = 0; - int local_mtpparentid; - Node* node = NULL; - struct stat st; #define EVENT_SIZE ( sizeof(struct inotify_event) ) #define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16) ) char buf[EVENT_BUF_LEN]; - std::string item, parent = ""; - MTPD("starting inotify thread\n"); + MTPD("inotify thread: inotify_init\n"); inotify_fd = inotify_init(); - if (inotify_fd < 0){ - MTPE("Can't run inotify for mtp server\n"); - } - - inotify_wd = inotify_add_watch(inotify_fd, getPath(), WATCH_FLAGS); - inotifymap[inotify_wd] = getPath(); - if (addInotifyDirs(getPath())) { - MTPE("MtpStorage::inotify_t failed to add watches to directories\n"); - for (std::map::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) { - inotify_rm_watch(inotify_fd, i->first); - } - close(inotify_fd); + if (inotify_fd < 0) { + MTPE("Can't run inotify for mtp server: %s\n", strerror(errno)); return -1; } while (true) { - i = 0; - len = read(inotify_fd, buf, EVENT_BUF_LEN); + int i = 0; + int len = read(inotify_fd, buf, EVENT_BUF_LEN); if (len < 0) { + if (errno == EINTR) + continue; MTPE("inotify_t Can't read inotify events\n"); } while (i < len) { - struct inotify_event *event = ( struct inotify_event * ) &buf[ i ]; - if ( event->len ) { - if (inotifymap[event->wd].empty()) { - MTPE("Unable to locate inotify_wd: %i\n", event->wd); - goto end; - } else { - item = inotifymap[event->wd]; - item = item + "/" + event->name; - MTPD("inotify_t item: '%s'\n", item.c_str()); - if (event->mask & IN_CREATE || event->mask & IN_MOVED_TO) { - lockMutex(1); - if (event->mask & IN_ISDIR) { - MTPD("inotify_t create is dir\n"); - } else { - MTPD("inotify_t create is file\n"); - } - for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) { - node = i->second->findNodePath(item, i->second->Root()); - if (node != NULL) - break; - } - if (node == NULL) { - parent = item.substr(0, item.find_last_of('/')); - MTPD("parent: %s\n", parent.c_str()); - if (parent == getPath()) { - local_mtpparentid = 1; - } else { - for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) { - node = i->second->findNodePath(parent, i->second->Root()); - MTPD("searching for node: %d\n", (int)node); - if (node != NULL) { - local_mtpparentid = i->second->getMtpParentId(node); - break; - } - } - if (node == NULL) { - MTPE("inotify_t unable to locate mtparentid\n"); - goto end; - } - } - ++mtpid; - MTPD("mtpid: %d\n", mtpid); - MTPD("mtpparentid1: %d\n", local_mtpparentid); - node = mtpmap[local_mtpparentid]->addNode(mtpid, item); - mtpmap[local_mtpparentid]->setMtpParentId(local_mtpparentid, node); - node->addProperties(getStorageID(), getParentObject(parent)); - if (event->mask & IN_ISDIR) { - createEmptyDir(item.c_str()); - } - mServer->sendObjectAdded(mtpid); - } else { - MTPD("inotify_t item already exists.\n"); - } - if (event->mask & IN_ISDIR) { - inotify_wd = inotify_add_watch(inotify_fd, item.c_str(), WATCH_FLAGS); - inotifymap[inotify_wd] = item; - MTPD("added inotify dir: '%s'\n", item.c_str()); - MTPD("inotify_t scanning new dir\n"); - readParentDirs(item); - std::string mtpParent; - while (!mtpParentList.empty()) { - mtpParent = mtpParentList.front(); - mtpParentList.pop_front(); - readParentDirs(mtpParent); - inotify_wd = inotify_add_watch(inotify_fd, mtpParent.c_str(), WATCH_FLAGS); - inotifymap[inotify_wd] = mtpParent; - MTPD("added inotify dir: '%s'\n", mtpParent.c_str()); - } - } - } else if (event->mask & IN_DELETE || event->mask & IN_MOVED_FROM) { - lockMutex(1); - if (event->mask & IN_ISDIR) { - MTPD("inotify_t Directory %s deleted\n", event->name); - } else { - MTPD("inotify_t File %s deleted\n", event->name); - } - for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) { - node = i->second->findNodePath(item, i->second->Root()); - if (node != NULL) - break; - } - if (node != NULL && node->Mtpid() > 0) { - int local_id = node->Mtpid(); - node = NULL; - deleteFile(local_id); - mServer->sendObjectRemoved(local_id); - } else { - MTPD("inotify_t already removed.\n"); - } - if (event->mask & IN_ISDIR) { - std::string orig_item = item + "/"; - size_t item_size = orig_item.size(); - std::string path_check; - for (std::map::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) { - if ((i->second.size() > item_size && i->second.substr(0, item_size) == orig_item) || i->second == item) { - inotify_rm_watch(inotify_fd, i->first); - MTPD("inotify_t removing watch on '%s'\n", i->second.c_str()); - inotifymap.erase(i->first); - } - } - } - } else if (event->mask & IN_MODIFY) { - MTPD("inotify_t item %s modified.\n", event->name); - for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) { - node = i->second->findNodePath(item, i->second->Root()); - if (node != NULL) - break; - } - if (node != NULL) { - uint64_t orig_size = node->getIntProperty(MTP_PROPERTY_OBJECT_SIZE); - struct stat st; - uint64_t new_size = 0; - if (lstat(item.c_str(), &st) == 0) - new_size = (uint64_t)st.st_size; - if (orig_size != new_size) { - MTPD("size changed from %llu to %llu on mtpid: %i\n", orig_size, new_size, node->Mtpid()); - node->updateProperty(MTP_PROPERTY_OBJECT_SIZE, new_size, "", MTP_TYPE_UINT64); - mServer->sendObjectUpdated(node->Mtpid()); - } - } else { - MTPE("inotify_t modified item not found\n"); - } - } - } + struct inotify_event *event = (struct inotify_event *) &buf[i]; + if (event->len) { + MTPD("inotify event: wd: %i, mask: %x, name: %s\n", event->wd, event->mask, event->name); + lockMutex(1); + handleInotifyEvent(event); + unlockMutex(1); } -end: - unlockMutex(1); i += EVENT_SIZE + event->len; } } - for (std::map::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) { + for (std::map::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) { inotify_rm_watch(inotify_fd, i->first); } close(inotify_fd); return 0; } -int MtpStorage::getParentObject(std::string parent_path) { - Node* node; - if (parent_path == getPath()) { - MTPD("MtpStorage::getParentObject for: '%s' returning: 0 for root\n", parent_path.c_str()); - return 0; +Node* MtpStorage::findNodeByPath(const std::string& path) { + MTPD("findNodeByPath: %s\n", path.c_str()); + std::string match = path.substr(0, mtpstorageparent.size()); + if (match != mtpstorageparent) { + // not on this device + MTPD("no match: %s is not on storage %s\n", match.c_str(), mtpstorageparent.c_str()); + return NULL; } - for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) { - node = i->second->findNodePath(parent_path, i->second->Root()); + + // TODO: fix and test this + std::string p = path.substr(mtpstorageparent.size()+1); // cut off "/" after storage root too + Tree* tree = mtpmap[0]; // start at storage root + + Node* node = NULL; + while (!p.empty()) { + size_t slashpos = p.find('/'); + std::string e; + if (slashpos != std::string::npos) { + e = p; + p.clear(); + } else { + e = p.substr(0, slashpos); + p = p.substr(slashpos + 1); + } + MTPD("path element: %s, rest: %s\n", e.c_str(), p.c_str()); + node = tree->findEntryByName(e); + if (!node) { + MTPE("path element of %s not found: %s\n", path.c_str(), e.c_str()); + return NULL; + } + if (node->isDir()) + tree = static_cast(node); + else if (!p.empty()) { + MTPE("path element of %s is not a directory: %s node: %p\n", path.c_str(), e.c_str(), node); + return NULL; + } + } + MTPD("findNodeByPath: found node %p, handle: %u, name: %s\n", node, node->Mtpid(), node->getName().c_str()); + return node; +} + +Node* MtpStorage::addNewNode(bool isDir, Tree* tree, const std::string& name) +{ + // global counter for new object handles + static MtpObjectHandle mtpid = 0; + + ++mtpid; + MTPD("adding new %s node for %s, new handle: %u\n", isDir ? "dir" : "file", name.c_str(), mtpid); + MtpObjectHandle parent = tree->Mtpid(); + MTPD("parent tree: %x, handle: %u, name: %s\n", tree, parent, tree->getName().c_str()); + Node* node; + if (isDir) + node = mtpmap[mtpid] = new Tree(mtpid, parent, name); + else + node = new Node(mtpid, parent, name); + tree->addEntry(node); + return node; +} + +Node* MtpStorage::findNode(MtpObjectHandle handle) { + for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) { + Node* node = i->second->findNode(handle); if (node != NULL) { - MTPD("MtpStorage::getParentObject for: '%s' returning: %i\n", parent_path.c_str(), node->Mtpid()); - return node->Mtpid(); + MTPD("findNode: found node %p for handle %u, name: %s\n", node, handle, node->getName().c_str()); + if (node->Mtpid() != handle) + { + MTPE("BUG: entry for handle %u points to node with handle %u\n", handle, node->Mtpid()); + } + return node; } } - MTPE("MtpStorage::getParentObject for: '%s' unable to locate node\n", parent_path.c_str()); - return -1; + // Item is not on this storage device + MTPE("MtpStorage::findNode: no node found for handle %u, searched %u trees\n", handle, mtpmap.size()); + return NULL; +} + +std::string MtpStorage::getNodePath(Node* node) { + std::string path; + MTPD("getNodePath: node %p, handle %u\n", node, node->Mtpid()); + while (node) + { + path = "/" + node->getName() + path; + MtpObjectHandle parent = node->getMtpParentId(); + if (parent == 0) // root + break; + node = findNode(parent); + } + path = mtpstorageparent + path; + MTPD("getNodePath: path %s\n", path.c_str()); + return path; } void MtpStorage::lockMutex(int thread_type) { -- cgit v1.2.3