Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/qt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ add_library(bitcoinqt STATIC EXCLUDE_FROM_ALL
clientmodel.h
csvmodelwriter.cpp
csvmodelwriter.h
freespacechecker.cpp
freespacechecker.h
guiutil.cpp
guiutil.h
initexecutor.cpp
Expand Down
58 changes: 58 additions & 0 deletions src/qt/freespacechecker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) 2011-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/freespacechecker.h>

#include <qt/guiutil.h>
#include <util/fs.h>

#include <QDir>
#include <QString>

#include <cstdint>

void FreespaceChecker::check()
{
QString dataDirStr = intro->getPathToCheck();
fs::path dataDir = GUIUtil::QStringToPath(dataDirStr);
uint64_t freeBytesAvailable = 0;
int replyStatus = ST_OK;
QString replyMessage = tr("A new data directory will be created.");

/* Find first parent that exists, so that fs::space does not fail */
fs::path parentDir = dataDir;
fs::path parentDirOld = fs::path();
while(parentDir.has_parent_path() && !fs::exists(parentDir))
{
parentDir = parentDir.parent_path();

/* Check if we make any progress, break if not to prevent an infinite loop here */
if (parentDirOld == parentDir)
break;

parentDirOld = parentDir;
}

try {
freeBytesAvailable = fs::space(parentDir).available;
if(fs::exists(dataDir))
{
if(fs::is_directory(dataDir))
{
QString separator = "<code>" + QDir::toNativeSeparators("/") + tr("name") + "</code>";
replyStatus = ST_OK;
replyMessage = tr("Directory already exists. Add %1 if you intend to create a new directory here.").arg(separator);
} else {
replyStatus = ST_ERROR;
replyMessage = tr("Path already exists, and is not a directory.");
}
}
} catch (const fs::filesystem_error&)
{
/* Parent directory does not exist or is not accessible */
replyStatus = ST_ERROR;
replyMessage = tr("Cannot create data directory here.");
}
Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable);
}
50 changes: 50 additions & 0 deletions src/qt/freespacechecker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) 2011-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_QT_FREESPACECHECKER_H
#define BITCOIN_QT_FREESPACECHECKER_H

#include <QObject>
#include <QString>
#include <QtGlobal>

/* Check free space asynchronously to prevent hanging the UI thread.

Up to one request to check a path is in flight to this thread; when the check()
function runs, the current path is requested from the associated Intro object.
The reply is sent back through a signal.

This ensures that no queue of checking requests is built up while the user is
still entering the path, and that always the most recently entered path is checked as
soon as the thread becomes available.
*/
class FreespaceChecker : public QObject
{
Q_OBJECT

public:
class PathQuery
{
public:
virtual QString getPathToCheck() = 0;
};

explicit FreespaceChecker(PathQuery* intro) : intro{intro} {}

enum Status {
ST_OK,
ST_ERROR
};

public Q_SLOTS:
void check();

Q_SIGNALS:
void reply(int status, const QString &message, quint64 available);

private:
PathQuery* intro;
};

#endif // BITCOIN_QT_FREESPACECHECKER_H
87 changes: 2 additions & 85 deletions src/qt/intro.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2011-2022 The Bitcoin Core developers
// Copyright (c) 2011-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

Expand All @@ -10,6 +10,7 @@
#include <util/chaintype.h>
#include <util/fs.h>

#include <qt/freespacechecker.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
Expand All @@ -25,90 +26,6 @@

#include <cmath>

/* Check free space asynchronously to prevent hanging the UI thread.

Up to one request to check a path is in flight to this thread; when the check()
function runs, the current path is requested from the associated Intro object.
The reply is sent back through a signal.

This ensures that no queue of checking requests is built up while the user is
still entering the path, and that always the most recently entered path is checked as
soon as the thread becomes available.
*/
class FreespaceChecker : public QObject
{
Q_OBJECT

public:
explicit FreespaceChecker(Intro *intro);

enum Status {
ST_OK,
ST_ERROR
};

public Q_SLOTS:
void check();

Q_SIGNALS:
void reply(int status, const QString &message, quint64 available);

private:
Intro *intro;
};

#include <qt/intro.moc>

FreespaceChecker::FreespaceChecker(Intro *_intro)
{
this->intro = _intro;
}

void FreespaceChecker::check()
{
QString dataDirStr = intro->getPathToCheck();
fs::path dataDir = GUIUtil::QStringToPath(dataDirStr);
uint64_t freeBytesAvailable = 0;
int replyStatus = ST_OK;
QString replyMessage = tr("A new data directory will be created.");

/* Find first parent that exists, so that fs::space does not fail */
fs::path parentDir = dataDir;
fs::path parentDirOld = fs::path();
while(parentDir.has_parent_path() && !fs::exists(parentDir))
{
parentDir = parentDir.parent_path();

/* Check if we make any progress, break if not to prevent an infinite loop here */
if (parentDirOld == parentDir)
break;

parentDirOld = parentDir;
}

try {
freeBytesAvailable = fs::space(parentDir).available;
if(fs::exists(dataDir))
{
if(fs::is_directory(dataDir))
{
QString separator = "<code>" + QDir::toNativeSeparators("/") + tr("name") + "</code>";
replyStatus = ST_OK;
replyMessage = tr("Directory already exists. Add %1 if you intend to create a new directory here.").arg(separator);
} else {
replyStatus = ST_ERROR;
replyMessage = tr("Path already exists, and is not a directory.");
}
}
} catch (const fs::filesystem_error&)
{
/* Parent directory does not exist or is not accessible */
replyStatus = ST_ERROR;
replyMessage = tr("Cannot create data directory here.");
}
Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable);
}

namespace {
//! Return pruning size that will be used if automatic pruning is enabled.
int GetPruneTargetGB()
Expand Down
10 changes: 5 additions & 5 deletions src/qt/intro.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// Copyright (c) 2011-2021 The Bitcoin Core developers
// Copyright (c) 2011-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_QT_INTRO_H
#define BITCOIN_QT_INTRO_H

#include <qt/freespacechecker.h>

#include <QDialog>
#include <QMutex>
#include <QThread>

static const bool DEFAULT_CHOOSE_DATADIR = false;

class FreespaceChecker;

namespace interfaces {
class Node;
}
Expand All @@ -25,7 +25,7 @@ namespace Ui {
Allows the user to choose a data directory,
in which the wallet and block chain will be stored.
*/
class Intro : public QDialog
class Intro : public QDialog, public FreespaceChecker::PathQuery
{
Q_OBJECT

Expand Down Expand Up @@ -78,7 +78,7 @@ private Q_SLOTS:

void startThread();
void checkPath(const QString &dataDir);
QString getPathToCheck();
QString getPathToCheck() override;
void UpdatePruneLabels(bool prune_checked);
void UpdateFreeSpaceLabel();

Expand Down
Loading