blob: 57c87745e7417b622847b58f78c7fb3a55eafa34 [file] [log] [blame]
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -04001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
17 */
18
19#include "MtpDebug.h"
20#include "MtpStorage.h"
21#include "MtpDataPacket.h"
22#include "MtpServer.h"
23#include "MtpEventPacket.h"
24
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/statfs.h>
28#include <unistd.h>
29#include <dirent.h>
30#include <errno.h>
31#include <string.h>
32#include <stdio.h>
33#include <limits.h>
34#include <pthread.h>
35#include <signal.h>
36#include <sys/inotify.h>
37#include <fcntl.h>
38#include <sstream>
39
40#define WATCH_FLAGS ( IN_CREATE | IN_DELETE | IN_MOVE | IN_MODIFY )
41
42static int mtpid = 0;
43
44MtpStorage::MtpStorage(MtpStorageID id, const char* filePath,
45 const char* description, uint64_t reserveSpace,
46 bool removable, uint64_t maxFileSize, MtpServer* refserver)
47 : mStorageID(id),
48 mFilePath(filePath),
49 mDescription(description),
50 mMaxCapacity(0),
51 mMaxFileSize(maxFileSize),
52 mReserveSpace(reserveSpace),
53 mRemovable(removable),
54 mServer(refserver)
55{
56 MTPI("MtpStorage id: %d path: %s\n", id, filePath);
57 mtpparentid = 0;
58 inotify_thread = 0;
59 sendEvents = false;
60 use_mutex = true;
61 if (pthread_mutex_init(&mtpMutex, NULL) != 0) {
62 MTPE("Failed to init mtpMutex\n");
63 use_mutex = false;
64 }
65 if (pthread_mutex_init(&inMutex, NULL) != 0) {
66 MTPE("Failed to init inMutex\n");
67 use_mutex = false;
68 }
69
70}
71
72MtpStorage::~MtpStorage() {
73 if (inotify_thread) {
74 pthread_kill(inotify_thread, 0);
75 for (std::map<int, std::string>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
76 inotify_rm_watch(inotify_fd, i->first);
77 }
78 close(inotify_fd);
79 }
80 for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
81 delete i->second;
82 }
83 if (use_mutex) {
84 use_mutex = false;
85 pthread_mutex_destroy(&mtpMutex);
86 pthread_mutex_destroy(&inMutex);
87 }
88}
89
90int MtpStorage::getType() const {
91 return (mRemovable ? MTP_STORAGE_REMOVABLE_RAM : MTP_STORAGE_FIXED_RAM);
92}
93
94int MtpStorage::getFileSystemType() const {
95 return MTP_STORAGE_FILESYSTEM_HIERARCHICAL;
96}
97
98int MtpStorage::getAccessCapability() const {
99 return MTP_STORAGE_READ_WRITE;
100}
101
102uint64_t MtpStorage::getMaxCapacity() {
103 if (mMaxCapacity == 0) {
104 struct statfs stat;
105 if (statfs(getPath(), &stat))
106 return -1;
107 mMaxCapacity = (uint64_t)stat.f_blocks * (uint64_t)stat.f_bsize;
108 }
109 return mMaxCapacity;
110}
111
112uint64_t MtpStorage::getFreeSpace() {
113 struct statfs stat;
114 if (statfs(getPath(), &stat))
115 return -1;
116 uint64_t freeSpace = (uint64_t)stat.f_bavail * (uint64_t)stat.f_bsize;
117 return (freeSpace > mReserveSpace ? freeSpace - mReserveSpace : 0);
118}
119
120const char* MtpStorage::getDescription() const {
121 return (const char *)mDescription;
122}
123
124int MtpStorage::createDB() {
125 std::string mtpParent = "";
126 mtpstorageparent = getPath();
127 readParentDirs(getPath());
128 while (!mtpParentList.empty()) {
129 mtpParent = mtpParentList.front();
130 mtpParentList.pop_front();
131 readParentDirs(mtpParent);
132 }
133 MTPD("MtpStorage::createDB DONE\n");
134 if (use_mutex) {
135 MTPD("Starting inotify thread\n");
136 sendEvents = true;
137 inotify_thread = inotify();
138 } else {
139 MTPD("NOT starting inotify thread\n");
140 }
141 return 0;
142}
143
144MtpObjectHandleList* MtpStorage::getObjectList(MtpStorageID storageID, MtpObjectHandle parent) {
145 std::vector<int> mtpids;
146 int local_mtpparentid;
147 MTPD("MtpStorage::getObjectList\n");
148 MTPD("parent: %d\n", parent);
149 //append object id (numerical #s) of database to int array
150 MtpObjectHandleList* list = new MtpObjectHandleList();
151 if (parent == MTP_PARENT_ROOT) {
152 MTPD("parent == MTP_PARENT_ROOT\n");
153 local_mtpparentid = 1;
154 }
155 else {
156 for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
157 MTPD("root: %d\n", i->second->Root());
158 Node* node = i->second->findNode(parent, i->second->Root());
159 if (node != NULL) {
160 local_mtpparentid = i->second->getMtpParentId(node);
161 MTPD("path: %s\n", i->second->getPath(node).c_str());
162 MTPD("mtpparentid: %d going to endloop\n", local_mtpparentid);
163 goto endloop;
164 }
165 }
166 }
167 MTPD("got to endloop\n");
168 endloop:
169
170 if (mtpmap[local_mtpparentid] == NULL) {
171 MTPD("mtpmap[mtpparentid] == NULL, returning\n");
172 return list;
173 }
174
175 MTPD("root: %d\n", mtpmap[local_mtpparentid]->Root());
176 mtpmap[local_mtpparentid]->getmtpids(mtpmap[local_mtpparentid]->Root(), &mtpids);
177 MTPD("here, mtpids->size(): %i\n", mtpids.size());
178
179 for (unsigned index = 0; index < mtpids.size(); index++) {
180 MTPD("mtpidhere[%i]: %d\n", index, mtpids.at(index));
181 list->push(mtpids.at(index));
182 }
183 return list;
184}
185
186int MtpStorage::getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info) {
187 struct stat st;
Ethan Yonker241a3ce2014-09-04 12:59:27 -0500188 uint64_t size = 0;
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400189 MTPD("MtpStorage::getObjectInfo handle: %d\n", handle);
190 for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
191 Node* node = i->second->findNode(handle, i->second->Root());
192 MTPD("node returned: %d\n", node);
193 if (node != NULL) {
194 MTPD("found mtpid: %d\n", node->Mtpid());
195 info.mStorageID = getStorageID();
196 MTPD("info.mStorageID: %d\n", info.mStorageID);
197 info.mParent = node->getMtpParentId();
198 MTPD("mParent: %d\n", info.mParent);
Ethan Yonker241a3ce2014-09-04 12:59:27 -0500199 if (lstat(node->getPath().c_str(), &st) == 0)
200 size = st.st_size;
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400201 MTPD("size is: %llu\n", size);
202 info.mCompressedSize = size;//(size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size);
203 info.mDateModified = st.st_mtime;
204 if (S_ISDIR(st.st_mode)) {
205 info.mFormat = MTP_FORMAT_ASSOCIATION;
206 }
207 else {
208 info.mFormat = MTP_FORMAT_UNDEFINED;
209 }
210 info.mName = strdup(basename(node->getPath().c_str()));
211 MTPD("MtpStorage::getObjectInfo found, Exiting getObjectInfo()\n");
212 return 0;
213 }
214 }
Ethan Yonker5e083dc2014-09-03 14:46:41 -0500215 // Item is not on this storage device
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400216 return -1;
217}
218
219MtpObjectHandle MtpStorage::beginSendObject(const char* path,
220 MtpObjectFormat format,
221 MtpObjectHandle parent,
222 MtpStorageID storage,
223 uint64_t size,
224 time_t modified) {
225 MTPD("MtpStorage::beginSendObject(), path: '%s', parent: %d, storage: %d, format: %04x\n", path, parent, storage, format);
226 Node* node;
227 std::string parentdir;
228 std::string pathstr(path);
229 int parent_id;
230 parentdir = pathstr.substr(0, pathstr.find_last_of('/'));
231 MTPD("MtpStorage::beginSendObject() parentdir: %s\n", parentdir.c_str());
232 if (parentdir.compare(mtpstorageparent) == 0) {
233 // root directory
234 MTPD("MtpStorage::beginSendObject() root dir\n");
235 parent_id = 1;
236 ++mtpid;
237 node = mtpmap[parent_id]->addNode(mtpid, path);
238 MTPD("node: %d\n", node);
239 node->addProperties(storage, 0);
240 if (format == MTP_FORMAT_ASSOCIATION) {
241 createEmptyDir(path);
242 }
243 return mtpid;
244 } else {
245 for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
246 node = i->second->findNodePath(parentdir, i->second->Root());
247 if (node != NULL) {
248 MTPD("mtpid: %d\n", mtpid);
249 MTPD("path: %s\n", i->second->getPath(node).c_str());
250 parentdir = i->second->getPath(node);
251 parent = i->second->getMtpParentId(node);
252 if (parent == 0) {
253 MTPD("MtpStorage::beginSendObject parent is 0, error.\n");
254 return -1;
255 } else {
256 ++mtpid;
257 node = mtpmap[parent]->addNode(mtpid, path);
258 node->addProperties(getStorageID(), getParentObject(parentdir));
259 for (iter i2 = mtpmap.begin(); i2 != mtpmap.end(); i2++) {
260 node = i2->second->findNodePath(path, i2->second->Root());
261 if (node != NULL) {
262 i2->second->setMtpParentId(parent, node);
263 }
264 }
265 if (format == MTP_FORMAT_ASSOCIATION) {
266 createEmptyDir(path);
267 }
268 }
269 return mtpid;
270 }
271 }
272 }
273 MTPE("MtpStorage::beginSendObject(), path: '%s', parent: %d, storage: %d, format: %04x\n", path, parent, storage, format);
274 return -1;
275}
276
277int MtpStorage::getObjectFilePath(MtpObjectHandle handle, MtpString& outFilePath, int64_t& outFileLength, MtpObjectFormat& outFormat) {
278 struct stat st;
279 Node* node;
280 MTPD("MtpStorage::getObjectFilePath handle: %i\n", handle);
281 for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
282 MTPD("handle: %d\n", handle);
283 node = i->second->findNode(handle, i->second->Root());
284 MTPD("node returned: %d\n", node);
285 if (node != NULL) {
Ethan Yonker241a3ce2014-09-04 12:59:27 -0500286 if (lstat(node->getPath().c_str(), &st) == 0)
287 outFileLength = st.st_size;
288 else
289 outFileLength = 0;
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400290 outFilePath = strdup(node->getPath().c_str());
291 MTPD("outFilePath: %s\n", node->getPath().c_str());
292 goto end;
293 }
294 }
Ethan Yonker5e083dc2014-09-03 14:46:41 -0500295 // Item is not on this storage
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400296 return -1;
297end:
298 outFormat = MTP_FORMAT_ASSOCIATION;
299 return 0;
300}
301
302int MtpStorage::readParentDirs(std::string path) {
303 struct dirent *de;
304 struct stat st;
305 DIR *d;
306 std::string parent, item, prevparent = "";
307 Node* node;
308 int storageID = getStorageID();
309
310 d = opendir(path.c_str());
311 MTPD("opening '%s'\n", path.c_str());
312 if (d == NULL) {
313 MTPD("error opening '%s' -- error: %s\n", path.c_str(), strerror(errno));
314 closedir(d);
315 }
316 while ((de = readdir(d)) != NULL) {
Ethan Yonker241a3ce2014-09-04 12:59:27 -0500317 // Because exfat-fuse causes issues with dirent, we will use stat
318 // for some things that dirent should be able to do
319 item = path + "/" + de->d_name;
320 if (lstat(item.c_str(), &st)) {
321 MTPE("Error running lstat on '%s'\n", item.c_str());
322 return -1;
323 }
324 if ((st.st_mode & S_IFDIR) && strcmp(de->d_name, ".") == 0)
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400325 continue;
Ethan Yonker241a3ce2014-09-04 12:59:27 -0500326 if ((st.st_mode & S_IFDIR) && strcmp(de->d_name, "..") != 0) {
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400327 // Handle dirs
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400328 MTPD("dir: %s\n", item.c_str());
329 mtpParentList.push_back(item);
330 parent = item.substr(0, item.find_last_of('/'));
331 ++mtpid;
332 MTPD("parent: %s\n", parent.c_str());
333 MTPD("mtpid: %d\n", mtpid);
334 if (prevparent != parent) {
335 mtpparentid++;
336 MTPD("Handle dirs, prevparent != parent, mtpparentid: %d\n", mtpparentid);
337 mtpmap[mtpparentid] = new Tree();
338 MTPD("prevparent addNode\n");
339 for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
340 node = i->second->findNodePath(parent, i->second->Root());
341 if (node != NULL) {
342 i->second->setMtpParentId(mtpparentid, node);
343 }
344 }
345 node = mtpmap[mtpparentid]->addNode(mtpid, item);
346 node->addProperties(storageID, getParentObject(path));
347 if (sendEvents)
348 mServer->sendObjectAdded(mtpid);
349 }
350 else {
351 MTPD("add node\n");
352 mtpmap[mtpparentid]->addNode(mtpid, item);
353 for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
354 node = i->second->findNodePath(item, i->second->Root());
355 if (node != NULL) {
356 i->second->setMtpParentId(mtpparentid, node);
357 node->addProperties(storageID, getParentObject(path));
358 }
359 }
360 if (sendEvents)
361 mServer->sendObjectAdded(mtpid);
362 }
363 prevparent = parent;
364 }
365 else {
366 if (strcmp(de->d_name, "..") != 0) {
367 // Handle files
368 item = path + "/" + de->d_name;
369 MTPD("file: %s\n", item.c_str());
370 parent = item.substr(0, item.find_last_of('/'));
371 MTPD("parent: %s\n", parent.c_str());
372 ++mtpid;
373 MTPD("mtpid: %d\n", mtpid);
374 if (prevparent != parent) {
375 mtpparentid++;
376 MTPD("mtpparentid1: %d\n", mtpparentid);
377 for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
378 node = i->second->findNodePath(path, i->second->Root());
379 if (node != NULL) {
380 i->second->setMtpParentId(mtpparentid, node);
381 node->addProperties(storageID, getParentObject(path));
382 }
383 }
384 }
385 if (mtpmap[mtpparentid] == NULL) {
386 mtpmap[mtpparentid] = new Tree();
387 }
388 MTPD("blank addNode\n");
389 node = mtpmap[mtpparentid]->addNode(mtpid, item);
390 node->addProperties(storageID, getParentObject(path));
391 prevparent = parent;
392 if (sendEvents)
393 mServer->sendObjectAdded(mtpid);
394 }
395 else {
396 // Handle empty dirs?
397 MTPD("checking for empty dir '%s'\n", path.c_str());
398 int count = 0;
399 DIR *dirc;
400 struct dirent *ep;
401 dirc = opendir(path.c_str());
402 if (dirc != NULL) {
403 while ((ep = readdir(dirc)))
404 ++count;
405 MTPD("count: %d\n", count);
406 closedir(dirc);
407 }
408 if (count == 2) {
409 MTPD("'%s' is an empty dir\n", path.c_str());
410 createEmptyDir(path.c_str());
411 goto end;
412 }
413 }
414 }
415 }
416 end:
417 closedir(d);
418 return 0;
419}
420
421void MtpStorage::deleteTrees(int parent) {
422 Node* node = mtpmap[parent]->Root();
423 MTPD("MtpStorage::deleteTrees deleting %i\n", parent);
424 while (node != NULL) {
425 if (node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT) == MTP_FORMAT_ASSOCIATION) {
426 deleteTrees(node->getMtpParentId());
427 }
428 node = mtpmap[parent]->getNext(node);
429 }
430 delete mtpmap[parent];
431 mtpmap.erase(parent);
432 MTPD("MtpStorage::deleteTrees deleted %i\n", parent);
433}
434
435int MtpStorage::deleteFile(MtpObjectHandle handle) {
436 int local_parent_id = 0;
437 for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
438 MTPD("MtpStorage::deleteFile handle: %d\n", handle);
439 Node* node = i->second->findNode(handle, i->second->Root());
440 MTPD("MtpStorage::deleteFile node returned: %d\n", node);
441 if (node != NULL) {
442 if (node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT) == MTP_FORMAT_ASSOCIATION) {
443 local_parent_id = node->getMtpParentId();
444 }
445 MTPD("deleting handle: %d\n", handle);
446 i->second->deleteNode(handle);
447 MTPD("deleted\n");
448 goto end;
449 }
450 }
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400451 return -1;
452end:
453 if (local_parent_id) {
454 deleteTrees(local_parent_id);
455 }
456 return 0;
457}
458
459int MtpStorage::getObjectPropertyList(MtpObjectHandle handle, uint32_t format, uint32_t property, int groupCode, int depth, MtpDataPacket& packet) {
460 Node *n;
461 int local_mtpid = 0;
462 int local_mtpparentid = 0;
463 std::vector<int> propertyCodes;
464 std::vector<int> dataTypes;
465 std::vector<std::string> valueStrs;
466 std::vector<int> longValues;
467 int count = 0;
468 MTPD("MtpStorage::getObjectPropertyList handle: %d, format: %d, property: %lx\n", handle, format, property);
469 if (property == MTP_PROPERTY_OBJECT_FORMAT) {
470 MTPD("MtpStorage::getObjectPropertyList MTP_PROPERTY_OBJECT_FORMAT\n");
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400471 for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
472 MTPD("root: %d\n", i->second->Root());
473 Node *node = i->second->findNode(handle, i->second->Root());
474 MTPD("index: %d\n", index);
475 MTPD("node: %d\n", node);
476 if (node != NULL) {
477 uint64_t longval = node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT);
478 local_mtpparentid = i->second->getMtpParentId(node);
479 MTPD("object format longValue: %llu\n", longval);
480 propertyCodes.push_back(MTP_PROPERTY_OBJECT_FORMAT);
481 longValues.push_back(node->getIntProperty(MTP_PROPERTY_OBJECT_FORMAT));
482 valueStrs.push_back("");
483 dataTypes.push_back(4);
484 count = 1;
485 local_mtpid = node->Mtpid();
486 goto endloop;
487 }
488 }
489 }
490 else if (property == MTP_PROPERTY_STORAGE_ID) {
491 MTPD("MtpStorage::getObjectPropertyList MTP_PROPERTY_STORAGE_ID\n");
492 for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
493 MTPD("root: %d\n", i->second->Root());
494 Node *node = i->second->findNode(handle, i->second->Root());
495 if (node != NULL) {
496 propertyCodes.push_back(MTP_PROPERTY_STORAGE_ID);
497 longValues.push_back(getStorageID());
498 valueStrs.push_back("");
499 dataTypes.push_back(4);
500 count = 1;
501 local_mtpid = node->Mtpid();
502 goto endloop;
503 }
504 }
505 }
506 else if (property == MTP_PARENT_ROOT) {
507 MTPD("MtpStorage::getObjectPropertyList MTP_PARENT_ROOT\n");
508 for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
509 MTPD("root: %d\n", i->second->Root());
510 Node* node = i->second->findNode(handle, i->second->Root());
511 if (node != NULL) {
512 local_mtpparentid = i->second->getMtpParentId(node);
513 MTPD("path: %s\n", i->second->getPath(node).c_str());
514 MTPD("mtpparentid: %d going to endloop\n", local_mtpparentid);
515 std::vector<Node::mtpProperty> mtpprop = node->getMtpProps();
516 count = mtpprop.size();
517 for (int i = 0; i < count; ++i) {
518 propertyCodes.push_back(mtpprop[i].property);
519 longValues.push_back(mtpprop[i].valueInt);
520 valueStrs.push_back(mtpprop[i].valueStr);
521 dataTypes.push_back(mtpprop[i].dataType);
522 }
523 local_mtpid = node->Mtpid();
524 goto endloop;
525 }
526 }
527 }
528 else if (property == MTP_PROPERTY_PROTECTION_STATUS) {
529 MTPD("MtpStorage::getObjectPropertyList MTP_PROPERTY_PROTECTION_STATUS\n");
530 for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
531 MTPD("root: %d\n", i->second->Root());
532 Node *node = i->second->findNode(handle, i->second->Root());
533 if (node != NULL) {
534 propertyCodes.push_back(MTP_PROPERTY_PROTECTION_STATUS);
535 longValues.push_back(0);
536 valueStrs.push_back("");
537 dataTypes.push_back(8);
538 count = 1;
539 local_mtpid = node->Mtpid();
540 goto endloop;
541 }
542 }
543 }
544 else if (property == MTP_PROPERTY_OBJECT_SIZE) {
545 MTPD("MtpStorage::getObjectPropertyList MTP_PROPERTY_OBJECT_SIZE\n");
546 for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
547 MTPD("root: %d\n", i->second->Root());
548 Node *node = i->second->findNode(handle, i->second->Root());
549 if (node != NULL) {
550 struct stat st;
Ethan Yonker241a3ce2014-09-04 12:59:27 -0500551 uint64_t size = 0;
552 if (lstat(node->getPath().c_str(), &st) == 0)
553 size = st.st_size;
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400554 propertyCodes.push_back(MTP_PROPERTY_OBJECT_SIZE);
555 longValues.push_back(size);
556 valueStrs.push_back("");
557 dataTypes.push_back(8);
558 count = 1;
559 local_mtpid = node->Mtpid();
560 goto endloop;
561 }
562 }
563 }
564 else {
Ethan Yonker5e083dc2014-09-03 14:46:41 -0500565 // Either the property is not supported or the handle is not on this storage
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400566 return -1;
567 }
Dees Troy53ea0a12014-09-04 14:17:44 +0000568 // handle not found on this storage
569 return -1;
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400570
571endloop:
572 MTPD("mtpparentid: %d\n", local_mtpparentid);
573 MTPD("count: %d\n", count);
574 packet.putUInt32(count);
575
576 if (count > 0) {
577 std::string stringValuesArray;
578 for (int i = 0; i < count; ++i) {
579 packet.putUInt32(local_mtpid);
580 packet.putUInt16(propertyCodes[i]);
581 MTPD("dataTypes: %d\n", dataTypes[i]);
582 packet.putUInt16(dataTypes[i]);
583 MTPD("propertyCode: %s\n", MtpDebug::getObjectPropCodeName(propertyCodes[i]));
584 MTPD("longValues: %d\n", longValues[i]);
585 switch (dataTypes[i]) {
586 case MTP_TYPE_INT8:
587 MTPD("MTP_TYPE_INT8\n");
588 packet.putInt8(longValues[i]);
589 break;
590 case MTP_TYPE_UINT8:
591 MTPD("MTP_TYPE_UINT8\n");
592 packet.putUInt8(longValues[i]);
593 break;
594 case MTP_TYPE_INT16:
595 MTPD("MTP_TYPE_INT16\n");
596 packet.putInt16(longValues[i]);
597 break;
598 case MTP_TYPE_UINT16:
599 MTPD("MTP_TYPE_UINT16\n");
600 packet.putUInt16(longValues[i]);
601 break;
602 case MTP_TYPE_INT32:
603 MTPD("MTP_TYPE_INT32\n");
604 packet.putInt32(longValues[i]);
605 break;
606 case MTP_TYPE_UINT32:
607 MTPD("MTP_TYPE_UINT32\n");
608 packet.putUInt32(longValues[i]);
609 break;
610 case MTP_TYPE_INT64:
611 MTPD("MTP_TYPE_INT64\n");
612 packet.putInt64(longValues[i]);
613 break;
614 case MTP_TYPE_UINT64:
615 MTPD("MTP_TYPE_UINT64\n");
616 packet.putUInt64(longValues[i]);
617 break;
618 case MTP_TYPE_INT128:
619 MTPD("MTP_TYPE_INT128\n");
620 packet.putInt128(longValues[i]);
621 break;
622 case MTP_TYPE_UINT128:
623 MTPD("MTP_TYPE_UINT128\n");
624 packet.putUInt128(longValues[i]);
625 break;
626 case MTP_TYPE_STR:
627 MTPD("MTP_TYPE_STR: %s\n", valueStrs[i].c_str());
628 packet.putString((const char*) valueStrs[i].c_str());
629 break;
630 default:
631 MTPE("bad or unsupported data type: %i in MyMtpDatabase::getObjectPropertyList", dataTypes[i]);
632 break;
633 }
634 }
635 }
636 return 0;
637}
638
639int MtpStorage::renameObject(MtpObjectHandle handle, std::string newName) {
640 int index;
641 MTPD("MtpStorage::renameObject, handle: %d, new name: '%s'\n", handle, newName.c_str());
642 if (handle == MTP_PARENT_ROOT) {
643 MTPE("parent == MTP_PARENT_ROOT, cannot rename root\n");
644 return -1;
645 } else {
646 for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
647 MTPD("root: %d\n", i->second->Root());
648 Node* node = i->second->findNode(handle, i->second->Root());
649 if (node != NULL) {
650 std::string oldName = i->second->getPath(node);
651 std::string parentdir = oldName.substr(0, oldName.find_last_of('/'));
652 std::string newFullName = parentdir + "/" + newName;
653 MTPD("old: '%s', new: '%s'\n", oldName.c_str(), newFullName.c_str());
654 if (rename(oldName.c_str(), newFullName.c_str()) == 0) {
Dees Troy2e07c042014-09-04 15:00:57 +0000655 node->rename(newFullName);
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400656 return 0;
657 } else {
658 MTPE("MtpStorage::renameObject failed, handle: %d, new name: '%s'\n", handle, newName.c_str());
659 return -1;
660 }
661 }
662 }
663 }
Ethan Yonker6f49e112014-09-03 21:42:49 -0500664 // handle not found on this storage
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400665 return -1;
666}
667
668void MtpStorage::createEmptyDir(const char* path) {
669 Node *node;
670 ++mtpparentid;
671 MtpStorageID storage = getStorageID();
672 MTPD("MtpStorage::createEmptyDir path: '%s', storage: %i, mtpparentid: %d\n", path, storage, mtpparentid);
673 mtpmap[mtpparentid] = new Tree();
674 for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
675 node = i->second->findNodePath(path, i->second->Root());
676 if (node != NULL) {
677 mtpmap[mtpparentid]->setMtpParentId(mtpparentid, node);
678 }
679 }
680}
681
682int MtpStorage::getObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property, uint64_t &longValue) {
683 Node *node;
684 for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
685 node = i->second->findNode(handle, i->second->Root());
686 if (node != NULL) {
687 longValue = node->getIntProperty(property);
688 return 0;
689 }
690 }
Ethan Yonker5e083dc2014-09-03 14:46:41 -0500691 // handle not found on this storage
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400692 return -1;
693}
694pthread_t MtpStorage::inotify(void) {
695 pthread_t thread;
696 ThreadPtr inotifyptr = &MtpStorage::inotify_t;
697 PThreadPtr p = *(PThreadPtr*)&inotifyptr;
698 pthread_create(&thread, NULL, p, this);
699 return thread;
700}
701
702int MtpStorage::addInotifyDirs(std::string path) {
703 struct dirent *de;
704 DIR *d;
705 struct stat st;
706 std::string inotifypath;
707
708 d = opendir(path.c_str());
709 if (d == NULL) {
710 MTPE("MtpStorage::addInotifyDirs unable to open '%s'\n", path.c_str());
711 closedir(d);
712 return -1;
713 }
714
715 while ((de = readdir(d)) != NULL) {
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400716 inotifypath = path + "/" + de->d_name;
Ethan Yonker241a3ce2014-09-04 12:59:27 -0500717 if (lstat(inotifypath.c_str(), &st)) {
718 MTPE("Error using lstat on '%s'\n", inotifypath.c_str());
719 return -1;
720 }
721 if (!(st.st_mode & S_IFDIR) || strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
722 continue;
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400723 if (addInotifyDirs(inotifypath)) {
724 closedir(d);
725 return -1;
726 }
Ethan Yonker241a3ce2014-09-04 12:59:27 -0500727 inotify_wd = inotify_add_watch(inotify_fd, inotifypath.c_str(), WATCH_FLAGS);
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400728 inotifymap[inotify_wd] = inotifypath;
729 MTPD("added inotify dir: '%s'\n", inotifypath.c_str());
730 }
731 closedir(d);
732 return 0;
733}
734
735int MtpStorage::inotify_t(void) {
736 int len, i = 0;
737 int local_mtpparentid;
738 Node* node = NULL;
739 struct stat st;
740 #define EVENT_SIZE ( sizeof(struct inotify_event) )
741 #define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16) )
742 char buf[EVENT_BUF_LEN];
743 std::string item, parent = "";
744
745 MTPD("starting inotify thread\n");
746 inotify_fd = inotify_init();
747
748 if (inotify_fd < 0){
749 MTPE("Can't run inotify for mtp server\n");
750 }
751
752 inotify_wd = inotify_add_watch(inotify_fd, getPath(), WATCH_FLAGS);
753 inotifymap[inotify_wd] = getPath();
754 if (addInotifyDirs(getPath())) {
755 MTPE("MtpStorage::inotify_t failed to add watches to directories\n");
756 for (std::map<int, std::string>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
757 inotify_rm_watch(inotify_fd, i->first);
758 }
759 close(inotify_fd);
760 return -1;
761 }
762
763 while (true) {
764 i = 0;
765 len = read(inotify_fd, buf, EVENT_BUF_LEN);
766
767 if (len < 0) {
768 MTPE("inotify_t Can't read inotify events\n");
769 }
770
771 while (i < len) {
772 struct inotify_event *event = ( struct inotify_event * ) &buf[ i ];
773 if ( event->len ) {
774 if (inotifymap[event->wd].empty()) {
775 MTPE("Unable to locate inotify_wd: %i\n", event->wd);
776 goto end;
777 } else {
778 item = inotifymap[event->wd];
779 item = item + "/" + event->name;
780 MTPD("inotify_t item: '%s'\n", item.c_str());
781 if (event->mask & IN_CREATE || event->mask & IN_MOVED_TO) {
782 lockMutex(1);
783 if (event->mask & IN_ISDIR) {
784 MTPD("inotify_t create is dir\n");
785 } else {
786 MTPD("inotify_t create is file\n");
787 }
788 for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
789 node = i->second->findNodePath(item, i->second->Root());
790 if (node != NULL)
791 break;
792 }
793 if (node == NULL) {
794 parent = item.substr(0, item.find_last_of('/'));
795 MTPD("parent: %s\n", parent.c_str());
796 if (parent == getPath()) {
797 local_mtpparentid = 1;
798 } else {
799 for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
800 node = i->second->findNodePath(parent, i->second->Root());
801 MTPD("searching for node: %d\n", (int)node);
802 if (node != NULL) {
803 local_mtpparentid = i->second->getMtpParentId(node);
804 break;
805 }
806 }
807 if (node == NULL) {
808 MTPE("inotify_t unable to locate mtparentid\n");
809 goto end;
810 }
811 }
812 ++mtpid;
813 MTPD("mtpid: %d\n", mtpid);
814 MTPD("mtpparentid1: %d\n", local_mtpparentid);
815 node = mtpmap[local_mtpparentid]->addNode(mtpid, item);
816 mtpmap[local_mtpparentid]->setMtpParentId(local_mtpparentid, node);
817 node->addProperties(getStorageID(), getParentObject(parent));
818 if (event->mask & IN_ISDIR) {
819 createEmptyDir(item.c_str());
820 }
821 mServer->sendObjectAdded(mtpid);
822 } else {
823 MTPD("inotify_t item already exists.\n");
824 }
825 if (event->mask & IN_ISDIR) {
826 inotify_wd = inotify_add_watch(inotify_fd, item.c_str(), WATCH_FLAGS);
827 inotifymap[inotify_wd] = item;
828 MTPD("added inotify dir: '%s'\n", item.c_str());
829 MTPD("inotify_t scanning new dir\n");
830 readParentDirs(item);
831 std::string mtpParent;
832 while (!mtpParentList.empty()) {
833 mtpParent = mtpParentList.front();
834 mtpParentList.pop_front();
835 readParentDirs(mtpParent);
836 inotify_wd = inotify_add_watch(inotify_fd, mtpParent.c_str(), WATCH_FLAGS);
837 inotifymap[inotify_wd] = mtpParent;
838 MTPD("added inotify dir: '%s'\n", mtpParent.c_str());
839 }
840 }
841 } else if (event->mask & IN_DELETE || event->mask & IN_MOVED_FROM) {
842 lockMutex(1);
843 if (event->mask & IN_ISDIR) {
844 MTPD("inotify_t Directory %s deleted\n", event->name);
845 } else {
846 MTPD("inotify_t File %s deleted\n", event->name);
847 }
848 for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
849 node = i->second->findNodePath(item, i->second->Root());
850 if (node != NULL)
851 break;
852 }
853 if (node != NULL && node->Mtpid() > 0) {
854 int local_id = node->Mtpid();
855 node = NULL;
856 deleteFile(local_id);
857 mServer->sendObjectRemoved(local_id);
858 } else {
859 MTPD("inotify_t already removed.\n");
860 }
861 if (event->mask & IN_ISDIR) {
862 std::string orig_item = item + "/";
863 size_t item_size = orig_item.size();
864 std::string path_check;
865 for (std::map<int, std::string>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
866 if ((i->second.size() > item_size && i->second.substr(0, item_size) == orig_item) || i->second == item) {
867 inotify_rm_watch(inotify_fd, i->first);
868 MTPD("inotify_t removing watch on '%s'\n", i->second.c_str());
869 inotifymap.erase(i->first);
870 }
871 }
872 }
873 } else if (event->mask & IN_MODIFY) {
874 MTPD("inotify_t item %s modified.\n", event->name);
875 for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
876 node = i->second->findNodePath(item, i->second->Root());
877 if (node != NULL)
878 break;
879 }
880 if (node != NULL) {
881 uint64_t orig_size = node->getIntProperty(MTP_PROPERTY_OBJECT_SIZE);
882 struct stat st;
Ethan Yonker241a3ce2014-09-04 12:59:27 -0500883 uint64_t new_size = 0;
884 if (lstat(item.c_str(), &st) == 0)
885 new_size = (uint64_t)st.st_size;
bigbiff bigbiffc7eee6f2014-09-02 18:59:01 -0400886 if (orig_size != new_size) {
887 MTPD("size changed from %llu to %llu on mtpid: %i\n", orig_size, new_size, node->Mtpid());
888 node->updateProperty(MTP_PROPERTY_OBJECT_SIZE, new_size, "", MTP_TYPE_UINT64);
889 mServer->sendObjectUpdated(node->Mtpid());
890 }
891 } else {
892 MTPE("inotify_t modified item not found\n");
893 }
894 }
895 }
896 }
897end:
898 unlockMutex(1);
899 i += EVENT_SIZE + event->len;
900 }
901 }
902
903 for (std::map<int, std::string>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
904 inotify_rm_watch(inotify_fd, i->first);
905 }
906 close(inotify_fd);
907 return 0;
908}
909
910int MtpStorage::getParentObject(std::string parent_path) {
911 Node* node;
912 if (parent_path == getPath()) {
913 MTPD("MtpStorage::getParentObject for: '%s' returning: 0 for root\n", parent_path.c_str());
914 return 0;
915 }
916 for (iter i = mtpmap.begin(); i != mtpmap.end(); ++i) {
917 node = i->second->findNodePath(parent_path, i->second->Root());
918 if (node != NULL) {
919 MTPD("MtpStorage::getParentObject for: '%s' returning: %i\n", parent_path.c_str(), node->Mtpid());
920 return node->Mtpid();
921 }
922 }
923 MTPE("MtpStorage::getParentObject for: '%s' unable to locate node\n", parent_path.c_str());
924 return -1;
925}
926
927void MtpStorage::lockMutex(int thread_type) {
928 if (!use_mutex)
929 return; // mutex is disabled
930 if (thread_type) {
931 // inotify thread
932 pthread_mutex_lock(&inMutex);
933 while (pthread_mutex_trylock(&mtpMutex)) {
934 pthread_mutex_unlock(&inMutex);
935 usleep(32000);
936 pthread_mutex_lock(&inMutex);
937 }
938 } else {
939 // main mtp thread
940 pthread_mutex_lock(&mtpMutex);
941 while (pthread_mutex_trylock(&inMutex)) {
942 pthread_mutex_unlock(&mtpMutex);
943 usleep(13000);
944 pthread_mutex_lock(&mtpMutex);
945 }
946 }
947}
948
949void MtpStorage::unlockMutex(int thread_type) {
950 if (!use_mutex)
951 return; // mutex is disabled
952 pthread_mutex_unlock(&inMutex);
953 pthread_mutex_unlock(&mtpMutex);
954}