diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index b0f6709aa..1c5d8fc9e 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -480,13 +480,20 @@ int LocalStore::getSchema() void LocalStore::openDB(State & state, bool create) { + if (create && readOnly) { + throw Error("unable to create database while in read-only mode"); + } + if (access(dbDir.c_str(), R_OK | (readOnly ? 0 : W_OK))) throw SysError("Nix database directory '%1%' is not writable", dbDir); /* Open the Nix database. */ std::string dbPath = dbDir + "/db.sqlite"; auto & db(state.db); - state.db = SQLite(dbPath, create); + auto openMode = readOnly ? SQLiteOpenMode::ReadOnly + : create ? SQLiteOpenMode::Normal + : SQLiteOpenMode::NoCreate; + state.db = SQLite(dbPath, openMode); #ifdef __CYGWIN__ /* The cygwin version of sqlite3 has a patch which calls diff --git a/src/libstore/sqlite.cc b/src/libstore/sqlite.cc index df334c23c..8159744b7 100644 --- a/src/libstore/sqlite.cc +++ b/src/libstore/sqlite.cc @@ -50,14 +50,15 @@ static void traceSQL(void * x, const char * sql) notice("SQL<[%1%]>", sql); }; -SQLite::SQLite(const Path & path, bool create) +SQLite::SQLite(const Path & path, SQLiteOpenMode mode) { // useSQLiteWAL also indicates what virtual file system we need. Using // `unix-dotfile` is needed on NFS file systems and on Windows' Subsystem // for Linux (WSL) where useSQLiteWAL should be false by default. const char *vfs = settings.useSQLiteWAL ? 0 : "unix-dotfile"; - int flags = SQLITE_OPEN_READWRITE; - if (create) flags |= SQLITE_OPEN_CREATE; + int flags = mode == SQLiteOpenMode::ReadOnly + ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE; + if (mode == SQLiteOpenMode::Normal) flags |= SQLITE_OPEN_CREATE; int ret = sqlite3_open_v2(path.c_str(), &db, flags, vfs); if (ret != SQLITE_OK) { const char * err = sqlite3_errstr(ret); diff --git a/src/libstore/sqlite.hh b/src/libstore/sqlite.hh index 8f4bc49a8..33f0eeed8 100644 --- a/src/libstore/sqlite.hh +++ b/src/libstore/sqlite.hh @@ -36,7 +36,7 @@ struct SQLite { sqlite3 * db = 0; SQLite() { } - SQLite(const Path & path, bool create = true); + SQLite(const Path & path, SQLiteOpenMode mode = SQLiteOpenMode::Normal); SQLite(const SQLite & from) = delete; SQLite& operator = (const SQLite & from) = delete; SQLite& operator = (SQLite && from) { db = from.db; from.db = 0; return *this; }