|
|
|
/*
|
|
|
|
* gfsec - Secret sharing tools
|
|
|
|
* Copyright (C) 2016 Damien Goutte-Gattat
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "scheme-libmtp.h"
|
|
|
|
#include "scheme-module.h"
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBMTP
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <splitstr.h>
|
|
|
|
#include <libmtp.h>
|
|
|
|
|
|
|
|
#define MTP_ROOT_FOLDER_ID 0xFFFFFFFF
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Finds a connected MTP device with the specified serial number.
|
|
|
|
*
|
|
|
|
* @param[in] wanted_serial The serial number of the device to find.
|
|
|
|
*
|
|
|
|
* @return An object representing the found device (to be freed with
|
|
|
|
* LIBMTP_Release_Device), or NULL if no device was found.
|
|
|
|
*/
|
|
|
|
static LIBMTP_mtpdevice_t *
|
|
|
|
find_mtp_device(const char *wanted_serial)
|
|
|
|
{
|
|
|
|
LIBMTP_raw_device_t *raw_devices;
|
|
|
|
LIBMTP_mtpdevice_t *device;
|
|
|
|
int i, n;
|
|
|
|
|
|
|
|
if ( LIBMTP_Detect_Raw_Devices(&raw_devices, &n) != 0 )
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for ( i = 0, device = NULL; i < n && device == NULL; i++ ) {
|
|
|
|
char *serial;
|
|
|
|
|
|
|
|
device = LIBMTP_Open_Raw_Device_Uncached(&(raw_devices[i]));
|
|
|
|
if ( (serial = LIBMTP_Get_Serialnumber(device)) == NULL ||
|
|
|
|
strcmp(serial, wanted_serial) != 0 ) {
|
|
|
|
LIBMTP_Release_Device(device);
|
|
|
|
device = NULL;
|
|
|
|
if ( serial )
|
|
|
|
free(serial);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(raw_devices);
|
|
|
|
|
|
|
|
return device;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Finds a file on a given MTP device.
|
|
|
|
*
|
|
|
|
* @param[in] device The MTP device.
|
|
|
|
* @param[in] storage Storage identifier (0 to search in all storages).
|
|
|
|
* @param[in] path The path of the file to find.
|
|
|
|
* @param[out] size If not NULL and the file is found, this will be set
|
|
|
|
* to the size of the file.
|
|
|
|
*
|
|
|
|
* @return The MTP identifier for the file if found, or -1 if not found.
|
|
|
|
*/
|
|
|
|
static long
|
|
|
|
find_mtp_file(LIBMTP_mtpdevice_t *device,
|
|
|
|
unsigned storage,
|
|
|
|
const char *path,
|
|
|
|
size_t *size)
|
|
|
|
{
|
|
|
|
char **components;
|
|
|
|
size_t n;
|
|
|
|
unsigned i, file_id;
|
|
|
|
long rc = -1;
|
|
|
|
|
|
|
|
if ( ! (components = splitstr(path, '/', &n)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for ( i = 0, file_id = MTP_ROOT_FOLDER_ID; i < n; i++ ) {
|
|
|
|
LIBMTP_file_t *files, *file;
|
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
files = LIBMTP_Get_Files_And_Folders(device, storage, file_id);
|
|
|
|
file = files;
|
|
|
|
|
|
|
|
while ( file && ! found ) {
|
|
|
|
LIBMTP_file_t *tmp;
|
|
|
|
|
|
|
|
if ( strcmp(file->filename, components[i]) == 0 ) {
|
|
|
|
if ( file->filetype == LIBMTP_FILETYPE_FOLDER && i < n - 1 ) {
|
|
|
|
file_id = file->item_id;
|
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
else if ( file->filetype != LIBMTP_FILETYPE_FOLDER && i == n - 1 ) {
|
|
|
|
rc = file->item_id;
|
|
|
|
found = 1;
|
|
|
|
|
|
|
|
if ( size )
|
|
|
|
*size = file->filesize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = file;
|
|
|
|
file = file->next;
|
|
|
|
LIBMTP_destroy_file_t(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! found )
|
|
|
|
i = n; /* Exit loop. */
|
|
|
|
}
|
|
|
|
|
|
|
|
free(components);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Finds a directory on a MTP device.
|
|
|
|
*
|
|
|
|
* @param[in] device The MTP device.
|
|
|
|
* @param[in,out] storage Storage identifier; may be NULL or point to
|
|
|
|
* a zero value to search in all storages; if
|
|
|
|
* non-NULL, will be set to the storage identifier
|
|
|
|
* of the directory if it is found.
|
|
|
|
* @param[in] path The path of the directory to find.
|
|
|
|
*
|
|
|
|
* @return The MTP identifier of the directory if found, or -1 if not found.
|
|
|
|
*/
|
|
|
|
static long
|
|
|
|
find_mtp_directory(LIBMTP_mtpdevice_t *device,
|
|
|
|
unsigned *storage,
|
|
|
|
const char *path)
|
|
|
|
{
|
|
|
|
char **components;
|
|
|
|
size_t n;
|
|
|
|
unsigned i, file_id;
|
|
|
|
long rc = -1;
|
|
|
|
|
|
|
|
if ( ! (components = splitstr(path, '/', &n)) )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for ( i = 0, file_id = MTP_ROOT_FOLDER_ID; i < n; i++ ) {
|
|
|
|
LIBMTP_file_t *files, *file;
|
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
files = LIBMTP_Get_Files_And_Folders(device, storage ? *storage : 0, file_id);
|
|
|
|
file = files;
|
|
|
|
|
|
|
|
while ( file && ! found ) {
|
|
|
|
LIBMTP_file_t *tmp;
|
|
|
|
|
|
|
|
if ( strcmp(file->filename, components[i]) == 0 &&
|
|
|
|
file->filetype == LIBMTP_FILETYPE_FOLDER ) {
|
|
|
|
file_id = file->item_id;
|
|
|
|
found = 1;
|
|
|
|
|
|
|
|
if ( i == n - 1 ) {
|
|
|
|
/* This was the last component, so we found
|
|
|
|
* what we looked for. */
|
|
|
|
rc = file_id;
|
|
|
|
if ( storage )
|
|
|
|
*storage = file->storage_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = file;
|
|
|
|
file = file->next;
|
|
|
|
LIBMTP_destroy_file_t(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! found )
|
|
|
|
i = n; /* Exit loop. */
|
|
|
|
}
|
|
|
|
|
|
|
|
free(components);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Splits a pathname into a filename and a directory name.
|
|
|
|
*
|
|
|
|
* @param[in] path The pathname to split.
|
|
|
|
* @param[out] dirname If non-NULL, will be set to a newly allocated
|
|
|
|
* string containing the directory name (or NULL
|
|
|
|
* if the pathname did not contain a slash).
|
|
|
|
*
|
|
|
|
* @return A newly allocated string containing the filename part of
|
|
|
|
* the pathname.
|
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
split_path(const char *path, char **dirname)
|
|
|
|
{
|
|
|
|
char *last_slash, *filename;
|
|
|
|
|
|
|
|
if ( (last_slash = strrchr(path, '/')) ) {
|
|
|
|
filename = strdup(last_slash + 1);
|
|
|
|
|
|
|
|
if ( dirname ) {
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = last_slash - path;
|
|
|
|
*dirname = malloc(last_slash - path + 1);
|
|
|
|
strncpy(*dirname, path, len);
|
|
|
|
(*dirname)[len] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
filename = strdup(path);
|
|
|
|
if ( dirname )
|
|
|
|
*dirname = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct getfile_cb_data {
|
|
|
|
unsigned char *buffer;
|
|
|
|
unsigned written;
|
|
|
|
size_t expected;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback for the LIBMTP_Get_File_To_Handler function.
|
|
|
|
*
|
|
|
|
* @param params MTP parameters (unused).
|
|
|
|
* @param priv Pointer to a getfile_cb_data structure.
|
|
|
|
* @param sendlen Number of bytes available.
|
|
|
|
* @param data Actual bytes available.
|
|
|
|
* @param[out] putlen Number of bytes used.
|
|
|
|
*
|
|
|
|
* @return LIBMTP_HANLDER_RETURN_OK if successful, or
|
|
|
|
* LIBMTP_HANDLER_RETURN_ERROR if we get more bytes than we expected.
|
|
|
|
*/
|
|
|
|
static unsigned short
|
|
|
|
getfile_cb(void *params,
|
|
|
|
void *priv,
|
|
|
|
unsigned sendlen,
|
|
|
|
unsigned char *data,
|
|
|
|
unsigned *putlen)
|
|
|
|
{
|
|
|
|
struct getfile_cb_data *cb_data = priv;
|
|
|
|
(void) params;
|
|
|
|
|
|
|
|
if ( cb_data->written + sendlen > cb_data->expected )
|
|
|
|
return LIBMTP_HANDLER_RETURN_ERROR;
|
|
|
|
|
|
|
|
memcpy(cb_data->buffer + cb_data->written, data, sendlen);
|
|
|
|
cb_data->written += sendlen;
|
|
|
|
*putlen = sendlen;
|
|
|
|
|
|
|
|
return LIBMTP_HANDLER_RETURN_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
gfsec_scheme_libmtp_get_file(gfsec_scheme_t scheme,
|
|
|
|
const char *authority,
|
|
|
|
const char *path,
|
|
|
|
unsigned char **buffer,
|
|
|
|
size_t *len)
|
|
|
|
{
|
|
|
|
LIBMTP_mtpdevice_t *device;
|
|
|
|
struct getfile_cb_data cb_data;
|
|
|
|
int rc = GFSEC_SCHEME_STATUS_ERROR;
|
|
|
|
|
|
|
|
if ( scheme != GFSEC_SCHEME_MTP )
|
|
|
|
return GFSEC_SCHEME_STATUS_UNSUPPORTED_SCHEME;
|
|
|
|
|
|
|
|
if ( (device = find_mtp_device(authority)) ) {
|
|
|
|
long file_id;
|
|
|
|
|
|
|
|
if ( (file_id = find_mtp_file(device, 0, path, len)) != -1 ) {
|
|
|
|
if ( (*buffer = malloc(*len)) ) {
|
|
|
|
cb_data.buffer = *buffer;
|
|
|
|
cb_data.written = 0;
|
|
|
|
cb_data.expected = *len;
|
|
|
|
|
|
|
|
if ( LIBMTP_Get_File_To_Handler(device, file_id,
|
|
|
|
getfile_cb, &cb_data, NULL, NULL) != 0 ) {
|
|
|
|
free(*buffer);
|
|
|
|
*buffer = NULL;
|
|
|
|
rc = GFSEC_SCHEME_STATUS_ERROR;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rc = GFSEC_SCHEME_STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LIBMTP_Release_Device(device);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback for the LIBMTP_Send_File_To_Handler function.
|
|
|
|
*
|
|
|
|
* @param params MTP parameters (unused).
|
|
|
|
* @param priv Pointer to a getfile_cb_data structure.
|
|
|
|
* @param wantlen Number of bytes to write.
|
|
|
|
* @param data The buffer to write the bytes to.
|
|
|
|
* @param[out] putlen The number of bytes actually written.
|
|
|
|
*
|
|
|
|
* @return LIBMTP_HANLDER_RETURN_OK if successful, or
|
|
|
|
* LIBMTP_HANDLER_RETURN_ERROR if we get more bytes than we expected.
|
|
|
|
*/
|
|
|
|
static unsigned short
|
|
|
|
putfile_cb(void *params,
|
|
|
|
void *priv,
|
|
|
|
unsigned wantlen,
|
|
|
|
unsigned char *data,
|
|
|
|
unsigned *gotlen)
|
|
|
|
{
|
|
|
|
struct getfile_cb_data *cb_data = priv;
|
|
|
|
(void) params;
|
|
|
|
|
|
|
|
if ( cb_data->written + wantlen > cb_data->expected )
|
|
|
|
return LIBMTP_HANDLER_RETURN_ERROR;
|
|
|
|
|
|
|
|
memcpy(data, cb_data->buffer + cb_data->written, wantlen);
|
|
|
|
cb_data->written += wantlen;
|
|
|
|
*gotlen = wantlen;
|
|
|
|
|
|
|
|
return LIBMTP_HANDLER_RETURN_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
gfsec_scheme_libmtp_put_file(gfsec_scheme_t scheme,
|
|
|
|
const char *authority,
|
|
|
|
const char *path,
|
|
|
|
unsigned char *buffer,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
LIBMTP_mtpdevice_t *device;
|
|
|
|
int rc = GFSEC_SCHEME_STATUS_ERROR;
|
|
|
|
|
|
|
|
if ( scheme != GFSEC_SCHEME_MTP )
|
|
|
|
return GFSEC_SCHEME_STATUS_UNSUPPORTED_SCHEME;
|
|
|
|
|
|
|
|
if ( (device = find_mtp_device(authority)) ) {
|
|
|
|
long folder_id = 0;
|
|
|
|
unsigned storage = 0;
|
|
|
|
char *filename, *dirname;
|
|
|
|
|
|
|
|
filename = split_path(path, &dirname);
|
|
|
|
|
|
|
|
if ( dirname ) {
|
|
|
|
folder_id = find_mtp_directory(device, &storage, dirname);
|
|
|
|
free(dirname);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( folder_id != -1 ) {
|
|
|
|
LIBMTP_file_t *file;
|
|
|
|
struct getfile_cb_data cb_data;
|
|
|
|
|
|
|
|
file = LIBMTP_new_file_t();
|
|
|
|
file->filesize = len;
|
|
|
|
file->filename = filename;
|
|
|
|
file->parent_id = folder_id;
|
|
|
|
file->storage_id = storage;
|
|
|
|
|
|
|
|
cb_data.buffer = buffer;
|
|
|
|
cb_data.written = 0;
|
|
|
|
cb_data.expected = len;
|
|
|
|
|
|
|
|
if ( LIBMTP_Send_File_From_Handler(device, putfile_cb, &cb_data,
|
|
|
|
file, NULL, NULL) == 0 )
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
LIBMTP_destroy_file_t(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
LIBMTP_Release_Device(device);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gfsec_scheme_libmtp_lst_auth(FILE *f)
|
|
|
|
{
|
|
|
|
LIBMTP_raw_device_t *raw_devices;
|
|
|
|
LIBMTP_mtpdevice_t *device;
|
|
|
|
int i, n;
|
|
|
|
|
|
|
|
if ( LIBMTP_Detect_Raw_Devices(&raw_devices, &n) != 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
for ( i = 0, device = NULL; i < n && device == NULL; i++ ) {
|
|
|
|
char *serial, *name;
|
|
|
|
|
|
|
|
device = LIBMTP_Open_Raw_Device_Uncached(&(raw_devices[i]));
|
|
|
|
serial = LIBMTP_Get_Serialnumber(device);
|
|
|
|
name = LIBMTP_Get_Friendlyname(device);
|
|
|
|
|
|
|
|
fprintf(f, "mtp://%s %s\n", serial, name);
|
|
|
|
|
|
|
|
free(serial);
|
|
|
|
free(name);
|
|
|
|
LIBMTP_Release_Device(device);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* HAVE_LIBMTP */
|