Exemple #1
0
int
pkgdb_repo_check_version(struct pkgdb *db, const char *database)
{
    int reposcver;
    int repomajor;
    int ret;

    assert(db != NULL);
    assert(database != NULL);

    if ((ret = get_repo_user_version(db->sqlite, database, &reposcver))
            != EPKG_OK)
        return (ret);	/* sqlite error */

    /*
     * If the local pkgng uses a repo schema behind that used to
     * create the repo, we may still be able use it for reading
     * (ie pkg install), but pkg repo can't do an incremental
     * update unless the actual schema matches the compiled in
     * schema version.
     *
     * Use a major - minor version schema: as the user_version
     * PRAGMA takes an integer version, encode this as MAJOR *
     * 1000 + MINOR.
     *
     * So long as the major versions are the same, the local pkgng
     * should be compatible with any repo created by a more recent
     * pkgng, although it may need some modification of the repo
     * schema
     */

    /* --- Temporary ---- Grandfather in the old repo schema
       version so this patch doesn't immediately invalidate all
       the repos out there */

    if (reposcver == 2)
        reposcver = 2000;
    if (reposcver == 3)
        reposcver = 2001;

    repomajor = reposcver / 1000;

    if (repomajor < REPO_SCHEMA_MAJOR) {
        pkg_emit_error("Repo %s (schema version %d) is too old - "
                       "need at least schema %d", database, reposcver,
                       REPO_SCHEMA_MAJOR * 1000);
        return (EPKG_REPOSCHEMA);
    }

    if (repomajor > REPO_SCHEMA_MAJOR) {
        pkg_emit_error("Repo %s (schema version %d) is too new - "
                       "we can accept at most schema %d", database, reposcver,
                       ((REPO_SCHEMA_MAJOR + 1) * 1000) - 1);
        return (EPKG_REPOSCHEMA);
    }

    /* This is a repo schema version we can work with */

    ret = EPKG_OK;

    if (reposcver < REPO_SCHEMA_VERSION) {
        if (sqlite3_db_readonly(db->sqlite, database)) {
            pkg_emit_error("Repo %s needs schema upgrade from "
                           "%d to %d but it is opened readonly", database,
                           reposcver, REPO_SCHEMA_VERSION
                          );
            ret = EPKG_FATAL;
        } else
            ret = upgrade_repo_schema(db, database, reposcver);
    } else if (reposcver > REPO_SCHEMA_VERSION) {
        if (sqlite3_db_readonly(db->sqlite, database)) {
            pkg_emit_error("Repo %s needs schema downgrade from "
                           "%d to %d but it is opened readonly", database,
                           reposcver, REPO_SCHEMA_VERSION
                          );
            ret = EPKG_FATAL;
        } else
            ret = downgrade_repo_schema(db, database, reposcver);
    }

    return (ret);
}
Exemple #2
0
bool Handle::isReadonly()
{
    return sqlite3_db_readonly((sqlite3 *) m_handle, NULL) == 1;
}
static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
        jstring labelStr, jboolean enableTrace, jboolean enableProfile) {
    int sqliteFlags;
    if (openFlags & SQLiteConnection::CREATE_IF_NECESSARY) {
        sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
    } else if (openFlags & SQLiteConnection::OPEN_READONLY) {
        sqliteFlags = SQLITE_OPEN_READONLY;
    } else {
        sqliteFlags = SQLITE_OPEN_READWRITE;
    }

    const char* pathChars = env->GetStringUTFChars(pathStr, NULL);
    String8 path(pathChars);
    env->ReleaseStringUTFChars(pathStr, pathChars);

    const char* labelChars = env->GetStringUTFChars(labelStr, NULL);
    String8 label(labelChars);
    env->ReleaseStringUTFChars(labelStr, labelChars);

    sqlite3* db;
    int err = sqlite3_open_v2(path.string(), &db, sqliteFlags, NULL);
    if (err != SQLITE_OK) {
        throw_sqlite3_exception_errcode(env, err, "Could not open database");
        return 0;
    }

    // Check that the database is really read/write when that is what we asked for.
    if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) {
        throw_sqlite3_exception(env, db, "Could not open the database in read/write mode.");
        sqlite3_close(db);
        return 0;
    }

    // Set the default busy handler to retry automatically before returning SQLITE_BUSY.
    err = sqlite3_busy_timeout(db, BUSY_TIMEOUT_MS);
    if (err != SQLITE_OK) {
        throw_sqlite3_exception(env, db, "Could not set busy timeout");
        sqlite3_close(db);
        return 0;
    }

    // Register custom Android functions.
    err = register_android_functions(db, UTF16_STORAGE);
    if (err) {
        throw_sqlite3_exception(env, db, "Could not register Android SQL functions.");
        sqlite3_close(db);
        return 0;
    }

    // Create wrapper object.
    SQLiteConnection* connection = new SQLiteConnection(db, openFlags, path, label);

    // Enable tracing and profiling if requested.
    if (enableTrace) {
        sqlite3_trace(db, &sqliteTraceCallback, connection);
    }
    if (enableProfile) {
        sqlite3_profile(db, &sqliteProfileCallback, connection);
    }

    ALOGV("Opened connection %p with label '%s'", db, label.string());
    return reinterpret_cast<jlong>(connection);
}
  /* public native void dbopen(String path, int flags, String locale); */
  void dbopen(JNIEnv* env, jobject object, jstring pathString, jint flags)
  {
    int err;
    sqlite3 * handle = NULL;
    sqlite3_stmt * statement = NULL;
    char const * path8 = env->GetStringUTFChars(pathString, NULL);
    int sqliteFlags;

    // register the logging func on sqlite. needs to be done BEFORE any sqlite3 func is called.
    registerLoggingFunc(path8);

    // convert our flags into the sqlite flags
    if (flags & CREATE_IF_NECESSARY) {
      sqliteFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
    } else if (flags & OPEN_READONLY) {
      sqliteFlags = SQLITE_OPEN_READONLY;
    } else {
      sqliteFlags = SQLITE_OPEN_READWRITE;
    }

    err = sqlite3_open_v2(path8, &handle, sqliteFlags, NULL);
    if (err != SQLITE_OK) {
      LOGE("sqlite3_open_v2(\"%s\", &handle, %d, NULL) failed\n", path8, sqliteFlags);
      throw_sqlite3_exception_errcode(env, err, "Could not open database");
      goto done;
    }

    // Check that the database is really read/write when that is what we asked for.
    if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(handle, NULL)) {
      throw_sqlite3_exception(env, handle, "Could not open the database in read/write mode.");
      goto done;
    }

    // The soft heap limit prevents the page cache allocations from growing
    // beyond the given limit, no matter what the max page cache sizes are
    // set to. The limit does not, as of 3.5.0, affect any other allocations.
    sqlite3_soft_heap_limit(SQLITE_SOFT_HEAP_LIMIT);

    // Set the default busy handler to retry for 1000ms and then return SQLITE_BUSY
    err = sqlite3_busy_timeout(handle, 1000 /* ms */);
    if (err != SQLITE_OK) {
      LOGE("sqlite3_busy_timeout(handle, 1000) failed for \"%s\"\n", path8);
      throw_sqlite3_exception(env, handle, "Could not set busy timeout");
      goto done;
    }

#ifdef DB_INTEGRITY_CHECK
    static const char* integritySql = "pragma integrity_check(1);";
    err = sqlite3_prepare_v2(handle, integritySql, -1, &statement, NULL);
    if (err != SQLITE_OK) {
      LOGE("sqlite_prepare_v2(handle, \"%s\") failed for \"%s\"\n", integritySql, path8);
      throw_sqlite3_exception(env, handle, "sqlite_prepare_v2(handle, \"pragma integrity_check(1);\") failed");
      goto done;
    }

    // first is OK or error message
    err = sqlite3_step(statement);
    if (err != SQLITE_ROW) {
      LOGE("integrity check failed for \"%s\"\n", integritySql, path8);
      throw_sqlite3_exception(env, handle);
      goto done;
    } else {
      const char *text = (const char*)sqlite3_column_text(statement, 0);
      if (strcmp(text, "ok") != 0) {
        LOGE("integrity check failed for \"%s\": %s\n", integritySql, path8, text);
        jniThrowException(env, "net/sqlcipher/database/SQLiteDatabaseCorruptException", text);
        goto done;
      }
    }
#endif

    sqlite3_enable_load_extension(handle, 1);

    LOGV("Opened '%s' - %p\n", path8, handle);
    env->SetLongField(object, offset_db_handle, (intptr_t)handle);
    handle = NULL;  // The caller owns the handle now.

  done:
    // Release allocated resources
    if (path8 != NULL) env->ReleaseStringUTFChars(pathString, path8);
    if (statement != NULL) sqlite3_finalize(statement);
    if (handle != NULL) sqlite3_close(handle);
  }