Making sqlite3_open() fail if the file already exists - sqlite

I'm developing an application that uses SQLite for its data files. I'm just linking in the SQLite amalgamation source, using it directly.
If the user chooses to create a new file, I check to see if the file already exists, ask the user if they want to overwrite the file, and delete it if they say yes. Then I call sqlite3_open_v2() with flags set to SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE to create and open the new data file.
Which is fine, except, what happens if a malicious user recreates the file I'm trying to open in between the file being deleted and SQLite opening it? As far as I'm aware, SQLite will just open the existing file.
My program doesn't involve passwords or any kind of security function whatsoever. It's a pretty simple app, all things considered. However, I've read plenty of stories where someone uses a simple app with an obscure bug in it to bypass the security of some system.
So, bottom line, is there a way to make sqlite3_open() fail if the file already exists?

You might be able to patch in support for the O_EXCL option flag of open(2). If you are using SQLite on a platform that supports that.

Related

How could it be possible to perform the equivalent of onUpgrade() from SQLite on Realm?

I'd like to know if such a method exits, so when the user installs an app actualization the database gets properly actualized.
I've found a way that although it can't always work, I think in practice it will never fail, which is the following:
Check if database version of installed app is higher than the version in a hidden file in the previous app, if so, actualize the database.
Write that file with the database version of installed app.
This way, only if the user were to manually remove the file and not the database would cause my solution to fail in its purpose.
Even then it would be better if there was something that works like onUpgrade() from SQLite in Realm.
Is what I'm mentioning possible?

Reading Locked SQLite DB In to Memory

I'm working on a project that has some pretty specific requirements, and am running in to a problem with one of them. We have a locked SQLite database. We can't unlock this database, but need to read it (but not write to it), and we cannot create any new files on the filesystem that contain the data from this database. What was suggested is to read the file in to RAM, and then access it from there. I've been trying to find out a way to do this, but this project is on Windows, so it's not going as smoothly as it might otherwise.
What I've been trying to do is read the file in to a bash variable, and then pass that variable to sqlite as the database. This hasn't been working particularly well.
I installed win-bash, but when I do "sqlite3.exe <(cat <<<"$database")" I get a 'syntax error near unexpected token `<('" I checked, and win-bash looks like it's based on an older version of bash. I tried zsh, but it's saying "doesn't look like your system supports FIFOs.". I installed cygwin, which wouldn't really be a good solution anyway (once I figure out how to do this, I need to pass it off to our Qt developers so that they can roll it in to a Qt application) but I was just trying to do a 'proof of concept' - that didn't work either. Sqlite opened just fine, but when i ran ".tables", it said "Error: unable to open database "/dev/fd/63": unable to open database file" So, it looks like I'm barking up the wrong tree, and need to think of some other way to do this.
I guess my questions are, first, is it possible to read a sqlite database in a variable as I was attempting, or am I going down an entirely incorrect path there? Second - if it can't be done that way, is there some way I'm overlooking that might make this possible?
Thanks!

Using MagicalRecord to prepopulate a database (swift). -wal journal created, however, data not copied to database

(Forgive me since I am not use to posting here. Will do my best)
I am working on an iOS application that will be using a pre-populated database. In my workspace, I have a project for the iOS app and a separate command line tool project to populate the database. I have dragged the database file from the "/Library/Application Support" folder into my iOS project (without using the "Copy Items If Needed"). So when there is a change in the data or additional data is required, I can just run the command line tool to pre-populate the data. From there I will remove the app from the simulator and do a clean. When I run the app, I would think everything would be ok.
It was driving me crazy for the longest but sometimes, I don't see the changes reflected after I remove the app, clean the project and then run. It seems the only way I can get this to work is, after I run the command line tool to pre-populate the database, I have to open the database file using Base, SQLiteStudio or Firefox's sqlite add-on. Once I do that, it seems to work.
When I look in finder, I do see the files .sqlite, sqlite-shm and sqlite-wal. Before opening the database file, I see that the wal file is the biggest (for now it's 2mb). Once I open the file using Base for example, and then close it, the sqlite file is now 2mb.
When the command line is about to finish, I have tried running PRAGMA statements on the file (vacuum, wal-checkpoint) but those did not work. What am I missing here. I also tried using NSManagedObjectContext.MR_defaultContext.saveToPersistentStoreAndWait
I am using the following code to setup and save.
MagicalRecord.setupCoreDataStackWithAutoMigratingSqliteStoreNamed("callithome.sqlite")
MagicalRecord.saveUsingCurrentThreadContextWithBlockAndWait({(context)->Void in
println("Data saved, I hope")})
MagicalRecord.cleanUp()
Any help would be appreciated
You need to enable the DELETE pragma mode for your sqlite store. This will not create the -wal and -shm files. This will make it easier for you to have a single file for use at your pre-populated data store. You will need to use MagicalRecord 3.0 with some of the extra abilities to add custom options to your stores if you'd like o go that route. However, you can still add a store to a coordinator and have that store configured with the proper pragma option as well. That is, MagicalRecord is not necessary if you use normal Core Data.

Write-Ahead Logging and Read-Only mode compatible in SQLite3?

Open read-only
I have a sqlite3 file on a filesystem that belongs to a different user than is running the reading process. I want the reading process to be able to read the file in read-only mode, so I'm passing SQLITE_OPEN_READONLY. I would expect that to work. Surely the idea is that read-only mode works on files that we don't want to write to?
When I prepare my first statement I get
unable to open database file
Similarly if I run the sqlite3 command line tool I get the same result unless I sudo. Which seems to confirm to me that the issue is writeability rather than anything else.
Journal files
The answer to this question seems to suggest that if there are journal files around then read-only access isn't possible.
Why are there journal files? Because another process is writing the file, my user process is trying to open it in read-only. To do this I am using Write-Ahead Logging, which produces two journal files, -shm and -wal. True enough, if I stop the writing process and remove the journal files, my user process can open it in read-only mode.
Incompatibility?
So I have two situations:
If the file belongs to the writing process and also the read-only process, write-ahead logging enables process A to write and process B to read-only
If the file belongs to the writing process but does not belong to the read-only process, the read-only process is blocked from opening read-only.
How do I achieve both of these? To spell it out, I want:
Writing process owns database
Read-only process does not own database
Read-only process cannot write to database
Write-ahead logging is enabled on database
Seems like a simple set of requirements, but I can't see an obvious solution.
**EDIT: ** Going by this documentation, it looks like this isn't possible. Can you suggest any alternative ways to achieve the above?
Yes WAL-journaled databases cannot be opened read-only, explicitly or otherwise (i.e. in the case where the database file is read-only to the process).
If you require that the read-only process absolutely not be allowed to modify the database file, then the only thing that comes to mind is that the write process maintains a not WAL-journal additional copy of the database.
Bottom line: to the best of my knowledge, WAL and read-only can't be done.
I think what the documentation is saying is that the WAL database itself may not be present on a readonly media, which does not necessarily mean you cannot use SQLITE_OPEN_READONLY. In fact, I have successfully opened two connections, a read-write as well as one with SQLITE_OPEN_READONLY, both on a WAL sqlite database. These work just fine. I tested an INSERT query using the read-only connection and the statement correctly returned an error that the database is read-only.
Just make sure that the database is stored on some media with write-access as a -shm file needs to be created and maintained, and so even a 'ready-only' connection may actually physically write something to disk - which doesn't necessarily mean that it can modify data using SQL.

I can't write to a SQLLite database in my AIR app

I am publishing an AIR app in debug mode using FlashDevelop and have included a database in the files/folders to be published.
When the app first launches it checks whether there is an instance of this db in the applicationStorageDirectory, if there isn't it copies the included one from the applicationDirectory to the applicationStorageDirectory.
This should mean that the referenced database dbFile = File.applicationStorageDirectory.resolvePath(DB_FILE_NAME); should now be writable, however when i run the app i can read the records from the table but when i attempt to write using an SQL statement I get an SQLError: 'Error #3122: Attempt to write a readonly database'.
I know that this would be thrown if i was attempting to write to the read only location of the applicationDirectory but i'm certainly using the File.applicationStorageDirectory location which should (as far as i know) be writable.
The location of the db on my Windows 7, 64bit = C:\Users\sean.duffy\AppData\Roaming\FishFightAppData\Local Store\db this is found using the dbFile.nativePath property so again i'm sure i should be able to update the db.
Anyone got any ideas? I have tried everything i could think of and searched all over but the only common cause seems to be when people try to write to the asplicationDirectory and not the storage directory....
UPDATE::
My bad - have just realised that i've misread the API of the 3rd party library i'm using! I should have been calling executeModify(statement) which can modify the contents of the db, instead i'm calling execute(statement) which doesn't/can't overwrite the db.
The source code is compiled into a swc and there was no documentation to point out you needed to use executeModify, although i should have guessed from the name i suppose!
Sorry about that and thanks for your help
(As a public courtesy to get this off the unanswered list, I am reposting the apparent solution. As usual, the asker is more than welcome to ignore mine and post it themselves and accept their own answer.)
In this API, you need to call executeModify(statement), not execute(statement). The latter does not overwrite the database.

Resources