rockbox/rbutil/rbutilqt/base/bootloaderinstallsansa.cpp
Dominik Riebeling 34e60dde60 Handle device name resolving failures.
Improve tracing of device name resolving. Explicitly fail if resolving the
device name from the mountpoint failed during ipod / sansa bootloader
installation. Fixes bootloader installation trying to use an empty device name
in some cases which can happen if the mountpoint to get resolved uses an
incompatible file system.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25743 a1c6a512-1295-4272-9138-f99709370657
2010-04-27 21:43:14 +00:00

294 lines
8.5 KiB
C++

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2008 by Dominik Riebeling
* $Id$
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <QtCore>
#include "bootloaderinstallbase.h"
#include "bootloaderinstallsansa.h"
#include "../sansapatcher/sansapatcher.h"
#include "autodetection.h"
BootloaderInstallSansa::BootloaderInstallSansa(QObject *parent)
: BootloaderInstallBase(parent)
{
(void)parent;
// initialize sector buffer. sansa_sectorbuf is instantiated by
// sansapatcher.
// The buffer itself is only present once, so make sure to not allocate
// it if it was already allocated. The application needs to take care
// no concurrent (i.e. multiple objects of this class running) requests
// are done.
if(sansa_sectorbuf == NULL)
sansa_alloc_buffer(&sansa_sectorbuf, BUFFER_SIZE);
}
BootloaderInstallSansa::~BootloaderInstallSansa()
{
if(sansa_sectorbuf) {
free(sansa_sectorbuf);
sansa_sectorbuf = NULL;
}
}
/** Start bootloader installation.
*/
bool BootloaderInstallSansa::install(void)
{
if(sansa_sectorbuf == NULL) {
emit logItem(tr("Error: can't allocate buffer memory!"), LOGERROR);
return false;
emit done(true);
}
emit logItem(tr("Searching for Sansa"), LOGINFO);
struct sansa_t sansa;
int n = sansa_scan(&sansa);
if(n == -1) {
emit logItem(tr("Permission for disc access denied!\n"
"This is required to install the bootloader"),
LOGERROR);
emit done(true);
return false;
}
if(n == 0) {
emit logItem(tr("No Sansa detected!"), LOGERROR);
emit done(true);
return false;
}
if(sansa.hasoldbootloader) {
emit logItem(tr("OLD ROCKBOX INSTALLATION DETECTED, ABORTING.\n"
"You must reinstall the original Sansa firmware before running\n"
"sansapatcher for the first time.\n"
"See http://www.rockbox.org/wiki/SansaE200Install\n"),
LOGERROR);
emit done(true);
return false;
}
emit logItem(tr("Downloading bootloader file"), LOGINFO);
downloadBlStart(m_blurl);
connect(this, SIGNAL(downloadDone()), this, SLOT(installStage2()));
return true;
}
/** Finish bootloader installation.
*/
void BootloaderInstallSansa::installStage2(void)
{
struct sansa_t sansa;
emit logItem(tr("Installing Rockbox bootloader"), LOGINFO);
QCoreApplication::processEvents();
if(!sansaInitialize(&sansa)) {
emit done(true);
return;
}
if(sansa_reopen_rw(&sansa) < 0) {
emit logItem(tr("Could not open Sansa in R/W mode"), LOGERROR);
emit done(true);
return;
}
// check model -- if sansapatcher reports a c200 don't install an e200
// bootloader and vice versa.
// The model is available in the mi4 file at offset 0x1fc and matches
// the targetname set by sansapatcher.
emit logItem(tr("Checking downloaded bootloader"), LOGINFO);
m_tempfile.open();
QString blfile = m_tempfile.fileName();
char magic[4];
m_tempfile.seek(0x1fc);
m_tempfile.read(magic, 4);
m_tempfile.close();
if(memcmp(sansa.targetname, magic, 4) != 0) {
emit logItem(tr("Bootloader mismatch! Aborting."), LOGERROR);
qDebug("[BootloaderInstallSansa] Targetname: %s, mi4 magic: %c%c%c%c",
sansa.targetname, magic[0], magic[1], magic[2], magic[3]);
emit done(true);
sansa_close(&sansa);
return;
}
if(sansa_add_bootloader(&sansa, blfile.toLatin1().data(),
FILETYPE_MI4) == 0) {
emit logItem(tr("Successfully installed bootloader"), LOGOK);
sansa_close(&sansa);
#if defined(Q_OS_MACX)
m_remountDevice = sansa.diskname;
connect(this, SIGNAL(remounted(bool)), this, SLOT(installStage3(bool)));
waitRemount();
#else
installStage3(true);
#endif
}
else {
emit logItem(tr("Failed to install bootloader"), LOGERROR);
sansa_close(&sansa);
emit done(true);
return;
}
}
void BootloaderInstallSansa::installStage3(bool mounted)
{
if(mounted) {
logInstall(LogAdd);
emit logItem(tr("Bootloader Installation complete."), LOGINFO);
emit done(false);
return;
}
else {
emit logItem(tr("Writing log aborted"), LOGERROR);
emit done(true);
}
qDebug() << "version installed:" << m_blversion.toString(Qt::ISODate);
}
/** Uninstall the bootloader.
*/
bool BootloaderInstallSansa::uninstall(void)
{
struct sansa_t sansa;
emit logItem(tr("Uninstalling bootloader"), LOGINFO);
QCoreApplication::processEvents();
if(!sansaInitialize(&sansa)) {
emit done(true);
return false;
}
if (sansa.hasoldbootloader) {
emit logItem(tr("OLD ROCKBOX INSTALLATION DETECTED, ABORTING.\n"
"You must reinstall the original Sansa firmware before running\n"
"sansapatcher for the first time.\n"
"See http://www.rockbox.org/wiki/SansaE200Install\n"),
LOGERROR);
emit done(true);
return false;
}
if (sansa_reopen_rw(&sansa) < 0) {
emit logItem(tr("Could not open Sansa in R/W mode"), LOGERROR);
emit done(true);
return false;
}
if (sansa_delete_bootloader(&sansa)==0) {
emit logItem(tr("Successfully removed bootloader"), LOGOK);
logInstall(LogRemove);
emit done(false);
sansa_close(&sansa);
return true;
}
else {
emit logItem(tr("Removing bootloader failed."),LOGERROR);
emit done(true);
sansa_close(&sansa);
return false;
}
return false;
}
/** Check if bootloader is already installed
*/
BootloaderInstallBase::BootloaderType BootloaderInstallSansa::installed(void)
{
struct sansa_t sansa;
int num;
if(!sansaInitialize(&sansa)) {
return BootloaderUnknown;
}
if((num = sansa_list_images(&sansa)) == 2) {
sansa_close(&sansa);
return BootloaderRockbox;
}
else if(num == 1) {
sansa_close(&sansa);
return BootloaderOther;
}
return BootloaderUnknown;
}
bool BootloaderInstallSansa::sansaInitialize(struct sansa_t *sansa)
{
if(!m_blfile.isEmpty()) {
QString devicename = Autodetection::resolveDevicename(m_blfile);
if(devicename.isEmpty()) {
emit logItem(tr("Error: could not retrieve device name"), LOGERROR);
return false;
}
#if defined(Q_OS_WIN32)
sprintf(sansa->diskname, "\\\\.\\PhysicalDrive%i", devicename.toInt());
#elif defined(Q_OS_MACX)
sprintf(sansa->diskname,
qPrintable(devicename.remove(QRegExp("s[0-9]+$"))));
#else
sprintf(sansa->diskname,
qPrintable(devicename.remove(QRegExp("[0-9]+$"))));
#endif
qDebug() << "[BootloaderInstallSansa] sansapatcher: overriding scan, using"
<< sansa->diskname;
}
else if(sansa_scan(sansa) != 1) {
emit logItem(tr("Can't find Sansa"), LOGERROR);
return false;
}
if (sansa_open(sansa, 0) < 0) {
emit logItem(tr("Could not open Sansa"), LOGERROR);
return false;
}
if (sansa_read_partinfo(sansa,0) < 0) {
emit logItem(tr("Could not read partition table"), LOGERROR);
sansa_close(sansa);
return false;
}
int i = is_sansa(sansa);
if(i < 0) {
emit logItem(tr("Disk is not a Sansa (Error %1), aborting.").arg(i), LOGERROR);
sansa_close(sansa);
return false;
}
return true;
}
/** Get capabilities of subclass installer.
*/
BootloaderInstallBase::Capabilities BootloaderInstallSansa::capabilities(void)
{
return (Install | Uninstall | IsRaw | CanCheckInstalled);
}