/* * 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 . */ #ifdef HAVE_CONFIG_H #include #endif #include "mtp-support.h" #ifndef HAVE_LIBMTP #include unsigned char * gfsec_get_file_from_mtp(const char *authority, const char *path, size_t *len) { (void) authority; (void) path; (void) len; errno = ENOSYS; return NULL; } #else #include #include #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; } 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; } /** * Gets the contents of a file on a MTP device. * * @param[in] authority Serial number of the MTP device. * @param[in] path Path to the file on the MTP device. * @param[out] len Number of bytes read from the device. * * @return A pointer to a newly allocated buffer containing * the file data, or NULL if an error occured. */ unsigned char * gfsec_get_file_from_mtp(const char *authority, const char *path, size_t *len) { LIBMTP_mtpdevice_t *device; struct getfile_cb_data cb_data; unsigned char *blob = NULL; if ( (device = find_mtp_device(authority)) ) { long file_id; if ( (file_id = find_mtp_file(device, 0, path, len)) != -1 ) { if ( (blob = malloc(*len)) ) { cb_data.buffer = blob; 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(blob); blob = NULL; } } } LIBMTP_Release_Device(device); } return blob; } #endif /* HAVE_LIBMTP */