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