summaryrefslogtreecommitdiffstats
path: root/mtp/MtpStorage.cpp
diff options
context:
space:
mode:
authorthat <github@that.at>2014-10-08 00:01:24 +0200
committerDees Troy <dees_troy@teamw.in>2014-10-08 18:34:39 +0200
commit9e0593eaf6defb15761f41246093c0d3661b140d (patch)
treeb9c42ddb95087c735d50b8ce34b5aee529adc5cb /mtp/MtpStorage.cpp
parentUpdate RECOVERY_VARIANT blocking to use project-path-for (diff)
downloadandroid_bootable_recovery-9e0593eaf6defb15761f41246093c0d3661b140d.tar
android_bootable_recovery-9e0593eaf6defb15761f41246093c0d3661b140d.tar.gz
android_bootable_recovery-9e0593eaf6defb15761f41246093c0d3661b140d.tar.bz2
android_bootable_recovery-9e0593eaf6defb15761f41246093c0d3661b140d.tar.lz
android_bootable_recovery-9e0593eaf6defb15761f41246093c0d3661b140d.tar.xz
android_bootable_recovery-9e0593eaf6defb15761f41246093c0d3661b140d.tar.zst
android_bootable_recovery-9e0593eaf6defb15761f41246093c0d3661b140d.zip
Diffstat (limited to 'mtp/MtpStorage.cpp')
-rwxr-xr-xmtp/MtpStorage.cpp1152
1 files changed, 508 insertions, 644 deletions
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 <sys/types.h>
#include <sys/stat.h>
@@ -35,12 +36,9 @@
#include <signal.h>
#include <sys/inotify.h>
#include <fcntl.h>
-#include <sstream>
#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<int, std::string>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
+ for (std::map<int, Tree*>::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<int> 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<int> propertyCodes;
- std::vector<int> dataTypes;
- std::vector<std::string> valueStrs;
- std::vector<int> 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<MtpStorage::PropEntry>& 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<Node::mtpProperty> 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<Node::mtpProperty> 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<PropEntry> 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<int, Tree*>::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<int, Tree*>::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<int, std::string>::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<int, std::string>::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<int, std::string>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
+ for (std::map<int, Tree*>::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<Tree*>(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) {