int twrpMtp::start(void) {
	MTPI("Starting MTP\n");
	twmtp_MtpServer *mtp = new twmtp_MtpServer();
	mtp->set_storages(mtpstorages);
	mtp->start();
	return 0;
}
Example #2
0
MtpStorage::MtpStorage(MtpStorageID id, const char* filePath,
		const char* description, uint64_t reserveSpace,
		bool removable, uint64_t maxFileSize, MtpServer* refserver)
	:	mStorageID(id),
		mFilePath(filePath),
		mDescription(description),
		mMaxCapacity(0),
		mMaxFileSize(maxFileSize),
		mReserveSpace(reserveSpace),
		mRemovable(removable),
		mServer(refserver)
{
	MTPI("MtpStorage id: %d path: %s\n", id, filePath);
	inotify_thread = 0;
	inotify_fd = -1;
	// Threading has not started yet so we should be safe to set these directly instead of using atomics
	inotify_thread_kill.set_value(0);
	sendEvents = false;
	handleCurrentlySending = 0;
	use_mutex = true;
	if (pthread_mutex_init(&mtpMutex, NULL) != 0) {
		MTPE("Failed to init mtpMutex\n");
		use_mutex = false;
	}
	if (pthread_mutex_init(&inMutex, NULL) != 0) {
		MTPE("Failed to init inMutex\n");
		pthread_mutex_destroy(&mtpMutex);
		use_mutex = false;
	}
}
int twmtp_MtpServer::mtppipe_thread(void)
{
	if (mtp_read_pipe == -1) {
		MTPD("mtppipe_thread exiting because mtp_read_pipe not set\n");
		return 0;
	}
	MTPD("Starting twmtp_MtpServer::mtppipe_thread\n");
	int read_count;
	struct mtpmsg mtp_message;
	while (1) {
		read_count = ::read(mtp_read_pipe, &mtp_message, sizeof(mtp_message));
		MTPD("read %i from mtppipe\n", read_count);
		if (read_count == sizeof(mtp_message)) {
			if (mtp_message.message_type == MTP_MESSAGE_ADD_STORAGE) {
				MTPI("mtppipe add storage %i '%s'\n", mtp_message.storage_id, mtp_message.path);
				if (mtp_message.storage_id) {
					long reserveSpace = 1;
					bool removable = false;
					MtpStorage* storage = new MtpStorage(mtp_message.storage_id, mtp_message.path, mtp_message.display, reserveSpace, removable, mtp_message.maxFileSize, refserver);
					server->addStorage(storage);
					MTPD("mtppipe done adding storage\n");
				} else {
					MTPE("Invalid storage ID %i specified\n", mtp_message.storage_id);
				}
			} else if (mtp_message.message_type == MTP_MESSAGE_REMOVE_STORAGE) {
				MTPI("mtppipe remove storage %i\n", mtp_message.storage_id);
				remove_storage(mtp_message.storage_id);
				MTPD("mtppipe done removing storage\n");
			} else {
				MTPE("Unknown mtppipe message value: %i\n", mtp_message.message_type);
			}
		} else {
			MTPE("twmtp_MtpServer::mtppipe_thread unexpected read_count %i\n", read_count);
			close(mtp_read_pipe);
			break;
		}
	}
	MTPD("twmtp_MtpServer::mtppipe_thread closing\n");
	return 0;
}
void twmtp_MtpServer::start()
{
	usePtp =  false;
	MyMtpDatabase* mtpdb = new MyMtpDatabase();
	/* Sleep for a bit before we open the MTP USB device because some
	 * devices are not ready due to the kernel not responding to our
	 * sysfs requests right away.
	 */
	usleep(800000);
#ifdef USB_MTP_DEVICE
#define STRINGIFY(x) #x
#define EXPAND(x) STRINGIFY(x)
	const char* mtp_device = EXPAND(USB_MTP_DEVICE);
	MTPI("Using '%s' for MTP device.\n", EXPAND(USB_MTP_DEVICE));
#else
	const char* mtp_device = "/dev/mtp_usb";
#endif
	int fd = open(mtp_device, O_RDWR);
	if (fd < 0) {
		MTPE("could not open MTP driver, errno: %d\n", errno);
		return;
	}
	MTPD("fd: %d\n", fd);
	server = new MtpServer(mtpdb, usePtp, 0, 0664, 0775);
	refserver = server;
	MTPI("created new mtpserver object\n");
	add_storage();
	MTPD("Starting add / remove mtppipe monitor thread\n");
	pthread_t thread;
	ThreadPtr mtpptr = &twmtp_MtpServer::mtppipe_thread;
	PThreadPtr p = *(PThreadPtr*)&mtpptr;
	pthread_create(&thread, NULL, p, this);
	// This loop restarts the MTP process if the device is unplugged and replugged in
	while (true) {
		server->run(fd);
		fd = open(mtp_device, O_RDWR);
		usleep(800000);
	}
}
void MtpObjectInfo::print() {
    MTPI("MtpObject Info %08X: %s\n", mHandle, mName);
    MTPI("  mStorageID: %08X mFormat: %04X mProtectionStatus: %d\n",
         mStorageID, mFormat, mProtectionStatus);
    MTPI("  mCompressedSize: %d mThumbFormat: %04X mThumbCompressedSize: %d\n",
         mCompressedSize, mFormat, mThumbCompressedSize);
    MTPI("  mThumbPixWidth: %d mThumbPixHeight: %d\n", mThumbPixWidth, mThumbPixHeight);
    MTPI("  mImagePixWidth: %d mImagePixHeight: %d mImagePixDepth: %d\n",
         mImagePixWidth, mImagePixHeight, mImagePixDepth);
    MTPI("  mParent: %08X mAssociationType: %04X mAssociationDesc: %04X\n",
         mParent, mAssociationType, mAssociationDesc);
    MTPI("  mSequenceNumber: %d mDateCreated: %ld mDateModified: %ld mKeywords: %s\n",
         mSequenceNumber, mDateCreated, mDateModified, mKeywords);
}
void MtpServer::run() {
	int fd = mFD;

	MTPI("MtpServer::run fd: %d\n", fd);

	while (1) {
		MTPD("About to read device...\n");
		int ret = mRequest.read(fd);
		if (ret < 0) {
			if (errno == ECANCELED) {
				// return to top of loop and wait for next command
				MTPD("request read returned %d ECANCELED, starting over\n", ret);
				continue;
			}
			MTPE("request read returned %d, errno: %d, exiting MtpServer::run loop\n", ret, errno);
			break;
		}
		MtpOperationCode operation = mRequest.getOperationCode();
		MtpTransactionID transaction = mRequest.getTransactionID();

		MTPD("operation: %s", MtpDebug::getOperationCodeName(operation));
		mRequest.dump();

		// FIXME need to generalize this
		bool dataIn = (operation == MTP_OPERATION_SEND_OBJECT_INFO
					|| operation == MTP_OPERATION_SET_OBJECT_REFERENCES
					|| operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
					|| operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
		if (dataIn) {
			int ret = mData.read(fd);
			if (ret < 0) {
				if (errno == ECANCELED) {
					// return to top of loop and wait for next command
					MTPD("data read returned %d ECANCELED, starting over\n", ret);
					continue;
				}
				MTPD("data read returned %d, errno: %d, exiting MtpServer::run loop\n", ret, errno);
				break;
			}
			MTPD("received data:");
			mData.dump();
		} else {
			mData.reset();
		}

		if (handleRequest()) {
			if (!dataIn && mData.hasData()) {
				mData.setOperationCode(operation);
				mData.setTransactionID(transaction);
				MTPD("sending data:");
				mData.dump();
				ret = mData.write(fd);
				if (ret < 0) {
					if (errno == ECANCELED) {
						// return to top of loop and wait for next command
						MTPD("data write returned %d ECANCELED, starting over\n", ret);
						continue;
					}
					MTPE("data write returned %d, errno: %d, exiting MtpServer::run loop\n", ret, errno);
					break;
				}
			}

			mResponse.setTransactionID(transaction);
			MTPD("sending response %04X\n", mResponse.getResponseCode());
			ret = mResponse.write(fd);
			MTPD("ret: %d\n", ret);
			mResponse.dump();
			if (ret < 0) {
				if (errno == ECANCELED) {
					// return to top of loop and wait for next command
					MTPD("response write returned %d ECANCELED, starting over\n", ret);
					continue;
				}
				MTPE("response write returned %d, errno: %d, exiting MtpServer::run loop\n", ret, errno);
				break;
			}
		} else {
			MTPD("skipping response\n");
		}
	}

	// commit any open edits
	int count = mObjectEditList.size();
	for (int i = 0; i < count; i++) {
		ObjectEdit* edit = mObjectEditList[i];
		commitEdit(edit);
		delete edit;
	}
	mObjectEditList.clear();

	if (mSessionOpen)
		mDatabase->sessionEnded();
	close(fd);
	mFD = -1;
}