Browse Source

Add support for directories in the MTP module

The put_file of the libmtp-based scheme module now supports
sending a file to any (pre-existing) directory on the device,
instead of only the root directory.
develop
Damien Goutte-Gattat 5 years ago
parent
commit
2b946d3e84
  1. 141
      src/scheme-libmtp.c

141
src/scheme-libmtp.c

@ -130,6 +130,106 @@ find_mtp_file(LIBMTP_mtpdevice_t *device,
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;
@ -254,24 +354,37 @@ gfsec_scheme_libmtp_put_file(gfsec_scheme_t scheme,
return GFSEC_SCHEME_STATUS_UNSUPPORTED_SCHEME;
if ( (device = find_mtp_device(authority)) ) {
LIBMTP_file_t *file;
struct getfile_cb_data cb_data;
long folder_id = 0;
unsigned storage = 0;
char *filename, *dirname;
file = LIBMTP_new_file_t();
file->filesize = len;
file->filename = strdup(path);
file->parent_id = 0;
file->storage_id = 0;
filename = split_path(path, &dirname);
if ( dirname ) {
folder_id = find_mtp_directory(device, &storage, dirname);
free(dirname);
}
cb_data.buffer = buffer;
cb_data.written = 0;
cb_data.expected = len;
if ( folder_id != -1 ) {
LIBMTP_file_t *file;
struct getfile_cb_data cb_data;
if ( LIBMTP_Send_File_From_Handler(device, putfile_cb, &cb_data, file,
NULL, NULL) == 0 )
rc = 0;
file = LIBMTP_new_file_t();
file->filesize = len;
file->filename = filename;
file->parent_id = folder_id;
file->storage_id = storage;
LIBMTP_destroy_file_t(file);
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);
}

Loading…
Cancel
Save