Test whether we can still talk to afc before freeing the lockdownd client (fixes usbmuxd errors once and for all), report afc copy errors, keep track of files that failed to copy to a device, don't attempt to write the itunesdb if there were errors during copying.

This commit is contained in:
David Sansome 2010-08-10 19:42:43 +00:00
parent 9d2a4783ff
commit b27238a480
14 changed files with 100 additions and 78 deletions

View File

@ -76,7 +76,7 @@ void DeleteFiles::ProcessSomeFiles() {
if (progress_ >= songs_.count()) {
task_manager_->SetTaskProgress(task_id_, progress_, songs_.count());
storage_->FinishCopy();
storage_->FinishCopy(songs_with_errors_.isEmpty());
task_manager_->SetTaskFinished(task_id_);
@ -96,7 +96,11 @@ void DeleteFiles::ProcessSomeFiles() {
for ( ; progress_<n ; ++progress_) {
task_manager_->SetTaskProgress(task_id_, progress_, songs_.count());
storage_->DeleteFromStorage(songs_.at(progress_));
const Song& song = songs_[progress_];
if (!storage_->DeleteFromStorage(song)) {
songs_with_errors_ << song;
}
}
QTimer::singleShot(0, this, SLOT(ProcessSomeFiles()));

View File

@ -53,6 +53,8 @@ private:
int task_id_;
int progress_;
SongList songs_with_errors_;
};
#endif // DELETEFILES_H

View File

@ -40,11 +40,11 @@ public:
virtual bool CopyToStorage(const QString& source, const QString& destination,
const Song& metadata, bool overwrite,
bool remove_original) = 0;
virtual void FinishCopy() {}
virtual void FinishCopy(bool success) {}
virtual void StartDelete() {}
virtual bool DeleteFromStorage(const Song& metadata) = 0;
virtual void FinishDelete() {}
virtual void FinishDelete(bool success) {}
virtual void Eject() {}
};

View File

@ -68,7 +68,7 @@ void Organise::ProcessSomeFiles() {
if (progress_ >= files_.count()) {
task_manager_->SetTaskProgress(task_id_, progress_, files_.count());
destination_->FinishCopy();
destination_->FinishCopy(files_with_errors_.isEmpty());
if (eject_after_)
destination_->Eject();
@ -110,8 +110,10 @@ void Organise::ProcessSomeFiles() {
if (!song.is_valid())
continue;
destination_->CopyToStorage(filename, format_.GetFilenameForSong(song),
song, overwrite_, !copy_);
if (!destination_->CopyToStorage(filename, format_.GetFilenameForSong(song),
song, overwrite_, !copy_)) {
files_with_errors_ << filename;
}
}
QTimer::singleShot(0, this, SLOT(ProcessSomeFiles()));

View File

@ -58,6 +58,8 @@ private:
int task_id_;
int progress_;
QStringList files_with_errors_;
};
#endif // ORGANISE_H

View File

@ -18,6 +18,7 @@
#include <QCoreApplication>
#include <QDir>
#include <QIODevice>
#include <QStringList>
#include <QTemporaryFile>
@ -135,4 +136,44 @@ void RemoveRecursive(const QString& path) {
dir.rmdir(path);
}
bool Copy(QIODevice* source, QIODevice* destination) {
if (!source->open(QIODevice::ReadOnly))
return false;
if (!destination->open(QIODevice::WriteOnly))
return false;
const qint64 bytes = source->size();
char* data = new char[bytes];
qint64 pos = 0;
forever {
const qint64 bytes_read = source->read(data + pos, bytes - pos);
if (bytes_read == -1) {
delete[] data;
return false;
}
pos += bytes_read;
if (bytes_read == 0 || pos == bytes)
break;
}
pos = 0;
forever {
const qint64 bytes_written = destination->write(data + pos, bytes - pos);
if (bytes_written == -1) {
delete[] data;
return false;
}
pos += bytes_written;
if (bytes_written == 0 || pos == bytes)
break;
}
delete[] data;
return true;
}
} // namespace

View File

@ -19,6 +19,8 @@
#include <QString>
class QIODevice;
namespace Utilities {
QString PrettyTime(int seconds);
QString PrettySize(quint64 bytes);
@ -29,6 +31,7 @@ namespace Utilities {
QString MakeTempDir();
void RemoveRecursive(const QString& path);
bool Copy(QIODevice* source, QIODevice* destination);
}
#endif // UTILITIES_H

View File

@ -94,9 +94,8 @@ bool AfcDevice::CopyToStorage(
{
QFile source_file(source);
AfcFile dest_file(&connection, dest);
source_file.open(QIODevice::ReadOnly);
dest_file.open(QIODevice::WriteOnly);
dest_file.write(source_file.readAll());
if (!Utilities::Copy(&source_file, &dest_file))
return false;
}
track->transferred = 1;
@ -111,12 +110,10 @@ bool AfcDevice::CopyToStorage(
else
track->filetype_marker |= suffix[i].toAscii();
}
qDebug() << track->filetype_marker;
// Set the filename
track->ipod_path = strdup(dest.toUtf8().constData());
itdb_filename_fs2ipod(track->ipod_path);
qDebug() << track->ipod_path;
AddTrackToModel(track, "afc://" + url_.host());
@ -128,11 +125,11 @@ bool AfcDevice::CopyToStorage(
return true;
}
void AfcDevice::FinishCopy() {
void AfcDevice::FinishCopy(bool success) {
// Temporarily unset the GUID so libgpod doesn't lock the device for syncing
itdb_device_set_sysinfo(db_->device, "FirewireGuid", NULL);
GPodDevice::FinishCopy();
GPodDevice::FinishCopy(success);
}
void AfcDevice::FinaliseDatabase() {

View File

@ -42,7 +42,7 @@ public:
bool CopyToStorage(const QString &source, const QString &destination,
const Song &metadata, bool overwrite, bool remove_original);
void FinishCopy();
void FinishCopy(bool success);
bool DeleteFromStorage(const Song &metadata);

View File

@ -18,6 +18,7 @@
#include "afctransfer.h"
#include "imobiledeviceconnection.h"
#include "core/taskmanager.h"
#include "core/utilities.h"
#include <QDir>
#include <QtDebug>
@ -117,52 +118,12 @@ bool AfcTransfer::CopyFileFromDevice(iMobileDeviceConnection *c, const QString &
QFile dest(local_filename);
AfcFile source(c, path);
return Copy(&source, &dest);
return Utilities::Copy(&source, &dest);
}
bool AfcTransfer::CopyFileToDevice(iMobileDeviceConnection *c, const QString &path) {
QFile source(local_destination_ + path);
AfcFile dest(c, path);
return Copy(&source, &dest);
}
bool AfcTransfer::Copy(QIODevice* source, QIODevice* destination) {
if (!source->open(QIODevice::ReadOnly))
return false;
if (!destination->open(QIODevice::WriteOnly))
return false;
const qint64 bytes = source->size();
char* data = new char[bytes];
qint64 pos = 0;
forever {
const qint64 bytes_read = source->read(data + pos, bytes - pos);
if (bytes_read == -1) {
delete[] data;
return false;
}
pos += bytes_read;
if (bytes_read == 0 || pos == bytes)
break;
}
pos = 0;
forever {
const qint64 bytes_written = destination->write(data + pos, bytes - pos);
if (bytes_written == -1) {
delete[] data;
return false;
}
pos += bytes_written;
if (bytes_written == 0 || pos == bytes)
break;
}
delete[] data;
return true;
return Utilities::Copy(&source, &dest);
}

View File

@ -51,8 +51,6 @@ private:
bool CopyFileFromDevice(iMobileDeviceConnection* c, const QString& path);
bool CopyFileToDevice(iMobileDeviceConnection* c, const QString& path);
static bool Copy(QIODevice* source, QIODevice* destination);
private:
boost::shared_ptr<ConnectedDevice> device_;
QThread* original_thread_;

View File

@ -129,22 +129,24 @@ bool GPodDevice::CopyToStorage(
return true;
}
void GPodDevice::FinishCopy() {
// Write the itunes database
GError* error = NULL;
itdb_write(db_, &error);
if (error) {
qDebug() << "GPodDevice error:" << error->message;
emit Error(QString::fromUtf8(error->message));
g_error_free(error);
} else {
FinaliseDatabase();
void GPodDevice::FinishCopy(bool success) {
if (success) {
// Write the itunes database
GError* error = NULL;
itdb_write(db_, &error);
if (error) {
qDebug() << "GPodDevice error:" << error->message;
emit Error(QString::fromUtf8(error->message));
g_error_free(error);
} else {
FinaliseDatabase();
// Update the library model
if (!songs_to_add_.isEmpty())
backend_->AddOrUpdateSongs(songs_to_add_);
if (!songs_to_remove_.isEmpty())
backend_->DeleteSongs(songs_to_remove_);
// Update the library model
if (!songs_to_add_.isEmpty())
backend_->AddOrUpdateSongs(songs_to_add_);
if (!songs_to_remove_.isEmpty())
backend_->DeleteSongs(songs_to_remove_);
}
}
songs_to_add_.clear();
@ -197,7 +199,7 @@ bool GPodDevice::DeleteFromStorage(const Song& metadata) {
return true;
}
void GPodDevice::FinishDelete() {
FinishCopy();
void GPodDevice::FinishDelete(bool success) {
FinishCopy(success);
}

View File

@ -44,11 +44,11 @@ public:
void StartCopy();
bool CopyToStorage(const QString &source, const QString &destination,
const Song &metadata, bool overwrite, bool remove_original);
void FinishCopy();
void FinishCopy(bool success);
void StartDelete();
bool DeleteFromStorage(const Song& metadata);
void FinishDelete();
void FinishDelete(bool success);
protected slots:
void LoadFinished(Itdb_iTunesDB* db);

View File

@ -52,8 +52,18 @@ iMobileDeviceConnection::iMobileDeviceConnection(const QString& uuid)
iMobileDeviceConnection::~iMobileDeviceConnection() {
if (afc_) {
// Do a test to see if we can still talk to the device. If not, it's
// probably not safe to free the lockdownd client.
char* model = NULL;
afc_error_t err = afc_get_device_info_key(afc_, "Model", &model);
free(model);
if (err != AFC_E_SUCCESS)
broken_ = true;
afc_client_free(afc_);
}
if (lockdown_ && !broken_) {
lockdownd_client_free(lockdown_);
}