int MTPDevice::dirRemove(const std::string &path) { const std::string tmp_basename(smtpfs_basename(path)); const std::string tmp_dirname(smtpfs_dirname(path)); const TypeDir *dir_parent = dirFetchContent(tmp_dirname); const TypeDir *dir_to_remove = dir_parent ? dir_parent->dir(tmp_basename) : nullptr; if (!dir_parent || !dir_to_remove || dir_parent->id() == 0) { logerr("No such directory '", path, "' to remove.\n"); return -ENOENT; } if (!dir_to_remove->isEmpty()) return -ENOTEMPTY; criticalEnter(); int rval = LIBMTP_Delete_Object(m_device, dir_to_remove->id()); criticalLeave(); if (rval != 0){ logerr("Could not remove the directory '", path, "'.\n"); LIBMTP_Dump_Errorstack(m_device); LIBMTP_Clear_Errorstack(m_device); return -EINVAL; } const_cast<TypeDir*>(dir_parent)->removeDir(*dir_to_remove); logmsg("Folder '", path, "' removed.\n"); return 0; }
static void prune_empty_folders(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *files, LIBMTP_folder_t *folderlist, int do_delete) { if(folderlist==NULL) return; if(folderlist->child == NULL) { int found = 0; LIBMTP_file_t *file; file = files; while (file != NULL) { if(file->parent_id == folderlist->folder_id) { found = 1; break; } file = file->next; } if(found == 0) { printf("empty folder %u (%s)\n",folderlist->folder_id,folderlist->name); if(do_delete) { if (LIBMTP_Delete_Object(device,folderlist->folder_id) != 0) { printf("Couldn't delete folder %u\n",folderlist->folder_id); LIBMTP_Dump_Errorstack(device); LIBMTP_Clear_Errorstack(device); } } } } prune_empty_folders(device,files,folderlist->child,do_delete); prune_empty_folders(device,files,folderlist->sibling,do_delete); }
/** * Update a playlist on the device. If only the playlist's name is being * changed the pl->playlist_id will likely remain the same. An updated track * list will result in the old playlist being replaced (ie: new playlist_id). * NOTE: Other playlist metadata aside from playlist name and tracks are * ignored. * * @param device mtp device pointer * @param new the LIBMTP_playlist_t to convert (pl->playlist_id will be updated * with the newly created object's id) * @return 0 on success, any other value means failure. */ int update_spl_playlist(LIBMTP_mtpdevice_t *device, LIBMTP_playlist_t * const newlist) { IF_DEBUG() printf("pl->name='%s'\n",newlist->name); // read in the playlist of interest LIBMTP_playlist_t * old = LIBMTP_Get_Playlist(device, newlist->playlist_id); // check to see if we found it if (!old) return -1; // check if the playlists match int delta = 0; int i; if(old->no_tracks != newlist->no_tracks) delta++; for(i=0;i<newlist->no_tracks && delta==0;i++) { if(old->tracks[i] != newlist->tracks[i]) delta++; } // if not, kill the playlist and replace it if(delta) { IF_DEBUG() printf("new tracks detected:\n"); IF_DEBUG() printf("delete old playlist and build a new one\n"); IF_DEBUG() printf(" NOTE: new playlist_id will result!\n"); if(LIBMTP_Delete_Object(device, old->playlist_id) != 0) return -1; IF_DEBUG() { if(strcmp(old->name,newlist->name) == 0) printf("name unchanged\n"); else printf("name is changing too -> %s\n",newlist->name); } return LIBMTP_Create_New_Playlist(device, newlist); } // update the name only if(strcmp(old->name,newlist->name) != 0) { IF_DEBUG() printf("ONLY name is changing -> %s\n",newlist->name); IF_DEBUG() printf("playlist_id will remain unchanged\n"); char* s = malloc(sizeof(char)*(strlen(newlist->name)+5)); strcpy(s, newlist->name); strcat(s,".spl"); // FIXME check for success int ret = LIBMTP_Set_Playlist_Name(device, newlist, s); free(s); return ret; } IF_DEBUG() printf("no change\n"); return 0; // nothing to be done, success }
static void impl_delete (RBSource *source) { RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source); GList *sel; GList *tem; RBEntryView *tracks; RhythmDB *db; int ret; db = get_db_for_source (RB_MTP_SOURCE (source)); tracks = rb_source_get_entry_view (source); sel = rb_entry_view_get_selected_entries (tracks); for (tem = sel; tem != NULL; tem = tem->next) { LIBMTP_track_t *track; RhythmDBEntry *entry; const char *uri; const char *album_name; entry = (RhythmDBEntry *)tem->data; uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION); track = g_hash_table_lookup (priv->entry_map, entry); if (track == NULL) { rb_debug ("Couldn't find track on mtp-device! (%s)", uri); continue; } ret = LIBMTP_Delete_Object (priv->device, track->item_id); if (ret != 0) { rb_debug ("Delete track %d failed", track->item_id); report_libmtp_errors (priv->device, TRUE); continue; } album_name = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM); if (strcmp (album_name, _("Unknown")) != 0) { remove_track_from_album (RB_MTP_SOURCE (source), album_name, track); } g_hash_table_remove (priv->entry_map, entry); rhythmdb_entry_delete (db, entry); } rhythmdb_commit (db); g_list_free (sel); g_list_free (tem); }
int MTPDevice::filePush(const std::string &src, const std::string &dst) { const std::string dst_basename(smtpfs_basename(dst)); const std::string dst_dirname(smtpfs_dirname(dst)); const TypeDir *dir_parent = dirFetchContent(dst_dirname); const TypeFile *file_to_remove = dir_parent ? dir_parent->file(dst_basename) : nullptr; if (dir_parent && file_to_remove) { criticalEnter(); int rval = LIBMTP_Delete_Object(m_device, file_to_remove->id()); criticalLeave(); if (rval != 0) { logerr("Can not upload '", src, "' to '", dst, "'.\n"); return -EINVAL; } } struct stat file_stat; stat(src.c_str(), &file_stat); TypeFile file_to_upload(0, dir_parent->id(), dir_parent->storageid(), dst_basename, static_cast<uint64_t>(file_stat.st_size), 0); LIBMTP_file_t *f = file_to_upload.toLIBMTPFile(); if (file_stat.st_size) logmsg("Started uploading '", dst, "'.\n"); criticalEnter(); int rval = LIBMTP_Send_File_From_File(m_device, src.c_str(), f, nullptr, nullptr); criticalLeave(); if (rval != 0) { logerr("Could not upload file '", src, "'.\n"); LIBMTP_Dump_Errorstack(m_device); LIBMTP_Clear_Errorstack(m_device); rval = -EINVAL; } else { file_to_upload.setId(f->item_id); file_to_upload.setParent(f->parent_id); file_to_upload.setStorage(f->storage_id); file_to_upload.setName(std::string(f->filename)); file_to_upload.setModificationDate(file_stat.st_mtime); if (file_to_remove) const_cast<TypeDir*>(dir_parent)->replaceFile(*file_to_remove, file_to_upload); else const_cast<TypeDir*>(dir_parent)->addFile(file_to_upload); } free(static_cast<void*>(f->filename)); free(static_cast<void*>(f)); logmsg("File '", dst, (file_stat.st_size ? " uploaded" : " created"), ".\n"); return rval; }
bool MtpDevice::DeleteFromStorage(const DeleteJob& job) { // Extract the ID from the song's URL QString filename = job.metadata_.url().path(); filename.remove('/'); bool ok = false; uint32_t id = filename.toUInt(&ok); if (!ok) return false; // Remove the file int ret = LIBMTP_Delete_Object(connection_->device(), id); if (ret != 0) return false; // Remove it from our library model songs_to_remove_ << job.metadata_; return true; }
// Device.delete_object {{{ static PyObject * Device_delete_object(Device *self, PyObject *args) { PyObject *errs; unsigned long id; int res; ENSURE_DEV(NULL); ENSURE_STORAGE(NULL); if (!PyArg_ParseTuple(args, "k", &id)) return NULL; errs = PyList_New(0); if (errs == NULL) { PyErr_NoMemory(); return NULL; } Py_BEGIN_ALLOW_THREADS; res = LIBMTP_Delete_Object(self->device, (uint32_t)id); Py_END_ALLOW_THREADS; if (res != 0) dump_errorstack(self->device, errs); return Py_BuildValue("ON", (res == 0) ? Py_True : Py_False, errs); } // }}}
int MTPDevice::fileRemove(const std::string &path) { const std::string tmp_basename(smtpfs_basename(path)); const std::string tmp_dirname(smtpfs_dirname(path)); const TypeDir *dir_parent = dirFetchContent(tmp_dirname); const TypeFile *file_to_remove = dir_parent ? dir_parent->file(tmp_basename) : nullptr; if (!dir_parent || !file_to_remove) { logerr("No such file '", path, "' to remove.\n"); return -ENOENT; } criticalEnter(); int rval = LIBMTP_Delete_Object(m_device, file_to_remove->id()); criticalLeave(); if (rval != 0) { logerr("Could not remove the directory '", path, "'.\n"); return -EINVAL; } const_cast<TypeDir*>(dir_parent)->removeFile(*file_to_remove); logmsg("File '", path, "' removed.\n"); return 0; }
static void remove_track_from_album (RBMtpSource *source, const char *album_name, LIBMTP_track_t *track) { RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source); LIBMTP_album_t *album; int i; album = g_hash_table_lookup (priv->album_map, album_name); if (album == NULL) { rb_debug ("Couldn't find an album for %s", album_name); return; } for (i = 0; i < album->no_tracks; i++) { if (album->tracks[i] == track->item_id) { break; } } if (i == album->no_tracks) { rb_debug ("Couldn't find track %d in album %d", track->item_id, album->album_id); return; } memmove (album->tracks + i, album->tracks + i + 1, album->no_tracks - (i+1)); album->no_tracks--; if (album->no_tracks == 0) { rb_debug ("deleting empty album %d", album->album_id); if (LIBMTP_Delete_Object (priv->device, album->album_id) != 0) { report_libmtp_errors (priv->device, FALSE); } g_hash_table_remove (priv->album_map, album_name); } else { rb_debug ("updating album %d: %d tracks remaining", album->album_id, album->no_tracks); if (LIBMTP_Update_Album (priv->device, album) != 0) { report_libmtp_errors (priv->device, FALSE); } } }
static void remove_track_from_album (RBMtpThread *thread, RBMtpThreadTask *task) { LIBMTP_album_t *album; int i; album = g_hash_table_lookup (thread->albums, task->album); if (album == NULL) { rb_debug ("Couldn't find an album for %s", task->album); return; } for (i = 0; i < album->no_tracks; i++) { if (album->tracks[i] == task->track_id) { break; } } if (i == album->no_tracks) { rb_debug ("Couldn't find track %d in album %d", task->track_id, album->album_id); return; } memmove (album->tracks + i, album->tracks + i + 1, album->no_tracks - (i+1)); album->no_tracks--; if (album->no_tracks == 0) { rb_debug ("deleting empty album %d", album->album_id); if (LIBMTP_Delete_Object (thread->device, album->album_id) != 0) { rb_mtp_thread_report_errors (thread, FALSE); } g_hash_table_remove (thread->albums, task->album); } else { rb_debug ("updating album %d: %d tracks remaining", album->album_id, album->no_tracks); if (LIBMTP_Update_Album (thread->device, album) != 0) { rb_mtp_thread_report_errors (thread, FALSE); } } }
static void delete_done_cb (LIBMTP_mtpdevice_t *device, TracksDeletedCallbackData *data) { LIBMTP_folder_t *folders; LIBMTP_file_t *files; data->actually_free = FALSE; update_free_space_cb (device, RB_MTP_SOURCE (data->source)); /* if any of the folders we just deleted from are now empty, delete them */ folders = LIBMTP_Get_Folder_List (device); files = LIBMTP_Get_Filelisting_With_Callback (device, NULL, NULL); if (folders != NULL) { GHashTableIter iter; gpointer key; g_hash_table_iter_init (&iter, data->check_folders); while (g_hash_table_iter_next (&iter, &key, NULL)) { LIBMTP_folder_t *f; LIBMTP_folder_t *c; LIBMTP_file_t *file; uint32_t folder_id = GPOINTER_TO_UINT(key); while (folder_id != device->default_music_folder && folder_id != 0) { f = LIBMTP_Find_Folder (folders, folder_id); if (f == NULL) { rb_debug ("unable to find folder %u", folder_id); break; } /* don't delete folders with children that we didn't just delete */ for (c = f->child; c != NULL; c = c->sibling) { if (g_hash_table_lookup (data->check_folders, GUINT_TO_POINTER (c->folder_id)) == NULL) { break; } } if (c != NULL) { rb_debug ("folder %s has children", f->name); break; } /* don't delete folders that contain files */ for (file = files; file != NULL; file = file->next) { if (file->parent_id == folder_id) { break; } } if (file != NULL) { rb_debug ("folder %s contains at least one file: %s", f->name, file->filename); break; } /* ok, the folder is empty */ rb_debug ("deleting empty folder %s", f->name); LIBMTP_Delete_Object (device, f->folder_id); /* if the folder we just deleted has siblings, the parent * can't be empty. */ if (f->sibling != NULL) { rb_debug ("folder %s has siblings, can't delete parent", f->name); break; } folder_id = f->parent_id; } } LIBMTP_destroy_folder_t (folders); } else { rb_debug ("unable to get device folder list"); } /* clean up the file list */ while (files != NULL) { LIBMTP_file_t *n; n = files->next; LIBMTP_destroy_file_t (files); files = n; } g_idle_add ((GSourceFunc) delete_done_idle_cb, data); }
static gboolean run_task (RBMtpThread *thread, RBMtpThreadTask *task) { char *name = task_name (task); rb_debug ("running task: %s", name); g_free (name); switch (task->task) { case OPEN_DEVICE: open_device (thread, task); break; case CLOSE_DEVICE: return TRUE; case SET_DEVICE_NAME: if (LIBMTP_Set_Friendlyname (thread->device, task->name)) { rb_mtp_thread_report_errors (thread, TRUE); } break; case THREAD_CALLBACK: { RBMtpThreadCallback cb = (RBMtpThreadCallback)task->callback; cb (thread->device, task->user_data); } break; case ADD_TO_ALBUM: add_track_to_album_and_update (thread, task); break; case REMOVE_FROM_ALBUM: remove_track_from_album (thread, task); break; case SET_ALBUM_IMAGE: set_album_image (thread, task); break; case GET_TRACK_LIST: get_track_list (thread, task); break; case DELETE_TRACK: if (LIBMTP_Delete_Object (thread->device, task->track_id)) { rb_mtp_thread_report_errors (thread, TRUE); } break; case UPLOAD_TRACK: upload_track (thread, task); break; case DOWNLOAD_TRACK: download_track (thread, task); break; default: g_assert_not_reached (); } return FALSE; }
static void get_track_list (RBMtpThread *thread, RBMtpThreadTask *task) { RBMtpTrackListCallback cb = task->callback; gboolean device_forgets_albums = TRUE; GHashTable *update_albums = NULL; LIBMTP_track_t *tracks = NULL; LIBMTP_album_t *albums; LIBMTP_album_t *album; /* get all the albums */ albums = LIBMTP_Get_Album_List (thread->device); rb_mtp_thread_report_errors (thread, FALSE); if (albums != NULL) { LIBMTP_album_t *album; for (album = albums; album != NULL; album = album->next) { if (album->name == NULL) continue; rb_debug ("album: %s, %d tracks", album->name, album->no_tracks); g_hash_table_insert (thread->albums, album->name, album); if (album->no_tracks != 0) { device_forgets_albums = FALSE; } } if (device_forgets_albums) { rb_debug ("stupid mtp device detected. will rebuild all albums."); } } else { rb_debug ("No albums"); device_forgets_albums = FALSE; } tracks = LIBMTP_Get_Tracklisting_With_Callback (thread->device, NULL, NULL); rb_mtp_thread_report_errors (thread, FALSE); if (tracks == NULL) { rb_debug ("no tracks on the device"); } else if (device_forgets_albums) { LIBMTP_track_t *track; rb_debug ("rebuilding albums"); update_albums = g_hash_table_new (g_direct_hash, g_direct_equal); for (track = tracks; track != NULL; track = track->next) { if (track->album != NULL) { gboolean new_album = FALSE; album = add_track_to_album (thread, track->album, track->item_id, track->storage_id, &new_album); g_hash_table_insert (update_albums, album, GINT_TO_POINTER (new_album)); } } rb_debug ("finished rebuilding albums"); } cb (tracks, task->user_data); /* the callback owns the tracklist */ if (device_forgets_albums) { GHashTableIter iter; gpointer album_ptr; gpointer new_album_ptr; rb_debug ("writing rebuilt albums back to the device"); g_hash_table_iter_init (&iter, update_albums); while (g_hash_table_iter_next (&iter, &album_ptr, &new_album_ptr)) { album = album_ptr; rb_debug ("writing album \"%s\"", album->name); write_album_to_device (thread, album, GPOINTER_TO_INT (new_album_ptr)); } g_hash_table_destroy (update_albums); rb_debug ("removing remaining empty albums"); g_hash_table_iter_init (&iter, thread->albums); while (g_hash_table_iter_next (&iter, NULL, &album_ptr)) { int ret; album = album_ptr; if (album->no_tracks == 0) { rb_debug ("pruning empty album \"%s\"", album->name); ret = LIBMTP_Delete_Object (thread->device, album->album_id); if (ret != 0) { rb_mtp_thread_report_errors (thread, FALSE); } g_hash_table_iter_remove (&iter); } } rb_debug ("finished updating albums on the device"); } }
static gboolean load_mtp_db_idle_cb (RBMtpSource* source) { RhythmDB *db = NULL; RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source); LIBMTP_track_t *tracks = NULL; LIBMTP_album_t *albums; gboolean device_forgets_albums = TRUE; db = get_db_for_source (source); g_assert (db != NULL); albums = LIBMTP_Get_Album_List (priv->device); report_libmtp_errors (priv->device, FALSE); if (albums != NULL) { LIBMTP_album_t *album; for (album = albums; album != NULL; album = album->next) { rb_debug ("album: %s, %d tracks", album->name, album->no_tracks); g_hash_table_insert (priv->album_map, album->name, album); if (album->no_tracks != 0) { device_forgets_albums = FALSE; } } if (device_forgets_albums) { rb_debug ("stupid mtp device detected. will rebuild all albums."); } } else { rb_debug ("No albums"); device_forgets_albums = FALSE; } #ifdef HAVE_LIBMTP_030 tracks = LIBMTP_Get_Tracklisting_With_Callback (priv->device, NULL, NULL); #else tracks = LIBMTP_Get_Tracklisting (priv->device); #endif report_libmtp_errors (priv->device, FALSE); if (tracks != NULL) { LIBMTP_track_t *track; for (track = tracks; track != NULL; track = track->next) { add_mtp_track_to_db (source, db, track); if (device_forgets_albums && track->album != NULL) { add_track_to_album (source, track->album, track); } } } else { rb_debug ("No tracks"); } /* for stupid devices, remove any albums left with no tracks */ if (device_forgets_albums) { GHashTableIter iter; gpointer value; LIBMTP_album_t *album; g_hash_table_iter_init (&iter, priv->album_map); while (g_hash_table_iter_next (&iter, NULL, &value)) { int ret; album = value; if (album->no_tracks == 0) { rb_debug ("pruning empty album \"%s\"", album->name); ret = LIBMTP_Delete_Object (priv->device, album->album_id); if (ret != 0) { report_libmtp_errors (priv->device, FALSE); } g_hash_table_iter_remove (&iter); } } } g_object_unref (G_OBJECT (db)); return FALSE; }