mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-24 11:11:02 -07:00
Replace the upgradefluxfile builtin with a seperate upgrade-flux-file tool.
This allows us to remove all the SQL stuff from the main program, and restores the ability to upgrade from version 2 SQL files.
This commit is contained in:
@@ -7,7 +7,7 @@ AllowAllArgumentsOnNextLine: 'true'
|
||||
AllowAllConstructorInitializersOnNextLine: 'false'
|
||||
AllowAllParametersOfDeclarationOnNextLine: 'true'
|
||||
AllowShortBlocksOnASingleLine: 'true'
|
||||
AllowShortCaseLabelsOnASingleLine: 'true'
|
||||
AllowShortCaseLabelsOnASingleLine: 'false'
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: None
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "globals.h"
|
||||
#include "sql.h"
|
||||
#include "fluxmap.h"
|
||||
#include "decoders/fluxmapreader.h"
|
||||
#include "decoders/decoders.h"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "fluxmap.h"
|
||||
#include "sql.h"
|
||||
#include "bytes.h"
|
||||
#include "protocol.h"
|
||||
#include "fluxsink/fluxsink.h"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "fluxmap.h"
|
||||
#include "sql.h"
|
||||
#include "bytes.h"
|
||||
#include "protocol.h"
|
||||
#include "fluxsink/fluxsink.h"
|
||||
@@ -18,8 +17,13 @@ class Fl2FluxSink : public FluxSink
|
||||
{
|
||||
public:
|
||||
Fl2FluxSink(const Fl2FluxSinkProto& lconfig):
|
||||
_config(lconfig),
|
||||
_of(lconfig.filename(), std::ios::out | std::ios::binary)
|
||||
Fl2FluxSink(lconfig.filename())
|
||||
{
|
||||
}
|
||||
|
||||
Fl2FluxSink(const std::string& filename):
|
||||
_filename(filename),
|
||||
_of(_filename, std::ios::out | std::ios::binary)
|
||||
{
|
||||
if (!_of.is_open())
|
||||
Error() << "cannot open output file";
|
||||
@@ -53,11 +57,11 @@ public:
|
||||
|
||||
operator std::string () const
|
||||
{
|
||||
return fmt::format("fl2({})", _config.filename());
|
||||
return fmt::format("fl2({})", _filename);
|
||||
}
|
||||
|
||||
private:
|
||||
const Fl2FluxSinkProto& _config;
|
||||
std::string _filename;
|
||||
std::ofstream _of;
|
||||
std::map<std::pair<unsigned, unsigned>, Bytes> _data;
|
||||
};
|
||||
@@ -67,4 +71,9 @@ std::unique_ptr<FluxSink> FluxSink::createFl2FluxSink(const Fl2FluxSinkProto& co
|
||||
return std::unique_ptr<FluxSink>(new Fl2FluxSink(config));
|
||||
}
|
||||
|
||||
std::unique_ptr<FluxSink> FluxSink::createFl2FluxSink(const std::string& filename)
|
||||
{
|
||||
return std::unique_ptr<FluxSink>(new Fl2FluxSink(filename));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,9 +11,6 @@ std::unique_ptr<FluxSink> FluxSink::create(const FluxSinkProto& config)
|
||||
{
|
||||
switch (config.dest_case())
|
||||
{
|
||||
case FluxSinkProto::kFluxfile:
|
||||
return createSqliteFluxSink(config.fluxfile());
|
||||
|
||||
case FluxSinkProto::kDrive:
|
||||
return createHardwareFluxSink(config.drive());
|
||||
|
||||
|
||||
@@ -17,13 +17,14 @@ class FluxSink
|
||||
public:
|
||||
virtual ~FluxSink() {}
|
||||
|
||||
static std::unique_ptr<FluxSink> createSqliteFluxSink(const std::string& filename);
|
||||
static std::unique_ptr<FluxSink> createHardwareFluxSink(const HardwareFluxSinkProto& config);
|
||||
static std::unique_ptr<FluxSink> createAuFluxSink(const AuFluxSinkProto& config);
|
||||
static std::unique_ptr<FluxSink> createVcdFluxSink(const VcdFluxSinkProto& config);
|
||||
static std::unique_ptr<FluxSink> createScpFluxSink(const ScpFluxSinkProto& config);
|
||||
static std::unique_ptr<FluxSink> createFl2FluxSink(const Fl2FluxSinkProto& config);
|
||||
|
||||
static std::unique_ptr<FluxSink> createFl2FluxSink(const std::string& filename);
|
||||
|
||||
static std::unique_ptr<FluxSink> create(const FluxSinkProto& config);
|
||||
static void updateConfigForFilename(FluxSinkProto* proto, const std::string& filename);
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ message Fl2FluxSinkProto {
|
||||
message FluxSinkProto {
|
||||
optional double rescale = 7 [ default = 1.0, (help) = "amount to multiply pulse periods by" ];
|
||||
oneof dest {
|
||||
string fluxfile = 1 [(help) = "name of destination flux file"];
|
||||
HardwareFluxSinkProto drive = 2;
|
||||
AuFluxSinkProto au = 3;
|
||||
VcdFluxSinkProto vcd = 4;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "fluxmap.h"
|
||||
#include "sql.h"
|
||||
#include "bytes.h"
|
||||
#include "protocol.h"
|
||||
#include "fluxsink/fluxsink.h"
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
#include "globals.h"
|
||||
#include "fluxmap.h"
|
||||
#include "sql.h"
|
||||
#include "fluxsink/fluxsink.h"
|
||||
#include "flags.h"
|
||||
#include "fmt/format.h"
|
||||
#include <unistd.h>
|
||||
|
||||
class SqliteFluxSink : public FluxSink
|
||||
{
|
||||
public:
|
||||
SqliteFluxSink(const std::string& filename):
|
||||
_filename(filename)
|
||||
{
|
||||
if ((access(filename.c_str(), F_OK) == 0) && (remove(filename.c_str()) != 0))
|
||||
Error() << fmt::format("failed to overwrite flux file");
|
||||
_outdb = sqlOpen(filename, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
|
||||
|
||||
int oldVersion = sqlReadIntProperty(_outdb, "version");
|
||||
if ((oldVersion != 0) && (oldVersion != FLUX_VERSION_CURRENT))
|
||||
Error() << fmt::format("that flux file is version {}, but this client is for version {}",
|
||||
oldVersion, FLUX_VERSION_CURRENT);
|
||||
|
||||
sqlPrepareFlux(_outdb);
|
||||
sqlStmt(_outdb, "BEGIN;");
|
||||
sqlWriteIntProperty(_outdb, "version", FLUX_VERSION_CURRENT);
|
||||
}
|
||||
|
||||
~SqliteFluxSink()
|
||||
{
|
||||
if (_outdb)
|
||||
{
|
||||
sqlStmt(_outdb, "COMMIT;");
|
||||
sqlClose(_outdb);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void writeFlux(int track, int side, Fluxmap& fluxmap)
|
||||
{
|
||||
return sqlWriteFlux(_outdb, track, side, fluxmap);
|
||||
}
|
||||
|
||||
|
||||
operator std::string () const
|
||||
{
|
||||
return fmt::format("fluxfile {}", _filename);
|
||||
}
|
||||
|
||||
private:
|
||||
sqlite3* _outdb;
|
||||
std::string _filename;
|
||||
};
|
||||
|
||||
std::unique_ptr<FluxSink> FluxSink::createSqliteFluxSink(const std::string& filename)
|
||||
{
|
||||
return std::unique_ptr<FluxSink>(new SqliteFluxSink(filename));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "fluxmap.h"
|
||||
#include "sql.h"
|
||||
#include "bytes.h"
|
||||
#include "protocol.h"
|
||||
#include "fluxsink/fluxsink.h"
|
||||
|
||||
@@ -53,10 +53,8 @@ std::unique_ptr<FluxSource> FluxSource::createFl2FluxSource(const Fl2FluxSourceP
|
||||
char buffer[16];
|
||||
std::ifstream(config.filename(), std::ios::in | std::ios::binary).read(buffer, 16);
|
||||
if (strncmp(buffer, "SQLite format 3", 16) == 0)
|
||||
{
|
||||
std::cerr << "Warning: reading a deprecated flux file format; please upgrade it\n";
|
||||
return FluxSource::createSqliteFluxSource(config.filename());
|
||||
}
|
||||
Error() << "this flux file is too old; please use the upgrade-flux-file to upgrade it";
|
||||
|
||||
return std::unique_ptr<FluxSource>(new Fl2FluxSource(config));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,6 @@ std::unique_ptr<FluxSource> FluxSource::create(const FluxSourceProto& config)
|
||||
{
|
||||
switch (config.source_case())
|
||||
{
|
||||
case FluxSourceProto::kFluxfile:
|
||||
return createSqliteFluxSource(config.fluxfile());
|
||||
|
||||
case FluxSourceProto::kDrive:
|
||||
return createHardwareFluxSource(config.drive());
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ private:
|
||||
static std::unique_ptr<FluxSource> createHardwareFluxSource(const HardwareFluxSourceProto& config);
|
||||
static std::unique_ptr<FluxSource> createKryofluxFluxSource(const KryofluxFluxSourceProto& config);
|
||||
static std::unique_ptr<FluxSource> createScpFluxSource(const ScpFluxSourceProto& config);
|
||||
static std::unique_ptr<FluxSource> createSqliteFluxSource(const std::string& filename);
|
||||
static std::unique_ptr<FluxSource> createTestPatternFluxSource(const TestPatternFluxSourceProto& config);
|
||||
|
||||
public:
|
||||
|
||||
@@ -41,7 +41,6 @@ message Fl2FluxSourceProto {
|
||||
message FluxSourceProto {
|
||||
optional double rescale = 9 [ default = 1.0, (help) = "amount to divide pulse periods by" ];
|
||||
oneof source {
|
||||
string fluxfile = 1 [default = "name of source flux file"];
|
||||
HardwareFluxSourceProto drive = 2;
|
||||
TestPatternFluxSourceProto test_pattern = 3;
|
||||
EraseFluxSourceProto erase = 4;
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
#include "globals.h"
|
||||
#include "fluxmap.h"
|
||||
#include "sql.h"
|
||||
#include "fluxsource/fluxsource.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
class SqliteFluxSource : public FluxSource
|
||||
{
|
||||
public:
|
||||
SqliteFluxSource(const std::string& filename)
|
||||
{
|
||||
_indb = sqlOpen(filename, SQLITE_OPEN_READONLY);
|
||||
int version = sqlGetVersion(_indb);
|
||||
if (version != FLUX_VERSION_CURRENT)
|
||||
Error() << fmt::format("that flux file is version {}, but this client is for version {}",
|
||||
version, FLUX_VERSION_CURRENT);
|
||||
}
|
||||
|
||||
~SqliteFluxSource()
|
||||
{
|
||||
if (_indb)
|
||||
sqlClose(_indb);
|
||||
}
|
||||
|
||||
public:
|
||||
std::unique_ptr<Fluxmap> readFlux(int track, int side)
|
||||
{
|
||||
return sqlReadFlux(_indb, track, side);
|
||||
}
|
||||
|
||||
void recalibrate() {}
|
||||
|
||||
private:
|
||||
sqlite3* _indb;
|
||||
};
|
||||
|
||||
std::unique_ptr<FluxSource> FluxSource::createSqliteFluxSource(const std::string& filename)
|
||||
{
|
||||
return std::unique_ptr<FluxSource>(new SqliteFluxSource(filename));
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "fluxsink/fluxsink.h"
|
||||
#include "reader.h"
|
||||
#include "fluxmap.h"
|
||||
#include "sql.h"
|
||||
#include "decoders/decoders.h"
|
||||
#include "sector.h"
|
||||
#include "bytes.h"
|
||||
|
||||
272
lib/sql.cc
272
lib/sql.cc
@@ -1,272 +0,0 @@
|
||||
#include "globals.h"
|
||||
#include "sql.h"
|
||||
#include "fluxmap.h"
|
||||
#include "bytes.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
enum
|
||||
{
|
||||
COMPRESSION_NONE,
|
||||
COMPRESSION_ZLIB
|
||||
};
|
||||
|
||||
static bool hasProperties(sqlite3* db);
|
||||
|
||||
void sqlCheck(sqlite3* db, int i)
|
||||
{
|
||||
if (i != SQLITE_OK)
|
||||
Error() << "database error: " << sqlite3_errmsg(db);
|
||||
}
|
||||
|
||||
sqlite3* sqlOpen(const std::string filename, int flags)
|
||||
{
|
||||
sqlite3* db;
|
||||
int i = sqlite3_open_v2(filename.c_str(), &db, flags, NULL);
|
||||
if (i != SQLITE_OK)
|
||||
Error() << "failed: " << sqlite3_errstr(i);
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
void sqlClose(sqlite3* db)
|
||||
{
|
||||
sqlite3_close(db);
|
||||
}
|
||||
|
||||
void sqlStmt(sqlite3* db, const char* sql)
|
||||
{
|
||||
char* errmsg;
|
||||
int i = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
|
||||
if (i != SQLITE_OK)
|
||||
Error() << "database error: %s" << errmsg;
|
||||
}
|
||||
|
||||
int sqlGetVersion(sqlite3* db)
|
||||
{
|
||||
return sqlReadIntProperty(db, "version");
|
||||
}
|
||||
|
||||
bool hasProperties(sqlite3* db)
|
||||
{
|
||||
sqlite3_stmt* stmt;
|
||||
sqlCheck(db, sqlite3_prepare_v2(db,
|
||||
"SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='properties'",
|
||||
-1, &stmt, NULL));
|
||||
|
||||
int i = sqlite3_step(stmt);
|
||||
if (i != SQLITE_ROW)
|
||||
Error() << "Error accessing sqlite metadata";
|
||||
bool has_properties = sqlite3_column_int(stmt, 0) != 0;
|
||||
sqlCheck(db, sqlite3_finalize(stmt));
|
||||
|
||||
return has_properties;
|
||||
}
|
||||
|
||||
void sql_bind_blob(sqlite3* db, sqlite3_stmt* stmt, const char* name,
|
||||
const void* ptr, size_t bytes)
|
||||
{
|
||||
sqlCheck(db, sqlite3_bind_blob(stmt,
|
||||
sqlite3_bind_parameter_index(stmt, name),
|
||||
ptr, bytes, SQLITE_TRANSIENT));
|
||||
}
|
||||
|
||||
void sql_bind_int(sqlite3* db, sqlite3_stmt* stmt, const char* name, int value)
|
||||
{
|
||||
sqlCheck(db, sqlite3_bind_int(stmt,
|
||||
sqlite3_bind_parameter_index(stmt, name),
|
||||
value));
|
||||
}
|
||||
|
||||
void sql_bind_string(sqlite3* db, sqlite3_stmt* stmt, const char* name, const char* value)
|
||||
{
|
||||
sqlCheck(db, sqlite3_bind_text(stmt,
|
||||
sqlite3_bind_parameter_index(stmt, name),
|
||||
value, -1, SQLITE_TRANSIENT));
|
||||
}
|
||||
|
||||
void sqlPrepareFlux(sqlite3* db)
|
||||
{
|
||||
sqlStmt(db, "PRAGMA synchronous = OFF;");
|
||||
sqlStmt(db, "PRAGMA auto_vacuum = FULL;");
|
||||
sqlStmt(db, "BEGIN;");
|
||||
sqlStmt(db, "CREATE TABLE IF NOT EXISTS properties ("
|
||||
" key TEXT UNIQUE NOT NULL PRIMARY KEY,"
|
||||
" value TEXT"
|
||||
");");
|
||||
sqlStmt(db, "CREATE TABLE IF NOT EXISTS zdata ("
|
||||
" track INTEGER,"
|
||||
" side INTEGER,"
|
||||
" data BLOB,"
|
||||
" compression INTEGER,"
|
||||
" PRIMARY KEY(track, side)"
|
||||
");");
|
||||
sqlStmt(db, "COMMIT;");
|
||||
}
|
||||
|
||||
void sqlWriteFlux(sqlite3* db, int track, int side, const Fluxmap& fluxmap)
|
||||
{
|
||||
const auto compressed = fluxmap.rawBytes().compress();
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
sqlCheck(db, sqlite3_prepare_v2(db,
|
||||
"INSERT OR REPLACE INTO zdata (track, side, data, compression)"
|
||||
" VALUES (:track, :side, :data, :compression)",
|
||||
-1, &stmt, NULL));
|
||||
sql_bind_int(db, stmt, ":track", track);
|
||||
sql_bind_int(db, stmt, ":side", side);
|
||||
sql_bind_blob(db, stmt, ":data", &compressed[0], compressed.size());
|
||||
sql_bind_int(db, stmt, ":compression", COMPRESSION_ZLIB);
|
||||
|
||||
if (sqlite3_step(stmt) != SQLITE_DONE)
|
||||
Error() << "failed to write to database: " << sqlite3_errmsg(db);
|
||||
sqlCheck(db, sqlite3_finalize(stmt));
|
||||
}
|
||||
|
||||
std::unique_ptr<Fluxmap> sqlReadFlux(sqlite3* db, int track, int side)
|
||||
{
|
||||
sqlite3_stmt* stmt;
|
||||
sqlCheck(db, sqlite3_prepare_v2(db,
|
||||
"SELECT data, compression FROM zdata WHERE track=:track AND side=:side",
|
||||
-1, &stmt, NULL));
|
||||
sql_bind_int(db, stmt, ":track", track);
|
||||
sql_bind_int(db, stmt, ":side", side);
|
||||
|
||||
auto fluxmap = std::unique_ptr<Fluxmap>(new Fluxmap());
|
||||
|
||||
int i = sqlite3_step(stmt);
|
||||
if (i != SQLITE_DONE)
|
||||
{
|
||||
if (i != SQLITE_ROW)
|
||||
Error() << "failed to read from database: " << sqlite3_errmsg(db);
|
||||
|
||||
const uint8_t* blobptr = (const uint8_t*) sqlite3_column_blob(stmt, 0);
|
||||
size_t bloblen = sqlite3_column_bytes(stmt, 0);
|
||||
int compression = sqlite3_column_int(stmt, 1);
|
||||
Bytes data(blobptr, bloblen);
|
||||
|
||||
switch (compression)
|
||||
{
|
||||
case COMPRESSION_NONE:
|
||||
break;
|
||||
|
||||
case COMPRESSION_ZLIB:
|
||||
data = data.decompress();
|
||||
break;
|
||||
|
||||
default:
|
||||
Error() << fmt::format("unsupported compression type {}", compression);
|
||||
}
|
||||
|
||||
fluxmap->appendBytes(data);
|
||||
}
|
||||
sqlCheck(db, sqlite3_finalize(stmt));
|
||||
return fluxmap;
|
||||
}
|
||||
|
||||
std::vector<std::pair<unsigned, unsigned>> sqlFindFlux(sqlite3* db)
|
||||
{
|
||||
std::vector<std::pair<unsigned, unsigned>> output;
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
sqlCheck(db, sqlite3_prepare_v2(db,
|
||||
"SELECT track, side FROM zdata",
|
||||
-1, &stmt, NULL));
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int i = sqlite3_step(stmt);
|
||||
if (i == SQLITE_DONE)
|
||||
break;
|
||||
if (i != SQLITE_ROW)
|
||||
Error() << "failed to read from database: " << sqlite3_errmsg(db);
|
||||
|
||||
unsigned track = sqlite3_column_int(stmt, 0);
|
||||
unsigned side = sqlite3_column_int(stmt, 1);
|
||||
output.push_back(std::make_pair(track, side));
|
||||
}
|
||||
sqlCheck(db, sqlite3_finalize(stmt));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void sqlWriteStringProperty(sqlite3* db, const std::string& name, const std::string& value)
|
||||
{
|
||||
if (!hasProperties(db))
|
||||
sqlPrepareFlux(db);
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
sqlCheck(db, sqlite3_prepare_v2(db,
|
||||
"INSERT OR REPLACE INTO properties (key, value) VALUES (:key, :value)",
|
||||
-1, &stmt, NULL));
|
||||
sql_bind_string(db, stmt, ":key", name.c_str());
|
||||
sql_bind_string(db, stmt, ":value", value.c_str());
|
||||
|
||||
if (sqlite3_step(stmt) != SQLITE_DONE)
|
||||
Error() << "failed to write to database: " << sqlite3_errmsg(db);
|
||||
sqlCheck(db, sqlite3_finalize(stmt));
|
||||
}
|
||||
|
||||
std::string sqlReadStringProperty(sqlite3* db, const std::string& name)
|
||||
{
|
||||
if (!hasProperties(db))
|
||||
return "";
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
sqlCheck(db, sqlite3_prepare_v2(db,
|
||||
"SELECT value FROM properties WHERE key=:key",
|
||||
-1, &stmt, NULL));
|
||||
sql_bind_string(db, stmt, ":key", name.c_str());
|
||||
|
||||
int i = sqlite3_step(stmt);
|
||||
std::string result;
|
||||
if (i != SQLITE_DONE)
|
||||
{
|
||||
if (i != SQLITE_ROW)
|
||||
Error() << "failed to read from database: " << sqlite3_errmsg(db);
|
||||
|
||||
result = (const char*) sqlite3_column_text(stmt, 0);
|
||||
}
|
||||
sqlCheck(db, sqlite3_finalize(stmt));
|
||||
return result;
|
||||
}
|
||||
|
||||
void sqlWriteIntProperty(sqlite3* db, const std::string& name, long value)
|
||||
{
|
||||
if (!hasProperties(db))
|
||||
sqlPrepareFlux(db);
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
sqlCheck(db, sqlite3_prepare_v2(db,
|
||||
"INSERT OR REPLACE INTO properties (key, value) VALUES (:key, :value)",
|
||||
-1, &stmt, NULL));
|
||||
sql_bind_string(db, stmt, ":key", name.c_str());
|
||||
sql_bind_int(db, stmt, ":value", value);
|
||||
|
||||
if (sqlite3_step(stmt) != SQLITE_DONE)
|
||||
Error() << "failed to write to database: " << sqlite3_errmsg(db);
|
||||
sqlCheck(db, sqlite3_finalize(stmt));
|
||||
}
|
||||
|
||||
long sqlReadIntProperty(sqlite3* db, const std::string& name)
|
||||
{
|
||||
if (!hasProperties(db))
|
||||
return 0;
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
sqlCheck(db, sqlite3_prepare_v2(db,
|
||||
"SELECT value FROM properties WHERE key=:key",
|
||||
-1, &stmt, NULL));
|
||||
sql_bind_string(db, stmt, ":key", name.c_str());
|
||||
|
||||
int i = sqlite3_step(stmt);
|
||||
long result = 0;
|
||||
if (i != SQLITE_DONE)
|
||||
{
|
||||
if (i != SQLITE_ROW)
|
||||
Error() << "failed to read from database: " << sqlite3_errmsg(db);
|
||||
|
||||
result = sqlite3_column_int(stmt, 0);
|
||||
}
|
||||
sqlCheck(db, sqlite3_finalize(stmt));
|
||||
return result;
|
||||
}
|
||||
35
lib/sql.h
35
lib/sql.h
@@ -1,35 +0,0 @@
|
||||
#ifndef SQL_H
|
||||
#define SQL_H
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
class Fluxmap;
|
||||
|
||||
enum
|
||||
{
|
||||
FLUX_VERSION_0, /* without properties table */
|
||||
FLUX_VERSION_1,
|
||||
FLUX_VERSION_2, /* new bytecode with index marks */
|
||||
FLUX_VERSION_3, /* simplified bytecode with six-bit timer */
|
||||
|
||||
FLUX_VERSION_CURRENT = FLUX_VERSION_3,
|
||||
};
|
||||
|
||||
extern void sqlCheck(sqlite3* db, int i);
|
||||
extern sqlite3* sqlOpen(const std::string filename, int flags);
|
||||
extern void sqlClose(sqlite3* db);
|
||||
extern void sqlStmt(sqlite3* db, const char* sql);
|
||||
extern int sqlGetVersion(sqlite3* db);
|
||||
|
||||
extern void sqlPrepareFlux(sqlite3* db);
|
||||
extern void sqlWriteFlux(sqlite3* db, int track, int side, const Fluxmap& fluxmap);
|
||||
extern std::unique_ptr<Fluxmap> sqlReadFlux(sqlite3* db, int track, int side);
|
||||
extern std::vector<std::pair<unsigned, unsigned>> sqlFindFlux(sqlite3* db);
|
||||
|
||||
extern void sqlWriteStringProperty(sqlite3* db, const std::string& name, const std::string& value);
|
||||
extern std::string sqlReadStringProperty(sqlite3* db, const std::string& name);
|
||||
|
||||
extern void sqlWriteIntProperty(sqlite3* db, const std::string& name, long value);
|
||||
extern long sqlReadIntProperty(sqlite3* db, const std::string& name);
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "flags.h"
|
||||
#include "fluxmap.h"
|
||||
#include "writer.h"
|
||||
#include "sql.h"
|
||||
#include "protocol.h"
|
||||
#include "usb/usb.h"
|
||||
#include "encoders/encoders.h"
|
||||
@@ -16,8 +15,6 @@
|
||||
#include "lib/config.pb.h"
|
||||
#include "proto.h"
|
||||
|
||||
static sqlite3* outdb;
|
||||
|
||||
void writeTracks(
|
||||
FluxSink& fluxSink,
|
||||
const std::function<std::unique_ptr<Fluxmap>(int track, int side)> producer)
|
||||
|
||||
12
mkninja.sh
12
mkninja.sh
@@ -438,7 +438,6 @@ buildlibrary libbackend.a \
|
||||
lib/fluxsink/fluxsink.cc \
|
||||
lib/fluxsink/hardwarefluxsink.cc \
|
||||
lib/fluxsink/scpfluxsink.cc \
|
||||
lib/fluxsink/sqlitefluxsink.cc \
|
||||
lib/fluxsink/vcdfluxsink.cc \
|
||||
lib/fluxsource/cwffluxsource.cc \
|
||||
lib/fluxsource/erasefluxsource.cc \
|
||||
@@ -448,7 +447,6 @@ buildlibrary libbackend.a \
|
||||
lib/fluxsource/kryoflux.cc \
|
||||
lib/fluxsource/kryofluxfluxsource.cc \
|
||||
lib/fluxsource/scpfluxsource.cc \
|
||||
lib/fluxsource/sqlitefluxsource.cc \
|
||||
lib/fluxsource/testpatternfluxsource.cc \
|
||||
lib/globals.cc \
|
||||
lib/hexdump.cc \
|
||||
@@ -477,7 +475,6 @@ buildlibrary libbackend.a \
|
||||
lib/proto.cc \
|
||||
lib/reader.cc \
|
||||
lib/sector.cc \
|
||||
lib/sql.cc \
|
||||
lib/usb/fluxengineusb.cc \
|
||||
lib/usb/greaseweazle.cc \
|
||||
lib/usb/greaseweazleusb.cc \
|
||||
@@ -559,7 +556,6 @@ buildlibrary libfrontend.a \
|
||||
src/fe-seek.cc \
|
||||
src/fe-testbandwidth.cc \
|
||||
src/fe-testvoltages.cc \
|
||||
src/fe-upgradefluxfile.cc \
|
||||
src/fe-write.cc \
|
||||
src/fluxengine.cc \
|
||||
|
||||
@@ -590,6 +586,14 @@ buildsimpleprogram brother240tool \
|
||||
libemu.a \
|
||||
libfmt.a \
|
||||
|
||||
buildsimpleprogram upgrade-flux-file \
|
||||
-Idep/emu \
|
||||
tools/upgrade-flux-file.cc \
|
||||
libbackend.a \
|
||||
libfl2.a \
|
||||
libemu.a \
|
||||
libfmt.a \
|
||||
|
||||
buildproto libtestproto.a \
|
||||
-d $OBJDIR/proto/lib/common.pb.h \
|
||||
tests/testproto.proto \
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
#include "globals.h"
|
||||
#include "flags.h"
|
||||
#include "sql.h"
|
||||
#include "fluxmap.h"
|
||||
#include "writer.h"
|
||||
#include "proto.h"
|
||||
#include "lib/fluxsource/fluxsource.h"
|
||||
#include "lib/fluxsink/fluxsink.h"
|
||||
#include "lib/fluxsource/fluxsource.pb.h"
|
||||
#include "lib/fluxsink/fluxsink.pb.h"
|
||||
#include "fmt/format.h"
|
||||
#include <fstream>
|
||||
|
||||
int mainUpgradeFluxFile(int argc, const char* argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
Error() << "syntax: fluxengine upgradefluxfile <fluxfile>";
|
||||
std::string filename = argv[1];
|
||||
std::string newfilename = filename + ".new";
|
||||
|
||||
setRange(config.mutable_cylinders(), "0-79");
|
||||
setRange(config.mutable_heads(), "0-1");
|
||||
|
||||
FluxSourceProto fluxSourceProto;
|
||||
fluxSourceProto.mutable_fl2()->set_filename(filename);
|
||||
|
||||
FluxSinkProto fluxSinkProto;
|
||||
fluxSinkProto.mutable_fl2()->set_filename(newfilename);
|
||||
|
||||
auto fluxSource = FluxSource::create(fluxSourceProto);
|
||||
auto fluxSink = FluxSink::create(fluxSinkProto);
|
||||
writeRawDiskCommand(*fluxSource, *fluxSink);
|
||||
|
||||
rename(newfilename.c_str(), filename.c_str());
|
||||
return 0;
|
||||
}
|
||||
@@ -14,7 +14,6 @@ extern command_cb mainRpm;
|
||||
extern command_cb mainSeek;
|
||||
extern command_cb mainTestBandwidth;
|
||||
extern command_cb mainTestVoltages;
|
||||
extern command_cb mainUpgradeFluxFile;
|
||||
extern command_cb mainWrite;
|
||||
|
||||
struct Command
|
||||
@@ -38,7 +37,6 @@ static std::vector<Command> commands =
|
||||
{ "rpm", mainRpm, "Measures the disk rotational speed.", },
|
||||
{ "seek", mainSeek, "Moves the disk head.", },
|
||||
{ "test", mainTest, "Various testing commands.", },
|
||||
{ "upgradefluxfile", mainUpgradeFluxFile, "Upgrades a flux file from a previous version of this software.", },
|
||||
};
|
||||
|
||||
static std::vector<Command> analysables =
|
||||
|
||||
307
tools/upgrade-flux-file.cc
Normal file
307
tools/upgrade-flux-file.cc
Normal file
@@ -0,0 +1,307 @@
|
||||
#include "globals.h"
|
||||
#include "fluxmap.h"
|
||||
#include "fluxsink/fluxsink.h"
|
||||
#include "bytes.h"
|
||||
#include "fmt/format.h"
|
||||
#include <string.h>
|
||||
#include <fstream>
|
||||
#include <sqlite3.h>
|
||||
|
||||
/* --- SQL library ------------------------------------------------------- */
|
||||
|
||||
enum
|
||||
{
|
||||
FLUX_VERSION_0, /* without properties table */
|
||||
FLUX_VERSION_1,
|
||||
FLUX_VERSION_2, /* new bytecode with index marks */
|
||||
FLUX_VERSION_3, /* simplified bytecode with six-bit timer */
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
COMPRESSION_NONE,
|
||||
COMPRESSION_ZLIB
|
||||
};
|
||||
|
||||
static bool hasProperties(sqlite3* db);
|
||||
|
||||
void sqlCheck(sqlite3* db, int i)
|
||||
{
|
||||
if (i != SQLITE_OK)
|
||||
Error() << "database error: " << sqlite3_errmsg(db);
|
||||
}
|
||||
|
||||
sqlite3* sqlOpen(const std::string filename, int flags)
|
||||
{
|
||||
sqlite3* db;
|
||||
int i = sqlite3_open_v2(filename.c_str(), &db, flags, NULL);
|
||||
if (i != SQLITE_OK)
|
||||
Error() << "failed: " << sqlite3_errstr(i);
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
void sqlClose(sqlite3* db)
|
||||
{
|
||||
sqlite3_close(db);
|
||||
}
|
||||
|
||||
void sqlStmt(sqlite3* db, const char* sql)
|
||||
{
|
||||
char* errmsg;
|
||||
int i = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
|
||||
if (i != SQLITE_OK)
|
||||
Error() << "database error: %s" << errmsg;
|
||||
}
|
||||
|
||||
bool hasProperties(sqlite3* db)
|
||||
{
|
||||
sqlite3_stmt* stmt;
|
||||
sqlCheck(db,
|
||||
sqlite3_prepare_v2(db,
|
||||
"SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND "
|
||||
"name='properties'",
|
||||
-1,
|
||||
&stmt,
|
||||
NULL));
|
||||
|
||||
int i = sqlite3_step(stmt);
|
||||
if (i != SQLITE_ROW)
|
||||
Error() << "Error accessing sqlite metadata";
|
||||
bool has_properties = sqlite3_column_int(stmt, 0) != 0;
|
||||
sqlCheck(db, sqlite3_finalize(stmt));
|
||||
|
||||
return has_properties;
|
||||
}
|
||||
|
||||
void sql_bind_blob(sqlite3* db,
|
||||
sqlite3_stmt* stmt,
|
||||
const char* name,
|
||||
const void* ptr,
|
||||
size_t bytes)
|
||||
{
|
||||
sqlCheck(db,
|
||||
sqlite3_bind_blob(stmt,
|
||||
sqlite3_bind_parameter_index(stmt, name),
|
||||
ptr,
|
||||
bytes,
|
||||
SQLITE_TRANSIENT));
|
||||
}
|
||||
|
||||
void sql_bind_int(sqlite3* db, sqlite3_stmt* stmt, const char* name, int value)
|
||||
{
|
||||
sqlCheck(db,
|
||||
sqlite3_bind_int(
|
||||
stmt, sqlite3_bind_parameter_index(stmt, name), value));
|
||||
}
|
||||
|
||||
void sql_bind_string(
|
||||
sqlite3* db, sqlite3_stmt* stmt, const char* name, const char* value)
|
||||
{
|
||||
sqlCheck(db,
|
||||
sqlite3_bind_text(stmt,
|
||||
sqlite3_bind_parameter_index(stmt, name),
|
||||
value,
|
||||
-1,
|
||||
SQLITE_TRANSIENT));
|
||||
}
|
||||
|
||||
std::vector<std::pair<unsigned, unsigned>> sqlFindFlux(sqlite3* db)
|
||||
{
|
||||
std::vector<std::pair<unsigned, unsigned>> output;
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
sqlCheck(db,
|
||||
sqlite3_prepare_v2(
|
||||
db, "SELECT track, side FROM zdata", -1, &stmt, NULL));
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int i = sqlite3_step(stmt);
|
||||
if (i == SQLITE_DONE)
|
||||
break;
|
||||
if (i != SQLITE_ROW)
|
||||
Error() << "failed to read from database: " << sqlite3_errmsg(db);
|
||||
|
||||
unsigned track = sqlite3_column_int(stmt, 0);
|
||||
unsigned side = sqlite3_column_int(stmt, 1);
|
||||
output.push_back(std::make_pair(track, side));
|
||||
}
|
||||
sqlCheck(db, sqlite3_finalize(stmt));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
long sqlReadIntProperty(sqlite3* db, const std::string& name)
|
||||
{
|
||||
if (!hasProperties(db))
|
||||
return 0;
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
sqlCheck(db,
|
||||
sqlite3_prepare_v2(db,
|
||||
"SELECT value FROM properties WHERE key=:key",
|
||||
-1,
|
||||
&stmt,
|
||||
NULL));
|
||||
sql_bind_string(db, stmt, ":key", name.c_str());
|
||||
|
||||
int i = sqlite3_step(stmt);
|
||||
long result = 0;
|
||||
if (i != SQLITE_DONE)
|
||||
{
|
||||
if (i != SQLITE_ROW)
|
||||
Error() << "failed to read from database: " << sqlite3_errmsg(db);
|
||||
|
||||
result = sqlite3_column_int(stmt, 0);
|
||||
}
|
||||
sqlCheck(db, sqlite3_finalize(stmt));
|
||||
return result;
|
||||
}
|
||||
|
||||
int sqlGetVersion(sqlite3* db)
|
||||
{
|
||||
return sqlReadIntProperty(db, "version");
|
||||
}
|
||||
|
||||
/* --- Actual program ---------------------------------------------------- */
|
||||
|
||||
static void syntax()
|
||||
{
|
||||
std::cerr
|
||||
<< "syntax: upgrade-flux-file <filename>\n"
|
||||
<< "This tool upgrades the flux file in-place to the current format.\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static Bytes sqlReadFluxBytes(sqlite3* db, int track, int side)
|
||||
{
|
||||
sqlite3_stmt* stmt;
|
||||
sqlCheck(db,
|
||||
sqlite3_prepare_v2(db,
|
||||
"SELECT data, compression FROM zdata WHERE track=:track AND "
|
||||
"side=:side",
|
||||
-1,
|
||||
&stmt,
|
||||
NULL));
|
||||
sql_bind_int(db, stmt, ":track", track);
|
||||
sql_bind_int(db, stmt, ":side", side);
|
||||
|
||||
Bytes data;
|
||||
int i = sqlite3_step(stmt);
|
||||
if (i != SQLITE_DONE)
|
||||
{
|
||||
if (i != SQLITE_ROW)
|
||||
Error() << "failed to read from database: " << sqlite3_errmsg(db);
|
||||
|
||||
const uint8_t* blobptr = (const uint8_t*)sqlite3_column_blob(stmt, 0);
|
||||
size_t bloblen = sqlite3_column_bytes(stmt, 0);
|
||||
int compression = sqlite3_column_int(stmt, 1);
|
||||
data = Bytes(blobptr, bloblen);
|
||||
|
||||
switch (compression)
|
||||
{
|
||||
case COMPRESSION_NONE:
|
||||
break;
|
||||
|
||||
case COMPRESSION_ZLIB:
|
||||
data = data.decompress();
|
||||
break;
|
||||
|
||||
default:
|
||||
Error() << fmt::format(
|
||||
"unsupported compression type {}", compression);
|
||||
}
|
||||
}
|
||||
sqlCheck(db, sqlite3_finalize(stmt));
|
||||
return data;
|
||||
}
|
||||
|
||||
static bool isSqlite(const std::string& filename)
|
||||
{
|
||||
char buffer[16];
|
||||
std::ifstream(filename, std::ios::in | std::ios::binary).read(buffer, 16);
|
||||
if (strncmp(buffer, "SQLite format 3", 16) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void translateFluxVersion2(Fluxmap& fluxmap, const Bytes& bytes)
|
||||
{
|
||||
unsigned pending = 0;
|
||||
for (uint8_t b : bytes)
|
||||
{
|
||||
switch (b)
|
||||
{
|
||||
case 0x80: /* pulse */
|
||||
fluxmap.appendInterval(pending);
|
||||
fluxmap.appendPulse();
|
||||
pending = 0;
|
||||
break;
|
||||
|
||||
case 0x81: /* index */
|
||||
fluxmap.appendInterval(pending);
|
||||
fluxmap.appendIndex();
|
||||
pending = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
pending += b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fluxmap.appendInterval(pending);
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if ((argc != 2) || (strcmp(argv[1], "--help") == 0))
|
||||
syntax();
|
||||
|
||||
std::string filename = argv[1];
|
||||
if (!isSqlite(filename))
|
||||
{
|
||||
std::cout << "File is up to date.\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
std::string outFilename = filename + ".out.flux";
|
||||
auto db = sqlOpen(filename, SQLITE_OPEN_READONLY);
|
||||
int version = sqlGetVersion(db);
|
||||
|
||||
{
|
||||
auto fluxsink = FluxSink::createFl2FluxSink(outFilename);
|
||||
for (const auto& locations : sqlFindFlux(db))
|
||||
{
|
||||
unsigned cylinder = locations.first;
|
||||
unsigned head = locations.second;
|
||||
Bytes bytes = sqlReadFluxBytes(db, cylinder, head);
|
||||
Fluxmap fluxmap;
|
||||
switch (version)
|
||||
{
|
||||
case FLUX_VERSION_2:
|
||||
translateFluxVersion2(fluxmap, bytes);
|
||||
break;
|
||||
|
||||
case FLUX_VERSION_3:
|
||||
fluxmap.appendBytes(bytes);
|
||||
break;
|
||||
|
||||
default:
|
||||
Error() << fmt::format(
|
||||
"you cannot upgrade version {} files (please file a "
|
||||
"bug)",
|
||||
version);
|
||||
}
|
||||
fluxsink->writeFlux(cylinder, head, fluxmap);
|
||||
std::cout << '.' << std::flush;
|
||||
}
|
||||
|
||||
std::cout << "Writing output file...\n";
|
||||
}
|
||||
|
||||
if (rename(outFilename.c_str(), filename.c_str()) != 0)
|
||||
Error() << fmt::format(
|
||||
"couldn't replace input file: {}", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user