una tabla saber guarda fichero existe esta donde datos crear actualizar acceder abrir c sqlite sqlite3 race-condition tocttou

tabla - ¿Cómo puedo detectar si sqlite3 creó un archivo de base de datos?



saber si existe tabla sqlite android (1)

No es posible diferenciar una base de datos recién creada de una base de datos vacía que se creó anteriormente.

Sin embargo, una base de datos vacía es la única con este problema. Se puede detectar cualquier otra base de datos comprobando si la tabla sqlite_master no está vacía. Haga esto y su creación de tabla dentro de una transacción, y no hay ninguna condición de carrera.

Si la primera vez que escribes en la base de datos (que es cuando el archivo se creó en realidad) está configurando el ID de aplicación , entonces sabes que cualquier archivo con otra ID no es tuyo. (Los ID de las aplicaciones registradas son únicos).

Estoy escribiendo un programa que usa un archivo de base de datos sqlite3 para almacenar sus datos. Si abro un archivo de base de datos con

sqlite3_open_v2(filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL)

el archivo de la base de datos se crea si no existe. ¿Cómo puedo averiguar si el archivo de la base de datos existía antes de abrirlo? El shell sqlite3 usa un código como este:

/* Go ahead and open the database file if it already exists. If the ** file does not exist, delay opening it. This prevents empty database ** files from being created if a user mistypes the database name argument ** to the sqlite command-line tool. */ if( access(data.zDbFilename, 0)==0 ){ open_db(&data, 0); }

Sin embargo, este código tiene una condición de carrera cuando el archivo de la base de datos es creado por otro proceso después de la llamada de access y antes de la llamada open_db (tiempo de verificación vs. tiempo de uso).

Otra respuesta (que no puedo encontrar ahora mismo) sugiere verificar los campos application_id y user_version . Si son cero, se acaba de crear una base de datos. Investigué este enfoque y descubrí que numerosas aplicaciones en realidad no se molestan en configurar estos campos en bases de datos recién creadas, por lo que este enfoque es confuso en el mejor de los casos, y no creo que resuelva mi problema.

¿Existe un método para averiguar si la base de datos existía antes de abrirla y no implica una condición de carrera como esta? También es aceptable si puedo simplemente averiguar si el archivo de la base de datos se inicializó (como en, un archivo truncado fue llenado con un encabezado sqlite3) por sqlite3.

El propósito de tener esa rutina es poder averiguar si necesito crear todas las tablas que necesito en la base de datos. No quiero sobrescribir accidentalmente otro archivo colocado allí por una aplicación diferente.

Código de muestra

Se puede encontrar una ilustración simplificada del problema en el siguiente script bash. Simula dos aplicaciones. Ambos trabajan de manera similar:

  1. Crear o abrir una base de datos test.db
  2. Si la base de datos no existía antes, cree una test tabla y escriba una sola fila en ella. El valor es 1 para la primera aplicación y 2 para la segunda.
  3. Imprime los contenidos de la base de datos.

Aquí está el código:

#!/bin/sh # sleeps are inserted to make the race conditions easier to trigger application() { echo Checking if database exists... [ ! -f test.db ] status=$? sleep 2 if (exit $status) then echo Database not found, making tables sqlite3 test.db "CREATE TABLE IF NOT EXISTS test (a);" sleep 2 echo Writing initial record into database sqlite3 test.db "INSERT INTO test VALUES ($1);" sleep 2 else echo Database found, checking if it belongs to me fi echo Printing content of database sqlite3 test.db "SELECT * FROM test;" } rm -f test.db echo First test: app1 and app1 race application 1 & (sleep 1 ; application 1) rm -f test.db echo Second test: app2 and app1 race application 2 & (sleep 1 ; application 1)

Mi objetivo es garantizar que los siguientes casos nunca puedan ocurrir:

  • Una instancia de la aplicación uno abre el archivo de la base de datos, concluye que no se inicializa y lo inicializa (creando la tabla y escribiendo el registro inicial) aunque ya contenga datos de una instancia diferente de la misma aplicación o de una aplicación diferente .
  • Se escribe un archivo de base de datos que pertenece a una aplicación diferente.

Si la application se programó correctamente, cada ejecución solo inicializaría la base de datos si no se había inicializado antes. Por lo tanto, el único resultado que vería es una base de datos que contiene solo la fila 1 o una base de datos que contiene solo la fila 2 .